diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 76b8266cae87c4b0b3fbf90e4bf72626aad7c9f3..c4727a0c267d3ecb5a3a5495945ce417d5adc38a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -115,6 +115,10 @@ clang/test/AST/Interp/ @tbaederr /mlir/**/LLVMIR/**/BasicPtxBuilderInterface* @grypp /mlir/**/NVVM*/ @grypp +# MLIR Python Bindings +/mlir/test/python/ @makslevental @stellaraccident +/mlir/python/ @makslevental @stellaraccident + # BOLT /bolt/ @aaupov @maksfb @rafaelauler @ayermolo @dcci diff --git a/.github/workflows/pr-code-format.yml b/.github/workflows/pr-code-format.yml index 10b18f245d8965a69251038f44f1505fc40c0cf0..983838858ba43ed90cca953b6b00668d6746f5df 100644 --- a/.github/workflows/pr-code-format.yml +++ b/.github/workflows/pr-code-format.yml @@ -1,4 +1,8 @@ name: "Check code formatting" + +permissions: + contents: read + on: pull_request: branches: diff --git a/.github/workflows/release-lit.yml b/.github/workflows/release-lit.yml index 36b0b6edd518fc74fecf397c8947ff706066a52e..0316ba406041d6fc63c812da994ea662276bee6e 100644 --- a/.github/workflows/release-lit.yml +++ b/.github/workflows/release-lit.yml @@ -58,7 +58,7 @@ jobs: cd llvm/utils/lit # Remove 'dev' suffix from lit version. sed -i 's/ + "dev"//g' lit/__init__.py - python3 setup.py sdist + python3 setup.py sdist bdist_wheel - name: Upload lit to test.pypi.org uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/bolt/include/bolt/Core/BinaryFunction.h b/bolt/include/bolt/Core/BinaryFunction.h index bc047fefa3151c9d32050e71ed3d182005665923..26d2d01f86267127f4c4bea9daa5862b4b412738 100644 --- a/bolt/include/bolt/Core/BinaryFunction.h +++ b/bolt/include/bolt/Core/BinaryFunction.h @@ -1402,7 +1402,8 @@ public: /// Return true if the function has CFI instructions bool hasCFI() const { - return !FrameInstructions.empty() || !CIEFrameInstructions.empty(); + return !FrameInstructions.empty() || !CIEFrameInstructions.empty() || + IsInjected; } /// Return unique number associated with the function. diff --git a/bolt/include/bolt/Profile/BoltAddressTranslation.h b/bolt/include/bolt/Profile/BoltAddressTranslation.h index 6a0a477f27583fecf56e57c6ee8f43a32de7ba81..eef05e8a0e681406cd1a48784ece7edf5f85ff4a 100644 --- a/bolt/include/bolt/Profile/BoltAddressTranslation.h +++ b/bolt/include/bolt/Profile/BoltAddressTranslation.h @@ -119,11 +119,6 @@ public: /// True if a given \p Address is a function with translation table entry. bool isBATFunction(uint64_t Address) const { return Maps.count(Address); } - /// Returns branch offsets grouped by containing basic block in a given - /// function. - std::unordered_map> - getBFBranches(uint64_t FuncOutputAddress) const; - /// For a given \p Symbol in the output binary and known \p InputOffset /// return a corresponding pair of parent BinaryFunction and secondary entry /// point in it. @@ -193,7 +188,7 @@ public: EntryTy(unsigned Index, size_t Hash) : Index(Index), Hash(Hash) {} }; - std::unordered_map Map; + std::map Map; const EntryTy &getEntry(uint32_t BBInputOffset) const { auto It = Map.find(BBInputOffset); assert(It != Map.end()); @@ -218,6 +213,10 @@ public: } size_t getNumBasicBlocks() const { return Map.size(); } + + auto begin() const { return Map.begin(); } + auto end() const { return Map.end(); } + auto upper_bound(uint32_t Offset) const { return Map.upper_bound(Offset); } }; /// Map function output address to its hash and basic blocks hash map. diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h index 4fbe524b1c385d24d10cd3a0ea33ca53580f0fc9..84f76caae9dbb01ea38e59f5eb629e0492ddb800 100644 --- a/bolt/include/bolt/Profile/DataAggregator.h +++ b/bolt/include/bolt/Profile/DataAggregator.h @@ -225,6 +225,10 @@ private: /// Aggregation statistics uint64_t NumInvalidTraces{0}; uint64_t NumLongRangeTraces{0}; + /// Specifies how many samples were recorded in cold areas if we are dealing + /// with profiling data collected in a bolted binary. For LBRs, incremented + /// for the source of the branch to avoid counting cold activity twice (one + /// for source and another for destination). uint64_t NumColdSamples{0}; /// Looks into system PATH for Linux Perf and set up the aggregator to use it @@ -245,14 +249,12 @@ private: /// disassembled BinaryFunctions BinaryFunction *getBinaryFunctionContainingAddress(uint64_t Address) const; + /// Perform BAT translation for a given \p Func and return the parent + /// BinaryFunction or nullptr. + BinaryFunction *getBATParentFunction(const BinaryFunction &Func) const; + /// Retrieve the location name to be used for samples recorded in \p Func. - /// If doing BAT translation, link cold parts to the hot part names (used by - /// the original binary). \p Count specifies how many samples were recorded - /// at that location, so we can tally total activity in cold areas if we are - /// dealing with profiling data collected in a bolted binary. For LBRs, - /// \p Count should only be used for the source of the branch to avoid - /// counting cold activity twice (one for source and another for destination). - StringRef getLocationName(BinaryFunction &Func, uint64_t Count); + StringRef getLocationName(const BinaryFunction &Func) const; /// Semantic actions - parser hooks to interpret parsed perf samples /// Register a sample (non-LBR mode), i.e. a new hit at \p Address @@ -467,9 +469,6 @@ private: std::error_code writeBATYAML(BinaryContext &BC, StringRef OutputFilename) const; - /// Fixup profile collected on BOLTed binary, namely handle split functions. - void fixupBATProfile(BinaryContext &BC); - /// Filter out binaries based on PID void filterBinaryMMapInfo(); diff --git a/bolt/lib/Core/BinaryEmitter.cpp b/bolt/lib/Core/BinaryEmitter.cpp index 591ea5829dd9aeff4594ce39a41226de85d2dc83..97d19b75200f51d0a4f6ea928e75cb2e8c70d222 100644 --- a/bolt/lib/Core/BinaryEmitter.cpp +++ b/bolt/lib/Core/BinaryEmitter.cpp @@ -485,7 +485,6 @@ void BinaryEmitter::emitFunctionBody(BinaryFunction &BF, FunctionFragment &FF, // This assumes the second instruction in the macro-op pair will get // assigned to its own MCRelaxableFragment. Since all JCC instructions // are relaxable, we should be safe. - Streamer.emitNeverAlignCodeAtEnd(/*Alignment to avoid=*/64, *BC.STI); } if (!EmitCodeOnly) { diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp index cbf95a7db08b52bc95856a90fd5266560fef7c2a..d16b7a94787c65d1e9b25324f3b1961b6b109102 100644 --- a/bolt/lib/Core/Relocation.cpp +++ b/bolt/lib/Core/Relocation.cpp @@ -774,60 +774,95 @@ static bool isPCRelativeRISCV(uint64_t Type) { } bool Relocation::isSupported(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + return false; + case Triple::aarch64: return isSupportedAArch64(Type); - if (Arch == Triple::riscv64) + case Triple::riscv64: return isSupportedRISCV(Type); - return isSupportedX86(Type); + case Triple::x86_64: + return isSupportedX86(Type); + } } size_t Relocation::getSizeForType(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return getSizeForTypeAArch64(Type); - if (Arch == Triple::riscv64) + case Triple::riscv64: return getSizeForTypeRISCV(Type); - return getSizeForTypeX86(Type); + case Triple::x86_64: + return getSizeForTypeX86(Type); + } } bool Relocation::skipRelocationType(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return skipRelocationTypeAArch64(Type); - if (Arch == Triple::riscv64) + case Triple::riscv64: return skipRelocationTypeRISCV(Type); - return skipRelocationTypeX86(Type); + case Triple::x86_64: + return skipRelocationTypeX86(Type); + } } bool Relocation::skipRelocationProcess(uint64_t &Type, uint64_t Contents) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return skipRelocationProcessAArch64(Type, Contents); - if (Arch == Triple::riscv64) - skipRelocationProcessRISCV(Type, Contents); - return skipRelocationProcessX86(Type, Contents); + case Triple::riscv64: + return skipRelocationProcessRISCV(Type, Contents); + case Triple::x86_64: + return skipRelocationProcessX86(Type, Contents); + } } uint64_t Relocation::encodeValue(uint64_t Type, uint64_t Value, uint64_t PC) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return encodeValueAArch64(Type, Value, PC); - if (Arch == Triple::riscv64) + case Triple::riscv64: return encodeValueRISCV(Type, Value, PC); - return encodeValueX86(Type, Value, PC); + case Triple::x86_64: + return encodeValueX86(Type, Value, PC); + } } uint64_t Relocation::extractValue(uint64_t Type, uint64_t Contents, uint64_t PC) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return extractValueAArch64(Type, Contents, PC); - if (Arch == Triple::riscv64) + case Triple::riscv64: return extractValueRISCV(Type, Contents, PC); - return extractValueX86(Type, Contents, PC); + case Triple::x86_64: + return extractValueX86(Type, Contents, PC); + } } bool Relocation::isGOT(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return isGOTAArch64(Type); - if (Arch == Triple::riscv64) + case Triple::riscv64: return isGOTRISCV(Type); - return isGOTX86(Type); + case Triple::x86_64: + return isGOTX86(Type); + } } bool Relocation::isX86GOTPCRELX(uint64_t Type) { @@ -845,27 +880,42 @@ bool Relocation::isX86GOTPC64(uint64_t Type) { bool Relocation::isNone(uint64_t Type) { return Type == getNone(); } bool Relocation::isRelative(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return Type == ELF::R_AARCH64_RELATIVE; - if (Arch == Triple::riscv64) + case Triple::riscv64: return Type == ELF::R_RISCV_RELATIVE; - return Type == ELF::R_X86_64_RELATIVE; + case Triple::x86_64: + return Type == ELF::R_X86_64_RELATIVE; + } } bool Relocation::isIRelative(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return Type == ELF::R_AARCH64_IRELATIVE; - if (Arch == Triple::riscv64) + case Triple::riscv64: llvm_unreachable("not implemented"); - return Type == ELF::R_X86_64_IRELATIVE; + case Triple::x86_64: + return Type == ELF::R_X86_64_IRELATIVE; + } } bool Relocation::isTLS(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return isTLSAArch64(Type); - if (Arch == Triple::riscv64) + case Triple::riscv64: return isTLSRISCV(Type); - return isTLSX86(Type); + case Triple::x86_64: + return isTLSX86(Type); + } } bool Relocation::isInstructionReference(uint64_t Type) { @@ -882,49 +932,81 @@ bool Relocation::isInstructionReference(uint64_t Type) { } uint64_t Relocation::getNone() { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return ELF::R_AARCH64_NONE; - if (Arch == Triple::riscv64) + case Triple::riscv64: return ELF::R_RISCV_NONE; - return ELF::R_X86_64_NONE; + case Triple::x86_64: + return ELF::R_X86_64_NONE; + } } uint64_t Relocation::getPC32() { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return ELF::R_AARCH64_PREL32; - if (Arch == Triple::riscv64) + case Triple::riscv64: return ELF::R_RISCV_32_PCREL; - return ELF::R_X86_64_PC32; + case Triple::x86_64: + return ELF::R_X86_64_PC32; + } } uint64_t Relocation::getPC64() { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return ELF::R_AARCH64_PREL64; - if (Arch == Triple::riscv64) + case Triple::riscv64: llvm_unreachable("not implemented"); - return ELF::R_X86_64_PC64; + case Triple::x86_64: + return ELF::R_X86_64_PC64; + } } bool Relocation::isPCRelative(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return isPCRelativeAArch64(Type); - if (Arch == Triple::riscv64) + case Triple::riscv64: return isPCRelativeRISCV(Type); - return isPCRelativeX86(Type); + case Triple::x86_64: + return isPCRelativeX86(Type); + } } uint64_t Relocation::getAbs64() { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return ELF::R_AARCH64_ABS64; - if (Arch == Triple::riscv64) + case Triple::riscv64: return ELF::R_RISCV_64; - return ELF::R_X86_64_64; + case Triple::x86_64: + return ELF::R_X86_64_64; + } } uint64_t Relocation::getRelative() { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return ELF::R_AARCH64_RELATIVE; - return ELF::R_X86_64_RELATIVE; + case Triple::riscv64: + llvm_unreachable("not implemented"); + case Triple::x86_64: + return ELF::R_X86_64_RELATIVE; + } } size_t Relocation::emit(MCStreamer *Streamer) const { @@ -991,9 +1073,16 @@ void Relocation::print(raw_ostream &OS) const { static const char *AArch64RelocNames[] = { #include "llvm/BinaryFormat/ELFRelocs/AArch64.def" }; - if (Arch == Triple::aarch64) + switch (Arch) { + default: + OS << "RType:" << Twine::utohexstr(Type); + break; + + case Triple::aarch64: OS << AArch64RelocNames[Type]; - else if (Arch == Triple::riscv64) { + break; + + case Triple::riscv64: // RISC-V relocations are not sequentially numbered so we cannot use an // array switch (Type) { @@ -1006,8 +1095,12 @@ void Relocation::print(raw_ostream &OS) const { break; #include "llvm/BinaryFormat/ELFRelocs/RISCV.def" } - } else + break; + + case Triple::x86_64: OS << X86RelocNames[Type]; + break; + } OS << ", 0x" << Twine::utohexstr(Offset); if (Symbol) { OS << ", " << Symbol->getName(); diff --git a/bolt/lib/Profile/BoltAddressTranslation.cpp b/bolt/lib/Profile/BoltAddressTranslation.cpp index 2b6e9208d8776e48ef485ac9a50ea02989f0bd0e..0141ce189acda584e98cf73168a70c32e661cd43 100644 --- a/bolt/lib/Profile/BoltAddressTranslation.cpp +++ b/bolt/lib/Profile/BoltAddressTranslation.cpp @@ -100,7 +100,7 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) { LLVM_DEBUG(dbgs() << "Function name: " << Function.getPrintName() << "\n"); LLVM_DEBUG(dbgs() << " Address reference: 0x" << Twine::utohexstr(Function.getOutputAddress()) << "\n"); - LLVM_DEBUG(dbgs() << formatv(" Hash: {0:x}\n", getBFHash(OutputAddress))); + LLVM_DEBUG(dbgs() << formatv(" Hash: {0:x}\n", getBFHash(InputAddress))); LLVM_DEBUG(dbgs() << " Secondary Entry Points: " << NumSecondaryEntryPoints << '\n'); @@ -197,8 +197,9 @@ void BoltAddressTranslation::writeMaps(std::map &Maps, ? SecondaryEntryPointsMap[Address].size() : 0; if (Cold) { - size_t HotIndex = - std::distance(ColdPartSource.begin(), ColdPartSource.find(Address)); + auto HotEntryIt = Maps.find(ColdPartSource[Address]); + assert(HotEntryIt != Maps.end()); + size_t HotIndex = std::distance(Maps.begin(), HotEntryIt); encodeULEB128(HotIndex - PrevIndex, OS); PrevIndex = HotIndex; } else { @@ -425,7 +426,7 @@ void BoltAddressTranslation::dump(raw_ostream &OS) { for (const auto &MapEntry : Maps) { const uint64_t Address = MapEntry.first; const uint64_t HotAddress = fetchParentAddress(Address); - bool IsHotFunction = HotAddress == 0; + const bool IsHotFunction = HotAddress == 0; OS << "Function Address: 0x" << Twine::utohexstr(Address); if (IsHotFunction) OS << formatv(", hash: {0:x}", getBFHash(Address)); @@ -581,26 +582,6 @@ void BoltAddressTranslation::saveMetadata(BinaryContext &BC) { } } -std::unordered_map> -BoltAddressTranslation::getBFBranches(uint64_t OutputAddress) const { - std::unordered_map> Branches; - auto FuncIt = Maps.find(OutputAddress); - assert(FuncIt != Maps.end()); - std::vector InputOffsets; - for (const auto &KV : FuncIt->second) - InputOffsets.emplace_back(KV.second); - // Sort with LSB BRANCHENTRY bit. - llvm::sort(InputOffsets); - uint32_t BBOffset{0}; - for (uint32_t InOffset : InputOffsets) { - if (InOffset & BRANCHENTRY) - Branches[BBOffset].push_back(InOffset >> 1); - else - BBOffset = InOffset >> 1; - } - return Branches; -} - unsigned BoltAddressTranslation::getSecondaryEntryPointId(uint64_t Address, uint32_t Offset) const { diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp index 71824e2cc0e97a5d15589487e9728d32d97edc19..0b2a4e86561f3aaa56a7385bf4fd8e5439f2d56a 100644 --- a/bolt/lib/Profile/DataAggregator.cpp +++ b/bolt/lib/Profile/DataAggregator.cpp @@ -604,8 +604,6 @@ Error DataAggregator::readProfile(BinaryContext &BC) { // BAT YAML is handled by DataAggregator since normal YAML output requires // CFG which is not available in BAT mode. if (usesBAT()) { - // Postprocess split function profile for BAT - fixupBATProfile(BC); if (opts::ProfileFormat == opts::ProfileFormatKind::PF_YAML) if (std::error_code EC = writeBATYAML(BC, opts::OutputFilename)) report_error("cannot create output data file", EC); @@ -664,18 +662,19 @@ DataAggregator::getBinaryFunctionContainingAddress(uint64_t Address) const { /*UseMaxSize=*/true); } -StringRef DataAggregator::getLocationName(BinaryFunction &Func, - uint64_t Count) { +BinaryFunction * +DataAggregator::getBATParentFunction(const BinaryFunction &Func) const { + if (BAT) + if (const uint64_t HotAddr = BAT->fetchParentAddress(Func.getAddress())) + return getBinaryFunctionContainingAddress(HotAddr); + return nullptr; +} + +StringRef DataAggregator::getLocationName(const BinaryFunction &Func) const { if (!BAT) return Func.getOneName(); const BinaryFunction *OrigFunc = &Func; - if (const uint64_t HotAddr = BAT->fetchParentAddress(Func.getAddress())) { - NumColdSamples += Count; - BinaryFunction *HotFunc = getBinaryFunctionContainingAddress(HotAddr); - if (HotFunc) - OrigFunc = HotFunc; - } // If it is a local function, prefer the name containing the file name where // the local function was declared for (StringRef AlternativeName : OrigFunc->getNames()) { @@ -690,12 +689,17 @@ StringRef DataAggregator::getLocationName(BinaryFunction &Func, return OrigFunc->getOneName(); } -bool DataAggregator::doSample(BinaryFunction &Func, uint64_t Address, +bool DataAggregator::doSample(BinaryFunction &OrigFunc, uint64_t Address, uint64_t Count) { + BinaryFunction *ParentFunc = getBATParentFunction(OrigFunc); + BinaryFunction &Func = ParentFunc ? *ParentFunc : OrigFunc; + if (ParentFunc) + NumColdSamples += Count; + auto I = NamesToSamples.find(Func.getOneName()); if (I == NamesToSamples.end()) { bool Success; - StringRef LocName = getLocationName(Func, Count); + StringRef LocName = getLocationName(Func); std::tie(I, Success) = NamesToSamples.insert( std::make_pair(Func.getOneName(), FuncSampleData(LocName, FuncSampleData::ContainerTy()))); @@ -715,22 +719,12 @@ bool DataAggregator::doIntraBranch(BinaryFunction &Func, uint64_t From, FuncBranchData *AggrData = getBranchData(Func); if (!AggrData) { AggrData = &NamesToBranches[Func.getOneName()]; - AggrData->Name = getLocationName(Func, Count); + AggrData->Name = getLocationName(Func); setBranchData(Func, AggrData); } - From -= Func.getAddress(); - To -= Func.getAddress(); LLVM_DEBUG(dbgs() << "BOLT-DEBUG: bumpBranchCount: " << formatv("{0} @ {1:x} -> {0} @ {2:x}\n", Func, From, To)); - if (BAT) { - From = BAT->translate(Func.getAddress(), From, /*IsBranchSrc=*/true); - To = BAT->translate(Func.getAddress(), To, /*IsBranchSrc=*/false); - LLVM_DEBUG( - dbgs() << "BOLT-DEBUG: BAT translation on bumpBranchCount: " - << formatv("{0} @ {1:x} -> {0} @ {2:x}\n", Func, From, To)); - } - AggrData->bumpBranchCount(From, To, Count, Mispreds); return true; } @@ -744,30 +738,24 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc, StringRef SrcFunc; StringRef DstFunc; if (FromFunc) { - SrcFunc = getLocationName(*FromFunc, Count); + SrcFunc = getLocationName(*FromFunc); FromAggrData = getBranchData(*FromFunc); if (!FromAggrData) { FromAggrData = &NamesToBranches[FromFunc->getOneName()]; FromAggrData->Name = SrcFunc; setBranchData(*FromFunc, FromAggrData); } - From -= FromFunc->getAddress(); - if (BAT) - From = BAT->translate(FromFunc->getAddress(), From, /*IsBranchSrc=*/true); recordExit(*FromFunc, From, Mispreds, Count); } if (ToFunc) { - DstFunc = getLocationName(*ToFunc, 0); + DstFunc = getLocationName(*ToFunc); ToAggrData = getBranchData(*ToFunc); if (!ToAggrData) { ToAggrData = &NamesToBranches[ToFunc->getOneName()]; ToAggrData->Name = DstFunc; setBranchData(*ToFunc, ToAggrData); } - To -= ToFunc->getAddress(); - if (BAT) - To = BAT->translate(ToFunc->getAddress(), To, /*IsBranchSrc=*/false); recordEntry(*ToFunc, To, Mispreds, Count); } @@ -783,15 +771,32 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc, bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count, uint64_t Mispreds) { - BinaryFunction *FromFunc = getBinaryFunctionContainingAddress(From); - BinaryFunction *ToFunc = getBinaryFunctionContainingAddress(To); + auto handleAddress = [&](uint64_t &Addr, bool IsFrom) -> BinaryFunction * { + if (BinaryFunction *Func = getBinaryFunctionContainingAddress(Addr)) { + Addr -= Func->getAddress(); + + if (BAT) + Addr = BAT->translate(Func->getAddress(), Addr, IsFrom); + + if (BinaryFunction *ParentFunc = getBATParentFunction(*Func)) { + Func = ParentFunc; + if (IsFrom) + NumColdSamples += Count; + } + + return Func; + } + return nullptr; + }; + + BinaryFunction *FromFunc = handleAddress(From, /*IsFrom=*/true); + BinaryFunction *ToFunc = handleAddress(To, /*IsFrom=*/false); if (!FromFunc && !ToFunc) return false; // Treat recursive control transfers as inter-branches. - if (FromFunc == ToFunc && (To != ToFunc->getAddress())) { - recordBranch(*FromFunc, From - FromFunc->getAddress(), - To - FromFunc->getAddress(), Count, Mispreds); + if (FromFunc == ToFunc && To != 0) { + recordBranch(*FromFunc, From, To, Count, Mispreds); return doIntraBranch(*FromFunc, From, To, Count, Mispreds); } @@ -842,9 +847,14 @@ bool DataAggregator::doTrace(const LBREntry &First, const LBREntry &Second, << FromFunc->getPrintName() << ":" << Twine::utohexstr(First.To) << " to " << Twine::utohexstr(Second.From) << ".\n"); - for (const std::pair &Pair : *FTs) - doIntraBranch(*FromFunc, Pair.first + FromFunc->getAddress(), - Pair.second + FromFunc->getAddress(), Count, false); + BinaryFunction *ParentFunc = getBATParentFunction(*FromFunc); + for (auto [From, To] : *FTs) { + if (BAT) { + From = BAT->translate(FromFunc->getAddress(), From, /*IsBranchSrc=*/true); + To = BAT->translate(FromFunc->getAddress(), To, /*IsBranchSrc=*/false); + } + doIntraBranch(ParentFunc ? *ParentFunc : *FromFunc, From, To, Count, false); + } return true; } @@ -2273,29 +2283,6 @@ DataAggregator::writeAggregatedFile(StringRef OutputFilename) const { return std::error_code(); } -void DataAggregator::fixupBATProfile(BinaryContext &BC) { - for (auto &[FuncName, Branches] : NamesToBranches) { - BinaryData *BD = BC.getBinaryDataByName(FuncName); - assert(BD); - uint64_t FuncAddress = BD->getAddress(); - if (!BAT->isBATFunction(FuncAddress)) - continue; - // Filter out cold fragments - if (!BD->getSectionName().equals(BC.getMainCodeSectionName())) - continue; - // Convert inter-branches between hot and cold fragments into - // intra-branches. - for (auto &[OffsetFrom, CallToMap] : Branches.InterIndex) { - for (auto &[CallToLoc, CallToIdx] : CallToMap) { - if (CallToLoc.Name != FuncName) - continue; - Branches.IntraIndex[OffsetFrom][CallToLoc.Offset] = CallToIdx; - Branches.InterIndex[OffsetFrom].erase(CallToLoc); - } - } - } -} - std::error_code DataAggregator::writeBATYAML(BinaryContext &BC, StringRef OutputFilename) const { std::error_code EC; @@ -2345,9 +2332,6 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC, uint64_t FuncAddress = BD->getAddress(); if (!BAT->isBATFunction(FuncAddress)) continue; - // Filter out cold fragments - if (!BD->getSectionName().equals(BC.getMainCodeSectionName())) - continue; BinaryFunction *BF = BC.getBinaryFunctionAtAddress(FuncAddress); assert(BF); YamlBF.Name = FuncName.str(); @@ -2357,87 +2341,68 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC, YamlBF.NumBasicBlocks = BAT->getNumBasicBlocks(FuncAddress); const BoltAddressTranslation::BBHashMapTy &BlockMap = BAT->getBBHashMap(FuncAddress); + YamlBF.Blocks.resize(YamlBF.NumBasicBlocks); - auto addSuccProfile = [&](yaml::bolt::BinaryBasicBlockProfile &YamlBB, - uint64_t SuccOffset, unsigned SuccDataIdx) { + for (auto &&[Idx, YamlBB] : llvm::enumerate(YamlBF.Blocks)) + YamlBB.Index = Idx; + + for (auto BI = BlockMap.begin(), BE = BlockMap.end(); BI != BE; ++BI) + YamlBF.Blocks[BI->second.getBBIndex()].Hash = BI->second.getBBHash(); + + auto getSuccessorInfo = [&](uint32_t SuccOffset, unsigned SuccDataIdx) { const llvm::bolt::BranchInfo &BI = Branches.Data.at(SuccDataIdx); yaml::bolt::SuccessorInfo SI; SI.Index = BlockMap.getBBIndex(SuccOffset); SI.Count = BI.Branches; SI.Mispreds = BI.Mispreds; - YamlBB.Successors.emplace_back(SI); + return SI; }; - std::unordered_map> BFBranches = - BAT->getBFBranches(FuncAddress); - - auto addCallsProfile = [&](yaml::bolt::BinaryBasicBlockProfile &YamlBB, - uint64_t Offset) { - // Iterate over BRANCHENTRY records in the current block - for (uint32_t BranchOffset : BFBranches[Offset]) { - if (!Branches.InterIndex.contains(BranchOffset)) - continue; - for (const auto &[CallToLoc, CallToIdx] : - Branches.InterIndex.at(BranchOffset)) { - const llvm::bolt::BranchInfo &BI = Branches.Data.at(CallToIdx); - yaml::bolt::CallSiteInfo YamlCSI; - YamlCSI.DestId = 0; // designated for unknown functions - YamlCSI.EntryDiscriminator = 0; - YamlCSI.Count = BI.Branches; - YamlCSI.Mispreds = BI.Mispreds; - YamlCSI.Offset = BranchOffset - Offset; - BinaryData *CallTargetBD = BC.getBinaryDataByName(CallToLoc.Name); - if (!CallTargetBD) { - YamlBB.CallSites.emplace_back(YamlCSI); - continue; - } - uint64_t CallTargetAddress = CallTargetBD->getAddress(); - BinaryFunction *CallTargetBF = - BC.getBinaryFunctionAtAddress(CallTargetAddress); - if (!CallTargetBF) { - YamlBB.CallSites.emplace_back(YamlCSI); - continue; - } - // Calls between hot and cold fragments must be handled in - // fixupBATProfile. - assert(CallTargetBF != BF && "invalid CallTargetBF"); - YamlCSI.DestId = CallTargetBF->getFunctionNumber(); - if (CallToLoc.Offset) { - if (BAT->isBATFunction(CallTargetAddress)) { - LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Unsupported secondary " - "entry point in BAT function " - << CallToLoc.Name << '\n'); - } else if (const BinaryBasicBlock *CallTargetBB = - CallTargetBF->getBasicBlockAtOffset( - CallToLoc.Offset)) { - // Only record true call information, ignoring returns (normally - // won't have a target basic block) and jumps to the landing - // pads (not an entry point). - if (CallTargetBB->isEntryPoint()) { - YamlCSI.EntryDiscriminator = - CallTargetBF->getEntryIDForSymbol( - CallTargetBB->getLabel()); - } - } - } - YamlBB.CallSites.emplace_back(YamlCSI); - } - } + auto getCallSiteInfo = [&](Location CallToLoc, unsigned CallToIdx, + uint32_t Offset) { + const llvm::bolt::BranchInfo &BI = Branches.Data.at(CallToIdx); + yaml::bolt::CallSiteInfo CSI; + CSI.DestId = 0; // designated for unknown functions + CSI.EntryDiscriminator = 0; + CSI.Count = BI.Branches; + CSI.Mispreds = BI.Mispreds; + CSI.Offset = Offset; + if (BinaryData *BD = BC.getBinaryDataByName(CallToLoc.Name)) + YAMLProfileWriter::setCSIDestination(BC, CSI, BD->getSymbol(), BAT, + CallToLoc.Offset); + return CSI; }; for (const auto &[FromOffset, SuccKV] : Branches.IntraIndex) { - yaml::bolt::BinaryBasicBlockProfile YamlBB; if (!BlockMap.isInputBlock(FromOffset)) continue; - YamlBB.Index = BlockMap.getBBIndex(FromOffset); - YamlBB.Hash = BlockMap.getBBHash(FromOffset); + const unsigned Index = BlockMap.getBBIndex(FromOffset); + yaml::bolt::BinaryBasicBlockProfile &YamlBB = YamlBF.Blocks[Index]; for (const auto &[SuccOffset, SuccDataIdx] : SuccKV) - addSuccProfile(YamlBB, SuccOffset, SuccDataIdx); - addCallsProfile(YamlBB, FromOffset); - if (YamlBB.ExecCount || !YamlBB.Successors.empty() || - !YamlBB.CallSites.empty()) - YamlBF.Blocks.emplace_back(YamlBB); + if (BlockMap.isInputBlock(SuccOffset)) + YamlBB.Successors.emplace_back( + getSuccessorInfo(SuccOffset, SuccDataIdx)); + } + for (const auto &[FromOffset, CallTo] : Branches.InterIndex) { + auto BlockIt = BlockMap.upper_bound(FromOffset); + --BlockIt; + const unsigned BlockOffset = BlockIt->first; + const unsigned BlockIndex = BlockIt->second.getBBIndex(); + yaml::bolt::BinaryBasicBlockProfile &YamlBB = YamlBF.Blocks[BlockIndex]; + const uint32_t Offset = FromOffset - BlockOffset; + for (const auto &[CallToLoc, CallToIdx] : CallTo) + YamlBB.CallSites.emplace_back( + getCallSiteInfo(CallToLoc, CallToIdx, Offset)); + llvm::sort(YamlBB.CallSites, [](yaml::bolt::CallSiteInfo &A, + yaml::bolt::CallSiteInfo &B) { + return A.Offset < B.Offset; + }); } + // Drop blocks without a hash, won't be useful for stale matching. + llvm::erase_if(YamlBF.Blocks, + [](const yaml::bolt::BinaryBasicBlockProfile &YamlBB) { + return YamlBB.Hash == (yaml::Hex64)0; + }); BP.Functions.emplace_back(YamlBF); } } diff --git a/bolt/lib/Rewrite/BinaryPassManager.cpp b/bolt/lib/Rewrite/BinaryPassManager.cpp index 6c26bb7957269d71c06da0d33bfe80984b0f4e16..be4888ccfa56457fe2f59dcee91abdd05b947021 100644 --- a/bolt/lib/Rewrite/BinaryPassManager.cpp +++ b/bolt/lib/Rewrite/BinaryPassManager.cpp @@ -377,8 +377,9 @@ Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) { Manager.registerPass(std::make_unique(PrintNormalized)); - Manager.registerPass(std::make_unique(NeverPrint), - opts::StripRepRet); + if (BC.isX86()) + Manager.registerPass(std::make_unique(NeverPrint), + opts::StripRepRet); Manager.registerPass(std::make_unique(PrintICF), opts::ICF); diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 0c8ee0d417233bb5617cb7a9fc2ddfa59a3dd710..f22bede002da58cb268015bfae7f5c146c18da16 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -556,7 +556,7 @@ Error RewriteInstance::discoverStorage() { if (Error E = SectionNameOrErr.takeError()) return E; StringRef SectionName = SectionNameOrErr.get(); - if (SectionName == ".text") { + if (SectionName == BC->getMainCodeSectionName()) { BC->OldTextSectionAddress = Section.getAddress(); BC->OldTextSectionSize = Section.getSize(); @@ -1864,7 +1864,8 @@ Error RewriteInstance::readSpecialSections() { "Use -update-debug-sections to keep it.\n"; } - HasTextRelocations = (bool)BC->getUniqueSectionByName(".rela.text"); + HasTextRelocations = (bool)BC->getUniqueSectionByName( + ".rela" + std::string(BC->getMainCodeSectionName())); HasSymbolTable = (bool)BC->getUniqueSectionByName(".symtab"); EHFrameSection = BC->getUniqueSectionByName(".eh_frame"); BuildIDSection = BC->getUniqueSectionByName(".note.gnu.build-id"); @@ -2305,9 +2306,13 @@ void RewriteInstance::processRelocations() { return; for (const SectionRef &Section : InputFile->sections()) { - if (cantFail(Section.getRelocatedSection()) != InputFile->section_end() && - !BinarySection(*BC, Section).isAllocatable()) - readRelocations(Section); + section_iterator SecIter = cantFail(Section.getRelocatedSection()); + if (SecIter == InputFile->section_end()) + continue; + if (BinarySection(*BC, Section).isAllocatable()) + continue; + + readRelocations(Section); } if (NumFailedRelocations) @@ -3441,7 +3446,8 @@ void RewriteInstance::emitAndLink() { ErrorOr TextSection = BC->getUniqueSectionByName(BC->getMainCodeSectionName()); if (BC->HasRelocations && TextSection) - BC->renameSection(*TextSection, getOrgSecPrefix() + ".text"); + BC->renameSection(*TextSection, + getOrgSecPrefix() + BC->getMainCodeSectionName()); ////////////////////////////////////////////////////////////////////////////// // Assign addresses to new sections. @@ -4298,7 +4304,7 @@ RewriteInstance::getOutputSections(ELFObjectFile *File, for (auto &SectionKV : OutputSections) { ELFShdrTy &Section = SectionKV.second; - // Ignore TLS sections as they don't take any space in the file. + // Ignore NOBITS sections as they don't take any space in the file. if (Section.sh_type == ELF::SHT_NOBITS) continue; @@ -4306,10 +4312,9 @@ RewriteInstance::getOutputSections(ELFObjectFile *File, // placed in different loadable segments. if (PrevSection && PrevSection->sh_offset + PrevSection->sh_size > Section.sh_offset) { - if (opts::Verbosity > 1) { + if (opts::Verbosity > 1) BC->outs() << "BOLT-INFO: adjusting size for section " << PrevBinSec->getOutputName() << '\n'; - } PrevSection->sh_size = Section.sh_offset - PrevSection->sh_offset; } @@ -4417,6 +4422,7 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile *File) { raw_fd_ostream &OS = Out->os(); const ELFFile &Obj = File->getELFFile(); + // Mapping from old section indices to new ones std::vector NewSectionIndex; std::vector OutputSections = getOutputSections(File, NewSectionIndex); @@ -4434,10 +4440,8 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile *File) { // Write all section header entries while patching section references. for (ELFShdrTy &Section : OutputSections) { Section.sh_link = NewSectionIndex[Section.sh_link]; - if (Section.sh_type == ELF::SHT_REL || Section.sh_type == ELF::SHT_RELA) { - if (Section.sh_info) - Section.sh_info = NewSectionIndex[Section.sh_info]; - } + if (Section.sh_type == ELF::SHT_REL || Section.sh_type == ELF::SHT_RELA) + Section.sh_info = NewSectionIndex[Section.sh_info]; OS.write(reinterpret_cast(&Section), sizeof(Section)); } diff --git a/bolt/test/X86/patch-entries.test b/bolt/test/X86/patch-entries.test index 54f358f273e793c30da84fe3a6134e77d4cb4759..4a725412dd616adeb760df155837c17b003213e0 100644 --- a/bolt/test/X86/patch-entries.test +++ b/bolt/test/X86/patch-entries.test @@ -7,4 +7,25 @@ REQUIRES: system-linux RUN: %clang %cflags -no-pie -g %p/Inputs/patch-entries.c -fuse-ld=lld -o %t.exe \ RUN: -Wl,-q -I%p/../Inputs -RUN: llvm-bolt -relocs %t.exe -o %t.out --update-debug-sections --force-patch +RUN: llvm-bolt -relocs %t.exe -o %t.out --update-debug-sections --force-patch \ +RUN: --enable-bat + +# Check that patched functions can be disassembled (override FDE from the +# original function) +# PREAGG: B X:0 #foo.org.0# 1 0 +RUN: link_fdata %s %t.out %t.preagg PREAGG +RUN: perf2bolt %t.out -p %t.preagg --pa -o %t.yaml --profile-format=yaml \ +RUN: -print-disasm -print-only=foo.org.0/1 2>&1 | FileCheck %s +CHECK-NOT: BOLT-WARNING: sizes differ for function foo.org.0/1 +CHECK: Binary Function "foo.org.0/1(*2)" after disassembly { + +# Check the expected eh_frame contents +RUN: llvm-nm --print-size %t.out > %t.foo +RUN: llvm-objdump %t.out --dwarf=frames >> %t.foo +RUN: FileCheck %s --input-file %t.foo --check-prefix=CHECK-FOO +CHECK-FOO: 0000000000[[#%x,FOO:]] [[#%x,OPTSIZE:]] t foo +CHECK-FOO: 0000000000[[#%x,ORG:]] [[#%x,ORGSIZE:]] t foo.org.0 +# patched FDE comes first +CHECK-FOO: FDE {{.*}} pc=00[[#%x,ORG]]...00[[#%x,ORG+ORGSIZE]] +# original FDE comes second +CHECK-FOO: FDE {{.*}} pc=00[[#%x,ORG]]...00[[#%x,ORG+OPTSIZE]] diff --git a/bolt/test/X86/yaml-secondary-entry-discriminator.s b/bolt/test/X86/yaml-secondary-entry-discriminator.s index 43c2e2a7f05549289293a39808762cc5a68cc285..5d6e291fd7c22a79594afa6b5daa7d828bacc082 100644 --- a/bolt/test/X86/yaml-secondary-entry-discriminator.s +++ b/bolt/test/X86/yaml-secondary-entry-discriminator.s @@ -1,5 +1,5 @@ -# This reproduces a bug with BOLT setting incorrect discriminator for -# secondary entry points in YAML profile. +## This reproduces a bug with BOLT setting incorrect discriminator for +## secondary entry points in YAML profile. # REQUIRES: system-linux # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o @@ -11,20 +11,20 @@ # RUN: FileCheck %s -input-file %t.yaml # CHECK: - name: main # CHECK-NEXT: fid: 2 -# CHECK-NEXT: hash: 0xADF270D550151185 +# CHECK-NEXT: hash: {{.*}} # CHECK-NEXT: exec: 0 # CHECK-NEXT: nblocks: 4 # CHECK-NEXT: blocks: # CHECK: - bid: 1 # CHECK-NEXT: insns: 1 -# CHECK-NEXT: hash: 0x36A303CBA4360014 +# CHECK-NEXT: hash: {{.*}} # CHECK-NEXT: calls: [ { off: 0x0, fid: 1, disc: 1, cnt: 1 } ] # CHECK: - bid: 2 # CHECK-NEXT: insns: 5 -# CHECK-NEXT: hash: 0x8B2F5747CD0019 +# CHECK-NEXT: hash: {{.*}} # CHECK-NEXT: calls: [ { off: 0x0, fid: 1, disc: 1, cnt: 1, mis: 1 } ] -# Make sure that the profile is attached correctly +## Make sure that the profile is attached correctly # RUN: llvm-bolt %t.exe -o %t.out --data %t.yaml --print-profile \ # RUN: --print-only=main | FileCheck %s --check-prefix=CHECK-CFG @@ -33,15 +33,80 @@ # CHECK-CFG: callq *%rax # Offset: [[#]] # CallProfile: 1 (1 misses) : # CHECK-CFG-NEXT: { secondary_entry: 1 (1 misses) } +## YAML BAT test of calling BAT secondary entry from non-BAT function +## Now force-split func and skip main (making it call secondary entries) +# RUN: llvm-bolt %t.exe -o %t.bat --data %t.fdata --funcs=func \ +# RUN: --split-functions --split-strategy=all --split-all-cold --enable-bat + +## Prepare pre-aggregated profile using %t.bat +# RUN: link_fdata %s %t.bat %t.preagg PREAGG +## Strip labels used for pre-aggregated profile +# RUN: llvm-strip -NLcall -NLindcall %t.bat + +## Convert pre-aggregated profile using BAT +# RUN: perf2bolt %t.bat -p %t.preagg --pa -o %t.bat.fdata -w %t.bat.yaml + +## Convert BAT fdata into YAML +# RUN: llvm-bolt %t.exe -data %t.bat.fdata -w %t.bat.fdata-yaml -o /dev/null + +## Check fdata YAML - make sure that a direct call has discriminator field +# RUN: FileCheck %s --input-file %t.bat.fdata-yaml -check-prefix CHECK-BAT-YAML + +## Check BAT YAML - make sure that a direct call has discriminator field +# RUN: FileCheck %s --input-file %t.bat.yaml --check-prefix CHECK-BAT-YAML + +## YAML BAT test of calling BAT secondary entry from BAT function +# RUN: llvm-bolt %t.exe -o %t.bat2 --data %t.fdata --funcs=main,func \ +# RUN: --split-functions --split-strategy=all --split-all-cold --enable-bat + +## Prepare pre-aggregated profile using %t.bat +# RUN: link_fdata %s %t.bat2 %t.preagg2 PREAGG2 + +## Strip labels used for pre-aggregated profile +# RUN: llvm-strip -NLcall -NLindcall %t.bat2 + +## Convert pre-aggregated profile using BAT +# RUN: perf2bolt %t.bat2 -p %t.preagg2 --pa -o %t.bat2.fdata -w %t.bat2.yaml + +## Convert BAT fdata into YAML +# RUN: llvm-bolt %t.exe -data %t.bat2.fdata -w %t.bat2.fdata-yaml -o /dev/null + +## Check fdata YAML - make sure that a direct call has discriminator field +# RUN: FileCheck %s --input-file %t.bat2.fdata-yaml -check-prefix CHECK-BAT-YAML + +## Check BAT YAML - make sure that a direct call has discriminator field +# RUN: FileCheck %s --input-file %t.bat2.yaml --check-prefix CHECK-BAT-YAML + +# CHECK-BAT-YAML: - name: main +# CHECK-BAT-YAML-NEXT: fid: [[#]] +# CHECK-BAT-YAML-NEXT: hash: 0xADF270D550151185 +# CHECK-BAT-YAML-NEXT: exec: 0 +# CHECK-BAT-YAML-NEXT: nblocks: 4 +# CHECK-BAT-YAML-NEXT: blocks: +# CHECK-BAT-YAML: - bid: 1 +# CHECK-BAT-YAML-NEXT: insns: [[#]] +# CHECK-BAT-YAML-NEXT: hash: 0x36A303CBA4360018 +# CHECK-BAT-YAML-NEXT: calls: [ { off: 0x0, fid: [[#]], disc: 1, cnt: 1 + .globl func .type func, @function func: # FDATA: 0 [unknown] 0 1 func 0 1 0 +# PREAGG: B X:0 #func# 1 1 +# PREAGG2: B X:0 #func# 1 1 .cfi_startproc pushq %rbp movq %rsp, %rbp +## Placeholder code to make splitting profitable +.rept 5 + testq %rax, %rax +.endr .globl secondary_entry secondary_entry: +## Placeholder code to make splitting profitable +.rept 5 + testq %rax, %rax +.endr popq %rbp retq nopl (%rax) @@ -58,17 +123,23 @@ main: movl $0, -4(%rbp) testq %rax, %rax jne Lindcall +.globl Lcall Lcall: call secondary_entry # FDATA: 1 main #Lcall# 1 secondary_entry 0 1 1 +# PREAGG: B #Lcall# #secondary_entry# 1 1 +# PREAGG2: B #main.cold.0# #func.cold.0# 1 1 +.globl Lindcall Lindcall: callq *%rax # FDATA: 1 main #Lindcall# 1 secondary_entry 0 1 1 +# PREAGG: B #Lindcall# #secondary_entry# 1 1 +# PREAGG2: B #main.cold.1# #func.cold.0# 1 1 xorl %eax, %eax addq $16, %rsp popq %rbp retq -# For relocations against .text +## For relocations against .text call exit .cfi_endproc .size main, .-main diff --git a/bolt/test/runtime/X86/jt-confusion.s b/bolt/test/runtime/X86/jt-confusion.s new file mode 100644 index 0000000000000000000000000000000000000000..f15c83b35b6a44e8e4733c66aad055be9fbe6a79 --- /dev/null +++ b/bolt/test/runtime/X86/jt-confusion.s @@ -0,0 +1,164 @@ +# REQUIRES: system-linux + +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o +# RUN: llvm-strip --strip-unneeded %t.o +# RUN: %clang %cflags -no-pie -nostartfiles -nostdlib -lc %t.o -o %t.exe -Wl,-q + +# RUN: llvm-bolt %t.exe -o %t.exe.bolt --relocs=1 --lite=0 + +# RUN: %t.exe.bolt + +## Check that BOLT's jump table detection diffrentiates between +## __builtin_unreachable() targets and function pointers. + +## The test case was built from the following two source files and +## modiffied for standalone build. main became _start, etc. +## $ $(CC) a.c -O1 -S -o a.s +## $ $(CC) b.c -O0 -S -o b.s + +## a.c: + +## typedef int (*fptr)(int); +## void check_fptr(fptr, int); +## +## int foo(int a) { +## check_fptr(foo, 0); +## switch (a) { +## default: +## __builtin_unreachable(); +## case 0: +## return 3; +## case 1: +## return 5; +## case 2: +## return 7; +## case 3: +## return 11; +## case 4: +## return 13; +## case 5: +## return 17; +## } +## return 0; +## } +## +## int main(int argc) { +## check_fptr(main, 1); +## return foo(argc); +## } +## +## const fptr funcs[2] = {foo, main}; + +## b.c.: + +## typedef int (*fptr)(int); +## extern const fptr funcs[2]; +## +## #define assert(C) { if (!(C)) (*(unsigned long long *)0) = 0; } +## void check_fptr(fptr f, int i) { +## assert(f == funcs[i]); +## } + + + .text + .globl foo + .type foo, @function +foo: +.LFB0: + .cfi_startproc + pushq %rbx + .cfi_def_cfa_offset 16 + .cfi_offset 3, -16 + movl %edi, %ebx + movl $0, %esi + movl $foo, %edi + call check_fptr + movl %ebx, %ebx + jmp *.L4(,%rbx,8) +.L8: + movl $5, %eax + jmp .L1 +.L7: + movl $7, %eax + jmp .L1 +.L6: + movl $11, %eax + jmp .L1 +.L5: + movl $13, %eax + jmp .L1 +.L3: + movl $17, %eax + jmp .L1 +.L10: + movl $3, %eax +.L1: + popq %rbx + .cfi_def_cfa_offset 8 + ret + .cfi_endproc +.LFE0: + .size foo, .-foo + .globl _start + .type _start, @function +_start: +.LFB1: + .cfi_startproc + pushq %rbx + .cfi_def_cfa_offset 16 + .cfi_offset 3, -16 + movl %edi, %ebx + movl $1, %esi + movl $_start, %edi + call check_fptr + movl $1, %edi + call foo + popq %rbx + .cfi_def_cfa_offset 8 + callq exit@PLT + .cfi_endproc +.LFE1: + .size _start, .-_start + .globl check_fptr + .type check_fptr, @function +check_fptr: +.LFB2: + .cfi_startproc + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset 6, -16 + movq %rsp, %rbp + .cfi_def_cfa_register 6 + movq %rdi, -8(%rbp) + movl %esi, -12(%rbp) + movl -12(%rbp), %eax + cltq + movq funcs(,%rax,8), %rax + cmpq %rax, -8(%rbp) + je .L33 + movl $0, %eax + movq $0, (%rax) +.L33: + nop + popq %rbp + .cfi_def_cfa 7, 8 + ret + .cfi_endproc + + .section .rodata + .align 8 + .align 4 +.L4: + .quad .L10 + .quad .L8 + .quad .L7 + .quad .L6 + .quad .L5 + .quad .L3 + + .globl funcs + .type funcs, @object + .size funcs, 16 +funcs: + .quad foo + .quad _start diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp index 87fd8adf997082593a28d680478c06f06fcfd9fc..bbb35228ce47fbb168a5a0c779177d0ae1510058 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp @@ -9,8 +9,8 @@ #include "MissingStdForwardCheck.h" #include "../utils/Matchers.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/ExprConcepts.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Basic/IdentifierTable.h" using namespace clang::ast_matchers; @@ -79,6 +79,11 @@ AST_MATCHER_P(LambdaExpr, hasCaptureDefaultKind, LambdaCaptureDefault, Kind) { return Node.getCaptureDefault() == Kind; } +AST_MATCHER(VarDecl, hasIdentifier) { + const IdentifierInfo *ID = Node.getIdentifier(); + return ID != NULL && !ID->isPlaceholder(); +} + } // namespace void MissingStdForwardCheck::registerMatchers(MatchFinder *Finder) { @@ -125,12 +130,14 @@ void MissingStdForwardCheck::registerMatchers(MatchFinder *Finder) { hasAncestor(expr(hasUnevaluatedContext()))))); Finder->addMatcher( - parmVarDecl(parmVarDecl().bind("param"), isTemplateTypeParameter(), - hasAncestor(functionDecl().bind("func")), - hasAncestor(functionDecl( - isDefinition(), equalsBoundNode("func"), ToParam, - unless(anyOf(isDeleted(), hasDescendant(std::move( - ForwardCallMatcher))))))), + parmVarDecl( + parmVarDecl().bind("param"), hasIdentifier(), + unless(hasAttr(attr::Kind::Unused)), isTemplateTypeParameter(), + hasAncestor(functionDecl().bind("func")), + hasAncestor(functionDecl( + isDefinition(), equalsBoundNode("func"), ToParam, + unless(anyOf(isDeleted(), + hasDescendant(std::move(ForwardCallMatcher))))))), this); } diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp index b299afd540b9a3cf4a71babcc04e8077988ef235..1548fc454cfb3765eb1aaf30ffa5afc8d7001fe5 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp @@ -29,6 +29,7 @@ #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MathExtras.h" #include +#include #include #include #include diff --git a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp index e3400f614fa5640784b1d6dee31caade6a5a2c8b..48bca41f4a3b1e87dbd7488617702f17e5f6e15a 100644 --- a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp @@ -7,19 +7,18 @@ //===----------------------------------------------------------------------===// #include "AvoidReturnWithVoidValueCheck.h" -#include "clang/AST/Stmt.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/ASTMatchers/ASTMatchers.h" +#include "../utils/BracesAroundStatement.h" +#include "../utils/LexerUtils.h" using namespace clang::ast_matchers; namespace clang::tidy::readability { -static constexpr auto IgnoreMacrosName = "IgnoreMacros"; -static constexpr auto IgnoreMacrosDefault = true; +static constexpr char IgnoreMacrosName[] = "IgnoreMacros"; +static const bool IgnoreMacrosDefault = true; -static constexpr auto StrictModeName = "StrictMode"; -static constexpr auto StrictModeDefault = true; +static constexpr char StrictModeName[] = "StrictMode"; +static const bool StrictModeDefault = true; AvoidReturnWithVoidValueCheck::AvoidReturnWithVoidValueCheck( StringRef Name, ClangTidyContext *Context) @@ -32,7 +31,10 @@ void AvoidReturnWithVoidValueCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( returnStmt( hasReturnValue(allOf(hasType(voidType()), unless(initListExpr()))), - optionally(hasParent(compoundStmt().bind("compound_parent")))) + optionally(hasParent( + compoundStmt( + optionally(hasParent(functionDecl().bind("function_parent")))) + .bind("compound_parent")))) .bind("void_return"), this); } @@ -42,10 +44,30 @@ void AvoidReturnWithVoidValueCheck::check( const auto *VoidReturn = Result.Nodes.getNodeAs("void_return"); if (IgnoreMacros && VoidReturn->getBeginLoc().isMacroID()) return; - if (!StrictMode && !Result.Nodes.getNodeAs("compound_parent")) + const auto *SurroundingBlock = + Result.Nodes.getNodeAs("compound_parent"); + if (!StrictMode && !SurroundingBlock) return; - diag(VoidReturn->getBeginLoc(), "return statement within a void function " - "should not have a specified return value"); + DiagnosticBuilder Diag = diag(VoidReturn->getBeginLoc(), + "return statement within a void function " + "should not have a specified return value"); + const SourceLocation SemicolonPos = utils::lexer::findNextTerminator( + VoidReturn->getEndLoc(), *Result.SourceManager, getLangOpts()); + if (SemicolonPos.isInvalid()) + return; + if (!SurroundingBlock) { + const auto BraceInsertionHints = utils::getBraceInsertionsHints( + VoidReturn, getLangOpts(), *Result.SourceManager, + VoidReturn->getBeginLoc()); + if (BraceInsertionHints) + Diag << BraceInsertionHints.openingBraceFixIt() + << BraceInsertionHints.closingBraceFixIt(); + } + Diag << FixItHint::CreateRemoval(VoidReturn->getReturnLoc()); + if (!Result.Nodes.getNodeAs("function_parent") || + SurroundingBlock->body_back() != VoidReturn) + Diag << FixItHint::CreateInsertion(SemicolonPos.getLocWithOffset(1), + " return;", true); } void AvoidReturnWithVoidValueCheck::storeOptions( diff --git a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp index 81ca33cbbdfb4b5461b54b8a0b5903c0d1186942..85bd9c1e4f9a043074963487e72077c55bc089b3 100644 --- a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "BracesAroundStatementsCheck.h" +#include "../utils/BracesAroundStatement.h" #include "../utils/LexerUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchers.h" @@ -17,12 +18,10 @@ using namespace clang::ast_matchers; namespace clang::tidy::readability { static tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM, - const ASTContext *Context) { + const LangOptions &LangOpts) { Token Tok; - SourceLocation Beginning = - Lexer::GetBeginningOfToken(Loc, SM, Context->getLangOpts()); - const bool Invalid = - Lexer::getRawToken(Beginning, Tok, SM, Context->getLangOpts()); + SourceLocation Beginning = Lexer::GetBeginningOfToken(Loc, SM, LangOpts); + const bool Invalid = Lexer::getRawToken(Beginning, Tok, SM, LangOpts); assert(!Invalid && "Expected a valid token."); if (Invalid) @@ -33,64 +32,21 @@ static tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM, static SourceLocation forwardSkipWhitespaceAndComments(SourceLocation Loc, const SourceManager &SM, - const ASTContext *Context) { + const LangOptions &LangOpts) { assert(Loc.isValid()); for (;;) { while (isWhitespace(*SM.getCharacterData(Loc))) Loc = Loc.getLocWithOffset(1); - tok::TokenKind TokKind = getTokenKind(Loc, SM, Context); + tok::TokenKind TokKind = getTokenKind(Loc, SM, LangOpts); if (TokKind != tok::comment) return Loc; // Fast-forward current token. - Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts()); + Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts); } } -static SourceLocation findEndLocation(const Stmt &S, const SourceManager &SM, - const ASTContext *Context) { - SourceLocation Loc = - utils::lexer::getUnifiedEndLoc(S, SM, Context->getLangOpts()); - if (!Loc.isValid()) - return Loc; - - // Start searching right after S. - Loc = Loc.getLocWithOffset(1); - - for (;;) { - assert(Loc.isValid()); - while (isHorizontalWhitespace(*SM.getCharacterData(Loc))) { - Loc = Loc.getLocWithOffset(1); - } - - if (isVerticalWhitespace(*SM.getCharacterData(Loc))) { - // EOL, insert brace before. - break; - } - tok::TokenKind TokKind = getTokenKind(Loc, SM, Context); - if (TokKind != tok::comment) { - // Non-comment token, insert brace before. - break; - } - - SourceLocation TokEndLoc = - Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts()); - SourceRange TokRange(Loc, TokEndLoc); - StringRef Comment = Lexer::getSourceText( - CharSourceRange::getTokenRange(TokRange), SM, Context->getLangOpts()); - if (Comment.starts_with("/*") && Comment.contains('\n')) { - // Multi-line block comment, insert brace before. - break; - } - // else: Trailing comment, insert brace after the newline. - - // Fast-forward current token. - Loc = TokEndLoc; - } - return Loc; -} - BracesAroundStatementsCheck::BracesAroundStatementsCheck( StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), @@ -124,7 +80,7 @@ void BracesAroundStatementsCheck::check( } else if (const auto *S = Result.Nodes.getNodeAs("do")) { checkStmt(Result, S->getBody(), S->getDoLoc(), S->getWhileLoc()); } else if (const auto *S = Result.Nodes.getNodeAs("while")) { - SourceLocation StartLoc = findRParenLoc(S, SM, Context); + SourceLocation StartLoc = findRParenLoc(S, SM, Context->getLangOpts()); if (StartLoc.isInvalid()) return; checkStmt(Result, S->getBody(), StartLoc); @@ -133,7 +89,7 @@ void BracesAroundStatementsCheck::check( if (S->isConsteval()) return; - SourceLocation StartLoc = findRParenLoc(S, SM, Context); + SourceLocation StartLoc = findRParenLoc(S, SM, Context->getLangOpts()); if (StartLoc.isInvalid()) return; if (ForceBracesStmts.erase(S)) @@ -156,7 +112,7 @@ template SourceLocation BracesAroundStatementsCheck::findRParenLoc(const IfOrWhileStmt *S, const SourceManager &SM, - const ASTContext *Context) { + const LangOptions &LangOpts) { // Skip macros. if (S->getBeginLoc().isMacroID()) return {}; @@ -170,14 +126,14 @@ BracesAroundStatementsCheck::findRParenLoc(const IfOrWhileStmt *S, } SourceLocation PastCondEndLoc = - Lexer::getLocForEndOfToken(CondEndLoc, 0, SM, Context->getLangOpts()); + Lexer::getLocForEndOfToken(CondEndLoc, 0, SM, LangOpts); if (PastCondEndLoc.isInvalid()) return {}; SourceLocation RParenLoc = - forwardSkipWhitespaceAndComments(PastCondEndLoc, SM, Context); + forwardSkipWhitespaceAndComments(PastCondEndLoc, SM, LangOpts); if (RParenLoc.isInvalid()) return {}; - tok::TokenKind TokKind = getTokenKind(RParenLoc, SM, Context); + tok::TokenKind TokKind = getTokenKind(RParenLoc, SM, LangOpts); if (TokKind != tok::r_paren) return {}; return RParenLoc; @@ -188,86 +144,23 @@ BracesAroundStatementsCheck::findRParenLoc(const IfOrWhileStmt *S, bool BracesAroundStatementsCheck::checkStmt( const MatchFinder::MatchResult &Result, const Stmt *S, SourceLocation StartLoc, SourceLocation EndLocHint) { - while (const auto *AS = dyn_cast(S)) S = AS->getSubStmt(); - const SourceManager &SM = *Result.SourceManager; - const ASTContext *Context = Result.Context; - - // 1) If there's a corresponding "else" or "while", the check inserts "} " - // right before that token. - // 2) If there's a multi-line block comment starting on the same line after - // the location we're inserting the closing brace at, or there's a non-comment - // token, the check inserts "\n}" right before that token. - // 3) Otherwise the check finds the end of line (possibly after some block or - // line comments) and inserts "\n}" right before that EOL. - if (!S || isa(S)) { - // Already inside braces. - return false; - } - - // When TreeTransform, Stmt in constexpr IfStmt will be transform to NullStmt. - // This NullStmt can be detected according to beginning token. - const SourceLocation StmtBeginLoc = S->getBeginLoc(); - if (isa(S) && StmtBeginLoc.isValid() && - getTokenKind(StmtBeginLoc, SM, Context) == tok::l_brace) - return false; - - if (StartLoc.isInvalid()) - return false; - - // Convert StartLoc to file location, if it's on the same macro expansion - // level as the start of the statement. We also need file locations for - // Lexer::getLocForEndOfToken working properly. - StartLoc = Lexer::makeFileCharRange( - CharSourceRange::getCharRange(StartLoc, S->getBeginLoc()), SM, - Context->getLangOpts()) - .getBegin(); - if (StartLoc.isInvalid()) - return false; - StartLoc = - Lexer::getLocForEndOfToken(StartLoc, 0, SM, Context->getLangOpts()); - - // StartLoc points at the location of the opening brace to be inserted. - SourceLocation EndLoc; - std::string ClosingInsertion; - if (EndLocHint.isValid()) { - EndLoc = EndLocHint; - ClosingInsertion = "} "; - } else { - EndLoc = findEndLocation(*S, SM, Context); - ClosingInsertion = "\n}"; - } - - assert(StartLoc.isValid()); - - // Don't require braces for statements spanning less than certain number of - // lines. - if (ShortStatementLines && !ForceBracesStmts.erase(S)) { - unsigned StartLine = SM.getSpellingLineNumber(StartLoc); - unsigned EndLine = SM.getSpellingLineNumber(EndLoc); - if (EndLine - StartLine < ShortStatementLines) + const auto BraceInsertionHints = utils::getBraceInsertionsHints( + S, Result.Context->getLangOpts(), *Result.SourceManager, StartLoc, + EndLocHint); + if (BraceInsertionHints) { + if (ShortStatementLines && !ForceBracesStmts.erase(S) && + BraceInsertionHints.resultingCompoundLineExtent(*Result.SourceManager) < + ShortStatementLines) return false; + auto Diag = diag(BraceInsertionHints.DiagnosticPos, + "statement should be inside braces"); + if (BraceInsertionHints.offersFixIts()) + Diag << BraceInsertionHints.openingBraceFixIt() + << BraceInsertionHints.closingBraceFixIt(); } - - auto Diag = diag(StartLoc, "statement should be inside braces"); - - // Change only if StartLoc and EndLoc are on the same macro expansion level. - // This will also catch invalid EndLoc. - // Example: LLVM_DEBUG( for(...) do_something() ); - // In this case fix-it cannot be provided as the semicolon which is not - // visible here is part of the macro. Adding braces here would require adding - // another semicolon. - if (Lexer::makeFileCharRange( - CharSourceRange::getTokenRange(SourceRange( - SM.getSpellingLoc(StartLoc), SM.getSpellingLoc(EndLoc))), - SM, Context->getLangOpts()) - .isInvalid()) - return false; - - Diag << FixItHint::CreateInsertion(StartLoc, " {") - << FixItHint::CreateInsertion(EndLoc, ClosingInsertion); return true; } diff --git a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h index 249aa1aaaa91545549c847912feb3415a381e8cf..4cd37a7b2dd6cc169f9301d6a21b1613748399db 100644 --- a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h +++ b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h @@ -52,7 +52,7 @@ private: SourceLocation EndLocHint = SourceLocation()); template SourceLocation findRParenLoc(const IfOrWhileStmt *S, const SourceManager &SM, - const ASTContext *Context); + const LangOptions &LangOpts); std::optional getCheckTraversalKind() const override { return TK_IgnoreUnlessSpelledInSource; } diff --git a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp index 67147164946ab405138aeafbb361f490f4382ad6..229e5583846b96c0a4ddc537bc78d7a4467fa355 100644 --- a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp @@ -79,6 +79,10 @@ void DuplicateIncludeCallbacks::InclusionDirective( bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File, StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule, bool ModuleImported, SrcMgr::CharacteristicKind FileType) { + // Skip includes behind macros + if (FilenameRange.getBegin().isMacroID() || + FilenameRange.getEnd().isMacroID()) + return; if (llvm::is_contained(Files.back(), FileName)) { // We want to delete the entire line, so make sure that [Start,End] covers // everything. diff --git a/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.cpp b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2a3b7bed08c1e00363d9ad2c899528d8e150f61e --- /dev/null +++ b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.cpp @@ -0,0 +1,168 @@ +//===--- BracesAroundStatement.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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file provides utilities to put braces around a statement. +/// +//===----------------------------------------------------------------------===// + +#include "BracesAroundStatement.h" +#include "../utils/LexerUtils.h" +#include "LexerUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Lex/Lexer.h" + +namespace clang::tidy::utils { + +BraceInsertionHints::operator bool() const { return DiagnosticPos.isValid(); } + +bool BraceInsertionHints::offersFixIts() const { + return OpeningBracePos.isValid() && ClosingBracePos.isValid(); +} + +unsigned BraceInsertionHints::resultingCompoundLineExtent( + const SourceManager &SourceMgr) const { + return SourceMgr.getSpellingLineNumber(ClosingBracePos) - + SourceMgr.getSpellingLineNumber(OpeningBracePos); +} + +FixItHint BraceInsertionHints::openingBraceFixIt() const { + return OpeningBracePos.isValid() + ? FixItHint::CreateInsertion(OpeningBracePos, " {") + : FixItHint(); +} + +FixItHint BraceInsertionHints::closingBraceFixIt() const { + return ClosingBracePos.isValid() + ? FixItHint::CreateInsertion(ClosingBracePos, ClosingBrace) + : FixItHint(); +} + +static tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM, + const LangOptions &LangOpts) { + Token Tok; + SourceLocation Beginning = Lexer::GetBeginningOfToken(Loc, SM, LangOpts); + const bool Invalid = Lexer::getRawToken(Beginning, Tok, SM, LangOpts); + assert(!Invalid && "Expected a valid token."); + + if (Invalid) + return tok::NUM_TOKENS; + + return Tok.getKind(); +} + +static SourceLocation findEndLocation(const Stmt &S, const SourceManager &SM, + const LangOptions &LangOpts) { + SourceLocation Loc = lexer::getUnifiedEndLoc(S, SM, LangOpts); + if (!Loc.isValid()) + return Loc; + + // Start searching right after S. + Loc = Loc.getLocWithOffset(1); + + for (;;) { + assert(Loc.isValid()); + while (isHorizontalWhitespace(*SM.getCharacterData(Loc))) { + Loc = Loc.getLocWithOffset(1); + } + + if (isVerticalWhitespace(*SM.getCharacterData(Loc))) { + // EOL, insert brace before. + break; + } + tok::TokenKind TokKind = getTokenKind(Loc, SM, LangOpts); + if (TokKind != tok::comment) { + // Non-comment token, insert brace before. + break; + } + + SourceLocation TokEndLoc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts); + SourceRange TokRange(Loc, TokEndLoc); + StringRef Comment = Lexer::getSourceText( + CharSourceRange::getTokenRange(TokRange), SM, LangOpts); + if (Comment.starts_with("/*") && Comment.contains('\n')) { + // Multi-line block comment, insert brace before. + break; + } + // else: Trailing comment, insert brace after the newline. + + // Fast-forward current token. + Loc = TokEndLoc; + } + return Loc; +} + +BraceInsertionHints getBraceInsertionsHints(const Stmt *const S, + const LangOptions &LangOpts, + const SourceManager &SM, + SourceLocation StartLoc, + SourceLocation EndLocHint) { + // 1) If there's a corresponding "else" or "while", the check inserts "} " + // right before that token. + // 2) If there's a multi-line block comment starting on the same line after + // the location we're inserting the closing brace at, or there's a non-comment + // token, the check inserts "\n}" right before that token. + // 3) Otherwise the check finds the end of line (possibly after some block or + // line comments) and inserts "\n}" right before that EOL. + if (!S || isa(S)) { + // Already inside braces. + return {}; + } + + // When TreeTransform, Stmt in constexpr IfStmt will be transform to NullStmt. + // This NullStmt can be detected according to beginning token. + const SourceLocation StmtBeginLoc = S->getBeginLoc(); + if (isa(S) && StmtBeginLoc.isValid() && + getTokenKind(StmtBeginLoc, SM, LangOpts) == tok::l_brace) + return {}; + + if (StartLoc.isInvalid()) + return {}; + + // Convert StartLoc to file location, if it's on the same macro expansion + // level as the start of the statement. We also need file locations for + // Lexer::getLocForEndOfToken working properly. + StartLoc = Lexer::makeFileCharRange( + CharSourceRange::getCharRange(StartLoc, S->getBeginLoc()), SM, + LangOpts) + .getBegin(); + if (StartLoc.isInvalid()) + return {}; + StartLoc = Lexer::getLocForEndOfToken(StartLoc, 0, SM, LangOpts); + + // StartLoc points at the location of the opening brace to be inserted. + SourceLocation EndLoc; + std::string ClosingInsertion; + if (EndLocHint.isValid()) { + EndLoc = EndLocHint; + ClosingInsertion = "} "; + } else { + EndLoc = findEndLocation(*S, SM, LangOpts); + ClosingInsertion = "\n}"; + } + + assert(StartLoc.isValid()); + + // Change only if StartLoc and EndLoc are on the same macro expansion level. + // This will also catch invalid EndLoc. + // Example: LLVM_DEBUG( for(...) do_something() ); + // In this case fix-it cannot be provided as the semicolon which is not + // visible here is part of the macro. Adding braces here would require adding + // another semicolon. + if (Lexer::makeFileCharRange( + CharSourceRange::getTokenRange(SourceRange( + SM.getSpellingLoc(StartLoc), SM.getSpellingLoc(EndLoc))), + SM, LangOpts) + .isInvalid()) + return {StartLoc}; + return {StartLoc, EndLoc, ClosingInsertion}; +} + +} // namespace clang::tidy::utils diff --git a/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.h b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.h new file mode 100644 index 0000000000000000000000000000000000000000..cb1c06c7aa1a1a9d5bdd56cd805aa26f19e56c8d --- /dev/null +++ b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.h @@ -0,0 +1,75 @@ +//===--- BracesAroundStatement.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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file provides utilities to put braces around a statement. +/// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Stmt.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" + +namespace clang::tidy::utils { + +/// A provider of fix-it hints to insert opening and closing braces. An instance +/// of this type is the result of calling `getBraceInsertionsHints` below. +struct BraceInsertionHints { + /// The position of a potential diagnostic. It coincides with the position of + /// the opening brace to insert, but can also just be the place to show a + /// diagnostic in case braces cannot be inserted automatically. + SourceLocation DiagnosticPos; + + /// Constructor for a no-hint. + BraceInsertionHints() = default; + + /// Constructor for a valid hint that cannot insert braces automatically. + BraceInsertionHints(SourceLocation DiagnosticPos) + : DiagnosticPos(DiagnosticPos) {} + + /// Constructor for a hint offering fix-its for brace insertion. Both + /// positions must be valid. + BraceInsertionHints(SourceLocation OpeningBracePos, + SourceLocation ClosingBracePos, std::string ClosingBrace) + : DiagnosticPos(OpeningBracePos), OpeningBracePos(OpeningBracePos), + ClosingBracePos(ClosingBracePos), ClosingBrace(ClosingBrace) { + assert(offersFixIts()); + } + + /// Indicates whether the hint provides at least the position of a diagnostic. + operator bool() const; + + /// Indicates whether the hint provides fix-its to insert braces. + bool offersFixIts() const; + + /// The number of lines between the inserted opening brace and its closing + /// counterpart. + unsigned resultingCompoundLineExtent(const SourceManager &SourceMgr) const; + + /// Fix-it to insert an opening brace. + FixItHint openingBraceFixIt() const; + + /// Fix-it to insert a closing brace. + FixItHint closingBraceFixIt() const; + +private: + SourceLocation OpeningBracePos; + SourceLocation ClosingBracePos; + std::string ClosingBrace; +}; + +/// Create fix-it hints for braces that wrap the given statement when applied. +/// The algorithm computing them respects comment before and after the statement +/// and adds line breaks before the braces accordingly. +BraceInsertionHints +getBraceInsertionsHints(const Stmt *const S, const LangOptions &LangOpts, + const SourceManager &SM, SourceLocation StartLoc, + SourceLocation EndLocHint = SourceLocation()); + +} // namespace clang::tidy::utils diff --git a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt index f0160fa9df74879429e6f6be554d43bf633af0d6..9cff7d475425d792c2c2f373a3e88d34f7216513 100644 --- a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt @@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS add_clang_library(clangTidyUtils Aliasing.cpp ASTUtils.cpp + BracesAroundStatement.cpp DeclRefExprUtils.cpp DesignatedInitializers.cpp ExceptionAnalyzer.cpp diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp index da1433aa2d05d472f5f581973fead7993d468794..962a243ce94d48bfcf3e9ed1ffa3278749cbb35a 100644 --- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp @@ -31,13 +31,12 @@ struct DenseMapInfo { using NamingCheckId = clang::tidy::RenamerClangTidyCheck::NamingCheckId; static inline NamingCheckId getEmptyKey() { - return {DenseMapInfo::getEmptyKey(), - "EMPTY"}; + return {DenseMapInfo::getEmptyKey(), "EMPTY"}; } static inline NamingCheckId getTombstoneKey() { return {DenseMapInfo::getTombstoneKey(), - "TOMBSTONE"}; + "TOMBSTONE"}; } static unsigned getHashValue(NamingCheckId Val) { @@ -170,14 +169,14 @@ public: return; if (SM.isWrittenInCommandLineFile(MacroNameTok.getLocation())) return; - Check->checkMacro(SM, MacroNameTok, Info); + Check->checkMacro(MacroNameTok, Info, SM); } /// MacroExpands calls expandMacro for macros in the main file void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD, SourceRange /*Range*/, const MacroArgs * /*Args*/) override { - Check->expandMacro(MacroNameTok, MD.getMacroInfo()); + Check->expandMacro(MacroNameTok, MD.getMacroInfo(), SM); } private: @@ -188,7 +187,7 @@ private: class RenamerClangTidyVisitor : public RecursiveASTVisitor { public: - RenamerClangTidyVisitor(RenamerClangTidyCheck *Check, const SourceManager *SM, + RenamerClangTidyVisitor(RenamerClangTidyCheck *Check, const SourceManager &SM, bool AggressiveDependentMemberLookup) : Check(Check), SM(SM), AggressiveDependentMemberLookup(AggressiveDependentMemberLookup) {} @@ -259,7 +258,7 @@ public: // Fix overridden methods if (const auto *Method = dyn_cast(Decl)) { if (const CXXMethodDecl *Overridden = getOverrideMethod(Method)) { - Check->addUsage(Overridden, Method->getLocation()); + Check->addUsage(Overridden, Method->getLocation(), SM); return true; // Don't try to add the actual decl as a Failure. } } @@ -269,7 +268,7 @@ public: if (isa(Decl)) return true; - Check->checkNamedDecl(Decl, *SM); + Check->checkNamedDecl(Decl, SM); return true; } @@ -367,9 +366,26 @@ public: return true; } + bool VisitDesignatedInitExpr(DesignatedInitExpr *Expr) { + for (const DesignatedInitExpr::Designator &D : Expr->designators()) { + if (!D.isFieldDesignator()) + continue; + const FieldDecl *FD = D.getFieldDecl(); + if (!FD) + continue; + const IdentifierInfo *II = FD->getIdentifier(); + if (!II) + continue; + SourceRange FixLocation{D.getFieldLoc(), D.getFieldLoc()}; + Check->addUsage(FD, FixLocation, SM); + } + + return true; + } + private: RenamerClangTidyCheck *Check; - const SourceManager *SM; + const SourceManager &SM; const bool AggressiveDependentMemberLookup; }; @@ -399,7 +415,7 @@ void RenamerClangTidyCheck::registerPPCallbacks( void RenamerClangTidyCheck::addUsage( const RenamerClangTidyCheck::NamingCheckId &Decl, SourceRange Range, - const SourceManager *SourceMgr) { + const SourceManager &SourceMgr) { // Do nothing if the provided range is invalid. if (Range.isInvalid()) return; @@ -409,8 +425,7 @@ void RenamerClangTidyCheck::addUsage( // spelling location to different source locations, and we only want to fix // the token once, before it is expanded by the macro. SourceLocation FixLocation = Range.getBegin(); - if (SourceMgr) - FixLocation = SourceMgr->getSpellingLoc(FixLocation); + FixLocation = SourceMgr.getSpellingLoc(FixLocation); if (FixLocation.isInvalid()) return; @@ -424,15 +439,15 @@ void RenamerClangTidyCheck::addUsage( if (!Failure.shouldFix()) return; - if (SourceMgr && SourceMgr->isWrittenInScratchSpace(FixLocation)) + if (SourceMgr.isWrittenInScratchSpace(FixLocation)) Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro; - if (!utils::rangeCanBeFixed(Range, SourceMgr)) + if (!utils::rangeCanBeFixed(Range, &SourceMgr)) Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro; } void RenamerClangTidyCheck::addUsage(const NamedDecl *Decl, SourceRange Range, - const SourceManager *SourceMgr) { + const SourceManager &SourceMgr) { // Don't keep track for non-identifier names. auto *II = Decl->getIdentifier(); if (!II) @@ -473,18 +488,24 @@ void RenamerClangTidyCheck::checkNamedDecl(const NamedDecl *Decl, } Failure.Info = std::move(Info); - addUsage(Decl, Range); + addUsage(Decl, Range, SourceMgr); } void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) { - RenamerClangTidyVisitor Visitor(this, Result.SourceManager, + if (!Result.SourceManager) { + // In principle SourceManager is not null but going only by the definition + // of MatchResult it must be handled. Cannot rename anything without a + // SourceManager. + return; + } + RenamerClangTidyVisitor Visitor(this, *Result.SourceManager, AggressiveDependentMemberLookup); Visitor.TraverseAST(*Result.Context); } -void RenamerClangTidyCheck::checkMacro(const SourceManager &SourceMgr, - const Token &MacroNameTok, - const MacroInfo *MI) { +void RenamerClangTidyCheck::checkMacro(const Token &MacroNameTok, + const MacroInfo *MI, + const SourceManager &SourceMgr) { std::optional MaybeFailure = getMacroFailureInfo(MacroNameTok, SourceMgr); if (!MaybeFailure) @@ -499,11 +520,12 @@ void RenamerClangTidyCheck::checkMacro(const SourceManager &SourceMgr, Failure.FixStatus = ShouldFixStatus::FixInvalidIdentifier; Failure.Info = std::move(Info); - addUsage(ID, Range); + addUsage(ID, Range, SourceMgr); } void RenamerClangTidyCheck::expandMacro(const Token &MacroNameTok, - const MacroInfo *MI) { + const MacroInfo *MI, + const SourceManager &SourceMgr) { StringRef Name = MacroNameTok.getIdentifierInfo()->getName(); NamingCheckId ID(MI->getDefinitionLoc(), Name); @@ -512,7 +534,7 @@ void RenamerClangTidyCheck::expandMacro(const Token &MacroNameTok, return; SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc()); - addUsage(ID, Range); + addUsage(ID, Range, SourceMgr); } static std::string diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h index 38228fb59bf62487674a5ba28bbe8449956d37e2..be5b6f0c7f76785d7f2aada7dd394cf3a568ddd4 100644 --- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h +++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h @@ -108,18 +108,19 @@ public: llvm::DenseMap; /// Check Macros for style violations. - void checkMacro(const SourceManager &SourceMgr, const Token &MacroNameTok, - const MacroInfo *MI); + void checkMacro(const Token &MacroNameTok, const MacroInfo *MI, + const SourceManager &SourceMgr); /// Add a usage of a macro if it already has a violation. - void expandMacro(const Token &MacroNameTok, const MacroInfo *MI); + void expandMacro(const Token &MacroNameTok, const MacroInfo *MI, + const SourceManager &SourceMgr); void addUsage(const RenamerClangTidyCheck::NamingCheckId &Decl, - SourceRange Range, const SourceManager *SourceMgr = nullptr); + SourceRange Range, const SourceManager &SourceMgr); /// Convenience method when the usage to be added is a NamedDecl. void addUsage(const NamedDecl *Decl, SourceRange Range, - const SourceManager *SourceMgr = nullptr); + const SourceManager &SourceMgr); void checkNamedDecl(const NamedDecl *Decl, const SourceManager &SourceMgr); diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp index 9e321dce4c5041901ef21708b2366f2722514b7a..89eee392837af4955a584fca6c0515949924baa1 100644 --- a/clang-tools-extra/clangd/CodeComplete.cpp +++ b/clang-tools-extra/clangd/CodeComplete.cpp @@ -89,7 +89,11 @@ const CodeCompleteOptions::CodeCompletionRankingModel namespace { -CompletionItemKind toCompletionItemKind(index::SymbolKind Kind) { +// Note: changes to this function should also be reflected in the +// CodeCompletionResult overload where appropriate. +CompletionItemKind +toCompletionItemKind(index::SymbolKind Kind, + const llvm::StringRef *Signature = nullptr) { using SK = index::SymbolKind; switch (Kind) { case SK::Unknown: @@ -99,7 +103,10 @@ CompletionItemKind toCompletionItemKind(index::SymbolKind Kind) { case SK::NamespaceAlias: return CompletionItemKind::Module; case SK::Macro: - return CompletionItemKind::Text; + // Use macro signature (if provided) to tell apart function-like and + // object-like macros. + return Signature && Signature->contains('(') ? CompletionItemKind::Function + : CompletionItemKind::Constant; case SK::Enum: return CompletionItemKind::Enum; case SK::Struct: @@ -150,6 +157,8 @@ CompletionItemKind toCompletionItemKind(index::SymbolKind Kind) { llvm_unreachable("Unhandled clang::index::SymbolKind."); } +// Note: changes to this function should also be reflected in the +// index::SymbolKind overload where appropriate. CompletionItemKind toCompletionItemKind(const CodeCompletionResult &Res, CodeCompletionContext::Kind CtxKind) { if (Res.Declaration) @@ -379,7 +388,8 @@ struct CodeCompletionBuilder { if (Completion.Scope.empty()) Completion.Scope = std::string(C.IndexResult->Scope); if (Completion.Kind == CompletionItemKind::Missing) - Completion.Kind = toCompletionItemKind(C.IndexResult->SymInfo.Kind); + Completion.Kind = toCompletionItemKind(C.IndexResult->SymInfo.Kind, + &C.IndexResult->Signature); if (Completion.Name.empty()) Completion.Name = std::string(C.IndexResult->Name); if (Completion.FilterText.empty()) diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp index 85b8fc549b016e4dc159ddf591266dba80511fbb..5c4e2150cf3123bb11ecb567887ee269ec6f0ca7 100644 --- a/clang-tools-extra/clangd/index/SymbolCollector.cpp +++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp @@ -409,7 +409,7 @@ private: // Framework headers are spelled as , not // "path/FrameworkName.framework/Headers/Foo.h". auto &HS = PP->getHeaderSearchInfo(); - if (const auto *HFI = HS.getExistingFileInfo(*FE, /*WantExternal*/ false)) + if (const auto *HFI = HS.getExistingFileInfo(*FE)) if (!HFI->Framework.empty()) if (auto Spelling = getFrameworkHeaderIncludeSpelling(*FE, HFI->Framework, HS)) diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp index 49337bddf98d5d93c22f75169844bc08ded35426..8fbac73cb653bcc20d4b68a92a6e80f2bd881315 100644 --- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp +++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp @@ -671,7 +671,8 @@ TEST(CompletionTest, Kinds) { #define MACRO 10 int X = ^ )cpp", - {func("indexFunction"), var("indexVariable"), cls("indexClass")}); + {func("indexFunction"), var("indexVariable"), cls("indexClass"), + macro("indexObjMacro"), macro("indexFuncMacro", "(x, y)")}); EXPECT_THAT(Results.Completions, AllOf(has("function", CompletionItemKind::Function), has("variable", CompletionItemKind::Variable), @@ -680,7 +681,9 @@ TEST(CompletionTest, Kinds) { has("MACRO", CompletionItemKind::Constant), has("indexFunction", CompletionItemKind::Function), has("indexVariable", CompletionItemKind::Variable), - has("indexClass", CompletionItemKind::Class))); + has("indexClass", CompletionItemKind::Class), + has("indexObjMacro", CompletionItemKind::Constant), + has("indexFuncMacro", CompletionItemKind::Function))); Results = completions("nam^"); EXPECT_THAT(Results.Completions, diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index 35db757b9c15b5d3258552783cbbe5351c8d1a3c..5ead74748f550cb4536c7edf9cc246a4d41b5a42 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -1983,10 +1983,14 @@ TEST(Hover, All) { HI.Kind = index::SymbolKind::Macro; HI.Definition = R"cpp(#define MACRO \ - { return 0; } + { \ + return 0; \ + } // Expands to -{ return 0; })cpp"; +{ + return 0; +})cpp"; }}, { R"cpp(// Forward class declaration diff --git a/clang-tools-extra/clangd/unittests/TestIndex.cpp b/clang-tools-extra/clangd/unittests/TestIndex.cpp index 278336bdde2ee5cd2f50a36eb8ffb892490f44c0..b13a5d32d175245b64a830189afc0d843d51ac68 100644 --- a/clang-tools-extra/clangd/unittests/TestIndex.cpp +++ b/clang-tools-extra/clangd/unittests/TestIndex.cpp @@ -38,7 +38,7 @@ static std::string replace(llvm::StringRef Haystack, llvm::StringRef Needle, // Helpers to produce fake index symbols for memIndex() or completions(). // USRFormat is a regex replacement string for the unqualified part of the USR. Symbol sym(llvm::StringRef QName, index::SymbolKind Kind, - llvm::StringRef USRFormat) { + llvm::StringRef USRFormat, llvm::StringRef Signature) { Symbol Sym; std::string USR = "c:"; // We synthesize a few simple cases of USRs by hand! size_t Pos = QName.rfind("::"); @@ -55,6 +55,7 @@ Symbol sym(llvm::StringRef QName, index::SymbolKind Kind, Sym.SymInfo.Kind = Kind; Sym.Flags |= Symbol::IndexedForCodeCompletion; Sym.Origin = SymbolOrigin::Static; + Sym.Signature = Signature; return Sym; } @@ -86,6 +87,10 @@ Symbol conceptSym(llvm::StringRef Name) { return sym(Name, index::SymbolKind::Concept, "@CT@\\0"); } +Symbol macro(llvm::StringRef Name, llvm::StringRef ArgList) { + return sym(Name, index::SymbolKind::Macro, "@macro@\\0", ArgList); +} + Symbol objcSym(llvm::StringRef Name, index::SymbolKind Kind, llvm::StringRef USRPrefix) { Symbol Sym; diff --git a/clang-tools-extra/clangd/unittests/TestIndex.h b/clang-tools-extra/clangd/unittests/TestIndex.h index 9280b0b12a67fe7a9f57e4e2344f32d84febc953..0699b29392d720dfad46335e823b837724f36316 100644 --- a/clang-tools-extra/clangd/unittests/TestIndex.h +++ b/clang-tools-extra/clangd/unittests/TestIndex.h @@ -20,7 +20,7 @@ Symbol symbol(llvm::StringRef QName); // Helpers to produce fake index symbols with proper SymbolID. // USRFormat is a regex replacement string for the unqualified part of the USR. Symbol sym(llvm::StringRef QName, index::SymbolKind Kind, - llvm::StringRef USRFormat); + llvm::StringRef USRFormat, llvm::StringRef Signature = {}); // Creats a function symbol assuming no function arg. Symbol func(llvm::StringRef Name); // Creates a class symbol. @@ -35,6 +35,8 @@ Symbol var(llvm::StringRef Name); Symbol ns(llvm::StringRef Name); // Create a C++20 concept symbol. Symbol conceptSym(llvm::StringRef Name); +// Create a macro symbol. +Symbol macro(llvm::StringRef Name, llvm::StringRef ArgList = {}); // Create an Objective-C symbol. Symbol objcSym(llvm::StringRef Name, index::SymbolKind Kind, diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 456e09204fa2f9f6f90a0b1b951f4abdfb85339d..1405fb0df1f8ddbb07aae02cd1ef149027a49d5a 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -100,6 +100,8 @@ 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. New checks ^^^^^^^^^^ @@ -179,8 +181,9 @@ Changes in existing checks - Improved :doc:`cppcoreguidelines-missing-std-forward ` check by no longer - giving false positives for deleted functions and fix false negative when some - parameters are forwarded, but other aren't. + giving false positives for deleted functions, by fixing false negatives when only + a few parameters are forwarded and by ignoring parameters without a name (unused + arguments). - Improved :doc:`cppcoreguidelines-owning-memory ` check to properly handle @@ -255,10 +258,19 @@ Changes in existing checks analyzed, se the check now handles the common patterns `const auto e = (*vector_ptr)[i]` and `const auto e = vector_ptr->at(i);`. +- Improved :doc:`readability-avoid-return-with-void-value + ` check by adding + fix-its. + +- Improved :doc:`readability-duplicate-include + ` check by excluding include + directives that form the filename using macro. + - Improved :doc:`readability-identifier-naming ` check in `GetConfigPerFile` mode by resolving symbolic links to header files. Fixed handling of Hungarian - Prefix when configured to `LowerCase`. + Prefix when configured to `LowerCase`. Added support for renaming designated + initializers. Added support for renaming macro arguments. - Improved :doc:`readability-implicit-bool-conversion ` check to provide diff --git a/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp b/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp index fd2de6a17ad4a53c009c9c5d1337cce4da9f0d52..7b28d1c252d715e1eb8501a25ead5f1abc41b2ef 100644 --- a/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp +++ b/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp @@ -275,6 +275,12 @@ llvm::SmallVector
headersForSymbol(const Symbol &S, // are already ranked in the stdlib mapping. if (H.kind() == Header::Standard) continue; + // Don't apply name match hints to exporting headers. As they usually have + // names similar to the original header, e.g. foo_wrapper/foo.h vs + // foo/foo.h, but shouldn't be preferred (unless marked as the public + // interface). + if ((H.Hint & Hints::OriginHeader) == Hints::None) + continue; if (nameMatch(SymbolName, H)) H.Hint |= Hints::PreferredHeader; } diff --git a/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp b/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp index 5a2a41b2d99bdd78b52b63fda3ce5db38394d404..07302142a13e363730f6a3713b9e8df806e2efdf 100644 --- a/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp @@ -628,5 +628,24 @@ TEST_F(HeadersForSymbolTest, StandardHeaders) { tooling::stdlib::Header::named(""))); } +TEST_F(HeadersForSymbolTest, ExporterNoNameMatch) { + Inputs.Code = R"cpp( + #include "exporter/foo.h" + #include "foo_public.h" + )cpp"; + Inputs.ExtraArgs.emplace_back("-I."); + // Deliberately named as foo_public to make sure it doesn't get name-match + // boost and also gets lexicographically bigger order than "exporter/foo.h". + Inputs.ExtraFiles["foo_public.h"] = guard(R"cpp( + struct foo {}; + )cpp"); + Inputs.ExtraFiles["exporter/foo.h"] = guard(R"cpp( + #include "foo_public.h" // IWYU pragma: export + )cpp"); + buildAST(); + EXPECT_THAT(headersForFoo(), ElementsAre(physicalHeader("foo_public.h"), + physicalHeader("exporter/foo.h"))); +} + } // namespace } // namespace clang::include_cleaner diff --git a/clang-tools-extra/test/clang-tidy/check_clang_tidy.py b/clang-tools-extra/test/clang-tidy/check_clang_tidy.py index 53ffca0bad8d06fd92d0e9c5663ecc8acc464208..6d4b466afa691a74b59185e360f0b9a8b6597261 100755 --- a/clang-tools-extra/test/clang-tidy/check_clang_tidy.py +++ b/clang-tools-extra/test/clang-tidy/check_clang_tidy.py @@ -8,25 +8,35 @@ # # ===------------------------------------------------------------------------===# -r""" +""" ClangTidy Test Helper ===================== -This script runs clang-tidy in fix mode and verify fixes, messages or both. +This script is used to simplify writing, running, and debugging tests compatible +with llvm-lit. By default it runs clang-tidy in fix mode and uses FileCheck to +verify messages and/or fixes. + +For debugging, with --export-fixes, the tool simply exports fixes to a provided +file and does not run FileCheck. -Usage: - check_clang_tidy.py [-resource-dir=] \ - [-assume-filename=] \ - [-check-suffix=] \ - [-check-suffixes=] \ - [-std=c++(98|11|14|17|20)[-or-later]] \ - \ - -- [optional clang-tidy arguments] +Extra arguments, those after the first -- if any, are passed to either +clang-tidy or clang: +* Arguments between the first -- and second -- are clang-tidy arguments. + * May be only whitespace if there are no clang-tidy arguments. + * clang-tidy's --config would go here. +* Arguments after the second -- are clang arguments + +Examples +-------- -Example: // RUN: %check_clang_tidy %s llvm-include-order %t -- -- -isystem %S/Inputs -Notes: +or + + // RUN: %check_clang_tidy %s llvm-include-order --export-fixes=fixes.yaml %t -std=c++20 + +Notes +----- -std=c++(98|11|14|17|20)-or-later: This flag will cause multiple runs within the same check_clang_tidy execution. Make sure you don't have shared state across these runs. @@ -34,6 +44,7 @@ Notes: import argparse import os +import pathlib import re import subprocess import sys @@ -88,6 +99,7 @@ class CheckRunner: self.has_check_fixes = False self.has_check_messages = False self.has_check_notes = False + self.export_fixes = args.export_fixes self.fixes = MessagePrefix("CHECK-FIXES") self.messages = MessagePrefix("CHECK-MESSAGES") self.notes = MessagePrefix("CHECK-NOTES") @@ -181,7 +193,13 @@ class CheckRunner: [ "clang-tidy", self.temp_file_name, - "-fix", + ] + + [ + "-fix" + if self.export_fixes is None + else "--export-fixes=" + self.export_fixes + ] + + [ "--checks=-*," + self.check_name, ] + self.clang_tidy_extra_args @@ -255,12 +273,14 @@ class CheckRunner: def run(self): self.read_input() - self.get_prefixes() + if self.export_fixes is None: + self.get_prefixes() self.prepare_test_inputs() clang_tidy_output = self.run_clang_tidy() - self.check_fixes() - self.check_messages(clang_tidy_output) - self.check_notes(clang_tidy_output) + if self.export_fixes is None: + self.check_fixes() + self.check_messages(clang_tidy_output) + self.check_notes(clang_tidy_output) def expand_std(std): @@ -284,7 +304,11 @@ def csv(string): def parse_arguments(): - parser = argparse.ArgumentParser() + parser = argparse.ArgumentParser( + prog=pathlib.Path(__file__).stem, + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter, + ) parser.add_argument("-expect-clang-tidy-error", action="store_true") parser.add_argument("-resource-dir") parser.add_argument("-assume-filename") @@ -298,7 +322,19 @@ def parse_arguments(): type=csv, help="comma-separated list of FileCheck suffixes", ) - parser.add_argument("-std", type=csv, default=["c++11-or-later"]) + parser.add_argument( + "-export-fixes", + default=None, + type=str, + metavar="file", + help="A file to export fixes into instead of fixing.", + ) + parser.add_argument( + "-std", + type=csv, + default=["c++11-or-later"], + help="Passed to clang. Special -or-later values are expanded.", + ) return parser.parse_known_args() diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp index 9a50eabf619bd57a8f18091b48796e2ef7a479f1..8116db58c937d44524b6f6e3b7dd26273bc2a288 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp @@ -198,3 +198,16 @@ struct S { }; } // namespace deleted_functions + +namespace unused_arguments { + +template +void unused_argument1(F&&) {} + +template +void unused_argument2([[maybe_unused]] F&& f) {} + +template +void unused_argument3(F&& _) {} + +} // namespace unused_arguments diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp index f00407c99ce57021a4be3fcad13feaa9bbd24140..7c948dba3e8f7c0d4991270f3647761ec3de3dbb 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp @@ -12,23 +12,30 @@ void f2() { return f1(); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: f1(); } void f3(bool b) { if (b) return f1(); // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: if (b) { f1(); return; + // CHECK-NEXT: } return f2(); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: f2(); + // CHECK-FIXES-LENIENT: f2(); } template T f4() {} void f5() { - return f4(); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] - // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + { return f4(); } + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:7: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: { f4(); return; } + // CHECK-FIXES-LENIENT: { f4(); return; } } void f6() { return; } @@ -41,6 +48,8 @@ void f9() { return (void)f7(); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: (void)f7(); + // CHECK-FIXES-LENIENT: (void)f7(); } #define RETURN_VOID return (void)1 @@ -50,12 +59,12 @@ void f10() { // CHECK-MESSAGES-INCLUDE-MACROS: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] } -template +template struct C { C(A) {} }; -template +template C f11() { return {}; } using VOID = void; @@ -66,4 +75,36 @@ VOID f13() { return f12(); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: f12(); return; + // CHECK-FIXES-LENIENT: f12(); return; + (void)1; +} + +void f14() { + return /* comment */ f1() /* comment */ ; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: /* comment */ f1() /* comment */ ; return; + // CHECK-FIXES-LENIENT: /* comment */ f1() /* comment */ ; return; + (void)1; +} + +void f15() { + return/*comment*/f1()/*comment*/;//comment + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: /*comment*/f1()/*comment*/; return;//comment + // CHECK-FIXES-LENIENT: /*comment*/f1()/*comment*/; return;//comment + (void)1; +} + +void f16(bool b) { + if (b) return f1(); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: if (b) { f1(); return; + // CHECK-NEXT: } + else return f2(); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: else { f2(); return; + // CHECK-NEXT: } } diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp index dd954c705514fb777bb5e0570623f076fb5a7070..2119602ba454b49d111524fd42730f41e76b8ede 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp @@ -70,3 +70,18 @@ int r; // CHECK-FIXES: {{^int q;$}} // CHECK-FIXES-NEXT: {{^#include $}} // CHECK-FIXES-NEXT: {{^int r;$}} + +namespace Issue_87303 { +#define RESET_INCLUDE_CACHE +// Expect no warnings + +#define MACRO_FILENAME "duplicate-include.h" +#include MACRO_FILENAME +#include "duplicate-include.h" + +#define MACRO_FILENAME_2 +#include +#include MACRO_FILENAME_2 + +#undef RESET_INCLUDE_CACHE +} // Issue_87303 diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp index d2e89a7c9855c9a8b9407406cbc7227b9c24ef44..99149fe86aceecf662ead7f674103230bb263630 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp @@ -108,10 +108,12 @@ USER_NS::object g_s2; // NO warnings or fixes expected as USER_NS and object are declared in a header file SYSTEM_MACRO(var1); -// NO warnings or fixes expected as var1 is from macro expansion +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: invalid case style for global variable 'var1' [readability-identifier-naming] +// CHECK-FIXES: {{^}}SYSTEM_MACRO(g_var1); USER_MACRO(var2); -// NO warnings or fixes expected as var2 is declared in a macro expansion +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: invalid case style for global variable 'var2' [readability-identifier-naming] +// CHECK-FIXES: {{^}}USER_MACRO(g_var2); #define BLA int FOO_bar BLA; @@ -602,9 +604,20 @@ static void static_Function() { // CHECK-FIXES: {{^}}#define MY_TEST_MACRO(X) X() void MY_TEST_Macro(function) {} -// CHECK-FIXES: {{^}}void MY_TEST_MACRO(function) {} -} -} +// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: invalid case style for global function 'function' [readability-identifier-naming] +// CHECK-FIXES: {{^}}void MY_TEST_MACRO(Function) {} + +#define MY_CAT_IMPL(l, r) l ## r +#define MY_CAT(l, r) MY_CAT_IMPL(l, r) +#define MY_MACRO2(foo) int MY_CAT(awesome_, MY_CAT(foo, __COUNTER__)) = 0 +#define MY_MACRO3(foo) int MY_CAT(awesome_, foo) = 0 +MY_MACRO2(myglob); +MY_MACRO3(myglob); +// No suggestions should occur even though the resulting decl of awesome_myglob# +// or awesome_myglob are not entirely within a macro argument. + +} // namespace InlineNamespace +} // namespace FOO_NS template struct a { // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: invalid case style for struct 'a' @@ -766,3 +779,13 @@ STATIC_MACRO void someFunc(MyFunPtr, const MyFunPtr****) {} // CHECK-FIXES: {{^}}STATIC_MACRO void someFunc(my_fun_ptr_t, const my_fun_ptr_t****) {} #undef STATIC_MACRO } + +struct Some_struct { + int SomeMember; +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for public member 'SomeMember' [readability-identifier-naming] +// CHECK-FIXES: {{^}} int some_member; +}; +Some_struct g_s1{ .SomeMember = 1 }; +// CHECK-FIXES: {{^}}Some_struct g_s1{ .some_member = 1 }; +Some_struct g_s2{.SomeMember=1}; +// CHECK-FIXES: {{^}}Some_struct g_s2{.some_member=1}; diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index 284b2af24ddaa0405398e8ea1826856e93401ba6..f092766fa19f07f754960ec9524078d6b65070d4 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -165,6 +165,13 @@ if(CLANG_ENABLE_LIBXML2) endif() endif() +if(CLANG_ENABLE_CIR) + if (NOT "${LLVM_ENABLE_PROJECTS}" MATCHES "MLIR|mlir") + message(FATAL_ERROR + "Cannot build ClangIR without MLIR in LLVM_ENABLE_PROJECTS") + endif() +endif() + include(CheckIncludeFile) check_include_file(sys/resource.h CLANG_HAVE_RLIMITS) diff --git a/clang/cmake/caches/Release.cmake b/clang/cmake/caches/Release.cmake index 1ca9138b98073118184385ba6eb6a8a0690132ad..bd1f688d61a7ea2aaa475aaec7d6a0970c12139f 100644 --- a/clang/cmake/caches/Release.cmake +++ b/clang/cmake/caches/Release.cmake @@ -4,7 +4,7 @@ # General Options set(LLVM_RELEASE_ENABLE_LTO THIN CACHE STRING "") -set(LLVM_RELEASE_ENABLE_PGO ON CACHE BOOL "") +set(LLVM_RELEASE_ENABLE_PGO OFF CACHE BOOL "") set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "") diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst index 80dc38a075c8fcf572ce093da3893007e23342b4..dbd9c91ae508e5d8175c5e1734e4fcdb34c80090 100644 --- a/clang/docs/ClangFormat.rst +++ b/clang/docs/ClangFormat.rst @@ -54,7 +54,7 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code. Objective-C: .m .mm Proto: .proto .protodevel TableGen: .td - TextProto: .textpb .pb.txt .textproto .asciipb + TextProto: .txtpb .textpb .pb.txt .textproto .asciipb Verilog: .sv .svh .v .vh --cursor= - The position of the cursor when invoking clang-format from an editor integration diff --git a/clang/docs/HIPSupport.rst b/clang/docs/HIPSupport.rst index 543c82cf90244945a7cf08b89009a6a37e5c34bf..5ba84c2f670556491b51f3d716be759d8f653fec 100644 --- a/clang/docs/HIPSupport.rst +++ b/clang/docs/HIPSupport.rst @@ -208,6 +208,20 @@ Host Code Compilation - These relocatable objects are then linked together. - Host code within a TU can call host functions and launch kernels from another TU. +Syntax Difference with CUDA +=========================== + +Clang's front end, used for both CUDA and HIP programming models, shares the same parsing and semantic analysis mechanisms. This includes the resolution of overloads concerning device and host functions. While there exists a comprehensive documentation on the syntax differences between Clang and NVCC for CUDA at `Dialect Differences Between Clang and NVCC `_, it is important to note that these differences also apply to HIP code compilation. + +Predefined Macros for Differentiation +------------------------------------- + +To facilitate differentiation between HIP and CUDA code, as well as between device and host compilations within HIP, Clang defines specific macros: + +- ``__HIP__`` : This macro is defined only when compiling HIP code. It can be used to conditionally compile code specific to HIP, enabling developers to write portable code that can be compiled for both CUDA and HIP. + +- ``__HIP_DEVICE_COMPILE__`` : Defined exclusively during HIP device compilation, this macro allows for conditional compilation of device-specific code. It provides a mechanism to segregate device and host code, ensuring that each can be optimized for their respective execution environments. + Function Pointers Support ========================= diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 7b23e4d1c2f30c1544b2eba17b2a53849a6bc6a9..05c8f765b556951a51febff0515b5b4904fec2c3 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1493,6 +1493,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 +``= delete ("should have a reason");`` __cpp_deleted_function C++26 C++03 -------------------------------------------- -------------------------------- ------------- ------------- Designated initializers (N494) C99 C89 Array & element qualification (N2607) C23 C89 @@ -1610,6 +1611,7 @@ The following type trait primitives are supported by Clang. Those traits marked * ``__is_pod`` (C++, GNU, Microsoft, Embarcadero): Note, the corresponding standard trait was deprecated in C++20. * ``__is_pointer`` (C++, Embarcadero) +* ``__is_pointer_interconvertible_base_of`` (C++, GNU, Microsoft) * ``__is_polymorphic`` (C++, GNU, Microsoft, Embarcadero) * ``__is_reference`` (C++, Embarcadero) * ``__is_referenceable`` (C++, GNU, Microsoft, Embarcadero): diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 28e8ddb3c41c3e9fb87cda31b1a0e4b7897b69c0..de5fa99bff5dbe7e0f42385ca707629f6b204360 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -98,7 +98,8 @@ C++20 Feature Support behavior can use the flag '-Xclang -fno-skip-odr-check-in-gmf'. (#GH79240). -- Implemented the `__is_layout_compatible` intrinsic to support +- Implemented the `__is_layout_compatible` and `__is_pointer_interconvertible_base_of` + intrinsics to support `P0466R5: Layout-compatibility and Pointer-interconvertibility Traits `_. - Clang now implements [module.import]p7 fully. Clang now will import module @@ -110,6 +111,10 @@ C++20 Feature Support templates (`P1814R0 `_). (#GH54051). +- We have sufficient confidence and experience with the concepts implementation + to update the ``__cpp_concepts`` macro to `202002L`. This enables + ```` from libstdc++ to work correctly with Clang. + C++23 Feature Support ^^^^^^^^^^^^^^^^^^^^^ @@ -124,6 +129,8 @@ C++2c Feature Support - Implemented `P2662R3 Pack Indexing `_. +- Implemented `P2573R2: = delete("should have a reason"); `_ + Resolutions to C++ Defect Reports ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -143,6 +150,9 @@ Resolutions to C++ Defect Reports compatibility of two types. (`CWG2759: [[no_unique_address] and common initial sequence `_). +- Clang now diagnoses declarative nested-name-specifiers with pack-index-specifiers. + (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers `_). + C Language Changes ------------------ @@ -198,6 +208,10 @@ Non-comprehensive list of changes in this release New Compiler Flags ------------------ +- ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and + sign change. +- ``-fsanitize=implicit-integer-conversion`` a group that replaces the previous + group ``-fsanitize=implicit-conversion``. - ``-Wmissing-designated-field-initializers``, grouped under ``-Wmissing-field-initializers``. This diagnostic can be disabled to make ``-Wmissing-field-initializers`` behave @@ -211,6 +225,9 @@ Modified Compiler Flags - Added a new diagnostic flag ``-Wreturn-mismatch`` which is grouped under ``-Wreturn-type``, and moved some of the diagnostics previously controlled by ``-Wreturn-type`` under this new flag. Fixes #GH72116. +- ``-fsanitize=implicit-conversion`` is now a group for both + ``-fsanitize=implicit-integer-conversion`` and + ``-fsanitize=implicit-bitfield-conversion``. - Added ``-Wcast-function-type-mismatch`` under the ``-Wcast-function-type`` warning group. Moved the diagnostic previously controlled by @@ -341,11 +358,23 @@ Improvements to Clang's diagnostics (with initializer) entirely consist the condition expression of a if/while/for construct but are not actually used in the body of the if/while/for construct. Fixes #GH41447 +- Clang emits a diagnostic when a tentative array definition is assumed to have + a single element, but that diagnostic was never given a diagnostic group. + Added the ``-Wtentative-definition-array`` warning group to cover this. + Fixes #GH87766 + +- Clang now uses the correct type-parameter-key (``class`` or ``typename``) when printing + template template parameter declarations. + Improvements to Clang's time-trace ---------------------------------- Bug Fixes in This Version ------------------------- +- Clang's ``-Wundefined-func-template`` no longer warns on pure virtual + functions. + (`#74016 `_) + - Fixed missing warnings when comparing mismatched enumeration constants in C (`#29217 `). @@ -504,10 +533,15 @@ Bug Fixes to C++ Support - Fix crash when inheriting from a cv-qualified type. Fixes: (`#35603 `_) - Fix a crash when the using enum declaration uses an anonymous enumeration. Fixes (#GH86790). +- Handled an edge case in ``getFullyPackExpandedSize`` so that we now avoid a false-positive diagnostic. (#GH84220) +- Clang now correctly tracks type dependence of by-value captures in lambdas with an explicit + object parameter. + Fixes (#GH70604), (#GH79754), (#GH84163), (#GH84425), (#GH86054), (#GH86398), and (#GH86399). Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ - Clang now properly preserves ``FoundDecls`` within a ``ConceptReference``. (#GH82628) +- The presence of the ``typename`` keyword is now stored in ``TemplateTemplateParmDecl``. Miscellaneous Bug Fixes ^^^^^^^^^^^^^^^^^^^^^^^ @@ -622,10 +656,14 @@ Fixed Point Support in Clang AST Matchers ------------ +- Fixes a long-standing performance issue in parent map generation for + ancestry-based matchers such as ``hasParent`` and ``hasAncestor``, making + them significantly faster. - ``isInStdNamespace`` now supports Decl declared with ``extern "C++"``. - Add ``isExplicitObjectMemberFunction``. - Fixed ``forEachArgumentWithParam`` and ``forEachArgumentWithParamType`` to not skip the explicit object parameter for operator calls. +- Fixed captureVars assertion failure if not capturesVariables. (#GH76425) clang-format ------------ diff --git a/clang/docs/UndefinedBehaviorSanitizer.rst b/clang/docs/UndefinedBehaviorSanitizer.rst index 8f58c92bd2a1634f50e357905ba7b4738e36b64a..531d56e313826c766e0d8b7c5a41c4792dca1c2f 100644 --- a/clang/docs/UndefinedBehaviorSanitizer.rst +++ b/clang/docs/UndefinedBehaviorSanitizer.rst @@ -148,6 +148,11 @@ Available checks are: Issues caught by this sanitizer are not undefined behavior, but are often unintentional. - ``-fsanitize=integer-divide-by-zero``: Integer division by zero. + - ``-fsanitize=implicit-bitfield-conversion``: Implicit conversion from + integer of larger bit width to smaller bitfield, if that results in data + loss. This includes unsigned/signed truncations and sign changes, similarly + to how the ``-fsanitize=implicit-integer-conversion`` group works, but + explicitly for bitfields. - ``-fsanitize=nonnull-attribute``: Passing null pointer as a function parameter which is declared to never be null. - ``-fsanitize=null``: Use of a null pointer or creation of a null @@ -193,8 +198,8 @@ Available checks are: signed division overflow (``INT_MIN/-1``). Note that checks are still added even when ``-fwrapv`` is enabled. This sanitizer does not check for lossy implicit conversions performed before the computation (see - ``-fsanitize=implicit-conversion``). Both of these two issues are handled - by ``-fsanitize=implicit-conversion`` group of checks. + ``-fsanitize=implicit-integer-conversion``). Both of these two issues are handled + by ``-fsanitize=implicit-integer-conversion`` group of checks. - ``-fsanitize=unreachable``: If control flow reaches an unreachable program point. - ``-fsanitize=unsigned-integer-overflow``: Unsigned integer overflow, where @@ -202,7 +207,7 @@ Available checks are: type. Unlike signed integer overflow, this is not undefined behavior, but it is often unintentional. This sanitizer does not check for lossy implicit conversions performed before such a computation - (see ``-fsanitize=implicit-conversion``). + (see ``-fsanitize=implicit-integer-conversion``). - ``-fsanitize=vla-bound``: A variable-length array whose bound does not evaluate to a positive value. - ``-fsanitize=vptr``: Use of an object whose vptr indicates that it is of @@ -224,11 +229,15 @@ You can also use the following check groups: - ``-fsanitize=implicit-integer-arithmetic-value-change``: Catches implicit conversions that change the arithmetic value of the integer. Enables ``implicit-signed-integer-truncation`` and ``implicit-integer-sign-change``. - - ``-fsanitize=implicit-conversion``: Checks for suspicious - behavior of implicit conversions. Enables + - ``-fsanitize=implicit-integer-conversion``: Checks for suspicious + behavior of implicit integer conversions. Enables ``implicit-unsigned-integer-truncation``, ``implicit-signed-integer-truncation``, and ``implicit-integer-sign-change``. + - ``-fsanitize=implicit-conversion``: Checks for suspicious + behavior of implicit conversions. Enables + ``implicit-integer-conversion``, and + ``implicit-bitfield-conversion``. - ``-fsanitize=integer``: Checks for undefined or suspicious integer behavior (e.g. unsigned integer overflow). Enables ``signed-integer-overflow``, ``unsigned-integer-overflow``, diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index f188f18ba5557e48efe4b5586e93cf90e1b1fafe..fb748d23a53d01ce04c607f38d605c3ac7b26de8 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -3138,10 +3138,16 @@ are detected: allowed in this state. * Invalid 3rd ("``whence``") argument to ``fseek``. -The checker does not track the correspondence between integer file descriptors -and ``FILE *`` pointers. Operations on standard streams like ``stdin`` are not -treated specially and are therefore often not recognized (because these streams -are usually not opened explicitly by the program, and are global variables). +The stream operations are by this checker usually split into two cases, a success +and a failure case. However, in the case of write operations (like ``fwrite``, +``fprintf`` and even ``fsetpos``) this behavior could produce a large amount of +unwanted reports on projects that don't have error checks around the write +operations, so by default the checker assumes that write operations always succeed. +This behavior can be controlled by the ``Pedantic`` flag: With +``-analyzer-config alpha.unix.Stream:Pedantic=true`` the checker will model the +cases where a write operation fails and report situations where this leads to +erroneous behavior. (The default is ``Pedantic=false``, where write operations +are assumed to succeed.) .. code-block:: c @@ -3196,6 +3202,13 @@ are usually not opened explicitly by the program, and are global variables). fclose(p); } +**Limitations** + +The checker does not track the correspondence between integer file descriptors +and ``FILE *`` pointers. Operations on standard streams like ``stdin`` are not +treated specially and are therefore often not recognized (because these streams +are usually not opened explicitly by the program, and are global variables). + .. _alpha-unix-cstring-BufferOverlap: alpha.unix.cstring.BufferOverlap (C) diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt index 70687c23b15e61e3417ff09cf32b78781b7e9c18..3089438c23d94e73b580ffb6442e7735a259e41e 100644 --- a/clang/docs/tools/clang-formatted-files.txt +++ b/clang/docs/tools/clang-formatted-files.txt @@ -123,7 +123,6 @@ clang/include/clang/Analysis/Analyses/CalledOnceCheck.h clang/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h clang/include/clang/Analysis/FlowSensitive/AdornedCFG.h -clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -2147,8 +2146,10 @@ flang/include/flang/Parser/message.h flang/include/flang/Parser/parse-state.h flang/include/flang/Parser/parse-tree-visitor.h flang/include/flang/Parser/parsing.h +flang/include/flang/Parser/preprocessor.h flang/include/flang/Parser/provenance.h flang/include/flang/Parser/source.h +flang/include/flang/Parser/token-sequence.h flang/include/flang/Parser/tools.h flang/include/flang/Parser/unparse.h flang/include/flang/Parser/user-state.h @@ -2319,7 +2320,6 @@ flang/lib/Parser/openmp-parsers.cpp flang/lib/Parser/parse-tree.cpp flang/lib/Parser/parsing.cpp flang/lib/Parser/preprocessor.cpp -flang/lib/Parser/preprocessor.h flang/lib/Parser/prescan.cpp flang/lib/Parser/prescan.h flang/lib/Parser/program-parsers.cpp @@ -2328,7 +2328,6 @@ flang/lib/Parser/source.cpp flang/lib/Parser/stmt-parser.h flang/lib/Parser/token-parsers.h flang/lib/Parser/token-sequence.cpp -flang/lib/Parser/token-sequence.h flang/lib/Parser/tools.cpp flang/lib/Parser/type-parser-implementation.h flang/lib/Parser/type-parsers.h diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 08f71051e6cbf32c20830d2503f8c511099f8908..28f8d67811f0a2517fba976008f0849b4793f25a 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -3411,13 +3411,13 @@ const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, /// Utility function for constructing a nullary selector. inline Selector GetNullarySelector(StringRef name, ASTContext &Ctx) { - IdentifierInfo* II = &Ctx.Idents.get(name); + const IdentifierInfo *II = &Ctx.Idents.get(name); return Ctx.Selectors.getSelector(0, &II); } /// Utility function for constructing an unary selector. inline Selector GetUnarySelector(StringRef name, ASTContext &Ctx) { - IdentifierInfo* II = &Ctx.Idents.get(name); + const IdentifierInfo *II = &Ctx.Idents.get(name); return Ctx.Selectors.getSelector(1, &II); } diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 94e7dd817809dd2e09c34ed71f819ddccc13db63..f5c47d8a7c2113ab5e3303fda5e86dbb27f029d2 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -243,7 +243,8 @@ public: void Visit(const OpenACCClause *C) { getNodeDelegate().AddChild([=] { getNodeDelegate().Visit(C); - // TODO OpenACC: Switch on clauses that have children, and add them. + for (const auto *S : C->children()) + Visit(S); }); } @@ -932,6 +933,14 @@ public: Visit(TArg); } + void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node) { + Visit(Node->getExpr()); + } + + void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node) { + Visit(Node->getExpr()); + } + // Implements Visit methods for Attrs. #include "clang/AST/AttrNodeTraverse.inc" }; diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 5f1f83bb00282f016a615e3821848af628394d81..01af50ca694fdd8611bd3bb08573d9fe1622d6b7 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1731,7 +1731,7 @@ public: static ImplicitParamDecl *CreateDeserialized(ASTContext &C, unsigned ID); ImplicitParamDecl(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, - IdentifierInfo *Id, QualType Type, + const IdentifierInfo *Id, QualType Type, ImplicitParamKind ParamKind) : VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type, /*TInfo=*/nullptr, SC_None) { @@ -1765,7 +1765,7 @@ public: protected: ParmVarDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, QualType T, + SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg) : VarDecl(DK, C, DC, StartLoc, IdLoc, Id, T, TInfo, S) { assert(ParmVarDeclBits.HasInheritedDefaultArg == false); @@ -1777,10 +1777,10 @@ protected: public: static ParmVarDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, - StorageClass S, Expr *DefArg); + SourceLocation StartLoc, SourceLocation IdLoc, + const IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, StorageClass S, + Expr *DefArg); static ParmVarDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -1993,21 +1993,35 @@ public: }; - /// Stashed information about a defaulted function definition whose body has - /// not yet been lazily generated. - class DefaultedFunctionInfo final - : llvm::TrailingObjects { + /// Stashed information about a defaulted/deleted function body. + class DefaultedOrDeletedFunctionInfo final + : llvm::TrailingObjects { friend TrailingObjects; unsigned NumLookups; + bool HasDeletedMessage; + + size_t numTrailingObjects(OverloadToken) const { + return NumLookups; + } public: - static DefaultedFunctionInfo *Create(ASTContext &Context, - ArrayRef Lookups); + static DefaultedOrDeletedFunctionInfo * + Create(ASTContext &Context, ArrayRef Lookups, + StringLiteral *DeletedMessage = nullptr); + /// Get the unqualified lookup results that should be used in this /// defaulted function definition. ArrayRef getUnqualifiedLookups() const { return {getTrailingObjects(), NumLookups}; } + + StringLiteral *getDeletedMessage() const { + return HasDeletedMessage ? *getTrailingObjects() + : nullptr; + } + + void setDeletedMessage(StringLiteral *Message); }; private: @@ -2017,12 +2031,12 @@ private: ParmVarDecl **ParamInfo = nullptr; /// The active member of this union is determined by - /// FunctionDeclBits.HasDefaultedFunctionInfo. + /// FunctionDeclBits.HasDefaultedOrDeletedInfo. union { /// The body of the function. LazyDeclStmtPtr Body; /// Information about a future defaulted function definition. - DefaultedFunctionInfo *DefaultedInfo; + DefaultedOrDeletedFunctionInfo *DefaultedOrDeletedInfo; }; unsigned ODRHash; @@ -2280,18 +2294,18 @@ public: /// Returns whether this specific declaration of the function has a body. bool doesThisDeclarationHaveABody() const { - return (!FunctionDeclBits.HasDefaultedFunctionInfo && Body) || + return (!FunctionDeclBits.HasDefaultedOrDeletedInfo && Body) || isLateTemplateParsed(); } void setBody(Stmt *B); void setLazyBody(uint64_t Offset) { - FunctionDeclBits.HasDefaultedFunctionInfo = false; + FunctionDeclBits.HasDefaultedOrDeletedInfo = false; Body = LazyDeclStmtPtr(Offset); } - void setDefaultedFunctionInfo(DefaultedFunctionInfo *Info); - DefaultedFunctionInfo *getDefaultedFunctionInfo() const; + void setDefaultedOrDeletedInfo(DefaultedOrDeletedFunctionInfo *Info); + DefaultedOrDeletedFunctionInfo *getDefalutedOrDeletedInfo() const; /// Whether this function is variadic. bool isVariadic() const; @@ -2494,7 +2508,7 @@ public: return FunctionDeclBits.IsDeleted && !isDefaulted(); } - void setDeletedAsWritten(bool D = true) { FunctionDeclBits.IsDeleted = D; } + void setDeletedAsWritten(bool D = true, StringLiteral *Message = nullptr); /// Determines whether this function is "main", which is the /// entry point into an executable program. @@ -2650,6 +2664,13 @@ public: AC.push_back(TRC); } + /// Get the message that indicates why this function was deleted. + StringLiteral *getDeletedMessage() const { + return FunctionDeclBits.HasDefaultedOrDeletedInfo + ? DefaultedOrDeletedInfo->getDeletedMessage() + : nullptr; + } + void setPreviousDeclaration(FunctionDecl * PrevDecl); FunctionDecl *getCanonicalDecl() override; @@ -3095,7 +3116,7 @@ class FieldDecl : public DeclaratorDecl, public Mergeable { protected: FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, QualType T, + SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle) : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), BitField(false), @@ -3111,7 +3132,7 @@ public: static FieldDecl *Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, QualType T, + const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle); @@ -3332,8 +3353,9 @@ public: friend class ASTDeclReader; static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - QualType T, llvm::MutableArrayRef CH); + SourceLocation L, const IdentifierInfo *Id, + QualType T, + llvm::MutableArrayRef CH); static IndirectFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -3381,9 +3403,9 @@ class TypeDecl : public NamedDecl { void anchor() override; protected: - TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, const IdentifierInfo *Id, SourceLocation StartL = SourceLocation()) - : NamedDecl(DK, DC, L, Id), LocStart(StartL) {} + : NamedDecl(DK, DC, L, Id), LocStart(StartL) {} public: // Low-level accessor. If you just want the type defined by this node, @@ -3425,7 +3447,7 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable { protected: TypedefNameDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, TypeSourceInfo *TInfo) + const IdentifierInfo *Id, TypeSourceInfo *TInfo) : TypeDecl(DK, DC, IdLoc, Id, StartLoc), redeclarable_base(C), MaybeModedTInfo(TInfo, 0) {} @@ -3512,13 +3534,14 @@ private: /// type specifier. class TypedefDecl : public TypedefNameDecl { TypedefDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) + SourceLocation IdLoc, const IdentifierInfo *Id, + TypeSourceInfo *TInfo) : TypedefNameDecl(Typedef, C, DC, StartLoc, IdLoc, Id, TInfo) {} public: static TypedefDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, TypeSourceInfo *TInfo); + const IdentifierInfo *Id, TypeSourceInfo *TInfo); static TypedefDecl *CreateDeserialized(ASTContext &C, unsigned ID); SourceRange getSourceRange() const override LLVM_READONLY; @@ -3535,14 +3558,15 @@ class TypeAliasDecl : public TypedefNameDecl { TypeAliasTemplateDecl *Template; TypeAliasDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) + SourceLocation IdLoc, const IdentifierInfo *Id, + TypeSourceInfo *TInfo) : TypedefNameDecl(TypeAlias, C, DC, StartLoc, IdLoc, Id, TInfo), Template(nullptr) {} public: static TypeAliasDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, TypeSourceInfo *TInfo); + const IdentifierInfo *Id, TypeSourceInfo *TInfo); static TypeAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID); SourceRange getSourceRange() const override LLVM_READONLY; diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 858450926455c602030671323257a4470bc096f7..2194d268fa86f0918112cec6d8e7301eeb6d97f3 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -1739,7 +1739,7 @@ class DeclContext { LLVM_PREFERRED_TYPE(bool) uint64_t IsExplicitlyDefaulted : 1; LLVM_PREFERRED_TYPE(bool) - uint64_t HasDefaultedFunctionInfo : 1; + uint64_t HasDefaultedOrDeletedInfo : 1; /// For member functions of complete types, whether this is an ineligible /// special member function or an unselected destructor. See diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index f8f894b4b10d1919a484eae6b14adf45517166ea..b8d17dd06d1550082446496c9d02ef5fa9c759a5 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -772,7 +772,7 @@ private: // Synthesize ivar for this property ObjCIvarDecl *PropertyIvarDecl = nullptr; - ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + ObjCPropertyDecl(DeclContext *DC, SourceLocation L, const IdentifierInfo *Id, SourceLocation AtLocation, SourceLocation LParenLocation, QualType T, TypeSourceInfo *TSI, PropertyControl propControl) : NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation), @@ -782,10 +782,12 @@ private: PropertyImplementation(propControl) {} public: - static ObjCPropertyDecl * - Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - SourceLocation AtLocation, SourceLocation LParenLocation, QualType T, - TypeSourceInfo *TSI, PropertyControl propControl = None); + static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, const IdentifierInfo *Id, + SourceLocation AtLocation, + SourceLocation LParenLocation, QualType T, + TypeSourceInfo *TSI, + PropertyControl propControl = None); static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -952,7 +954,7 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext { void anchor() override; public: - ObjCContainerDecl(Kind DK, DeclContext *DC, IdentifierInfo *Id, + ObjCContainerDecl(Kind DK, DeclContext *DC, const IdentifierInfo *Id, SourceLocation nameLoc, SourceLocation atStartLoc); // Iterator access to instance/class properties. @@ -1240,7 +1242,7 @@ class ObjCInterfaceDecl : public ObjCContainerDecl llvm::PointerIntPair Data; ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc, - IdentifierInfo *Id, ObjCTypeParamList *typeParamList, + const IdentifierInfo *Id, ObjCTypeParamList *typeParamList, SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl, bool IsInternal); @@ -1271,13 +1273,11 @@ class ObjCInterfaceDecl : public ObjCContainerDecl } public: - static ObjCInterfaceDecl *Create(const ASTContext &C, DeclContext *DC, - SourceLocation atLoc, - IdentifierInfo *Id, - ObjCTypeParamList *typeParamList, - ObjCInterfaceDecl *PrevDecl, - SourceLocation ClassLoc = SourceLocation(), - bool isInternal = false); + static ObjCInterfaceDecl * + Create(const ASTContext &C, DeclContext *DC, SourceLocation atLoc, + const IdentifierInfo *Id, ObjCTypeParamList *typeParamList, + ObjCInterfaceDecl *PrevDecl, + SourceLocation ClassLoc = SourceLocation(), bool isInternal = false); static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C, unsigned ID); @@ -1338,7 +1338,8 @@ public: ObjCImplementationDecl *getImplementation() const; void setImplementation(ObjCImplementationDecl *ImplD); - ObjCCategoryDecl *FindCategoryDeclaration(IdentifierInfo *CategoryId) const; + ObjCCategoryDecl * + FindCategoryDeclaration(const IdentifierInfo *CategoryId) const; // Get the local instance/class method declared in a category. ObjCMethodDecl *getCategoryInstanceMethod(Selector Sel) const; @@ -1794,9 +1795,9 @@ public: data().CategoryList = category; } - ObjCPropertyDecl - *FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId, - ObjCPropertyQueryKind QueryKind) const; + ObjCPropertyDecl * + FindPropertyVisibleInPrimaryClass(const IdentifierInfo *PropertyId, + ObjCPropertyQueryKind QueryKind) const; void collectPropertiesToImplement(PropertyMap &PM) const override; @@ -1954,8 +1955,8 @@ public: private: ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, + SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, bool synthesized) : FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW, /*Mutable=*/false, /*HasInit=*/ICIS_NoInit), @@ -1964,10 +1965,9 @@ private: public: static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, QualType T, - TypeSourceInfo *TInfo, - AccessControl ac, Expr *BW = nullptr, - bool synthesized=false); + const IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, AccessControl ac, + Expr *BW = nullptr, bool synthesized = false); static ObjCIvarDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -2343,7 +2343,7 @@ class ObjCCategoryDecl : public ObjCContainerDecl { ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc, SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, - IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, + const IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, ObjCTypeParamList *typeParamList, SourceLocation IvarLBraceLoc = SourceLocation(), SourceLocation IvarRBraceLoc = SourceLocation()); @@ -2354,15 +2354,13 @@ public: friend class ASTDeclReader; friend class ASTDeclWriter; - static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation AtLoc, - SourceLocation ClassNameLoc, - SourceLocation CategoryNameLoc, - IdentifierInfo *Id, - ObjCInterfaceDecl *IDecl, - ObjCTypeParamList *typeParamList, - SourceLocation IvarLBraceLoc=SourceLocation(), - SourceLocation IvarRBraceLoc=SourceLocation()); + static ObjCCategoryDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation AtLoc, + SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, + const IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, + ObjCTypeParamList *typeParamList, + SourceLocation IvarLBraceLoc = SourceLocation(), + SourceLocation IvarRBraceLoc = SourceLocation()); static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID); ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } @@ -2472,10 +2470,9 @@ class ObjCImplDecl : public ObjCContainerDecl { void anchor() override; protected: - ObjCImplDecl(Kind DK, DeclContext *DC, - ObjCInterfaceDecl *classInterface, - IdentifierInfo *Id, - SourceLocation nameLoc, SourceLocation atStartLoc) + ObjCImplDecl(Kind DK, DeclContext *DC, ObjCInterfaceDecl *classInterface, + const IdentifierInfo *Id, SourceLocation nameLoc, + SourceLocation atStartLoc) : ObjCContainerDecl(DK, DC, Id, nameLoc, atStartLoc), ClassInterface(classInterface) {} @@ -2543,12 +2540,12 @@ class ObjCCategoryImplDecl : public ObjCImplDecl { // Category name location SourceLocation CategoryNameLoc; - ObjCCategoryImplDecl(DeclContext *DC, IdentifierInfo *Id, + ObjCCategoryImplDecl(DeclContext *DC, const IdentifierInfo *Id, ObjCInterfaceDecl *classInterface, SourceLocation nameLoc, SourceLocation atStartLoc, SourceLocation CategoryNameLoc) - : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id, - nameLoc, atStartLoc), + : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id, nameLoc, + atStartLoc), CategoryNameLoc(CategoryNameLoc) {} void anchor() override; @@ -2557,12 +2554,10 @@ public: friend class ASTDeclReader; friend class ASTDeclWriter; - static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC, - IdentifierInfo *Id, - ObjCInterfaceDecl *classInterface, - SourceLocation nameLoc, - SourceLocation atStartLoc, - SourceLocation CategoryNameLoc); + static ObjCCategoryImplDecl * + Create(ASTContext &C, DeclContext *DC, const IdentifierInfo *Id, + ObjCInterfaceDecl *classInterface, SourceLocation nameLoc, + SourceLocation atStartLoc, SourceLocation CategoryNameLoc); static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, unsigned ID); ObjCCategoryDecl *getCategoryDecl() const; diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index e3b6a7efb1127af56d594d8299f49a21ed38a43f..f24e71ff229648d80336e76faef5abbe850a0fe9 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1389,14 +1389,14 @@ class NonTypeTemplateParmDecl final NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, unsigned D, unsigned P, - IdentifierInfo *Id, QualType T, + const IdentifierInfo *Id, QualType T, bool ParameterPack, TypeSourceInfo *TInfo) : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc), TemplateParmPosition(D, P), ParameterPack(ParameterPack) {} NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, unsigned D, unsigned P, - IdentifierInfo *Id, QualType T, + const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, ArrayRef ExpandedTypes, ArrayRef ExpandedTInfos); @@ -1404,12 +1404,12 @@ class NonTypeTemplateParmDecl final public: static NonTypeTemplateParmDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, + SourceLocation IdLoc, unsigned D, unsigned P, const IdentifierInfo *Id, QualType T, bool ParameterPack, TypeSourceInfo *TInfo); static NonTypeTemplateParmDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, + SourceLocation IdLoc, unsigned D, unsigned P, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, ArrayRef ExpandedTypes, ArrayRef ExpandedTInfos); @@ -1581,26 +1581,36 @@ class TemplateTemplateParmDecl final DefaultArgStorage; DefArgStorage DefaultArgument; + /// Whether this template template parameter was declaration with + /// the 'typename' keyword. + /// + /// If false, it was declared with the 'class' keyword. + LLVM_PREFERRED_TYPE(bool) + unsigned Typename : 1; + /// Whether this parameter is a parameter pack. - bool ParameterPack; + LLVM_PREFERRED_TYPE(bool) + unsigned ParameterPack : 1; /// Whether this template template parameter is an "expanded" /// parameter pack, meaning that it is a pack expansion and we /// already know the set of template parameters that expansion expands to. - bool ExpandedParameterPack = false; + LLVM_PREFERRED_TYPE(bool) + unsigned ExpandedParameterPack : 1; /// The number of parameters in an expanded parameter pack. unsigned NumExpandedParams = 0; - TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, - unsigned D, unsigned P, bool ParameterPack, - IdentifierInfo *Id, TemplateParameterList *Params) + TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, + unsigned P, bool ParameterPack, IdentifierInfo *Id, + bool Typename, TemplateParameterList *Params) : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), - TemplateParmPosition(D, P), ParameterPack(ParameterPack) {} + TemplateParmPosition(D, P), Typename(Typename), + ParameterPack(ParameterPack), ExpandedParameterPack(false) {} - TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, - unsigned D, unsigned P, - IdentifierInfo *Id, TemplateParameterList *Params, + TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, + unsigned P, IdentifierInfo *Id, bool Typename, + TemplateParameterList *Params, ArrayRef Expansions); void anchor() override; @@ -1613,14 +1623,13 @@ public: static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, bool ParameterPack, - IdentifierInfo *Id, + IdentifierInfo *Id, bool Typename, TemplateParameterList *Params); - static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC, - SourceLocation L, unsigned D, - unsigned P, - IdentifierInfo *Id, - TemplateParameterList *Params, - ArrayRef Expansions); + static TemplateTemplateParmDecl * + Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, + unsigned P, IdentifierInfo *Id, bool Typename, + TemplateParameterList *Params, + ArrayRef Expansions); static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -1634,6 +1643,14 @@ public: using TemplateParmPosition::setPosition; using TemplateParmPosition::getIndex; + /// Whether this template template parameter was declared with + /// the 'typename' keyword. + bool wasDeclaredWithTypename() const { return Typename; } + + /// Set whether this template template parameter was declared with + /// the 'typename' or 'class' keyword. + void setDeclaredWithTypename(bool withTypename) { Typename = withTypename; } + /// Whether this template template parameter is a template /// parameter pack. /// diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 6003b866c9f564519006077b3618fc324bd09bef..d28e5c3a78ee4bbb9c76ddb2d229a9d99372ab19 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -1149,6 +1149,7 @@ class CXXThisExpr : public Expr { CXXThisExpr(SourceLocation L, QualType Ty, bool IsImplicit, ExprValueKind VK) : Expr(CXXThisExprClass, Ty, VK, OK_Ordinary) { CXXThisExprBits.IsImplicit = IsImplicit; + CXXThisExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter = false; CXXThisExprBits.Loc = L; setDependence(computeDependence(this)); } @@ -1170,6 +1171,15 @@ public: bool isImplicit() const { return CXXThisExprBits.IsImplicit; } void setImplicit(bool I) { CXXThisExprBits.IsImplicit = I; } + bool isCapturedByCopyInLambdaWithExplicitObjectParameter() const { + return CXXThisExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter; + } + + void setCapturedByCopyInLambdaWithExplicitObjectParameter(bool Set) { + CXXThisExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter = Set; + setDependence(computeDependence(this)); + } + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXThisExprClass; } @@ -2549,7 +2559,7 @@ public: class PseudoDestructorTypeStorage { /// Either the type source information or the name of the type, if /// it couldn't be resolved due to type-dependence. - llvm::PointerUnion Type; + llvm::PointerUnion Type; /// The starting source location of the pseudo-destructor type. SourceLocation Location; @@ -2557,7 +2567,7 @@ class PseudoDestructorTypeStorage { public: PseudoDestructorTypeStorage() = default; - PseudoDestructorTypeStorage(IdentifierInfo *II, SourceLocation Loc) + PseudoDestructorTypeStorage(const IdentifierInfo *II, SourceLocation Loc) : Type(II), Location(Loc) {} PseudoDestructorTypeStorage(TypeSourceInfo *Info); @@ -2566,8 +2576,8 @@ public: return Type.dyn_cast(); } - IdentifierInfo *getIdentifier() const { - return Type.dyn_cast(); + const IdentifierInfo *getIdentifier() const { + return Type.dyn_cast(); } SourceLocation getLocation() const { return Location; } @@ -2698,7 +2708,7 @@ public: /// In a dependent pseudo-destructor expression for which we do not /// have full type information on the destroyed type, provides the name /// of the destroyed type. - IdentifierInfo *getDestroyedTypeIdentifier() const { + const IdentifierInfo *getDestroyedTypeIdentifier() const { return DestroyedType.getIdentifier(); } diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h index 8e573965b0a3360c2f70ea4cd95ec85fa718f925..230c83943c2224469f59e40d5eb264a262e453d3 100644 --- a/clang/include/clang/AST/ExternalASTSource.h +++ b/clang/include/clang/AST/ExternalASTSource.h @@ -138,7 +138,7 @@ public: virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset); /// Update an out-of-date identifier. - virtual void updateOutOfDateIdentifier(IdentifierInfo &II) {} + virtual void updateOutOfDateIdentifier(const IdentifierInfo &II) {} /// Find all declarations with the given name in the given context, /// and add them to the context by calling SetExternalVisibleDeclsForName diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h index 7a60f362650ca0a939a03acb390bef7ae887eb57..55bd583e304e8b515b93fadb3b7da4664efabb5c 100644 --- a/clang/include/clang/AST/JSONNodeDumper.h +++ b/clang/include/clang/AST/JSONNodeDumper.h @@ -310,6 +310,8 @@ public: void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE); void VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *ME); void VisitRequiresExpr(const RequiresExpr *RE); + void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node); + void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node); void VisitObjCEncodeExpr(const ObjCEncodeExpr *OEE); void VisitObjCMessageExpr(const ObjCMessageExpr *OME); diff --git a/clang/include/clang/AST/NestedNameSpecifier.h b/clang/include/clang/AST/NestedNameSpecifier.h index 3b6cf97211850925e4b2392b56a1d88a16612161..7b0c21b9e7cfb1515789809bee50566bedbad480 100644 --- a/clang/include/clang/AST/NestedNameSpecifier.h +++ b/clang/include/clang/AST/NestedNameSpecifier.h @@ -124,7 +124,7 @@ public: /// cannot be resolved. static NestedNameSpecifier *Create(const ASTContext &Context, NestedNameSpecifier *Prefix, - IdentifierInfo *II); + const IdentifierInfo *II); /// Builds a nested name specifier that names a namespace. static NestedNameSpecifier *Create(const ASTContext &Context, @@ -134,7 +134,7 @@ public: /// Builds a nested name specifier that names a namespace alias. static NestedNameSpecifier *Create(const ASTContext &Context, NestedNameSpecifier *Prefix, - NamespaceAliasDecl *Alias); + const NamespaceAliasDecl *Alias); /// Builds a nested name specifier that names a type. static NestedNameSpecifier *Create(const ASTContext &Context, @@ -148,7 +148,7 @@ public: /// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent /// type. static NestedNameSpecifier *Create(const ASTContext &Context, - IdentifierInfo *II); + const IdentifierInfo *II); /// Returns the nested name specifier representing the global /// scope. diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h index 06a0098bbda4cdbfd675eb7a8fb66770058fb1fa..401b8e904a1b7ae17dc76ae3735557d053d10669 100644 --- a/clang/include/clang/AST/OpenACCClause.h +++ b/clang/include/clang/AST/OpenACCClause.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_AST_OPENACCCLAUSE_H #define LLVM_CLANG_AST_OPENACCCLAUSE_H #include "clang/AST/ASTContext.h" +#include "clang/AST/StmtIterator.h" #include "clang/Basic/OpenACCKinds.h" namespace clang { @@ -34,6 +35,17 @@ public: static bool classof(const OpenACCClause *) { return true; } + using child_iterator = StmtIterator; + using const_child_iterator = ConstStmtIterator; + using child_range = llvm::iterator_range; + using const_child_range = llvm::iterator_range; + + child_range children(); + const_child_range children() const { + auto Children = const_cast(this)->children(); + return const_child_range(Children.begin(), Children.end()); + } + virtual ~OpenACCClause() = default; }; @@ -49,6 +61,88 @@ protected: public: SourceLocation getLParenLoc() const { return LParenLoc; } + + child_range children() { + return child_range(child_iterator(), child_iterator()); + } + const_child_range children() const { + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + +/// A 'default' clause, has the optional 'none' or 'present' argument. +class OpenACCDefaultClause : public OpenACCClauseWithParams { + friend class ASTReaderStmt; + friend class ASTWriterStmt; + + OpenACCDefaultClauseKind DefaultClauseKind; + +protected: + OpenACCDefaultClause(OpenACCDefaultClauseKind K, SourceLocation BeginLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OpenACCClauseWithParams(OpenACCClauseKind::Default, BeginLoc, LParenLoc, + EndLoc), + DefaultClauseKind(K) { + assert((DefaultClauseKind == OpenACCDefaultClauseKind::None || + DefaultClauseKind == OpenACCDefaultClauseKind::Present) && + "Invalid Clause Kind"); + } + +public: + OpenACCDefaultClauseKind getDefaultClauseKind() const { + return DefaultClauseKind; + } + + static OpenACCDefaultClause *Create(const ASTContext &C, + OpenACCDefaultClauseKind K, + SourceLocation BeginLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); +}; + +/// Represents one of the handful of classes that has an optional/required +/// 'condition' expression as an argument. +class OpenACCClauseWithCondition : public OpenACCClauseWithParams { + Expr *ConditionExpr = nullptr; + +protected: + OpenACCClauseWithCondition(OpenACCClauseKind K, SourceLocation BeginLoc, + SourceLocation LParenLoc, Expr *ConditionExpr, + SourceLocation EndLoc) + : OpenACCClauseWithParams(K, BeginLoc, LParenLoc, EndLoc), + ConditionExpr(ConditionExpr) {} + +public: + bool hasConditionExpr() const { return ConditionExpr; } + const Expr *getConditionExpr() const { return ConditionExpr; } + Expr *getConditionExpr() { return ConditionExpr; } + + child_range children() { + if (ConditionExpr) + return child_range(reinterpret_cast(&ConditionExpr), + reinterpret_cast(&ConditionExpr + 1)); + return child_range(child_iterator(), child_iterator()); + } + + const_child_range children() const { + if (ConditionExpr) + return const_child_range( + reinterpret_cast(&ConditionExpr), + reinterpret_cast(&ConditionExpr + 1)); + return const_child_range(const_child_iterator(), const_child_iterator()); + } +}; + +/// An 'if' clause, which has a required condition expression. +class OpenACCIfClause : public OpenACCClauseWithCondition { +protected: + OpenACCIfClause(SourceLocation BeginLoc, SourceLocation LParenLoc, + Expr *ConditionExpr, SourceLocation EndLoc); + +public: + static OpenACCIfClause *Create(const ASTContext &C, SourceLocation BeginLoc, + SourceLocation LParenLoc, Expr *ConditionExpr, + SourceLocation EndLoc); }; template class OpenACCClauseVisitor { @@ -66,6 +160,11 @@ public: switch (C->getClauseKind()) { case OpenACCClauseKind::Default: + VisitDefaultClause(*cast(C)); + return; + case OpenACCClauseKind::If: + VisitIfClause(*cast(C)); + return; case OpenACCClauseKind::Finalize: case OpenACCClauseKind::IfPresent: case OpenACCClauseKind::Seq: @@ -74,7 +173,6 @@ public: case OpenACCClauseKind::Worker: case OpenACCClauseKind::Vector: case OpenACCClauseKind::NoHost: - case OpenACCClauseKind::If: case OpenACCClauseKind::Self: case OpenACCClauseKind::Copy: case OpenACCClauseKind::UseDevice: @@ -112,6 +210,14 @@ public: } llvm_unreachable("Invalid Clause kind"); } + +#define VISIT_CLAUSE(CLAUSE_NAME) \ + void Visit##CLAUSE_NAME##Clause( \ + const OpenACC##CLAUSE_NAME##Clause &Clause) { \ + return getDerived().Visit##CLAUSE_NAME##Clause(Clause); \ + } + +#include "clang/Basic/OpenACCClauses.def" }; class OpenACCClausePrinter final @@ -128,6 +234,10 @@ public: } } OpenACCClausePrinter(raw_ostream &OS) : OS(OS) {} + +#define VISIT_CLAUSE(CLAUSE_NAME) \ + void Visit##CLAUSE_NAME##Clause(const OpenACC##CLAUSE_NAME##Clause &Clause); +#include "clang/Basic/OpenACCClauses.def" }; } // namespace clang diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 8892518d58e853230751cf3cf67d1eaff8258e5d..1b9c9231047717bd32f2c19d77f18264eed512bf 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -784,6 +784,11 @@ protected: LLVM_PREFERRED_TYPE(bool) unsigned IsImplicit : 1; + /// Whether there is a lambda with an explicit object parameter that + /// captures this "this" by copy. + LLVM_PREFERRED_TYPE(bool) + unsigned CapturedByCopyInLambdaWithExplicitObjectParameter : 1; + /// The location of the "this". SourceLocation Loc; }; diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h index 3cb3c1014d73b7526dcfe326f78482ff36e28829..f735fa5643aecf9631d1f5efc26a43c7cafe0866 100644 --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -6109,6 +6109,8 @@ public: class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective { friend class ASTStmtReader; friend class OMPExecutableDirective; + /// true if loop directive's associated loop can be a parallel for. + bool CanBeParallelFor = false; /// Build directive with the given start and end location. /// /// \param StartLoc Starting location of the directive kind. @@ -6131,6 +6133,9 @@ class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective { llvm::omp::OMPD_target_teams_loop, SourceLocation(), SourceLocation(), CollapsedNum) {} + /// Set whether associated loop can be a parallel for. + void setCanBeParallelFor(bool ParFor) { CanBeParallelFor = ParFor; } + public: /// Creates directive with a list of \p Clauses. /// @@ -6145,7 +6150,7 @@ public: static OMPTargetTeamsGenericLoopDirective * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, ArrayRef Clauses, - Stmt *AssociatedStmt, const HelperExprs &Exprs); + Stmt *AssociatedStmt, const HelperExprs &Exprs, bool CanBeParallelFor); /// Creates an empty directive with the place /// for \a NumClauses clauses. @@ -6159,6 +6164,10 @@ public: unsigned CollapsedNum, EmptyShell); + /// Return true if current loop directive's associated loop can be a + /// parallel for. + bool canBeParallelFor() const { return CanBeParallelFor; } + static bool classof(const Stmt *T) { return T->getStmtClass() == OMPTargetTeamsGenericLoopDirectiveClass; } diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 2f71053d030f688f6921d15e265072a8b0cbf759..8a2bbfff9e9e6b0025c5af3cb7d94c0017038efa 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -4961,6 +4961,8 @@ AST_MATCHER_P(LambdaExpr, hasAnyCapture, internal::Matcher, /// capturesVar(hasName("x")) matches `x` and `x = 1`. AST_MATCHER_P(LambdaCapture, capturesVar, internal::Matcher, InnerMatcher) { + if (!Node.capturesVariable()) + return false; auto *capturedVar = Node.getCapturedVar(); return capturedVar && InnerMatcher.matches(*capturedVar, Finder, Builder); } diff --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h deleted file mode 100644 index 3972962d0b2daa681b0cdc99b3e951507e2d61ee..0000000000000000000000000000000000000000 --- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h +++ /dev/null @@ -1,27 +0,0 @@ -//===-- ControlFlowContext.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 a deprecated alias for AdornedCFG. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CONTROLFLOWCONTEXT_H -#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CONTROLFLOWCONTEXT_H - -#include "clang/Analysis/FlowSensitive/AdornedCFG.h" - -namespace clang { -namespace dataflow { - -// This is a deprecated alias. Use `AdornedCFG` instead. -using ControlFlowContext = AdornedCFG; - -} // namespace dataflow -} // namespace clang - -#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CONTROLFLOWCONTEXT_H diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 9a65f76cdf56bcb3de4fb36bc699d904f87e2308..706664d7db1c25b9829a255aa7869c3a5254869c 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -30,6 +30,7 @@ #include "llvm/ADT/MapVector.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include #include #include @@ -344,17 +345,6 @@ public: /// location of the result object to pass in `this`, even though prvalues are /// otherwise not associated with storage locations. /// - /// FIXME: Currently, this simply returns a stable storage location for `E`, - /// but this doesn't do the right thing in scenarios like the following: - /// ``` - /// MyClass c = some_condition()? MyClass(foo) : MyClass(bar); - /// ``` - /// Here, `MyClass(foo)` and `MyClass(bar)` will have two different storage - /// locations, when in fact their storage locations should be the same. - /// Eventually, we want to propagate storage locations from result objects - /// down to the prvalues that initialize them, similar to the way that this is - /// done in Clang's CodeGen. - /// /// Requirements: /// `E` must be a prvalue of record type. RecordStorageLocation & @@ -462,7 +452,13 @@ public: /// Initializes the fields (including synthetic fields) of `Loc` with values, /// unless values of the field type are not supported or we hit one of the /// limits at which we stop producing values. - void initializeFieldsWithValues(RecordStorageLocation &Loc); + /// If `Type` is provided, initializes only those fields that are modeled for + /// `Type`; this is intended for use in cases where `Loc` is a derived type + /// and we only want to initialize the fields of a base type. + void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type); + void initializeFieldsWithValues(RecordStorageLocation &Loc) { + initializeFieldsWithValues(Loc, Loc.getType()); + } /// Assigns `Val` as the value of `Loc` in the environment. void setValue(const StorageLocation &Loc, Value &Val); @@ -653,6 +649,9 @@ public: LLVM_DUMP_METHOD void dump(raw_ostream &OS) const; private: + using PrValueToResultObject = + llvm::DenseMap; + // The copy-constructor is for use in fork() only. Environment(const Environment &) = default; @@ -682,8 +681,10 @@ private: /// Initializes the fields (including synthetic fields) of `Loc` with values, /// unless values of the field type are not supported or we hit one of the /// limits at which we stop producing values (controlled by `Visited`, - /// `Depth`, and `CreatedValuesCount`). - void initializeFieldsWithValues(RecordStorageLocation &Loc, + /// `Depth`, and `CreatedValuesCount`). If `Type` is different from + /// `Loc.getType()`, initializes only those fields that are modeled for + /// `Type`. + void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type, llvm::DenseSet &Visited, int Depth, int &CreatedValuesCount); @@ -702,22 +703,45 @@ private: /// and functions referenced in `FuncDecl`. `FuncDecl` must have a body. void initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl); + static PrValueToResultObject + buildResultObjectMap(DataflowAnalysisContext *DACtx, + const FunctionDecl *FuncDecl, + RecordStorageLocation *ThisPointeeLoc, + RecordStorageLocation *LocForRecordReturnVal); + // `DACtx` is not null and not owned by this object. DataflowAnalysisContext *DACtx; - // FIXME: move the fields `CallStack`, `ReturnVal`, `ReturnLoc` and - // `ThisPointeeLoc` into a separate call-context object, shared between - // environments in the same call. + // FIXME: move the fields `CallStack`, `ResultObjectMap`, `ReturnVal`, + // `ReturnLoc` and `ThisPointeeLoc` into a separate call-context object, + // shared between environments in the same call. // https://github.com/llvm/llvm-project/issues/59005 // `DeclContext` of the block being analysed if provided. std::vector CallStack; - // Value returned by the function (if it has non-reference return type). + // Maps from prvalues of record type to their result objects. Shared between + // all environments for the same function. + // FIXME: It's somewhat unsatisfactory that we have to use a `shared_ptr` + // here, though the cost is acceptable: The overhead of a `shared_ptr` is + // incurred when it is copied, and this happens only relatively rarely (when + // we fork the environment). The need for a `shared_ptr` will go away once we + // introduce a shared call-context object (see above). + std::shared_ptr ResultObjectMap; + + // The following three member variables handle various different types of + // return values. + // - If the return type is not a reference and not a record: Value returned + // by the function. Value *ReturnVal = nullptr; - // Storage location of the reference returned by the function (if it has - // reference return type). + // - If the return type is a reference: Storage location of the reference + // returned by the function. StorageLocation *ReturnLoc = nullptr; + // - If the return type is a record or the function being analyzed is a + // constructor: Storage location into which the return value should be + // constructed. + RecordStorageLocation *LocForRecordReturnVal = nullptr; + // The storage location of the `this` pointee. Should only be null if the // function being analyzed is only a function and not a method. RecordStorageLocation *ThisPointeeLoc = nullptr; diff --git a/clang/include/clang/Analysis/SelectorExtras.h b/clang/include/clang/Analysis/SelectorExtras.h index 1e1daf5706bbf5a53dbe91a661fd393d03f293c5..ac2c2519beae35e54479e622b281827954a140ae 100644 --- a/clang/include/clang/Analysis/SelectorExtras.h +++ b/clang/include/clang/Analysis/SelectorExtras.h @@ -15,10 +15,10 @@ namespace clang { template static inline Selector getKeywordSelector(ASTContext &Ctx, - IdentifierInfos *... IIs) { + const IdentifierInfos *...IIs) { static_assert(sizeof...(IdentifierInfos) > 0, "keyword selectors must have at least one argument"); - SmallVector II({&Ctx.Idents.get(IIs)...}); + SmallVector II({&Ctx.Idents.get(IIs)...}); return Ctx.Selectors.getSelector(II.size(), &II[0]); } diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 6584460cf5685ea031ab5a6f746ae10871c8caf2..dc87a8c6f022dc5f451f51f13c0dfdb068104ae6 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -324,13 +324,10 @@ class Spelling { } class GNU : Spelling; -class Declspec : Spelling { - bit PrintOnLeft = 1; -} +class Declspec : Spelling; class Microsoft : Spelling; class CXX11 : Spelling { - bit CanPrintOnLeft = 0; string Namespace = namespace; } class C23 @@ -596,12 +593,6 @@ class AttrSubjectMatcherAggregateRule { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; class Attr { - // Specifies that when printed, this attribute is meaningful on the - // 'left side' of the declaration. - bit CanPrintOnLeft = 1; - // Specifies that when printed, this attribute is required to be printed on - // the 'left side' of the declaration. - bit PrintOnLeft = 0; // The various ways in which an attribute can be spelled in source list Spellings; // The things to which an attribute can appertain @@ -937,7 +928,6 @@ def AVRSignal : InheritableAttr, TargetSpecificAttr { } def AsmLabel : InheritableAttr { - let CanPrintOnLeft = 0; let Spellings = [CustomKeyword<"asm">, CustomKeyword<"__asm__">]; let Args = [ // Label specifies the mangled name for the decl. @@ -1534,7 +1524,6 @@ def AllocSize : InheritableAttr { } def EnableIf : InheritableAttr { - let CanPrintOnLeft = 0; // Does not have a [[]] spelling because this attribute requires the ability // to parse function arguments but the attribute is not written in the type // position. @@ -3171,7 +3160,6 @@ def Unavailable : InheritableAttr { } def DiagnoseIf : InheritableAttr { - let CanPrintOnLeft = 0; // Does not have a [[]] spelling because this attribute requires the ability // to parse function arguments but the attribute is not written in the type // position. diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 0ca4ea377fc36aca742d155d53edb072474ab255..a0bbe5861c5722dea021d62fb609ec98b5db7031 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -1604,27 +1604,40 @@ specifies availability for the current target platform, the availability attributes are ignored. Supported platforms are: ``ios`` - Apple's iOS operating system. The minimum deployment target is specified by - the ``-mios-version-min=*version*`` or ``-miphoneos-version-min=*version*`` - command-line arguments. + Apple's iOS operating system. The minimum deployment target is specified + as part of the ``-target *arch*-apple-ios*version*`` command line argument. + Alternatively, it can be specified by the ``-mtargetos=ios*version*`` + command-line argument. ``macos`` - Apple's macOS operating system. The minimum deployment target is - specified by the ``-mmacosx-version-min=*version*`` command-line argument. - ``macosx`` is supported for backward-compatibility reasons, but it is - deprecated. + Apple's macOS operating system. The minimum deployment target is specified + as part of the ``-target *arch*-apple-macos*version*`` command line argument. + Alternatively, it can be specified by the ``-mtargetos=macos*version*`` + command-line argument. ``macosx`` is supported for + backward-compatibility reasons, but it is deprecated. ``tvos`` - Apple's tvOS operating system. The minimum deployment target is specified by - the ``-mtvos-version-min=*version*`` command-line argument. + Apple's tvOS operating system. The minimum deployment target is specified + as part of the ``-target *arch*-apple-tvos*version*`` command line argument. + Alternatively, it can be specified by the ``-mtargetos=tvos*version*`` + command-line argument. ``watchos`` - Apple's watchOS operating system. The minimum deployment target is specified by - the ``-mwatchos-version-min=*version*`` command-line argument. + Apple's watchOS operating system. The minimum deployment target is specified + as part of the ``-target *arch*-apple-watchos*version*`` command line argument. + Alternatively, it can be specified by the ``-mtargetos=watchos*version*`` + command-line argument. + +``visionos`` + Apple's visionOS operating system. The minimum deployment target is specified + as part of the ``-target *arch*-apple-visionos*version*`` command line argument. + Alternatively, it can be specified by the ``-mtargetos=visionos*version*`` + command-line argument. ``driverkit`` Apple's DriverKit userspace kernel extensions. The minimum deployment target - is specified as part of the triple. + is specified as part of the ``-target *arch*-apple-driverkit*version*`` + command line argument. A declaration can typically be used even when deploying back to a platform version prior to when the declaration was introduced. When this happens, the @@ -7509,7 +7522,7 @@ means that it can e.g no longer be part of an initializer expression. /* This may print something else than "6 * 7 = 42", if there is a non-weak definition of "ANSWER" in - an object linked in */ + an object linked in */ printf("6 * 7 = %d\n", ANSWER); return 0; diff --git a/clang/include/clang/Basic/BuiltinsAMDGPU.def b/clang/include/clang/Basic/BuiltinsAMDGPU.def index c660582cc98e666031ae1dfbecf9d9b4612c9eae..3e21a2fe2ac6b31cc6bd09644884b2719c13fa3d 100644 --- a/clang/include/clang/Basic/BuiltinsAMDGPU.def +++ b/clang/include/clang/Basic/BuiltinsAMDGPU.def @@ -61,6 +61,7 @@ BUILTIN(__builtin_amdgcn_s_waitcnt, "vIi", "n") BUILTIN(__builtin_amdgcn_s_sendmsg, "vIiUi", "n") BUILTIN(__builtin_amdgcn_s_sendmsghalt, "vIiUi", "n") BUILTIN(__builtin_amdgcn_s_barrier, "v", "n") +BUILTIN(__builtin_amdgcn_s_ttracedata, "vi", "n") BUILTIN(__builtin_amdgcn_wave_barrier, "v", "n") BUILTIN(__builtin_amdgcn_sched_barrier, "vIi", "n") BUILTIN(__builtin_amdgcn_sched_group_barrier, "vIiIiIi", "n") @@ -267,6 +268,7 @@ TARGET_BUILTIN(__builtin_amdgcn_dot4_f32_bf8_bf8, "fUiUif", "nc", "dot11-insts") TARGET_BUILTIN(__builtin_amdgcn_permlane16, "UiUiUiUiUiIbIb", "nc", "gfx10-insts") TARGET_BUILTIN(__builtin_amdgcn_permlanex16, "UiUiUiUiUiIbIb", "nc", "gfx10-insts") TARGET_BUILTIN(__builtin_amdgcn_mov_dpp8, "UiUiIUi", "nc", "gfx10-insts") +TARGET_BUILTIN(__builtin_amdgcn_s_ttracedata_imm, "vIs", "n", "gfx10-insts") //===----------------------------------------------------------------------===// // Raytracing builtins. diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt index 7d53c751c13ac405d8293d912f97dd2a683e1659..2ef6ddc68f4bf364b676975de566fbcd6d07f924 100644 --- a/clang/include/clang/Basic/CMakeLists.txt +++ b/clang/include/clang/Basic/CMakeLists.txt @@ -31,16 +31,6 @@ clang_tablegen(AttrList.inc -gen-clang-attr-list SOURCE Attr.td TARGET ClangAttrList) -clang_tablegen(AttrLeftSideCanPrintList.inc -gen-clang-attr-can-print-left-list - -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ - SOURCE Attr.td - TARGET ClangAttrCanPrintLeftList) - -clang_tablegen(AttrLeftSideMustPrintList.inc -gen-clang-attr-must-print-left-list - -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ - SOURCE Attr.td - TARGET ClangAttrMustPrintLeftList) - clang_tablegen(AttrSubMatchRulesList.inc -gen-clang-attr-subject-match-rule-list -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ SOURCE Attr.td diff --git a/clang/include/clang/Basic/Cuda.h b/clang/include/clang/Basic/Cuda.h index 3e77a74c7c0092239c2f9235de9c43b532423ab3..38f30543a0f66268bad94751c2f6944b290369ea 100644 --- a/clang/include/clang/Basic/Cuda.h +++ b/clang/include/clang/Basic/Cuda.h @@ -50,6 +50,10 @@ const char *CudaVersionToString(CudaVersion V); // Input is "Major.Minor" CudaVersion CudaStringToVersion(const llvm::Twine &S); +// We have a name conflict with sys/mac.h on AIX +#ifdef SM_32 +#undef SM_32 +#endif enum class CudaArch { UNUSED, UNKNOWN, @@ -126,6 +130,14 @@ enum class CudaArch { HIPDefault = CudaArch::GFX906, }; +enum class CUDAFunctionTarget { + Device, + Global, + Host, + HostDevice, + InvalidTarget +}; + static inline bool IsNVIDIAGpuArch(CudaArch A) { return A >= CudaArch::SM_20 && A < CudaArch::GFX600; } diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 5251774ff4efd6d7f607431511991ca633d22252..47747d8704b6c85413312beb703c6800f6173893 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1412,6 +1412,9 @@ def MultiGPU: DiagGroup<"multi-gpu">; // libc and the CRT to be skipped. def AVRRtlibLinkingQuirks : DiagGroup<"avr-rtlib-linking-quirks">; +// A warning group related to AArch64 SME function attribues. +def AArch64SMEAttributes : DiagGroup<"aarch64-sme-attributes">; + // A warning group for things that will change semantics in the future. def FutureCompat : DiagGroup<"future-compat">; diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index 0a477da7186b09b0f95ba850fb111d970c2eb155..396bff0146a373c94de9bd2c425c13e6c8e59083 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -20,6 +20,10 @@ def warn_no_such_excluded_header_file : Warning<"no such excluded %select{public def warn_glob_did_not_match: Warning<"glob '%0' did not match any header file">, InGroup; def err_no_such_umbrella_header_file : Error<"%select{public|private|project}1 umbrella header file not found in input: '%0'">; def err_cannot_find_reexport : Error<"cannot find re-exported %select{framework|library}0: '%1'">; +def err_no_matching_target : Error<"no matching target found for target variant '%0'">; +def err_unsupported_vendor : Error<"vendor '%0' is not supported: '%1'">; +def err_unsupported_environment : Error<"environment '%0' is not supported: '%1'">; +def err_unsupported_os : Error<"os '%0' is not supported: '%1'">; } // end of command line category. let CategoryName = "Verification" in { diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 46a44418a3153bc75df0ac7327bab65ac1528bc3..bb9ca2a50cc06c36cbea45f4b4917a382433c7e2 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -941,6 +941,12 @@ def warn_cxx98_compat_defaulted_deleted_function : Warning< "%select{defaulted|deleted}0 function definitions are incompatible with C++98">, InGroup, DefaultIgnore; +def ext_delete_with_message : ExtWarn< + "'= delete' with a message is a C++2c extension">, InGroup; +def warn_cxx23_delete_with_message : Warning< + "'= delete' with a message is incompatible with C++ standards before C++2c">, + DefaultIgnore, InGroup; + // C++11 default member initialization def ext_nonstatic_member_init : ExtWarn< "default member initializer for non-static data member is a C++11 " diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index df57f5e6ce11ba02faf873f677242a26a8a2f881..5ec0218aedfe868a48e6eb7b36dd4a26b05fb572 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -165,7 +165,7 @@ def ext_vla_folded_to_constant : ExtWarn< "variable length array folded to constant array as an extension">, InGroup; def err_vla_unsupported : Error< - "variable length arrays are not supported for %select{the current target|'%1'}0">; + "variable length arrays are not supported %select{for the current target|in '%1'}0">; def err_vla_in_coroutine_unsupported : Error< "variable length arrays in a coroutine are not supported">; def note_vla_unsupported : Note< @@ -2402,10 +2402,6 @@ def err_selected_explicit_constructor : Error< def note_explicit_ctor_deduction_guide_here : Note< "explicit %select{constructor|deduction guide}0 declared here">; -// C++11 decltype -def err_decltype_in_declarator : Error< - "'decltype' cannot be used to name a declaration">; - // C++11 auto def warn_cxx98_compat_auto_type_specifier : Warning< "'auto' type specifier is incompatible with C++98">, @@ -3755,6 +3751,16 @@ def err_sme_definition_using_za_in_non_sme_target : Error< "function using ZA state requires 'sme'">; def err_sme_definition_using_zt0_in_non_sme2_target : Error< "function using ZT0 state requires 'sme2'">; +def warn_sme_streaming_pass_return_vl_to_non_streaming : Warning< + "passing a VL-dependent argument to/from a function that has a different" + " streaming-mode. The streaming and non-streaming vector lengths may be" + " different">, + InGroup, DefaultIgnore; +def warn_sme_locally_streaming_has_vl_args_returns : Warning< + "passing/returning a VL-dependent argument to/from a __arm_locally_streaming" + " function. The streaming and non-streaming vector" + " lengths may be different">, + InGroup, DefaultIgnore; def err_conflicting_attributes_arm_state : Error< "conflicting attributes for state '%0'">; def err_sme_streaming_cannot_be_multiversioned : Error< @@ -4677,11 +4683,10 @@ def err_ovl_no_viable_member_function_in_call : Error< "no matching member function for call to %0">; def err_ovl_ambiguous_call : Error< "call to %0 is ambiguous">; -def err_ovl_deleted_call : Error<"call to deleted function %0">; +def err_ovl_deleted_call : Error<"call to deleted" + "%select{| member}0 function %1%select{|: %3}2">; def err_ovl_ambiguous_member_call : Error< "call to member function %0 is ambiguous">; -def err_ovl_deleted_member_call : Error< - "call to deleted member function %0">; def note_ovl_too_many_candidates : Note< "remaining %0 candidate%s0 omitted; " "pass -fshow-overloads=all to show them">; @@ -4909,12 +4914,12 @@ def err_ovl_ambiguous_conversion_in_cast : Error< "dynamic_cast|C-style cast|functional-style cast|}0 from %1 to %2">; def err_ovl_deleted_conversion_in_cast : Error< "%select{|static_cast|reinterpret_cast|dynamic_cast|C-style cast|" - "functional-style cast|}0 from %1 to %2 uses deleted function">; + "functional-style cast|}0 from %1 to %2 uses deleted function%select{|: %4}3">; def err_ovl_ambiguous_init : Error<"call to constructor of %0 is ambiguous">; def err_ref_init_ambiguous : Error< "reference initialization of type %0 with initializer of type %1 is ambiguous">; def err_ovl_deleted_init : Error< - "call to deleted constructor of %0">; + "call to deleted constructor of %0%select{|: %2}1">; def err_ovl_deleted_special_init : Error< "call to implicitly-deleted %select{default constructor|copy constructor|" "move constructor|copy assignment operator|move assignment operator|" @@ -4940,7 +4945,7 @@ def note_ovl_ambiguous_oper_binary_reversed_candidate : Note< def err_ovl_no_viable_oper : Error<"no viable overloaded '%0'">; def note_assign_lhs_incomplete : Note<"type %0 is incomplete">; def err_ovl_deleted_oper : Error< - "overload resolution selected deleted operator '%0'">; + "overload resolution selected deleted operator '%0'%select{|: %2}1">; def err_ovl_deleted_special_oper : Error< "object of type %0 cannot be %select{constructed|copied|moved|assigned|" "assigned|destroyed}1 because its %sub{select_special_member_kind}1 is " @@ -4977,7 +4982,7 @@ def err_ovl_ambiguous_object_call : Error< def err_ovl_ambiguous_subscript_call : Error< "call to subscript operator of type %0 is ambiguous">; def err_ovl_deleted_object_call : Error< - "call to deleted function call operator in type %0">; + "call to deleted function call operator in type %0%select{|: %2}1">; def note_ovl_surrogate_cand : Note<"conversion candidate of type %0">; def err_member_call_without_object : Error< "call to %select{non-static|explicit}0 member function without an object argument">; @@ -7142,7 +7147,8 @@ def ext_typecheck_decl_incomplete_type : ExtWarn< def err_tentative_def_incomplete_type : Error< "tentative definition has type %0 that is never completed">; def warn_tentative_incomplete_array : Warning< - "tentative array definition assumed to have one element">; + "tentative array definition assumed to have one element">, + InGroup>; def err_typecheck_incomplete_array_needs_initializer : Error< "definition of variable with array type needs an explicit size " "or an initializer">; @@ -7581,8 +7587,8 @@ def ext_gnu_ptr_func_arith : Extension< InGroup; def err_readonly_message_assignment : Error< "assigning to 'readonly' return result of an Objective-C message not allowed">; -def ext_integer_increment_complex : Extension< - "ISO C does not support '++'/'--' on complex integer type %0">; +def ext_increment_complex : Extension< + "'%select{--|++}0' on an object of complex type is a Clang extension">; def ext_integer_complement_complex : Extension< "ISO C does not support '~' for complex conjugation of %0">; def err_nosetter_property_assignment : Error< @@ -8277,7 +8283,7 @@ def err_typecheck_nonviable_condition_incomplete : Error< "no viable conversion%diff{ from $ to incomplete type $|}0,1">; def err_typecheck_deleted_function : Error< "conversion function %diff{from $ to $|between types}0,1 " - "invokes a deleted function">; + "invokes a deleted function%select{|: %3}2">; def err_expected_class_or_namespace : Error<"%0 is not a class" "%select{ or namespace|, namespace, or enumeration}1">; @@ -8302,6 +8308,9 @@ def ext_template_after_declarative_nns : ExtWarn< def ext_alias_template_in_declarative_nns : ExtWarn< "a declarative nested name specifier cannot name an alias template">, InGroup>; +def err_computed_type_in_declarative_nns : Error< + "a %select{pack indexing|'decltype'}0 specifier cannot be used in " + "a declarative nested name specifier">; def err_no_typeid_with_fno_rtti : Error< "use of typeid requires -frtti">; @@ -8874,7 +8883,7 @@ def err_nontemporal_builtin_must_be_pointer_intfltptr_or_vector : Error< "address argument to nontemporal builtin must be a pointer to integer, float, " "pointer, or a vector of such types (%0 invalid)">; -def err_deleted_function_use : Error<"attempt to use a deleted function">; +def err_deleted_function_use : Error<"attempt to use a deleted function%select{|: %1}0">; def err_deleted_inherited_ctor_use : Error< "constructor inherited by %0 from base class %1 is implicitly deleted">; @@ -12252,6 +12261,12 @@ def warn_acc_clause_unimplemented def err_acc_construct_appertainment : Error<"OpenACC construct '%0' cannot be used here; it can only " "be used in a statement context">; +def err_acc_clause_appertainment + : Error<"OpenACC '%1' clause is not valid on '%0' directive">; +def err_acc_duplicate_clause_disallowed + : Error<"OpenACC '%1' clause cannot appear more than once on a '%0' " + "directive">; +def note_acc_previous_clause_here : Note<"previous clause is here">; def err_acc_branch_in_out_compute_construct : Error<"invalid %select{branch|return|throw}0 %select{out of|into}1 " "OpenACC Compute Construct">; diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index a091639bfa2542cad34c50db6df289b8302f7d95..a893e6f4d3d39de843b673f60600c6747ce98985 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -913,12 +913,13 @@ class alignas(IdentifierInfoAlignment) MultiKeywordSelector public: // Constructor for keyword selectors. - MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) + MultiKeywordSelector(unsigned nKeys, const IdentifierInfo **IIV) : DeclarationNameExtra(nKeys) { assert((nKeys > 1) && "not a multi-keyword selector"); // Fill in the trailing keyword array. - IdentifierInfo **KeyInfo = reinterpret_cast(this + 1); + const IdentifierInfo **KeyInfo = + reinterpret_cast(this + 1); for (unsigned i = 0; i != nKeys; ++i) KeyInfo[i] = IIV[i]; } @@ -928,7 +929,7 @@ public: using DeclarationNameExtra::getNumArgs; - using keyword_iterator = IdentifierInfo *const *; + using keyword_iterator = const IdentifierInfo *const *; keyword_iterator keyword_begin() const { return reinterpret_cast(this + 1); @@ -938,7 +939,7 @@ public: return keyword_begin() + getNumArgs(); } - IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const { + const IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const { assert(i < getNumArgs() && "getIdentifierInfoForSlot(): illegal index"); return keyword_begin()[i]; } @@ -991,10 +992,10 @@ class Selector { /// Do not reorder or add any arguments to this template /// without thoroughly understanding how tightly coupled these classes are. llvm::PointerIntPair< - llvm::PointerUnion, 2> + llvm::PointerUnion, 2> InfoPtr; - Selector(IdentifierInfo *II, unsigned nArgs) { + Selector(const IdentifierInfo *II, unsigned nArgs) { assert(nArgs < 2 && "nArgs not equal to 0/1"); InfoPtr.setPointerAndInt(II, nArgs + 1); } @@ -1006,8 +1007,8 @@ class Selector { InfoPtr.setPointerAndInt(SI, MultiArg & 0b11); } - IdentifierInfo *getAsIdentifierInfo() const { - return InfoPtr.getPointer().dyn_cast(); + const IdentifierInfo *getAsIdentifierInfo() const { + return InfoPtr.getPointer().dyn_cast(); } MultiKeywordSelector *getMultiKeywordSelector() const { @@ -1075,7 +1076,7 @@ public: /// /// \returns the uniqued identifier for this slot, or NULL if this slot has /// no corresponding identifier. - IdentifierInfo *getIdentifierInfoForSlot(unsigned argIndex) const; + const IdentifierInfo *getIdentifierInfoForSlot(unsigned argIndex) const; /// Retrieve the name at a given position in the selector. /// @@ -1132,13 +1133,13 @@ public: /// /// \p NumArgs indicates whether this is a no argument selector "foo", a /// single argument selector "foo:" or multi-argument "foo:bar:". - Selector getSelector(unsigned NumArgs, IdentifierInfo **IIV); + Selector getSelector(unsigned NumArgs, const IdentifierInfo **IIV); - Selector getUnarySelector(IdentifierInfo *ID) { + Selector getUnarySelector(const IdentifierInfo *ID) { return Selector(ID, 1); } - Selector getNullarySelector(IdentifierInfo *ID) { + Selector getNullarySelector(const IdentifierInfo *ID) { return Selector(ID, 0); } diff --git a/clang/include/clang/Basic/OpenACCClauses.def b/clang/include/clang/Basic/OpenACCClauses.def new file mode 100644 index 0000000000000000000000000000000000000000..7fd2720e02ce2283cf7695e5d37c379b7dba2a9d --- /dev/null +++ b/clang/include/clang/Basic/OpenACCClauses.def @@ -0,0 +1,21 @@ +//===-- OpenACCClauses.def - List of implemented OpenACC Clauses -- 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 a list of currently implemented OpenACC Clauses (and +// eventually, the entire list) in a way that makes generating 'visitor' and +// other lists easier. +// +// The primary macro is a single-argument version taking the name of the Clause +// as used in Clang source (so `Default` instead of `default`). +// +// VISIT_CLAUSE(CLAUSE_NAME) + +VISIT_CLAUSE(Default) +VISIT_CLAUSE(If) + +#undef VISIT_CLAUSE diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h index 4456f4afd142df0c74023d74ff1640bb79fe1435..3414df9999170192492dd1fb8283e8a866b0008d 100644 --- a/clang/include/clang/Basic/OpenACCKinds.h +++ b/clang/include/clang/Basic/OpenACCKinds.h @@ -67,7 +67,7 @@ enum class OpenACCDirectiveKind { }; template -inline StreamTy &PrintOpenACCDirectiveKind(StreamTy &Out, +inline StreamTy &printOpenACCDirectiveKind(StreamTy &Out, OpenACCDirectiveKind K) { switch (K) { case OpenACCDirectiveKind::Parallel: @@ -138,12 +138,12 @@ inline StreamTy &PrintOpenACCDirectiveKind(StreamTy &Out, inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out, OpenACCDirectiveKind K) { - return PrintOpenACCDirectiveKind(Out, K); + return printOpenACCDirectiveKind(Out, K); } inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out, OpenACCDirectiveKind K) { - return PrintOpenACCDirectiveKind(Out, K); + return printOpenACCDirectiveKind(Out, K); } enum class OpenACCAtomicKind { @@ -266,7 +266,7 @@ enum class OpenACCClauseKind { }; template -inline StreamTy &PrintOpenACCClauseKind(StreamTy &Out, OpenACCClauseKind K) { +inline StreamTy &printOpenACCClauseKind(StreamTy &Out, OpenACCClauseKind K) { switch (K) { case OpenACCClauseKind::Finalize: return Out << "finalize"; @@ -402,12 +402,12 @@ inline StreamTy &PrintOpenACCClauseKind(StreamTy &Out, OpenACCClauseKind K) { inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out, OpenACCClauseKind K) { - return PrintOpenACCClauseKind(Out, K); + return printOpenACCClauseKind(Out, K); } inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out, OpenACCClauseKind K) { - return PrintOpenACCClauseKind(Out, K); + return printOpenACCClauseKind(Out, K); } enum class OpenACCDefaultClauseKind { @@ -419,6 +419,30 @@ enum class OpenACCDefaultClauseKind { Invalid, }; +template +inline StreamTy &printOpenACCDefaultClauseKind(StreamTy &Out, + OpenACCDefaultClauseKind K) { + switch (K) { + case OpenACCDefaultClauseKind::None: + return Out << "none"; + case OpenACCDefaultClauseKind::Present: + return Out << "present"; + case OpenACCDefaultClauseKind::Invalid: + return Out << ""; + } + llvm_unreachable("Unknown OpenACCDefaultClauseKind enum"); +} + +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out, + OpenACCDefaultClauseKind K) { + return printOpenACCDefaultClauseKind(Out, K); +} + +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out, + OpenACCDefaultClauseKind K) { + return printOpenACCDefaultClauseKind(Out, K); +} + enum class OpenACCReductionOperator { /// '+'. Addition, diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def index c2137e3f61f64508606a6d2ec84e40b9f9a97c59..b228ffd07ee7454dafab9255bbda0d3e3f43484f 100644 --- a/clang/include/clang/Basic/Sanitizers.def +++ b/clang/include/clang/Basic/Sanitizers.def @@ -163,24 +163,24 @@ SANITIZER_GROUP("implicit-integer-arithmetic-value-change", ImplicitIntegerArithmeticValueChange, ImplicitIntegerSignChange | ImplicitSignedIntegerTruncation) -SANITIZER("objc-cast", ObjCCast) +SANITIZER_GROUP("implicit-integer-conversion", ImplicitIntegerConversion, + ImplicitIntegerArithmeticValueChange | + ImplicitUnsignedIntegerTruncation) -// FIXME: -//SANITIZER_GROUP("implicit-integer-conversion", ImplicitIntegerConversion, -// ImplicitIntegerArithmeticValueChange | -// ImplicitUnsignedIntegerTruncation) -//SANITIZER_GROUP("implicit-conversion", ImplicitConversion, -// ImplicitIntegerConversion) +// Implicit bitfield sanitizers +SANITIZER("implicit-bitfield-conversion", ImplicitBitfieldConversion) SANITIZER_GROUP("implicit-conversion", ImplicitConversion, - ImplicitIntegerArithmeticValueChange | - ImplicitUnsignedIntegerTruncation) + ImplicitIntegerConversion | + ImplicitBitfieldConversion) SANITIZER_GROUP("integer", Integer, - ImplicitConversion | IntegerDivideByZero | Shift | + ImplicitIntegerConversion | IntegerDivideByZero | Shift | SignedIntegerOverflow | UnsignedIntegerOverflow | UnsignedShiftBase) +SANITIZER("objc-cast", ObjCCast) + SANITIZER("local-bounds", LocalBounds) SANITIZER_GROUP("bounds", Bounds, ArrayBounds | LocalBounds) diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 800af0e6d0448058d901d396e4f41025610d3b02..a27fbed358a60c2376c938800e477a32e0859fcd 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -521,6 +521,7 @@ TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX) TYPE_TRAIT_1(__has_unique_object_representations, HasUniqueObjectRepresentations, KEYCXX) TYPE_TRAIT_2(__is_layout_compatible, IsLayoutCompatible, KEYCXX) +TYPE_TRAIT_2(__is_pointer_interconvertible_base_of, IsPointerInterconvertibleBaseOf, KEYCXX) #define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) KEYWORD(__##Trait, KEYCXX) #include "clang/Basic/TransformTypeTraits.def" diff --git a/clang/include/clang/CIR/CMakeLists.txt b/clang/include/clang/CIR/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/clang/include/clang/CMakeLists.txt b/clang/include/clang/CMakeLists.txt index 0dc9ea5ed8ac8a48c4fee5856449bf28a8085956..47ac70cd21690f795659acd6f5a95f7e324b9b89 100644 --- a/clang/include/clang/CMakeLists.txt +++ b/clang/include/clang/CMakeLists.txt @@ -1,5 +1,8 @@ add_subdirectory(AST) add_subdirectory(Basic) +if(CLANG_ENABLE_CIR) + add_subdirectory(CIR) +endif() add_subdirectory(Driver) add_subdirectory(Parse) add_subdirectory(Sema) diff --git a/clang/include/clang/CodeGen/CodeGenAction.h b/clang/include/clang/CodeGen/CodeGenAction.h index 7ad2988e589eb2e521a5848dc17090b415b9224e..186dbb43f01ef7cea0cb56d13816608592b8bbb6 100644 --- a/clang/include/clang/CodeGen/CodeGenAction.h +++ b/clang/include/clang/CodeGen/CodeGenAction.h @@ -57,6 +57,8 @@ private: bool loadLinkModules(CompilerInstance &CI); protected: + bool BeginSourceFileAction(CompilerInstance &CI) override; + /// Create a new code generation action. If the optional \p _VMContext /// parameter is supplied, the action uses it without taking ownership, /// otherwise it creates a fresh LLVM context and takes ownership. diff --git a/clang/include/clang/Config/config.h.cmake b/clang/include/clang/Config/config.h.cmake index 4015ac8040861c2cb92d0c79a4334d5d3324dcb3..27ed69e21562bff28e065c3f04cb50159556dd46 100644 --- a/clang/include/clang/Config/config.h.cmake +++ b/clang/include/clang/Config/config.h.cmake @@ -83,4 +83,7 @@ /* Spawn a new process clang.exe for the CC1 tool invocation, when necessary */ #cmakedefine01 CLANG_SPAWN_CC1 +/* Whether CIR is built into Clang */ +#cmakedefine01 CLANG_ENABLE_CIR + #endif diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index c31f433d93104a8763e8ed775ffd9cbd062f7136..e24626913add7627602398ab4f556b4340ec5d2f 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1003,7 +1003,8 @@ def : Joined<["-"], "Xclang=">, Group, def Xcuda_fatbinary : Separate<["-"], "Xcuda-fatbinary">, HelpText<"Pass to fatbinary invocation">, MetaVarName<"">; def Xcuda_ptxas : Separate<["-"], "Xcuda-ptxas">, - HelpText<"Pass to the ptxas assembler">, MetaVarName<"">; + HelpText<"Pass to the ptxas assembler">, MetaVarName<"">, + Visibility<[ClangOption, CLOption]>; def Xopenmp_target : Separate<["-"], "Xopenmp-target">, Group, HelpText<"Pass to the target offloading toolchain.">, MetaVarName<"">; def Xopenmp_target_EQ : JoinedAndSeparate<["-"], "Xopenmp-target=">, Group, @@ -1340,7 +1341,8 @@ def hip_link : Flag<["--"], "hip-link">, Group, HelpText<"Link clang-offload-bundler bundles for HIP">; def no_hip_rt: Flag<["-"], "no-hip-rt">, Group, HelpText<"Do not link against HIP runtime libraries">; -def rocm_path_EQ : Joined<["--"], "rocm-path=">, Group, +def rocm_path_EQ : Joined<["--"], "rocm-path=">, + Visibility<[FlangOption]>, Group, HelpText<"ROCm installation path, used for finding and automatically linking required bitcode libraries.">; def hip_path_EQ : Joined<["--"], "hip-path=">, Group, HelpText<"HIP runtime installation path, used for finding HIP version and adding HIP include path.">; @@ -1448,7 +1450,7 @@ def dD : Flag<["-"], "dD">, Group, Visibility<[ClangOption, CC1Option]> def dI : Flag<["-"], "dI">, Group, Visibility<[ClangOption, CC1Option]>, HelpText<"Print include directives in -E mode in addition to normal output">, MarshallingInfoFlag>; -def dM : Flag<["-"], "dM">, Group, Visibility<[ClangOption, CC1Option]>, +def dM : Flag<["-"], "dM">, Group, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, HelpText<"Print macro definitions in -E mode instead of normal output">; def dead__strip : Flag<["-"], "dead_strip">; def dependency_file : Separate<["-"], "dependency-file">, @@ -3034,6 +3036,7 @@ defm prebuilt_implicit_modules : BoolFOption<"prebuilt-implicit-modules", def fmodule_output_EQ : Joined<["-"], "fmodule-output=">, Flags<[NoXarchOption]>, Visibility<[ClangOption, CC1Option]>, + MarshallingInfoString>, HelpText<"Save intermediate module file results when compiling a standard C++ module unit.">; def fmodule_output : Flag<["-"], "fmodule-output">, Flags<[NoXarchOption]>, Visibility<[ClangOption, CC1Option]>, @@ -3047,6 +3050,11 @@ defm skip_odr_check_in_gmf : BoolOption<"f", "skip-odr-check-in-gmf", "Perform ODR checks for decls in the global module fragment.">>, Group; +def modules_reduced_bmi : Flag<["-"], "fexperimental-modules-reduced-bmi">, + Group, Visibility<[ClangOption, CC1Option]>, + HelpText<"Generate the reduced BMI">, + MarshallingInfoFlag>; + def fmodules_prune_interval : Joined<["-"], "fmodules-prune-interval=">, Group, Visibility<[ClangOption, CC1Option]>, MetaVarName<"">, HelpText<"Specify the interval (in seconds) between attempts to prune the module cache">, @@ -4911,6 +4919,9 @@ defm tgsplit : SimpleMFlag<"tgsplit", "Enable", "Disable", defm wavefrontsize64 : SimpleMFlag<"wavefrontsize64", "Specify wavefront size 64", "Specify wavefront size 32", " mode (AMDGPU only)">; +defm amdgpu_precise_memory_op + : SimpleMFlag<"amdgpu-precise-memory-op", "Enable", "Disable", + " precise memory mode (AMDGPU only)">; defm unsafe_fp_atomics : BoolMOption<"unsafe-fp-atomics", TargetOpts<"AllowAMDGPUUnsafeFPAtomics">, DefaultFalse, @@ -5386,10 +5397,6 @@ def pg : Flag<["-"], "pg">, HelpText<"Enable mcount instrumentation">, MarshallingInfoFlag>; def pipe : Flag<["-", "--"], "pipe">, HelpText<"Use pipes between commands, when possible">; -// Facebook T92898286 -def post_link_optimize : Flag<["--"], "post-link-optimize">, - HelpText<"Apply post-link optimizations using BOLT">; -// End Facebook T92898286 def prebind__all__twolevel__modules : Flag<["-"], "prebind_all_twolevel_modules">; def prebind : Flag<["-"], "prebind">; def preload : Flag<["-"], "preload">; @@ -5464,21 +5471,23 @@ def rdynamic : Flag<["-"], "rdynamic">, Group, Visibility<[ClangOption, FlangOption]>; def resource_dir : Separate<["-"], "resource-dir">, Flags<[NoXarchOption, HelpHidden]>, - Visibility<[ClangOption, CC1Option, CLOption, DXCOption]>, + Visibility<[ClangOption, CC1Option, CLOption, DXCOption, FlangOption, FC1Option]>, HelpText<"The directory which holds the compiler resource files">, MarshallingInfoString>; def resource_dir_EQ : Joined<["-"], "resource-dir=">, Flags<[NoXarchOption]>, - Visibility<[ClangOption, CLOption, DXCOption]>, + Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>, Alias; def rpath : Separate<["-"], "rpath">, Flags<[LinkerInput]>, Group, Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>; def rtlib_EQ : Joined<["-", "--"], "rtlib=">, Visibility<[ClangOption, CLOption]>, HelpText<"Compiler runtime library to use">; def frtlib_add_rpath: Flag<["-"], "frtlib-add-rpath">, Flags<[NoArgumentUnused]>, + Visibility<[ClangOption, FlangOption]>, HelpText<"Add -rpath with architecture-specific resource directory to the linker flags. " "When --hip-link is specified, also add -rpath with HIP runtime library directory to the linker flags">; def fno_rtlib_add_rpath: Flag<["-"], "fno-rtlib-add-rpath">, Flags<[NoArgumentUnused]>, + Visibility<[ClangOption, FlangOption]>, HelpText<"Do not add -rpath with architecture-specific resource directory to the linker flags. " "When --hip-link is specified, do not add -rpath with HIP runtime library directory to the linker flags">; def offload_add_rpath: Flag<["--"], "offload-add-rpath">, diff --git a/clang/include/clang/Frontend/FrontendActions.h b/clang/include/clang/Frontend/FrontendActions.h index 0518a8823a03ea94ca284aee9256bbb5f7295ac0..a620ddfc40447d7795df64c407300b6ca8da5d44 100644 --- a/clang/include/clang/Frontend/FrontendActions.h +++ b/clang/include/clang/Frontend/FrontendActions.h @@ -34,18 +34,12 @@ public: /// Preprocessor-based frontend action that also loads PCH files. class ReadPCHAndPreprocessAction : public FrontendAction { - llvm::unique_function AdjustCI; - void ExecuteAction() override; std::unique_ptr CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override; public: - ReadPCHAndPreprocessAction( - llvm::unique_function AdjustCI) - : AdjustCI(std::move(AdjustCI)) {} - bool usesPreprocessorOnly() const override { return false; } }; @@ -327,15 +321,11 @@ protected: class GetDependenciesByModuleNameAction : public PreprocessOnlyAction { StringRef ModuleName; - llvm::unique_function AdjustCI; - void ExecuteAction() override; public: - GetDependenciesByModuleNameAction( - StringRef ModuleName, - llvm::unique_function AdjustCI) - : ModuleName(ModuleName), AdjustCI(std::move(AdjustCI)) {} + GetDependenciesByModuleNameAction(StringRef ModuleName) + : ModuleName(ModuleName) {} }; } // end namespace clang diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index 5ee4d471670f48bae893ad9da4432923ae305660..a738c1f375768282259993be13e40fcf6ce11ae0 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -404,6 +404,10 @@ public: LLVM_PREFERRED_TYPE(bool) unsigned EmitPrettySymbolGraphs : 1; + /// Whether to generate reduced BMI for C++20 named modules. + LLVM_PREFERRED_TYPE(bool) + unsigned GenReducedBMI : 1; + CodeCompleteOptions CodeCompleteOpts; /// Specifies the output format of the AST. @@ -568,6 +572,9 @@ public: /// Path which stores the output files for -ftime-trace std::string TimeTracePath; + /// Output Path for module output file. + std::string ModuleOutputPath; + public: FrontendOptions() : DisableFree(false), RelocatablePCH(false), ShowHelp(false), @@ -582,7 +589,8 @@ public: AllowPCMWithCompilerErrors(false), ModulesShareFileManager(true), EmitSymbolGraph(false), EmitExtensionSymbolGraphs(false), EmitSymbolGraphSymbolLabelsForTesting(false), - EmitPrettySymbolGraphs(false), TimeTraceGranularity(500) {} + EmitPrettySymbolGraphs(false), GenReducedBMI(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/InstallAPI/DylibVerifier.h b/clang/include/clang/InstallAPI/DylibVerifier.h index 07dbd3bf5f2b100156fce17a2fb9422952ab61ba..31de212fc423a5e8548d894c2ac26e3a4a225ae8 100644 --- a/clang/include/clang/InstallAPI/DylibVerifier.h +++ b/clang/include/clang/InstallAPI/DylibVerifier.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" #include "clang/InstallAPI/MachO.h" namespace clang { @@ -27,6 +28,16 @@ enum class VerificationMode { using LibAttrs = llvm::StringMap; using ReexportedInterfaces = llvm::SmallVector; +// Pointers to information about a zippered declaration used for +// querying and reporting violations against different +// declarations that all map to the same symbol. +struct ZipperedDeclSource { + const FrontendAttrs *FA; + clang::SourceManager *SrcMgr; + Target T; +}; +using ZipperedDeclSources = std::vector; + /// Service responsible to tracking state of verification across the /// lifetime of InstallAPI. /// As declarations are collected during AST traversal, they are @@ -67,10 +78,10 @@ public: DylibVerifier() = default; DylibVerifier(llvm::MachO::Records &&Dylib, ReexportedInterfaces &&Reexports, - DiagnosticsEngine *Diag, VerificationMode Mode, bool Demangle, - StringRef DSYMPath) + DiagnosticsEngine *Diag, VerificationMode Mode, bool Zippered, + bool Demangle, StringRef DSYMPath) : Dylib(std::move(Dylib)), Reexports(std::move(Reexports)), Mode(Mode), - Demangle(Demangle), DSYMPath(DSYMPath), + Zippered(Zippered), Demangle(Demangle), DSYMPath(DSYMPath), Exports(std::make_unique()), Ctx(VerifierContext{Diag}) {} Result verify(GlobalRecord *R, const FrontendAttrs *FA); @@ -99,11 +110,7 @@ public: Result getState() const { return Ctx.FrontendState; } /// Set different source managers to the same diagnostics engine. - void setSourceManager(SourceManager &SourceMgr) const { - if (!Ctx.Diag) - return; - Ctx.Diag->setSourceManager(&SourceMgr); - } + void setSourceManager(IntrusiveRefCntPtr SourceMgr); private: /// Determine whether to compare declaration to symbol in binary. @@ -121,6 +128,15 @@ private: /// symbols should be omitted from the text-api file. bool shouldIgnoreReexport(const Record *R, SymbolContext &SymCtx) const; + // Ignore and omit unavailable symbols in zippered libraries. + bool shouldIgnoreZipperedAvailability(const Record *R, SymbolContext &SymCtx); + + // Check if an internal declaration in zippered library has an + // external declaration for a different platform. This results + // in the symbol being in a "seperate" platform slice. + bool shouldIgnoreInternalZipperedSymbol(const Record *R, + const SymbolContext &SymCtx) const; + /// Compare the visibility declarations to the linkage of symbol found in /// dylib. Result compareVisibility(const Record *R, SymbolContext &SymCtx, @@ -176,6 +192,9 @@ private: // Controls what class of violations to report. VerificationMode Mode = VerificationMode::Invalid; + // Library is zippered. + bool Zippered = false; + // Attempt to demangle when reporting violations. bool Demangle = false; @@ -185,11 +204,18 @@ private: // Valid symbols in final text file. std::unique_ptr Exports = std::make_unique(); + // Unavailable or obsoleted declarations for a zippered library. + // These are cross referenced against symbols in the dylib. + llvm::StringMap DeferredZipperedSymbols; + // Track current state of verification while traversing AST. VerifierContext Ctx; // Track DWARF provided source location for dylibs. DWARFContext *DWARFCtx = nullptr; + + // Source manager for each unique compiler instance. + llvm::SmallVector, 12> SourceManagers; }; } // namespace installapi diff --git a/clang/include/clang/InstallAPI/Frontend.h b/clang/include/clang/InstallAPI/Frontend.h index 5cccd891c58093ac540b5ac8af103b493f54871d..bc4e77de2b72569b1ad6f603b6609892a69ed4cd 100644 --- a/clang/include/clang/InstallAPI/Frontend.h +++ b/clang/include/clang/InstallAPI/Frontend.h @@ -36,7 +36,7 @@ public: std::unique_ptr CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override { Ctx.Diags->getClient()->BeginSourceFile(CI.getLangOpts()); - Ctx.Verifier->setSourceManager(CI.getSourceManager()); + Ctx.Verifier->setSourceManager(CI.getSourceManagerPtr()); return std::make_unique( CI.getASTContext(), Ctx, CI.getSourceManager(), CI.getPreprocessor()); } diff --git a/clang/include/clang/InstallAPI/FrontendRecords.h b/clang/include/clang/InstallAPI/FrontendRecords.h index 59271e81e230c2f022e1bec0894e0529e3f3a0e2..ef82398addd7ac85add76d2aea3534e94e154d86 100644 --- a/clang/include/clang/InstallAPI/FrontendRecords.h +++ b/clang/include/clang/InstallAPI/FrontendRecords.h @@ -21,6 +21,7 @@ namespace installapi { struct FrontendAttrs { const AvailabilityInfo Avail; const Decl *D; + const SourceLocation Loc; const HeaderType Access; }; diff --git a/clang/include/clang/Lex/ExternalPreprocessorSource.h b/clang/include/clang/Lex/ExternalPreprocessorSource.h index 685941b66bd8bf4eab40fd2c1d069aaba4d66668..6775841860373cb35d690a3647f7ccf861d679ee 100644 --- a/clang/include/clang/Lex/ExternalPreprocessorSource.h +++ b/clang/include/clang/Lex/ExternalPreprocessorSource.h @@ -31,7 +31,7 @@ public: virtual void ReadDefinedMacros() = 0; /// Update an out-of-date identifier. - virtual void updateOutOfDateIdentifier(IdentifierInfo &II) = 0; + virtual void updateOutOfDateIdentifier(const IdentifierInfo &II) = 0; /// Return the identifier associated with the given ID number. /// diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h index 855f81f775f8a83bedb0fcdb490ec18ba404cdd5..c5f90ef4cb3682a35f0869f81ff3f5a433ca396f 100644 --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -547,14 +547,15 @@ public: /// Return whether the specified file is a normal header, /// a system header, or a C++ friendly system header. SrcMgr::CharacteristicKind getFileDirFlavor(FileEntryRef File) { - return (SrcMgr::CharacteristicKind)getFileInfo(File).DirInfo; + if (const HeaderFileInfo *HFI = getExistingFileInfo(File)) + return (SrcMgr::CharacteristicKind)HFI->DirInfo; + return (SrcMgr::CharacteristicKind)HeaderFileInfo().DirInfo; } /// Mark the specified file as a "once only" file due to /// \#pragma once. void MarkFileIncludeOnce(FileEntryRef File) { - HeaderFileInfo &FI = getFileInfo(File); - FI.isPragmaOnce = true; + getFileInfo(File).isPragmaOnce = true; } /// Mark the specified file as a system header, e.g. due to @@ -834,16 +835,17 @@ public: unsigned header_file_size() const { return FileInfo.size(); } - /// Return the HeaderFileInfo structure for the specified FileEntry, - /// in preparation for updating it in some way. + /// Return the HeaderFileInfo structure for the specified FileEntry, in + /// preparation for updating it in some way. HeaderFileInfo &getFileInfo(FileEntryRef FE); - /// Return the HeaderFileInfo structure for the specified FileEntry, - /// if it has ever been filled in. - /// \param WantExternal Whether the caller wants purely-external header file - /// info (where \p External is true). - const HeaderFileInfo *getExistingFileInfo(FileEntryRef FE, - bool WantExternal = true) const; + /// Return the HeaderFileInfo structure for the specified FileEntry, if it has + /// ever been filled in (either locally or externally). + const HeaderFileInfo *getExistingFileInfo(FileEntryRef FE) const; + + /// Return the headerFileInfo structure for the specified FileEntry, if it has + /// ever been filled in locally. + const HeaderFileInfo *getExistingLocalFileInfo(FileEntryRef FE) const; SearchDirIterator search_dir_begin() { return {*this, 0}; } SearchDirIterator search_dir_end() { return {*this, SearchDirs.size()}; } diff --git a/clang/include/clang/Lex/MacroInfo.h b/clang/include/clang/Lex/MacroInfo.h index 1237fc62eb6cf392e2c5831e0f9bdebd831c9b87..19a706216d5093c07d85a86b4ce3888f551e3cc8 100644 --- a/clang/include/clang/Lex/MacroInfo.h +++ b/clang/include/clang/Lex/MacroInfo.h @@ -515,7 +515,7 @@ class ModuleMacro : public llvm::FoldingSetNode { friend class Preprocessor; /// The name defined by the macro. - IdentifierInfo *II; + const IdentifierInfo *II; /// The body of the #define, or nullptr if this is a #undef. MacroInfo *Macro; @@ -529,7 +529,7 @@ class ModuleMacro : public llvm::FoldingSetNode { /// The number of modules whose macros are directly overridden by this one. unsigned NumOverrides; - ModuleMacro(Module *OwningModule, IdentifierInfo *II, MacroInfo *Macro, + ModuleMacro(Module *OwningModule, const IdentifierInfo *II, MacroInfo *Macro, ArrayRef Overrides) : II(II), Macro(Macro), OwningModule(OwningModule), NumOverrides(Overrides.size()) { @@ -539,7 +539,7 @@ class ModuleMacro : public llvm::FoldingSetNode { public: static ModuleMacro *create(Preprocessor &PP, Module *OwningModule, - IdentifierInfo *II, MacroInfo *Macro, + const IdentifierInfo *II, MacroInfo *Macro, ArrayRef Overrides); void Profile(llvm::FoldingSetNodeID &ID) const { @@ -553,7 +553,7 @@ public: } /// Get the name of the macro. - IdentifierInfo *getName() const { return II; } + const IdentifierInfo *getName() const { return II; } /// Get the ID of the module that exports this macro. Module *getOwningModule() const { return OwningModule; } diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 24e146a589a758baf7080d7dfcd066ec910a8f70..e89b4a2c5230e7612e07ca5fea84b67537a2a001 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -736,19 +736,6 @@ private: State ConditionalStackState = Off; } PreambleConditionalStack; - /// Function for getting the dependency preprocessor directives of a file. - /// - /// These are directives derived from a special form of lexing where the - /// source input is scanned for the preprocessor directives that might have an - /// effect on the dependencies for a compilation unit. - /// - /// Enables a client to cache the directives for a file and provide them - /// across multiple compiler invocations. - /// FIXME: Allow returning an error. - using DependencyDirectivesFn = llvm::unique_function>(FileEntryRef)>; - DependencyDirectivesFn DependencyDirectivesForFile; - /// The current top of the stack that we're lexing from if /// not expanding a macro and we are lexing directly from source code. /// @@ -849,7 +836,7 @@ private: ModuleMacroInfo *getModuleInfo(Preprocessor &PP, const IdentifierInfo *II) const { if (II->isOutOfDate()) - PP.updateOutOfDateIdentifier(const_cast(*II)); + PP.updateOutOfDateIdentifier(*II); // FIXME: Find a spare bit on IdentifierInfo and store a // HasModuleMacros flag. if (!II->hasMacroDefinition() || @@ -1175,7 +1162,7 @@ private: /// skipped. llvm::DenseMap RecordedSkippedRanges; - void updateOutOfDateIdentifier(IdentifierInfo &II) const; + void updateOutOfDateIdentifier(const IdentifierInfo &II) const; public: Preprocessor(std::shared_ptr PPOpts, @@ -1283,11 +1270,6 @@ public: /// false if it is producing tokens to be consumed by Parse and Sema. bool isPreprocessedOutput() const { return PreprocessedOutput; } - /// Set the function used to get dependency directives for a file. - void setDependencyDirectivesFn(DependencyDirectivesFn Fn) { - DependencyDirectivesForFile = std::move(Fn); - } - /// Return true if we are lexing directly from the specified lexer. bool isCurrentLexer(const PreprocessorLexer *L) const { return CurPPLexer == L; @@ -1450,14 +1432,15 @@ public: MacroDirective *MD); /// Register an exported macro for a module and identifier. - ModuleMacro *addModuleMacro(Module *Mod, IdentifierInfo *II, MacroInfo *Macro, + ModuleMacro *addModuleMacro(Module *Mod, const IdentifierInfo *II, + MacroInfo *Macro, ArrayRef Overrides, bool &IsNew); ModuleMacro *getModuleMacro(Module *Mod, const IdentifierInfo *II); /// Get the list of leaf (non-overridden) module macros for a name. ArrayRef getLeafModuleMacros(const IdentifierInfo *II) const { if (II->isOutOfDate()) - updateOutOfDateIdentifier(const_cast(*II)); + updateOutOfDateIdentifier(*II); auto I = LeafModuleMacros.find(II); if (I != LeafModuleMacros.end()) return I->second; diff --git a/clang/include/clang/Lex/PreprocessorOptions.h b/clang/include/clang/Lex/PreprocessorOptions.h index 50b5fba0ff773ec5ba6aa4bdc2d1bcce9a38b02f..635971d0ce5ee8c410ef488628bda2519ab62714 100644 --- a/clang/include/clang/Lex/PreprocessorOptions.h +++ b/clang/include/clang/Lex/PreprocessorOptions.h @@ -186,6 +186,19 @@ public: /// with support for lifetime-qualified pointers. ObjCXXARCStandardLibraryKind ObjCXXARCStandardLibrary = ARCXX_nolib; + /// Function for getting the dependency preprocessor directives of a file. + /// + /// These are directives derived from a special form of lexing where the + /// source input is scanned for the preprocessor directives that might have an + /// effect on the dependencies for a compilation unit. + /// + /// Enables a client to cache the directives for a file and provide them + /// across multiple compiler invocations. + /// FIXME: Allow returning an error. + std::function>( + FileEntryRef)> + DependencyDirectivesForFile; + /// Set up preprocessor for RunAnalysis action. bool SetUpStaticAnalyzer = false; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 580bf2a5d79df516b6e5008c5a7dcd34b6935f66..5950dd74cfe83c7f2457a12b7fd27253bdf2a7cd 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -41,6 +41,7 @@ namespace clang { class InMessageExpressionRAIIObject; class PoisonSEHIdentifiersRAIIObject; class OMPClause; + class OpenACCClause; class ObjCTypeParamList; struct OMPTraitProperty; struct OMPTraitSelector; @@ -328,7 +329,7 @@ class Parser : public CodeCompletionHandler { }; /// Identifiers which have been declared within a tentative parse. - SmallVector TentativelyDeclaredIdentifiers; + SmallVector TentativelyDeclaredIdentifiers; /// Tracker for '<' tokens that might have been intended to be treated as an /// angle bracket instead of a less-than comparison. @@ -1600,6 +1601,8 @@ private: const ParsedTemplateInfo &TemplateInfo, const VirtSpecifiers &VS, SourceLocation PureSpecLoc); + StringLiteral *ParseCXXDeletedFunctionMessage(); + void SkipDeletedFunctionBody(); void ParseCXXNonStaticMemberInitializer(Decl *VarD); void ParseLexedAttributes(ParsingClass &Class); void ParseLexedAttributeList(LateParsedAttrList &LAs, Decl *D, @@ -1926,15 +1929,11 @@ private: bool EnteringContext, IdentifierInfo &II, CXXScopeSpec &SS); - bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, - ParsedType ObjectType, - bool ObjectHasErrors, - bool EnteringContext, - bool *MayBePseudoDestructor = nullptr, - bool IsTypename = false, - IdentifierInfo **LastII = nullptr, - bool OnlyNamespace = false, - bool InUsingDeclaration = false); + bool ParseOptionalCXXScopeSpecifier( + CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHasErrors, + bool EnteringContext, bool *MayBePseudoDestructor = nullptr, + bool IsTypename = false, const IdentifierInfo **LastII = nullptr, + bool OnlyNamespace = false, bool InUsingDeclaration = false); //===--------------------------------------------------------------------===// // C++11 5.1.2: Lambda expressions @@ -3594,11 +3593,26 @@ private: OpenACCDirectiveKind DirKind; SourceLocation StartLoc; SourceLocation EndLoc; - // TODO OpenACC: Add Clause list here once we have a type for that. + SmallVector Clauses; // TODO OpenACC: As we implement support for the Atomic, Routine, Cache, and // Wait constructs, we likely want to put that information in here as well. }; + /// Represents the 'error' state of parsing an OpenACC Clause, and stores + /// whether we can continue parsing, or should give up on the directive. + enum class OpenACCParseCanContinue { Cannot = 0, Can = 1 }; + + /// A type to represent the state of parsing an OpenACC Clause. Situations + /// that result in an OpenACCClause pointer are a success and can continue + /// parsing, however some other situations can also continue. + /// FIXME: This is better represented as a std::expected when we get C++23. + using OpenACCClauseParseResult = + llvm::PointerIntPair; + + OpenACCClauseParseResult OpenACCCanContinue(); + OpenACCClauseParseResult OpenACCCannotContinue(); + OpenACCClauseParseResult OpenACCSuccess(OpenACCClause *Clause); + /// Parses the OpenACC directive (the entire pragma) including the clause /// list, but does not produce the main AST node. OpenACCDirectiveParseInfo ParseOpenACCDirective(); @@ -3613,12 +3627,18 @@ private: bool ParseOpenACCClauseVarList(OpenACCClauseKind Kind); /// Parses any parameters for an OpenACC Clause, including required/optional /// parens. - bool ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, - OpenACCClauseKind Kind); - /// Parses a single clause in a clause-list for OpenACC. - bool ParseOpenACCClause(OpenACCDirectiveKind DirKind); + OpenACCClauseParseResult + ParseOpenACCClauseParams(ArrayRef ExistingClauses, + OpenACCDirectiveKind DirKind, OpenACCClauseKind Kind, + SourceLocation ClauseLoc); + /// Parses a single clause in a clause-list for OpenACC. Returns nullptr on + /// error. + OpenACCClauseParseResult + ParseOpenACCClause(ArrayRef ExistingClauses, + OpenACCDirectiveKind DirKind); /// Parses the clause-list for an OpenACC directive. - void ParseOpenACCClauseList(OpenACCDirectiveKind DirKind); + SmallVector + ParseOpenACCClauseList(OpenACCDirectiveKind DirKind); bool ParseOpenACCWaitArgument(); /// Parses the clause of the 'bind' argument, which can be a string literal or /// an ID expression. @@ -3639,6 +3659,8 @@ private: bool ParseOpenACCGangArgList(); /// Parses a 'gang-arg', used for the 'gang' clause. bool ParseOpenACCGangArg(); + /// Parses a 'condition' expr, ensuring it results in a + ExprResult ParseOpenACCConditionExpr(); private: //===--------------------------------------------------------------------===// diff --git a/clang/include/clang/Sema/CodeCompleteConsumer.h b/clang/include/clang/Sema/CodeCompleteConsumer.h index a2028e40f83d54c1008d78568ad67cfe47479449..0924dc27af82b512331dd3049f41319880c5cd48 100644 --- a/clang/include/clang/Sema/CodeCompleteConsumer.h +++ b/clang/include/clang/Sema/CodeCompleteConsumer.h @@ -362,7 +362,7 @@ private: QualType BaseType; /// The identifiers for Objective-C selector parts. - ArrayRef SelIdents; + ArrayRef SelIdents; /// The scope specifier that comes before the completion token e.g. /// "a::b::" @@ -378,8 +378,9 @@ public: : CCKind(CCKind), IsUsingDeclaration(false), SelIdents(std::nullopt) {} /// Construct a new code-completion context of the given kind. - CodeCompletionContext(Kind CCKind, QualType T, - ArrayRef SelIdents = std::nullopt) + CodeCompletionContext( + Kind CCKind, QualType T, + ArrayRef SelIdents = std::nullopt) : CCKind(CCKind), IsUsingDeclaration(false), SelIdents(SelIdents) { if (CCKind == CCC_DotMemberAccess || CCKind == CCC_ArrowMemberAccess || CCKind == CCC_ObjCPropertyAccess || CCKind == CCC_ObjCClassMessage || @@ -406,7 +407,7 @@ public: QualType getBaseType() const { return BaseType; } /// Retrieve the Objective-C selector identifiers. - ArrayRef getSelIdents() const { return SelIdents; } + ArrayRef getSelIdents() const { return SelIdents; } /// Determines whether we want C++ constructors as results within this /// context. diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index a176159707486c61f618ec55e78d100b1a4a9d0a..c9eecdafe62c7ce148f69dfbfca8f791e129112d 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -1049,7 +1049,7 @@ public: union { /// When Kind == IK_Identifier, the parsed identifier, or when /// Kind == IK_UserLiteralId, the identifier suffix. - IdentifierInfo *Identifier; + const IdentifierInfo *Identifier; /// When Kind == IK_OperatorFunctionId, the overloaded operator /// that we parsed. @@ -1111,7 +1111,7 @@ public: /// \param IdLoc the location of the parsed identifier. void setIdentifier(const IdentifierInfo *Id, SourceLocation IdLoc) { Kind = UnqualifiedIdKind::IK_Identifier; - Identifier = const_cast(Id); + Identifier = Id; StartLocation = EndLocation = IdLoc; } @@ -1154,9 +1154,9 @@ public: /// /// \param IdLoc the location of the identifier. void setLiteralOperatorId(const IdentifierInfo *Id, SourceLocation OpLoc, - SourceLocation IdLoc) { + SourceLocation IdLoc) { Kind = UnqualifiedIdKind::IK_LiteralOperatorId; - Identifier = const_cast(Id); + Identifier = Id; StartLocation = OpLoc; EndLocation = IdLoc; } @@ -1225,7 +1225,7 @@ public: /// \param Id the identifier. void setImplicitSelfParam(const IdentifierInfo *Id) { Kind = UnqualifiedIdKind::IK_ImplicitSelfParam; - Identifier = const_cast(Id); + Identifier = Id; StartLocation = EndLocation = SourceLocation(); } @@ -1327,7 +1327,7 @@ struct DeclaratorChunk { /// Parameter type lists will have type info (if the actions module provides /// it), but may have null identifier info: e.g. for 'void foo(int X, int)'. struct ParamInfo { - IdentifierInfo *Ident; + const IdentifierInfo *Ident; SourceLocation IdentLoc; Decl *Param; @@ -1339,11 +1339,10 @@ struct DeclaratorChunk { std::unique_ptr DefaultArgTokens; ParamInfo() = default; - ParamInfo(IdentifierInfo *ident, SourceLocation iloc, - Decl *param, + ParamInfo(const IdentifierInfo *ident, SourceLocation iloc, Decl *param, std::unique_ptr DefArgTokens = nullptr) - : Ident(ident), IdentLoc(iloc), Param(param), - DefaultArgTokens(std::move(DefArgTokens)) {} + : Ident(ident), IdentLoc(iloc), Param(param), + DefaultArgTokens(std::move(DefArgTokens)) {} }; struct TypeAndRange { @@ -2326,7 +2325,7 @@ public: return BindingGroup.isSet(); } - IdentifierInfo *getIdentifier() const { + const IdentifierInfo *getIdentifier() const { if (Name.getKind() == UnqualifiedIdKind::IK_Identifier) return Name.Identifier; @@ -2335,7 +2334,7 @@ public: SourceLocation getIdentifierLoc() const { return Name.StartLocation; } /// Set the name of this declarator to be the given identifier. - void SetIdentifier(IdentifierInfo *Id, SourceLocation IdLoc) { + void SetIdentifier(const IdentifierInfo *Id, SourceLocation IdLoc) { Name.setIdentifier(Id, IdLoc); } diff --git a/clang/include/clang/Sema/ParsedTemplate.h b/clang/include/clang/Sema/ParsedTemplate.h index 65182d57246ae7209ac06f03449c87f1c4808380..ac4dbbf294caf2f61ff785f992d18d5713cd30d3 100644 --- a/clang/include/clang/Sema/ParsedTemplate.h +++ b/clang/include/clang/Sema/ParsedTemplate.h @@ -159,7 +159,7 @@ namespace clang { SourceLocation TemplateNameLoc; /// FIXME: Temporarily stores the name of a specialization - IdentifierInfo *Name; + const IdentifierInfo *Name; /// FIXME: Temporarily stores the overloaded operator kind. OverloadedOperatorKind Operator; @@ -197,7 +197,7 @@ namespace clang { /// appends it to List. static TemplateIdAnnotation * Create(SourceLocation TemplateKWLoc, SourceLocation TemplateNameLoc, - IdentifierInfo *Name, OverloadedOperatorKind OperatorKind, + const IdentifierInfo *Name, OverloadedOperatorKind OperatorKind, ParsedTemplateTy OpaqueTemplateName, TemplateNameKind TemplateKind, SourceLocation LAngleLoc, SourceLocation RAngleLoc, ArrayRef TemplateArgs, bool ArgsInvalid, @@ -236,7 +236,8 @@ namespace clang { TemplateIdAnnotation(const TemplateIdAnnotation &) = delete; TemplateIdAnnotation(SourceLocation TemplateKWLoc, - SourceLocation TemplateNameLoc, IdentifierInfo *Name, + SourceLocation TemplateNameLoc, + const IdentifierInfo *Name, OverloadedOperatorKind OperatorKind, ParsedTemplateTy OpaqueTemplateName, TemplateNameKind TemplateKind, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f52816e12efe47befeed371926505859fd658d0d..c6035445e90192e8dd0004a522e1bc6f17a53153 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -38,6 +38,7 @@ #include "clang/AST/TypeOrdering.h" #include "clang/Basic/BitmaskEnum.h" #include "clang/Basic/Builtins.h" +#include "clang/Basic/Cuda.h" #include "clang/Basic/DarwinSDKInfo.h" #include "clang/Basic/ExpressionTraits.h" #include "clang/Basic/Module.h" @@ -55,10 +56,12 @@ #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/SemaBase.h" #include "clang/Sema/SemaConcept.h" #include "clang/Sema/TypoCorrection.h" #include "clang/Sema/Weak.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallPtrSet.h" @@ -181,7 +184,10 @@ class Preprocessor; class PseudoDestructorTypeStorage; class PseudoObjectExpr; class QualType; +class SemaCUDA; +class SemaHLSL; class SemaOpenACC; +class SemaSYCL; class StandardConversionSequence; class Stmt; class StringLiteral; @@ -420,9 +426,20 @@ enum class TemplateDeductionResult { AlreadyDiagnosed }; +/// Kinds of C++ special members. +enum class CXXSpecialMemberKind { + DefaultConstructor, + CopyConstructor, + MoveConstructor, + CopyAssignment, + MoveAssignment, + Destructor, + Invalid +}; + /// Sema - This implements semantic analysis and AST building for C. /// \nosubgrouping -class Sema final { +class Sema final : public SemaBase { // Table of Contents // ----------------- // 1. Semantic Analysis (Sema.cpp) @@ -463,10 +480,7 @@ class Sema final { // 35. Code Completion (SemaCodeComplete.cpp) // 36. FixIt Helpers (SemaFixItUtils.cpp) // 37. Name Lookup for RISC-V Vector Intrinsic (SemaRISCVVectorLookup.cpp) - // 38. CUDA (SemaCUDA.cpp) - // 39. HLSL Constructs (SemaHLSL.cpp) - // 40. OpenMP Directives and Clauses (SemaOpenMP.cpp) - // 41. SYCL Constructs (SemaSYCL.cpp) + // 38. OpenMP Directives and Clauses (SemaOpenMP.cpp) /// \name Semantic Analysis /// Implementations are in Sema.cpp @@ -512,195 +526,6 @@ public: /// void addExternalSource(ExternalSemaSource *E); - /// Helper class that creates diagnostics with optional - /// template instantiation stacks. - /// - /// This class provides a wrapper around the basic DiagnosticBuilder - /// class that emits diagnostics. ImmediateDiagBuilder is - /// responsible for emitting the diagnostic (as DiagnosticBuilder - /// does) and, if the diagnostic comes from inside a template - /// instantiation, printing the template instantiation stack as - /// well. - class ImmediateDiagBuilder : public DiagnosticBuilder { - Sema &SemaRef; - unsigned DiagID; - - public: - ImmediateDiagBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) - : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} - ImmediateDiagBuilder(DiagnosticBuilder &&DB, Sema &SemaRef, unsigned DiagID) - : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} - - // This is a cunning lie. DiagnosticBuilder actually performs move - // construction in its copy constructor (but due to varied uses, it's not - // possible to conveniently express this as actual move construction). So - // the default copy ctor here is fine, because the base class disables the - // source anyway, so the user-defined ~ImmediateDiagBuilder is a safe no-op - // in that case anwyay. - ImmediateDiagBuilder(const ImmediateDiagBuilder &) = default; - - ~ImmediateDiagBuilder() { - // If we aren't active, there is nothing to do. - if (!isActive()) - return; - - // Otherwise, we need to emit the diagnostic. First clear the diagnostic - // builder itself so it won't emit the diagnostic in its own destructor. - // - // This seems wasteful, in that as written the DiagnosticBuilder dtor will - // do its own needless checks to see if the diagnostic needs to be - // emitted. However, because we take care to ensure that the builder - // objects never escape, a sufficiently smart compiler will be able to - // eliminate that code. - Clear(); - - // Dispatch to Sema to emit the diagnostic. - SemaRef.EmitCurrentDiagnostic(DiagID); - } - - /// Teach operator<< to produce an object of the correct type. - template - friend const ImmediateDiagBuilder & - operator<<(const ImmediateDiagBuilder &Diag, const T &Value) { - const DiagnosticBuilder &BaseDiag = Diag; - BaseDiag << Value; - return Diag; - } - - // It is necessary to limit this to rvalue reference to avoid calling this - // function with a bitfield lvalue argument since non-const reference to - // bitfield is not allowed. - template ::value>> - const ImmediateDiagBuilder &operator<<(T &&V) const { - const DiagnosticBuilder &BaseDiag = *this; - BaseDiag << std::move(V); - return *this; - } - }; - - /// A generic diagnostic builder for errors which may or may not be deferred. - /// - /// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch) - /// which are not allowed to appear inside __device__ functions and are - /// allowed to appear in __host__ __device__ functions only if the host+device - /// function is never codegen'ed. - /// - /// To handle this, we use the notion of "deferred diagnostics", where we - /// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed. - /// - /// This class lets you emit either a regular diagnostic, a deferred - /// diagnostic, or no diagnostic at all, according to an argument you pass to - /// its constructor, thus simplifying the process of creating these "maybe - /// deferred" diagnostics. - class SemaDiagnosticBuilder { - public: - enum Kind { - /// Emit no diagnostics. - K_Nop, - /// Emit the diagnostic immediately (i.e., behave like Sema::Diag()). - K_Immediate, - /// Emit the diagnostic immediately, and, if it's a warning or error, also - /// emit a call stack showing how this function can be reached by an a - /// priori known-emitted function. - K_ImmediateWithCallStack, - /// Create a deferred diagnostic, which is emitted only if the function - /// it's attached to is codegen'ed. Also emit a call stack as with - /// K_ImmediateWithCallStack. - K_Deferred - }; - - SemaDiagnosticBuilder(Kind K, SourceLocation Loc, unsigned DiagID, - const FunctionDecl *Fn, Sema &S); - SemaDiagnosticBuilder(SemaDiagnosticBuilder &&D); - SemaDiagnosticBuilder(const SemaDiagnosticBuilder &) = default; - - // The copy and move assignment operator is defined as deleted pending - // further motivation. - SemaDiagnosticBuilder &operator=(const SemaDiagnosticBuilder &) = delete; - SemaDiagnosticBuilder &operator=(SemaDiagnosticBuilder &&) = delete; - - ~SemaDiagnosticBuilder(); - - bool isImmediate() const { return ImmediateDiag.has_value(); } - - /// Convertible to bool: True if we immediately emitted an error, false if - /// we didn't emit an error or we created a deferred error. - /// - /// Example usage: - /// - /// if (SemaDiagnosticBuilder(...) << foo << bar) - /// return ExprError(); - /// - /// But see CUDADiagIfDeviceCode() and CUDADiagIfHostCode() -- you probably - /// want to use these instead of creating a SemaDiagnosticBuilder yourself. - operator bool() const { return isImmediate(); } - - template - friend const SemaDiagnosticBuilder & - operator<<(const SemaDiagnosticBuilder &Diag, const T &Value) { - if (Diag.ImmediateDiag) - *Diag.ImmediateDiag << Value; - else if (Diag.PartialDiagId) - Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second - << Value; - return Diag; - } - - // It is necessary to limit this to rvalue reference to avoid calling this - // function with a bitfield lvalue argument since non-const reference to - // bitfield is not allowed. - template ::value>> - const SemaDiagnosticBuilder &operator<<(T &&V) const { - if (ImmediateDiag) - *ImmediateDiag << std::move(V); - else if (PartialDiagId) - S.DeviceDeferredDiags[Fn][*PartialDiagId].second << std::move(V); - return *this; - } - - friend const SemaDiagnosticBuilder & - operator<<(const SemaDiagnosticBuilder &Diag, const PartialDiagnostic &PD) { - if (Diag.ImmediateDiag) - PD.Emit(*Diag.ImmediateDiag); - else if (Diag.PartialDiagId) - Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second = PD; - return Diag; - } - - void AddFixItHint(const FixItHint &Hint) const { - if (ImmediateDiag) - ImmediateDiag->AddFixItHint(Hint); - else if (PartialDiagId) - S.DeviceDeferredDiags[Fn][*PartialDiagId].second.AddFixItHint(Hint); - } - - friend ExprResult ExprError(const SemaDiagnosticBuilder &) { - return ExprError(); - } - friend StmtResult StmtError(const SemaDiagnosticBuilder &) { - return StmtError(); - } - operator ExprResult() const { return ExprError(); } - operator StmtResult() const { return StmtError(); } - operator TypeResult() const { return TypeError(); } - operator DeclResult() const { return DeclResult(true); } - operator MemInitResult() const { return MemInitResult(true); } - - private: - Sema &S; - SourceLocation Loc; - unsigned DiagID; - const FunctionDecl *Fn; - bool ShowCallStack; - - // Invariant: At most one of these Optionals has a value. - // FIXME: Switch these to a Variant once that exists. - std::optional ImmediateDiag; - std::optional PartialDiagId; - }; - void PrintStats() const; /// Warn that the stack is nearly exhausted. @@ -742,14 +567,6 @@ public: void addImplicitTypedef(StringRef Name, QualType T); - /// Emit a diagnostic. - SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, - bool DeferHint = false); - - /// Emit a partial diagnostic. - SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD, - bool DeferHint = false); - /// Whether uncompilable error has occurred. This includes error happens /// in deferred diagnostics. bool hasUncompilableErrorOccurred() const; @@ -764,7 +581,7 @@ public: /// Invent a new identifier for parameters of abbreviated templates. IdentifierInfo * - InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName, + InventAbbreviatedTemplateParameterTypeName(const IdentifierInfo *ParamName, unsigned Index); void emitAndClearUnusedLocalTypedefWarnings(); @@ -1157,14 +974,34 @@ public: return DelayedDiagnostics.push(pool); } + /// Diagnostics that are emitted only if we discover that the given function + /// must be codegen'ed. Because handling these correctly adds overhead to + /// compilation, this is currently only enabled for CUDA compilations. + SemaDiagnosticBuilder::DeferredDiagnosticsType DeviceDeferredDiags; + /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; + SemaCUDA &CUDA() { + assert(CUDAPtr); + return *CUDAPtr; + } + + SemaHLSL &HLSL() { + assert(HLSLPtr); + return *HLSLPtr; + } + SemaOpenACC &OpenACC() { assert(OpenACCPtr); return *OpenACCPtr; } + SemaSYCL &SYCL() { + assert(SYCLPtr); + return *SYCLPtr; + } + protected: friend class Parser; friend class InitializationSequence; @@ -1195,7 +1032,10 @@ private: mutable IdentifierInfo *Ident_super; + std::unique_ptr CUDAPtr; + std::unique_ptr HLSLPtr; std::unique_ptr OpenACCPtr; + std::unique_ptr SYCLPtr; ///@} @@ -2027,10 +1867,10 @@ public: bool IsVariadic, FormatStringInfo *FSI); // Used by C++ template instantiation. - ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall); - ExprResult SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, - SourceLocation BuiltinLoc, - SourceLocation RParenLoc); + ExprResult BuiltinShuffleVector(CallExpr *TheCall); + ExprResult ConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc); enum FormatStringType { FST_Scanf, @@ -2159,10 +1999,17 @@ public: }; bool IsLayoutCompatible(QualType T1, QualType T2) const; + bool IsPointerInterconvertibleBaseOf(const TypeSourceInfo *Base, + const TypeSourceInfo *Derived); bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, const FunctionProtoType *Proto); + bool BuiltinVectorMath(CallExpr *TheCall, QualType &Res); + bool BuiltinVectorToScalarMath(CallExpr *TheCall); + + bool CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + private: void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const ArraySubscriptExpr *ASE = nullptr, @@ -2252,62 +2099,59 @@ private: bool CheckNVPTXBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); - bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall); - bool SemaBuiltinVAStartARMMicrosoft(CallExpr *Call); - bool SemaBuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID); - bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, - unsigned BuiltinID); - bool SemaBuiltinComplex(CallExpr *TheCall); - bool SemaBuiltinVSX(CallExpr *TheCall); - bool SemaBuiltinOSLogFormat(CallExpr *TheCall); - bool SemaValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum); - - bool SemaBuiltinPrefetch(CallExpr *TheCall); - bool SemaBuiltinAllocaWithAlign(CallExpr *TheCall); - bool SemaBuiltinArithmeticFence(CallExpr *TheCall); - bool SemaBuiltinAssume(CallExpr *TheCall); - bool SemaBuiltinAssumeAligned(CallExpr *TheCall); - bool SemaBuiltinLongjmp(CallExpr *TheCall); - bool SemaBuiltinSetjmp(CallExpr *TheCall); - ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult); - ExprResult SemaBuiltinNontemporalOverloaded(ExprResult TheCallResult); - ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult, - AtomicExpr::AtomicOp Op); - bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, - llvm::APSInt &Result); - bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, - int High, bool RangeIsError = true); - bool SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, - unsigned Multiple); - bool SemaBuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum); - bool SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, - unsigned ArgBits); - bool SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, int ArgNum, - unsigned ArgBits); - bool SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, - int ArgNum, unsigned ExpectedFieldNum, - bool AllowName); - bool SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall); - bool SemaBuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, - const char *TypeDesc); + bool BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall); + bool BuiltinVAStartARMMicrosoft(CallExpr *Call); + bool BuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID); + bool BuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, + unsigned BuiltinID); + bool BuiltinComplex(CallExpr *TheCall); + bool BuiltinVSX(CallExpr *TheCall); + bool BuiltinOSLogFormat(CallExpr *TheCall); + bool ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum); + + bool BuiltinPrefetch(CallExpr *TheCall); + bool BuiltinAllocaWithAlign(CallExpr *TheCall); + bool BuiltinArithmeticFence(CallExpr *TheCall); + bool BuiltinAssume(CallExpr *TheCall); + bool BuiltinAssumeAligned(CallExpr *TheCall); + bool BuiltinLongjmp(CallExpr *TheCall); + bool BuiltinSetjmp(CallExpr *TheCall); + ExprResult BuiltinAtomicOverloaded(ExprResult TheCallResult); + ExprResult BuiltinNontemporalOverloaded(ExprResult TheCallResult); + ExprResult AtomicOpsOverloaded(ExprResult TheCallResult, + AtomicExpr::AtomicOp Op); + bool BuiltinConstantArg(CallExpr *TheCall, int ArgNum, llvm::APSInt &Result); + bool BuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, int High, + bool RangeIsError = true); + bool BuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, + unsigned Multiple); + bool BuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum); + bool BuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, + unsigned ArgBits); + bool BuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, int ArgNum, + unsigned ArgBits); + bool BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, int ArgNum, + unsigned ExpectedFieldNum, bool AllowName); + bool BuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall); + bool BuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, + const char *TypeDesc); bool CheckPPCMMAType(QualType Type, SourceLocation TypeLoc); - bool SemaBuiltinElementwiseMath(CallExpr *TheCall); - bool SemaBuiltinElementwiseTernaryMath(CallExpr *TheCall, - bool CheckForFloatArgs = true); + bool BuiltinElementwiseMath(CallExpr *TheCall); + bool BuiltinElementwiseTernaryMath(CallExpr *TheCall, + bool CheckForFloatArgs = true); bool PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall); bool PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall); - bool SemaBuiltinNonDeterministicValue(CallExpr *TheCall); + bool BuiltinNonDeterministicValue(CallExpr *TheCall); // Matrix builtin handling. - ExprResult SemaBuiltinMatrixTranspose(CallExpr *TheCall, - ExprResult CallResult); - ExprResult SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall, - ExprResult CallResult); - ExprResult SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall, - ExprResult CallResult); + ExprResult BuiltinMatrixTranspose(CallExpr *TheCall, ExprResult CallResult); + ExprResult BuiltinMatrixColumnMajorLoad(CallExpr *TheCall, + ExprResult CallResult); + ExprResult BuiltinMatrixColumnMajorStore(CallExpr *TheCall, + ExprResult CallResult); // WebAssembly builtin handling. bool BuiltinWasmRefNullExtern(CallExpr *TheCall); @@ -3122,13 +2966,6 @@ public: QualType NewT, QualType OldT); void CheckMain(FunctionDecl *FD, const DeclSpec &D); void CheckMSVCRTEntryPoint(FunctionDecl *FD); - void ActOnHLSLTopLevelFunction(FunctionDecl *FD); - void CheckHLSLEntryPoint(FunctionDecl *FD); - void CheckHLSLSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param, - const HLSLAnnotationAttr *AnnotationAttr); - void DiagnoseHLSLAttrStageMismatch( - const Attr *A, HLSLShaderAttr::ShaderType Stage, - std::initializer_list AllowedStages); Attr *getImplicitCodeSegOrSectionAttrForFunction(const FunctionDecl *FD, bool IsDefinition); void CheckFunctionOrTemplateParamDeclarator(Scope *S, Declarator &D); @@ -3140,9 +2977,9 @@ public: SourceLocation NameLoc, TypeSourceInfo *TSInfo); ParmVarDecl *CheckParameter(DeclContext *DC, SourceLocation StartLoc, - SourceLocation NameLoc, IdentifierInfo *Name, - QualType T, TypeSourceInfo *TSInfo, - StorageClass SC); + SourceLocation NameLoc, + const IdentifierInfo *Name, QualType T, + TypeSourceInfo *TSInfo, StorageClass SC); // Contexts where using non-trivial C union types can be disallowed. This is // passed to err_non_trivial_c_union_in_invalid_context. @@ -3208,14 +3045,18 @@ public: void ActOnDocumentableDecls(ArrayRef Group); enum class FnBodyKind { - /// C++ [dcl.fct.def.general]p1 + /// C++26 [dcl.fct.def.general]p1 /// function-body: /// ctor-initializer[opt] compound-statement /// function-try-block Other, /// = default ; Default, + /// deleted-function-body + /// + /// deleted-function-body: /// = delete ; + /// = delete ( unevaluated-string ) ; Delete }; @@ -3547,7 +3388,7 @@ public: /// variable. void DiagnoseUnusedButSetDecl(const VarDecl *VD, DiagReceiverTy DiagReceiver); - ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, + ObjCInterfaceDecl *getObjCInterfaceDecl(const IdentifierInfo *&Id, SourceLocation IdLoc, bool TypoCorrection = false); @@ -3624,8 +3465,9 @@ public: /// VerifyBitField - verifies that a bit field expression is an ICE and has /// the correct width, and that the field type is valid. /// Returns false on success. - ExprResult VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, - QualType FieldTy, bool IsMsStruct, Expr *BitWidth); + ExprResult VerifyBitField(SourceLocation FieldLoc, + const IdentifierInfo *FieldName, QualType FieldTy, + bool IsMsStruct, Expr *BitWidth); /// IsValueInFlagEnum - Determine if a value is allowed as part of a flag /// enum. If AllowMask is true, then we also allow the complement of a valid @@ -3839,20 +3681,12 @@ public: InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, const InternalLinkageAttr &AL); - enum CUDAFunctionTarget { - CFT_Device, - CFT_Global, - CFT_Host, - CFT_HostDevice, - CFT_InvalidTarget - }; - /// Check validaty of calling convention attribute \p attr. If \p FD /// is not null pointer, use \p FD to determine the CUDA/HIP host/device /// target. Otherwise, it is specified by \p CFT. - bool CheckCallingConvAttr(const ParsedAttr &attr, CallingConv &CC, - const FunctionDecl *FD = nullptr, - CUDAFunctionTarget CFT = CFT_InvalidTarget); + bool CheckCallingConvAttr( + const ParsedAttr &attr, CallingConv &CC, const FunctionDecl *FD = nullptr, + CUDAFunctionTarget CFT = CUDAFunctionTarget::InvalidTarget); void AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI, ParameterABI ABI); @@ -3889,14 +3723,6 @@ public: StringRef UuidAsWritten, MSGuidDecl *GuidDecl); BTFDeclTagAttr *mergeBTFDeclTagAttr(Decl *D, const BTFDeclTagAttr &AL); - HLSLNumThreadsAttr *mergeHLSLNumThreadsAttr(Decl *D, - const AttributeCommonInfo &AL, - int X, int Y, int Z); - HLSLShaderAttr *mergeHLSLShaderAttr(Decl *D, const AttributeCommonInfo &AL, - HLSLShaderAttr::ShaderType ShaderType); - HLSLParamModifierAttr * - mergeHLSLParamModifierAttr(Decl *D, const AttributeCommonInfo &AL, - HLSLParamModifierAttr::Spelling Spelling); WebAssemblyImportNameAttr * mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL); @@ -4273,22 +4099,11 @@ public: SourceRange SpecificationRange, ArrayRef DynamicExceptions, ArrayRef DynamicExceptionRanges, Expr *NoexceptExpr); - /// Kinds of C++ special members. - enum CXXSpecialMember { - CXXDefaultConstructor, - CXXCopyConstructor, - CXXMoveConstructor, - CXXCopyAssignment, - CXXMoveAssignment, - CXXDestructor, - CXXInvalid - }; - class InheritedConstructorInfo; /// Determine if a special member function should have a deleted /// definition when it is defaulted. - bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, + bool ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMemberKind CSM, InheritedConstructorInfo *ICI = nullptr, bool Diagnose = false); @@ -4654,7 +4469,7 @@ public: void CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *MD); bool CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, - CXXSpecialMember CSM, + CXXSpecialMemberKind CSM, SourceLocation DefaultLoc); void CheckDelayedMemberExceptionSpecs(); @@ -4814,13 +4629,14 @@ public: void CheckCXXDefaultArguments(FunctionDecl *FD); void CheckExtraCXXDefaultArguments(Declarator &D); - CXXSpecialMember getSpecialMember(const CXXMethodDecl *MD) { + CXXSpecialMemberKind getSpecialMember(const CXXMethodDecl *MD) { return getDefaultedFunctionKind(MD).asSpecialMember(); } VarDecl *BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id); + SourceLocation IdLoc, + const IdentifierInfo *Id); Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D); @@ -4840,7 +4656,8 @@ public: AccessSpecifier AS, const ParsedAttr &MSPropertyAttr); - void DiagnoseNontrivial(const CXXRecordDecl *Record, CXXSpecialMember CSM); + void DiagnoseNontrivial(const CXXRecordDecl *Record, + CXXSpecialMemberKind CSM); enum TrivialABIHandling { /// The triviality of a method unaffected by "trivial_abi". @@ -4850,26 +4667,31 @@ public: TAH_ConsiderTrivialABI }; - bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, + bool SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMemberKind CSM, TrivialABIHandling TAH = TAH_IgnoreTrivialABI, bool Diagnose = false); /// For a defaulted function, the kind of defaulted function that it is. class DefaultedFunctionKind { + LLVM_PREFERRED_TYPE(CXXSpecialMemberKind) unsigned SpecialMember : 8; unsigned Comparison : 8; public: DefaultedFunctionKind() - : SpecialMember(CXXInvalid), + : SpecialMember(llvm::to_underlying(CXXSpecialMemberKind::Invalid)), Comparison(llvm::to_underlying(DefaultedComparisonKind::None)) {} - DefaultedFunctionKind(CXXSpecialMember CSM) - : SpecialMember(CSM), + DefaultedFunctionKind(CXXSpecialMemberKind CSM) + : SpecialMember(llvm::to_underlying(CSM)), Comparison(llvm::to_underlying(DefaultedComparisonKind::None)) {} DefaultedFunctionKind(DefaultedComparisonKind Comp) - : SpecialMember(CXXInvalid), Comparison(llvm::to_underlying(Comp)) {} + : SpecialMember(llvm::to_underlying(CXXSpecialMemberKind::Invalid)), + Comparison(llvm::to_underlying(Comp)) {} - bool isSpecialMember() const { return SpecialMember != CXXInvalid; } + bool isSpecialMember() const { + return static_cast(SpecialMember) != + CXXSpecialMemberKind::Invalid; + } bool isComparison() const { return static_cast(Comparison) != DefaultedComparisonKind::None; @@ -4879,8 +4701,8 @@ public: return isSpecialMember() || isComparison(); } - CXXSpecialMember asSpecialMember() const { - return static_cast(SpecialMember); + CXXSpecialMemberKind asSpecialMember() const { + return static_cast(SpecialMember); } DefaultedComparisonKind asComparison() const { return static_cast(Comparison); @@ -4888,7 +4710,8 @@ public: /// Get the index of this function kind for use in diagnostics. unsigned getDiagnosticIndex() const { - static_assert(CXXInvalid > CXXDestructor, + static_assert(llvm::to_underlying(CXXSpecialMemberKind::Invalid) > + llvm::to_underlying(CXXSpecialMemberKind::Destructor), "invalid should have highest index"); static_assert((unsigned)DefaultedComparisonKind::None == 0, "none should be equal to zero"); @@ -4932,10 +4755,12 @@ public: SourceLocation EqualLoc); void ActOnPureSpecifier(Decl *D, SourceLocation PureSpecLoc); - void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc); + void SetDeclDeleted(Decl *dcl, SourceLocation DelLoc, + StringLiteral *Message = nullptr); void SetDeclDefaulted(Decl *dcl, SourceLocation DefaultLoc); - void SetFunctionBodyKind(Decl *D, SourceLocation Loc, FnBodyKind BodyKind); + void SetFunctionBodyKind(Decl *D, SourceLocation Loc, FnBodyKind BodyKind, + StringLiteral *DeletedMessage = nullptr); void ActOnStartTrailingRequiresClause(Scope *S, Declarator &D); ExprResult ActOnFinishTrailingRequiresClause(ExprResult ConstraintExpr); ExprResult ActOnRequiresClause(ExprResult ConstraintExpr); @@ -4994,7 +4819,7 @@ public: /// definition in this translation unit. llvm::MapVector UndefinedButUsed; - typedef llvm::PointerIntPair + typedef llvm::PointerIntPair SpecialMemberDecl; /// The C++ special members which we are currently in the process of @@ -5643,15 +5468,6 @@ public: ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val); - ExprResult BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc, - SourceLocation LParen, - SourceLocation RParen, - TypeSourceInfo *TSI); - ExprResult ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc, - SourceLocation LParen, - SourceLocation RParen, - ParsedType ParsedTy); - bool CheckLoopHintExpr(Expr *E, SourceLocation Loc); ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr); @@ -6746,12 +6562,12 @@ public: ParsedType getInheritingConstructorName(CXXScopeSpec &SS, SourceLocation NameLoc, - IdentifierInfo &Name); + const IdentifierInfo &Name); - ParsedType getConstructorName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, CXXScopeSpec &SS, - bool EnteringContext); - ParsedType getDestructorName(IdentifierInfo &II, SourceLocation NameLoc, + ParsedType getConstructorName(const IdentifierInfo &II, + SourceLocation NameLoc, Scope *S, + CXXScopeSpec &SS, bool EnteringContext); + ParsedType getDestructorName(const IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext); @@ -7151,7 +6967,7 @@ public: concepts::Requirement *ActOnTypeRequirement(SourceLocation TypenameKWLoc, CXXScopeSpec &SS, SourceLocation NameLoc, - IdentifierInfo *TypeName, + const IdentifierInfo *TypeName, TemplateIdAnnotation *TemplateId); concepts::Requirement *ActOnCompoundRequirement(Expr *E, SourceLocation NoexceptLoc); @@ -7182,8 +6998,8 @@ public: SourceLocation ClosingBraceLoc); private: - ExprResult SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, - bool IsDelete); + ExprResult BuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, + bool IsDelete); void AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE); void AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, @@ -7689,7 +7505,7 @@ public: }; SpecialMemberOverloadResult - LookupSpecialMember(CXXRecordDecl *D, CXXSpecialMember SM, bool ConstArg, + LookupSpecialMember(CXXRecordDecl *D, CXXSpecialMemberKind SM, bool ConstArg, bool VolatileArg, bool RValueThis, bool ConstThis, bool VolatileThis); @@ -8275,6 +8091,11 @@ public: bool IsFunctionConversion(QualType FromType, QualType ToType, QualType &ResultTy); bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType); + void DiagnoseUseOfDeletedFunction(SourceLocation Loc, SourceRange Range, + DeclarationName Name, + OverloadCandidateSet &CandidateSet, + FunctionDecl *Fn, MultiExprArg Args, + bool IsMember = false); ExprResult InitializeExplicitObjectArgument(Sema &S, Expr *Obj, FunctionDecl *Fun); @@ -9253,7 +9074,7 @@ public: Expr *DefaultArg); NamedDecl *ActOnTemplateTemplateParameter( Scope *S, SourceLocation TmpLoc, TemplateParameterList *Params, - SourceLocation EllipsisLoc, IdentifierInfo *ParamName, + bool Typename, SourceLocation EllipsisLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, ParsedTemplateArgument DefaultArg); @@ -9307,7 +9128,7 @@ public: TypeResult ActOnTemplateIdType(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - TemplateTy Template, IdentifierInfo *TemplateII, + TemplateTy Template, const IdentifierInfo *TemplateII, SourceLocation TemplateIILoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, bool IsCtorOrDtorName = false, bool IsClassName = false, @@ -9648,7 +9469,7 @@ public: TypeResult ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, const CXXScopeSpec &SS, SourceLocation TemplateLoc, - TemplateTy TemplateName, IdentifierInfo *TemplateII, + TemplateTy TemplateName, const IdentifierInfo *TemplateII, SourceLocation TemplateIILoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc); @@ -9726,14 +9547,15 @@ public: Decl *ActOnConceptDefinition(Scope *S, MultiTemplateParamsArg TemplateParameterLists, - IdentifierInfo *Name, SourceLocation NameLoc, - Expr *ConstraintExpr); + const IdentifierInfo *Name, + SourceLocation NameLoc, Expr *ConstraintExpr); void CheckConceptRedefinition(ConceptDecl *NewDecl, LookupResult &Previous, bool &AddToScope); TypeResult ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, - const CXXScopeSpec &SS, IdentifierInfo *Name, + const CXXScopeSpec &SS, + const IdentifierInfo *Name, SourceLocation TagLoc, SourceLocation NameLoc); void MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD, @@ -10209,7 +10031,7 @@ public: unsigned NumCallArgs; /// The special member being declared or defined. - CXXSpecialMember SpecialMember; + CXXSpecialMemberKind SpecialMember; }; ArrayRef template_arguments() const { @@ -10265,7 +10087,7 @@ public: /// Note that we are instantiating a type alias template declaration. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, - TypeAliasTemplateDecl *Template, + TypeAliasTemplateDecl *Entity, ArrayRef TemplateArgs, SourceRange InstantiationRange = SourceRange()); @@ -12179,22 +12001,22 @@ public: SkipBodyInfo *SkipBody); ObjCCategoryDecl *ActOnStartCategoryInterface( - SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, + SourceLocation AtInterfaceLoc, const IdentifierInfo *ClassName, SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, - IdentifierInfo *CategoryName, SourceLocation CategoryLoc, + const IdentifierInfo *CategoryName, SourceLocation CategoryLoc, Decl *const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, const ParsedAttributesView &AttrList); ObjCImplementationDecl *ActOnStartClassImplementation( - SourceLocation AtClassImplLoc, IdentifierInfo *ClassName, - SourceLocation ClassLoc, IdentifierInfo *SuperClassname, + SourceLocation AtClassImplLoc, const IdentifierInfo *ClassName, + SourceLocation ClassLoc, const IdentifierInfo *SuperClassname, SourceLocation SuperClassLoc, const ParsedAttributesView &AttrList); ObjCCategoryImplDecl *ActOnStartCategoryImplementation( - SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, - SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc, - const ParsedAttributesView &AttrList); + SourceLocation AtCatImplLoc, const IdentifierInfo *ClassName, + SourceLocation ClassLoc, const IdentifierInfo *CatName, + SourceLocation CatLoc, const ParsedAttributesView &AttrList); DeclGroupPtrTy ActOnFinishObjCImplementation(Decl *ObjCImpDecl, ArrayRef Decls); @@ -12377,11 +12199,13 @@ public: bool CheckObjCDeclScope(Decl *D); void ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, - IdentifierInfo *ClassName, SmallVectorImpl &Decls); + const IdentifierInfo *ClassName, + SmallVectorImpl &Decls); VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, bool Invalid = false); + const IdentifierInfo *Id, + bool Invalid = false); Decl *ActOnObjCExceptionDecl(Scope *S, Declarator &D); @@ -12498,8 +12322,8 @@ public: SourceLocation SuperLoc, QualType SuperType, bool Super); - ExprResult ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, - IdentifierInfo &propertyName, + ExprResult ActOnClassPropertyRefExpr(const IdentifierInfo &receiverName, + const IdentifierInfo &propertyName, SourceLocation receiverNameLoc, SourceLocation propertyNameLoc); @@ -12974,18 +12798,18 @@ public: bool IsParameter); void CodeCompleteObjCMessageReceiver(Scope *S); void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, - ArrayRef SelIdents, + ArrayRef SelIdents, bool AtArgumentExpression); void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, - ArrayRef SelIdents, + ArrayRef SelIdents, bool AtArgumentExpression, bool IsSuper = false); - void CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, - ArrayRef SelIdents, - bool AtArgumentExpression, - ObjCInterfaceDecl *Super = nullptr); + void CodeCompleteObjCInstanceMessage( + Scope *S, Expr *Receiver, ArrayRef SelIdents, + bool AtArgumentExpression, ObjCInterfaceDecl *Super = nullptr); void CodeCompleteObjCForCollection(Scope *S, DeclGroupPtrTy IterationVar); - void CodeCompleteObjCSelector(Scope *S, ArrayRef SelIdents); + void CodeCompleteObjCSelector(Scope *S, + ArrayRef SelIdents); void CodeCompleteObjCProtocolReferences(ArrayRef Protocols); void CodeCompleteObjCProtocolDecl(Scope *S); @@ -13005,11 +12829,11 @@ public: void CodeCompleteObjCMethodDecl(Scope *S, std::optional IsInstanceMethod, ParsedType ReturnType); - void CodeCompleteObjCMethodDeclSelector(Scope *S, bool IsInstanceMethod, - bool AtParameterName, - ParsedType ReturnType, - ArrayRef SelIdents); - void CodeCompleteObjCClassPropertyRefExpr(Scope *S, IdentifierInfo &ClassName, + void CodeCompleteObjCMethodDeclSelector( + Scope *S, bool IsInstanceMethod, bool AtParameterName, + ParsedType ReturnType, ArrayRef SelIdents); + void CodeCompleteObjCClassPropertyRefExpr(Scope *S, + const IdentifierInfo &ClassName, SourceLocation ClassNameLoc, bool IsBaseExprStatement); void CodeCompletePreprocessorDirective(bool InConditional); @@ -13093,282 +12917,6 @@ private: // // - /// \name CUDA - /// Implementations are in SemaCUDA.cpp - ///@{ - -public: - /// Increments our count of the number of times we've seen a pragma forcing - /// functions to be __host__ __device__. So long as this count is greater - /// than zero, all functions encountered will be __host__ __device__. - void PushForceCUDAHostDevice(); - - /// Decrements our count of the number of times we've seen a pragma forcing - /// functions to be __host__ __device__. Returns false if the count is 0 - /// before incrementing, so you can emit an error. - bool PopForceCUDAHostDevice(); - - ExprResult ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, - MultiExprArg ExecConfig, - SourceLocation GGGLoc); - - /// Diagnostics that are emitted only if we discover that the given function - /// must be codegen'ed. Because handling these correctly adds overhead to - /// compilation, this is currently only enabled for CUDA compilations. - llvm::DenseMap, - std::vector> - DeviceDeferredDiags; - - /// A pair of a canonical FunctionDecl and a SourceLocation. When used as the - /// key in a hashtable, both the FD and location are hashed. - struct FunctionDeclAndLoc { - CanonicalDeclPtr FD; - SourceLocation Loc; - }; - - /// FunctionDecls and SourceLocations for which CheckCUDACall has emitted a - /// (maybe deferred) "bad call" diagnostic. We use this to avoid emitting the - /// same deferred diag twice. - llvm::DenseSet LocsWithCUDACallDiags; - - /// An inverse call graph, mapping known-emitted functions to one of their - /// known-emitted callers (plus the location of the call). - /// - /// Functions that we can tell a priori must be emitted aren't added to this - /// map. - llvm::DenseMap, - /* Caller = */ FunctionDeclAndLoc> - DeviceKnownEmittedFns; - - /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current - /// context is "used as device code". - /// - /// - If CurContext is a __host__ function, does not emit any diagnostics - /// unless \p EmitOnBothSides is true. - /// - If CurContext is a __device__ or __global__ function, emits the - /// diagnostics immediately. - /// - If CurContext is a __host__ __device__ function and we are compiling for - /// the device, creates a diagnostic which is emitted if and when we realize - /// that the function will be codegen'ed. - /// - /// Example usage: - /// - /// // Variable-length arrays are not allowed in CUDA device code. - /// if (CUDADiagIfDeviceCode(Loc, diag::err_cuda_vla) << CurrentCUDATarget()) - /// return ExprError(); - /// // Otherwise, continue parsing as normal. - SemaDiagnosticBuilder CUDADiagIfDeviceCode(SourceLocation Loc, - unsigned DiagID); - - /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current - /// context is "used as host code". - /// - /// Same as CUDADiagIfDeviceCode, with "host" and "device" switched. - SemaDiagnosticBuilder CUDADiagIfHostCode(SourceLocation Loc, unsigned DiagID); - - /// Determines whether the given function is a CUDA device/host/kernel/etc. - /// function. - /// - /// Use this rather than examining the function's attributes yourself -- you - /// will get it wrong. Returns CFT_Host if D is null. - CUDAFunctionTarget IdentifyCUDATarget(const FunctionDecl *D, - bool IgnoreImplicitHDAttr = false); - CUDAFunctionTarget IdentifyCUDATarget(const ParsedAttributesView &Attrs); - - enum CUDAVariableTarget { - CVT_Device, /// Emitted on device side with a shadow variable on host side - CVT_Host, /// Emitted on host side only - CVT_Both, /// Emitted on both sides with different addresses - CVT_Unified, /// Emitted as a unified address, e.g. managed variables - }; - /// Determines whether the given variable is emitted on host or device side. - CUDAVariableTarget IdentifyCUDATarget(const VarDecl *D); - - /// Defines kinds of CUDA global host/device context where a function may be - /// called. - enum CUDATargetContextKind { - CTCK_Unknown, /// Unknown context - CTCK_InitGlobalVar, /// Function called during global variable - /// initialization - }; - - /// Define the current global CUDA host/device context where a function may be - /// called. Only used when a function is called outside of any functions. - struct CUDATargetContext { - CUDAFunctionTarget Target = CFT_HostDevice; - CUDATargetContextKind Kind = CTCK_Unknown; - Decl *D = nullptr; - } CurCUDATargetCtx; - - struct CUDATargetContextRAII { - Sema &S; - CUDATargetContext SavedCtx; - CUDATargetContextRAII(Sema &S_, CUDATargetContextKind K, Decl *D); - ~CUDATargetContextRAII() { S.CurCUDATargetCtx = SavedCtx; } - }; - - /// Gets the CUDA target for the current context. - CUDAFunctionTarget CurrentCUDATarget() { - return IdentifyCUDATarget(dyn_cast(CurContext)); - } - - static bool isCUDAImplicitHostDeviceFunction(const FunctionDecl *D); - - // CUDA function call preference. Must be ordered numerically from - // worst to best. - enum CUDAFunctionPreference { - CFP_Never, // Invalid caller/callee combination. - CFP_WrongSide, // Calls from host-device to host or device - // function that do not match current compilation - // mode. - CFP_HostDevice, // Any calls to host/device functions. - CFP_SameSide, // Calls from host-device to host or device - // function matching current compilation mode. - CFP_Native, // host-to-host or device-to-device calls. - }; - - /// Identifies relative preference of a given Caller/Callee - /// combination, based on their host/device attributes. - /// \param Caller function which needs address of \p Callee. - /// nullptr in case of global context. - /// \param Callee target function - /// - /// \returns preference value for particular Caller/Callee combination. - CUDAFunctionPreference IdentifyCUDAPreference(const FunctionDecl *Caller, - const FunctionDecl *Callee); - - /// Determines whether Caller may invoke Callee, based on their CUDA - /// host/device attributes. Returns false if the call is not allowed. - /// - /// Note: Will return true for CFP_WrongSide calls. These may appear in - /// semantically correct CUDA programs, but only if they're never codegen'ed. - bool IsAllowedCUDACall(const FunctionDecl *Caller, - const FunctionDecl *Callee) { - return IdentifyCUDAPreference(Caller, Callee) != CFP_Never; - } - - /// May add implicit CUDAHostAttr and CUDADeviceAttr attributes to FD, - /// depending on FD and the current compilation settings. - void maybeAddCUDAHostDeviceAttrs(FunctionDecl *FD, - const LookupResult &Previous); - - /// May add implicit CUDAConstantAttr attribute to VD, depending on VD - /// and current compilation settings. - void MaybeAddCUDAConstantAttr(VarDecl *VD); - - /// Check whether we're allowed to call Callee from the current context. - /// - /// - If the call is never allowed in a semantically-correct program - /// (CFP_Never), emits an error and returns false. - /// - /// - If the call is allowed in semantically-correct programs, but only if - /// it's never codegen'ed (CFP_WrongSide), creates a deferred diagnostic to - /// be emitted if and when the caller is codegen'ed, and returns true. - /// - /// Will only create deferred diagnostics for a given SourceLocation once, - /// so you can safely call this multiple times without generating duplicate - /// deferred errors. - /// - /// - Otherwise, returns true without emitting any diagnostics. - bool CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee); - - void CUDACheckLambdaCapture(CXXMethodDecl *D, const sema::Capture &Capture); - - /// Set __device__ or __host__ __device__ attributes on the given lambda - /// operator() method. - /// - /// CUDA lambdas by default is host device function unless it has explicit - /// host or device attribute. - void CUDASetLambdaAttrs(CXXMethodDecl *Method); - - /// Record \p FD if it is a CUDA/HIP implicit host device function used on - /// device side in device compilation. - void CUDARecordImplicitHostDeviceFuncUsedByDevice(const FunctionDecl *FD); - - /// Finds a function in \p Matches with highest calling priority - /// from \p Caller context and erases all functions with lower - /// calling priority. - void EraseUnwantedCUDAMatches( - const FunctionDecl *Caller, - SmallVectorImpl> &Matches); - - /// Given a implicit special member, infer its CUDA target from the - /// calls it needs to make to underlying base/field special members. - /// \param ClassDecl the class for which the member is being created. - /// \param CSM the kind of special member. - /// \param MemberDecl the special member itself. - /// \param ConstRHS true if this is a copy operation with a const object on - /// its RHS. - /// \param Diagnose true if this call should emit diagnostics. - /// \return true if there was an error inferring. - /// The result of this call is implicit CUDA target attribute(s) attached to - /// the member declaration. - bool inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, - CXXSpecialMember CSM, - CXXMethodDecl *MemberDecl, - bool ConstRHS, bool Diagnose); - - /// \return true if \p CD can be considered empty according to CUDA - /// (E.2.3.1 in CUDA 7.5 Programming guide). - bool isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD); - bool isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *CD); - - // \brief Checks that initializers of \p Var satisfy CUDA restrictions. In - // case of error emits appropriate diagnostic and invalidates \p Var. - // - // \details CUDA allows only empty constructors as initializers for global - // variables (see E.2.3.1, CUDA 7.5). The same restriction also applies to all - // __shared__ variables whether they are local or not (they all are implicitly - // static in CUDA). One exception is that CUDA allows constant initializers - // for __constant__ and __device__ variables. - void checkAllowedCUDAInitializer(VarDecl *VD); - - /// Check whether NewFD is a valid overload for CUDA. Emits - /// diagnostics and invalidates NewFD if not. - void checkCUDATargetOverload(FunctionDecl *NewFD, - const LookupResult &Previous); - /// Copies target attributes from the template TD to the function FD. - void inheritCUDATargetAttrs(FunctionDecl *FD, const FunctionTemplateDecl &TD); - - /// Returns the name of the launch configuration function. This is the name - /// of the function that will be called to configure kernel call, with the - /// parameters specified via <<<>>>. - std::string getCudaConfigureFuncName() const; - -private: - unsigned ForceCUDAHostDeviceDepth = 0; - - ///@} - - // - // - // ------------------------------------------------------------------------- - // - // - - /// \name HLSL Constructs - /// Implementations are in SemaHLSL.cpp - ///@{ - -public: - Decl *ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer, - SourceLocation KwLoc, IdentifierInfo *Ident, - SourceLocation IdentLoc, SourceLocation LBrace); - void ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace); - - bool CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - - bool SemaBuiltinVectorMath(CallExpr *TheCall, QualType &Res); - bool SemaBuiltinVectorToScalarMath(CallExpr *TheCall); - - ///@} - - // - // - // ------------------------------------------------------------------------- - // - // - /// \name OpenMP Directives and Clauses /// Implementations are in SemaOpenMP.cpp ///@{ @@ -14729,44 +14277,6 @@ private: OpenMPDirectiveKind CancelRegion); ///@} - - // - // - // ------------------------------------------------------------------------- - // - // - - /// \name SYCL Constructs - /// Implementations are in SemaSYCL.cpp - ///@{ - -public: - /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current - /// context is "used as device code". - /// - /// - If CurLexicalContext is a kernel function or it is known that the - /// function will be emitted for the device, emits the diagnostics - /// immediately. - /// - If CurLexicalContext is a function and we are compiling - /// for the device, but we don't know that this function will be codegen'ed - /// for devive yet, creates a diagnostic which is emitted if and when we - /// realize that the function will be codegen'ed. - /// - /// Example usage: - /// - /// Diagnose __float128 type usage only from SYCL device code if the current - /// target doesn't support it - /// if (!S.Context.getTargetInfo().hasFloat128Type() && - /// S.getLangOpts().SYCLIsDevice) - /// SYCLDiagIfDeviceCode(Loc, diag::err_type_unsupported) << "__float128"; - SemaDiagnosticBuilder SYCLDiagIfDeviceCode(SourceLocation Loc, - unsigned DiagID); - - void deepTypeCheckForSYCLDevice(SourceLocation UsedAt, - llvm::DenseSet Visited, - ValueDecl *DeclToCheck); - - ///@} }; DeductionFailureInfo @@ -14793,32 +14303,4 @@ std::unique_ptr CreateRISCVIntrinsicManager(Sema &S); } // end namespace clang -namespace llvm { -// Hash a FunctionDeclAndLoc by looking at both its FunctionDecl and its -// SourceLocation. -template <> struct DenseMapInfo { - using FunctionDeclAndLoc = clang::Sema::FunctionDeclAndLoc; - using FDBaseInfo = - DenseMapInfo>; - - static FunctionDeclAndLoc getEmptyKey() { - return {FDBaseInfo::getEmptyKey(), clang::SourceLocation()}; - } - - static FunctionDeclAndLoc getTombstoneKey() { - return {FDBaseInfo::getTombstoneKey(), clang::SourceLocation()}; - } - - static unsigned getHashValue(const FunctionDeclAndLoc &FDL) { - return hash_combine(FDBaseInfo::getHashValue(FDL.FD), - FDL.Loc.getHashValue()); - } - - static bool isEqual(const FunctionDeclAndLoc &LHS, - const FunctionDeclAndLoc &RHS) { - return LHS.FD == RHS.FD && LHS.Loc == RHS.Loc; - } -}; -} // namespace llvm - #endif diff --git a/clang/include/clang/Sema/SemaBase.h b/clang/include/clang/Sema/SemaBase.h new file mode 100644 index 0000000000000000000000000000000000000000..3220f71dd797ed0a125a666a17ee85150e57c283 --- /dev/null +++ b/clang/include/clang/Sema/SemaBase.h @@ -0,0 +1,224 @@ +//===--- SemaBase.h - Common utilities for semantic analysis-----*- 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 the SemaBase class, which provides utilities for Sema +// and its parts like SemaOpenACC. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMABASE_H +#define LLVM_CLANG_SEMA_SEMABASE_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Redeclarable.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/Ownership.h" +#include "llvm/ADT/DenseMap.h" +#include +#include +#include +#include + +namespace clang { + +class ASTContext; +class DiagnosticsEngine; +class LangOptions; +class Sema; + +class SemaBase { +public: + SemaBase(Sema &S); + + Sema &SemaRef; + + ASTContext &getASTContext() const; + DiagnosticsEngine &getDiagnostics() const; + const LangOptions &getLangOpts() const; + + /// Helper class that creates diagnostics with optional + /// template instantiation stacks. + /// + /// This class provides a wrapper around the basic DiagnosticBuilder + /// class that emits diagnostics. ImmediateDiagBuilder is + /// responsible for emitting the diagnostic (as DiagnosticBuilder + /// does) and, if the diagnostic comes from inside a template + /// instantiation, printing the template instantiation stack as + /// well. + class ImmediateDiagBuilder : public DiagnosticBuilder { + Sema &SemaRef; + unsigned DiagID; + + public: + ImmediateDiagBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) + : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} + ImmediateDiagBuilder(DiagnosticBuilder &&DB, Sema &SemaRef, unsigned DiagID) + : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} + + // This is a cunning lie. DiagnosticBuilder actually performs move + // construction in its copy constructor (but due to varied uses, it's not + // possible to conveniently express this as actual move construction). So + // the default copy ctor here is fine, because the base class disables the + // source anyway, so the user-defined ~ImmediateDiagBuilder is a safe no-op + // in that case anwyay. + ImmediateDiagBuilder(const ImmediateDiagBuilder &) = default; + + ~ImmediateDiagBuilder(); + + /// Teach operator<< to produce an object of the correct type. + template + friend const ImmediateDiagBuilder & + operator<<(const ImmediateDiagBuilder &Diag, const T &Value) { + const DiagnosticBuilder &BaseDiag = Diag; + BaseDiag << Value; + return Diag; + } + + // It is necessary to limit this to rvalue reference to avoid calling this + // function with a bitfield lvalue argument since non-const reference to + // bitfield is not allowed. + template ::value>> + const ImmediateDiagBuilder &operator<<(T &&V) const { + const DiagnosticBuilder &BaseDiag = *this; + BaseDiag << std::move(V); + return *this; + } + }; + + /// A generic diagnostic builder for errors which may or may not be deferred. + /// + /// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch) + /// which are not allowed to appear inside __device__ functions and are + /// allowed to appear in __host__ __device__ functions only if the host+device + /// function is never codegen'ed. + /// + /// To handle this, we use the notion of "deferred diagnostics", where we + /// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed. + /// + /// This class lets you emit either a regular diagnostic, a deferred + /// diagnostic, or no diagnostic at all, according to an argument you pass to + /// its constructor, thus simplifying the process of creating these "maybe + /// deferred" diagnostics. + class SemaDiagnosticBuilder { + public: + enum Kind { + /// Emit no diagnostics. + K_Nop, + /// Emit the diagnostic immediately (i.e., behave like Sema::Diag()). + K_Immediate, + /// Emit the diagnostic immediately, and, if it's a warning or error, also + /// emit a call stack showing how this function can be reached by an a + /// priori known-emitted function. + K_ImmediateWithCallStack, + /// Create a deferred diagnostic, which is emitted only if the function + /// it's attached to is codegen'ed. Also emit a call stack as with + /// K_ImmediateWithCallStack. + K_Deferred + }; + + SemaDiagnosticBuilder(Kind K, SourceLocation Loc, unsigned DiagID, + const FunctionDecl *Fn, Sema &S); + SemaDiagnosticBuilder(SemaDiagnosticBuilder &&D); + SemaDiagnosticBuilder(const SemaDiagnosticBuilder &) = default; + + // The copy and move assignment operator is defined as deleted pending + // further motivation. + SemaDiagnosticBuilder &operator=(const SemaDiagnosticBuilder &) = delete; + SemaDiagnosticBuilder &operator=(SemaDiagnosticBuilder &&) = delete; + + ~SemaDiagnosticBuilder(); + + bool isImmediate() const { return ImmediateDiag.has_value(); } + + /// Convertible to bool: True if we immediately emitted an error, false if + /// we didn't emit an error or we created a deferred error. + /// + /// Example usage: + /// + /// if (SemaDiagnosticBuilder(...) << foo << bar) + /// return ExprError(); + /// + /// But see DiagIfDeviceCode() and DiagIfHostCode() -- you probably + /// want to use these instead of creating a SemaDiagnosticBuilder yourself. + operator bool() const { return isImmediate(); } + + template + friend const SemaDiagnosticBuilder & + operator<<(const SemaDiagnosticBuilder &Diag, const T &Value) { + if (Diag.ImmediateDiag) + *Diag.ImmediateDiag << Value; + else if (Diag.PartialDiagId) + Diag.getDeviceDeferredDiags()[Diag.Fn][*Diag.PartialDiagId].second + << Value; + return Diag; + } + + // It is necessary to limit this to rvalue reference to avoid calling this + // function with a bitfield lvalue argument since non-const reference to + // bitfield is not allowed. + template ::value>> + const SemaDiagnosticBuilder &operator<<(T &&V) const { + if (ImmediateDiag) + *ImmediateDiag << std::move(V); + else if (PartialDiagId) + getDeviceDeferredDiags()[Fn][*PartialDiagId].second << std::move(V); + return *this; + } + + friend const SemaDiagnosticBuilder & + operator<<(const SemaDiagnosticBuilder &Diag, const PartialDiagnostic &PD); + + void AddFixItHint(const FixItHint &Hint) const; + + friend ExprResult ExprError(const SemaDiagnosticBuilder &) { + return ExprError(); + } + friend StmtResult StmtError(const SemaDiagnosticBuilder &) { + return StmtError(); + } + operator ExprResult() const { return ExprError(); } + operator StmtResult() const { return StmtError(); } + operator TypeResult() const { return TypeError(); } + operator DeclResult() const { return DeclResult(true); } + operator MemInitResult() const { return MemInitResult(true); } + + using DeferredDiagnosticsType = + llvm::DenseMap, + std::vector>; + + private: + Sema &S; + SourceLocation Loc; + unsigned DiagID; + const FunctionDecl *Fn; + bool ShowCallStack; + + // Invariant: At most one of these Optionals has a value. + // FIXME: Switch these to a Variant once that exists. + std::optional ImmediateDiag; + std::optional PartialDiagId; + + DeferredDiagnosticsType &getDeviceDeferredDiags() const; + }; + + /// Emit a diagnostic. + SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, + bool DeferHint = false); + + /// Emit a partial diagnostic. + SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD, + bool DeferHint = false); +}; + +} // namespace clang + +#endif diff --git a/clang/include/clang/Sema/SemaCUDA.h b/clang/include/clang/Sema/SemaCUDA.h new file mode 100644 index 0000000000000000000000000000000000000000..63dc3f4da240b365cc51325b6d0fe7899d62f13c --- /dev/null +++ b/clang/include/clang/Sema/SemaCUDA.h @@ -0,0 +1,304 @@ +//===----- SemaCUDA.h ----- Semantic Analysis for CUDA constructs ---------===// +// +// 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 +/// This file declares semantic analysis for CUDA constructs. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMACUDA_H +#define LLVM_CLANG_SEMA_SEMACUDA_H + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Redeclarable.h" +#include "clang/Basic/Cuda.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Ownership.h" +#include "clang/Sema/ParsedAttr.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaBase.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallVector.h" +#include + +namespace clang { + +enum class CUDAFunctionTarget; + +class SemaCUDA : public SemaBase { +public: + SemaCUDA(Sema &S); + + /// Increments our count of the number of times we've seen a pragma forcing + /// functions to be __host__ __device__. So long as this count is greater + /// than zero, all functions encountered will be __host__ __device__. + void PushForceHostDevice(); + + /// Decrements our count of the number of times we've seen a pragma forcing + /// functions to be __host__ __device__. Returns false if the count is 0 + /// before incrementing, so you can emit an error. + bool PopForceHostDevice(); + + ExprResult ActOnExecConfigExpr(Scope *S, SourceLocation LLLLoc, + MultiExprArg ExecConfig, + SourceLocation GGGLoc); + + /// A pair of a canonical FunctionDecl and a SourceLocation. When used as the + /// key in a hashtable, both the FD and location are hashed. + struct FunctionDeclAndLoc { + CanonicalDeclPtr FD; + SourceLocation Loc; + }; + + /// FunctionDecls and SourceLocations for which CheckCall has emitted a + /// (maybe deferred) "bad call" diagnostic. We use this to avoid emitting the + /// same deferred diag twice. + llvm::DenseSet LocsWithCUDACallDiags; + + /// An inverse call graph, mapping known-emitted functions to one of their + /// known-emitted callers (plus the location of the call). + /// + /// Functions that we can tell a priori must be emitted aren't added to this + /// map. + llvm::DenseMap, + /* Caller = */ FunctionDeclAndLoc> + DeviceKnownEmittedFns; + + /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current + /// context is "used as device code". + /// + /// - If CurContext is a __host__ function, does not emit any diagnostics + /// unless \p EmitOnBothSides is true. + /// - If CurContext is a __device__ or __global__ function, emits the + /// diagnostics immediately. + /// - If CurContext is a __host__ __device__ function and we are compiling for + /// the device, creates a diagnostic which is emitted if and when we realize + /// that the function will be codegen'ed. + /// + /// Example usage: + /// + /// // Variable-length arrays are not allowed in CUDA device code. + /// if (DiagIfDeviceCode(Loc, diag::err_cuda_vla) << CurrentTarget()) + /// return ExprError(); + /// // Otherwise, continue parsing as normal. + SemaDiagnosticBuilder DiagIfDeviceCode(SourceLocation Loc, unsigned DiagID); + + /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current + /// context is "used as host code". + /// + /// Same as DiagIfDeviceCode, with "host" and "device" switched. + SemaDiagnosticBuilder DiagIfHostCode(SourceLocation Loc, unsigned DiagID); + + /// Determines whether the given function is a CUDA device/host/kernel/etc. + /// function. + /// + /// Use this rather than examining the function's attributes yourself -- you + /// will get it wrong. Returns CUDAFunctionTarget::Host if D is null. + CUDAFunctionTarget IdentifyTarget(const FunctionDecl *D, + bool IgnoreImplicitHDAttr = false); + CUDAFunctionTarget IdentifyTarget(const ParsedAttributesView &Attrs); + + enum CUDAVariableTarget { + CVT_Device, /// Emitted on device side with a shadow variable on host side + CVT_Host, /// Emitted on host side only + CVT_Both, /// Emitted on both sides with different addresses + CVT_Unified, /// Emitted as a unified address, e.g. managed variables + }; + /// Determines whether the given variable is emitted on host or device side. + CUDAVariableTarget IdentifyTarget(const VarDecl *D); + + /// Defines kinds of CUDA global host/device context where a function may be + /// called. + enum CUDATargetContextKind { + CTCK_Unknown, /// Unknown context + CTCK_InitGlobalVar, /// Function called during global variable + /// initialization + }; + + /// Define the current global CUDA host/device context where a function may be + /// called. Only used when a function is called outside of any functions. + struct CUDATargetContext { + CUDAFunctionTarget Target = CUDAFunctionTarget::HostDevice; + CUDATargetContextKind Kind = CTCK_Unknown; + Decl *D = nullptr; + } CurCUDATargetCtx; + + struct CUDATargetContextRAII { + SemaCUDA &S; + SemaCUDA::CUDATargetContext SavedCtx; + CUDATargetContextRAII(SemaCUDA &S_, SemaCUDA::CUDATargetContextKind K, + Decl *D); + ~CUDATargetContextRAII() { S.CurCUDATargetCtx = SavedCtx; } + }; + + /// Gets the CUDA target for the current context. + CUDAFunctionTarget CurrentTarget() { + return IdentifyTarget(dyn_cast(SemaRef.CurContext)); + } + + static bool isImplicitHostDeviceFunction(const FunctionDecl *D); + + // CUDA function call preference. Must be ordered numerically from + // worst to best. + enum CUDAFunctionPreference { + CFP_Never, // Invalid caller/callee combination. + CFP_WrongSide, // Calls from host-device to host or device + // function that do not match current compilation + // mode. + CFP_HostDevice, // Any calls to host/device functions. + CFP_SameSide, // Calls from host-device to host or device + // function matching current compilation mode. + CFP_Native, // host-to-host or device-to-device calls. + }; + + /// Identifies relative preference of a given Caller/Callee + /// combination, based on their host/device attributes. + /// \param Caller function which needs address of \p Callee. + /// nullptr in case of global context. + /// \param Callee target function + /// + /// \returns preference value for particular Caller/Callee combination. + CUDAFunctionPreference IdentifyPreference(const FunctionDecl *Caller, + const FunctionDecl *Callee); + + /// Determines whether Caller may invoke Callee, based on their CUDA + /// host/device attributes. Returns false if the call is not allowed. + /// + /// Note: Will return true for CFP_WrongSide calls. These may appear in + /// semantically correct CUDA programs, but only if they're never codegen'ed. + bool IsAllowedCall(const FunctionDecl *Caller, const FunctionDecl *Callee) { + return IdentifyPreference(Caller, Callee) != CFP_Never; + } + + /// May add implicit CUDAHostAttr and CUDADeviceAttr attributes to FD, + /// depending on FD and the current compilation settings. + void maybeAddHostDeviceAttrs(FunctionDecl *FD, const LookupResult &Previous); + + /// May add implicit CUDAConstantAttr attribute to VD, depending on VD + /// and current compilation settings. + void MaybeAddConstantAttr(VarDecl *VD); + + /// Check whether we're allowed to call Callee from the current context. + /// + /// - If the call is never allowed in a semantically-correct program + /// (CFP_Never), emits an error and returns false. + /// + /// - If the call is allowed in semantically-correct programs, but only if + /// it's never codegen'ed (CFP_WrongSide), creates a deferred diagnostic to + /// be emitted if and when the caller is codegen'ed, and returns true. + /// + /// Will only create deferred diagnostics for a given SourceLocation once, + /// so you can safely call this multiple times without generating duplicate + /// deferred errors. + /// + /// - Otherwise, returns true without emitting any diagnostics. + bool CheckCall(SourceLocation Loc, FunctionDecl *Callee); + + void CheckLambdaCapture(CXXMethodDecl *D, const sema::Capture &Capture); + + /// Set __device__ or __host__ __device__ attributes on the given lambda + /// operator() method. + /// + /// CUDA lambdas by default is host device function unless it has explicit + /// host or device attribute. + void SetLambdaAttrs(CXXMethodDecl *Method); + + /// Record \p FD if it is a CUDA/HIP implicit host device function used on + /// device side in device compilation. + void RecordImplicitHostDeviceFuncUsedByDevice(const FunctionDecl *FD); + + /// Finds a function in \p Matches with highest calling priority + /// from \p Caller context and erases all functions with lower + /// calling priority. + void EraseUnwantedMatches( + const FunctionDecl *Caller, + llvm::SmallVectorImpl> + &Matches); + + /// Given a implicit special member, infer its CUDA target from the + /// calls it needs to make to underlying base/field special members. + /// \param ClassDecl the class for which the member is being created. + /// \param CSM the kind of special member. + /// \param MemberDecl the special member itself. + /// \param ConstRHS true if this is a copy operation with a const object on + /// its RHS. + /// \param Diagnose true if this call should emit diagnostics. + /// \return true if there was an error inferring. + /// The result of this call is implicit CUDA target attribute(s) attached to + /// the member declaration. + bool inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, + CXXSpecialMemberKind CSM, + CXXMethodDecl *MemberDecl, + bool ConstRHS, bool Diagnose); + + /// \return true if \p CD can be considered empty according to CUDA + /// (E.2.3.1 in CUDA 7.5 Programming guide). + bool isEmptyConstructor(SourceLocation Loc, CXXConstructorDecl *CD); + bool isEmptyDestructor(SourceLocation Loc, CXXDestructorDecl *CD); + + // \brief Checks that initializers of \p Var satisfy CUDA restrictions. In + // case of error emits appropriate diagnostic and invalidates \p Var. + // + // \details CUDA allows only empty constructors as initializers for global + // variables (see E.2.3.1, CUDA 7.5). The same restriction also applies to all + // __shared__ variables whether they are local or not (they all are implicitly + // static in CUDA). One exception is that CUDA allows constant initializers + // for __constant__ and __device__ variables. + void checkAllowedInitializer(VarDecl *VD); + + /// Check whether NewFD is a valid overload for CUDA. Emits + /// diagnostics and invalidates NewFD if not. + void checkTargetOverload(FunctionDecl *NewFD, const LookupResult &Previous); + /// Copies target attributes from the template TD to the function FD. + void inheritTargetAttrs(FunctionDecl *FD, const FunctionTemplateDecl &TD); + + /// Returns the name of the launch configuration function. This is the name + /// of the function that will be called to configure kernel call, with the + /// parameters specified via <<<>>>. + std::string getConfigureFuncName() const; + +private: + unsigned ForceHostDeviceDepth = 0; + + friend class ASTReader; + friend class ASTWriter; +}; + +} // namespace clang + +namespace llvm { +// Hash a FunctionDeclAndLoc by looking at both its FunctionDecl and its +// SourceLocation. +template <> struct DenseMapInfo { + using FunctionDeclAndLoc = clang::SemaCUDA::FunctionDeclAndLoc; + using FDBaseInfo = + DenseMapInfo>; + + static FunctionDeclAndLoc getEmptyKey() { + return {FDBaseInfo::getEmptyKey(), clang::SourceLocation()}; + } + + static FunctionDeclAndLoc getTombstoneKey() { + return {FDBaseInfo::getTombstoneKey(), clang::SourceLocation()}; + } + + static unsigned getHashValue(const FunctionDeclAndLoc &FDL) { + return hash_combine(FDBaseInfo::getHashValue(FDL.FD), + FDL.Loc.getHashValue()); + } + + static bool isEqual(const FunctionDeclAndLoc &LHS, + const FunctionDeclAndLoc &RHS) { + return LHS.FD == RHS.FD && LHS.Loc == RHS.Loc; + } +}; +} // namespace llvm + +#endif // LLVM_CLANG_SEMA_SEMACUDA_H diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h new file mode 100644 index 0000000000000000000000000000000000000000..34acaf19517f2a58be7fd54667d7b8a1a8e28ef1 --- /dev/null +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -0,0 +1,56 @@ +//===----- SemaHLSL.h ----- Semantic Analysis for HLSL constructs ---------===// +// +// 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 +/// This file declares semantic analysis for HLSL constructs. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAHLSL_H +#define LLVM_CLANG_SEMA_SEMAHLSL_H + +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/Expr.h" +#include "clang/Basic/AttributeCommonInfo.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/SemaBase.h" +#include + +namespace clang { + +class SemaHLSL : public SemaBase { +public: + SemaHLSL(Sema &S); + + Decl *ActOnStartBuffer(Scope *BufferScope, bool CBuffer, SourceLocation KwLoc, + IdentifierInfo *Ident, SourceLocation IdentLoc, + SourceLocation LBrace); + void ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace); + HLSLNumThreadsAttr *mergeNumThreadsAttr(Decl *D, + const AttributeCommonInfo &AL, int X, + int Y, int Z); + HLSLShaderAttr *mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL, + HLSLShaderAttr::ShaderType ShaderType); + HLSLParamModifierAttr * + mergeParamModifierAttr(Decl *D, const AttributeCommonInfo &AL, + HLSLParamModifierAttr::Spelling Spelling); + void ActOnTopLevelFunction(FunctionDecl *FD); + void CheckEntryPoint(FunctionDecl *FD); + void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param, + const HLSLAnnotationAttr *AnnotationAttr); + void DiagnoseAttrStageMismatch( + const Attr *A, HLSLShaderAttr::ShaderType Stage, + std::initializer_list AllowedStages); +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAHLSL_H diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h index 7f50d7889ad79bf237eeb3b7d6abdd7e013fd7cb..c1fe0f5b9c0f6bdad1d83d49cb4cc85ae49722c9 100644 --- a/clang/include/clang/Sema/SemaOpenACC.h +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -18,26 +18,92 @@ #include "clang/Basic/OpenACCKinds.h" #include "clang/Basic/SourceLocation.h" #include "clang/Sema/Ownership.h" +#include "clang/Sema/SemaBase.h" +#include namespace clang { +class OpenACCClause; -class ASTContext; -class DiagnosticEngine; -class LangOptions; -class Sema; - -class SemaOpenACC { +class SemaOpenACC : public SemaBase { public: - SemaOpenACC(Sema &S); + /// A type to represent all the data for an OpenACC Clause that has been + /// parsed, but not yet created/semantically analyzed. This is effectively a + /// discriminated union on the 'Clause Kind', with all of the individual + /// clause details stored in a std::variant. + class OpenACCParsedClause { + OpenACCDirectiveKind DirKind; + OpenACCClauseKind ClauseKind; + SourceRange ClauseRange; + SourceLocation LParenLoc; + + struct DefaultDetails { + OpenACCDefaultClauseKind DefaultClauseKind; + }; + + struct ConditionDetails { + Expr *ConditionExpr; + }; + + std::variant Details; + + public: + OpenACCParsedClause(OpenACCDirectiveKind DirKind, + OpenACCClauseKind ClauseKind, SourceLocation BeginLoc) + : DirKind(DirKind), ClauseKind(ClauseKind), ClauseRange(BeginLoc, {}) {} + + OpenACCDirectiveKind getDirectiveKind() const { return DirKind; } + + OpenACCClauseKind getClauseKind() const { return ClauseKind; } + + SourceLocation getBeginLoc() const { return ClauseRange.getBegin(); } + + SourceLocation getLParenLoc() const { return LParenLoc; } - ASTContext &getASTContext() const; - DiagnosticsEngine &getDiagnostics() const; - const LangOptions &getLangOpts() const; + SourceLocation getEndLoc() const { return ClauseRange.getEnd(); } - Sema &SemaRef; + OpenACCDefaultClauseKind getDefaultClauseKind() const { + assert(ClauseKind == OpenACCClauseKind::Default && + "Parsed clause is not a default clause"); + return std::get(Details).DefaultClauseKind; + } + + const Expr *getConditionExpr() const { + return const_cast(this)->getConditionExpr(); + } + + Expr *getConditionExpr() { + assert(ClauseKind == OpenACCClauseKind::If && + "Parsed clause kind does not have a condition expr"); + return std::get(Details).ConditionExpr; + } + + void setLParenLoc(SourceLocation EndLoc) { LParenLoc = EndLoc; } + void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); } + + void setDefaultDetails(OpenACCDefaultClauseKind DefKind) { + assert(ClauseKind == OpenACCClauseKind::Default && + "Parsed clause is not a default clause"); + Details = DefaultDetails{DefKind}; + } + + void setConditionDetails(Expr *ConditionExpr) { + assert(ClauseKind == OpenACCClauseKind::If && + "Parsed clause kind does not have a condition expr"); + // In C++ we can count on this being a 'bool', but in C this gets left as + // some sort of scalar that codegen will have to take care of converting. + assert((!ConditionExpr || ConditionExpr->isInstantiationDependent() || + ConditionExpr->getType()->isScalarType()) && + "Condition expression type not scalar/dependent"); + + Details = ConditionDetails{ConditionExpr}; + } + }; + + SemaOpenACC(Sema &S); /// Called after parsing an OpenACC Clause so that it can be checked. - bool ActOnClause(OpenACCClauseKind ClauseKind, SourceLocation StartLoc); + OpenACCClause *ActOnClause(ArrayRef ExistingClauses, + OpenACCParsedClause &Clause); /// Called after the construct has been parsed, but clauses haven't been /// parsed. This allows us to diagnose not-implemented, as well as set up any @@ -63,7 +129,10 @@ public: /// declaration group or associated statement. StmtResult ActOnEndStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc, - SourceLocation EndLoc, StmtResult AssocStmt); + SourceLocation EndLoc, + ArrayRef Clauses, + StmtResult AssocStmt); + /// Called after the directive has been completely parsed, including the /// declaration group or associated statement. DeclGroupRef ActOnEndDeclDirective(); diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h new file mode 100644 index 0000000000000000000000000000000000000000..f0dcb92ee9ab3e74a41a2d12c3287eb89e21666b --- /dev/null +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -0,0 +1,65 @@ +//===----- SemaSYCL.h ------- Semantic Analysis for SYCL constructs -------===// +// +// 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 +/// This file declares semantic analysis for SYCL constructs. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMASYCL_H +#define LLVM_CLANG_SEMA_SEMASYCL_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Type.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/Ownership.h" +#include "clang/Sema/SemaBase.h" +#include "llvm/ADT/DenseSet.h" + +namespace clang { + +class SemaSYCL : public SemaBase { +public: + SemaSYCL(Sema &S); + + /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current + /// context is "used as device code". + /// + /// - If CurLexicalContext is a kernel function or it is known that the + /// function will be emitted for the device, emits the diagnostics + /// immediately. + /// - If CurLexicalContext is a function and we are compiling + /// for the device, but we don't know yet that this function will be + /// codegen'ed for the devive, creates a diagnostic which is emitted if and + /// when we realize that the function will be codegen'ed. + /// + /// Example usage: + /// + /// Diagnose __float128 type usage only from SYCL device code if the current + /// target doesn't support it + /// if (!S.Context.getTargetInfo().hasFloat128Type() && + /// S.getLangOpts().SYCLIsDevice) + /// DiagIfDeviceCode(Loc, diag::err_type_unsupported) << "__float128"; + SemaDiagnosticBuilder DiagIfDeviceCode(SourceLocation Loc, unsigned DiagID); + + void deepTypeCheckForDevice(SourceLocation UsedAt, + llvm::DenseSet Visited, + ValueDecl *DeclToCheck); + + ExprResult BuildUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + TypeSourceInfo *TSI); + ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + ParsedType ParsedTy); +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMASYCL_H diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index f762116fea956c3fbee92038538e0f3e81f06c7e..500098dd3dab1d25e49cb350e67b2e5ce1ad104b 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -698,6 +698,10 @@ enum ASTRecordTypes { /// Record code for an unterminated \#pragma clang assume_nonnull begin /// recorded in a preamble. PP_ASSUME_NONNULL_LOC = 67, + + /// Record code for lexical and visible block for delayed namespace in + /// reduced BMI. + DELAYED_NAMESPACE_LEXICAL_VISIBLE_RECORD = 68, }; /// Record types used within a source manager block. diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 370d8037a4da17933e80256f651ddfa104d78203..e3fde887f99cb743b096fef6bc4b04bc3da07b54 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -517,6 +517,20 @@ private: /// in the chain. DeclUpdateOffsetsMap DeclUpdateOffsets; + using DelayedNamespaceOffsetMapTy = llvm::DenseMap< + serialization::DeclID, + std::pair>; + + /// Mapping from global declaration IDs to the lexical and visible block + /// offset for delayed namespace in reduced BMI. + /// + /// We can't use the existing DeclUpdate mechanism since the DeclUpdate + /// may only be applied in an outer most read. However, we need to know + /// whether or not a DeclContext has external storage during the recursive + /// reading. So we need to apply the offset immediately after we read the + /// namespace as if it is not delayed. + DelayedNamespaceOffsetMapTy DelayedNamespaceOffsetMap; + struct PendingUpdateRecord { Decl *D; serialization::GlobalDeclID ID; @@ -859,7 +873,7 @@ private: /// Our current depth in #pragma cuda force_host_device begin/end /// macros. - unsigned ForceCUDAHostDeviceDepth = 0; + unsigned ForceHostDeviceDepth = 0; /// The IDs of the declarations Sema stores directly. /// @@ -1082,26 +1096,12 @@ private: /// The set of lookup results that we have faked in order to support /// merging of partially deserialized decls but that we have not yet removed. - llvm::SmallMapVector, 16> - PendingFakeLookupResults; + llvm::SmallMapVector, 16> + PendingFakeLookupResults; /// The generation number of each identifier, which keeps track of /// the last time we loaded information about this identifier. - llvm::DenseMap IdentifierGeneration; - - class InterestingDecl { - Decl *D; - bool DeclHasPendingBody; - - public: - InterestingDecl(Decl *D, bool HasBody) - : D(D), DeclHasPendingBody(HasBody) {} - - Decl *getDecl() { return D; } - - /// Whether the declaration has a pending body. - bool hasPendingBody() { return DeclHasPendingBody; } - }; + llvm::DenseMap IdentifierGeneration; /// Contains declarations and definitions that could be /// "interesting" to the ASTConsumer, when we get that AST consumer. @@ -1109,7 +1109,7 @@ private: /// "Interesting" declarations are those that have data that may /// need to be emitted, such as inline function definitions or /// Objective-C protocols. - std::deque PotentiallyInterestingDecls; + std::deque PotentiallyInterestingDecls; /// The list of deduced function types that we have not yet read, because /// they might contain a deduced return type that refers to a local type @@ -1506,6 +1506,7 @@ public: getModuleFileLevelDecls(ModuleFile &Mod); private: + bool isConsumerInterestedIn(Decl *D); void PassInterestingDeclsToConsumer(); void PassInterestingDeclToConsumer(Decl *D); @@ -2344,10 +2345,10 @@ public: void ReadDefinedMacros() override; /// Update an out-of-date identifier. - void updateOutOfDateIdentifier(IdentifierInfo &II) override; + void updateOutOfDateIdentifier(const IdentifierInfo &II) override; /// Note that this identifier is up-to-date. - void markIdentifierUpToDate(IdentifierInfo *II); + void markIdentifierUpToDate(const IdentifierInfo *II); /// Load all external visible decls in the given DeclContext. void completeVisibleDeclsMap(const DeclContext *DC) override; diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index 214eb3601148b0d18d6392d535e23e7d5d3baffd..443f77031047006df8108f26570a669f30fc5c75 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -201,6 +201,16 @@ private: /// The declarations and types to emit. std::queue DeclTypesToEmit; + /// The delayed namespace to emit. Only meaningful for reduced BMI. + /// + /// In reduced BMI, we want to elide the unreachable declarations in + /// the global module fragment. However, in ASTWriterDecl, when we see + /// a namespace, all the declarations in the namespace would be emitted. + /// So the optimization become meaningless. To solve the issue, we + /// delay recording all the declarations until we emit all the declarations. + /// Then we can safely record the reached declarations only. + llvm::SmallVector DelayedNamespace; + /// The first ID number we can use for our own declarations. serialization::DeclID FirstDeclID = serialization::NUM_PREDEF_DECL_IDS; @@ -529,7 +539,8 @@ private: void WriteType(QualType T); bool isLookupResultExternal(StoredDeclsList &Result, DeclContext *DC); - bool isLookupResultEntirelyExternal(StoredDeclsList &Result, DeclContext *DC); + bool isLookupResultEntirelyExternalOrUnreachable(StoredDeclsList &Result, + DeclContext *DC); void GenerateNameLookupTable(const DeclContext *DC, llvm::SmallVectorImpl &LookupTable); @@ -704,6 +715,15 @@ public: /// declaration. serialization::DeclID getDeclID(const Decl *D); + /// Whether or not the declaration got emitted. If not, it wouldn't be + /// emitted. + /// + /// This may only be called after we've done the job to write the + /// declarations (marked by DoneWritingDeclsAndTypes). + /// + /// A declaration may only be omitted in reduced BMI. + bool wasDeclEmitted(const Decl *D) const; + unsigned getAnonymousDeclarationNumber(const NamedDecl *D); /// Add a string to the given record. @@ -798,6 +818,10 @@ public: return WritingModule && WritingModule->isNamedModule(); } + bool isGeneratingReducedBMI() const { return GeneratingReducedBMI; } + + bool getDoneWritingDeclsAndTypes() const { return DoneWritingDeclsAndTypes; } + private: // ASTDeserializationListener implementation void ReaderInitialized(ASTReader *Reader) override; diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 5fe5c9286dabb791937aa53041252745a605afe5..9aa1c6ddfe4492c38f1a07851be9c15587479ccf 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -604,6 +604,15 @@ def PthreadLockChecker : Checker<"PthreadLock">, def StreamChecker : Checker<"Stream">, HelpText<"Check stream handling functions">, WeakDependencies<[NonNullParamChecker]>, + CheckerOptions<[ + CmdLineOption + ]>, Documentation; def SimpleStreamChecker : Checker<"SimpleStream">, diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h index 9a522a3e2fe252082e1b2ee5b839c3d1d519cb63..f7b4510d7f7beb4b6e300180453385e1a84e6af4 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h @@ -142,6 +142,8 @@ private: CachedFileContents *Contents; }; +using CachedRealPath = llvm::ErrorOr; + /// This class is a shared cache, that caches the 'stat' and 'open' calls to the /// underlying real file system, and the scanned preprocessor directives of /// files. @@ -154,9 +156,11 @@ public: /// The mutex that needs to be locked before mutation of any member. mutable std::mutex CacheLock; - /// Map from filenames to cached entries. - llvm::StringMap - EntriesByFilename; + /// Map from filenames to cached entries and real paths. + llvm::StringMap< + std::pair, + llvm::BumpPtrAllocator> + CacheByFilename; /// Map from unique IDs to cached entries. llvm::DenseMap @@ -168,6 +172,9 @@ public: /// The backing storage for cached contents. llvm::SpecificBumpPtrAllocator ContentsStorage; + /// The backing storage for cached real paths. + llvm::SpecificBumpPtrAllocator RealPathStorage; + /// Returns entry associated with the filename or nullptr if none is found. const CachedFileSystemEntry *findEntryByFilename(StringRef Filename) const; @@ -194,6 +201,17 @@ public: const CachedFileSystemEntry & getOrInsertEntryForFilename(StringRef Filename, const CachedFileSystemEntry &Entry); + + /// Returns the real path associated with the filename or nullptr if none is + /// found. + const CachedRealPath *findRealPathByFilename(StringRef Filename) const; + + /// Returns the real path associated with the filename if there is some. + /// Otherwise, constructs new one with the given one, associates it with the + /// filename and returns the result. + const CachedRealPath & + getOrEmplaceRealPathForFilename(StringRef Filename, + llvm::ErrorOr RealPath); }; DependencyScanningFilesystemSharedCache(); @@ -210,14 +228,17 @@ private: /// This class is a local cache, that caches the 'stat' and 'open' calls to the /// underlying real file system. class DependencyScanningFilesystemLocalCache { - llvm::StringMap Cache; + llvm::StringMap< + std::pair, + llvm::BumpPtrAllocator> + Cache; public: /// Returns entry associated with the filename or nullptr if none is found. const CachedFileSystemEntry *findEntryByFilename(StringRef Filename) const { assert(llvm::sys::path::is_absolute_gnu(Filename)); auto It = Cache.find(Filename); - return It == Cache.end() ? nullptr : It->getValue(); + return It == Cache.end() ? nullptr : It->getValue().first; } /// Associates the given entry with the filename and returns the given entry @@ -226,9 +247,40 @@ public: insertEntryForFilename(StringRef Filename, const CachedFileSystemEntry &Entry) { assert(llvm::sys::path::is_absolute_gnu(Filename)); - const auto *InsertedEntry = Cache.insert({Filename, &Entry}).first->second; - assert(InsertedEntry == &Entry && "entry already present"); - return *InsertedEntry; + auto [It, Inserted] = Cache.insert({Filename, {&Entry, nullptr}}); + auto &[CachedEntry, CachedRealPath] = It->getValue(); + if (!Inserted) { + // The file is already present in the local cache. If we got here, it only + // contains the real path. Let's make sure the entry is populated too. + assert((!CachedEntry && CachedRealPath) && "entry already present"); + CachedEntry = &Entry; + } + return *CachedEntry; + } + + /// Returns real path associated with the filename or nullptr if none is + /// found. + const CachedRealPath *findRealPathByFilename(StringRef Filename) const { + assert(llvm::sys::path::is_absolute_gnu(Filename)); + auto It = Cache.find(Filename); + return It == Cache.end() ? nullptr : It->getValue().second; + } + + /// Associates the given real path with the filename and returns the given + /// entry pointer (for convenience). + const CachedRealPath & + insertRealPathForFilename(StringRef Filename, + const CachedRealPath &RealPath) { + assert(llvm::sys::path::is_absolute_gnu(Filename)); + auto [It, Inserted] = Cache.insert({Filename, {nullptr, &RealPath}}); + auto &[CachedEntry, CachedRealPath] = It->getValue(); + if (!Inserted) { + // The file is already present in the local cache. If we got here, it only + // contains the entry. Let's make sure the real path is populated too. + assert((!CachedRealPath && CachedEntry) && "real path already present"); + CachedRealPath = &RealPath; + } + return *CachedRealPath; } }; @@ -296,6 +348,9 @@ public: llvm::ErrorOr> openFileForRead(const Twine &Path) override; + std::error_code getRealPath(const Twine &Path, + SmallVectorImpl &Output) override; + std::error_code setCurrentWorkingDirectory(const Twine &Path) override; /// Returns entry for the given filename. @@ -310,6 +365,10 @@ public: /// false if not (i.e. this entry is not a file or its scan fails). bool ensureDirectiveTokensArePopulated(EntryRef Entry); + /// Check whether \p Path exists. By default checks cached result of \c + /// status(), and falls back on FS if unable to do so. + bool exists(const Twine &Path) override; + private: /// For a filename that's not yet associated with any entry in the caches, /// uses the underlying filesystem to either look up the entry based in the @@ -402,6 +461,10 @@ private: llvm::ErrorOr WorkingDirForCacheLookup; void updateWorkingDirForCacheLookup(); + + llvm::ErrorOr + tryGetFilenameForLookup(StringRef OriginalFilename, + llvm::SmallVectorImpl &PathBuf) const; }; } // end namespace dependencies diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp index 0786c81516b2d14e7c3b7f79fbdf557c96d26016..b9dcfb8951b3e17858a9d6d641bdd0293b9777bf 100644 --- a/clang/lib/ARCMigrate/ObjCMT.cpp +++ b/clang/lib/ARCMigrate/ObjCMT.cpp @@ -1144,7 +1144,7 @@ static bool IsValidIdentifier(ASTContext &Ctx, return false; std::string NameString = Name; NameString[0] = toLowercase(NameString[0]); - IdentifierInfo *II = &Ctx.Idents.get(NameString); + const IdentifierInfo *II = &Ctx.Idents.get(NameString); return II->getTokenID() == tok::identifier; } @@ -1166,7 +1166,7 @@ bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx, if (OIT_Family != OIT_None) return false; - IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0); + const IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0); Selector SetterSelector = SelectorTable::constructSetterSelector(PP.getIdentifierTable(), PP.getSelectorTable(), @@ -1311,7 +1311,8 @@ void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx, std::string StringLoweredClassName = LoweredClassName.lower(); LoweredClassName = StringLoweredClassName; - IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0); + const IdentifierInfo *MethodIdName = + OM->getSelector().getIdentifierInfoForSlot(0); // Handle method with no name at its first selector slot; e.g. + (id):(int)x. if (!MethodIdName) return; diff --git a/clang/lib/ARCMigrate/TransAPIUses.cpp b/clang/lib/ARCMigrate/TransAPIUses.cpp index 638850dcf9ecc72a524a78f30ae101c53ad78b17..8f5d4f4bde06ca313a3f9075a797fb3a45d0fba7 100644 --- a/clang/lib/ARCMigrate/TransAPIUses.cpp +++ b/clang/lib/ARCMigrate/TransAPIUses.cpp @@ -41,7 +41,7 @@ public: getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue")); setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue")); - IdentifierInfo *selIds[2]; + const IdentifierInfo *selIds[2]; selIds[0] = &ids.get("getArgument"); selIds[1] = &ids.get("atIndex"); getArgumentSel = sels.getSelector(2, selIds); diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index f7f55dc4e7a9f436cf3a84b2c54849514c352662..6ce233704a5885ab27094b8db7614bd98ef95b9e 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -799,7 +799,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( TemplateTemplateParmDecl *CanonTTP = TemplateTemplateParmDecl::Create( *this, getTranslationUnitDecl(), SourceLocation(), TTP->getDepth(), - TTP->getPosition(), TTP->isParameterPack(), nullptr, + TTP->getPosition(), TTP->isParameterPack(), nullptr, /*Typename=*/false, TemplateParameterList::Create(*this, SourceLocation(), SourceLocation(), CanonParams, SourceLocation(), /*RequiresClause=*/nullptr)); @@ -6929,16 +6929,13 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { // typedef typename T::type T1; // typedef typename T1::type T2; if (const auto *DNT = T->getAs()) - return NestedNameSpecifier::Create( - *this, DNT->getQualifier(), - const_cast(DNT->getIdentifier())); + return NestedNameSpecifier::Create(*this, DNT->getQualifier(), + DNT->getIdentifier()); if (const auto *DTST = T->getAs()) - return NestedNameSpecifier::Create(*this, DTST->getQualifier(), true, - const_cast(T)); + return NestedNameSpecifier::Create(*this, DTST->getQualifier(), true, T); // TODO: Set 'Template' parameter to true for other template types. - return NestedNameSpecifier::Create(*this, nullptr, false, - const_cast(T)); + return NestedNameSpecifier::Create(*this, nullptr, false, T); } case NestedNameSpecifier::Global: diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 45d4c9600537be68bad71322bc7defc991cb3f26..6aaa34c55ce3078510f4210edcc4fa11259c2739 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -3947,6 +3947,14 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { // decl and its redeclarations may be required. } + StringLiteral *Msg = D->getDeletedMessage(); + if (Msg) { + auto Imported = import(Msg); + if (!Imported) + return Imported.takeError(); + Msg = *Imported; + } + ToFunction->setQualifierInfo(ToQualifierLoc); ToFunction->setAccess(D->getAccess()); ToFunction->setLexicalDeclContext(LexicalDC); @@ -3961,6 +3969,11 @@ ExpectedDecl ASTNodeImporter::VisitFunctionDecl(FunctionDecl *D) { ToFunction->setRangeEnd(ToEndLoc); ToFunction->setDefaultLoc(ToDefaultLoc); + if (Msg) + ToFunction->setDefaultedOrDeletedInfo( + FunctionDecl::DefaultedOrDeletedFunctionInfo::Create( + Importer.getToContext(), {}, Msg)); + // Set the parameters. for (auto *Param : Parameters) { Param->setOwningFunction(ToFunction); @@ -5952,7 +5965,8 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { ToD, D, Importer.getToContext(), Importer.getToContext().getTranslationUnitDecl(), *LocationOrErr, D->getDepth(), D->getPosition(), D->isParameterPack(), - (*NameOrErr).getAsIdentifierInfo(), *TemplateParamsOrErr)) + (*NameOrErr).getAsIdentifierInfo(), D->wasDeclaredWithTypename(), + *TemplateParamsOrErr)) return ToD; if (D->hasDefaultArgument()) { @@ -8383,8 +8397,8 @@ ASTNodeImporter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { return std::move(Err); PseudoDestructorTypeStorage Storage; - if (IdentifierInfo *FromII = E->getDestroyedTypeIdentifier()) { - IdentifierInfo *ToII = Importer.Import(FromII); + if (const IdentifierInfo *FromII = E->getDestroyedTypeIdentifier()) { + const IdentifierInfo *ToII = Importer.Import(FromII); ExpectedSLoc ToDestroyedTypeLocOrErr = import(E->getDestroyedTypeLoc()); if (!ToDestroyedTypeLocOrErr) return ToDestroyedTypeLocOrErr.takeError(); @@ -10194,7 +10208,7 @@ Expected ASTImporter::Import(Selector FromSel) { if (FromSel.isNull()) return Selector{}; - SmallVector Idents; + SmallVector Idents; Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(0))); for (unsigned I = 1, N = FromSel.getNumArgs(); I < N; ++I) Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(I))); diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 86b77b49a0fbc4f5b99041be851e7074d1bf8861..5ec3013fabba9ae4868d8faef7989a1ae0c648f0 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -310,6 +310,16 @@ ExprDependence clang::computeDependence(CXXThisExpr *E) { // 'this' is type-dependent if the class type of the enclosing // member function is dependent (C++ [temp.dep.expr]p2) auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); + + // If a lambda with an explicit object parameter captures '*this', then + // 'this' now refers to the captured copy of lambda, and if the lambda + // is type-dependent, so is the object and thus 'this'. + // + // Note: The standard does not mention this case explicitly, but we need + // to do this so we can mark NSDM accesses as dependent. + if (E->isCapturedByCopyInLambdaWithExplicitObjectParameter()) + D |= ExprDependence::Type; + assert(!(D & ExprDependence::UnexpandedPack)); return D; } diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 131f82985e903bb6e2e76458fc03686f0702e3ef..2b2d5a2663a18b41ffb551ebe896dd944d597486 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2913,10 +2913,10 @@ VarDecl::setInstantiationOfStaticDataMember(VarDecl *VD, //===----------------------------------------------------------------------===// ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, - StorageClass S, Expr *DefArg) { + SourceLocation StartLoc, SourceLocation IdLoc, + const IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, StorageClass S, + Expr *DefArg) { return new (C, DC) ParmVarDecl(ParmVar, C, DC, StartLoc, IdLoc, Id, T, TInfo, S, DefArg); } @@ -3058,7 +3058,7 @@ FunctionDecl::FunctionDecl(Kind DK, ASTContext &C, DeclContext *DC, FunctionDeclBits.IsTrivialForCall = false; FunctionDeclBits.IsDefaulted = false; FunctionDeclBits.IsExplicitlyDefaulted = false; - FunctionDeclBits.HasDefaultedFunctionInfo = false; + FunctionDeclBits.HasDefaultedOrDeletedInfo = false; FunctionDeclBits.IsIneligibleOrNotSelected = false; FunctionDeclBits.HasImplicitReturnZero = false; FunctionDeclBits.IsLateTemplateParsed = false; @@ -3092,30 +3092,65 @@ bool FunctionDecl::isVariadic() const { return false; } -FunctionDecl::DefaultedFunctionInfo * -FunctionDecl::DefaultedFunctionInfo::Create(ASTContext &Context, - ArrayRef Lookups) { - DefaultedFunctionInfo *Info = new (Context.Allocate( - totalSizeToAlloc(Lookups.size()), - std::max(alignof(DefaultedFunctionInfo), alignof(DeclAccessPair)))) - DefaultedFunctionInfo; +FunctionDecl::DefaultedOrDeletedFunctionInfo * +FunctionDecl::DefaultedOrDeletedFunctionInfo::Create( + ASTContext &Context, ArrayRef Lookups, + StringLiteral *DeletedMessage) { + static constexpr size_t Alignment = + std::max({alignof(DefaultedOrDeletedFunctionInfo), + alignof(DeclAccessPair), alignof(StringLiteral *)}); + size_t Size = totalSizeToAlloc( + Lookups.size(), DeletedMessage != nullptr); + + DefaultedOrDeletedFunctionInfo *Info = + new (Context.Allocate(Size, Alignment)) DefaultedOrDeletedFunctionInfo; Info->NumLookups = Lookups.size(); + Info->HasDeletedMessage = DeletedMessage != nullptr; + std::uninitialized_copy(Lookups.begin(), Lookups.end(), Info->getTrailingObjects()); + if (DeletedMessage) + *Info->getTrailingObjects() = DeletedMessage; return Info; } -void FunctionDecl::setDefaultedFunctionInfo(DefaultedFunctionInfo *Info) { - assert(!FunctionDeclBits.HasDefaultedFunctionInfo && "already have this"); +void FunctionDecl::setDefaultedOrDeletedInfo( + DefaultedOrDeletedFunctionInfo *Info) { + assert(!FunctionDeclBits.HasDefaultedOrDeletedInfo && "already have this"); assert(!Body && "can't replace function body with defaulted function info"); - FunctionDeclBits.HasDefaultedFunctionInfo = true; - DefaultedInfo = Info; + FunctionDeclBits.HasDefaultedOrDeletedInfo = true; + DefaultedOrDeletedInfo = Info; +} + +void FunctionDecl::setDeletedAsWritten(bool D, StringLiteral *Message) { + FunctionDeclBits.IsDeleted = D; + + if (Message) { + assert(isDeletedAsWritten() && "Function must be deleted"); + if (FunctionDeclBits.HasDefaultedOrDeletedInfo) + DefaultedOrDeletedInfo->setDeletedMessage(Message); + else + setDefaultedOrDeletedInfo(DefaultedOrDeletedFunctionInfo::Create( + getASTContext(), /*Lookups=*/{}, Message)); + } +} + +void FunctionDecl::DefaultedOrDeletedFunctionInfo::setDeletedMessage( + StringLiteral *Message) { + // We should never get here with the DefaultedOrDeletedInfo populated, but + // no space allocated for the deleted message, since that would require + // recreating this, but setDefaultedOrDeletedInfo() disallows overwriting + // an already existing DefaultedOrDeletedFunctionInfo. + assert(HasDeletedMessage && + "No space to store a delete message in this DefaultedOrDeletedInfo"); + *getTrailingObjects() = Message; } -FunctionDecl::DefaultedFunctionInfo * -FunctionDecl::getDefaultedFunctionInfo() const { - return FunctionDeclBits.HasDefaultedFunctionInfo ? DefaultedInfo : nullptr; +FunctionDecl::DefaultedOrDeletedFunctionInfo * +FunctionDecl::getDefalutedOrDeletedInfo() const { + return FunctionDeclBits.HasDefaultedOrDeletedInfo ? DefaultedOrDeletedInfo + : nullptr; } bool FunctionDecl::hasBody(const FunctionDecl *&Definition) const { @@ -3202,7 +3237,7 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { if (!hasBody(Definition)) return nullptr; - assert(!Definition->FunctionDeclBits.HasDefaultedFunctionInfo && + assert(!Definition->FunctionDeclBits.HasDefaultedOrDeletedInfo && "definition should not have a body"); if (Definition->Body) return Definition->Body.get(getASTContext().getExternalSource()); @@ -3211,7 +3246,7 @@ Stmt *FunctionDecl::getBody(const FunctionDecl *&Definition) const { } void FunctionDecl::setBody(Stmt *B) { - FunctionDeclBits.HasDefaultedFunctionInfo = false; + FunctionDeclBits.HasDefaultedOrDeletedInfo = false; Body = LazyDeclStmtPtr(B); if (B) EndRangeLoc = B->getEndLoc(); @@ -4511,7 +4546,7 @@ unsigned FunctionDecl::getODRHash() { FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, QualType T, + const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle) { return new (C, DC) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo, @@ -5438,7 +5473,7 @@ IndirectFieldDecl::IndirectFieldDecl(ASTContext &C, DeclContext *DC, IndirectFieldDecl * IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, + const IdentifierInfo *Id, QualType T, llvm::MutableArrayRef CH) { return new (C, DC) IndirectFieldDecl(C, DC, L, Id, T, CH); } @@ -5461,7 +5496,8 @@ void TypeDecl::anchor() {} TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, TypeSourceInfo *TInfo) { + const IdentifierInfo *Id, + TypeSourceInfo *TInfo) { return new (C, DC) TypedefDecl(C, DC, StartLoc, IdLoc, Id, TInfo); } @@ -5511,7 +5547,8 @@ TypedefDecl *TypedefDecl::CreateDeserialized(ASTContext &C, unsigned ID) { TypeAliasDecl *TypeAliasDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, + SourceLocation IdLoc, + const IdentifierInfo *Id, TypeSourceInfo *TInfo) { return new (C, DC) TypeAliasDecl(C, DC, StartLoc, IdLoc, Id, TInfo); } diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index 962f503306a0f0df585e4116c240dff26a5fd822..32c14938cd5888cd65a8dda612f5b996bf4a7f30 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -66,7 +66,8 @@ void ObjCProtocolList::set(ObjCProtocolDecl* const* InList, unsigned Elts, //===----------------------------------------------------------------------===// ObjCContainerDecl::ObjCContainerDecl(Kind DK, DeclContext *DC, - IdentifierInfo *Id, SourceLocation nameLoc, + const IdentifierInfo *Id, + SourceLocation nameLoc, SourceLocation atStartLoc) : NamedDecl(DK, DC, nameLoc, Id), DeclContext(DK) { setAtStartLoc(atStartLoc); @@ -378,10 +379,8 @@ SourceLocation ObjCInterfaceDecl::getSuperClassLoc() const { /// FindPropertyVisibleInPrimaryClass - Finds declaration of the property /// with name 'PropertyId' in the primary class; including those in protocols /// (direct or indirect) used by the primary class. -ObjCPropertyDecl * -ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass( - IdentifierInfo *PropertyId, - ObjCPropertyQueryKind QueryKind) const { +ObjCPropertyDecl *ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass( + const IdentifierInfo *PropertyId, ObjCPropertyQueryKind QueryKind) const { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) return nullptr; @@ -1539,14 +1538,10 @@ void ObjCTypeParamList::gatherDefaultTypeArgs( // ObjCInterfaceDecl //===----------------------------------------------------------------------===// -ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C, - DeclContext *DC, - SourceLocation atLoc, - IdentifierInfo *Id, - ObjCTypeParamList *typeParamList, - ObjCInterfaceDecl *PrevDecl, - SourceLocation ClassLoc, - bool isInternal){ +ObjCInterfaceDecl *ObjCInterfaceDecl::Create( + const ASTContext &C, DeclContext *DC, SourceLocation atLoc, + const IdentifierInfo *Id, ObjCTypeParamList *typeParamList, + ObjCInterfaceDecl *PrevDecl, SourceLocation ClassLoc, bool isInternal) { auto *Result = new (C, DC) ObjCInterfaceDecl(C, DC, atLoc, Id, typeParamList, ClassLoc, PrevDecl, isInternal); @@ -1564,12 +1559,10 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C, return Result; } -ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, - SourceLocation AtLoc, IdentifierInfo *Id, - ObjCTypeParamList *typeParamList, - SourceLocation CLoc, - ObjCInterfaceDecl *PrevDecl, - bool IsInternal) +ObjCInterfaceDecl::ObjCInterfaceDecl( + const ASTContext &C, DeclContext *DC, SourceLocation AtLoc, + const IdentifierInfo *Id, ObjCTypeParamList *typeParamList, + SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl, bool IsInternal) : ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc), redeclarable_base(C) { setPreviousDecl(PrevDecl); @@ -1751,8 +1744,8 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() { /// categories for this class and returns it. Name of the category is passed /// in 'CategoryId'. If category not found, return 0; /// -ObjCCategoryDecl * -ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const { +ObjCCategoryDecl *ObjCInterfaceDecl::FindCategoryDeclaration( + const IdentifierInfo *CategoryId) const { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) return nullptr; @@ -1838,10 +1831,10 @@ void ObjCIvarDecl::anchor() {} ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, - AccessControl ac, Expr *BW, - bool synthesized) { + SourceLocation IdLoc, + const IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, AccessControl ac, + Expr *BW, bool synthesized) { if (DC) { // Ivar's can only appear in interfaces, implementations (via synthesized // properties), and class extensions (via direct declaration, or synthesized @@ -2120,28 +2113,23 @@ void ObjCProtocolDecl::setHasODRHash(bool HasHash) { void ObjCCategoryDecl::anchor() {} -ObjCCategoryDecl::ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc, - SourceLocation ClassNameLoc, - SourceLocation CategoryNameLoc, - IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, - ObjCTypeParamList *typeParamList, - SourceLocation IvarLBraceLoc, - SourceLocation IvarRBraceLoc) +ObjCCategoryDecl::ObjCCategoryDecl( + DeclContext *DC, SourceLocation AtLoc, SourceLocation ClassNameLoc, + SourceLocation CategoryNameLoc, const IdentifierInfo *Id, + ObjCInterfaceDecl *IDecl, ObjCTypeParamList *typeParamList, + SourceLocation IvarLBraceLoc, SourceLocation IvarRBraceLoc) : ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc), ClassInterface(IDecl), CategoryNameLoc(CategoryNameLoc), IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) { setTypeParamList(typeParamList); } -ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation AtLoc, - SourceLocation ClassNameLoc, - SourceLocation CategoryNameLoc, - IdentifierInfo *Id, - ObjCInterfaceDecl *IDecl, - ObjCTypeParamList *typeParamList, - SourceLocation IvarLBraceLoc, - SourceLocation IvarRBraceLoc) { +ObjCCategoryDecl *ObjCCategoryDecl::Create( + ASTContext &C, DeclContext *DC, SourceLocation AtLoc, + SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, + const IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, + ObjCTypeParamList *typeParamList, SourceLocation IvarLBraceLoc, + SourceLocation IvarRBraceLoc) { auto *CatDecl = new (C, DC) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id, IDecl, typeParamList, IvarLBraceLoc, @@ -2190,13 +2178,10 @@ void ObjCCategoryDecl::setTypeParamList(ObjCTypeParamList *TPL) { void ObjCCategoryImplDecl::anchor() {} -ObjCCategoryImplDecl * -ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC, - IdentifierInfo *Id, - ObjCInterfaceDecl *ClassInterface, - SourceLocation nameLoc, - SourceLocation atStartLoc, - SourceLocation CategoryNameLoc) { +ObjCCategoryImplDecl *ObjCCategoryImplDecl::Create( + ASTContext &C, DeclContext *DC, const IdentifierInfo *Id, + ObjCInterfaceDecl *ClassInterface, SourceLocation nameLoc, + SourceLocation atStartLoc, SourceLocation CategoryNameLoc) { if (ClassInterface && ClassInterface->hasDefinition()) ClassInterface = ClassInterface->getDefinition(); return new (C, DC) ObjCCategoryImplDecl(DC, Id, ClassInterface, nameLoc, @@ -2365,14 +2350,11 @@ ObjCCompatibleAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void ObjCPropertyDecl::anchor() {} -ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - IdentifierInfo *Id, - SourceLocation AtLoc, - SourceLocation LParenLoc, - QualType T, - TypeSourceInfo *TSI, - PropertyControl propControl) { +ObjCPropertyDecl * +ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + const IdentifierInfo *Id, SourceLocation AtLoc, + SourceLocation LParenLoc, QualType T, + TypeSourceInfo *TSI, PropertyControl propControl) { return new (C, DC) ObjCPropertyDecl(DC, L, Id, AtLoc, LParenLoc, T, TSI, propControl); } diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index edbcdfe4d55bc94beb16169f374c4ab386237573..93857adb990bf209d3ccbff6e0016f2fbe0de4f8 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -21,6 +21,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/Module.h" +#include "clang/Basic/SourceManager.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -49,18 +50,6 @@ namespace { void PrintObjCTypeParams(ObjCTypeParamList *Params); - enum class AttrPrintLoc { - None = 0, - Left = 1, - Right = 2, - Any = Left | Right, - - LLVM_MARK_AS_BITMASK_ENUM(/*DefaultValue=*/Any) - }; - - void prettyPrintAttributes(Decl *D, raw_ostream &out, - AttrPrintLoc loc = AttrPrintLoc::Any); - public: DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy, const ASTContext &Context, unsigned Indentation = 0, @@ -129,11 +118,10 @@ namespace { const TemplateParameterList *Params); void printTemplateArguments(llvm::ArrayRef Args, const TemplateParameterList *Params); - - inline void prettyPrintAttributes(Decl *D) { - prettyPrintAttributes(D, Out); - } - + enum class AttrPosAsWritten { Default = 0, Left, Right }; + void + prettyPrintAttributes(const Decl *D, + AttrPosAsWritten Pos = AttrPosAsWritten::Default); void prettyPrintPragmas(Decl *D); void printDeclType(QualType T, StringRef DeclName, bool Pack = false); }; @@ -250,87 +238,48 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) { return Out; } -// For CLANG_ATTR_LIST_CanPrintOnLeft macro. -#include "clang/Basic/AttrLeftSideCanPrintList.inc" +static DeclPrinter::AttrPosAsWritten getPosAsWritten(const Attr *A, + const Decl *D) { + SourceLocation ALoc = A->getLoc(); + SourceLocation DLoc = D->getLocation(); + const ASTContext &C = D->getASTContext(); + if (ALoc.isInvalid() || DLoc.isInvalid()) + return DeclPrinter::AttrPosAsWritten::Left; -// For CLANG_ATTR_LIST_PrintOnLeft macro. -#include "clang/Basic/AttrLeftSideMustPrintList.inc" + if (C.getSourceManager().isBeforeInTranslationUnit(ALoc, DLoc)) + return DeclPrinter::AttrPosAsWritten::Left; -static bool canPrintOnLeftSide(attr::Kind kind) { -#ifdef CLANG_ATTR_LIST_CanPrintOnLeft - switch (kind) { - CLANG_ATTR_LIST_CanPrintOnLeft - return true; - default: - return false; - } -#else - return false; -#endif -} - -static bool canPrintOnLeftSide(const Attr *A) { - if (A->isStandardAttributeSyntax()) - return false; - - return canPrintOnLeftSide(A->getKind()); -} - -static bool mustPrintOnLeftSide(attr::Kind kind) { -#ifdef CLANG_ATTR_LIST_PrintOnLeft - switch (kind) { - CLANG_ATTR_LIST_PrintOnLeft - return true; - default: - return false; - } -#else - return false; -#endif + return DeclPrinter::AttrPosAsWritten::Right; } -static bool mustPrintOnLeftSide(const Attr *A) { - if (A->isDeclspecAttribute()) - return true; - - return mustPrintOnLeftSide(A->getKind()); -} - -void DeclPrinter::prettyPrintAttributes(Decl *D, llvm::raw_ostream &Out, - AttrPrintLoc Loc) { +void DeclPrinter::prettyPrintAttributes(const Decl *D, + AttrPosAsWritten Pos /*=Default*/) { if (Policy.PolishForDeclaration) return; if (D->hasAttrs()) { - AttrVec &Attrs = D->getAttrs(); + const AttrVec &Attrs = D->getAttrs(); for (auto *A : Attrs) { if (A->isInherited() || A->isImplicit()) continue; - - AttrPrintLoc AttrLoc = AttrPrintLoc::Right; - if (mustPrintOnLeftSide(A)) { - // If we must always print on left side (e.g. declspec), then mark as - // so. - AttrLoc = AttrPrintLoc::Left; - } else if (canPrintOnLeftSide(A)) { - // For functions with body defined we print the attributes on the left - // side so that GCC accept our dumps as well. - if (const FunctionDecl *FD = dyn_cast(D); - FD && FD->isThisDeclarationADefinition()) - // In case Decl is a function with a body, then attrs should be print - // on the left side. - AttrLoc = AttrPrintLoc::Left; - - // In case it is a variable declaration with a ctor, then allow - // printing on the left side for readbility. - else if (const VarDecl *VD = dyn_cast(D); - VD && VD->getInit() && - VD->getInitStyle() == VarDecl::CallInit) - AttrLoc = AttrPrintLoc::Left; + switch (A->getKind()) { +#define ATTR(X) +#define PRAGMA_SPELLING_ATTR(X) case attr::X: +#include "clang/Basic/AttrList.inc" + break; + default: + AttrPosAsWritten APos = getPosAsWritten(A, D); + assert(APos != AttrPosAsWritten::Default && + "Default not a valid for an attribute location"); + if (Pos == AttrPosAsWritten::Default || Pos == APos) { + if (Pos != AttrPosAsWritten::Left) + Out << ' '; + A->printPretty(Out, Policy); + if (Pos == AttrPosAsWritten::Left) + Out << ' '; + } + break; } - // Only print the side matches the user requested. - if ((Loc & AttrLoc) != AttrPrintLoc::None) - A->printPretty(Out, Policy); } } } @@ -691,8 +640,10 @@ static void MaybePrintTagKeywordIfSupressingScopes(PrintingPolicy &Policy, void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (!D->getDescribedFunctionTemplate() && - !D->isFunctionTemplateSpecialization()) + !D->isFunctionTemplateSpecialization()) { prettyPrintPragmas(D); + prettyPrintAttributes(D, AttrPosAsWritten::Left); + } if (D->isFunctionTemplateSpecialization()) Out << "template<> "; @@ -702,22 +653,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { printTemplateParameters(D->getTemplateParameterList(I)); } - std::string LeftsideAttrs; - llvm::raw_string_ostream LSAS(LeftsideAttrs); - - prettyPrintAttributes(D, LSAS, AttrPrintLoc::Left); - - // prettyPrintAttributes print a space on left side of the attribute. - if (LeftsideAttrs[0] == ' ') { - // Skip the space prettyPrintAttributes generated. - LeftsideAttrs.erase(0, LeftsideAttrs.find_first_not_of(' ')); - - // Add a single space between the attribute and the Decl name. - LSAS << ' '; - } - - Out << LeftsideAttrs; - CXXConstructorDecl *CDecl = dyn_cast(D); CXXConversionDecl *ConversionDecl = dyn_cast(D); CXXDeductionGuideDecl *GuideDecl = dyn_cast(D); @@ -883,13 +818,18 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Ty.print(Out, Policy, Proto); } - prettyPrintAttributes(D, Out, AttrPrintLoc::Right); + prettyPrintAttributes(D, AttrPosAsWritten::Right); if (D->isPureVirtual()) Out << " = 0"; - else if (D->isDeletedAsWritten()) + else if (D->isDeletedAsWritten()) { Out << " = delete"; - else if (D->isExplicitlyDefaulted()) + if (const StringLiteral *M = D->getDeletedMessage()) { + Out << "("; + M->outputString(Out); + Out << ")"; + } + } else if (D->isExplicitlyDefaulted()) Out << " = default"; else if (D->doesThisDeclarationHaveABody()) { if (!Policy.TerseOutput) { @@ -976,27 +916,12 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) { void DeclPrinter::VisitVarDecl(VarDecl *D) { prettyPrintPragmas(D); + prettyPrintAttributes(D, AttrPosAsWritten::Left); + if (const auto *Param = dyn_cast(D); Param && Param->isExplicitObjectParameter()) Out << "this "; - std::string LeftSide; - llvm::raw_string_ostream LeftSideStream(LeftSide); - - // Print attributes that should be placed on the left, such as __declspec. - prettyPrintAttributes(D, LeftSideStream, AttrPrintLoc::Left); - - // prettyPrintAttributes print a space on left side of the attribute. - if (LeftSide[0] == ' ') { - // Skip the space prettyPrintAttributes generated. - LeftSide.erase(0, LeftSide.find_first_not_of(' ')); - - // Add a single space between the attribute and the Decl name. - LeftSideStream << ' '; - } - - Out << LeftSide; - QualType T = D->getTypeSourceInfo() ? D->getTypeSourceInfo()->getType() : D->getASTContext().getUnqualifiedObjCPointerType(D->getType()); @@ -1029,21 +954,16 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { } } - StringRef Name; - - Name = (isa(D) && Policy.CleanUglifiedParameters && - D->getIdentifier()) - ? D->getIdentifier()->deuglifiedName() - : D->getName(); - if (!Policy.SuppressTagKeyword && Policy.SuppressScope && !Policy.SuppressUnwrittenScope) MaybePrintTagKeywordIfSupressingScopes(Policy, T, Out); - printDeclType(T, Name); - // Print the attributes that should be placed right before the end of the - // decl. - prettyPrintAttributes(D, Out, AttrPrintLoc::Right); + printDeclType(T, (isa(D) && Policy.CleanUglifiedParameters && + D->getIdentifier()) + ? D->getIdentifier()->deuglifiedName() + : D->getName()); + + prettyPrintAttributes(D, AttrPosAsWritten::Right); Expr *Init = D->getInit(); if (!Policy.SuppressInitializers && Init) { @@ -1303,7 +1223,10 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) { if (const TemplateTemplateParmDecl *TTP = dyn_cast(D)) { - Out << "class"; + if (TTP->wasDeclaredWithTypename()) + Out << "typename"; + else + Out << "class"; if (TTP->isParameterPack()) Out << " ..."; diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 3c217d6a6a5ae31933e3f88d249c0d5d116fc119..5aa2484197372bae11343ba22335c1734023ca1d 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -715,7 +715,7 @@ void TemplateTypeParmDecl::setTypeConstraint( NonTypeTemplateParmDecl::NonTypeTemplateParmDecl( DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, unsigned D, - unsigned P, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, + unsigned P, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, ArrayRef ExpandedTypes, ArrayRef ExpandedTInfos) : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc), TemplateParmPosition(D, P), ParameterPack(true), @@ -730,12 +730,10 @@ NonTypeTemplateParmDecl::NonTypeTemplateParmDecl( } } -NonTypeTemplateParmDecl * -NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, - SourceLocation StartLoc, SourceLocation IdLoc, - unsigned D, unsigned P, IdentifierInfo *Id, - QualType T, bool ParameterPack, - TypeSourceInfo *TInfo) { +NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create( + const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, unsigned D, unsigned P, const IdentifierInfo *Id, + QualType T, bool ParameterPack, TypeSourceInfo *TInfo) { AutoType *AT = C.getLangOpts().CPlusPlus20 ? T->getContainedAutoType() : nullptr; return new (C, DC, @@ -748,7 +746,7 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create( const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, + SourceLocation IdLoc, unsigned D, unsigned P, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, ArrayRef ExpandedTypes, ArrayRef ExpandedTInfos) { AutoType *AT = TInfo->getType()->getContainedAutoType(); @@ -807,10 +805,10 @@ void TemplateTemplateParmDecl::anchor() {} TemplateTemplateParmDecl::TemplateTemplateParmDecl( DeclContext *DC, SourceLocation L, unsigned D, unsigned P, - IdentifierInfo *Id, TemplateParameterList *Params, + IdentifierInfo *Id, bool Typename, TemplateParameterList *Params, ArrayRef Expansions) : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), - TemplateParmPosition(D, P), ParameterPack(true), + TemplateParmPosition(D, P), Typename(Typename), ParameterPack(true), ExpandedParameterPack(true), NumExpandedParams(Expansions.size()) { if (!Expansions.empty()) std::uninitialized_copy(Expansions.begin(), Expansions.end(), @@ -821,26 +819,26 @@ TemplateTemplateParmDecl * TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, bool ParameterPack, IdentifierInfo *Id, - TemplateParameterList *Params) { + bool Typename, TemplateParameterList *Params) { return new (C, DC) TemplateTemplateParmDecl(DC, L, D, P, ParameterPack, Id, - Params); + Typename, Params); } TemplateTemplateParmDecl * TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, - IdentifierInfo *Id, + IdentifierInfo *Id, bool Typename, TemplateParameterList *Params, ArrayRef Expansions) { return new (C, DC, additionalSizeToAlloc(Expansions.size())) - TemplateTemplateParmDecl(DC, L, D, P, Id, Params, Expansions); + TemplateTemplateParmDecl(DC, L, D, P, Id, Typename, Params, Expansions); } TemplateTemplateParmDecl * TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0, - false, nullptr, nullptr); + false, nullptr, false, nullptr); } TemplateTemplateParmDecl * @@ -849,7 +847,7 @@ TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID, auto *TTP = new (C, ID, additionalSizeToAlloc(NumExpansions)) TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0, nullptr, - nullptr, std::nullopt); + false, nullptr, std::nullopt); TTP->NumExpandedParams = NumExpansions; return TTP; } @@ -1471,7 +1469,7 @@ createMakeIntegerSeqParameterList(const ASTContext &C, DeclContext *DC) { // template class IntSeq auto *TemplateTemplateParm = TemplateTemplateParmDecl::Create( C, DC, SourceLocation(), /*Depth=*/0, /*Position=*/0, - /*ParameterPack=*/false, /*Id=*/nullptr, TPL); + /*ParameterPack=*/false, /*Id=*/nullptr, /*Typename=*/false, TPL); TemplateTemplateParm->setImplicit(true); // typename T diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 46182809810bcf5108e90ff8a05b84dbc35d8d07..01ec31e4077f707c8fa540b6ec5d13564e2f920c 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -173,10 +173,18 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return this->emitCastFloatingIntegral(*ToT, CE); } - case CK_NullToPointer: + case CK_NullToPointer: { if (DiscardResult) return true; - return this->emitNull(classifyPrim(CE->getType()), CE); + + const Descriptor *Desc = nullptr; + const QualType PointeeType = CE->getType()->getPointeeType(); + if (!PointeeType.isNull()) { + if (std::optional T = classify(PointeeType)) + Desc = P.createDescriptor(SubExpr, *T); + } + return this->emitNull(classifyPrim(CE->getType()), Desc, CE); + } case CK_PointerToIntegral: { if (DiscardResult) @@ -199,6 +207,41 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return true; } + case CK_IntegralToPointer: { + QualType IntType = SubExpr->getType(); + assert(IntType->isIntegralOrEnumerationType()); + if (!this->visit(SubExpr)) + return false; + // FIXME: I think the discard is wrong since the int->ptr cast might cause a + // diagnostic. + PrimType T = classifyPrim(IntType); + if (DiscardResult) + return this->emitPop(T, CE); + + QualType PtrType = CE->getType(); + assert(PtrType->isPointerType()); + + const Descriptor *Desc; + if (std::optional T = classify(PtrType->getPointeeType())) + Desc = P.createDescriptor(SubExpr, *T); + else if (PtrType->getPointeeType()->isVoidType()) + Desc = nullptr; + else + Desc = P.createDescriptor(CE, PtrType->getPointeeType().getTypePtr(), + Descriptor::InlineDescMD, true, false, + /*IsMutable=*/false, nullptr); + + if (!this->emitGetIntPtr(T, Desc, CE)) + return false; + + PrimType DestPtrT = classifyPrim(PtrType); + if (DestPtrT == PT_Ptr) + return true; + + // In case we're converting the integer to a non-Pointer. + return this->emitDecayPtr(PT_Ptr, DestPtrT, CE); + } + case CK_AtomicToNonAtomic: case CK_ConstructorConversion: case CK_FunctionToPointerDecay: @@ -207,13 +250,31 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { case CK_UserDefinedConversion: return this->delegate(SubExpr); - case CK_BitCast: + case CK_BitCast: { + // Reject bitcasts to atomic types. if (CE->getType()->isAtomicType()) { if (!this->discard(SubExpr)) return false; return this->emitInvalidCast(CastKind::Reinterpret, CE); } - return this->delegate(SubExpr); + + if (DiscardResult) + return this->discard(SubExpr); + + std::optional FromT = classify(SubExpr->getType()); + std::optional ToT = classifyPrim(CE->getType()); + if (!FromT || !ToT) + return false; + + assert(isPtrType(*FromT)); + assert(isPtrType(*ToT)); + if (FromT == ToT) + return this->delegate(SubExpr); + + if (!this->visit(SubExpr)) + return false; + return this->emitDecayPtr(*FromT, *ToT, CE); + } case CK_IntegralToBoolean: case CK_IntegralCast: { @@ -245,7 +306,7 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { if (!this->visit(SubExpr)) return false; - if (!this->emitNull(PtrT, CE)) + if (!this->emitNull(PtrT, nullptr, CE)) return false; return this->emitNE(PtrT, CE); @@ -455,7 +516,7 @@ bool ByteCodeExprGen::VisitBinaryOperator(const BinaryOperator *BO) { // Pointer arithmetic special case. if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) { - if (T == PT_Ptr || (LT == PT_Ptr && RT == PT_Ptr)) + if (isPtrType(*T) || (isPtrType(*LT) && isPtrType(*RT))) return this->VisitPointerArithBinOp(BO); } @@ -1033,6 +1094,34 @@ bool ByteCodeExprGen::VisitInitListExpr(const InitListExpr *E) { return true; } + if (const auto *VecT = E->getType()->getAs()) { + unsigned NumVecElements = VecT->getNumElements(); + assert(NumVecElements >= E->getNumInits()); + + QualType ElemQT = VecT->getElementType(); + PrimType ElemT = classifyPrim(ElemQT); + + // All initializer elements. + unsigned InitIndex = 0; + for (const Expr *Init : E->inits()) { + if (!this->visit(Init)) + return false; + + if (!this->emitInitElem(ElemT, InitIndex, E)) + return false; + ++InitIndex; + } + + // Fill the rest with zeroes. + for (; InitIndex != NumVecElements; ++InitIndex) { + if (!this->visitZeroInitializer(ElemT, ElemQT, E)) + return false; + if (!this->emitInitElem(ElemT, InitIndex, E)) + return false; + } + return true; + } + return false; } @@ -1084,6 +1173,9 @@ static CharUnits AlignOfType(QualType T, const ASTContext &ASTCtx, if (const auto *Ref = T->getAs()) T = Ref->getPointeeType(); + if (T.getQualifiers().hasUnaligned()) + return CharUnits::One(); + // __alignof is defined to return the preferred alignment. // Before 8, clang returned the preferred alignment for alignof and // _Alignof as well. @@ -2323,7 +2415,7 @@ bool ByteCodeExprGen::visitBool(const Expr *E) { // Convert pointers to bool. if (T == PT_Ptr || T == PT_FnPtr) { - if (!this->emitNull(*T, E)) + if (!this->emitNull(*T, nullptr, E)) return false; return this->emitNE(*T, E); } @@ -2363,9 +2455,9 @@ bool ByteCodeExprGen::visitZeroInitializer(PrimType T, QualType QT, case PT_IntAPS: return this->emitZeroIntAPS(Ctx.getBitWidth(QT), E); case PT_Ptr: - return this->emitNullPtr(E); + return this->emitNullPtr(nullptr, E); case PT_FnPtr: - return this->emitNullFnPtr(E); + return this->emitNullFnPtr(nullptr, E); case PT_Float: { return this->emitConstFloat(APFloat::getZero(Ctx.getFloatSemantics(QT)), E); } @@ -2511,6 +2603,7 @@ unsigned ByteCodeExprGen::allocateLocalPrimitive(DeclTy &&Src, dyn_cast_if_present(Src.dyn_cast())) { assert(!P.getGlobal(VD)); assert(!Locals.contains(VD)); + (void)VD; } // FIXME: There are cases where Src.is() is wrong, e.g. @@ -2685,26 +2778,34 @@ bool ByteCodeExprGen::visitVarDecl(const VarDecl *VD) { std::optional VarT = classify(VD->getType()); if (Context::shouldBeGloballyIndexed(VD)) { - // We've already seen and initialized this global. - if (P.getGlobal(VD)) - return true; - - std::optional GlobalIndex = P.createGlobal(VD, Init); - - if (!GlobalIndex) - return false; - - if (Init) { + auto initGlobal = [&](unsigned GlobalIndex) -> bool { + assert(Init); DeclScope LocalScope(this, VD); if (VarT) { if (!this->visit(Init)) return false; - return this->emitInitGlobal(*VarT, *GlobalIndex, VD); + return this->emitInitGlobal(*VarT, GlobalIndex, VD); } - return this->visitGlobalInitializer(Init, *GlobalIndex); + return this->visitGlobalInitializer(Init, GlobalIndex); + }; + + // We've already seen and initialized this global. + if (std::optional GlobalIndex = P.getGlobal(VD)) { + if (P.getPtrGlobal(*GlobalIndex).isInitialized()) + return true; + + // The previous attempt at initialization might've been unsuccessful, + // so let's try this one. + return Init && initGlobal(*GlobalIndex); } - return true; + + std::optional GlobalIndex = P.createGlobal(VD, Init); + + if (!GlobalIndex) + return false; + + return !Init || initGlobal(*GlobalIndex); } else { VariableScope LocalScope(this); if (VarT) { @@ -2948,7 +3049,7 @@ bool ByteCodeExprGen::VisitCXXNullPtrLiteralExpr( if (DiscardResult) return true; - return this->emitNullPtr(E); + return this->emitNullPtr(nullptr, E); } template diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp index 675063e74898867e0edc7875a252c8510a701a87..55a06f37a0c3dec8296174593d35c07579e53f80 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -110,7 +110,7 @@ bool ByteCodeStmtGen::emitLambdaStaticInvokerBody( // one here, and we don't need one either because the lambda cannot have // any captures, as verified above. Emit a null pointer. This is then // special-cased when interpreting to not emit any misleading diagnostics. - if (!this->emitNullPtr(MD)) + if (!this->emitNullPtr(nullptr, MD)) return false; // Forward all arguments from the static invoker to the lambda call operator. diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp index 15a9d46880e954acf13d2a7fc4d7ac33d3e62ede..274178837bf047d346ba7be09a6ac6ba159dbc92 100644 --- a/clang/lib/AST/Interp/Context.cpp +++ b/clang/lib/AST/Interp/Context.cpp @@ -120,7 +120,8 @@ std::optional Context::classify(QualType T) const { if (T->isBooleanType()) return PT_Bool; - if (T->isAnyComplexType()) + // We map these to primitive arrays. + if (T->isAnyComplexType() || T->isVectorType()) return std::nullopt; if (T->isSignedIntegerOrEnumerationType()) { diff --git a/clang/lib/AST/Interp/Descriptor.h b/clang/lib/AST/Interp/Descriptor.h index 4e257361ad146bfaa14c78873cb1f08bf1bbf162..c386fc8ac7b09d5030d1332e2d8dc227bba19a4c 100644 --- a/clang/lib/AST/Interp/Descriptor.h +++ b/clang/lib/AST/Interp/Descriptor.h @@ -168,6 +168,7 @@ public: const Decl *asDecl() const { return Source.dyn_cast(); } const Expr *asExpr() const { return Source.dyn_cast(); } + const DeclTy &getSource() const { return Source; } const ValueDecl *asValueDecl() const { return dyn_cast_if_present(asDecl()); diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp index 01ef1c24744a582f4df50980ec4ddd81ac86bc10..022b394e58e6438cbaa27039a5d6e773aa67d7de 100644 --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -233,3 +233,34 @@ LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS, F = F->Caller; } } + +LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation, + unsigned Offset) const { + unsigned Indent = Indentation * 2; + OS.indent(Indent); + { + ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true}); + OS << getName() << "\n"; + } + + unsigned I = 0; + for (const Record::Base &B : bases()) { + OS.indent(Indent) << "- Base " << I << ". Offset " << (Offset + B.Offset) + << "\n"; + B.R->dump(OS, Indentation + 1, Offset + B.Offset); + ++I; + } + + // FIXME: Virtual bases. + + I = 0; + for (const Record::Field &F : fields()) { + OS.indent(Indent) << "- Field " << I << ": "; + { + ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true}); + OS << F.Decl->getName(); + } + OS << ". Offset " << (Offset + F.Offset) << "\n"; + ++I; + } +} diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp index caffb69d83e379a8d62225359889a0f1d22d1f9b..d764b4b6f6d17b1fde40c37c1e0ef85a77573db3 100644 --- a/clang/lib/AST/Interp/EvalEmitter.cpp +++ b/clang/lib/AST/Interp/EvalEmitter.cpp @@ -51,7 +51,8 @@ EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD, this->CheckFullyInitialized = CheckFullyInitialized; this->ConvertResultToRValue = VD->getAnyInitializer() && - (VD->getAnyInitializer()->getType()->isAnyComplexType()); + (VD->getAnyInitializer()->getType()->isAnyComplexType() || + VD->getAnyInitializer()->getType()->isVectorType()); EvalResult.setSource(VD); if (!this->visitDecl(VD) && EvalResult.empty()) diff --git a/clang/lib/AST/Interp/FunctionPointer.h b/clang/lib/AST/Interp/FunctionPointer.h index 2ff691b1cd3e186323e4907d4e7ca78dfa0a7327..c2ea295b82bdf560d26b16ec2b21a87028e9ed63 100644 --- a/clang/lib/AST/Interp/FunctionPointer.h +++ b/clang/lib/AST/Interp/FunctionPointer.h @@ -20,27 +20,45 @@ namespace interp { class FunctionPointer final { private: const Function *Func; + bool Valid; public: - FunctionPointer() : Func(nullptr) {} - FunctionPointer(const Function *Func) : Func(Func) { assert(Func); } + FunctionPointer(const Function *Func) : Func(Func), Valid(true) { + assert(Func); + } + + FunctionPointer(uintptr_t IntVal = 0, const Descriptor *Desc = nullptr) + : Func(reinterpret_cast(IntVal)), Valid(false) {} const Function *getFunction() const { return Func; } bool isZero() const { return !Func; } + bool isWeak() const { + if (!Func || !Valid) + return false; + + return Func->getDecl()->isWeak(); + } APValue toAPValue() const { if (!Func) return APValue(static_cast(nullptr), CharUnits::Zero(), {}, /*OnePastTheEnd=*/false, /*IsNull=*/true); + if (!Valid) + return APValue(static_cast(nullptr), + CharUnits::fromQuantity(getIntegerRepresentation()), {}, + /*OnePastTheEnd=*/false, /*IsNull=*/false); + return APValue(Func->getDecl(), CharUnits::Zero(), {}, /*OnePastTheEnd=*/false, /*IsNull=*/false); } void print(llvm::raw_ostream &OS) const { OS << "FnPtr("; - if (Func) + if (Func && Valid) OS << Func->getName(); + else if (Func) + OS << reinterpret_cast(Func); else OS << "nullptr"; OS << ")"; @@ -53,6 +71,10 @@ public: return toAPValue().getAsString(Ctx, Func->getDecl()->getType()); } + uint64_t getIntegerRepresentation() const { + return static_cast(reinterpret_cast(Func)); + } + ComparisonCategoryResult compare(const FunctionPointer &RHS) const { if (Func == RHS.Func) return ComparisonCategoryResult::Equal; diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 0ce64a572c263f3daa07d3de4385037e24fa6496..2607e0743251673aaba35b958795723ec22b5002 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -56,22 +56,65 @@ static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) { return true; } +static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC, + const ValueDecl *VD) { + const SourceInfo &E = S.Current->getSource(OpPC); + S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD; + S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange(); +} + +static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, + const ValueDecl *VD); +static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC, + const ValueDecl *D) { + const SourceInfo &E = S.Current->getSource(OpPC); + + if (isa(D)) { + if (S.getLangOpts().CPlusPlus11) { + S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D; + S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange(); + } else { + S.FFDiag(E); + } + } else if (const auto *VD = dyn_cast(D)) { + if (!VD->getType().isConstQualified()) { + diagnoseNonConstVariable(S, OpPC, VD); + return false; + } + + // const, but no initializer. + if (!VD->getAnyInitializer()) { + diagnoseMissingInitializer(S, OpPC, VD); + return false; + } + } + return false; +} + static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, const ValueDecl *VD) { if (!S.getLangOpts().CPlusPlus) return; const SourceInfo &Loc = S.Current->getSource(OpPC); + if (const auto *VarD = dyn_cast(VD); + VarD && VarD->getType().isConstQualified() && + !VarD->getAnyInitializer()) { + diagnoseMissingInitializer(S, OpPC, VD); + return; + } - if (VD->getType()->isIntegralOrEnumerationType()) + if (VD->getType()->isIntegralOrEnumerationType()) { S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD; - else - S.FFDiag(Loc, - S.getLangOpts().CPlusPlus11 - ? diag::note_constexpr_ltor_non_constexpr - : diag::note_constexpr_ltor_non_integral, - 1) - << VD << VD->getType(); + S.Note(VD->getLocation(), diag::note_declared_at); + return; + } + + S.FFDiag(Loc, + S.getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr + : diag::note_constexpr_ltor_non_integral, + 1) + << VD << VD->getType(); S.Note(VD->getLocation(), diag::note_declared_at); } @@ -202,6 +245,9 @@ bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (!Ptr.isExtern()) return true; + if (Ptr.isInitialized()) + return true; + if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) { const auto *VD = Ptr.getDeclDesc()->asValueDecl(); diagnoseNonConstVariable(S, OpPC, VD); @@ -282,6 +328,8 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { } static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { + if (Ptr.isIntegralPointer()) + return true; return CheckConstant(S, OpPC, Ptr.getDeclDesc()); } @@ -335,6 +383,9 @@ bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { return true; } + if (!Ptr.isBlockPointer()) + return false; + const QualType Ty = Ptr.getType(); const SourceInfo &Loc = S.Current->getSource(OpPC); S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty; @@ -364,9 +415,15 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, if (const auto *VD = Ptr.getDeclDesc()->asVarDecl(); VD && VD->hasGlobalStorage()) { const SourceInfo &Loc = S.Current->getSource(OpPC); - S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD; - S.Note(VD->getLocation(), diag::note_declared_at); + if (VD->getAnyInitializer()) { + S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD; + S.Note(VD->getLocation(), diag::note_declared_at); + } else { + diagnoseMissingInitializer(S, OpPC, VD); + } + return false; } + if (!S.checkingPotentialConstantExpression()) { S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit) << AK << /*uninitialized=*/true << S.Current->getRange(OpPC); @@ -593,33 +650,6 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, return true; } -static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC, - const ValueDecl *D) { - const SourceInfo &E = S.Current->getSource(OpPC); - - if (isa(D)) { - if (S.getLangOpts().CPlusPlus11) { - S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D; - S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange(); - } else { - S.FFDiag(E); - } - } else if (const auto *VD = dyn_cast(D)) { - if (!VD->getType().isConstQualified()) { - diagnoseNonConstVariable(S, OpPC, VD); - return false; - } - - // const, but no initializer. - if (!VD->getAnyInitializer()) { - S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD; - S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange(); - return false; - } - } - return false; -} - /// We aleady know the given DeclRefExpr is invalid for some reason, /// now figure out why and print appropriate diagnostics. bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) { diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 405993eb827036f620ec62e119ddb33667697682..4182254357eb9a4327b4458b973662f7bd789c49 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -758,7 +758,7 @@ inline bool CmpHelperEQ(InterpState &S, CodePtr OpPC, // We cannot compare against weak declarations at compile time. for (const auto &FP : {LHS, RHS}) { - if (!FP.isZero() && FP.getFunction()->getDecl()->isWeak()) { + if (FP.isWeak()) { const SourceInfo &Loc = S.Current->getSource(OpPC); S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison) << FP.toDiagnosticString(S.getCtx()); @@ -801,6 +801,17 @@ inline bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) { return true; } + for (const auto &P : {LHS, RHS}) { + if (P.isZero()) + continue; + if (P.isWeak()) { + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison) + << P.toDiagnosticString(S.getCtx()); + return false; + } + } + if (!Pointer::hasSameBase(LHS, RHS)) { S.Stk.push(BoolT::from(Fn(ComparisonCategoryResult::Unordered))); return true; @@ -812,9 +823,9 @@ inline bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) { // element in the same array are NOT equal. They have the same Base value, // but a different Offset. This is a pretty rare case, so we fix this here // by comparing pointers to the first elements. - if (!LHS.isDummy() && LHS.isArrayRoot()) + if (!LHS.isZero() && !LHS.isDummy() && LHS.isArrayRoot()) VL = LHS.atIndex(0).getByteOffset(); - if (!RHS.isDummy() && RHS.isArrayRoot()) + if (!RHS.isZero() && !RHS.isDummy() && RHS.isArrayRoot()) VR = RHS.atIndex(0).getByteOffset(); S.Stk.push(BoolT::from(Fn(Compare(VL, VR)))); @@ -1333,6 +1344,11 @@ inline bool FinishInit(InterpState &S, CodePtr OpPC) { return true; } +inline bool Dump(InterpState &S, CodePtr OpPC) { + S.Stk.dump(); + return true; +} + inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, const Pointer &Ptr) { Pointer Base = Ptr; @@ -1370,6 +1386,8 @@ bool Load(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.peek(); if (!CheckLoad(S, OpPC, Ptr)) return false; + if (!Ptr.isBlockPointer()) + return false; S.Stk.push(Ptr.deref()); return true; } @@ -1379,6 +1397,8 @@ bool LoadPop(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop(); if (!CheckLoad(S, OpPC, Ptr)) return false; + if (!Ptr.isBlockPointer()) + return false; S.Stk.push(Ptr.deref()); return true; } @@ -1517,8 +1537,12 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, return true; } - if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) - return false; + if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) { + // The CheckNull will have emitted a note already, but we only + // abort in C++, since this is fine in C. + if (S.getLangOpts().CPlusPlus) + return false; + } // Arrays of unknown bounds cannot have pointers into them. if (!CheckArray(S, OpPC, Ptr)) @@ -1544,23 +1568,25 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, Invalid = true; }; - T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth()); - if constexpr (Op == ArithOp::Add) { - // If the new offset would be negative, bail out. - if (Offset.isNegative() && (Offset.isMin() || -Offset > Index)) - DiagInvalidOffset(); - - // If the new offset would be out of bounds, bail out. - if (Offset.isPositive() && Offset > MaxOffset) - DiagInvalidOffset(); - } else { - // If the new offset would be negative, bail out. - if (Offset.isPositive() && Index < Offset) - DiagInvalidOffset(); - - // If the new offset would be out of bounds, bail out. - if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset)) - DiagInvalidOffset(); + if (Ptr.isBlockPointer()) { + T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth()); + if constexpr (Op == ArithOp::Add) { + // If the new offset would be negative, bail out. + if (Offset.isNegative() && (Offset.isMin() || -Offset > Index)) + DiagInvalidOffset(); + + // If the new offset would be out of bounds, bail out. + if (Offset.isPositive() && Offset > MaxOffset) + DiagInvalidOffset(); + } else { + // If the new offset would be negative, bail out. + if (Offset.isPositive() && Index < Offset) + DiagInvalidOffset(); + + // If the new offset would be out of bounds, bail out. + if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset)) + DiagInvalidOffset(); + } } if (Invalid && !Ptr.isDummy() && S.getLangOpts().CPlusPlus) @@ -1644,6 +1670,11 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC) { const Pointer &LHS = S.Stk.pop(); const Pointer &RHS = S.Stk.pop(); + if (RHS.isZero()) { + S.Stk.push(T::from(LHS.getIndex())); + return true; + } + if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) { // TODO: Diagnose. return false; @@ -1822,8 +1853,9 @@ static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { } template ::T> -inline bool Null(InterpState &S, CodePtr OpPC) { - S.Stk.push(); +inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { + // Note: Desc can be null. + S.Stk.push(0, Desc); return true; } @@ -1841,6 +1873,15 @@ inline bool This(InterpState &S, CodePtr OpPC) { if (!CheckThis(S, OpPC, This)) return false; + // Ensure the This pointer has been cast to the correct base. + if (!This.isDummy()) { + assert(isa(S.Current->getFunction()->getDecl())); + assert(This.getRecord()); + assert( + This.getRecord()->getDecl() == + cast(S.Current->getFunction()->getDecl())->getParent()); + } + S.Stk.push(This); return true; } @@ -2218,6 +2259,14 @@ inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) { return true; } +template ::T> +inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { + const T &IntVal = S.Stk.pop(); + + S.Stk.push(static_cast(IntVal), Desc); + return true; +} + /// Just emit a diagnostic. The expression that caused emission of this /// op is not valid in a constant context. inline bool Invalid(InterpState &S, CodePtr OpPC) { @@ -2274,6 +2323,18 @@ inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) { return false; } +/// OldPtr -> Integer -> NewPtr. +template +inline bool DecayPtr(InterpState &S, CodePtr OpPC) { + static_assert(isPtrType(TIn) && isPtrType(TOut)); + using FromT = typename PrimConv::T; + using ToT = typename PrimConv::T; + + const FromT &OldPtr = S.Stk.pop(); + S.Stk.push(ToT(OldPtr.getIntegerRepresentation(), nullptr)); + return true; +} + //===----------------------------------------------------------------------===// // Read opcode arguments //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/Interp/InterpBlock.cpp b/clang/lib/AST/Interp/InterpBlock.cpp index a62128d9cfaedd292b38238715b7d0bf33754751..9b33d1b778fb2c0aadf77cc10d8c1dbb42a2fcb9 100644 --- a/clang/lib/AST/Interp/InterpBlock.cpp +++ b/clang/lib/AST/Interp/InterpBlock.cpp @@ -73,7 +73,7 @@ void Block::replacePointer(Pointer *Old, Pointer *New) { removePointer(Old); addPointer(New); - Old->Pointee = nullptr; + Old->PointeeStorage.BS.Pointee = nullptr; #ifndef NDEBUG assert(!hasPointer(Old)); @@ -104,7 +104,7 @@ DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk) // Transfer pointers. B.Pointers = Blk->Pointers; for (Pointer *P = Blk->Pointers; P; P = P->Next) - P->Pointee = &B; + P->PointeeStorage.BS.Pointee = &B; } void DeadBlock::free() { diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index 1bf5d55314f1f2ac2a059defc40903cb2dec3e85..984ba4f7f2689c0e61b944e31882ae8533c1b760 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -16,6 +16,16 @@ namespace clang { namespace interp { +static unsigned callArgSize(const InterpState &S, const CallExpr *C) { + unsigned O = 0; + + for (const Expr *E : C->arguments()) { + O += align(primSize(*S.getContext().classify(E))); + } + + return O; +} + template static T getParam(const InterpFrame *Frame, unsigned Index) { assert(Frame->getFunction()->getNumParams() > Index); @@ -816,9 +826,10 @@ static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC, static bool interp__builtin_clz(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, const CallExpr *Call) { + unsigned CallSize = callArgSize(S, Call); unsigned BuiltinOp = Func->getBuiltinID(); PrimType ValT = *S.getContext().classify(Call->getArg(0)); - const APSInt &Val = peekToAPSInt(S.Stk, ValT); + const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize); // When the argument is 0, the result of GCC builtins is undefined, whereas // for Microsoft intrinsics, the result is the bit-width of the argument. @@ -826,8 +837,19 @@ static bool interp__builtin_clz(InterpState &S, CodePtr OpPC, BuiltinOp != Builtin::BI__lzcnt && BuiltinOp != Builtin::BI__lzcnt64; - if (ZeroIsUndefined && Val == 0) - return false; + if (Val == 0) { + if (Func->getBuiltinID() == Builtin::BI__builtin_clzg && + Call->getNumArgs() == 2) { + // We have a fallback parameter. + PrimType FallbackT = *S.getContext().classify(Call->getArg(1)); + const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT); + pushInteger(S, Fallback, Call->getType()); + return true; + } + + if (ZeroIsUndefined) + return false; + } pushInteger(S, Val.countl_zero(), Call->getType()); return true; @@ -836,11 +858,21 @@ static bool interp__builtin_clz(InterpState &S, CodePtr OpPC, static bool interp__builtin_ctz(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, const CallExpr *Call) { + unsigned CallSize = callArgSize(S, Call); PrimType ValT = *S.getContext().classify(Call->getArg(0)); - const APSInt &Val = peekToAPSInt(S.Stk, ValT); - - if (Val == 0) + const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize); + + if (Val == 0) { + if (Func->getBuiltinID() == Builtin::BI__builtin_ctzg && + Call->getNumArgs() == 2) { + // We have a fallback parameter. + PrimType FallbackT = *S.getContext().classify(Call->getArg(1)); + const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT); + pushInteger(S, Fallback, Call->getType()); + return true; + } return false; + } pushInteger(S, Val.countr_zero(), Call->getType()); return true; @@ -1223,6 +1255,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, case Builtin::BI__builtin_clzl: case Builtin::BI__builtin_clzll: case Builtin::BI__builtin_clzs: + case Builtin::BI__builtin_clzg: case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes case Builtin::BI__lzcnt: case Builtin::BI__lzcnt64: @@ -1234,6 +1267,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, case Builtin::BI__builtin_ctzl: case Builtin::BI__builtin_ctzll: case Builtin::BI__builtin_ctzs: + case Builtin::BI__builtin_ctzg: if (!interp__builtin_ctz(S, OpPC, Frame, F, Call)) return false; break; diff --git a/clang/lib/AST/Interp/InterpState.h b/clang/lib/AST/Interp/InterpState.h index 8f84bf6ed2eaffa908c61f2f1e2ddf5930d7cde1..c17cfad11b1e2b6145c2554cb0d29c0cd208a993 100644 --- a/clang/lib/AST/Interp/InterpState.h +++ b/clang/lib/AST/Interp/InterpState.h @@ -89,7 +89,11 @@ public: /// Delegates source mapping to the mapper. SourceInfo getSource(const Function *F, CodePtr PC) const override { - return M ? M->getSource(F, PC) : F->getSource(PC); + if (M) + return M->getSource(F, PC); + + assert(F && "Function cannot be null"); + return F->getSource(PC); } Context &getContext() const { return Ctx; } diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index cc1310f4c0d52aeb0b00ac8fd39acafdcce43fac..e17be3afd25729a7f3a1b78fcb425af3d16ae1fa 100644 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -59,6 +59,7 @@ def ArgCastKind : ArgType { let Name = "CastKind"; } def ArgCallExpr : ArgType { let Name = "const CallExpr *"; } def ArgOffsetOfExpr : ArgType { let Name = "const OffsetOfExpr *"; } def ArgDeclRef : ArgType { let Name = "const DeclRefExpr *"; } +def ArgDesc : ArgType { let Name = "const Descriptor *"; } def ArgCCI : ArgType { let Name = "const ComparisonCategoryInfo *"; } //===----------------------------------------------------------------------===// @@ -272,6 +273,7 @@ def ZeroIntAPS : Opcode { // [] -> [Pointer] def Null : Opcode { let Types = [PtrTypeClass]; + let Args = [ArgDesc]; let HasGroup = 1; } @@ -530,6 +532,11 @@ def GetFnPtr : Opcode { let Args = [ArgFunction]; } +def GetIntPtr : Opcode { + let Types = [AluTypeClass]; + let Args = [ArgDesc]; + let HasGroup = 1; +} //===----------------------------------------------------------------------===// // Binary operators. @@ -662,6 +669,11 @@ def CastPointerIntegral : Opcode { let HasGroup = 1; } +def DecayPtr : Opcode { + let Types = [PtrTypeClass, PtrTypeClass]; + let HasGroup = 1; +} + //===----------------------------------------------------------------------===// // Comparison opcodes. //===----------------------------------------------------------------------===// @@ -723,3 +735,8 @@ def CheckNonNullArg : Opcode { } def Memcpy : Opcode; + +//===----------------------------------------------------------------------===// +// Debugging. +//===----------------------------------------------------------------------===// +def Dump : Opcode; diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index af60ced0e10e9ea2a6e4231a6bf34a3c841976d6..e163e658d462b2d2020900e95d27798461c41f4c 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -26,60 +26,95 @@ Pointer::Pointer(Block *Pointee) Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset) : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {} -Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {} +Pointer::Pointer(const Pointer &P) + : Offset(P.Offset), PointeeStorage(P.PointeeStorage), + StorageKind(P.StorageKind) { -Pointer::Pointer(Pointer &&P) - : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) { - if (Pointee) - Pointee->replacePointer(&P, this); + if (isBlockPointer() && PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->addPointer(this); } Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset) - : Pointee(Pointee), Base(Base), Offset(Offset) { + : Offset(Offset), StorageKind(Storage::Block) { assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base"); + + PointeeStorage.BS = {Pointee, Base}; + if (Pointee) Pointee->addPointer(this); } +Pointer::Pointer(Pointer &&P) + : Offset(P.Offset), PointeeStorage(P.PointeeStorage), + StorageKind(P.StorageKind) { + + if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->replacePointer(&P, this); +} + Pointer::~Pointer() { - if (Pointee) { - Pointee->removePointer(this); - Pointee->cleanup(); + if (isIntegralPointer()) + return; + + if (PointeeStorage.BS.Pointee) { + PointeeStorage.BS.Pointee->removePointer(this); + PointeeStorage.BS.Pointee->cleanup(); } } void Pointer::operator=(const Pointer &P) { - Block *Old = Pointee; - if (Pointee) - Pointee->removePointer(this); + if (!this->isIntegralPointer() || !P.isBlockPointer()) + assert(P.StorageKind == StorageKind); - Offset = P.Offset; - Base = P.Base; + bool WasBlockPointer = isBlockPointer(); + StorageKind = P.StorageKind; + if (StorageKind == Storage::Block) { + Block *Old = PointeeStorage.BS.Pointee; + if (WasBlockPointer && PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->removePointer(this); - Pointee = P.Pointee; - if (Pointee) - Pointee->addPointer(this); + Offset = P.Offset; + PointeeStorage.BS = P.PointeeStorage.BS; + + if (PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->addPointer(this); + + if (WasBlockPointer && Old) + Old->cleanup(); - if (Old) - Old->cleanup(); + } else if (StorageKind == Storage::Int) { + PointeeStorage.Int = P.PointeeStorage.Int; + } else { + assert(false && "Unhandled storage kind"); + } } void Pointer::operator=(Pointer &&P) { - Block *Old = Pointee; + if (!this->isIntegralPointer() || !P.isBlockPointer()) + assert(P.StorageKind == StorageKind); - if (Pointee) - Pointee->removePointer(this); + bool WasBlockPointer = isBlockPointer(); + StorageKind = P.StorageKind; + if (StorageKind == Storage::Block) { + Block *Old = PointeeStorage.BS.Pointee; + if (WasBlockPointer && PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->removePointer(this); - Offset = P.Offset; - Base = P.Base; + Offset = P.Offset; + PointeeStorage.BS = P.PointeeStorage.BS; - Pointee = P.Pointee; - if (Pointee) - Pointee->replacePointer(&P, this); + if (PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->addPointer(this); - if (Old) - Old->cleanup(); + if (WasBlockPointer && Old) + Old->cleanup(); + + } else if (StorageKind == Storage::Int) { + PointeeStorage.Int = P.PointeeStorage.Int; + } else { + assert(false && "Unhandled storage kind"); + } } APValue Pointer::toAPValue() const { @@ -88,6 +123,11 @@ APValue Pointer::toAPValue() const { if (isZero()) return APValue(static_cast(nullptr), CharUnits::Zero(), Path, /*IsOnePastEnd=*/false, /*IsNullPtr=*/true); + if (isIntegralPointer()) + return APValue(static_cast(nullptr), + CharUnits::fromQuantity(asIntPointer().Value + this->Offset), + Path, + /*IsOnePastEnd=*/false, /*IsNullPtr=*/false); // Build the lvalue base from the block. const Descriptor *Desc = getDeclDesc(); @@ -137,19 +177,52 @@ APValue Pointer::toAPValue() const { return APValue(Base, Offset, Path, IsOnePastEnd, /*IsNullPtr=*/false); } +void Pointer::print(llvm::raw_ostream &OS) const { + OS << PointeeStorage.BS.Pointee << " ("; + if (isBlockPointer()) { + OS << "Block) {"; + + if (PointeeStorage.BS.Base == RootPtrMark) + OS << "rootptr, "; + else + OS << PointeeStorage.BS.Base << ", "; + + if (Offset == PastEndMark) + OS << "pastend, "; + else + OS << Offset << ", "; + + if (isBlockPointer() && PointeeStorage.BS.Pointee) + OS << PointeeStorage.BS.Pointee->getSize(); + else + OS << "nullptr"; + } else { + OS << "Int) {"; + OS << PointeeStorage.Int.Value << ", " << PointeeStorage.Int.Desc; + } + OS << "}"; +} + std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const { - if (!Pointee) + if (isZero()) return "nullptr"; + if (isIntegralPointer()) + return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str(); + return toAPValue().getAsString(Ctx, getType()); } bool Pointer::isInitialized() const { - assert(Pointee && "Cannot check if null pointer was initialized"); + if (isIntegralPointer()) + return true; + + assert(PointeeStorage.BS.Pointee && + "Cannot check if null pointer was initialized"); const Descriptor *Desc = getFieldDesc(); assert(Desc); if (Desc->isPrimitiveArray()) { - if (isStatic() && Base == 0) + if (isStatic() && PointeeStorage.BS.Base == 0) return true; InitMapPtr &IM = getInitMap(); @@ -164,17 +237,24 @@ bool Pointer::isInitialized() const { } // Field has its bit in an inline descriptor. - return Base == 0 || getInlineDesc()->IsInitialized; + return PointeeStorage.BS.Base == 0 || getInlineDesc()->IsInitialized; } void Pointer::initialize() const { - assert(Pointee && "Cannot initialize null pointer"); + if (isIntegralPointer()) + return; + + assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer"); const Descriptor *Desc = getFieldDesc(); assert(Desc); if (Desc->isPrimitiveArray()) { // Primitive global arrays don't have an initmap. - if (isStatic() && Base == 0) + if (isStatic() && PointeeStorage.BS.Base == 0) + return; + + // Nothing to do for these. + if (Desc->getNumElems() == 0) return; InitMapPtr &IM = getInitMap(); @@ -196,13 +276,15 @@ void Pointer::initialize() const { } // Field has its bit in an inline descriptor. - assert(Base != 0 && "Only composite fields can be initialised"); + assert(PointeeStorage.BS.Base != 0 && + "Only composite fields can be initialised"); getInlineDesc()->IsInitialized = true; } void Pointer::activate() const { // Field has its bit in an inline descriptor. - assert(Base != 0 && "Only composite fields can be initialised"); + assert(PointeeStorage.BS.Base != 0 && + "Only composite fields can be initialised"); getInlineDesc()->IsActive = true; } @@ -211,11 +293,23 @@ void Pointer::deactivate() const { } bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) { - return A.Pointee == B.Pointee; + // Two null pointers always have the same base. + if (A.isZero() && B.isZero()) + return true; + + if (A.isIntegralPointer() && B.isIntegralPointer()) + return true; + + if (A.isIntegralPointer() || B.isIntegralPointer()) + return A.getSource() == B.getSource(); + + return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee; } bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) { - return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray; + return hasSameBase(A, B) && + A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base && + A.getFieldDesc()->IsArray; } std::optional Pointer::toRValue(const Context &Ctx) const { @@ -338,6 +432,25 @@ std::optional Pointer::toRValue(const Context &Ctx) const { return false; } + // Vector types. + if (const auto *VT = Ty->getAs()) { + assert(Ptr.getFieldDesc()->isPrimitiveArray()); + QualType ElemTy = VT->getElementType(); + PrimType ElemT = *Ctx.classify(ElemTy); + + SmallVector Values; + Values.reserve(VT->getNumElements()); + for (unsigned I = 0; I != VT->getNumElements(); ++I) { + TYPE_SWITCH(ElemT, { + Values.push_back(Ptr.atIndex(I).deref().toAPValue()); + }); + } + + assert(Values.size() == VT->getNumElements()); + R = APValue(Values.data(), Values.size()); + return true; + } + llvm_unreachable("invalid value to return"); }; diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index fffb4aba492fc83c8a3082342e324959bd10c151..fcd00aac62f93e6d0af089ae8c61c089976d84b7 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -28,11 +28,26 @@ class Block; class DeadBlock; class Pointer; class Context; +template class Integral; enum PrimType : unsigned; class Pointer; inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P); +struct BlockPointer { + /// The block the pointer is pointing to. + Block *Pointee; + /// Start of the current subfield. + unsigned Base; +}; + +struct IntPointer { + const Descriptor *Desc; + uint64_t Value; +}; + +enum class Storage { Block, Int }; + /// A pointer to a memory block, live or dead. /// /// This object can be allocated into interpreter stack frames. If pointing to @@ -68,11 +83,20 @@ private: static constexpr unsigned RootPtrMark = ~0u; public: - Pointer() {} + Pointer() { + StorageKind = Storage::Int; + PointeeStorage.Int.Value = 0; + PointeeStorage.Int.Desc = nullptr; + } Pointer(Block *B); Pointer(Block *B, unsigned BaseAndOffset); Pointer(const Pointer &P); Pointer(Pointer &&P); + Pointer(uint64_t Address, const Descriptor *Desc, unsigned Offset = 0) + : Offset(Offset), StorageKind(Storage::Int) { + PointeeStorage.Int.Value = Address; + PointeeStorage.Int.Desc = Desc; + } ~Pointer(); void operator=(const Pointer &P); @@ -80,21 +104,30 @@ public: /// Equality operators are just for tests. bool operator==(const Pointer &P) const { - return Pointee == P.Pointee && Base == P.Base && Offset == P.Offset; - } + if (P.StorageKind != StorageKind) + return false; + if (isIntegralPointer()) + return P.asIntPointer().Value == asIntPointer().Value && + Offset == P.Offset; - bool operator!=(const Pointer &P) const { - return Pointee != P.Pointee || Base != P.Base || Offset != P.Offset; + assert(isBlockPointer()); + return P.asBlockPointer().Pointee == asBlockPointer().Pointee && + P.asBlockPointer().Base == asBlockPointer().Base && + Offset == P.Offset; } + bool operator!=(const Pointer &P) const { return !(P == *this); } + /// Converts the pointer to an APValue. APValue toAPValue() const; /// Converts the pointer to a string usable in diagnostics. std::string toDiagnosticString(const ASTContext &Ctx) const; - unsigned getIntegerRepresentation() const { - return reinterpret_cast(Pointee) + Offset; + uint64_t getIntegerRepresentation() const { + if (isIntegralPointer()) + return asIntPointer().Value + (Offset * elemSize()); + return reinterpret_cast(asBlockPointer().Pointee) + Offset; } /// Converts the pointer to an APValue that is an rvalue. @@ -102,20 +135,27 @@ public: /// Offsets a pointer inside an array. [[nodiscard]] Pointer atIndex(unsigned Idx) const { - if (Base == RootPtrMark) - return Pointer(Pointee, RootPtrMark, getDeclDesc()->getSize()); + if (isIntegralPointer()) + return Pointer(asIntPointer().Value, asIntPointer().Desc, Idx); + + if (asBlockPointer().Base == RootPtrMark) + return Pointer(asBlockPointer().Pointee, RootPtrMark, + getDeclDesc()->getSize()); unsigned Off = Idx * elemSize(); if (getFieldDesc()->ElemDesc) Off += sizeof(InlineDescriptor); else Off += sizeof(InitMapPtr); - return Pointer(Pointee, Base, Base + Off); + return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, + asBlockPointer().Base + Off); } /// Creates a pointer to a field. [[nodiscard]] Pointer atField(unsigned Off) const { unsigned Field = Offset + Off; - return Pointer(Pointee, Field, Field); + if (isIntegralPointer()) + return Pointer(asIntPointer().Value + Field, asIntPointer().Desc); + return Pointer(asBlockPointer().Pointee, Field, Field); } /// Subtract the given offset from the current Base and Offset @@ -123,44 +163,49 @@ public: [[nodiscard]] Pointer atFieldSub(unsigned Off) const { assert(Offset >= Off); unsigned O = Offset - Off; - return Pointer(Pointee, O, O); + return Pointer(asBlockPointer().Pointee, O, O); } /// Restricts the scope of an array element pointer. [[nodiscard]] Pointer narrow() const { + if (!isBlockPointer()) + return *this; + assert(isBlockPointer()); // Null pointers cannot be narrowed. if (isZero() || isUnknownSizeArray()) return *this; // Pointer to an array of base types - enter block. - if (Base == RootPtrMark) - return Pointer(Pointee, sizeof(InlineDescriptor), + if (asBlockPointer().Base == RootPtrMark) + return Pointer(asBlockPointer().Pointee, sizeof(InlineDescriptor), Offset == 0 ? Offset : PastEndMark); // Pointer is one past end - magic offset marks that. if (isOnePastEnd()) - return Pointer(Pointee, Base, PastEndMark); + return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, + PastEndMark); // Primitive arrays are a bit special since they do not have inline // descriptors. If Offset != Base, then the pointer already points to // an element and there is nothing to do. Otherwise, the pointer is // adjusted to the first element of the array. if (inPrimitiveArray()) { - if (Offset != Base) + if (Offset != asBlockPointer().Base) return *this; - return Pointer(Pointee, Base, Offset + sizeof(InitMapPtr)); + return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, + Offset + sizeof(InitMapPtr)); } // Pointer is to a field or array element - enter it. - if (Offset != Base) - return Pointer(Pointee, Offset, Offset); + if (Offset != asBlockPointer().Base) + return Pointer(asBlockPointer().Pointee, Offset, Offset); // Enter the first element of an array. if (!getFieldDesc()->isArray()) return *this; - const unsigned NewBase = Base + sizeof(InlineDescriptor); - return Pointer(Pointee, NewBase, NewBase); + const unsigned NewBase = asBlockPointer().Base + sizeof(InlineDescriptor); + return Pointer(asBlockPointer().Pointee, NewBase, NewBase); } /// Expands a pointer to the containing array, undoing narrowing. @@ -172,72 +217,109 @@ public: Adjust = sizeof(InitMapPtr); else Adjust = sizeof(InlineDescriptor); - return Pointer(Pointee, Base, Base + getSize() + Adjust); + return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, + asBlockPointer().Base + getSize() + Adjust); } // Do not step out of array elements. - if (Base != Offset) + if (asBlockPointer().Base != Offset) return *this; // If at base, point to an array of base types. - if (Base == 0 || Base == sizeof(InlineDescriptor)) - return Pointer(Pointee, RootPtrMark, 0); + if (asBlockPointer().Base == 0 || + asBlockPointer().Base == sizeof(InlineDescriptor)) + return Pointer(asBlockPointer().Pointee, RootPtrMark, 0); // Step into the containing array, if inside one. - unsigned Next = Base - getInlineDesc()->Offset; + unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset; const Descriptor *Desc = Next == 0 ? getDeclDesc() : getDescriptor(Next)->Desc; if (!Desc->IsArray) return *this; - return Pointer(Pointee, Next, Offset); + return Pointer(asBlockPointer().Pointee, Next, Offset); } /// Checks if the pointer is null. - bool isZero() const { return Pointee == nullptr; } + bool isZero() const { + if (Offset != 0) + return false; + + if (isBlockPointer()) + return asBlockPointer().Pointee == nullptr; + assert(isIntegralPointer()); + return asIntPointer().Value == 0; + } /// Checks if the pointer is live. - bool isLive() const { return Pointee && !Pointee->IsDead; } + bool isLive() const { + if (isIntegralPointer()) + return true; + return asBlockPointer().Pointee && !asBlockPointer().Pointee->IsDead; + } /// Checks if the item is a field in an object. bool isField() const { + if (isIntegralPointer()) + return false; + + unsigned Base = asBlockPointer().Base; return Base != 0 && Base != sizeof(InlineDescriptor) && Base != RootPtrMark && getFieldDesc()->asDecl(); } /// Accessor for information about the declaration site. const Descriptor *getDeclDesc() const { - assert(Pointee); - return Pointee->Desc; + if (isIntegralPointer()) + return asIntPointer().Desc; + + assert(isBlockPointer()); + assert(asBlockPointer().Pointee); + return asBlockPointer().Pointee->Desc; } SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); } + /// Returns the expression or declaration the pointer has been created for. + DeclTy getSource() const { + if (isBlockPointer()) + return getDeclDesc()->getSource(); + + assert(isIntegralPointer()); + return asIntPointer().Desc ? asIntPointer().Desc->getSource() : DeclTy(); + } + /// Returns a pointer to the object of which this pointer is a field. [[nodiscard]] Pointer getBase() const { - if (Base == RootPtrMark) { + if (asBlockPointer().Base == RootPtrMark) { assert(Offset == PastEndMark && "cannot get base of a block"); - return Pointer(Pointee, Base, 0); + return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0); } - unsigned NewBase = Base - getInlineDesc()->Offset; - return Pointer(Pointee, NewBase, NewBase); + unsigned NewBase = asBlockPointer().Base - getInlineDesc()->Offset; + return Pointer(asBlockPointer().Pointee, NewBase, NewBase); } /// Returns the parent array. [[nodiscard]] Pointer getArray() const { - if (Base == RootPtrMark) { + if (asBlockPointer().Base == RootPtrMark) { assert(Offset != 0 && Offset != PastEndMark && "not an array element"); - return Pointer(Pointee, Base, 0); + return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0); } - assert(Offset != Base && "not an array element"); - return Pointer(Pointee, Base, Base); + assert(Offset != asBlockPointer().Base && "not an array element"); + return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, + asBlockPointer().Base); } /// Accessors for information about the innermost field. const Descriptor *getFieldDesc() const { - if (Base == 0 || Base == sizeof(InlineDescriptor) || Base == RootPtrMark) + if (isIntegralPointer()) + return asIntPointer().Desc; + if (isBlockPointer() && + (asBlockPointer().Base == 0 || + asBlockPointer().Base == sizeof(InlineDescriptor) || + asBlockPointer().Base == RootPtrMark)) return getDeclDesc(); return getInlineDesc()->Desc; } /// Returns the type of the innermost field. QualType getType() const { - if (inPrimitiveArray() && Offset != Base) { + if (inPrimitiveArray() && Offset != asBlockPointer().Base) { // Unfortunately, complex types are not array types in clang, but they are // for us. if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe()) @@ -248,58 +330,104 @@ public: return getFieldDesc()->getType(); } - [[nodiscard]] Pointer getDeclPtr() const { return Pointer(Pointee); } + [[nodiscard]] Pointer getDeclPtr() const { + return Pointer(asBlockPointer().Pointee); + } /// Returns the element size of the innermost field. size_t elemSize() const { - if (Base == RootPtrMark) + if (isIntegralPointer()) { + if (!asIntPointer().Desc) + return 1; + return asIntPointer().Desc->getElemSize(); + } + + if (asBlockPointer().Base == RootPtrMark) return getDeclDesc()->getSize(); return getFieldDesc()->getElemSize(); } /// Returns the total size of the innermost field. - size_t getSize() const { return getFieldDesc()->getSize(); } + size_t getSize() const { + assert(isBlockPointer()); + return getFieldDesc()->getSize(); + } /// Returns the offset into an array. unsigned getOffset() const { assert(Offset != PastEndMark && "invalid offset"); - if (Base == RootPtrMark) + if (asBlockPointer().Base == RootPtrMark) return Offset; unsigned Adjust = 0; - if (Offset != Base) { + if (Offset != asBlockPointer().Base) { if (getFieldDesc()->ElemDesc) Adjust = sizeof(InlineDescriptor); else Adjust = sizeof(InitMapPtr); } - return Offset - Base - Adjust; + return Offset - asBlockPointer().Base - Adjust; } /// Whether this array refers to an array, but not /// to the first element. - bool isArrayRoot() const { return inArray() && Offset == Base; } + bool isArrayRoot() const { + return inArray() && Offset == asBlockPointer().Base; + } /// Checks if the innermost field is an array. - bool inArray() const { return getFieldDesc()->IsArray; } + bool inArray() const { + if (isBlockPointer()) + return getFieldDesc()->IsArray; + return false; + } /// Checks if the structure is a primitive array. - bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); } + bool inPrimitiveArray() const { + if (isBlockPointer()) + return getFieldDesc()->isPrimitiveArray(); + return false; + } /// Checks if the structure is an array of unknown size. bool isUnknownSizeArray() const { + if (!isBlockPointer()) + return false; // If this points inside a dummy block, return true. // FIXME: This might change in the future. If it does, we need // to set the proper Ctor/Dtor functions for dummy Descriptors. - if (Base != 0 && Base != sizeof(InlineDescriptor) && isDummy()) + if (asBlockPointer().Base != 0 && + asBlockPointer().Base != sizeof(InlineDescriptor) && isDummy()) return true; return getFieldDesc()->isUnknownSizeArray(); } /// Checks if the pointer points to an array. - bool isArrayElement() const { return inArray() && Base != Offset; } + bool isArrayElement() const { + if (isBlockPointer()) + return inArray() && asBlockPointer().Base != Offset; + return false; + } /// Pointer points directly to a block. bool isRoot() const { - return (Base == 0 || Base == RootPtrMark) && Offset == 0; + return (asBlockPointer().Base == 0 || + asBlockPointer().Base == RootPtrMark) && + Offset == 0; } /// If this pointer has an InlineDescriptor we can use to initialize. - bool canBeInitialized() const { return Pointee && Base > 0; } + bool canBeInitialized() const { + if (!isBlockPointer()) + return false; + + return asBlockPointer().Pointee && asBlockPointer().Base > 0; + } + + [[nodiscard]] const BlockPointer &asBlockPointer() const { + assert(isBlockPointer()); + return PointeeStorage.BS; + } + [[nodiscard]] const IntPointer &asIntPointer() const { + assert(isIntegralPointer()); + return PointeeStorage.Int; + } + bool isBlockPointer() const { return StorageKind == Storage::Block; } + bool isIntegralPointer() const { return StorageKind == Storage::Int; } /// Returns the record descriptor of a class. const Record *getRecord() const { return getFieldDesc()->ElemRecord; } @@ -315,71 +443,119 @@ public: bool isUnion() const; /// Checks if the storage is extern. - bool isExtern() const { return Pointee && Pointee->isExtern(); } + bool isExtern() const { + if (isBlockPointer()) + return asBlockPointer().Pointee && asBlockPointer().Pointee->isExtern(); + return false; + } /// Checks if the storage is static. bool isStatic() const { - assert(Pointee); - return Pointee->isStatic(); + if (isIntegralPointer()) + return true; + assert(asBlockPointer().Pointee); + return asBlockPointer().Pointee->isStatic(); } /// Checks if the storage is temporary. bool isTemporary() const { - assert(Pointee); - return Pointee->isTemporary(); + if (isBlockPointer()) { + assert(asBlockPointer().Pointee); + return asBlockPointer().Pointee->isTemporary(); + } + return false; } /// Checks if the storage is a static temporary. bool isStaticTemporary() const { return isStatic() && isTemporary(); } /// Checks if the field is mutable. bool isMutable() const { - return Base != 0 && Base != sizeof(InlineDescriptor) && + if (!isBlockPointer()) + return false; + return asBlockPointer().Base != 0 && + asBlockPointer().Base != sizeof(InlineDescriptor) && getInlineDesc()->IsFieldMutable; } + + bool isWeak() const { + if (isIntegralPointer()) + return false; + + assert(isBlockPointer()); + if (const ValueDecl *VD = getDeclDesc()->asValueDecl()) + return VD->isWeak(); + return false; + } /// Checks if an object was initialized. bool isInitialized() const; /// Checks if the object is active. bool isActive() const { - return Base == 0 || Base == sizeof(InlineDescriptor) || + if (!isBlockPointer()) + return true; + return asBlockPointer().Base == 0 || + asBlockPointer().Base == sizeof(InlineDescriptor) || getInlineDesc()->IsActive; } /// Checks if a structure is a base class. bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; } /// Checks if the pointer points to a dummy value. bool isDummy() const { - if (!Pointee) + if (!isBlockPointer()) return false; + + if (!asBlockPointer().Pointee) + return false; + return getDeclDesc()->isDummy(); } /// Checks if an object or a subfield is mutable. bool isConst() const { - return (Base == 0 || Base == sizeof(InlineDescriptor)) + if (isIntegralPointer()) + return true; + return (asBlockPointer().Base == 0 || + asBlockPointer().Base == sizeof(InlineDescriptor)) ? getDeclDesc()->IsConst : getInlineDesc()->IsConst; } /// Returns the declaration ID. std::optional getDeclID() const { - assert(Pointee); - return Pointee->getDeclID(); + if (isBlockPointer()) { + assert(asBlockPointer().Pointee); + return asBlockPointer().Pointee->getDeclID(); + } + return std::nullopt; } /// Returns the byte offset from the start. unsigned getByteOffset() const { + if (isIntegralPointer()) + return asIntPointer().Value + Offset; return Offset; } /// Returns the number of elements. - unsigned getNumElems() const { return getSize() / elemSize(); } + unsigned getNumElems() const { + if (isIntegralPointer()) + return ~unsigned(0); + return getSize() / elemSize(); + } - const Block *block() const { return Pointee; } + const Block *block() const { return asBlockPointer().Pointee; } /// Returns the index into an array. int64_t getIndex() const { + if (!isBlockPointer()) + return 0; + + if (isZero()) + return 0; + if (isElementPastEnd()) return 1; // narrow()ed element in a composite array. - if (Base > sizeof(InlineDescriptor) && Base == Offset) + if (asBlockPointer().Base > sizeof(InlineDescriptor) && + asBlockPointer().Base == Offset) return 0; if (auto ElemSize = elemSize()) @@ -389,7 +565,10 @@ public: /// Checks if the index is one past end. bool isOnePastEnd() const { - if (!Pointee) + if (isIntegralPointer()) + return false; + + if (!asBlockPointer().Pointee) return false; return isElementPastEnd() || getSize() == getOffset(); } @@ -400,20 +579,25 @@ public: /// Dereferences the pointer, if it's live. template T &deref() const { assert(isLive() && "Invalid pointer"); - assert(Pointee); + assert(isBlockPointer()); + assert(asBlockPointer().Pointee); + assert(Offset + sizeof(T) <= + asBlockPointer().Pointee->getDescriptor()->getAllocSize()); + if (isArrayRoot()) - return *reinterpret_cast(Pointee->rawData() + Base + - sizeof(InitMapPtr)); + return *reinterpret_cast(asBlockPointer().Pointee->rawData() + + asBlockPointer().Base + sizeof(InitMapPtr)); - assert(Offset + sizeof(T) <= Pointee->getDescriptor()->getAllocSize()); - return *reinterpret_cast(Pointee->rawData() + Offset); + return *reinterpret_cast(asBlockPointer().Pointee->rawData() + Offset); } /// Dereferences a primitive element. template T &elem(unsigned I) const { assert(I < getNumElems()); - assert(Pointee); - return reinterpret_cast(Pointee->data() + sizeof(InitMapPtr))[I]; + assert(isBlockPointer()); + assert(asBlockPointer().Pointee); + return reinterpret_cast(asBlockPointer().Pointee->data() + + sizeof(InitMapPtr))[I]; } /// Initializes a field. @@ -442,24 +626,7 @@ public: static bool hasSameArray(const Pointer &A, const Pointer &B); /// Prints the pointer. - void print(llvm::raw_ostream &OS) const { - OS << Pointee << " {"; - if (Base == RootPtrMark) - OS << "rootptr, "; - else - OS << Base << ", "; - - if (Offset == PastEndMark) - OS << "pastend, "; - else - OS << Offset << ", "; - - if (Pointee) - OS << Pointee->getSize(); - else - OS << "nullptr"; - OS << "}"; - } + void print(llvm::raw_ostream &OS) const; private: friend class Block; @@ -469,33 +636,41 @@ private: Pointer(Block *Pointee, unsigned Base, unsigned Offset); /// Returns the embedded descriptor preceding a field. - InlineDescriptor *getInlineDesc() const { return getDescriptor(Base); } + InlineDescriptor *getInlineDesc() const { + return getDescriptor(asBlockPointer().Base); + } /// Returns a descriptor at a given offset. InlineDescriptor *getDescriptor(unsigned Offset) const { assert(Offset != 0 && "Not a nested pointer"); - assert(Pointee); - return reinterpret_cast(Pointee->rawData() + Offset) - + assert(isBlockPointer()); + assert(!isZero()); + return reinterpret_cast( + asBlockPointer().Pointee->rawData() + Offset) - 1; } /// Returns a reference to the InitMapPtr which stores the initialization map. InitMapPtr &getInitMap() const { - assert(Pointee); - return *reinterpret_cast(Pointee->rawData() + Base); + assert(isBlockPointer()); + assert(!isZero()); + return *reinterpret_cast(asBlockPointer().Pointee->rawData() + + asBlockPointer().Base); } - /// The block the pointer is pointing to. - Block *Pointee = nullptr; - /// Start of the current subfield. - unsigned Base = 0; - /// Offset into the block. + /// Offset into the storage. unsigned Offset = 0; /// Previous link in the pointer chain. Pointer *Prev = nullptr; /// Next link in the pointer chain. Pointer *Next = nullptr; + + union { + BlockPointer BS; + IntPointer Int; + } PointeeStorage; + Storage StorageKind = Storage::Int; }; inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) { diff --git a/clang/lib/AST/Interp/PrimType.h b/clang/lib/AST/Interp/PrimType.h index 2bc83b334643e352d2e9e2594b0f571d58b3b424..05a094d0c5b1ff122160b900448d89373d0668f9 100644 --- a/clang/lib/AST/Interp/PrimType.h +++ b/clang/lib/AST/Interp/PrimType.h @@ -46,6 +46,10 @@ enum PrimType : unsigned { PT_FnPtr, }; +inline constexpr bool isPtrType(PrimType T) { + return T == PT_Ptr || T == PT_FnPtr; +} + enum class CastKind : uint8_t { Reinterpret, Atomic, diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp index 25e938e0150322109fd619eada6970f7b6c09d8f..e6f22e79451e970e06d5ab47744be4489d3b7715 100644 --- a/clang/lib/AST/Interp/Program.cpp +++ b/clang/lib/AST/Interp/Program.cpp @@ -177,7 +177,7 @@ std::optional Program::createGlobal(const ValueDecl *VD, bool IsStatic, IsExtern; if (const auto *Var = dyn_cast(VD)) { IsStatic = Context::shouldBeGloballyIndexed(VD); - IsExtern = !Var->getAnyInitializer(); + IsExtern = Var->hasExternalStorage(); } else if (isa(VD)) { IsStatic = true; IsExtern = false; @@ -411,5 +411,12 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, IsMutable); } + // Same with vector types. + if (const auto *VT = Ty->getAs()) { + PrimType ElemTy = *Ctx.classify(VT->getElementType()); + return allocateDescriptor(D, ElemTy, MDSize, VT->getNumElements(), IsConst, + IsTemporary, IsMutable); + } + return nullptr; } diff --git a/clang/lib/AST/Interp/Record.cpp b/clang/lib/AST/Interp/Record.cpp index 909416e6e1a1a53936061d4ff5ce2d6add7b8578..6a0a28bc9124bcc15e7a7dc00a3cb7ac132a2aa1 100644 --- a/clang/lib/AST/Interp/Record.cpp +++ b/clang/lib/AST/Interp/Record.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Record.h" +#include "clang/AST/ASTContext.h" using namespace clang; using namespace clang::interp; @@ -27,6 +28,14 @@ Record::Record(const RecordDecl *Decl, BaseList &&SrcBases, VirtualBaseMap[V.Decl] = &V; } +const std::string Record::getName() const { + std::string Ret; + llvm::raw_string_ostream OS(Ret); + Decl->getNameForDiagnostic(OS, Decl->getASTContext().getPrintingPolicy(), + /*Qualified=*/true); + return Ret; +} + const Record::Field *Record::getField(const FieldDecl *FD) const { auto It = FieldMap.find(FD); assert(It != FieldMap.end() && "Missing field"); diff --git a/clang/lib/AST/Interp/Record.h b/clang/lib/AST/Interp/Record.h index a6bde01062531b8982771dcca6692b7c538e73ce..cf0480b3f62fa668ceff6a442c728b5ff653c3ed 100644 --- a/clang/lib/AST/Interp/Record.h +++ b/clang/lib/AST/Interp/Record.h @@ -51,7 +51,7 @@ public: /// Returns the underlying declaration. const RecordDecl *getDecl() const { return Decl; } /// Returns the name of the underlying declaration. - const std::string getName() const { return Decl->getNameAsString(); } + const std::string getName() const; /// Checks if the record is a union. bool isUnion() const { return getDecl()->isUnion(); } /// Returns the size of the record. @@ -100,6 +100,10 @@ public: unsigned getNumVirtualBases() const { return VirtualBases.size(); } const Base *getVirtualBase(unsigned I) const { return &VirtualBases[I]; } + void dump(llvm::raw_ostream &OS, unsigned Indentation = 0, + unsigned Offset = 0) const; + void dump() const { dump(llvm::errs()); } + private: /// Constructor used by Program to create record descriptors. Record(const RecordDecl *, BaseList &&Bases, FieldList &&Fields, diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index fb3494393f7559af8765b5c29a0634f6bdb6dfb5..42608476b1c195ca9c23bd0b91b7cfb822316857 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -975,6 +975,9 @@ void JSONNodeDumper::VisitFunctionDecl(const FunctionDecl *FD) { if (FD->isDefaulted()) JOS.attribute("explicitlyDefaulted", FD->isDeleted() ? "deleted" : "default"); + + if (StringLiteral *Msg = FD->getDeletedMessage()) + JOS.attribute("deletedMessage", Msg->getString()); } void JSONNodeDumper::VisitEnumDecl(const EnumDecl *ED) { @@ -1576,6 +1579,14 @@ void JSONNodeDumper::VisitMaterializeTemporaryExpr( attributeOnlyIfTrue("boundToLValueRef", MTE->isBoundToLvalueReference()); } +void JSONNodeDumper::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node) { + attributeOnlyIfTrue("hasRewrittenInit", Node->hasRewrittenInit()); +} + +void JSONNodeDumper::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node) { + attributeOnlyIfTrue("hasRewrittenInit", Node->hasRewrittenInit()); +} + void JSONNodeDumper::VisitCXXDependentScopeMemberExpr( const CXXDependentScopeMemberExpr *DSME) { JOS.attribute("isArrow", DSME->isArrow()); diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp index 86dee540e9e299546a3b1a90840f6eebf6a27dba..ecc56c13fb757338751e5b7e60ae64d078924cb9 100644 --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -56,10 +56,8 @@ Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const { &Ctx.Idents.get("initWithUTF8String")); break; case NSStr_stringWithCStringEncoding: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("stringWithCString"), - &Ctx.Idents.get("encoding") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("stringWithCString"), + &Ctx.Idents.get("encoding")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } @@ -93,10 +91,8 @@ Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const { Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObjects")); break; case NSArr_arrayWithObjectsCount: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("arrayWithObjects"), - &Ctx.Idents.get("count") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("arrayWithObjects"), + &Ctx.Idents.get("count")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } @@ -110,10 +106,9 @@ Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const { Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectAtIndex")); break; case NSMutableArr_replaceObjectAtIndex: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("replaceObjectAtIndex"), - &Ctx.Idents.get("withObject") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("replaceObjectAtIndex"), + &Ctx.Idents.get("withObject")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } @@ -121,18 +116,14 @@ Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const { Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject")); break; case NSMutableArr_insertObjectAtIndex: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("insertObject"), - &Ctx.Idents.get("atIndex") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("insertObject"), + &Ctx.Idents.get("atIndex")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSMutableArr_setObjectAtIndexedSubscript: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("setObject"), - &Ctx.Idents.get("atIndexedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("setObject"), &Ctx.Idents.get("atIndexedSubscript")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } @@ -167,27 +158,21 @@ Selector NSAPI::getNSDictionarySelector( &Ctx.Idents.get("dictionaryWithDictionary")); break; case NSDict_dictionaryWithObjectForKey: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("dictionaryWithObject"), - &Ctx.Idents.get("forKey") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("dictionaryWithObject"), &Ctx.Idents.get("forKey")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSDict_dictionaryWithObjectsForKeys: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("dictionaryWithObjects"), - &Ctx.Idents.get("forKeys") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("dictionaryWithObjects"), &Ctx.Idents.get("forKeys")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSDict_dictionaryWithObjectsForKeysCount: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("dictionaryWithObjects"), - &Ctx.Idents.get("forKeys"), - &Ctx.Idents.get("count") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("dictionaryWithObjects"), &Ctx.Idents.get("forKeys"), + &Ctx.Idents.get("count")}; Sel = Ctx.Selectors.getSelector(3, KeyIdents); break; } @@ -204,10 +189,8 @@ Selector NSAPI::getNSDictionarySelector( &Ctx.Idents.get("initWithObjectsAndKeys")); break; case NSDict_initWithObjectsForKeys: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("initWithObjects"), - &Ctx.Idents.get("forKeys") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("initWithObjects"), + &Ctx.Idents.get("forKeys")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } @@ -215,26 +198,20 @@ Selector NSAPI::getNSDictionarySelector( Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey")); break; case NSMutableDict_setObjectForKey: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("setObject"), - &Ctx.Idents.get("forKey") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setObject"), + &Ctx.Idents.get("forKey")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSMutableDict_setObjectForKeyedSubscript: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("setObject"), - &Ctx.Idents.get("forKeyedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("setObject"), &Ctx.Idents.get("forKeyedSubscript")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSMutableDict_setValueForKey: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("setValue"), - &Ctx.Idents.get("forKey") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setValue"), + &Ctx.Idents.get("forKey")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } @@ -264,34 +241,27 @@ Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const { Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject")); break; case NSOrderedSet_insertObjectAtIndex: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("insertObject"), - &Ctx.Idents.get("atIndex") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("insertObject"), + &Ctx.Idents.get("atIndex")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSOrderedSet_setObjectAtIndex: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("setObject"), - &Ctx.Idents.get("atIndex") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setObject"), + &Ctx.Idents.get("atIndex")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSOrderedSet_setObjectAtIndexedSubscript: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("setObject"), - &Ctx.Idents.get("atIndexedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("setObject"), &Ctx.Idents.get("atIndexedSubscript")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSOrderedSet_replaceObjectAtIndexWithObject: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("replaceObjectAtIndex"), - &Ctx.Idents.get("withObject") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("replaceObjectAtIndex"), + &Ctx.Idents.get("withObject")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } @@ -606,7 +576,7 @@ bool NSAPI::isObjCEnumerator(const Expr *E, Selector NSAPI::getOrInitSelector(ArrayRef Ids, Selector &Sel) const { if (Sel.isNull()) { - SmallVector Idents; + SmallVector Idents; for (ArrayRef::const_iterator I = Ids.begin(), E = Ids.end(); I != E; ++I) Idents.push_back(&Ctx.Idents.get(*I)); @@ -617,7 +587,7 @@ Selector NSAPI::getOrInitSelector(ArrayRef Ids, Selector NSAPI::getOrInitNullarySelector(StringRef Id, Selector &Sel) const { if (Sel.isNull()) { - IdentifierInfo *Ident = &Ctx.Idents.get(Id); + const IdentifierInfo *Ident = &Ctx.Idents.get(Id); Sel = Ctx.Selectors.getSelector(0, &Ident); } return Sel; diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp index 36f2c47b30005d9123fc276dadfe3d2fe96d6dd6..785c46e86a77c57de82240343a39205d64079593 100644 --- a/clang/lib/AST/NestedNameSpecifier.cpp +++ b/clang/lib/AST/NestedNameSpecifier.cpp @@ -55,16 +55,16 @@ NestedNameSpecifier::FindOrInsert(const ASTContext &Context, return NNS; } -NestedNameSpecifier * -NestedNameSpecifier::Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, IdentifierInfo *II) { +NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, + NestedNameSpecifier *Prefix, + const IdentifierInfo *II) { assert(II && "Identifier cannot be NULL"); assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent"); NestedNameSpecifier Mockup; Mockup.Prefix.setPointer(Prefix); Mockup.Prefix.setInt(StoredIdentifier); - Mockup.Specifier = II; + Mockup.Specifier = const_cast(II); return FindOrInsert(Context, Mockup); } @@ -87,7 +87,7 @@ NestedNameSpecifier::Create(const ASTContext &Context, NestedNameSpecifier * NestedNameSpecifier::Create(const ASTContext &Context, NestedNameSpecifier *Prefix, - NamespaceAliasDecl *Alias) { + const NamespaceAliasDecl *Alias) { assert(Alias && "Namespace alias cannot be NULL"); assert((!Prefix || (Prefix->getAsType() == nullptr && @@ -96,7 +96,7 @@ NestedNameSpecifier::Create(const ASTContext &Context, NestedNameSpecifier Mockup; Mockup.Prefix.setPointer(Prefix); Mockup.Prefix.setInt(StoredDecl); - Mockup.Specifier = Alias; + Mockup.Specifier = const_cast(Alias); return FindOrInsert(Context, Mockup); } @@ -112,13 +112,13 @@ NestedNameSpecifier::Create(const ASTContext &Context, return FindOrInsert(Context, Mockup); } -NestedNameSpecifier * -NestedNameSpecifier::Create(const ASTContext &Context, IdentifierInfo *II) { +NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, + const IdentifierInfo *II) { assert(II && "Identifier cannot be NULL"); NestedNameSpecifier Mockup; Mockup.Prefix.setPointer(nullptr); Mockup.Prefix.setInt(StoredIdentifier); - Mockup.Specifier = II; + Mockup.Specifier = const_cast(II); return FindOrInsert(Context, Mockup); } diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index e159a1b00be552bab566c07313ff64264f9951ff..6f04739cf6693d612d9464075b7699624568bad9 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -696,6 +696,12 @@ void ODRHash::AddFunctionDecl(const FunctionDecl *Function, AddBoolean(Function->isDeletedAsWritten()); AddBoolean(Function->isExplicitlyDefaulted()); + StringLiteral *DeletedMessage = Function->getDeletedMessage(); + AddBoolean(DeletedMessage); + + if (DeletedMessage) + ID.AddString(DeletedMessage->getBytes()); + AddDecl(Function); AddQualType(Function->getReturnType()); diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp index e1db872f25c3221f15bcdb62b4bb78bac655c3ed..dcb512cb514179f627138eba0a4246c17604d71e 100644 --- a/clang/lib/AST/OpenACCClause.cpp +++ b/clang/lib/AST/OpenACCClause.cpp @@ -13,5 +13,62 @@ #include "clang/AST/OpenACCClause.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" using namespace clang; + +OpenACCDefaultClause *OpenACCDefaultClause::Create(const ASTContext &C, + OpenACCDefaultClauseKind K, + SourceLocation BeginLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + void *Mem = + C.Allocate(sizeof(OpenACCDefaultClause), alignof(OpenACCDefaultClause)); + + return new (Mem) OpenACCDefaultClause(K, BeginLoc, LParenLoc, EndLoc); +} + +OpenACCIfClause *OpenACCIfClause::Create(const ASTContext &C, + SourceLocation BeginLoc, + SourceLocation LParenLoc, + Expr *ConditionExpr, + SourceLocation EndLoc) { + void *Mem = C.Allocate(sizeof(OpenACCIfClause), alignof(OpenACCIfClause)); + return new (Mem) OpenACCIfClause(BeginLoc, LParenLoc, ConditionExpr, EndLoc); +} + +OpenACCIfClause::OpenACCIfClause(SourceLocation BeginLoc, + SourceLocation LParenLoc, Expr *ConditionExpr, + SourceLocation EndLoc) + : OpenACCClauseWithCondition(OpenACCClauseKind::If, BeginLoc, LParenLoc, + ConditionExpr, EndLoc) { + assert(ConditionExpr && "if clause requires condition expr"); + assert((ConditionExpr->isInstantiationDependent() || + ConditionExpr->getType()->isScalarType()) && + "Condition expression type not scalar/dependent"); +} + +OpenACCClause::child_range OpenACCClause::children() { + switch (getClauseKind()) { + default: + assert(false && "Clause children function not implemented"); + break; +#define VISIT_CLAUSE(CLAUSE_NAME) \ + case OpenACCClauseKind::CLAUSE_NAME: \ + return cast(this)->children(); + +#include "clang/Basic/OpenACCClauses.def" + } + return child_range(child_iterator(), child_iterator()); +} + +//===----------------------------------------------------------------------===// +// OpenACC clauses printing methods +//===----------------------------------------------------------------------===// +void OpenACCClausePrinter::VisitDefaultClause(const OpenACCDefaultClause &C) { + OS << "default(" << C.getDefaultClauseKind() << ")"; +} + +void OpenACCClausePrinter::VisitIfClause(const OpenACCIfClause &C) { + OS << "if(" << C.getConditionExpr() << ")"; +} diff --git a/clang/lib/AST/ParentMapContext.cpp b/clang/lib/AST/ParentMapContext.cpp index 21cfd5b1de6e9dd38f7884d6cf2b24b14094633b..9723c0cfa83bbeaf5938616f5ec560bda0430661 100644 --- a/clang/lib/AST/ParentMapContext.cpp +++ b/clang/lib/AST/ParentMapContext.cpp @@ -61,7 +61,26 @@ class ParentMapContext::ParentMap { template friend struct ::MatchParents; /// Contains parents of a node. - using ParentVector = llvm::SmallVector; + class ParentVector { + public: + ParentVector() = default; + explicit ParentVector(size_t N, const DynTypedNode &Value) { + Items.reserve(N); + for (; N > 0; --N) + push_back(Value); + } + bool contains(const DynTypedNode &Value) { + return Seen.contains(Value); + } + void push_back(const DynTypedNode &Value) { + if (!Value.getMemoizationData() || Seen.insert(Value).second) + Items.push_back(Value); + } + llvm::ArrayRef view() const { return Items; } + private: + llvm::SmallVector Items; + llvm::SmallDenseSet Seen; + }; /// Maps from a node to its parents. This is used for nodes that have /// pointer identity only, which are more common and we can save space by @@ -99,7 +118,7 @@ class ParentMapContext::ParentMap { return llvm::ArrayRef(); } if (const auto *V = I->second.template dyn_cast()) { - return llvm::ArrayRef(*V); + return V->view(); } return getSingleDynTypedNodeFromParentMap(I->second); } @@ -252,7 +271,7 @@ public: const auto *S = It->second.dyn_cast(); if (!S) { if (auto *Vec = It->second.dyn_cast()) - return llvm::ArrayRef(*Vec); + return Vec->view(); return getSingleDynTypedNodeFromParentMap(It->second); } const auto *P = dyn_cast(S); diff --git a/clang/lib/AST/SelectorLocationsKind.cpp b/clang/lib/AST/SelectorLocationsKind.cpp index 2c34c9c60c2b20b79e8fd96607bf4b73a4c2b781..ebe6324f904c7819eb9d319bccd668ee0fc14c90 100644 --- a/clang/lib/AST/SelectorLocationsKind.cpp +++ b/clang/lib/AST/SelectorLocationsKind.cpp @@ -26,7 +26,7 @@ static SourceLocation getStandardSelLoc(unsigned Index, assert(Index == 0); if (EndLoc.isInvalid()) return SourceLocation(); - IdentifierInfo *II = Sel.getIdentifierInfoForSlot(0); + const IdentifierInfo *II = Sel.getIdentifierInfoForSlot(0); unsigned Len = II ? II->getLength() : 0; return EndLoc.getLocWithOffset(-Len); } @@ -34,7 +34,7 @@ static SourceLocation getStandardSelLoc(unsigned Index, assert(Index < NumSelArgs); if (ArgLoc.isInvalid()) return SourceLocation(); - IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Index); + const IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Index); unsigned Len = /* selector id */ (II ? II->getLength() : 0) + /* ':' */ 1; if (WithArgSpace) ++Len; diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp index 426b35848cb5c894540beb11db9f93bced621243..d8519b2071e6da9d65c9c7409b45212b3239de74 100644 --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -2431,7 +2431,7 @@ OMPTeamsGenericLoopDirective::CreateEmpty(const ASTContext &C, OMPTargetTeamsGenericLoopDirective *OMPTargetTeamsGenericLoopDirective::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, ArrayRef Clauses, Stmt *AssociatedStmt, - const HelperExprs &Exprs) { + const HelperExprs &Exprs, bool CanBeParallelFor) { auto *Dir = createDirective( C, Clauses, AssociatedStmt, numLoopChildren(CollapsedNum, OMPD_target_teams_loop), StartLoc, EndLoc, @@ -2473,6 +2473,7 @@ OMPTargetTeamsGenericLoopDirective *OMPTargetTeamsGenericLoopDirective::Create( Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB); Dir->setCombinedDistCond(Exprs.DistCombinedFields.DistCond); Dir->setCombinedParForInDistCond(Exprs.DistCombinedFields.ParForInDistCond); + Dir->setCanBeParallelFor(CanBeParallelFor); return Dir; } diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 74b18e50bf1f400187800b7bc00997f9e91f6d05..5855ab3141edcc7d89a27ca956a4e670e1f8c604 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -292,8 +292,11 @@ void StmtPrinter::VisitLabelStmt(LabelStmt *Node) { } void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) { - for (const auto *Attr : Node->getAttrs()) { + llvm::ArrayRef Attrs = Node->getAttrs(); + for (const auto *Attr : Attrs) { Attr->printPretty(OS, Policy); + if (Attr != Attrs.back()) + OS << ' '; } PrintStmt(Node->getSubStmt(), 0); @@ -1444,7 +1447,7 @@ void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) { continue; // Field or identifier node. - IdentifierInfo *Id = ON.getFieldName(); + const IdentifierInfo *Id = ON.getFieldName(); if (!Id) continue; @@ -2345,7 +2348,7 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { E->getQualifier()->print(OS, Policy); OS << "~"; - if (IdentifierInfo *II = E->getDestroyedTypeIdentifier()) + if (const IdentifierInfo *II = E->getDestroyedTypeIdentifier()) OS << II->getName(); else E->getDestroyedType().print(OS, Policy); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index d68547f444c52f9686d466e7d8a905dfb81efdc7..d2aac1e640380f956194b45ce1492c3f38430ec4 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -61,7 +61,7 @@ namespace { virtual void VisitName(DeclarationName Name, bool TreatAsDecl = false) = 0; /// Visit identifiers that are not in Decl's or Type's. - virtual void VisitIdentifierInfo(IdentifierInfo *II) = 0; + virtual void VisitIdentifierInfo(const IdentifierInfo *II) = 0; /// Visit a nested-name-specifier that occurs within an expression /// or statement. @@ -163,7 +163,7 @@ namespace { ID.AddPointer(Name.getAsOpaquePtr()); } - void VisitIdentifierInfo(IdentifierInfo *II) override { + void VisitIdentifierInfo(const IdentifierInfo *II) override { ID.AddPointer(II); } @@ -211,7 +211,7 @@ namespace { } Hash.AddDeclarationName(Name, TreatAsDecl); } - void VisitIdentifierInfo(IdentifierInfo *II) override { + void VisitIdentifierInfo(const IdentifierInfo *II) override { ID.AddBoolean(II); if (II) { Hash.AddIdentifierInfo(II); @@ -2011,6 +2011,7 @@ void StmtProfiler::VisitMSPropertySubscriptExpr( void StmtProfiler::VisitCXXThisExpr(const CXXThisExpr *S) { VisitExpr(S); ID.AddBoolean(S->isImplicit()); + ID.AddBoolean(S->isCapturedByCopyInLambdaWithExplicitObjectParameter()); } void StmtProfiler::VisitCXXThrowExpr(const CXXThrowExpr *S) { @@ -2444,9 +2445,10 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) { namespace { class OpenACCClauseProfiler : public OpenACCClauseVisitor { + StmtProfiler &Profiler; public: - OpenACCClauseProfiler() = default; + OpenACCClauseProfiler(StmtProfiler &P) : Profiler(P) {} void VisitOpenACCClauseList(ArrayRef Clauses) { for (const OpenACCClause *Clause : Clauses) { @@ -2455,7 +2457,22 @@ public: Visit(Clause); } } + +#define VISIT_CLAUSE(CLAUSE_NAME) \ + void Visit##CLAUSE_NAME##Clause(const OpenACC##CLAUSE_NAME##Clause &Clause); + +#include "clang/Basic/OpenACCClauses.def" }; + +/// Nothing to do here, there are no sub-statements. +void OpenACCClauseProfiler::VisitDefaultClause( + const OpenACCDefaultClause &Clause) {} + +void OpenACCClauseProfiler::VisitIfClause(const OpenACCIfClause &Clause) { + assert(Clause.hasConditionExpr() && + "if clause requires a valid condition expr"); + Profiler.VisitStmt(Clause.getConditionExpr()); +} } // namespace void StmtProfiler::VisitOpenACCComputeConstruct( @@ -2463,7 +2480,7 @@ void StmtProfiler::VisitOpenACCComputeConstruct( // VisitStmt handles children, so the AssociatedStmt is handled. VisitStmt(S); - OpenACCClauseProfiler P; + OpenACCClauseProfiler P{*this}; P.VisitOpenACCClauseList(S->clauses()); } diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index 0ffbf47c9a2f4eaf900f52f187ac85207e708898..688daa64d619744ed29e7fc6987edc9a2f89042d 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -394,6 +394,14 @@ void TextNodeDumper::Visit(const OpenACCClause *C) { // Handle clauses with parens for types that have no children, likely // because there is no sub expression. switch (C->getClauseKind()) { + case OpenACCClauseKind::Default: + OS << '(' << cast(C)->getDefaultClauseKind() << ')'; + break; + case OpenACCClauseKind::If: + // The condition expression will be printed as a part of the 'children', + // but print 'clause' here so it is clear what is happening from the dump. + OS << " clause"; + break; default: // Nothing to do here. break; @@ -1202,8 +1210,11 @@ void TextNodeDumper::VisitDeclRefExpr(const DeclRefExpr *Node) { case NOUR_Constant: OS << " non_odr_use_constant"; break; case NOUR_Discarded: OS << " non_odr_use_discarded"; break; } - if (Node->refersToEnclosingVariableOrCapture()) + if (Node->isCapturedByCopyInLambdaWithExplicitObjectParameter()) + OS << " dependent_capture"; + else if (Node->refersToEnclosingVariableOrCapture()) OS << " refers_to_enclosing_variable_or_capture"; + if (Node->isImmediateEscalating()) OS << " immediate-escalating"; } @@ -1359,6 +1370,8 @@ void TextNodeDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node) { void TextNodeDumper::VisitCXXThisExpr(const CXXThisExpr *Node) { if (Node->isImplicit()) OS << " implicit"; + if (Node->isCapturedByCopyInLambdaWithExplicitObjectParameter()) + OS << " dependent_capture"; OS << " this"; } @@ -1442,23 +1455,13 @@ void TextNodeDumper::VisitExpressionTraitExpr(const ExpressionTraitExpr *Node) { } void TextNodeDumper::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node) { - if (Node->hasRewrittenInit()) { + if (Node->hasRewrittenInit()) OS << " has rewritten init"; - AddChild([=] { - ColorScope Color(OS, ShowColors, StmtColor); - Visit(Node->getExpr()); - }); - } } void TextNodeDumper::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node) { - if (Node->hasRewrittenInit()) { + if (Node->hasRewrittenInit()) OS << " has rewritten init"; - AddChild([=] { - ColorScope Color(OS, ShowColors, StmtColor); - Visit(Node->getExpr()); - }); - } } void TextNodeDumper::VisitMaterializeTemporaryExpr( @@ -1958,6 +1961,9 @@ void TextNodeDumper::VisitFunctionDecl(const FunctionDecl *D) { if (D->isTrivial()) OS << " trivial"; + if (const StringLiteral *M = D->getDeletedMessage()) + AddChild("delete message", [=] { Visit(M); }); + if (D->isIneligibleOrNotSelected()) OS << (isa(D) ? " not_selected" : " ineligible"); diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 075c8aba11fcb90bf98bd8cabaf0f952ac3b6dca..9602f448e942796f8c2dccf927635c3d5ef81cef 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -1213,10 +1213,13 @@ void TypePrinter::printDecltypeBefore(const DecltypeType *T, raw_ostream &OS) { void TypePrinter::printPackIndexingBefore(const PackIndexingType *T, raw_ostream &OS) { - if (T->hasSelectedType()) + if (T->hasSelectedType()) { OS << T->getSelectedType(); - else - OS << T->getPattern() << "...[" << T->getIndexExpr() << "]"; + } else { + OS << T->getPattern() << "...["; + T->getIndexExpr()->printPretty(OS, nullptr, Policy); + OS << "]"; + } spaceBeforePlaceHolder(OS); } diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 70ac0764476f6034309bd6408681faf5701ba8c1..bea15ce9bd24d11f5c8a5eaa0cda92e326d82801 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -15,6 +15,7 @@ #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Type.h" #include "clang/Analysis/FlowSensitive/DataflowLattice.h" #include "clang/Analysis/FlowSensitive/Value.h" @@ -26,6 +27,8 @@ #include #include +#define DEBUG_TYPE "dataflow" + namespace clang { namespace dataflow { @@ -354,6 +357,8 @@ getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields, for (auto *Child : S.children()) if (Child != nullptr) getFieldsGlobalsAndFuncs(*Child, Fields, Vars, Funcs); + if (const auto *DefaultArg = dyn_cast(&S)) + getFieldsGlobalsAndFuncs(*DefaultArg->getExpr(), Fields, Vars, Funcs); if (const auto *DefaultInit = dyn_cast(&S)) getFieldsGlobalsAndFuncs(*DefaultInit->getExpr(), Fields, Vars, Funcs); @@ -386,6 +391,186 @@ getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields, } } +namespace { + +// Visitor that builds a map from record prvalues to result objects. +// This traverses the body of the function to be analyzed; for each result +// object that it encounters, it propagates the storage location of the result +// object to all record prvalues that can initialize it. +class ResultObjectVisitor : public RecursiveASTVisitor { +public: + // `ResultObjectMap` will be filled with a map from record prvalues to result + // object. If the function being analyzed returns a record by value, + // `LocForRecordReturnVal` is the location to which this record should be + // written; otherwise, it is null. + explicit ResultObjectVisitor( + llvm::DenseMap &ResultObjectMap, + RecordStorageLocation *LocForRecordReturnVal, + DataflowAnalysisContext &DACtx) + : ResultObjectMap(ResultObjectMap), + LocForRecordReturnVal(LocForRecordReturnVal), DACtx(DACtx) {} + + bool shouldVisitImplicitCode() { return true; } + + bool shouldVisitLambdaBody() const { return false; } + + // Traverse all member and base initializers of `Ctor`. This function is not + // called by `RecursiveASTVisitor`; it should be called manually if we are + // analyzing a constructor. `ThisPointeeLoc` is the storage location that + // `this` points to. + void TraverseConstructorInits(const CXXConstructorDecl *Ctor, + RecordStorageLocation *ThisPointeeLoc) { + assert(ThisPointeeLoc != nullptr); + for (const CXXCtorInitializer *Init : Ctor->inits()) { + Expr *InitExpr = Init->getInit(); + if (FieldDecl *Field = Init->getMember(); + Field != nullptr && Field->getType()->isRecordType()) { + PropagateResultObject(InitExpr, cast( + ThisPointeeLoc->getChild(*Field))); + } else if (Init->getBaseClass()) { + PropagateResultObject(InitExpr, ThisPointeeLoc); + } + + // Ensure that any result objects within `InitExpr` (e.g. temporaries) + // are also propagated to the prvalues that initialize them. + TraverseStmt(InitExpr); + + // If this is a `CXXDefaultInitExpr`, also propagate any result objects + // within the default expression. + if (auto *DefaultInit = dyn_cast(InitExpr)) + TraverseStmt(DefaultInit->getExpr()); + } + } + + bool TraverseBindingDecl(BindingDecl *BD) { + // `RecursiveASTVisitor` doesn't traverse holding variables for + // `BindingDecl`s by itself, so we need to tell it to. + if (VarDecl *HoldingVar = BD->getHoldingVar()) + TraverseDecl(HoldingVar); + return RecursiveASTVisitor::TraverseBindingDecl(BD); + } + + bool VisitVarDecl(VarDecl *VD) { + if (VD->getType()->isRecordType() && VD->hasInit()) + PropagateResultObject( + VD->getInit(), + &cast(DACtx.getStableStorageLocation(*VD))); + return true; + } + + bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE) { + if (MTE->getType()->isRecordType()) + PropagateResultObject( + MTE->getSubExpr(), + &cast(DACtx.getStableStorageLocation(*MTE))); + return true; + } + + bool VisitReturnStmt(ReturnStmt *Return) { + Expr *RetValue = Return->getRetValue(); + if (RetValue != nullptr && RetValue->getType()->isRecordType() && + RetValue->isPRValue()) + PropagateResultObject(RetValue, LocForRecordReturnVal); + return true; + } + + bool VisitExpr(Expr *E) { + // Clang's AST can have record-type prvalues without a result object -- for + // example as full-expressions contained in a compound statement or as + // arguments of call expressions. We notice this if we get here and a + // storage location has not yet been associated with `E`. In this case, + // treat this as if it was a `MaterializeTemporaryExpr`. + if (E->isPRValue() && E->getType()->isRecordType() && + !ResultObjectMap.contains(E)) + PropagateResultObject( + E, &cast(DACtx.getStableStorageLocation(*E))); + return true; + } + + // Assigns `Loc` as the result object location of `E`, then propagates the + // location to all lower-level prvalues that initialize the same object as + // `E` (or one of its base classes or member variables). + void PropagateResultObject(Expr *E, RecordStorageLocation *Loc) { + if (!E->isPRValue() || !E->getType()->isRecordType()) { + assert(false); + // Ensure we don't propagate the result object if we hit this in a + // release build. + return; + } + + ResultObjectMap[E] = Loc; + + // The following AST node kinds are "original initializers": They are the + // lowest-level AST node that initializes a given object, and nothing + // below them can initialize the same object (or part of it). + if (isa(E) || isa(E) || isa(E) || + isa(E) || isa(E) || + isa(E)) { + return; + } + + if (auto *InitList = dyn_cast(E)) { + if (!InitList->isSemanticForm()) + return; + if (InitList->isTransparent()) { + PropagateResultObject(InitList->getInit(0), Loc); + return; + } + + RecordInitListHelper InitListHelper(InitList); + + for (auto [Base, Init] : InitListHelper.base_inits()) { + assert(Base->getType().getCanonicalType() == + Init->getType().getCanonicalType()); + + // Storage location for the base class is the same as that of the + // derived class because we "flatten" the object hierarchy and put all + // fields in `RecordStorageLocation` of the derived class. + PropagateResultObject(Init, Loc); + } + + for (auto [Field, Init] : InitListHelper.field_inits()) { + // Fields of non-record type are handled in + // `TransferVisitor::VisitInitListExpr()`. + if (!Field->getType()->isRecordType()) + continue; + PropagateResultObject( + Init, cast(Loc->getChild(*Field))); + } + return; + } + + if (auto *Op = dyn_cast(E); Op && Op->isCommaOp()) { + PropagateResultObject(Op->getRHS(), Loc); + return; + } + + if (auto *Cond = dyn_cast(E)) { + PropagateResultObject(Cond->getTrueExpr(), Loc); + PropagateResultObject(Cond->getFalseExpr(), Loc); + return; + } + + // All other expression nodes that propagate a record prvalue should have + // exactly one child. + SmallVector Children(E->child_begin(), E->child_end()); + LLVM_DEBUG({ + if (Children.size() != 1) + E->dump(); + }); + assert(Children.size() == 1); + for (Stmt *S : Children) + PropagateResultObject(cast(S), Loc); + } + +private: + llvm::DenseMap &ResultObjectMap; + RecordStorageLocation *LocForRecordReturnVal; + DataflowAnalysisContext &DACtx; +}; + +} // namespace + Environment::Environment(DataflowAnalysisContext &DACtx) : DACtx(&DACtx), FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {} @@ -401,17 +586,23 @@ void Environment::initialize() { if (DeclCtx == nullptr) return; - if (const auto *FuncDecl = dyn_cast(DeclCtx)) { - assert(FuncDecl->doesThisDeclarationHaveABody()); + const auto *FuncDecl = dyn_cast(DeclCtx); + if (FuncDecl == nullptr) + return; - initFieldsGlobalsAndFuncs(FuncDecl); + assert(FuncDecl->doesThisDeclarationHaveABody()); - for (const auto *ParamDecl : FuncDecl->parameters()) { - assert(ParamDecl != nullptr); - setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr)); - } + initFieldsGlobalsAndFuncs(FuncDecl); + + for (const auto *ParamDecl : FuncDecl->parameters()) { + assert(ParamDecl != nullptr); + setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr)); } + if (FuncDecl->getReturnType()->isRecordType()) + LocForRecordReturnVal = &cast( + createStorageLocation(FuncDecl->getReturnType())); + if (const auto *MethodDecl = dyn_cast(DeclCtx)) { auto *Parent = MethodDecl->getParent(); assert(Parent != nullptr); @@ -444,6 +635,12 @@ void Environment::initialize() { initializeFieldsWithValues(ThisLoc); } } + + // We do this below the handling of `CXXMethodDecl` above so that we can + // be sure that the storage location for `this` has been set. + ResultObjectMap = std::make_shared( + buildResultObjectMap(DACtx, FuncDecl, getThisPointeeStorageLocation(), + LocForRecordReturnVal)); } // FIXME: Add support for resetting globals after function calls to enable @@ -484,13 +681,18 @@ void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) { if (getStorageLocation(*D) != nullptr) continue; - setStorageLocation(*D, createObject(*D)); + // We don't run transfer functions on the initializers of global variables, + // so they won't be associated with a value or storage location. We + // therefore intentionally don't pass an initializer to `createObject()`; + // in particular, this ensures that `createObject()` will initialize the + // fields of record-type variables with values. + setStorageLocation(*D, createObject(*D, nullptr)); } for (const FunctionDecl *FD : Funcs) { if (getStorageLocation(*FD) != nullptr) continue; - auto &Loc = createStorageLocation(FD->getType()); + auto &Loc = createStorageLocation(*FD); setStorageLocation(*FD, Loc); } } @@ -519,6 +721,9 @@ Environment Environment::pushCall(const CallExpr *Call) const { } } + if (Call->getType()->isRecordType() && Call->isPRValue()) + Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call); + Env.pushCallInternal(Call->getDirectCallee(), llvm::ArrayRef(Call->getArgs(), Call->getNumArgs())); @@ -529,6 +734,7 @@ Environment Environment::pushCall(const CXXConstructExpr *Call) const { Environment Env(*this); Env.ThisPointeeLoc = &Env.getResultObjectLocation(*Call); + Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call); Env.pushCallInternal(Call->getConstructor(), llvm::ArrayRef(Call->getArgs(), Call->getNumArgs())); @@ -557,6 +763,10 @@ void Environment::pushCallInternal(const FunctionDecl *FuncDecl, const VarDecl *Param = *ParamIt; setStorageLocation(*Param, createObject(*Param, Args[ArgIndex])); } + + ResultObjectMap = std::make_shared( + buildResultObjectMap(DACtx, FuncDecl, getThisPointeeStorageLocation(), + LocForRecordReturnVal)); } void Environment::popCall(const CallExpr *Call, const Environment &CalleeEnv) { @@ -600,6 +810,9 @@ bool Environment::equivalentTo(const Environment &Other, if (ReturnLoc != Other.ReturnLoc) return false; + if (LocForRecordReturnVal != Other.LocForRecordReturnVal) + return false; + if (ThisPointeeLoc != Other.ThisPointeeLoc) return false; @@ -623,8 +836,10 @@ LatticeEffect Environment::widen(const Environment &PrevEnv, assert(DACtx == PrevEnv.DACtx); assert(ReturnVal == PrevEnv.ReturnVal); assert(ReturnLoc == PrevEnv.ReturnLoc); + assert(LocForRecordReturnVal == PrevEnv.LocForRecordReturnVal); assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc); assert(CallStack == PrevEnv.CallStack); + assert(ResultObjectMap == PrevEnv.ResultObjectMap); auto Effect = LatticeEffect::Unchanged; @@ -656,12 +871,16 @@ Environment Environment::join(const Environment &EnvA, const Environment &EnvB, Environment::ValueModel &Model, ExprJoinBehavior ExprBehavior) { assert(EnvA.DACtx == EnvB.DACtx); + assert(EnvA.LocForRecordReturnVal == EnvB.LocForRecordReturnVal); assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc); assert(EnvA.CallStack == EnvB.CallStack); + assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap); Environment JoinedEnv(*EnvA.DACtx); JoinedEnv.CallStack = EnvA.CallStack; + JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap; + JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal; JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc; if (EnvA.ReturnVal == nullptr || EnvB.ReturnVal == nullptr) { @@ -730,6 +949,12 @@ StorageLocation &Environment::createStorageLocation(const Expr &E) { void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { assert(!DeclToLoc.contains(&D)); + // The only kinds of declarations that may have a "variable" storage location + // are declarations of reference type and `BindingDecl`. For all other + // declaration, the storage location should be the stable storage location + // returned by `createStorageLocation()`. + assert(D.getType()->isReferenceType() || isa(D) || + &Loc == &createStorageLocation(D)); DeclToLoc[&D] = &Loc; } @@ -764,77 +989,34 @@ StorageLocation *Environment::getStorageLocation(const Expr &E) const { return It == ExprToLoc.end() ? nullptr : &*It->second; } -// Returns whether a prvalue of record type is the one that originally -// constructs the object (i.e. it doesn't propagate it from one of its -// children). -static bool isOriginalRecordConstructor(const Expr &RecordPRValue) { - if (auto *Init = dyn_cast(&RecordPRValue)) - return !Init->isSemanticForm() || !Init->isTransparent(); - return isa(RecordPRValue) || isa(RecordPRValue) || - isa(RecordPRValue) || - isa(RecordPRValue) || - isa(RecordPRValue) || - // The framework currently does not propagate the objects created in - // the two branches of a `ConditionalOperator` because there is no way - // to reconcile their storage locations, which are different. We - // therefore claim that the `ConditionalOperator` is the expression - // that originally constructs the object. - // Ultimately, this will be fixed by propagating locations down from - // the result object, rather than up from the original constructor as - // we do now (see also the FIXME in the documentation for - // `getResultObjectLocation()`). - isa(RecordPRValue); -} - RecordStorageLocation & Environment::getResultObjectLocation(const Expr &RecordPRValue) const { assert(RecordPRValue.getType()->isRecordType()); assert(RecordPRValue.isPRValue()); - // Returns a storage location that we can use if assertions fail. - auto FallbackForAssertFailure = - [this, &RecordPRValue]() -> RecordStorageLocation & { + assert(ResultObjectMap != nullptr); + RecordStorageLocation *Loc = ResultObjectMap->lookup(&RecordPRValue); + assert(Loc != nullptr); + // In release builds, use the "stable" storage location if the map lookup + // failed. + if (Loc == nullptr) return cast( DACtx->getStableStorageLocation(RecordPRValue)); - }; - - if (isOriginalRecordConstructor(RecordPRValue)) { - auto *Val = cast_or_null(getValue(RecordPRValue)); - // The builtin transfer function should have created a `RecordValue` for all - // original record constructors. - assert(Val); - if (!Val) - return FallbackForAssertFailure(); - return Val->getLoc(); - } - - if (auto *Op = dyn_cast(&RecordPRValue); - Op && Op->isCommaOp()) { - return getResultObjectLocation(*Op->getRHS()); - } - - // All other expression nodes that propagate a record prvalue should have - // exactly one child. - llvm::SmallVector children(RecordPRValue.child_begin(), - RecordPRValue.child_end()); - assert(children.size() == 1); - if (children.empty()) - return FallbackForAssertFailure(); - - return getResultObjectLocation(*cast(children[0])); + return *Loc; } PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) { return DACtx->getOrCreateNullPointerValue(PointeeType); } -void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc) { +void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc, + QualType Type) { llvm::DenseSet Visited; int CreatedValuesCount = 0; - initializeFieldsWithValues(Loc, Visited, 0, CreatedValuesCount); + initializeFieldsWithValues(Loc, Type, Visited, 0, CreatedValuesCount); if (CreatedValuesCount > MaxCompositeValueSize) { - llvm::errs() << "Attempting to initialize a huge value of type: " - << Loc.getType() << '\n'; + llvm::errs() << "Attempting to initialize a huge value of type: " << Type + << '\n'; } } @@ -848,8 +1030,8 @@ void Environment::setValue(const Expr &E, Value &Val) { const Expr &CanonE = ignoreCFGOmittedNodes(E); if (auto *RecordVal = dyn_cast(&Val)) { - assert(isOriginalRecordConstructor(CanonE) || - &RecordVal->getLoc() == &getResultObjectLocation(CanonE)); + assert(&RecordVal->getLoc() == &getResultObjectLocation(CanonE)); + (void)RecordVal; } assert(CanonE.isPRValue()); @@ -927,7 +1109,8 @@ Value *Environment::createValueUnlessSelfReferential( if (Type->isRecordType()) { CreatedValuesCount++; auto &Loc = cast(createStorageLocation(Type)); - initializeFieldsWithValues(Loc, Visited, Depth, CreatedValuesCount); + initializeFieldsWithValues(Loc, Loc.getType(), Visited, Depth, + CreatedValuesCount); return &refreshRecordValue(Loc, *this); } @@ -959,6 +1142,7 @@ Environment::createLocAndMaybeValue(QualType Ty, } void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc, + QualType Type, llvm::DenseSet &Visited, int Depth, int &CreatedValuesCount) { @@ -966,8 +1150,8 @@ void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc, if (FieldType->isRecordType()) { auto &FieldRecordLoc = cast(FieldLoc); setValue(FieldRecordLoc, create(FieldRecordLoc)); - initializeFieldsWithValues(FieldRecordLoc, Visited, Depth + 1, - CreatedValuesCount); + initializeFieldsWithValues(FieldRecordLoc, FieldRecordLoc.getType(), + Visited, Depth + 1, CreatedValuesCount); } else { if (!Visited.insert(FieldType.getCanonicalType()).second) return; @@ -978,7 +1162,7 @@ void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc, } }; - for (const auto &[Field, FieldLoc] : Loc.children()) { + for (const FieldDecl *Field : DACtx->getModeledFields(Type)) { assert(Field != nullptr); QualType FieldType = Field->getType(); @@ -987,14 +1171,12 @@ void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc, &createLocAndMaybeValue(FieldType, Visited, Depth + 1, CreatedValuesCount)); } else { + StorageLocation *FieldLoc = Loc.getChild(*Field); assert(FieldLoc != nullptr); initField(FieldType, *FieldLoc); } } - for (const auto &[FieldName, FieldLoc] : Loc.synthetic_fields()) { - assert(FieldLoc != nullptr); - QualType FieldType = FieldLoc->getType(); - + for (const auto &[FieldName, FieldType] : DACtx->getSyntheticFields(Type)) { // Synthetic fields cannot have reference type, so we don't need to deal // with this case. assert(!FieldType->isReferenceType()); @@ -1021,38 +1203,36 @@ StorageLocation &Environment::createObjectInternal(const ValueDecl *D, return createObjectInternal(D, Ty.getNonReferenceType(), nullptr); } - Value *Val = nullptr; - if (InitExpr) { - // In the (few) cases where an expression is intentionally - // "uninterpreted", `InitExpr` is not associated with a value. There are - // two ways to handle this situation: propagate the status, so that - // uninterpreted initializers result in uninterpreted variables, or - // provide a default value. We choose the latter so that later refinements - // of the variable can be used for reasoning about the surrounding code. - // For this reason, we let this case be handled by the `createValue()` - // call below. - // - // FIXME. If and when we interpret all language cases, change this to - // assert that `InitExpr` is interpreted, rather than supplying a - // default value (assuming we don't update the environment API to return - // references). - Val = getValue(*InitExpr); - - if (!Val && isa(InitExpr) && - InitExpr->getType()->isPointerType()) - Val = &getOrCreateNullPointerValue(InitExpr->getType()->getPointeeType()); - } - if (!Val) - Val = createValue(Ty); - - if (Ty->isRecordType()) - return cast(Val)->getLoc(); - StorageLocation &Loc = D ? createStorageLocation(*D) : createStorageLocation(Ty); - if (Val) - setValue(Loc, *Val); + if (Ty->isRecordType()) { + auto &RecordLoc = cast(Loc); + if (!InitExpr) + initializeFieldsWithValues(RecordLoc); + refreshRecordValue(RecordLoc, *this); + } else { + Value *Val = nullptr; + if (InitExpr) + // In the (few) cases where an expression is intentionally + // "uninterpreted", `InitExpr` is not associated with a value. There are + // two ways to handle this situation: propagate the status, so that + // uninterpreted initializers result in uninterpreted variables, or + // provide a default value. We choose the latter so that later refinements + // of the variable can be used for reasoning about the surrounding code. + // For this reason, we let this case be handled by the `createValue()` + // call below. + // + // FIXME. If and when we interpret all language cases, change this to + // assert that `InitExpr` is interpreted, rather than supplying a + // default value (assuming we don't update the environment API to return + // references). + Val = getValue(*InitExpr); + if (!Val) + Val = createValue(Ty); + if (Val) + setValue(Loc, *Val); + } return Loc; } @@ -1071,6 +1251,8 @@ bool Environment::allows(const Formula &F) const { void Environment::dump(raw_ostream &OS) const { llvm::DenseMap LocToName; + if (LocForRecordReturnVal != nullptr) + LocToName[LocForRecordReturnVal] = "(returned record)"; if (ThisPointeeLoc != nullptr) LocToName[ThisPointeeLoc] = "this"; @@ -1101,6 +1283,9 @@ void Environment::dump(raw_ostream &OS) const { if (auto Iter = LocToName.find(ReturnLoc); Iter != LocToName.end()) OS << " (" << Iter->second << ")"; OS << "\n"; + } else if (Func->getReturnType()->isRecordType() || + isa(Func)) { + OS << "LocForRecordReturnVal: " << LocForRecordReturnVal << "\n"; } else if (!Func->getReturnType()->isVoidType()) { if (ReturnVal == nullptr) OS << "ReturnVal: nullptr\n"; @@ -1121,6 +1306,22 @@ void Environment::dump() const { dump(llvm::dbgs()); } +Environment::PrValueToResultObject Environment::buildResultObjectMap( + DataflowAnalysisContext *DACtx, const FunctionDecl *FuncDecl, + RecordStorageLocation *ThisPointeeLoc, + RecordStorageLocation *LocForRecordReturnVal) { + assert(FuncDecl->doesThisDeclarationHaveABody()); + + PrValueToResultObject Map; + + ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx); + if (const auto *Ctor = dyn_cast(FuncDecl)) + Visitor.TraverseConstructorInits(Ctor, ThisPointeeLoc); + Visitor.TraverseStmt(FuncDecl->getBody()); + + return Map; +} + RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE, const Environment &Env) { Expr *ImplicitObject = MCE.getImplicitObjectArgument(); @@ -1215,24 +1416,11 @@ RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env) { RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env) { assert(Expr.getType()->isRecordType()); - if (Expr.isPRValue()) { - if (auto *ExistingVal = Env.get(Expr)) { - auto &NewVal = Env.create(ExistingVal->getLoc()); - Env.setValue(Expr, NewVal); - Env.setValue(NewVal.getLoc(), NewVal); - return NewVal; - } + if (Expr.isPRValue()) + refreshRecordValue(Env.getResultObjectLocation(Expr), Env); - auto &NewVal = *cast(Env.createValue(Expr.getType())); - Env.setValue(Expr, NewVal); - return NewVal; - } - - if (auto *Loc = Env.get(Expr)) { - auto &NewVal = Env.create(*Loc); - Env.setValue(*Loc, NewVal); - return NewVal; - } + if (auto *Loc = Env.get(Expr)) + refreshRecordValue(*Loc, Env); auto &NewVal = *cast(Env.createValue(Expr.getType())); Env.setStorageLocation(Expr, NewVal.getLoc()); diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 0a2e8368d541dd0f684d7e8672b7b8fc82aeb40b..88a9c0eccbebc0e325cfaf17aacd0e852f3b4cd2 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -460,11 +460,9 @@ public: // So make sure we have a value if we didn't propagate one above. if (S->isPRValue() && S->getType()->isRecordType()) { if (Env.getValue(*S) == nullptr) { - Value *Val = Env.createValue(S->getType()); - // We're guaranteed to always be able to create a value for record - // types. - assert(Val != nullptr); - Env.setValue(*S, *Val); + auto &Loc = Env.getResultObjectLocation(*S); + Env.initializeFieldsWithValues(Loc); + refreshRecordValue(Loc, Env); } } } @@ -472,6 +470,13 @@ public: void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { const Expr *InitExpr = S->getExpr(); assert(InitExpr != nullptr); + + // If this is a prvalue of record type, the handler for `*InitExpr` (if one + // exists) will initialize the result object; there is no value to propgate + // here. + if (S->getType()->isRecordType() && S->isPRValue()) + return; + propagateValueOrStorageLocation(*InitExpr, *S, Env); } @@ -479,6 +484,17 @@ public: const CXXConstructorDecl *ConstructorDecl = S->getConstructor(); assert(ConstructorDecl != nullptr); + // `CXXConstructExpr` can have array type if default-initializing an array + // of records. We don't handle this specifically beyond potentially inlining + // the call. + if (!S->getType()->isRecordType()) { + transferInlineCall(S, ConstructorDecl); + return; + } + + RecordStorageLocation &Loc = Env.getResultObjectLocation(*S); + Env.setValue(*S, refreshRecordValue(Loc, Env)); + if (ConstructorDecl->isCopyOrMoveConstructor()) { // It is permissible for a copy/move constructor to have additional // parameters as long as they have default arguments defined for them. @@ -491,24 +507,14 @@ public: if (ArgLoc == nullptr) return; - if (S->isElidable()) { - if (Value *Val = Env.getValue(*ArgLoc)) - Env.setValue(*S, *Val); - } else { - auto &Val = *cast(Env.createValue(S->getType())); - Env.setValue(*S, Val); - copyRecord(*ArgLoc, Val.getLoc(), Env); - } + // Even if the copy/move constructor call is elidable, we choose to copy + // the record in all cases (which isn't wrong, just potentially not + // optimal). + copyRecord(*ArgLoc, Loc, Env); return; } - // `CXXConstructExpr` can have array type if default-initializing an array - // of records, and we currently can't create values for arrays. So check if - // we've got a record type. - if (S->getType()->isRecordType()) { - auto &InitialVal = *cast(Env.createValue(S->getType())); - Env.setValue(*S, InitialVal); - } + Env.initializeFieldsWithValues(Loc, S->getType()); transferInlineCall(S, ConstructorDecl); } @@ -551,19 +557,15 @@ public: if (S->isGLValue()) { Env.setStorageLocation(*S, *LocDst); } else if (S->getType()->isRecordType()) { - // Make sure that we have a `RecordValue` for this expression so that - // `Environment::getResultObjectLocation()` is able to return a location - // for it. - if (Env.getValue(*S) == nullptr) - refreshRecordValue(*S, Env); + // Assume that the assignment returns the assigned value. + copyRecord(*LocDst, Env.getResultObjectLocation(*S), Env); } return; } - // CXXOperatorCallExpr can be prvalues. Call `VisitCallExpr`() to create - // a `RecordValue` for them so that `Environment::getResultObjectLocation()` - // can return a value. + // `CXXOperatorCallExpr` can be a prvalue. Call `VisitCallExpr`() to + // initialize the prvalue's fields with values. VisitCallExpr(S); } @@ -580,11 +582,6 @@ public: } } - void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) { - if (Value *Val = Env.createValue(S->getType())) - Env.setValue(*S, *Val); - } - void VisitCallExpr(const CallExpr *S) { // Of clang's builtins, only `__builtin_expect` is handled explicitly, since // others (like trap, debugtrap, and unreachable) are handled by CFG @@ -612,13 +609,14 @@ public: } else if (const FunctionDecl *F = S->getDirectCallee()) { transferInlineCall(S, F); - // If this call produces a prvalue of record type, make sure that we have - // a `RecordValue` for it. This is required so that - // `Environment::getResultObjectLocation()` is able to return a location - // for this `CallExpr`. + // If this call produces a prvalue of record type, initialize its fields + // with values. if (S->getType()->isRecordType() && S->isPRValue()) - if (Env.getValue(*S) == nullptr) - refreshRecordValue(*S, Env); + if (Env.getValue(*S) == nullptr) { + RecordStorageLocation &Loc = Env.getResultObjectLocation(*S); + Env.initializeFieldsWithValues(Loc); + Env.setValue(*S, refreshRecordValue(Loc, Env)); + } } } @@ -666,8 +664,10 @@ public: // `getLogicOperatorSubExprValue()`. if (S->isGLValue()) Env.setStorageLocation(*S, Env.createObject(S->getType())); - else if (Value *Val = Env.createValue(S->getType())) - Env.setValue(*S, *Val); + else if (!S->getType()->isRecordType()) { + if (Value *Val = Env.createValue(S->getType())) + Env.setValue(*S, *Val); + } } void VisitInitListExpr(const InitListExpr *S) { @@ -688,71 +688,51 @@ public: return; } - llvm::DenseMap FieldLocs; - RecordInitListHelper InitListHelper(S); + RecordStorageLocation &Loc = Env.getResultObjectLocation(*S); + Env.setValue(*S, refreshRecordValue(Loc, Env)); - for (auto [Base, Init] : InitListHelper.base_inits()) { - assert(Base->getType().getCanonicalType() == - Init->getType().getCanonicalType()); - auto *BaseVal = Env.get(*Init); - if (!BaseVal) - BaseVal = cast(Env.createValue(Init->getType())); - // Take ownership of the fields of the `RecordValue` for the base class - // and incorporate them into the "flattened" set of fields for the - // derived class. - auto Children = BaseVal->getLoc().children(); - FieldLocs.insert(Children.begin(), Children.end()); - } + // Initialization of base classes and fields of record type happens when we + // visit the nested `CXXConstructExpr` or `InitListExpr` for that base class + // or field. We therefore only need to deal with fields of non-record type + // here. - for (auto [Field, Init] : InitListHelper.field_inits()) { - assert( - // The types are same, or - Field->getType().getCanonicalType().getUnqualifiedType() == - Init->getType().getCanonicalType().getUnqualifiedType() || - // The field's type is T&, and initializer is T - (Field->getType()->isReferenceType() && - Field->getType().getCanonicalType()->getPointeeType() == - Init->getType().getCanonicalType())); - auto& Loc = Env.createObject(Field->getType(), Init); - FieldLocs.insert({Field, &Loc}); - } + RecordInitListHelper InitListHelper(S); - // In the case of a union, we don't in general have initializers for all - // of the fields. Create storage locations for the remaining fields (but - // don't associate them with values). - if (Type->isUnionType()) { - for (const FieldDecl *Field : - Env.getDataflowAnalysisContext().getModeledFields(Type)) { - if (auto [it, inserted] = FieldLocs.insert({Field, nullptr}); inserted) - it->second = &Env.createStorageLocation(Field->getType()); + for (auto [Field, Init] : InitListHelper.field_inits()) { + if (Field->getType()->isRecordType()) + continue; + if (Field->getType()->isReferenceType()) { + assert(Field->getType().getCanonicalType()->getPointeeType() == + Init->getType().getCanonicalType()); + Loc.setChild(*Field, &Env.createObject(Field->getType(), Init)); + continue; } + assert(Field->getType().getCanonicalType().getUnqualifiedType() == + Init->getType().getCanonicalType().getUnqualifiedType()); + StorageLocation *FieldLoc = Loc.getChild(*Field); + // Locations for non-reference fields must always be non-null. + assert(FieldLoc != nullptr); + Value *Val = Env.getValue(*Init); + if (Val == nullptr && isa(Init) && + Init->getType()->isPointerType()) + Val = + &Env.getOrCreateNullPointerValue(Init->getType()->getPointeeType()); + if (Val == nullptr) + Val = Env.createValue(Field->getType()); + if (Val != nullptr) + Env.setValue(*FieldLoc, *Val); } - // Check that we satisfy the invariant that a `RecordStorageLoation` - // contains exactly the set of modeled fields for that type. - // `ModeledFields` includes fields from all the bases, but only the - // modeled ones. However, if a class type is initialized with an - // `InitListExpr`, all fields in the class, including those from base - // classes, are included in the set of modeled fields. The code above - // should therefore populate exactly the modeled fields. - assert(containsSameFields( - Env.getDataflowAnalysisContext().getModeledFields(Type), FieldLocs)); - - RecordStorageLocation::SyntheticFieldMap SyntheticFieldLocs; - for (const auto &Entry : - Env.getDataflowAnalysisContext().getSyntheticFields(Type)) { - SyntheticFieldLocs.insert( - {Entry.getKey(), &Env.createObject(Entry.getValue())}); + for (const auto &[FieldName, FieldLoc] : Loc.synthetic_fields()) { + QualType FieldType = FieldLoc->getType(); + if (FieldType->isRecordType()) { + Env.initializeFieldsWithValues(*cast(FieldLoc)); + } else { + if (Value *Val = Env.createValue(FieldType)) + Env.setValue(*FieldLoc, *Val); + } } - auto &Loc = Env.getDataflowAnalysisContext().createRecordStorageLocation( - Type, std::move(FieldLocs), std::move(SyntheticFieldLocs)); - RecordValue &RecordVal = Env.create(Loc); - - Env.setValue(Loc, RecordVal); - - Env.setValue(*S, RecordVal); - // FIXME: Implement array initialization. } diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 595f70f819ddb518d01cf1a3ba2edbc3402cd21c..1b73c5d6830161070d66fa4c76614e4ab90d82a1 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -369,17 +369,10 @@ builtinTransferInitializer(const CFGInitializer &Elt, ParentLoc->setChild(*Member, InitExprLoc); } else if (auto *InitExprVal = Env.getValue(*InitExpr)) { assert(MemberLoc != nullptr); - if (Member->getType()->isRecordType()) { - auto *InitValStruct = cast(InitExprVal); - // FIXME: Rather than performing a copy here, we should really be - // initializing the field in place. This would require us to propagate the - // storage location of the field to the AST node that creates the - // `RecordValue`. - copyRecord(InitValStruct->getLoc(), - *cast(MemberLoc), Env); - } else { + // Record-type initializers construct themselves directly into the result + // object, so there is no need to handle them here. + if (!Member->getType()->isRecordType()) Env.setValue(*MemberLoc, *InitExprVal); - } } } diff --git a/clang/lib/Analysis/ObjCNoReturn.cpp b/clang/lib/Analysis/ObjCNoReturn.cpp index 9d7c365c3b9924d77dbaeb26adba6ddb67e7026d..9e651c29e085da395f424d4f6c12272c69a179c0 100644 --- a/clang/lib/Analysis/ObjCNoReturn.cpp +++ b/clang/lib/Analysis/ObjCNoReturn.cpp @@ -17,7 +17,8 @@ using namespace clang; -static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) { +static bool isSubclass(const ObjCInterfaceDecl *Class, + const IdentifierInfo *II) { if (!Class) return false; if (Class->getIdentifier() == II) @@ -30,7 +31,7 @@ ObjCNoReturn::ObjCNoReturn(ASTContext &C) NSExceptionII(&C.Idents.get("NSException")) { // Generate selectors. - SmallVector II; + SmallVector II; // raise:format: II.push_back(&C.Idents.get("raise")); diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index a9b07aca65c0529483c43ee5c4b72749a61744ea..feea84544d62fbdb4e20a83671958491ab3824fe 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -541,7 +541,8 @@ unsigned Selector::getNumArgs() const { return SI->getNumArgs(); } -IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const { +const IdentifierInfo * +Selector::getIdentifierInfoForSlot(unsigned argIndex) const { if (getIdentifierInfoFlag() < MultiArg) { assert(argIndex == 0 && "illegal keyword index"); return getAsIdentifierInfo(); @@ -553,7 +554,7 @@ IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const { } StringRef Selector::getNameForSlot(unsigned int argIndex) const { - IdentifierInfo *II = getIdentifierInfoForSlot(argIndex); + const IdentifierInfo *II = getIdentifierInfoForSlot(argIndex); return II ? II->getName() : StringRef(); } @@ -574,7 +575,7 @@ std::string Selector::getAsString() const { return ""; if (getIdentifierInfoFlag() < MultiArg) { - IdentifierInfo *II = getAsIdentifierInfo(); + const IdentifierInfo *II = getAsIdentifierInfo(); if (getNumArgs() == 0) { assert(II && "If the number of arguments is 0 then II is guaranteed to " @@ -608,7 +609,7 @@ static bool startsWithWord(StringRef name, StringRef word) { } ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) { - IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); + const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); if (!first) return OMF_None; StringRef name = first->getName(); @@ -655,7 +656,7 @@ ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) { } ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) { - IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); + const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); if (!first) return OIT_None; StringRef name = first->getName(); @@ -683,7 +684,7 @@ ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) { } ObjCStringFormatFamily Selector::getStringFormatFamilyImpl(Selector sel) { - IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); + const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); if (!first) return SFF_None; StringRef name = first->getName(); @@ -750,7 +751,8 @@ size_t SelectorTable::getTotalMemory() const { return SelTabImpl.Allocator.getTotalMemory(); } -Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) { +Selector SelectorTable::getSelector(unsigned nKeys, + const IdentifierInfo **IIV) { if (nKeys < 2) return Selector(IIV[0], nKeys); diff --git a/clang/lib/Basic/Module.cpp b/clang/lib/Basic/Module.cpp index 256365d66bb9074128d65c481a83165ff48a8b3a..bb212cde878826f157d6929d119145c0cde10a91 100644 --- a/clang/lib/Basic/Module.cpp +++ b/clang/lib/Basic/Module.cpp @@ -305,6 +305,10 @@ bool Module::directlyUses(const Module *Requested) { if (Requested->fullModuleNameIs({"_Builtin_stddef", "max_align_t"}) || Requested->fullModuleNameIs({"_Builtin_stddef_wint_t"})) return true; + // Darwin is allowed is to use our builtin 'ptrauth.h' and its accompanying + // module. + if (!Requested->Parent && Requested->Name == "ptrauth") + return true; if (NoUndeclaredIncludes) UndeclaredUses.insert(Requested); diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 1569b5e04b770a0d2b8ef045263abb12d2c8f769..c8d243a8fb7aea25e5c02c308fc62ec5ad17b1c9 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -1543,10 +1543,13 @@ WindowsARM64TargetInfo::getBuiltinVaListKind() const { TargetInfo::CallingConvCheckResult WindowsARM64TargetInfo::checkCallingConvention(CallingConv CC) const { switch (CC) { + case CC_X86VectorCall: + if (getTriple().isWindowsArm64EC()) + return CCCR_OK; + return CCCR_Ignore; case CC_X86StdCall: case CC_X86ThisCall: case CC_X86FastCall: - case CC_X86VectorCall: return CCCR_Ignore; case CC_C: case CC_OpenCLKernel: diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 1966af17904d65c98f923558bf15007ba75533b9..bf1767c87fe1cec99a985636108bfcd49152dcff 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -954,6 +954,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__CCMP__"); if (HasCF) Builder.defineMacro("__CF__"); + // Condition here is aligned with the feature set of mapxf in Options.td + if (HasEGPR && HasPush2Pop2 && HasPPX && HasNDD) + Builder.defineMacro("__APX_F__"); // Each case falls through to the previous one here. switch (SSELevel) { diff --git a/clang/lib/CIR/CMakeLists.txt b/clang/lib/CIR/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/clang/lib/CMakeLists.txt b/clang/lib/CMakeLists.txt index 0cac86451f39e45c724a8655f4a9a6a6d499270b..14ba55360fe05096408292abb334a6943bdd7ac1 100644 --- a/clang/lib/CMakeLists.txt +++ b/clang/lib/CMakeLists.txt @@ -31,3 +31,7 @@ if(CLANG_INCLUDE_TESTS) endif() add_subdirectory(Interpreter) add_subdirectory(Support) + +if(CLANG_ENABLE_CIR) + add_subdirectory(CIR) +endif() diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp index d35ce0409d723258cd82ec955071efa6d850921e..07452b18a85ea4905a1e8b412b2dbeef795b544d 100644 --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -1806,7 +1806,11 @@ void AtomicInfo::EmitAtomicUpdateOp( /*NumReservedValues=*/2); PHI->addIncoming(OldVal, CurBB); Address NewAtomicAddr = CreateTempAlloca(); - Address NewAtomicIntAddr = castToAtomicIntPointer(NewAtomicAddr); + Address NewAtomicIntAddr = + shouldCastToInt(NewAtomicAddr.getElementType(), /*CmpXchg=*/true) + ? castToAtomicIntPointer(NewAtomicAddr) + : NewAtomicAddr; + if ((LVal.isBitField() && BFI.Size != ValueSizeInBits) || requiresMemSetZero(getAtomicAddress().getElementType())) { CGF.Builder.CreateStore(PHI, NewAtomicIntAddr); diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index 47f063b5501cc6cdb480cb7cdc84dfe50ae78c06..2742c39965b2c86368231586497ad4b249e14560 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -1447,7 +1447,7 @@ llvm::Function *CodeGenFunction::GenerateBlockFunction( selfTy = getContext().getPointerType(getContext().getAddrSpaceQualType( getContext().VoidTy, LangAS::opencl_generic)); - IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor"); + const IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor"); ImplicitParamDecl SelfDecl(getContext(), const_cast(blockDecl), SourceLocation(), II, selfTy, @@ -2791,7 +2791,7 @@ static void configureBlocksRuntimeObject(CodeGenModule &CGM, auto *GV = cast(C->stripPointerCasts()); if (CGM.getTarget().getTriple().isOSBinFormatCOFF()) { - IdentifierInfo &II = CGM.getContext().Idents.get(C->getName()); + const IdentifierInfo &II = CGM.getContext().Idents.get(C->getName()); TranslationUnitDecl *TUDecl = CGM.getContext().getTranslationUnitDecl(); DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl); diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index df7502b8def5314839e903bc161c99e120790660..c7b219dcfcec51f9306ec6cd91e11d15e4366339 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -17288,6 +17288,16 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, Value *Op1 = EmitScalarExpr(E->getArg(1)); Value *Op2 = EmitScalarExpr(E->getArg(2)); Value *Op3 = EmitScalarExpr(E->getArg(3)); + // rldimi is 64-bit instruction, expand the intrinsic before isel to + // leverage peephole and avoid legalization efforts. + if (BuiltinID == PPC::BI__builtin_ppc_rldimi && + !getTarget().getTriple().isPPC64()) { + Function *F = CGM.getIntrinsic(Intrinsic::fshl, Op0->getType()); + Op2 = Builder.CreateZExt(Op2, Int64Ty); + Value *Shift = Builder.CreateCall(F, {Op0, Op0, Op2}); + return Builder.CreateOr(Builder.CreateAnd(Shift, Op3), + Builder.CreateAnd(Op1, Builder.CreateNot(Op3))); + } return Builder.CreateCall( CGM.getIntrinsic(BuiltinID == PPC::BI__builtin_ppc_rldimi ? Intrinsic::ppc_rldimi @@ -18293,9 +18303,16 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, Value *Op0 = EmitScalarExpr(E->getArg(0)); if (!E->getArg(0)->getType()->hasFloatingRepresentation()) llvm_unreachable("rcp operand must have a float representation"); - return Builder.CreateIntrinsic( - /*ReturnType=*/Op0->getType(), Intrinsic::dx_rcp, - ArrayRef{Op0}, nullptr, "dx.rcp"); + llvm::Type *Ty = Op0->getType(); + llvm::Type *EltTy = Ty->getScalarType(); + Constant *One = + Ty->isVectorTy() + ? ConstantVector::getSplat( + ElementCount::getFixed( + dyn_cast(Ty)->getNumElements()), + ConstantFP::get(EltTy, 1.0)) + : ConstantFP::get(EltTy, 1.0); + return Builder.CreateFDiv(One, Op0, "hlsl.rcp"); } case Builtin::BI__builtin_hlsl_elementwise_rsqrt: { Value *Op0 = EmitScalarExpr(E->getArg(0)); diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp index 0cb5b06a519c0098773e6ecafdd1c315048a8007..370642cb3d5364f8622125c6298d00fc61f7194c 100644 --- a/clang/lib/CodeGen/CGCUDANV.cpp +++ b/clang/lib/CodeGen/CGCUDANV.cpp @@ -361,7 +361,7 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF, KernelLaunchAPI = KernelLaunchAPI + "_ptsz"; } auto LaunchKernelName = addPrefixToName(KernelLaunchAPI); - IdentifierInfo &cudaLaunchKernelII = + const IdentifierInfo &cudaLaunchKernelII = CGM.getContext().Idents.get(LaunchKernelName); FunctionDecl *cudaLaunchKernelFD = nullptr; for (auto *Result : DC->lookup(&cudaLaunchKernelII)) { diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index f12765b826935b2d0c174f3a7ebb27d0dd6690c7..7a0bc6fa77b889354209663c4eb6fba7057f4a04 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -4124,7 +4124,8 @@ static bool isProvablyNull(llvm::Value *addr) { } static bool isProvablyNonNull(Address Addr, CodeGenFunction &CGF) { - return llvm::isKnownNonZero(Addr.getBasePointer(), CGF.CGM.getDataLayout()); + return llvm::isKnownNonZero(Addr.getBasePointer(), /*Depth=*/0, + CGF.CGM.getDataLayout()); } /// Emit the actual writing-back of a writeback. @@ -5591,6 +5592,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, /*AttrOnCallSite=*/true, /*IsThunk=*/false); + if (CallingConv == llvm::CallingConv::X86_VectorCall && + getTarget().getTriple().isWindowsArm64EC()) { + CGM.Error(Loc, "__vectorcall calling convention is not currently " + "supported"); + } + if (const FunctionDecl *FD = dyn_cast_or_null(CurFuncDecl)) { if (FD->hasAttr()) // All calls within a strictfp function are marked strictfp diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 8c1c8ee455d2e634dc83a8845f2a970125184b9d..b3077292f4a206a0b1459fb5ea031416b88482db 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -1404,7 +1404,7 @@ FieldHasTrivialDestructorBody(ASTContext &Context, // The destructor for an implicit anonymous union member is never invoked. if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion()) - return false; + return true; return HasTrivialDestructorBody(Context, FieldClassDecl, FieldClassDecl); } diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp index e6f8e6873004f29d716caea0e82fb902be0f8117..5bf48bc22a5495e483c0001dca7d2c0200bedf12 100644 --- a/clang/lib/CodeGen/CGCleanup.cpp +++ b/clang/lib/CodeGen/CGCleanup.cpp @@ -667,7 +667,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 +693,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 @@ -765,6 +770,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { EmitSehCppScopeEnd(); } destroyOptimisticNormalEntry(*this, Scope); + Scope.MarkEmitted(); EHStack.popCleanup(); } else { // If we have a fallthrough and no other need for the cleanup, @@ -781,6 +787,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { } destroyOptimisticNormalEntry(*this, Scope); + Scope.MarkEmitted(); EHStack.popCleanup(); EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag); @@ -916,6 +923,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { } // IV. Pop the cleanup and emit it. + Scope.MarkEmitted(); EHStack.popCleanup(); assert(EHStack.hasNormalCleanups() == HasEnclosingCleanups); 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/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 267f2e40a7bbaa198ed551bcc67702a38d783f11..8bdafa7c569b0802c860a4734b54dab7d74ff2bd 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" @@ -1383,7 +1384,7 @@ void CodeGenFunction::EmitAndRegisterVariableArrayDimensions( // For each dimension stores its QualType and corresponding // size-expression Value. SmallVector Dimensions; - SmallVector VLAExprNames; + SmallVector VLAExprNames; // Break down the array into individual dimensions. QualType Type1D = D.getType(); @@ -1420,7 +1421,7 @@ void CodeGenFunction::EmitAndRegisterVariableArrayDimensions( MD = llvm::ConstantAsMetadata::get(C); else { // Create an artificial VarDecl to generate debug info for. - IdentifierInfo *NameIdent = VLAExprNames[NameIdx++]; + const IdentifierInfo *NameIdent = VLAExprNames[NameIdx++]; auto QT = getContext().getIntTypeForBitwidth( SizeTy->getScalarSizeInBits(), false); auto *ArtificialDecl = VarDecl::Create( @@ -2201,6 +2202,24 @@ 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) { + pushCleanupAndDeferDeactivation( + cleanupKind, addr, type, destroyer, useEHCleanupForArray); +} + void CodeGenFunction::pushStackRestore(CleanupKind Kind, Address SPMem) { EHStack.pushCleanup(Kind, SPMem); } @@ -2217,16 +2236,19 @@ 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. @@ -2241,13 +2263,12 @@ void CodeGenFunction::pushLifetimeExtendedDestroy(CleanupKind cleanupKind, Address ActiveFlag = createCleanupActiveFlag(); SavedType SavedAddr = saveValueInCond(addr); - if (cleanupKind & EHCleanup) { - EHStack.pushCleanup( - static_cast(cleanupKind & ~NormalCleanup), SavedAddr, type, - destroyer, useEHCleanupForArray); - initFullExprCleanupWithFlag(ActiveFlag); - } + pushCleanupAndDeferDeactivation( + cleanupKind, SavedAddr, type, destroyer, useEHCleanupForArray); + initFullExprCleanupWithFlag(ActiveFlag); + // Since this is lifetime-extended, push it once again to the EHStack after + // the full expression. pushCleanupAfterFullExprWithActiveFlag( cleanupKind, ActiveFlag, SavedAddr, type, destroyer, useEHCleanupForArray); @@ -2442,9 +2463,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 +2474,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 2480972f1432f700f34db1fa371ee0615225605b..c85a339f5e3f885c2524121c5d270a306cf9aeb9 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 @@ -5597,11 +5603,44 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { break; } - RValue RV = EmitAnyExpr(E->getRHS()); + // TODO: Can we de-duplicate this code with the corresponding code in + // CGExprScalar, similar to the way EmitCompoundAssignmentLValue works? + RValue RV; + llvm::Value *Previous = nullptr; + QualType SrcType = E->getRHS()->getType(); + // Check if LHS is a bitfield, if RHS contains an implicit cast expression + // we want to extract that value and potentially (if the bitfield sanitizer + // is enabled) use it to check for an implicit conversion. + if (E->getLHS()->refersToBitField()) { + llvm::Value *RHS = + EmitWithOriginalRHSBitfieldAssignment(E, &Previous, &SrcType); + RV = RValue::get(RHS); + } else + RV = EmitAnyExpr(E->getRHS()); + LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store); + if (RV.isScalar()) EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc()); - EmitStoreThroughLValue(RV, LV); + + if (LV.isBitField()) { + llvm::Value *Result = nullptr; + // If bitfield sanitizers are enabled we want to use the result + // to check whether a truncation or sign change has occurred. + if (SanOpts.has(SanitizerKind::ImplicitBitfieldConversion)) + EmitStoreThroughBitfieldLValue(RV, LV, &Result); + else + EmitStoreThroughBitfieldLValue(RV, LV); + + // If the expression contained an implicit conversion, make sure + // to use the value before the scalar conversion. + llvm::Value *Src = Previous ? Previous : RV.getScalarVal(); + QualType DstType = E->getLHS()->getType(); + EmitBitfieldConversionCheck(Src, SrcType, Result, DstType, + LV.getBitFieldInfo(), E->getExprLoc()); + } else + EmitStoreThroughLValue(RV, LV); + if (getLangOpts().OpenMP) CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(*this, E->getLHS()); diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 1b9287ea239347d334c2c7d52e2cc092e281aeb5..560a9e2c5ead5c9c37eef219b08c42718d6263d3 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()); } } @@ -1813,10 +1789,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; } } @@ -1829,17 +1805,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 a4fb673284ceca6bde6cc331279a4c4b42b6e39d..a88b29b326bb927611719b04d38fcea1b5d153c6 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 397b4977acc3e9d536c000c12955a55f51262156..1f18e0d5ba409a88b3e51b098219685d7a5fc8cb 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -15,6 +15,7 @@ #include "CGDebugInfo.h" #include "CGObjCRuntime.h" #include "CGOpenMPRuntime.h" +#include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" @@ -308,6 +309,7 @@ public: llvm::Type *DstTy, SourceLocation Loc); /// Known implicit conversion check kinds. + /// This is used for bitfield conversion checks as well. /// Keep in sync with the enum of the same name in ubsan_handlers.h enum ImplicitConversionCheckKind : unsigned char { ICCK_IntegerTruncation = 0, // Legacy, was only used by clang 7. @@ -1098,11 +1100,28 @@ void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType, llvm::Constant *StaticArgs[] = { CGF.EmitCheckSourceLocation(Loc), CGF.EmitCheckTypeDescriptor(SrcType), CGF.EmitCheckTypeDescriptor(DstType), - llvm::ConstantInt::get(Builder.getInt8Ty(), Check.first)}; + llvm::ConstantInt::get(Builder.getInt8Ty(), Check.first), + llvm::ConstantInt::get(Builder.getInt32Ty(), 0)}; + CGF.EmitCheck(Check.second, SanitizerHandler::ImplicitConversion, StaticArgs, {Src, Dst}); } +static llvm::Value *EmitIsNegativeTestHelper(Value *V, QualType VType, + const char *Name, + CGBuilderTy &Builder) { + bool VSigned = VType->isSignedIntegerOrEnumerationType(); + llvm::Type *VTy = V->getType(); + if (!VSigned) { + // If the value is unsigned, then it is never negative. + return llvm::ConstantInt::getFalse(VTy->getContext()); + } + llvm::Constant *Zero = llvm::ConstantInt::get(VTy, 0); + return Builder.CreateICmp(llvm::ICmpInst::ICMP_SLT, V, Zero, + llvm::Twine(Name) + "." + V->getName() + + ".negativitycheck"); +} + // Should be called within CodeGenFunction::SanitizerScope RAII scope. // Returns 'i1 false' when the conversion Src -> Dst changed the sign. static std::pair Value * { - // Is this value a signed type? - bool VSigned = VType->isSignedIntegerOrEnumerationType(); - llvm::Type *VTy = V->getType(); - if (!VSigned) { - // If the value is unsigned, then it is never negative. - // FIXME: can we encounter non-scalar VTy here? - return llvm::ConstantInt::getFalse(VTy->getContext()); - } - // Get the zero of the same type with which we will be comparing. - llvm::Constant *Zero = llvm::ConstantInt::get(VTy, 0); - // %V.isnegative = icmp slt %V, 0 - // I.e is %V *strictly* less than zero, does it have negative value? - return Builder.CreateICmp(llvm::ICmpInst::ICMP_SLT, V, Zero, - llvm::Twine(Name) + "." + V->getName() + - ".negativitycheck"); - }; - // 1. Was the old Value negative? - llvm::Value *SrcIsNegative = EmitIsNegativeTest(Src, SrcType, "src"); + llvm::Value *SrcIsNegative = + EmitIsNegativeTestHelper(Src, SrcType, "src", Builder); // 2. Is the new Value negative? - llvm::Value *DstIsNegative = EmitIsNegativeTest(Dst, DstType, "dst"); + llvm::Value *DstIsNegative = + EmitIsNegativeTestHelper(Dst, DstType, "dst", Builder); // 3. Now, was the 'negativity status' preserved during the conversion? // NOTE: conversion from negative to zero is considered to change the sign. // (We want to get 'false' when the conversion changed the sign) @@ -1239,12 +1240,143 @@ void ScalarExprEmitter::EmitIntegerSignChangeCheck(Value *Src, QualType SrcType, llvm::Constant *StaticArgs[] = { CGF.EmitCheckSourceLocation(Loc), CGF.EmitCheckTypeDescriptor(SrcType), CGF.EmitCheckTypeDescriptor(DstType), - llvm::ConstantInt::get(Builder.getInt8Ty(), CheckKind)}; + llvm::ConstantInt::get(Builder.getInt8Ty(), CheckKind), + llvm::ConstantInt::get(Builder.getInt32Ty(), 0)}; // EmitCheck() will 'and' all the checks together. CGF.EmitCheck(Checks, SanitizerHandler::ImplicitConversion, StaticArgs, {Src, Dst}); } +// Should be called within CodeGenFunction::SanitizerScope RAII scope. +// Returns 'i1 false' when the truncation Src -> Dst was lossy. +static std::pair> +EmitBitfieldTruncationCheckHelper(Value *Src, QualType SrcType, Value *Dst, + QualType DstType, CGBuilderTy &Builder) { + bool SrcSigned = SrcType->isSignedIntegerOrEnumerationType(); + bool DstSigned = DstType->isSignedIntegerOrEnumerationType(); + + ScalarExprEmitter::ImplicitConversionCheckKind Kind; + if (!SrcSigned && !DstSigned) + Kind = ScalarExprEmitter::ICCK_UnsignedIntegerTruncation; + else + Kind = ScalarExprEmitter::ICCK_SignedIntegerTruncation; + + llvm::Value *Check = nullptr; + // 1. Extend the truncated value back to the same width as the Src. + Check = Builder.CreateIntCast(Dst, Src->getType(), DstSigned, "bf.anyext"); + // 2. Equality-compare with the original source value + Check = Builder.CreateICmpEQ(Check, Src, "bf.truncheck"); + // If the comparison result is 'i1 false', then the truncation was lossy. + + return std::make_pair( + Kind, std::make_pair(Check, SanitizerKind::ImplicitBitfieldConversion)); +} + +// Should be called within CodeGenFunction::SanitizerScope RAII scope. +// Returns 'i1 false' when the conversion Src -> Dst changed the sign. +static std::pair> +EmitBitfieldSignChangeCheckHelper(Value *Src, QualType SrcType, Value *Dst, + QualType DstType, CGBuilderTy &Builder) { + // 1. Was the old Value negative? + llvm::Value *SrcIsNegative = + EmitIsNegativeTestHelper(Src, SrcType, "bf.src", Builder); + // 2. Is the new Value negative? + llvm::Value *DstIsNegative = + EmitIsNegativeTestHelper(Dst, DstType, "bf.dst", Builder); + // 3. Now, was the 'negativity status' preserved during the conversion? + // NOTE: conversion from negative to zero is considered to change the sign. + // (We want to get 'false' when the conversion changed the sign) + // So we should just equality-compare the negativity statuses. + llvm::Value *Check = nullptr; + Check = + Builder.CreateICmpEQ(SrcIsNegative, DstIsNegative, "bf.signchangecheck"); + // If the comparison result is 'false', then the conversion changed the sign. + return std::make_pair( + ScalarExprEmitter::ICCK_IntegerSignChange, + std::make_pair(Check, SanitizerKind::ImplicitBitfieldConversion)); +} + +void CodeGenFunction::EmitBitfieldConversionCheck(Value *Src, QualType SrcType, + Value *Dst, QualType DstType, + const CGBitFieldInfo &Info, + SourceLocation Loc) { + + if (!SanOpts.has(SanitizerKind::ImplicitBitfieldConversion)) + return; + + // We only care about int->int conversions here. + // We ignore conversions to/from pointer and/or bool. + if (!PromotionIsPotentiallyEligibleForImplicitIntegerConversionCheck(SrcType, + DstType)) + return; + + if (DstType->isBooleanType() || SrcType->isBooleanType()) + return; + + // This should be truncation of integral types. + assert(isa(Src->getType()) && + isa(Dst->getType()) && "non-integer llvm type"); + + // TODO: Calculate src width to avoid emitting code + // for unecessary cases. + unsigned SrcBits = ConvertType(SrcType)->getScalarSizeInBits(); + unsigned DstBits = Info.Size; + + bool SrcSigned = SrcType->isSignedIntegerOrEnumerationType(); + bool DstSigned = DstType->isSignedIntegerOrEnumerationType(); + + CodeGenFunction::SanitizerScope SanScope(this); + + std::pair> + Check; + + // Truncation + bool EmitTruncation = DstBits < SrcBits; + // If Dst is signed and Src unsigned, we want to be more specific + // about the CheckKind we emit, in this case we want to emit + // ICCK_SignedIntegerTruncationOrSignChange. + bool EmitTruncationFromUnsignedToSigned = + EmitTruncation && DstSigned && !SrcSigned; + // Sign change + bool SameTypeSameSize = SrcSigned == DstSigned && SrcBits == DstBits; + bool BothUnsigned = !SrcSigned && !DstSigned; + bool LargerSigned = (DstBits > SrcBits) && DstSigned; + // We can avoid emitting sign change checks in some obvious cases + // 1. If Src and Dst have the same signedness and size + // 2. If both are unsigned sign check is unecessary! + // 3. If Dst is signed and bigger than Src, either + // sign-extension or zero-extension will make sure + // the sign remains. + bool EmitSignChange = !SameTypeSameSize && !BothUnsigned && !LargerSigned; + + if (EmitTruncation) + Check = + EmitBitfieldTruncationCheckHelper(Src, SrcType, Dst, DstType, Builder); + else if (EmitSignChange) { + assert(((SrcBits != DstBits) || (SrcSigned != DstSigned)) && + "either the widths should be different, or the signednesses."); + Check = + EmitBitfieldSignChangeCheckHelper(Src, SrcType, Dst, DstType, Builder); + } else + return; + + ScalarExprEmitter::ImplicitConversionCheckKind CheckKind = Check.first; + if (EmitTruncationFromUnsignedToSigned) + CheckKind = ScalarExprEmitter::ICCK_SignedIntegerTruncationOrSignChange; + + llvm::Constant *StaticArgs[] = { + EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(SrcType), + EmitCheckTypeDescriptor(DstType), + llvm::ConstantInt::get(Builder.getInt8Ty(), CheckKind), + llvm::ConstantInt::get(Builder.getInt32Ty(), Info.Size)}; + + EmitCheck(Check.second, SanitizerHandler::ImplicitConversion, StaticArgs, + {Src, Dst}); +} + Value *ScalarExprEmitter::EmitScalarCast(Value *Src, QualType SrcType, QualType DstType, llvm::Type *SrcTy, llvm::Type *DstTy, @@ -2620,6 +2752,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, llvm::PHINode *atomicPHI = nullptr; llvm::Value *value; llvm::Value *input; + llvm::Value *Previous = nullptr; + QualType SrcType = E->getType(); int amount = (isInc ? 1 : -1); bool isSubtraction = !isInc; @@ -2708,7 +2842,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, "base or promoted) will be signed, or the bitwidths will match."); } if (CGF.SanOpts.hasOneOf( - SanitizerKind::ImplicitIntegerArithmeticValueChange) && + SanitizerKind::ImplicitIntegerArithmeticValueChange | + SanitizerKind::ImplicitBitfieldConversion) && canPerformLossyDemotionCheck) { // While `x += 1` (for `x` with width less than int) is modeled as // promotion+arithmetics+demotion, and we can catch lossy demotion with @@ -2719,13 +2854,26 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, // the increment/decrement in the wider type, and finally // perform the demotion. This will catch lossy demotions. + // We have a special case for bitfields defined using all the bits of the + // type. In this case we need to do the same trick as for the integer + // sanitizer checks, i.e., promotion -> increment/decrement -> demotion. + value = EmitScalarConversion(value, type, promotedType, E->getExprLoc()); Value *amt = llvm::ConstantInt::get(value->getType(), amount, true); value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec"); // Do pass non-default ScalarConversionOpts so that sanitizer check is - // emitted. + // emitted if LV is not a bitfield, otherwise the bitfield sanitizer + // checks will take care of the conversion. + ScalarConversionOpts Opts; + if (!LV.isBitField()) + Opts = ScalarConversionOpts(CGF.SanOpts); + else if (CGF.SanOpts.has(SanitizerKind::ImplicitBitfieldConversion)) { + Previous = value; + SrcType = promotedType; + } + value = EmitScalarConversion(value, promotedType, type, E->getExprLoc(), - ScalarConversionOpts(CGF.SanOpts)); + Opts); // Note that signed integer inc/dec with width less than int can't // overflow because of promotion rules; we're just eliding a few steps @@ -2910,9 +3058,12 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, } // Store the updated result through the lvalue. - if (LV.isBitField()) + if (LV.isBitField()) { + Value *Src = Previous ? Previous : value; CGF.EmitStoreThroughBitfieldLValue(RValue::get(value), LV, &value); - else + CGF.EmitBitfieldConversionCheck(Src, SrcType, value, E->getType(), + LV.getBitFieldInfo(), E->getExprLoc()); + } else CGF.EmitStoreThroughLValue(RValue::get(value), LV); // If this is a postinc, return the value read from memory, otherwise use the @@ -3417,8 +3568,15 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue( // Convert the result back to the LHS type, // potentially with Implicit Conversion sanitizer check. - Result = EmitScalarConversion(Result, PromotionTypeCR, LHSTy, Loc, - ScalarConversionOpts(CGF.SanOpts)); + // If LHSLV is a bitfield, use default ScalarConversionOpts + // to avoid emit any implicit integer checks. + Value *Previous = nullptr; + if (LHSLV.isBitField()) { + Previous = Result; + Result = EmitScalarConversion(Result, PromotionTypeCR, LHSTy, Loc); + } else + Result = EmitScalarConversion(Result, PromotionTypeCR, LHSTy, Loc, + ScalarConversionOpts(CGF.SanOpts)); if (atomicPHI) { llvm::BasicBlock *curBlock = Builder.GetInsertBlock(); @@ -3437,9 +3595,14 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue( // specially because the result is altered by the store, i.e., [C99 6.5.16p1] // 'An assignment expression has the value of the left operand after the // assignment...'. - if (LHSLV.isBitField()) + if (LHSLV.isBitField()) { + Value *Src = Previous ? Previous : Result; + QualType SrcType = E->getRHS()->getType(); + QualType DstType = E->getLHS()->getType(); CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, &Result); - else + CGF.EmitBitfieldConversionCheck(Src, SrcType, Result, DstType, + LHSLV.getBitFieldInfo(), E->getExprLoc()); + } else CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV); if (CGF.getLangOpts().OpenMP) @@ -4551,6 +4714,24 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E, E->getExprLoc()); } +llvm::Value *CodeGenFunction::EmitWithOriginalRHSBitfieldAssignment( + const BinaryOperator *E, Value **Previous, QualType *SrcType) { + // In case we have the integer or bitfield sanitizer checks enabled + // we want to get the expression before scalar conversion. + if (auto *ICE = dyn_cast(E->getRHS())) { + CastKind Kind = ICE->getCastKind(); + if (Kind == CK_IntegralCast || Kind == CK_LValueToRValue) { + *SrcType = ICE->getSubExpr()->getType(); + *Previous = EmitScalarExpr(ICE->getSubExpr()); + // Pass default ScalarConversionOpts to avoid emitting + // integer sanitizer checks as E refers to bitfield. + return EmitScalarConversion(*Previous, *SrcType, ICE->getType(), + ICE->getExprLoc()); + } + } + return EmitScalarExpr(E->getRHS()); +} + Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { bool Ignore = TestAndClearIgnoreResultAssign(); @@ -4579,7 +4760,16 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { case Qualifiers::OCL_None: // __block variables need to have the rhs evaluated first, plus // this should improve codegen just a little. - RHS = Visit(E->getRHS()); + Value *Previous = nullptr; + QualType SrcType = E->getRHS()->getType(); + // Check if LHS is a bitfield, if RHS contains an implicit cast expression + // we want to extract that value and potentially (if the bitfield sanitizer + // is enabled) use it to check for an implicit conversion. + if (E->getLHS()->refersToBitField()) + RHS = CGF.EmitWithOriginalRHSBitfieldAssignment(E, &Previous, &SrcType); + else + RHS = Visit(E->getRHS()); + LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store); // Store the value into the LHS. Bit-fields are handled specially @@ -4588,6 +4778,12 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { // the assignment...'. if (LHS.isBitField()) { CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, &RHS); + // If the expression contained an implicit conversion, make sure + // to use the value before the scalar conversion. + Value *Src = Previous ? Previous : RHS; + QualType DstType = E->getLHS()->getType(); + CGF.EmitBitfieldConversionCheck(Src, SrcType, RHS, DstType, + LHS.getBitFieldInfo(), E->getExprLoc()); } else { CGF.EmitNullabilityCheck(LHS, RHS, E->getExprLoc()); CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS); diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index c7f497a7c8451be6918c726ebdb3423a600170db..ee571995ce4c3f4aab64b65af09d570ac89f22ea 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -1789,11 +1789,10 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ static const unsigned NumItems = 16; // Fetch the countByEnumeratingWithState:objects:count: selector. - IdentifierInfo *II[] = { - &CGM.getContext().Idents.get("countByEnumeratingWithState"), - &CGM.getContext().Idents.get("objects"), - &CGM.getContext().Idents.get("count") - }; + const IdentifierInfo *II[] = { + &CGM.getContext().Idents.get("countByEnumeratingWithState"), + &CGM.getContext().Idents.get("objects"), + &CGM.getContext().Idents.get("count")}; Selector FastEnumSel = CGM.getContext().Selectors.getSelector(std::size(II), &II[0]); @@ -2720,7 +2719,7 @@ llvm::Value *CodeGenFunction::EmitObjCMRRAutoreleasePoolPush() { CGObjCRuntime &Runtime = CGM.getObjCRuntime(); llvm::Value *Receiver = Runtime.EmitNSAutoreleasePoolClassRef(*this); // [NSAutoreleasePool alloc] - IdentifierInfo *II = &CGM.getContext().Idents.get("alloc"); + const IdentifierInfo *II = &CGM.getContext().Idents.get("alloc"); Selector AllocSel = getContext().Selectors.getSelector(0, &II); CallArgList Args; RValue AllocRV = @@ -2767,7 +2766,7 @@ llvm::Value *CodeGenFunction::EmitObjCAllocInit(llvm::Value *value, /// Produce the code to do a primitive release. /// [tmp drain]; void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) { - IdentifierInfo *II = &CGM.getContext().Idents.get("drain"); + const IdentifierInfo *II = &CGM.getContext().Idents.get("drain"); Selector DrainSel = getContext().Selectors.getSelector(0, &II); CallArgList Args; CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), @@ -3715,8 +3714,8 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction( if ((HelperFn = CGM.getAtomicSetterHelperFnMap(Ty))) return HelperFn; - IdentifierInfo *II - = &CGM.getContext().Idents.get("__assign_helper_atomic_property_"); + const IdentifierInfo *II = + &CGM.getContext().Idents.get("__assign_helper_atomic_property_"); QualType ReturnTy = C.VoidTy; QualType DestTy = C.getPointerType(Ty); @@ -3813,7 +3812,7 @@ llvm::Constant *CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction( if ((HelperFn = CGM.getAtomicGetterHelperFnMap(Ty))) return HelperFn; - IdentifierInfo *II = + const IdentifierInfo *II = &CGM.getContext().Idents.get("__copy_helper_atomic_property_"); QualType ReturnTy = C.VoidTy; @@ -3907,10 +3906,10 @@ llvm::Constant *CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction( llvm::Value * CodeGenFunction::EmitBlockCopyAndAutorelease(llvm::Value *Block, QualType Ty) { // Get selectors for retain/autorelease. - IdentifierInfo *CopyID = &getContext().Idents.get("copy"); + const IdentifierInfo *CopyID = &getContext().Idents.get("copy"); Selector CopySelector = getContext().Selectors.getNullarySelector(CopyID); - IdentifierInfo *AutoreleaseID = &getContext().Idents.get("autorelease"); + const IdentifierInfo *AutoreleaseID = &getContext().Idents.get("autorelease"); Selector AutoreleaseSelector = getContext().Selectors.getNullarySelector(AutoreleaseID); diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index 8a599c10e1caf17328d7f3e1d70f3b7d499aacbc..042cd5d46da4b2eb608a9b5065c7514bde04df2a 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -1555,12 +1555,12 @@ private: // Shamelessly stolen from Analysis/CFRefCount.cpp Selector GetNullarySelector(const char* name) const { - IdentifierInfo* II = &CGM.getContext().Idents.get(name); + const IdentifierInfo *II = &CGM.getContext().Idents.get(name); return CGM.getContext().Selectors.getSelector(0, &II); } Selector GetUnarySelector(const char* name) const { - IdentifierInfo* II = &CGM.getContext().Idents.get(name); + const IdentifierInfo *II = &CGM.getContext().Idents.get(name); return CGM.getContext().Selectors.getSelector(1, &II); } @@ -6268,11 +6268,10 @@ bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) { VTableDispatchMethods.insert(GetUnarySelector("addObject")); // "countByEnumeratingWithState:objects:count" - IdentifierInfo *KeyIdents[] = { - &CGM.getContext().Idents.get("countByEnumeratingWithState"), - &CGM.getContext().Idents.get("objects"), - &CGM.getContext().Idents.get("count") - }; + const IdentifierInfo *KeyIdents[] = { + &CGM.getContext().Idents.get("countByEnumeratingWithState"), + &CGM.getContext().Idents.get("objects"), + &CGM.getContext().Idents.get("count")}; VTableDispatchMethods.insert( CGM.getContext().Selectors.getSelector(3, KeyIdents)); } diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 8eb10584699fad864bba39fe3bc65b724d0710f0..2ae11e129c75e42b88df5ceae7d3d1c71c3a6339 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -2656,11 +2656,12 @@ void CGOpenMPRuntime::emitForStaticFinish(CodeGenFunction &CGF, // Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid); llvm::Value *Args[] = { emitUpdateLocation(CGF, Loc, - isOpenMPDistributeDirective(DKind) + isOpenMPDistributeDirective(DKind) || + (DKind == OMPD_target_teams_loop) ? OMP_IDENT_WORK_DISTRIBUTE - : isOpenMPLoopDirective(DKind) - ? OMP_IDENT_WORK_LOOP - : OMP_IDENT_WORK_SECTIONS), + : isOpenMPLoopDirective(DKind) + ? OMP_IDENT_WORK_LOOP + : OMP_IDENT_WORK_SECTIONS), getThreadID(CGF, Loc)}; auto DL = ApplyDebugLocation::CreateDefaultArtificial(CGF, Loc); if (isOpenMPDistributeDirective(DKind) && @@ -8885,7 +8886,8 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) { OpenMPDirectiveKind DKind = NestedDir->getDirectiveKind(); switch (D.getDirectiveKind()) { case OMPD_target: - // For now, just treat 'target teams loop' as if it's distributed. + // For now, treat 'target' with nested 'teams loop' as if it's + // distributed (target teams distribute). if (isOpenMPDistributeDirective(DKind) || DKind == OMPD_teams_loop) return NestedDir; if (DKind == OMPD_teams) { @@ -9369,7 +9371,8 @@ llvm::Value *CGOpenMPRuntime::emitTargetNumIterationsCall( SizeEmitter) { OpenMPDirectiveKind Kind = D.getDirectiveKind(); const OMPExecutableDirective *TD = &D; - // Get nested teams distribute kind directive, if any. + // Get nested teams distribute kind directive, if any. For now, treat + // 'target_teams_loop' as if it's really a target_teams_distribute. if ((!isOpenMPDistributeDirective(Kind) || !isOpenMPTeamsDirective(Kind)) && Kind != OMPD_target_teams_loop) TD = getNestedDistributeDirective(CGM.getContext(), D); diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index 5baac8f0e3e268bf2789014edae018ec0436f557..59ba03c6b862532575766a2985a7405ba0a6b3af 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -646,7 +646,6 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx, case OMPD_target: case OMPD_target_teams: return hasNestedSPMDDirective(Ctx, D); - case OMPD_target_teams_loop: case OMPD_target_parallel_loop: case OMPD_target_parallel: case OMPD_target_parallel_for: @@ -658,6 +657,12 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx, return true; case OMPD_target_teams_distribute: return false; + case OMPD_target_teams_loop: + // Whether this is true or not depends on how the directive will + // eventually be emitted. + if (auto *TTLD = dyn_cast(&D)) + return TTLD->canBeParallelFor(); + return false; case OMPD_parallel: case OMPD_for: case OMPD_parallel_for: diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index e6d504bcdeca5b4e86d7f04974e8dd4713c2d0c0..a0a8a07c76ba16528fea5c39459684d7ee37a74c 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -24,6 +24,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/PrettyStackTrace.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallSet.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" @@ -34,11 +35,14 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Metadata.h" #include "llvm/Support/AtomicOrdering.h" +#include "llvm/Support/Debug.h" #include using namespace clang; using namespace CodeGen; using namespace llvm::omp; +#define TTL_CODEGEN_TYPE "target-teams-loop-codegen" + static const VarDecl *getBaseDecl(const Expr *Ref); namespace { @@ -1432,9 +1436,12 @@ void CodeGenFunction::EmitOMPReductionClauseFinal( *this, D.getBeginLoc(), isOpenMPWorksharingDirective(D.getDirectiveKind())); } + bool TeamsLoopCanBeParallel = false; + if (auto *TTLD = dyn_cast(&D)) + TeamsLoopCanBeParallel = TTLD->canBeParallelFor(); bool WithNowait = D.getSingleClause() || isOpenMPParallelDirective(D.getDirectiveKind()) || - ReductionKind == OMPD_simd; + TeamsLoopCanBeParallel || ReductionKind == OMPD_simd; bool SimpleReduction = ReductionKind == OMPD_simd; // Emit nowait reduction if nowait clause is present or directive is a // parallel directive (it always has implicit barrier). @@ -7928,11 +7935,9 @@ void CodeGenFunction::EmitOMPParallelGenericLoopDirective( void CodeGenFunction::EmitOMPTeamsGenericLoopDirective( const OMPTeamsGenericLoopDirective &S) { // To be consistent with current behavior of 'target teams loop', emit - // 'teams loop' as if its constituent constructs are 'distribute, - // 'parallel, and 'for'. + // 'teams loop' as if its constituent constructs are 'teams' and 'distribute'. auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) { - CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined, - S.getDistInc()); + CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc()); }; // Emit teams region as a standalone region. @@ -7946,15 +7951,33 @@ void CodeGenFunction::EmitOMPTeamsGenericLoopDirective( CodeGenDistribute); CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams); }; - emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for, CodeGen); + emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen); emitPostUpdateForReductionClause(*this, S, [](CodeGenFunction &) { return nullptr; }); } -static void -emitTargetTeamsGenericLoopRegion(CodeGenFunction &CGF, - const OMPTargetTeamsGenericLoopDirective &S, - PrePostActionTy &Action) { +#ifndef NDEBUG +static void emitTargetTeamsLoopCodegenStatus(CodeGenFunction &CGF, + std::string StatusMsg, + const OMPExecutableDirective &D) { + bool IsDevice = CGF.CGM.getLangOpts().OpenMPIsTargetDevice; + if (IsDevice) + StatusMsg += ": DEVICE"; + else + StatusMsg += ": HOST"; + SourceLocation L = D.getBeginLoc(); + auto &SM = CGF.getContext().getSourceManager(); + PresumedLoc PLoc = SM.getPresumedLoc(L); + const char *FileName = PLoc.isValid() ? PLoc.getFilename() : nullptr; + unsigned LineNo = + PLoc.isValid() ? PLoc.getLine() : SM.getExpansionLineNumber(L); + llvm::dbgs() << StatusMsg << ": " << FileName << ": " << LineNo << "\n"; +} +#endif + +static void emitTargetTeamsGenericLoopRegionAsParallel( + CodeGenFunction &CGF, PrePostActionTy &Action, + const OMPTargetTeamsGenericLoopDirective &S) { Action.Enter(CGF); // Emit 'teams loop' as if its constituent constructs are 'distribute, // 'parallel, and 'for'. @@ -7974,19 +7997,50 @@ emitTargetTeamsGenericLoopRegion(CodeGenFunction &CGF, CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false); CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams); }; - + DEBUG_WITH_TYPE(TTL_CODEGEN_TYPE, + emitTargetTeamsLoopCodegenStatus( + CGF, TTL_CODEGEN_TYPE " as parallel for", S)); emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_parallel_for, CodeGenTeams); emitPostUpdateForReductionClause(CGF, S, [](CodeGenFunction &) { return nullptr; }); } -/// Emit combined directive 'target teams loop' as if its constituent -/// constructs are 'target', 'teams', 'distribute', 'parallel', and 'for'. +static void emitTargetTeamsGenericLoopRegionAsDistribute( + CodeGenFunction &CGF, PrePostActionTy &Action, + const OMPTargetTeamsGenericLoopDirective &S) { + Action.Enter(CGF); + // Emit 'teams loop' as if its constituent construct is 'distribute'. + auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) { + CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc()); + }; + + // Emit teams region as a standalone region. + auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF, + PrePostActionTy &Action) { + Action.Enter(CGF); + CodeGenFunction::OMPPrivateScope PrivateScope(CGF); + CGF.EmitOMPReductionClauseInit(S, PrivateScope); + (void)PrivateScope.Privatize(); + CGF.CGM.getOpenMPRuntime().emitInlinedDirective( + CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false); + CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams); + }; + DEBUG_WITH_TYPE(TTL_CODEGEN_TYPE, + emitTargetTeamsLoopCodegenStatus( + CGF, TTL_CODEGEN_TYPE " as distribute", S)); + emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute, CodeGen); + emitPostUpdateForReductionClause(CGF, S, + [](CodeGenFunction &) { return nullptr; }); +} + void CodeGenFunction::EmitOMPTargetTeamsGenericLoopDirective( const OMPTargetTeamsGenericLoopDirective &S) { auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { - emitTargetTeamsGenericLoopRegion(CGF, S, Action); + if (S.canBeParallelFor()) + emitTargetTeamsGenericLoopRegionAsParallel(CGF, Action, S); + else + emitTargetTeamsGenericLoopRegionAsDistribute(CGF, Action, S); }; emitCommonOMPTargetDirective(*this, S, CodeGen); } @@ -7996,7 +8050,10 @@ void CodeGenFunction::EmitOMPTargetTeamsGenericLoopDeviceFunction( const OMPTargetTeamsGenericLoopDirective &S) { // Emit SPMD target parallel loop region as a standalone region. auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { - emitTargetTeamsGenericLoopRegion(CGF, S, Action); + if (S.canBeParallelFor()) + emitTargetTeamsGenericLoopRegionAsParallel(CGF, Action, S); + else + emitTargetTeamsGenericLoopRegionAsDistribute(CGF, Action, S); }; llvm::Function *Fn; llvm::Constant *Addr; diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp index bb9aaba025fa59899a12ad855041f48cf5a743ae..1a6b628016f7461a36427b5e2614bb25e98df482 100644 --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -25,8 +25,11 @@ #include "clang/CodeGen/ModuleBuilder.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/MultiplexConsumer.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Serialization/ASTWriter.h" #include "llvm/ADT/Hashing.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h" @@ -1003,6 +1006,12 @@ CodeGenerator *CodeGenAction::getCodeGenerator() const { return BEConsumer->getCodeGenerator(); } +bool CodeGenAction::BeginSourceFileAction(CompilerInstance &CI) { + if (CI.getFrontendOpts().GenReducedBMI) + CI.getLangOpts().setCompilingModule(LangOptions::CMK_ModuleInterface); + return true; +} + static std::unique_ptr GetOutputStream(CompilerInstance &CI, StringRef InFile, BackendAction Action) { switch (Action) { @@ -1061,6 +1070,16 @@ CodeGenAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { CI.getPreprocessor().addPPCallbacks(std::move(Callbacks)); } + if (CI.getFrontendOpts().GenReducedBMI && + !CI.getFrontendOpts().ModuleOutputPath.empty()) { + std::vector> Consumers(2); + Consumers[0] = std::make_unique( + CI.getPreprocessor(), CI.getModuleCache(), + CI.getFrontendOpts().ModuleOutputPath); + Consumers[1] = std::move(Result); + return std::make_unique(std::move(Consumers)); + } + return std::move(Result); } diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 6474d6c8c1d1e42a2290e722371497165a6c4322..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 @@ -822,7 +828,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, // .cxx_destruct, __destroy_helper_block_ and all of their calees at run time. if (SanOpts.has(SanitizerKind::Thread)) { if (const auto *OMD = dyn_cast_or_null(D)) { - IdentifierInfo *II = OMD->getSelector().getIdentifierInfoForSlot(0); + const IdentifierInfo *II = OMD->getSelector().getIdentifierInfoForSlot(0); if (OMD->getMethodFamily() == OMF_dealloc || OMD->getMethodFamily() == OMF_initialize || (OMD->getSelector().isUnarySelector() && II->isStr(".cxx_destruct"))) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index e2a7e28c8211ea7fd399aa0063f2cb7e9a0f3073..c49e9fd00c8d3e0f43771f3d700090be9c48cc66 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() { @@ -926,6 +985,7 @@ public: class RunCleanupsScope { EHScopeStack::stable_iterator CleanupStackDepth, OldCleanupScopeDepth; size_t LifetimeExtendedCleanupStackSize; + CleanupDeactivationScope DeactivateCleanups; bool OldDidCallStackSave; protected: bool PerformCleanup; @@ -940,8 +1000,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 +1030,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 +2220,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 +2763,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 @@ -2786,6 +2878,21 @@ public: /// expression and compare the result against zero, returning an Int1Ty value. llvm::Value *EvaluateExprAsBool(const Expr *E); + /// Retrieve the implicit cast expression of the rhs in a binary operator + /// expression by passing pointers to Value and QualType + /// This is used for implicit bitfield conversion checks, which + /// must compare with the value before potential truncation. + llvm::Value *EmitWithOriginalRHSBitfieldAssignment(const BinaryOperator *E, + llvm::Value **Previous, + QualType *SrcType); + + /// Emit a check that an [implicit] conversion of a bitfield. It is not UB, + /// so we use the value after conversion. + void EmitBitfieldConversionCheck(llvm::Value *Src, QualType SrcType, + llvm::Value *Dst, QualType DstType, + const CGBitFieldInfo &Info, + SourceLocation Loc); + /// EmitIgnoredExpr - Emit an expression in a context which ignores the result. void EmitIgnoredExpr(const Expr *E); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 00b3bfcaa0bc2565862d659b122b1caf18ff0599..73a9cb9d6e0424ad38e0b874482015663766cbce 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2087,6 +2087,14 @@ void CodeGenModule::SetLLVMFunctionAttributes(GlobalDecl GD, llvm::AttributeList PAL; ConstructAttributeList(F->getName(), Info, GD, PAL, CallingConv, /*AttrOnCallSite=*/false, IsThunk); + if (CallingConv == llvm::CallingConv::X86_VectorCall && + getTarget().getTriple().isWindowsArm64EC()) { + SourceLocation Loc; + if (const Decl *D = GD.getDecl()) + Loc = D->getLocation(); + + Error(Loc, "__vectorcall calling convention is not currently supported"); + } F->setAttributes(PAL); F->setCallingConv(static_cast(CallingConv)); } @@ -2627,7 +2635,7 @@ void CodeGenModule::setNonAliasAttributes(GlobalDecl GD, addUsedGlobal(F); if (auto *SA = D->getAttr()) if (!D->getAttr()) - F->addFnAttr("implicit-section-name", SA->getName()); + F->setSection(SA->getName()); llvm::AttrBuilder Attrs(F->getContext()); if (GetCPUAndFeaturesAttributes(GD, Attrs)) { @@ -6618,7 +6626,7 @@ static bool AllTrivialInitializers(CodeGenModule &CGM, void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { // We might need a .cxx_destruct even if we don't have any ivar initializers. if (needsDestructMethod(D)) { - IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct"); + const IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct"); Selector cxxSelector = getContext().Selectors.getSelector(0, &II); ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create( getContext(), D->getLocation(), D->getLocation(), cxxSelector, @@ -6638,7 +6646,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { AllTrivialInitializers(*this, D)) return; - IdentifierInfo *II = &getContext().Idents.get(".cxx_construct"); + const IdentifierInfo *II = &getContext().Idents.get(".cxx_construct"); Selector cxxSelector = getContext().Selectors.getSelector(0, &II); // The constructor returns 'self'. ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create( @@ -7206,7 +7214,7 @@ void CodeGenModule::EmitStaticExternCAliases() { if (!getTargetCodeGenInfo().shouldEmitStaticExternCAliases()) return; for (auto &I : StaticExternCValues) { - IdentifierInfo *Name = I.first; + const IdentifierInfo *Name = I.first; llvm::GlobalValue *Val = I.second; // If Val is null, that implies there were multiple declarations that each diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp index 837bf725da388a9c3541f91d4784e7cbdf7b8566..da689ee6a13d7087ee019caccbd18911888ee33b 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -98,8 +98,6 @@ static bool TypeHasMayAlias(QualType QTy) { /// Check if the given type is a valid base type to be used in access tags. static bool isValidBaseType(QualType QTy) { - if (QTy->isReferenceType()) - return false; if (const RecordType *TTy = QTy->getAs()) { const RecordDecl *RD = TTy->getDecl()->getDefinition(); // Incomplete types are not valid base access types. @@ -243,9 +241,10 @@ llvm::MDNode *CodeGenTBAA::getTypeInfo(QualType QTy) { // aggregate will result into the may-alias access descriptor, meaning all // subsequent accesses to direct and indirect members of that aggregate will // be considered may-alias too. - // TODO: Combine getTypeInfo() and getBaseTypeInfo() into a single function. + // TODO: Combine getTypeInfo() and getValidBaseTypeInfo() into a single + // function. if (isValidBaseType(QTy)) - return getBaseTypeInfo(QTy); + return getValidBaseTypeInfo(QTy); const Type *Ty = Context.getCanonicalType(QTy).getTypePtr(); if (llvm::MDNode *N = MetadataCache[Ty]) @@ -394,7 +393,7 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) { if (BaseRD->isEmpty()) continue; llvm::MDNode *TypeNode = isValidBaseType(BaseQTy) - ? getBaseTypeInfo(BaseQTy) + ? getValidBaseTypeInfo(BaseQTy) : getTypeInfo(BaseQTy); if (!TypeNode) return nullptr; @@ -418,8 +417,9 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) { if (Field->isZeroSize(Context) || Field->isUnnamedBitfield()) continue; QualType FieldQTy = Field->getType(); - llvm::MDNode *TypeNode = isValidBaseType(FieldQTy) ? - getBaseTypeInfo(FieldQTy) : getTypeInfo(FieldQTy); + llvm::MDNode *TypeNode = isValidBaseType(FieldQTy) + ? getValidBaseTypeInfo(FieldQTy) + : getTypeInfo(FieldQTy); if (!TypeNode) return nullptr; @@ -456,9 +456,8 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) { return nullptr; } -llvm::MDNode *CodeGenTBAA::getBaseTypeInfo(QualType QTy) { - if (!isValidBaseType(QTy)) - return nullptr; +llvm::MDNode *CodeGenTBAA::getValidBaseTypeInfo(QualType QTy) { + assert(isValidBaseType(QTy) && "Must be a valid base type"); const Type *Ty = Context.getCanonicalType(QTy).getTypePtr(); @@ -477,6 +476,10 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfo(QualType QTy) { return TypeNode; } +llvm::MDNode *CodeGenTBAA::getBaseTypeInfo(QualType QTy) { + return isValidBaseType(QTy) ? getValidBaseTypeInfo(QTy) : nullptr; +} + llvm::MDNode *CodeGenTBAA::getAccessTagInfo(TBAAAccessInfo Info) { assert(!Info.isIncomplete() && "Access to an object of an incomplete type!"); diff --git a/clang/lib/CodeGen/CodeGenTBAA.h b/clang/lib/CodeGen/CodeGenTBAA.h index aa6da2731a4163c055de0b76768b5833516ca876..5d9ecec3ff0fe2c8880b701f3830276d09aaac03 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.h +++ b/clang/lib/CodeGen/CodeGenTBAA.h @@ -168,6 +168,10 @@ class CodeGenTBAA { /// used to describe accesses to objects of the given base type. llvm::MDNode *getBaseTypeInfoHelper(const Type *Ty); + /// getValidBaseTypeInfo - Return metadata that describes the given base + /// access type. The type must be suitable. + llvm::MDNode *getValidBaseTypeInfo(QualType QTy); + public: CodeGenTBAA(ASTContext &Ctx, CodeGenTypes &CGTypes, llvm::Module &M, const CodeGenOptions &CGO, const LangOptions &Features, @@ -190,8 +194,9 @@ public: /// the given type. llvm::MDNode *getTBAAStructInfo(QualType QTy); - /// getBaseTypeInfo - Get metadata that describes the given base access type. - /// Return null if the type is not suitable for use in TBAA access tags. + /// getBaseTypeInfo - Get metadata that describes the given base access + /// type. Return null if the type is not suitable for use in TBAA access + /// tags. llvm::MDNode *getBaseTypeInfo(QualType QTy); /// getAccessTagInfo - Get TBAA tag for a given memory access. diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp index c831777699f6270f50728ce91fcfdb80ed599481..f04db56db3357dd26364d4ce23fe0ecb6b7ccc1d 100644 --- a/clang/lib/CodeGen/Targets/X86.cpp +++ b/clang/lib/CodeGen/Targets/X86.cpp @@ -2106,8 +2106,11 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo, postMerge(Size, Lo, Hi); return; } + + bool IsInMemory = + Offset % getContext().getTypeAlign(i->getType().getCanonicalType()); // Note, skip this test for bit-fields, see below. - if (!BitField && Offset % getContext().getTypeAlign(i->getType())) { + if (!BitField && IsInMemory) { Lo = Memory; postMerge(Size, Lo, Hi); return; diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index e7335a61b10c533ecfafd5d3149a167a542518fb..0da92001e08c2701481b697ab3a30d7be6913bd7 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -4756,6 +4756,14 @@ Action *Driver::ConstructPhaseAction( if (Args.hasArg(options::OPT_extract_api)) return C.MakeAction(Input, types::TY_API_INFO); + // With 'fexperimental-modules-reduced-bmi', we don't want to run the + // precompile phase unless the user specified '--precompile'. In the case + // the '--precompile' flag is enabled, we will try to emit the reduced BMI + // as a by product in GenerateModuleInterfaceAction. + if (Args.hasArg(options::OPT_modules_reduced_bmi) && + !Args.getLastArg(options::OPT__precompile)) + return Input; + types::ID OutputTy = getPrecompiledType(Input->getType()); assert(OutputTy != types::TY_INVALID && "Cannot precompile this input type!"); @@ -5916,8 +5924,10 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, // If we're emitting a module output with the specified option // `-fmodule-output`. if (!AtTopLevel && isa(JA) && - JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput) + JA.getType() == types::TY_ModuleFile && SpecifiedModuleOutput) { + assert(!C.getArgs().hasArg(options::OPT_modules_reduced_bmi)); return GetModuleOutputPath(C, JA, BaseInput); + } // Output to a temporary file? if ((!AtTopLevel && !isSaveTempsEnabled() && diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp index 03450fc0f57b93e9acb16f1ece913f68d88f6a58..237092ed07e5dcf09dd90974d7a634d4cfecb507 100644 --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -796,7 +796,13 @@ ToolChain::getTargetSubDirPath(StringRef BaseDir) const { std::optional ToolChain::getRuntimePath() const { SmallString<128> P(D.ResourceDir); llvm::sys::path::append(P, "lib"); - return getTargetSubDirPath(P); + if (auto Ret = getTargetSubDirPath(P)) + return Ret; + // Darwin does not use per-target runtime directory. + if (Triple.isOSDarwin()) + return {}; + llvm::sys::path::append(P, Triple.str()); + return std::string(P); } std::optional ToolChain::getStdlibPath() const { diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp index 7a62b0f9aec419c2319ec39dfd853c3a059bd1d0..3f10888596a29a04d7dea3f1af0962be4c680b01 100644 --- a/clang/lib/Driver/ToolChains/AIX.cpp +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -17,6 +17,8 @@ #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Path.h" +#include + using AIX = clang::driver::toolchains::AIX; using namespace clang::driver; using namespace clang::driver::tools; diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index e122379e860e208b3008e4df160a1b16f7627fb6..4e6362a0f40632246ae10abc6512d703332164f0 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -670,6 +670,10 @@ void amdgpu::getAMDGPUTargetFeatures(const Driver &D, options::OPT_mno_wavefrontsize64, false)) Features.push_back("+wavefrontsize64"); + if (Args.hasFlag(options::OPT_mamdgpu_precise_memory_op, + options::OPT_mno_amdgpu_precise_memory_op, false)) + Features.push_back("+precise-memory"); + handleTargetFeaturesGroup(D, Triple, Args, Features, options::OPT_m_amdgpu_Features_Group); } diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index 3e6e29584df3ac719a340293419fb2c0a11e6fb5..2cd2b35ee51bc68a7fccda3e76e7f8286a811e2b 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -402,9 +402,6 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, if (Args.hasArg(options::OPT_ffixed_x28)) Features.push_back("+reserve-x28"); - if (Args.hasArg(options::OPT_ffixed_x30)) - Features.push_back("+reserve-x30"); - if (Args.hasArg(options::OPT_fcall_saved_x8)) Features.push_back("+call-saved-x8"); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 766a9b91e3c0ada294a3dc4a33f3fa4aeeeca201..6d52eced10429693f2d02e1057d763e3f39db093 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4045,6 +4045,24 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D, // module fragment. CmdArgs.push_back("-fskip-odr-check-in-gmf"); + if (Args.hasArg(options::OPT_modules_reduced_bmi) && + (Input.getType() == driver::types::TY_CXXModule || + Input.getType() == driver::types::TY_PP_CXXModule)) { + CmdArgs.push_back("-fexperimental-modules-reduced-bmi"); + + if (Args.hasArg(options::OPT_fmodule_output_EQ)) + Args.AddLastArg(CmdArgs, options::OPT_fmodule_output_EQ); + else + CmdArgs.push_back(Args.MakeArgString( + "-fmodule-output=" + + getCXX20NamedModuleOutputPath(Args, Input.getBaseInput()))); + } + + // Noop if we see '-fexperimental-modules-reduced-bmi' with other translation + // units than module units. This is more user friendly to allow end uers to + // enable this feature without asking for help from build systems. + Args.ClaimAllArgs(options::OPT_modules_reduced_bmi); + // We need to include the case the input file is a module file here. // Since the default compilation model for C++ module interface unit will // create temporary module file and compile the temporary module file diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 62a53b85ce098b89c83a54701e5c4e6d0bd63bd2..f10aa4dfaa9ddd9a9dde4679e8990240d63a1d44 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -114,6 +114,7 @@ static bool useFramePointerForTargetByDefault(const llvm::opt::ArgList &Args, case llvm::Triple::csky: case llvm::Triple::loongarch32: case llvm::Triple::loongarch64: + case llvm::Triple::m68k: return !clang::driver::tools::areOptimizationsEnabled(Args); default: break; diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 5f0b516e1a1a08f0d40bec2c8f66ba42a277c1b2..6634e6d818b33e5e9c93dce48a346b0877d8faa8 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -990,7 +990,10 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, } for (Arg *A : Args) { - DAL->append(A); + // Make sure flags are not duplicated. + if (!llvm::is_contained(*DAL, A)) { + DAL->append(A); + } } if (!BoundArch.empty()) { diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 2c83f70eb7887ebd67b901d608e6974feee83ebb..b46bac24503ce1c64cfa0fa0c51a07164a986600 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -264,7 +264,7 @@ static void addVSDefines(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back(Args.MakeArgString("-D_MSC_FULL_VER=" + Twine(ver))); CmdArgs.push_back(Args.MakeArgString("-D_WIN32")); - llvm::Triple triple = TC.getTriple(); + const llvm::Triple &triple = TC.getTriple(); if (triple.isAArch64()) { CmdArgs.push_back("-D_M_ARM64=1"); } else if (triple.isX86() && triple.isArch32Bit()) { @@ -589,7 +589,7 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args, if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath && ApproxFunc && !SignedZeros && - (FPContract == "fast" || FPContract == "")) { + (FPContract == "fast" || FPContract.empty())) { CmdArgs.push_back("-ffast-math"); return; } @@ -679,7 +679,10 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(TripleStr)); if (isa(JA)) { - CmdArgs.push_back("-E"); + CmdArgs.push_back("-E"); + if (Args.getLastArg(options::OPT_dM)) { + CmdArgs.push_back("-dM"); + } } else if (isa(JA) || isa(JA)) { if (JA.getType() == types::TY_Nothing) { CmdArgs.push_back("-fsyntax-only"); @@ -783,6 +786,10 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, } } + // Pass the path to compiler resource files. + CmdArgs.push_back("-resource-dir"); + CmdArgs.push_back(D.ResourceDir.c_str()); + // Offloading related options addOffloadOptions(C, Inputs, JA, Args, CmdArgs); diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 41e99b0c95ea81d4cebd738a012efd81c5409b85..dedbfac6cb25d26b67587d4ed273597366f1296d 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -672,41 +672,12 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, } } - // Facebook T92898286 - if (Args.hasArg(options::OPT_post_link_optimize)) - CmdArgs.push_back("-q"); - // End Facebook T92898286 - Args.AddAllArgs(CmdArgs, options::OPT_T); const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::AtFileCurCP(), Exec, CmdArgs, Inputs, Output)); - // Facebook T92898286 - if (!Args.hasArg(options::OPT_post_link_optimize) || !Output.isFilename()) - return; - - const char *MvExec = Args.MakeArgString(ToolChain.GetProgramPath("mv")); - ArgStringList MoveCmdArgs; - MoveCmdArgs.push_back(Output.getFilename()); - const char *PreBoltBin = - Args.MakeArgString(Twine(Output.getFilename()) + ".pre-bolt"); - MoveCmdArgs.push_back(PreBoltBin); - C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::None(), - MvExec, MoveCmdArgs, std::nullopt)); - - ArgStringList BoltCmdArgs; - const char *BoltExec = - Args.MakeArgString(ToolChain.GetProgramPath("llvm-bolt")); - BoltCmdArgs.push_back(PreBoltBin); - BoltCmdArgs.push_back("-reorder-blocks=reverse"); - BoltCmdArgs.push_back("-update-debug-sections"); - BoltCmdArgs.push_back("-o"); - BoltCmdArgs.push_back(Output.getFilename()); - C.addCommand(std::make_unique(JA, *this, ResponseFileSupport::None(), - BoltExec, BoltCmdArgs, std::nullopt)); - // End Facebook T92898286 } void tools::gnutools::Assembler::ConstructJob(Compilation &C, diff --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp index 6c2f23e57bce05f0a112c3db6be3cbcfe896b1db..fb65881061effc3abc4f88028b48f889f8bab1ae 100644 --- a/clang/lib/Driver/ToolChains/Linux.cpp +++ b/clang/lib/Driver/ToolChains/Linux.cpp @@ -244,8 +244,9 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // Android ARM uses max-page-size=4096 to reduce VMA usage. ExtraOpts.push_back("-z"); ExtraOpts.push_back("max-page-size=4096"); - } else if (Triple.isAArch64()) { + } else if (Triple.isAArch64() || Triple.getArch() == llvm::Triple::x86_64) { // Android AArch64 uses max-page-size=16384 to support 4k/16k page sizes. + // Android emulates a 16k page size for app testing on x86_64 machines. ExtraOpts.push_back("-z"); ExtraOpts.push_back("max-page-size=16384"); } diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp index 700bce35c86839a516079441676cd21e5ff099c2..ad0e2c3c620c32b0fa4a88dd652670cae0f90a9a 100644 --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/clang/lib/Format/ContinuationIndenter.cpp @@ -684,7 +684,13 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun, // arguments to function calls. We do this by ensuring that either all // arguments (including any lambdas) go on the same line as the function // call, or we break before the first argument. - auto PrevNonComment = Current.getPreviousNonComment(); + const auto *Prev = Current.Previous; + if (!Prev) + return false; + // For example, `/*Newline=*/false`. + if (Prev->is(TT_BlockComment) && Current.SpacesRequiredBefore == 0) + return false; + const auto *PrevNonComment = Current.getPreviousNonComment(); if (!PrevNonComment || PrevNonComment->isNot(tok::l_paren)) return false; if (Current.isOneOf(tok::comment, tok::l_paren, TT_LambdaLSquare)) diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 89e6c19b0af45c10e975c36f50fbbc3ca2ad85ba..ccb2c9190e2eff0bdb551c3ecb95dde3c987639d 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -3891,7 +3891,11 @@ static FormatStyle::LanguageKind getLanguageByFileName(StringRef FileName) { FileName.ends_with_insensitive(".protodevel")) { return FormatStyle::LK_Proto; } - if (FileName.ends_with_insensitive(".textpb") || + // txtpb is the canonical extension, and textproto is the legacy canonical + // extension + // https://protobuf.dev/reference/protobuf/textformat-spec/#text-format-files + if (FileName.ends_with_insensitive(".txtpb") || + FileName.ends_with_insensitive(".textpb") || FileName.ends_with_insensitive(".pb.txt") || FileName.ends_with_insensitive(".textproto") || FileName.ends_with_insensitive(".asciipb")) { diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 48b6a9092a8c094531dd170cd7fba93b3a35adf7..f651e6228c206da58363e5d7482e108001cba788 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -35,6 +35,8 @@ namespace format { TYPE(BinaryOperator) \ TYPE(BitFieldColon) \ TYPE(BlockComment) \ + /* l_brace of a block that is not the body of a (e.g. loop) statement. */ \ + TYPE(BlockLBrace) \ TYPE(BracedListLBrace) \ /* The colon at the end of a case label. */ \ TYPE(CaseLabelColon) \ diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index 036f7e6a4efc1ea9f12689b6accaec700d527595..f430d3764babeb270fb937ab4119ec7827738510 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -404,7 +404,7 @@ bool FormatTokenLexer::tryMergeNullishCoalescingEqual() { return false; auto &NullishCoalescing = *(Tokens.end() - 2); auto &Equal = *(Tokens.end() - 1); - if (NullishCoalescing->getType() != TT_NullCoalescingOperator || + if (NullishCoalescing->isNot(TT_NullCoalescingOperator) || Equal->isNot(tok::equal)) { return false; } diff --git a/clang/lib/Format/FormatTokenSource.h b/clang/lib/Format/FormatTokenSource.h index cce19f527a9236df8dc8df12cdcfbe09cf87bd6e..2b93f302d360340dd0aa6862b32fc3d6665aa813 100644 --- a/clang/lib/Format/FormatTokenSource.h +++ b/clang/lib/Format/FormatTokenSource.h @@ -72,6 +72,15 @@ public: // getNextToken() -> a1 // getNextToken() -> a2 virtual FormatToken *insertTokens(ArrayRef Tokens) = 0; + + [[nodiscard]] FormatToken *getNextNonComment() { + FormatToken *Tok; + do { + Tok = getNextToken(); + assert(Tok); + } while (Tok->is(tok::comment)); + return Tok; + } }; class IndexedTokenSource : public FormatTokenSource { diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 3e9988d5094554bfcdbb1bf6e55a1f98d38273c5..628f70417866c38505cf01128d26ffbfa345b22b 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -825,8 +825,7 @@ private: Parent->overwriteFixedType(TT_BinaryOperator); } // An arrow after an ObjC method expression is not a lambda arrow. - if (CurrentToken->getType() == TT_ObjCMethodExpr && - CurrentToken->Next && + if (CurrentToken->is(TT_ObjCMethodExpr) && CurrentToken->Next && CurrentToken->Next->is(TT_TrailingReturnArrow)) { CurrentToken->Next->overwriteFixedType(TT_Unknown); } @@ -1563,7 +1562,7 @@ private: case tok::l_brace: if (Style.Language == FormatStyle::LK_TextProto) { FormatToken *Previous = Tok->getPreviousNonComment(); - if (Previous && Previous->getType() != TT_DictLiteral) + if (Previous && Previous->isNot(TT_DictLiteral)) Previous->setType(TT_SelectorName); } Scopes.push_back(getScopeType(*Tok)); @@ -1583,7 +1582,7 @@ private: Tok->Previous->isOneOf(TT_SelectorName, TT_DictLiteral))) { Tok->setType(TT_DictLiteral); FormatToken *Previous = Tok->getPreviousNonComment(); - if (Previous && Previous->getType() != TT_DictLiteral) + if (Previous && Previous->isNot(TT_DictLiteral)) Previous->setType(TT_SelectorName); } if (Style.isTableGen()) @@ -2355,7 +2354,8 @@ private: // Line.MightBeFunctionDecl can only be true after the parentheses of a // function declaration have been found. In this case, 'Current' is a // trailing token of this declaration and thus cannot be a name. - if (Current.is(Keywords.kw_instanceof)) { + if ((Style.isJavaScript() || Style.Language == FormatStyle::LK_Java) && + Current.is(Keywords.kw_instanceof)) { Current.setType(TT_BinaryOperator); } else if (isStartOfName(Current) && (!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) { @@ -4754,8 +4754,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, // Objective-C dictionary literal -> no space before closing brace. return false; } - if (Right.getType() == TT_TrailingAnnotation && - Right.isOneOf(tok::amp, tok::ampamp) && + if (Right.is(TT_TrailingAnnotation) && Right.isOneOf(tok::amp, tok::ampamp) && Left.isOneOf(tok::kw_const, tok::kw_volatile) && (!Right.Next || Right.Next->is(tok::semi))) { // Match const and volatile ref-qualifiers without any additional diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index fb31980ab9f491bedddcfb93de529af20e7145f1..4ae54e56331bdcfcfb8c606618de71a0762cb652 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -796,8 +796,12 @@ private: } } - if (const auto *LastNonComment = Line.getLastNonComment(); - LastNonComment && LastNonComment->is(tok::l_brace)) { + if (Line.endsWith(tok::l_brace)) { + if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never && + Line.First->is(TT_BlockLBrace)) { + return 0; + } + if (IsSplitBlock && Line.First == Line.Last && I > AnnotatedLines.begin() && (I[-1]->endsWith(tok::kw_else) || IsCtrlStmt(*I[-1]))) { diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 55c627d87f08b5d2296f73e6371098f88f60d9d2..603268f771ac5226165ba33e30c0c97918c11c4a 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -365,11 +365,11 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, nextToken(); continue; } - tok::TokenKind kind = FormatTok->Tok.getKind(); - if (FormatTok->getType() == TT_MacroBlockBegin) - kind = tok::l_brace; - else if (FormatTok->getType() == TT_MacroBlockEnd) - kind = tok::r_brace; + tok::TokenKind Kind = FormatTok->Tok.getKind(); + if (FormatTok->is(TT_MacroBlockBegin)) + Kind = tok::l_brace; + else if (FormatTok->is(TT_MacroBlockEnd)) + Kind = tok::r_brace; auto ParseDefault = [this, OpeningBrace, IfKind, &IfLBrace, &HasDoWhile, &HasLabel, &StatementCount] { @@ -380,7 +380,7 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, assert(StatementCount > 0 && "StatementCount overflow!"); }; - switch (kind) { + switch (Kind) { case tok::comment: nextToken(); addUnwrappedLine(); @@ -395,9 +395,10 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, ParseDefault(); continue; } - if (!InRequiresExpression && FormatTok->isNot(TT_MacroBlockBegin) && - tryToParseBracedList()) { - continue; + if (!InRequiresExpression && FormatTok->isNot(TT_MacroBlockBegin)) { + if (tryToParseBracedList()) + continue; + FormatTok->setFinalizedType(TT_BlockLBrace); } parseBlock(); ++StatementCount; @@ -427,11 +428,7 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, break; case tok::kw_default: { unsigned StoredPosition = Tokens->getPosition(); - FormatToken *Next; - do { - Next = Tokens->getNextToken(); - assert(Next); - } while (Next->is(tok::comment)); + auto *Next = Tokens->getNextNonComment(); FormatTok = Tokens->setPosition(StoredPosition); if (Next->isNot(tok::colon)) { // default not followed by ':' is not a case label; treat it like @@ -497,10 +494,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { assert(Tok->is(tok::l_brace)); do { - FormatToken *NextTok; - do { - NextTok = Tokens->getNextToken(); - } while (NextTok->is(tok::comment)); + auto *NextTok = Tokens->getNextNonComment(); if (!Line->InMacroBody && !Style.isTableGen()) { // Skip PPDirective lines and comments. @@ -545,16 +539,6 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { if (Style.Language == FormatStyle::LK_Proto) { ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square); } else { - // Skip NextTok over preprocessor lines, otherwise we may not - // properly diagnose the block as a braced intializer - // if the comma separator appears after the pp directive. - while (NextTok->is(tok::hash)) { - ScopedMacroState MacroState(*Line, Tokens, NextTok); - do { - NextTok = Tokens->getNextToken(); - } while (NextTok->isNot(tok::eof)); - } - // Using OriginalColumn to distinguish between ObjC methods and // binary operators is a bit hacky. bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) && @@ -613,6 +597,16 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { NextTok = Tokens->getNextToken(); ProbablyBracedList = NextTok->isNot(tok::l_square); } + + // Cpp macro definition body that is a nonempty braced list or block: + if (IsCpp && Line->InMacroBody && PrevTok != FormatTok && + !FormatTok->Previous && NextTok->is(tok::eof) && + // A statement can end with only `;` (simple statement), a block + // closing brace (compound statement), or `:` (label statement). + // If PrevTok is a block opening brace, Tok ends an empty block. + !PrevTok->isOneOf(tok::semi, BK_Block, tok::colon)) { + ProbablyBracedList = true; + } } if (ProbablyBracedList) { Tok->setBlockKind(BK_BracedInit); @@ -3280,8 +3274,8 @@ void UnwrappedLineParser::parseSwitch() { } // Operators that can follow a C variable. -static bool isCOperatorFollowingVar(tok::TokenKind kind) { - switch (kind) { +static bool isCOperatorFollowingVar(tok::TokenKind Kind) { + switch (Kind) { case tok::ampamp: case tok::ampequal: case tok::arrow: @@ -4709,14 +4703,13 @@ void UnwrappedLineParser::readToken(int LevelDifference) { do { FormatTok = Tokens->getNextToken(); assert(FormatTok); - while (FormatTok->getType() == TT_ConflictStart || - FormatTok->getType() == TT_ConflictEnd || - FormatTok->getType() == TT_ConflictAlternative) { - if (FormatTok->getType() == TT_ConflictStart) + while (FormatTok->isOneOf(TT_ConflictStart, TT_ConflictEnd, + TT_ConflictAlternative)) { + if (FormatTok->is(TT_ConflictStart)) conditionalCompilationStart(/*Unreachable=*/false); - else if (FormatTok->getType() == TT_ConflictAlternative) + else if (FormatTok->is(TT_ConflictAlternative)) conditionalCompilationAlternative(); - else if (FormatTok->getType() == TT_ConflictEnd) + else if (FormatTok->is(TT_ConflictEnd)) conditionalCompilationEnd(); FormatTok = Tokens->getNextToken(); FormatTok->MustBreakBefore = true; diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index d06c42d5f4c5c5bf93db1c6c734da710a2450086..4f822807dd987dc8ceeb43e8a550c4c135f50b86 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -473,8 +473,7 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, Style.ReferenceAlignment != FormatStyle::RAS_Right && Style.ReferenceAlignment != FormatStyle::RAS_Pointer; for (int Previous = i - 1; - Previous >= 0 && - Changes[Previous].Tok->getType() == TT_PointerOrReference; + Previous >= 0 && Changes[Previous].Tok->is(TT_PointerOrReference); --Previous) { assert(Changes[Previous].Tok->isPointerOrReference()); if (Changes[Previous].Tok->isNot(tok::star)) { diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 7ee6ccf396a891bbd47ab25996ced61bd41314dd..04eb104132671357f84a8d74b070636bff90087e 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -69,10 +69,7 @@ void InitOnlyAction::ExecuteAction() { // Basically PreprocessOnlyAction::ExecuteAction. void ReadPCHAndPreprocessAction::ExecuteAction() { - CompilerInstance &CI = getCompilerInstance(); - AdjustCI(CI); - - Preprocessor &PP = CI.getPreprocessor(); + Preprocessor &PP = getCompilerInstance().getPreprocessor(); // Ignore unknown pragmas. PP.IgnorePragmas(); @@ -284,6 +281,13 @@ GenerateModuleInterfaceAction::CreateASTConsumer(CompilerInstance &CI, if (Consumers.empty()) return nullptr; + if (CI.getFrontendOpts().GenReducedBMI && + !CI.getFrontendOpts().ModuleOutputPath.empty()) { + Consumers.push_back(std::make_unique( + CI.getPreprocessor(), CI.getModuleCache(), + CI.getFrontendOpts().ModuleOutputPath)); + } + return std::make_unique(std::move(Consumers)); } @@ -453,7 +457,7 @@ private: return "BuildingBuiltinDumpStructCall"; case CodeSynthesisContext::BuildingDeductionGuides: return "BuildingDeductionGuides"; - case Sema::CodeSynthesisContext::TypeAliasTemplateInstantiation: + case CodeSynthesisContext::TypeAliasTemplateInstantiation: return "TypeAliasTemplateInstantiation"; } return ""; @@ -1193,8 +1197,6 @@ void PrintDependencyDirectivesSourceMinimizerAction::ExecuteAction() { void GetDependenciesByModuleNameAction::ExecuteAction() { CompilerInstance &CI = getCompilerInstance(); - AdjustCI(CI); - Preprocessor &PP = CI.getPreprocessor(); SourceManager &SM = PP.getSourceManager(); FileID MainFileID = SM.getMainFileID(); diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 48ad92063bd46165c5ed481c38708fe4a6733090..4f44c3b7b89d4d860ad3815fb77c23557fcb1b37 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -720,10 +720,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, if (LangOpts.CPlusPlus20) { Builder.defineMacro("__cpp_aggregate_paren_init", "201902L"); - // P0848 is implemented, but we're still waiting for other concepts - // issues to be addressed before bumping __cpp_concepts up to 202002L. - // Refer to the discussion of this at https://reviews.llvm.org/D128619. - Builder.defineMacro("__cpp_concepts", "201907L"); + Builder.defineMacro("__cpp_concepts", "202002"); Builder.defineMacro("__cpp_conditional_explicit", "201806L"); Builder.defineMacro("__cpp_consteval", "202211L"); Builder.defineMacro("__cpp_constexpr_dynamic_alloc", "201907L"); @@ -750,6 +747,9 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, Builder.defineMacro("__cpp_named_character_escapes", "202207L"); Builder.defineMacro("__cpp_placeholder_variables", "202306L"); + // C++26 features supported in earlier language modes. + Builder.defineMacro("__cpp_deleted_function", "202403L"); + if (LangOpts.Char8) Builder.defineMacro("__cpp_char8_t", "202207L"); Builder.defineMacro("__cpp_impl_destroying_delete", "201806L"); diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp index 1f40db785981d6cb633d48883d8a7010d0a7ea4e..6ae955a2380b74c58f72afdde91eeec658c96d8e 100644 --- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -592,7 +592,7 @@ namespace { } bool ImplementationIsNonLazy(const ObjCImplDecl *OD) const { - IdentifierInfo* II = &Context->Idents.get("load"); + const IdentifierInfo *II = &Context->Idents.get("load"); Selector LoadSel = Context->Selectors.getSelector(0, &II); return OD->getClassMethod(LoadSel) != nullptr; } diff --git a/clang/lib/Headers/CMakeLists.txt b/clang/lib/Headers/CMakeLists.txt index 97104ccd8db59c5a7db747e1bb1375cc92d177d3..e6ae4e19e81db9c13b2aeb040714c747c9953e56 100644 --- a/clang/lib/Headers/CMakeLists.txt +++ b/clang/lib/Headers/CMakeLists.txt @@ -437,14 +437,14 @@ foreach( f ${generated_files} ) endforeach( f ) function(add_header_target target_name file_list) - add_custom_target(${target_name} DEPENDS ${file_list}) + add_library(${target_name} INTERFACE ${file_list}) set_target_properties(${target_name} PROPERTIES FOLDER "Misc" RUNTIME_OUTPUT_DIRECTORY "${output_dir}") endfunction() # The catch-all clang-resource-headers target -add_custom_target("clang-resource-headers" ALL DEPENDS ${out_files}) +add_library(clang-resource-headers INTERFACE ${out_files}) set_target_properties("clang-resource-headers" PROPERTIES FOLDER "Misc" RUNTIME_OUTPUT_DIRECTORY "${output_dir}") @@ -501,6 +501,10 @@ add_header_target("windows-resource-headers" ${windows_only_files}) add_header_target("utility-resource-headers" ${utility_files}) get_clang_resource_dir(header_install_dir SUBDIR include) +target_include_directories(clang-resource-headers INTERFACE + $ + $) +set_property(GLOBAL APPEND PROPERTY CLANG_EXPORTS clang-resource-headers) ############################################################# # Install rules for the catch-all clang-resource-headers target diff --git a/clang/lib/Headers/intrin.h b/clang/lib/Headers/intrin.h index fd27955fbe002d8069a55d04de8f933edd7b2d75..7eb6dceaabfaeb611123945343d43d15bfece664 100644 --- a/clang/lib/Headers/intrin.h +++ b/clang/lib/Headers/intrin.h @@ -18,7 +18,7 @@ #include /* First include the standard intrinsics. */ -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) #include #endif @@ -26,7 +26,7 @@ #include #endif -#if defined(__aarch64__) +#if defined(__aarch64__) || defined(__arm64ec__) #include #endif @@ -166,7 +166,7 @@ unsigned __int32 xbegin(void); void _xend(void); /* These additional intrinsics are turned on in x64/amd64/x86_64 mode. */ -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__arm64ec__) void __addgsbyte(unsigned long, unsigned char); void __addgsdword(unsigned long, unsigned long); void __addgsqword(unsigned long, unsigned __int64); @@ -236,7 +236,8 @@ __int64 _mul128(__int64, __int64, __int64 *); /*----------------------------------------------------------------------------*\ |* movs, stos \*----------------------------------------------------------------------------*/ -#if defined(__i386__) || defined(__x86_64__) + +#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) static __inline__ void __DEFAULT_FN_ATTRS __movsb(unsigned char *__dst, unsigned char const *__src, size_t __n) { @@ -305,7 +306,7 @@ static __inline__ void __DEFAULT_FN_ATTRS __stosw(unsigned short *__dst, : "memory"); } #endif -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__arm64ec__) static __inline__ void __DEFAULT_FN_ATTRS __movsq( unsigned long long *__dst, unsigned long long const *__src, size_t __n) { __asm__ __volatile__("rep movsq" @@ -324,7 +325,7 @@ static __inline__ void __DEFAULT_FN_ATTRS __stosq(unsigned __int64 *__dst, /*----------------------------------------------------------------------------*\ |* Misc \*----------------------------------------------------------------------------*/ -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) static __inline__ void __DEFAULT_FN_ATTRS __halt(void) { __asm__ volatile("hlt"); } @@ -339,7 +340,7 @@ static __inline__ void __DEFAULT_FN_ATTRS __nop(void) { /*----------------------------------------------------------------------------*\ |* MS AArch64 specific \*----------------------------------------------------------------------------*/ -#if defined(__aarch64__) +#if defined(__aarch64__) || defined(__arm64ec__) unsigned __int64 __getReg(int); long _InterlockedAdd(long volatile *Addend, long Value); __int64 _InterlockedAdd64(__int64 volatile *Addend, __int64 Value); @@ -383,7 +384,7 @@ void __cdecl __prefetch(void *); /*----------------------------------------------------------------------------*\ |* Privileged intrinsics \*----------------------------------------------------------------------------*/ -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) static __inline__ unsigned __int64 __DEFAULT_FN_ATTRS __readmsr(unsigned long __register) { // Loads the contents of a 64-bit model specific register (MSR) specified in @@ -397,7 +398,6 @@ __readmsr(unsigned long __register) { __asm__ ("rdmsr" : "=d"(__edx), "=a"(__eax) : "c"(__register)); return (((unsigned __int64)__edx) << 32) | (unsigned __int64)__eax; } -#endif static __inline__ unsigned __LPTRINT_TYPE__ __DEFAULT_FN_ATTRS __readcr3(void) { unsigned __LPTRINT_TYPE__ __cr3_val; @@ -413,6 +413,7 @@ static __inline__ void __DEFAULT_FN_ATTRS __writecr3(unsigned __INTPTR_TYPE__ __cr3_val) { __asm__ ("mov {%0, %%cr3|cr3, %0}" : : "r"(__cr3_val) : "memory"); } +#endif #ifdef __cplusplus } diff --git a/clang/lib/Headers/intrin0.h b/clang/lib/Headers/intrin0.h index 31f362ec84d5c571113c34f1ac2932d1af0ba699..866c8896617d22aea66ef301f68a623318bddc6e 100644 --- a/clang/lib/Headers/intrin0.h +++ b/clang/lib/Headers/intrin0.h @@ -15,7 +15,7 @@ #ifndef __INTRIN0_H #define __INTRIN0_H -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__arm64ec__) #include #endif @@ -27,7 +27,7 @@ unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask); unsigned char _BitScanReverse(unsigned long *_Index, unsigned long _Mask); void _ReadWriteBarrier(void); -#if defined(__aarch64__) +#if defined(__aarch64__) || defined(__arm64ec__) unsigned int _CountLeadingZeros(unsigned long); unsigned int _CountLeadingZeros64(unsigned _int64); unsigned char _InterlockedCompareExchange128_acq(__int64 volatile *_Destination, @@ -44,7 +44,7 @@ unsigned char _InterlockedCompareExchange128_rel(__int64 volatile *_Destination, __int64 *_ComparandResult); #endif -#ifdef __x86_64__ +#ifdef __x86_64__ && !defined(__arm64ec__) unsigned __int64 _umul128(unsigned __int64, unsigned __int64, unsigned __int64 *); unsigned __int64 __shiftleft128(unsigned __int64 _LowPart, @@ -55,7 +55,7 @@ unsigned __int64 __shiftright128(unsigned __int64 _LowPart, unsigned char _Shift); #endif -#if defined(__x86_64__) || defined(__i386__) +#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) void _mm_pause(void); #endif @@ -83,7 +83,7 @@ __int64 _InterlockedXor64(__int64 volatile *_Value, __int64 _Mask); __int64 _InterlockedAnd64(__int64 volatile *_Value, __int64 _Mask); #endif -#if defined(__arm__) || defined(__aarch64__) +#if defined(__arm__) || defined(__aarch64__) || defined(__arm64ec__) /*----------------------------------------------------------------------------*\ |* Interlocked Exchange Add \*----------------------------------------------------------------------------*/ diff --git a/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp index 1fa988f93bdd5cba0bb8961fd15a4c42e50afcad..cc252d51e3b67711ac6449949f4880586b2a6b25 100644 --- a/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp +++ b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp @@ -81,8 +81,9 @@ const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, return DB; case FileType::Invalid: case FileType::All: - llvm_unreachable("Unexpected file type for diagnostics."); + break; } + llvm_unreachable("Unexpected file type for diagnostics."); } const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, diff --git a/clang/lib/InstallAPI/DylibVerifier.cpp b/clang/lib/InstallAPI/DylibVerifier.cpp index 2387ee0e78ad56ab4969b1f2618b69837e4653ff..84d9b5892e88da14471d78a4ada28cd4f2a86012 100644 --- a/clang/lib/InstallAPI/DylibVerifier.cpp +++ b/clang/lib/InstallAPI/DylibVerifier.cpp @@ -176,7 +176,13 @@ void DylibVerifier::addSymbol(const Record *R, SymbolContext &SymCtx, bool DylibVerifier::shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx, const Record *DR) { - return SymCtx.FA->Avail.isObsoleted(); + if (!SymCtx.FA->Avail.isObsoleted()) + return false; + + if (Zippered) + DeferredZipperedSymbols[SymCtx.SymbolName].emplace_back(ZipperedDeclSource{ + SymCtx.FA, &Ctx.Diag->getSourceManager(), Ctx.Target}); + return true; } bool DylibVerifier::shouldIgnoreReexport(const Record *R, @@ -195,6 +201,28 @@ bool DylibVerifier::shouldIgnoreReexport(const Record *R, return false; } +bool DylibVerifier::shouldIgnoreInternalZipperedSymbol( + const Record *R, const SymbolContext &SymCtx) const { + if (!Zippered) + return false; + + return Exports->findSymbol(SymCtx.Kind, SymCtx.SymbolName, + SymCtx.ObjCIFKind) != nullptr; +} + +bool DylibVerifier::shouldIgnoreZipperedAvailability(const Record *R, + SymbolContext &SymCtx) { + if (!(Zippered && SymCtx.FA->Avail.isUnavailable())) + return false; + + // Collect source location incase there is an exported symbol to diagnose + // during `verifyRemainingSymbols`. + DeferredZipperedSymbols[SymCtx.SymbolName].emplace_back( + ZipperedDeclSource{SymCtx.FA, SourceManagers.back().get(), Ctx.Target}); + + return true; +} + bool DylibVerifier::compareObjCInterfaceSymbols(const Record *R, SymbolContext &SymCtx, const ObjCInterfaceRecord *DR) { @@ -214,16 +242,16 @@ bool DylibVerifier::compareObjCInterfaceSymbols(const Record *R, StringRef SymName, bool PrintAsWarning = false) { if (SymLinkage == RecordLinkage::Unknown) Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - PrintAsWarning ? diag::warn_library_missing_symbol - : diag::err_library_missing_symbol) + Ctx.Diag->Report(SymCtx.FA->Loc, PrintAsWarning + ? diag::warn_library_missing_symbol + : diag::err_library_missing_symbol) << SymName; }); else Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - PrintAsWarning ? diag::warn_library_hidden_symbol - : diag::err_library_hidden_symbol) + Ctx.Diag->Report(SymCtx.FA->Loc, PrintAsWarning + ? diag::warn_library_hidden_symbol + : diag::err_library_hidden_symbol) << SymName; }); }; @@ -270,16 +298,14 @@ DylibVerifier::Result DylibVerifier::compareVisibility(const Record *R, if (R->isExported()) { if (!DR) { Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::err_library_missing_symbol) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_library_missing_symbol) << getAnnotatedName(R, SymCtx); }); return Result::Invalid; } if (DR->isInternal()) { Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::err_library_hidden_symbol) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_library_hidden_symbol) << getAnnotatedName(R, SymCtx); }); return Result::Invalid; @@ -296,6 +322,9 @@ DylibVerifier::Result DylibVerifier::compareVisibility(const Record *R, if (shouldIgnorePrivateExternAttr(SymCtx.FA->D)) return Result::Ignore; + if (shouldIgnoreInternalZipperedSymbol(R, SymCtx)) + return Result::Ignore; + unsigned ID; Result Outcome; if (Mode == VerificationMode::ErrorsAndWarnings) { @@ -306,8 +335,7 @@ DylibVerifier::Result DylibVerifier::compareVisibility(const Record *R, Outcome = Result::Invalid; } Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), ID) - << getAnnotatedName(R, SymCtx); + Ctx.Diag->Report(SymCtx.FA->Loc, ID) << getAnnotatedName(R, SymCtx); }); return Outcome; } @@ -324,20 +352,21 @@ DylibVerifier::Result DylibVerifier::compareAvailability(const Record *R, if (!SymCtx.FA->Avail.isUnavailable()) return Result::Valid; + if (shouldIgnoreZipperedAvailability(R, SymCtx)) + return Result::Ignore; + const bool IsDeclAvailable = SymCtx.FA->Avail.isUnavailable(); switch (Mode) { case VerificationMode::ErrorsAndWarnings: Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::warn_header_availability_mismatch) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::warn_header_availability_mismatch) << getAnnotatedName(R, SymCtx) << IsDeclAvailable << IsDeclAvailable; }); return Result::Ignore; case VerificationMode::Pedantic: Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::err_header_availability_mismatch) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_header_availability_mismatch) << getAnnotatedName(R, SymCtx) << IsDeclAvailable << IsDeclAvailable; }); return Result::Invalid; @@ -353,16 +382,14 @@ bool DylibVerifier::compareSymbolFlags(const Record *R, SymbolContext &SymCtx, const Record *DR) { if (DR->isThreadLocalValue() && !R->isThreadLocalValue()) { Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::err_dylib_symbol_flags_mismatch) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_dylib_symbol_flags_mismatch) << getAnnotatedName(DR, SymCtx) << DR->isThreadLocalValue(); }); return false; } if (!DR->isThreadLocalValue() && R->isThreadLocalValue()) { Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::err_header_symbol_flags_mismatch) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_header_symbol_flags_mismatch) << getAnnotatedName(R, SymCtx) << R->isThreadLocalValue(); }); return false; @@ -370,16 +397,14 @@ bool DylibVerifier::compareSymbolFlags(const Record *R, SymbolContext &SymCtx, if (DR->isWeakDefined() && !R->isWeakDefined()) { Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::err_dylib_symbol_flags_mismatch) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_dylib_symbol_flags_mismatch) << getAnnotatedName(DR, SymCtx) << R->isWeakDefined(); }); return false; } if (!DR->isWeakDefined() && R->isWeakDefined()) { Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::err_header_symbol_flags_mismatch) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_header_symbol_flags_mismatch) << getAnnotatedName(R, SymCtx) << R->isWeakDefined(); }); return false; @@ -487,6 +512,14 @@ void DylibVerifier::setTarget(const Target &T) { assignSlice(T); } +void DylibVerifier::setSourceManager( + IntrusiveRefCntPtr SourceMgr) { + if (!Ctx.Diag) + return; + SourceManagers.push_back(std::move(SourceMgr)); + Ctx.Diag->setSourceManager(SourceManagers.back().get()); +} + DylibVerifier::Result DylibVerifier::verify(ObjCIVarRecord *R, const FrontendAttrs *FA, const StringRef SuperClass) { @@ -589,13 +622,58 @@ void DylibVerifier::visitSymbolInDylib(const Record &R, SymbolContext &SymCtx) { } } + const bool IsLinkerSymbol = SymbolName.starts_with("$ld$"); + + if (R.isVerified()) { + // Check for unavailable symbols. + // This should only occur in the zippered case where we ignored + // availability until all headers have been parsed. + auto It = DeferredZipperedSymbols.find(SymCtx.SymbolName); + if (It == DeferredZipperedSymbols.end()) { + updateState(Result::Valid); + return; + } + + ZipperedDeclSources Locs; + for (const ZipperedDeclSource &ZSource : It->second) { + if (ZSource.FA->Avail.isObsoleted()) { + updateState(Result::Ignore); + return; + } + if (ZSource.T.Arch != Ctx.Target.Arch) + continue; + Locs.emplace_back(ZSource); + } + assert(Locs.size() == 2 && "Expected two decls for zippered symbol"); + + // Print violating declarations per platform. + for (const ZipperedDeclSource &ZSource : Locs) { + unsigned DiagID = 0; + if (Mode == VerificationMode::Pedantic || IsLinkerSymbol) { + updateState(Result::Invalid); + DiagID = diag::err_header_availability_mismatch; + } else if (Mode == VerificationMode::ErrorsAndWarnings) { + updateState(Result::Ignore); + DiagID = diag::warn_header_availability_mismatch; + } else { + updateState(Result::Ignore); + return; + } + // Bypass emitDiag banner and print the target everytime. + Ctx.Diag->setSourceManager(ZSource.SrcMgr); + Ctx.Diag->Report(diag::warn_target) << getTargetTripleName(ZSource.T); + Ctx.Diag->Report(ZSource.FA->Loc, DiagID) + << getAnnotatedName(&R, SymCtx) << ZSource.FA->Avail.isUnavailable() + << ZSource.FA->Avail.isUnavailable(); + } + return; + } + if (shouldIgnoreCpp(SymbolName, R.isWeakDefined())) { updateState(Result::Valid); return; } - const bool IsLinkerSymbol = SymbolName.starts_with("$ld$"); - // All checks at this point classify as some kind of violation. // The different verification modes dictate whether they are reported to the // user. @@ -648,8 +726,6 @@ void DylibVerifier::visitSymbolInDylib(const Record &R, SymbolContext &SymCtx) { } void DylibVerifier::visitGlobal(const GlobalRecord &R) { - if (R.isVerified()) - return; SymbolContext SymCtx; SimpleSymbol Sym = parseSymbol(R.getName()); SymCtx.SymbolName = Sym.Name; @@ -659,8 +735,6 @@ void DylibVerifier::visitGlobal(const GlobalRecord &R) { void DylibVerifier::visitObjCIVar(const ObjCIVarRecord &R, const StringRef Super) { - if (R.isVerified()) - return; SymbolContext SymCtx; SymCtx.SymbolName = ObjCIVarRecord::createScopedName(Super, R.getName()); SymCtx.Kind = EncodeKind::ObjectiveCInstanceVariable; @@ -680,8 +754,6 @@ void DylibVerifier::accumulateSrcLocForDylibSymbols() { } void DylibVerifier::visitObjCInterface(const ObjCInterfaceRecord &R) { - if (R.isVerified()) - return; SymbolContext SymCtx; SymCtx.SymbolName = R.getName(); SymCtx.ObjCIFKind = assignObjCIFSymbolKind(&R); @@ -714,9 +786,12 @@ DylibVerifier::Result DylibVerifier::verifyRemainingSymbols() { DWARFContext DWARFInfo; DWARFCtx = &DWARFInfo; - Ctx.DiscoveredFirstError = false; - Ctx.PrintArch = true; + Ctx.Target = Target(Architecture::AK_unknown, PlatformType::PLATFORM_UNKNOWN); for (std::shared_ptr Slice : Dylib) { + if (Ctx.Target.Arch == Slice->getTarget().Arch) + continue; + Ctx.DiscoveredFirstError = false; + Ctx.PrintArch = true; Ctx.Target = Slice->getTarget(); Ctx.DylibSlice = Slice.get(); Slice->visit(*this); diff --git a/clang/lib/InstallAPI/Frontend.cpp b/clang/lib/InstallAPI/Frontend.cpp index bd7589c13e043fcf1dda06b74f858a6a1c524d27..04d06f46d2652086014eb1fbcb19655fdfa3028d 100644 --- a/clang/lib/InstallAPI/Frontend.cpp +++ b/clang/lib/InstallAPI/Frontend.cpp @@ -23,7 +23,8 @@ std::pair FrontendRecordsSlice::addGlobal( GlobalRecord *GR = llvm::MachO::RecordsSlice::addGlobal(Name, Linkage, GV, Flags, Inlined); - auto Result = FrontendRecords.insert({GR, FrontendAttrs{Avail, D, Access}}); + auto Result = FrontendRecords.insert( + {GR, FrontendAttrs{Avail, D, D->getLocation(), Access}}); return {GR, &(Result.first->second)}; } @@ -39,8 +40,8 @@ FrontendRecordsSlice::addObjCInterface(StringRef Name, RecordLinkage Linkage, ObjCInterfaceRecord *ObjCR = llvm::MachO::RecordsSlice::addObjCInterface(Name, Linkage, SymType); - auto Result = - FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}}); + auto Result = FrontendRecords.insert( + {ObjCR, FrontendAttrs{Avail, D, D->getLocation(), Access}}); return {ObjCR, &(Result.first->second)}; } @@ -51,8 +52,8 @@ FrontendRecordsSlice::addObjCCategory(StringRef ClassToExtend, const Decl *D, HeaderType Access) { ObjCCategoryRecord *ObjCR = llvm::MachO::RecordsSlice::addObjCCategory(ClassToExtend, CategoryName); - auto Result = - FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}}); + auto Result = FrontendRecords.insert( + {ObjCR, FrontendAttrs{Avail, D, D->getLocation(), Access}}); return {ObjCR, &(Result.first->second)}; } @@ -67,8 +68,8 @@ std::pair FrontendRecordsSlice::addObjCIVar( Linkage = RecordLinkage::Internal; ObjCIVarRecord *ObjCR = llvm::MachO::RecordsSlice::addObjCIVar(Container, IvarName, Linkage); - auto Result = - FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}}); + auto Result = FrontendRecords.insert( + {ObjCR, FrontendAttrs{Avail, D, D->getLocation(), Access}}); return {ObjCR, &(Result.first->second)}; } diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index 7dffcf0e941e094d4c8b55509de0f0c24e44af3b..0632882b2961469c2c905b4c8a951e6bb6683937 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -64,8 +64,7 @@ HeaderFileInfo::getControllingMacro(ExternalPreprocessorSource *External) { if (ControllingMacro->isOutOfDate()) { assert(External && "We must have an external source if we have a " "controlling macro that is out of date."); - External->updateOutOfDateIdentifier( - *const_cast(ControllingMacro)); + External->updateOutOfDateIdentifier(*ControllingMacro); } return ControllingMacro; } @@ -947,9 +946,13 @@ OptionalFileEntryRef HeaderSearch::LookupFile( // If we have no includer, that means we're processing a #include // from a module build. We should treat this as a system header if we're // building a [system] module. - bool IncluderIsSystemHeader = - Includer ? getFileInfo(*Includer).DirInfo != SrcMgr::C_User : - BuildSystemModule; + bool IncluderIsSystemHeader = [&]() { + if (!Includer) + return BuildSystemModule; + const HeaderFileInfo *HFI = getExistingFileInfo(*Includer); + assert(HFI && "includer without file info"); + return HFI->DirInfo != SrcMgr::C_User; + }(); if (OptionalFileEntryRef FE = getFileAndSuggestModule( TmpDir, IncludeLoc, IncluderAndDir.second, IncluderIsSystemHeader, RequestingModule, SuggestedModule)) { @@ -964,10 +967,11 @@ OptionalFileEntryRef HeaderSearch::LookupFile( // Note that we only use one of FromHFI/ToHFI at once, due to potential // reallocation of the underlying vector potentially making the first // reference binding dangling. - HeaderFileInfo &FromHFI = getFileInfo(*Includer); - unsigned DirInfo = FromHFI.DirInfo; - bool IndexHeaderMapHeader = FromHFI.IndexHeaderMapHeader; - StringRef Framework = FromHFI.Framework; + const HeaderFileInfo *FromHFI = getExistingFileInfo(*Includer); + assert(FromHFI && "includer without file info"); + unsigned DirInfo = FromHFI->DirInfo; + bool IndexHeaderMapHeader = FromHFI->IndexHeaderMapHeader; + StringRef Framework = FromHFI->Framework; HeaderFileInfo &ToHFI = getFileInfo(*FE); ToHFI.DirInfo = DirInfo; @@ -1154,10 +1158,12 @@ OptionalFileEntryRef HeaderSearch::LookupFile( // "Foo" is the name of the framework in which the including header was found. if (!Includers.empty() && Includers.front().first && !isAngled && !Filename.contains('/')) { - HeaderFileInfo &IncludingHFI = getFileInfo(*Includers.front().first); - if (IncludingHFI.IndexHeaderMapHeader) { + const HeaderFileInfo *IncludingHFI = + getExistingFileInfo(*Includers.front().first); + assert(IncludingHFI && "includer without file info"); + if (IncludingHFI->IndexHeaderMapHeader) { SmallString<128> ScratchFilename; - ScratchFilename += IncludingHFI.Framework; + ScratchFilename += IncludingHFI->Framework; ScratchFilename += '/'; ScratchFilename += Filename; @@ -1287,11 +1293,11 @@ OptionalFileEntryRef HeaderSearch::LookupSubframeworkHeader( } // This file is a system header or C++ unfriendly if the old file is. - // - // Note that the temporary 'DirInfo' is required here, as either call to - // getFileInfo could resize the vector and we don't want to rely on order - // of evaluation. - unsigned DirInfo = getFileInfo(ContextFileEnt).DirInfo; + const HeaderFileInfo *ContextHFI = getExistingFileInfo(ContextFileEnt); + assert(ContextHFI && "context file without file info"); + // Note that the temporary 'DirInfo' is required here, as the call to + // getFileInfo could resize the vector and might invalidate 'ContextHFI'. + unsigned DirInfo = ContextHFI->DirInfo; getFileInfo(*File).DirInfo = DirInfo; FrameworkName.pop_back(); // remove the trailing '/' @@ -1349,8 +1355,6 @@ static void mergeHeaderFileInfo(HeaderFileInfo &HFI, HFI.Framework = OtherHFI.Framework; } -/// getFileInfo - Return the HeaderFileInfo structure for the specified -/// FileEntry. HeaderFileInfo &HeaderSearch::getFileInfo(FileEntryRef FE) { if (FE.getUID() >= FileInfo.size()) FileInfo.resize(FE.getUID() + 1); @@ -1367,27 +1371,20 @@ HeaderFileInfo &HeaderSearch::getFileInfo(FileEntryRef FE) { } HFI->IsValid = true; - // We have local information about this header file, so it's no longer - // strictly external. + // We assume the caller has local information about this header file, so it's + // no longer strictly external. HFI->External = false; return *HFI; } -const HeaderFileInfo * -HeaderSearch::getExistingFileInfo(FileEntryRef FE, bool WantExternal) const { - // If we have an external source, ensure we have the latest information. - // FIXME: Use a generation count to check whether this is really up to date. +const HeaderFileInfo *HeaderSearch::getExistingFileInfo(FileEntryRef FE) const { HeaderFileInfo *HFI; if (ExternalSource) { - if (FE.getUID() >= FileInfo.size()) { - if (!WantExternal) - return nullptr; + if (FE.getUID() >= FileInfo.size()) FileInfo.resize(FE.getUID() + 1); - } HFI = &FileInfo[FE.getUID()]; - if (!WantExternal && (!HFI->IsValid || HFI->External)) - return nullptr; + // FIXME: Use a generation count to check whether this is really up to date. if (!HFI->Resolved) { auto ExternalHFI = ExternalSource->GetHeaderFileInfo(FE); if (ExternalHFI.IsValid) { @@ -1396,16 +1393,25 @@ HeaderSearch::getExistingFileInfo(FileEntryRef FE, bool WantExternal) const { mergeHeaderFileInfo(*HFI, ExternalHFI); } } - } else if (FE.getUID() >= FileInfo.size()) { - return nullptr; - } else { + } else if (FE.getUID() < FileInfo.size()) { HFI = &FileInfo[FE.getUID()]; + } else { + HFI = nullptr; } - if (!HFI->IsValid || (HFI->External && !WantExternal)) - return nullptr; + return (HFI && HFI->IsValid) ? HFI : nullptr; +} + +const HeaderFileInfo * +HeaderSearch::getExistingLocalFileInfo(FileEntryRef FE) const { + HeaderFileInfo *HFI; + if (FE.getUID() < FileInfo.size()) { + HFI = &FileInfo[FE.getUID()]; + } else { + HFI = nullptr; + } - return HFI; + return (HFI && HFI->IsValid && !HFI->External) ? HFI : nullptr; } bool HeaderSearch::isFileMultipleIncludeGuarded(FileEntryRef File) const { diff --git a/clang/lib/Lex/MacroInfo.cpp b/clang/lib/Lex/MacroInfo.cpp index 39bb0f44eff25ba1e502c9b9b0b05c5a6f7cfcb7..dfdf463665f3c137aa6e1ec1c931f009620dc005 100644 --- a/clang/lib/Lex/MacroInfo.cpp +++ b/clang/lib/Lex/MacroInfo.cpp @@ -257,7 +257,7 @@ LLVM_DUMP_METHOD void MacroDirective::dump() const { } ModuleMacro *ModuleMacro::create(Preprocessor &PP, Module *OwningModule, - IdentifierInfo *II, MacroInfo *Macro, + const IdentifierInfo *II, MacroInfo *Macro, ArrayRef Overrides) { void *Mem = PP.getPreprocessorAllocator().Allocate( sizeof(ModuleMacro) + sizeof(ModuleMacro *) * Overrides.size(), diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp index a0cc2b516574c197ea3d2e1eaa0ab993c52a01f5..2ca2122ac71099bf3e9903353878ccff48a6214b 100644 --- a/clang/lib/Lex/PPLexerChange.cpp +++ b/clang/lib/Lex/PPLexerChange.cpp @@ -93,10 +93,16 @@ bool Preprocessor::EnterSourceFile(FileID FID, ConstSearchDirIterator CurDir, } Lexer *TheLexer = new Lexer(FID, *InputFile, *this, IsFirstIncludeOfFile); - if (DependencyDirectivesForFile && FID != PredefinesFileID) - if (OptionalFileEntryRef File = SourceMgr.getFileEntryRefForID(FID)) - if (auto DepDirectives = DependencyDirectivesForFile(*File)) + if (getPreprocessorOpts().DependencyDirectivesForFile && + FID != PredefinesFileID) { + if (OptionalFileEntryRef File = SourceMgr.getFileEntryRefForID(FID)) { + if (std::optional> + DepDirectives = + getPreprocessorOpts().DependencyDirectivesForFile(*File)) { TheLexer->DepDirectives = *DepDirectives; + } + } + } EnterSourceFileWithLexer(TheLexer, CurDir); return false; @@ -362,8 +368,7 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { // Okay, this has a controlling macro, remember in HeaderFileInfo. if (OptionalFileEntryRef FE = CurPPLexer->getFileEntry()) { HeaderInfo.SetFileControllingMacro(*FE, ControllingMacro); - if (MacroInfo *MI = - getMacroInfo(const_cast(ControllingMacro))) + if (MacroInfo *MI = getMacroInfo(ControllingMacro)) MI->setUsedForHeaderGuard(true); if (const IdentifierInfo *DefinedMacro = CurPPLexer->MIOpt.GetDefinedMacro()) { @@ -799,7 +804,7 @@ Module *Preprocessor::LeaveSubmodule(bool ForPragma) { llvm::SmallPtrSet VisitedMacros; for (unsigned I = Info.OuterPendingModuleMacroNames; I != PendingModuleMacroNames.size(); ++I) { - auto *II = const_cast(PendingModuleMacroNames[I]); + const auto *II = PendingModuleMacroNames[I]; if (!VisitedMacros.insert(II).second) continue; @@ -849,8 +854,8 @@ Module *Preprocessor::LeaveSubmodule(bool ForPragma) { // Don't bother creating a module macro if it would represent a #undef // that doesn't override anything. if (Def || !Macro.getOverriddenMacros().empty()) - addModuleMacro(LeavingMod, II, Def, - Macro.getOverriddenMacros(), IsNew); + addModuleMacro(LeavingMod, II, Def, Macro.getOverriddenMacros(), + IsNew); if (!getLangOpts().ModulesLocalVisibility) { // This macro is exposed to the rest of this compilation as a diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 516269c0c6013e965e657713ef53ee2ce5dc2eff..a5f22f01682d252c1ff05de0acde3c3962b244c4 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -129,7 +129,7 @@ void Preprocessor::setLoadedMacroDirective(IdentifierInfo *II, II->setHasMacroDefinition(false); } -ModuleMacro *Preprocessor::addModuleMacro(Module *Mod, IdentifierInfo *II, +ModuleMacro *Preprocessor::addModuleMacro(Module *Mod, const IdentifierInfo *II, MacroInfo *Macro, ArrayRef Overrides, bool &New) { @@ -162,7 +162,7 @@ ModuleMacro *Preprocessor::addModuleMacro(Module *Mod, IdentifierInfo *II, // The new macro is always a leaf macro. LeafMacros.push_back(MM); // The identifier now has defined macros (that may or may not be visible). - II->setHasMacroDefinition(true); + const_cast(II)->setHasMacroDefinition(true); New = true; return MM; diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 031ed1e16bb8fce58682d32adf08410d2d6dbf8b..0b70192743a399e396f4b0b2854fae42168dbbe3 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -759,7 +759,7 @@ void Preprocessor::HandlePoisonedIdentifier(Token & Identifier) { Diag(Identifier,it->second) << Identifier.getIdentifierInfo(); } -void Preprocessor::updateOutOfDateIdentifier(IdentifierInfo &II) const { +void Preprocessor::updateOutOfDateIdentifier(const IdentifierInfo &II) const { assert(II.isOutOfDate() && "not out of date"); getExternalSource()->updateOutOfDateIdentifier(II); } diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index d790060c17c0496130add0aeeb379597fce6b6f6..d054eda279b8c874b50c6844fc7dd2b593e77b80 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -20,6 +20,49 @@ using namespace clang; +/// Parse the optional ("message") part of a deleted-function-body. +StringLiteral *Parser::ParseCXXDeletedFunctionMessage() { + if (!Tok.is(tok::l_paren)) + return nullptr; + StringLiteral *Message = nullptr; + BalancedDelimiterTracker BT{*this, tok::l_paren}; + BT.consumeOpen(); + + if (isTokenStringLiteral()) { + ExprResult Res = ParseUnevaluatedStringLiteralExpression(); + if (Res.isUsable()) { + Message = Res.getAs(); + Diag(Message->getBeginLoc(), getLangOpts().CPlusPlus26 + ? diag::warn_cxx23_delete_with_message + : diag::ext_delete_with_message) + << Message->getSourceRange(); + } + } else { + Diag(Tok.getLocation(), diag::err_expected_string_literal) + << /*Source='in'*/ 0 << "'delete'"; + SkipUntil(tok::r_paren, StopAtSemi | StopBeforeMatch); + } + + BT.consumeClose(); + return Message; +} + +/// If we've encountered '= delete' in a context where it is ill-formed, such +/// as in the declaration of a non-function, also skip the ("message") part if +/// it is present to avoid issuing further diagnostics. +void Parser::SkipDeletedFunctionBody() { + if (!Tok.is(tok::l_paren)) + return; + + BalancedDelimiterTracker BT{*this, tok::l_paren}; + BT.consumeOpen(); + + // Just skip to the end of the current declaration. + SkipUntil(tok::r_paren, tok::comma, StopAtSemi | StopBeforeMatch); + if (Tok.is(tok::r_paren)) + BT.consumeClose(); +} + /// ParseCXXInlineMethodDef - We parsed and verified that the specified /// Declarator is a well formed C++ inline method definition. Now lex its body /// and store its tokens for parsing after the C++ class is complete. @@ -70,7 +113,8 @@ NamedDecl *Parser::ParseCXXInlineMethodDef( ? diag::warn_cxx98_compat_defaulted_deleted_function : diag::ext_defaulted_deleted_function) << 1 /* deleted */; - Actions.SetDeclDeleted(FnD, KWLoc); + StringLiteral *Message = ParseCXXDeletedFunctionMessage(); + Actions.SetDeclDeleted(FnD, KWLoc, Message); Delete = true; if (auto *DeclAsFunction = dyn_cast(FnD)) { DeclAsFunction->setRangeEnd(KWEndLoc); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 0aa14b0510746b9378b4a82d540b4751e78e4422..a990ef398c8230725cd00286edf372d88ed9bf82 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -26,6 +26,7 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaDiagnostic.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" @@ -2664,7 +2665,8 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( } } - Sema::CUDATargetContextRAII X(Actions, Sema::CTCK_InitGlobalVar, ThisDecl); + SemaCUDA::CUDATargetContextRAII X(Actions.CUDA(), + SemaCUDA::CTCK_InitGlobalVar, ThisDecl); switch (TheInitKind) { // Parse declarator '=' initializer. case InitKind::Equal: { @@ -2676,6 +2678,7 @@ Decl *Parser::ParseDeclarationAfterDeclaratorAndAttributes( << 1 /* delete */; else Diag(ConsumeToken(), diag::err_deleted_non_function); + SkipDeletedFunctionBody(); } else if (Tok.is(tok::kw_default)) { if (D.isFunctionDeclarator()) Diag(ConsumeToken(), diag::err_default_delete_in_multiple_declaration) @@ -7700,7 +7703,7 @@ void Parser::ParseParameterDeclarationClause( } // Remember this parsed parameter in ParamInfo. - IdentifierInfo *ParmII = ParmDeclarator.getIdentifier(); + const IdentifierInfo *ParmII = ParmDeclarator.getIdentifier(); // DefArgToks is used when the parsing of default arguments needs // to be delayed. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 861a25dc5103c129c82ee5b2e11b1d57a168300d..cd4803d51bc1de0759885fbf1017ebd64837c09c 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -616,7 +616,7 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context, } // Parse nested-name-specifier. - IdentifierInfo *LastII = nullptr; + const IdentifierInfo *LastII = nullptr; if (ParseOptionalCXXScopeSpecifier(D.SS, /*ObjectType=*/nullptr, /*ObjectHasErrors=*/false, /*EnteringContext=*/false, @@ -3397,6 +3397,7 @@ ExprResult Parser::ParseCXXMemberInitializer(Decl *D, bool IsFunction, << 1 /* delete */; else Diag(ConsumeToken(), diag::err_deleted_non_function); + SkipDeletedFunctionBody(); return ExprError(); } } else if (Tok.is(tok::kw_default)) { diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index ae23cb432c43913b3d26cf663df93d7eb0eb8b1e..473ec9afd60181208f4441b557971eddf9c2595e 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -30,6 +30,8 @@ #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/SemaCUDA.h" +#include "clang/Sema/SemaSYCL.h" #include "clang/Sema/TypoCorrection.h" #include "llvm/ADT/SmallVector.h" #include @@ -2128,10 +2130,8 @@ Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { } if (!LHS.isInvalid()) { - ExprResult ECResult = Actions.ActOnCUDAExecConfigExpr(getCurScope(), - OpenLoc, - ExecConfigExprs, - CloseLoc); + ExprResult ECResult = Actions.CUDA().ActOnExecConfigExpr( + getCurScope(), OpenLoc, ExecConfigExprs, CloseLoc); if (ECResult.isInvalid()) LHS = ExprError(); else @@ -2490,8 +2490,8 @@ ExprResult Parser::ParseSYCLUniqueStableNameExpression() { if (T.consumeClose()) return ExprError(); - return Actions.ActOnSYCLUniqueStableNameExpr(OpLoc, T.getOpenLocation(), - T.getCloseLocation(), Ty.get()); + return Actions.SYCL().ActOnUniqueStableNameExpr( + OpLoc, T.getOpenLocation(), T.getCloseLocation(), Ty.get()); } /// Parse a sizeof or alignof expression. diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 73c85c585baae4f42dd52e75400af6fee40f1d6a..43d6105dcf31c43ee9c56621907e5c7cc192dba0 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -157,7 +157,8 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, bool Parser::ParseOptionalCXXScopeSpecifier( CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors, bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename, - IdentifierInfo **LastII, bool OnlyNamespace, bool InUsingDeclaration) { + const IdentifierInfo **LastII, bool OnlyNamespace, + bool InUsingDeclaration) { assert(getLangOpts().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); @@ -2626,7 +2627,7 @@ bool Parser::ParseUnqualifiedIdTemplateId( // UnqualifiedId. // FIXME: Store name for literal operator too. - IdentifierInfo *TemplateII = + const IdentifierInfo *TemplateII = Id.getKind() == UnqualifiedIdKind::IK_Identifier ? Id.Identifier : nullptr; OverloadedOperatorKind OpKind = diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp index 4fc6a2203cec367b783e2ee30f43f75ee5b09fd3..d97985d42369ad9626a31ff83f725af40a4bf4b9 100644 --- a/clang/lib/Parse/ParseHLSL.cpp +++ b/clang/lib/Parse/ParseHLSL.cpp @@ -15,6 +15,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" +#include "clang/Sema/SemaHLSL.h" using namespace clang; @@ -71,9 +72,9 @@ Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) { return nullptr; } - Decl *D = Actions.ActOnStartHLSLBuffer(getCurScope(), IsCBuffer, BufferLoc, - Identifier, IdentifierLoc, - T.getOpenLocation()); + Decl *D = Actions.HLSL().ActOnStartBuffer(getCurScope(), IsCBuffer, BufferLoc, + Identifier, IdentifierLoc, + T.getOpenLocation()); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { // FIXME: support attribute on constants inside cbuffer/tbuffer. @@ -87,7 +88,7 @@ Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) { T.skipToEnd(); DeclEnd = T.getCloseLocation(); BufferScope.Exit(); - Actions.ActOnFinishHLSLBuffer(D, DeclEnd); + Actions.HLSL().ActOnFinishBuffer(D, DeclEnd); return nullptr; } } @@ -95,7 +96,7 @@ Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) { T.consumeClose(); DeclEnd = T.getCloseLocation(); BufferScope.Exit(); - Actions.ActOnFinishHLSLBuffer(D, DeclEnd); + Actions.HLSL().ActOnFinishBuffer(D, DeclEnd); Actions.ProcessDeclAttributeList(Actions.CurScope, D, Attrs); return D; diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 88bab0eb27a3edf479f18b6f03460ee5a8f9fdb9..887d7a36cee7e976112792c65b45940a871e7756 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -799,11 +799,11 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, addedToDeclSpec); // Install the property declarator into interfaceDecl. - IdentifierInfo *SelName = + const IdentifierInfo *SelName = OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier(); Selector GetterSel = PP.getSelectorTable().getNullarySelector(SelName); - IdentifierInfo *SetterName = OCDS.getSetterName(); + const IdentifierInfo *SetterName = OCDS.getSetterName(); Selector SetterSel; if (SetterName) SetterSel = PP.getSelectorTable().getSelector(1, &SetterName); @@ -1445,7 +1445,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, return Result; } - SmallVector KeyIdents; + SmallVector KeyIdents; SmallVector KeyLocs; SmallVector ArgInfos; ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope | @@ -1541,7 +1541,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, Declarator ParmDecl(DS, ParsedAttributesView::none(), DeclaratorContext::Prototype); ParseDeclarator(ParmDecl); - IdentifierInfo *ParmII = ParmDecl.getIdentifier(); + const IdentifierInfo *ParmII = ParmDecl.getIdentifier(); Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl); CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, ParmDecl.getIdentifierLoc(), @@ -3242,7 +3242,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, SourceLocation Loc; IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc); - SmallVector KeyIdents; + SmallVector KeyIdents; SmallVector KeyLocs; ExprVector KeyExprs; @@ -3642,7 +3642,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { if (Tok.isNot(tok::l_paren)) return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector"); - SmallVector KeyIdents; + SmallVector KeyIdents; SourceLocation sLoc; BalancedDelimiterTracker T(*this, tok::l_paren); diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index 07dd2ba0106a4e209debe366879156a50a4b8f17..91f2b8afcf0c241759cb315f629eecf12e6c8940 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/OpenACCClause.h" #include "clang/Basic/OpenACCKinds.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" @@ -534,14 +535,6 @@ bool ClauseHasRequiredParens(OpenACCDirectiveKind DirKind, return getClauseParensKind(DirKind, Kind) == ClauseParensKind::Required; } -ExprResult ParseOpenACCConditionalExpr(Parser &P) { - // FIXME: It isn't clear if the spec saying 'condition' means the same as - // it does in an if/while/etc (See ParseCXXCondition), however as it was - // written with Fortran/C in mind, we're going to assume it just means an - // 'expression evaluating to boolean'. - return P.getActions().CorrectDelayedTyposInExpr(P.ParseExpression()); -} - // Skip until we see the end of pragma token, but don't consume it. This is us // just giving up on the rest of the pragma so we can continue executing. We // have to do this because 'SkipUntil' considers paren balancing, which isn't @@ -582,12 +575,43 @@ unsigned getOpenACCScopeFlags(OpenACCDirectiveKind DirKind) { } // namespace +Parser::OpenACCClauseParseResult Parser::OpenACCCanContinue() { + return {nullptr, OpenACCParseCanContinue::Can}; +} + +Parser::OpenACCClauseParseResult Parser::OpenACCCannotContinue() { + return {nullptr, OpenACCParseCanContinue::Cannot}; +} + +Parser::OpenACCClauseParseResult Parser::OpenACCSuccess(OpenACCClause *Clause) { + return {Clause, OpenACCParseCanContinue::Can}; +} + +ExprResult Parser::ParseOpenACCConditionExpr() { + // FIXME: It isn't clear if the spec saying 'condition' means the same as + // it does in an if/while/etc (See ParseCXXCondition), however as it was + // written with Fortran/C in mind, we're going to assume it just means an + // 'expression evaluating to boolean'. + ExprResult ER = getActions().CorrectDelayedTyposInExpr(ParseExpression()); + + if (!ER.isUsable()) + return ER; + + Sema::ConditionResult R = + getActions().ActOnCondition(getCurScope(), ER.get()->getExprLoc(), + ER.get(), Sema::ConditionKind::Boolean); + + return R.isInvalid() ? ExprError() : R.get().second; +} + // OpenACC 3.3, section 1.7: // To simplify the specification and convey appropriate constraint information, // a pqr-list is a comma-separated list of pdr items. The one exception is a // clause-list, which is a list of one or more clauses optionally separated by // commas. -void Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) { +SmallVector +Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) { + SmallVector Clauses; bool FirstClause = true; while (getCurToken().isNot(tok::annot_pragma_openacc_end)) { // Comma is optional in a clause-list. @@ -595,13 +619,17 @@ void Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) { ConsumeToken(); FirstClause = false; - // Recovering from a bad clause is really difficult, so we just give up on - // error. - if (ParseOpenACCClause(DirKind)) { + OpenACCClauseParseResult Result = ParseOpenACCClause(Clauses, DirKind); + if (OpenACCClause *Clause = Result.getPointer()) { + Clauses.push_back(Clause); + } else if (Result.getInt() == OpenACCParseCanContinue::Cannot) { + // Recovering from a bad clause is really difficult, so we just give up on + // error. SkipUntilEndOfDirective(*this); - return; + return Clauses; } } + return Clauses; } ExprResult Parser::ParseOpenACCIntExpr() { @@ -762,42 +790,48 @@ bool Parser::ParseOpenACCGangArgList() { // really have its owner grammar and each individual one has its own definition. // However, they all are named with a single-identifier (or auto/default!) // token, followed in some cases by either braces or parens. -bool Parser::ParseOpenACCClause(OpenACCDirectiveKind DirKind) { +Parser::OpenACCClauseParseResult +Parser::ParseOpenACCClause(ArrayRef ExistingClauses, + OpenACCDirectiveKind DirKind) { // A number of clause names are actually keywords, so accept a keyword that // can be converted to a name. if (expectIdentifierOrKeyword(*this)) - return true; + return OpenACCCannotContinue(); OpenACCClauseKind Kind = getOpenACCClauseKind(getCurToken()); - if (Kind == OpenACCClauseKind::Invalid) - return Diag(getCurToken(), diag::err_acc_invalid_clause) - << getCurToken().getIdentifierInfo(); + if (Kind == OpenACCClauseKind::Invalid) { + Diag(getCurToken(), diag::err_acc_invalid_clause) + << getCurToken().getIdentifierInfo(); + return OpenACCCannotContinue(); + } // Consume the clause name. SourceLocation ClauseLoc = ConsumeToken(); - bool Result = ParseOpenACCClauseParams(DirKind, Kind); - getActions().OpenACC().ActOnClause(Kind, ClauseLoc); - return Result; + return ParseOpenACCClauseParams(ExistingClauses, DirKind, Kind, ClauseLoc); } -bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, - OpenACCClauseKind Kind) { +Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( + ArrayRef ExistingClauses, + OpenACCDirectiveKind DirKind, OpenACCClauseKind ClauseKind, + SourceLocation ClauseLoc) { BalancedDelimiterTracker Parens(*this, tok::l_paren, tok::annot_pragma_openacc_end); + SemaOpenACC::OpenACCParsedClause ParsedClause(DirKind, ClauseKind, ClauseLoc); - if (ClauseHasRequiredParens(DirKind, Kind)) { + if (ClauseHasRequiredParens(DirKind, ClauseKind)) { + ParsedClause.setLParenLoc(getCurToken().getLocation()); if (Parens.expectAndConsume()) { // We are missing a paren, so assume that the person just forgot the // parameter. Return 'false' so we try to continue on and parse the next // clause. SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end, Parser::StopBeforeMatch); - return false; + return OpenACCCanContinue(); } - switch (Kind) { + switch (ClauseKind) { case OpenACCClauseKind::Default: { Token DefKindTok = getCurToken(); @@ -806,46 +840,52 @@ bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, ConsumeToken(); - if (getOpenACCDefaultClauseKind(DefKindTok) == - OpenACCDefaultClauseKind::Invalid) + OpenACCDefaultClauseKind DefKind = + getOpenACCDefaultClauseKind(DefKindTok); + + if (DefKind == OpenACCDefaultClauseKind::Invalid) Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind); + else + ParsedClause.setDefaultDetails(DefKind); break; } case OpenACCClauseKind::If: { - ExprResult CondExpr = ParseOpenACCConditionalExpr(*this); - // An invalid expression can be just about anything, so just give up on - // this clause list. + ExprResult CondExpr = ParseOpenACCConditionExpr(); + ParsedClause.setConditionDetails(CondExpr.isUsable() ? CondExpr.get() + : nullptr); + if (CondExpr.isInvalid()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } + break; } case OpenACCClauseKind::CopyIn: tryParseAndConsumeSpecialTokenKind( - *this, OpenACCSpecialTokenKind::ReadOnly, Kind); - if (ParseOpenACCClauseVarList(Kind)) { + *this, OpenACCSpecialTokenKind::ReadOnly, ClauseKind); + if (ParseOpenACCClauseVarList(ClauseKind)) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; case OpenACCClauseKind::Create: case OpenACCClauseKind::CopyOut: tryParseAndConsumeSpecialTokenKind(*this, OpenACCSpecialTokenKind::Zero, - Kind); - if (ParseOpenACCClauseVarList(Kind)) { + ClauseKind); + if (ParseOpenACCClauseVarList(ClauseKind)) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; case OpenACCClauseKind::Reduction: // If we're missing a clause-kind (or it is invalid), see if we can parse // the var-list anyway. ParseReductionOperator(*this); - if (ParseOpenACCClauseVarList(Kind)) { + if (ParseOpenACCClauseVarList(ClauseKind)) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; case OpenACCClauseKind::Self: @@ -868,19 +908,19 @@ bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, case OpenACCClauseKind::Present: case OpenACCClauseKind::Private: case OpenACCClauseKind::UseDevice: - if (ParseOpenACCClauseVarList(Kind)) { + if (ParseOpenACCClauseVarList(ClauseKind)) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; case OpenACCClauseKind::Collapse: { tryParseAndConsumeSpecialTokenKind(*this, OpenACCSpecialTokenKind::Force, - Kind); + ClauseKind); ExprResult NumLoops = getActions().CorrectDelayedTyposInExpr(ParseConstantExpression()); if (NumLoops.isInvalid()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; } @@ -888,7 +928,7 @@ bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, ExprResult BindArg = ParseOpenACCBindClauseArgument(); if (BindArg.isInvalid()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; } @@ -900,7 +940,7 @@ bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, ExprResult IntExpr = ParseOpenACCIntExpr(); if (IntExpr.isInvalid()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; } @@ -912,45 +952,50 @@ bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, ConsumeToken(); } else if (ParseOpenACCDeviceTypeList()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; case OpenACCClauseKind::Tile: if (ParseOpenACCSizeExprList()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; default: llvm_unreachable("Not a required parens type?"); } - return Parens.consumeClose(); - } else if (ClauseHasOptionalParens(DirKind, Kind)) { + ParsedClause.setEndLoc(getCurToken().getLocation()); + + if (Parens.consumeClose()) + return OpenACCCannotContinue(); + + } else if (ClauseHasOptionalParens(DirKind, ClauseKind)) { + ParsedClause.setLParenLoc(getCurToken().getLocation()); if (!Parens.consumeOpen()) { - switch (Kind) { + switch (ClauseKind) { case OpenACCClauseKind::Self: { assert(DirKind != OpenACCDirectiveKind::Update); - ExprResult CondExpr = ParseOpenACCConditionalExpr(*this); - // An invalid expression can be just about anything, so just give up on - // this clause list. + ExprResult CondExpr = ParseOpenACCConditionExpr(); + if (CondExpr.isInvalid()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; } case OpenACCClauseKind::Vector: case OpenACCClauseKind::Worker: { tryParseAndConsumeSpecialTokenKind(*this, - Kind == OpenACCClauseKind::Vector + ClauseKind == + OpenACCClauseKind::Vector ? OpenACCSpecialTokenKind::Length : OpenACCSpecialTokenKind::Num, - Kind); + ClauseKind); ExprResult IntExpr = ParseOpenACCIntExpr(); if (IntExpr.isInvalid()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; } @@ -958,29 +1003,32 @@ bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, ExprResult AsyncArg = ParseOpenACCAsyncArgument(); if (AsyncArg.isInvalid()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; } case OpenACCClauseKind::Gang: if (ParseOpenACCGangArgList()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; case OpenACCClauseKind::Wait: if (ParseOpenACCWaitArgument()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; default: llvm_unreachable("Not an optional parens type?"); } - Parens.consumeClose(); + ParsedClause.setEndLoc(getCurToken().getLocation()); + if (Parens.consumeClose()) + return OpenACCCannotContinue(); } } - return false; + return OpenACCSuccess( + Actions.OpenACC().ActOnClause(ExistingClauses, ParsedClause)); } /// OpenACC 3.3 section 2.16: @@ -1204,15 +1252,17 @@ Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() { Diag(Tok, diag::err_expected) << tok::l_paren; } - // Parses the list of clauses, if present. - ParseOpenACCClauseList(DirKind); + // Parses the list of clauses, if present, plus set up return value. + OpenACCDirectiveParseInfo ParseInfo{DirKind, StartLoc, SourceLocation{}, + ParseOpenACCClauseList(DirKind)}; assert(Tok.is(tok::annot_pragma_openacc_end) && "Didn't parse all OpenACC Clauses"); - SourceLocation EndLoc = ConsumeAnnotationToken(); - assert(EndLoc.isValid()); + ParseInfo.EndLoc = ConsumeAnnotationToken(); + assert(ParseInfo.EndLoc.isValid() && + "Terminating annotation token not present"); - return OpenACCDirectiveParseInfo{DirKind, StartLoc, EndLoc}; + return ParseInfo; } // Parse OpenACC directive on a declaration. @@ -1255,5 +1305,6 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() { } return getActions().OpenACC().ActOnEndStmtDirective( - DirInfo.DirKind, DirInfo.StartLoc, DirInfo.EndLoc, AssocStmt); + DirInfo.DirKind, DirInfo.StartLoc, DirInfo.EndLoc, DirInfo.Clauses, + AssocStmt); } diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 0f692e2146a4901df7411ab11bfefa2746959fce..3979f75b6020dbba3d91ae2e747aac6bbcdf996a 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -21,6 +21,7 @@ #include "clang/Parse/RAIIObjectsForParser.h" #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/SemaCUDA.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringSwitch.h" #include @@ -3900,8 +3901,8 @@ void PragmaForceCUDAHostDeviceHandler::HandlePragma( } if (Info->isStr("begin")) - Actions.PushForceCUDAHostDevice(); - else if (!Actions.PopForceCUDAHostDevice()) + Actions.CUDA().PushForceHostDevice(); + else if (!Actions.CUDA().PopForceHostDevice()) PP.Diag(FirstTok.getLocation(), diag::err_pragma_cannot_end_force_cuda_host_device); diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index d4897f8f66072ea08f372ce91eb5bfcca22e8d08..b07ce451e878eb3a3d9a17a3b5db9c6c8f52e6e7 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -313,7 +313,7 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo, return nullptr; } - IdentifierInfo *Id = Result.Identifier; + const IdentifierInfo *Id = Result.Identifier; SourceLocation IdLoc = Result.getBeginLoc(); DiagnoseAndSkipCXX11Attributes(); @@ -805,10 +805,12 @@ NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth, // identifier, comma, or greater. Provide a fixit if the identifier, comma, // or greater appear immediately or after 'struct'. In the latter case, // replace the keyword with 'class'. + bool TypenameKeyword = false; if (!TryConsumeToken(tok::kw_class)) { bool Replace = Tok.isOneOf(tok::kw_typename, tok::kw_struct); const Token &Next = Tok.is(tok::kw_struct) ? NextToken() : Tok; if (Tok.is(tok::kw_typename)) { + TypenameKeyword = true; Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_template_template_param_typename @@ -878,10 +880,9 @@ NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth, } } - return Actions.ActOnTemplateTemplateParameter(getCurScope(), TemplateLoc, - ParamList, EllipsisLoc, - ParamName, NameLoc, Depth, - Position, EqualLoc, DefaultArg); + return Actions.ActOnTemplateTemplateParameter( + getCurScope(), TemplateLoc, ParamList, TypenameKeyword, EllipsisLoc, + ParamName, NameLoc, Depth, Position, EqualLoc, DefaultArg); } /// ParseNonTypeTemplateParameter - Handle the parsing of non-type @@ -1289,7 +1290,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // later. Tok.setKind(tok::annot_template_id); - IdentifierInfo *TemplateII = + const IdentifierInfo *TemplateII = TemplateName.getKind() == UnqualifiedIdKind::IK_Identifier ? TemplateName.Identifier : nullptr; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index cc0e41ed221c4f1d0058ea30a685e5ad01045824..d6f2b9f448cd5259220a5060d76ec5a51e1bcb19 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -1404,6 +1404,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, // Parse function body eagerly if it is either '= delete;' or '= default;' as // ActOnStartOfFunctionDef needs to know whether the function is deleted. + StringLiteral *DeletedMessage = nullptr; Sema::FnBodyKind BodyKind = Sema::FnBodyKind::Other; SourceLocation KWLoc; if (TryConsumeToken(tok::equal)) { @@ -1415,6 +1416,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, : diag::ext_defaulted_deleted_function) << 1 /* deleted */; BodyKind = Sema::FnBodyKind::Delete; + DeletedMessage = ParseCXXDeletedFunctionMessage(); } else if (TryConsumeToken(tok::kw_default, KWLoc)) { Diag(KWLoc, getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_defaulted_deleted_function @@ -1473,7 +1475,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, D.getMutableDeclSpec().abort(); if (BodyKind != Sema::FnBodyKind::Other) { - Actions.SetFunctionBodyKind(Res, KWLoc, BodyKind); + Actions.SetFunctionBodyKind(Res, KWLoc, BodyKind, DeletedMessage); Stmt *GeneratedBody = Res ? Res->getBody() : nullptr; Actions.ActOnFinishFunctionBody(Res, GeneratedBody, false); return Res; diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index e8bff07ced0cfa60064d69b3a879ddaa0099f42c..ab3b813a9ccd97efc5d99104cd1d493024aff78a 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -29,6 +29,7 @@ add_clang_library(clangSema SemaAttr.cpp SemaAPINotes.cpp SemaAvailability.cpp + SemaBase.cpp SemaCXXScopeSpec.cpp SemaCast.cpp SemaChecking.cpp diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp index 350bd78b57107bbfaa0dde13af5ec7c18af9b503..91713d71786ee5eeffa9b050f2d72d6593490aec 100644 --- a/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -854,7 +854,8 @@ StringRef CodeCompletionResult::getOrderedName(std::string &Saved) const { if (IdentifierInfo *Id = Name.getAsIdentifierInfo()) return Id->getName(); if (Name.isObjCZeroArgSelector()) - if (IdentifierInfo *Id = Name.getObjCSelector().getIdentifierInfoForSlot(0)) + if (const IdentifierInfo *Id = + Name.getObjCSelector().getIdentifierInfoForSlot(0)) return Id->getName(); Saved = Name.getAsString(); diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index b7e4fc0ac9b5b277f8f0bc1ca84c5aa0d2519254..8de202f4f7a0c32c4dc12f3413faed50b94272e5 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -41,9 +41,12 @@ #include "clang/Sema/RISCVIntrinsicManager.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaConsumer.h" +#include "clang/Sema/SemaHLSL.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaOpenACC.h" +#include "clang/Sema/SemaSYCL.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" #include "clang/Sema/TypoCorrection.h" @@ -90,9 +93,8 @@ DarwinSDKInfo *Sema::getDarwinSDKInfoForAvailabilityChecking() { return nullptr; } -IdentifierInfo * -Sema::InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName, - unsigned int Index) { +IdentifierInfo *Sema::InventAbbreviatedTemplateParameterTypeName( + const IdentifierInfo *ParamName, unsigned int Index) { std::string InventedName; llvm::raw_string_ostream OS(InventedName); @@ -190,14 +192,18 @@ const uint64_t Sema::MaximumAlignment; Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter) - : CollectStats(false), TUKind(TUKind), CurFPFeatures(pp.getLangOpts()), - LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer), - Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), - APINotes(SourceMgr, LangOpts), AnalysisWarnings(*this), - ThreadSafetyDeclCache(nullptr), LateTemplateParser(nullptr), - LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), - CurContext(nullptr), ExternalSource(nullptr), CurScope(nullptr), - Ident_super(nullptr), OpenACCPtr(std::make_unique(*this)), + : SemaBase(*this), CollectStats(false), TUKind(TUKind), + CurFPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp), + Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), + SourceMgr(PP.getSourceManager()), APINotes(SourceMgr, LangOpts), + AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr), + LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr), + OpaqueParser(nullptr), CurContext(nullptr), ExternalSource(nullptr), + CurScope(nullptr), Ident_super(nullptr), + CUDAPtr(std::make_unique(*this)), + HLSLPtr(std::make_unique(*this)), + OpenACCPtr(std::make_unique(*this)), + SYCLPtr(std::make_unique(*this)), MSPointerToMemberRepresentationMethod( LangOpts.getMSPointerToMemberRepresentationMethod()), MSStructPragmaOn(false), VtorDispStack(LangOpts.getVtorDispMode()), @@ -1612,11 +1618,6 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) { PrintContextStack(); } -Sema::SemaDiagnosticBuilder -Sema::Diag(SourceLocation Loc, const PartialDiagnostic &PD, bool DeferHint) { - return Diag(Loc, PD.getDiagID(), DeferHint) << PD; -} - bool Sema::hasUncompilableErrorOccurred() const { if (getDiagnostics().hasUncompilableErrorOccurred()) return true; @@ -1636,15 +1637,15 @@ bool Sema::hasUncompilableErrorOccurred() const { // Print notes showing how we can reach FD starting from an a priori // known-callable function. static void emitCallStackNotes(Sema &S, const FunctionDecl *FD) { - auto FnIt = S.DeviceKnownEmittedFns.find(FD); - while (FnIt != S.DeviceKnownEmittedFns.end()) { + auto FnIt = S.CUDA().DeviceKnownEmittedFns.find(FD); + while (FnIt != S.CUDA().DeviceKnownEmittedFns.end()) { // Respect error limit. if (S.Diags.hasFatalErrorOccurred()) return; DiagnosticBuilder Builder( S.Diags.Report(FnIt->second.Loc, diag::note_called_by)); Builder << FnIt->second.FD; - FnIt = S.DeviceKnownEmittedFns.find(FnIt->second.FD); + FnIt = S.CUDA().DeviceKnownEmittedFns.find(FnIt->second.FD); } } @@ -1748,7 +1749,7 @@ public: (ShouldEmitRootNode || InOMPDeviceContext)) S.finalizeOpenMPDelayedAnalysis(Caller, FD, Loc); if (Caller) - S.DeviceKnownEmittedFns[FD] = {Caller, Loc}; + S.CUDA().DeviceKnownEmittedFns[FD] = {Caller, Loc}; // Always emit deferred diagnostics for the direct users. This does not // lead to explosion of diagnostics since each user is visited at most // twice. @@ -1837,8 +1838,8 @@ void Sema::emitDeferredDiags() { // which other not-known-emitted functions. // // When we see something which is illegal if the current function is emitted -// (usually by way of CUDADiagIfDeviceCode, CUDADiagIfHostCode, or -// CheckCUDACall), we first check if the current function is known-emitted. If +// (usually by way of DiagIfDeviceCode, DiagIfHostCode, or +// CheckCall), we first check if the current function is known-emitted. If // so, we immediately output the diagnostic. // // Otherwise, we "defer" the diagnostic. It sits in Sema::DeviceDeferredDiags @@ -1901,39 +1902,16 @@ Sema::targetDiag(SourceLocation Loc, unsigned DiagID, const FunctionDecl *FD) { ? diagIfOpenMPDeviceCode(Loc, DiagID, FD) : diagIfOpenMPHostCode(Loc, DiagID, FD); if (getLangOpts().CUDA) - return getLangOpts().CUDAIsDevice ? CUDADiagIfDeviceCode(Loc, DiagID) - : CUDADiagIfHostCode(Loc, DiagID); + return getLangOpts().CUDAIsDevice ? CUDA().DiagIfDeviceCode(Loc, DiagID) + : CUDA().DiagIfHostCode(Loc, DiagID); if (getLangOpts().SYCLIsDevice) - return SYCLDiagIfDeviceCode(Loc, DiagID); + return SYCL().DiagIfDeviceCode(Loc, DiagID); return SemaDiagnosticBuilder(SemaDiagnosticBuilder::K_Immediate, Loc, DiagID, FD, *this); } -Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID, - bool DeferHint) { - bool IsError = Diags.getDiagnosticIDs()->isDefaultMappingAsError(DiagID); - bool ShouldDefer = getLangOpts().CUDA && LangOpts.GPUDeferDiag && - DiagnosticIDs::isDeferrable(DiagID) && - (DeferHint || DeferDiags || !IsError); - auto SetIsLastErrorImmediate = [&](bool Flag) { - if (IsError) - IsLastErrorImmediate = Flag; - }; - if (!ShouldDefer) { - SetIsLastErrorImmediate(true); - return SemaDiagnosticBuilder(SemaDiagnosticBuilder::K_Immediate, Loc, - DiagID, getCurFunctionDecl(), *this); - } - - SemaDiagnosticBuilder DB = getLangOpts().CUDAIsDevice - ? CUDADiagIfDeviceCode(Loc, DiagID) - : CUDADiagIfHostCode(Loc, DiagID); - SetIsLastErrorImmediate(DB.isImmediate()); - return DB; -} - void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { if (isUnevaluatedContext() || Ty.isNull()) return; @@ -1944,7 +1922,7 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { // constant byte size like zero length arrays. So, do a deep check for SYCL. if (D && LangOpts.SYCLIsDevice) { llvm::DenseSet Visited; - deepTypeCheckForSYCLDevice(Loc, Visited, D); + SYCL().deepTypeCheckForDevice(Loc, Visited, D); } Decl *C = cast(getCurLexicalContext()); diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp index a3128306c664fe17ffa439ceda3dda798c2e2f50..4c445f28bba8c62debc5ba52dfc1b0897c4f7459 100644 --- a/clang/lib/Sema/SemaAPINotes.cpp +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -463,6 +463,8 @@ static void ProcessAPINotes(Sema &S, FunctionOrMethod AnyFunc, D = MD; } + assert((FD || MD) && "Expecting Function or ObjCMethod"); + // Nullability of return type. if (Info.NullabilityAudited) applyNullability(S, D, Info.getReturnTypeInfo(), Metadata); diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index 4af3c0f30a8e8a23e4a59bd733645cc2556f21bb..6a707eeb66d012ba49b8b4f466b2d83a920a3409 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -10,8 +10,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Basic/Specifiers.h" -#include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" @@ -19,9 +17,12 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DependentDiagnostic.h" #include "clang/AST/ExprCXX.h" +#include "clang/Basic/Specifiers.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/SemaInternal.h" +#include "llvm/ADT/STLForwardCompat.h" using namespace clang; using namespace sema; @@ -1658,21 +1659,24 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, case InitializedEntity::EK_Base: PD = PDiag(diag::err_access_base_ctor); PD << Entity.isInheritedVirtualBase() - << Entity.getBaseSpecifier()->getType() << getSpecialMember(Constructor); + << Entity.getBaseSpecifier()->getType() + << llvm::to_underlying(getSpecialMember(Constructor)); break; case InitializedEntity::EK_Member: case InitializedEntity::EK_ParenAggInitMember: { const FieldDecl *Field = cast(Entity.getDecl()); PD = PDiag(diag::err_access_field_ctor); - PD << Field->getType() << getSpecialMember(Constructor); + PD << Field->getType() + << llvm::to_underlying(getSpecialMember(Constructor)); break; } case InitializedEntity::EK_LambdaCapture: { StringRef VarName = Entity.getCapturedVarName(); PD = PDiag(diag::err_access_lambda_capture); - PD << VarName << Entity.getType() << getSpecialMember(Constructor); + PD << VarName << Entity.getType() + << llvm::to_underlying(getSpecialMember(Constructor)); break; } diff --git a/clang/lib/Sema/SemaBase.cpp b/clang/lib/Sema/SemaBase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0442fb2929e3c647f94a4f3a927fe8af960d05d4 --- /dev/null +++ b/clang/lib/Sema/SemaBase.cpp @@ -0,0 +1,86 @@ +#include "clang/Sema/SemaBase.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaCUDA.h" + +namespace clang { + +SemaBase::SemaBase(Sema &S) : SemaRef(S) {} + +ASTContext &SemaBase::getASTContext() const { return SemaRef.Context; } +DiagnosticsEngine &SemaBase::getDiagnostics() const { return SemaRef.Diags; } +const LangOptions &SemaBase::getLangOpts() const { return SemaRef.LangOpts; } + +SemaBase::ImmediateDiagBuilder::~ImmediateDiagBuilder() { + // If we aren't active, there is nothing to do. + if (!isActive()) + return; + + // Otherwise, we need to emit the diagnostic. First clear the diagnostic + // builder itself so it won't emit the diagnostic in its own destructor. + // + // This seems wasteful, in that as written the DiagnosticBuilder dtor will + // do its own needless checks to see if the diagnostic needs to be + // emitted. However, because we take care to ensure that the builder + // objects never escape, a sufficiently smart compiler will be able to + // eliminate that code. + Clear(); + + // Dispatch to Sema to emit the diagnostic. + SemaRef.EmitCurrentDiagnostic(DiagID); +} + +const SemaBase::SemaDiagnosticBuilder & +operator<<(const SemaBase::SemaDiagnosticBuilder &Diag, + const PartialDiagnostic &PD) { + if (Diag.ImmediateDiag) + PD.Emit(*Diag.ImmediateDiag); + else if (Diag.PartialDiagId) + Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second = PD; + return Diag; +} + +void SemaBase::SemaDiagnosticBuilder::AddFixItHint( + const FixItHint &Hint) const { + if (ImmediateDiag) + ImmediateDiag->AddFixItHint(Hint); + else if (PartialDiagId) + S.DeviceDeferredDiags[Fn][*PartialDiagId].second.AddFixItHint(Hint); +} + +llvm::DenseMap, + std::vector> & +SemaBase::SemaDiagnosticBuilder::getDeviceDeferredDiags() const { + return S.DeviceDeferredDiags; +} + +Sema::SemaDiagnosticBuilder SemaBase::Diag(SourceLocation Loc, unsigned DiagID, + bool DeferHint) { + bool IsError = + getDiagnostics().getDiagnosticIDs()->isDefaultMappingAsError(DiagID); + bool ShouldDefer = getLangOpts().CUDA && getLangOpts().GPUDeferDiag && + DiagnosticIDs::isDeferrable(DiagID) && + (DeferHint || SemaRef.DeferDiags || !IsError); + auto SetIsLastErrorImmediate = [&](bool Flag) { + if (IsError) + SemaRef.IsLastErrorImmediate = Flag; + }; + if (!ShouldDefer) { + SetIsLastErrorImmediate(true); + return SemaDiagnosticBuilder(SemaDiagnosticBuilder::K_Immediate, Loc, + DiagID, SemaRef.getCurFunctionDecl(), SemaRef); + } + + SemaDiagnosticBuilder DB = getLangOpts().CUDAIsDevice + ? SemaRef.CUDA().DiagIfDeviceCode(Loc, DiagID) + : SemaRef.CUDA().DiagIfHostCode(Loc, DiagID); + SetIsLastErrorImmediate(DB.isImmediate()); + return DB; +} + +Sema::SemaDiagnosticBuilder SemaBase::Diag(SourceLocation Loc, + const PartialDiagnostic &PD, + bool DeferHint) { + return Diag(Loc, PD.getDiagID(), DeferHint) << PD; +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp index 4d4f4b6a2d4d95a6a1313266e71d1ea449ea0ff7..80ea43dc5316eb2932c4a339c8f3115edb1b6171 100644 --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -10,6 +10,7 @@ /// //===----------------------------------------------------------------------===// +#include "clang/Sema/SemaCUDA.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/ExprCXX.h" @@ -22,10 +23,13 @@ #include "clang/Sema/SemaDiagnostic.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" +#include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/SmallVector.h" #include using namespace clang; +SemaCUDA::SemaCUDA(Sema &S) : SemaBase(S) {} + template static bool hasExplicitAttr(const VarDecl *D) { if (!D) return false; @@ -34,38 +38,37 @@ template static bool hasExplicitAttr(const VarDecl *D) { return false; } -void Sema::PushForceCUDAHostDevice() { +void SemaCUDA::PushForceHostDevice() { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); - ForceCUDAHostDeviceDepth++; + ForceHostDeviceDepth++; } -bool Sema::PopForceCUDAHostDevice() { +bool SemaCUDA::PopForceHostDevice() { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); - if (ForceCUDAHostDeviceDepth == 0) + if (ForceHostDeviceDepth == 0) return false; - ForceCUDAHostDeviceDepth--; + ForceHostDeviceDepth--; return true; } -ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, +ExprResult SemaCUDA::ActOnExecConfigExpr(Scope *S, SourceLocation LLLLoc, MultiExprArg ExecConfig, SourceLocation GGGLoc) { - FunctionDecl *ConfigDecl = Context.getcudaConfigureCallDecl(); + FunctionDecl *ConfigDecl = getASTContext().getcudaConfigureCallDecl(); if (!ConfigDecl) return ExprError(Diag(LLLLoc, diag::err_undeclared_var_use) - << getCudaConfigureFuncName()); + << getConfigureFuncName()); QualType ConfigQTy = ConfigDecl->getType(); - DeclRefExpr *ConfigDR = new (Context) - DeclRefExpr(Context, ConfigDecl, false, ConfigQTy, VK_LValue, LLLLoc); - MarkFunctionReferenced(LLLLoc, ConfigDecl); + DeclRefExpr *ConfigDR = new (getASTContext()) DeclRefExpr( + getASTContext(), ConfigDecl, false, ConfigQTy, VK_LValue, LLLLoc); + SemaRef.MarkFunctionReferenced(LLLLoc, ConfigDecl); - return BuildCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, nullptr, - /*IsExecConfig=*/true); + return SemaRef.BuildCallExpr(S, ConfigDR, LLLLoc, ExecConfig, GGGLoc, nullptr, + /*IsExecConfig=*/true); } -Sema::CUDAFunctionTarget -Sema::IdentifyCUDATarget(const ParsedAttributesView &Attrs) { +CUDAFunctionTarget SemaCUDA::IdentifyTarget(const ParsedAttributesView &Attrs) { bool HasHostAttr = false; bool HasDeviceAttr = false; bool HasGlobalAttr = false; @@ -90,18 +93,18 @@ Sema::IdentifyCUDATarget(const ParsedAttributesView &Attrs) { } if (HasInvalidTargetAttr) - return CFT_InvalidTarget; + return CUDAFunctionTarget::InvalidTarget; if (HasGlobalAttr) - return CFT_Global; + return CUDAFunctionTarget::Global; if (HasHostAttr && HasDeviceAttr) - return CFT_HostDevice; + return CUDAFunctionTarget::HostDevice; if (HasDeviceAttr) - return CFT_Device; + return CUDAFunctionTarget::Device; - return CFT_Host; + return CUDAFunctionTarget::Host; } template @@ -112,55 +115,54 @@ static bool hasAttr(const Decl *D, bool IgnoreImplicitAttr) { }); } -Sema::CUDATargetContextRAII::CUDATargetContextRAII(Sema &S_, - CUDATargetContextKind K, - Decl *D) +SemaCUDA::CUDATargetContextRAII::CUDATargetContextRAII( + SemaCUDA &S_, SemaCUDA::CUDATargetContextKind K, Decl *D) : S(S_) { SavedCtx = S.CurCUDATargetCtx; - assert(K == CTCK_InitGlobalVar); + assert(K == SemaCUDA::CTCK_InitGlobalVar); auto *VD = dyn_cast_or_null(D); if (VD && VD->hasGlobalStorage() && !VD->isStaticLocal()) { - auto Target = CFT_Host; + auto Target = CUDAFunctionTarget::Host; if ((hasAttr(VD, /*IgnoreImplicit=*/true) && !hasAttr(VD, /*IgnoreImplicit=*/true)) || hasAttr(VD, /*IgnoreImplicit=*/true) || hasAttr(VD, /*IgnoreImplicit=*/true)) - Target = CFT_Device; + Target = CUDAFunctionTarget::Device; S.CurCUDATargetCtx = {Target, K, VD}; } } -/// IdentifyCUDATarget - Determine the CUDA compilation target for this function -Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D, - bool IgnoreImplicitHDAttr) { +/// IdentifyTarget - Determine the CUDA compilation target for this function +CUDAFunctionTarget SemaCUDA::IdentifyTarget(const FunctionDecl *D, + bool IgnoreImplicitHDAttr) { // Code that lives outside a function gets the target from CurCUDATargetCtx. if (D == nullptr) return CurCUDATargetCtx.Target; if (D->hasAttr()) - return CFT_InvalidTarget; + return CUDAFunctionTarget::InvalidTarget; if (D->hasAttr()) - return CFT_Global; + return CUDAFunctionTarget::Global; if (hasAttr(D, IgnoreImplicitHDAttr)) { if (hasAttr(D, IgnoreImplicitHDAttr)) - return CFT_HostDevice; - return CFT_Device; + return CUDAFunctionTarget::HostDevice; + return CUDAFunctionTarget::Device; } else if (hasAttr(D, IgnoreImplicitHDAttr)) { - return CFT_Host; + return CUDAFunctionTarget::Host; } else if ((D->isImplicit() || !D->isUserProvided()) && !IgnoreImplicitHDAttr) { // Some implicit declarations (like intrinsic functions) are not marked. // Set the most lenient target on them for maximal flexibility. - return CFT_HostDevice; + return CUDAFunctionTarget::HostDevice; } - return CFT_Host; + return CUDAFunctionTarget::Host; } /// IdentifyTarget - Determine the CUDA compilation target for this variable. -Sema::CUDAVariableTarget Sema::IdentifyCUDATarget(const VarDecl *Var) { +SemaCUDA::CUDAVariableTarget SemaCUDA::IdentifyTarget(const VarDecl *Var) { if (Var->hasAttr()) return CVT_Unified; // Only constexpr and const variabless with implicit constant attribute @@ -180,11 +182,11 @@ Sema::CUDAVariableTarget Sema::IdentifyCUDATarget(const VarDecl *Var) { // - on both sides in host device functions // - on device side in device or global functions if (auto *FD = dyn_cast(Var->getDeclContext())) { - switch (IdentifyCUDATarget(FD)) { - case CFT_HostDevice: + switch (IdentifyTarget(FD)) { + case CUDAFunctionTarget::HostDevice: return CVT_Both; - case CFT_Device: - case CFT_Global: + case CUDAFunctionTarget::Device: + case CUDAFunctionTarget::Global: return CVT_Device; default: return CVT_Host; @@ -221,58 +223,65 @@ Sema::CUDAVariableTarget Sema::IdentifyCUDATarget(const VarDecl *Var) { // | hd | h | SS | WS | (d) | // | hd | hd | HD | HD | (b) | -Sema::CUDAFunctionPreference -Sema::IdentifyCUDAPreference(const FunctionDecl *Caller, +SemaCUDA::CUDAFunctionPreference +SemaCUDA::IdentifyPreference(const FunctionDecl *Caller, const FunctionDecl *Callee) { assert(Callee && "Callee must be valid."); // Treat ctor/dtor as host device function in device var initializer to allow // trivial ctor/dtor without device attr to be used. Non-trivial ctor/dtor - // will be diagnosed by checkAllowedCUDAInitializer. + // will be diagnosed by checkAllowedInitializer. if (Caller == nullptr && CurCUDATargetCtx.Kind == CTCK_InitGlobalVar && - CurCUDATargetCtx.Target == CFT_Device && + CurCUDATargetCtx.Target == CUDAFunctionTarget::Device && (isa(Callee) || isa(Callee))) return CFP_HostDevice; - CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller); - CUDAFunctionTarget CalleeTarget = IdentifyCUDATarget(Callee); + CUDAFunctionTarget CallerTarget = IdentifyTarget(Caller); + CUDAFunctionTarget CalleeTarget = IdentifyTarget(Callee); // If one of the targets is invalid, the check always fails, no matter what // the other target is. - if (CallerTarget == CFT_InvalidTarget || CalleeTarget == CFT_InvalidTarget) + if (CallerTarget == CUDAFunctionTarget::InvalidTarget || + CalleeTarget == CUDAFunctionTarget::InvalidTarget) return CFP_Never; // (a) Can't call global from some contexts until we support CUDA's // dynamic parallelism. - if (CalleeTarget == CFT_Global && - (CallerTarget == CFT_Global || CallerTarget == CFT_Device)) + if (CalleeTarget == CUDAFunctionTarget::Global && + (CallerTarget == CUDAFunctionTarget::Global || + CallerTarget == CUDAFunctionTarget::Device)) return CFP_Never; // (b) Calling HostDevice is OK for everyone. - if (CalleeTarget == CFT_HostDevice) + if (CalleeTarget == CUDAFunctionTarget::HostDevice) return CFP_HostDevice; // (c) Best case scenarios if (CalleeTarget == CallerTarget || - (CallerTarget == CFT_Host && CalleeTarget == CFT_Global) || - (CallerTarget == CFT_Global && CalleeTarget == CFT_Device)) + (CallerTarget == CUDAFunctionTarget::Host && + CalleeTarget == CUDAFunctionTarget::Global) || + (CallerTarget == CUDAFunctionTarget::Global && + CalleeTarget == CUDAFunctionTarget::Device)) return CFP_Native; // HipStdPar mode is special, in that assessing whether a device side call to // a host target is deferred to a subsequent pass, and cannot unambiguously be // adjudicated in the AST, hence we optimistically allow them to pass here. if (getLangOpts().HIPStdPar && - (CallerTarget == CFT_Global || CallerTarget == CFT_Device || - CallerTarget == CFT_HostDevice) && - CalleeTarget == CFT_Host) + (CallerTarget == CUDAFunctionTarget::Global || + CallerTarget == CUDAFunctionTarget::Device || + CallerTarget == CUDAFunctionTarget::HostDevice) && + CalleeTarget == CUDAFunctionTarget::Host) return CFP_HostDevice; // (d) HostDevice behavior depends on compilation mode. - if (CallerTarget == CFT_HostDevice) { + if (CallerTarget == CUDAFunctionTarget::HostDevice) { // It's OK to call a compilation-mode matching function from an HD one. - if ((getLangOpts().CUDAIsDevice && CalleeTarget == CFT_Device) || + if ((getLangOpts().CUDAIsDevice && + CalleeTarget == CUDAFunctionTarget::Device) || (!getLangOpts().CUDAIsDevice && - (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global))) + (CalleeTarget == CUDAFunctionTarget::Host || + CalleeTarget == CUDAFunctionTarget::Global))) return CFP_SameSide; // Calls from HD to non-mode-matching functions (i.e., to host functions @@ -283,9 +292,12 @@ Sema::IdentifyCUDAPreference(const FunctionDecl *Caller, } // (e) Calling across device/host boundary is not something you should do. - if ((CallerTarget == CFT_Host && CalleeTarget == CFT_Device) || - (CallerTarget == CFT_Device && CalleeTarget == CFT_Host) || - (CallerTarget == CFT_Global && CalleeTarget == CFT_Host)) + if ((CallerTarget == CUDAFunctionTarget::Host && + CalleeTarget == CUDAFunctionTarget::Device) || + (CallerTarget == CUDAFunctionTarget::Device && + CalleeTarget == CUDAFunctionTarget::Host) || + (CallerTarget == CUDAFunctionTarget::Global && + CalleeTarget == CUDAFunctionTarget::Host)) return CFP_Never; llvm_unreachable("All cases should've been handled by now."); @@ -299,13 +311,13 @@ template static bool hasImplicitAttr(const FunctionDecl *D) { return D->isImplicit(); } -bool Sema::isCUDAImplicitHostDeviceFunction(const FunctionDecl *D) { +bool SemaCUDA::isImplicitHostDeviceFunction(const FunctionDecl *D) { bool IsImplicitDevAttr = hasImplicitAttr(D); bool IsImplicitHostAttr = hasImplicitAttr(D); return IsImplicitDevAttr && IsImplicitHostAttr; } -void Sema::EraseUnwantedCUDAMatches( +void SemaCUDA::EraseUnwantedMatches( const FunctionDecl *Caller, SmallVectorImpl> &Matches) { if (Matches.size() <= 1) @@ -315,7 +327,7 @@ void Sema::EraseUnwantedCUDAMatches( // Gets the CUDA function preference for a call from Caller to Match. auto GetCFP = [&](const Pair &Match) { - return IdentifyCUDAPreference(Caller, Match.second); + return IdentifyPreference(Caller, Match.second); }; // Find the best call preference among the functions in Matches. @@ -337,16 +349,16 @@ void Sema::EraseUnwantedCUDAMatches( /// \param ResolvedTarget with a target that resolves for both calls. /// \return true if there's a conflict, false otherwise. static bool -resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1, - Sema::CUDAFunctionTarget Target2, - Sema::CUDAFunctionTarget *ResolvedTarget) { +resolveCalleeCUDATargetConflict(CUDAFunctionTarget Target1, + CUDAFunctionTarget Target2, + CUDAFunctionTarget *ResolvedTarget) { // Only free functions and static member functions may be global. - assert(Target1 != Sema::CFT_Global); - assert(Target2 != Sema::CFT_Global); + assert(Target1 != CUDAFunctionTarget::Global); + assert(Target2 != CUDAFunctionTarget::Global); - if (Target1 == Sema::CFT_HostDevice) { + if (Target1 == CUDAFunctionTarget::HostDevice) { *ResolvedTarget = Target2; - } else if (Target2 == Sema::CFT_HostDevice) { + } else if (Target2 == CUDAFunctionTarget::HostDevice) { *ResolvedTarget = Target1; } else if (Target1 != Target2) { return true; @@ -357,8 +369,8 @@ resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1, return false; } -bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, - CXXSpecialMember CSM, +bool SemaCUDA::inferTargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, + CXXSpecialMemberKind CSM, CXXMethodDecl *MemberDecl, bool ConstRHS, bool Diagnose) { @@ -378,7 +390,7 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, // We're going to invoke special member lookup; mark that these special // members are called from this one, and not from its caller. - ContextRAII MethodContext(*this, MemberDecl); + Sema::ContextRAII MethodContext(SemaRef, MemberDecl); // Look for special members in base classes that should be invoked from here. // Infer the target of this member base on the ones it should call. @@ -402,17 +414,17 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, CXXRecordDecl *BaseClassDecl = cast(BaseType->getDecl()); Sema::SpecialMemberOverloadResult SMOR = - LookupSpecialMember(BaseClassDecl, CSM, - /* ConstArg */ ConstRHS, - /* VolatileArg */ false, - /* RValueThis */ false, - /* ConstThis */ false, - /* VolatileThis */ false); + SemaRef.LookupSpecialMember(BaseClassDecl, CSM, + /* ConstArg */ ConstRHS, + /* VolatileArg */ false, + /* RValueThis */ false, + /* ConstThis */ false, + /* VolatileThis */ false); if (!SMOR.getMethod()) continue; - CUDAFunctionTarget BaseMethodTarget = IdentifyCUDATarget(SMOR.getMethod()); + CUDAFunctionTarget BaseMethodTarget = IdentifyTarget(SMOR.getMethod()); if (!InferredTarget) { InferredTarget = BaseMethodTarget; } else { @@ -422,9 +434,11 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, if (Diagnose) { Diag(ClassDecl->getLocation(), diag::note_implicit_member_target_infer_collision) - << (unsigned)CSM << *InferredTarget << BaseMethodTarget; + << (unsigned)CSM << llvm::to_underlying(*InferredTarget) + << llvm::to_underlying(BaseMethodTarget); } - MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context)); + MemberDecl->addAttr( + CUDAInvalidTargetAttr::CreateImplicit(getASTContext())); return true; } } @@ -437,25 +451,24 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, } const RecordType *FieldType = - Context.getBaseElementType(F->getType())->getAs(); + getASTContext().getBaseElementType(F->getType())->getAs(); if (!FieldType) { continue; } CXXRecordDecl *FieldRecDecl = cast(FieldType->getDecl()); Sema::SpecialMemberOverloadResult SMOR = - LookupSpecialMember(FieldRecDecl, CSM, - /* ConstArg */ ConstRHS && !F->isMutable(), - /* VolatileArg */ false, - /* RValueThis */ false, - /* ConstThis */ false, - /* VolatileThis */ false); + SemaRef.LookupSpecialMember(FieldRecDecl, CSM, + /* ConstArg */ ConstRHS && !F->isMutable(), + /* VolatileArg */ false, + /* RValueThis */ false, + /* ConstThis */ false, + /* VolatileThis */ false); if (!SMOR.getMethod()) continue; - CUDAFunctionTarget FieldMethodTarget = - IdentifyCUDATarget(SMOR.getMethod()); + CUDAFunctionTarget FieldMethodTarget = IdentifyTarget(SMOR.getMethod()); if (!InferredTarget) { InferredTarget = FieldMethodTarget; } else { @@ -465,9 +478,11 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, if (Diagnose) { Diag(ClassDecl->getLocation(), diag::note_implicit_member_target_infer_collision) - << (unsigned)CSM << *InferredTarget << FieldMethodTarget; + << (unsigned)CSM << llvm::to_underlying(*InferredTarget) + << llvm::to_underlying(FieldMethodTarget); } - MemberDecl->addAttr(CUDAInvalidTargetAttr::CreateImplicit(Context)); + MemberDecl->addAttr( + CUDAInvalidTargetAttr::CreateImplicit(getASTContext())); return true; } } @@ -478,25 +493,25 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, // it's the least restrictive option that can be invoked from any target. bool NeedsH = true, NeedsD = true; if (InferredTarget) { - if (*InferredTarget == CFT_Device) + if (*InferredTarget == CUDAFunctionTarget::Device) NeedsH = false; - else if (*InferredTarget == CFT_Host) + else if (*InferredTarget == CUDAFunctionTarget::Host) NeedsD = false; } // We either setting attributes first time, or the inferred ones must match // previously set ones. if (NeedsD && !HasD) - MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(Context)); + MemberDecl->addAttr(CUDADeviceAttr::CreateImplicit(getASTContext())); if (NeedsH && !HasH) - MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(Context)); + MemberDecl->addAttr(CUDAHostAttr::CreateImplicit(getASTContext())); return false; } -bool Sema::isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD) { +bool SemaCUDA::isEmptyConstructor(SourceLocation Loc, CXXConstructorDecl *CD) { if (!CD->isDefined() && CD->isTemplateInstantiation()) - InstantiateFunctionDefinition(Loc, CD->getFirstDecl()); + SemaRef.InstantiateFunctionDefinition(Loc, CD->getFirstDecl()); // (E.2.3.1, CUDA 7.5) A constructor for a class type is considered // empty at a point in the translation unit, if it is either a @@ -524,7 +539,7 @@ bool Sema::isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD) { if (!llvm::all_of(CD->inits(), [&](const CXXCtorInitializer *CI) { if (const CXXConstructExpr *CE = dyn_cast(CI->getInit())) - return isEmptyCudaConstructor(Loc, CE->getConstructor()); + return isEmptyConstructor(Loc, CE->getConstructor()); return false; })) return false; @@ -532,13 +547,13 @@ bool Sema::isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD) { return true; } -bool Sema::isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *DD) { +bool SemaCUDA::isEmptyDestructor(SourceLocation Loc, CXXDestructorDecl *DD) { // No destructor -> no problem. if (!DD) return true; if (!DD->isDefined() && DD->isTemplateInstantiation()) - InstantiateFunctionDefinition(Loc, DD->getFirstDecl()); + SemaRef.InstantiateFunctionDefinition(Loc, DD->getFirstDecl()); // (E.2.3.1, CUDA 7.5) A destructor for a class type is considered // empty at a point in the translation unit, if it is either a @@ -567,7 +582,7 @@ bool Sema::isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *DD) { // destructors for all base classes... if (!llvm::all_of(ClassDecl->bases(), [&](const CXXBaseSpecifier &BS) { if (CXXRecordDecl *RD = BS.getType()->getAsCXXRecordDecl()) - return isEmptyCudaDestructor(Loc, RD->getDestructor()); + return isEmptyDestructor(Loc, RD->getDestructor()); return true; })) return false; @@ -577,7 +592,7 @@ bool Sema::isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *DD) { if (CXXRecordDecl *RD = Field->getType() ->getBaseElementTypeUnsafe() ->getAsCXXRecordDecl()) - return isEmptyCudaDestructor(Loc, RD->getDestructor()); + return isEmptyDestructor(Loc, RD->getDestructor()); return true; })) return false; @@ -608,7 +623,7 @@ bool IsDependentVar(VarDecl *VD) { // __shared__ variables whether they are local or not (they all are implicitly // static in CUDA). One exception is that CUDA allows constant initializers // for __constant__ and __device__ variables. -bool HasAllowedCUDADeviceStaticInitializer(Sema &S, VarDecl *VD, +bool HasAllowedCUDADeviceStaticInitializer(SemaCUDA &S, VarDecl *VD, CUDAInitializerCheckKind CheckKind) { assert(!VD->isInvalidDecl() && VD->hasGlobalStorage()); assert(!IsDependentVar(VD) && "do not check dependent var"); @@ -617,30 +632,30 @@ bool HasAllowedCUDADeviceStaticInitializer(Sema &S, VarDecl *VD, if (!Init) return true; if (const auto *CE = dyn_cast(Init)) { - return S.isEmptyCudaConstructor(VD->getLocation(), CE->getConstructor()); + return S.isEmptyConstructor(VD->getLocation(), CE->getConstructor()); } return false; }; auto IsConstantInit = [&](const Expr *Init) { assert(Init); - ASTContext::CUDAConstantEvalContextRAII EvalCtx(S.Context, + ASTContext::CUDAConstantEvalContextRAII EvalCtx(S.getASTContext(), /*NoWronSidedVars=*/true); - return Init->isConstantInitializer(S.Context, + return Init->isConstantInitializer(S.getASTContext(), VD->getType()->isReferenceType()); }; auto HasEmptyDtor = [&](VarDecl *VD) { if (const auto *RD = VD->getType()->getAsCXXRecordDecl()) - return S.isEmptyCudaDestructor(VD->getLocation(), RD->getDestructor()); + return S.isEmptyDestructor(VD->getLocation(), RD->getDestructor()); return true; }; if (CheckKind == CICK_Shared) return IsEmptyInit(Init) && HasEmptyDtor(VD); - return S.LangOpts.GPUAllowDeviceInit || + return S.getLangOpts().GPUAllowDeviceInit || ((IsEmptyInit(Init) || IsConstantInit(Init)) && HasEmptyDtor(VD)); } } // namespace -void Sema::checkAllowedCUDAInitializer(VarDecl *VD) { +void SemaCUDA::checkAllowedInitializer(VarDecl *VD) { // Return early if VD is inside a non-instantiated template function since // the implicit constructor is not defined yet. if (const FunctionDecl *FD = @@ -676,10 +691,11 @@ void Sema::checkAllowedCUDAInitializer(VarDecl *VD) { InitFn = CE->getDirectCallee(); } if (InitFn) { - CUDAFunctionTarget InitFnTarget = IdentifyCUDATarget(InitFn); - if (InitFnTarget != CFT_Host && InitFnTarget != CFT_HostDevice) { + CUDAFunctionTarget InitFnTarget = IdentifyTarget(InitFn); + if (InitFnTarget != CUDAFunctionTarget::Host && + InitFnTarget != CUDAFunctionTarget::HostDevice) { Diag(VD->getLocation(), diag::err_ref_bad_target_global_initializer) - << InitFnTarget << InitFn; + << llvm::to_underlying(InitFnTarget) << InitFn; Diag(InitFn->getLocation(), diag::note_previous_decl) << InitFn; VD->setInvalidDecl(); } @@ -687,21 +703,22 @@ void Sema::checkAllowedCUDAInitializer(VarDecl *VD) { } } -void Sema::CUDARecordImplicitHostDeviceFuncUsedByDevice( +void SemaCUDA::RecordImplicitHostDeviceFuncUsedByDevice( const FunctionDecl *Callee) { - FunctionDecl *Caller = getCurFunctionDecl(/*AllowLambda=*/true); + FunctionDecl *Caller = SemaRef.getCurFunctionDecl(/*AllowLambda=*/true); if (!Caller) return; - if (!isCUDAImplicitHostDeviceFunction(Callee)) + if (!isImplicitHostDeviceFunction(Callee)) return; - CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller); + CUDAFunctionTarget CallerTarget = IdentifyTarget(Caller); // Record whether an implicit host device function is used on device side. - if (CallerTarget != CFT_Device && CallerTarget != CFT_Global && - (CallerTarget != CFT_HostDevice || - (isCUDAImplicitHostDeviceFunction(Caller) && + if (CallerTarget != CUDAFunctionTarget::Device && + CallerTarget != CUDAFunctionTarget::Global && + (CallerTarget != CUDAFunctionTarget::HostDevice || + (isImplicitHostDeviceFunction(Caller) && !getASTContext().CUDAImplicitHostDeviceFunUsedByDevice.count(Caller)))) return; @@ -717,18 +734,18 @@ void Sema::CUDARecordImplicitHostDeviceFuncUsedByDevice( // system header, in which case we leave the constexpr function unattributed. // // In addition, all function decls are treated as __host__ __device__ when -// ForceCUDAHostDeviceDepth > 0 (corresponding to code within a +// ForceHostDeviceDepth > 0 (corresponding to code within a // #pragma clang force_cuda_host_device_begin/end // pair). -void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD, +void SemaCUDA::maybeAddHostDeviceAttrs(FunctionDecl *NewD, const LookupResult &Previous) { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); - if (ForceCUDAHostDeviceDepth > 0) { + if (ForceHostDeviceDepth > 0) { if (!NewD->hasAttr()) - NewD->addAttr(CUDAHostAttr::CreateImplicit(Context)); + NewD->addAttr(CUDAHostAttr::CreateImplicit(getASTContext())); if (!NewD->hasAttr()) - NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context)); + NewD->addAttr(CUDADeviceAttr::CreateImplicit(getASTContext())); return; } @@ -739,8 +756,8 @@ void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD, !NewD->hasAttr() && (NewD->getDescribedFunctionTemplate() || NewD->isFunctionTemplateSpecialization())) { - NewD->addAttr(CUDAHostAttr::CreateImplicit(Context)); - NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context)); + NewD->addAttr(CUDAHostAttr::CreateImplicit(getASTContext())); + NewD->addAttr(CUDADeviceAttr::CreateImplicit(getASTContext())); return; } @@ -757,8 +774,9 @@ void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD, FunctionDecl *OldD = D->getAsFunction(); return OldD && OldD->hasAttr() && !OldD->hasAttr() && - !IsOverload(NewD, OldD, /* UseMemberUsingDeclRules = */ false, - /* ConsiderCudaAttrs = */ false); + !SemaRef.IsOverload(NewD, OldD, + /* UseMemberUsingDeclRules = */ false, + /* ConsiderCudaAttrs = */ false); }; auto It = llvm::find_if(Previous, IsMatchingDeviceFn); if (It != Previous.end()) { @@ -767,7 +785,7 @@ void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD, // in a system header, in which case we simply return without making NewD // host+device. NamedDecl *Match = *It; - if (!getSourceManager().isInSystemHeader(Match->getLocation())) { + if (!SemaRef.getSourceManager().isInSystemHeader(Match->getLocation())) { Diag(NewD->getLocation(), diag::err_cuda_unattributed_constexpr_cannot_overload_device) << NewD; @@ -777,14 +795,14 @@ void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD, return; } - NewD->addAttr(CUDAHostAttr::CreateImplicit(Context)); - NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context)); + NewD->addAttr(CUDAHostAttr::CreateImplicit(getASTContext())); + NewD->addAttr(CUDADeviceAttr::CreateImplicit(getASTContext())); } // TODO: `__constant__` memory may be a limited resource for certain targets. // A safeguard may be needed at the end of compilation pipeline if // `__constant__` memory usage goes beyond limit. -void Sema::MaybeAddCUDAConstantAttr(VarDecl *VD) { +void SemaCUDA::MaybeAddConstantAttr(VarDecl *VD) { // Do not promote dependent variables since the cotr/dtor/initializer are // not determined. Do it after instantiation. if (getLangOpts().CUDAIsDevice && !VD->hasAttr() && @@ -798,86 +816,90 @@ void Sema::MaybeAddCUDAConstantAttr(VarDecl *VD) { } } -Sema::SemaDiagnosticBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc, - unsigned DiagID) { +SemaBase::SemaDiagnosticBuilder SemaCUDA::DiagIfDeviceCode(SourceLocation Loc, + unsigned DiagID) { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); - FunctionDecl *CurFunContext = getCurFunctionDecl(/*AllowLambda=*/true); + FunctionDecl *CurFunContext = + SemaRef.getCurFunctionDecl(/*AllowLambda=*/true); SemaDiagnosticBuilder::Kind DiagKind = [&] { if (!CurFunContext) return SemaDiagnosticBuilder::K_Nop; - switch (CurrentCUDATarget()) { - case CFT_Global: - case CFT_Device: + switch (CurrentTarget()) { + case CUDAFunctionTarget::Global: + case CUDAFunctionTarget::Device: return SemaDiagnosticBuilder::K_Immediate; - case CFT_HostDevice: + case CUDAFunctionTarget::HostDevice: // An HD function counts as host code if we're compiling for host, and // device code if we're compiling for device. Defer any errors in device // mode until the function is known-emitted. if (!getLangOpts().CUDAIsDevice) return SemaDiagnosticBuilder::K_Nop; - if (IsLastErrorImmediate && Diags.getDiagnosticIDs()->isBuiltinNote(DiagID)) + if (SemaRef.IsLastErrorImmediate && + getDiagnostics().getDiagnosticIDs()->isBuiltinNote(DiagID)) return SemaDiagnosticBuilder::K_Immediate; - return (getEmissionStatus(CurFunContext) == - FunctionEmissionStatus::Emitted) + return (SemaRef.getEmissionStatus(CurFunContext) == + Sema::FunctionEmissionStatus::Emitted) ? SemaDiagnosticBuilder::K_ImmediateWithCallStack : SemaDiagnosticBuilder::K_Deferred; default: return SemaDiagnosticBuilder::K_Nop; } }(); - return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, CurFunContext, *this); + return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, CurFunContext, SemaRef); } -Sema::SemaDiagnosticBuilder Sema::CUDADiagIfHostCode(SourceLocation Loc, +Sema::SemaDiagnosticBuilder SemaCUDA::DiagIfHostCode(SourceLocation Loc, unsigned DiagID) { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); - FunctionDecl *CurFunContext = getCurFunctionDecl(/*AllowLambda=*/true); + FunctionDecl *CurFunContext = + SemaRef.getCurFunctionDecl(/*AllowLambda=*/true); SemaDiagnosticBuilder::Kind DiagKind = [&] { if (!CurFunContext) return SemaDiagnosticBuilder::K_Nop; - switch (CurrentCUDATarget()) { - case CFT_Host: + switch (CurrentTarget()) { + case CUDAFunctionTarget::Host: return SemaDiagnosticBuilder::K_Immediate; - case CFT_HostDevice: + case CUDAFunctionTarget::HostDevice: // An HD function counts as host code if we're compiling for host, and // device code if we're compiling for device. Defer any errors in device // mode until the function is known-emitted. if (getLangOpts().CUDAIsDevice) return SemaDiagnosticBuilder::K_Nop; - if (IsLastErrorImmediate && Diags.getDiagnosticIDs()->isBuiltinNote(DiagID)) + if (SemaRef.IsLastErrorImmediate && + getDiagnostics().getDiagnosticIDs()->isBuiltinNote(DiagID)) return SemaDiagnosticBuilder::K_Immediate; - return (getEmissionStatus(CurFunContext) == - FunctionEmissionStatus::Emitted) + return (SemaRef.getEmissionStatus(CurFunContext) == + Sema::FunctionEmissionStatus::Emitted) ? SemaDiagnosticBuilder::K_ImmediateWithCallStack : SemaDiagnosticBuilder::K_Deferred; default: return SemaDiagnosticBuilder::K_Nop; } }(); - return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, CurFunContext, *this); + return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, CurFunContext, SemaRef); } -bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) { +bool SemaCUDA::CheckCall(SourceLocation Loc, FunctionDecl *Callee) { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); assert(Callee && "Callee may not be null."); - const auto &ExprEvalCtx = currentEvaluationContext(); + const auto &ExprEvalCtx = SemaRef.currentEvaluationContext(); if (ExprEvalCtx.isUnevaluated() || ExprEvalCtx.isConstantEvaluated()) return true; // FIXME: Is bailing out early correct here? Should we instead assume that // the caller is a global initializer? - FunctionDecl *Caller = getCurFunctionDecl(/*AllowLambda=*/true); + FunctionDecl *Caller = SemaRef.getCurFunctionDecl(/*AllowLambda=*/true); if (!Caller) return true; // If the caller is known-emitted, mark the callee as known-emitted. // Otherwise, mark the call in our call graph so we can traverse it later. - bool CallerKnownEmitted = - getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted; + bool CallerKnownEmitted = SemaRef.getEmissionStatus(Caller) == + Sema::FunctionEmissionStatus::Emitted; SemaDiagnosticBuilder::Kind DiagKind = [this, Caller, Callee, CallerKnownEmitted] { - switch (IdentifyCUDAPreference(Caller, Callee)) { + switch (IdentifyPreference(Caller, Callee)) { case CFP_Never: case CFP_WrongSide: assert(Caller && "Never/wrongSide calls require a non-null caller"); @@ -894,7 +916,7 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) { if (DiagKind == SemaDiagnosticBuilder::K_Nop) { // For -fgpu-rdc, keep track of external kernels used by host functions. - if (LangOpts.CUDAIsDevice && LangOpts.GPURelocatableDeviceCode && + if (getLangOpts().CUDAIsDevice && getLangOpts().GPURelocatableDeviceCode && Callee->hasAttr() && !Callee->isDefined() && (!Caller || (!Caller->getDescribedFunctionTemplate() && getASTContext().GetGVALinkageForFunction(Caller) == @@ -910,12 +932,13 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) { if (!LocsWithCUDACallDiags.insert({Caller, Loc}).second) return true; - SemaDiagnosticBuilder(DiagKind, Loc, diag::err_ref_bad_target, Caller, *this) - << IdentifyCUDATarget(Callee) << /*function*/ 0 << Callee - << IdentifyCUDATarget(Caller); + SemaDiagnosticBuilder(DiagKind, Loc, diag::err_ref_bad_target, Caller, + SemaRef) + << llvm::to_underlying(IdentifyTarget(Callee)) << /*function*/ 0 << Callee + << llvm::to_underlying(IdentifyTarget(Caller)); if (!Callee->getBuiltinID()) SemaDiagnosticBuilder(DiagKind, Callee->getLocation(), - diag::note_previous_decl, Caller, *this) + diag::note_previous_decl, Caller, SemaRef) << Callee; return DiagKind != SemaDiagnosticBuilder::K_Immediate && DiagKind != SemaDiagnosticBuilder::K_ImmediateWithCallStack; @@ -926,7 +949,7 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) { // defined and uses the capture by reference when the lambda is called. When // the capture and use happen on different sides, the capture is invalid and // should be diagnosed. -void Sema::CUDACheckLambdaCapture(CXXMethodDecl *Callee, +void SemaCUDA::CheckLambdaCapture(CXXMethodDecl *Callee, const sema::Capture &Capture) { // In host compilation we only need to check lambda functions emitted on host // side. In such lambda functions, a reference capture is invalid only @@ -936,12 +959,12 @@ void Sema::CUDACheckLambdaCapture(CXXMethodDecl *Callee, // kernel cannot pass a lambda back to a host function since we cannot // define a kernel argument type which can hold the lambda before the lambda // itself is defined. - if (!LangOpts.CUDAIsDevice) + if (!getLangOpts().CUDAIsDevice) return; // File-scope lambda can only do init captures for global variables, which // results in passing by value for these global variables. - FunctionDecl *Caller = getCurFunctionDecl(/*AllowLambda=*/true); + FunctionDecl *Caller = SemaRef.getCurFunctionDecl(/*AllowLambda=*/true); if (!Caller) return; @@ -958,7 +981,7 @@ void Sema::CUDACheckLambdaCapture(CXXMethodDecl *Callee, auto DiagKind = SemaDiagnosticBuilder::K_Deferred; if (Capture.isVariableCapture() && !getLangOpts().HIPStdPar) { SemaDiagnosticBuilder(DiagKind, Capture.getLocation(), - diag::err_capture_bad_target, Callee, *this) + diag::err_capture_bad_target, Callee, SemaRef) << Capture.getVariable(); } else if (Capture.isThisCapture()) { // Capture of this pointer is allowed since this pointer may be pointing to @@ -967,47 +990,49 @@ void Sema::CUDACheckLambdaCapture(CXXMethodDecl *Callee, // accessible on device side. SemaDiagnosticBuilder(DiagKind, Capture.getLocation(), diag::warn_maybe_capture_bad_target_this_ptr, Callee, - *this); + SemaRef); } } -void Sema::CUDASetLambdaAttrs(CXXMethodDecl *Method) { +void SemaCUDA::SetLambdaAttrs(CXXMethodDecl *Method) { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); if (Method->hasAttr() || Method->hasAttr()) return; - Method->addAttr(CUDADeviceAttr::CreateImplicit(Context)); - Method->addAttr(CUDAHostAttr::CreateImplicit(Context)); + Method->addAttr(CUDADeviceAttr::CreateImplicit(getASTContext())); + Method->addAttr(CUDAHostAttr::CreateImplicit(getASTContext())); } -void Sema::checkCUDATargetOverload(FunctionDecl *NewFD, +void SemaCUDA::checkTargetOverload(FunctionDecl *NewFD, const LookupResult &Previous) { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); - CUDAFunctionTarget NewTarget = IdentifyCUDATarget(NewFD); + CUDAFunctionTarget NewTarget = IdentifyTarget(NewFD); for (NamedDecl *OldND : Previous) { FunctionDecl *OldFD = OldND->getAsFunction(); if (!OldFD) continue; - CUDAFunctionTarget OldTarget = IdentifyCUDATarget(OldFD); + CUDAFunctionTarget OldTarget = IdentifyTarget(OldFD); // Don't allow HD and global functions to overload other functions with the // same signature. We allow overloading based on CUDA attributes so that // functions can have different implementations on the host and device, but // HD/global functions "exist" in some sense on both the host and device, so // should have the same implementation on both sides. if (NewTarget != OldTarget && - ((NewTarget == CFT_HostDevice && - !(LangOpts.OffloadImplicitHostDeviceTemplates && - isCUDAImplicitHostDeviceFunction(NewFD) && - OldTarget == CFT_Device)) || - (OldTarget == CFT_HostDevice && - !(LangOpts.OffloadImplicitHostDeviceTemplates && - isCUDAImplicitHostDeviceFunction(OldFD) && - NewTarget == CFT_Device)) || - (NewTarget == CFT_Global) || (OldTarget == CFT_Global)) && - !IsOverload(NewFD, OldFD, /* UseMemberUsingDeclRules = */ false, - /* ConsiderCudaAttrs = */ false)) { + ((NewTarget == CUDAFunctionTarget::HostDevice && + !(getLangOpts().OffloadImplicitHostDeviceTemplates && + isImplicitHostDeviceFunction(NewFD) && + OldTarget == CUDAFunctionTarget::Device)) || + (OldTarget == CUDAFunctionTarget::HostDevice && + !(getLangOpts().OffloadImplicitHostDeviceTemplates && + isImplicitHostDeviceFunction(OldFD) && + NewTarget == CUDAFunctionTarget::Device)) || + (NewTarget == CUDAFunctionTarget::Global) || + (OldTarget == CUDAFunctionTarget::Global)) && + !SemaRef.IsOverload(NewFD, OldFD, /* UseMemberUsingDeclRules = */ false, + /* ConsiderCudaAttrs = */ false)) { Diag(NewFD->getLocation(), diag::err_cuda_ovl_target) - << NewTarget << NewFD->getDeclName() << OldTarget << OldFD; + << llvm::to_underlying(NewTarget) << NewFD->getDeclName() + << llvm::to_underlying(OldTarget) << OldFD; Diag(OldFD->getLocation(), diag::note_previous_declaration); NewFD->setInvalidDecl(); break; @@ -1025,21 +1050,21 @@ static void copyAttrIfPresent(Sema &S, FunctionDecl *FD, } } -void Sema::inheritCUDATargetAttrs(FunctionDecl *FD, +void SemaCUDA::inheritTargetAttrs(FunctionDecl *FD, const FunctionTemplateDecl &TD) { const FunctionDecl &TemplateFD = *TD.getTemplatedDecl(); - copyAttrIfPresent(*this, FD, TemplateFD); - copyAttrIfPresent(*this, FD, TemplateFD); - copyAttrIfPresent(*this, FD, TemplateFD); + copyAttrIfPresent(SemaRef, FD, TemplateFD); + copyAttrIfPresent(SemaRef, FD, TemplateFD); + copyAttrIfPresent(SemaRef, FD, TemplateFD); } -std::string Sema::getCudaConfigureFuncName() const { +std::string SemaCUDA::getConfigureFuncName() const { if (getLangOpts().HIP) return getLangOpts().HIPUseNewLaunchAPI ? "__hipPushCallConfiguration" : "hipConfigureCall"; // New CUDA kernel launch sequence. - if (CudaFeatureEnabled(Context.getTargetInfo().getSDKVersion(), + if (CudaFeatureEnabled(getASTContext().getTargetInfo().getSDKVersion(), CudaFeature::CUDA_USES_NEW_LAUNCH)) return "__cudaPushCallConfiguration"; diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index 9d85568d97b2d27936b6b94c45b1546bf22cfa4e..b0c28531fe873854a9502347362c014271ebb66a 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -498,10 +498,22 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, howManyCandidates = OCD_AmbiguousCandidates; break; - case OR_Deleted: - msg = diag::err_ovl_deleted_conversion_in_cast; - howManyCandidates = OCD_ViableCandidates; - break; + case OR_Deleted: { + OverloadCandidateSet::iterator Best; + [[maybe_unused]] OverloadingResult Res = + candidates.BestViableFunction(S, range.getBegin(), Best); + assert(Res == OR_Deleted && "Inconsistent overload resolution"); + + StringLiteral *Msg = Best->Function->getDeletedMessage(); + candidates.NoteCandidates( + PartialDiagnosticAt(range.getBegin(), + S.PDiag(diag::err_ovl_deleted_conversion_in_cast) + << CT << srcType << destType << (Msg != nullptr) + << (Msg ? Msg->getString() : StringRef()) + << range << src->getSourceRange()), + S, OCD_ViableCandidates, src); + return true; + } } candidates.NoteCandidates( diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 4c30cc3160ded5e026d6d443d0ca105e636914e2..8e21811b67d900d7ca72fc2c99adc045e4acf3df 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -188,7 +188,7 @@ static bool convertArgumentToType(Sema &S, Expr *&Value, QualType Ty) { /// Check that the first argument to __builtin_annotation is an integer /// and the second argument is a non-wide string literal. -static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) { +static bool BuiltinAnnotation(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 2)) return true; @@ -214,7 +214,7 @@ static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) { return false; } -static bool SemaBuiltinMSVCAnnotation(Sema &S, CallExpr *TheCall) { +static bool BuiltinMSVCAnnotation(Sema &S, CallExpr *TheCall) { // We need at least one argument. if (TheCall->getNumArgs() < 1) { S.Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least) @@ -238,7 +238,7 @@ static bool SemaBuiltinMSVCAnnotation(Sema &S, CallExpr *TheCall) { /// Check that the argument to __builtin_addressof is a glvalue, and set the /// result type to the corresponding pointer type. -static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) { +static bool BuiltinAddressof(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) return true; @@ -253,7 +253,7 @@ static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) { } /// Check that the argument to __builtin_function_start is a function. -static bool SemaBuiltinFunctionStart(Sema &S, CallExpr *TheCall) { +static bool BuiltinFunctionStart(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) return true; @@ -277,7 +277,7 @@ static bool SemaBuiltinFunctionStart(Sema &S, CallExpr *TheCall) { /// Check the number of arguments and set the result type to /// the argument type. -static bool SemaBuiltinPreserveAI(Sema &S, CallExpr *TheCall) { +static bool BuiltinPreserveAI(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) return true; @@ -288,7 +288,7 @@ static bool SemaBuiltinPreserveAI(Sema &S, CallExpr *TheCall) { /// Check that the value argument for __builtin_is_aligned(value, alignment) and /// __builtin_aligned_{up,down}(value, alignment) is an integer or a pointer /// type (but not a function pointer) and that the alignment is a power-of-two. -static bool SemaBuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) { +static bool BuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) { if (checkArgCount(S, TheCall, 2)) return true; @@ -366,8 +366,7 @@ static bool SemaBuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) { return false; } -static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall, - unsigned BuiltinID) { +static bool BuiltinOverflow(Sema &S, CallExpr *TheCall, unsigned BuiltinID) { if (checkArgCount(S, TheCall, 3)) return true; @@ -695,7 +694,7 @@ struct BuiltinDumpStructGenerator { }; } // namespace -static ExprResult SemaBuiltinDumpStruct(Sema &S, CallExpr *TheCall) { +static ExprResult BuiltinDumpStruct(Sema &S, CallExpr *TheCall) { if (checkArgCountAtLeast(S, TheCall, 2)) return ExprError(); @@ -761,7 +760,7 @@ static ExprResult SemaBuiltinDumpStruct(Sema &S, CallExpr *TheCall) { return Generator.buildWrapper(); } -static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { +static bool BuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { if (checkArgCount(S, BuiltinCall, 2)) return true; @@ -1427,9 +1426,9 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, << FunctionName << DestinationStr << SourceStr); } -static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, - Scope::ScopeFlags NeededScopeFlags, - unsigned DiagID) { +static bool BuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, + Scope::ScopeFlags NeededScopeFlags, + unsigned DiagID) { // Scopes aren't available during instantiation. Fortunately, builtin // functions cannot be template args so they cannot be formed through template // instantiation. Therefore checking once during the parse is sufficient. @@ -1503,7 +1502,7 @@ static bool checkOpenCLSubgroupExt(Sema &S, CallExpr *Call) { return false; } -static bool SemaOpenCLBuiltinNDRangeAndBlock(Sema &S, CallExpr *TheCall) { +static bool OpenCLBuiltinNDRangeAndBlock(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 2)) return true; @@ -1530,7 +1529,7 @@ static bool SemaOpenCLBuiltinNDRangeAndBlock(Sema &S, CallExpr *TheCall) { /// OpenCL C v2.0, s6.13.17.6 - Check the argument to the /// get_kernel_work_group_size /// and get_kernel_preferred_work_group_size_multiple builtin functions. -static bool SemaOpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) { +static bool OpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) return true; @@ -1606,7 +1605,7 @@ static bool checkOpenCLEnqueueVariadicArgs(Sema &S, CallExpr *TheCall, /// clk_event_t *event_ret, /// void (^block)(local void*, ...), /// uint size0, ...) -static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { +static bool OpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { unsigned NumArgs = TheCall->getNumArgs(); if (NumArgs < 4) { @@ -1805,7 +1804,7 @@ static bool checkOpenCLPipePacketType(Sema &S, CallExpr *Call, unsigned Idx) { // \param S Reference to the semantic analyzer. // \param Call A pointer to the builtin call. // \return True if a semantic error has been found, false otherwise. -static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { +static bool BuiltinRWPipe(Sema &S, CallExpr *Call) { // OpenCL v2.0 s6.13.16.2 - The built-in read/write // functions have two forms. switch (Call->getNumArgs()) { @@ -1860,7 +1859,7 @@ static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. // \return True if a semantic error was found, false otherwise. -static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) { +static bool BuiltinReserveRWPipe(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 2)) return true; @@ -1889,7 +1888,7 @@ static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) { // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. // \return True if a semantic error was found, false otherwise. -static bool SemaBuiltinCommitRWPipe(Sema &S, CallExpr *Call) { +static bool BuiltinCommitRWPipe(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 2)) return true; @@ -1912,7 +1911,7 @@ static bool SemaBuiltinCommitRWPipe(Sema &S, CallExpr *Call) { // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. // \return True if a semantic error was found, false otherwise. -static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) { +static bool BuiltinPipePackets(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 1)) return true; @@ -1931,8 +1930,7 @@ static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) { // \param BuiltinID ID of the builtin function. // \param Call A pointer to the builtin call. // \return True if a semantic error has been found, false otherwise. -static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID, - CallExpr *Call) { +static bool OpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID, CallExpr *Call) { if (checkArgCount(S, Call, 1)) return true; @@ -2087,7 +2085,7 @@ static bool checkPointerAuthValue(Sema &S, Expr *&Arg, return false; } -static ExprResult SemaPointerAuthStrip(Sema &S, CallExpr *Call) { +static ExprResult PointerAuthStrip(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 2)) return ExprError(); if (checkPointerAuthEnabled(S, Call)) @@ -2100,7 +2098,7 @@ static ExprResult SemaPointerAuthStrip(Sema &S, CallExpr *Call) { return Call; } -static ExprResult SemaPointerAuthBlendDiscriminator(Sema &S, CallExpr *Call) { +static ExprResult PointerAuthBlendDiscriminator(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 2)) return ExprError(); if (checkPointerAuthEnabled(S, Call)) @@ -2113,7 +2111,7 @@ static ExprResult SemaPointerAuthBlendDiscriminator(Sema &S, CallExpr *Call) { return Call; } -static ExprResult SemaPointerAuthSignGenericData(Sema &S, CallExpr *Call) { +static ExprResult PointerAuthSignGenericData(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 2)) return ExprError(); if (checkPointerAuthEnabled(S, Call)) @@ -2126,8 +2124,8 @@ static ExprResult SemaPointerAuthSignGenericData(Sema &S, CallExpr *Call) { return Call; } -static ExprResult SemaPointerAuthSignOrAuth(Sema &S, CallExpr *Call, - PointerAuthOpKind OpKind) { +static ExprResult PointerAuthSignOrAuth(Sema &S, CallExpr *Call, + PointerAuthOpKind OpKind) { if (checkArgCount(S, Call, 3)) return ExprError(); if (checkPointerAuthEnabled(S, Call)) @@ -2141,7 +2139,7 @@ static ExprResult SemaPointerAuthSignOrAuth(Sema &S, CallExpr *Call, return Call; } -static ExprResult SemaPointerAuthAuthAndResign(Sema &S, CallExpr *Call) { +static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 5)) return ExprError(); if (checkPointerAuthEnabled(S, Call)) @@ -2157,7 +2155,7 @@ static ExprResult SemaPointerAuthAuthAndResign(Sema &S, CallExpr *Call) { return Call; } -static ExprResult SemaBuiltinLaunder(Sema &S, CallExpr *TheCall) { +static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) return ExprError(); @@ -2330,11 +2328,11 @@ static bool checkFPMathBuiltinElementType(Sema &S, SourceLocation Loc, return false; } -/// SemaBuiltinCpu{Supports|Is} - Handle __builtin_cpu_{supports|is}(char *). +/// BuiltinCpu{Supports|Is} - Handle __builtin_cpu_{supports|is}(char *). /// This checks that the target supports the builtin and that the string /// argument is constant and valid. -static bool SemaBuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall, - const TargetInfo *AuxTI, unsigned BuiltinID) { +static bool BuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall, + const TargetInfo *AuxTI, unsigned BuiltinID) { assert((BuiltinID == Builtin::BI__builtin_cpu_supports || BuiltinID == Builtin::BI__builtin_cpu_is) && "Expecting __builtin_cpu_..."); @@ -2379,7 +2377,7 @@ static bool SemaBuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall, /// Checks that __builtin_popcountg was called with a single argument, which is /// an unsigned integer. -static bool SemaBuiltinPopcountg(Sema &S, CallExpr *TheCall) { +static bool BuiltinPopcountg(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) return true; @@ -2403,7 +2401,7 @@ static bool SemaBuiltinPopcountg(Sema &S, CallExpr *TheCall) { /// Checks that __builtin_{clzg,ctzg} was called with a first argument, which is /// an unsigned integer, and an optional second argument, which is promoted to /// an 'int'. -static bool SemaBuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) { +static bool BuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) { if (checkArgCountRange(S, TheCall, 1, 2)) return true; @@ -2463,7 +2461,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, // If we don't have enough arguments, continue so we can issue better // diagnostic in checkArgCount(...) if (ArgNo < TheCall->getNumArgs() && - SemaBuiltinConstantArg(TheCall, ArgNo, Result)) + BuiltinConstantArg(TheCall, ArgNo, Result)) return true; ICEArguments &= ~(1 << ArgNo); } @@ -2472,8 +2470,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, switch (BuiltinID) { case Builtin::BI__builtin_cpu_supports: case Builtin::BI__builtin_cpu_is: - if (SemaBuiltinCpu(*this, Context.getTargetInfo(), TheCall, - Context.getAuxTargetInfo(), BuiltinID)) + if (BuiltinCpu(*this, Context.getTargetInfo(), TheCall, + Context.getAuxTargetInfo(), BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_cpu_init: @@ -2498,7 +2496,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_ms_va_start: case Builtin::BI__builtin_stdarg_start: case Builtin::BI__builtin_va_start: - if (SemaBuiltinVAStart(BuiltinID, TheCall)) + if (BuiltinVAStart(BuiltinID, TheCall)) return ExprError(); break; case Builtin::BI__va_start: { @@ -2506,11 +2504,11 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case llvm::Triple::aarch64: case llvm::Triple::arm: case llvm::Triple::thumb: - if (SemaBuiltinVAStartARMMicrosoft(TheCall)) + if (BuiltinVAStartARMMicrosoft(TheCall)) return ExprError(); break; default: - if (SemaBuiltinVAStart(BuiltinID, TheCall)) + if (BuiltinVAStart(BuiltinID, TheCall)) return ExprError(); break; } @@ -2558,15 +2556,15 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_islessequal: case Builtin::BI__builtin_islessgreater: case Builtin::BI__builtin_isunordered: - if (SemaBuiltinUnorderedCompare(TheCall, BuiltinID)) + if (BuiltinUnorderedCompare(TheCall, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_fpclassify: - if (SemaBuiltinFPClassification(TheCall, 6, BuiltinID)) + if (BuiltinFPClassification(TheCall, 6, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_isfpclass: - if (SemaBuiltinFPClassification(TheCall, 2, BuiltinID)) + if (BuiltinFPClassification(TheCall, 2, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_isfinite: @@ -2580,20 +2578,20 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_signbit: case Builtin::BI__builtin_signbitf: case Builtin::BI__builtin_signbitl: - if (SemaBuiltinFPClassification(TheCall, 1, BuiltinID)) + if (BuiltinFPClassification(TheCall, 1, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_shufflevector: - return SemaBuiltinShuffleVector(TheCall); + return BuiltinShuffleVector(TheCall); // TheCall will be freed by the smart pointer here, but that's fine, since - // SemaBuiltinShuffleVector guts it, but then doesn't release it. + // BuiltinShuffleVector guts it, but then doesn't release it. case Builtin::BI__builtin_prefetch: - if (SemaBuiltinPrefetch(TheCall)) + if (BuiltinPrefetch(TheCall)) return ExprError(); break; case Builtin::BI__builtin_alloca_with_align: case Builtin::BI__builtin_alloca_with_align_uninitialized: - if (SemaBuiltinAllocaWithAlign(TheCall)) + if (BuiltinAllocaWithAlign(TheCall)) return ExprError(); [[fallthrough]]; case Builtin::BI__builtin_alloca: @@ -2602,29 +2600,29 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, << TheCall->getDirectCallee(); break; case Builtin::BI__arithmetic_fence: - if (SemaBuiltinArithmeticFence(TheCall)) + if (BuiltinArithmeticFence(TheCall)) return ExprError(); break; case Builtin::BI__assume: case Builtin::BI__builtin_assume: - if (SemaBuiltinAssume(TheCall)) + if (BuiltinAssume(TheCall)) return ExprError(); break; case Builtin::BI__builtin_assume_aligned: - if (SemaBuiltinAssumeAligned(TheCall)) + if (BuiltinAssumeAligned(TheCall)) return ExprError(); break; case Builtin::BI__builtin_dynamic_object_size: case Builtin::BI__builtin_object_size: - if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3)) + if (BuiltinConstantArgRange(TheCall, 1, 0, 3)) return ExprError(); break; case Builtin::BI__builtin_longjmp: - if (SemaBuiltinLongjmp(TheCall)) + if (BuiltinLongjmp(TheCall)) return ExprError(); break; case Builtin::BI__builtin_setjmp: - if (SemaBuiltinSetjmp(TheCall)) + if (BuiltinSetjmp(TheCall)) return ExprError(); break; case Builtin::BI__builtin_classify_type: @@ -2632,7 +2630,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, TheCall->setType(Context.IntTy); break; case Builtin::BI__builtin_complex: - if (SemaBuiltinComplex(TheCall)) + if (BuiltinComplex(TheCall)) return ExprError(); break; case Builtin::BI__builtin_constant_p: { @@ -2644,7 +2642,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } case Builtin::BI__builtin_launder: - return SemaBuiltinLaunder(*this, TheCall); + return BuiltinLaunder(*this, TheCall); case Builtin::BI__sync_fetch_and_add: case Builtin::BI__sync_fetch_and_add_1: case Builtin::BI__sync_fetch_and_add_2: @@ -2747,14 +2745,14 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__sync_swap_4: case Builtin::BI__sync_swap_8: case Builtin::BI__sync_swap_16: - return SemaBuiltinAtomicOverloaded(TheCallResult); + return BuiltinAtomicOverloaded(TheCallResult); case Builtin::BI__sync_synchronize: Diag(TheCall->getBeginLoc(), diag::warn_atomic_implicit_seq_cst) << TheCall->getCallee()->getSourceRange(); break; case Builtin::BI__builtin_nontemporal_load: case Builtin::BI__builtin_nontemporal_store: - return SemaBuiltinNontemporalOverloaded(TheCallResult); + return BuiltinNontemporalOverloaded(TheCallResult); case Builtin::BI__builtin_memcpy_inline: { clang::Expr *SizeOp = TheCall->getArg(2); // We warn about copying to or from `nullptr` pointers when `size` is @@ -2780,49 +2778,49 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } #define BUILTIN(ID, TYPE, ATTRS) -#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ - case Builtin::BI##ID: \ - return SemaAtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID); +#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ + case Builtin::BI##ID: \ + return AtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID); #include "clang/Basic/Builtins.inc" case Builtin::BI__annotation: - if (SemaBuiltinMSVCAnnotation(*this, TheCall)) + if (BuiltinMSVCAnnotation(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_annotation: - if (SemaBuiltinAnnotation(*this, TheCall)) + if (BuiltinAnnotation(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_addressof: - if (SemaBuiltinAddressof(*this, TheCall)) + if (BuiltinAddressof(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_function_start: - if (SemaBuiltinFunctionStart(*this, TheCall)) + if (BuiltinFunctionStart(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_is_aligned: case Builtin::BI__builtin_align_up: case Builtin::BI__builtin_align_down: - if (SemaBuiltinAlignment(*this, TheCall, BuiltinID)) + if (BuiltinAlignment(*this, TheCall, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_add_overflow: case Builtin::BI__builtin_sub_overflow: case Builtin::BI__builtin_mul_overflow: - if (SemaBuiltinOverflow(*this, TheCall, BuiltinID)) + if (BuiltinOverflow(*this, TheCall, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_operator_new: case Builtin::BI__builtin_operator_delete: { bool IsDelete = BuiltinID == Builtin::BI__builtin_operator_delete; ExprResult Res = - SemaBuiltinOperatorNewDeleteOverloaded(TheCallResult, IsDelete); + BuiltinOperatorNewDeleteOverloaded(TheCallResult, IsDelete); if (Res.isInvalid()) CorrectDelayedTyposInExpr(TheCallResult.get()); return Res; } case Builtin::BI__builtin_dump_struct: - return SemaBuiltinDumpStruct(*this, TheCall); + return BuiltinDumpStruct(*this, TheCall); case Builtin::BI__builtin_expect_with_probability: { // We first want to ensure we are called with 3 arguments if (checkArgCount(*this, TheCall, 3)) @@ -2853,23 +2851,23 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } case Builtin::BI__builtin_preserve_access_index: - if (SemaBuiltinPreserveAI(*this, TheCall)) + if (BuiltinPreserveAI(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_call_with_static_chain: - if (SemaBuiltinCallWithStaticChain(*this, TheCall)) + if (BuiltinCallWithStaticChain(*this, TheCall)) return ExprError(); break; case Builtin::BI__exception_code: case Builtin::BI_exception_code: - if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHExceptScope, - diag::err_seh___except_block)) + if (BuiltinSEHScopeCheck(*this, TheCall, Scope::SEHExceptScope, + diag::err_seh___except_block)) return ExprError(); break; case Builtin::BI__exception_info: case Builtin::BI_exception_info: - if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHFilterScope, - diag::err_seh___except_filter)) + if (BuiltinSEHScopeCheck(*this, TheCall, Scope::SEHFilterScope, + diag::err_seh___except_filter)) return ExprError(); break; case Builtin::BI__GetExceptionInfo: @@ -2912,87 +2910,87 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } case Builtin::BI__builtin_ptrauth_strip: - return SemaPointerAuthStrip(*this, TheCall); + return PointerAuthStrip(*this, TheCall); case Builtin::BI__builtin_ptrauth_blend_discriminator: - return SemaPointerAuthBlendDiscriminator(*this, TheCall); + return PointerAuthBlendDiscriminator(*this, TheCall); case Builtin::BI__builtin_ptrauth_sign_unauthenticated: - return SemaPointerAuthSignOrAuth(*this, TheCall, PAO_Sign); + return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign); case Builtin::BI__builtin_ptrauth_auth: - return SemaPointerAuthSignOrAuth(*this, TheCall, PAO_Auth); + return PointerAuthSignOrAuth(*this, TheCall, PAO_Auth); case Builtin::BI__builtin_ptrauth_sign_generic_data: - return SemaPointerAuthSignGenericData(*this, TheCall); + return PointerAuthSignGenericData(*this, TheCall); case Builtin::BI__builtin_ptrauth_auth_and_resign: - return SemaPointerAuthAuthAndResign(*this, TheCall); + return PointerAuthAuthAndResign(*this, TheCall); // OpenCL v2.0, s6.13.16 - Pipe functions case Builtin::BIread_pipe: case Builtin::BIwrite_pipe: // Since those two functions are declared with var args, we need a semantic // check for the argument. - if (SemaBuiltinRWPipe(*this, TheCall)) + if (BuiltinRWPipe(*this, TheCall)) return ExprError(); break; case Builtin::BIreserve_read_pipe: case Builtin::BIreserve_write_pipe: case Builtin::BIwork_group_reserve_read_pipe: case Builtin::BIwork_group_reserve_write_pipe: - if (SemaBuiltinReserveRWPipe(*this, TheCall)) + if (BuiltinReserveRWPipe(*this, TheCall)) return ExprError(); break; case Builtin::BIsub_group_reserve_read_pipe: case Builtin::BIsub_group_reserve_write_pipe: if (checkOpenCLSubgroupExt(*this, TheCall) || - SemaBuiltinReserveRWPipe(*this, TheCall)) + BuiltinReserveRWPipe(*this, TheCall)) return ExprError(); break; case Builtin::BIcommit_read_pipe: case Builtin::BIcommit_write_pipe: case Builtin::BIwork_group_commit_read_pipe: case Builtin::BIwork_group_commit_write_pipe: - if (SemaBuiltinCommitRWPipe(*this, TheCall)) + if (BuiltinCommitRWPipe(*this, TheCall)) return ExprError(); break; case Builtin::BIsub_group_commit_read_pipe: case Builtin::BIsub_group_commit_write_pipe: if (checkOpenCLSubgroupExt(*this, TheCall) || - SemaBuiltinCommitRWPipe(*this, TheCall)) + BuiltinCommitRWPipe(*this, TheCall)) return ExprError(); break; case Builtin::BIget_pipe_num_packets: case Builtin::BIget_pipe_max_packets: - if (SemaBuiltinPipePackets(*this, TheCall)) + if (BuiltinPipePackets(*this, TheCall)) return ExprError(); break; case Builtin::BIto_global: case Builtin::BIto_local: case Builtin::BIto_private: - if (SemaOpenCLBuiltinToAddr(*this, BuiltinID, TheCall)) + if (OpenCLBuiltinToAddr(*this, BuiltinID, TheCall)) return ExprError(); break; // OpenCL v2.0, s6.13.17 - Enqueue kernel functions. case Builtin::BIenqueue_kernel: - if (SemaOpenCLBuiltinEnqueueKernel(*this, TheCall)) + if (OpenCLBuiltinEnqueueKernel(*this, TheCall)) return ExprError(); break; case Builtin::BIget_kernel_work_group_size: case Builtin::BIget_kernel_preferred_work_group_size_multiple: - if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) + if (OpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) return ExprError(); break; case Builtin::BIget_kernel_max_sub_group_size_for_ndrange: case Builtin::BIget_kernel_sub_group_count_for_ndrange: - if (SemaOpenCLBuiltinNDRangeAndBlock(*this, TheCall)) + if (OpenCLBuiltinNDRangeAndBlock(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_os_log_format: Cleanup.setExprNeedsCleanups(true); [[fallthrough]]; case Builtin::BI__builtin_os_log_format_buffer_size: - if (SemaBuiltinOSLogFormat(TheCall)) + if (BuiltinOSLogFormat(TheCall)) return ExprError(); break; case Builtin::BI__builtin_frame_address: case Builtin::BI__builtin_return_address: { - if (SemaBuiltinConstantArgRange(TheCall, 0, 0, 0xFFFF)) + if (BuiltinConstantArgRange(TheCall, 0, 0, 0xFFFF)) return ExprError(); // -Wframe-address warning if non-zero passed to builtin @@ -3010,7 +3008,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, } case Builtin::BI__builtin_nondeterministic_value: { - if (SemaBuiltinNonDeterministicValue(TheCall)) + if (BuiltinNonDeterministicValue(TheCall)) return ExprError(); break; } @@ -3063,7 +3061,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } case Builtin::BI__builtin_elementwise_fma: { - if (SemaBuiltinElementwiseTernaryMath(TheCall)) + if (BuiltinElementwiseTernaryMath(TheCall)) return ExprError(); break; } @@ -3071,7 +3069,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, // These builtins restrict the element type to floating point // types only, and take in two arguments. case Builtin::BI__builtin_elementwise_pow: { - if (SemaBuiltinElementwiseMath(TheCall)) + if (BuiltinElementwiseMath(TheCall)) return ExprError(); QualType ArgTy = TheCall->getArg(0)->getType(); @@ -3087,7 +3085,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, // types only. case Builtin::BI__builtin_elementwise_add_sat: case Builtin::BI__builtin_elementwise_sub_sat: { - if (SemaBuiltinElementwiseMath(TheCall)) + if (BuiltinElementwiseMath(TheCall)) return ExprError(); const Expr *Arg = TheCall->getArg(0); @@ -3107,7 +3105,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_elementwise_min: case Builtin::BI__builtin_elementwise_max: - if (SemaBuiltinElementwiseMath(TheCall)) + if (BuiltinElementwiseMath(TheCall)) return ExprError(); break; @@ -3198,13 +3196,13 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, } case Builtin::BI__builtin_matrix_transpose: - return SemaBuiltinMatrixTranspose(TheCall, TheCallResult); + return BuiltinMatrixTranspose(TheCall, TheCallResult); case Builtin::BI__builtin_matrix_column_major_load: - return SemaBuiltinMatrixColumnMajorLoad(TheCall, TheCallResult); + return BuiltinMatrixColumnMajorLoad(TheCall, TheCallResult); case Builtin::BI__builtin_matrix_column_major_store: - return SemaBuiltinMatrixColumnMajorStore(TheCall, TheCallResult); + return BuiltinMatrixColumnMajorStore(TheCall, TheCallResult); case Builtin::BI__builtin_get_device_side_mangled_name: { auto Check = [](CallExpr *TheCall) { @@ -3227,12 +3225,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } case Builtin::BI__builtin_popcountg: - if (SemaBuiltinPopcountg(*this, TheCall)) + if (BuiltinPopcountg(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_clzg: case Builtin::BI__builtin_ctzg: - if (SemaBuiltinCountZeroBitsGeneric(*this, TheCall)) + if (BuiltinCountZeroBitsGeneric(*this, TheCall)) return ExprError(); break; } @@ -3378,7 +3376,7 @@ bool Sema::ParseSVEImmChecks( // Check constant-ness first. llvm::APSInt Imm; - if (SemaBuiltinConstantArg(TheCall, ArgNum, Imm)) + if (BuiltinConstantArg(TheCall, ArgNum, Imm)) return true; if (!CheckImm(Imm.getSExtValue())) @@ -3388,65 +3386,63 @@ bool Sema::ParseSVEImmChecks( switch ((SVETypeFlags::ImmCheckType)CheckTy) { case SVETypeFlags::ImmCheck0_31: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 31)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 31)) HasError = true; break; case SVETypeFlags::ImmCheck0_13: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 13)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 13)) HasError = true; break; case SVETypeFlags::ImmCheck1_16: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, 16)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 16)) HasError = true; break; case SVETypeFlags::ImmCheck0_7: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 7)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 7)) HasError = true; break; case SVETypeFlags::ImmCheck1_1: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, 1)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 1)) HasError = true; break; case SVETypeFlags::ImmCheck1_3: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, 3)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 3)) HasError = true; break; case SVETypeFlags::ImmCheck1_7: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, 7)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 7)) HasError = true; break; case SVETypeFlags::ImmCheckExtract: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, - (2048 / ElementSizeInBits) - 1)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, + (2048 / ElementSizeInBits) - 1)) HasError = true; break; case SVETypeFlags::ImmCheckShiftRight: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, ElementSizeInBits)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 1, ElementSizeInBits)) HasError = true; break; case SVETypeFlags::ImmCheckShiftRightNarrow: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, - ElementSizeInBits / 2)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 1, ElementSizeInBits / 2)) HasError = true; break; case SVETypeFlags::ImmCheckShiftLeft: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, - ElementSizeInBits - 1)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, ElementSizeInBits - 1)) HasError = true; break; case SVETypeFlags::ImmCheckLaneIndex: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, - (128 / (1 * ElementSizeInBits)) - 1)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, + (128 / (1 * ElementSizeInBits)) - 1)) HasError = true; break; case SVETypeFlags::ImmCheckLaneIndexCompRotate: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, - (128 / (2 * ElementSizeInBits)) - 1)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, + (128 / (2 * ElementSizeInBits)) - 1)) HasError = true; break; case SVETypeFlags::ImmCheckLaneIndexDot: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, - (128 / (4 * ElementSizeInBits)) - 1)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, + (128 / (4 * ElementSizeInBits)) - 1)) HasError = true; break; case SVETypeFlags::ImmCheckComplexRot90_270: @@ -3463,32 +3459,32 @@ bool Sema::ParseSVEImmChecks( HasError = true; break; case SVETypeFlags::ImmCheck0_1: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 1)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 1)) HasError = true; break; case SVETypeFlags::ImmCheck0_2: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 2)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 2)) HasError = true; break; case SVETypeFlags::ImmCheck0_3: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 3)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 3)) HasError = true; break; case SVETypeFlags::ImmCheck0_0: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 0)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 0)) HasError = true; break; case SVETypeFlags::ImmCheck0_15: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 15)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 15)) HasError = true; break; case SVETypeFlags::ImmCheck0_255: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 255)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 255)) HasError = true; break; case SVETypeFlags::ImmCheck2_4_Mul2: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 2, 4) || - SemaBuiltinConstantArgMultiple(TheCall, ArgNum, 2)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 2, 4) || + BuiltinConstantArgMultiple(TheCall, ArgNum, 2)) HasError = true; break; } @@ -3664,7 +3660,7 @@ bool Sema::CheckNeonBuiltinFunctionCall(const TargetInfo &TI, // the immediate which specifies which variant to emit. unsigned ImmArg = TheCall->getNumArgs()-1; if (mask) { - if (SemaBuiltinConstantArg(TheCall, ImmArg, Result)) + if (BuiltinConstantArg(TheCall, ImmArg, Result)) return true; TV = Result.getLimitedValue(64); @@ -3712,7 +3708,7 @@ bool Sema::CheckNeonBuiltinFunctionCall(const TargetInfo &TI, #undef GET_NEON_IMMEDIATE_CHECK } - return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); + return BuiltinConstantArgRange(TheCall, i, l, u + l); } bool Sema::CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { @@ -3886,19 +3882,19 @@ bool Sema::CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, } if (BuiltinID == ARM::BI__builtin_arm_prefetch) { - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 1); + return BuiltinConstantArgRange(TheCall, 1, 0, 1) || + BuiltinConstantArgRange(TheCall, 2, 0, 1); } if (BuiltinID == ARM::BI__builtin_arm_rsr64 || BuiltinID == ARM::BI__builtin_arm_wsr64) - return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, false); + return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, false); if (BuiltinID == ARM::BI__builtin_arm_rsr || BuiltinID == ARM::BI__builtin_arm_rsrp || BuiltinID == ARM::BI__builtin_arm_wsr || BuiltinID == ARM::BI__builtin_arm_wsrp) - return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall)) return true; @@ -3913,21 +3909,21 @@ bool Sema::CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, switch (BuiltinID) { default: return false; case ARM::BI__builtin_arm_ssat: - return SemaBuiltinConstantArgRange(TheCall, 1, 1, 32); + return BuiltinConstantArgRange(TheCall, 1, 1, 32); case ARM::BI__builtin_arm_usat: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + return BuiltinConstantArgRange(TheCall, 1, 0, 31); case ARM::BI__builtin_arm_ssat16: - return SemaBuiltinConstantArgRange(TheCall, 1, 1, 16); + return BuiltinConstantArgRange(TheCall, 1, 1, 16); case ARM::BI__builtin_arm_usat16: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 15); case ARM::BI__builtin_arm_vcvtr_f: case ARM::BI__builtin_arm_vcvtr_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); + return BuiltinConstantArgRange(TheCall, 1, 0, 1); case ARM::BI__builtin_arm_dmb: case ARM::BI__builtin_arm_dsb: case ARM::BI__builtin_arm_isb: case ARM::BI__builtin_arm_dbg: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 15); + return BuiltinConstantArgRange(TheCall, 0, 0, 15); case ARM::BI__builtin_arm_cdp: case ARM::BI__builtin_arm_cdp2: case ARM::BI__builtin_arm_mcr: @@ -3946,7 +3942,7 @@ bool Sema::CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case ARM::BI__builtin_arm_stcl: case ARM::BI__builtin_arm_stc2: case ARM::BI__builtin_arm_stc2l: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 15) || + return BuiltinConstantArgRange(TheCall, 0, 0, 15) || CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), /*WantCDE*/ false); } @@ -3963,17 +3959,17 @@ bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, } if (BuiltinID == AArch64::BI__builtin_arm_prefetch) { - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 1) || - SemaBuiltinConstantArgRange(TheCall, 4, 0, 1); + return BuiltinConstantArgRange(TheCall, 1, 0, 1) || + BuiltinConstantArgRange(TheCall, 2, 0, 3) || + BuiltinConstantArgRange(TheCall, 3, 0, 1) || + BuiltinConstantArgRange(TheCall, 4, 0, 1); } if (BuiltinID == AArch64::BI__builtin_arm_rsr64 || BuiltinID == AArch64::BI__builtin_arm_wsr64 || BuiltinID == AArch64::BI__builtin_arm_rsr128 || BuiltinID == AArch64::BI__builtin_arm_wsr128) - return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); // Memory Tagging Extensions (MTE) Intrinsics if (BuiltinID == AArch64::BI__builtin_arm_irg || @@ -3982,27 +3978,27 @@ bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, BuiltinID == AArch64::BI__builtin_arm_ldg || BuiltinID == AArch64::BI__builtin_arm_stg || BuiltinID == AArch64::BI__builtin_arm_subp) { - return SemaBuiltinARMMemoryTaggingCall(BuiltinID, TheCall); + return BuiltinARMMemoryTaggingCall(BuiltinID, TheCall); } if (BuiltinID == AArch64::BI__builtin_arm_rsr || BuiltinID == AArch64::BI__builtin_arm_rsrp || BuiltinID == AArch64::BI__builtin_arm_wsr || BuiltinID == AArch64::BI__builtin_arm_wsrp) - return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); // Only check the valid encoding range. Any constant in this range would be // converted to a register of the form S1_2_C3_C4_5. Let the hardware throw // an exception for incorrect registers. This matches MSVC behavior. if (BuiltinID == AArch64::BI_ReadStatusReg || BuiltinID == AArch64::BI_WriteStatusReg) - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 0x7fff); + return BuiltinConstantArgRange(TheCall, 0, 0, 0x7fff); if (BuiltinID == AArch64::BI__getReg) - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31); + return BuiltinConstantArgRange(TheCall, 0, 0, 31); if (BuiltinID == AArch64::BI__break) - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 0xffff); + return BuiltinConstantArgRange(TheCall, 0, 0, 0xffff); if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall)) return true; @@ -4024,7 +4020,7 @@ bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break; } - return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); + return BuiltinConstantArgRange(TheCall, i, l, u + l); } static bool isValidBPFPreserveFieldInfoArg(Expr *Arg) { @@ -4423,13 +4419,13 @@ bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { int32_t Min = A.IsSigned ? -(1 << (A.BitWidth - 1)) : 0; int32_t Max = (1 << (A.IsSigned ? A.BitWidth - 1 : A.BitWidth)) - 1; if (!A.Align) { - Error |= SemaBuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); + Error |= BuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); } else { unsigned M = 1 << A.Align; Min *= M; Max *= M; - Error |= SemaBuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); - Error |= SemaBuiltinConstantArgMultiple(TheCall, A.OpNum, M); + Error |= BuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); + Error |= BuiltinConstantArgMultiple(TheCall, A.OpNum, M); } } return Error; @@ -4449,9 +4445,8 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, // Basic intrinsics. case LoongArch::BI__builtin_loongarch_cacop_d: case LoongArch::BI__builtin_loongarch_cacop_w: { - SemaBuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(5)); - SemaBuiltinConstantArgRange(TheCall, 2, llvm::minIntN(12), - llvm::maxIntN(12)); + BuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(5)); + BuiltinConstantArgRange(TheCall, 2, llvm::minIntN(12), llvm::maxIntN(12)); break; } case LoongArch::BI__builtin_loongarch_break: @@ -4459,22 +4454,22 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_loongarch_ibar: case LoongArch::BI__builtin_loongarch_syscall: // Check if immediate is in [0, 32767]. - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 32767); + return BuiltinConstantArgRange(TheCall, 0, 0, 32767); case LoongArch::BI__builtin_loongarch_csrrd_w: case LoongArch::BI__builtin_loongarch_csrrd_d: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 16383); + return BuiltinConstantArgRange(TheCall, 0, 0, 16383); case LoongArch::BI__builtin_loongarch_csrwr_w: case LoongArch::BI__builtin_loongarch_csrwr_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 16383); + return BuiltinConstantArgRange(TheCall, 1, 0, 16383); case LoongArch::BI__builtin_loongarch_csrxchg_w: case LoongArch::BI__builtin_loongarch_csrxchg_d: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 16383); + return BuiltinConstantArgRange(TheCall, 2, 0, 16383); case LoongArch::BI__builtin_loongarch_lddir_d: case LoongArch::BI__builtin_loongarch_ldpte_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + return BuiltinConstantArgRange(TheCall, 1, 0, 31); case LoongArch::BI__builtin_loongarch_movfcsr2gr: case LoongArch::BI__builtin_loongarch_movgr2fcsr: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(2)); + return BuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(2)); // LSX intrinsics. case LoongArch::BI__builtin_lsx_vbitclri_b: @@ -4490,7 +4485,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vsllwil_hu_bu: case LoongArch::BI__builtin_lsx_vrotri_b: case LoongArch::BI__builtin_lsx_vsrlri_b: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 7); + return BuiltinConstantArgRange(TheCall, 1, 0, 7); case LoongArch::BI__builtin_lsx_vbitclri_h: case LoongArch::BI__builtin_lsx_vbitrevi_h: case LoongArch::BI__builtin_lsx_vbitseti_h: @@ -4504,7 +4499,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vsllwil_wu_hu: case LoongArch::BI__builtin_lsx_vrotri_h: case LoongArch::BI__builtin_lsx_vsrlri_h: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 15); case LoongArch::BI__builtin_lsx_vssrarni_b_h: case LoongArch::BI__builtin_lsx_vssrarni_bu_h: case LoongArch::BI__builtin_lsx_vssrani_b_h: @@ -4517,7 +4512,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vssrlrni_b_h: case LoongArch::BI__builtin_lsx_vssrlrni_bu_h: case LoongArch::BI__builtin_lsx_vsrani_b_h: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); + return BuiltinConstantArgRange(TheCall, 2, 0, 15); case LoongArch::BI__builtin_lsx_vslei_bu: case LoongArch::BI__builtin_lsx_vslei_hu: case LoongArch::BI__builtin_lsx_vslei_wu: @@ -4557,7 +4552,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vbsll_v: case LoongArch::BI__builtin_lsx_vsubi_wu: case LoongArch::BI__builtin_lsx_vsubi_du: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + return BuiltinConstantArgRange(TheCall, 1, 0, 31); case LoongArch::BI__builtin_lsx_vssrarni_h_w: case LoongArch::BI__builtin_lsx_vssrarni_hu_w: case LoongArch::BI__builtin_lsx_vssrani_h_w: @@ -4572,7 +4567,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vssrlni_hu_w: case LoongArch::BI__builtin_lsx_vssrlrni_h_w: case LoongArch::BI__builtin_lsx_vssrlrni_hu_w: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + return BuiltinConstantArgRange(TheCall, 2, 0, 31); case LoongArch::BI__builtin_lsx_vbitclri_d: case LoongArch::BI__builtin_lsx_vbitrevi_d: case LoongArch::BI__builtin_lsx_vbitseti_d: @@ -4584,7 +4579,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vsrari_d: case LoongArch::BI__builtin_lsx_vrotri_d: case LoongArch::BI__builtin_lsx_vsrlri_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 63); + return BuiltinConstantArgRange(TheCall, 1, 0, 63); case LoongArch::BI__builtin_lsx_vssrarni_w_d: case LoongArch::BI__builtin_lsx_vssrarni_wu_d: case LoongArch::BI__builtin_lsx_vssrani_w_d: @@ -4597,7 +4592,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vssrlrni_w_d: case LoongArch::BI__builtin_lsx_vssrlrni_wu_d: case LoongArch::BI__builtin_lsx_vsrani_w_d: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 63); + return BuiltinConstantArgRange(TheCall, 2, 0, 63); case LoongArch::BI__builtin_lsx_vssrarni_d_q: case LoongArch::BI__builtin_lsx_vssrarni_du_q: case LoongArch::BI__builtin_lsx_vssrani_d_q: @@ -4610,7 +4605,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vsrani_d_q: case LoongArch::BI__builtin_lsx_vsrlrni_d_q: case LoongArch::BI__builtin_lsx_vsrlni_d_q: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 127); + return BuiltinConstantArgRange(TheCall, 2, 0, 127); case LoongArch::BI__builtin_lsx_vseqi_b: case LoongArch::BI__builtin_lsx_vseqi_h: case LoongArch::BI__builtin_lsx_vseqi_w: @@ -4631,7 +4626,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vmini_h: case LoongArch::BI__builtin_lsx_vmini_w: case LoongArch::BI__builtin_lsx_vmini_d: - return SemaBuiltinConstantArgRange(TheCall, 1, -16, 15); + return BuiltinConstantArgRange(TheCall, 1, -16, 15); case LoongArch::BI__builtin_lsx_vandi_b: case LoongArch::BI__builtin_lsx_vnori_b: case LoongArch::BI__builtin_lsx_vori_b: @@ -4639,7 +4634,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vshuf4i_h: case LoongArch::BI__builtin_lsx_vshuf4i_w: case LoongArch::BI__builtin_lsx_vxori_b: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 255); + return BuiltinConstantArgRange(TheCall, 1, 0, 255); case LoongArch::BI__builtin_lsx_vbitseli_b: case LoongArch::BI__builtin_lsx_vshuf4i_d: case LoongArch::BI__builtin_lsx_vextrins_b: @@ -4647,61 +4642,61 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vextrins_w: case LoongArch::BI__builtin_lsx_vextrins_d: case LoongArch::BI__builtin_lsx_vpermi_w: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 255); + return BuiltinConstantArgRange(TheCall, 2, 0, 255); case LoongArch::BI__builtin_lsx_vpickve2gr_b: case LoongArch::BI__builtin_lsx_vpickve2gr_bu: case LoongArch::BI__builtin_lsx_vreplvei_b: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 15); case LoongArch::BI__builtin_lsx_vinsgr2vr_b: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); + return BuiltinConstantArgRange(TheCall, 2, 0, 15); case LoongArch::BI__builtin_lsx_vpickve2gr_h: case LoongArch::BI__builtin_lsx_vpickve2gr_hu: case LoongArch::BI__builtin_lsx_vreplvei_h: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 7); + return BuiltinConstantArgRange(TheCall, 1, 0, 7); case LoongArch::BI__builtin_lsx_vinsgr2vr_h: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 7); + return BuiltinConstantArgRange(TheCall, 2, 0, 7); case LoongArch::BI__builtin_lsx_vpickve2gr_w: case LoongArch::BI__builtin_lsx_vpickve2gr_wu: case LoongArch::BI__builtin_lsx_vreplvei_w: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3); + return BuiltinConstantArgRange(TheCall, 1, 0, 3); case LoongArch::BI__builtin_lsx_vinsgr2vr_w: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3); + return BuiltinConstantArgRange(TheCall, 2, 0, 3); case LoongArch::BI__builtin_lsx_vpickve2gr_d: case LoongArch::BI__builtin_lsx_vpickve2gr_du: case LoongArch::BI__builtin_lsx_vreplvei_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); + return BuiltinConstantArgRange(TheCall, 1, 0, 1); case LoongArch::BI__builtin_lsx_vinsgr2vr_d: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 1); + return BuiltinConstantArgRange(TheCall, 2, 0, 1); case LoongArch::BI__builtin_lsx_vstelm_b: - return SemaBuiltinConstantArgRange(TheCall, 2, -128, 127) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 15); + return BuiltinConstantArgRange(TheCall, 2, -128, 127) || + BuiltinConstantArgRange(TheCall, 3, 0, 15); case LoongArch::BI__builtin_lsx_vstelm_h: - return SemaBuiltinConstantArgRange(TheCall, 2, -256, 254) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 7); + return BuiltinConstantArgRange(TheCall, 2, -256, 254) || + BuiltinConstantArgRange(TheCall, 3, 0, 7); case LoongArch::BI__builtin_lsx_vstelm_w: - return SemaBuiltinConstantArgRange(TheCall, 2, -512, 508) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 3); + return BuiltinConstantArgRange(TheCall, 2, -512, 508) || + BuiltinConstantArgRange(TheCall, 3, 0, 3); case LoongArch::BI__builtin_lsx_vstelm_d: - return SemaBuiltinConstantArgRange(TheCall, 2, -1024, 1016) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 1); + return BuiltinConstantArgRange(TheCall, 2, -1024, 1016) || + BuiltinConstantArgRange(TheCall, 3, 0, 1); case LoongArch::BI__builtin_lsx_vldrepl_b: case LoongArch::BI__builtin_lsx_vld: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2047); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2047); case LoongArch::BI__builtin_lsx_vldrepl_h: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2046); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2046); case LoongArch::BI__builtin_lsx_vldrepl_w: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2044); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2044); case LoongArch::BI__builtin_lsx_vldrepl_d: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2040); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2040); case LoongArch::BI__builtin_lsx_vst: - return SemaBuiltinConstantArgRange(TheCall, 2, -2048, 2047); + return BuiltinConstantArgRange(TheCall, 2, -2048, 2047); case LoongArch::BI__builtin_lsx_vldi: - return SemaBuiltinConstantArgRange(TheCall, 0, -4096, 4095); + return BuiltinConstantArgRange(TheCall, 0, -4096, 4095); case LoongArch::BI__builtin_lsx_vrepli_b: case LoongArch::BI__builtin_lsx_vrepli_h: case LoongArch::BI__builtin_lsx_vrepli_w: case LoongArch::BI__builtin_lsx_vrepli_d: - return SemaBuiltinConstantArgRange(TheCall, 0, -512, 511); + return BuiltinConstantArgRange(TheCall, 0, -512, 511); // LASX intrinsics. case LoongArch::BI__builtin_lasx_xvbitclri_b: @@ -4717,7 +4712,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvsllwil_hu_bu: case LoongArch::BI__builtin_lasx_xvrotri_b: case LoongArch::BI__builtin_lasx_xvsrlri_b: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 7); + return BuiltinConstantArgRange(TheCall, 1, 0, 7); case LoongArch::BI__builtin_lasx_xvbitclri_h: case LoongArch::BI__builtin_lasx_xvbitrevi_h: case LoongArch::BI__builtin_lasx_xvbitseti_h: @@ -4731,7 +4726,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvsllwil_wu_hu: case LoongArch::BI__builtin_lasx_xvrotri_h: case LoongArch::BI__builtin_lasx_xvsrlri_h: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 15); case LoongArch::BI__builtin_lasx_xvssrarni_b_h: case LoongArch::BI__builtin_lasx_xvssrarni_bu_h: case LoongArch::BI__builtin_lasx_xvssrani_b_h: @@ -4744,7 +4739,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvssrlrni_b_h: case LoongArch::BI__builtin_lasx_xvssrlrni_bu_h: case LoongArch::BI__builtin_lasx_xvsrani_b_h: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); + return BuiltinConstantArgRange(TheCall, 2, 0, 15); case LoongArch::BI__builtin_lasx_xvslei_bu: case LoongArch::BI__builtin_lasx_xvslei_hu: case LoongArch::BI__builtin_lasx_xvslei_wu: @@ -4784,7 +4779,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvsubi_du: case LoongArch::BI__builtin_lasx_xvbsrl_v: case LoongArch::BI__builtin_lasx_xvbsll_v: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + return BuiltinConstantArgRange(TheCall, 1, 0, 31); case LoongArch::BI__builtin_lasx_xvssrarni_h_w: case LoongArch::BI__builtin_lasx_xvssrarni_hu_w: case LoongArch::BI__builtin_lasx_xvssrani_h_w: @@ -4799,7 +4794,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvssrlni_hu_w: case LoongArch::BI__builtin_lasx_xvssrlrni_h_w: case LoongArch::BI__builtin_lasx_xvssrlrni_hu_w: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + return BuiltinConstantArgRange(TheCall, 2, 0, 31); case LoongArch::BI__builtin_lasx_xvbitclri_d: case LoongArch::BI__builtin_lasx_xvbitrevi_d: case LoongArch::BI__builtin_lasx_xvbitseti_d: @@ -4811,7 +4806,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvsrari_d: case LoongArch::BI__builtin_lasx_xvrotri_d: case LoongArch::BI__builtin_lasx_xvsrlri_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 63); + return BuiltinConstantArgRange(TheCall, 1, 0, 63); case LoongArch::BI__builtin_lasx_xvssrarni_w_d: case LoongArch::BI__builtin_lasx_xvssrarni_wu_d: case LoongArch::BI__builtin_lasx_xvssrani_w_d: @@ -4824,7 +4819,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvssrlrni_w_d: case LoongArch::BI__builtin_lasx_xvssrlrni_wu_d: case LoongArch::BI__builtin_lasx_xvsrani_w_d: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 63); + return BuiltinConstantArgRange(TheCall, 2, 0, 63); case LoongArch::BI__builtin_lasx_xvssrarni_d_q: case LoongArch::BI__builtin_lasx_xvssrarni_du_q: case LoongArch::BI__builtin_lasx_xvssrani_d_q: @@ -4837,7 +4832,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvsrani_d_q: case LoongArch::BI__builtin_lasx_xvsrlni_d_q: case LoongArch::BI__builtin_lasx_xvsrlrni_d_q: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 127); + return BuiltinConstantArgRange(TheCall, 2, 0, 127); case LoongArch::BI__builtin_lasx_xvseqi_b: case LoongArch::BI__builtin_lasx_xvseqi_h: case LoongArch::BI__builtin_lasx_xvseqi_w: @@ -4858,7 +4853,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvmini_h: case LoongArch::BI__builtin_lasx_xvmini_w: case LoongArch::BI__builtin_lasx_xvmini_d: - return SemaBuiltinConstantArgRange(TheCall, 1, -16, 15); + return BuiltinConstantArgRange(TheCall, 1, -16, 15); case LoongArch::BI__builtin_lasx_xvandi_b: case LoongArch::BI__builtin_lasx_xvnori_b: case LoongArch::BI__builtin_lasx_xvori_b: @@ -4867,7 +4862,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvshuf4i_w: case LoongArch::BI__builtin_lasx_xvxori_b: case LoongArch::BI__builtin_lasx_xvpermi_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 255); + return BuiltinConstantArgRange(TheCall, 1, 0, 255); case LoongArch::BI__builtin_lasx_xvbitseli_b: case LoongArch::BI__builtin_lasx_xvshuf4i_d: case LoongArch::BI__builtin_lasx_xvextrins_b: @@ -4876,59 +4871,59 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvextrins_d: case LoongArch::BI__builtin_lasx_xvpermi_q: case LoongArch::BI__builtin_lasx_xvpermi_w: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 255); + return BuiltinConstantArgRange(TheCall, 2, 0, 255); case LoongArch::BI__builtin_lasx_xvrepl128vei_b: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 15); case LoongArch::BI__builtin_lasx_xvrepl128vei_h: case LoongArch::BI__builtin_lasx_xvpickve2gr_w: case LoongArch::BI__builtin_lasx_xvpickve2gr_wu: case LoongArch::BI__builtin_lasx_xvpickve_w_f: case LoongArch::BI__builtin_lasx_xvpickve_w: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 7); + return BuiltinConstantArgRange(TheCall, 1, 0, 7); case LoongArch::BI__builtin_lasx_xvinsgr2vr_w: case LoongArch::BI__builtin_lasx_xvinsve0_w: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 7); + return BuiltinConstantArgRange(TheCall, 2, 0, 7); case LoongArch::BI__builtin_lasx_xvrepl128vei_w: case LoongArch::BI__builtin_lasx_xvpickve2gr_d: case LoongArch::BI__builtin_lasx_xvpickve2gr_du: case LoongArch::BI__builtin_lasx_xvpickve_d_f: case LoongArch::BI__builtin_lasx_xvpickve_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3); + return BuiltinConstantArgRange(TheCall, 1, 0, 3); case LoongArch::BI__builtin_lasx_xvinsve0_d: case LoongArch::BI__builtin_lasx_xvinsgr2vr_d: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3); + return BuiltinConstantArgRange(TheCall, 2, 0, 3); case LoongArch::BI__builtin_lasx_xvstelm_b: - return SemaBuiltinConstantArgRange(TheCall, 2, -128, 127) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 31); + return BuiltinConstantArgRange(TheCall, 2, -128, 127) || + BuiltinConstantArgRange(TheCall, 3, 0, 31); case LoongArch::BI__builtin_lasx_xvstelm_h: - return SemaBuiltinConstantArgRange(TheCall, 2, -256, 254) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 15); + return BuiltinConstantArgRange(TheCall, 2, -256, 254) || + BuiltinConstantArgRange(TheCall, 3, 0, 15); case LoongArch::BI__builtin_lasx_xvstelm_w: - return SemaBuiltinConstantArgRange(TheCall, 2, -512, 508) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 7); + return BuiltinConstantArgRange(TheCall, 2, -512, 508) || + BuiltinConstantArgRange(TheCall, 3, 0, 7); case LoongArch::BI__builtin_lasx_xvstelm_d: - return SemaBuiltinConstantArgRange(TheCall, 2, -1024, 1016) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 3); + return BuiltinConstantArgRange(TheCall, 2, -1024, 1016) || + BuiltinConstantArgRange(TheCall, 3, 0, 3); case LoongArch::BI__builtin_lasx_xvrepl128vei_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); + return BuiltinConstantArgRange(TheCall, 1, 0, 1); case LoongArch::BI__builtin_lasx_xvldrepl_b: case LoongArch::BI__builtin_lasx_xvld: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2047); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2047); case LoongArch::BI__builtin_lasx_xvldrepl_h: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2046); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2046); case LoongArch::BI__builtin_lasx_xvldrepl_w: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2044); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2044); case LoongArch::BI__builtin_lasx_xvldrepl_d: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2040); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2040); case LoongArch::BI__builtin_lasx_xvst: - return SemaBuiltinConstantArgRange(TheCall, 2, -2048, 2047); + return BuiltinConstantArgRange(TheCall, 2, -2048, 2047); case LoongArch::BI__builtin_lasx_xvldi: - return SemaBuiltinConstantArgRange(TheCall, 0, -4096, 4095); + return BuiltinConstantArgRange(TheCall, 0, -4096, 4095); case LoongArch::BI__builtin_lasx_xvrepli_b: case LoongArch::BI__builtin_lasx_xvrepli_h: case LoongArch::BI__builtin_lasx_xvrepli_w: case LoongArch::BI__builtin_lasx_xvrepli_d: - return SemaBuiltinConstantArgRange(TheCall, 0, -512, 511); + return BuiltinConstantArgRange(TheCall, 0, -512, 511); } return false; } @@ -5144,10 +5139,10 @@ bool Sema::CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { } if (!m) - return SemaBuiltinConstantArgRange(TheCall, i, l, u); + return BuiltinConstantArgRange(TheCall, i, l, u); - return SemaBuiltinConstantArgRange(TheCall, i, l, u) || - SemaBuiltinConstantArgMultiple(TheCall, i, m); + return BuiltinConstantArgRange(TheCall, i, l, u) || + BuiltinConstantArgMultiple(TheCall, i, m); } /// DecodePPCMMATypeFromStr - This decodes one PPC MMA type descriptor from Str, @@ -5237,7 +5232,6 @@ static bool isPPC_64Builtin(unsigned BuiltinID) { case PPC::BI__builtin_ppc_fetch_and_andlp: case PPC::BI__builtin_ppc_fetch_and_orlp: case PPC::BI__builtin_ppc_fetch_and_swaplp: - case PPC::BI__builtin_ppc_rldimi: return true; } return false; @@ -5247,7 +5241,7 @@ static bool isPPC_64Builtin(unsigned BuiltinID) { /// number of 0s on either side. The 1s are allowed to wrap from LSB to MSB, so /// 0x000FFF0, 0x0000FFFF, 0xFF0000FF, 0x0 are all runs. 0x0F0F0000 is not, /// since all 1s are not contiguous. -bool Sema::SemaValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum) { +bool Sema::ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum) { llvm::APSInt Result; // We can't check the value of a dependent argument. Expr *Arg = TheCall->getArg(ArgNum); @@ -5255,7 +5249,7 @@ bool Sema::SemaValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum) { return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; // Check contiguous run of 1s, 0xFF0000FF is also a run of 1s. @@ -5281,27 +5275,27 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, default: return false; case PPC::BI__builtin_altivec_crypto_vshasigmaw: case PPC::BI__builtin_altivec_crypto_vshasigmad: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 1) || + BuiltinConstantArgRange(TheCall, 2, 0, 15); case PPC::BI__builtin_altivec_dss: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3); + return BuiltinConstantArgRange(TheCall, 0, 0, 3); case PPC::BI__builtin_tbegin: case PPC::BI__builtin_tend: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1); + return BuiltinConstantArgRange(TheCall, 0, 0, 1); case PPC::BI__builtin_tsr: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 7); + return BuiltinConstantArgRange(TheCall, 0, 0, 7); case PPC::BI__builtin_tabortwc: case PPC::BI__builtin_tabortdc: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31); + return BuiltinConstantArgRange(TheCall, 0, 0, 31); case PPC::BI__builtin_tabortwci: case PPC::BI__builtin_tabortdci: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + return BuiltinConstantArgRange(TheCall, 0, 0, 31) || + BuiltinConstantArgRange(TheCall, 2, 0, 31); // According to GCC 'Basic PowerPC Built-in Functions Available on ISA 2.05', // __builtin_(un)pack_longdouble are available only if long double uses IBM // extended double representation. case PPC::BI__builtin_unpack_longdouble: - if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 1)) + if (BuiltinConstantArgRange(TheCall, 1, 0, 1)) return true; [[fallthrough]]; case PPC::BI__builtin_pack_longdouble: @@ -5313,39 +5307,39 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case PPC::BI__builtin_altivec_dstt: case PPC::BI__builtin_altivec_dstst: case PPC::BI__builtin_altivec_dststt: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3); + return BuiltinConstantArgRange(TheCall, 2, 0, 3); case PPC::BI__builtin_vsx_xxpermdi: case PPC::BI__builtin_vsx_xxsldwi: - return SemaBuiltinVSX(TheCall); + return BuiltinVSX(TheCall); case PPC::BI__builtin_unpack_vector_int128: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); + return BuiltinConstantArgRange(TheCall, 1, 0, 1); case PPC::BI__builtin_altivec_vgnb: - return SemaBuiltinConstantArgRange(TheCall, 1, 2, 7); + return BuiltinConstantArgRange(TheCall, 1, 2, 7); case PPC::BI__builtin_vsx_xxeval: - return SemaBuiltinConstantArgRange(TheCall, 3, 0, 255); + return BuiltinConstantArgRange(TheCall, 3, 0, 255); case PPC::BI__builtin_altivec_vsldbi: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 7); + return BuiltinConstantArgRange(TheCall, 2, 0, 7); case PPC::BI__builtin_altivec_vsrdbi: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 7); + return BuiltinConstantArgRange(TheCall, 2, 0, 7); case PPC::BI__builtin_vsx_xxpermx: - return SemaBuiltinConstantArgRange(TheCall, 3, 0, 7); + return BuiltinConstantArgRange(TheCall, 3, 0, 7); case PPC::BI__builtin_ppc_tw: case PPC::BI__builtin_ppc_tdw: - return SemaBuiltinConstantArgRange(TheCall, 2, 1, 31); + return BuiltinConstantArgRange(TheCall, 2, 1, 31); case PPC::BI__builtin_ppc_cmprb: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1); + return BuiltinConstantArgRange(TheCall, 0, 0, 1); // For __rlwnm, __rlwimi and __rldimi, the last parameter mask must // be a constant that represents a contiguous bit field. case PPC::BI__builtin_ppc_rlwnm: - return SemaValueIsRunOfOnes(TheCall, 2); + return ValueIsRunOfOnes(TheCall, 2); case PPC::BI__builtin_ppc_rlwimi: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 31) || - SemaValueIsRunOfOnes(TheCall, 3); + return BuiltinConstantArgRange(TheCall, 2, 0, 31) || + ValueIsRunOfOnes(TheCall, 3); case PPC::BI__builtin_ppc_rldimi: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 63) || - SemaValueIsRunOfOnes(TheCall, 3); + return BuiltinConstantArgRange(TheCall, 2, 0, 63) || + ValueIsRunOfOnes(TheCall, 3); case PPC::BI__builtin_ppc_addex: { - if (SemaBuiltinConstantArgRange(TheCall, 2, 0, 3)) + if (BuiltinConstantArgRange(TheCall, 2, 0, 3)) return true; // Output warning for reserved values 1 to 3. int ArgValue = @@ -5357,29 +5351,29 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, } case PPC::BI__builtin_ppc_mtfsb0: case PPC::BI__builtin_ppc_mtfsb1: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31); + return BuiltinConstantArgRange(TheCall, 0, 0, 31); case PPC::BI__builtin_ppc_mtfsf: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 255); + return BuiltinConstantArgRange(TheCall, 0, 0, 255); case PPC::BI__builtin_ppc_mtfsfi: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 7) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + return BuiltinConstantArgRange(TheCall, 0, 0, 7) || + BuiltinConstantArgRange(TheCall, 1, 0, 15); case PPC::BI__builtin_ppc_alignx: - return SemaBuiltinConstantArgPower2(TheCall, 0); + return BuiltinConstantArgPower2(TheCall, 0); case PPC::BI__builtin_ppc_rdlam: - return SemaValueIsRunOfOnes(TheCall, 2); + return ValueIsRunOfOnes(TheCall, 2); case PPC::BI__builtin_vsx_ldrmb: case PPC::BI__builtin_vsx_strmb: - return SemaBuiltinConstantArgRange(TheCall, 1, 1, 16); + return BuiltinConstantArgRange(TheCall, 1, 1, 16); case PPC::BI__builtin_altivec_vcntmbb: case PPC::BI__builtin_altivec_vcntmbh: case PPC::BI__builtin_altivec_vcntmbw: case PPC::BI__builtin_altivec_vcntmbd: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); + return BuiltinConstantArgRange(TheCall, 1, 0, 1); case PPC::BI__builtin_vsx_xxgenpcvbm: case PPC::BI__builtin_vsx_xxgenpcvhm: case PPC::BI__builtin_vsx_xxgenpcvwm: case PPC::BI__builtin_vsx_xxgenpcvdm: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3); + return BuiltinConstantArgRange(TheCall, 1, 0, 3); case PPC::BI__builtin_ppc_test_data_class: { // Check if the first argument of the __builtin_ppc_test_data_class call is // valid. The argument must be 'float' or 'double' or '__float128'. @@ -5389,7 +5383,7 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, ArgType != QualType(Context.Float128Ty)) return Diag(TheCall->getBeginLoc(), diag::err_ppc_invalid_test_data_class_type); - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 127); + return BuiltinConstantArgRange(TheCall, 1, 0, 127); } case PPC::BI__builtin_ppc_maxfe: case PPC::BI__builtin_ppc_minfe: @@ -5418,12 +5412,12 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, << TheCall->getArg(I)->getType() << ArgType << 1 << 0 << 0; return false; } -#define CUSTOM_BUILTIN(Name, Intr, Types, Acc, Feature) \ +#define CUSTOM_BUILTIN(Name, Intr, Types, Acc, Feature) \ case PPC::BI__builtin_##Name: \ - return SemaBuiltinPPCMMACall(TheCall, BuiltinID, Types); + return BuiltinPPCMMACall(TheCall, BuiltinID, Types); #include "clang/Basic/BuiltinsPPC.def" } - return SemaBuiltinConstantArgRange(TheCall, i, l, u); + return BuiltinConstantArgRange(TheCall, i, l, u); } // Check if the given type is a non-pointer PPC MMA type. This function is used @@ -5574,7 +5568,7 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return true; if (CheckVectorElementCallArgs(this, TheCall)) return true; - if (SemaBuiltinElementwiseTernaryMath( + if (BuiltinElementwiseTernaryMath( TheCall, /*CheckForFloatArgs*/ TheCall->getArg(0)->getType()->hasFloatingRepresentation())) return true; @@ -5585,7 +5579,7 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return true; if (CheckVectorElementCallArgs(this, TheCall)) return true; - if (SemaBuiltinVectorToScalarMath(TheCall)) + if (BuiltinVectorToScalarMath(TheCall)) return true; if (CheckNoDoubleVectors(this, TheCall)) return true; @@ -5619,7 +5613,7 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return true; if (CheckVectorElementCallArgs(this, TheCall)) return true; - if (SemaBuiltinElementwiseTernaryMath(TheCall)) + if (BuiltinElementwiseTernaryMath(TheCall)) return true; if (CheckFloatOrHalfRepresentations(this, TheCall)) return true; @@ -5630,7 +5624,7 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return true; if (CheckVectorElementCallArgs(this, TheCall)) return true; - if (SemaBuiltinElementwiseTernaryMath( + if (BuiltinElementwiseTernaryMath( TheCall, /*CheckForFloatArgs*/ TheCall->getArg(0)->getType()->hasFloatingRepresentation())) return true; @@ -5737,7 +5731,7 @@ bool Sema::CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum) { return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; int64_t Val = Result.getSExtValue(); @@ -5847,10 +5841,10 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, switch (BuiltinID) { case RISCVVector::BI__builtin_rvv_vsetvli: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3) || + return BuiltinConstantArgRange(TheCall, 1, 0, 3) || CheckRISCVLMUL(TheCall, 2); case RISCVVector::BI__builtin_rvv_vsetvlimax: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || CheckRISCVLMUL(TheCall, 1); case RISCVVector::BI__builtin_rvv_vget_v: { ASTContext::BuiltinVectorTypeInfo ResVecInfo = @@ -5865,7 +5859,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, else // vget for non-tuple type MaxIndex = (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors) / (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors); - return SemaBuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); + return BuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); } case RISCVVector::BI__builtin_rvv_vset_v: { ASTContext::BuiltinVectorTypeInfo ResVecInfo = @@ -5880,7 +5874,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, else // vset fo non-tuple type MaxIndex = (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors) / (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors); - return SemaBuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); + return BuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); } // Vector Crypto case RISCVVector::BI__builtin_rvv_vaeskf1_vi_tu: @@ -5891,19 +5885,19 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, QualType Op2Type = TheCall->getArg(1)->getType(); return CheckInvalidVLENandLMUL(TI, TheCall, *this, Op1Type, 128) || CheckInvalidVLENandLMUL(TI, TheCall, *this, Op2Type, 128) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + BuiltinConstantArgRange(TheCall, 2, 0, 31); } case RISCVVector::BI__builtin_rvv_vsm3c_vi_tu: case RISCVVector::BI__builtin_rvv_vsm3c_vi: { QualType Op1Type = TheCall->getArg(0)->getType(); return CheckInvalidVLENandLMUL(TI, TheCall, *this, Op1Type, 256) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + BuiltinConstantArgRange(TheCall, 2, 0, 31); } case RISCVVector::BI__builtin_rvv_vaeskf1_vi: case RISCVVector::BI__builtin_rvv_vsm4k_vi: { QualType Op1Type = TheCall->getArg(0)->getType(); return CheckInvalidVLENandLMUL(TI, TheCall, *this, Op1Type, 128) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + BuiltinConstantArgRange(TheCall, 1, 0, 31); } case RISCVVector::BI__builtin_rvv_vaesdf_vv: case RISCVVector::BI__builtin_rvv_vaesdf_vs: @@ -5956,27 +5950,27 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_sf_vc_i_se: // bit_27_26, bit_24_20, bit_11_7, simm5, sew, log2lmul - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 31) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 31) || - SemaBuiltinConstantArgRange(TheCall, 3, -16, 15) || + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || + BuiltinConstantArgRange(TheCall, 1, 0, 31) || + BuiltinConstantArgRange(TheCall, 2, 0, 31) || + BuiltinConstantArgRange(TheCall, 3, -16, 15) || CheckRISCVLMUL(TheCall, 5); case RISCVVector::BI__builtin_rvv_sf_vc_iv_se: // bit_27_26, bit_11_7, vs2, simm5 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 31) || - SemaBuiltinConstantArgRange(TheCall, 3, -16, 15); + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || + BuiltinConstantArgRange(TheCall, 1, 0, 31) || + BuiltinConstantArgRange(TheCall, 3, -16, 15); case RISCVVector::BI__builtin_rvv_sf_vc_v_i: case RISCVVector::BI__builtin_rvv_sf_vc_v_i_se: // bit_27_26, bit_24_20, simm5 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 31) || - SemaBuiltinConstantArgRange(TheCall, 2, -16, 15); + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || + BuiltinConstantArgRange(TheCall, 1, 0, 31) || + BuiltinConstantArgRange(TheCall, 2, -16, 15); case RISCVVector::BI__builtin_rvv_sf_vc_v_iv: case RISCVVector::BI__builtin_rvv_sf_vc_v_iv_se: // bit_27_26, vs2, simm5 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 2, -16, 15); + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || + BuiltinConstantArgRange(TheCall, 2, -16, 15); case RISCVVector::BI__builtin_rvv_sf_vc_ivv_se: case RISCVVector::BI__builtin_rvv_sf_vc_ivw_se: case RISCVVector::BI__builtin_rvv_sf_vc_v_ivv: @@ -5984,13 +5978,13 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_sf_vc_v_ivv_se: case RISCVVector::BI__builtin_rvv_sf_vc_v_ivw_se: // bit_27_26, vd, vs2, simm5 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 3, -16, 15); + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || + BuiltinConstantArgRange(TheCall, 3, -16, 15); case RISCVVector::BI__builtin_rvv_sf_vc_x_se: // bit_27_26, bit_24_20, bit_11_7, xs1, sew, log2lmul - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 31) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 31) || + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || + BuiltinConstantArgRange(TheCall, 1, 0, 31) || + BuiltinConstantArgRange(TheCall, 2, 0, 31) || CheckRISCVLMUL(TheCall, 5); case RISCVVector::BI__builtin_rvv_sf_vc_xv_se: case RISCVVector::BI__builtin_rvv_sf_vc_vv_se: @@ -5998,8 +5992,8 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_sf_vc_v_x: case RISCVVector::BI__builtin_rvv_sf_vc_v_x_se: // bit_27_26, bit_24-20, xs1 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || + BuiltinConstantArgRange(TheCall, 1, 0, 31); case RISCVVector::BI__builtin_rvv_sf_vc_vvv_se: case RISCVVector::BI__builtin_rvv_sf_vc_xvv_se: case RISCVVector::BI__builtin_rvv_sf_vc_vvw_se: @@ -6019,11 +6013,11 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_sf_vc_v_xvw_se: case RISCVVector::BI__builtin_rvv_sf_vc_v_vvw_se: // bit_27_26, vd, vs2, xs1/vs1 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3); + return BuiltinConstantArgRange(TheCall, 0, 0, 3); case RISCVVector::BI__builtin_rvv_sf_vc_fv_se: // bit_26, bit_11_7, vs2, fs1 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + return BuiltinConstantArgRange(TheCall, 0, 0, 1) || + BuiltinConstantArgRange(TheCall, 1, 0, 31); case RISCVVector::BI__builtin_rvv_sf_vc_fvv_se: case RISCVVector::BI__builtin_rvv_sf_vc_fvw_se: case RISCVVector::BI__builtin_rvv_sf_vc_v_fvv: @@ -6034,7 +6028,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_sf_vc_v_fv: case RISCVVector::BI__builtin_rvv_sf_vc_v_fv_se: // bit_26, vs2, fs1 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1); + return BuiltinConstantArgRange(TheCall, 0, 0, 1); // Check if byteselect is in [0, 3] case RISCV::BI__builtin_riscv_aes32dsi: case RISCV::BI__builtin_riscv_aes32dsmi: @@ -6042,10 +6036,10 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCV::BI__builtin_riscv_aes32esmi: case RISCV::BI__builtin_riscv_sm4ks: case RISCV::BI__builtin_riscv_sm4ed: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3); + return BuiltinConstantArgRange(TheCall, 2, 0, 3); // Check if rnum is in [0, 10] case RISCV::BI__builtin_riscv_aes64ks1i: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 10); + return BuiltinConstantArgRange(TheCall, 1, 0, 10); // Check if value range for vxrm is in [0, 3] case RISCVVector::BI__builtin_rvv_vaaddu_vv: case RISCVVector::BI__builtin_rvv_vaaddu_vx: @@ -6065,7 +6059,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vnclip_wx: case RISCVVector::BI__builtin_rvv_vnclipu_wv: case RISCVVector::BI__builtin_rvv_vnclipu_wx: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3); + return BuiltinConstantArgRange(TheCall, 2, 0, 3); case RISCVVector::BI__builtin_rvv_vaaddu_vv_tu: case RISCVVector::BI__builtin_rvv_vaaddu_vx_tu: case RISCVVector::BI__builtin_rvv_vaadd_vv_tu: @@ -6102,7 +6096,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vnclip_wx_m: case RISCVVector::BI__builtin_rvv_vnclipu_wv_m: case RISCVVector::BI__builtin_rvv_vnclipu_wx_m: - return SemaBuiltinConstantArgRange(TheCall, 3, 0, 3); + return BuiltinConstantArgRange(TheCall, 3, 0, 3); case RISCVVector::BI__builtin_rvv_vaaddu_vv_tum: case RISCVVector::BI__builtin_rvv_vaaddu_vv_tumu: case RISCVVector::BI__builtin_rvv_vaaddu_vv_mu: @@ -6157,7 +6151,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vnclip_wx_tumu: case RISCVVector::BI__builtin_rvv_vnclipu_wv_tumu: case RISCVVector::BI__builtin_rvv_vnclipu_wx_tumu: - return SemaBuiltinConstantArgRange(TheCall, 4, 0, 3); + return BuiltinConstantArgRange(TheCall, 4, 0, 3); case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm: case RISCVVector::BI__builtin_rvv_vfrec7_v_rm: case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm: @@ -6171,7 +6165,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm: case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm: case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 4); + return BuiltinConstantArgRange(TheCall, 1, 0, 4); case RISCVVector::BI__builtin_rvv_vfadd_vv_rm: case RISCVVector::BI__builtin_rvv_vfadd_vf_rm: case RISCVVector::BI__builtin_rvv_vfsub_vv_rm: @@ -6222,7 +6216,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_m: case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_m: case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_m: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 4); + return BuiltinConstantArgRange(TheCall, 2, 0, 4); case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_tu: case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_tu: case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_tu: @@ -6358,7 +6352,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_mu: case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_mu: case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_mu: - return SemaBuiltinConstantArgRange(TheCall, 3, 0, 4); + return BuiltinConstantArgRange(TheCall, 3, 0, 4); case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_m: case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_m: case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_m: @@ -6519,7 +6513,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_mu: case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_mu: case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_mu: - return SemaBuiltinConstantArgRange(TheCall, 4, 0, 4); + return BuiltinConstantArgRange(TheCall, 4, 0, 4); case RISCV::BI__builtin_riscv_ntl_load: case RISCV::BI__builtin_riscv_ntl_store: DeclRefExpr *DRE = @@ -6539,7 +6533,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, // Domain value should be compile-time constant. // 2 <= domain <= 5 if (TheCall->getNumArgs() == NumArgs && - SemaBuiltinConstantArgRange(TheCall, NumArgs - 1, 2, 5)) + BuiltinConstantArgRange(TheCall, NumArgs - 1, 2, 5)) return true; Expr *PointerArg = TheCall->getArg(0); @@ -6623,8 +6617,8 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, case SystemZ::BI__builtin_s390_vfaezfs: i = 2; l = 0; u = 15; break; case SystemZ::BI__builtin_s390_vfisb: case SystemZ::BI__builtin_s390_vfidb: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 15) || + BuiltinConstantArgRange(TheCall, 2, 0, 15); case SystemZ::BI__builtin_s390_vftcisb: case SystemZ::BI__builtin_s390_vftcidb: i = 1; l = 0; u = 4095; break; case SystemZ::BI__builtin_s390_vlbb: i = 1; l = 0; u = 15; break; @@ -6655,7 +6649,7 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, case SystemZ::BI__builtin_s390_vcnf: i = 1; l = 0; u = 15; break; case SystemZ::BI__builtin_s390_vcrnfs: i = 2; l = 0; u = 15; break; } - return SemaBuiltinConstantArgRange(TheCall, i, l, u); + return BuiltinConstantArgRange(TheCall, i, l, u); } bool Sema::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, @@ -7008,7 +7002,7 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; // Make sure rounding mode is either ROUND_CUR_DIRECTION or ROUND_NO_EXC bit @@ -7118,7 +7112,7 @@ bool Sema::CheckX86BuiltinGatherScatterScale(unsigned BuiltinID, return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; if (Result == 1 || Result == 2 || Result == 4 || Result == 8) @@ -7133,7 +7127,7 @@ enum { TileRegLow = 0, TileRegHigh = 7 }; bool Sema::CheckX86BuiltinTileArgumentsRange(CallExpr *TheCall, ArrayRef ArgNums) { for (int ArgNum : ArgNums) { - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, TileRegLow, TileRegHigh)) + if (BuiltinConstantArgRange(TheCall, ArgNum, TileRegLow, TileRegHigh)) return true; } return false; @@ -7150,7 +7144,7 @@ bool Sema::CheckX86BuiltinTileDuplicate(CallExpr *TheCall, continue; llvm::APSInt Result; - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; int ArgExtValue = Result.getExtValue(); assert((ArgExtValue >= TileRegLow && ArgExtValue <= TileRegHigh) && @@ -7576,7 +7570,7 @@ bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, // template-generated or macro-generated dead code to potentially have out-of- // range values. These need to code generate, but don't need to necessarily // make any sense. We use a warning that defaults to an error. - return SemaBuiltinConstantArgRange(TheCall, i, l, u, /*RangeIsError*/ false); + return BuiltinConstantArgRange(TheCall, i, l, u, /*RangeIsError*/ false); } /// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo @@ -7944,6 +7938,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, // For variadic functions, we may have more args than parameters. // For some K&R functions, we may have less args than parameters. const auto N = std::min(Proto->getNumParams(), Args.size()); + bool AnyScalableArgsOrRet = Proto->getReturnType()->isSizelessVectorType(); for (unsigned ArgIdx = 0; ArgIdx < N; ++ArgIdx) { // Args[ArgIdx] can be null in malformed code. if (const Expr *Arg = Args[ArgIdx]) { @@ -7957,6 +7952,8 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, checkAIXMemberAlignment((Arg->getExprLoc()), Arg); QualType ParamTy = Proto->getParamType(ArgIdx); + if (ParamTy->isSizelessVectorType()) + AnyScalableArgsOrRet = true; QualType ArgTy = Arg->getType(); CheckArgAlignment(Arg->getExprLoc(), FDecl, std::to_string(ArgIdx + 1), ArgTy, ParamTy); @@ -7977,6 +7974,23 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, } } + // If the call requires a streaming-mode change and has scalable vector + // arguments or return values, then warn the user that the streaming and + // non-streaming vector lengths may be different. + const auto *CallerFD = dyn_cast(CurContext); + if (CallerFD && (!FD || !FD->getBuiltinID()) && AnyScalableArgsOrRet) { + bool IsCalleeStreaming = + ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask; + bool IsCalleeStreamingCompatible = + ExtInfo.AArch64SMEAttributes & + FunctionType::SME_PStateSMCompatibleMask; + ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD); + if (!IsCalleeStreamingCompatible && + (CallerFnType == ArmStreamingCompatible || + ((CallerFnType == ArmStreaming) ^ IsCalleeStreaming))) + Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming); + } + FunctionType::ArmStateValue CalleeArmZAState = FunctionType::getArmZAState(ExtInfo.AArch64SMEAttributes); FunctionType::ArmStateValue CalleeArmZT0State = @@ -7985,7 +7999,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, CalleeArmZT0State != FunctionType::ARM_None) { bool CallerHasZAState = false; bool CallerHasZT0State = false; - if (const auto *CallerFD = dyn_cast(CurContext)) { + if (CallerFD) { auto *Attr = CallerFD->getAttr(); if (Attr && Attr->isNewZA()) CallerHasZAState = true; @@ -8237,8 +8251,8 @@ static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) { } } -ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, - AtomicExpr::AtomicOp Op) { +ExprResult Sema::AtomicOpsOverloaded(ExprResult TheCallResult, + AtomicExpr::AtomicOp Op) { CallExpr *TheCall = cast(TheCallResult.get()); DeclRefExpr *DRE =cast(TheCall->getCallee()->IgnoreParenCasts()); MultiExprArg Args{TheCall->getArgs(), TheCall->getNumArgs()}; @@ -8867,8 +8881,7 @@ bool Sema::BuiltinWasmRefNullFunc(CallExpr *TheCall) { /// /// This function goes through and does final semantic checking for these /// builtins, as well as generating any warnings. -ExprResult -Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { +ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) { CallExpr *TheCall = static_cast(TheCallResult.get()); Expr *Callee = TheCall->getCallee(); DeclRefExpr *DRE = cast(Callee->IgnoreParenCasts()); @@ -9239,13 +9252,13 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { return TheCallResult; } -/// SemaBuiltinNontemporalOverloaded - We have a call to +/// BuiltinNontemporalOverloaded - We have a call to /// __builtin_nontemporal_store or __builtin_nontemporal_load, which is an /// overloaded function based on the pointer type of its last argument. /// /// This function goes through and does final semantic checking for these /// builtins. -ExprResult Sema::SemaBuiltinNontemporalOverloaded(ExprResult TheCallResult) { +ExprResult Sema::BuiltinNontemporalOverloaded(ExprResult TheCallResult) { CallExpr *TheCall = (CallExpr *)TheCallResult.get(); DeclRefExpr *DRE = cast(TheCall->getCallee()->IgnoreParenCasts()); @@ -9446,7 +9459,7 @@ static bool checkVAStartIsInVariadicFunction(Sema &S, Expr *Fn, /// Check the arguments to '__builtin_va_start' or '__builtin_ms_va_start' /// for validity. Emit an error and return true on failure; return false /// on success. -bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { +bool Sema::BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { Expr *Fn = TheCall->getCallee(); if (checkVAStartABI(*this, BuiltinID, Fn)) @@ -9520,7 +9533,7 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { return false; } -bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) { +bool Sema::BuiltinVAStartARMMicrosoft(CallExpr *Call) { auto IsSuitablyTypedFormatArgument = [this](const Expr *Arg) -> bool { const LangOptions &LO = getLangOpts(); @@ -9583,9 +9596,9 @@ bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) { return false; } -/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isgreater and +/// BuiltinUnorderedCompare - Handle functions like __builtin_isgreater and /// friends. This is declared to take (...), so we have to check everything. -bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) { +bool Sema::BuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) { if (checkArgCount(*this, TheCall, 2)) return true; @@ -9625,11 +9638,11 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) { return false; } -/// SemaBuiltinSemaBuiltinFPClassification - Handle functions like +/// BuiltinSemaBuiltinFPClassification - Handle functions like /// __builtin_isnan and friends. This is declared to take (...), so we have /// to check everything. -bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, - unsigned BuiltinID) { +bool Sema::BuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, + unsigned BuiltinID) { if (checkArgCount(*this, TheCall, NumArgs)) return true; @@ -9697,7 +9710,7 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, // __builtin_isfpclass has integer parameter that specify test mask. It is // passed in (...), so it should be analyzed completely here. if (IsFPClass) - if (SemaBuiltinConstantArgRange(TheCall, 1, 0, llvm::fcAllFlags)) + if (BuiltinConstantArgRange(TheCall, 1, 0, llvm::fcAllFlags)) return true; // TODO: enable this code to all classification functions. @@ -9714,7 +9727,7 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, } /// Perform semantic analysis for a call to __builtin_complex. -bool Sema::SemaBuiltinComplex(CallExpr *TheCall) { +bool Sema::BuiltinComplex(CallExpr *TheCall) { if (checkArgCount(*this, TheCall, 2)) return true; @@ -9775,7 +9788,7 @@ bool Sema::SemaBuiltinComplex(CallExpr *TheCall) { // Example builtins are : // vector double vec_xxpermdi(vector double, vector double, int); // vector short vec_xxsldwi(vector short, vector short, int); -bool Sema::SemaBuiltinVSX(CallExpr *TheCall) { +bool Sema::BuiltinVSX(CallExpr *TheCall) { unsigned ExpectedNumArgs = 3; if (checkArgCount(*this, TheCall, ExpectedNumArgs)) return true; @@ -9817,9 +9830,9 @@ bool Sema::SemaBuiltinVSX(CallExpr *TheCall) { return false; } -/// SemaBuiltinShuffleVector - Handle __builtin_shufflevector. +/// BuiltinShuffleVector - Handle __builtin_shufflevector. // This is declared to take (...), so we have to check everything. -ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { +ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) { if (TheCall->getNumArgs() < 2) return ExprError(Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least) @@ -9907,10 +9920,10 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { TheCall->getRParenLoc()); } -/// SemaConvertVectorExpr - Handle __builtin_convertvector -ExprResult Sema::SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, - SourceLocation BuiltinLoc, - SourceLocation RParenLoc) { +/// ConvertVectorExpr - Handle __builtin_convertvector +ExprResult Sema::ConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc) { ExprValueKind VK = VK_PRValue; ExprObjectKind OK = OK_Ordinary; QualType DstTy = TInfo->getType(); @@ -9934,14 +9947,14 @@ ExprResult Sema::SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, << E->getSourceRange()); } - return new (Context) - ConvertVectorExpr(E, TInfo, DstTy, VK, OK, BuiltinLoc, RParenLoc); + return new (Context) class ConvertVectorExpr(E, TInfo, DstTy, VK, OK, + BuiltinLoc, RParenLoc); } -/// SemaBuiltinPrefetch - Handle __builtin_prefetch. +/// BuiltinPrefetch - Handle __builtin_prefetch. // This is declared to take (const void*, ...) and can take two // optional constant int args. -bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { +bool Sema::BuiltinPrefetch(CallExpr *TheCall) { unsigned NumArgs = TheCall->getNumArgs(); if (NumArgs > 3) @@ -9953,14 +9966,14 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { // Argument 0 is checked for us and the remaining arguments must be // constant integers. for (unsigned i = 1; i != NumArgs; ++i) - if (SemaBuiltinConstantArgRange(TheCall, i, 0, i == 1 ? 1 : 3)) + if (BuiltinConstantArgRange(TheCall, i, 0, i == 1 ? 1 : 3)) return true; return false; } -/// SemaBuiltinArithmeticFence - Handle __arithmetic_fence. -bool Sema::SemaBuiltinArithmeticFence(CallExpr *TheCall) { +/// BuiltinArithmeticFence - Handle __arithmetic_fence. +bool Sema::BuiltinArithmeticFence(CallExpr *TheCall) { if (!Context.getTargetInfo().checkArithmeticFenceSupported()) return Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported) << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc()); @@ -9982,10 +9995,10 @@ bool Sema::SemaBuiltinArithmeticFence(CallExpr *TheCall) { return false; } -/// SemaBuiltinAssume - Handle __assume (MS Extension). +/// BuiltinAssume - Handle __assume (MS Extension). // __assume does not evaluate its arguments, and should warn if its argument // has side effects. -bool Sema::SemaBuiltinAssume(CallExpr *TheCall) { +bool Sema::BuiltinAssume(CallExpr *TheCall) { Expr *Arg = TheCall->getArg(0); if (Arg->isInstantiationDependent()) return false; @@ -10000,7 +10013,7 @@ bool Sema::SemaBuiltinAssume(CallExpr *TheCall) { /// Handle __builtin_alloca_with_align. This is declared /// as (size_t, size_t) where the second size_t must be a power of 2 greater /// than 8. -bool Sema::SemaBuiltinAllocaWithAlign(CallExpr *TheCall) { +bool Sema::BuiltinAllocaWithAlign(CallExpr *TheCall) { // The alignment must be a constant integer. Expr *Arg = TheCall->getArg(1); @@ -10033,7 +10046,7 @@ bool Sema::SemaBuiltinAllocaWithAlign(CallExpr *TheCall) { /// Handle __builtin_assume_aligned. This is declared /// as (const void*, size_t, ...) and can take one optional constant int arg. -bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { +bool Sema::BuiltinAssumeAligned(CallExpr *TheCall) { if (checkArgCountRange(*this, TheCall, 2, 3)) return true; @@ -10055,7 +10068,7 @@ bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { // We can't check the value of a dependent argument. if (!SecondArg->isValueDependent()) { llvm::APSInt Result; - if (SemaBuiltinConstantArg(TheCall, 1, Result)) + if (BuiltinConstantArg(TheCall, 1, Result)) return true; if (!Result.isPowerOf2()) @@ -10077,7 +10090,7 @@ bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { return false; } -bool Sema::SemaBuiltinOSLogFormat(CallExpr *TheCall) { +bool Sema::BuiltinOSLogFormat(CallExpr *TheCall) { unsigned BuiltinID = cast(TheCall->getCalleeDecl())->getBuiltinID(); bool IsSizeCall = BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size; @@ -10157,10 +10170,10 @@ bool Sema::SemaBuiltinOSLogFormat(CallExpr *TheCall) { return false; } -/// SemaBuiltinConstantArg - Handle a check if argument ArgNum of CallExpr +/// BuiltinConstantArg - Handle a check if argument ArgNum of CallExpr /// TheCall is a constant expression. -bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, - llvm::APSInt &Result) { +bool Sema::BuiltinConstantArg(CallExpr *TheCall, int ArgNum, + llvm::APSInt &Result) { Expr *Arg = TheCall->getArg(ArgNum); DeclRefExpr *DRE =cast(TheCall->getCallee()->IgnoreParenCasts()); FunctionDecl *FDecl = cast(DRE->getDecl()); @@ -10175,10 +10188,10 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, return false; } -/// SemaBuiltinConstantArgRange - Handle a check if argument ArgNum of CallExpr +/// BuiltinConstantArgRange - Handle a check if argument ArgNum of CallExpr /// TheCall is a constant expression in the range [Low, High]. -bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, - int Low, int High, bool RangeIsError) { +bool Sema::BuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, + int High, bool RangeIsError) { if (isConstantEvaluatedContext()) return false; llvm::APSInt Result; @@ -10189,7 +10202,7 @@ bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; if (Result.getSExtValue() < Low || Result.getSExtValue() > High) { @@ -10208,10 +10221,10 @@ bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, return false; } -/// SemaBuiltinConstantArgMultiple - Handle a check if argument ArgNum of CallExpr +/// BuiltinConstantArgMultiple - Handle a check if argument ArgNum of CallExpr /// TheCall is a constant expression is a multiple of Num.. -bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, - unsigned Num) { +bool Sema::BuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, + unsigned Num) { llvm::APSInt Result; // We can't check the value of a dependent argument. @@ -10220,7 +10233,7 @@ bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; if (Result.getSExtValue() % Num != 0) @@ -10230,9 +10243,9 @@ bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, return false; } -/// SemaBuiltinConstantArgPower2 - Check if argument ArgNum of TheCall is a +/// BuiltinConstantArgPower2 - Check if argument ArgNum of TheCall is a /// constant expression representing a power of 2. -bool Sema::SemaBuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum) { +bool Sema::BuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum) { llvm::APSInt Result; // We can't check the value of a dependent argument. @@ -10241,7 +10254,7 @@ bool Sema::SemaBuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum) { return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; // Bit-twiddling to test for a power of 2: for x > 0, x & (x-1) is zero if @@ -10275,11 +10288,11 @@ static bool IsShiftedByte(llvm::APSInt Value) { } } -/// SemaBuiltinConstantArgShiftedByte - Check if argument ArgNum of TheCall is +/// BuiltinConstantArgShiftedByte - Check if argument ArgNum of TheCall is /// a constant expression representing an arbitrary byte value shifted left by /// a multiple of 8 bits. -bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, - unsigned ArgBits) { +bool Sema::BuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, + unsigned ArgBits) { llvm::APSInt Result; // We can't check the value of a dependent argument. @@ -10288,7 +10301,7 @@ bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; // Truncate to the given size. @@ -10302,14 +10315,13 @@ bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, << Arg->getSourceRange(); } -/// SemaBuiltinConstantArgShiftedByteOr0xFF - Check if argument ArgNum of +/// BuiltinConstantArgShiftedByteOr0xFF - Check if argument ArgNum of /// TheCall is a constant expression representing either a shifted byte value, /// or a value of the form 0x??FF (i.e. a member of the arithmetic progression /// 0x00FF, 0x01FF, ..., 0xFFFF). This strange range check is needed for some /// Arm MVE intrinsics. -bool Sema::SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, - int ArgNum, - unsigned ArgBits) { +bool Sema::BuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, int ArgNum, + unsigned ArgBits) { llvm::APSInt Result; // We can't check the value of a dependent argument. @@ -10318,7 +10330,7 @@ bool Sema::SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; // Truncate to the given size. @@ -10335,8 +10347,8 @@ bool Sema::SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, << Arg->getSourceRange(); } -/// SemaBuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions -bool Sema::SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall) { +/// BuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions +bool Sema::BuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == AArch64::BI__builtin_arm_irg) { if (checkArgCount(*this, TheCall, 2)) return true; @@ -10383,7 +10395,7 @@ bool Sema::SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall TheCall->setType(FirstArgType); // Second arg must be an constant in range [0,15] - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 15); } if (BuiltinID == AArch64::BI__builtin_arm_gmi) { @@ -10489,11 +10501,11 @@ bool Sema::SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall return true; } -/// SemaBuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr +/// BuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr /// TheCall is an ARM/AArch64 special register string literal. -bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, - int ArgNum, unsigned ExpectedFieldNum, - bool AllowName) { +bool Sema::BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, + int ArgNum, unsigned ExpectedFieldNum, + bool AllowName) { bool IsARMBuiltin = BuiltinID == ARM::BI__builtin_arm_rsr64 || BuiltinID == ARM::BI__builtin_arm_wsr64 || BuiltinID == ARM::BI__builtin_arm_rsr || @@ -10615,18 +10627,18 @@ bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, // If a programmer wants to codegen the MSR (register) form of `msr tco, // xN`, they can still do so by specifying the register using five // colon-separated numbers in a string. - return SemaBuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit); + return BuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit); } return false; } -/// SemaBuiltinPPCMMACall - Check the call to a PPC MMA builtin for validity. +/// BuiltinPPCMMACall - Check the call to a PPC MMA builtin for validity. /// Emit an error and return true on failure; return false on success. /// TypeStr is a string containing the type descriptor of the value returned by /// the builtin and the descriptors of the expected type of the arguments. -bool Sema::SemaBuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, - const char *TypeStr) { +bool Sema::BuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, + const char *TypeStr) { assert((TypeStr[0] != '\0') && "Invalid types in PPC MMA builtin declaration"); @@ -10669,8 +10681,7 @@ bool Sema::SemaBuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, // If the value of the Mask is not 0, we have a constraint in the size of // the integer argument so here we ensure the argument is a constant that // is in the valid range. - if (Mask != 0 && - SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, Mask, true)) + if (Mask != 0 && BuiltinConstantArgRange(TheCall, ArgNum, 0, Mask, true)) return true; ArgNum++; @@ -10690,10 +10701,10 @@ bool Sema::SemaBuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, return false; } -/// SemaBuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val). +/// BuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val). /// This checks that the target supports __builtin_longjmp and /// that val is a constant 1. -bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { +bool Sema::BuiltinLongjmp(CallExpr *TheCall) { if (!Context.getTargetInfo().hasSjLjLowering()) return Diag(TheCall->getBeginLoc(), diag::err_builtin_longjmp_unsupported) << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc()); @@ -10702,7 +10713,7 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { llvm::APSInt Result; // TODO: This is less than ideal. Overload this to take a value. - if (SemaBuiltinConstantArg(TheCall, 1, Result)) + if (BuiltinConstantArg(TheCall, 1, Result)) return true; if (Result != 1) @@ -10712,9 +10723,9 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { return false; } -/// SemaBuiltinSetjmp - Handle __builtin_setjmp(void *env[5]). +/// BuiltinSetjmp - Handle __builtin_setjmp(void *env[5]). /// This checks that the target supports __builtin_setjmp. -bool Sema::SemaBuiltinSetjmp(CallExpr *TheCall) { +bool Sema::BuiltinSetjmp(CallExpr *TheCall) { if (!Context.getTargetInfo().hasSjLjLowering()) return Diag(TheCall->getBeginLoc(), diag::err_builtin_setjmp_unsupported) << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc()); @@ -19699,6 +19710,27 @@ bool Sema::IsLayoutCompatible(QualType T1, QualType T2) const { return isLayoutCompatible(getASTContext(), T1, T2); } +//===-------------- Pointer interconvertibility ----------------------------// + +bool Sema::IsPointerInterconvertibleBaseOf(const TypeSourceInfo *Base, + const TypeSourceInfo *Derived) { + QualType BaseT = Base->getType()->getCanonicalTypeUnqualified(); + QualType DerivedT = Derived->getType()->getCanonicalTypeUnqualified(); + + if (BaseT->isStructureOrClassType() && DerivedT->isStructureOrClassType() && + getASTContext().hasSameType(BaseT, DerivedT)) + return true; + + if (!IsDerivedFrom(Derived->getTypeLoc().getBeginLoc(), DerivedT, BaseT)) + return false; + + // Per [basic.compound]/4.3, containing object has to be standard-layout. + if (DerivedT->getAsCXXRecordDecl()->isStandardLayout()) + return true; + + return false; +} + //===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----// /// Given a type tag expression find the type tag itself. @@ -20134,17 +20166,17 @@ bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) { return false; } -bool Sema::SemaBuiltinElementwiseMath(CallExpr *TheCall) { +bool Sema::BuiltinElementwiseMath(CallExpr *TheCall) { QualType Res; - if (SemaBuiltinVectorMath(TheCall, Res)) + if (BuiltinVectorMath(TheCall, Res)) return true; TheCall->setType(Res); return false; } -bool Sema::SemaBuiltinVectorToScalarMath(CallExpr *TheCall) { +bool Sema::BuiltinVectorToScalarMath(CallExpr *TheCall) { QualType Res; - if (SemaBuiltinVectorMath(TheCall, Res)) + if (BuiltinVectorMath(TheCall, Res)) return true; if (auto *VecTy0 = Res->getAs()) @@ -20155,7 +20187,7 @@ bool Sema::SemaBuiltinVectorToScalarMath(CallExpr *TheCall) { return false; } -bool Sema::SemaBuiltinVectorMath(CallExpr *TheCall, QualType &Res) { +bool Sema::BuiltinVectorMath(CallExpr *TheCall, QualType &Res) { if (checkArgCount(*this, TheCall, 2)) return true; @@ -20183,8 +20215,8 @@ bool Sema::SemaBuiltinVectorMath(CallExpr *TheCall, QualType &Res) { return false; } -bool Sema::SemaBuiltinElementwiseTernaryMath(CallExpr *TheCall, - bool CheckForFloatArgs) { +bool Sema::BuiltinElementwiseTernaryMath(CallExpr *TheCall, + bool CheckForFloatArgs) { if (checkArgCount(*this, TheCall, 3)) return true; @@ -20239,7 +20271,7 @@ bool Sema::PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall) { return false; } -bool Sema::SemaBuiltinNonDeterministicValue(CallExpr *TheCall) { +bool Sema::BuiltinNonDeterministicValue(CallExpr *TheCall) { if (checkArgCount(*this, TheCall, 1)) return true; @@ -20254,8 +20286,8 @@ bool Sema::SemaBuiltinNonDeterministicValue(CallExpr *TheCall) { return false; } -ExprResult Sema::SemaBuiltinMatrixTranspose(CallExpr *TheCall, - ExprResult CallResult) { +ExprResult Sema::BuiltinMatrixTranspose(CallExpr *TheCall, + ExprResult CallResult) { if (checkArgCount(*this, TheCall, 1)) return ExprError(); @@ -20304,8 +20336,8 @@ getAndVerifyMatrixDimension(Expr *Expr, StringRef Name, Sema &S) { return Dim; } -ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall, - ExprResult CallResult) { +ExprResult Sema::BuiltinMatrixColumnMajorLoad(CallExpr *TheCall, + ExprResult CallResult) { if (!getLangOpts().MatrixTypes) { Diag(TheCall->getBeginLoc(), diag::err_builtin_matrix_disabled); return ExprError(); @@ -20420,8 +20452,8 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall, return CallResult; } -ExprResult Sema::SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall, - ExprResult CallResult) { +ExprResult Sema::BuiltinMatrixColumnMajorStore(CallExpr *TheCall, + ExprResult CallResult) { if (checkArgCount(*this, TheCall, 3)) return ExprError(); diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 83ebcaf9e765a78e95de4630df7b0b8f55f370ff..c335017f243eb27b59d83da452f02bb657e05f99 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -3691,7 +3691,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( std::string Keyword; if (Idx > StartParameter) Result.AddChunk(CodeCompletionString::CK_HorizontalSpace); - if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx)) + if (const IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx)) Keyword += II->getName(); Keyword += ":"; if (Idx < StartParameter || AllParametersAreInformative) @@ -3720,7 +3720,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier(), ParamType); Arg += ParamType.getAsString(Policy) + ")"; - if (IdentifierInfo *II = (*P)->getIdentifier()) + if (const IdentifierInfo *II = (*P)->getIdentifier()) if (DeclaringEntity || AllParametersAreInformative) Arg += II->getName(); } @@ -4500,11 +4500,11 @@ void Sema::CodeCompleteOrdinaryName(Scope *S, Results.data(), Results.size()); } -static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, - ParsedType Receiver, - ArrayRef SelIdents, - bool AtArgumentExpression, bool IsSuper, - ResultBuilder &Results); +static void +AddClassMessageCompletions(Sema &SemaRef, Scope *S, ParsedType Receiver, + ArrayRef SelIdents, + bool AtArgumentExpression, bool IsSuper, + ResultBuilder &Results); void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, bool AllowNonIdentifiers, @@ -4928,7 +4928,7 @@ void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E, /// The set of properties that have already been added, referenced by /// property name. -typedef llvm::SmallPtrSet AddedPropertiesSet; +typedef llvm::SmallPtrSet AddedPropertiesSet; /// Retrieve the container definition, if any? static ObjCContainerDecl *getContainerDef(ObjCContainerDecl *Container) { @@ -5090,7 +5090,7 @@ AddObjCProperties(const CodeCompletionContext &CCContext, PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema()); // Adds a method result const auto AddMethod = [&](const ObjCMethodDecl *M) { - IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0); + const IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0); if (!Name) return; if (!AddedProperties.insert(Name).second) @@ -5859,10 +5859,10 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, } void Sema::CodeCompleteObjCClassPropertyRefExpr(Scope *S, - IdentifierInfo &ClassName, + const IdentifierInfo &ClassName, SourceLocation ClassNameLoc, bool IsBaseExprStatement) { - IdentifierInfo *ClassNamePtr = &ClassName; + const IdentifierInfo *ClassNamePtr = &ClassName; ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(ClassNamePtr, ClassNameLoc); if (!IFace) return; @@ -7527,7 +7527,7 @@ enum ObjCMethodKind { }; static bool isAcceptableObjCSelector(Selector Sel, ObjCMethodKind WantKind, - ArrayRef SelIdents, + ArrayRef SelIdents, bool AllowSameLength = true) { unsigned NumSelIdents = SelIdents.size(); if (NumSelIdents > Sel.getNumArgs()) @@ -7554,7 +7554,7 @@ static bool isAcceptableObjCSelector(Selector Sel, ObjCMethodKind WantKind, static bool isAcceptableObjCMethod(ObjCMethodDecl *Method, ObjCMethodKind WantKind, - ArrayRef SelIdents, + ArrayRef SelIdents, bool AllowSameLength = true) { return isAcceptableObjCSelector(Method->getSelector(), WantKind, SelIdents, AllowSameLength); @@ -7586,7 +7586,7 @@ typedef llvm::SmallPtrSet VisitedSelectorSet; /// \param Results the structure into which we'll add results. static void AddObjCMethods(ObjCContainerDecl *Container, bool WantInstanceMethods, ObjCMethodKind WantKind, - ArrayRef SelIdents, + ArrayRef SelIdents, DeclContext *CurContext, VisitedSelectorSet &Selectors, bool AllowSameLength, ResultBuilder &Results, bool InOriginalClass = true, @@ -7819,7 +7819,7 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) { if (Sel.isNull()) return nullptr; - IdentifierInfo *Id = Sel.getIdentifierInfoForSlot(0); + const IdentifierInfo *Id = Sel.getIdentifierInfoForSlot(0); if (!Id) return nullptr; @@ -7895,7 +7895,7 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) { /// this "super" completion. If NULL, no completion was added. static ObjCMethodDecl * AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword, - ArrayRef SelIdents, + ArrayRef SelIdents, ResultBuilder &Results) { ObjCMethodDecl *CurMethod = S.getCurMethodDecl(); if (!CurMethod) @@ -8032,9 +8032,9 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) { Results.data(), Results.size()); } -void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, - ArrayRef SelIdents, - bool AtArgumentExpression) { +void Sema::CodeCompleteObjCSuperMessage( + Scope *S, SourceLocation SuperLoc, + ArrayRef SelIdents, bool AtArgumentExpression) { ObjCInterfaceDecl *CDecl = nullptr; if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { // Figure out which interface we're in. @@ -8059,7 +8059,7 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, } else { // "super" may be the name of a type or variable. Figure out which // it is. - IdentifierInfo *Super = getSuperIdentifier(); + const IdentifierInfo *Super = getSuperIdentifier(); NamedDecl *ND = LookupSingleName(S, Super, SuperLoc, LookupOrdinaryName); if ((CDecl = dyn_cast_or_null(ND))) { // "super" names an interface. Use it. @@ -8127,11 +8127,11 @@ static QualType getPreferredArgumentTypeForMessageSend(ResultBuilder &Results, return PreferredType; } -static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, - ParsedType Receiver, - ArrayRef SelIdents, - bool AtArgumentExpression, bool IsSuper, - ResultBuilder &Results) { +static void +AddClassMessageCompletions(Sema &SemaRef, Scope *S, ParsedType Receiver, + ArrayRef SelIdents, + bool AtArgumentExpression, bool IsSuper, + ResultBuilder &Results) { typedef CodeCompletionResult Result; ObjCInterfaceDecl *CDecl = nullptr; @@ -8202,10 +8202,9 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, Results.ExitScope(); } -void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, - ArrayRef SelIdents, - bool AtArgumentExpression, - bool IsSuper) { +void Sema::CodeCompleteObjCClassMessage( + Scope *S, ParsedType Receiver, ArrayRef SelIdents, + bool AtArgumentExpression, bool IsSuper) { QualType T = this->GetTypeFromParser(Receiver); @@ -8237,10 +8236,9 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, Results.data(), Results.size()); } -void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, - ArrayRef SelIdents, - bool AtArgumentExpression, - ObjCInterfaceDecl *Super) { +void Sema::CodeCompleteObjCInstanceMessage( + Scope *S, Expr *Receiver, ArrayRef SelIdents, + bool AtArgumentExpression, ObjCInterfaceDecl *Super) { typedef CodeCompletionResult Result; Expr *RecExpr = static_cast(Receiver); @@ -8410,8 +8408,8 @@ void Sema::CodeCompleteObjCForCollection(Scope *S, CodeCompleteExpression(S, Data); } -void Sema::CodeCompleteObjCSelector(Scope *S, - ArrayRef SelIdents) { +void Sema::CodeCompleteObjCSelector( + Scope *S, ArrayRef SelIdents) { // If we have an external source, load the entire class method // pool from the AST file. if (ExternalSource) { @@ -9166,8 +9164,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // Add -(void)getKey:(type **)buffer range:(NSRange)inRange if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("get") + UpperKey).str(); - IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName), - &Context.Idents.get("range")}; + const IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName), + &Context.Idents.get("range")}; if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { @@ -9198,8 +9196,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)insertObject:(type *)object inKeyAtIndex:(NSUInteger)index if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("in") + UpperKey + "AtIndex").str(); - IdentifierInfo *SelectorIds[2] = {&Context.Idents.get("insertObject"), - &Context.Idents.get(SelectorName)}; + const IdentifierInfo *SelectorIds[2] = {&Context.Idents.get("insertObject"), + &Context.Idents.get(SelectorName)}; if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { @@ -9228,8 +9226,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)insertKey:(NSArray *)array atIndexes:(NSIndexSet *)indexes if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("insert") + UpperKey).str(); - IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName), - &Context.Idents.get("atIndexes")}; + const IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName), + &Context.Idents.get("atIndexes")}; if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { @@ -9258,7 +9256,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("removeObjectFrom") + UpperKey + "AtIndex").str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9279,7 +9277,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // -(void)removeKeyAtIndexes:(NSIndexSet *)indexes if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("remove") + UpperKey + "AtIndexes").str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9301,8 +9299,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("replaceObjectIn") + UpperKey + "AtIndex").str(); - IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName), - &Context.Idents.get("withObject")}; + const IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName), + &Context.Idents.get("withObject")}; if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { @@ -9332,8 +9330,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName1 = (Twine("replace") + UpperKey + "AtIndexes").str(); std::string SelectorName2 = (Twine("with") + UpperKey).str(); - IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName1), - &Context.Idents.get(SelectorName2)}; + const IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName1), + &Context.Idents.get(SelectorName2)}; if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { @@ -9368,7 +9366,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ->getInterfaceDecl() ->getName() == "NSEnumerator"))) { std::string SelectorName = (Twine("enumeratorOf") + UpperKey).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) .second) { if (ReturnType.isNull()) { @@ -9387,7 +9385,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) { std::string SelectorName = (Twine("memberOf") + UpperKey).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9417,7 +9415,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("add") + UpperKey + Twine("Object")).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9439,7 +9437,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)addKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("add") + UpperKey).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9461,7 +9459,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("remove") + UpperKey + Twine("Object")).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9483,7 +9481,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)removeKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("remove") + UpperKey).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9504,7 +9502,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)intersectKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("intersect") + UpperKey).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9533,7 +9531,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ->getName() == "NSSet"))) { std::string SelectorName = (Twine("keyPathsForValuesAffecting") + UpperKey).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) .second) { if (ReturnType.isNull()) { @@ -9554,7 +9552,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ReturnType->isBooleanType())) { std::string SelectorName = (Twine("automaticallyNotifiesObserversOf") + UpperKey).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) .second) { if (ReturnType.isNull()) { @@ -9749,7 +9747,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, void Sema::CodeCompleteObjCMethodDeclSelector( Scope *S, bool IsInstanceMethod, bool AtParameterName, ParsedType ReturnTy, - ArrayRef SelIdents) { + ArrayRef SelIdents) { // If we have an external source, load the entire class method // pool from the AST file. if (ExternalSource) { diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index c790dab72dd7210dc8daf7b98702ccf63c31fc51..8b3b9d020db5723aeb100b183f94016572761acb 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -45,8 +45,11 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaCUDA.h" +#include "clang/Sema/SemaHLSL.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" +#include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/TargetParser/Triple.h" @@ -2318,7 +2321,7 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { /// /// \returns The declaration of the named Objective-C class, or NULL if the /// class could not be found. -ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id, +ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(const IdentifierInfo *&Id, SourceLocation IdLoc, bool DoTypoCorrection) { // The third "scope" argument is 0 since we aren't enabling lazy built-in @@ -2972,10 +2975,10 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, else if (const auto *BTFA = dyn_cast(Attr)) NewAttr = S.mergeBTFDeclTagAttr(D, *BTFA); else if (const auto *NT = dyn_cast(Attr)) - NewAttr = - S.mergeHLSLNumThreadsAttr(D, *NT, NT->getX(), NT->getY(), NT->getZ()); + NewAttr = S.HLSL().mergeNumThreadsAttr(D, *NT, NT->getX(), NT->getY(), + NT->getZ()); else if (const auto *SA = dyn_cast(Attr)) - NewAttr = S.mergeHLSLShaderAttr(D, *SA, SA->getType()); + NewAttr = S.HLSL().mergeShaderAttr(D, *SA, SA->getType()); else if (isa(Attr)) // Do nothing. Each redeclaration should be suppressed separately. NewAttr = nullptr; @@ -4048,13 +4051,13 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Scope *S, } else { Diag(NewMethod->getLocation(), diag::err_definition_of_implicitly_declared_member) - << New << getSpecialMember(OldMethod); + << New << llvm::to_underlying(getSpecialMember(OldMethod)); return true; } } else if (OldMethod->getFirstDecl()->isExplicitlyDefaulted() && !isFriend) { Diag(NewMethod->getLocation(), diag::err_definition_of_explicitly_defaulted_member) - << getSpecialMember(OldMethod); + << llvm::to_underlying(getSpecialMember(OldMethod)); return true; } } @@ -6335,16 +6338,15 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, if (TST->isDependentType() && TST->isTypeAlias()) Diag(Loc, diag::ext_alias_template_in_declarative_nns) << SpecLoc.getLocalSourceRange(); - } else if (T->isDecltypeType()) { + } else if (T->isDecltypeType() || T->getAsAdjusted()) { // C++23 [expr.prim.id.qual]p2: // [...] A declarative nested-name-specifier shall not have a - // decltype-specifier. + // computed-type-specifier. // - // FIXME: This wording appears to be defective as it does not forbid - // declarative nested-name-specifiers with pack-index-specifiers. - // See https://github.com/cplusplus/CWG/issues/499. - Diag(Loc, diag::err_decltype_in_declarator) - << SpecLoc.getTypeLoc().getSourceRange(); + // CWG2858 changed this from 'decltype-specifier' to + // 'computed-type-specifier'. + Diag(Loc, diag::err_computed_type_in_declarative_nns) + << T->isDecltypeType() << SpecLoc.getTypeLoc().getSourceRange(); } } } while ((SpecLoc = SpecLoc.getPrefix())); @@ -10594,12 +10596,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // We do not add HD attributes to specializations here because // they may have different constexpr-ness compared to their - // templates and, after maybeAddCUDAHostDeviceAttrs() is applied, + // templates and, after maybeAddHostDeviceAttrs() is applied, // may end up with different effective targets. Instead, a // specialization inherits its target attributes from its template // in the CheckFunctionTemplateSpecialization() call below. if (getLangOpts().CUDA && !isFunctionTemplateSpecialization) - maybeAddCUDAHostDeviceAttrs(NewFD, Previous); + CUDA().maybeAddHostDeviceAttrs(NewFD, Previous); // Handle explict specializations of function templates // and friend function declarations with an explicit @@ -10809,10 +10811,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (getLangOpts().HLSL && D.isFunctionDefinition()) { // Any top level function could potentially be specified as an entry. if (!NewFD->isInvalidDecl() && S->getDepth() == 0 && Name.isIdentifier()) - ActOnHLSLTopLevelFunction(NewFD); + HLSL().ActOnTopLevelFunction(NewFD); if (NewFD->hasAttr()) - CheckHLSLEntryPoint(NewFD); + HLSL().CheckEntryPoint(NewFD); } // If this is the first declaration of a library builtin function, add @@ -10897,12 +10899,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (getLangOpts().CUDA) { IdentifierInfo *II = NewFD->getIdentifier(); - if (II && II->isStr(getCudaConfigureFuncName()) && + if (II && II->isStr(CUDA().getConfigureFuncName()) && !NewFD->isInvalidDecl() && NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { if (!R->castAs()->getReturnType()->isScalarType()) Diag(NewFD->getLocation(), diag::err_config_scalar_return) - << getCudaConfigureFuncName(); + << CUDA().getConfigureFuncName(); Context.setcudaConfigureCallDecl(NewFD); } @@ -11912,8 +11914,14 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, return false; } + const llvm::Triple &T = S.getASTContext().getTargetInfo().getTriple(); + // Target attribute on AArch64 is not used for multiversioning - if (NewTA && S.getASTContext().getTargetInfo().getTriple().isAArch64()) + if (NewTA && T.isAArch64()) + return false; + + // Target attribute on RISCV is not used for multiversioning + if (NewTA && T.isRISCV()) return false; if (!OldDecl || !OldDecl->getAsFunction() || @@ -12391,16 +12399,26 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } if (!Redeclaration && LangOpts.CUDA) - checkCUDATargetOverload(NewFD, Previous); + CUDA().checkTargetOverload(NewFD, Previous); } // Check if the function definition uses any AArch64 SME features without - // having the '+sme' feature enabled. + // having the '+sme' feature enabled and warn user if sme locally streaming + // function returns or uses arguments with VL-based types. if (DeclIsDefn) { const auto *Attr = NewFD->getAttr(); bool UsesSM = NewFD->hasAttr(); bool UsesZA = Attr && Attr->isNewZA(); bool UsesZT0 = Attr && Attr->isNewZT0(); + + if (NewFD->hasAttr()) { + if (NewFD->getReturnType()->isSizelessVectorType() || + llvm::any_of(NewFD->parameters(), [](ParmVarDecl *P) { + return P->getOriginalType()->isSizelessVectorType(); + })) + Diag(NewFD->getLocation(), + diag::warn_sme_locally_streaming_has_vl_args_returns); + } if (const auto *FPT = NewFD->getType()->getAs()) { FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); UsesSM |= @@ -12650,125 +12668,6 @@ void Sema::CheckMSVCRTEntryPoint(FunctionDecl *FD) { } } -void Sema::ActOnHLSLTopLevelFunction(FunctionDecl *FD) { - auto &TargetInfo = getASTContext().getTargetInfo(); - - if (FD->getName() != TargetInfo.getTargetOpts().HLSLEntry) - return; - - StringRef Env = TargetInfo.getTriple().getEnvironmentName(); - HLSLShaderAttr::ShaderType ShaderType; - if (HLSLShaderAttr::ConvertStrToShaderType(Env, ShaderType)) { - if (const auto *Shader = FD->getAttr()) { - // The entry point is already annotated - check that it matches the - // triple. - if (Shader->getType() != ShaderType) { - Diag(Shader->getLocation(), diag::err_hlsl_entry_shader_attr_mismatch) - << Shader; - FD->setInvalidDecl(); - } - } else { - // Implicitly add the shader attribute if the entry function isn't - // explicitly annotated. - FD->addAttr(HLSLShaderAttr::CreateImplicit(Context, ShaderType, - FD->getBeginLoc())); - } - } else { - switch (TargetInfo.getTriple().getEnvironment()) { - case llvm::Triple::UnknownEnvironment: - case llvm::Triple::Library: - break; - default: - llvm_unreachable("Unhandled environment in triple"); - } - } -} - -void Sema::CheckHLSLEntryPoint(FunctionDecl *FD) { - const auto *ShaderAttr = FD->getAttr(); - assert(ShaderAttr && "Entry point has no shader attribute"); - HLSLShaderAttr::ShaderType ST = ShaderAttr->getType(); - - switch (ST) { - case HLSLShaderAttr::Pixel: - case HLSLShaderAttr::Vertex: - case HLSLShaderAttr::Geometry: - case HLSLShaderAttr::Hull: - case HLSLShaderAttr::Domain: - case HLSLShaderAttr::RayGeneration: - case HLSLShaderAttr::Intersection: - case HLSLShaderAttr::AnyHit: - case HLSLShaderAttr::ClosestHit: - case HLSLShaderAttr::Miss: - case HLSLShaderAttr::Callable: - if (const auto *NT = FD->getAttr()) { - DiagnoseHLSLAttrStageMismatch(NT, ST, - {HLSLShaderAttr::Compute, - HLSLShaderAttr::Amplification, - HLSLShaderAttr::Mesh}); - FD->setInvalidDecl(); - } - break; - - case HLSLShaderAttr::Compute: - case HLSLShaderAttr::Amplification: - case HLSLShaderAttr::Mesh: - if (!FD->hasAttr()) { - Diag(FD->getLocation(), diag::err_hlsl_missing_numthreads) - << HLSLShaderAttr::ConvertShaderTypeToStr(ST); - FD->setInvalidDecl(); - } - break; - } - - for (ParmVarDecl *Param : FD->parameters()) { - if (const auto *AnnotationAttr = Param->getAttr()) { - CheckHLSLSemanticAnnotation(FD, Param, AnnotationAttr); - } else { - // FIXME: Handle struct parameters where annotations are on struct fields. - // See: https://github.com/llvm/llvm-project/issues/57875 - Diag(FD->getLocation(), diag::err_hlsl_missing_semantic_annotation); - Diag(Param->getLocation(), diag::note_previous_decl) << Param; - FD->setInvalidDecl(); - } - } - // FIXME: Verify return type semantic annotation. -} - -void Sema::CheckHLSLSemanticAnnotation( - FunctionDecl *EntryPoint, const Decl *Param, - const HLSLAnnotationAttr *AnnotationAttr) { - auto *ShaderAttr = EntryPoint->getAttr(); - assert(ShaderAttr && "Entry point has no shader attribute"); - HLSLShaderAttr::ShaderType ST = ShaderAttr->getType(); - - switch (AnnotationAttr->getKind()) { - case attr::HLSLSV_DispatchThreadID: - case attr::HLSLSV_GroupIndex: - if (ST == HLSLShaderAttr::Compute) - return; - DiagnoseHLSLAttrStageMismatch(AnnotationAttr, ST, - {HLSLShaderAttr::Compute}); - break; - default: - llvm_unreachable("Unknown HLSLAnnotationAttr"); - } -} - -void Sema::DiagnoseHLSLAttrStageMismatch( - const Attr *A, HLSLShaderAttr::ShaderType Stage, - std::initializer_list AllowedStages) { - SmallVector StageStrings; - llvm::transform(AllowedStages, std::back_inserter(StageStrings), - [](HLSLShaderAttr::ShaderType ST) { - return StringRef( - HLSLShaderAttr::ConvertShaderTypeToStr(ST)); - }); - Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage) - << A << HLSLShaderAttr::ConvertShaderTypeToStr(Stage) - << (AllowedStages.size() != 1) << join(StageStrings, ", "); -} - bool Sema::CheckForConstantInitializer(Expr *Init, QualType DclT) { // FIXME: Need strict checking. In C89, we need to check for // any assignment, increment, decrement, function-calls, or @@ -14517,7 +14416,7 @@ StmtResult Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (var->isInvalidDecl()) return; - MaybeAddCUDAConstantAttr(var); + CUDA().MaybeAddConstantAttr(var); if (getLangOpts().OpenCL) { // OpenCL v2.0 s6.12.5 - Every block variable declaration must have an @@ -14931,7 +14830,7 @@ void Sema::FinalizeDeclaration(Decl *ThisDecl) { // variables whether they are local or not. CUDA also allows // constant initializers for __constant__ and __device__ variables. if (getLangOpts().CUDA) - checkAllowedCUDAInitializer(VD); + CUDA().checkAllowedInitializer(VD); // Grab the dllimport or dllexport attribute off of the VarDecl. const InheritableAttr *DLLAttr = getDLLAttr(VD); @@ -15297,7 +15196,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D, QualType parmDeclType = TInfo->getType(); // Check for redeclaration of parameters, e.g. int foo(int x, int x); - IdentifierInfo *II = D.getIdentifier(); + const IdentifierInfo *II = D.getIdentifier(); if (II) { LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName, ForVisibleRedeclaration); @@ -15449,9 +15348,9 @@ QualType Sema::AdjustParameterTypeForObjCAutoRefCount(QualType T, } ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, - SourceLocation NameLoc, IdentifierInfo *Name, - QualType T, TypeSourceInfo *TSInfo, - StorageClass SC) { + SourceLocation NameLoc, + const IdentifierInfo *Name, QualType T, + TypeSourceInfo *TSInfo, StorageClass SC) { // In ARC, infer a lifetime qualifier for appropriate parameter types. if (getLangOpts().ObjCAutoRefCount && T.getObjCLifetime() == Qualifiers::OCL_None && @@ -16184,7 +16083,17 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // This is meant to pop the context added in ActOnStartOfFunctionDef(). ExitFunctionBodyRAII ExitRAII(*this, isLambdaCallOperator(FD)); if (FD) { - FD->setBody(Body); + // If this is called by Parser::ParseFunctionDefinition() after marking + // the declaration as deleted, and if the deleted-function-body contains + // a message (C++26), then a DefaultedOrDeletedInfo will have already been + // added to store that message; do not overwrite it in that case. + // + // Since this would always set the body to 'nullptr' in that case anyway, + // which is already done when the function decl is initially created, + // always skipping this irrespective of whether there is a delete message + // should not be a problem. + if (!FD->isDeletedAsWritten()) + FD->setBody(Body); FD->setWillHaveBody(false); CheckImmediateEscalatingFunctionDefinition(FD, FSI); @@ -18541,8 +18450,9 @@ void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) { // Note that FieldName may be null for anonymous bitfields. ExprResult Sema::VerifyBitField(SourceLocation FieldLoc, - IdentifierInfo *FieldName, QualType FieldTy, - bool IsMsStruct, Expr *BitWidth) { + const IdentifierInfo *FieldName, + QualType FieldTy, bool IsMsStruct, + Expr *BitWidth) { assert(BitWidth); if (BitWidth->containsErrors()) return ExprError(); @@ -18651,7 +18561,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, return nullptr; } - IdentifierInfo *II = D.getIdentifier(); + const IdentifierInfo *II = D.getIdentifier(); SourceLocation Loc = DeclStart; if (II) Loc = D.getIdentifierLoc(); @@ -18752,7 +18662,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D) { - IdentifierInfo *II = Name.getAsIdentifierInfo(); + const IdentifierInfo *II = Name.getAsIdentifierInfo(); bool InvalidDecl = false; if (D) InvalidDecl = D->isInvalidType(); @@ -18949,22 +18859,22 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) { // because otherwise we'll never get complaints about // copy constructors. - CXXSpecialMember member = CXXInvalid; + CXXSpecialMemberKind member = CXXSpecialMemberKind::Invalid; // We're required to check for any non-trivial constructors. Since the // implicit default constructor is suppressed if there are any // user-declared constructors, we just need to check that there is a // trivial default constructor and a trivial copy constructor. (We don't // worry about move constructors here, since this is a C++98 check.) if (RDecl->hasNonTrivialCopyConstructor()) - member = CXXCopyConstructor; + member = CXXSpecialMemberKind::CopyConstructor; else if (!RDecl->hasTrivialDefaultConstructor()) - member = CXXDefaultConstructor; + member = CXXSpecialMemberKind::DefaultConstructor; else if (RDecl->hasNonTrivialCopyAssignment()) - member = CXXCopyAssignment; + member = CXXSpecialMemberKind::CopyAssignment; else if (RDecl->hasNonTrivialDestructor()) - member = CXXDestructor; + member = CXXSpecialMemberKind::Destructor; - if (member != CXXInvalid) { + if (member != CXXSpecialMemberKind::Invalid) { if (!getLangOpts().CPlusPlus11 && getLangOpts().ObjCAutoRefCount && RDecl->hasObjectMember()) { // Objective-C++ ARC: it is an error to have a non-trivial field of @@ -18981,10 +18891,13 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) { } } - Diag(FD->getLocation(), getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member : - diag::err_illegal_union_or_anon_struct_member) - << FD->getParent()->isUnion() << FD->getDeclName() << member; + Diag( + FD->getLocation(), + getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_nontrivial_union_or_anon_struct_member + : diag::err_illegal_union_or_anon_struct_member) + << FD->getParent()->isUnion() << FD->getDeclName() + << llvm::to_underlying(member); DiagnoseNontrivial(RDecl, member); return !getLangOpts().CPlusPlus11; } @@ -19012,7 +18925,7 @@ TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) { Decl *Sema::ActOnIvar(Scope *S, SourceLocation DeclStart, Declarator &D, Expr *BitWidth, tok::ObjCKeywordKind Visibility) { - IdentifierInfo *II = D.getIdentifier(); + const IdentifierInfo *II = D.getIdentifier(); SourceLocation Loc = DeclStart; if (II) Loc = D.getIdentifierLoc(); @@ -19234,10 +19147,10 @@ static void ComputeSelectedDestructor(Sema &S, CXXRecordDecl *Record) { static bool AreSpecialMemberFunctionsSameKind(ASTContext &Context, CXXMethodDecl *M1, CXXMethodDecl *M2, - Sema::CXXSpecialMember CSM) { + CXXSpecialMemberKind CSM) { // We don't want to compare templates to non-templates: See // https://github.com/llvm/llvm-project/issues/59206 - if (CSM == Sema::CXXDefaultConstructor) + if (CSM == CXXSpecialMemberKind::DefaultConstructor) return bool(M1->getDescribedFunctionTemplate()) == bool(M2->getDescribedFunctionTemplate()); // FIXME: better resolve CWG @@ -19260,7 +19173,7 @@ static bool AreSpecialMemberFunctionsSameKind(ASTContext &Context, /// [CWG2595], if any, are satisfied is more constrained. static void SetEligibleMethods(Sema &S, CXXRecordDecl *Record, ArrayRef Methods, - Sema::CXXSpecialMember CSM) { + CXXSpecialMemberKind CSM) { SmallVector SatisfactionStatus; for (CXXMethodDecl *Method : Methods) { @@ -19318,7 +19231,8 @@ static void SetEligibleMethods(Sema &S, CXXRecordDecl *Record, // DR1734 and DR1496. if (!AnotherMethodIsMoreConstrained) { Method->setIneligibleOrNotSelected(false); - Record->addedEligibleSpecialMemberFunction(Method, 1 << CSM); + Record->addedEligibleSpecialMemberFunction(Method, + 1 << llvm::to_underlying(CSM)); } } } @@ -19357,13 +19271,15 @@ static void ComputeSpecialMemberFunctionsEligiblity(Sema &S, } SetEligibleMethods(S, Record, DefaultConstructors, - Sema::CXXDefaultConstructor); - SetEligibleMethods(S, Record, CopyConstructors, Sema::CXXCopyConstructor); - SetEligibleMethods(S, Record, MoveConstructors, Sema::CXXMoveConstructor); + CXXSpecialMemberKind::DefaultConstructor); + SetEligibleMethods(S, Record, CopyConstructors, + CXXSpecialMemberKind::CopyConstructor); + SetEligibleMethods(S, Record, MoveConstructors, + CXXSpecialMemberKind::MoveConstructor); SetEligibleMethods(S, Record, CopyAssignmentOperators, - Sema::CXXCopyAssignment); + CXXSpecialMemberKind::CopyAssignment); SetEligibleMethods(S, Record, MoveAssignmentOperators, - Sema::CXXMoveAssignment); + CXXSpecialMemberKind::MoveAssignment); } void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, @@ -19732,7 +19648,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, if (CXXRecord) { auto *Dtor = CXXRecord->getDestructor(); if (Dtor && Dtor->isImplicit() && - ShouldDeleteSpecialMember(Dtor, CXXDestructor)) { + ShouldDeleteSpecialMember(Dtor, CXXSpecialMemberKind::Destructor)) { CXXRecord->setImplicitDestructorIsDeleted(); SetDeclDeleted(Dtor, CXXRecord->getLocation()); } @@ -20761,11 +20677,11 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(const FunctionDecl *FD, // when compiling for host, device and global functions are never emitted. // (Technically, we do emit a host-side stub for global functions, but this // doesn't count for our purposes here.) - Sema::CUDAFunctionTarget T = IdentifyCUDATarget(FD); - if (LangOpts.CUDAIsDevice && T == Sema::CFT_Host) + CUDAFunctionTarget T = CUDA().IdentifyTarget(FD); + if (LangOpts.CUDAIsDevice && T == CUDAFunctionTarget::Host) return FunctionEmissionStatus::CUDADiscarded; if (!LangOpts.CUDAIsDevice && - (T == Sema::CFT_Device || T == Sema::CFT_Global)) + (T == CUDAFunctionTarget::Device || T == CUDAFunctionTarget::Global)) return FunctionEmissionStatus::CUDADiscarded; if (IsEmittedForExternalSymbol()) @@ -20786,5 +20702,5 @@ bool Sema::shouldIgnoreInHostDeviceCheck(FunctionDecl *Callee) { // for host, only HD functions actually called from the host get marked as // known-emitted. return LangOpts.CUDA && !LangOpts.CUDAIsDevice && - IdentifyCUDATarget(Callee) == CFT_Global; + CUDA().IdentifyTarget(Callee) == CUDAFunctionTarget::Global; } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 8bce04640e748e8a419f6f76cfa38844568ea2c6..b7b1fbc625a150c62d4fa091085472b10b8e23e1 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -39,8 +39,11 @@ #include "clang/Sema/ParsedAttr.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaCUDA.h" +#include "clang/Sema/SemaHLSL.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/Assumptions.h" #include "llvm/MC/MCSectionMachO.h" @@ -5097,8 +5100,8 @@ static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } if (S.getLangOpts().CUDA && VD->hasLocalStorage() && - S.CUDADiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared) - << S.CurrentCUDATarget()) + S.CUDA().DiagIfHostCode(AL.getLoc(), diag::err_cuda_host_shared) + << llvm::to_underlying(S.CUDA().CurrentTarget())) return; D->addAttr(::new (S.Context) CUDASharedAttr(S.Context, AL)); } @@ -5187,8 +5190,9 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Diagnostic is emitted elsewhere: here we store the (valid) AL // in the Decl node for syntactic reasoning, e.g., pretty-printing. CallingConv CC; - if (S.CheckCallingConvAttr(AL, CC, /*FD*/ nullptr, - S.IdentifyCUDATarget(dyn_cast(D)))) + if (S.CheckCallingConvAttr( + AL, CC, /*FD*/ nullptr, + S.CUDA().IdentifyTarget(dyn_cast(D)))) return; if (!isa(D)) { @@ -5492,22 +5496,22 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, // on their host/device attributes. if (LangOpts.CUDA) { auto *Aux = Context.getAuxTargetInfo(); - assert(FD || CFT != CFT_InvalidTarget); - auto CudaTarget = FD ? IdentifyCUDATarget(FD) : CFT; + assert(FD || CFT != CUDAFunctionTarget::InvalidTarget); + auto CudaTarget = FD ? CUDA().IdentifyTarget(FD) : CFT; bool CheckHost = false, CheckDevice = false; switch (CudaTarget) { - case CFT_HostDevice: + case CUDAFunctionTarget::HostDevice: CheckHost = true; CheckDevice = true; break; - case CFT_Host: + case CUDAFunctionTarget::Host: CheckHost = true; break; - case CFT_Device: - case CFT_Global: + case CUDAFunctionTarget::Device: + case CUDAFunctionTarget::Global: CheckDevice = true; break; - case CFT_InvalidTarget: + case CUDAFunctionTarget::InvalidTarget: llvm_unreachable("unexpected cuda target"); } auto *HostTI = LangOpts.CUDAIsDevice ? Aux : &TI; @@ -7238,24 +7242,11 @@ static void handleHLSLNumThreadsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - HLSLNumThreadsAttr *NewAttr = S.mergeHLSLNumThreadsAttr(D, AL, X, Y, Z); + HLSLNumThreadsAttr *NewAttr = S.HLSL().mergeNumThreadsAttr(D, AL, X, Y, Z); if (NewAttr) D->addAttr(NewAttr); } -HLSLNumThreadsAttr *Sema::mergeHLSLNumThreadsAttr(Decl *D, - const AttributeCommonInfo &AL, - int X, int Y, int Z) { - if (HLSLNumThreadsAttr *NT = D->getAttr()) { - if (NT->getX() != X || NT->getY() != Y || NT->getZ() != Z) { - Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL; - Diag(AL.getLoc(), diag::note_conflicting_attribute); - } - return nullptr; - } - return ::new (Context) HLSLNumThreadsAttr(Context, AL, X, Y, Z); -} - static bool isLegalTypeForHLSLSV_DispatchThreadID(QualType T) { if (!T->hasUnsignedIntegerRepresentation()) return false; @@ -7299,24 +7290,11 @@ static void handleHLSLShaderAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // FIXME: check function match the shader stage. - HLSLShaderAttr *NewAttr = S.mergeHLSLShaderAttr(D, AL, ShaderType); + HLSLShaderAttr *NewAttr = S.HLSL().mergeShaderAttr(D, AL, ShaderType); if (NewAttr) D->addAttr(NewAttr); } -HLSLShaderAttr * -Sema::mergeHLSLShaderAttr(Decl *D, const AttributeCommonInfo &AL, - HLSLShaderAttr::ShaderType ShaderType) { - if (HLSLShaderAttr *NT = D->getAttr()) { - if (NT->getType() != ShaderType) { - Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL; - Diag(AL.getLoc(), diag::note_conflicting_attribute); - } - return nullptr; - } - return HLSLShaderAttr::Create(Context, ShaderType, AL); -} - static void handleHLSLResourceBindingAttr(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Space = "space0"; @@ -7391,34 +7369,13 @@ static void handleHLSLResourceBindingAttr(Sema &S, Decl *D, static void handleHLSLParamModifierAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - HLSLParamModifierAttr *NewAttr = S.mergeHLSLParamModifierAttr( + HLSLParamModifierAttr *NewAttr = S.HLSL().mergeParamModifierAttr( D, AL, static_cast(AL.getSemanticSpelling())); if (NewAttr) D->addAttr(NewAttr); } -HLSLParamModifierAttr * -Sema::mergeHLSLParamModifierAttr(Decl *D, const AttributeCommonInfo &AL, - HLSLParamModifierAttr::Spelling Spelling) { - // We can only merge an `in` attribute with an `out` attribute. All other - // combinations of duplicated attributes are ill-formed. - if (HLSLParamModifierAttr *PA = D->getAttr()) { - if ((PA->isIn() && Spelling == HLSLParamModifierAttr::Keyword_out) || - (PA->isOut() && Spelling == HLSLParamModifierAttr::Keyword_in)) { - D->dropAttr(); - SourceRange AdjustedRange = {PA->getLocation(), AL.getRange().getEnd()}; - return HLSLParamModifierAttr::Create( - Context, /*MergedSpelling=*/true, AdjustedRange, - HLSLParamModifierAttr::Keyword_inout); - } - Diag(AL.getLoc(), diag::err_hlsl_duplicate_parameter_modifier) << AL; - Diag(PA->getLocation(), diag::note_conflicting_attribute); - return nullptr; - } - return HLSLParamModifierAttr::Create(Context, AL); -} - static void handleMSInheritanceAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.LangOpts.CPlusPlus) { S.Diag(AL.getLoc(), diag::err_attribute_not_supported_in_lang) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 068a2e4f04fa50a5ac888a6f1a91f89b65e1fac5..7669171fea56ff4bcd4673168e8ec65c2f230f80 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -42,10 +42,12 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" @@ -657,13 +659,13 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, // is ill-formed. This can only happen for constructors. if (isa(New) && New->getMinRequiredArguments() < Old->getMinRequiredArguments()) { - CXXSpecialMember NewSM = getSpecialMember(cast(New)), - OldSM = getSpecialMember(cast(Old)); + CXXSpecialMemberKind NewSM = getSpecialMember(cast(New)), + OldSM = getSpecialMember(cast(Old)); if (NewSM != OldSM) { ParmVarDecl *NewParam = New->getParamDecl(New->getMinRequiredArguments()); assert(NewParam->hasDefaultArg()); Diag(NewParam->getLocation(), diag::err_default_arg_makes_ctor_special) - << NewParam->getDefaultArgRange() << NewSM; + << NewParam->getDefaultArgRange() << llvm::to_underlying(NewSM); Diag(Old->getLocation(), diag::note_previous_declaration); } } @@ -6779,7 +6781,7 @@ void Sema::propagateDLLAttrToBaseClassTemplate( /// /// If the function is both a default constructor and a copy / move constructor /// (due to having a default argument for the first parameter), this picks -/// CXXDefaultConstructor. +/// CXXSpecialMemberKind::DefaultConstructor. /// /// FIXME: Check that case is properly handled by all callers. Sema::DefaultedFunctionKind @@ -6787,23 +6789,23 @@ Sema::getDefaultedFunctionKind(const FunctionDecl *FD) { if (auto *MD = dyn_cast(FD)) { if (const CXXConstructorDecl *Ctor = dyn_cast(FD)) { if (Ctor->isDefaultConstructor()) - return Sema::CXXDefaultConstructor; + return CXXSpecialMemberKind::DefaultConstructor; if (Ctor->isCopyConstructor()) - return Sema::CXXCopyConstructor; + return CXXSpecialMemberKind::CopyConstructor; if (Ctor->isMoveConstructor()) - return Sema::CXXMoveConstructor; + return CXXSpecialMemberKind::MoveConstructor; } if (MD->isCopyAssignmentOperator()) - return Sema::CXXCopyAssignment; + return CXXSpecialMemberKind::CopyAssignment; if (MD->isMoveAssignmentOperator()) - return Sema::CXXMoveAssignment; + return CXXSpecialMemberKind::MoveAssignment; if (isa(FD)) - return Sema::CXXDestructor; + return CXXSpecialMemberKind::Destructor; } switch (FD->getDeclName().getCXXOverloadedOperator()) { @@ -6843,26 +6845,26 @@ static void DefineDefaultedFunction(Sema &S, FunctionDecl *FD, return S.DefineDefaultedComparison(DefaultLoc, FD, DFK.asComparison()); switch (DFK.asSpecialMember()) { - case Sema::CXXDefaultConstructor: + case CXXSpecialMemberKind::DefaultConstructor: S.DefineImplicitDefaultConstructor(DefaultLoc, cast(FD)); break; - case Sema::CXXCopyConstructor: + case CXXSpecialMemberKind::CopyConstructor: S.DefineImplicitCopyConstructor(DefaultLoc, cast(FD)); break; - case Sema::CXXCopyAssignment: + case CXXSpecialMemberKind::CopyAssignment: S.DefineImplicitCopyAssignment(DefaultLoc, cast(FD)); break; - case Sema::CXXDestructor: + case CXXSpecialMemberKind::Destructor: S.DefineImplicitDestructor(DefaultLoc, cast(FD)); break; - case Sema::CXXMoveConstructor: + case CXXSpecialMemberKind::MoveConstructor: S.DefineImplicitMoveConstructor(DefaultLoc, cast(FD)); break; - case Sema::CXXMoveAssignment: + case CXXSpecialMemberKind::MoveAssignment: S.DefineImplicitMoveAssignment(DefaultLoc, cast(FD)); break; - case Sema::CXXInvalid: + case CXXSpecialMemberKind::Invalid: llvm_unreachable("Invalid special member."); } } @@ -7182,9 +7184,9 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { // For an explicitly defaulted or deleted special member, we defer // determining triviality until the class is complete. That time is now! - CXXSpecialMember CSM = getSpecialMember(M); + CXXSpecialMemberKind CSM = getSpecialMember(M); if (!M->isImplicit() && !M->isUserProvided()) { - if (CSM != CXXInvalid) { + if (CSM != CXXSpecialMemberKind::Invalid) { M->setTrivial(SpecialMemberIsTrivial(M, CSM)); // Inform the class that we've finished declaring this member. Record->finishedDefaultedOrDeletedMember(M); @@ -7197,8 +7199,10 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { // Set triviality for the purpose of calls if this is a user-provided // copy/move constructor or destructor. - if ((CSM == CXXCopyConstructor || CSM == CXXMoveConstructor || - CSM == CXXDestructor) && M->isUserProvided()) { + if ((CSM == CXXSpecialMemberKind::CopyConstructor || + CSM == CXXSpecialMemberKind::MoveConstructor || + CSM == CXXSpecialMemberKind::Destructor) && + M->isUserProvided()) { M->setTrivialForCall(HasTrivialABI); Record->setTrivialForCallFlags(M); } @@ -7207,8 +7211,9 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { M->hasAttr()) { if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) && M->isTrivial() && - (CSM == CXXDefaultConstructor || CSM == CXXCopyConstructor || - CSM == CXXDestructor)) + (CSM == CXXSpecialMemberKind::DefaultConstructor || + CSM == CXXSpecialMemberKind::CopyConstructor || + CSM == CXXSpecialMemberKind::Destructor)) M->dropAttr(); if (M->hasAttr()) { @@ -7220,8 +7225,8 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { // Define defaulted constexpr virtual functions that override a base class // function right away. // FIXME: We can defer doing this until the vtable is marked as used. - if (CSM != CXXInvalid && !M->isDeleted() && M->isDefaulted() && - M->isConstexpr() && M->size_overridden_methods()) + if (CSM != CXXSpecialMemberKind::Invalid && !M->isDeleted() && + M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods()) DefineDefaultedFunction(*this, M, M->getLocation()); if (!Incomplete) @@ -7343,15 +7348,18 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { /// \param ConstRHS True if this is a copy operation with a const object /// on its RHS, that is, if the argument to the outer special member /// function is 'const' and this is not a field marked 'mutable'. -static Sema::SpecialMemberOverloadResult lookupCallFromSpecialMember( - Sema &S, CXXRecordDecl *Class, Sema::CXXSpecialMember CSM, - unsigned FieldQuals, bool ConstRHS) { +static Sema::SpecialMemberOverloadResult +lookupCallFromSpecialMember(Sema &S, CXXRecordDecl *Class, + CXXSpecialMemberKind CSM, unsigned FieldQuals, + bool ConstRHS) { unsigned LHSQuals = 0; - if (CSM == Sema::CXXCopyAssignment || CSM == Sema::CXXMoveAssignment) + if (CSM == CXXSpecialMemberKind::CopyAssignment || + CSM == CXXSpecialMemberKind::MoveAssignment) LHSQuals = FieldQuals; unsigned RHSQuals = FieldQuals; - if (CSM == Sema::CXXDefaultConstructor || CSM == Sema::CXXDestructor) + if (CSM == CXXSpecialMemberKind::DefaultConstructor || + CSM == CXXSpecialMemberKind::Destructor) RHSQuals = 0; else if (ConstRHS) RHSQuals |= Qualifiers::Const; @@ -7447,12 +7455,10 @@ public: /// Is the special member function which would be selected to perform the /// specified operation on the specified class type a constexpr constructor? -static bool -specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, - Sema::CXXSpecialMember CSM, unsigned Quals, - bool ConstRHS, - CXXConstructorDecl *InheritedCtor = nullptr, - Sema::InheritedConstructorInfo *Inherited = nullptr) { +static bool specialMemberIsConstexpr( + Sema &S, CXXRecordDecl *ClassDecl, CXXSpecialMemberKind CSM, unsigned Quals, + bool ConstRHS, CXXConstructorDecl *InheritedCtor = nullptr, + Sema::InheritedConstructorInfo *Inherited = nullptr) { // Suppress duplicate constraint checking here, in case a constraint check // caused us to decide to do this. Any truely recursive checks will get // caught during these checks anyway. @@ -7461,16 +7467,16 @@ specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, // If we're inheriting a constructor, see if we need to call it for this base // class. if (InheritedCtor) { - assert(CSM == Sema::CXXDefaultConstructor); + assert(CSM == CXXSpecialMemberKind::DefaultConstructor); auto BaseCtor = Inherited->findConstructorForBase(ClassDecl, InheritedCtor).first; if (BaseCtor) return BaseCtor->isConstexpr(); } - if (CSM == Sema::CXXDefaultConstructor) + if (CSM == CXXSpecialMemberKind::DefaultConstructor) return ClassDecl->hasConstexprDefaultConstructor(); - if (CSM == Sema::CXXDestructor) + if (CSM == CXXSpecialMemberKind::Destructor) return ClassDecl->hasConstexprDestructor(); Sema::SpecialMemberOverloadResult SMOR = @@ -7485,8 +7491,8 @@ specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, /// Determine whether the specified special member function would be constexpr /// if it were implicitly defined. static bool defaultedSpecialMemberIsConstexpr( - Sema &S, CXXRecordDecl *ClassDecl, Sema::CXXSpecialMember CSM, - bool ConstArg, CXXConstructorDecl *InheritedCtor = nullptr, + Sema &S, CXXRecordDecl *ClassDecl, CXXSpecialMemberKind CSM, bool ConstArg, + CXXConstructorDecl *InheritedCtor = nullptr, Sema::InheritedConstructorInfo *Inherited = nullptr) { if (!S.getLangOpts().CPlusPlus11) return false; @@ -7495,7 +7501,7 @@ static bool defaultedSpecialMemberIsConstexpr( // In the definition of a constexpr constructor [...] bool Ctor = true; switch (CSM) { - case Sema::CXXDefaultConstructor: + case CXXSpecialMemberKind::DefaultConstructor: if (Inherited) break; // Since default constructor lookup is essentially trivial (and cannot @@ -7506,23 +7512,23 @@ static bool defaultedSpecialMemberIsConstexpr( // constructor is constexpr to determine whether the type is a literal type. return ClassDecl->defaultedDefaultConstructorIsConstexpr(); - case Sema::CXXCopyConstructor: - case Sema::CXXMoveConstructor: + case CXXSpecialMemberKind::CopyConstructor: + case CXXSpecialMemberKind::MoveConstructor: // For copy or move constructors, we need to perform overload resolution. break; - case Sema::CXXCopyAssignment: - case Sema::CXXMoveAssignment: + case CXXSpecialMemberKind::CopyAssignment: + case CXXSpecialMemberKind::MoveAssignment: if (!S.getLangOpts().CPlusPlus14) return false; // In C++1y, we need to perform overload resolution. Ctor = false; break; - case Sema::CXXDestructor: + case CXXSpecialMemberKind::Destructor: return ClassDecl->defaultedDestructorIsConstexpr(); - case Sema::CXXInvalid: + case CXXSpecialMemberKind::Invalid: return false; } @@ -7534,7 +7540,7 @@ static bool defaultedSpecialMemberIsConstexpr( // will be initialized (if the constructor isn't deleted), we just don't know // which one. if (Ctor && ClassDecl->isUnion()) - return CSM == Sema::CXXDefaultConstructor + return CSM == CXXSpecialMemberKind::DefaultConstructor ? ClassDecl->hasInClassInitializer() || !ClassDecl->hasVariantMembers() : true; @@ -7575,7 +7581,8 @@ static bool defaultedSpecialMemberIsConstexpr( for (const auto *F : ClassDecl->fields()) { if (F->isInvalidDecl()) continue; - if (CSM == Sema::CXXDefaultConstructor && F->hasInClassInitializer()) + if (CSM == CXXSpecialMemberKind::DefaultConstructor && + F->hasInClassInitializer()) continue; QualType BaseType = S.Context.getBaseElementType(F->getType()); if (const RecordType *RecordTy = BaseType->getAs()) { @@ -7584,7 +7591,7 @@ static bool defaultedSpecialMemberIsConstexpr( BaseType.getCVRQualifiers(), ConstArg && !F->isMutable())) return false; - } else if (CSM == Sema::CXXDefaultConstructor) { + } else if (CSM == CXXSpecialMemberKind::DefaultConstructor) { return false; } } @@ -7615,9 +7622,10 @@ struct ComputingExceptionSpec { } static Sema::ImplicitExceptionSpecification -ComputeDefaultedSpecialMemberExceptionSpec( - Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM, - Sema::InheritedConstructorInfo *ICI); +ComputeDefaultedSpecialMemberExceptionSpec(Sema &S, SourceLocation Loc, + CXXMethodDecl *MD, + CXXSpecialMemberKind CSM, + Sema::InheritedConstructorInfo *ICI); static Sema::ImplicitExceptionSpecification ComputeDefaultedComparisonExceptionSpec(Sema &S, SourceLocation Loc, @@ -7641,7 +7649,7 @@ computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, FunctionDecl *FD) { Sema::InheritedConstructorInfo ICI( S, Loc, CD->getInheritedConstructor().getShadowDecl()); return ComputeDefaultedSpecialMemberExceptionSpec( - S, Loc, CD, Sema::CXXDefaultConstructor, &ICI); + S, Loc, CD, CXXSpecialMemberKind::DefaultConstructor, &ICI); } static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S, @@ -7693,11 +7701,11 @@ void Sema::CheckExplicitlyDefaultedFunction(Scope *S, FunctionDecl *FD) { } bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, - CXXSpecialMember CSM, + CXXSpecialMemberKind CSM, SourceLocation DefaultLoc) { CXXRecordDecl *RD = MD->getParent(); - assert(MD->isExplicitlyDefaulted() && CSM != CXXInvalid && + assert(MD->isExplicitlyDefaulted() && CSM != CXXSpecialMemberKind::Invalid && "not an explicitly-defaulted special member"); // Defer all checking for special members of a dependent type. @@ -7723,21 +7731,22 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, bool DeleteOnTypeMismatch = getLangOpts().CPlusPlus20 && First; bool ShouldDeleteForTypeMismatch = false; unsigned ExpectedParams = 1; - if (CSM == CXXDefaultConstructor || CSM == CXXDestructor) + if (CSM == CXXSpecialMemberKind::DefaultConstructor || + CSM == CXXSpecialMemberKind::Destructor) ExpectedParams = 0; if (MD->getNumExplicitParams() != ExpectedParams) { // This checks for default arguments: a copy or move constructor with a // default argument is classified as a default constructor, and assignment // operations and destructors can't have default arguments. Diag(MD->getLocation(), diag::err_defaulted_special_member_params) - << CSM << MD->getSourceRange(); + << llvm::to_underlying(CSM) << MD->getSourceRange(); HadError = true; } else if (MD->isVariadic()) { if (DeleteOnTypeMismatch) ShouldDeleteForTypeMismatch = true; else { Diag(MD->getLocation(), diag::err_defaulted_special_member_variadic) - << CSM << MD->getSourceRange(); + << llvm::to_underlying(CSM) << MD->getSourceRange(); HadError = true; } } @@ -7745,13 +7754,14 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, const FunctionProtoType *Type = MD->getType()->castAs(); bool CanHaveConstParam = false; - if (CSM == CXXCopyConstructor) + if (CSM == CXXSpecialMemberKind::CopyConstructor) CanHaveConstParam = RD->implicitCopyConstructorHasConstParam(); - else if (CSM == CXXCopyAssignment) + else if (CSM == CXXSpecialMemberKind::CopyAssignment) CanHaveConstParam = RD->implicitCopyAssignmentHasConstParam(); QualType ReturnType = Context.VoidTy; - if (CSM == CXXCopyAssignment || CSM == CXXMoveAssignment) { + if (CSM == CXXSpecialMemberKind::CopyAssignment || + CSM == CXXSpecialMemberKind::MoveAssignment) { // Check for return type matching. ReturnType = Type->getReturnType(); QualType ThisType = MD->getFunctionObjectParameterType(); @@ -7765,7 +7775,8 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, if (!Context.hasSameType(ReturnType, ExpectedReturnType)) { Diag(MD->getLocation(), diag::err_defaulted_special_member_return_type) - << (CSM == CXXMoveAssignment) << ExpectedReturnType; + << (CSM == CXXSpecialMemberKind::MoveAssignment) + << ExpectedReturnType; HadError = true; } @@ -7775,7 +7786,8 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, ShouldDeleteForTypeMismatch = true; else { Diag(MD->getLocation(), diag::err_defaulted_special_member_quals) - << (CSM == CXXMoveAssignment) << getLangOpts().CPlusPlus14; + << (CSM == CXXSpecialMemberKind::MoveAssignment) + << getLangOpts().CPlusPlus14; HadError = true; } } @@ -7793,7 +7805,8 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, else { Diag(MD->getLocation(), diag::err_defaulted_special_member_explicit_object_mismatch) - << (CSM == CXXMoveAssignment) << RD << MD->getSourceRange(); + << (CSM == CXXSpecialMemberKind::MoveAssignment) << RD + << MD->getSourceRange(); HadError = true; } } @@ -7815,7 +7828,8 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, ShouldDeleteForTypeMismatch = true; else { Diag(MD->getLocation(), - diag::err_defaulted_special_member_volatile_param) << CSM; + diag::err_defaulted_special_member_volatile_param) + << llvm::to_underlying(CSM); HadError = true; } } @@ -7823,23 +7837,25 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, if (HasConstParam && !CanHaveConstParam) { if (DeleteOnTypeMismatch) ShouldDeleteForTypeMismatch = true; - else if (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment) { + else if (CSM == CXXSpecialMemberKind::CopyConstructor || + CSM == CXXSpecialMemberKind::CopyAssignment) { Diag(MD->getLocation(), diag::err_defaulted_special_member_copy_const_param) - << (CSM == CXXCopyAssignment); + << (CSM == CXXSpecialMemberKind::CopyAssignment); // FIXME: Explain why this special member can't be const. HadError = true; } else { Diag(MD->getLocation(), diag::err_defaulted_special_member_move_const_param) - << (CSM == CXXMoveAssignment); + << (CSM == CXXSpecialMemberKind::MoveAssignment); HadError = true; } } } else if (ExpectedParams) { // A copy assignment operator can take its argument by value, but a // defaulted one cannot. - assert(CSM == CXXCopyAssignment && "unexpected non-ref argument"); + assert(CSM == CXXSpecialMemberKind::CopyAssignment && + "unexpected non-ref argument"); Diag(MD->getLocation(), diag::err_defaulted_copy_assign_not_ref); HadError = true; } @@ -7874,12 +7890,12 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, if (!MD->isConsteval() && RD->getNumVBases()) { Diag(MD->getBeginLoc(), diag::err_incorrect_defaulted_constexpr_with_vb) - << CSM; + << llvm::to_underlying(CSM); for (const auto &I : RD->vbases()) Diag(I.getBeginLoc(), diag::note_constexpr_virtual_base_here); } else { Diag(MD->getBeginLoc(), diag::err_incorrect_defaulted_constexpr) - << CSM << MD->isConsteval(); + << llvm::to_underlying(CSM) << MD->isConsteval(); } HadError = true; // FIXME: Explain why the special member can't be constexpr. @@ -7912,9 +7928,11 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, if (First) { SetDeclDeleted(MD, MD->getLocation()); if (!inTemplateInstantiation() && !HadError) { - Diag(MD->getLocation(), diag::warn_defaulted_method_deleted) << CSM; + Diag(MD->getLocation(), diag::warn_defaulted_method_deleted) + << llvm::to_underlying(CSM); if (ShouldDeleteForTypeMismatch) { - Diag(MD->getLocation(), diag::note_deleted_type_mismatch) << CSM; + Diag(MD->getLocation(), diag::note_deleted_type_mismatch) + << llvm::to_underlying(CSM); } else if (ShouldDeleteSpecialMember(MD, CSM, nullptr, /*Diagnose*/ true) && DefaultLoc.isValid()) { @@ -7924,13 +7942,15 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, } if (ShouldDeleteForTypeMismatch && !HadError) { Diag(MD->getLocation(), - diag::warn_cxx17_compat_defaulted_method_type_mismatch) << CSM; + diag::warn_cxx17_compat_defaulted_method_type_mismatch) + << llvm::to_underlying(CSM); } } else { // C++11 [dcl.fct.def.default]p4: // [For a] user-provided explicitly-defaulted function [...] if such a // function is implicitly defined as deleted, the program is ill-formed. - Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) << CSM; + Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) + << llvm::to_underlying(CSM); assert(!ShouldDeleteForTypeMismatch && "deleted non-first decl"); ShouldDeleteSpecialMember(MD, CSM, nullptr, /*Diagnose*/true); HadError = true; @@ -7962,7 +7982,7 @@ public: DefaultedComparisonVisitor(Sema &S, CXXRecordDecl *RD, FunctionDecl *FD, DefaultedComparisonKind DCK) : S(S), RD(RD), FD(FD), DCK(DCK) { - if (auto *Info = FD->getDefaultedFunctionInfo()) { + if (auto *Info = FD->getDefalutedOrDeletedInfo()) { // FIXME: Change CreateOverloadedBinOp to take an ArrayRef instead of an // UnresolvedSet to avoid this copy. Fns.assign(Info->getUnqualifiedLookups().begin(), @@ -8830,8 +8850,9 @@ bool Sema::CheckExplicitlyDefaultedComparison(Scope *S, FunctionDecl *FD, UnresolvedSet<32> Operators; lookupOperatorsForDefaultedComparison(*this, S, Operators, FD->getOverloadedOperator()); - FD->setDefaultedFunctionInfo(FunctionDecl::DefaultedFunctionInfo::Create( - Context, Operators.pairs())); + FD->setDefaultedOrDeletedInfo( + FunctionDecl::DefaultedOrDeletedFunctionInfo::Create( + Context, Operators.pairs())); } // C++2a [class.compare.default]p1: @@ -9271,28 +9292,28 @@ template struct SpecialMemberVisitor { Sema &S; CXXMethodDecl *MD; - Sema::CXXSpecialMember CSM; + CXXSpecialMemberKind CSM; Sema::InheritedConstructorInfo *ICI; // Properties of the special member, computed for convenience. bool IsConstructor = false, IsAssignment = false, ConstArg = false; - SpecialMemberVisitor(Sema &S, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM, + SpecialMemberVisitor(Sema &S, CXXMethodDecl *MD, CXXSpecialMemberKind CSM, Sema::InheritedConstructorInfo *ICI) : S(S), MD(MD), CSM(CSM), ICI(ICI) { switch (CSM) { - case Sema::CXXDefaultConstructor: - case Sema::CXXCopyConstructor: - case Sema::CXXMoveConstructor: + case CXXSpecialMemberKind::DefaultConstructor: + case CXXSpecialMemberKind::CopyConstructor: + case CXXSpecialMemberKind::MoveConstructor: IsConstructor = true; break; - case Sema::CXXCopyAssignment: - case Sema::CXXMoveAssignment: + case CXXSpecialMemberKind::CopyAssignment: + case CXXSpecialMemberKind::MoveAssignment: IsAssignment = true; break; - case Sema::CXXDestructor: + case CXXSpecialMemberKind::Destructor: break; - case Sema::CXXInvalid: + case CXXSpecialMemberKind::Invalid: llvm_unreachable("invalid special member kind"); } @@ -9307,7 +9328,8 @@ struct SpecialMemberVisitor { /// Is this a "move" special member? bool isMove() const { - return CSM == Sema::CXXMoveConstructor || CSM == Sema::CXXMoveAssignment; + return CSM == CXXSpecialMemberKind::MoveConstructor || + CSM == CXXSpecialMemberKind::MoveAssignment; } /// Look up the corresponding special member in the given class. @@ -9322,7 +9344,7 @@ struct SpecialMemberVisitor { Sema::SpecialMemberOverloadResult lookupInheritedCtor(CXXRecordDecl *Class) { if (!ICI) return {}; - assert(CSM == Sema::CXXDefaultConstructor); + assert(CSM == CXXSpecialMemberKind::DefaultConstructor); auto *BaseCtor = cast(MD)->getInheritedConstructor().getConstructor(); if (auto *MD = ICI->findConstructorForBase(Class, BaseCtor).first) @@ -9392,15 +9414,15 @@ struct SpecialMemberDeletionInfo bool AllFieldsAreConst; SpecialMemberDeletionInfo(Sema &S, CXXMethodDecl *MD, - Sema::CXXSpecialMember CSM, + CXXSpecialMemberKind CSM, Sema::InheritedConstructorInfo *ICI, bool Diagnose) : SpecialMemberVisitor(S, MD, CSM, ICI), Diagnose(Diagnose), Loc(MD->getLocation()), AllFieldsAreConst(true) {} bool inUnion() const { return MD->getParent()->isUnion(); } - Sema::CXXSpecialMember getEffectiveCSM() { - return ICI ? Sema::CXXInvalid : CSM; + CXXSpecialMemberKind getEffectiveCSM() { + return ICI ? CXXSpecialMemberKind::Invalid : CSM; } bool shouldDeleteForVariantObjCPtrMember(FieldDecl *FD, QualType FieldType); @@ -9466,7 +9488,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall( // must be accessible and non-deleted, but need not be trivial. Such a // destructor is never actually called, but is semantically checked as // if it were. - if (CSM == Sema::CXXDefaultConstructor) { + if (CSM == CXXSpecialMemberKind::DefaultConstructor) { // [class.default.ctor]p2: // A defaulted default constructor for class X is defined as deleted if // - X is a union that has a variant member with a non-trivial default @@ -9487,15 +9509,16 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall( if (Field) { S.Diag(Field->getLocation(), diag::note_deleted_special_member_class_subobject) - << getEffectiveCSM() << MD->getParent() << /*IsField*/true - << Field << DiagKind << IsDtorCallInCtor << /*IsObjCPtr*/false; + << llvm::to_underlying(getEffectiveCSM()) << MD->getParent() + << /*IsField*/ true << Field << DiagKind << IsDtorCallInCtor + << /*IsObjCPtr*/ false; } else { CXXBaseSpecifier *Base = Subobj.get(); S.Diag(Base->getBeginLoc(), diag::note_deleted_special_member_class_subobject) - << getEffectiveCSM() << MD->getParent() << /*IsField*/ false - << Base->getType() << DiagKind << IsDtorCallInCtor - << /*IsObjCPtr*/false; + << llvm::to_underlying(getEffectiveCSM()) << MD->getParent() + << /*IsField*/ false << Base->getType() << DiagKind + << IsDtorCallInCtor << /*IsObjCPtr*/ false; } if (DiagKind == 1) @@ -9527,8 +9550,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject( // C++11 [class.dtor]p5: // -- any direct or virtual base class [...] has a type with a destructor // that is deleted or inaccessible - if (!(CSM == Sema::CXXDefaultConstructor && - Field && Field->hasInClassInitializer()) && + if (!(CSM == CXXSpecialMemberKind::DefaultConstructor && Field && + Field->hasInClassInitializer()) && shouldDeleteForSubobjectCall(Subobj, lookupIn(Class, Quals, IsMutable), false)) return true; @@ -9538,8 +9561,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForClassSubobject( // type with a destructor that is deleted or inaccessible if (IsConstructor) { Sema::SpecialMemberOverloadResult SMOR = - S.LookupSpecialMember(Class, Sema::CXXDestructor, - false, false, false, false, false); + S.LookupSpecialMember(Class, CXXSpecialMemberKind::Destructor, false, + false, false, false, false); if (shouldDeleteForSubobjectCall(Subobj, SMOR, true)) return true; } @@ -9557,15 +9580,16 @@ bool SpecialMemberDeletionInfo::shouldDeleteForVariantObjCPtrMember( // Don't make the defaulted default constructor defined as deleted if the // member has an in-class initializer. - if (CSM == Sema::CXXDefaultConstructor && FD->hasInClassInitializer()) + if (CSM == CXXSpecialMemberKind::DefaultConstructor && + FD->hasInClassInitializer()) return false; if (Diagnose) { auto *ParentClass = cast(FD->getParent()); - S.Diag(FD->getLocation(), - diag::note_deleted_special_member_class_subobject) - << getEffectiveCSM() << ParentClass << /*IsField*/true - << FD << 4 << /*IsDtorCallInCtor*/false << /*IsObjCPtr*/true; + S.Diag(FD->getLocation(), diag::note_deleted_special_member_class_subobject) + << llvm::to_underlying(getEffectiveCSM()) << ParentClass + << /*IsField*/ true << FD << 4 << /*IsDtorCallInCtor*/ false + << /*IsObjCPtr*/ true; } return true; @@ -9590,9 +9614,9 @@ bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) { if (BaseCtor->isDeleted() && Diagnose) { S.Diag(Base->getBeginLoc(), diag::note_deleted_special_member_class_subobject) - << getEffectiveCSM() << MD->getParent() << /*IsField*/ false - << Base->getType() << /*Deleted*/ 1 << /*IsDtorCallInCtor*/ false - << /*IsObjCPtr*/false; + << llvm::to_underlying(getEffectiveCSM()) << MD->getParent() + << /*IsField*/ false << Base->getType() << /*Deleted*/ 1 + << /*IsDtorCallInCtor*/ false << /*IsObjCPtr*/ false; S.NoteDeletedFunction(BaseCtor); } return BaseCtor->isDeleted(); @@ -9609,7 +9633,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { if (inUnion() && shouldDeleteForVariantObjCPtrMember(FD, FieldType)) return true; - if (CSM == Sema::CXXDefaultConstructor) { + if (CSM == CXXSpecialMemberKind::DefaultConstructor) { // For a default constructor, all references must be initialized in-class // and, if a union, it must have a non-const member. if (FieldType->isReferenceType() && !FD->hasInClassInitializer()) { @@ -9632,7 +9656,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { if (inUnion() && !FieldType.isConstQualified()) AllFieldsAreConst = false; - } else if (CSM == Sema::CXXCopyConstructor) { + } else if (CSM == CXXSpecialMemberKind::CopyConstructor) { // For a copy constructor, data members must not be of rvalue reference // type. if (FieldType->isRValueReferenceType()) { @@ -9683,8 +9707,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { } // At least one member in each anonymous union must be non-const - if (CSM == Sema::CXXDefaultConstructor && AllVariantFieldsAreConst && - !FieldRecord->field_empty()) { + if (CSM == CXXSpecialMemberKind::DefaultConstructor && + AllVariantFieldsAreConst && !FieldRecord->field_empty()) { if (Diagnose) S.Diag(FieldRecord->getLocation(), diag::note_deleted_default_ctor_all_const) @@ -9712,7 +9736,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() { // This is a silly definition, because it gives an empty union a deleted // default constructor. Don't do that. - if (CSM == Sema::CXXDefaultConstructor && inUnion() && AllFieldsAreConst) { + if (CSM == CXXSpecialMemberKind::DefaultConstructor && inUnion() && + AllFieldsAreConst) { bool AnyFields = false; for (auto *F : MD->getParent()->fields()) if ((AnyFields = !F->isUnnamedBitfield())) @@ -9731,7 +9756,8 @@ bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() { /// Determine whether a defaulted special member function should be defined as /// deleted, as specified in C++11 [class.ctor]p5, C++11 [class.copy]p11, /// C++11 [class.copy]p23, and C++11 [class.dtor]p5. -bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, +bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, + CXXSpecialMemberKind CSM, InheritedConstructorInfo *ICI, bool Diagnose) { if (MD->isInvalidDecl()) @@ -9748,7 +9774,8 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, // assignment operator. // C++2a adds back these operators if the lambda has no lambda-capture. if (RD->isLambda() && !RD->lambdaIsDefaultConstructibleAndAssignable() && - (CSM == CXXDefaultConstructor || CSM == CXXCopyAssignment)) { + (CSM == CXXSpecialMemberKind::DefaultConstructor || + CSM == CXXSpecialMemberKind::CopyAssignment)) { if (Diagnose) Diag(RD->getLocation(), diag::note_lambda_decl); return true; @@ -9757,16 +9784,16 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, // For an anonymous struct or union, the copy and assignment special members // will never be used, so skip the check. For an anonymous union declared at // namespace scope, the constructor and destructor are used. - if (CSM != CXXDefaultConstructor && CSM != CXXDestructor && - RD->isAnonymousStructOrUnion()) + if (CSM != CXXSpecialMemberKind::DefaultConstructor && + CSM != CXXSpecialMemberKind::Destructor && RD->isAnonymousStructOrUnion()) return false; // C++11 [class.copy]p7, p18: // If the class definition declares a move constructor or move assignment // operator, an implicitly declared copy constructor or copy assignment // operator is defined as deleted. - if (MD->isImplicit() && - (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment)) { + if (MD->isImplicit() && (CSM == CXXSpecialMemberKind::CopyConstructor || + CSM == CXXSpecialMemberKind::CopyAssignment)) { CXXMethodDecl *UserDeclaredMove = nullptr; // In Microsoft mode up to MSVC 2013, a user-declared move only causes the @@ -9777,7 +9804,8 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, !getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015); if (RD->hasUserDeclaredMoveConstructor() && - (!DeletesOnlyMatchingCopy || CSM == CXXCopyConstructor)) { + (!DeletesOnlyMatchingCopy || + CSM == CXXSpecialMemberKind::CopyConstructor)) { if (!Diagnose) return true; // Find any user-declared move constructor. @@ -9789,7 +9817,8 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, } assert(UserDeclaredMove); } else if (RD->hasUserDeclaredMoveAssignment() && - (!DeletesOnlyMatchingCopy || CSM == CXXCopyAssignment)) { + (!DeletesOnlyMatchingCopy || + CSM == CXXSpecialMemberKind::CopyAssignment)) { if (!Diagnose) return true; // Find any user-declared move assignment operator. @@ -9805,8 +9834,8 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, if (UserDeclaredMove) { Diag(UserDeclaredMove->getLocation(), diag::note_deleted_copy_user_declared_move) - << (CSM == CXXCopyAssignment) << RD - << UserDeclaredMove->isMoveAssignmentOperator(); + << (CSM == CXXSpecialMemberKind::CopyAssignment) << RD + << UserDeclaredMove->isMoveAssignmentOperator(); return true; } } @@ -9817,7 +9846,7 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, // C++11 [class.dtor]p5: // -- for a virtual destructor, lookup of the non-array deallocation function // results in an ambiguity or in a function that is deleted or inaccessible - if (CSM == CXXDestructor && MD->isVirtual()) { + if (CSM == CXXSpecialMemberKind::Destructor && MD->isVirtual()) { FunctionDecl *OperatorDelete = nullptr; DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Delete); @@ -9849,15 +9878,15 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, // failed. // For inherited constructors (non-null ICI), CSM may be passed so that MD // is treated as certain special member, which may not reflect what special - // member MD really is. However inferCUDATargetForImplicitSpecialMember + // member MD really is. However inferTargetForImplicitSpecialMember // expects CSM to match MD, therefore recalculate CSM. assert(ICI || CSM == getSpecialMember(MD)); auto RealCSM = CSM; if (ICI) RealCSM = getSpecialMember(MD); - return inferCUDATargetForImplicitSpecialMember(RD, RealCSM, MD, - SMI.ConstArg, Diagnose); + return CUDA().inferTargetForImplicitSpecialMember(RD, RealCSM, MD, + SMI.ConstArg, Diagnose); } return false; @@ -9891,7 +9920,7 @@ void Sema::DiagnoseDeletedDefaultedFunction(FunctionDecl *FD) { /// If \p ForCall is true, look at CXXRecord::HasTrivialSpecialMembersForCall to /// determine whether the special member is trivial. static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, - Sema::CXXSpecialMember CSM, unsigned Quals, + CXXSpecialMemberKind CSM, unsigned Quals, bool ConstRHS, Sema::TrivialABIHandling TAH, CXXMethodDecl **Selected) { @@ -9899,10 +9928,10 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, *Selected = nullptr; switch (CSM) { - case Sema::CXXInvalid: + case CXXSpecialMemberKind::Invalid: llvm_unreachable("not a special member"); - case Sema::CXXDefaultConstructor: + case CXXSpecialMemberKind::DefaultConstructor: // C++11 [class.ctor]p5: // A default constructor is trivial if: // - all the [direct subobjects] have trivial default constructors @@ -9931,7 +9960,7 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, return false; - case Sema::CXXDestructor: + case CXXSpecialMemberKind::Destructor: // C++11 [class.dtor]p5: // A destructor is trivial if: // - all the direct [subobjects] have trivial destructors @@ -9948,7 +9977,7 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, return false; - case Sema::CXXCopyConstructor: + case CXXSpecialMemberKind::CopyConstructor: // C++11 [class.copy]p12: // A copy constructor is trivial if: // - the constructor selected to copy each direct [subobject] is trivial @@ -9969,7 +9998,7 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, // struct B { mutable A a; }; goto NeedOverloadResolution; - case Sema::CXXCopyAssignment: + case CXXSpecialMemberKind::CopyAssignment: // C++11 [class.copy]p25: // A copy assignment operator is trivial if: // - the assignment operator selected to copy each direct [subobject] is @@ -9984,8 +10013,8 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, // treat that as a language defect. goto NeedOverloadResolution; - case Sema::CXXMoveConstructor: - case Sema::CXXMoveAssignment: + case CXXSpecialMemberKind::MoveConstructor: + case CXXSpecialMemberKind::MoveAssignment: NeedOverloadResolution: Sema::SpecialMemberOverloadResult SMOR = lookupCallFromSpecialMember(S, RD, CSM, Quals, ConstRHS); @@ -10009,7 +10038,8 @@ static bool findTrivialSpecialMember(Sema &S, CXXRecordDecl *RD, *Selected = SMOR.getMethod(); if (TAH == Sema::TAH_ConsiderTrivialABI && - (CSM == Sema::CXXCopyConstructor || CSM == Sema::CXXMoveConstructor)) + (CSM == CXXSpecialMemberKind::CopyConstructor || + CSM == CXXSpecialMemberKind::MoveConstructor)) return SMOR.getMethod()->isTrivialForCall(); return SMOR.getMethod()->isTrivial(); } @@ -10047,9 +10077,10 @@ enum TrivialSubobjectKind { /// Check whether the special member selected for a given type would be trivial. static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc, QualType SubType, bool ConstRHS, - Sema::CXXSpecialMember CSM, + CXXSpecialMemberKind CSM, TrivialSubobjectKind Kind, - Sema::TrivialABIHandling TAH, bool Diagnose) { + Sema::TrivialABIHandling TAH, + bool Diagnose) { CXXRecordDecl *SubRD = SubType->getAsCXXRecordDecl(); if (!SubRD) return true; @@ -10063,27 +10094,28 @@ static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc, if (ConstRHS) SubType.addConst(); - if (!Selected && CSM == Sema::CXXDefaultConstructor) { + if (!Selected && CSM == CXXSpecialMemberKind::DefaultConstructor) { S.Diag(SubobjLoc, diag::note_nontrivial_no_def_ctor) << Kind << SubType.getUnqualifiedType(); if (CXXConstructorDecl *CD = findUserDeclaredCtor(SubRD)) S.Diag(CD->getLocation(), diag::note_user_declared_ctor); } else if (!Selected) S.Diag(SubobjLoc, diag::note_nontrivial_no_copy) - << Kind << SubType.getUnqualifiedType() << CSM << SubType; + << Kind << SubType.getUnqualifiedType() << llvm::to_underlying(CSM) + << SubType; else if (Selected->isUserProvided()) { if (Kind == TSK_CompleteObject) S.Diag(Selected->getLocation(), diag::note_nontrivial_user_provided) - << Kind << SubType.getUnqualifiedType() << CSM; + << Kind << SubType.getUnqualifiedType() << llvm::to_underlying(CSM); else { S.Diag(SubobjLoc, diag::note_nontrivial_user_provided) - << Kind << SubType.getUnqualifiedType() << CSM; + << Kind << SubType.getUnqualifiedType() << llvm::to_underlying(CSM); S.Diag(Selected->getLocation(), diag::note_declared_at); } } else { if (Kind != TSK_CompleteObject) S.Diag(SubobjLoc, diag::note_nontrivial_subobject) - << Kind << SubType.getUnqualifiedType() << CSM; + << Kind << SubType.getUnqualifiedType() << llvm::to_underlying(CSM); // Explain why the defaulted or deleted special member isn't trivial. S.SpecialMemberIsTrivial(Selected, CSM, Sema::TAH_IgnoreTrivialABI, @@ -10097,8 +10129,7 @@ static bool checkTrivialSubobjectCall(Sema &S, SourceLocation SubobjLoc, /// Check whether the members of a class type allow a special member to be /// trivial. static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD, - Sema::CXXSpecialMember CSM, - bool ConstArg, + CXXSpecialMemberKind CSM, bool ConstArg, Sema::TrivialABIHandling TAH, bool Diagnose) { for (const auto *FI : RD->fields()) { @@ -10119,7 +10150,8 @@ static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD, // A default constructor is trivial if [...] // -- no non-static data member of its class has a // brace-or-equal-initializer - if (CSM == Sema::CXXDefaultConstructor && FI->hasInClassInitializer()) { + if (CSM == CXXSpecialMemberKind::DefaultConstructor && + FI->hasInClassInitializer()) { if (Diagnose) S.Diag(FI->getLocation(), diag::note_nontrivial_default_member_init) << FI; @@ -10148,10 +10180,12 @@ static bool checkTrivialClassMembers(Sema &S, CXXRecordDecl *RD, /// Diagnose why the specified class does not have a trivial special member of /// the given kind. -void Sema::DiagnoseNontrivial(const CXXRecordDecl *RD, CXXSpecialMember CSM) { +void Sema::DiagnoseNontrivial(const CXXRecordDecl *RD, + CXXSpecialMemberKind CSM) { QualType Ty = Context.getRecordType(RD); - bool ConstArg = (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment); + bool ConstArg = (CSM == CXXSpecialMemberKind::CopyConstructor || + CSM == CXXSpecialMemberKind::CopyAssignment); checkTrivialSubobjectCall(*this, RD->getLocation(), Ty, ConstArg, CSM, TSK_CompleteObject, TAH_IgnoreTrivialABI, /*Diagnose*/true); @@ -10160,9 +10194,10 @@ void Sema::DiagnoseNontrivial(const CXXRecordDecl *RD, CXXSpecialMember CSM) { /// Determine whether a defaulted or deleted special member function is trivial, /// as specified in C++11 [class.ctor]p5, C++11 [class.copy]p12, /// C++11 [class.copy]p25, and C++11 [class.dtor]p5. -bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, +bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMemberKind CSM, TrivialABIHandling TAH, bool Diagnose) { - assert(!MD->isUserProvided() && CSM != CXXInvalid && "not special enough"); + assert(!MD->isUserProvided() && CSM != CXXSpecialMemberKind::Invalid && + "not special enough"); CXXRecordDecl *RD = MD->getParent(); @@ -10172,13 +10207,13 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, // A [special member] is trivial if [...] its parameter-type-list is // equivalent to the parameter-type-list of an implicit declaration [...] switch (CSM) { - case CXXDefaultConstructor: - case CXXDestructor: + case CXXSpecialMemberKind::DefaultConstructor: + case CXXSpecialMemberKind::Destructor: // Trivial default constructors and destructors cannot have parameters. break; - case CXXCopyConstructor: - case CXXCopyAssignment: { + case CXXSpecialMemberKind::CopyConstructor: + case CXXSpecialMemberKind::CopyAssignment: { const ParmVarDecl *Param0 = MD->getNonObjectParameter(0); const ReferenceType *RT = Param0->getType()->getAs(); @@ -10207,8 +10242,8 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, break; } - case CXXMoveConstructor: - case CXXMoveAssignment: { + case CXXSpecialMemberKind::MoveConstructor: + case CXXSpecialMemberKind::MoveAssignment: { // Trivial move operations always have non-cv-qualified parameters. const ParmVarDecl *Param0 = MD->getNonObjectParameter(0); const RValueReferenceType *RT = @@ -10223,7 +10258,7 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, break; } - case CXXInvalid: + case CXXSpecialMemberKind::Invalid: llvm_unreachable("not a special member"); } @@ -10272,7 +10307,7 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, // C++11 [class.dtor]p5: // A destructor is trivial if [...] // -- the destructor is not virtual - if (CSM == CXXDestructor && MD->isVirtual()) { + if (CSM == CXXSpecialMemberKind::Destructor && MD->isVirtual()) { if (Diagnose) Diag(MD->getLocation(), diag::note_nontrivial_virtual_dtor) << RD; return false; @@ -10281,7 +10316,8 @@ bool Sema::SpecialMemberIsTrivial(CXXMethodDecl *MD, CXXSpecialMember CSM, // C++11 [class.ctor]p5, C++11 [class.copy]p12, C++11 [class.copy]p25: // A [special member] for class X is trivial if [...] // -- class X has no virtual functions and no virtual base classes - if (CSM != CXXDestructor && MD->getParent()->isDynamicClass()) { + if (CSM != CXXSpecialMemberKind::Destructor && + MD->getParent()->isDynamicClass()) { if (!Diagnose) return false; @@ -13760,7 +13796,7 @@ struct SpecialMemberExceptionSpecInfo Sema::ImplicitExceptionSpecification ExceptSpec; SpecialMemberExceptionSpecInfo(Sema &S, CXXMethodDecl *MD, - Sema::CXXSpecialMember CSM, + CXXSpecialMemberKind CSM, Sema::InheritedConstructorInfo *ICI, SourceLocation Loc) : SpecialMemberVisitor(S, MD, CSM, ICI), Loc(Loc), ExceptSpec(S) {} @@ -13793,7 +13829,8 @@ bool SpecialMemberExceptionSpecInfo::visitBase(CXXBaseSpecifier *Base) { } bool SpecialMemberExceptionSpecInfo::visitField(FieldDecl *FD) { - if (CSM == Sema::CXXDefaultConstructor && FD->hasInClassInitializer()) { + if (CSM == CXXSpecialMemberKind::DefaultConstructor && + FD->hasInClassInitializer()) { Expr *E = FD->getInClassInitializer(); if (!E) // FIXME: It's a little wasteful to build and throw away a @@ -13852,7 +13889,7 @@ ExplicitSpecifier Sema::ActOnExplicitBoolSpecifier(Expr *ExplicitExpr) { static Sema::ImplicitExceptionSpecification ComputeDefaultedSpecialMemberExceptionSpec( - Sema &S, SourceLocation Loc, CXXMethodDecl *MD, Sema::CXXSpecialMember CSM, + Sema &S, SourceLocation Loc, CXXMethodDecl *MD, CXXSpecialMemberKind CSM, Sema::InheritedConstructorInfo *ICI) { ComputingExceptionSpec CES(S, MD, Loc); @@ -13902,7 +13939,7 @@ struct DeclaringSpecialMember { Sema::ContextRAII SavedContext; bool WasAlreadyBeingDeclared; - DeclaringSpecialMember(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM) + DeclaringSpecialMember(Sema &S, CXXRecordDecl *RD, CXXSpecialMemberKind CSM) : S(S), D(RD, CSM), SavedContext(S, RD) { WasAlreadyBeingDeclared = !S.SpecialMembersBeingDeclared.insert(D).second; if (WasAlreadyBeingDeclared) @@ -13992,13 +14029,13 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( assert(ClassDecl->needsImplicitDefaultConstructor() && "Should not build implicit default constructor!"); - DeclaringSpecialMember DSM(*this, ClassDecl, CXXDefaultConstructor); + DeclaringSpecialMember DSM(*this, ClassDecl, + CXXSpecialMemberKind::DefaultConstructor); if (DSM.isAlreadyBeingDeclared()) return nullptr; - bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, - CXXDefaultConstructor, - false); + bool Constexpr = defaultedSpecialMemberIsConstexpr( + *this, ClassDecl, CXXSpecialMemberKind::DefaultConstructor, false); // Create the actual constructor declaration. CanQualType ClassType @@ -14020,10 +14057,10 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( setupImplicitSpecialMemberType(DefaultCon, Context.VoidTy, std::nullopt); if (getLangOpts().CUDA) - inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDefaultConstructor, - DefaultCon, - /* ConstRHS */ false, - /* Diagnose */ false); + CUDA().inferTargetForImplicitSpecialMember( + ClassDecl, CXXSpecialMemberKind::DefaultConstructor, DefaultCon, + /* ConstRHS */ false, + /* Diagnose */ false); // We don't need to use SpecialMemberIsTrivial here; triviality for default // constructors is easy to compute. @@ -14035,7 +14072,8 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, DefaultCon); - if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor)) + if (ShouldDeleteSpecialMember(DefaultCon, + CXXSpecialMemberKind::DefaultConstructor)) SetDeclDeleted(DefaultCon, ClassLoc); if (S) @@ -14127,10 +14165,10 @@ Sema::findInheritingConstructor(SourceLocation Loc, // from which it was inherited. InheritedConstructorInfo ICI(*this, Loc, Shadow); - bool Constexpr = - BaseCtor->isConstexpr() && - defaultedSpecialMemberIsConstexpr(*this, Derived, CXXDefaultConstructor, - false, BaseCtor, &ICI); + bool Constexpr = BaseCtor->isConstexpr() && + defaultedSpecialMemberIsConstexpr( + *this, Derived, CXXSpecialMemberKind::DefaultConstructor, + false, BaseCtor, &ICI); CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create( Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo, @@ -14174,7 +14212,8 @@ Sema::findInheritingConstructor(SourceLocation Loc, DerivedCtor->setParams(ParamDecls); Derived->addDecl(DerivedCtor); - if (ShouldDeleteSpecialMember(DerivedCtor, CXXDefaultConstructor, &ICI)) + if (ShouldDeleteSpecialMember(DerivedCtor, + CXXSpecialMemberKind::DefaultConstructor, &ICI)) SetDeclDeleted(DerivedCtor, UsingLoc); return DerivedCtor; @@ -14183,8 +14222,9 @@ Sema::findInheritingConstructor(SourceLocation Loc, void Sema::NoteDeletedInheritingConstructor(CXXConstructorDecl *Ctor) { InheritedConstructorInfo ICI(*this, Ctor->getLocation(), Ctor->getInheritedConstructor().getShadowDecl()); - ShouldDeleteSpecialMember(Ctor, CXXDefaultConstructor, &ICI, - /*Diagnose*/true); + ShouldDeleteSpecialMember(Ctor, CXXSpecialMemberKind::DefaultConstructor, + &ICI, + /*Diagnose*/ true); } void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, @@ -14275,13 +14315,13 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { // inline public member of its class. assert(ClassDecl->needsImplicitDestructor()); - DeclaringSpecialMember DSM(*this, ClassDecl, CXXDestructor); + DeclaringSpecialMember DSM(*this, ClassDecl, + CXXSpecialMemberKind::Destructor); if (DSM.isAlreadyBeingDeclared()) return nullptr; - bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, - CXXDestructor, - false); + bool Constexpr = defaultedSpecialMemberIsConstexpr( + *this, ClassDecl, CXXSpecialMemberKind::Destructor, false); // Create the actual destructor declaration. CanQualType ClassType @@ -14303,10 +14343,10 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { setupImplicitSpecialMemberType(Destructor, Context.VoidTy, std::nullopt); if (getLangOpts().CUDA) - inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXDestructor, - Destructor, - /* ConstRHS */ false, - /* Diagnose */ false); + CUDA().inferTargetForImplicitSpecialMember( + ClassDecl, CXXSpecialMemberKind::Destructor, Destructor, + /* ConstRHS */ false, + /* Diagnose */ false); // We don't need to use SpecialMemberIsTrivial here; triviality for // destructors is easy to compute. @@ -14324,7 +14364,7 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { // the definition of the class, because its validity depends on the alignment // of the class. We'll check this from ActOnFields once the class is complete. if (ClassDecl->isCompleteDefinition() && - ShouldDeleteSpecialMember(Destructor, CXXDestructor)) + ShouldDeleteSpecialMember(Destructor, CXXSpecialMemberKind::Destructor)) SetDeclDeleted(Destructor, ClassLoc); // Introduce this destructor into its scope. @@ -14905,7 +14945,8 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { // operators taking an object instead of a reference are allowed. assert(ClassDecl->needsImplicitCopyAssignment()); - DeclaringSpecialMember DSM(*this, ClassDecl, CXXCopyAssignment); + DeclaringSpecialMember DSM(*this, ClassDecl, + CXXSpecialMemberKind::CopyAssignment); if (DSM.isAlreadyBeingDeclared()) return nullptr; @@ -14922,9 +14963,8 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { ArgType = Context.getLValueReferenceType(ArgType); - bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, - CXXCopyAssignment, - Const); + bool Constexpr = defaultedSpecialMemberIsConstexpr( + *this, ClassDecl, CXXSpecialMemberKind::CopyAssignment, Const); // An implicitly-declared copy assignment operator is an inline public // member of its class. @@ -14945,10 +14985,10 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { setupImplicitSpecialMemberType(CopyAssignment, RetType, ArgType); if (getLangOpts().CUDA) - inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXCopyAssignment, - CopyAssignment, - /* ConstRHS */ Const, - /* Diagnose */ false); + CUDA().inferTargetForImplicitSpecialMember( + ClassDecl, CXXSpecialMemberKind::CopyAssignment, CopyAssignment, + /* ConstRHS */ Const, + /* Diagnose */ false); // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, CopyAssignment, @@ -14959,9 +14999,10 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { CopyAssignment->setParams(FromParam); CopyAssignment->setTrivial( - ClassDecl->needsOverloadResolutionForCopyAssignment() - ? SpecialMemberIsTrivial(CopyAssignment, CXXCopyAssignment) - : ClassDecl->hasTrivialCopyAssignment()); + ClassDecl->needsOverloadResolutionForCopyAssignment() + ? SpecialMemberIsTrivial(CopyAssignment, + CXXSpecialMemberKind::CopyAssignment) + : ClassDecl->hasTrivialCopyAssignment()); // Note that we have added this copy-assignment operator. ++getASTContext().NumImplicitCopyAssignmentOperatorsDeclared; @@ -14969,7 +15010,8 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, CopyAssignment); - if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) { + if (ShouldDeleteSpecialMember(CopyAssignment, + CXXSpecialMemberKind::CopyAssignment)) { ClassDecl->setImplicitCopyAssignmentIsDeleted(); SetDeclDeleted(CopyAssignment, ClassLoc); } @@ -15256,7 +15298,8 @@ void Sema::DefineImplicitCopyAssignment(SourceLocation CurrentLocation, CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { assert(ClassDecl->needsImplicitMoveAssignment()); - DeclaringSpecialMember DSM(*this, ClassDecl, CXXMoveAssignment); + DeclaringSpecialMember DSM(*this, ClassDecl, + CXXSpecialMemberKind::MoveAssignment); if (DSM.isAlreadyBeingDeclared()) return nullptr; @@ -15272,9 +15315,8 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { QualType RetType = Context.getLValueReferenceType(ArgType); ArgType = Context.getRValueReferenceType(ArgType); - bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, - CXXMoveAssignment, - false); + bool Constexpr = defaultedSpecialMemberIsConstexpr( + *this, ClassDecl, CXXSpecialMemberKind::MoveAssignment, false); // An implicitly-declared move assignment operator is an inline public // member of its class. @@ -15295,10 +15337,10 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { setupImplicitSpecialMemberType(MoveAssignment, RetType, ArgType); if (getLangOpts().CUDA) - inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXMoveAssignment, - MoveAssignment, - /* ConstRHS */ false, - /* Diagnose */ false); + CUDA().inferTargetForImplicitSpecialMember( + ClassDecl, CXXSpecialMemberKind::MoveAssignment, MoveAssignment, + /* ConstRHS */ false, + /* Diagnose */ false); // Add the parameter to the operator. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveAssignment, @@ -15309,9 +15351,10 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { MoveAssignment->setParams(FromParam); MoveAssignment->setTrivial( - ClassDecl->needsOverloadResolutionForMoveAssignment() - ? SpecialMemberIsTrivial(MoveAssignment, CXXMoveAssignment) - : ClassDecl->hasTrivialMoveAssignment()); + ClassDecl->needsOverloadResolutionForMoveAssignment() + ? SpecialMemberIsTrivial(MoveAssignment, + CXXSpecialMemberKind::MoveAssignment) + : ClassDecl->hasTrivialMoveAssignment()); // Note that we have added this copy-assignment operator. ++getASTContext().NumImplicitMoveAssignmentOperatorsDeclared; @@ -15319,7 +15362,8 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, MoveAssignment); - if (ShouldDeleteSpecialMember(MoveAssignment, CXXMoveAssignment)) { + if (ShouldDeleteSpecialMember(MoveAssignment, + CXXSpecialMemberKind::MoveAssignment)) { ClassDecl->setImplicitMoveAssignmentIsDeleted(); SetDeclDeleted(MoveAssignment, ClassLoc); } @@ -15368,10 +15412,10 @@ static void checkMoveAssignmentForRepeatedMove(Sema &S, CXXRecordDecl *Class, // If we're not actually going to call a move assignment for this base, // or the selected move assignment is trivial, skip it. Sema::SpecialMemberOverloadResult SMOR = - S.LookupSpecialMember(Base, Sema::CXXMoveAssignment, - /*ConstArg*/false, /*VolatileArg*/false, - /*RValueThis*/true, /*ConstThis*/false, - /*VolatileThis*/false); + S.LookupSpecialMember(Base, CXXSpecialMemberKind::MoveAssignment, + /*ConstArg*/ false, /*VolatileArg*/ false, + /*RValueThis*/ true, /*ConstThis*/ false, + /*VolatileThis*/ false); if (!SMOR.getMethod() || SMOR.getMethod()->isTrivial() || !SMOR.getMethod()->isMoveAssignmentOperator()) continue; @@ -15648,7 +15692,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( // constructor, one is declared implicitly. assert(ClassDecl->needsImplicitCopyConstructor()); - DeclaringSpecialMember DSM(*this, ClassDecl, CXXCopyConstructor); + DeclaringSpecialMember DSM(*this, ClassDecl, + CXXSpecialMemberKind::CopyConstructor); if (DSM.isAlreadyBeingDeclared()) return nullptr; @@ -15666,9 +15711,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( ArgType = Context.getLValueReferenceType(ArgType); - bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, - CXXCopyConstructor, - Const); + bool Constexpr = defaultedSpecialMemberIsConstexpr( + *this, ClassDecl, CXXSpecialMemberKind::CopyConstructor, Const); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( @@ -15691,10 +15735,10 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( setupImplicitSpecialMemberType(CopyConstructor, Context.VoidTy, ArgType); if (getLangOpts().CUDA) - inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXCopyConstructor, - CopyConstructor, - /* ConstRHS */ Const, - /* Diagnose */ false); + CUDA().inferTargetForImplicitSpecialMember( + ClassDecl, CXXSpecialMemberKind::CopyConstructor, CopyConstructor, + /* ConstRHS */ Const, + /* Diagnose */ false); // During template instantiation of special member functions we need a // reliable TypeSourceInfo for the parameter types in order to allow functions @@ -15712,14 +15756,16 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( CopyConstructor->setTrivial( ClassDecl->needsOverloadResolutionForCopyConstructor() - ? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor) + ? SpecialMemberIsTrivial(CopyConstructor, + CXXSpecialMemberKind::CopyConstructor) : ClassDecl->hasTrivialCopyConstructor()); CopyConstructor->setTrivialForCall( ClassDecl->hasAttr() || (ClassDecl->needsOverloadResolutionForCopyConstructor() - ? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor, - TAH_ConsiderTrivialABI) + ? SpecialMemberIsTrivial(CopyConstructor, + CXXSpecialMemberKind::CopyConstructor, + TAH_ConsiderTrivialABI) : ClassDecl->hasTrivialCopyConstructorForCall())); // Note that we have declared this constructor. @@ -15728,7 +15774,8 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, CopyConstructor); - if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) { + if (ShouldDeleteSpecialMember(CopyConstructor, + CXXSpecialMemberKind::CopyConstructor)) { ClassDecl->setImplicitCopyConstructorIsDeleted(); SetDeclDeleted(CopyConstructor, ClassLoc); } @@ -15793,7 +15840,8 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( CXXRecordDecl *ClassDecl) { assert(ClassDecl->needsImplicitMoveConstructor()); - DeclaringSpecialMember DSM(*this, ClassDecl, CXXMoveConstructor); + DeclaringSpecialMember DSM(*this, ClassDecl, + CXXSpecialMemberKind::MoveConstructor); if (DSM.isAlreadyBeingDeclared()) return nullptr; @@ -15807,9 +15855,8 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( ArgType = Context.getAddrSpaceQualType(ClassType, AS); ArgType = Context.getRValueReferenceType(ArgType); - bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, ClassDecl, - CXXMoveConstructor, - false); + bool Constexpr = defaultedSpecialMemberIsConstexpr( + *this, ClassDecl, CXXSpecialMemberKind::MoveConstructor, false); DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( @@ -15833,10 +15880,10 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( setupImplicitSpecialMemberType(MoveConstructor, Context.VoidTy, ArgType); if (getLangOpts().CUDA) - inferCUDATargetForImplicitSpecialMember(ClassDecl, CXXMoveConstructor, - MoveConstructor, - /* ConstRHS */ false, - /* Diagnose */ false); + CUDA().inferTargetForImplicitSpecialMember( + ClassDecl, CXXSpecialMemberKind::MoveConstructor, MoveConstructor, + /* ConstRHS */ false, + /* Diagnose */ false); // Add the parameter to the constructor. ParmVarDecl *FromParam = ParmVarDecl::Create(Context, MoveConstructor, @@ -15848,13 +15895,15 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( MoveConstructor->setTrivial( ClassDecl->needsOverloadResolutionForMoveConstructor() - ? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor) + ? SpecialMemberIsTrivial(MoveConstructor, + CXXSpecialMemberKind::MoveConstructor) : ClassDecl->hasTrivialMoveConstructor()); MoveConstructor->setTrivialForCall( ClassDecl->hasAttr() || (ClassDecl->needsOverloadResolutionForMoveConstructor() - ? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor, + ? SpecialMemberIsTrivial(MoveConstructor, + CXXSpecialMemberKind::MoveConstructor, TAH_ConsiderTrivialABI) : ClassDecl->hasTrivialMoveConstructorForCall())); @@ -15864,7 +15913,8 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, MoveConstructor); - if (ShouldDeleteSpecialMember(MoveConstructor, CXXMoveConstructor)) { + if (ShouldDeleteSpecialMember(MoveConstructor, + CXXSpecialMemberKind::MoveConstructor)) { ClassDecl->setImplicitMoveConstructorIsDeleted(); SetDeclDeleted(MoveConstructor, ClassLoc); } @@ -16136,7 +16186,7 @@ ExprResult Sema::BuildCXXConstructExpr( DeclInitType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) && "given constructor for wrong type"); MarkFunctionReferenced(ConstructLoc, Constructor); - if (getLangOpts().CUDA && !CheckCUDACall(ConstructLoc, Constructor)) + if (getLangOpts().CUDA && !CUDA().CheckCall(ConstructLoc, Constructor)) return ExprError(); return CheckForImmediateInvocation( @@ -16913,11 +16963,10 @@ Decl *Sema::ActOnEmptyDeclaration(Scope *S, /// Perform semantic analysis for the variable declaration that /// occurs within a C++ catch clause, returning the newly-created /// variable. -VarDecl *Sema::BuildExceptionDeclaration(Scope *S, - TypeSourceInfo *TInfo, +VarDecl *Sema::BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, SourceLocation StartLoc, SourceLocation Loc, - IdentifierInfo *Name) { + const IdentifierInfo *Name) { bool Invalid = false; QualType ExDeclType = TInfo->getType(); @@ -17062,7 +17111,7 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { Invalid = true; } - IdentifierInfo *II = D.getIdentifier(); + const IdentifierInfo *II = D.getIdentifier(); if (NamedDecl *PrevDecl = LookupSingleName(S, II, D.getIdentifierLoc(), LookupOrdinaryName, ForVisibleRedeclaration)) { @@ -18111,7 +18160,8 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, return ND; } -void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { +void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc, + StringLiteral *Message) { AdjustDeclIfTemplate(Dcl); FunctionDecl *Fn = dyn_cast_or_null(Dcl); @@ -18160,7 +18210,7 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { // C++11 [dcl.fct.def.delete]p4: // A deleted function is implicitly inline. Fn->setImplicitlyInline(); - Fn->setDeletedAsWritten(); + Fn->setDeletedAsWritten(true, Message); } void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { @@ -18273,11 +18323,11 @@ void Sema::DiagnoseReturnInConstructorExceptionHandler(CXXTryStmt *TryBlock) { } } -void Sema::SetFunctionBodyKind(Decl *D, SourceLocation Loc, - FnBodyKind BodyKind) { +void Sema::SetFunctionBodyKind(Decl *D, SourceLocation Loc, FnBodyKind BodyKind, + StringLiteral *DeletedMessage) { switch (BodyKind) { case FnBodyKind::Delete: - SetDeclDeleted(D, Loc); + SetDeclDeleted(D, Loc, DeletedMessage); break; case FnBodyKind::Default: SetDeclDefaulted(D, Loc); @@ -19158,7 +19208,7 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record, InClassInitStyle InitStyle, AccessSpecifier AS, const ParsedAttr &MSPropertyAttr) { - IdentifierInfo *II = D.getIdentifier(); + const IdentifierInfo *II = D.getIdentifier(); if (!II) { Diag(DeclStart, diag::err_anonymous_property); return nullptr; diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 94a245f0f905f33a2bc9d2512b30419f6646eb47..74d6f0700b0e4f52e79864564426133328a0e723 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -1818,9 +1818,9 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, } ObjCCategoryDecl *Sema::ActOnStartCategoryInterface( - SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, + SourceLocation AtInterfaceLoc, const IdentifierInfo *ClassName, SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, - IdentifierInfo *CategoryName, SourceLocation CategoryLoc, + const IdentifierInfo *CategoryName, SourceLocation CategoryLoc, Decl *const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, const ParsedAttributesView &AttrList) { @@ -1916,9 +1916,9 @@ ObjCCategoryDecl *Sema::ActOnStartCategoryInterface( /// category implementation declaration and build an ObjCCategoryImplDecl /// object. ObjCCategoryImplDecl *Sema::ActOnStartCategoryImplementation( - SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, - SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc, - const ParsedAttributesView &Attrs) { + SourceLocation AtCatImplLoc, const IdentifierInfo *ClassName, + SourceLocation ClassLoc, const IdentifierInfo *CatName, + SourceLocation CatLoc, const ParsedAttributesView &Attrs) { ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true); ObjCCategoryDecl *CatIDecl = nullptr; if (IDecl && IDecl->hasDefinition()) { @@ -1982,8 +1982,8 @@ ObjCCategoryImplDecl *Sema::ActOnStartCategoryImplementation( } ObjCImplementationDecl *Sema::ActOnStartClassImplementation( - SourceLocation AtClassImplLoc, IdentifierInfo *ClassName, - SourceLocation ClassLoc, IdentifierInfo *SuperClassname, + SourceLocation AtClassImplLoc, const IdentifierInfo *ClassName, + SourceLocation ClassLoc, const IdentifierInfo *SuperClassname, SourceLocation SuperClassLoc, const ParsedAttributesView &Attrs) { ObjCInterfaceDecl *IDecl = nullptr; // Check for another declaration kind with the same name. @@ -2751,7 +2751,7 @@ static void CheckProtocolMethodDefs( // implemented in the class, we should not issue "Method definition not // found" warnings. // FIXME: Use a general GetUnarySelector method for this. - IdentifierInfo* II = &S.Context.Idents.get("forwardInvocation"); + const IdentifierInfo *II = &S.Context.Idents.get("forwardInvocation"); Selector fISelector = S.Context.Selectors.getSelector(1, &II); if (InsMap.count(fISelector)) // Is IDecl derived from 'NSProxy'? If so, no instance methods @@ -5105,8 +5105,8 @@ bool Sema::CheckObjCDeclScope(Decl *D) { /// Called whenever \@defs(ClassName) is encountered in the source. Inserts the /// instance variables of ClassName into Decls. void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, - IdentifierInfo *ClassName, - SmallVectorImpl &Decls) { + const IdentifierInfo *ClassName, + SmallVectorImpl &Decls) { // Check that ClassName is a valid class ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName, DeclStart); if (!Class) { @@ -5148,8 +5148,7 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, - bool Invalid) { + const IdentifierInfo *Id, bool Invalid) { // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage // duration shall not be qualified by an address-space qualifier." // Since all parameters have automatic store duration, they can not have diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index ffe7e44e2387f4b1962ebbbbc6e3981d65dabd63..c5395fb2068a188b91d80a87c6c872e27957a402 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -49,10 +49,12 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaFixItUtils.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ConvertUTF.h" @@ -271,8 +273,11 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef Locs, Diag(Loc, diag::err_deleted_inherited_ctor_use) << Ctor->getParent() << Ctor->getInheritedConstructor().getConstructor()->getParent(); - else - Diag(Loc, diag::err_deleted_function_use); + else { + StringLiteral *Msg = FD->getDeletedMessage(); + Diag(Loc, diag::err_deleted_function_use) + << (Msg != nullptr) << (Msg ? Msg->getString() : StringRef()); + } NoteDeletedFunction(FD); return true; } @@ -307,7 +312,7 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef Locs, DeduceReturnType(FD, Loc)) return true; - if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD)) + if (getLangOpts().CUDA && !CUDA().CheckCall(Loc, FD)) return true; } @@ -3794,28 +3799,6 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, SL); } -ExprResult Sema::BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc, - SourceLocation LParen, - SourceLocation RParen, - TypeSourceInfo *TSI) { - return SYCLUniqueStableNameExpr::Create(Context, OpLoc, LParen, RParen, TSI); -} - -ExprResult Sema::ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc, - SourceLocation LParen, - SourceLocation RParen, - ParsedType ParsedTy) { - TypeSourceInfo *TSI = nullptr; - QualType Ty = GetTypeFromParser(ParsedTy, &TSI); - - if (Ty.isNull()) - return ExprError(); - if (!TSI) - TSI = Context.getTrivialTypeSourceInfo(Ty, LParen); - - return BuildSYCLUniqueStableNameExpr(OpLoc, LParen, RParen, TSI); -} - ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { return BuildPredefinedExpr(Loc, getPredefinedExprKind(Kind)); } @@ -7479,7 +7462,7 @@ ExprResult Sema::ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy, SourceLocation RParenLoc) { TypeSourceInfo *TInfo; GetTypeFromParser(ParsedDestTy, &TInfo); - return SemaConvertVectorExpr(E, TInfo, BuiltinLoc, RParenLoc); + return ConvertVectorExpr(E, TInfo, BuiltinLoc, RParenLoc); } /// BuildResolvedCallExpr - Build a call to a resolved expression, @@ -14896,8 +14879,8 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, return QualType(); } else if (ResType->isAnyComplexType()) { // C99 does not support ++/-- on complex types, we allow as an extension. - S.Diag(OpLoc, diag::ext_integer_increment_complex) - << ResType << Op->getSourceRange(); + S.Diag(OpLoc, diag::ext_increment_complex) + << IsInc << Op->getSourceRange(); } else if (ResType->isPlaceholderType()) { ExprResult PR = S.CheckPlaceholderExpr(Op); if (PR.isInvalid()) return QualType(); @@ -17344,8 +17327,9 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, // CUDA device code does not support varargs. if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) { if (const FunctionDecl *F = dyn_cast(CurContext)) { - CUDAFunctionTarget T = IdentifyCUDATarget(F); - if (T == CFT_Global || T == CFT_Device || T == CFT_HostDevice) + CUDAFunctionTarget T = CUDA().IdentifyTarget(F); + if (T == CUDAFunctionTarget::Global || T == CUDAFunctionTarget::Device || + T == CUDAFunctionTarget::HostDevice) return ExprError(Diag(E->getBeginLoc(), diag::err_va_arg_in_device)); } } @@ -18981,8 +18965,10 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // Note that we skip the implicit instantiation of templates that are only // used in unused default arguments or by recursive calls to themselves. // This is formally non-conforming, but seems reasonable in practice. - bool NeedDefinition = !IsRecursiveCall && (OdrUse == OdrUseContext::Used || - NeededForConstantEvaluation); + bool NeedDefinition = + !IsRecursiveCall && + (OdrUse == OdrUseContext::Used || + (NeededForConstantEvaluation && !Func->isPureVirtual())); // C++14 [temp.expl.spec]p6: // If a template [...] is explicitly specialized then that specialization @@ -18995,7 +18981,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, checkSpecializationReachability(Loc, Func); if (getLangOpts().CUDA) - CheckCUDACall(Loc, Func); + CUDA().CheckCall(Loc, Func); // If we need a definition, try to create one. if (NeedDefinition && !Func->getBody()) { @@ -19142,7 +19128,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // side. Therefore keep trying until it is recorded. if (LangOpts.OffloadImplicitHostDeviceTemplates && LangOpts.CUDAIsDevice && !getASTContext().CUDAImplicitHostDeviceFunUsedByDevice.count(Func)) - CUDARecordImplicitHostDeviceFuncUsedByDevice(Func); + CUDA().RecordImplicitHostDeviceFuncUsedByDevice(Func); // If this is the first "real" use, act on that. if (OdrUse == OdrUseContext::Used && !Func->isUsed(/*CheckUsedAttr=*/false)) { @@ -19215,26 +19201,28 @@ MarkVarDeclODRUsed(ValueDecl *V, SourceLocation Loc, Sema &SemaRef, if (SemaRef.LangOpts.CUDA && Var->hasGlobalStorage()) { auto *FD = dyn_cast_or_null(SemaRef.CurContext); - auto VarTarget = SemaRef.IdentifyCUDATarget(Var); - auto UserTarget = SemaRef.IdentifyCUDATarget(FD); - if (VarTarget == Sema::CVT_Host && - (UserTarget == Sema::CFT_Device || UserTarget == Sema::CFT_HostDevice || - UserTarget == Sema::CFT_Global)) { + auto VarTarget = SemaRef.CUDA().IdentifyTarget(Var); + auto UserTarget = SemaRef.CUDA().IdentifyTarget(FD); + if (VarTarget == SemaCUDA::CVT_Host && + (UserTarget == CUDAFunctionTarget::Device || + UserTarget == CUDAFunctionTarget::HostDevice || + UserTarget == CUDAFunctionTarget::Global)) { // Diagnose ODR-use of host global variables in device functions. // Reference of device global variables in host functions is allowed // through shadow variables therefore it is not diagnosed. if (SemaRef.LangOpts.CUDAIsDevice && !SemaRef.LangOpts.HIPStdPar) { SemaRef.targetDiag(Loc, diag::err_ref_bad_target) - << /*host*/ 2 << /*variable*/ 1 << Var << UserTarget; + << /*host*/ 2 << /*variable*/ 1 << Var + << llvm::to_underlying(UserTarget); SemaRef.targetDiag(Var->getLocation(), Var->getType().isConstQualified() ? diag::note_cuda_const_var_unpromoted : diag::note_cuda_host_var); } - } else if (VarTarget == Sema::CVT_Device && + } else if (VarTarget == SemaCUDA::CVT_Device && !Var->hasAttr() && - (UserTarget == Sema::CFT_Host || - UserTarget == Sema::CFT_HostDevice)) { + (UserTarget == CUDAFunctionTarget::Host || + UserTarget == CUDAFunctionTarget::HostDevice)) { // Record a CUDA/HIP device side variable if it is ODR-used // by host code. This is done conservatively, when the variable is // referenced in any of the following contexts: @@ -20719,20 +20707,42 @@ void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) { static void FixDependencyOfIdExpressionsInLambdaWithDependentObjectParameter( Sema &SemaRef, ValueDecl *D, Expr *E) { auto *ID = dyn_cast(E); - if (!ID || ID->isTypeDependent()) + if (!ID || ID->isTypeDependent() || !ID->refersToEnclosingVariableOrCapture()) return; + // If any enclosing lambda with a dependent explicit object parameter either + // explicitly captures the variable by value, or has a capture default of '=' + // and does not capture the variable by reference, then the type of the DRE + // is dependent on the type of that lambda's explicit object parameter. auto IsDependent = [&]() { - const LambdaScopeInfo *LSI = SemaRef.getCurLambda(); - if (!LSI) - return false; - if (!LSI->ExplicitObjectParameter || - !LSI->ExplicitObjectParameter->getType()->isDependentType()) - return false; - if (!LSI->CaptureMap.count(D)) - return false; - const Capture &Cap = LSI->getCapture(D); - return !Cap.isCopyCapture(); + for (auto *Scope : llvm::reverse(SemaRef.FunctionScopes)) { + auto *LSI = dyn_cast(Scope); + if (!LSI) + continue; + + if (LSI->Lambda && !LSI->Lambda->Encloses(SemaRef.CurContext) && + LSI->AfterParameterList) + return false; + + const auto *MD = LSI->CallOperator; + if (MD->getType().isNull()) + continue; + + const auto *Ty = MD->getType()->getAs(); + if (!Ty || !MD->isExplicitObjectMemberFunction() || + !Ty->getParamType(0)->isDependentType()) + continue; + + if (auto *C = LSI->CaptureMap.count(D) ? &LSI->getCapture(D) : nullptr) { + if (C->isCopyCapture()) + return true; + continue; + } + + if (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByval) + return true; + } + return false; }(); ID->setCapturedByCopyInLambdaWithExplicitObjectParameter( diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 76bb78aa8b5458fa2e7f9cd994ad9c05599def3f..fa7b92a43346b11e47f4934d19e86c1ae6c7b7c5 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -38,12 +38,14 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/SemaLambda.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TypeSize.h" @@ -57,7 +59,7 @@ using namespace sema; /// name of the corresponding type. ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS, SourceLocation NameLoc, - IdentifierInfo &Name) { + const IdentifierInfo &Name) { NestedNameSpecifier *NNS = SS.getScopeRep(); // Convert the nested-name-specifier into a type. @@ -89,10 +91,9 @@ ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS, Context.getTrivialTypeSourceInfo(Type, NameLoc)); } -ParsedType Sema::getConstructorName(IdentifierInfo &II, - SourceLocation NameLoc, - Scope *S, CXXScopeSpec &SS, - bool EnteringContext) { +ParsedType Sema::getConstructorName(const IdentifierInfo &II, + SourceLocation NameLoc, Scope *S, + CXXScopeSpec &SS, bool EnteringContext) { CXXRecordDecl *CurClass = getCurrentClass(S, &SS); assert(CurClass && &II == CurClass->getIdentifier() && "not a constructor name"); @@ -140,9 +141,9 @@ ParsedType Sema::getConstructorName(IdentifierInfo &II, return ParsedType::make(T); } -ParsedType Sema::getDestructorName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, CXXScopeSpec &SS, - ParsedType ObjectTypePtr, +ParsedType Sema::getDestructorName(const IdentifierInfo &II, + SourceLocation NameLoc, Scope *S, + CXXScopeSpec &SS, ParsedType ObjectTypePtr, bool EnteringContext) { // Determine where to perform name lookup. @@ -500,7 +501,7 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, // // double operator""_Bq(long double); // OK: not a reserved identifier // double operator"" _Bq(long double); // ill-formed, no diagnostic required - IdentifierInfo *II = Name.Identifier; + const IdentifierInfo *II = Name.Identifier; ReservedIdentifierStatus Status = II->isReserved(PP.getLangOpts()); SourceLocation Loc = Name.getEndLoc(); if (!PP.getSourceManager().isInSystemHeader(Loc)) { @@ -884,8 +885,8 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, // Exceptions aren't allowed in CUDA device code. if (getLangOpts().CUDA) - CUDADiagIfDeviceCode(OpLoc, diag::err_cuda_device_exceptions) - << "throw" << CurrentCUDATarget(); + CUDA().DiagIfDeviceCode(OpLoc, diag::err_cuda_device_exceptions) + << "throw" << llvm::to_underlying(CUDA().CurrentTarget()); if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope()) Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw"; @@ -1446,6 +1447,42 @@ Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type, void Sema::MarkThisReferenced(CXXThisExpr *This) { CheckCXXThisCapture(This->getExprLoc()); + if (This->isTypeDependent()) + return; + + // Check if 'this' is captured by value in a lambda with a dependent explicit + // object parameter, and mark it as type-dependent as well if so. + auto IsDependent = [&]() { + for (auto *Scope : llvm::reverse(FunctionScopes)) { + auto *LSI = dyn_cast(Scope); + if (!LSI) + continue; + + if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext) && + LSI->AfterParameterList) + return false; + + // If this lambda captures 'this' by value, then 'this' is dependent iff + // this lambda has a dependent explicit object parameter. If we can't + // determine whether it does (e.g. because the CXXMethodDecl's type is + // null), assume it doesn't. + if (LSI->isCXXThisCaptured()) { + if (!LSI->getCXXThisCapture().isCopyCapture()) + continue; + + const auto *MD = LSI->CallOperator; + if (MD->getType().isNull()) + return false; + + const auto *Ty = MD->getType()->getAs(); + return Ty && MD->isExplicitObjectMemberFunction() && + Ty->getParamType(0)->isDependentType(); + } + } + return false; + }(); + + This->setCapturedByCopyInLambdaWithExplicitObjectParameter(IsDependent); } bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) { @@ -1656,17 +1693,17 @@ bool Sema::isUsualDeallocationFunction(const CXXMethodDecl *Method) { // [CUDA] Ignore this function, if we can't call it. const FunctionDecl *Caller = getCurFunctionDecl(/*AllowLambda=*/true); if (getLangOpts().CUDA) { - auto CallPreference = IdentifyCUDAPreference(Caller, Method); + auto CallPreference = CUDA().IdentifyPreference(Caller, Method); // If it's not callable at all, it's not the right function. - if (CallPreference < CFP_WrongSide) + if (CallPreference < SemaCUDA::CFP_WrongSide) return false; - if (CallPreference == CFP_WrongSide) { + if (CallPreference == SemaCUDA::CFP_WrongSide) { // Maybe. We have to check if there are better alternatives. DeclContext::lookup_result R = Method->getDeclContext()->lookup(Method->getDeclName()); for (const auto *D : R) { if (const auto *FD = dyn_cast(D)) { - if (IdentifyCUDAPreference(Caller, FD) > CFP_WrongSide) + if (CUDA().IdentifyPreference(Caller, FD) > SemaCUDA::CFP_WrongSide) return false; } } @@ -1685,7 +1722,7 @@ bool Sema::isUsualDeallocationFunction(const CXXMethodDecl *Method) { return llvm::none_of(PreventedBy, [&](const FunctionDecl *FD) { assert(FD->getNumParams() == 1 && "Only single-operand functions should be in PreventedBy"); - return IdentifyCUDAPreference(Caller, FD) >= CFP_HostDevice; + return CUDA().IdentifyPreference(Caller, FD) >= SemaCUDA::CFP_HostDevice; }); } @@ -1722,7 +1759,7 @@ namespace { UsualDeallocFnInfo(Sema &S, DeclAccessPair Found) : Found(Found), FD(dyn_cast(Found->getUnderlyingDecl())), Destroying(false), HasSizeT(false), HasAlignValT(false), - CUDAPref(Sema::CFP_Native) { + CUDAPref(SemaCUDA::CFP_Native) { // A function template declaration is never a usual deallocation function. if (!FD) return; @@ -1748,7 +1785,7 @@ namespace { // In CUDA, determine how much we'd like / dislike to call this. if (S.getLangOpts().CUDA) - CUDAPref = S.IdentifyCUDAPreference( + CUDAPref = S.CUDA().IdentifyPreference( S.getCurFunctionDecl(/*AllowLambda=*/true), FD); } @@ -1779,7 +1816,7 @@ namespace { DeclAccessPair Found; FunctionDecl *FD; bool Destroying, HasSizeT, HasAlignValT; - Sema::CUDAFunctionPreference CUDAPref; + SemaCUDA::CUDAFunctionPreference CUDAPref; }; } @@ -1803,7 +1840,7 @@ static UsualDeallocFnInfo resolveDeallocationOverload( for (auto I = R.begin(), E = R.end(); I != E; ++I) { UsualDeallocFnInfo Info(S, I.getPair()); if (!Info || !isNonPlacementDeallocationFunction(S, Info.FD) || - Info.CUDAPref == Sema::CFP_Never) + Info.CUDAPref == SemaCUDA::CFP_Never) continue; if (!Best) { @@ -2663,13 +2700,9 @@ static bool resolveAllocationOverload( return true; case OR_Deleted: { - if (Diagnose) { - Candidates.NoteCandidates( - PartialDiagnosticAt(R.getNameLoc(), - S.PDiag(diag::err_ovl_deleted_call) - << R.getLookupName() << Range), - S, OCD_AllCandidates, Args); - } + if (Diagnose) + S.DiagnoseUseOfDeletedFunction(R.getNameLoc(), Range, R.getLookupName(), + Candidates, Best->Function, Args); return true; } } @@ -2904,8 +2937,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, } if (getLangOpts().CUDA) - EraseUnwantedCUDAMatches(getCurFunctionDecl(/*AllowLambda=*/true), - Matches); + CUDA().EraseUnwantedMatches(getCurFunctionDecl(/*AllowLambda=*/true), + Matches); } else { // C++1y [expr.new]p22: // For a non-placement allocation function, the normal deallocation @@ -3323,7 +3356,9 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, // FIXME: DiagnoseUseOfDecl? if (Operator->isDeleted()) { if (Diagnose) { - Diag(StartLoc, diag::err_deleted_function_use); + StringLiteral *Msg = Operator->getDeletedMessage(); + Diag(StartLoc, diag::err_deleted_function_use) + << (Msg != nullptr) << (Msg ? Msg->getString() : StringRef()); NoteDeletedFunction(Operator); } return true; @@ -3927,20 +3962,16 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall, S, OCD_AmbiguousCandidates, Args); return true; - case OR_Deleted: { - Candidates.NoteCandidates( - PartialDiagnosticAt(R.getNameLoc(), S.PDiag(diag::err_ovl_deleted_call) - << R.getLookupName() << Range), - S, OCD_AllCandidates, Args); + case OR_Deleted: + S.DiagnoseUseOfDeletedFunction(R.getNameLoc(), Range, R.getLookupName(), + Candidates, Best->Function, Args); return true; } - } llvm_unreachable("Unreachable, bad result from BestViableFunction"); } -ExprResult -Sema::SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, - bool IsDelete) { +ExprResult Sema::BuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, + bool IsDelete) { CallExpr *TheCall = cast(TheCallResult.get()); if (!getLangOpts().CPlusPlus) { Diag(TheCall->getExprLoc(), diag::err_builtin_requires_language) @@ -4960,6 +4991,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, return From; } +/// Checks that type T is not a VLA. +/// +/// @returns @c true if @p T is VLA and a diagnostic was emitted, +/// @c false otherwise. +static bool DiagnoseVLAInCXXTypeTrait(Sema &S, const TypeSourceInfo *T, + clang::tok::TokenKind TypeTraitID) { + if (!T->getType()->isVariableArrayType()) + return false; + + S.Diag(T->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported) + << 1 << TypeTraitID; + return true; +} + /// Check the completeness of a type in a unary type trait. /// /// If the particular type trait requires a complete type, tries to complete @@ -5136,7 +5181,9 @@ static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op, } static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, - SourceLocation KeyLoc, QualType T) { + SourceLocation KeyLoc, + TypeSourceInfo *TInfo) { + QualType T = TInfo->getType(); assert(!T->isDependentType() && "Cannot evaluate traits of dependent type"); ASTContext &C = Self.Context; @@ -5153,21 +5200,13 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, case UTT_IsArray: return T->isArrayType(); case UTT_IsBoundedArray: - if (!T->isVariableArrayType()) { - return T->isArrayType() && !T->isIncompleteArrayType(); - } - - Self.Diag(KeyLoc, diag::err_vla_unsupported) - << 1 << tok::kw___is_bounded_array; - return false; + if (DiagnoseVLAInCXXTypeTrait(Self, TInfo, tok::kw___is_bounded_array)) + return false; + return T->isArrayType() && !T->isIncompleteArrayType(); case UTT_IsUnboundedArray: - if (!T->isVariableArrayType()) { - return T->isIncompleteArrayType(); - } - - Self.Diag(KeyLoc, diag::err_vla_unsupported) - << 1 << tok::kw___is_unbounded_array; - return false; + if (DiagnoseVLAInCXXTypeTrait(Self, TInfo, tok::kw___is_unbounded_array)) + return false; + return T->isIncompleteArrayType(); case UTT_IsPointer: return T->isAnyPointerType(); case UTT_IsNullPointer: @@ -5567,8 +5606,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, } } -static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, - QualType RhsT, SourceLocation KeyLoc); +static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceInfo *Lhs, + const TypeSourceInfo *Rhs, SourceLocation KeyLoc); static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, @@ -5579,13 +5618,13 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind, return false; if (Kind <= UTT_Last) - return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]->getType()); + return EvaluateUnaryTypeTrait(S, Kind, KWLoc, Args[0]); // Evaluate ReferenceBindsToTemporary and ReferenceConstructsFromTemporary // alongside the IsConstructible traits to avoid duplication. if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary && Kind != BTT_ReferenceConstructsFromTemporary) - return EvaluateBinaryTypeTrait(S, Kind, Args[0]->getType(), - Args[1]->getType(), RParenLoc); + return EvaluateBinaryTypeTrait(S, Kind, Args[0], + Args[1], RParenLoc); switch (Kind) { case clang::BTT_ReferenceBindsToTemporary: @@ -5680,8 +5719,8 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind, if (U->isReferenceType()) return false; - QualType TPtr = S.Context.getPointerType(S.BuiltinRemoveReference(T, UnaryTransformType::RemoveCVRef, {})); - QualType UPtr = S.Context.getPointerType(S.BuiltinRemoveReference(U, UnaryTransformType::RemoveCVRef, {})); + TypeSourceInfo *TPtr = S.Context.CreateTypeSourceInfo(S.Context.getPointerType(S.BuiltinRemoveReference(T, UnaryTransformType::RemoveCVRef, {}))); + TypeSourceInfo *UPtr = S.Context.CreateTypeSourceInfo(S.Context.getPointerType(S.BuiltinRemoveReference(U, UnaryTransformType::RemoveCVRef, {}))); return EvaluateBinaryTypeTrait(S, TypeTrait::BTT_IsConvertibleTo, UPtr, TPtr, RParenLoc); } @@ -5815,8 +5854,11 @@ ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, return BuildTypeTrait(Kind, KWLoc, ConvertedArgs, RParenLoc); } -static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, - QualType RhsT, SourceLocation KeyLoc) { +static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceInfo *Lhs, + const TypeSourceInfo *Rhs, SourceLocation KeyLoc) { + QualType LhsT = Lhs->getType(); + QualType RhsT = Rhs->getType(); + assert(!LhsT->isDependentType() && !RhsT->isDependentType() && "Cannot evaluate traits of dependent types"); @@ -5841,7 +5883,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, return false; if (Self.RequireCompleteType( - KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) + Rhs->getTypeLoc().getBeginLoc(), RhsT, + diag::err_incomplete_type_used_in_type_trait_expr)) return false; return BaseInterface->isSuperClassOf(DerivedInterface); @@ -5864,8 +5907,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, // If Base and Derived are class types and are different types // (ignoring possible cv-qualifiers) then Derived shall be a // complete type. - if (Self.RequireCompleteType(KeyLoc, RhsT, - diag::err_incomplete_type_used_in_type_trait_expr)) + if (Self.RequireCompleteType( + Rhs->getTypeLoc().getBeginLoc(), RhsT, + diag::err_incomplete_type_used_in_type_trait_expr)) return false; return cast(rhsRecord->getDecl()) @@ -5917,7 +5961,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, return LhsT->isVoidType(); // A function definition requires a complete, non-abstract return type. - if (!Self.isCompleteType(KeyLoc, RhsT) || Self.isAbstractType(KeyLoc, RhsT)) + if (!Self.isCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT) || + Self.isAbstractType(Rhs->getTypeLoc().getBeginLoc(), RhsT)) return false; // Compute the result of add_rvalue_reference. @@ -5967,12 +6012,14 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, // For both, T and U shall be complete types, (possibly cv-qualified) // void, or arrays of unknown bound. if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() && - Self.RequireCompleteType(KeyLoc, LhsT, - diag::err_incomplete_type_used_in_type_trait_expr)) + Self.RequireCompleteType( + Lhs->getTypeLoc().getBeginLoc(), LhsT, + diag::err_incomplete_type_used_in_type_trait_expr)) return false; if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() && - Self.RequireCompleteType(KeyLoc, RhsT, - diag::err_incomplete_type_used_in_type_trait_expr)) + Self.RequireCompleteType( + Rhs->getTypeLoc().getBeginLoc(), RhsT, + diag::err_incomplete_type_used_in_type_trait_expr)) return false; // cv void is never assignable. @@ -6026,7 +6073,31 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, return false; } case BTT_IsLayoutCompatible: { + if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType()) + Self.RequireCompleteType(Lhs->getTypeLoc().getBeginLoc(), LhsT, + diag::err_incomplete_type); + if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType()) + Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT, + diag::err_incomplete_type); + + DiagnoseVLAInCXXTypeTrait(Self, Lhs, tok::kw___is_layout_compatible); + DiagnoseVLAInCXXTypeTrait(Self, Rhs, tok::kw___is_layout_compatible); + return Self.IsLayoutCompatible(LhsT, RhsT); + } + case BTT_IsPointerInterconvertibleBaseOf: { + if (LhsT->isStructureOrClassType() && RhsT->isStructureOrClassType() && + !Self.getASTContext().hasSameUnqualifiedType(LhsT, RhsT)) { + Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT, + diag::err_incomplete_type); + } + + DiagnoseVLAInCXXTypeTrait(Self, Lhs, + tok::kw___is_pointer_interconvertible_base_of); + DiagnoseVLAInCXXTypeTrait(Self, Rhs, + tok::kw___is_pointer_interconvertible_base_of); + + return Self.IsPointerInterconvertibleBaseOf(Lhs, Rhs); } default: llvm_unreachable("not a BTT"); } @@ -9122,10 +9193,9 @@ concepts::Requirement *Sema::ActOnSimpleRequirement(Expr *E) { /*ReturnTypeRequirement=*/{}); } -concepts::Requirement * -Sema::ActOnTypeRequirement(SourceLocation TypenameKWLoc, CXXScopeSpec &SS, - SourceLocation NameLoc, IdentifierInfo *TypeName, - TemplateIdAnnotation *TemplateId) { +concepts::Requirement *Sema::ActOnTypeRequirement( + SourceLocation TypenameKWLoc, CXXScopeSpec &SS, SourceLocation NameLoc, + const IdentifierInfo *TypeName, TemplateIdAnnotation *TemplateId) { assert(((!TypeName && TemplateId) || (TypeName && !TemplateId)) && "Exactly one of TypeName and TemplateId must be specified."); TypeSourceInfo *TSI = nullptr; diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index a8853f634c9cc95d2fbc92de20945cf860c49939..3148f0db6e20c86bd3632f241fe756ecfe3583cb 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -663,10 +663,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { } if (!ValueWithBytesObjCTypeMethod) { - IdentifierInfo *II[] = { - &Context.Idents.get("valueWithBytes"), - &Context.Idents.get("objCType") - }; + const IdentifierInfo *II[] = {&Context.Idents.get("valueWithBytes"), + &Context.Idents.get("objCType")}; Selector ValueWithBytesObjCType = Context.Selectors.getSelector(2, II); // Look for the appropriate method within NSValue. @@ -2155,13 +2153,12 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, return ExprError(); } -ExprResult Sema:: -ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, - IdentifierInfo &propertyName, - SourceLocation receiverNameLoc, - SourceLocation propertyNameLoc) { +ExprResult Sema::ActOnClassPropertyRefExpr(const IdentifierInfo &receiverName, + const IdentifierInfo &propertyName, + SourceLocation receiverNameLoc, + SourceLocation propertyNameLoc) { - IdentifierInfo *receiverNamePtr = &receiverName; + const IdentifierInfo *receiverNamePtr = &receiverName; ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr, receiverNameLoc); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index cf82cc9bccdf51cfe04ecab5f47e2277772953bc..bb9e37f18d370c38f0cd663e4fb22a9a8ed35df7 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -8,27 +8,205 @@ // This implements Semantic Analysis for HLSL constructs. //===----------------------------------------------------------------------===// +#include "clang/Sema/SemaHLSL.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/LLVM.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Sema/Sema.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/TargetParser/Triple.h" +#include using namespace clang; -Decl *Sema::ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer, +SemaHLSL::SemaHLSL(Sema &S) : SemaBase(S) {} + +Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer, SourceLocation KwLoc, IdentifierInfo *Ident, SourceLocation IdentLoc, SourceLocation LBrace) { // For anonymous namespace, take the location of the left brace. - DeclContext *LexicalParent = getCurLexicalContext(); + DeclContext *LexicalParent = SemaRef.getCurLexicalContext(); HLSLBufferDecl *Result = HLSLBufferDecl::Create( - Context, LexicalParent, CBuffer, KwLoc, Ident, IdentLoc, LBrace); + getASTContext(), LexicalParent, CBuffer, KwLoc, Ident, IdentLoc, LBrace); - PushOnScopeChains(Result, BufferScope); - PushDeclContext(BufferScope, Result); + SemaRef.PushOnScopeChains(Result, BufferScope); + SemaRef.PushDeclContext(BufferScope, Result); return Result; } -void Sema::ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace) { +void SemaHLSL::ActOnFinishBuffer(Decl *Dcl, SourceLocation RBrace) { auto *BufDecl = cast(Dcl); BufDecl->setRBraceLoc(RBrace); - PopDeclContext(); + SemaRef.PopDeclContext(); +} + +HLSLNumThreadsAttr *SemaHLSL::mergeNumThreadsAttr(Decl *D, + const AttributeCommonInfo &AL, + int X, int Y, int Z) { + if (HLSLNumThreadsAttr *NT = D->getAttr()) { + if (NT->getX() != X || NT->getY() != Y || NT->getZ() != Z) { + Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL; + Diag(AL.getLoc(), diag::note_conflicting_attribute); + } + return nullptr; + } + return ::new (getASTContext()) + HLSLNumThreadsAttr(getASTContext(), AL, X, Y, Z); +} + +HLSLShaderAttr * +SemaHLSL::mergeShaderAttr(Decl *D, const AttributeCommonInfo &AL, + HLSLShaderAttr::ShaderType ShaderType) { + if (HLSLShaderAttr *NT = D->getAttr()) { + if (NT->getType() != ShaderType) { + Diag(NT->getLocation(), diag::err_hlsl_attribute_param_mismatch) << AL; + Diag(AL.getLoc(), diag::note_conflicting_attribute); + } + return nullptr; + } + return HLSLShaderAttr::Create(getASTContext(), ShaderType, AL); +} + +HLSLParamModifierAttr * +SemaHLSL::mergeParamModifierAttr(Decl *D, const AttributeCommonInfo &AL, + HLSLParamModifierAttr::Spelling Spelling) { + // We can only merge an `in` attribute with an `out` attribute. All other + // combinations of duplicated attributes are ill-formed. + if (HLSLParamModifierAttr *PA = D->getAttr()) { + if ((PA->isIn() && Spelling == HLSLParamModifierAttr::Keyword_out) || + (PA->isOut() && Spelling == HLSLParamModifierAttr::Keyword_in)) { + D->dropAttr(); + SourceRange AdjustedRange = {PA->getLocation(), AL.getRange().getEnd()}; + return HLSLParamModifierAttr::Create( + getASTContext(), /*MergedSpelling=*/true, AdjustedRange, + HLSLParamModifierAttr::Keyword_inout); + } + Diag(AL.getLoc(), diag::err_hlsl_duplicate_parameter_modifier) << AL; + Diag(PA->getLocation(), diag::note_conflicting_attribute); + return nullptr; + } + return HLSLParamModifierAttr::Create(getASTContext(), AL); +} + +void SemaHLSL::ActOnTopLevelFunction(FunctionDecl *FD) { + auto &TargetInfo = getASTContext().getTargetInfo(); + + if (FD->getName() != TargetInfo.getTargetOpts().HLSLEntry) + return; + + StringRef Env = TargetInfo.getTriple().getEnvironmentName(); + HLSLShaderAttr::ShaderType ShaderType; + if (HLSLShaderAttr::ConvertStrToShaderType(Env, ShaderType)) { + if (const auto *Shader = FD->getAttr()) { + // The entry point is already annotated - check that it matches the + // triple. + if (Shader->getType() != ShaderType) { + Diag(Shader->getLocation(), diag::err_hlsl_entry_shader_attr_mismatch) + << Shader; + FD->setInvalidDecl(); + } + } else { + // Implicitly add the shader attribute if the entry function isn't + // explicitly annotated. + FD->addAttr(HLSLShaderAttr::CreateImplicit(getASTContext(), ShaderType, + FD->getBeginLoc())); + } + } else { + switch (TargetInfo.getTriple().getEnvironment()) { + case llvm::Triple::UnknownEnvironment: + case llvm::Triple::Library: + break; + default: + llvm_unreachable("Unhandled environment in triple"); + } + } +} + +void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) { + const auto *ShaderAttr = FD->getAttr(); + assert(ShaderAttr && "Entry point has no shader attribute"); + HLSLShaderAttr::ShaderType ST = ShaderAttr->getType(); + + switch (ST) { + case HLSLShaderAttr::Pixel: + case HLSLShaderAttr::Vertex: + case HLSLShaderAttr::Geometry: + case HLSLShaderAttr::Hull: + case HLSLShaderAttr::Domain: + case HLSLShaderAttr::RayGeneration: + case HLSLShaderAttr::Intersection: + case HLSLShaderAttr::AnyHit: + case HLSLShaderAttr::ClosestHit: + case HLSLShaderAttr::Miss: + case HLSLShaderAttr::Callable: + if (const auto *NT = FD->getAttr()) { + DiagnoseAttrStageMismatch(NT, ST, + {HLSLShaderAttr::Compute, + HLSLShaderAttr::Amplification, + HLSLShaderAttr::Mesh}); + FD->setInvalidDecl(); + } + break; + + case HLSLShaderAttr::Compute: + case HLSLShaderAttr::Amplification: + case HLSLShaderAttr::Mesh: + if (!FD->hasAttr()) { + Diag(FD->getLocation(), diag::err_hlsl_missing_numthreads) + << HLSLShaderAttr::ConvertShaderTypeToStr(ST); + FD->setInvalidDecl(); + } + break; + } + + for (ParmVarDecl *Param : FD->parameters()) { + if (const auto *AnnotationAttr = Param->getAttr()) { + CheckSemanticAnnotation(FD, Param, AnnotationAttr); + } else { + // FIXME: Handle struct parameters where annotations are on struct fields. + // See: https://github.com/llvm/llvm-project/issues/57875 + Diag(FD->getLocation(), diag::err_hlsl_missing_semantic_annotation); + Diag(Param->getLocation(), diag::note_previous_decl) << Param; + FD->setInvalidDecl(); + } + } + // FIXME: Verify return type semantic annotation. +} + +void SemaHLSL::CheckSemanticAnnotation( + FunctionDecl *EntryPoint, const Decl *Param, + const HLSLAnnotationAttr *AnnotationAttr) { + auto *ShaderAttr = EntryPoint->getAttr(); + assert(ShaderAttr && "Entry point has no shader attribute"); + HLSLShaderAttr::ShaderType ST = ShaderAttr->getType(); + + switch (AnnotationAttr->getKind()) { + case attr::HLSLSV_DispatchThreadID: + case attr::HLSLSV_GroupIndex: + if (ST == HLSLShaderAttr::Compute) + return; + DiagnoseAttrStageMismatch(AnnotationAttr, ST, {HLSLShaderAttr::Compute}); + break; + default: + llvm_unreachable("Unknown HLSLAnnotationAttr"); + } +} + +void SemaHLSL::DiagnoseAttrStageMismatch( + const Attr *A, HLSLShaderAttr::ShaderType Stage, + std::initializer_list AllowedStages) { + SmallVector StageStrings; + llvm::transform(AllowedStages, std::back_inserter(StageStrings), + [](HLSLShaderAttr::ShaderType ST) { + return StringRef( + HLSLShaderAttr::ConvertShaderTypeToStr(ST)); + }); + Diag(A->getLoc(), diag::err_hlsl_attr_unsupported_in_stage) + << A << HLSLShaderAttr::ConvertShaderTypeToStr(Stage) + << (AllowedStages.size() != 1) << join(StageStrings, ", "); } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index a75e9925a431468e6dfbeca50fae10c01dc07fe7..fb7a80ab02846cd078c64bccf7b3ba9f19360d1a 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -31,6 +31,7 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/FoldingSet.h" #include "llvm/ADT/PointerIntPair.h" +#include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringExtras.h" @@ -9762,12 +9763,15 @@ bool InitializationSequence::Diagnose(Sema &S, break; } case OR_Deleted: { - S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function) - << OnlyArg->getType() << DestType.getNonReferenceType() - << Args[0]->getSourceRange(); OverloadCandidateSet::iterator Best; OverloadingResult Ovl = FailedCandidateSet.BestViableFunction(S, Kind.getLocation(), Best); + + StringLiteral *Msg = Best->Function->getDeletedMessage(); + S.Diag(Kind.getLocation(), diag::err_typecheck_deleted_function) + << OnlyArg->getType() << DestType.getNonReferenceType() + << (Msg != nullptr) << (Msg ? Msg->getString() : StringRef()) + << Args[0]->getSourceRange(); if (Ovl == OR_Deleted) { S.NoteDeletedFunction(Best->Function); } else { @@ -10023,11 +10027,15 @@ bool InitializationSequence::Diagnose(Sema &S, // implicit. if (S.isImplicitlyDeleted(Best->Function)) S.Diag(Kind.getLocation(), diag::err_ovl_deleted_special_init) - << S.getSpecialMember(cast(Best->Function)) - << DestType << ArgsRange; - else - S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init) + << llvm::to_underlying( + S.getSpecialMember(cast(Best->Function))) << DestType << ArgsRange; + else { + StringLiteral *Msg = Best->Function->getDeletedMessage(); + S.Diag(Kind.getLocation(), diag::err_ovl_deleted_init) + << DestType << (Msg != nullptr) + << (Msg ? Msg->getString() : StringRef()) << ArgsRange; + } S.NoteDeletedFunction(Best->Function); break; @@ -11059,6 +11067,9 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( } case OR_Deleted: { + // FIXME: There are no tests for this diagnostic, and it doesn't seem + // like we ever get here; attempts to trigger this seem to yield a + // generic c'all to deleted function' diagnostic instead. Diag(Kind.getLocation(), diag::err_deduced_class_template_deleted) << TemplateName; NoteDeletedFunction(Best->Function); diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index 5b95bae567b7217af0a57f9e6d419acaf6e2ac12..35a51c6c2328dbc7469aea5c3a5ccbe363b75d27 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -9,17 +9,18 @@ // This file implements semantic analysis for C++ lambda expressions. // //===----------------------------------------------------------------------===// -#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/SemaLambda.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTLambda.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Sema/DeclSpec.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaInternal.h" -#include "clang/Sema/SemaLambda.h" #include "clang/Sema/Template.h" #include "llvm/ADT/STLExtras.h" #include @@ -1393,7 +1394,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // CUDA lambdas get implicit host and device attributes. if (getLangOpts().CUDA) - CUDASetLambdaAttrs(Method); + CUDA().SetLambdaAttrs(Method); // OpenMP lambdas might get assumumption attributes. if (LangOpts.OpenMP) @@ -2136,7 +2137,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, CaptureInits.push_back(Init.get()); if (LangOpts.CUDA) - CUDACheckLambdaCapture(CallOperator, From); + CUDA().CheckLambdaCapture(CallOperator, From); } Class->setCaptures(Context, Captures); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 38237ee578079db65a94f5af9614cd1d744f0a6f..d65f52b8efe81f21fae83fab72d9a431e05a9009 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -37,6 +37,7 @@ #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TypoCorrection.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/edit_distance.h" @@ -3341,21 +3342,20 @@ void Sema::LookupOverloadedOperatorName(OverloadedOperatorKind Op, Scope *S, Functions.append(Operators.begin(), Operators.end()); } -Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, - CXXSpecialMember SM, - bool ConstArg, - bool VolatileArg, - bool RValueThis, - bool ConstThis, - bool VolatileThis) { +Sema::SpecialMemberOverloadResult +Sema::LookupSpecialMember(CXXRecordDecl *RD, CXXSpecialMemberKind SM, + bool ConstArg, bool VolatileArg, bool RValueThis, + bool ConstThis, bool VolatileThis) { assert(CanDeclareSpecialMemberFunction(RD) && "doing special member lookup into record that isn't fully complete"); RD = RD->getDefinition(); if (RValueThis || ConstThis || VolatileThis) - assert((SM == CXXCopyAssignment || SM == CXXMoveAssignment) && + assert((SM == CXXSpecialMemberKind::CopyAssignment || + SM == CXXSpecialMemberKind::MoveAssignment) && "constructors and destructors always have unqualified lvalue this"); if (ConstArg || VolatileArg) - assert((SM != CXXDefaultConstructor && SM != CXXDestructor) && + assert((SM != CXXSpecialMemberKind::DefaultConstructor && + SM != CXXSpecialMemberKind::Destructor) && "parameter-less special members can't have qualified arguments"); // FIXME: Get the caller to pass in a location for the lookup. @@ -3363,7 +3363,7 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, llvm::FoldingSetNodeID ID; ID.AddPointer(RD); - ID.AddInteger(SM); + ID.AddInteger(llvm::to_underlying(SM)); ID.AddInteger(ConstArg); ID.AddInteger(VolatileArg); ID.AddInteger(RValueThis); @@ -3382,7 +3382,7 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, Result = new (Result) SpecialMemberOverloadResultEntry(ID); SpecialMemberCache.InsertNode(Result, InsertPoint); - if (SM == CXXDestructor) { + if (SM == CXXSpecialMemberKind::Destructor) { if (RD->needsImplicitDestructor()) { runWithSufficientStackSpace(RD->getLocation(), [&] { DeclareImplicitDestructor(RD); @@ -3406,7 +3406,7 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, QualType ArgType = CanTy; ExprValueKind VK = VK_LValue; - if (SM == CXXDefaultConstructor) { + if (SM == CXXSpecialMemberKind::DefaultConstructor) { Name = Context.DeclarationNames.getCXXConstructorName(CanTy); NumArgs = 0; if (RD->needsImplicitDefaultConstructor()) { @@ -3415,7 +3415,8 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, }); } } else { - if (SM == CXXCopyConstructor || SM == CXXMoveConstructor) { + if (SM == CXXSpecialMemberKind::CopyConstructor || + SM == CXXSpecialMemberKind::MoveConstructor) { Name = Context.DeclarationNames.getCXXConstructorName(CanTy); if (RD->needsImplicitCopyConstructor()) { runWithSufficientStackSpace(RD->getLocation(), [&] { @@ -3453,7 +3454,8 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, // Possibly an XValue is actually correct in the case of move, but // there is no semantic difference for class types in this restricted // case. - if (SM == CXXCopyConstructor || SM == CXXCopyAssignment) + if (SM == CXXSpecialMemberKind::CopyConstructor || + SM == CXXSpecialMemberKind::CopyAssignment) VK = VK_LValue; else VK = VK_PRValue; @@ -3461,7 +3463,7 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, OpaqueValueExpr FakeArg(LookupLoc, ArgType, VK); - if (SM != CXXDefaultConstructor) { + if (SM != CXXSpecialMemberKind::DefaultConstructor) { NumArgs = 1; Arg = &FakeArg; } @@ -3487,7 +3489,7 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, // type, rather than because there's some other declared constructor. // Every class has a copy/move constructor, copy/move assignment, and // destructor. - assert(SM == CXXDefaultConstructor && + assert(SM == CXXSpecialMemberKind::DefaultConstructor && "lookup for a constructor or assignment operator was empty"); Result->setMethod(nullptr); Result->setKind(SpecialMemberOverloadResult::NoMemberOrDeleted); @@ -3505,7 +3507,8 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, DeclAccessPair Cand = DeclAccessPair::make(CandDecl, AS_public); auto CtorInfo = getConstructorInfo(Cand); if (CXXMethodDecl *M = dyn_cast(Cand->getUnderlyingDecl())) { - if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) + if (SM == CXXSpecialMemberKind::CopyAssignment || + SM == CXXSpecialMemberKind::MoveAssignment) AddMethodCandidate(M, Cand, RD, ThisTy, Classification, llvm::ArrayRef(&Arg, NumArgs), OCS, true); else if (CtorInfo) @@ -3517,7 +3520,8 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, /*SuppressUserConversions*/ true); } else if (FunctionTemplateDecl *Tmpl = dyn_cast(Cand->getUnderlyingDecl())) { - if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) + if (SM == CXXSpecialMemberKind::CopyAssignment || + SM == CXXSpecialMemberKind::MoveAssignment) AddMethodTemplateCandidate(Tmpl, Cand, RD, nullptr, ThisTy, Classification, llvm::ArrayRef(&Arg, NumArgs), OCS, true); @@ -3563,8 +3567,8 @@ Sema::SpecialMemberOverloadResult Sema::LookupSpecialMember(CXXRecordDecl *RD, /// Look up the default constructor for the given class. CXXConstructorDecl *Sema::LookupDefaultConstructor(CXXRecordDecl *Class) { SpecialMemberOverloadResult Result = - LookupSpecialMember(Class, CXXDefaultConstructor, false, false, false, - false, false); + LookupSpecialMember(Class, CXXSpecialMemberKind::DefaultConstructor, + false, false, false, false, false); return cast_or_null(Result.getMethod()); } @@ -3574,9 +3578,9 @@ CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class, unsigned Quals) { assert(!(Quals & ~(Qualifiers::Const | Qualifiers::Volatile)) && "non-const, non-volatile qualifiers for copy ctor arg"); - SpecialMemberOverloadResult Result = - LookupSpecialMember(Class, CXXCopyConstructor, Quals & Qualifiers::Const, - Quals & Qualifiers::Volatile, false, false, false); + SpecialMemberOverloadResult Result = LookupSpecialMember( + Class, CXXSpecialMemberKind::CopyConstructor, Quals & Qualifiers::Const, + Quals & Qualifiers::Volatile, false, false, false); return cast_or_null(Result.getMethod()); } @@ -3584,9 +3588,9 @@ CXXConstructorDecl *Sema::LookupCopyingConstructor(CXXRecordDecl *Class, /// Look up the moving constructor for the given class. CXXConstructorDecl *Sema::LookupMovingConstructor(CXXRecordDecl *Class, unsigned Quals) { - SpecialMemberOverloadResult Result = - LookupSpecialMember(Class, CXXMoveConstructor, Quals & Qualifiers::Const, - Quals & Qualifiers::Volatile, false, false, false); + SpecialMemberOverloadResult Result = LookupSpecialMember( + Class, CXXSpecialMemberKind::MoveConstructor, Quals & Qualifiers::Const, + Quals & Qualifiers::Volatile, false, false, false); return cast_or_null(Result.getMethod()); } @@ -3618,11 +3622,10 @@ CXXMethodDecl *Sema::LookupCopyingAssignment(CXXRecordDecl *Class, "non-const, non-volatile qualifiers for copy assignment arg"); assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) && "non-const, non-volatile qualifiers for copy assignment this"); - SpecialMemberOverloadResult Result = - LookupSpecialMember(Class, CXXCopyAssignment, Quals & Qualifiers::Const, - Quals & Qualifiers::Volatile, RValueThis, - ThisQuals & Qualifiers::Const, - ThisQuals & Qualifiers::Volatile); + SpecialMemberOverloadResult Result = LookupSpecialMember( + Class, CXXSpecialMemberKind::CopyAssignment, Quals & Qualifiers::Const, + Quals & Qualifiers::Volatile, RValueThis, ThisQuals & Qualifiers::Const, + ThisQuals & Qualifiers::Volatile); return Result.getMethod(); } @@ -3634,11 +3637,10 @@ CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class, unsigned ThisQuals) { assert(!(ThisQuals & ~(Qualifiers::Const | Qualifiers::Volatile)) && "non-const, non-volatile qualifiers for copy assignment this"); - SpecialMemberOverloadResult Result = - LookupSpecialMember(Class, CXXMoveAssignment, Quals & Qualifiers::Const, - Quals & Qualifiers::Volatile, RValueThis, - ThisQuals & Qualifiers::Const, - ThisQuals & Qualifiers::Volatile); + SpecialMemberOverloadResult Result = LookupSpecialMember( + Class, CXXSpecialMemberKind::MoveAssignment, Quals & Qualifiers::Const, + Quals & Qualifiers::Volatile, RValueThis, ThisQuals & Qualifiers::Const, + ThisQuals & Qualifiers::Volatile); return Result.getMethod(); } @@ -3651,8 +3653,8 @@ CXXMethodDecl *Sema::LookupMovingAssignment(CXXRecordDecl *Class, /// \returns The destructor for this class. CXXDestructorDecl *Sema::LookupDestructor(CXXRecordDecl *Class) { return cast_or_null( - LookupSpecialMember(Class, CXXDestructor, false, false, false, false, - false) + LookupSpecialMember(Class, CXXSpecialMemberKind::Destructor, false, false, + false, false, false) .getMethod()); } diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index f9e1ad0121e2a2ab9579674b7170598a0280bc05..222a65a13dd0b2f9cbbcf4999352c81a0a43203a 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -419,7 +419,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl = cast(CurContext); // Diagnose if this property is already in continuation class. DeclContext *DC = CurContext; - IdentifierInfo *PropertyId = FD.D.getIdentifier(); + const IdentifierInfo *PropertyId = FD.D.getIdentifier(); ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface(); // We need to look in the @interface to see if the @property was @@ -571,7 +571,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, TypeSourceInfo *TInfo, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC){ - IdentifierInfo *PropertyId = FD.D.getIdentifier(); + const IdentifierInfo *PropertyId = FD.D.getIdentifier(); // Property defaults to 'assign' if it is readwrite, unless this is ARC // and the type is retainable. diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index 86ffa5ad74c130f2baec1a9e040de3977f0bdb6e..1249136c87650bfe0ad22e3eb5a52cc5b163c230 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -11,8 +11,8 @@ /// //===----------------------------------------------------------------------===// -#include "clang/AST/StmtOpenACC.h" #include "clang/Sema/SemaOpenACC.h" +#include "clang/AST/StmtOpenACC.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Sema/Sema.h" @@ -31,31 +31,150 @@ bool diagnoseConstructAppertainment(SemaOpenACC &S, OpenACCDirectiveKind K, case OpenACCDirectiveKind::Serial: case OpenACCDirectiveKind::Kernels: if (!IsStmt) - return S.SemaRef.Diag(StartLoc, diag::err_acc_construct_appertainment) - << K; + return S.Diag(StartLoc, diag::err_acc_construct_appertainment) << K; break; } return false; } + +bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind, + OpenACCClauseKind ClauseKind) { + switch (ClauseKind) { + // FIXME: For each clause as we implement them, we can add the + // 'legalization' list here. + case OpenACCClauseKind::Default: + switch (DirectiveKind) { + case OpenACCDirectiveKind::Parallel: + case OpenACCDirectiveKind::Serial: + case OpenACCDirectiveKind::Kernels: + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::KernelsLoop: + case OpenACCDirectiveKind::Data: + return true; + default: + return false; + } + case OpenACCClauseKind::If: + switch (DirectiveKind) { + case OpenACCDirectiveKind::Parallel: + case OpenACCDirectiveKind::Serial: + case OpenACCDirectiveKind::Kernels: + case OpenACCDirectiveKind::Data: + case OpenACCDirectiveKind::EnterData: + case OpenACCDirectiveKind::ExitData: + case OpenACCDirectiveKind::HostData: + case OpenACCDirectiveKind::Init: + case OpenACCDirectiveKind::Shutdown: + case OpenACCDirectiveKind::Set: + case OpenACCDirectiveKind::Update: + case OpenACCDirectiveKind::Wait: + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::KernelsLoop: + return true; + default: + return false; + } + default: + // Do nothing so we can go to the 'unimplemented' diagnostic instead. + return true; + } + llvm_unreachable("Invalid clause kind"); +} + +bool checkAlreadyHasClauseOfKind( + SemaOpenACC &S, ArrayRef ExistingClauses, + SemaOpenACC::OpenACCParsedClause &Clause) { + const auto *Itr = llvm::find_if(ExistingClauses, [&](const OpenACCClause *C) { + return C->getClauseKind() == Clause.getClauseKind(); + }); + if (Itr != ExistingClauses.end()) { + S.Diag(Clause.getBeginLoc(), diag::err_acc_duplicate_clause_disallowed) + << Clause.getDirectiveKind() << Clause.getClauseKind(); + S.Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here); + return true; + } + return false; +} + } // namespace -SemaOpenACC::SemaOpenACC(Sema &S) : SemaRef(S) {} - -ASTContext &SemaOpenACC::getASTContext() const { return SemaRef.Context; } -DiagnosticsEngine &SemaOpenACC::getDiagnostics() const { return SemaRef.Diags; } -const LangOptions &SemaOpenACC::getLangOpts() const { return SemaRef.LangOpts; } - -bool SemaOpenACC::ActOnClause(OpenACCClauseKind ClauseKind, - SourceLocation StartLoc) { - if (ClauseKind == OpenACCClauseKind::Invalid) - return false; - // For now just diagnose that it is unsupported and leave the parsing to do - // whatever it can do. This function will eventually need to start returning - // some sort of Clause AST type, but for now just return true/false based on - // success. - return SemaRef.Diag(StartLoc, diag::warn_acc_clause_unimplemented) - << ClauseKind; +SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {} + +OpenACCClause * +SemaOpenACC::ActOnClause(ArrayRef ExistingClauses, + OpenACCParsedClause &Clause) { + if (Clause.getClauseKind() == OpenACCClauseKind::Invalid) + return nullptr; + + // Diagnose that we don't support this clause on this directive. + if (!doesClauseApplyToDirective(Clause.getDirectiveKind(), + Clause.getClauseKind())) { + Diag(Clause.getBeginLoc(), diag::err_acc_clause_appertainment) + << Clause.getDirectiveKind() << Clause.getClauseKind(); + return nullptr; + } + + switch (Clause.getClauseKind()) { + case OpenACCClauseKind::Default: { + // Restrictions only properly implemented on 'compute' constructs, and + // 'compute' constructs are the only construct that can do anything with + // this yet, so skip/treat as unimplemented in this case. + if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Parallel && + Clause.getDirectiveKind() != OpenACCDirectiveKind::Serial && + Clause.getDirectiveKind() != OpenACCDirectiveKind::Kernels) + break; + + // Don't add an invalid clause to the AST. + if (Clause.getDefaultClauseKind() == OpenACCDefaultClauseKind::Invalid) + return nullptr; + + // OpenACC 3.3, Section 2.5.4: + // At most one 'default' clause may appear, and it must have a value of + // either 'none' or 'present'. + // Second half of the sentence is diagnosed during parsing. + if (checkAlreadyHasClauseOfKind(*this, ExistingClauses, Clause)) + return nullptr; + + return OpenACCDefaultClause::Create( + getASTContext(), Clause.getDefaultClauseKind(), Clause.getBeginLoc(), + Clause.getLParenLoc(), Clause.getEndLoc()); + } + + case OpenACCClauseKind::If: { + // Restrictions only properly implemented on 'compute' constructs, and + // 'compute' constructs are the only construct that can do anything with + // this yet, so skip/treat as unimplemented in this case. + if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Parallel && + Clause.getDirectiveKind() != OpenACCDirectiveKind::Serial && + Clause.getDirectiveKind() != OpenACCDirectiveKind::Kernels) + break; + + // There is no prose in the standard that says duplicates aren't allowed, + // but this diagnostic is present in other compilers, as well as makes + // sense. + if (checkAlreadyHasClauseOfKind(*this, ExistingClauses, Clause)) + return nullptr; + + // The parser has ensured that we have a proper condition expr, so there + // isn't really much to do here. + + // TODO OpenACC: When we implement 'self', this clauses causes us to + // 'ignore' the self clause, so we should implement a warning here. + return OpenACCIfClause::Create( + getASTContext(), Clause.getBeginLoc(), Clause.getLParenLoc(), + Clause.getConditionExpr(), Clause.getEndLoc()); + } + default: + break; + } + + Diag(Clause.getBeginLoc(), diag::warn_acc_clause_unimplemented) + << Clause.getClauseKind(); + return nullptr; } + void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K, SourceLocation StartLoc) { switch (K) { @@ -72,7 +191,7 @@ void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K, // here as these constructs do not take any arguments. break; default: - SemaRef.Diag(StartLoc, diag::warn_acc_construct_unimplemented) << K; + Diag(StartLoc, diag::warn_acc_construct_unimplemented) << K; break; } } @@ -85,6 +204,7 @@ bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K, StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, StmtResult AssocStmt) { switch (K) { default: @@ -96,8 +216,7 @@ StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K, case OpenACCDirectiveKind::Kernels: // TODO OpenACC: Add clauses to the construct here. return OpenACCComputeConstruct::Create( - getASTContext(), K, StartLoc, EndLoc, - /*Clauses=*/std::nullopt, + getASTContext(), K, StartLoc, EndLoc, Clauses, AssocStmt.isUsable() ? AssocStmt.get() : nullptr); } llvm_unreachable("Unhandled case in directive handling?"); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 0ba54a3a9cae3565bffc667b0b22e7ce3c825da1..e9efb4721133fe1f12181d9207b0035292f526e7 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -4478,6 +4478,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } + // For 'target teams loop', collect all captured regions so codegen can + // later decide the best IR to emit given the associated loop-nest. case OMPD_target_teams_loop: case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: { @@ -6135,6 +6137,79 @@ processImplicitMapsWithDefaultMappers(Sema &S, DSAStackTy *Stack, } } +namespace { +/// A 'teams loop' with a nested 'loop bind(parallel)' or generic function +/// call in the associated loop-nest cannot be a 'parallel for'. +class TeamsLoopChecker final : public ConstStmtVisitor { + Sema &SemaRef; + +public: + bool teamsLoopCanBeParallelFor() const { return TeamsLoopCanBeParallelFor; } + + // Is there a nested OpenMP loop bind(parallel) + void VisitOMPExecutableDirective(const OMPExecutableDirective *D) { + if (D->getDirectiveKind() == llvm::omp::Directive::OMPD_loop) { + if (const auto *C = D->getSingleClause()) + if (C->getBindKind() == OMPC_BIND_parallel) { + TeamsLoopCanBeParallelFor = false; + // No need to continue visiting any more + return; + } + } + for (const Stmt *Child : D->children()) + if (Child) + Visit(Child); + } + + void VisitCallExpr(const CallExpr *C) { + // Function calls inhibit parallel loop translation of 'target teams loop' + // unless the assume-no-nested-parallelism flag has been specified. + // OpenMP API runtime library calls do not inhibit parallel loop + // translation, regardless of the assume-no-nested-parallelism. + if (C) { + bool IsOpenMPAPI = false; + auto *FD = dyn_cast_or_null(C->getCalleeDecl()); + if (FD) { + std::string Name = FD->getNameInfo().getAsString(); + IsOpenMPAPI = Name.find("omp_") == 0; + } + TeamsLoopCanBeParallelFor = + IsOpenMPAPI || SemaRef.getLangOpts().OpenMPNoNestedParallelism; + if (!TeamsLoopCanBeParallelFor) + return; + } + for (const Stmt *Child : C->children()) + if (Child) + Visit(Child); + } + + void VisitCapturedStmt(const CapturedStmt *S) { + if (!S) + return; + Visit(S->getCapturedDecl()->getBody()); + } + + void VisitStmt(const Stmt *S) { + if (!S) + return; + for (const Stmt *Child : S->children()) + if (Child) + Visit(Child); + } + explicit TeamsLoopChecker(Sema &SemaRef) + : SemaRef(SemaRef), TeamsLoopCanBeParallelFor(true) {} + +private: + bool TeamsLoopCanBeParallelFor; +}; +} // namespace + +static bool teamsLoopCanBeParallelFor(Stmt *AStmt, Sema &SemaRef) { + TeamsLoopChecker Checker(SemaRef); + Checker.Visit(AStmt); + return Checker.teamsLoopCanBeParallelFor(); +} + bool Sema::mapLoopConstruct(llvm::SmallVector &ClausesWithoutBind, ArrayRef Clauses, OpenMPBindClauseKind &BindKind, @@ -7300,7 +7375,7 @@ void Sema::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope( llvm::omp::TraitProperty::implementation_extension_allow_templates)) return; - IdentifierInfo *BaseII = D.getIdentifier(); + const IdentifierInfo *BaseII = D.getIdentifier(); LookupResult Lookup(*this, DeclarationName(BaseII), D.getIdentifierLoc(), LookupOrdinaryName); LookupParsedName(Lookup, S, &D.getCXXScopeSpec()); @@ -10895,7 +10970,8 @@ StmtResult Sema::ActOnOpenMPTargetTeamsGenericLoopDirective( setFunctionHasBranchProtectedScope(); return OMPTargetTeamsGenericLoopDirective::Create( - Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, + teamsLoopCanBeParallelFor(AStmt, *this)); } StmtResult Sema::ActOnOpenMPParallelGenericLoopDirective( @@ -15645,6 +15721,12 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel) CaptureRegion = OMPD_target; break; + case OMPD_teams_loop: + case OMPD_target_teams_loop: + // For [target] teams loop, assume capture region is 'teams' so it's + // available for codegen later to use if/when necessary. + CaptureRegion = OMPD_teams; + break; case OMPD_target_teams_distribute_parallel_for_simd: if (OpenMPVersion >= 50 && (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)) { @@ -15652,7 +15734,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( break; } [[fallthrough]]; - case OMPD_target_teams_loop: case OMPD_target_teams_distribute_parallel_for: // If this clause applies to the nested 'parallel' region, capture within // the 'teams' region, otherwise do not capture. @@ -15775,7 +15856,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_loop: - case OMPD_teams_loop: case OMPD_teams: case OMPD_tile: case OMPD_unroll: diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 0c913bc700f4a1908cd3617d0c97c9bacb4438b7..675eb6ec05e78e283d873c70567e86fec5d61c5d 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -31,11 +31,13 @@ #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" +#include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" @@ -1548,10 +1550,10 @@ static bool IsOverloadOrOverrideImpl(Sema &SemaRef, FunctionDecl *New, // Don't allow overloading of destructors. (In theory we could, but it // would be a giant change to clang.) if (!isa(New)) { - Sema::CUDAFunctionTarget NewTarget = SemaRef.IdentifyCUDATarget(New), - OldTarget = SemaRef.IdentifyCUDATarget(Old); - if (NewTarget != Sema::CFT_InvalidTarget) { - assert((OldTarget != Sema::CFT_InvalidTarget) && + CUDAFunctionTarget NewTarget = SemaRef.CUDA().IdentifyTarget(New), + OldTarget = SemaRef.CUDA().IdentifyTarget(Old); + if (NewTarget != CUDAFunctionTarget::InvalidTarget) { + assert((OldTarget != CUDAFunctionTarget::InvalidTarget) && "Unexpected invalid target."); // Allow overloading of functions with same signature and different CUDA @@ -6354,6 +6356,7 @@ Sema::EvaluateConvertedConstantExpression(Expr *E, QualType T, APValue &Value, // by this point. assert(CE->getResultStorageKind() != ConstantResultStorageKind::None && "ConstantExpr has no value associated with it"); + (void)CE; } else { E = ConstantExpr::Create(Context, Result.get(), Value); } @@ -7098,7 +7101,7 @@ void Sema::AddOverloadCandidate( // inferred for the member automatically, based on the bases and fields of // the class. if (!(Caller && Caller->isImplicit()) && - !IsAllowedCUDACall(Caller, Function)) { + !CUDA().IsAllowedCall(Caller, Function)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_target; return; @@ -7616,7 +7619,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // (CUDA B.1): Check for invalid calls between targets. if (getLangOpts().CUDA) - if (!IsAllowedCUDACall(getCurFunctionDecl(/*AllowLambda=*/true), Method)) { + if (!CUDA().IsAllowedCall(getCurFunctionDecl(/*AllowLambda=*/true), + Method)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_target; return; @@ -10438,7 +10442,7 @@ bool clang::isBetterOverloadCandidate( // If other rules cannot determine which is better, CUDA preference will be // used again to determine which is better. // - // TODO: Currently IdentifyCUDAPreference does not return correct values + // TODO: Currently IdentifyPreference does not return correct values // for functions called in global variable initializers due to missing // correct context about device/host. Therefore we can only enforce this // rule when there is a caller. We should enforce this rule for functions @@ -10450,14 +10454,14 @@ bool clang::isBetterOverloadCandidate( if (S.getLangOpts().CUDA && Cand1.Function && Cand2.Function && S.getLangOpts().GPUExcludeWrongSideOverloads) { if (FunctionDecl *Caller = S.getCurFunctionDecl(/*AllowLambda=*/true)) { - bool IsCallerImplicitHD = Sema::isCUDAImplicitHostDeviceFunction(Caller); + bool IsCallerImplicitHD = SemaCUDA::isImplicitHostDeviceFunction(Caller); bool IsCand1ImplicitHD = - Sema::isCUDAImplicitHostDeviceFunction(Cand1.Function); + SemaCUDA::isImplicitHostDeviceFunction(Cand1.Function); bool IsCand2ImplicitHD = - Sema::isCUDAImplicitHostDeviceFunction(Cand2.Function); - auto P1 = S.IdentifyCUDAPreference(Caller, Cand1.Function); - auto P2 = S.IdentifyCUDAPreference(Caller, Cand2.Function); - assert(P1 != Sema::CFP_Never && P2 != Sema::CFP_Never); + SemaCUDA::isImplicitHostDeviceFunction(Cand2.Function); + auto P1 = S.CUDA().IdentifyPreference(Caller, Cand1.Function); + auto P2 = S.CUDA().IdentifyPreference(Caller, Cand2.Function); + assert(P1 != SemaCUDA::CFP_Never && P2 != SemaCUDA::CFP_Never); // The implicit HD function may be a function in a system header which // is forced by pragma. In device compilation, if we prefer HD candidates // over wrong-sided candidates, overloading resolution may change, which @@ -10471,8 +10475,8 @@ bool clang::isBetterOverloadCandidate( auto EmitThreshold = (S.getLangOpts().CUDAIsDevice && IsCallerImplicitHD && (IsCand1ImplicitHD || IsCand2ImplicitHD)) - ? Sema::CFP_Never - : Sema::CFP_WrongSide; + ? SemaCUDA::CFP_Never + : SemaCUDA::CFP_WrongSide; auto Cand1Emittable = P1 > EmitThreshold; auto Cand2Emittable = P2 > EmitThreshold; if (Cand1Emittable && !Cand2Emittable) @@ -10756,8 +10760,8 @@ bool clang::isBetterOverloadCandidate( // to determine which is better. if (S.getLangOpts().CUDA && Cand1.Function && Cand2.Function) { FunctionDecl *Caller = S.getCurFunctionDecl(/*AllowLambda=*/true); - return S.IdentifyCUDAPreference(Caller, Cand1.Function) > - S.IdentifyCUDAPreference(Caller, Cand2.Function); + return S.CUDA().IdentifyPreference(Caller, Cand1.Function) > + S.CUDA().IdentifyPreference(Caller, Cand2.Function); } // General member function overloading is handled above, so this only handles @@ -10889,15 +10893,15 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, llvm::any_of(Candidates, [&](OverloadCandidate *Cand) { // Check viable function only. return Cand->Viable && Cand->Function && - S.IdentifyCUDAPreference(Caller, Cand->Function) == - Sema::CFP_SameSide; + S.CUDA().IdentifyPreference(Caller, Cand->Function) == + SemaCUDA::CFP_SameSide; }); if (ContainsSameSideCandidate) { auto IsWrongSideCandidate = [&](OverloadCandidate *Cand) { // Check viable function only to avoid unnecessary data copying/moving. return Cand->Viable && Cand->Function && - S.IdentifyCUDAPreference(Caller, Cand->Function) == - Sema::CFP_WrongSide; + S.CUDA().IdentifyPreference(Caller, Cand->Function) == + SemaCUDA::CFP_WrongSide; }; llvm::erase_if(Candidates, IsWrongSideCandidate); } @@ -11936,8 +11940,8 @@ static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) { FunctionDecl *Caller = S.getCurFunctionDecl(/*AllowLambda=*/true); FunctionDecl *Callee = Cand->Function; - Sema::CUDAFunctionTarget CallerTarget = S.IdentifyCUDATarget(Caller), - CalleeTarget = S.IdentifyCUDATarget(Callee); + CUDAFunctionTarget CallerTarget = S.CUDA().IdentifyTarget(Caller), + CalleeTarget = S.CUDA().IdentifyTarget(Callee); std::string FnDesc; std::pair FnKindPair = @@ -11947,32 +11951,32 @@ static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) { S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target) << (unsigned)FnKindPair.first << (unsigned)ocs_non_template << FnDesc /* Ignored */ - << CalleeTarget << CallerTarget; + << llvm::to_underlying(CalleeTarget) << llvm::to_underlying(CallerTarget); // This could be an implicit constructor for which we could not infer the // target due to a collsion. Diagnose that case. CXXMethodDecl *Meth = dyn_cast(Callee); if (Meth != nullptr && Meth->isImplicit()) { CXXRecordDecl *ParentClass = Meth->getParent(); - Sema::CXXSpecialMember CSM; + CXXSpecialMemberKind CSM; switch (FnKindPair.first) { default: return; case oc_implicit_default_constructor: - CSM = Sema::CXXDefaultConstructor; + CSM = CXXSpecialMemberKind::DefaultConstructor; break; case oc_implicit_copy_constructor: - CSM = Sema::CXXCopyConstructor; + CSM = CXXSpecialMemberKind::CopyConstructor; break; case oc_implicit_move_constructor: - CSM = Sema::CXXMoveConstructor; + CSM = CXXSpecialMemberKind::MoveConstructor; break; case oc_implicit_copy_assignment: - CSM = Sema::CXXCopyAssignment; + CSM = CXXSpecialMemberKind::CopyAssignment; break; case oc_implicit_move_assignment: - CSM = Sema::CXXMoveAssignment; + CSM = CXXSpecialMemberKind::MoveAssignment; break; }; @@ -11984,9 +11988,9 @@ static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) { } } - S.inferCUDATargetForImplicitSpecialMember(ParentClass, CSM, Meth, - /* ConstRHS */ ConstRHS, - /* Diagnose */ true); + S.CUDA().inferTargetForImplicitSpecialMember(ParentClass, CSM, Meth, + /* ConstRHS */ ConstRHS, + /* Diagnose */ true); } } @@ -13058,7 +13062,7 @@ private: if (S.getLangOpts().CUDA) { FunctionDecl *Caller = S.getCurFunctionDecl(/*AllowLambda=*/true); if (!(Caller && Caller->isImplicit()) && - !S.IsAllowedCUDACall(Caller, FunDecl)) + !S.CUDA().IsAllowedCall(Caller, FunDecl)) return false; } if (FunDecl->isMultiVersion()) { @@ -13178,8 +13182,8 @@ private: } void EliminateSuboptimalCudaMatches() { - S.EraseUnwantedCUDAMatches(S.getCurFunctionDecl(/*AllowLambda=*/true), - Matches); + S.CUDA().EraseUnwantedMatches(S.getCurFunctionDecl(/*AllowLambda=*/true), + Matches); } public: @@ -13333,8 +13337,8 @@ Sema::resolveAddressOfSingleOverloadCandidate(Expr *E, DeclAccessPair &Pair) { // Return positive for better, negative for worse, 0 for equal preference. auto CheckCUDAPreference = [&](FunctionDecl *FD1, FunctionDecl *FD2) { FunctionDecl *Caller = getCurFunctionDecl(/*AllowLambda=*/true); - return static_cast(IdentifyCUDAPreference(Caller, FD1)) - - static_cast(IdentifyCUDAPreference(Caller, FD2)); + return static_cast(CUDA().IdentifyPreference(Caller, FD1)) - + static_cast(CUDA().IdentifyPreference(Caller, FD2)); }; auto CheckMoreConstrained = [&](FunctionDecl *FD1, @@ -14167,15 +14171,13 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, break; case OR_Deleted: { - CandidateSet->NoteCandidates( - PartialDiagnosticAt(Fn->getBeginLoc(), - SemaRef.PDiag(diag::err_ovl_deleted_call) - << ULE->getName() << Fn->getSourceRange()), - SemaRef, OCD_AllCandidates, Args); + FunctionDecl *FDecl = (*Best)->Function; + SemaRef.DiagnoseUseOfDeletedFunction(Fn->getBeginLoc(), + Fn->getSourceRange(), ULE->getName(), + *CandidateSet, FDecl, Args); // We emitted an error for the unavailable/deleted function call but keep // the call in the AST. - FunctionDecl *FDecl = (*Best)->Function; ExprResult Res = SemaRef.FixOverloadedFunctionReference(Fn, (*Best)->FoundDecl, FDecl); if (Res.isInvalid()) @@ -14527,20 +14529,24 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); - case OR_Deleted: + case OR_Deleted: { // CreateOverloadedUnaryOp fills the first element of ArgsArray with the // object whose method was called. Later in NoteCandidates size of ArgsArray // is passed further and it eventually ends up compared to number of // function candidate parameters which never includes the object parameter, // so slice ArgsArray to make sure apples are compared to apples. + StringLiteral *Msg = Best->Function->getDeletedMessage(); CandidateSet.NoteCandidates( PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_deleted_oper) << UnaryOperator::getOpcodeStr(Opc) + << (Msg != nullptr) + << (Msg ? Msg->getString() : StringRef()) << Input->getSourceRange()), *this, OCD_AllCandidates, ArgsArray.drop_front(), UnaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); } + } // Either we found no viable overloaded operator or we matched a // built-in operator. In either case, fall through to trying to @@ -15057,13 +15063,14 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, OpLoc); return ExprError(); - case OR_Deleted: + case OR_Deleted: { if (isImplicitlyDeleted(Best->Function)) { FunctionDecl *DeletedFD = Best->Function; DefaultedFunctionKind DFK = getDefaultedFunctionKind(DeletedFD); if (DFK.isSpecialMember()) { Diag(OpLoc, diag::err_ovl_deleted_special_oper) - << Args[0]->getType() << DFK.asSpecialMember(); + << Args[0]->getType() + << llvm::to_underlying(DFK.asSpecialMember()); } else { assert(DFK.isComparison()); Diag(OpLoc, diag::err_ovl_deleted_comparison) @@ -15075,16 +15082,20 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, NoteDeletedFunction(DeletedFD); return ExprError(); } + + StringLiteral *Msg = Best->Function->getDeletedMessage(); CandidateSet.NoteCandidates( PartialDiagnosticAt( - OpLoc, PDiag(diag::err_ovl_deleted_oper) - << getOperatorSpelling(Best->Function->getDeclName() - .getCXXOverloadedOperator()) - << Args[0]->getSourceRange() - << Args[1]->getSourceRange()), + OpLoc, + PDiag(diag::err_ovl_deleted_oper) + << getOperatorSpelling(Best->Function->getDeclName() + .getCXXOverloadedOperator()) + << (Msg != nullptr) << (Msg ? Msg->getString() : StringRef()) + << Args[0]->getSourceRange() << Args[1]->getSourceRange()), *this, OCD_AllCandidates, Args, BinaryOperator::getOpcodeStr(Opc), OpLoc); return ExprError(); + } } // We matched a built-in operator; build it. @@ -15396,14 +15407,18 @@ ExprResult Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, } return ExprError(); - case OR_Deleted: + case OR_Deleted: { + StringLiteral *Msg = Best->Function->getDeletedMessage(); CandidateSet.NoteCandidates( - PartialDiagnosticAt(LLoc, PDiag(diag::err_ovl_deleted_oper) - << "[]" << Args[0]->getSourceRange() - << Range), + PartialDiagnosticAt(LLoc, + PDiag(diag::err_ovl_deleted_oper) + << "[]" << (Msg != nullptr) + << (Msg ? Msg->getString() : StringRef()) + << Args[0]->getSourceRange() << Range), *this, OCD_AllCandidates, Args, "[]", LLoc); return ExprError(); } + } // We matched a built-in operator; build it. return CreateBuiltinArraySubscriptExpr(Args[0], LLoc, Args[1], RLoc); @@ -15617,11 +15632,9 @@ ExprResult Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, *this, OCD_AmbiguousCandidates, Args); break; case OR_Deleted: - CandidateSet.NoteCandidates( - PartialDiagnosticAt(UnresExpr->getMemberLoc(), - PDiag(diag::err_ovl_deleted_member_call) - << DeclName << MemExprE->getSourceRange()), - *this, OCD_AllCandidates, Args); + DiagnoseUseOfDeletedFunction( + UnresExpr->getMemberLoc(), MemExprE->getSourceRange(), DeclName, + CandidateSet, Best->Function, Args, /*IsMember=*/true); break; } // Overload resolution fails, try to recover. @@ -15885,15 +15898,21 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, *this, OCD_AmbiguousCandidates, Args); break; - case OR_Deleted: + case OR_Deleted: { + // FIXME: Is this diagnostic here really necessary? It seems that + // 1. we don't have any tests for this diagnostic, and + // 2. we already issue err_deleted_function_use for this later on anyway. + StringLiteral *Msg = Best->Function->getDeletedMessage(); CandidateSet.NoteCandidates( PartialDiagnosticAt(Object.get()->getBeginLoc(), PDiag(diag::err_ovl_deleted_object_call) - << Object.get()->getType() + << Object.get()->getType() << (Msg != nullptr) + << (Msg ? Msg->getString() : StringRef()) << Object.get()->getSourceRange()), *this, OCD_AllCandidates, Args); break; } + } if (Best == CandidateSet.end()) return true; @@ -16092,13 +16111,17 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, *this, OCD_AmbiguousCandidates, Base); return ExprError(); - case OR_Deleted: + case OR_Deleted: { + StringLiteral *Msg = Best->Function->getDeletedMessage(); CandidateSet.NoteCandidates( PartialDiagnosticAt(OpLoc, PDiag(diag::err_ovl_deleted_oper) - << "->" << Base->getSourceRange()), + << "->" << (Msg != nullptr) + << (Msg ? Msg->getString() : StringRef()) + << Base->getSourceRange()), *this, OCD_AllCandidates, Base); return ExprError(); } + } CheckMemberOperatorAccess(OpLoc, Base, nullptr, Best->FoundDecl); @@ -16512,3 +16535,17 @@ bool clang::shouldEnforceArgLimit(bool PartialOverloading, return false; return true; } + +void Sema::DiagnoseUseOfDeletedFunction(SourceLocation Loc, SourceRange Range, + DeclarationName Name, + OverloadCandidateSet &CandidateSet, + FunctionDecl *Fn, MultiExprArg Args, + bool IsMember) { + StringLiteral *Msg = Fn->getDeletedMessage(); + CandidateSet.NoteCandidates( + PartialDiagnosticAt(Loc, PDiag(diag::err_ovl_deleted_call) + << IsMember << Name << (Msg != nullptr) + << (Msg ? Msg->getString() : StringRef()) + << Range), + *this, OCD_AllCandidates, Args); +} diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index 528c261c4a297f5b4ca6a530be5be741062f4dac..82774760b34d440a1a014129845a9c480091a165 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -613,9 +613,9 @@ bool ObjCPropertyOpBuilder::findGetter() { // Must build the getter selector the hard way. ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter(); assert(setter && "both setter and getter are null - cannot happen"); - IdentifierInfo *setterName = - setter->getSelector().getIdentifierInfoForSlot(0); - IdentifierInfo *getterName = + const IdentifierInfo *setterName = + setter->getSelector().getIdentifierInfoForSlot(0); + const IdentifierInfo *getterName = &S.Context.Idents.get(setterName->getName().substr(3)); GetterSelector = S.PP.getSelectorTable().getNullarySelector(getterName); @@ -640,9 +640,9 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) { SetterSelector = setter->getSelector(); return true; } else { - IdentifierInfo *getterName = - RefExpr->getImplicitPropertyGetter()->getSelector() - .getIdentifierInfoForSlot(0); + const IdentifierInfo *getterName = RefExpr->getImplicitPropertyGetter() + ->getSelector() + .getIdentifierInfoForSlot(0); SetterSelector = SelectorTable::constructSetterSelector(S.PP.getIdentifierTable(), S.PP.getSelectorTable(), @@ -667,7 +667,8 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) { front = isLowercase(front) ? toUppercase(front) : toLowercase(front); SmallString<100> PropertyName = thisPropertyName; PropertyName[0] = front; - IdentifierInfo *AltMember = &S.PP.getIdentifierTable().get(PropertyName); + const IdentifierInfo *AltMember = + &S.PP.getIdentifierTable().get(PropertyName); if (ObjCPropertyDecl *prop1 = IFace->FindPropertyDeclaration( AltMember, prop->getQueryKind())) if (prop != prop1 && (prop1->getSetterMethodDecl() == setter)) { @@ -1126,9 +1127,8 @@ static void CheckKeyForObjCARCConversion(Sema &S, QualType ContainerT, return; // dictionary subscripting. // - (id)objectForKeyedSubscript:(id)key; - IdentifierInfo *KeyIdents[] = { - &S.Context.Idents.get("objectForKeyedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &S.Context.Idents.get("objectForKeyedSubscript")}; Selector GetterSelector = S.Context.Selectors.getSelector(1, KeyIdents); ObjCMethodDecl *Getter = S.LookupMethodInObjectType(GetterSelector, ContainerT, true /*instance*/); @@ -1169,16 +1169,14 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { if (!arrayRef) { // dictionary subscripting. // - (id)objectForKeyedSubscript:(id)key; - IdentifierInfo *KeyIdents[] = { - &S.Context.Idents.get("objectForKeyedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &S.Context.Idents.get("objectForKeyedSubscript")}; AtIndexGetterSelector = S.Context.Selectors.getSelector(1, KeyIdents); } else { // - (id)objectAtIndexedSubscript:(size_t)index; - IdentifierInfo *KeyIdents[] = { - &S.Context.Idents.get("objectAtIndexedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &S.Context.Idents.get("objectAtIndexedSubscript")}; AtIndexGetterSelector = S.Context.Selectors.getSelector(1, KeyIdents); } @@ -1274,18 +1272,16 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { if (!arrayRef) { // dictionary subscripting. // - (void)setObject:(id)object forKeyedSubscript:(id)key; - IdentifierInfo *KeyIdents[] = { - &S.Context.Idents.get("setObject"), - &S.Context.Idents.get("forKeyedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &S.Context.Idents.get("setObject"), + &S.Context.Idents.get("forKeyedSubscript")}; AtIndexSetterSelector = S.Context.Selectors.getSelector(2, KeyIdents); } else { // - (void)setObject:(id)object atIndexedSubscript:(NSInteger)index; - IdentifierInfo *KeyIdents[] = { - &S.Context.Idents.get("setObject"), - &S.Context.Idents.get("atIndexedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &S.Context.Idents.get("setObject"), + &S.Context.Idents.get("atIndexedSubscript")}; AtIndexSetterSelector = S.Context.Selectors.getSelector(2, KeyIdents); } AtIndexSetter = S.LookupMethodInObjectType(AtIndexSetterSelector, ResultType, @@ -1474,7 +1470,7 @@ ExprResult MSPropertyOpBuilder::buildGet() { } UnqualifiedId GetterName; - IdentifierInfo *II = RefExpr->getPropertyDecl()->getGetterId(); + const IdentifierInfo *II = RefExpr->getPropertyDecl()->getGetterId(); GetterName.setIdentifier(II, RefExpr->getMemberLoc()); CXXScopeSpec SS; SS.Adopt(RefExpr->getQualifierLoc()); @@ -1503,7 +1499,7 @@ ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl, } UnqualifiedId SetterName; - IdentifierInfo *II = RefExpr->getPropertyDecl()->getSetterId(); + const IdentifierInfo *II = RefExpr->getPropertyDecl()->getSetterId(); SetterName.setIdentifier(II, RefExpr->getMemberLoc()); CXXScopeSpec SS; SS.Adopt(RefExpr->getQualifierLoc()); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index 18ebaa13346a443ee9bbff8346b2dbacc94271cf..18f6d8f03047376d55d760bd94b174d08a42f2d1 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -8,6 +8,7 @@ // This implements Semantic Analysis for SYCL constructs. //===----------------------------------------------------------------------===// +#include "clang/Sema/SemaSYCL.h" #include "clang/AST/Mangle.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" @@ -18,28 +19,30 @@ using namespace clang; // SYCL device specific diagnostics implementation // ----------------------------------------------------------------------------- -Sema::SemaDiagnosticBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc, +SemaSYCL::SemaSYCL(Sema &S) : SemaBase(S) {} + +Sema::SemaDiagnosticBuilder SemaSYCL::DiagIfDeviceCode(SourceLocation Loc, unsigned DiagID) { assert(getLangOpts().SYCLIsDevice && "Should only be called during SYCL compilation"); - FunctionDecl *FD = dyn_cast(getCurLexicalContext()); + FunctionDecl *FD = dyn_cast(SemaRef.getCurLexicalContext()); SemaDiagnosticBuilder::Kind DiagKind = [this, FD] { if (!FD) return SemaDiagnosticBuilder::K_Nop; - if (getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted) + if (SemaRef.getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted) return SemaDiagnosticBuilder::K_ImmediateWithCallStack; return SemaDiagnosticBuilder::K_Deferred; }(); - return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, *this); + return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, SemaRef); } -static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) { - if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(Ty)) +static bool isZeroSizedArray(SemaSYCL &S, QualType Ty) { + if (const auto *CAT = S.getASTContext().getAsConstantArrayType(Ty)) return CAT->isZeroSize(); return false; } -void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt, +void SemaSYCL::deepTypeCheckForDevice(SourceLocation UsedAt, llvm::DenseSet Visited, ValueDecl *DeclToCheck) { assert(getLangOpts().SYCLIsDevice && @@ -51,18 +54,18 @@ void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt, auto Check = [&](QualType TypeToCheck, const ValueDecl *D) { bool ErrorFound = false; if (isZeroSizedArray(*this, TypeToCheck)) { - SYCLDiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1; + DiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1; ErrorFound = true; } // Checks for other types can also be done here. if (ErrorFound) { if (NeedToEmitNotes) { if (auto *FD = dyn_cast(D)) - SYCLDiagIfDeviceCode(FD->getLocation(), - diag::note_illegal_field_declared_here) + DiagIfDeviceCode(FD->getLocation(), + diag::note_illegal_field_declared_here) << FD->getType()->isPointerType() << FD->getType(); else - SYCLDiagIfDeviceCode(D->getLocation(), diag::note_declared_at); + DiagIfDeviceCode(D->getLocation(), diag::note_declared_at); } } @@ -93,8 +96,8 @@ void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt, auto EmitHistory = [&]() { // The first element is always nullptr. for (uint64_t Index = 1; Index < History.size(); ++Index) { - SYCLDiagIfDeviceCode(History[Index]->getLocation(), - diag::note_within_field_of_type) + DiagIfDeviceCode(History[Index]->getLocation(), + diag::note_within_field_of_type) << History[Index]->getType(); } }; @@ -130,3 +133,26 @@ void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt, } } while (!StackForRecursion.empty()); } + +ExprResult SemaSYCL::BuildUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + TypeSourceInfo *TSI) { + return SYCLUniqueStableNameExpr::Create(getASTContext(), OpLoc, LParen, + RParen, TSI); +} + +ExprResult SemaSYCL::ActOnUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + ParsedType ParsedTy) { + TypeSourceInfo *TSI = nullptr; + QualType Ty = SemaRef.GetTypeFromParser(ParsedTy, &TSI); + + if (Ty.isNull()) + return ExprError(); + if (!TSI) + TSI = getASTContext().getTrivialTypeSourceInfo(Ty, LParen); + + return BuildUniqueStableNameExpr(OpLoc, LParen, RParen, TSI); +} diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index e72397adec24fb9e505ad39e4ccc54937e421d6d..d28c24cfdfd33c5091be1b56a7c4dae6136e94f9 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -33,10 +33,12 @@ #include "clang/Sema/Ownership.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/STLForwardCompat.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" @@ -2275,11 +2277,9 @@ Sema::CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) { // Otherwise, if we have any useful type information, check that // the type declares the appropriate method. } else if (iface || !objectType->qual_empty()) { - IdentifierInfo *selectorIdents[] = { - &Context.Idents.get("countByEnumeratingWithState"), - &Context.Idents.get("objects"), - &Context.Idents.get("count") - }; + const IdentifierInfo *selectorIdents[] = { + &Context.Idents.get("countByEnumeratingWithState"), + &Context.Idents.get("objects"), &Context.Idents.get("count")}; Selector selector = Context.Selectors.getSelector(3, &selectorIdents[0]); ObjCMethodDecl *method = nullptr; @@ -4575,8 +4575,8 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, // Exceptions aren't allowed in CUDA device code. if (getLangOpts().CUDA) - CUDADiagIfDeviceCode(TryLoc, diag::err_cuda_device_exceptions) - << "try" << CurrentCUDATarget(); + CUDA().DiagIfDeviceCode(TryLoc, diag::err_cuda_device_exceptions) + << "try" << llvm::to_underlying(CUDA().CurrentTarget()); if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope()) Diag(TryLoc, diag::err_omp_simd_region_cannot_use_stmt) << "try"; diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 73030cf4b72203bbab3a94ef6cdf61d8273bcdfc..95171359f0ab174ddf9be131baa65a3acc6cef84 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -33,6 +33,7 @@ #include "clang/Sema/Overload.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/SemaCUDA.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" @@ -970,7 +971,7 @@ void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn, static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S, SourceLocation Loc, - IdentifierInfo *Name) { + const IdentifierInfo *Name) { NamedDecl *PrevDecl = SemaRef.LookupSingleName( S, Name, Loc, Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) @@ -1578,7 +1579,7 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, CheckFunctionOrTemplateParamDeclarator(S, D); - IdentifierInfo *ParamName = D.getIdentifier(); + const IdentifierInfo *ParamName = D.getIdentifier(); bool IsParameterPack = D.hasEllipsis(); NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create( Context, Context.getTranslationUnitDecl(), D.getBeginLoc(), @@ -1630,26 +1631,20 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, /// ActOnTemplateTemplateParameter - Called when a C++ template template /// parameter (e.g. T in template