diff --git a/.ci/generate-buildkite-pipeline-premerge b/.ci/generate-buildkite-pipeline-premerge index 81e9246de9b5895d1ab099a6b8a9919f2f569416..78a9cb77ff7d90f03179049c069aa9e05af3e66d 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 b347c443da677fd530afb91936a9605ec1218b2b..b00a4b984a1d23f4cdedb601a0e22a2ac518f162 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/CODEOWNERS b/.github/CODEOWNERS index 45da8af51bb9cefa6312b8966bf6cd63a6dcc09e..0f178df1d18f8c46a2b06aa00667e81f3a1be32a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -35,6 +35,10 @@ clang/lib/AST/Interp/ @tbaederr clang/test/AST/Interp/ @tbaederr +/clang/include/clang/CIR @lanza @bcardosolopes +/clang/lib/CIR @lanza @bcardosolopes +/clang/tools/cir-* @lanza @bcardosolopes + /lldb/ @JDevlieghere # MLIR Interfaces. diff --git a/.github/new-prs-labeler.yml b/.github/new-prs-labeler.yml index 9cf64417d3cb2cce3a61707ae1693e692c6e1a0e..d608ea449f1d40c841e2ae356f4a0fa8431d2d48 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 8d89ef8b5484f8e18d7ea034c3d38df57746760a..5d7692559eda882b125ee5314117eb5fe65932d0 100644 --- a/bolt/include/bolt/Passes/BinaryPasses.h +++ b/bolt/include/bolt/Passes/BinaryPasses.h @@ -400,8 +400,7 @@ public: /// 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 af832b4c7c84cf32b059f99adba4ed4df6fc5b19..41a92e7ba01e8495bc0a6b4329017d2f1e2c40fd 100644 --- a/bolt/include/bolt/Rewrite/RewriteInstance.h +++ b/bolt/include/bolt/Rewrite/RewriteInstance.h @@ -422,10 +422,18 @@ private: /// 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 @@ private: /// 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 2e3ac20a532d76f848ea48d865194f8348dc65ba..ccffa5633245ce4504e9bf4d7b4fc95d62e3c996 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/Passes/ValidateMemRefs.cpp b/bolt/lib/Passes/ValidateMemRefs.cpp index f29a97c43f497c289edbadfef7a59461f90b9694..ca58493b279c9eaf07ac01000f94f0a10dc8d36d 100644 --- a/bolt/lib/Passes/ValidateMemRefs.cpp +++ b/bolt/lib/Passes/ValidateMemRefs.cpp @@ -29,8 +29,7 @@ bool ValidateMemRefs::checkAndFixJTReference(BinaryFunction &BF, MCInst &Inst, if (!BD) return false; - const uint64_t TargetAddress = BD->getAddress() + Offset; - JumpTable *JT = BC.getJumpTableContainingAddress(TargetAddress); + JumpTable *JT = BC.getJumpTableContainingAddress(BD->getAddress()); if (!JT) return false; @@ -43,8 +42,9 @@ bool ValidateMemRefs::checkAndFixJTReference(BinaryFunction &BF, MCInst &Inst, // the jump table label with a regular rodata reference. Get a // non-JT reference by fetching the symbol 1 byte before the JT // label. - MCSymbol *NewSym = BC.getOrCreateGlobalSymbol(TargetAddress - 1, "DATAat"); - BC.MIB->setOperandToSymbolRef(Inst, OperandNum, NewSym, 1, &*BC.Ctx, 0); + MCSymbol *NewSym = BC.getOrCreateGlobalSymbol(BD->getAddress() - 1, "DATAat"); + BC.MIB->setOperandToSymbolRef(Inst, OperandNum, NewSym, Offset + 1, &*BC.Ctx, + 0); LLVM_DEBUG(dbgs() << "BOLT-DEBUG: replaced reference @" << BF.getPrintName() << " from " << BD->getName() << " to " << NewSym->getName() << " + 1\n"); diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp index 0b2a4e86561f3aaa56a7385bf4fd8e5439f2d56a..70e324cc0165bb969c6a63d8f9334b80fb8fbd6c 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 be4888ccfa56457fe2f59dcee91abdd05b947021..cbb7199a53ddd14f77730645efd8a8fd2a4109a4 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 fa43b7a2f92c23d04270bb13930faea443e91add..74b5ca18abce429410d11306189b3c5bfa5f4c73 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/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 21fa15b6a11faf485a6fd21b5d7487ccd6acfd62..644d87eeca42e65a2dbf4a6618e63911f5996dae 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,7 +4041,7 @@ void RewriteInstance::patchELFPHDRTable() { if (!NewWritableSegmentSize) { if (PHDRTableAddress) NewTextSegmentSize = NextAvailableAddress - PHDRTableAddress; - else + else if (NewTextSegmentAddress) NewTextSegmentSize = NextAvailableAddress - NewTextSegmentAddress; } else { NewWritableSegmentSize = NextAvailableAddress - NewWritableSegmentAddress; @@ -3932,11 +4049,6 @@ void RewriteInstance::patchELFPHDRTable() { 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 +4064,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 +4121,36 @@ 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; + } + break; + case ELF::PT_DYNAMIC: + if (!opts::UseGnuStack) { + // Insert new headers before DYNAMIC. + writeNewSegmentPhdrs(); + AddedSegment = true; } - 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(); } - assert((!opts::UseGnuStack || ModdedGnuStack) && - "could not find GNU_STACK program header to modify"); + if (opts::UseGnuStack && !ModdedGnuStack) { + BC->errs() + << "BOLT-ERROR: could not find PT_GNU_STACK program header to modify\n"; + exit(1); + } } namespace { @@ -4050,9 +4176,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 +4618,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 +4678,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 +4916,7 @@ void RewriteInstance::updateELFSymbolTable( ++NumHotDataSymsUpdated; } - if (*SymbolName == "_end") + if (*SymbolName == "_end" && NextAvailableAddress > Symbol.st_value) updateSymbolValue(*SymbolName, NextAvailableAddress); if (IsDynSym) @@ -4889,13 +5030,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())) { @@ -4907,6 +5041,10 @@ void RewriteInstance::patchELFSymTabs(ELFObjectFile *File) { assert((DynSymSection || BC->IsStaticExecutable) && "dynamic symbol table expected"); if (DynSymSection) { + // Set pointer to the end of the section, so we can use pwrite to update + // the dynamic symbol table. + Out->os().seek(DynSymSection->sh_offset + DynSymSection->sh_size); + updateELFSymbolTable( File, /*IsDynSym=*/true, @@ -5460,10 +5598,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 @@ -5682,7 +5820,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); @@ -5694,25 +5833,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 88% rename from bolt/test/RISCV/unnamed-sym-no-entry.c rename to bolt/test/RISCV/fake-label-no-entry.c index b4173506b213ce574df197c0c39f1aa172a6dfa3..bd125263101bb461149967745d23f52e32128781 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]] .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 e2259276e2554c406223f9d209a52863fa184ab0..e53863e22246d63d54ce4f56283d69c8ac37c856 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 97069bf8096e1ce56c88c28dd619e4ab1ff94bed..32d1f5a98b64a3732295d8f6898ce60b19e3c149 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/jt-symbol-disambiguation-4.s b/bolt/test/X86/jt-symbol-disambiguation-4.s new file mode 100644 index 0000000000000000000000000000000000000000..816b0fb501a590dc72af46f419a3305fda0f6568 --- /dev/null +++ b/bolt/test/X86/jt-symbol-disambiguation-4.s @@ -0,0 +1,60 @@ +# If the operand references a symbol that differs from the jump table label, +# no reference updating is required even if its target address resides within +# the jump table's range. +# In this test case, consider the second instruction within the main function, +# where the address resulting from 'c + 17' corresponds to one byte beyond the +# address of the .LJTI2_0 jump table label. However, this operand represents +# an offset calculation related to the global variable 'c' and should remain +# unaffected by the jump table. + +# REQUIRES: system-linux + + +# RUN: %clang -no-pie %s -o %t.exe -Wl,-q + +# RUN: %t.exe +# RUN: llvm-bolt -funcs=main,foo/1 %t.exe -o %t.exe.bolt -jump-tables=move +# RUN: %t.exe.bolt + + .text + .globl main + .type main,@function +main: + pushq %rbp + movq %rsp, %rbp + movq $-16, %rax + movl c+17(%rax), %edx + cmpl $255, %edx + je .LCorrect + movl $1, %eax + popq %rbp + ret +.LCorrect: + movl $0, %eax + popq %rbp + ret + .p2align 4, 0x90 + .type foo,@function +foo: + movq $0, %rax + jmpq *.LJTI2_0(,%rax,8) + addl $-36, %eax +.LBB2_2: + addl $-16, %eax + retq + .section .rodata,"a",@progbits + .type c,@object + .data + .globl c + .p2align 4, 0x0 +c: + .byte 1 + .byte 0xff + .zero 14 + .size c, 16 +.LJTI2_0: + .quad .LBB2_2 + .quad .LBB2_2 + .quad .LBB2_2 + .quad .LBB2_2 + diff --git a/bolt/test/X86/pre-aggregated-perf.test b/bolt/test/X86/pre-aggregated-perf.test index e8c3f64239a27ddb831f801ccf76b09d44fda6b1..0bd44720f1b7a102f8590d575d3156277c488624 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 0000000000000000000000000000000000000000..fa9b70e0b2d8919a371b609263e03c1d902547bb --- /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/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/EasilySwappableParametersCheck.cpp index 84e99c7fafc74b2930bea63155fa3a1506152713..10868129e76da955c45a4555b55088c806420b65 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 6852db6c2ee31103b684e93114cc29b9d9c5f633..8005d6e91c060c6e9b0e08d8f11cffb094c5fa4e 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 0000000000000000000000000000000000000000..45f7700463d5708673a78d5caf31cea9a3d0dd17 --- /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 0000000000000000000000000000000000000000..577d12653076124235cf25227544ce4ad091bb15 --- /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 e96cf274f58cfefccb746abd6f6f5d89f69dfe26..776558433c5baa492e8f33637becee5d85775de1 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 @@ public: 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 6c32a4edb4ff96ed48703067a7b52dc9041be4d7..f1591bae4465798750f1642eac64d70991d678cb 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h +++ b/clang-tools-extra/clang-tidy/modernize/UseNullptrCheck.h @@ -19,7 +19,7 @@ public: 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 48bca41f4a3b1e87dbd7488617702f17e5f6e15a..f077040a35295e97c9f4606787757a6a04e0190e 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 dd772d692025481a9eae7475168f96ec29baf6fe..41065fc8e8785903b220113cde72e3e286166c3b 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 0000000000000000000000000000000000000000..65fd296094915bbddf4e114e3ee96f8d5efb5f50 --- /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 0000000000000000000000000000000000000000..9a9d2b3cfaabaeb928b18a088791a2dec723434c --- /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 376b84683df74e4e8880431b58a70220b600e486..d61c0ba39658e5ff47fdd0a3ac2fdec28a10e155 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 @@ public: "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 2075e5965f181ede2a7c2b737b63afbc91ba8285..9b4442b0bb76fd780af6909772a89d2e6e069cde 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/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 5b1feffb89ea0602e2f38392b2ef1ff7ba365ba4..3038d2b125f20d9364f413df0be4ab53a5fa05b0 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,6 +251,10 @@ 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. @@ -269,6 +287,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 +346,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 c5321b07f7f84d537f92381b72ff1a1d94e67640..9271c9ecccc00c7e223f56c82334e702eeca4fdb 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 5d9d487f75f9cbea36f798442391fb7ad41075e1..49747ff896ba5c6f8556af99a0993090328e406b 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 0000000000000000000000000000000000000000..d6721a25629b05c71e5e5197de98d9ec7964c38a --- /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 5e1ba858adf3a9c42e20f8334781cd8dc6c2aab7..25e17fee0a3d6106cc83e86297ea8541990802c0 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 0000000000000000000000000000000000000000..21d66daab334c60d4b1cc6e1122ff75cab9b15e1 --- /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/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 0000000000000000000000000000000000000000..51ab9bda975f10baba00221fe02a6ab13f07ae90 --- /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-nullptr-c23.c b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nullptr-c23.c new file mode 100644 index 0000000000000000000000000000000000000000..6fb879b91e41c1c5ee0ab97bc76bd8ce072cc2c1 --- /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 c2ccbbd81171526ba6447ca244cb85a98b3868ab..1218b837199c0c2dcc3f857ac63d7f83366141e2 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 0000000000000000000000000000000000000000..a6045c079a4823bb0852e64e15a0d8853bd13bc7 --- /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 f01ebd1ec67d7007bf3487191f5484056bc66b78..b16ec56e321bd29ba010900827624add4fb5da96 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 932b0eb93c90eb783b6eb0d1923ddaf5fafe23dd..f5bf9ac2b955dcd6f35a4a339c196394411bd66d 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 31f61027994f768801b24750ea45caeae7cd9711..ed33d37eb3d596899cb0fd4f0f034fdc60ad4858 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 f092766fa19f07f754960ec9524078d6b65070d4..cf97e3c6e851aee92dd5378b85515304fc875999 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 fa972636553f1f613eaa7e8f19d55f9b54f42f0d..c0bfcbdfc1c2ae6cb32edfcb26e376baa1dd2641 100644 --- a/clang/cmake/caches/Release.cmake +++ b/clang/cmake/caches/Release.cmake @@ -1,95 +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 - package - 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 e3976f3206db5309780e3b2625812ee413ae106b..2f968a21cc407e7a79220b68cec30229101d22cf 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 84fc4dee02fa803766b66528e53f40057fc8a1df..c2e90f4e7d587ada3c26a321def23227b56ed95f 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**: @@ -5572,3 +5577,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 df50dcebf9b83c72704aa9a7ba4b2c2578336a8d..87d84321ab2830837dbba25a6d8746f35a3b01d0 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 f8146bc365e8333d1e16389b162139386aa8c743..5e63b2c0f0be6ba7a986060d68a153461a694f22 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 7bea43ec64f062f6617bfbf1eb26c819c17772bb..4c0fe5bcf6b122d3326d1f9506e52a9bf552e6d3 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 ------------------------- @@ -436,6 +475,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 +607,10 @@ 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. Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -616,6 +663,9 @@ Arm and AArch64 Support * Arm Cortex-A78AE (cortex-a78ae). * Arm Cortex-A520AE (cortex-a520ae). * Arm Cortex-A720AE (cortex-a720ae). + * Arm Neoverse-N3 (neoverse-n3). + * Arm Neoverse-V3 (neoverse-v3). + * Arm Neoverse-V3AE (neoverse-v3ae). Android Support ^^^^^^^^^^^^^^^ @@ -672,6 +722,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 ^^^^^^^^^^^ diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 8df40566fcba3d815a8a4e18da81e4e708580269..6ba0a531fedf9bb6ea41ff70ef4fc24fe81e75e1 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= @@ -1692,7 +1698,6 @@ floating point semantic models: precise (the default), strict, and fast. * ``-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 +1943,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 +2322,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 +2453,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 +2501,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 +2553,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/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 7a8bd985a91fc00b2c3a6c488aca5030fc211c8d..365b607c741179e94146e57d3909e164857a9960 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 93bb045d6a667046239bccff8deb83dc479d2f6e..026a4a431e7349e51f424df87f15d3a25e6d44fd 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 @@ public: 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 @@ public: 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 @@ public: 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 d5ed20ff50157d611ba643c9bdf6e2a5302a68de..6dbd06251ddad69d94ba95c5f57b061e775968cf 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 @@ public: /// 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); @@ -1127,7 +1127,8 @@ public: 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" @@ -2196,6 +2197,16 @@ public: 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 216dc9eef08b62c87cde4d19d5af36c2f2680562..bf7c204e4ad73ab6408292215d3a839cc495c0ca 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -844,6 +844,12 @@ public: } } + 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 1f2797cc701458947ba3fa6f240dbb95cc67e326..ab036f1d445acc5c56a8a1e0f3b1eb3b7ea65a44 100644 --- a/clang/include/clang/AST/AbstractBasicReader.h +++ b/clang/include/clang/AST/AbstractBasicReader.h @@ -213,9 +213,9 @@ public: } 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 07afa388de2c178bf63c276b1f0a2daa77821807..8e42fcaad1d388ecab9bb76c9082655fbcb750fc 100644 --- a/clang/include/clang/AST/AbstractBasicWriter.h +++ b/clang/include/clang/AST/AbstractBasicWriter.h @@ -196,9 +196,9 @@ public: } 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 c04f6f6f1271916bc93d5d818c2680958962c119..0a36fdc5d9c0f7ee7f12405d7bf04f2fd7aef666 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 7abf9141237dc87206548a7fc2a0bb639e436496..6d3a51c379f9df335bd0e7b084d532fe5ae4ad94 100644 --- a/clang/include/clang/AST/ComputeDependence.h +++ b/clang/include/clang/AST/ComputeDependence.h @@ -94,7 +94,7 @@ class DesignatedInitExpr; class ParenListExpr; class PseudoObjectExpr; class AtomicExpr; -class OMPArraySectionExpr; +class ArraySectionExpr; class OMPArrayShapingExpr; class OMPIteratorExpr; class ObjCArrayLiteral; @@ -189,7 +189,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 8b121896d66d158d06be1c317d7d1e1698782bc5..a53c27a99a8c3645c48c8ff2554e0ebf67cd38f1 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -157,7 +157,7 @@ public: 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 @@ public: 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; } @@ -518,7 +518,7 @@ public: 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; } @@ -581,7 +581,7 @@ public: 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; @@ -1146,7 +1146,7 @@ public: 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; @@ -1728,7 +1728,7 @@ public: 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, @@ -1782,7 +1782,7 @@ public: 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; @@ -2178,7 +2178,7 @@ public: 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); @@ -3136,7 +3136,7 @@ public: 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. @@ -3311,7 +3311,7 @@ public: 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; } @@ -3357,7 +3357,7 @@ public: 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; @@ -3542,7 +3542,7 @@ public: 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; @@ -3567,7 +3567,7 @@ public: 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; @@ -3977,7 +3977,7 @@ public: 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. @@ -4182,7 +4182,7 @@ public: 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( @@ -4433,7 +4433,7 @@ public: 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; } @@ -4469,7 +4469,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; } @@ -4563,7 +4563,7 @@ protected: 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(); } @@ -4717,7 +4717,7 @@ public: 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; @@ -4851,7 +4851,7 @@ public: 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. @@ -4892,7 +4892,7 @@ private: 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; } @@ -4931,7 +4931,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; } @@ -4957,7 +4957,7 @@ public: 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 d8cafc3d81526ef53ac6290fc6f03cae2acdf6f3..e43e812cd94558469ee5d6c53f6742dd89045e59 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 @@ public: 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 @@ protected: /// \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 @@ public: /// 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 a7644d2a19d2459c0a746a62cb1fc06f5fa5c2d5..fb52ac804849d87c91017bfd2b4381d9d55150aa 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -120,7 +120,7 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: LifetimeExtendedTemporaryDecl(Temp, EDec, Mangling); } static LifetimeExtendedTemporaryDecl *CreateDeserialized(ASTContext &C, - DeclID ID) { + GlobalDeclID ID) { return new (C, ID) LifetimeExtendedTemporaryDecl(EmptyShell{}); } @@ -3357,7 +3360,7 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ private: 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 c4734ab578953835ee9719264ae2e9279d7d979f..e169c4859219290f483d59eb5aafb5bb99fa591b 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 @@ public: 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 @@ public: 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 b56627a5337d63a80af5b4ad2856aad5c1be2998..9789282f351a55c07e242598489aeb2a9b8b4e56 100644 --- a/clang/include/clang/AST/DeclFriend.h +++ b/clang/include/clang/AST/DeclFriend.h @@ -112,7 +112,7 @@ public: 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 0000000000000000000000000000000000000000..614ba06b63860cdd13f7c1f2761c40231ca39275 --- /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 7780afa6f1cf5c11b286b39613cc18c21293630b..d2cc61ca19f8a5796a7a499c0780de95a0b92a6c 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -236,7 +236,7 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 c7ede7f2157fef7676cb6bf068761c49602479d9..e542c3c8e66b0f28a4de617c302c60542cee632e 100644 --- a/clang/include/clang/AST/DeclOpenMP.h +++ b/clang/include/clang/AST/DeclOpenMP.h @@ -59,7 +59,7 @@ protected: } 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 231bda44a9fcfdfbcfc532cb0894040dc6332492..3ee03eebdb8ca45d48358b8e52d2cce85553c5bf 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -797,7 +797,7 @@ protected: /// /// 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: ClassTemplatePartialSpecializationDecl *PrevDecl); static ClassTemplatePartialSpecializationDecl * - CreateDeserialized(ASTContext &C, DeclID ID); + CreateDeserialized(ASTContext &C, GlobalDeclID ID); ClassTemplatePartialSpecializationDecl *getMostRecentDecl() { return cast( @@ -2306,7 +2305,7 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ public: 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 @@ private: 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 2bfefeabc348bee1cc399a43bfd8aa057a18ec3d..f2bf667636dc9b5d63864130240af4c01cfbc3ff 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -6610,6 +6610,275 @@ public: }; +/// 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/ExprOpenMP.h b/clang/include/clang/AST/ExprOpenMP.h index be5b1f3fdd112f1008891aa3abcfc7854ff32a19..54a0c203f656c3585ef440c8aea0fbfac404a787 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 eee8d6b6c6ef115e2e9c44d8aca7ee714f58ea6f..385c32edbae0fdba3218d0711bee53fa3f72bd68 100644 --- a/clang/include/clang/AST/ExternalASTSource.h +++ b/clang/include/clang/AST/ExternalASTSource.h @@ -99,7 +99,7 @@ public: /// 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 @@ public: 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 7b0c21b9e7cfb1515789809bee50566bedbad480..a1d9e30e660d143610d3fdd22fcfcecff3443476 100644 --- a/clang/include/clang/AST/NestedNameSpecifier.h +++ b/clang/include/clang/AST/NestedNameSpecifier.h @@ -266,7 +266,7 @@ public: 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/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 7eb92e304a3856bcdbc70bb9733e108389df3778..f9b145b4e86a5579dc13760ecce791468620c681 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2740,7 +2740,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 99f45d518c7960fab956a317719a6870a2c8fdf4..e6643469e0b3344937d69beeee77e37d8bfed37e 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 @@ public: 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 @@ public: /// 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 @@ public: } // 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 @@ public: } 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 @@ public: 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 @@ public: } 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 @@ public: addObjCGCAttr(Q.getObjCGCAttr()); if (Q.hasObjCLifetime()) addObjCLifetime(Q.getObjCLifetime()); + if (Q.hasPointerAuth()) + addPointerAuth(Q.getPointerAuth()); } } @@ -471,6 +665,8 @@ public: removeObjCLifetime(); if (getAddressSpace() == Q.getAddressSpace()) removeAddressSpace(); + if (getPointerAuth() == Q.getPointerAuth()) + removePointerAuth(); } } @@ -483,6 +679,8 @@ public: !hasObjCGCAttr() || !qs.hasObjCGCAttr()); assert(getObjCLifetime() == qs.getObjCLifetime() || !hasObjCLifetime() || !qs.hasObjCLifetime()); + assert(!hasPointerAuth() || !qs.hasPointerAuth() || + getPointerAuth() == qs.getPointerAuth()); Mask |= qs.Mask; } @@ -536,6 +734,8 @@ public: // 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 @@ public: 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 @@ public: // 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 @@ public: /// '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 4408d517e70e5883f1e68357a3fde364aaaf6b59..0225598cbbe8ad8f1d5e8085688e22fda4ef75b1 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -592,6 +592,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; @@ -603,8 +646,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; @@ -3173,7 +3216,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; } @@ -3211,7 +3254,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]; } @@ -3472,7 +3515,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; @@ -3488,7 +3531,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; @@ -3504,7 +3547,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; @@ -3520,7 +3563,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; @@ -3539,7 +3582,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; @@ -3559,7 +3602,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; @@ -3570,7 +3613,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; @@ -3581,7 +3624,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; @@ -3592,7 +3635,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; @@ -3603,7 +3646,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; @@ -3614,7 +3657,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; @@ -3627,7 +3670,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; @@ -3640,7 +3683,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; @@ -3651,7 +3694,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]>; @@ -3661,7 +3704,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 14b08d4927ec5e264ac9bb73cf8f07ebc4eb1cc2..fcffadacc8e631ebbd7b3d54368b02a50c815b29 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -370,4 +370,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/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 38174cf3549f14ecad83883acff62b47f15b92c0..fdffb35ea0d955473d86b74d22787391de49d0b2 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 '+'">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 6732a1a98452ad3c3063f8028634d19f376682f4..f72d5c252b863e03c1ebd418dcf116f99e23f931 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -9901,6 +9901,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; @@ -9950,6 +9953,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; @@ -10328,9 +10333,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< @@ -11161,7 +11170,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< diff --git a/clang/include/clang/Basic/FileManager.h b/clang/include/clang/Basic/FileManager.h index 2245fd78bfc9f0c77479dbcb07b192de48d59129..8b4206e52cd482bc10ce449a176c447b1dcb0218 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 @@ private: 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 8ef6700ecdc78eca7ec8a245d37d5d49122dd0d6..55c81eab1ec1508f75fef5d2def123ac1196bbc6 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 ae4715921d166595cfe899e54527736ac9051cf7..e2a2aa71b880b3b8a366c1363e3784e8d2e42b67 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/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h new file mode 100644 index 0000000000000000000000000000000000000000..e5cdcc31ebfb70d2c55f9d717bd24996f5c1b169 --- /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 b4e3ae573b95e62af4fae5529bc8d1e52bbcf88c..305f19daa4a9238fff2d9a755fb163da2ff06dfc 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -71,7 +71,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 e1ef7454f01669c4ecff7f1998275a0b2512ed71..3ced2e7397a75402021d8eb7444f007ee1d9c396 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 @@ public: /// 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 6d655c39360d3beaa76fc2198f13cf31f85d4bc8..6390ba3f9fe5e50252da63f247b1c8ed17cea451 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 6cc249837d3f3d42414331ee5a0bf3f0e9c36bee..15340ebb62b365d1ea8d7a40811097a49aaa5e26 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/CIR/CMakeLists.txt b/clang/include/clang/CIR/CMakeLists.txt index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..f8d6f407a03d02358be081c96682e8736385b53c 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 0000000000000000000000000000000000000000..f33061b2d87cffc48b072763eb55d349e9070aba --- /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 0000000000000000000000000000000000000000..d53e5d1663d62a478d74a7f5624b9d0a75314003 --- /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 0000000000000000000000000000000000000000..69d6e9774942b9dfb0eb85793dafb63c0b89baf3 --- /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 0000000000000000000000000000000000000000..7311c8db783e061705e3745ca266d87aa379c2db --- /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 0000000000000000000000000000000000000000..28ae30dab8dfb23a75751a885cf6795eaa2ee217 --- /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 922bda721dc780bd141393ba28011353ceec46d3..864da4e1157f7da167feeb4e04613f7271ee6408 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1608,6 +1608,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; @@ -2881,6 +2893,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, @@ -4876,6 +4899,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; @@ -6582,12 +6607,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 a2c1b25dd224768fa38aeae466da1f0919bcfe4f..080844893c13c9503663a9ed7b8805a67ec20940 100644 --- a/clang/include/clang/Frontend/ASTUnit.h +++ b/clang/include/clang/Frontend/ASTUnit.h @@ -241,7 +241,7 @@ private: /// 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 a738c1f375768282259993be13e40fcf6ce11ae0..bd4981ca0ac08cf2109649bfd5c22bc0169ce810 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 @@ public: 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 @@ public: 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 7f8d2858b3863eb71018e5dfca54c5efbf1fdce9..f29c8e92fded0cebb77329fc8cd4f3583992bb7c 100644 --- a/clang/include/clang/Frontend/MultiplexConsumer.h +++ b/clang/include/clang/Frontend/MultiplexConsumer.h @@ -35,7 +35,7 @@ public: 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/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index fb117bf04087ee4e528ae19b4dcebccdda57ce44..81aab8c888ab65001a7d5184501696d2d48f256a 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1398,12 +1398,21 @@ private: // 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 diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index c9eecdafe62c7ce148f69dfbfca8f791e129112d..23bc780e04979d84cbd5d789fd6a4e3921b27696 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 @@ public: struct Binding { IdentifierInfo *Name; SourceLocation NameLoc; + std::optional Attrs; }; private: @@ -1809,15 +1811,15 @@ public: : 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 @@ public: } /// 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/MultiplexExternalSemaSource.h b/clang/include/clang/Sema/MultiplexExternalSemaSource.h index 993c9b1daa309b5fe8998cebd935a852b31ec737..238fb398b7d12930becba1be738f44e7470024f8 100644 --- a/clang/include/clang/Sema/MultiplexExternalSemaSource.h +++ b/clang/include/clang/Sema/MultiplexExternalSemaSource.h @@ -65,7 +65,7 @@ public: /// 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 25a5fa05b21c7d8ab1054231de0af5f109b74227..8368d9ce61466de8d91bea09956befdd641dc14a 100644 --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -948,6 +948,7 @@ public: 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/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index ea28617f79b81b65df7d5cc63050a55a07003adb..da19503c2902fd270817f049bab819bd574919ce 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -193,6 +193,12 @@ public: /// conversions and diagnostics to 'int'. ExprResult ActOnIntExpr(OpenACCDirectiveKind DK, OpenACCClauseKind CK, SourceLocation Loc, Expr *IntExpr); + + /// 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 dcfa4ac0c1967797b8425ba53fd96fbe0e297edb..a8df5a0bda085092308105bfef680032e28dc5e2 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, @@ -1238,74 +1157,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; @@ -2075,7 +1926,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, @@ -2132,7 +1983,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; @@ -2231,27 +2082,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 f3a01a4b9731580c7b8e9eb056ea7ffc5cfa6af9..3ab7f1a91843b5c87afb91f64582323a3a107117 100644 --- a/clang/include/clang/Serialization/ASTDeserializationListener.h +++ b/clang/include/clang/Serialization/ASTDeserializationListener.h @@ -44,7 +44,7 @@ public: /// 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 ed917aa1642293154f6e61d42a9f44579cf15629..64f1ebc117b327047c942f164702cbeccfbc490d 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -501,10 +501,7 @@ private: /// = 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 @@ private: 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 @@ private: 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 @@ private: 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 @@ private: /// 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 @@ private: /// 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 @@ private: /// 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 @@ private: /// 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 @@ private: /// 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 @@ private: /// 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 @@ private: /// 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 @@ private: /// 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 @@ private: /// 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 @@ private: /// /// 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 @@ private: 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 @@ private: /// 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 @@ private: /// /// 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 @@ private: /// 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 @@ private: /// 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 @@ private: 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 @@ private: /// 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 @@ private: 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 @@ public: 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 @@ private: 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 @@ public: /// 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 @@ public: /// /// \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 @@ public: 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 @@ public: // 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 9eaf50a76d52f4c6f5ec33a65c4385855cda80c4..06b80f266a9441639796bea1f55b882fb46d4a0a 100644 --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -136,7 +136,7 @@ public: /// 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 @@ public: /// 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. diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index 13b4ad4ad2953dba072d56eec9ff2c033cfb8a45..4e433deaaf2dbc6e93bfc6e0c53810cfff301118 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -212,10 +212,10 @@ private: 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 +223,7 @@ private: /// 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 +233,8 @@ private: /// 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 +249,7 @@ private: /// 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 +420,8 @@ private: /// 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. @@ -709,7 +708,7 @@ public: 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 +716,13 @@ public: // 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. @@ -928,17 +928,30 @@ public: bool hasEmittedPCH() const { return Buffer->IsComplete; } }; -class ReducedBMIGenerator : public PCHGenerator { +class CXX20ModulesGenerator : public PCHGenerator { 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 { +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 492c35dceb08d4f08b3ddbeab49b7976b4e1ecdb..25f644e76edb1a4ce15551aa81293e7a49df8821 100644 --- a/clang/include/clang/Serialization/ModuleFile.h +++ b/clang/include/clang/Serialization/ModuleFile.h @@ -474,7 +474,7 @@ public: 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/Core/PathSensitive/Store.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h index fac0c04ae2caab5b1abae8d9cd6889dcbd343996..ef23b160a3c03291be9f5fcd7e97ecd0840dc368 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/Store.h @@ -225,15 +225,11 @@ public: /// 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/lib/APINotes/APINotesFormat.h b/clang/lib/APINotes/APINotesFormat.h index 615314c46f09cac62bffcac147c040a670c8417c..97e630e97fdcc2587f373f9c57cb2dee68f70451 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 dfc3beb6fa13ee6ca2723f7163fbe2ee1c272614..b60ca685f62c98dc9010c4fddf92c08a70888500 100644 --- a/clang/lib/APINotes/APINotesReader.cpp +++ b/clang/lib/APINotes/APINotesReader.cpp @@ -527,6 +527,13 @@ public: 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 e3f5d102fcd07fe5b398bfd95c0edc7df0cc5b2d..3e61597631509039874a821f594a0809e475218d 100644 --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -1128,7 +1128,7 @@ public: 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 @@ public: 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 57d6da7a1775960beec3ea1af7e26c5b905602c4..2295d769d344b8da145e586e3fd799b30cb85b0f 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 @@ public: 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 0f894c623beeeaf44dc2a1e52ccd9dc48315830d..cbf4932aff9a6b9ad6f5b24e8d74d0aafa25f29f 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 5ec3013fabba9ae4868d8faef7989a1ae0c648f0..bad8e75b2f878c25b47170ae6f31f3e11b8a098e 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 474e0ccde5bbf793369028e9fee2a2d6660032f1..e7e95c16b6978637f1dbdeb57191ea59366b396f 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2151,7 +2151,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); @@ -2929,7 +2929,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); @@ -4553,7 +4553,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); @@ -4863,7 +4863,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); @@ -5025,7 +5025,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); @@ -5297,7 +5298,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); @@ -5322,7 +5323,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); @@ -5349,7 +5350,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()); } @@ -5390,7 +5391,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); } @@ -5408,7 +5409,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); @@ -5418,7 +5419,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()); } @@ -5432,7 +5433,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); @@ -5458,8 +5459,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()); } @@ -5486,7 +5487,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); @@ -5547,7 +5548,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); } @@ -5560,7 +5561,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); } @@ -5591,7 +5593,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()); } @@ -5609,7 +5611,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); } @@ -5630,7 +5632,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()); } @@ -5663,7 +5665,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()); } @@ -5719,7 +5722,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()); @@ -5752,6 +5755,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 7cb6b31c541fd373662921cc8e46de533d9c16f7..03e1055251c24f446d502b0bfb2f04d857bf92f0 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 426c5262051094b23d83023eacd2b0ac31abba65..75c441293d62e2038743e7b2f218c70082a5b665 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 1fabf8aa80c2bdb66fca9e368f4d6f95a147038d..04b9b93699f36cebc9bfe7d72198eac8d03e09b4 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 d4275eea058212976f056a3f72874d144e15f11f..83062b0e68878d4e42d6b68d808e1e1eea852bc4 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 b178a15aab5f282363b48a29bfa252c9c2a1783b..81ca48e60942d5a69c7d5a3f873459dae4a79afe 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 67bb9e41e3e61e75d05baeeac4e102a9572a1de4..d27a30e0c5fce18b3c6d30e1fe10fd092e6cfed2 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 9eec7edc9d1a3e16c02df045792be33f589f1011..63dcdb919c7117f1f727bf6ac020d6f400561af2 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -3680,7 +3680,7 @@ bool Expr::HasSideEffects(const ASTContext &Ctx, case ParenExprClass: case ArraySubscriptExprClass: case MatrixSubscriptExprClass: - case OMPArraySectionExprClass: + case ArraySectionExprClass: case OMPArrayShapingExprClass: case OMPIteratorExprClass: case MemberExprClass: @@ -5060,9 +5060,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 7026fca8554ce9fa6b7f6cc6dd20f69e919fa153..2bb8f9aeedc7e245abdf1a2759bd336fc944d87a 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; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index de3c2a63913e94295d0a3007231b70e04c2318aa..f1aa19e4409e159c2a008901306876e615b2f6e3 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; @@ -9237,9 +9241,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 @@ -10709,8 +10714,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 @@ -10961,6 +10969,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 //===----------------------------------------------------------------------===// @@ -16130,7 +16254,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 2e54d9f9af1c6d571c4f83566cb63f0ae7036d7c..e96a4749685115bd6d989d2ad07b159793ed5f62 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 8cd0c198d9a844d6de48d284b4a4321bffbfd22a..17f95e7f3cac0dcd771e74546af063af92658a33 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(); + }; + + // 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 this->emitGetPtrBasePop(DerivedOffset, CE); + 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,14 +1175,14 @@ 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; @@ -1179,19 +1204,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 +1358,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; } @@ -2321,8 +2379,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 +2387,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 +2953,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 +3522,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 +3609,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 7e9dc8631fc0d3aa4f428cf245bbf20269906a7f..a89e37c67aa67c16876b795bd481fc665391012d 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -181,6 +181,7 @@ protected: 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 @@ protected: 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 @@ private: 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 36dab6252ece67a4071ed3b338e28f9524a3db3e..ff91baf595f1b1ea82253bc6136b0b734b13364f 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)) @@ -323,7 +332,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 274178837bf047d346ba7be09a6ac6ba159dbc92..d51a57e5e92eae17070b18116d16a1d59e9f486f 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 23c439ad8912a74839c8c93a788893247b913a15..360e9499d0844071e0ffe9b3c857c93a9800ada9 100644 --- a/clang/lib/AST/Interp/Context.h +++ b/clang/lib/AST/Interp/Context.h @@ -104,6 +104,9 @@ public: /// 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 a4ccc0236d292ce40665aaf2d37138e1e9831b86..954c58c8cb37162c1beb3335f39e9ac47baffc4c 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 c386fc8ac7b09d5030d1332e2d8dc227bba19a4c..cd20495c259c7d7e8db623aa014f59c79ec2ed5b 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 d127f33223e802b993ac5ec5d8d37091f781008b..ccdc96a79436dad25bcf595c537e7953b64fe042 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 9283f697c007098804c8486cc9f0c4d31635f846..9da0286deada175870c5174c940751af41b3d7f8 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(); diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index 742785b28eb4d7131cd862b0dbad87a5495e75be..2a97b978b523251fa64c91c77310b5224681596b 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]; } diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp index 3773e0662f784ce3b9f23224ee5150f5c1caaf73..02075c20cf556ddebcb69a3897b47129af928104 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 106c69dd5beed718256fc003af4caee51f475909..ed9e6eeb36c75d1832a7b2cf3572baf0c6e700a0 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -4715,7 +4715,7 @@ recurse: 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 ecc56c13fb757338751e5b7e60ae64d078924cb9..6f586173edb021ba365351eea9ffed220b7cf299 100644 --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -462,7 +462,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/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 5855ab3141edcc7d89a27ca956a4e670e1f8c604..f010d36513a49e34bf6e7f4295bbb05a7bfb3577 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -1521,7 +1521,7 @@ void StmtPrinter::VisitMatrixSubscriptExpr(MatrixSubscriptExpr *Node) { OS << "]"; } -void StmtPrinter::VisitOMPArraySectionExpr(OMPArraySectionExpr *Node) { +void StmtPrinter::VisitArraySectionExpr(ArraySectionExpr *Node) { PrintExpr(Node->getBase()); OS << "["; if (Node->getLowerBound()) @@ -1531,7 +1531,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 c81724f84dd9cee09aed44aa37b6819cd2d2b613..a95f5c6103e24dd49332611b32a44650fae7e303 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -1435,7 +1435,7 @@ void StmtProfiler::VisitMatrixSubscriptExpr(const MatrixSubscriptExpr *S) { VisitExpr(S); } -void StmtProfiler::VisitOMPArraySectionExpr(const OMPArraySectionExpr *S) { +void StmtProfiler::VisitArraySectionExpr(const ArraySectionExpr *S) { VisitExpr(S); } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index cb22c91a12aa8911b9c487e7044f3032ef5c9654..68e81f45b4c28eeab60a390a73f654dc8f9a7e46 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!"); @@ -3413,8 +3425,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: @@ -4710,7 +4722,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 21e152f6aea8a0e1cc03418c8a6e582b7dadafcf..ce45b47d5cfea5ea4395e7777f7da30d20bb39c7 100644 --- a/clang/lib/AST/TypeLoc.cpp +++ b/clang/lib/AST/TypeLoc.cpp @@ -429,7 +429,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/FlowSensitive/ASTOps.cpp b/clang/lib/Analysis/FlowSensitive/ASTOps.cpp index 619bf772bba5eec46215759e62e197176e2d7718..bd1676583ecccdec2c1d262c4bba9c4d6e2878ae 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 3cb656adcbdc0cfa5ba8fa15cc0223d1e03f1011..d79e734402892a65331ebac4208cef6c4518eb9f 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 @@ public: } } + 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 43fdfa5abcbb51fd3aaeb130156fc8fadc4be38b..fd224aeb79b15109c783484855809b8d963c05a9 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/FileManager.cpp b/clang/lib/Basic/FileManager.cpp index cd520a6375e07e5f0629dfeb0843f5d02d02444b..143c04309d0753d114c36120c689e4e6b7e36489 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 e69adbe754739f66f6084b252661404bf96b892b..df9855a52e61c0fd38520675f06e5cbac3dd9433 100644 --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -225,6 +225,10 @@ public: 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 9376c46cd98ca120f7797efe434580c07769d371..feeb04f37eeba7b6ad0ed0c89800670519dfd367 100644 --- a/clang/lib/Basic/Targets/AVR.h +++ b/clang/lib/Basic/Targets/AVR.h @@ -175,6 +175,10 @@ public: 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 489f29fc4fead37246c96467d6beeab167c7da49..d19b37dd4df7a7d2cbf42b4321079a8d5ca9f8aa 100644 --- a/clang/lib/Basic/Targets/BPF.h +++ b/clang/lib/Basic/Targets/BPF.h @@ -113,6 +113,10 @@ public: 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 7ffa901127e504046908f0ce659a2b0bc4d2c89c..b732add77e0340150a7f4bce7c92421af7d12fcc 100644 --- a/clang/lib/Basic/Targets/M68k.h +++ b/clang/lib/Basic/Targets/M68k.h @@ -56,6 +56,10 @@ public: 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 0d6e4b4d0808906ba38020878c7e952ee1cf3346..730deb674aa5795af5e41df7d1382095900e3788 100644 --- a/clang/lib/Basic/Targets/Mips.h +++ b/clang/lib/Basic/Targets/Mips.h @@ -431,6 +431,10 @@ public: 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 60bc1dec8f95c62a21e69f93e2a7cf1a2caa8146..cd0f08dfb3bc986bc146d56d701c8b5d8dc2f851 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -423,6 +423,10 @@ public: // 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 @@ public: 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 9fa42e75bbfd147fcf73b9ef32c63eb70dfa97ed..d0e9cdc6da07b3a7310abc11846e30e5d5a60dd2 100644 --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -122,6 +122,10 @@ public: 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 214fef88e1dcd4b0a258ab7f85446469c2a83f7b..3357bee33e1ac7cb160f780c891c47886f06eb1d 100644 --- a/clang/lib/Basic/Targets/Sparc.h +++ b/clang/lib/Basic/Targets/Sparc.h @@ -140,6 +140,10 @@ public: 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 8e302acd51b8ad1d40e175e65c3e5ab7a2895dc6..73d3aa01a043f423c2259097007f3b117dba9e69 100644 --- a/clang/lib/Basic/Targets/SystemZ.h +++ b/clang/lib/Basic/Targets/SystemZ.h @@ -220,6 +220,10 @@ public: 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 d473fd19086460ba508499e5bddad840a789912f..0db7b668d8a0ac40bc03c76db48cffd87cd2fa3c 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) @@ -147,19 +148,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 +224,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 5568aa28eaefa7152637b70f4343937676f2a3d4..e4c18879182ed73f45aa0370c97155bc410aa151 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 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..d2ff200e0da5f58fb304607c1fd9e568d6e3d7e2 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 0000000000000000000000000000000000000000..f33061b2d87cffc48b072763eb55d349e9070aba --- /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 0000000000000000000000000000000000000000..c2829c3ff2af8cfcf29784ba48b65e3b20ffb142 --- /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 0000000000000000000000000000000000000000..0d7476b555705da5a565cb35427e1838f04ff84a --- /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 e67a600c1cdd77f6f3fb3ea5838fd10315574204..a370734e00d3e1cb4dc147d927695d66d279c6f4 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -3628,7 +3628,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: @@ -3885,9 +3885,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()) @@ -3900,9 +3903,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()) @@ -5366,7 +5372,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: @@ -18850,7 +18856,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 @@ -18859,7 +18865,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/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 6c33cc17621f8961ae4cbfb7c3500a9f67e7ed0d..69548902dc43b9b756e0ad54735fcac5ce40c581 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -1585,6 +1585,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(); @@ -4693,11 +4698,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(); @@ -4706,14 +4711,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 e6f8e6873004f29d716caea0e82fb902be0f8117..469e0363b744acf63943ecead6f79173e8f0ae5e 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 03e4a29d7b3dbfa5b3953725e9fc1fe0fe55bb44..c73c97146abc4d4d5ec4adba51bf0a02106d7d89 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 @@ public: 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 @@ public: } 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 539ded5cca5e1b406df7b1c860501d50620b686a..787db350487417c0013c42e0f4625968a677105b 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1372,7 +1372,26 @@ llvm::DIType *CGDebugInfo::CreateType(const TemplateSpecializationType *Ty, SourceLocation Loc = AliasDecl->getLocation(); - if (CGM.getCodeGenOpts().DebugTemplateAlias) { + if (CGM.getCodeGenOpts().DebugTemplateAlias && + // 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 ce6d6d8956076e4966eb0fd6719e1ab4f9a00af3..9cc67cdbe424b4022dc59c6cbad188744daef92a 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -19,6 +19,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" +#include "EHScopeStack.h" #include "PatternInit.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" @@ -35,6 +36,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 @@ -2201,6 +2203,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); } @@ -2217,39 +2240,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); } @@ -2442,9 +2474,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 @@ -2453,10 +2485,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 931cb391342ea236224fbd9ba85a05edd356c09f..d96c7bb1e56822f108ad5a17839f48253d7bfb51 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -115,10 +115,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 @@ -1621,8 +1627,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: @@ -4363,8 +4369,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(); @@ -4396,9 +4402,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 355fec42be4489389fa71aa73b948afbf9701069..44d476976a55bf4392ca733dae2e88e0f1e2909c 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; @@ -558,24 +560,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); @@ -671,9 +676,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); } //===----------------------------------------------------------------------===// @@ -1374,9 +1376,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(), @@ -1395,28 +1396,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) { @@ -1705,14 +1690,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; @@ -1735,10 +1713,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()); } } @@ -1815,10 +1791,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; } } @@ -1831,17 +1807,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 673ccef84d67814dd27bdd54bcc168f28540ae92..c18c36d3f3f3267fba9906f2c81092b8bfe3ff94 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 40a5cd20c3d715a343f1e44866000641be07d5c4..af48e8d2b839e0c023e54ee2e0151d4b45b3e3f0 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -2330,7 +2330,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 72d1471021ac02971f8d4da33e0ef149df12a501..0d4800b90a2f26c67ba51fff219673fb5290a8e4 100644 --- a/clang/lib/CodeGen/CGLoopInfo.cpp +++ b/clang/lib/CodeGen/CGLoopInfo.cpp @@ -673,8 +673,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 4e7f777ba1d9160fd872c7a3466fcf2a438f12e2..43dd38659518d11616bd3abfe2d466aff0fc178a 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 2ae11e129c75e42b88df5ceae7d3d1c71c3a6339..e39c7c58d2780e5488a848bf97161b96bbd6732b 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), @@ -6672,8 +6671,8 @@ private: // 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(); @@ -6779,7 +6778,7 @@ private: /// 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) @@ -6795,7 +6794,7 @@ private: // 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())) @@ -7027,7 +7026,7 @@ private: 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)) { @@ -7179,14 +7178,14 @@ private: // 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(); @@ -7207,7 +7206,7 @@ private: assert((Next == CE || isa(Next->getAssociatedExpression()) || isa(Next->getAssociatedExpression()) || - isa(Next->getAssociatedExpression()) || + isa(Next->getAssociatedExpression()) || isa(Next->getAssociatedExpression()) || isa(Next->getAssociatedExpression()) || isa(Next->getAssociatedExpression())) && @@ -7439,7 +7438,7 @@ private: 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 { @@ -7452,7 +7451,7 @@ private: } 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 { @@ -7510,12 +7509,12 @@ private: 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); @@ -7589,7 +7588,7 @@ private: continue; } - const auto *OASE = dyn_cast(AssocExpr); + const auto *OASE = dyn_cast(AssocExpr); if (!OASE) continue; @@ -8780,7 +8779,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 eb716520e5ff562754f645acf3e7198f0de5da25..87496c8e488c679b1ffb74d00d87a04eedf41a9b 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 a0a8a07c76ba16528fea5c39459684d7ee37a74c..ef3aa3a8e0dc619fd3b0f95e654ccb812cd5b573 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/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 86a6ddd80cc11464aa65b310fe050f44dbe12217..87766a758311d5f0e2b50e5a8dc8b58535735a30 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -91,6 +91,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); @@ -346,6 +348,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 a751649cdb597a520778c43ec9b98b8f4a53c310..6e7417fc7f52b679c26bcf7fd0aa5d0a3f8c60a7 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 @@ public: 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 @@ public: 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 @@ public: /// 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 @@ public: class RunCleanupsScope { EHScopeStack::stable_iterator CleanupStackDepth, OldCleanupScopeDepth; size_t LifetimeExtendedCleanupStackSize; + CleanupDeactivationScope DeactivateCleanups; bool OldDidCallStackSave; protected: bool PerformCleanup; @@ -940,8 +1001,7 @@ public: 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 @@ public: void ForceCleanup(std::initializer_list ValuesToReload = {}) { assert(PerformCleanup && "Already forced cleanup"); CGF.DidCallStackSave = OldDidCallStackSave; + DeactivateCleanups.ForceDeactivate(); CGF.PopCleanupBlocks(CleanupStackDepth, LifetimeExtendedCleanupStackSize, ValuesToReload); PerformCleanup = false; @@ -2160,6 +2221,11 @@ public: 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); @@ -2698,6 +2764,33 @@ public: 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 @@ -4169,8 +4262,8 @@ public: 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 d085e735ecb443a1bc59f9dea2ba4ae319ac56ae..c8898ce196c1edb0010ba49c3c699b663d0f9845 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -73,6 +73,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; @@ -442,6 +443,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() {} @@ -980,11 +986,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); @@ -4781,6 +4782,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 1cc447765e2c977cec62df9b7aaa54c44e20ebc4..be43a18fc60856b6e9fb0f79e89112f4948b8aec 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1241,6 +1241,9 @@ public: /// 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 1568b6e6275b9dee1c65a56f872f2897c24cba0f..e8d75eda029e6653a3d46218020a7bab6d425cdb 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -409,7 +409,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 d38a26940a3cb613a29557019f92b60b49cb7a9e..d47927745759e1406d0b97cb6cd34d5b05a6ddf6 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1131,9 +1131,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/Driver.cpp b/clang/lib/Driver/Driver.cpp index 76b7b9fdfb4f9b0cc8a82c1f69d534443b483fcc..114320f5d314681ebef32466078da47dc4f8e235 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -361,6 +361,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; @@ -4799,6 +4800,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 237092ed07e5dcf09dd90974d7a634d4cfecb507..0e86bc07e0ea2c5d5265bc0a1422f535e70d0449 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -1307,19 +1307,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 c1b350893b3744ae818aef707591eacec1e6904c..aab98506adb96f0a86f0389b01ca92515312ddd3 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 5f5d720cf759f4a29a94b1c5bfc9fac80a5cf893..1988a90a48ae6b7416299e119421bf46e2b0957d 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -835,46 +835,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, @@ -2472,8 +2432,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. @@ -2775,13 +2743,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; @@ -2931,11 +2897,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")) { @@ -3154,9 +3115,6 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, 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 != "") { @@ -3186,9 +3144,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 != "") { @@ -3203,8 +3159,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 ; @@ -7536,6 +7490,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 b65b96db16bd79583dc6dd4857f27c111ee0fb88..fec11c7e716fdffad42e99db202611ee8dc39bf7 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1191,118 +1191,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 6d93c1f3d7034a02dd8beed312e7b0457ba67bd6..8955b9fb653c2acc5a4a7708d430a8aa976dca79 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 f55b8bf48c13f781a69eaf464b60123618bd022b..9849c59685cca78b6e1645ed7aa3d8a05cd9f182 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -1796,9 +1796,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 fb65881061effc3abc4f88028b48f889f8bab1ae..db2c20d7b461d0a782ce6b4dd5a498903cc5e204 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -842,25 +842,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 524391743090ba386cc55a50a039a6be31ebf3a1..2d9e674e50a630325659166d5e9eeb9dc4912cdc 100644 --- a/clang/lib/Driver/ToolChains/Linux.h +++ b/clang/lib/Driver/ToolChains/Linux.h @@ -59,10 +59,6 @@ public: 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 ccb2c9190e2eff0bdb551c3ecb95dde3c987639d..c8d8ec3afbd990c8f4618a6b5f36cf115f8c2e56 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 f651e6228c206da58363e5d7482e108001cba788..28b6488e54a4223c03dde637ee246db7c6e0cdc9 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 cdfb4256e41d93ddf36de11fb047aeb4fdc37eb0..d366ae2080bc25eebff64e74b9fd06db1433be5c 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 6e4e6901e473f72dbe204c2b78645644d467252f..3a263955a6a8fef805a83e48ce8b77672fb32b0e 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; } diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index 4f822807dd987dc8ceeb43e8a550c4c135f50b86..44fd807ec27ea75450754dc38c85330ab3aed4a0 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 3610a08831e79a9fe0206941f4b59d2bab2fd56d..1b93588553a276507dc14d36a67ba7f666a77afc 100644 --- a/clang/lib/Frontend/ASTUnit.cpp +++ b/clang/lib/Frontend/ASTUnit.cpp @@ -1067,7 +1067,7 @@ public: std::vector takeTopLevelDecls() { return std::move(TopLevelDecls); } - std::vector takeTopLevelDeclIDs() { + std::vector takeTopLevelDeclIDs() { return std::move(TopLevelDeclIDs); } @@ -1101,7 +1101,7 @@ public: 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 6e3baf8386441593bd767ce2260bd1b107be3e6c..66a45b888f15cc736b11aeba5ee02cac93742ba1 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1293,6 +1293,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 8236051e30c4a5daa74b8ae09ce7e77d286cfad9..8312abc3603953e90f5334854cfbde1f5c0e2822 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -2549,6 +2549,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}, @@ -2891,6 +2892,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)); @@ -4337,6 +4340,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 b7c9967316f0b82ff2b211315d1be87a05d6340c..9ae7664b4b49d435dc8ea3ed90e6b89f7ac90678 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -80,7 +80,7 @@ public: 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 @@ public: 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 @@ public: : 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 04eb104132671357f84a8d74b070636bff90087e..454653a31534cd3ef7d22d2dbf51aed94314b547 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 4f44c3b7b89d4d860ad3815fb77c23557fcb1b37..c1d209466ffe5dd34edc5ab5f703f2656f88b92a 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 @@ -704,7 +703,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"); @@ -1309,6 +1308,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 744ea70cc24def6442cdd1c306ab43334daa6862..c74bfd86195fec275b875c50b747d907fdfbd164 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 f85f0365616f9ad8a92805a753bbc385aaa7a304..7476b1076d10381df8f485ffc3a05573ad68c9ee 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/cpuid.h b/clang/lib/Headers/cpuid.h index 0bb9912b465ffef7d1ce9cd8cb2d0a525ada6fc0..bb7692efb78ffe1902d5c7ec2b9f473143bc4385 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/Lex/Pragma.cpp b/clang/lib/Lex/Pragma.cpp index 499813f8ab7df0e6f81f8b84e2d8ea5b6cd5399b..10f0ab7180e62d09d41debe9e8fb7bb96982f280 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 05ad5ecbfaa0cff6e311750f7499d848e9c17b6e..7431c256d2c1357653a7d27c06af8f2debe65af6 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; @@ -7038,18 +7066,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)) { @@ -7074,13 +7107,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)) @@ -7095,6 +7142,8 @@ void Parser::ParseDecompositionDeclarator(Declarator &D) { T.consumeClose(); } + PA.Commit(); + return D.setDecompositionBindings(T.getOpenLocation(), Bindings, T.getCloseLocation()); } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 32d96f81c4c8de09b0723a7d94ef72d149a9cbb3..7d6febb04a82c430588cf3b7c64e504ad05c3b3d 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" @@ -2070,15 +2071,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 8a18fca8064ee119ae2d429844eb41021b93cc72..29326f5d993a9d56b861a61bfbaa437518b62295 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -327,7 +327,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; @@ -945,7 +945,7 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( // 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: diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index b79683bb32a69ec559c401fb3329c648cfdea686..5f63c857c430670938a971f1502a010fc3192b9f 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); } } diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp index ce6211c23218bbd2024bad7aa5dcb690e005ebeb..8af36d5c24e3d232ad0a067c84ff56b93340c341 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 6a5f9f6680e640972990384cfe01661d4a5eb959..79e656eb4b7e27d47869e3ef192fc644f4612cd4 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 4c445f28bba8c62debc5ba52dfc1b0897c4f7459..c5998aca0d721149f0efe0b3748c142c6b03dcdf 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/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 67132701b41cfd77574d6bac44c0dedf15f9d7c5..cf8840c63024d4c449649e3a64c57e6d56d21f2a 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -3164,13 +3164,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; } @@ -3186,12 +3193,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; } @@ -12544,6 +12559,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; @@ -18724,8 +18750,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 378615497b13cfd25404bf7e80066bcbb5e97b0b..671752b56e01f472238ba06b52ad44d2f927d88d 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1974,7 +1974,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); } @@ -13502,16 +13502,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; } @@ -13523,6 +13525,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 abdbc9d8830c03f6c70121e73f9f2427450cc577..338b0ec1e099c0ac6ffdd12ff4188d30f2db9a30 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -910,6 +910,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) @@ -12052,11 +12054,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; diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 00384f9dc16aa04bf43ff94243bda82f8aefb4fd..c9dd6bb2413e38b204ed473ee9a9f88e610d5484 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1314,7 +1314,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 5c861467bc1023dc85dba17e56d5fdafc2fa6fc3..50f92c496a539a7c1ec459d54831cd6ecbe7f014 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5069,11 +5069,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)) { @@ -6361,7 +6368,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; @@ -21343,8 +21350,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/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 793e16df17891459d79a4cfd208d55f24558eb76..7d9eaf6720461d2e4f9c746a7f09485c8e48b965 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -7753,9 +7753,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; } @@ -8340,8 +8340,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; } @@ -10790,8 +10799,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/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index ba69e71e30a181f855f3015c870a201675b37768..d5cfe82a5d70980dd93cadc8a3678cb50528d64a 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -423,6 +423,21 @@ ExprResult SemaOpenACC::ActOnIntExpr(OpenACCDirectiveKind DK, return IntExpr; } +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 5ba09926acf2b9e92c9eb3bcfc29b004d1fdebd3..cee8da495c549566de34ccff6973ccb6b7f2c5e4 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -2230,7 +2230,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; @@ -3884,7 +3884,7 @@ public: MappableComponent &MC) { return MC.getAssociatedDeclaration() == nullptr && - (isa( + (isa( MC.getAssociatedExpression()) || isa( MC.getAssociatedExpression()) || @@ -4062,7 +4062,7 @@ public: // Do both expressions have the same kind? if (CCI->getAssociatedExpression()->getStmtClass() != SC.getAssociatedExpression()->getStmtClass()) - if (!((isa( + if (!((isa( SC.getAssociatedExpression()) || isa( SC.getAssociatedExpression())) && @@ -5428,9 +5428,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(); @@ -6060,10 +6060,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(); @@ -19513,7 +19513,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) { @@ -19540,7 +19540,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 @@ -19745,12 +19745,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 @@ -21284,10 +21284,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()) @@ -21346,7 +21346,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) @@ -21447,7 +21447,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 @@ -21505,7 +21505,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. @@ -21720,14 +21720,14 @@ public: 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 @@ -21900,7 +21900,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()) @@ -21970,10 +21970,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) @@ -22001,11 +22001,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(); @@ -22480,13 +22479,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 @@ -23955,7 +23954,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(); @@ -24105,7 +24104,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(); @@ -24519,7 +24518,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(); @@ -24632,7 +24631,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(); @@ -24672,13 +24671,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(); @@ -24801,14 +24800,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 9d44c22c8ddcc3a234c46af72b16d19e96829d4f..1c84830b6ddd2e6de81be299fb907a8a5eb78c1e 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -109,16 +109,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/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 98d5c7cb3a8a808d203ccd97e07614c5bad7e60d..3a9fd906b7af86ad4d501d0d2f0045739179a5f3 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -2151,13 +2151,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/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 9404be5a46f3f73d503fe298e94ca7a0aaae384b..f47bc219e6fa32b2368c7b0338c96779f17ec98b 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -2784,15 +2784,23 @@ public: /// /// 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. @@ -11742,7 +11750,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(); @@ -11762,20 +11770,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 @@ -14186,6 +14199,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 f8d54c0c3989064e43b250f4eb7208d197eba168..e017f5bdb48858b6b936145395b3bf858f124a71 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -261,8 +261,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 43b69045bb05436ff9e086f8992a8189eb91fae1..0ef57a3ea804efcaa9e513e273e8a6b4fab2b4af 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -5101,8 +5101,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 +6011,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; } @@ -7384,11 +7385,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; @@ -7517,9 +7518,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) { @@ -7668,8 +7667,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; @@ -7768,7 +7766,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. @@ -7805,28 +7803,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, @@ -7872,7 +7870,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. @@ -7954,7 +7952,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; @@ -7967,13 +7965,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))); } @@ -7994,6 +7991,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) diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index bb82173dfe0b3ac6a0320d2b8aef8f1848b52307..744f11de88c2f89cfca2e9999e71582082145ad2 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 baded0fe19831ff62d6b8d5739093fcad8407b20..7d3930022a69c02997ddfd92be91bcc29e7e5ecf 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -956,14 +956,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()); } @@ -3090,8 +3098,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 30195868ca9965b7f4f9d5f20f9ca19caf1b416c..7db60c67d712340f9e6f44c7873cb055241c64e2 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -3043,7 +3043,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); @@ -3205,6 +3205,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. /// @@ -3225,8 +3236,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; @@ -3261,7 +3281,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)); } } @@ -3282,7 +3302,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(); @@ -3420,11 +3440,11 @@ public: 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"); } @@ -3743,8 +3763,8 @@ public: // 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))); } } }; @@ -3860,7 +3880,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; @@ -3886,6 +3906,13 @@ public: !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()); @@ -3893,8 +3920,10 @@ public: 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()); } @@ -3983,7 +4012,7 @@ public: 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"); } }; @@ -4255,6 +4284,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); } } @@ -4317,7 +4352,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); } @@ -4371,7 +4407,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); } @@ -4914,8 +4950,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; } @@ -5089,7 +5124,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()); @@ -5100,10 +5135,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); @@ -5473,7 +5508,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); } @@ -5507,7 +5542,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(); @@ -5568,7 +5603,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: @@ -5709,7 +5744,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) { } } - OffsetsRecord.push_back(GetDeclRef(D)); + AddDeclRef(D, OffsetsRecord); OffsetsRecord.push_back(Record.Emit(DECL_UPDATES)); } } @@ -5974,18 +6009,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. @@ -5999,14 +6034,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 @@ -6018,14 +6053,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]; @@ -6046,8 +6081,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(); @@ -6079,7 +6114,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); } @@ -6349,7 +6384,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. @@ -6453,7 +6488,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(); diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index c6db107e0ca42961e2fd646b2e4128d1b4bbcde4..0edc4feda3ef2337b14dafb2bcf441df66c1d12a 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 cd5f733baf76f4e5d6cfb3004d2fd375fa2281b6..39aec31b6d87900d95e8afa5aa7e4e993b0799f6 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -880,16 +880,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 bed74399098d7f93ae4d1d43ab78ecb810fbf835..7b97b73f7bbd00e77f1780bc4f37b36efe603cc0 100644 --- a/clang/lib/Serialization/GeneratePCH.cpp +++ b/clang/lib/Serialization/GeneratePCH.cpp @@ -88,31 +88,28 @@ ASTDeserializationListener *PCHGenerator::GetASTDeserializationListener() { return &Writer; } -ReducedBMIGenerator::ReducedBMIGenerator(Preprocessor &PP, - InMemoryModuleCache &ModuleCache, - StringRef OutputFile) +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; diff --git a/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/DereferenceChecker.cpp index a678c3827e7f12b37b49733014c20b9cea36b6c5..1cebfbbee77dae25dd4a6022a2773b387516ad79 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 1cf81b54e77d32ddb32aecfe7d216fe30084b934..7ac34ef8164e4c20eee1e1427edba4252b9bc9f5 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/WebKit/PtrTypesSemantics.h b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h index 9ed8e7cab6abb9ed1484829899d926e7bb134239..ec1db1cc3358073d4d4d2dc6c14a97bb96edd600 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 8b41a949fd67345e6923b263bea6a20ef190c3ca..ae494de58da3da16b7babae11a25db9d938ecc5b 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/UncountedCallArgsChecker.cpp @@ -53,6 +53,13 @@ public: 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 09c69f9612d96b8ed81baca77adce23b741e5c79..0b1edf3e5c96bf531883ea4553c7330d138d74f9 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1948,7 +1948,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 32850f5eea92a945b99a164b9bc0b7209d841071..0c047b6c5da2f8007a7e4d17c8d8d06d8da549a0 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -439,6 +439,9 @@ public: 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 5dbb83cab86bd7968b3e9248ef9f8bcdf8762130..b0eead42869a4124508364c4c793806a70582da9 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 82b8a6749c4fe2a8a714db5b2622cc8ab61f2b69..a8f6d0248eae4055e5e3e49e00e371aa0d9e3aeb 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 904857e5859303f9f498c98c6e7717bff9c4a2c7..103cf02f431afbd93a25f2e9c22122f058c64a0b 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/Interp/c.c b/clang/test/AST/Interp/c.c index a5951158ed0e0d808303711ae1e69475fd006015..207da5fe812608497cc67088ac208597f92929bb 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 f0325eef6d87cfbb7763b64574d76bea1da7f868..13cc9f43febc741706c6cb08740b043846b68db7 100644 --- a/clang/test/AST/Interp/cxx23.cpp +++ b/clang/test/AST/Interp/cxx23.cpp @@ -141,3 +141,19 @@ 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; + } +} diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp index f9bb5d53634e0ba0cbcfe20d47a3f8ee0e33525b..a5bb9f1a19aaa7fe169cdfef09ee8506caa42a14 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 0000000000000000000000000000000000000000..b9ba4f8b9b555a268f0277c92ac2ad66ee1d779f --- /dev/null +++ b/clang/test/AST/Interp/opencl.cl @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -fsyntax-only -verify=ref,both %s +// RUN: %clang_cc1 -fsyntax-only -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]; +} + diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index 3e52354a4a1067a84d549563f529138c4ff13640..771e5adfca34a45fcc60aeffbd9807176b6639b7 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 96f4be6fec3ddfe63d677b2fc11c2d991f89de7e..fb9b4118b4f1787eb8817c8e65084beef8f26159 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 0000000000000000000000000000000000000000..f9c254b803ff2b277ba11579e34659a99587c21d --- /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 cfb013585ad7443a52d53475e8661810d6ae670b..77527743fe85772c1e3d155c2ca075135926acd0 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 cf740516db6f4b4e7d5b8459b7c8327835bc4d4c..5ac55d269dce48507b9805e8e1345fedc8b5c6d1 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 d25ef36dd4d32c001d54d071484cdfea2ec95181..9fcafbcbcc46b69f0acce5affb17513d164d7735 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/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 0000000000000000000000000000000000000000..3d8e822025f62b2074d74409eb917e4779757926 --- /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