@@ -91,7 +91,7 @@ function add-dependencies | |||
echo "${project}" | echo "${project}" | ||
case ${project} in | case ${project} in | ||
bolt) | bolt) | ||
- for p in lld llvm; do | + for p in clang lld llvm; do | ||
echo $p | echo $p | ||
done | done | ||
;; | ;; |
@@ -48,7 +48,6 @@ cmake -S "${MONOREPO_ROOT | |||
-D LLVM_LIT_ARGS="-v --xunit-xml-output ${BUILD_DIR}/test-results.xml --timeout=1200 --time-tests" \ | -D LLVM_LIT_ARGS="-v --xunit-xml-output ${BUILD_DIR}/test-results.xml --timeout=1200 --time-tests" \ | ||
-D LLVM_ENABLE_LLD=ON \ | -D LLVM_ENABLE_LLD=ON \ | ||
-D CMAKE_CXX_FLAGS=-gmlt \ | -D CMAKE_CXX_FLAGS=-gmlt \ | ||
- -D BOLT_CLANG_EXE=/usr/bin/clang \ | |||
-D LLVM_CCACHE_BUIL | -D LLVM_CCACHE_BUIL | ||
-D MLIR_ENABLE_BIND | -D MLIR_ENABLE_BIND | ||
@@ -35,6 +35,10 @@ | |||
clang/lib/AST/Interp/ @tbaederr | clang/lib/AST/Interp/ @tbaederr | ||
clang/test/AST/Interp/ @tbaederr | clang/test/AST/Interp/ @tbaederr | ||
+/clang/include/clang/CIR @lanza @bcardosolopes | |||
+/clang/lib/CIR @lanza @bcardosolopes | |||
+/clang/tools/cir-* @lanza @bcardosolopes | |||
+ | |||
/lldb/ @JDevlieghere | /lldb/ @JDevlieghere | ||
# MLIR Interfaces. | # MLIR Interfaces. |
@@ -1,3 +1,6 @@ | |||
+BOLT: | |||
+ - bolt/**/* | |||
+ | |||
ClangIR: | ClangIR: | ||
- clang/include/clang/CIR/**/* | - clang/include/clang/CIR/**/* | ||
- clang/lib/CIR/**/* | - clang/lib/CIR/**/* | ||
@@ -467,6 +470,7 @@ backend:m68k: | |||
libc++: | libc++: | ||
- libcxx/** | - libcxx/** | ||
+ - .github/workflows/libcxx-* | |||
libc++abi: | libc++abi: | ||
- libcxxabi/** | - libcxxabi/** |
@@ -400,8 +400,7 @@ public: | |||
/// dyno stats categories. | /// dyno stats categories. | ||
class PrintProgramStat | class PrintProgramStat | ||
public: | public: | ||
- explicit PrintProgramStats( | + explicit PrintProgramStats() : BinaryFunctionPass(false) {} | ||
- : BinaryFunctionPa | |||
const char *getName() const override { return "print-stats"; } | const char *getName() const override { return "print-stats"; } | ||
bool shouldPrint(const BinaryFunction &) const override { return false; } | bool shouldPrint(const BinaryFunction &) const override { return false; } |
@@ -198,14 +198,8 @@ private: | |||
/// A trace is region of code executed between two LBR entries supplied in | /// A trace is region of code executed between two LBR entries supplied in | ||
/// execution order. | /// execution order. | ||
/// | /// | ||
- /// Return true if the trace is valid, false otherwise. | |||
- bool | |||
- recordTrace(BinaryFunction &BF, const LBREntry &First, const LBREntry &Second, | |||
- uint64_t Count, | |||
- SmallVector<std::pair<uint64_t, uint64_t>, 16> &Branches) const; | |||
- | |||
/// Return a vector of offsets corresponding to a trace in a function | /// Return a vector of offsets corresponding to a trace in a function | ||
- /// (see recordTrace() above). | + /// if the trace is valid, std::nullopt otherwise. | ||
std::optional<SmallVector<std::pair<uint64_t, uint64_t>, 16>> | std::optional<SmallVector<std::pair<uint64_t, uint64_t>, 16>> | ||
getFallthroughsI | getFallthroughsI | ||
const LBREntry &Second, uint64_t Count = 1) const; | const LBREntry &Second, uint64_t Count = 1) const; |
@@ -422,10 +422,18 @@ private: | |||
/// Section name used for extra BOLT code in addition to .text. | /// Section name used for extra BOLT code in addition to .text. | ||
static StringRef getBOLTTextSecti | static StringRef getBOLTTextSecti | ||
+ /// Symbol markers for BOLT reserved area. | |||
+ static StringRef getBOLTReservedS | |||
+ static StringRef getBOLTReservedE | |||
+ | |||
/// Common section names. | /// Common section names. | ||
static StringRef getEHFrameSectio | static StringRef getEHFrameSectio | ||
+ static StringRef getEHFrameHdrSec | |||
static StringRef getRelaDynSectio | static StringRef getRelaDynSectio | ||
+ /// FILE symbol name used for local fragments of global functions. | |||
+ static StringRef getBOLTFileSymbo | |||
+ | |||
/// An instance of the input binary we are processing, externally owned. | /// An instance of the input binary we are processing, externally owned. | ||
llvm::object::ELFObjectFileBas | llvm::object::ELFObjectFileBas | ||
@@ -490,6 +498,9 @@ private: | |||
/// Store all non-zero symbols in this map for a quick address lookup. | /// Store all non-zero symbols in this map for a quick address lookup. | ||
std::map<uint64_t, llvm::object::SymbolRef> FileSymRefs; | std::map<uint64_t, llvm::object::SymbolRef> FileSymRefs; | ||
+ /// FILE symbols used for disambiguating split function parents. | |||
+ std::vector<ELFSymbolRef> FileSymbols; | |||
+ | |||
std::unique_ptr<DWARFRewriter> DebugInfoRewrite | std::unique_ptr<DWARFRewriter> DebugInfoRewrite | ||
std::unique_ptr<BoltAddressTrans | std::unique_ptr<BoltAddressTrans |
@@ -28,10 +28,23 @@ class NameResolver { | |||
static constexpr char Sep = '/'; | static constexpr char Sep = '/'; | ||
public: | public: | ||
- /// Return | + /// Return the number of uniquified versions of a given \p Name. | ||
+ uint64_t getUniquifiedNam | |||
+ if (Counters.contains(Name)) | |||
+ return Counters.at(Name); | |||
+ return 0; | |||
+ } | |||
+ | |||
+ /// Return unique version of the \p Name in the form "Name<Sep><ID>". | |||
+ std::string getUniqueName(StringRef Name, const uint64_t ID) const { | |||
+ return (Name + Twine(Sep) + Twine(ID)).str(); | |||
+ } | |||
+ | |||
+ /// Register new version of \p Name and return unique version in the form | |||
+ /// "Name<Sep><Number>". | |||
std::string uniquify(StringRef Name) { | std::string uniquify(StringRef Name) { | ||
const uint64_t ID = ++Counters[Name]; | const uint64_t ID = ++Counters[Name]; | ||
- return (Name + Twine(Sep) + Twine(ID)).str(); | + return getUniqueName(Name, ID); | ||
} | } | ||
/// For uniquified \p Name, return the original form (that may no longer be | /// For uniquified \p Name, return the original form (that may no longer be |
@@ -14,6 +14,7 @@ | |||
#include "bolt/Profile/DataAggregator.h" | #include "bolt/Profile/DataAggregator.h" | ||
#include "bolt/Core/BinaryContext.h" | #include "bolt/Core/BinaryContext.h" | ||
#include "bolt/Core/BinaryFunction.h" | #include "bolt/Core/BinaryFunction.h" | ||
+#include "bolt/Passes/BinaryPasses.h" | |||
#include "bolt/Profile/BoltAddressTrans | #include "bolt/Profile/BoltAddressTrans | ||
#include "bolt/Profile/Heatmap.h" | #include "bolt/Profile/Heatmap.h" | ||
#include "bolt/Profile/YAMLProfileWrite | #include "bolt/Profile/YAMLProfileWrite | ||
@@ -611,6 +612,7 @@ Error DataAggregator:: | |||
if (std::error_code EC = writeBATYAML(BC, opts::SaveProfile)) | if (std::error_code EC = writeBATYAML(BC, opts::SaveProfile)) | ||
report_error("cannot create output data file", EC); | report_error("cannot create output data file", EC); | ||
} | } | ||
+ BC.logBOLTErrorsAnd | |||
} | } | ||
return Error::success(); | return Error::success(); | ||
@@ -859,14 +861,17 @@ bool DataAggregator:: | |||
return true; | return true; | ||
} | } | ||
-bool DataAggregator::recordTrace( | +std::optional<SmallVector<std::pair<uint64_t, uint64_t>, 16>> | ||
- BinaryFunction &BF, const LBREntry &FirstLBR, const LBREntry &SecondLBR, | +DataAggregator::getFallthroughsI | ||
- uint64_t Count, | + const LBREntry &FirstLBR, | ||
- SmallVector<std::pair<uint64_t, uint64_t>, 16> &Branches) const { | + const LBREntry &SecondLBR, | ||
+ uint64_t Count) const { | |||
+ SmallVector<std::pair<uint64_t, uint64_t>, 16> Branches; | |||
+ | |||
BinaryContext &BC = BF.getBinaryContext | BinaryContext &BC = BF.getBinaryContext | ||
if (!BF.isSimple()) | if (!BF.isSimple()) | ||
- return | + return std::nullopt; | ||
assert(BF.hasCFG() && "can only record traces in CFG state"); | assert(BF.hasCFG() && "can only record traces in CFG state"); | ||
@@ -875,13 +880,13 @@ bool DataAggregator:: | |||
const uint64_t To = SecondLBR.From - BF.getAddress(); | const uint64_t To = SecondLBR.From - BF.getAddress(); | ||
if (From > To) | if (From > To) | ||
- return | + return std::nullopt; | ||
const BinaryBasicBlock | const BinaryBasicBlock | ||
const BinaryBasicBlock | const BinaryBasicBlock | ||
if (!FromBB || !ToBB) | if (!FromBB || !ToBB) | ||
- return | + return std::nullopt; | ||
// Adjust FromBB if the first LBR is a return from the last instruction in | // Adjust FromBB if the first LBR is a return from the last instruction in | ||
// the previous block (that instruction should be a call). | // the previous block (that instruction should be a call). | ||
@@ -905,7 +910,7 @@ bool DataAggregator:: | |||
// within the same basic block, e.g. when two call instructions are in the | // within the same basic block, e.g. when two call instructions are in the | ||
// same block. In this case we skip the processing. | // same block. In this case we skip the processing. | ||
if (FromBB == ToBB) | if (FromBB == ToBB) | ||
- return | + return Branches; | ||
// Process blocks in the original layout order. | // Process blocks in the original layout order. | ||
BinaryBasicBlock | BinaryBasicBlock | ||
@@ -919,7 +924,7 @@ bool DataAggregator:: | |||
LLVM_DEBUG(dbgs() << "no fall-through for the trace:\n" | LLVM_DEBUG(dbgs() << "no fall-through for the trace:\n" | ||
<< " " << FirstLBR << '\n' | << " " << FirstLBR << '\n' | ||
<< " " << SecondLBR << '\n'); | << " " << SecondLBR << '\n'); | ||
- return | + return std::nullopt; | ||
} | } | ||
const MCInst *Instr = BB->getLastNonPseudo | const MCInst *Instr = BB->getLastNonPseudo | ||
@@ -943,20 +948,7 @@ bool DataAggregator:: | |||
BI.Count += Count; | BI.Count += Count; | ||
} | } | ||
- return | + return Branches; | ||
-} | |||
- | |||
-std::optional<SmallVector<std::pair<uint64_t, uint64_t>, 16>> | |||
-DataAggregator::getFallthroughsI | |||
- const LBREntry &FirstLBR, | |||
- const LBREntry &SecondLBR, | |||
- uint64_t Count) const { | |||
- SmallVector<std::pair<uint64_t, uint64_t>, 16> Res; | |||
- | |||
- if (!recordTrace(BF, FirstLBR, SecondLBR, Count, Res)) | |||
- return std::nullopt; | |||
- | |||
- return Res; | |||
} | } | ||
bool DataAggregator::recordEntry(BinaryFunction &BF, uint64_t To, bool Mispred, | bool DataAggregator::recordEntry(BinaryFunction &BF, uint64_t To, bool Mispred, |
@@ -356,7 +356,7 @@ Error BinaryFunctionPa | |||
// order they're registered. | // order they're registered. | ||
// Run this pass first to use stats for the original functions. | // Run this pass first to use stats for the original functions. | ||
- Manager.registerPass(std::make_unique<PrintProgramStats>( | + Manager.registerPass(std::make_unique<PrintProgramStats>()); | ||
if (opts::PrintProfileStat | if (opts::PrintProfileStat | ||
Manager.registerPass(std::make_unique<PrintProfileStat | Manager.registerPass(std::make_unique<PrintProfileStat |
@@ -292,7 +292,7 @@ class RewriteInstanceD | |||
} | } | ||
} | } | ||
} | } | ||
- PrintProgramStats | + PrintProgramStats PPS; | ||
outs() << "* BOLT-DIFF: Starting print program stats pass for binary 1\n"; | outs() << "* BOLT-DIFF: Starting print program stats pass for binary 1\n"; | ||
RI1.BC->logBOLTErrorsAnd | RI1.BC->logBOLTErrorsAnd | ||
outs() << "* BOLT-DIFF: Starting print program stats pass for binary 2\n"; | outs() << "* BOLT-DIFF: Starting print program stats pass for binary 2\n"; |
@@ -248,6 +248,9 @@ class LinuxKernelRewri | |||
/// Update ORC data in the binary. | /// Update ORC data in the binary. | ||
Error rewriteORCTables | Error rewriteORCTables | ||
+ /// Validate written ORC tables after binary emission. | |||
+ Error validateORCTable | |||
+ | |||
/// Static call table handling. | /// Static call table handling. | ||
Error readStaticCalls(); | Error readStaticCalls(); | ||
Error rewriteStaticCal | Error rewriteStaticCal | ||
@@ -358,6 +361,9 @@ public: | |||
if (Error E = updateStaticKeys | if (Error E = updateStaticKeys | ||
return E; | return E; | ||
+ if (Error E = validateORCTable | |||
+ return E; | |||
+ | |||
return Error::success(); | return Error::success(); | ||
} | } | ||
}; | }; | ||
@@ -837,6 +843,32 @@ Error LinuxKernelRewri | |||
return Error::success(); | return Error::success(); | ||
} | } | ||
+Error LinuxKernelRewri | |||
+ if (!ORCUnwindIPSecti | |||
+ return Error::success(); | |||
+ | |||
+ const uint64_t IPSectionAddress | |||
+ DataExtractor IPDE = DataExtractor(ORCUnwindIPSecti | |||
+ BC.AsmInfo->isLittleEndian(), | |||
+ BC.AsmInfo->getCodePointerSi | |||
+ DataExtractor::Cursor IPCursor(0); | |||
+ uint64_t PrevIP = 0; | |||
+ for (uint32_t Index = 0; Index < NumORCEntries; ++Index) { | |||
+ const uint64_t IP = | |||
+ IPSectionAddress | |||
+ if (!IPCursor) | |||
+ return createStringErro | |||
+ "out of bounds while reading ORC IP table: %s", | |||
+ toString(IPCursor.takeError()).c_str()); | |||
+ | |||
+ assert(IP >= PrevIP && "Unsorted ORC table detected"); | |||
+ (void)PrevIP; | |||
+ PrevIP = IP; | |||
+ } | |||
+ | |||
+ return Error::success(); | |||
+} | |||
+ | |||
/// The static call site table is created by objtool and contains entries in the | /// The static call site table is created by objtool and contains entries in the | ||
/// following format: | /// following format: | ||
/// | /// |
@@ -840,6 +840,7 @@ void RewriteInstance: | |||
continue; | continue; | ||
if (cantFail(Symbol.getType()) == SymbolRef::ST_File) { | if (cantFail(Symbol.getType()) == SymbolRef::ST_File) { | ||
+ FileSymbols.emplace_back(Symbol); | |||
StringRef Name = | StringRef Name = | ||
cantFail(std::move(NameOrError), "cannot get symbol name for file"); | cantFail(std::move(NameOrError), "cannot get symbol name for file"); | ||
// Ignore Clang LTO artificial FILE symbol as it is not always generated, | // Ignore Clang LTO artificial FILE symbol as it is not always generated, | ||
@@ -1062,6 +1063,11 @@ void RewriteInstance: | |||
continue; | continue; | ||
} | } | ||
+ if (SymName == getBOLTReservedS | |||
+ registerName(SymbolSize); | |||
+ continue; | |||
+ } | |||
+ | |||
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: considering symbol " << UniqueName | LLVM_DEBUG(dbgs() << "BOLT-DEBUG: considering symbol " << UniqueName | ||
<< " for function\n"); | << " for function\n"); | ||
@@ -1340,6 +1346,7 @@ void RewriteInstance: | |||
} | } | ||
registerFragment | registerFragment | ||
+ FileSymbols.clear(); | |||
} | } | ||
Error RewriteInstance::discoverRtFiniAd | Error RewriteInstance::discoverRtFiniAd | ||
@@ -1417,50 +1424,134 @@ void RewriteInstance: | |||
if (!BC->HasSplitFunction | if (!BC->HasSplitFunction | ||
return; | return; | ||
+ // Process fragments with ambiguous parents separately as they are typically a | |||
+ // vanishing minority of cases and require expensive symbol table lookups. | |||
+ std::vector<std::pair<StringRef, BinaryFunction *>> AmbiguousFragmen | |||
for (auto &BFI : BC->getBinaryFunctio | for (auto &BFI : BC->getBinaryFunctio | ||
BinaryFunction &Function = BFI.second; | BinaryFunction &Function = BFI.second; | ||
if (!Function.isFragment()) | if (!Function.isFragment()) | ||
continue; | continue; | ||
- unsigned ParentsFound = 0; | |||
for (StringRef Name : Function.getNames()) { | for (StringRef Name : Function.getNames()) { | ||
- StringRef BaseName | + StringRef BaseName = NR.restore(Name); | ||
- std::tie(BaseName, Suffix) = Name.split('/'); | + const bool IsGlobal = BaseName == Name; | ||
const size_t ColdSuffixPos = BaseName.find(".cold"); | const size_t ColdSuffixPos = BaseName.find(".cold"); | ||
if (ColdSuffixPos == StringRef::npos) | if (ColdSuffixPos == StringRef::npos) | ||
continue; | continue; | ||
- // For cold function with local (foo.cold/1) symbol, prefer a parent with | + StringRef ParentName = BaseName.substr(0, ColdSuffixPos); | ||
- // local symbol as well (foo/1) over global symbol (foo). | |||
- std::string ParentName = BaseName.substr(0, ColdSuffixPos).str(); | |||
const BinaryData *BD = BC->getBinaryDataByN | const BinaryData *BD = BC->getBinaryDataByN | ||
- if (Suffix != "") { | + const uint64_t NumPossibleLocal | ||
- ParentName.append(Twine("/", Suffix).str()); | + NR.getUniquifiedNam | ||
- const BinaryData *BDLocal = BC->getBinaryDataByN | + // The most common case: single local parent fragment. | ||
- if (BDLocal || !BD) | + if (!BD && NumPossibleLocal | ||
- BD = BDLocal; | + BD = BC->getBinaryDataByN | ||
- } | + } else if (BD && (!NumPossibleLocal | ||
- if (!BD) { | + // Global parent and either no local candidates (second most common), or | ||
- if (opts::Verbosity >= 1) | + // the fragment is global as well (uncommon). | ||
- BC->outs() << "BOLT-INFO: parent function not found for " << Name | + } else { | ||
- << "\n"; | + // Any other case: need to disambiguate using FILE symbols. | ||
+ AmbiguousFragmen | |||
continue; | continue; | ||
} | } | ||
- const uint64_t Address = BD->getAddress(); | + if (BD) { | ||
- BinaryFunction *BF = BC->getBinaryFunctio | + BinaryFunction *BF = BC->getFunctionForSy | ||
- | + if (BF) { | ||
- if (opts::Verbosity >= 1) | + BC->registerFragment | ||
- BC->outs() << formatv( | + continue; | ||
- "BOLT-INFO: parent function not found at {0:x}\n", Address); | + } | ||
- continue; | |||
} | } | ||
- BC->registerFragment | |||
- ++ParentsFound; | |||
- } | |||
- if (!ParentsFound) { | |||
BC->errs() << "BOLT-ERROR: parent function not found for " << Function | BC->errs() << "BOLT-ERROR: parent function not found for " << Function | ||
<< '\n'; | << '\n'; | ||
exit(1); | exit(1); | ||
} | } | ||
} | } | ||
+ | |||
+ if (AmbiguousFragmen | |||
+ return; | |||
+ | |||
+ if (!BC->hasSymbolsWithFi | |||
+ BC->errs() << "BOLT-ERROR: input file has split functions but does not " | |||
+ "have FILE symbols. If the binary was stripped, preserve " | |||
+ "FILE symbols with --keep-file-symbols strip option"; | |||
+ exit(1); | |||
+ } | |||
+ | |||
+ // The first global symbol is identified by the symbol table sh_info value. | |||
+ // Used as local symbol search stopping point. | |||
+ auto *ELF64LEFile = cast<ELF64LEObjectFil | |||
+ const ELFFile<ELF64LE> &Obj = ELF64LEFile->getELFFile(); | |||
+ auto *SymTab = llvm::find_if(cantFail(Obj.sections()), [](const auto &Sec) { | |||
+ return Sec.sh_type == ELF::SHT_SYMTAB; | |||
+ }); | |||
+ assert(SymTab); | |||
+ // Symtab sh_info contains the value one greater than the symbol table index | |||
+ // of the last local symbol. | |||
+ ELFSymbolRef LocalSymEnd = ELF64LEFile->toSymbolRef(SymTab, SymTab->sh_info); | |||
+ | |||
+ for (auto &[ParentName, BF] : AmbiguousFragmen | |||
+ const uint64_t Address = BF->getAddress(); | |||
+ | |||
+ // Get fragment's own symbol | |||
+ const auto SymIt = FileSymRefs.find(Address); | |||
+ if (SymIt == FileSymRefs.end()) { | |||
+ BC->errs() | |||
+ << "BOLT-ERROR: symbol lookup failed for function at address 0x" | |||
+ << Twine::utohexstr(Address) << '\n'; | |||
+ exit(1); | |||
+ } | |||
+ | |||
+ // Find containing FILE symbol | |||
+ ELFSymbolRef Symbol = SymIt->second; | |||
+ auto FSI = llvm::upper_bound(FileSymbols, Symbol); | |||
+ if (FSI == FileSymbols.begin()) { | |||
+ BC->errs() << "BOLT-ERROR: owning FILE symbol not found for symbol " | |||
+ << cantFail(Symbol.getName()) << '\n'; | |||
+ exit(1); | |||
+ } | |||
+ | |||
+ ELFSymbolRef StopSymbol = LocalSymEnd; | |||
+ if (FSI != FileSymbols.end()) | |||
+ StopSymbol = *FSI; | |||
+ | |||
+ uint64_t ParentAddress{0}; | |||
+ | |||
+ // BOLT split fragment symbols are emitted just before the main function | |||
+ // symbol. | |||
+ for (ELFSymbolRef NextSymbol = Symbol; NextSymbol < StopSymbol; | |||
+ NextSymbol.moveNext()) { | |||
+ StringRef Name = cantFail(NextSymbol.getName()); | |||
+ if (Name == ParentName) { | |||
+ ParentAddress = cantFail(NextSymbol.getValue()); | |||
+ goto registerParent; | |||
+ } | |||
+ if (Name.starts_with(ParentName)) | |||
+ // With multi-way splitting, there are multiple fragments with different | |||
+ // suffixes. Parent follows the last fragment. | |||
+ continue; | |||
+ break; | |||
+ } | |||
+ | |||
+ // Iterate over local file symbols and check symbol names to match parent. | |||
+ for (ELFSymbolRef Symbol(FSI[-1]); Symbol < StopSymbol; Symbol.moveNext()) { | |||
+ if (cantFail(Symbol.getName()) == ParentName) { | |||
+ ParentAddress = cantFail(Symbol.getAddress()); | |||
+ break; | |||
+ } | |||
+ } | |||
+ | |||
+registerParent: | |||
+ // No local parent is found, use global parent function. | |||
+ if (!ParentAddress) | |||
+ if (BinaryData *ParentBD = BC->getBinaryDataByN | |||
+ ParentAddress = ParentBD->getAddress(); | |||
+ | |||
+ if (BinaryFunction *ParentBF = | |||
+ BC->getBinaryFunctio | |||
+ BC->registerFragment | |||
+ continue; | |||
+ } | |||
+ BC->errs() << "BOLT-ERROR: parent function not found for " << *BF << '\n'; | |||
+ exit(1); | |||
+ } | |||
} | } | ||
void RewriteInstance::createPLTBinaryF | void RewriteInstance::createPLTBinaryF | ||
@@ -1725,12 +1816,6 @@ void RewriteInstance: | |||
if (!Function.isSymbolValidInS | if (!Function.isSymbolValidInS | ||
break; | break; | ||
- // Ignore unnamed symbols. Used, for example, by debugging info on RISC-V. | |||
- if (BC->isRISCV() && cantFail(Symbol.getName()).empty()) { | |||
- ++NextSymRefI; | |||
- continue; | |||
- } | |||
- | |||
// Skip basic block labels. This happens on RISC-V with linker relaxation | // Skip basic block labels. This happens on RISC-V with linker relaxation | ||
// enabled because every branch needs a relocation and corresponding | // enabled because every branch needs a relocation and corresponding | ||
// symbol. We don't want to add such symbols as entry points. | // symbol. We don't want to add such symbols as entry points. | ||
@@ -3532,6 +3617,26 @@ void RewriteInstance: | |||
void RewriteInstance::mapFileSections(BOLTLinker::SectionMapper MapSection) { | void RewriteInstance::mapFileSections(BOLTLinker::SectionMapper MapSection) { | ||
BC->deregisterUnused | BC->deregisterUnused | ||
+ // Check if the input has a space reserved for BOLT. | |||
+ BinaryData *StartBD = BC->getBinaryDataByN | |||
+ BinaryData *EndBD = BC->getBinaryDataByN | |||
+ if (!StartBD != !EndBD) { | |||
+ BC->errs() << "BOLT-ERROR: one of the symbols is missing from the binary: " | |||
+ << getBOLTReservedS | |||
+ << '\n'; | |||
+ exit(1); | |||
+ } | |||
+ | |||
+ if (StartBD) { | |||
+ PHDRTableOffset = 0; | |||
+ PHDRTableAddress | |||
+ NewTextSegmentAd | |||
+ NewTextSegmentOf | |||
+ NextAvailableAdd | |||
+ BC->outs() | |||
+ << "BOLT-INFO: using reserved space for allocating new sections\n"; | |||
+ } | |||
+ | |||
// If no new .eh_frame was written, remove relocated original .eh_frame. | // If no new .eh_frame was written, remove relocated original .eh_frame. | ||
BinarySection *RelocatedEHFrame | BinarySection *RelocatedEHFrame | ||
getSection(".relocated" + getEHFrameSectio | getSection(".relocated" + getEHFrameSectio | ||
@@ -3551,6 +3656,18 @@ void RewriteInstance: | |||
// Map the rest of the sections. | // Map the rest of the sections. | ||
mapAllocatableSe | mapAllocatableSe | ||
+ | |||
+ if (StartBD) { | |||
+ const uint64_t ReservedSpace = EndBD->getAddress() - StartBD->getAddress(); | |||
+ const uint64_t AllocatedSize = NextAvailableAdd | |||
+ if (ReservedSpace < AllocatedSize) { | |||
+ BC->errs() << "BOLT-ERROR: reserved space (" << ReservedSpace << " byte" | |||
+ << (ReservedSpace == 1 ? "" : "s") | |||
+ << ") is smaller than required for new allocations (" | |||
+ << AllocatedSize << " bytes)\n"; | |||
+ exit(1); | |||
+ } | |||
+ } | |||
} | } | ||
std::vector<BinarySection *> RewriteInstance::getCodeSections() { | std::vector<BinarySection *> RewriteInstance::getCodeSections() { | ||
@@ -3792,7 +3909,7 @@ void RewriteInstance: | |||
// Add the new text section aggregating all existing code sections. | // Add the new text section aggregating all existing code sections. | ||
// This is pseudo-section that serves a purpose of creating a corresponding | // This is pseudo-section that serves a purpose of creating a corresponding | ||
// entry in section header table. | // entry in section header table. | ||
- | + const uint64_t NewTextSectionSize = | ||
NextAvailableAdd | NextAvailableAdd | ||
if (NewTextSectionSi | if (NewTextSectionSi | ||
const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/true, | const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/true, | ||
@@ -3875,7 +3992,7 @@ void RewriteInstance: | |||
if (PHDRTableAddress | if (PHDRTableAddress | ||
// Segment size includes the size of the PHDR area. | // Segment size includes the size of the PHDR area. | ||
NewTextSegmentSi | NewTextSegmentSi | ||
- } else { | + } else if (NewTextSegmentAddress) { | ||
// Existing PHDR table would be updated. | // Existing PHDR table would be updated. | ||
NewTextSegmentSi | NewTextSegmentSi | ||
} | } | ||
@@ -3914,7 +4031,7 @@ void RewriteInstance: | |||
assert(!PHDRTableAddress | assert(!PHDRTableAddress | ||
PHDRTableOffset = Obj.getHeader().e_phoff; | PHDRTableOffset = Obj.getHeader().e_phoff; | ||
if (NewWritableSegme | if (NewWritableSegme | ||
- BC->errs() << | + BC->errs() << "BOLT-ERROR: unable to add writable segment\n"; | ||
exit(1); | exit(1); | ||
} | } | ||
} | } | ||
@@ -3924,19 +4041,15 @@ void RewriteInstance: | |||
if (!NewWritableSegme | if (!NewWritableSegme | ||
if (PHDRTableAddress | if (PHDRTableAddress | ||
NewTextSegmentSi | NewTextSegmentSi | ||
- else | + else if (NewTextSegmentAddress) | ||
NewTextSegmentSi | NewTextSegmentSi | ||
} else { | } else { | ||
NewWritableSegme | NewWritableSegme | ||
} | } | ||
+ const uint64_t SavedPos = OS.tell(); | |||
OS.seek(PHDRTableOffset); | OS.seek(PHDRTableOffset); | ||
- bool ModdedGnuStack = false; | |||
- (void)ModdedGnuStack; | |||
- bool AddedSegment = false; | |||
- (void)AddedSegment; | |||
- | |||
auto createNewTextPhd | auto createNewTextPhd | ||
ELF64LEPhdrTy NewPhdr; | ELF64LEPhdrTy NewPhdr; | ||
NewPhdr.p_type = ELF::PT_LOAD; | NewPhdr.p_type = ELF::PT_LOAD; | ||
@@ -3952,40 +4065,55 @@ void RewriteInstance: | |||
NewPhdr.p_filesz = NewTextSegmentSi | NewPhdr.p_filesz = NewTextSegmentSi | ||
NewPhdr.p_memsz = NewTextSegmentSi | NewPhdr.p_memsz = NewTextSegmentSi | ||
NewPhdr.p_flags = ELF::PF_X | ELF::PF_R; | NewPhdr.p_flags = ELF::PF_X | ELF::PF_R; | ||
- // FIXME: Currently instrumentation is experimental and the runtime data | + if (opts::Instrument) { | ||
- // is emitted with code, thus everything needs to be writable | + // FIXME: Currently instrumentation is experimental and the runtime data | ||
- if (opts::Instrument) | + // is emitted with code, thus everything needs to be writable. | ||
NewPhdr.p_flags |= ELF::PF_W; | NewPhdr.p_flags |= ELF::PF_W; | ||
+ } | |||
NewPhdr.p_align = BC->PageAlign; | NewPhdr.p_align = BC->PageAlign; | ||
return NewPhdr; | return NewPhdr; | ||
}; | }; | ||
- auto | + auto writeNewSegmentPhdrs = [&]() { | ||
- ELF64LEPhdrTy NewPhdr; | + if (PHDRTableAddress | ||
- NewPhdr.p_type = ELF::PT_LOAD; | + ELF64LE::Phdr NewPhdr = createNewTextPhd | ||
- NewPhdr.p_offset = getFileOffsetFor | + OS.write(reinterpret_cast | ||
- NewPhdr.p_vaddr = NewWritableSegme | + } | ||
- NewPhdr.p_paddr = NewWritableSegme | + | ||
- NewPhdr.p_filesz = NewWritableSegme | + if (NewWritableSegme | ||
- NewPhdr.p_memsz = NewWritableSegme | + ELF64LEPhdrTy NewPhdr; | ||
- NewPhdr.p_align = BC->RegularPageSize; | + NewPhdr.p_type = ELF::PT_LOAD; | ||
- NewPhdr.p_flags = ELF::PF_R | ELF::PF_W; | + NewPhdr.p_offset = getFileOffsetFor | ||
- return NewPhdr; | + NewPhdr.p_vaddr = NewWritableSegme | ||
+ NewPhdr.p_paddr = NewWritableSegme | |||
+ NewPhdr.p_filesz = NewWritableSegme | |||
+ NewPhdr.p_memsz = NewWritableSegme | |||
+ NewPhdr.p_align = BC->RegularPageSize; | |||
+ NewPhdr.p_flags = ELF::PF_R | ELF::PF_W; | |||
+ OS.write(reinterpret_cast | |||
+ } | |||
}; | }; | ||
+ bool ModdedGnuStack = false; | |||
+ bool AddedSegment = false; | |||
+ | |||
// Copy existing program headers with modifications. | // Copy existing program headers with modifications. | ||
for (const ELF64LE::Phdr &Phdr : cantFail(Obj.program_headers())) { | for (const ELF64LE::Phdr &Phdr : cantFail(Obj.program_headers())) { | ||
ELF64LE::Phdr NewPhdr = Phdr; | ELF64LE::Phdr NewPhdr = Phdr; | ||
- if (PHDRTableAddress | + switch (Phdr.p_type) { | ||
- NewPhdr.p_offset = PHDRTableOffset; | + case ELF::PT_PHDR: | ||
- NewPhdr.p_vaddr = PHDRTableAddress | + if (PHDRTableAddress | ||
- | + NewPhdr.p_offset = PHDRTableOffset; | ||
- NewPhdr.p_filesz = sizeof(NewPhdr) * Phnum; | + NewPhdr.p_vaddr = PHDRTableAddress | ||
- NewPhdr.p_memsz = sizeof(NewPhdr) * Phnum; | + NewPhdr.p_paddr = PHDRTableAddress | ||
- } else if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) { | + NewPhdr.p_filesz = sizeof(NewPhdr) * Phnum; | ||
- ErrorOr<BinarySection &> EHFrameHdrSec = | + NewPhdr.p_memsz = sizeof(NewPhdr) * Phnum; | ||
- BC->getUniqueSection | + } | ||
+ break; | |||
+ case ELF::PT_GNU_EH_FRAME: { | |||
+ ErrorOr<BinarySection &> EHFrameHdrSec = BC->getUniqueSection | |||
+ getNewSecPrefix() + getEHFrameHdrSec | |||
if (EHFrameHdrSec && EHFrameHdrSec->isAllocatable() && | if (EHFrameHdrSec && EHFrameHdrSec->isAllocatable() && | ||
EHFrameHdrSec->isFinalized()) { | EHFrameHdrSec->isFinalized()) { | ||
NewPhdr.p_offset = EHFrameHdrSec->getOutputFileOff | NewPhdr.p_offset = EHFrameHdrSec->getOutputFileOff | ||
@@ -3994,37 +4122,38 @@ void RewriteInstance: | |||
NewPhdr.p_filesz = EHFrameHdrSec->getOutputSize(); | NewPhdr.p_filesz = EHFrameHdrSec->getOutputSize(); | ||
NewPhdr.p_memsz = EHFrameHdrSec->getOutputSize(); | NewPhdr.p_memsz = EHFrameHdrSec->getOutputSize(); | ||
} | } | ||
- } else if (opts::UseGnuStack && Phdr.p_type == ELF::PT_GNU_STACK) { | + break; | ||
- NewPhdr = createNewTextPhd | + } | ||
- ModdedGnuStack = true; | + case ELF::PT_GNU_STACK: | ||
- } else if (!opts::UseGnuStack && Phdr.p_type == ELF::PT_DYNAMIC) { | + if (opts::UseGnuStack) { | ||
- // Insert the new header before DYNAMIC. | + // Overwrite the header with the new text segment header. | ||
- | + NewPhdr = createNewTextPhdr(); | ||
- OS.write(reinterpret_cast | + ModdedGnuStack = true; | ||
- sizeof(NewTextPhdr)); | |||
- if (NewWritableSegme | |||
- ELF64LEPhdrTy NewWritablePhdr = createNewWritabl | |||
- OS.write(reinterpret_cast | |||
- sizeof(NewWritablePhdr)); | |||
} | } | ||
- AddedSegment = true; | + break; | ||
+ case ELF::PT_DYNAMIC: | |||
+ if (!opts::UseGnuStack) { | |||
+ // Insert new headers before DYNAMIC. | |||
+ writeNewSegmentP | |||
+ AddedSegment = true; | |||
+ } | |||
+ break; | |||
} | } | ||
OS.write(reinterpret_cast | OS.write(reinterpret_cast | ||
} | } | ||
if (!opts::UseGnuStack && !AddedSegment) { | if (!opts::UseGnuStack && !AddedSegment) { | ||
- // Append | + // Append new headers to the end of the table. | ||
- ELF64LE::Phdr NewTextPhdr = createNewTextPhd | + writeNewSegmentP | ||
- OS.write(reinterpret_cast | + } | ||
- if (NewWritableSegme | + | ||
- ELF64LEPhdrTy NewWritablePhdr = createNewWritabl | + if (opts::UseGnuStack && !ModdedGnuStack) { | ||
- OS.write(reinterpret_cast | + BC->errs() | ||
- sizeof(NewWritablePhdr)); | + << "BOLT-ERROR: could not find PT_GNU_STACK program header to modify\n"; | ||
- } | + exit(1); | ||
} | } | ||
- assert((!opts::UseGnuStack || ModdedGnuStack) && | + OS.seek(SavedPos); | ||
- "could not find GNU_STACK program header to modify"); | |||
} | } | ||
namespace { | namespace { | ||
@@ -4050,9 +4179,8 @@ void RewriteInstance: | |||
const ELFFile<ELF64LE> &Obj = ELF64LEFile->getELFFile(); | const ELFFile<ELF64LE> &Obj = ELF64LEFile->getELFFile(); | ||
raw_fd_ostream &OS = Out->os(); | raw_fd_ostream &OS = Out->os(); | ||
- uint64_t NextAvailableOffset = | + uint64_t NextAvailableOffset = std::max( | ||
- | + getFileOffsetForAddress(NextAvailableAddress), FirstNonAllocatableOffset); | ||
- "next available offset calculation failure"); | |||
OS.seek(NextAvailableOff | OS.seek(NextAvailableOff | ||
// Copy over non-allocatable section contents and update file offsets. | // Copy over non-allocatable section contents and update file offsets. | ||
@@ -4493,6 +4621,8 @@ void RewriteInstance: | |||
// Symbols for the new symbol table. | // Symbols for the new symbol table. | ||
std::vector<ELFSymTy> Symbols; | std::vector<ELFSymTy> Symbols; | ||
+ bool EmittedColdFileS | |||
+ | |||
auto getNewSectionInd | auto getNewSectionInd | ||
// For dynamic symbol table, the section index could be wrong on the input, | // For dynamic symbol table, the section index could be wrong on the input, | ||
// and its value is ignored by the runtime if it's different from | // and its value is ignored by the runtime if it's different from | ||
@@ -4551,6 +4681,20 @@ void RewriteInstance: | |||
Symbols.emplace_back(ICFSymbol); | Symbols.emplace_back(ICFSymbol); | ||
} | } | ||
if (Function.isSplit()) { | if (Function.isSplit()) { | ||
+ // Prepend synthetic FILE symbol to prevent local cold fragments from | |||
+ // colliding with existing symbols with the same name. | |||
+ if (!EmittedColdFileS | |||
+ FunctionSymbol.getBinding() == ELF::STB_GLOBAL) { | |||
+ ELFSymTy FileSymbol; | |||
+ FileSymbol.st_shndx = ELF::SHN_ABS; | |||
+ FileSymbol.st_name = AddToStrTab(getBOLTFileSymbo | |||
+ FileSymbol.st_value = 0; | |||
+ FileSymbol.st_size = 0; | |||
+ FileSymbol.st_other = 0; | |||
+ FileSymbol.setBindingAndTyp | |||
+ Symbols.emplace_back(FileSymbol); | |||
+ EmittedColdFileS | |||
+ } | |||
for (const FunctionFragment | for (const FunctionFragment | ||
Function.getLayout().getSplitFragment | Function.getLayout().getSplitFragment | ||
if (FF.getAddress()) { | if (FF.getAddress()) { | ||
@@ -4775,7 +4919,7 @@ void RewriteInstance: | |||
++NumHotDataSymsUp | ++NumHotDataSymsUp | ||
} | } | ||
- if (*SymbolName == "_end") | + if (*SymbolName == "_end" && NextAvailableAddress > Symbol.st_value) | ||
updateSymbolValu | updateSymbolValu | ||
if (IsDynSym) | if (IsDynSym) | ||
@@ -4889,13 +5033,6 @@ void RewriteInstance: | |||
std::vector<uint32_t> NewSectionIndex; | std::vector<uint32_t> NewSectionIndex; | ||
getOutputSection | getOutputSection | ||
- // Set pointer at the end of the output file, so we can pwrite old symbol | |||
- // tables if we need to. | |||
- uint64_t NextAvailableOff | |||
- assert(NextAvailableOff | |||
- "next available offset calculation failure"); | |||
- Out->os().seek(NextAvailableOff | |||
- | |||
// Update dynamic symbol table. | // Update dynamic symbol table. | ||
const ELFShdrTy *DynSymSection = nullptr; | const ELFShdrTy *DynSymSection = nullptr; | ||
for (const ELFShdrTy &Section : cantFail(Obj.sections())) { | for (const ELFShdrTy &Section : cantFail(Obj.sections())) { | ||
@@ -5432,6 +5569,17 @@ uint64_t RewriteInstance: | |||
if (BD && BD->isMoved()) | if (BD && BD->isMoved()) | ||
return BD->getOutputAddress | return BD->getOutputAddress | ||
+ if (const BinaryFunction *BF = | |||
+ BC->getBinaryFunctio | |||
+ if (BF->isEmitted()) { | |||
+ BC->errs() << "BOLT-ERROR: unable to get new address corresponding to " | |||
+ "input address 0x" | |||
+ << Twine::utohexstr(OldAddress) << " in function " << *BF | |||
+ << ". Consider adding this function to --skip-funcs=...\n"; | |||
+ exit(1); | |||
+ } | |||
+ } | |||
+ | |||
return 0; | return 0; | ||
} | } | ||
@@ -5449,10 +5597,10 @@ void RewriteInstance: | |||
auto Streamer = BC->createStreamer(OS); | auto Streamer = BC->createStreamer(OS); | ||
// Make sure output stream has enough reserved space, otherwise | // Make sure output stream has enough reserved space, otherwise | ||
// pwrite() will fail. | // pwrite() will fail. | ||
- uint64_t Offset = | + uint64_t Offset = std::max(getFileOffsetForAddress(NextAvailableAddress), | ||
- (void)Offset; | + FirstNonAllocata | ||
- assert(Offset == getFileOffsetFor | + Offset = OS.seek(Offset); | ||
- "error resizing output file"); | + assert((Offset != (uint64_t)-1) && "Error resizing output file"); | ||
// Overwrite functions with fixed output address. This is mostly used by | // Overwrite functions with fixed output address. This is mostly used by | ||
// non-relocation mode, with one exception: injected functions are covered | // non-relocation mode, with one exception: injected functions are covered | ||
@@ -5671,7 +5819,8 @@ void RewriteInstance: | |||
BC->AsmInfo->getCodePointerSi | BC->AsmInfo->getCodePointerSi | ||
check_error(std::move(Er), "failed to parse EH frame"); | check_error(std::move(Er), "failed to parse EH frame"); | ||
- LLVM_DEBUG(dbgs() << "BOLT: writing a new | + LLVM_DEBUG(dbgs() << "BOLT: writing a new " << getEHFrameHdrSectionName() | ||
+ << '\n'); | |||
NextAvailableAdd | NextAvailableAdd | ||
appendPadding(Out->os(), NextAvailableAdd | appendPadding(Out->os(), NextAvailableAdd | ||
@@ -5683,25 +5832,35 @@ void RewriteInstance: | |||
std::vector<char> NewEHFrameHdr = CFIRdWrt->generateEHFrameH | std::vector<char> NewEHFrameHdr = CFIRdWrt->generateEHFrameH | ||
RelocatedEHFrame | RelocatedEHFrame | ||
- assert(Out->os().tell() == EHFrameHdrFileOf | + Out->os().seek(EHFrameHdrFileOf | ||
Out->os().write(NewEHFrameHdr.data(), NewEHFrameHdr.size()); | Out->os().write(NewEHFrameHdr.data(), NewEHFrameHdr.size()); | ||
const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/true, | const unsigned Flags = BinarySection::getFlags(/*IsReadOnly=*/true, | ||
/*IsText=*/false, | /*IsText=*/false, | ||
/*IsAllocatable=*/true); | /*IsAllocatable=*/true); | ||
- BinarySection *OldEHFrameHdrSection = getSection( | + BinarySection *OldEHFrameHdrSection = getSection(getEHFrameHdrSectionName()); | ||
if (OldEHFrameHdrSec | if (OldEHFrameHdrSec | ||
- OldEHFrameHdrSection->setOutputName(getOrgSecPrefix() + | + OldEHFrameHdrSection->setOutputName(getOrgSecPrefix() + | ||
+ getEHFrameHdrSec | |||
BinarySection &EHFrameHdrSec = BC->registerOrUpdate | BinarySection &EHFrameHdrSec = BC->registerOrUpdate | ||
- getNewSecPrefix() + | + getNewSecPrefix() + getEHFrameHdrSectionName(), ELF::SHT_PROGBITS, Flags, | ||
- NewEHFrameHdr.size(), /*Alignment=*/1); | + nullptr, NewEHFrameHdr.size(), /*Alignment=*/1); | ||
EHFrameHdrSec.setOutputFileOff | EHFrameHdrSec.setOutputFileOff | ||
EHFrameHdrSec.setOutputAddress | EHFrameHdrSec.setOutputAddress | ||
- EHFrameHdrSec.setOutputName( | + EHFrameHdrSec.setOutputName(getEHFrameHdrSectionName()); | ||
NextAvailableAdd | NextAvailableAdd | ||
+ if (const BinaryData *ReservedEnd = | |||
+ BC->getBinaryDataByN | |||
+ if (NextAvailableAdd | |||
+ BC->errs() << "BOLT-ERROR: unable to fit " << getEHFrameHdrSec | |||
+ << " into reserved space\n"; | |||
+ exit(1); | |||
+ } | |||
+ } | |||
+ | |||
// Merge new .eh_frame with the relocated original so that gdb can locate all | // Merge new .eh_frame with the relocated original so that gdb can locate all | ||
// FDEs. | // FDEs. | ||
if (RelocatedEHFrame | if (RelocatedEHFrame |
@@ -5,12 +5,12 @@ | |||
// RUN: %clang %cflags -g -Wl,-q -o %t %s | // RUN: %clang %cflags -g -Wl,-q -o %t %s | ||
-/// Verify that the binary indeed contains | +/// Verify that the binary indeed contains a fake label ".L0 " at _start. | ||
// RUN: llvm-readelf -s %t | FileCheck %s --check-prefix=CHECK-ELF | // RUN: llvm-readelf -s %t | FileCheck %s --check-prefix=CHECK-ELF | ||
// CHECK-ELF-DAG: [[#%x,START:]] {{.*}} FUNC GLOBAL DEFAULT [[#%d,SECTION:]] _start{{$}} | // CHECK-ELF-DAG: [[#%x,START:]] {{.*}} FUNC GLOBAL DEFAULT [[#%d,SECTION:]] _start{{$}} | ||
-// CHECK-ELF-DAG: [[#%x,START]] {{.*}} NOTYPE LOCAL DEFAULT [[#SECTION]] {{$}} | +// CHECK-ELF-DAG: [[#%x,START]] {{.*}} NOTYPE LOCAL DEFAULT [[#SECTION]] .L0 {{$}} | ||
-/// Verify that BOLT did not create an extra entry point for the | +/// Verify that BOLT did not create an extra entry point for the fake label. | ||
// RUN: llvm-bolt -o %t.bolt %t --print-cfg | FileCheck %s | // RUN: llvm-bolt -o %t.bolt %t --print-cfg | FileCheck %s | ||
// CHECK: Binary Function "_start" after building cfg { | // CHECK: Binary Function "_start" after building cfg { | ||
// CHECK: IsMultiEntry: 0 | // CHECK: IsMultiEntry: 0 |
@@ -10,6 +10,7 @@ | |||
# RUN: --call-scale=2 --data=%t.fdata --reorder-blocks=ext-tsp | # RUN: --call-scale=2 --data=%t.fdata --reorder-blocks=ext-tsp | ||
# RUN: llvm-objdump --syms %t.bolt | FileCheck %s --check-prefix=CHECK-SYMS-WARM | # RUN: llvm-objdump --syms %t.bolt | FileCheck %s --check-prefix=CHECK-SYMS-WARM | ||
+# CHECK-SYMS-WARM: 0000000000000000 | |||
# CHECK-SYMS-WARM: .text.warm | # CHECK-SYMS-WARM: .text.warm | ||
# CHECK-SYMS-WARM-SAME: chain.warm | # CHECK-SYMS-WARM-SAME: chain.warm | ||
# CHECK-SYMS-WARM: .text.cold | # CHECK-SYMS-WARM: .text.cold |
@@ -3,35 +3,42 @@ | |||
# RUN: split-file %s %t | # RUN: split-file %s %t | ||
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/main.s -o %t.o | # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/main.s -o %t.o | ||
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/baz.s -o %t.baz.o | # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/baz.s -o %t.baz.o | ||
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/baz2.s -o %t.baz2.o | |||
# RUN: link_fdata %s %t.o %t.main.fdata | # RUN: link_fdata %s %t.o %t.main.fdata | ||
# RUN: link_fdata %s %t.baz.o %t.baz.fdata | # RUN: link_fdata %s %t.baz.o %t.baz.fdata | ||
-# RUN: merge-fdata %t.main.fdata %t.baz.fdata > %t.fdata | +# RUN: link_fdata %s %t.baz2.o %t.baz2.fdata | ||
-# RUN: %clang %cflags %t.o %t.baz.o -o %t.exe -Wl,-q | +# RUN: merge-fdata %t.main.fdata %t.baz.fdata %t.baz2.fdata > %t.fdata | ||
+# RUN: %clang %cflags %t.o %t.baz.o %t.baz2.o -o %t.exe -Wl,-q | |||
# RUN: llvm-bolt %t.exe -o %t.out --lite=1 --data %t.fdata -v=1 -print-cfg \ | # RUN: llvm-bolt %t.exe -o %t.out --lite=1 --data %t.fdata -v=1 -print-cfg \ | ||
# RUN: 2>&1 | FileCheck %s | # RUN: 2>&1 | FileCheck %s | ||
# CHECK: BOLT-INFO: processing main.cold.1 as a sibling of non-ignored function | # CHECK: BOLT-INFO: processing main.cold.1 as a sibling of non-ignored function | ||
-# CHECK: BOLT-INFO: processing foo.cold.1/1 as a sibling of non-ignored function | +# CHECK: BOLT-INFO: processing foo.cold.1/1(*2) as a sibling of non-ignored function | ||
-# CHECK: BOLT-INFO: processing bar.cold.1/1 as a sibling of non-ignored function | +# CHECK: BOLT-INFO: processing bar.cold.1/1(*2) as a sibling of non-ignored function | ||
# CHECK: BOLT-INFO: processing baz.cold.1 as a sibling of non-ignored function | # CHECK: BOLT-INFO: processing baz.cold.1 as a sibling of non-ignored function | ||
-# CHECK: BOLT-INFO: processing baz.cold.1/1 as a sibling of non-ignored function | +# CHECK: BOLT-INFO: processing baz.cold.1/1(*2) as a sibling of non-ignored function | ||
+# CHECK: BOLT-INFO: processing baz.cold.1/2(*2) as a sibling of non-ignored function | |||
# CHECK: Binary Function "main.cold.1" after building cfg | # CHECK: Binary Function "main.cold.1" after building cfg | ||
# CHECK: Parent : main | # CHECK: Parent : main | ||
-# CHECK: Binary Function "foo.cold.1/ | +# CHECK: Binary Function "foo.cold.1/1(*2)" after building cfg | ||
# CHECK: Parent : foo | # CHECK: Parent : foo | ||
-# CHECK: Binary Function "bar.cold.1/ | +# CHECK: Binary Function "bar.cold.1/1(*2)" after building cfg | ||
-# CHECK: Parent : bar/1 | +# CHECK: Parent : bar/1(*2) | ||
# CHECK: Binary Function "baz.cold.1" after building cfg | # CHECK: Binary Function "baz.cold.1" after building cfg | ||
# CHECK: Parent : baz{{$}} | # CHECK: Parent : baz{{$}} | ||
-# CHECK: Binary Function "baz.cold.1/ | +# CHECK: Binary Function "baz.cold.1/1(*2)" after building cfg | ||
-# CHECK: Parent : baz/1 | +# CHECK: Parent : baz/1(*2) | ||
+ | |||
+# CHECK: Binary Function "baz.cold.1/2(*2)" after building cfg | |||
+# CHECK: Parent : baz/2(*2) | |||
#--- main.s | #--- main.s | ||
+.file "main.s" | |||
.globl main | .globl main | ||
.type main, %function | .type main, %function | ||
main: | main: | ||
@@ -126,6 +133,7 @@ baz.cold.1: | |||
.size baz.cold.1, .-baz.cold.1 | .size baz.cold.1, .-baz.cold.1 | ||
#--- baz.s | #--- baz.s | ||
+.file "baz.s" | |||
.local baz | .local baz | ||
.type baz, %function | .type baz, %function | ||
baz: | baz: | ||
@@ -149,3 +157,29 @@ baz.cold.1: | |||
retq | retq | ||
.cfi_endproc | .cfi_endproc | ||
.size baz.cold.1, .-baz.cold.1 | .size baz.cold.1, .-baz.cold.1 | ||
+ | |||
+#--- baz2.s | |||
+.file "baz2.s" | |||
+ .local baz | |||
+ .type baz, %function | |||
+baz: | |||
+ .cfi_startproc | |||
+# FDATA: 0 [unknown] 0 1 baz/2 0 1 0 | |||
+ cmpl $0x0, %eax | |||
+ je baz.cold.1 | |||
+ retq | |||
+ .cfi_endproc | |||
+.size baz, .-baz | |||
+ | |||
+ .section .text.cold | |||
+ .local baz.cold.1 | |||
+ .type baz.cold.1, %function | |||
+baz.cold.1: | |||
+ .cfi_startproc | |||
+ pushq %rbp | |||
+ movq %rsp, %rbp | |||
+ movl $0x0, %eax | |||
+ popq %rbp | |||
+ retq | |||
+ .cfi_endproc | |||
+.size baz.cold.1, .-baz.cold.1 |
@@ -0,0 +1,16 @@ | |||
+# Check that llvm-bolt fails to process PIC binaries with computed goto, as the | |||
+# support is not there yet for correctly updating dynamic relocations | |||
+# referencing code inside functions. | |||
+ | |||
+REQUIRES: x86_64-linux | |||
+ | |||
+RUN: %clang %S/Inputs/indirect_goto.c -o %t -fpic -pie -Wl,-q | |||
+RUN: not llvm-bolt %t -o %t.bolt --relocs=1 --print-cfg --print-only=main \ | |||
+RUN: |& FileCheck %s | |||
+ | |||
+# Check that processing works if main() is skipped. | |||
+RUN: llvm-bolt %t -o %t.bolt --relocs=1 --skip-funcs=main | |||
+ | |||
+CHECK: jmpq *%rax # UNKNOWN CONTROL FLOW | |||
+ | |||
+CHECK: BOLT-ERROR: unable to get new address |
@@ -11,7 +11,14 @@ REQUIRES: system-linux | |||
RUN: yaml2obj %p/Inputs/blarge.yaml &> %t.exe | RUN: yaml2obj %p/Inputs/blarge.yaml &> %t.exe | ||
RUN: perf2bolt %t.exe -o %t --pa -p %p/Inputs/pre-aggregated.txt -w %t.new \ | RUN: perf2bolt %t.exe -o %t --pa -p %p/Inputs/pre-aggregated.txt -w %t.new \ | ||
-RUN: --profile-use-dfs | +RUN: --profile-use-dfs | FileCheck %s | ||
+ | |||
+RUN: llvm-bolt %t.exe -data %t -o %t.null | FileCheck %s | |||
+RUN: llvm-bolt %t.exe -data %t.new -o %t.null | FileCheck %s | |||
+RUN: llvm-bolt %t.exe -p %p/Inputs/pre-aggregated.txt --pa -o %t.null | FileCheck %s | |||
+ | |||
+CHECK: BOLT-INFO: 4 out of 7 functions in the binary (57.1%) have non-empty execution profile | |||
+ | |||
RUN: cat %t | sort | FileCheck %s -check-prefix=PERF2BOLT | RUN: cat %t | sort | FileCheck %s -check-prefix=PERF2BOLT | ||
RUN: cat %t.new | FileCheck %s -check-prefix=NEWFORMAT | RUN: cat %t.new | FileCheck %s -check-prefix=NEWFORMAT | ||
@@ -0,0 +1,32 @@ | |||
+# Test the heuristics for matching BOLT-added split functions. | |||
+ | |||
+# RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %S/cdsplit-symbol-names.s -o %t.main.o | |||
+# RUN: llvm-mc --filetype=obj --triple x86_64-unknown-unknown %s -o %t.chain.o | |||
+# RUN: link_fdata %S/cdsplit-symbol-names.s %t.main.o %t.fdata | |||
+# RUN: sed -i 's|chain|chain/2|g' %t.fdata | |||
+# RUN: llvm-strip --strip-unneeded %t.main.o | |||
+# RUN: llvm-objcopy --localize-symbol=chain %t.main.o | |||
+# RUN: %clang %cflags %t.chain.o %t.main.o -o %t.exe -Wl,-q | |||
+# RUN: llvm-bolt %t.exe -o %t.bolt --split-functions --split-strategy=randomN \ | |||
+# RUN: --reorder-blocks=ext-tsp --enable-bat --bolt-seed=7 --data=%t.fdata | |||
+# RUN: llvm-objdump --syms %t.bolt | FileCheck %s --check-prefix=CHECK-SYMS | |||
+ | |||
+# RUN: link_fdata %s %t.bolt %t.preagg PREAGG | |||
+# PREAGG: B X:0 #chain.cold.0# 1 0 | |||
+# RUN: perf2bolt %t.bolt -p %t.preagg --pa -o %t.bat.fdata -w %t.bat.yaml -v=1 \ | |||
+# RUN: | FileCheck %s --check-prefix=CHECK-REGISTER | |||
+ | |||
+# CHECK-SYMS: l df *ABS* [[#]] chain.s | |||
+# CHECK-SYMS: l F .bolt.org.text [[#]] chain | |||
+# CHECK-SYMS: l F .text.cold [[#]] chain.cold.0 | |||
+# CHECK-SYMS: l F .text [[#]] chain | |||
+# CHECK-SYMS: l df *ABS* [[#]] bolt-pseudo.o | |||
+ | |||
+# CHECK-REGISTER: BOLT-INFO: marking chain.cold.0/1(*2) as a fragment of chain/2(*2) | |||
+ | |||
+.file "chain.s" | |||
+ .text | |||
+ .type chain, @function | |||
+chain: | |||
+ ret | |||
+ .size chain, .-chain |
@@ -53,6 +53,6 @@ end_if_1: | |||
.size _start, .-_start | .size _start, .-_start | ||
.data | .data | ||
-rel: .quad | +rel: .quad _start | ||
# CHECK: BOLT-INFO: Shrink wrapping moved 0 spills inserting load/stores and 0 spills inserting push/pops | # CHECK: BOLT-INFO: Shrink wrapping moved 0 spills inserting load/stores and 0 spills inserting push/pops |
@@ -1,18 +0,0 @@ | |||
-int main(int argc, char *argv[]) { | |||
- static const void *T1[] = { &&L1, &&L2 }; | |||
- static const void *T2[] = { &&L2, &&L3 }; | |||
- | |||
- const void **T = (argc > 1) ? T1 : T2; | |||
- | |||
- int i = 0; | |||
- | |||
-L0: | |||
- goto *T[argc]; | |||
-L1: | |||
- ++i; | |||
-L2: | |||
- i++; | |||
-L3: | |||
- i++; | |||
- return i; | |||
-} |
@@ -1,10 +0,0 @@ | |||
-# Check llvm-bolt processes binaries compiled from sources that use indirect goto. | |||
-REQUIRES: x86_64-linux | |||
- | |||
-RUN: %clang %S/Inputs/indirect_goto.c -o %t -fpic -pie -Wl,-q | |||
-RUN: llvm-bolt %t -o %t.bolt --relocs=1 --print-cfg --print-only=main \ | |||
-RUN: |& FileCheck %s | |||
-# The test fails as we don't update corresponding dynamic relocations. | |||
-RUN: not %t.bolt | |||
- | |||
-CHECK: jmpq *%rax # UNKNOWN CONTROL FLOW |
@@ -967,7 +967,8 @@ approximateStand | |||
// Get out the qualifiers of the original type. This will always be | // Get out the qualifiers of the original type. This will always be | ||
// re-applied to the WorkType to ensure it is the same qualification as the | // re-applied to the WorkType to ensure it is the same qualification as the | ||
// original From was. | // original From was. | ||
- auto QualifiersToAppl | + auto FastQualifiersTo | ||
+ From.split().Quals.getAsOpaqueValue | |||
// LValue->RValue is irrelevant for the check, because it is a thing to be | // LValue->RValue is irrelevant for the check, because it is a thing to be | ||
// done at a call site, and will be performed if need be performed. | // done at a call site, and will be performed if need be performed. | ||
@@ -993,7 +994,7 @@ approximateStand | |||
// "const double -> double". | // "const double -> double". | ||
LLVM_DEBUG(llvm::dbgs() | LLVM_DEBUG(llvm::dbgs() | ||
<< "--- approximateStdCo | << "--- approximateStdCo | ||
- WorkType = QualType{ToBuiltin, | + WorkType = QualType{ToBuiltin, FastQualifiersToApply}; | ||
} | } | ||
const auto *FromEnum = WorkType->getAs<EnumType>(); | const auto *FromEnum = WorkType->getAs<EnumType>(); | ||
@@ -1002,7 +1003,7 @@ approximateStand | |||
// Unscoped enumerations (or enumerations in C) convert to numerics. | // Unscoped enumerations (or enumerations in C) convert to numerics. | ||
LLVM_DEBUG(llvm::dbgs() | LLVM_DEBUG(llvm::dbgs() | ||
<< "--- approximateStdCo | << "--- approximateStdCo | ||
- WorkType = QualType{ToBuiltin, | + WorkType = QualType{ToBuiltin, FastQualifiersToApply}; | ||
} else if (FromNumeric && ToEnum && ToEnum->isUnscopedEnumer | } else if (FromNumeric && ToEnum && ToEnum->isUnscopedEnumer | ||
// Numeric types convert to enumerations only in C. | // Numeric types convert to enumerations only in C. | ||
if (Ctx.getLangOpts().CPlusPlus) { | if (Ctx.getLangOpts().CPlusPlus) { | ||
@@ -1013,7 +1014,7 @@ approximateStand | |||
LLVM_DEBUG(llvm::dbgs() | LLVM_DEBUG(llvm::dbgs() | ||
<< "--- approximateStdCo | << "--- approximateStdCo | ||
- WorkType = QualType{ToEnum, | + WorkType = QualType{ToEnum, FastQualifiersToApply}; | ||
} | } | ||
// Check for pointer conversions. | // Check for pointer conversions. | ||
@@ -1022,14 +1023,14 @@ approximateStand | |||
if (FromPtr && ToPtr) { | if (FromPtr && ToPtr) { | ||
if (ToPtr->isVoidPointerTyp | if (ToPtr->isVoidPointerTyp | ||
LLVM_DEBUG(llvm::dbgs() << "--- approximateStdCo | LLVM_DEBUG(llvm::dbgs() << "--- approximateStdCo | ||
- WorkType = QualType{ToPtr, | + WorkType = QualType{ToPtr, FastQualifiersToApply}; | ||
} | } | ||
const auto *FromRecordPtr = FromPtr->getPointeeCXXRec | const auto *FromRecordPtr = FromPtr->getPointeeCXXRec | ||
const auto *ToRecordPtr = ToPtr->getPointeeCXXRec | const auto *ToRecordPtr = ToPtr->getPointeeCXXRec | ||
if (isDerivedToBase(FromRecordPtr, ToRecordPtr)) { | if (isDerivedToBase(FromRecordPtr, ToRecordPtr)) { | ||
LLVM_DEBUG(llvm::dbgs() << "--- approximateStdCo | LLVM_DEBUG(llvm::dbgs() << "--- approximateStdCo | ||
- WorkType = QualType{ToPtr, | + WorkType = QualType{ToPtr, FastQualifiersToApply}; | ||
} | } | ||
} | } | ||
@@ -1039,7 +1040,7 @@ approximateStand | |||
const auto *ToRecord = To->getAsCXXRecordDe | const auto *ToRecord = To->getAsCXXRecordDe | ||
if (isDerivedToBase(FromRecord, ToRecord)) { | if (isDerivedToBase(FromRecord, ToRecord)) { | ||
LLVM_DEBUG(llvm::dbgs() << "--- approximateStdCo | LLVM_DEBUG(llvm::dbgs() << "--- approximateStdCo | ||
- WorkType = QualType{ToRecord->getTypeForDecl(), | + WorkType = QualType{ToRecord->getTypeForDecl(), FastQualifiersToApply}; | ||
} | } | ||
if (Ctx.getLangOpts().CPlusPlus17 && FromPtr && ToPtr) { | if (Ctx.getLangOpts().CPlusPlus17 && FromPtr && ToPtr) { | ||
@@ -1054,7 +1055,7 @@ approximateStand | |||
!ToFunctionPtr->hasNoexceptExcep | !ToFunctionPtr->hasNoexceptExcep | ||
LLVM_DEBUG(llvm::dbgs() << "--- approximateStdCo | LLVM_DEBUG(llvm::dbgs() << "--- approximateStdCo | ||
"pointer to non-noexcept.\n"); | "pointer to non-noexcept.\n"); | ||
- WorkType = QualType{ToPtr, | + WorkType = QualType{ToPtr, FastQualifiersToApply}; | ||
} | } | ||
} | } | ||
@@ -16,6 +16,7 @@ add_clang_librar | |||
MakeSharedCheck.cpp | MakeSharedCheck.cpp | ||
MakeSmartPtrChec | MakeSmartPtrChec | ||
MakeUniqueCheck.cpp | MakeUniqueCheck.cpp | ||
+ MinMaxUseInitial | |||
ModernizeTidyMod | ModernizeTidyMod | ||
PassByValueCheck | PassByValueCheck | ||
RawStringLiteral | RawStringLiteral |
@@ -0,0 +1,271 @@ | |||
+//===--- MinMaxUseInitial | |||
+// | |||
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
+// See https://llvm.org/LICENSE.txt for license information. | |||
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
+// | |||
+//===----------------------------------------------------------------------===// | |||
+ | |||
+#include "MinMaxUseInitial | |||
+#include "../utils/ASTUtils.h" | |||
+#include "../utils/LexerUtils.h" | |||
+#include "clang/ASTMatchers/ASTMatchFinder.h" | |||
+#include "clang/Frontend/CompilerInstance | |||
+#include "clang/Lex/Lexer.h" | |||
+ | |||
+using namespace clang; | |||
+ | |||
+namespace { | |||
+ | |||
+struct FindArgsResult { | |||
+ const Expr *First; | |||
+ const Expr *Last; | |||
+ const Expr *Compare; | |||
+ SmallVector<const clang::Expr *, 2> Args; | |||
+}; | |||
+ | |||
+} // anonymous namespace | |||
+ | |||
+using namespace clang::ast_matchers; | |||
+ | |||
+namespace clang::tidy::modernize { | |||
+ | |||
+static FindArgsResult findArgs(const CallExpr *Call) { | |||
+ FindArgsResult Result; | |||
+ Result.First = nullptr; | |||
+ Result.Last = nullptr; | |||
+ Result.Compare = nullptr; | |||
+ | |||
+ // check if the function has initializer list argument | |||
+ if (Call->getNumArgs() < 3) { | |||
+ auto ArgIterator = Call->arguments().begin(); | |||
+ | |||
+ const auto *InitListExpr = | |||
+ dyn_cast<CXXStdInitialize | |||
+ const auto *InitList = | |||
+ InitListExpr != nullptr | |||
+ ? dyn_cast<clang::InitListExpr>( | |||
+ InitListExpr->getSubExpr()->IgnoreImplicit()) | |||
+ : nullptr; | |||
+ | |||
+ if (InitList) { | |||
+ Result.Args.append(InitList->inits().begin(), InitList->inits().end()); | |||
+ Result.First = *ArgIterator; | |||
+ Result.Last = *ArgIterator; | |||
+ | |||
+ // check if there is a comparison argument | |||
+ std::advance(ArgIterator, 1); | |||
+ if (ArgIterator != Call->arguments().end()) | |||
+ Result.Compare = *ArgIterator; | |||
+ | |||
+ return Result; | |||
+ } | |||
+ Result.Args = SmallVector<const Expr *>(Call->arguments()); | |||
+ } else { | |||
+ // if it has 3 arguments then the last will be the comparison | |||
+ Result.Compare = *(std::next(Call->arguments().begin(), 2)); | |||
+ Result.Args = SmallVector<const Expr *>(llvm::drop_end(Call->arguments())); | |||
+ } | |||
+ Result.First = Result.Args.front(); | |||
+ Result.Last = Result.Args.back(); | |||
+ | |||
+ return Result; | |||
+} | |||
+ | |||
+static SmallVector<FixItHint> | |||
+generateReplacem | |||
+ const CallExpr *TopCall, const FindArgsResult &Result, | |||
+ const bool IgnoreNonTrivial | |||
+ const std::uint64_t IgnoreTrivialTyp | |||
+ SmallVector<FixItHint> FixItHints; | |||
+ const SourceManager &SourceMngr = *Match.SourceManager; | |||
+ const LangOptions &LanguageOpts = Match.Context->getLangOpts(); | |||
+ | |||
+ const QualType ResultType = TopCall->getDirectCallee() | |||
+ ->getReturnType() | |||
+ .getCanonicalType | |||
+ .getNonReferenceT | |||
+ .getUnqualifiedTy | |||
+ | |||
+ // check if the type is trivial | |||
+ const bool IsResultTypeTriv | |||
+ | |||
+ if ((!IsResultTypeTriv | |||
+ return FixItHints; | |||
+ | |||
+ if (IsResultTypeTriv | |||
+ static_cast<std::uint64_t>( | |||
+ Match.Context->getTypeSizeInCha | |||
+ IgnoreTrivialTyp | |||
+ return FixItHints; | |||
+ | |||
+ for (const Expr *Arg : Result.Args) { | |||
+ const auto *InnerCall = dyn_cast<CallExpr>(Arg->IgnoreParenImpCa | |||
+ | |||
+ // If the argument is not a nested call | |||
+ if (!InnerCall) { | |||
+ // check if typecast is required | |||
+ const QualType ArgType = Arg->IgnoreParenImpCa | |||
+ ->getType() | |||
+ .getCanonicalType | |||
+ .getUnqualifiedTy | |||
+ | |||
+ if (ArgType == ResultType) | |||
+ continue; | |||
+ | |||
+ const StringRef ArgText = Lexer::getSourceText( | |||
+ CharSourceRange::getTokenRange(Arg->getSourceRange()), SourceMngr, | |||
+ LanguageOpts); | |||
+ | |||
+ const auto Replacement = Twine("static_cast<") | |||
+ .concat(ResultType.getAsString(LanguageOpts)) | |||
+ .concat(">(") | |||
+ .concat(ArgText) | |||
+ .concat(")") | |||
+ .str(); | |||
+ | |||
+ FixItHints.push_back( | |||
+ FixItHint::CreateReplacemen | |||
+ continue; | |||
+ } | |||
+ | |||
+ const FindArgsResult InnerResult = findArgs(InnerCall); | |||
+ | |||
+ // if the nested call doesn't have arguments skip it | |||
+ if (!InnerResult.First || !InnerResult.Last) | |||
+ continue; | |||
+ | |||
+ // if the nested call is not the same as the top call | |||
+ if (InnerCall->getDirectCallee()->getQualifiedName | |||
+ TopCall->getDirectCallee()->getQualifiedName | |||
+ continue; | |||
+ | |||
+ // if the nested call doesn't have the same compare function | |||
+ if ((Result.Compare || InnerResult.Compare) && | |||
+ !utils::areStatementsIde | |||
+ *Match.Context)) | |||
+ continue; | |||
+ | |||
+ // remove the function call | |||
+ FixItHints.push_back( | |||
+ FixItHint::CreateRemoval(InnerCall->getCallee()->getSourceRange())); | |||
+ | |||
+ // remove the parentheses | |||
+ const auto LParen = utils::lexer::findNextTokenSki | |||
+ InnerCall->getCallee()->getEndLoc(), SourceMngr, LanguageOpts); | |||
+ if (LParen.has_value() && LParen->is(tok::l_paren)) | |||
+ FixItHints.push_back( | |||
+ FixItHint::CreateRemoval(SourceRange(LParen->getLocation()))); | |||
+ FixItHints.push_back( | |||
+ FixItHint::CreateRemoval(SourceRange(InnerCall->getRParenLoc()))); | |||
+ | |||
+ // if the inner call has an initializer list arg | |||
+ if (InnerResult.First == InnerResult.Last) { | |||
+ // remove the initializer list braces | |||
+ FixItHints.push_back(FixItHint::CreateRemoval( | |||
+ CharSourceRange::getTokenRange(InnerResult.First->getBeginLoc()))); | |||
+ FixItHints.push_back(FixItHint::CreateRemoval( | |||
+ CharSourceRange::getTokenRange(InnerResult.First->getEndLoc()))); | |||
+ } | |||
+ | |||
+ const SmallVector<FixItHint> InnerReplacement | |||
+ Match, InnerCall, InnerResult, IgnoreNonTrivial | |||
+ IgnoreTrivialTyp | |||
+ | |||
+ FixItHints.append(InnerReplacement | |||
+ | |||
+ if (InnerResult.Compare) { | |||
+ // find the comma after the value arguments | |||
+ const auto Comma = utils::lexer::findNextTokenSki | |||
+ InnerResult.Last->getEndLoc(), SourceMngr, LanguageOpts); | |||
+ | |||
+ // remove the comma and the comparison | |||
+ if (Comma.has_value() && Comma->is(tok::comma)) | |||
+ FixItHints.push_back( | |||
+ FixItHint::CreateRemoval(SourceRange(Comma->getLocation()))); | |||
+ | |||
+ FixItHints.push_back( | |||
+ FixItHint::CreateRemoval(InnerResult.Compare->getSourceRange())); | |||
+ } | |||
+ } | |||
+ | |||
+ return FixItHints; | |||
+} | |||
+ | |||
+MinMaxUseInitial | |||
+ StringRef Name, ClangTidyContext | |||
+ : ClangTidyCheck(Name, Context), | |||
+ IgnoreNonTrivial | |||
+ IgnoreTrivialTyp | |||
+ Options.get("IgnoreTrivialTyp | |||
+ Inserter(Options.getLocalOrGlobal | |||
+ utils::IncludeSorter::IS_LLVM), | |||
+ areDiagsSelfCont | |||
+ | |||
+void MinMaxUseInitial | |||
+ ClangTidyOptions | |||
+ Options.store(Opts, "IgnoreNonTrivial | |||
+ Options.store(Opts, "IgnoreTrivialTyp | |||
+ IgnoreTrivialTyp | |||
+ Options.store(Opts, "IncludeStyle", Inserter.getStyle()); | |||
+} | |||
+ | |||
+void MinMaxUseInitial | |||
+ auto CreateMatcher = [](const StringRef FunctionName) { | |||
+ auto FuncDecl = functionDecl(hasName(FunctionName)); | |||
+ auto Expression = callExpr(callee(FuncDecl)); | |||
+ | |||
+ return callExpr(callee(FuncDecl), | |||
+ anyOf(hasArgument(0, Expression), | |||
+ hasArgument(1, Expression), | |||
+ hasArgument(0, cxxStdInitialize | |||
+ unless(hasParent(Expression))) | |||
+ .bind("topCall"); | |||
+ }; | |||
+ | |||
+ Finder->addMatcher(CreateMatcher("::std::max"), this); | |||
+ Finder->addMatcher(CreateMatcher("::std::min"), this); | |||
+} | |||
+ | |||
+void MinMaxUseInitial | |||
+ const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP | |||
+ Inserter.registerPreproce | |||
+} | |||
+ | |||
+void MinMaxUseInitial | |||
+ const MatchFinder::MatchResult &Match) { | |||
+ | |||
+ const auto *TopCall = Match.Nodes.getNodeAs<CallExpr>("topCall"); | |||
+ | |||
+ const FindArgsResult Result = findArgs(TopCall); | |||
+ const SmallVector<FixItHint> Replacements = | |||
+ generateReplacem | |||
+ IgnoreTrivialTyp | |||
+ | |||
+ if (Replacements.empty()) | |||
+ return; | |||
+ | |||
+ const DiagnosticBuilde | |||
+ diag(TopCall->getBeginLoc(), | |||
+ "do not use nested 'std::%0' calls, use an initializer list instead") | |||
+ << TopCall->getDirectCallee()->getName() | |||
+ << Inserter.createIncludeIns | |||
+ Match.SourceManager->getFileID(TopCall->getBeginLoc()), | |||
+ "<algorithm>"); | |||
+ | |||
+ // if the top call doesn't have an initializer list argument | |||
+ if (Result.First != Result.Last) { | |||
+ // add { and } insertions | |||
+ Diagnostic << FixItHint::CreateInsertion(Result.First->getBeginLoc(), "{"); | |||
+ | |||
+ Diagnostic << FixItHint::CreateInsertion( | |||
+ Lexer::getLocForEndOfTo | |||
+ *Match.SourceManager, | |||
+ Match.Context->getLangOpts()), | |||
+ "}"); | |||
+ } | |||
+ | |||
+ Diagnostic << Replacements; | |||
+} | |||
+ | |||
+} // namespace clang::tidy::modernize |
@@ -0,0 +1,56 @@ | |||
+//===--- MinMaxUseInitial | |||
+// | |||
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
+// See https://llvm.org/LICENSE.txt for license information. | |||
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
+// | |||
+//===----------------------------------------------------------------------===// | |||
+ | |||
+#ifndef LLVM_CLANG_TOOLS | |||
+#define LLVM_CLANG_TOOLS | |||
+ | |||
+#include "../ClangTidyCheck.h" | |||
+#include "../utils/IncludeInserter.h" | |||
+ | |||
+namespace clang::tidy::modernize { | |||
+ | |||
+/// Replaces nested ``std::min`` and ``std::max`` calls with an initializer list | |||
+/// where applicable. | |||
+/// | |||
+/// For example: | |||
+/// | |||
+/// \code | |||
+/// int a = std::max(std::max(i, j), k); | |||
+/// \endcode | |||
+/// | |||
+/// This code is transformed to: | |||
+/// | |||
+/// \code | |||
+/// int a = std::max({i, j, k}); | |||
+/// \endcode | |||
+class MinMaxUseInitial | |||
+public: | |||
+ MinMaxUseInitial | |||
+ | |||
+ void storeOptions(ClangTidyOptions | |||
+ void registerMatchers | |||
+ void registerPPCallba | |||
+ Preprocessor *ModuleExpanderPP | |||
+ void check(const ast_matchers::MatchFinder::MatchResult &Match) override; | |||
+ | |||
+ bool isLanguageVersio | |||
+ return LangOpts.CPlusPlus11; | |||
+ } | |||
+ std::optional<TraversalKind> getCheckTraversa | |||
+ return TK_IgnoreUnlessS | |||
+ } | |||
+ | |||
+private: | |||
+ bool IgnoreNonTrivial | |||
+ std::uint64_t IgnoreTrivialTyp | |||
+ utils::IncludeInserter Inserter; | |||
+}; | |||
+ | |||
+} // namespace clang::tidy::modernize | |||
+ | |||
+#endif // LLVM_CLANG_TOOLS |
@@ -18,6 +18,7 @@ | |||
#include "MacroToEnumCheck | #include "MacroToEnumCheck | ||
#include "MakeSharedCheck.h" | #include "MakeSharedCheck.h" | ||
#include "MakeUniqueCheck.h" | #include "MakeUniqueCheck.h" | ||
+#include "MinMaxUseInitial | |||
#include "PassByValueCheck | #include "PassByValueCheck | ||
#include "RawStringLiteral | #include "RawStringLiteral | ||
#include "RedundantVoidArg | #include "RedundantVoidArg | ||
@@ -68,6 +69,8 @@ public: | |||
CheckFactories.registerCheck<MacroToEnumCheck | CheckFactories.registerCheck<MacroToEnumCheck | ||
CheckFactories.registerCheck<MakeSharedCheck>("modernize-make-shared"); | CheckFactories.registerCheck<MakeSharedCheck>("modernize-make-shared"); | ||
CheckFactories.registerCheck<MakeUniqueCheck>("modernize-make-unique"); | CheckFactories.registerCheck<MakeUniqueCheck>("modernize-make-unique"); | ||
+ CheckFactories.registerCheck<MinMaxUseInitial | |||
+ "modernize-min-max-use-initializer-list"); | |||
CheckFactories.registerCheck<PassByValueCheck | CheckFactories.registerCheck<PassByValueCheck | ||
CheckFactories.registerCheck<UseDesignatedIni | CheckFactories.registerCheck<UseDesignatedIni | ||
"modernize-use-designated-initializers"); | "modernize-use-designated-initializers"); |
@@ -19,7 +19,7 @@ public: | |||
bool isLanguageVersio | bool isLanguageVersio | ||
// FIXME this should be CPlusPlus11 but that causes test cases to | // FIXME this should be CPlusPlus11 but that causes test cases to | ||
// erroneously fail. | // erroneously fail. | ||
- return LangOpts. | + return LangOpts.CPlusPlus || LangOpts.C23; | ||
} | } | ||
void storeOptions(ClangTidyOptions | void storeOptions(ClangTidyOptions | ||
void registerMatchers | void registerMatchers |
@@ -64,8 +64,11 @@ void AvoidReturnWithV | |||
<< BraceInsertionHi | << BraceInsertionHi | ||
} | } | ||
Diag << FixItHint::CreateRemoval(VoidReturn->getReturnLoc()); | Diag << FixItHint::CreateRemoval(VoidReturn->getReturnLoc()); | ||
- if (!Result.Nodes.getNodeAs<FunctionDecl>("function_parent") || | + const auto *FunctionParent = | ||
- SurroundingBlock | + Result.Nodes.getNodeAs<FunctionDecl>("function_parent"); | ||
+ if (!FunctionParent || | |||
+ (SurroundingBlock | |||
+ // If this is not the last statement in a function body, we add a `return`. | |||
Diag << FixItHint::CreateInsertion(SemicolonPos.getLocWithOffset | Diag << FixItHint::CreateInsertion(SemicolonPos.getLocWithOffset | ||
" return;", true); | " return;", true); | ||
} | } |
@@ -28,6 +28,7 @@ add_clang_librar | |||
IsolateDeclarati | IsolateDeclarati | ||
MagicNumbersChec | MagicNumbersChec | ||
MakeMemberFuncti | MakeMemberFuncti | ||
+ MathMissingParen | |||
MisleadingIndent | MisleadingIndent | ||
MisplacedArrayIn | MisplacedArrayIn | ||
NamedParameterCh | NamedParameterCh |
@@ -0,0 +1,99 @@ | |||
+//===--- MathMissingParen | |||
+// | |||
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
+// See https://llvm.org/LICENSE.txt for license information. | |||
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
+// | |||
+//===----------------------------------------------------------------------===// | |||
+ | |||
+#include "MathMissingParen | |||
+#include "clang/AST/ASTContext.h" | |||
+#include "clang/ASTMatchers/ASTMatchFinder.h" | |||
+#include "clang/Lex/Lexer.h" | |||
+ | |||
+using namespace clang::ast_matchers; | |||
+ | |||
+namespace clang::tidy::readability { | |||
+ | |||
+void MathMissingParen | |||
+ Finder->addMatcher(binaryOperator(unless(hasParent(binaryOperator())), | |||
+ unless(isAssignmentOper | |||
+ unless(isComparisonOper | |||
+ unless(hasAnyOperatorNa | |||
+ hasDescendant(binaryOperator())) | |||
+ .bind("binOp"), | |||
+ this); | |||
+} | |||
+ | |||
+static int getPrecedence(const BinaryOperator *BinOp) { | |||
+ if (!BinOp) | |||
+ return 0; | |||
+ switch (BinOp->getOpcode()) { | |||
+ case BO_Mul: | |||
+ case BO_Div: | |||
+ case BO_Rem: | |||
+ return 5; | |||
+ case BO_Add: | |||
+ case BO_Sub: | |||
+ return 4; | |||
+ case BO_And: | |||
+ return 3; | |||
+ case BO_Xor: | |||
+ return 2; | |||
+ case BO_Or: | |||
+ return 1; | |||
+ default: | |||
+ return 0; | |||
+ } | |||
+} | |||
+static void addParantheses(const BinaryOperator *BinOp, | |||
+ const BinaryOperator *ParentBinOp, | |||
+ ClangTidyCheck *Check, | |||
+ const clang::SourceManager &SM, | |||
+ const clang::LangOptions &LangOpts) { | |||
+ if (!BinOp) | |||
+ return; | |||
+ | |||
+ int Precedence1 = getPrecedence(BinOp); | |||
+ int Precedence2 = getPrecedence(ParentBinOp); | |||
+ | |||
+ if (ParentBinOp != nullptr && Precedence1 != Precedence2) { | |||
+ const clang::SourceLocation StartLoc = BinOp->getBeginLoc(); | |||
+ const clang::SourceLocation EndLoc = | |||
+ clang::Lexer::getLocForEndOfTo | |||
+ | |||
+ auto Diag = | |||
+ Check->diag(StartLoc, | |||
+ "'%0' has higher precedence than '%1'; add parentheses to " | |||
+ "explicitly specify the order of operations") | |||
+ << (Precedence1 > Precedence2 ? BinOp->getOpcodeStr() | |||
+ : ParentBinOp->getOpcodeStr()) | |||
+ << (Precedence1 > Precedence2 ? ParentBinOp->getOpcodeStr() | |||
+ : BinOp->getOpcodeStr()) | |||
+ << SourceRange(StartLoc, EndLoc); | |||
+ | |||
+ if (EndLoc.isValid()) { | |||
+ Diag << FixItHint::CreateInsertion(StartLoc, "(") | |||
+ << FixItHint::CreateInsertion(EndLoc, ")"); | |||
+ } | |||
+ } | |||
+ | |||
+ addParantheses(dyn_cast<BinaryOperator>(BinOp->getLHS()->IgnoreImpCasts()), | |||
+ BinOp, Check, SM, LangOpts); | |||
+ addParantheses(dyn_cast<BinaryOperator>(BinOp->getRHS()->IgnoreImpCasts()), | |||
+ BinOp, Check, SM, LangOpts); | |||
+} | |||
+ | |||
+void MathMissingParen | |||
+ const MatchFinder::MatchResult &Result) { | |||
+ const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binOp"); | |||
+ std::vector< | |||
+ std::pair<clang::SourceRange, std::pair<const clang::BinaryOperator *, | |||
+ const clang::BinaryOperator *>>> | |||
+ Insertions; | |||
+ const SourceManager &SM = *Result.SourceManager; | |||
+ const clang::LangOptions &LO = Result.Context->getLangOpts(); | |||
+ addParantheses(BinOp, nullptr, this, SM, LO); | |||
+} | |||
+ | |||
+} // namespace clang::tidy::readability |
@@ -0,0 +1,34 @@ | |||
+//===--- MathMissingParen | |||
+// | |||
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
+// See https://llvm.org/LICENSE.txt for license information. | |||
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
+// | |||
+//===----------------------------------------------------------------------===// | |||
+ | |||
+#ifndef LLVM_CLANG_TOOLS | |||
+#define LLVM_CLANG_TOOLS | |||
+ | |||
+#include "../ClangTidyCheck.h" | |||
+ | |||
+namespace clang::tidy::readability { | |||
+ | |||
+/// Check for mising parantheses in mathematical expressions that involve | |||
+/// operators of different priorities. | |||
+/// | |||
+/// For the user-facing documentation see: | |||
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability/math-missing-parentheses.html | |||
+class MathMissingParen | |||
+public: | |||
+ MathMissingParen | |||
+ : ClangTidyCheck(Name, Context) {} | |||
+ void registerMatchers | |||
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override; | |||
+ std::optional<TraversalKind> getCheckTraversa | |||
+ return TK_IgnoreUnlessS | |||
+ } | |||
+}; | |||
+ | |||
+} // namespace clang::tidy::readability | |||
+ | |||
+#endif // LLVM_CLANG_TOOLS |
@@ -32,6 +32,7 @@ | |||
#include "IsolateDeclarati | #include "IsolateDeclarati | ||
#include "MagicNumbersChec | #include "MagicNumbersChec | ||
#include "MakeMemberFuncti | #include "MakeMemberFuncti | ||
+#include "MathMissingParen | |||
#include "MisleadingIndent | #include "MisleadingIndent | ||
#include "MisplacedArrayIn | #include "MisplacedArrayIn | ||
#include "NamedParameterCh | #include "NamedParameterCh | ||
@@ -105,6 +106,8 @@ public: | |||
"readability-identifier-naming"); | "readability-identifier-naming"); | ||
CheckFactories.registerCheck<ImplicitBoolConv | CheckFactories.registerCheck<ImplicitBoolConv | ||
"readability-implicit-bool-conversion"); | "readability-implicit-bool-conversion"); | ||
+ CheckFactories.registerCheck<MathMissingParen | |||
+ "readability-math-missing-parentheses"); | |||
CheckFactories.registerCheck<RedundantInlineS | CheckFactories.registerCheck<RedundantInlineS | ||
"readability-redundant-inline-specifier"); | "readability-redundant-inline-specifier"); | ||
CheckFactories.registerCheck<InconsistentDecl | CheckFactories.registerCheck<InconsistentDecl |
@@ -253,7 +253,7 @@ void getSignature(con | |||
if (!IncludeFunctionA | if (!IncludeFunctionA | ||
ResultKind == CodeCompletionRe | ResultKind == CodeCompletionRe | ||
TruncateSnippetA | TruncateSnippetA | ||
- LLVM_FALLTHROUGH | + [[fallthrough]]; | ||
case CodeCompletionSt | case CodeCompletionSt | ||
case CodeCompletionSt | case CodeCompletionSt | ||
case CodeCompletionSt | case CodeCompletionSt |
@@ -854,7 +854,7 @@ TEST_F(TargetDec | |||
} | } | ||
}; | }; | ||
)cpp"; | )cpp"; | ||
- EXPECT_DECLS( | + EXPECT_DECLS("MemberExpr", "void foo()"); | ||
// Similar to above but base expression involves a function call. | // Similar to above but base expression involves a function call. | ||
Code = R"cpp( | Code = R"cpp( | ||
@@ -872,7 +872,7 @@ TEST_F(TargetDec | |||
} | } | ||
}; | }; | ||
)cpp"; | )cpp"; | ||
- EXPECT_DECLS( | + EXPECT_DECLS("MemberExpr", "void foo()"); | ||
// Similar to above but uses a function pointer. | // Similar to above but uses a function pointer. | ||
Code = R"cpp( | Code = R"cpp( | ||
@@ -891,7 +891,7 @@ TEST_F(TargetDec | |||
} | } | ||
}; | }; | ||
)cpp"; | )cpp"; | ||
- EXPECT_DECLS( | + EXPECT_DECLS("MemberExpr", "void foo()"); | ||
// Base expression involves a member access into this. | // Base expression involves a member access into this. | ||
Code = R"cpp( | Code = R"cpp( | ||
@@ -962,7 +962,7 @@ TEST_F(TargetDec | |||
void Foo() { this->[[find]](); } | void Foo() { this->[[find]](); } | ||
}; | }; | ||
)cpp"; | )cpp"; | ||
- EXPECT_DECLS( | + EXPECT_DECLS("MemberExpr", "void find()"); | ||
} | } | ||
TEST_F(TargetDeclTest, DependentTypes) { | TEST_F(TargetDeclTest, DependentTypes) { |
@@ -621,7 +621,7 @@ sizeof...($Templ | |||
struct $Class_def[[Foo]] { | struct $Class_def[[Foo]] { | ||
int $Field_decl[[Waldo]]; | int $Field_decl[[Waldo]]; | ||
void $Method_def[[bar]]() { | void $Method_def[[bar]]() { | ||
- $Class[[Foo]](). | + $Class[[Foo]]().$Field[[Waldo]]; | ||
} | } | ||
template $Bracket[[<]]typename $TemplateParamete | template $Bracket[[<]]typename $TemplateParamete | ||
void $Method_def[[bar1]]() { | void $Method_def[[bar1]]() { |
@@ -100,13 +100,15 @@ Improvements to clang-tidy | |||
- Improved :program:`run-clang-tidy.py` script. Added argument `-source-filter` | - Improved :program:`run-clang-tidy.py` script. Added argument `-source-filter` | ||
to filter source files from the compilation database, via a RegEx. In a | to filter source files from the compilation database, via a RegEx. In a | ||
similar fashion to what `-header-filter` does for header files. | similar fashion to what `-header-filter` does for header files. | ||
+ | |||
- Improved :program:`check_clang_tidy | - Improved :program:`check_clang_tidy | ||
to aid in clang-tidy and test development. | to aid in clang-tidy and test development. | ||
+ | |||
- Fixed bug where big values for unsigned check options overflowed into negative values | - Fixed bug where big values for unsigned check options overflowed into negative values | ||
- when being printed with | + when being printed with `--dump-config`. | ||
-- Fixed | +- Fixed `--verify-config` option not properly parsing checks when using the | ||
- literal operator in the | + literal operator in the `.clang-tidy` config. | ||
New checks | New checks | ||
^^^^^^^^^^ | ^^^^^^^^^^ | ||
@@ -131,6 +133,12 @@ New checks | |||
to reading out-of-bounds data due to inadequate or incorrect string null | to reading out-of-bounds data due to inadequate or incorrect string null | ||
termination. | termination. | ||
+- New :doc:`modernize-min-max-use-initializer-list | |||
+ <clang-tidy/checks/modernize/min-max-use-initializer-list>` check. | |||
+ | |||
+ Replaces nested ``std::min`` and ``std::max`` calls with an initializer list | |||
+ where applicable. | |||
+ | |||
- New :doc:`modernize-use-designated-initializers | - New :doc:`modernize-use-designated-initializers | ||
<clang-tidy/checks/modernize/use-designated-initializers>` check. | <clang-tidy/checks/modernize/use-designated-initializers>` check. | ||
@@ -143,6 +151,12 @@ New checks | |||
Enforces consistent style for enumerators' initialization, covering three | Enforces consistent style for enumerators' initialization, covering three | ||
styles: none, first only, or all initialized explicitly. | styles: none, first only, or all initialized explicitly. | ||
+- New :doc:`readability-math-missing-parentheses | |||
+ <clang-tidy/checks/readability/math-missing-parentheses>` check. | |||
+ | |||
+ Check for missing parentheses in mathematical expressions that involve | |||
+ operators of different priorities. | |||
+ | |||
- New :doc:`readability-use-std-min-max | - New :doc:`readability-use-std-min-max | ||
<clang-tidy/checks/readability/use-std-min-max>` check. | <clang-tidy/checks/readability/use-std-min-max>` check. | ||
@@ -224,7 +238,7 @@ Changes in existing checks | |||
- Improved :doc:`google-explicit-constructor | - Improved :doc:`google-explicit-constructor | ||
<clang-tidy/checks/google/explicit-constructor>` check to better handle | <clang-tidy/checks/google/explicit-constructor>` check to better handle | ||
- | + C++20 `explicit(bool)`. | ||
- Improved :doc:`google-global-names-in-headers | - Improved :doc:`google-global-names-in-headers | ||
<clang-tidy/checks/google/global-names-in-headers>` check by replacing the local | <clang-tidy/checks/google/global-names-in-headers>` check by replacing the local | ||
@@ -237,13 +251,18 @@ Changes in existing checks | |||
check by ignoring other functions with same prefixes as the target specific | check by ignoring other functions with same prefixes as the target specific | ||
functions. | functions. | ||
+- Improved :doc:`linuxkernel-must-check-errs | |||
+ <clang-tidy/checks/linuxkernel/must-check-errs>` check documentation to | |||
+ consistently use the check's proper name. | |||
+ | |||
- Improved :doc:`llvm-header-guard | - Improved :doc:`llvm-header-guard | ||
<clang-tidy/checks/llvm/header-guard>` check by replacing the local | <clang-tidy/checks/llvm/header-guard>` check by replacing the local | ||
option `HeaderFileExtens | option `HeaderFileExtens | ||
- Improved :doc:`misc-const-correctness | - Improved :doc:`misc-const-correctness | ||
<clang-tidy/checks/misc/const-correctness>` check by avoiding infinite recursion | <clang-tidy/checks/misc/const-correctness>` check by avoiding infinite recursion | ||
- for recursive forwarding reference | + for recursive functions with forwarding reference parameters and reference | ||
+ variables which refer to themselves. | |||
- Improved :doc:`misc-definitions-in-headers | - Improved :doc:`misc-definitions-in-headers | ||
<clang-tidy/checks/misc/definitions-in-headers>` check by replacing the local | <clang-tidy/checks/misc/definitions-in-headers>` check by replacing the local | ||
@@ -269,6 +288,10 @@ Changes in existing checks | |||
don't remove parentheses used in ``sizeof`` calls when they have array index | don't remove parentheses used in ``sizeof`` calls when they have array index | ||
accesses as arguments. | accesses as arguments. | ||
+- Improved :doc:`modernize-use-nullptr | |||
+ <clang-tidy/checks/modernize/use-nullptr>` check to include support for C23, | |||
+ which also has introduced the ``nullptr`` keyword. | |||
+ | |||
- Improved :doc:`modernize-use-override | - Improved :doc:`modernize-use-override | ||
<clang-tidy/checks/modernize/use-override>` check to also remove any trailing | <clang-tidy/checks/modernize/use-override>` check to also remove any trailing | ||
whitespace when deleting the ``virtual`` keyword. | whitespace when deleting the ``virtual`` keyword. | ||
@@ -324,13 +347,9 @@ Miscellaneous | |||
^^^^^^^^^^^^^ | ^^^^^^^^^^^^^ | ||
- Fixed incorrect formatting in :program:`clang-apply-replacements` when no | - Fixed incorrect formatting in :program:`clang-apply-replacements` when no | ||
- | + `--format` option is specified. Now :program:`clang-apply-replacements` | ||
applies formatting only with the option. | applies formatting only with the option. | ||
-- Fixed the :doc:`linuxkernel-must-check-errs | |||
- <clang-tidy/checks/linuxkernel/must-check-errs>` documentation to consistently | |||
- use the check's proper name. | |||
- | |||
Improvements to include-fixer | Improvements to include-fixer | ||
----------------------------- | ----------------------------- | ||
@@ -10,4 +10,4 @@ but does not actually attempt to execute a command. | |||
This check corresponds to the CERT C Coding Standard rule | This check corresponds to the CERT C Coding Standard rule | ||
`ENV33-C. Do not call system() | `ENV33-C. Do not call system() | ||
-<https://www.securecoding.cert.org/confluence/ | +<https://www.securecoding.cert.org/confluence/display/c/ENV33-C.+Do+not+call+system()>`_. |
@@ -276,6 +276,7 @@ Clang-Tidy Checks | |||
:doc:`modernize-macro-to-enum <modernize/macro-to-enum>`, "Yes" | :doc:`modernize-macro-to-enum <modernize/macro-to-enum>`, "Yes" | ||
:doc:`modernize-make-shared <modernize/make-shared>`, "Yes" | :doc:`modernize-make-shared <modernize/make-shared>`, "Yes" | ||
:doc:`modernize-make-unique <modernize/make-unique>`, "Yes" | :doc:`modernize-make-unique <modernize/make-unique>`, "Yes" | ||
+ :doc:`modernize-min-max-use-initializer-list <modernize/min-max-use-initializer-list>`, "Yes" | |||
:doc:`modernize-pass-by-value <modernize/pass-by-value>`, "Yes" | :doc:`modernize-pass-by-value <modernize/pass-by-value>`, "Yes" | ||
:doc:`modernize-raw-string-literal <modernize/raw-string-literal>`, "Yes" | :doc:`modernize-raw-string-literal <modernize/raw-string-literal>`, "Yes" | ||
:doc:`modernize-redundant-void-arg <modernize/redundant-void-arg>`, "Yes" | :doc:`modernize-redundant-void-arg <modernize/redundant-void-arg>`, "Yes" | ||
@@ -363,6 +364,7 @@ Clang-Tidy Checks | |||
:doc:`readability-isolate-declaration <readability/isolate-declaration>`, "Yes" | :doc:`readability-isolate-declaration <readability/isolate-declaration>`, "Yes" | ||
:doc:`readability-magic-numbers <readability/magic-numbers>`, | :doc:`readability-magic-numbers <readability/magic-numbers>`, | ||
:doc:`readability-make-member-function-const <readability/make-member-function-const>`, "Yes" | :doc:`readability-make-member-function-const <readability/make-member-function-const>`, "Yes" | ||
+ :doc:`readability-math-missing-parentheses <readability/math-missing-parentheses>`, "Yes" | |||
:doc:`readability-misleading-indentation <readability/misleading-indentation>`, | :doc:`readability-misleading-indentation <readability/misleading-indentation>`, | ||
:doc:`readability-misplaced-array-index <readability/misplaced-array-index>`, "Yes" | :doc:`readability-misplaced-array-index <readability/misplaced-array-index>`, "Yes" | ||
:doc:`readability-named-parameter <readability/named-parameter>`, "Yes" | :doc:`readability-named-parameter <readability/named-parameter>`, "Yes" |
@@ -0,0 +1,50 @@ | |||
+.. title:: clang-tidy - modernize-min-max-use-initializer-list | |||
+ | |||
+modernize-min-max-use-initializer-list | |||
+====================================== | |||
+ | |||
+Replaces nested ``std::min`` and ``std::max`` calls with an initializer list | |||
+where applicable. | |||
+ | |||
+For instance, consider the following code: | |||
+ | |||
+.. code-block:: cpp | |||
+ | |||
+ int a = std::max(std::max(i, j), k); | |||
+ | |||
+The check will transform the above code to: | |||
+ | |||
+.. code-block:: cpp | |||
+ | |||
+ int a = std::max({i, j, k}); | |||
+ | |||
+Performance Considerations | |||
+========================== | |||
+ | |||
+While this check simplifies the code and makes it more readable, it may cause | |||
+performance degradation for non-trivial types due to the need to copy objects | |||
+into the initializer list. | |||
+ | |||
+To avoid this, it is recommended to use `std::ref` or `std::cref` for | |||
+non-trivial types: | |||
+ | |||
+.. code-block:: cpp | |||
+ | |||
+ std::string b = std::max({std::ref(i), std::ref(j), std::ref(k)}); | |||
+ | |||
+Options | |||
+======= | |||
+ | |||
+.. option:: IncludeStyle | |||
+ | |||
+ A string specifying which include-style is used, `llvm` or `google`. Default | |||
+ is `llvm`. | |||
+ | |||
+.. option:: IgnoreNonTrivial | |||
+ | |||
+ A boolean specifying whether to ignore non-trivial types. Default is `true`. | |||
+ | |||
+.. option:: IgnoreTrivialTyp | |||
+ | |||
+ An integer specifying the size (in bytes) above which trivial types are | |||
+ ignored. Default is `32`. |
@@ -4,7 +4,7 @@ modernize-use-nu | |||
===================== | ===================== | ||
The check converts the usage of null pointer constants (e.g. ``NULL``, ``0``) | The check converts the usage of null pointer constants (e.g. ``NULL``, ``0``) | ||
-to use the new C++11 ``nullptr`` keyword. | +to use the new C++11 and C23 ``nullptr`` keyword. | ||
Example | Example | ||
------- | ------- |
@@ -0,0 +1,27 @@ | |||
+.. title:: clang-tidy - readability-math-missing-parentheses | |||
+ | |||
+readability-math-missing-parentheses | |||
+==================================== | |||
+ | |||
+Check for missing parentheses in mathematical expressions that involve operators | |||
+of different priorities. | |||
+ | |||
+Parentheses in mathematical expressions clarify the order | |||
+of operations, especially with different-priority operators. Lengthy or multiline | |||
+expressions can obscure this order, leading to coding errors. IDEs can aid clarity | |||
+by highlighting parentheses. Explicitly using parentheses also clarifies what the | |||
+developer had in mind when writing the expression. Ensuring their presence reduces | |||
+ambiguity and errors, promoting clearer and more maintainable code. | |||
+ | |||
+Before: | |||
+ | |||
+.. code-block:: c++ | |||
+ | |||
+ int x = 1 + 2 * 3 - 4 / 5; | |||
+ | |||
+ | |||
+After: | |||
+ | |||
+.. code-block:: c++ | |||
+ | |||
+ int x = 1 + (2 * 3) - (4 / 5); |
@@ -67,33 +67,30 @@ foreach(dep ${LLVM_UTILS_DEP | |||
endif() | endif() | ||
endforeach() | endforeach() | ||
-if (NOT | +if (NOT WIN32 OR NOT LLVM_LINK_LLVM_DYLIB) | ||
- if (NOT WIN32 OR NOT LLVM_LINK_LLVM_D | + llvm_add_library | ||
- llvm_add_library | + CTTestTidyModule | ||
- | + MODULE clang-tidy/CTTestTidyModule.cpp | ||
- MODULE clang-tidy/CTTestTidyModule | + PLUGIN_TOOL clang-tidy) | ||
- PLUGIN_TOOL clang-tidy | +endif() | ||
- DEPENDS clang-tidy-headers) | |||
- endif() | |||
- | +if(CLANG_BUILT_STANDALONE) | ||
- | + # LLVMHello library is needed below | ||
- | + if (EXISTS ${LLVM_MAIN_SRC_DIR}/lib/Transforms/Hello | ||
- | + AND NOT TARGET LLVMHello) | ||
- | + add_subdirectory(${LLVM_MAIN_SRC_DIR}/lib/Transforms/Hello | ||
- | + lib/Transforms/Hello) | ||
- endif() | |||
endif() | endif() | ||
+endif() | |||
- | +if(TARGET CTTestTidyModule) | ||
- | + list(APPEND CLANG_TOOLS_TEST_DEPS CTTestTidyModule LLVMHello) | ||
- | + target_include_directories(CTTestTidyModule PUBLIC BEFORE "${CLANG_TOOLS_SOURCE_DIR}") | ||
- | + if(CLANG_PLUGIN_SUPPORT AND (WIN32 OR CYGWIN)) | ||
- | + set(LLVM_LINK_COMPONENTS | ||
- | + Support | ||
- | + ) | ||
- | + endif() | ||
- endif() | |||
endif() | endif() | ||
add_lit_testsuit | add_lit_testsuit |
@@ -309,6 +309,8 @@ struct HeapArray { // Ok, since destruc | |||
HeapArray(HeapArray &&other) : _data(other._data), size(other.size) { // Ok | HeapArray(HeapArray &&other) : _data(other._data), size(other.size) { // Ok | ||
other._data = nullptr; // Ok | other._data = nullptr; // Ok | ||
+ // CHECK-NOTES: [[@LINE-1]]:5: warning: expected assignment source to be of type 'gsl::owner<>'; got 'std::nullptr_t' | |||
+ // FIXME: This warning is emitted because an ImplicitCastExpr | |||
other.size = 0; | other.size = 0; | ||
} | } | ||
@@ -0,0 +1,305 @@ | |||
+// RUN: %check_clang_tidy | |||
+ | |||
+// CHECK-FIXES: #include <algorithm> | |||
+namespace utils { | |||
+template <typename T> | |||
+T max(T a, T b) { | |||
+ return (a < b) ? b : a; | |||
+} | |||
+} // namespace utils | |||
+ | |||
+namespace std { | |||
+template< class T > | |||
+struct initializer_list | |||
+ initializer_list | |||
+ initializer_list | |||
+ const T* begin() const {return nullptr;} | |||
+ const T* end() const {return nullptr;} | |||
+}; | |||
+ | |||
+template<class ForwardIt> | |||
+ForwardIt min_element(ForwardIt first, ForwardIt last) | |||
+{ | |||
+ if (first == last) | |||
+ return last; | |||
+ | |||
+ ForwardIt smallest = first; | |||
+ | |||
+ while (++first != last) | |||
+ if (*first < *smallest) | |||
+ smallest = first; | |||
+ | |||
+ return smallest; | |||
+} | |||
+ | |||
+template<class ForwardIt, class Compare> | |||
+ForwardIt min_element(ForwardIt first, ForwardIt last, Compare comp) | |||
+{ | |||
+ if (first == last) | |||
+ return last; | |||
+ | |||
+ ForwardIt smallest = first; | |||
+ | |||
+ while (++first != last) | |||
+ if (comp(*first, *smallest)) | |||
+ smallest = first; | |||
+ | |||
+ return smallest; | |||
+} | |||
+ | |||
+template<class ForwardIt> | |||
+ForwardIt max_element(ForwardIt first, ForwardIt last) | |||
+{ | |||
+ if (first == last) | |||
+ return last; | |||
+ | |||
+ ForwardIt largest = first; | |||
+ | |||
+ while (++first != last) | |||
+ if (*largest < *first) | |||
+ largest = first; | |||
+ | |||
+ return largest; | |||
+} | |||
+ | |||
+template<class ForwardIt, class Compare> | |||
+ForwardIt max_element(ForwardIt first, ForwardIt last, Compare comp) | |||
+{ | |||
+ if (first == last) | |||
+ return last; | |||
+ | |||
+ ForwardIt largest = first; | |||
+ | |||
+ while(++first != last) | |||
+ if (comp(*largest, *first)) | |||
+ largest = first; | |||
+ | |||
+ return largest; | |||
+} | |||
+ | |||
+template< class T > | |||
+const T& max( const T& a, const T& b ) { | |||
+ return (a < b) ? b : a; | |||
+}; | |||
+ | |||
+template< class T > | |||
+T max(std::initializer_list | |||
+{ | |||
+ return *std::max_element(ilist.begin(), ilist.end()); | |||
+} | |||
+ | |||
+template< class T, class Compare > | |||
+const T& max( const T& a, const T& b, Compare comp ) { | |||
+ return (comp(a, b)) ? b : a; | |||
+}; | |||
+ | |||
+template< class T, class Compare > | |||
+T max(std::initializer_list | |||
+ return *std::max_element(ilist.begin(), ilist.end(), comp); | |||
+}; | |||
+ | |||
+template< class T > | |||
+const T& min( const T& a, const T& b ) { | |||
+ return (b < a) ? b : a; | |||
+}; | |||
+ | |||
+template< class T > | |||
+T min(std::initializer_list | |||
+{ | |||
+ return *std::min_element(ilist.begin(), ilist.end()); | |||
+} | |||
+ | |||
+ | |||
+template< class T, class Compare > | |||
+const T& min( const T& a, const T& b, Compare comp ) { | |||
+ return (comp(b, a)) ? b : a; | |||
+}; | |||
+ | |||
+template< class T, class Compare > | |||
+T min(std::initializer_list | |||
+ return *std::min_element(ilist.begin(), ilist.end(), comp); | |||
+}; | |||
+ | |||
+} // namespace std | |||
+ | |||
+using namespace std; | |||
+ | |||
+namespace { | |||
+bool fless_than(int a, int b) { | |||
+return a < b; | |||
+} | |||
+ | |||
+bool fgreater_than(int a, int b) { | |||
+return a > b; | |||
+} | |||
+auto less_than = [](int a, int b) { return a < b; }; | |||
+auto greater_than = [](int a, int b) { return a > b; }; | |||
+ | |||
+int max1 = std::max(1, std::max(2, 3)); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int max1 = std::max({1, 2, 3}); | |||
+ | |||
+int min1 = std::min(1, std::min(2, 3)); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int min1 = std::min({1, 2, 3}); | |||
+ | |||
+int max2 = std::max(1, std::max(2, std::max(3, 4))); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int max2 = std::max({1, 2, 3, 4}); | |||
+ | |||
+int max2b = std::max(std::max(std::max(1, 2), std::max(3, 4)), std::max(std::max(5, 6), std::max(7, 8))); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int max2b = std::max({1, 2, 3, 4, 5, 6, 7, 8}); | |||
+ | |||
+int max2c = std::max(std::max(1, std::max(2, 3)), 4); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int max2c = std::max({1, 2, 3, 4}); | |||
+ | |||
+int max2d = std::max(std::max({1, 2, 3}), 4); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int max2d = std::max({1, 2, 3, 4}); | |||
+ | |||
+ | |||
+int max2e = std::max(1, max(2, max(3, 4))); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int max2e = std::max({1, 2, 3, 4}); | |||
+ | |||
+int min2 = std::min(1, std::min(2, std::min(3, 4))); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int min2 = std::min({1, 2, 3, 4}); | |||
+ | |||
+int max3 = std::max(std::max(4, 5), std::min(2, std::min(3, 1))); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-MESSAGES: :[[@LINE-2]]:37: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int max3 = std::max({4, 5, std::min({2, 3, 1})}); | |||
+ | |||
+int min3 = std::min(std::min(4, 5), std::max(2, std::max(3, 1))); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-MESSAGES: :[[@LINE-2]]:37: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int min3 = std::min({4, 5, std::max({2, 3, 1})}); | |||
+ | |||
+int max4 = std::max(1, std::max(2, 3, greater_than), less_than); | |||
+// CHECK-FIXES: int max4 = std::max(1, std::max(2, 3, greater_than), less_than); | |||
+ | |||
+int min4 = std::min(1, std::min(2, 3, greater_than), less_than); | |||
+// CHECK-FIXES: int min4 = std::min(1, std::min(2, 3, greater_than), less_than); | |||
+ | |||
+int max5 = std::max(1, std::max(2, 3), less_than); | |||
+// CHECK-FIXES: int max5 = std::max(1, std::max(2, 3), less_than); | |||
+ | |||
+int min5 = std::min(1, std::min(2, 3), less_than); | |||
+// CHECK-FIXES: int min5 = std::min(1, std::min(2, 3), less_than); | |||
+ | |||
+int max6 = std::max(1, std::max(2, 3, greater_than), greater_than); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int max6 = std::max({1, 2, 3 }, greater_than); | |||
+ | |||
+int min6 = std::min(1, std::min(2, 3, greater_than), greater_than); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int min6 = std::min({1, 2, 3 }, greater_than); | |||
+ | |||
+int max7 = std::max(1, std::max(2, 3, fless_than), fgreater_than); | |||
+// CHECK-FIXES: int max7 = std::max(1, std::max(2, 3, fless_than), fgreater_than); | |||
+ | |||
+int min7 = std::min(1, std::min(2, 3, fless_than), fgreater_than); | |||
+// CHECK-FIXES: int min7 = std::min(1, std::min(2, 3, fless_than), fgreater_than); | |||
+ | |||
+int max8 = std::max(1, std::max(2, 3, fless_than), less_than); | |||
+// CHECK-FIXES: int max8 = std::max(1, std::max(2, 3, fless_than), less_than) | |||
+ | |||
+int min8 = std::min(1, std::min(2, 3, fless_than), less_than); | |||
+// CHECK-FIXES: int min8 = std::min(1, std::min(2, 3, fless_than), less_than); | |||
+ | |||
+int max9 = std::max(1, std::max(2, 3, fless_than), fless_than); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int max9 = std::max({1, 2, 3 }, fless_than); | |||
+ | |||
+int min9 = std::min(1, std::min(2, 3, fless_than), fless_than); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int min9 = std::min({1, 2, 3 }, fless_than); | |||
+ | |||
+int min10 = std::min(std::min(4, 5), std::max(2, utils::max(3, 1))); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::min' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int min10 = std::min({4, 5, std::max(2, utils::max(3, 1))}); | |||
+ | |||
+int max10 = std::max({std::max(1, 2), std::max({5, 6, 1}), 2, std::min({1, 2, 4})}); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int max10 = std::max({1, 2, 5, 6, 1, 2, std::min({1, 2, 4})}); | |||
+ | |||
+int typecastTest = std::max(std::max<int>(0U, 0.0f), 0); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int typecastTest = std::max({static_cast<int>(0U), static_cast<int>(0.0f), 0}); | |||
+ | |||
+int typecastTest1 = std::max(std::max<long>(0U, 0.0f), 0L); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int typecastTest1 = std::max({static_cast<long>(0U), static_cast<long>(0.0f), 0L}); | |||
+ | |||
+int typecastTest2 = std::max(std::max<int>(10U, 20.0f), 30); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int typecastTest2 = std::max({static_cast<int>(10U), static_cast<int>(20.0f), 30}); | |||
+ | |||
+int typecastTest3 = std::max(std::max<int>(0U, std::max<int>(0.0f, 1.0f)), 0); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int typecastTest3 = std::max({static_cast<int>(0U), static_cast<int>(0.0f), static_cast<int>(1.0f), 0}); | |||
+ | |||
+#define max3f(a, b, c) std::max(a, std::max(b, c)) | |||
+// CHECK-FIXES: #define max3f(a, b, c) std::max(a, std::max(b, c)) | |||
+ | |||
+#define value 4545 | |||
+int macroVarMax = std::max(value, std::max(1, 2)); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int macroVarMax = std::max({value, 1, 2}); | |||
+ | |||
+#define value2 45U | |||
+int macroVarMax2 = std::max(1, std::max<int>(value2, 2.0f)); | |||
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] | |||
+// CHECK-FIXES: int macroVarMax2 = std::max({1, static_cast<int>(value2), static_cast<int>(2.0f)}); | |||
+ | |||
+// True-negative tests | |||
+int maxTN1 = std::max(1, 2); | |||
+// CHECK-FIXES: int maxTN1 = std::max(1, 2); | |||
+ | |||
+int maxTN2 = std::max({1, 2, 3}); | |||
+// CHECK-FIXES: int maxTN2 = std::max({1, 2, 3}); | |||
+ | |||
+int maxTN3 = std::max({1, 2, 3}, less_than); | |||
+// CHECK-FIXES: int maxTN3 = std::max({1, 2, 3}, less_than); | |||
+ | |||
+// non-trivial types | |||
+struct A { | |||
+ int a; | |||
+ A(int a) : a(a) {} | |||
+ bool operator<(const A &rhs) const { return a < rhs.a; } | |||
+}; | |||
+ | |||
+A maxNT1 = std::max(A(1), A(2)); | |||
+// CHECK-FIXES: A maxNT1 = std::max(A(1), A(2)); | |||
+ | |||
+A maxNT2 = std::max(A(1), std::max(A(2), A(3))); | |||
+// CHECK-FIXES: A maxNT2 = std::max(A(1), std::max(A(2), A(3))); | |||
+ | |||
+A maxNT3 = std::max(A(1), std::max(A(2), A(3)), [](const A &lhs, const A &rhs) { return lhs.a < rhs.a; }); | |||
+// CHECK-FIXES: A maxNT3 = std::max(A(1), std::max(A(2), A(3)), [](const A &lhs, const A &rhs) { return lhs.a < rhs.a; }); | |||
+ | |||
+// Trivial type with size greater than 32 | |||
+struct B { | |||
+ // 9*4 = 36 bytes > 32 bytes | |||
+ int a[9]; | |||
+ | |||
+ bool operator<(const B& rhs) const { | |||
+ return a[0] < rhs.a[0]; | |||
+ } | |||
+}; | |||
+ | |||
+B maxTT1 = std::max(B(), B()); | |||
+// CHECK-FIXES: B maxTT1 = std::max(B(), B()); | |||
+ | |||
+B maxTT2 = std::max(B(), std::max(B(), B())); | |||
+// CHECK-FIXES: B maxTT2 = std::max(B(), std::max(B(), B())); | |||
+ | |||
+B maxTT3 = std::max(B(), std::max(B(), B()), [](const B &lhs, const B &rhs) { return lhs.a[0] < rhs.a[0]; }); | |||
+// CHECK-FIXES: B maxTT3 = std::max(B(), std::max(B(), B()), [](const B &lhs, const B &rhs) { return lhs.a[0] < rhs.a[0]; }); | |||
+ | |||
+ | |||
+} // namespace | |||
+ |
@@ -260,6 +260,8 @@ template <class T> | |||
struct Template { | struct Template { | ||
Template() = default; | Template() = default; | ||
Template(const Template &Other) : Field(Other.Field) {} | Template(const Template &Other) : Field(Other.Field) {} | ||
+ // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use '= default' | |||
+ // CHECK-FIXES: Template(const Template &Other) = default; | |||
Template &operator=(const Template &Other); | Template &operator=(const Template &Other); | ||
void foo(const T &t); | void foo(const T &t); | ||
int Field; | int Field; | ||
@@ -269,8 +271,12 @@ Template<T> &Template<T>::op | |||
Field = Other.Field; | Field = Other.Field; | ||
return *this; | return *this; | ||
} | } | ||
+// CHECK-MESSAGES: :[[@LINE-4]]:27: warning: use '= default' | |||
+// CHECK-FIXES: Template<T> &Template<T>::operator=(const Template<T> &Other) = default; | |||
+ | |||
Template<int> T1; | Template<int> T1; | ||
+ | |||
// Dependent types. | // Dependent types. | ||
template <class T> | template <class T> | ||
struct DT1 { | struct DT1 { | ||
@@ -284,6 +290,9 @@ DT1<T> &DT1<T>::operato | |||
Field = Other.Field; | Field = Other.Field; | ||
return *this; | return *this; | ||
} | } | ||
+// CHECK-MESSAGES: :[[@LINE-4]]:17: warning: use '= default' | |||
+// CHECK-FIXES: DT1<T> &DT1<T>::operator=(const DT1<T> &Other) = default; | |||
+ | |||
DT1<int> Dt1; | DT1<int> Dt1; | ||
template <class T> | template <class T> | ||
@@ -303,6 +312,9 @@ DT2<T> &DT2<T>::operato | |||
struct T { | struct T { | ||
typedef int TT; | typedef int TT; | ||
}; | }; | ||
+// CHECK-MESSAGES: :[[@LINE-8]]:17: warning: use '= default' | |||
+// CHECK-FIXES: DT2<T> &DT2<T>::operator=(const DT2<T> &Other) = default; | |||
+ | |||
DT2<T> Dt2; | DT2<T> Dt2; | ||
// Default arguments. | // Default arguments. |
@@ -0,0 +1,139 @@ | |||
+// RUN: %check_clang_tidy | |||
+ | |||
+#define NULL 0 | |||
+ | |||
+void test_assignment() { | |||
+ int *p1 = 0; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr [modernize-use-nullptr] | |||
+ // CHECK-FIXES: int *p1 = nullptr; | |||
+ p1 = 0; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr | |||
+ // CHECK-FIXES: p1 = nullptr; | |||
+ | |||
+ int *p2 = NULL; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr | |||
+ // CHECK-FIXES: int *p2 = nullptr; | |||
+ | |||
+ p2 = p1; | |||
+ // CHECK-FIXES: p2 = p1; | |||
+ | |||
+ const int null = 0; | |||
+ int *p3 = &null; | |||
+ | |||
+ p3 = NULL; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: use nullptr | |||
+ // CHECK-FIXES: p3 = nullptr; | |||
+ | |||
+ int *p4 = p3; | |||
+ | |||
+ int i1 = 0; | |||
+ | |||
+ int i2 = NULL; | |||
+ | |||
+ int i3 = null; | |||
+ | |||
+ int *p5, *p6, *p7; | |||
+ p5 = p6 = p7 = NULL; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use nullptr | |||
+ // CHECK-FIXES: p5 = p6 = p7 = nullptr; | |||
+} | |||
+ | |||
+void test_function(int *p) {} | |||
+ | |||
+void test_function_no | |||
+ | |||
+void test_function_ca | |||
+ test_function(0); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr | |||
+ // CHECK-FIXES: test_function(nullptr); | |||
+ | |||
+ test_function(NULL); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use nullptr | |||
+ // CHECK-FIXES: test_function(nullptr); | |||
+ | |||
+ test_function_no | |||
+} | |||
+ | |||
+char *test_function_re | |||
+ return 0; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr | |||
+ // CHECK-FIXES: return nullptr; | |||
+} | |||
+ | |||
+void *test_function_re | |||
+ return NULL; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr | |||
+ // CHECK-FIXES: return nullptr; | |||
+} | |||
+ | |||
+int test_function_re | |||
+ return 0; | |||
+} | |||
+ | |||
+int test_function_re | |||
+ return NULL; | |||
+} | |||
+ | |||
+int *test_function_re | |||
+ return(int)0; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: use nullptr | |||
+ // CHECK-FIXES: return nullptr; | |||
+} | |||
+ | |||
+int *test_function_re | |||
+#define RET return | |||
+ RET(int)0; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:6: warning: use nullptr | |||
+ // CHECK-FIXES: RET nullptr; | |||
+#undef RET | |||
+} | |||
+ | |||
+// Test parentheses expressions resulting in a nullptr. | |||
+int *test_parentheses | |||
+ return(0); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr | |||
+ // CHECK-FIXES: return(nullptr); | |||
+} | |||
+ | |||
+int *test_parentheses | |||
+ return((int)(0.0f)); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: use nullptr | |||
+ // CHECK-FIXES: return(nullptr); | |||
+} | |||
+ | |||
+int *test_nested_pare | |||
+ return((((0)))); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use nullptr | |||
+ // CHECK-FIXES: return((((nullptr)))); | |||
+} | |||
+ | |||
+void test_const_point | |||
+ const int *const_p1 = 0; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr | |||
+ // CHECK-FIXES: const int *const_p1 = nullptr; | |||
+ const int *const_p2 = NULL; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr | |||
+ // CHECK-FIXES: const int *const_p2 = nullptr; | |||
+ const int *const_p3 = (int)0; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr | |||
+ // CHECK-FIXES: const int *const_p3 = nullptr; | |||
+ const int *const_p4 = (int)0.0f; | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use nullptr | |||
+ // CHECK-FIXES: const int *const_p4 = nullptr; | |||
+} | |||
+ | |||
+void test_nested_impl | |||
+ int func0(void*, void*); | |||
+ int func1(int, void*, void*); | |||
+ | |||
+ (double)func1(0, 0, 0); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use nullptr | |||
+ // CHECK-MESSAGES: :[[@LINE-2]]:23: warning: use nullptr | |||
+ // CHECK-FIXES: (double)func1(0, nullptr, nullptr); | |||
+ (double)func1(func0(0, 0), 0, 0); | |||
+ // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use nullptr | |||
+ // CHECK-MESSAGES: :[[@LINE-2]]:26: warning: use nullptr | |||
+ // CHECK-MESSAGES: :[[@LINE-3]]:30: warning: use nullptr | |||
+ // CHECK-MESSAGES: :[[@LINE-4]]:33: warning: use nullptr | |||
+ // CHECK-FIXES: (double)func1(func0(nullptr, nullptr), nullptr, nullptr); | |||
+} |
@@ -1,4 +1,4 @@ | |||
-// RUN: clang-tidy %s -checks=-*,modernize-use-nullptr -- | count 0 | +// RUN: clang-tidy %s -checks=-*,modernize-use-nullptr -- -std=c17 | count 0 | ||
// Note: this test expects no diagnostics, but FileCheck cannot handle that, | // Note: this test expects no diagnostics, but FileCheck cannot handle that, | ||
// hence the use of | count 0. | // hence the use of | count 0. |
@@ -0,0 +1,142 @@ | |||
+// RUN: %check_clang_tidy | |||
+ | |||
+#define MACRO_AND & | |||
+#define MACRO_ADD + | |||
+#define MACRO_OR | | |||
+#define MACRO_MULTIPLY * | |||
+#define MACRO_XOR ^ | |||
+#define MACRO_SUBTRACT - | |||
+#define MACRO_DIVIDE / | |||
+ | |||
+int foo(){ | |||
+ return 5; | |||
+} | |||
+ | |||
+int bar(){ | |||
+ return 4; | |||
+} | |||
+ | |||
+int sink(int); | |||
+#define FUN(ARG) (sink(ARG)) | |||
+#define FUN2(ARG) sink((ARG)) | |||
+#define FUN3(ARG) sink(ARG) | |||
+#define FUN4(ARG) sink(1 + ARG) | |||
+#define FUN5(ARG) sink(4 * ARG) | |||
+ | |||
+class fun{ | |||
+public: | |||
+ int A; | |||
+ double B; | |||
+ fun(){ | |||
+ A = 5; | |||
+ B = 5.4; | |||
+ } | |||
+}; | |||
+ | |||
+void f(){ | |||
+ //CHECK-MESSAGES: :[[@LINE+2]]:17: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-FIXES: int a = 1 + (2 * 3); | |||
+ int a = 1 + 2 * 3; | |||
+ | |||
+ int a_negative = 1 + (2 * 3); // No warning | |||
+ | |||
+ int b = 1 + 2 + 3; // No warning | |||
+ | |||
+ int c = 1 * 2 * 3; // No warning | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+3]]:17: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-MESSAGES: :[[@LINE+2]]:25: warning: '/' has higher precedence than '-'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-FIXES: int d = 1 + (2 * 3) - (4 / 5); | |||
+ int d = 1 + 2 * 3 - 4 / 5; | |||
+ | |||
+ int d_negative = 1 + (2 * 3) - (4 / 5); // No warning | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+4]]:13: warning: '&' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-MESSAGES: :[[@LINE+3]]:17: warning: '+' has higher precedence than '&'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-MESSAGES: :[[@LINE+2]]:25: warning: '*' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-FIXES: int e = (1 & (2 + 3)) | (4 * 5); | |||
+ int e = 1 & 2 + 3 | 4 * 5; | |||
+ | |||
+ int e_negative = (1 & (2 + 3)) | (4 * 5); // No warning | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+2]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-FIXES: int f = (1 * -2) + 4; | |||
+ int f = 1 * -2 + 4; | |||
+ | |||
+ int f_negative = (1 * -2) + 4; // No warning | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+2]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-FIXES: int g = (1 * 2 * 3) + 4 + 5; | |||
+ int g = 1 * 2 * 3 + 4 + 5; | |||
+ | |||
+ int g_negative = (1 * 2 * 3) + 4 + 5; // No warning | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+4]]:13: warning: '&' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-MESSAGES: :[[@LINE+3]]:19: warning: '+' has higher precedence than '&'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-MESSAGES: :[[@LINE+2]]:27: warning: '*' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-FIXES: int h = (120 & (2 + 3)) | (22 * 5); | |||
+ int h = 120 & 2 + 3 | 22 * 5; | |||
+ | |||
+ int h_negative = (120 & (2 + 3)) | (22 * 5); // No warning | |||
+ | |||
+ int i = 1 & 2 & 3; // No warning | |||
+ | |||
+ int j = 1 | 2 | 3; // No warning | |||
+ | |||
+ int k = 1 ^ 2 ^ 3; // No warning | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+2]]:13: warning: '+' has higher precedence than '^'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-FIXES: int l = (1 + 2) ^ 3; | |||
+ int l = 1 + 2 ^ 3; | |||
+ | |||
+ int l_negative = (1 + 2) ^ 3; // No warning | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+2]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-FIXES: int m = (2 * foo()) + bar(); | |||
+ int m = 2 * foo() + bar(); | |||
+ | |||
+ int m_negative = (2 * foo()) + bar(); // No warning | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+2]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-FIXES: int n = (1.05 * foo()) + double(bar()); | |||
+ int n = 1.05 * foo() + double(bar()); | |||
+ | |||
+ int n_negative = (1.05 * foo()) + double(bar()); // No warning | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+3]]:17: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-FIXES: int o = 1 + (obj.A * 3) + obj.B; | |||
+ fun obj; | |||
+ int o = 1 + obj.A * 3 + obj.B; | |||
+ | |||
+ int o_negative = 1 + (obj.A * 3) + obj.B; // No warning | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+2]]:18: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-FIXES: int p = 1U + (2 * 3); | |||
+ int p = 1U + 2 * 3; | |||
+ | |||
+ int p_negative = 1U + (2 * 3); // No warning | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+7]]:13: warning: '+' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-MESSAGES: :[[@LINE+6]]:25: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-MESSAGES: :[[@LINE+5]]:53: warning: '&' has higher precedence than '^'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-MESSAGES: :[[@LINE+4]]:53: warning: '^' has higher precedence than '|'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-MESSAGES: :[[@LINE+3]]:77: warning: '-' has higher precedence than '^'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-MESSAGES: :[[@LINE+2]]:94: warning: '/' has higher precedence than '-'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ //CHECK-FIXES: int q = (1 MACRO_ADD (2 MACRO_MULTIPLY 3)) MACRO_OR ((4 MACRO_AND 5) MACRO_XOR (6 MACRO_SUBTRACT (7 MACRO_DIVIDE 8))); | |||
+ int q = 1 MACRO_ADD 2 MACRO_MULTIPLY 3 MACRO_OR 4 MACRO_AND 5 MACRO_XOR 6 MACRO_SUBTRACT 7 MACRO_DIVIDE 8; // No warning | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+1]]:21: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ int r = FUN(0 + 1 * 2); | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+1]]:22: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ int s = FUN2(0 + 1 * 2); | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+1]]:22: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ int t = FUN3(0 + 1 * 2); | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+1]]:18: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ int u = FUN4(1 * 2); | |||
+ | |||
+ //CHECK-MESSAGES: :[[@LINE+1]]:13: warning: '*' has higher precedence than '+'; add parentheses to explicitly specify the order of operations [readability-math-missing-parentheses] | |||
+ int v = FUN5(0 + 1); | |||
+} |
@@ -10,7 +10,7 @@ config.python_ex | |||
config.target_triple = "@LLVM_TARGET_TRIP | config.target_triple = "@LLVM_TARGET_TRIP | ||
config.host_triple = "@LLVM_HOST_TRIPLE | config.host_triple = "@LLVM_HOST_TRIPLE | ||
config.clang_tidy_stati | config.clang_tidy_stati | ||
-config.has_plugins = @CLANG_PLUGIN_SUPPORT@ | +config.has_plugins = @CLANG_PLUGIN_SUPPORT@ | ||
# Support substitution of the tools and libs dirs with user parameters. This is | # Support substitution of the tools and libs dirs with user parameters. This is | ||
# used when we can't determine the tool dir at configuration time. | # used when we can't determine the tool dir at configuration time. | ||
config.llvm_tools_dir = lit_config.substitute("@LLVM_TOOLS_DIR@") | config.llvm_tools_dir = lit_config.substitute("@LLVM_TOOLS_DIR@") |
@@ -21,6 +21,12 @@ void foo() { | |||
// CHECK: --- | // CHECK: --- | ||
// CHECK-NEXT: - Callback: PragmaDirective | // CHECK-NEXT: - Callback: PragmaDirective | ||
+// CHECK-NEXT: Loc: "<built-in>:{{.+}}:1" | |||
+// CHECK-NEXT: Introducer: PIK_HashPragma | |||
+// CHECK-NEXT: - Callback: PragmaDirective | |||
+// CHECK-NEXT: Loc: "<built-in>:{{.+}}:1" | |||
+// CHECK-NEXT: Introducer: PIK_HashPragma | |||
+// CHECK-NEXT: - Callback: PragmaDirective | |||
// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:3:1" | // CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-general.cpp:3:1" | ||
// CHECK-NEXT: Introducer: PIK_HashPragma | // CHECK-NEXT: Introducer: PIK_HashPragma | ||
// CHECK-NEXT: - Callback: PragmaDiagnostic | // CHECK-NEXT: - Callback: PragmaDiagnostic |
@@ -18,6 +18,12 @@ | |||
// CHECK: --- | // CHECK: --- | ||
// CHECK-NEXT: - Callback: PragmaDirective | // CHECK-NEXT: - Callback: PragmaDirective | ||
+// CHECK-NEXT: Loc: "<built-in>:{{.+}}:1" | |||
+// CHECK-NEXT: Introducer: PIK_HashPragma | |||
+// CHECK-NEXT: - Callback: PragmaDirective | |||
+// CHECK-NEXT: Loc: "<built-in>:{{.+}}:1" | |||
+// CHECK-NEXT: Introducer: PIK_HashPragma | |||
+// CHECK-NEXT: - Callback: PragmaDirective | |||
// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:3:1" | // CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:3:1" | ||
// CHECK-NEXT: Introducer: PIK_HashPragma | // CHECK-NEXT: Introducer: PIK_HashPragma | ||
// CHECK-NEXT: - Callback: PragmaComment | // CHECK-NEXT: - Callback: PragmaComment | ||
@@ -67,7 +73,7 @@ | |||
// CHECK-NEXT: Introducer: PIK_HashPragma | // CHECK-NEXT: Introducer: PIK_HashPragma | ||
// CHECK-NEXT: - Callback: PragmaMessage | // CHECK-NEXT: - Callback: PragmaMessage | ||
// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:13:9" | // CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-ms.cpp:13:9" | ||
-// CHECK-NEXT: Namespace: | +// CHECK-NEXT: Namespace: | ||
// CHECK-NEXT: Kind: PMK_Message | // CHECK-NEXT: Kind: PMK_Message | ||
// CHECK-NEXT: Str: message argument | // CHECK-NEXT: Str: message argument | ||
// CHECK-NEXT: - Callback: PragmaDirective | // CHECK-NEXT: - Callback: PragmaDirective |
@@ -6,6 +6,12 @@ | |||
// CHECK: --- | // CHECK: --- | ||
// CHECK-NEXT: - Callback: PragmaDirective | // CHECK-NEXT: - Callback: PragmaDirective | ||
+// CHECK-NEXT: Loc: "<built-in>:{{.+}}:1" | |||
+// CHECK-NEXT: Introducer: PIK_HashPragma | |||
+// CHECK-NEXT: - Callback: PragmaDirective | |||
+// CHECK-NEXT: Loc: "<built-in>:{{.+}}:1" | |||
+// CHECK-NEXT: Introducer: PIK_HashPragma | |||
+// CHECK-NEXT: - Callback: PragmaDirective | |||
// CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-opencl.cpp:3:1" | // CHECK-NEXT: Loc: "{{.*}}{{[/\\]}}pp-trace-pragma-opencl.cpp:3:1" | ||
// CHECK-NEXT: Introducer: PIK_HashPragma | // CHECK-NEXT: Introducer: PIK_HashPragma | ||
// CHECK-NEXT: - Callback: PragmaOpenCLExte | // CHECK-NEXT: - Callback: PragmaOpenCLExte |
@@ -166,6 +166,10 @@ if(CLANG_ENABLE_ | |||
endif() | endif() | ||
if(CLANG_ENABLE_CIR | if(CLANG_ENABLE_CIR | ||
+ if (CLANG_BUILT_STAN | |||
+ message(FATAL_ERROR | |||
+ "ClangIR is not yet supported in the standalone build.") | |||
+ endif() | |||
if (NOT "${LLVM_ENABLE_PROJ | if (NOT "${LLVM_ENABLE_PROJ | ||
message(FATAL_ERROR | message(FATAL_ERROR | ||
"Cannot build ClangIR without MLIR in LLVM_ENABLE_PROJ | "Cannot build ClangIR without MLIR in LLVM_ENABLE_PROJ |
@@ -1,95 +1,94 @@ | |||
# Plain options configure the first build. | # Plain options configure the first build. | ||
# BOOTSTRAP_* options configure the second build. | # BOOTSTRAP_* options configure the second build. | ||
# BOOTSTRAP_BOOTST | # BOOTSTRAP_BOOTST | ||
+# PGO Builds have 3 stages (stage1, stage2-instrumented, stage2) | |||
+# non-PGO Builds have 2 stages (stage1, stage2) | |||
-# General Options | + | ||
+function (set_final_stage_ | |||
+ if (LLVM_RELEASE_ENA | |||
+ set(BOOTSTRAP_BOOTST | |||
+ else() | |||
+ set(BOOTSTRAP_${name} ${value} CACHE ${type} "") | |||
+ endif() | |||
+endfunction() | |||
+ | |||
+function (set_instrument_a | |||
+ # This sets the varaible for the final stage in non-PGO builds and in | |||
+ # the stage2-instrumented stage for PGO builds. | |||
+ set(BOOTSTRAP_${name} ${value} CACHE ${type} "") | |||
+ if (LLVM_RELEASE_ENA | |||
+ # Set the variable in the final stage for PGO builds. | |||
+ set(BOOTSTRAP_BOOTST | |||
+ endif() | |||
+endfunction() | |||
+ | |||
+# General Options: | |||
+# If you want to override any of the LLVM_RELEASE_* variables you can set them | |||
+# on the command line via -D, but you need to do this before you pass this | |||
+# cache file to CMake via -C. e.g. | |||
+# | |||
+# cmake -D LLVM_RELEASE_ENA | |||
set(LLVM_RELEASE_ENA | set(LLVM_RELEASE_ENA | ||
set(LLVM_RELEASE_ENA | set(LLVM_RELEASE_ENA | ||
- | +set(LLVM_RELEASE_ENA | ||
+set(LLVM_RELEASE_ENA | |||
+# Note we don't need to add install here, since it is one of the pre-defined | |||
+# steps. | |||
+set(LLVM_RELEASE_FIN | |||
set(CMAKE_BUILD_TYPE | set(CMAKE_BUILD_TYPE | ||
-# Stage 1 | +# Stage 1 Options | ||
+set(LLVM_TARGETS_TO_ | |||
set(CLANG_ENABLE_BOO | set(CLANG_ENABLE_BOO | ||
+ | |||
+set(STAGE1_PROJECTS "clang") | |||
+set(STAGE1_RUNTIMES "") | |||
+ | |||
if (LLVM_RELEASE_ENA | if (LLVM_RELEASE_ENA | ||
+ list(APPEND STAGE1_PROJECTS "lld") | |||
+ list(APPEND STAGE1_RUNTIMES "compiler-rt") | |||
set(CLANG_BOOTSTRAP_ | set(CLANG_BOOTSTRAP_ | ||
generate-profdata | generate-profdata | ||
- stage2 | |||
stage2-package | stage2-package | ||
stage2-clang | stage2-clang | ||
- stage2-distribution | |||
stage2-install | stage2-install | ||
- stage2-install-distribution | |||
- stage2-install-distribution-toolchain | |||
stage2-check-all | stage2-check-all | ||
stage2-check-llvm | stage2-check-llvm | ||
- stage2-check-clang | + stage2-check-clang CACHE STRING "") | ||
- stage2-test-suite CACHE STRING "") | |||
-else() | |||
- set(CLANG_BOOTSTRAP_ | |||
- clang | |||
- check-all | |||
- check-llvm | |||
- check-clang | |||
- test-suite | |||
- stage3 | |||
- stage3-clang | |||
- stage3-check-all | |||
- stage3-check-llvm | |||
- stage3-check-clang | |||
- stage3-install | |||
- stage3-test-suite CACHE STRING "") | |||
-endif() | |||
-# Stage 1 Options | + # Configuration for stage2-instrumented | ||
-set(STAGE1_PROJECTS "clang") | + set(BOOTSTRAP_CLANG_ | ||
-set(STAGE1_RUNTIMES "") | + # This enables the build targets for the final stage which is called stage2. | ||
+ set(BOOTSTRAP_CLANG_ | |||
+ set(BOOTSTRAP_LLVM_B | |||
+ set(BOOTSTRAP_LLVM_E | |||
+ set(BOOTSTRAP_LLVM_E | |||
-if (LLVM_RELEASE_ENA | +else() | ||
- list(APPEND STAGE1_PROJECTS "lld") | + if (LLVM_RELEASE_ENA | ||
- list(APPEND STAGE1_RUNTIMES "compiler-rt") | + list(APPEND STAGE1_PROJECTS "lld") | ||
+ endif() | |||
+ # Any targets added here will be given the target name stage2-${target}, so | |||
+ # if you want to run them you can just use: | |||
+ # ninja -C $BUILDDIR stage2-${target} | |||
+ set(CLANG_BOOTSTRAP_ | |||
endif() | endif() | ||
+# Stage 1 Common Config | |||
set(LLVM_ENABLE_RUNT | set(LLVM_ENABLE_RUNT | ||
set(LLVM_ENABLE_PROJ | set(LLVM_ENABLE_PROJ | ||
-set(LLVM_TARGETS_TO_ | +# stage2-instrumented and Final Stage Config: | ||
- | +# Options that need to be set in both the instrumented stage (if we are doing | ||
-# Stage 2 Bootstrap Setup | +# a pgo build) and the final stage. | ||
-set(BOOTSTRAP_CLANG_ | +set_instrument_a | ||
-set(BOOTSTRAP_CLANG_ | +set_instrument_a | ||
- clang | +if (LLVM_RELEASE_ENA | ||
- package | + set_instrument_a | ||
- check-all | |||
- check-llvm | |||
- check-clang CACHE STRING "") | |||
- | |||
-# Stage 2 Options | |||
-set(STAGE2_PROJECTS "clang") | |||
-set(STAGE2_RUNTIMES "") | |||
- | |||
-if (LLVM_RELEASE_ENA | |||
- list(APPEND STAGE2_PROJECTS "lld") | |||
-endif() | |||
- | |||
-if (LLVM_RELEASE_ENA | |||
- set(BOOTSTRAP_LLVM_B | |||
- list(APPEND STAGE2_RUNTIMES "compiler-rt") | |||
- set(BOOTSTRAP_LLVM_E | |||
- if (LLVM_RELEASE_ENA | |||
- set(BOOTSTRAP_LLVM_E | |||
- endif() | |||
endif() | endif() | ||
-set(BOOTSTRAP_LLVM_E | +# Final Stage Config (stage2) | ||
-set(BOOTSTRAP_LLVM_E | +set_final_stage_ | ||
-if (NOT LLVM_RELEASE_ENA | +set_final_stage_ | ||
- set(BOOTSTRAP_LLVM_T | |||
-endif() | |||
-# Stage 3 Options | |||
-set(BOOTSTRAP_BOOTST | |||
-set(BOOTSTRAP_BOOTST | |||
-set(BOOTSTRAP_BOOTST | |||
-if (LLVM_RELEASE_ENA | |||
- set(BOOTSTRAP_BOOTST | |||
-endif() |
@@ -40,6 +40,7 @@ set(RUNTIMES_x86 | |||
set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_ | set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_ | ||
set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_ | set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_ | ||
set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_ | set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_ | ||
+set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_ | |||
set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_ | set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_ | ||
set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_ | set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_ | ||
set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_ | set(RUNTIMES_x86_64-unknown-linux-gnu_COMPILER_RT_ | ||
@@ -52,6 +53,7 @@ set(RUNTIMES_ve- | |||
set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_ | set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_ | ||
set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_ | set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_ | ||
set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_ | set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_ | ||
+set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_ | |||
set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_ | set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_ | ||
set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_ | set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_ | ||
set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_ | set(RUNTIMES_ve-unknown-linux-gnu_COMPILER_RT_ |
@@ -711,6 +711,8 @@ even-odd element pair with indices ``i * 2`` and ``i * 2 + 1`` with | |||
power of 2, the vector is widened with neutral elements for the reduction | power of 2, the vector is widened with neutral elements for the reduction | ||
at the end to the next power of 2. | at the end to the next power of 2. | ||
+These reductions support both fixed-sized and scalable vector types. | |||
+ | |||
Example: | Example: | ||
.. code-block:: c++ | .. code-block:: c++ | ||
@@ -1493,6 +1495,7 @@ Conditional ``explicit`` __cpp_conditiona | |||
``if consteval`` __cpp_if_constev | ``if consteval`` __cpp_if_constev | ||
``static operator()`` __cpp_static_cal | ``static operator()`` __cpp_static_cal | ||
Attributes on Lambda-Expressions C++23 C++11 | Attributes on Lambda-Expressions C++23 C++11 | ||
+Attributes on Structured Bindings __cpp_structured | |||
``= delete ("should have a reason");`` __cpp_deleted_fu | ``= delete ("should have a reason");`` __cpp_deleted_fu | ||
-------------------------------------------- -------------------------------- ------------- ------------- | -------------------------------------------- -------------------------------- ------------- ------------- | ||
Designated initializers (N494) C99 C89 | Designated initializers (N494) C99 C89 | ||
@@ -2928,7 +2931,7 @@ Query for this feature with ``__has_builtin( | |||
``__builtin_shuffl | ``__builtin_shuffl | ||
permutation/shuffle/swizzle operations. This builtin is also very important | permutation/shuffle/swizzle operations. This builtin is also very important | ||
for the implementation of various target-specific header files like | for the implementation of various target-specific header files like | ||
-``<xmmintrin.h>``. | +``<xmmintrin.h>``. This builtin can be used within constant expressions. | ||
**Syntax**: | **Syntax**: | ||
@@ -2955,7 +2958,7 @@ for the implementation of various target-specific header files like | |||
// Concatenate every other element of 8-element vectors V1 and V2. | // Concatenate every other element of 8-element vectors V1 and V2. | ||
__builtin_shuffl | __builtin_shuffl | ||
- // Shuffle v1 with some elements being undefined | + // Shuffle v1 with some elements being undefined. Not allowed in constexpr. | ||
__builtin_shuffl | __builtin_shuffl | ||
**Description**: | **Description**: | ||
@@ -2968,6 +2971,7 @@ starting with the first vector, continuing into the second vector. Thus, if | |||
``vec1`` is a 4-element vector, index 5 would refer to the second element of | ``vec1`` is a 4-element vector, index 5 would refer to the second element of | ||
``vec2``. An index of -1 can be used to indicate that the corresponding element | ``vec2``. An index of -1 can be used to indicate that the corresponding element | ||
in the returned vector is a don't care and can be optimized by the backend. | in the returned vector is a don't care and can be optimized by the backend. | ||
+Values of -1 are not supported in constant expressions. | |||
The result of ``__builtin_shuffl | The result of ``__builtin_shuffl | ||
type as ``vec1``/``vec2`` but that has an element count equal to the number of | type as ``vec1``/``vec2`` but that has an element count equal to the number of | ||
@@ -2982,7 +2986,8 @@ Query for this feature with ``__has_builtin( | |||
``__builtin_conver | ``__builtin_conver | ||
type-conversion operations. The input vector and the output vector | type-conversion operations. The input vector and the output vector | ||
-type must have the same number of elements. | +type must have the same number of elements. This builtin can be used within | ||
+constant expressions. | |||
**Syntax**: | **Syntax**: | ||
@@ -5572,3 +5577,25 @@ but the expression has no runtime effects. | |||
Type- and value-dependent expressions are not supported yet. | Type- and value-dependent expressions are not supported yet. | ||
This facility is designed to aid with testing name lookup machinery. | This facility is designed to aid with testing name lookup machinery. | ||
+ | |||
+Predefined Macros | |||
+================= | |||
+ | |||
+`__GCC_DESTRUCTIV | |||
+------------------------------------------------------ | |||
+Specify the mimum offset between two objects to avoid false sharing and the | |||
+maximum size of contiguous memory to promote true sharing, respectively. These | |||
+macros are predefined in all C and C++ language modes, but can be redefined on | |||
+the command line with ``-D`` to specify different values as needed or can be | |||
+undefined on the command line with ``-U`` to disable support for the feature. | |||
+ | |||
+**Note: the values the macros expand to are not guaranteed to be stable. They | |||
+are are affected by architectures and CPU tuning flags, can change between | |||
+releases of Clang and will not match the values defined by other compilers such | |||
+as GCC.** | |||
+ | |||
+Compiling different TUs depending on these flags (including use of | |||
+``std::hardware_constru | |||
+``std::hardware_destruc | |||
+definitions, or architecture flags will lead to ODR violations and should be | |||
+avoided. |
@@ -63,15 +63,22 @@ and automatic location of the compilation database using source files paths. | |||
#include "llvm/Support/CommandLine.h" | #include "llvm/Support/CommandLine.h" | ||
using namespace clang::tooling; | using namespace clang::tooling; | ||
+ using namespace llvm; | |||
// Apply a custom category to all command-line options so that they are the | // Apply a custom category to all command-line options so that they are the | ||
// only ones displayed. | // only ones displayed. | ||
- static | + static cl::OptionCategory MyToolCategory("my-tool options"); | ||
int main(int argc, const char **argv) { | int main(int argc, const char **argv) { | ||
- // | + // CommonOptionsParser::create will parse arguments and create a | ||
- // CompilationDatabase. | + // CompilationDatabase. | ||
- | + auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory); | ||
+ if (!ExpectedParser) { | |||
+ // Fail gracefully for unsupported options. | |||
+ llvm::errs() << ExpectedParser.takeError(); | |||
+ return 1; | |||
+ } | |||
+ CommonOptionsPar | |||
// Use OptionsParser.getCompilations() and OptionsParser.getSourcePathLis | // Use OptionsParser.getCompilations() and OptionsParser.getSourcePathLis | ||
// to retrieve CompilationDatab | // to retrieve CompilationDatab | ||
@@ -133,7 +140,12 @@ version of this example tool is also checked into the clang tree at | |||
static cl::extrahelp MoreHelp("\nMore help text...\n"); | static cl::extrahelp MoreHelp("\nMore help text...\n"); | ||
int main(int argc, const char **argv) { | int main(int argc, const char **argv) { | ||
- | + auto ExpectedParser = CommonOptionsParser::create(argc, argv, MyToolCategory); | ||
+ if (!ExpectedParser) { | |||
+ llvm::errs() << ExpectedParser.takeError(); | |||
+ return 1; | |||
+ } | |||
+ CommonOptionsPar | |||
ClangTool Tool(OptionsParser.getCompilations(), | ClangTool Tool(OptionsParser.getCompilations(), | ||
OptionsParser.getSourcePathLis | OptionsParser.getSourcePathLis | ||
return Tool.run(newFrontendActio | return Tool.run(newFrontendActio |
@@ -310,7 +310,9 @@ implementation. | |||
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | ||
| misc | dispatch construct and function variant argument adjustment | :part:`worked on` | D99537, D99679 | | | misc | dispatch construct and function variant argument adjustment | :part:`worked on` | D99537, D99679 | | ||
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | ||
-| misc | | +| misc | assumes directives | :part:`worked on` | | | ||
++------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | |||
+| misc | assume directive | :part:`worked on` | | | |||
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | ||
| misc | nothing directive | :good:`done` | D123286 | | | misc | nothing directive | :good:`done` | D123286 | | ||
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ | +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+ |
@@ -63,6 +63,12 @@ ABI Changes in This Version | |||
MSVC uses a different mangling for these objects, compatibility is not affected. | MSVC uses a different mangling for these objects, compatibility is not affected. | ||
(#GH85423). | (#GH85423). | ||
+- Fixed Microsoft calling convention for returning certain classes with a | |||
+ templated constructor. If a class has a templated constructor, it should | |||
+ be returned indirectly even if it meets all the other requirements for | |||
+ returning a class in a register. This affects some uses of std::pair. | |||
+ (#GH86384). | |||
+ | |||
AST Dumping Potentially Breaking Changes | AST Dumping Potentially Breaking Changes | ||
---------------------------------------- | ---------------------------------------- | ||
@@ -90,6 +96,18 @@ C++ Language Changes | |||
-------------------- | -------------------- | ||
- Implemented ``_BitInt`` literal suffixes ``__wb`` or ``__WB`` as a Clang extension with ``unsigned`` modifiers also allowed. (#GH85223). | - Implemented ``_BitInt`` literal suffixes ``__wb`` or ``__WB`` as a Clang extension with ``unsigned`` modifiers also allowed. (#GH85223). | ||
+C++17 Feature Support | |||
+^^^^^^^^^^^^^^^^^^^^^ | |||
+- Clang now exposes ``__GCC_DESTRUCTIV | |||
+ predefined macros to support standard library implementations of | |||
+ ``std::hardware_destruc | |||
+ ``std::hardware_constru | |||
+ are predefined in all C and C++ language modes. The values the macros | |||
+ expand to are not stable between releases of Clang and do not need to match | |||
+ the values produced by GCC, so these macros should not be used from header | |||
+ files because they may not be stable across multiple TUs (the values may vary | |||
+ based on compiler version as well as CPU tuning). #GH60174 | |||
+ | |||
C++20 Feature Support | C++20 Feature Support | ||
^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^ | ||
@@ -131,6 +149,9 @@ C++2c Feature Support | |||
- Implemented `P2573R2: = delete("should have a reason"); <https://wg21.link/P2573R2>`_ | - Implemented `P2573R2: = delete("should have a reason"); <https://wg21.link/P2573R2>`_ | ||
+- Implemented `P0609R3: Attributes for Structured Bindings <https://wg21.link/P0609R3>`_ | |||
+ | |||
+- Implemented `P2748R5 Disallow Binding a Returned Glvalue to a Temporary <https://wg21.link/P2748R5>`_. | |||
Resolutions to C++ Defect Reports | Resolutions to C++ Defect Reports | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
@@ -207,6 +228,20 @@ Non-comprehensiv | |||
- ``__typeof_unqual_ | - ``__typeof_unqual_ | ||
like ``typeof_unqual`` from C23, similar to ``__typeof__`` and ``typeof``. | like ``typeof_unqual`` from C23, similar to ``__typeof__`` and ``typeof``. | ||
+- ``__builtin_reduce | |||
+ | |||
+* Shared libraries linked with either the ``-ffast-math``, ``-Ofast``, or | |||
+ ``-funsafe-math-optimizations`` flags will no longer enable flush-to-zero | |||
+ floating-point mode by default. This decision can be overridden with use of | |||
+ ``-mdaz-ftz``. This behavior now matches GCC's behavior. | |||
+ (`#57589 <https://github.com/llvm/llvm-project/issues/57589>`_) | |||
+ | |||
+* ``-fdenormal-fp-math=preserve-sign`` is no longer implied by ``-ffast-math`` | |||
+ on x86 systems. | |||
+ | |||
+- Builtins ``__builtin_shuffl | |||
+ now be used within constant expressions. | |||
+ | |||
New Compiler Flags | New Compiler Flags | ||
------------------ | ------------------ | ||
- ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and | - ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and | ||
@@ -221,6 +256,10 @@ New Compiler Flags | |||
- ``-fexperimental-modules-reduced-bmi`` enables the Reduced BMI for C++20 named modules. | - ``-fexperimental-modules-reduced-bmi`` enables the Reduced BMI for C++20 named modules. | ||
See the document of standard C++ modules for details. | See the document of standard C++ modules for details. | ||
+- ``-fexperimental-late-parse-attributes`` enables an experimental feature to | |||
+ allow late parsing certain attributes in specific contexts where they would | |||
+ not normally be late parsed. | |||
+ | |||
Deprecated Compiler Flags | Deprecated Compiler Flags | ||
------------------------- | ------------------------- | ||
@@ -375,6 +414,18 @@ Improvements to Clang's diagnostics | |||
- Clang now diagnoses requires expressions with explicit object parameters. | - Clang now diagnoses requires expressions with explicit object parameters. | ||
+- Clang now looks up members of the current instantiation in the template definition context | |||
+ if the current instantiation has no dependent base classes. | |||
+ | |||
+ .. code-block:: c++ | |||
+ | |||
+ template<typename T> | |||
+ struct A { | |||
+ int f() { | |||
+ return this->x; // error: no member named 'x' in 'A<T>' | |||
+ } | |||
+ }; | |||
+ | |||
Improvements to Clang's time-trace | Improvements to Clang's time-trace | ||
---------------------------------- | ---------------------------------- | ||
@@ -421,6 +472,9 @@ Bug Fixes in This Version | |||
- Clang now correctly generates overloads for bit-precise integer types for | - Clang now correctly generates overloads for bit-precise integer types for | ||
builtin operators in C++. Fixes #GH82998. | builtin operators in C++. Fixes #GH82998. | ||
+- Fix crash when destructor definition is preceded with an equals sign. | |||
+ Fixes (#GH89544). | |||
+ | |||
- When performing mixed arithmetic between ``_Complex`` floating-point types and integers, | - When performing mixed arithmetic between ``_Complex`` floating-point types and integers, | ||
Clang now correctly promotes the integer to its corresponding real floating-point | Clang now correctly promotes the integer to its corresponding real floating-point | ||
type only rather than to the complex type (e.g. ``_Complex float / int`` is now evaluated | type only rather than to the complex type (e.g. ``_Complex float / int`` is now evaluated | ||
@@ -436,6 +490,10 @@ Bug Fixes in This Version | |||
- Fixed an assertion failure on invalid InitListExpr in C89 mode (#GH88008). | - Fixed an assertion failure on invalid InitListExpr in C89 mode (#GH88008). | ||
+- Fixed missing destructor calls when we branch from middle of an expression. | |||
+ This could happen through a branch in stmt-expr or in an expression containing a coroutine | |||
+ suspension. Fixes (#GH63818) (#GH88478). | |||
+ | |||
- Clang will no longer diagnose an erroneous non-dependent ``switch`` condition | - Clang will no longer diagnose an erroneous non-dependent ``switch`` condition | ||
during instantiation, and instead will only diagnose it once, during checking | during instantiation, and instead will only diagnose it once, during checking | ||
of the function template. | of the function template. | ||
@@ -564,6 +622,14 @@ Bug Fixes to C++ Support | |||
- Fixed a crash when trying to evaluate a user-defined ``static_assert`` message whose ``size()`` | - Fixed a crash when trying to evaluate a user-defined ``static_assert`` message whose ``size()`` | ||
function returns a large or negative value. Fixes (#GH89407). | function returns a large or negative value. Fixes (#GH89407). | ||
- Fixed a use-after-free bug in parsing of type constraints with default arguments that involve lambdas. (#GH67235) | - Fixed a use-after-free bug in parsing of type constraints with default arguments that involve lambdas. (#GH67235) | ||
+- Fixed bug in which the body of a consteval lambda within a template was not parsed as within an | |||
+ immediate function context. | |||
+- Fix CTAD for ``std::initializer_list | |||
+ ``std::initializer_list | |||
+- Fix a bug on template partial specialization whose template parameter is `decltype(auto)`. | |||
+- Fix a bug on template partial specialization with issue on deduction of nontype template parameter | |||
+ whose type is `decltype(auto)`. Fixes (#GH68885). | |||
+- Clang now correctly treats the noexcept-specifier of a friend function to be a complete-class context. | |||
Bug Fixes to AST Handling | Bug Fixes to AST Handling | ||
^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
@@ -616,6 +682,10 @@ Arm and AArch64 Support | |||
* Arm Cortex-A78AE (cortex-a78ae). | * Arm Cortex-A78AE (cortex-a78ae). | ||
* Arm Cortex-A520AE (cortex-a520ae). | * Arm Cortex-A520AE (cortex-a520ae). | ||
* Arm Cortex-A720AE (cortex-a720ae). | * Arm Cortex-A720AE (cortex-a720ae). | ||
+ * Arm Cortex-R82AE (cortex-r82ae). | |||
+ * Arm Neoverse-N3 (neoverse-n3). | |||
+ * Arm Neoverse-V3 (neoverse-v3). | |||
+ * Arm Neoverse-V3AE (neoverse-v3ae). | |||
Android Support | Android Support | ||
^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^ | ||
@@ -672,6 +742,11 @@ AIX Support | |||
WebAssembly Support | WebAssembly Support | ||
^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^ | ||
+The -mcpu=generic configuration now enables multivalue and reference-types.These | |||
+proposals are standardized and available in all major engines. Enabling | |||
+multivalue here only enables the language feature but does not turn on the | |||
+multivalue ABI (this enables non-ABI uses of multivalue, like exnref). | |||
+ | |||
AVR Support | AVR Support | ||
^^^^^^^^^^^ | ^^^^^^^^^^^ | ||
@@ -1452,8 +1452,6 @@ floating point semantic models: precise (the default), strict, and fast. | |||
"fenv_access", "off", "on", "off" | "fenv_access", "off", "on", "off" | ||
"rounding_mode", "tonearest", "dynamic", "tonearest" | "rounding_mode", "tonearest", "dynamic", "tonearest" | ||
"contract", "on", "off", "fast" | "contract", "on", "off", "fast" | ||
- "denormal_fp_math | |||
- "denormal_fp32_ma | |||
"support_math_err | "support_math_err | ||
"no_honor_nans", "off", "off", "on" | "no_honor_nans", "off", "off", "on" | ||
"no_honor_infinit | "no_honor_infinit | ||
@@ -1462,6 +1460,14 @@ floating point semantic models: precise (the default), strict, and fast. | |||
"allow_approximat | "allow_approximat | ||
"allow_reassociat | "allow_reassociat | ||
+The ``-ffp-model`` option does not modify the ``fdenormal-fp-math`` | |||
+setting, but it does have an impact on whether ``crtfastmath.o`` is | |||
+linked. Because linking ``crtfastmath.o`` has a global effect on the | |||
+program, and because the global denormal handling can be changed in | |||
+other ways, the state of ``fdenormal-fp-math`` handling cannot | |||
+be assumed in any function based on fp-model. See :ref:`crtfastmath.o` | |||
+for more details. | |||
+ | |||
.. option:: -ffast-math | .. option:: -ffast-math | ||
Enable fast-math mode. This option lets the | Enable fast-math mode. This option lets the | ||
@@ -1506,7 +1512,8 @@ floating point semantic models: precise (the default), strict, and fast. | |||
* ``-ffp-contract=fast`` | * ``-ffp-contract=fast`` | ||
- Note: ``-ffast-math`` causes ``crtfastmath.o`` to be linked with code | + Note: ``-ffast-math`` causes ``crtfastmath.o`` to be linked with code unless | ||
+ ``-shared`` or ``-mno-daz-ftz`` is present. See | |||
:ref:`crtfastmath.o` for more details. | :ref:`crtfastmath.o` for more details. | ||
.. option:: -fno-fast-math | .. option:: -fno-fast-math | ||
@@ -1536,7 +1543,6 @@ floating point semantic models: precise (the default), strict, and fast. | |||
Also, this option resets following options to their target-dependent defaults. | Also, this option resets following options to their target-dependent defaults. | ||
* ``-f[no-]math-errno`` | * ``-f[no-]math-errno`` | ||
- * ``-fdenormal-fp-math=<value>`` | |||
There is ambiguity about how ``-ffp-contract``, ``-ffast-math``, | There is ambiguity about how ``-ffp-contract``, ``-ffast-math``, | ||
and ``-fno-fast-math`` behave when combined. To keep the value of | and ``-fno-fast-math`` behave when combined. To keep the value of | ||
@@ -1559,8 +1565,8 @@ floating point semantic models: precise (the default), strict, and fast. | |||
``-ffp-contract`` setting is determined by the default value of | ``-ffp-contract`` setting is determined by the default value of | ||
``-ffp-contract``. | ``-ffp-contract``. | ||
- Note: ``-fno-fast-math`` implies ``-fdenormal-fp-math=ieee``. | + Note: ``-fno-fast-math`` causes ``crtfastmath.o`` to not be linked with code | ||
- ``-fno-fast-math`` causes ``crtfastmath.o`` to not be linked with code. | + unless ``-mdaz-ftz`` is present. | ||
.. option:: -fdenormal-fp-math=<value> | .. option:: -fdenormal-fp-math=<value> | ||
@@ -1690,9 +1696,7 @@ floating point semantic models: precise (the default), strict, and fast. | |||
* ``-fno-associative-math`` | * ``-fno-associative-math`` | ||
* ``-fno-reciprocal-math`` | * ``-fno-reciprocal-math`` | ||
* ``-fsigned-zeros`` | * ``-fsigned-zeros`` | ||
- * ``-ftrapping-math`` | |||
* ``-ffp-contract=on`` | * ``-ffp-contract=on`` | ||
- * ``-fdenormal-fp-math=ieee`` | |||
There is ambiguity about how ``-ffp-contract``, | There is ambiguity about how ``-ffp-contract``, | ||
``-funsafe-math-optimizations``, and ``-fno-unsafe-math-optimizations`` | ``-funsafe-math-optimizations``, and ``-fno-unsafe-math-optimizations`` | ||
@@ -1938,10 +1942,13 @@ by using ``#pragma STDC FENV_ROUND`` with a value other than ``FE_DYNAMIC``. | |||
A note about ``crtfastmath.o`` | A note about ``crtfastmath.o`` | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
-``-ffast-math`` and ``-funsafe-math-optimizations`` | +``-ffast-math`` and ``-funsafe-math-optimizations`` without the ``-shared`` | ||
-automatically linked, which adds a static constructor that sets the FTZ/DAZ | +option cause ``crtfastmath.o`` to be | ||
+automatically linked, which adds a static constructor that sets the FTZ/DAZ | |||
bits in MXCSR, affecting not only the current compilation unit but all static | bits in MXCSR, affecting not only the current compilation unit but all static | ||
-and shared libraries included in the program. | +and shared libraries included in the program. This decision can be overridden | ||
+by using either the flag ``-mdaz-ftz`` or ``-mno-daz-ftz`` to respectively | |||
+link or not link ``crtfastmath.o``. | |||
.. _FLT_EVAL_METHOD | .. _FLT_EVAL_METHOD | ||
@@ -2314,6 +2321,8 @@ are listed below. | |||
on ELF targets when using the integrated assembler. This flag currently | on ELF targets when using the integrated assembler. This flag currently | ||
only has an effect on ELF targets. | only has an effect on ELF targets. | ||
+.. _funique_interna | |||
+ | |||
.. option:: -f[no]-unique-internal-linkage-names | .. option:: -f[no]-unique-internal-linkage-names | ||
Controls whether Clang emits a unique (best-effort) symbol name for internal | Controls whether Clang emits a unique (best-effort) symbol name for internal | ||
@@ -2443,27 +2452,41 @@ usual build cycle when using sample profilers for optimization: | |||
usual build flags that you always build your application with. The only | usual build flags that you always build your application with. The only | ||
requirement is that DWARF debug info including source line information is | requirement is that DWARF debug info including source line information is | ||
generated. This DWARF information is important for the profiler to be able | generated. This DWARF information is important for the profiler to be able | ||
- to map instructions back to source line locations. | + to map instructions back to source line locations. The usefulness of this | ||
+ DWARF information can be improved with the ``-fdebug-info-for-profiling`` | |||
+ and ``-funique-internal-linkage-names`` options. | |||
- On Linux, ``-g`` or just ``-gline-tables-only`` is sufficient: | + On Linux: | ||
.. code-block:: console | .. code-block:: console | ||
- $ clang++ -O2 -gline-tables-only | + $ clang++ -O2 -gline-tables-only \ | ||
+ -fdebug-info-for-profiling -funique-internal-linkage-names \ | |||
+ code.cc -o code | |||
While MSVC-style targets default to CodeView debug information, DWARF debug | While MSVC-style targets default to CodeView debug information, DWARF debug | ||
information is required to generate source-level LLVM profiles. Use | information is required to generate source-level LLVM profiles. Use | ||
``-gdwarf`` to include DWARF debug information: | ``-gdwarf`` to include DWARF debug information: | ||
- .. code-block:: | + .. code-block:: winbatch | ||
+ | |||
+ > clang-cl /O2 -gdwarf -gline-tables-only ^ | |||
+ /clang:-fdebug-info-for-profiling /clang:-funique-internal-linkage-names ^ | |||
+ code.cc /Fe:code /fuse-ld=lld /link /debug:dwarf | |||
- $ clang-cl -O2 -gdwarf -gline-tables-only coff-profile.cpp -fuse-ld=lld -link -debug:dwarf | +.. note:: | ||
+ | |||
+ :ref:`-funique-internal-linkage-names <funique_internal | |||
+ generates unique names based on given command-line source file paths. If | |||
+ your build system uses absolute source paths and these paths may change | |||
+ between steps 1 and 4, then the uniqued function names may change and result | |||
+ in unused profile data. Consider omitting this option in such cases. | |||
2. Run the executable under a sampling profiler. The specific profiler | 2. Run the executable under a sampling profiler. The specific profiler | ||
you use does not really matter, as long as its output can be converted | you use does not really matter, as long as its output can be converted | ||
into the format that the LLVM optimizer understands. | into the format that the LLVM optimizer understands. | ||
- Two such profilers are the | + Two such profilers are the Linux Perf profiler | ||
(https://perf.wiki.kernel.org/) and Intel's Sampling Enabling Product (SEP), | (https://perf.wiki.kernel.org/) and Intel's Sampling Enabling Product (SEP), | ||
available as part of `Intel VTune | available as part of `Intel VTune | ||
<https://software.intel.com/content/www/us/en/develop/tools/oneapi/components/vtune-profiler.html>`_. | <https://software.intel.com/content/www/us/en/develop/tools/oneapi/components/vtune-profiler.html>`_. | ||
@@ -2477,7 +2500,9 @@ usual build cycle when using sample profilers for optimization: | |||
.. code-block:: console | .. code-block:: console | ||
- $ perf record -b ./code | + $ perf record -b -e BR_INST_RETIRED.NEAR_TAKEN:uppp ./code | ||
+ | |||
+ If the event above is unavailable, ``branches:u`` is probably next-best. | |||
Note the use of the ``-b`` flag. This tells Perf to use the Last Branch | Note the use of the ``-b`` flag. This tells Perf to use the Last Branch | ||
Record (LBR) to record call chains. While this is not strictly required, | Record (LBR) to record call chains. While this is not strictly required, | ||
@@ -2527,21 +2552,42 @@ usual build cycle when using sample profilers for optimization: | |||
that executes faster than the original one. Note that you are not | that executes faster than the original one. Note that you are not | ||
required to build the code with the exact same arguments that you | required to build the code with the exact same arguments that you | ||
used in the first step. The only requirement is that you build the code | used in the first step. The only requirement is that you build the code | ||
- with | + with the same debug info options and ``-fprofile-sample-use``. | ||
+ | |||
+ On Linux: | |||
.. code-block:: console | .. code-block:: console | ||
- $ clang++ -O2 -gline-tables-only | + $ clang++ -O2 -gline-tables-only \ | ||
+ -fdebug-info-for-profiling -funique-internal-linkage-names \ | |||
+ -fprofile-sample-use=code.prof code.cc -o code | |||
- [OPTIONAL] Sampling-based profiles can have inaccuracies or missing block/ | + On Windows: | ||
- edge counters. The profile inference algorithm (profi) can be used to infer | |||
- missing blocks and edge counts, and improve the quality of profile data. | |||
- Enable it with ``-fsample-profile-use-profi``. | |||
- | + .. code-block:: winbatch | ||
+ | |||
+ > clang-cl /O2 -gdwarf -gline-tables-only ^ | |||
+ /clang:-fdebug-info-for-profiling /clang:-funique-internal-linkage-names ^ | |||
+ /fprofile-sample-use=code.prof code.cc /Fe:code /fuse-ld=lld /link /debug:dwarf | |||
+ | |||
+ [OPTIONAL] Sampling-based profiles can have inaccuracies or missing block/ | |||
+ edge counters. The profile inference algorithm (profi) can be used to infer | |||
+ missing blocks and edge counts, and improve the quality of profile data. | |||
+ Enable it with ``-fsample-profile-use-profi``. For example, on Linux: | |||
+ | |||
+ .. code-block:: console | |||
+ | |||
+ $ clang++ -fsample-profile-use-profi -O2 -gline-tables-only \ | |||
+ -fdebug-info-for-profiling -funique-internal-linkage-names \ | |||
+ -fprofile-sample-use=code.prof code.cc -o code | |||
+ | |||
+ On Windows: | |||
+ | |||
+ .. code-block:: winbatch | |||
- | + > clang-cl /clang:-fsample-profile-use-profi /O2 -gdwarf -gline-tables-only ^ | ||
- -fsample-profile-use-profi code.cc -o code | + /clang:-fdebug-info-for-profiling /clang:-funique-internal-linkage-names ^ | ||
+ /fprofile-sample-use=code.prof code.cc /Fe:code /fuse-ld=lld /link /debug:dwarf | |||
Sample Profile Formats | Sample Profile Formats | ||
"""""""""""""""""""""" | """""""""""""""""""""" |
@@ -1462,6 +1462,99 @@ checker). | |||
Default value of the option is ``true``. | Default value of the option is ``true``. | ||
+.. _unix-Stream: | |||
+ | |||
+unix.Stream (C) | |||
+""""""""""""""" | |||
+Check C stream handling functions: | |||
+``fopen, fdopen, freopen, tmpfile, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, fprintf, fscanf, ungetc, getdelim, getline, fseek, fseeko, ftell, ftello, fflush, rewind, fgetpos, fsetpos, clearerr, feof, ferror, fileno``. | |||
+ | |||
+The checker maintains information about the C stream objects (``FILE *``) and | |||
+can detect error conditions related to use of streams. The following conditions | |||
+are detected: | |||
+ | |||
+* The ``FILE *`` pointer passed to the function is NULL (the single exception is | |||
+ ``fflush`` where NULL is allowed). | |||
+* Use of stream after close. | |||
+* Opened stream is not closed. | |||
+* Read from a stream after end-of-file. (This is not a fatal error but reported | |||
+ by the checker. Stream remains in EOF state and the read operation fails.) | |||
+* Use of stream when the file position is indeterminate after a previous failed | |||
+ operation. Some functions (like ``ferror``, ``clearerr``, ``fseek``) are | |||
+ allowed in this state. | |||
+* Invalid 3rd ("``whence``") argument to ``fseek``. | |||
+ | |||
+The stream operations are by this checker usually split into two cases, a success | |||
+and a failure case. However, in the case of write operations (like ``fwrite``, | |||
+``fprintf`` and even ``fsetpos``) this behavior could produce a large amount of | |||
+unwanted reports on projects that don't have error checks around the write | |||
+operations, so by default the checker assumes that write operations always succeed. | |||
+This behavior can be controlled by the ``Pedantic`` flag: With | |||
+``-analyzer-config unix.Stream:Pedantic=true`` the checker will model the | |||
+cases where a write operation fails and report situations where this leads to | |||
+erroneous behavior. (The default is ``Pedantic=false``, where write operations | |||
+are assumed to succeed.) | |||
+ | |||
+.. code-block:: c | |||
+ | |||
+ void test1() { | |||
+ FILE *p = fopen("foo", "r"); | |||
+ } // warn: opened file is never closed | |||
+ | |||
+ void test2() { | |||
+ FILE *p = fopen("foo", "r"); | |||
+ fseek(p, 1, SEEK_SET); // warn: stream pointer might be NULL | |||
+ fclose(p); | |||
+ } | |||
+ | |||
+ void test3() { | |||
+ FILE *p = fopen("foo", "r"); | |||
+ if (p) { | |||
+ fseek(p, 1, 3); // warn: third arg should be SEEK_SET, SEEK_END, or SEEK_CUR | |||
+ fclose(p); | |||
+ } | |||
+ } | |||
+ | |||
+ void test4() { | |||
+ FILE *p = fopen("foo", "r"); | |||
+ if (!p) | |||
+ return; | |||
+ | |||
+ fclose(p); | |||
+ fclose(p); // warn: stream already closed | |||
+ } | |||
+ | |||
+ void test5() { | |||
+ FILE *p = fopen("foo", "r"); | |||
+ if (!p) | |||
+ return; | |||
+ | |||
+ fgetc(p); | |||
+ if (!ferror(p)) | |||
+ fgetc(p); // warn: possible read after end-of-file | |||
+ | |||
+ fclose(p); | |||
+ } | |||
+ | |||
+ void test6() { | |||
+ FILE *p = fopen("foo", "r"); | |||
+ if (!p) | |||
+ return; | |||
+ | |||
+ fgetc(p); | |||
+ if (!feof(p)) | |||
+ fgetc(p); // warn: file position may be indeterminate after I/O error | |||
+ | |||
+ fclose(p); | |||
+ } | |||
+ | |||
+**Limitations** | |||
+ | |||
+The checker does not track the correspondence between integer file descriptors | |||
+and ``FILE *`` pointers. Operations on standard streams like ``stdin`` are not | |||
+treated specially and are therefore often not recognized (because these streams | |||
+are usually not opened explicitly by the program, and are global variables). | |||
+ | |||
.. _osx-checkers: | .. _osx-checkers: | ||
osx | osx | ||
@@ -3116,99 +3209,6 @@ Check for misuses of stream APIs. Check for misuses of stream APIs: ``fopen, fcl | |||
fclose(F); // warn: closing a previously closed file stream | fclose(F); // warn: closing a previously closed file stream | ||
} | } | ||
-.. _alpha-unix-Stream: | |||
- | |||
-alpha.unix.Stream (C) | |||
-""""""""""""""""""""" | |||
-Check C stream handling functions: | |||
-``fopen, fdopen, freopen, tmpfile, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, fprintf, fscanf, ungetc, getdelim, getline, fseek, fseeko, ftell, ftello, fflush, rewind, fgetpos, fsetpos, clearerr, feof, ferror, fileno``. | |||
- | |||
-The checker maintains information about the C stream objects (``FILE *``) and | |||
-can detect error conditions related to use of streams. The following conditions | |||
-are detected: | |||
- | |||
-* The ``FILE *`` pointer passed to the function is NULL (the single exception is | |||
- ``fflush`` where NULL is allowed). | |||
-* Use of stream after close. | |||
-* Opened stream is not closed. | |||
-* Read from a stream after end-of-file. (This is not a fatal error but reported | |||
- by the checker. Stream remains in EOF state and the read operation fails.) | |||
-* Use of stream when the file position is indeterminate after a previous failed | |||
- operation. Some functions (like ``ferror``, ``clearerr``, ``fseek``) are | |||
- allowed in this state. | |||
-* Invalid 3rd ("``whence``") argument to ``fseek``. | |||
- | |||
-The stream operations are by this checker usually split into two cases, a success | |||
-and a failure case. However, in the case of write operations (like ``fwrite``, | |||
-``fprintf`` and even ``fsetpos``) this behavior could produce a large amount of | |||
-unwanted reports on projects that don't have error checks around the write | |||
-operations, so by default the checker assumes that write operations always succeed. | |||
-This behavior can be controlled by the ``Pedantic`` flag: With | |||
-``-analyzer-config alpha.unix.Stream:Pedantic=true`` the checker will model the | |||
-cases where a write operation fails and report situations where this leads to | |||
-erroneous behavior. (The default is ``Pedantic=false``, where write operations | |||
-are assumed to succeed.) | |||
- | |||
-.. code-block:: c | |||
- | |||
- void test1() { | |||
- FILE *p = fopen("foo", "r"); | |||
- } // warn: opened file is never closed | |||
- | |||
- void test2() { | |||
- FILE *p = fopen("foo", "r"); | |||
- fseek(p, 1, SEEK_SET); // warn: stream pointer might be NULL | |||
- fclose(p); | |||
- } | |||
- | |||
- void test3() { | |||
- FILE *p = fopen("foo", "r"); | |||
- if (p) { | |||
- fseek(p, 1, 3); // warn: third arg should be SEEK_SET, SEEK_END, or SEEK_CUR | |||
- fclose(p); | |||
- } | |||
- } | |||
- | |||
- void test4() { | |||
- FILE *p = fopen("foo", "r"); | |||
- if (!p) | |||
- return; | |||
- | |||
- fclose(p); | |||
- fclose(p); // warn: stream already closed | |||
- } | |||
- | |||
- void test5() { | |||
- FILE *p = fopen("foo", "r"); | |||
- if (!p) | |||
- return; | |||
- | |||
- fgetc(p); | |||
- if (!ferror(p)) | |||
- fgetc(p); // warn: possible read after end-of-file | |||
- | |||
- fclose(p); | |||
- } | |||
- | |||
- void test6() { | |||
- FILE *p = fopen("foo", "r"); | |||
- if (!p) | |||
- return; | |||
- | |||
- fgetc(p); | |||
- if (!feof(p)) | |||
- fgetc(p); // warn: file position may be indeterminate after I/O error | |||
- | |||
- fclose(p); | |||
- } | |||
- | |||
-**Limitations** | |||
- | |||
-The checker does not track the correspondence between integer file descriptors | |||
-and ``FILE *`` pointers. Operations on standard streams like ``stdin`` are not | |||
-treated specially and are therefore often not recognized (because these streams | |||
-are usually not opened explicitly by the program, and are global variables). | |||
- | |||
.. _alpha-unix-cstring-BufferOverlap: | .. _alpha-unix-cstring-BufferOverlap: | ||
alpha.unix.cstring.BufferOverlap (C) | alpha.unix.cstring.BufferOverlap (C) |
@@ -1644,8 +1644,9 @@ enum CXCursorKind { | |||
CXCursor_ObjCSel | CXCursor_ObjCSel | ||
/** OpenMP 5.0 [2.1.5, Array Section]. | /** OpenMP 5.0 [2.1.5, Array Section]. | ||
+ * OpenACC 3.3 [2.7.1, Data Specification for Data Clauses (Sub Arrays)] | |||
*/ | */ | ||
- | + CXCursor_ArraySectionExpr = 147, | ||
/** Represents an @available(...) check. | /** Represents an @available(...) check. | ||
*/ | */ |
@@ -675,6 +675,11 @@ class TagInfo : public CommonTypeInfo { | |||
LLVM_PREFERRED_T | LLVM_PREFERRED_T | ||
unsigned IsFlagEnum : 1; | unsigned IsFlagEnum : 1; | ||
+ LLVM_PREFERRED_T | |||
+ unsigned SwiftCopyableSpe | |||
+ LLVM_PREFERRED_T | |||
+ unsigned SwiftCopyable : 1; | |||
+ | |||
public: | public: | ||
std::optional<std::string> SwiftImportAs; | std::optional<std::string> SwiftImportAs; | ||
std::optional<std::string> SwiftRetainOp; | std::optional<std::string> SwiftRetainOp; | ||
@@ -682,7 +687,9 @@ public: | |||
std::optional<EnumExtensibilit | std::optional<EnumExtensibilit | ||
- TagInfo() | + TagInfo() | ||
+ : HasFlagEnum(0), IsFlagEnum(0), SwiftCopyableSpe | |||
+ SwiftCopyable(false) {} | |||
std::optional<bool> isFlagEnum() const { | std::optional<bool> isFlagEnum() const { | ||
if (HasFlagEnum) | if (HasFlagEnum) | ||
@@ -694,6 +701,15 @@ public: | |||
IsFlagEnum = Value.value_or(false); | IsFlagEnum = Value.value_or(false); | ||
} | } | ||
+ std::optional<bool> isSwiftCopyable() const { | |||
+ return SwiftCopyableSpe | |||
+ : std::nullopt; | |||
+ } | |||
+ void setSwiftCopyable | |||
+ SwiftCopyableSpe | |||
+ SwiftCopyable = Value.value_or(false); | |||
+ } | |||
+ | |||
TagInfo &operator|=(const TagInfo &RHS) { | TagInfo &operator|=(const TagInfo &RHS) { | ||
static_cast<CommonTypeInfo &>(*this) |= RHS; | static_cast<CommonTypeInfo &>(*this) |= RHS; | ||
@@ -710,6 +726,9 @@ public: | |||
if (!EnumExtensibilit | if (!EnumExtensibilit | ||
EnumExtensibilit | EnumExtensibilit | ||
+ if (!SwiftCopyableSpe | |||
+ setSwiftCopyable | |||
+ | |||
return *this; | return *this; | ||
} | } | ||
@@ -724,6 +743,7 @@ inline bool operator==(const | |||
LHS.SwiftRetainOp == RHS.SwiftRetainOp && | LHS.SwiftRetainOp == RHS.SwiftRetainOp && | ||
LHS.SwiftReleaseOp == RHS.SwiftReleaseOp && | LHS.SwiftReleaseOp == RHS.SwiftReleaseOp && | ||
LHS.isFlagEnum() == RHS.isFlagEnum() && | LHS.isFlagEnum() == RHS.isFlagEnum() && | ||
+ LHS.isSwiftCopyable() == RHS.isSwiftCopyable() && | |||
LHS.EnumExtensibilit | LHS.EnumExtensibilit | ||
} | } | ||
@@ -455,7 +455,7 @@ class ASTContext : public RefCountedBase<A | |||
/// initialization of another module). | /// initialization of another module). | ||
struct PerModuleInitial | struct PerModuleInitial | ||
llvm::SmallVector<Decl*, 4> Initializers; | llvm::SmallVector<Decl*, 4> Initializers; | ||
- | + llvm::SmallVector<GlobalDeclID, 4> LazyInitializers; | ||
void resolve(ASTContext &Ctx); | void resolve(ASTContext &Ctx); | ||
}; | }; | ||
@@ -1059,7 +1059,7 @@ public: | |||
/// or an ImportDecl nominating another module that has initializers. | /// or an ImportDecl nominating another module that has initializers. | ||
void addModuleInitial | void addModuleInitial | ||
- void addLazyModuleInitializers(Module *M, | + void addLazyModuleInitializers(Module *M, ArrayRef<GlobalDeclID> IDs); | ||
/// Get the initializations to perform when importing a module, if any. | /// Get the initializations to perform when importing a module, if any. | ||
ArrayRef<Decl*> getModuleInitial | ArrayRef<Decl*> getModuleInitial | ||
@@ -1127,7 +1127,8 @@ public: | |||
CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy; | CanQualType OCLSamplerTy, OCLEventTy, OCLClkEventTy; | ||
CanQualType OCLQueueTy, OCLReserveIDTy; | CanQualType OCLQueueTy, OCLReserveIDTy; | ||
CanQualType IncompleteMatrix | CanQualType IncompleteMatrix | ||
- CanQualType | + CanQualType ArraySectionTy; | ||
+ CanQualType OMPArrayShapingT | |||
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ | #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ | ||
CanQualType Id##Ty; | CanQualType Id##Ty; | ||
#include "clang/Basic/OpenCLExtensionT | #include "clang/Basic/OpenCLExtensionT | ||
@@ -2196,6 +2197,16 @@ public: | |||
return getQualifiedType | return getQualifiedType | ||
} | } | ||
+ /// \brief Return a type with the given __ptrauth qualifier. | |||
+ QualType getPointerAuthTy | |||
+ assert(!Ty.getPointerAuth()); | |||
+ assert(PointerAuth); | |||
+ | |||
+ Qualifiers Qs; | |||
+ Qs.setPointerAuth(PointerAuth); | |||
+ return getQualifiedType | |||
+ } | |||
+ | |||
unsigned char getFixedPointSca | unsigned char getFixedPointSca | ||
unsigned char getFixedPointIBi | unsigned char getFixedPointIBi | ||
llvm::FixedPointSemant | llvm::FixedPointSemant |
@@ -844,6 +844,12 @@ public: | |||
} | } | ||
} | } | ||
+ void VisitUnresolvedL | |||
+ if (E->hasExplicitTempl | |||
+ for (auto Arg : E->template_argumen | |||
+ Visit(Arg.getArgument()); | |||
+ } | |||
+ | |||
void VisitRequiresExp | void VisitRequiresExp | ||
for (auto *D : E->getLocalParamete | for (auto *D : E->getLocalParamete | ||
Visit(D); | Visit(D); |
@@ -213,9 +213,9 @@ public: | |||
} | } | ||
Qualifiers readQualifiers() { | Qualifiers readQualifiers() { | ||
- static_assert(sizeof(Qualifiers().getAsOpaqueValue()) <= sizeof( | + static_assert(sizeof(Qualifiers().getAsOpaqueValue()) <= sizeof(uint64_t), | ||
"update this if the value size changes"); | "update this if the value size changes"); | ||
- | + uint64_t value = asImpl().readUInt64(); | ||
return Qualifiers::fromOpaqueValue(value); | return Qualifiers::fromOpaqueValue(value); | ||
} | } | ||
@@ -196,9 +196,9 @@ public: | |||
} | } | ||
void writeQualifiers(Qualifiers value) { | void writeQualifiers(Qualifiers value) { | ||
- static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof( | + static_assert(sizeof(value.getAsOpaqueValue()) <= sizeof(uint64_t), | ||
"update this if the value size changes"); | "update this if the value size changes"); | ||
- asImpl(). | + asImpl().writeUInt64(value.getAsOpaqueValue()); | ||
} | } | ||
void writeExceptionSp | void writeExceptionSp |
@@ -320,7 +320,7 @@ PLACEHOLDER_TYPE | |||
PLACEHOLDER_TYPE | PLACEHOLDER_TYPE | ||
// A placeholder type for OpenMP array sections. | // A placeholder type for OpenMP array sections. | ||
-PLACEHOLDER_TYPE( | +PLACEHOLDER_TYPE(ArraySection, ArraySectionTy) | ||
// A placeholder type for OpenMP array shaping operation. | // A placeholder type for OpenMP array shaping operation. | ||
PLACEHOLDER_TYPE | PLACEHOLDER_TYPE |
@@ -94,7 +94,7 @@ class DesignatedInitEx | |||
class ParenListExpr; | class ParenListExpr; | ||
class PseudoObjectExpr | class PseudoObjectExpr | ||
class AtomicExpr; | class AtomicExpr; | ||
-class | +class ArraySectionExpr; | ||
class OMPArrayShapingE | class OMPArrayShapingE | ||
class OMPIteratorExpr; | class OMPIteratorExpr; | ||
class ObjCArrayLiteral | class ObjCArrayLiteral | ||
@@ -189,7 +189,7 @@ ExprDependence computeDependenc | |||
ExprDependence computeDependenc | ExprDependence computeDependenc | ||
ExprDependence computeDependenc | ExprDependence computeDependenc | ||
-ExprDependence computeDependence( | +ExprDependence computeDependence(ArraySectionExpr *E); | ||
ExprDependence computeDependenc | ExprDependence computeDependenc | ||
ExprDependence computeDependenc | ExprDependence computeDependenc | ||
@@ -157,7 +157,7 @@ public: | |||
SourceLocation CommentLoc, | SourceLocation CommentLoc, | ||
PragmaMSCommentK | PragmaMSCommentK | ||
StringRef Arg); | StringRef Arg); | ||
- static PragmaCommentDecl *CreateDeserialized(ASTContext &C, | + static PragmaCommentDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
unsigned ArgSize); | unsigned ArgSize); | ||
PragmaMSCommentK | PragmaMSCommentK | ||
@@ -192,7 +192,7 @@ public: | |||
SourceLocation Loc, StringRef Name, | SourceLocation Loc, StringRef Name, | ||
StringRef Value); | StringRef Value); | ||
static PragmaDetectMism | static PragmaDetectMism | ||
- CreateDeserialized(ASTContext &C, | + CreateDeserialized(ASTContext &C, GlobalDeclID ID, unsigned NameValueSize); | ||
StringRef getName() const { return getTrailingObjec | StringRef getName() const { return getTrailingObjec | ||
StringRef getValue() const { return getTrailingObjec | StringRef getValue() const { return getTrailingObjec | ||
@@ -518,7 +518,7 @@ public: | |||
static LabelDecl *Create(ASTContext &C, DeclContext *DC, | static LabelDecl *Create(ASTContext &C, DeclContext *DC, | ||
SourceLocation IdentL, IdentifierInfo *II, | SourceLocation IdentL, IdentifierInfo *II, | ||
SourceLocation GnuLabelL); | SourceLocation GnuLabelL); | ||
- static LabelDecl *CreateDeserialized(ASTContext &C, | + static LabelDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
LabelStmt *getStmt() const { return TheStmt; } | LabelStmt *getStmt() const { return TheStmt; } | ||
void setStmt(LabelStmt *T) { TheStmt = T; } | void setStmt(LabelStmt *T) { TheStmt = T; } | ||
@@ -581,7 +581,7 @@ public: | |||
IdentifierInfo *Id, NamespaceDecl *PrevDecl, | IdentifierInfo *Id, NamespaceDecl *PrevDecl, | ||
bool Nested); | bool Nested); | ||
- static NamespaceDecl *CreateDeserialized(ASTContext &C, | + static NamespaceDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
using redecl_range = redeclarable_bas | using redecl_range = redeclarable_bas | ||
using redecl_iterator = redeclarable_bas | using redecl_iterator = redeclarable_bas | ||
@@ -1146,7 +1146,7 @@ public: | |||
const IdentifierInfo *Id, QualType T, | const IdentifierInfo *Id, QualType T, | ||
TypeSourceInfo *TInfo, StorageClass S); | TypeSourceInfo *TInfo, StorageClass S); | ||
- static VarDecl *CreateDeserialized(ASTContext &C, | + static VarDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
SourceRange getSourceRange() const override LLVM_READONLY; | SourceRange getSourceRange() const override LLVM_READONLY; | ||
@@ -1728,7 +1728,7 @@ public: | |||
static ImplicitParamDec | static ImplicitParamDec | ||
ImplicitParamKin | ImplicitParamKin | ||
- static ImplicitParamDecl *CreateDeserialized(ASTContext &C, | + static ImplicitParamDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
ImplicitParamDec | ImplicitParamDec | ||
const IdentifierInfo *Id, QualType Type, | const IdentifierInfo *Id, QualType Type, | ||
@@ -1782,7 +1782,7 @@ public: | |||
TypeSourceInfo *TInfo, StorageClass S, | TypeSourceInfo *TInfo, StorageClass S, | ||
Expr *DefArg); | Expr *DefArg); | ||
- static ParmVarDecl *CreateDeserialized(ASTContext &C, | + static ParmVarDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
SourceRange getSourceRange() const override LLVM_READONLY; | SourceRange getSourceRange() const override LLVM_READONLY; | ||
@@ -2178,7 +2178,7 @@ public: | |||
bool hasWrittenProtot | bool hasWrittenProtot | ||
Expr *TrailingRequires | Expr *TrailingRequires | ||
- static FunctionDecl *CreateDeserialized(ASTContext &C, | + static FunctionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
DeclarationNameI | DeclarationNameI | ||
return DeclarationNameI | return DeclarationNameI | ||
@@ -3136,7 +3136,7 @@ public: | |||
TypeSourceInfo *TInfo, Expr *BW, bool Mutable, | TypeSourceInfo *TInfo, Expr *BW, bool Mutable, | ||
InClassInitStyle | InClassInitStyle | ||
- static FieldDecl *CreateDeserialized(ASTContext &C, | + static FieldDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
/// Returns the index of this field within its record, | /// Returns the index of this field within its record, | ||
/// as appropriate for passing to ASTRecordLayout::getFieldOffset. | /// as appropriate for passing to ASTRecordLayout::getFieldOffset. | ||
@@ -3311,7 +3311,7 @@ public: | |||
SourceLocation L, IdentifierInfo *Id, | SourceLocation L, IdentifierInfo *Id, | ||
QualType T, Expr *E, | QualType T, Expr *E, | ||
const llvm::APSInt &V); | const llvm::APSInt &V); | ||
- static EnumConstantDecl *CreateDeserialized(ASTContext &C, | + static EnumConstantDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
const Expr *getInitExpr() const { return (const Expr*) Init; } | const Expr *getInitExpr() const { return (const Expr*) Init; } | ||
Expr *getInitExpr() { return (Expr*) Init; } | Expr *getInitExpr() { return (Expr*) Init; } | ||
@@ -3357,7 +3357,7 @@ public: | |||
QualType T, | QualType T, | ||
llvm::MutableArrayRef<NamedDecl *> CH); | llvm::MutableArrayRef<NamedDecl *> CH); | ||
- static IndirectFieldDecl *CreateDeserialized(ASTContext &C, | + static IndirectFieldDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
using chain_iterator = ArrayRef<NamedDecl *>::const_iterator; | using chain_iterator = ArrayRef<NamedDecl *>::const_iterator; | ||
@@ -3542,7 +3542,7 @@ public: | |||
static TypedefDecl *Create(ASTContext &C, DeclContext *DC, | static TypedefDecl *Create(ASTContext &C, DeclContext *DC, | ||
SourceLocation StartLoc, SourceLocation IdLoc, | SourceLocation StartLoc, SourceLocation IdLoc, | ||
const IdentifierInfo *Id, TypeSourceInfo *TInfo); | const IdentifierInfo *Id, TypeSourceInfo *TInfo); | ||
- static TypedefDecl *CreateDeserialized(ASTContext &C, | + static TypedefDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
SourceRange getSourceRange() const override LLVM_READONLY; | SourceRange getSourceRange() const override LLVM_READONLY; | ||
@@ -3567,7 +3567,7 @@ public: | |||
static TypeAliasDecl *Create(ASTContext &C, DeclContext *DC, | static TypeAliasDecl *Create(ASTContext &C, DeclContext *DC, | ||
SourceLocation StartLoc, SourceLocation IdLoc, | SourceLocation StartLoc, SourceLocation IdLoc, | ||
const IdentifierInfo *Id, TypeSourceInfo *TInfo); | const IdentifierInfo *Id, TypeSourceInfo *TInfo); | ||
- static TypeAliasDecl *CreateDeserialized(ASTContext &C, | + static TypeAliasDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
SourceRange getSourceRange() const override LLVM_READONLY; | SourceRange getSourceRange() const override LLVM_READONLY; | ||
@@ -3977,7 +3977,7 @@ public: | |||
IdentifierInfo *Id, EnumDecl *PrevDecl, | IdentifierInfo *Id, EnumDecl *PrevDecl, | ||
bool IsScoped, bool IsScopedUsingCla | bool IsScoped, bool IsScopedUsingCla | ||
bool IsFixed); | bool IsFixed); | ||
- static EnumDecl *CreateDeserialized(ASTContext &C, | + static EnumDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
/// Overrides to provide correct range when there's an enum-base specifier | /// Overrides to provide correct range when there's an enum-base specifier | ||
/// with forward declarations. | /// with forward declarations. | ||
@@ -4182,7 +4182,7 @@ public: | |||
static RecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC, | static RecordDecl *Create(const ASTContext &C, TagKind TK, DeclContext *DC, | ||
SourceLocation StartLoc, SourceLocation IdLoc, | SourceLocation StartLoc, SourceLocation IdLoc, | ||
IdentifierInfo *Id, RecordDecl* PrevDecl = nullptr); | IdentifierInfo *Id, RecordDecl* PrevDecl = nullptr); | ||
- static RecordDecl *CreateDeserialized(const ASTContext &C, | + static RecordDecl *CreateDeserialized(const ASTContext &C, GlobalDeclID ID); | ||
RecordDecl *getPreviousDecl() { | RecordDecl *getPreviousDecl() { | ||
return cast_or_null<RecordDecl>( | return cast_or_null<RecordDecl>( | ||
@@ -4433,7 +4433,7 @@ public: | |||
StringLiteral *Str, SourceLocation AsmLoc, | StringLiteral *Str, SourceLocation AsmLoc, | ||
SourceLocation RParenLoc); | SourceLocation RParenLoc); | ||
- static FileScopeAsmDecl *CreateDeserialized(ASTContext &C, | + static FileScopeAsmDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
SourceLocation getAsmLoc() const { return getLocation(); } | SourceLocation getAsmLoc() const { return getLocation(); } | ||
SourceLocation getRParenLoc() const { return RParenLoc; } | SourceLocation getRParenLoc() const { return RParenLoc; } | ||
@@ -4469,7 +4469,7 @@ class TopLevelStmtDecl | |||
public: | public: | ||
static TopLevelStmtDecl | static TopLevelStmtDecl | ||
- static TopLevelStmtDecl *CreateDeserialized(ASTContext &C, | + static TopLevelStmtDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
SourceRange getSourceRange() const override LLVM_READONLY; | SourceRange getSourceRange() const override LLVM_READONLY; | ||
Stmt *getStmt() { return Statement; } | Stmt *getStmt() { return Statement; } | ||
@@ -4563,7 +4563,7 @@ protected: | |||
public: | public: | ||
static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); | static BlockDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L); | ||
- static BlockDecl *CreateDeserialized(ASTContext &C, | + static BlockDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
SourceLocation getCaretLocation | SourceLocation getCaretLocation | ||
@@ -4717,7 +4717,7 @@ public: | |||
static CapturedDecl *Create(ASTContext &C, DeclContext *DC, | static CapturedDecl *Create(ASTContext &C, DeclContext *DC, | ||
unsigned NumParams); | unsigned NumParams); | ||
- static CapturedDecl *CreateDeserialized(ASTContext &C, | + static CapturedDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
unsigned NumParams); | unsigned NumParams); | ||
Stmt *getBody() const override; | Stmt *getBody() const override; | ||
@@ -4851,7 +4851,7 @@ public: | |||
SourceLocation EndLoc); | SourceLocation EndLoc); | ||
/// Create a new, deserialized module import declaration. | /// Create a new, deserialized module import declaration. | ||
- static ImportDecl *CreateDeserialized(ASTContext &C, | + static ImportDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
unsigned NumLocations); | unsigned NumLocations); | ||
/// Retrieve the module that was imported by the import declaration. | /// Retrieve the module that was imported by the import declaration. | ||
@@ -4892,7 +4892,7 @@ private: | |||
public: | public: | ||
static ExportDecl *Create(ASTContext &C, DeclContext *DC, | static ExportDecl *Create(ASTContext &C, DeclContext *DC, | ||
SourceLocation ExportLoc); | SourceLocation ExportLoc); | ||
- static ExportDecl *CreateDeserialized(ASTContext &C, | + static ExportDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
SourceLocation getExportLoc() const { return getLocation(); } | SourceLocation getExportLoc() const { return getLocation(); } | ||
SourceLocation getRBraceLoc() const { return RBraceLoc; } | SourceLocation getRBraceLoc() const { return RBraceLoc; } | ||
@@ -4931,7 +4931,7 @@ class EmptyDecl : public Decl { | |||
public: | public: | ||
static EmptyDecl *Create(ASTContext &C, DeclContext *DC, | static EmptyDecl *Create(ASTContext &C, DeclContext *DC, | ||
SourceLocation L); | SourceLocation L); | ||
- static EmptyDecl *CreateDeserialized(ASTContext &C, | + static EmptyDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
static bool classof(const Decl *D) { return classofKind(D->getKind()); } | static bool classof(const Decl *D) { return classofKind(D->getKind()); } | ||
static bool classofKind(Kind K) { return K == Empty; } | static bool classofKind(Kind K) { return K == Empty; } | ||
@@ -4957,7 +4957,7 @@ public: | |||
bool CBuffer, SourceLocation KwLoc, | bool CBuffer, SourceLocation KwLoc, | ||
IdentifierInfo *ID, SourceLocation IDLoc, | IdentifierInfo *ID, SourceLocation IDLoc, | ||
SourceLocation LBrace); | SourceLocation LBrace); | ||
- static HLSLBufferDecl *CreateDeserialized(ASTContext &C, | + static HLSLBufferDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
SourceRange getSourceRange() const override LLVM_READONLY { | SourceRange getSourceRange() const override LLVM_READONLY { | ||
return SourceRange(getLocStart(), RBraceLoc); | return SourceRange(getLocStart(), RBraceLoc); |
@@ -15,6 +15,7 @@ | |||
#include "clang/AST/ASTDumperUtils.h" | #include "clang/AST/ASTDumperUtils.h" | ||
#include "clang/AST/AttrIterator.h" | #include "clang/AST/AttrIterator.h" | ||
+#include "clang/AST/DeclID.h" | |||
#include "clang/AST/DeclarationName.h" | #include "clang/AST/DeclarationName.h" | ||
#include "clang/AST/SelectorLocation | #include "clang/AST/SelectorLocation | ||
#include "clang/Basic/IdentifierTable.h" | #include "clang/Basic/IdentifierTable.h" | ||
@@ -239,9 +240,6 @@ public: | |||
ModulePrivate | ModulePrivate | ||
}; | }; | ||
- /// An ID number that refers to a declaration in an AST file. | |||
- using DeclID = uint32_t; | |||
- | |||
protected: | protected: | ||
/// The next declaration within the same lexical | /// The next declaration within the same lexical | ||
/// DeclContext. These pointers form the linked list that is | /// DeclContext. These pointers form the linked list that is | ||
@@ -361,7 +359,7 @@ protected: | |||
/// \param Ctx The context in which we will allocate memory. | /// \param Ctx The context in which we will allocate memory. | ||
/// \param ID The global ID of the deserialized declaration. | /// \param ID The global ID of the deserialized declaration. | ||
/// \param Extra The amount of extra space to allocate after the object. | /// \param Extra The amount of extra space to allocate after the object. | ||
- void *operator new(std::size_t Size, const ASTContext &Ctx, | + void *operator new(std::size_t Size, const ASTContext &Ctx, GlobalDeclID ID, | ||
std::size_t Extra = 0); | std::size_t Extra = 0); | ||
/// Allocate memory for a non-deserialized declaration. | /// Allocate memory for a non-deserialized declaration. | ||
@@ -779,10 +777,10 @@ public: | |||
/// Retrieve the global declaration ID associated with this | /// Retrieve the global declaration ID associated with this | ||
/// declaration, which specifies where this Decl was loaded from. | /// declaration, which specifies where this Decl was loaded from. | ||
- | + GlobalDeclID getGlobalID() const { | ||
if (isFromASTFile()) | if (isFromASTFile()) | ||
- return *((const | + return (*((const GlobalDeclID *)this - 1)); | ||
- return | + return GlobalDeclID(); | ||
} | } | ||
/// Retrieve the global ID of the module that owns this particular | /// Retrieve the global ID of the module that owns this particular |
@@ -120,7 +120,7 @@ public: | |||
return new (C, DC) AccessSpecDecl(AS, DC, ASLoc, ColonLoc); | return new (C, DC) AccessSpecDecl(AS, DC, ASLoc, ColonLoc); | ||
} | } | ||
- static AccessSpecDecl *CreateDeserialized(ASTContext &C, | + static AccessSpecDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
// Implement isa/cast/dyncast/etc. | // Implement isa/cast/dyncast/etc. | ||
static bool classof(const Decl *D) { return classofKind(D->getKind()); } | static bool classof(const Decl *D) { return classofKind(D->getKind()); } | ||
@@ -579,7 +579,8 @@ public: | |||
TypeSourceInfo *Info, SourceLocation Loc, | TypeSourceInfo *Info, SourceLocation Loc, | ||
unsigned DependencyKind, bool IsGeneric, | unsigned DependencyKind, bool IsGeneric, | ||
LambdaCaptureDef | LambdaCaptureDef | ||
- static CXXRecordDecl *CreateDeserialized(const ASTContext &C, | + static CXXRecordDecl *CreateDeserialized(const ASTContext &C, | ||
+ GlobalDeclID ID); | |||
bool isDynamicClass() const { | bool isDynamicClass() const { | ||
return data().Polymorphic || data().NumVBases != 0; | return data().Polymorphic || data().NumVBases != 0; | ||
@@ -1980,7 +1981,8 @@ public: | |||
CXXConstructorDe | CXXConstructorDe | ||
DeductionCandida | DeductionCandida | ||
- static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, | + static CXXDeductionGuideDecl *CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID); | |||
ExplicitSpecifie | ExplicitSpecifie | ||
const ExplicitSpecifie | const ExplicitSpecifie | ||
@@ -2035,7 +2037,8 @@ public: | |||
static RequiresExprBody | static RequiresExprBody | ||
SourceLocation StartLoc); | SourceLocation StartLoc); | ||
- static RequiresExprBodyDecl *CreateDeserialized(ASTContext &C, | + static RequiresExprBodyDecl *CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID); | |||
// Implement isa/cast/dyncast/etc. | // Implement isa/cast/dyncast/etc. | ||
static bool classof(const Decl *D) { return classofKind(D->getKind()); } | static bool classof(const Decl *D) { return classofKind(D->getKind()); } | ||
@@ -2078,7 +2081,7 @@ public: | |||
ConstexprSpecKin | ConstexprSpecKin | ||
Expr *TrailingRequires | Expr *TrailingRequires | ||
- static CXXMethodDecl *CreateDeserialized(ASTContext &C, | + static CXXMethodDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
bool isStatic() const; | bool isStatic() const; | ||
bool isInstance() const { return !isStatic(); } | bool isInstance() const { return !isStatic(); } | ||
@@ -2579,7 +2582,7 @@ public: | |||
friend class ASTDeclWriter; | friend class ASTDeclWriter; | ||
friend TrailingObjects; | friend TrailingObjects; | ||
- static CXXConstructorDecl *CreateDeserialized(ASTContext &C, | + static CXXConstructorDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
uint64_t AllocKind); | uint64_t AllocKind); | ||
static CXXConstructorDe | static CXXConstructorDe | ||
Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, | Create(ASTContext &C, CXXRecordDecl *RD, SourceLocation StartLoc, | ||
@@ -2822,7 +2825,7 @@ public: | |||
bool UsesFPIntrin, bool isInline, bool isImplicitlyDecl | bool UsesFPIntrin, bool isInline, bool isImplicitlyDecl | ||
ConstexprSpecKin | ConstexprSpecKin | ||
Expr *TrailingRequires | Expr *TrailingRequires | ||
- static CXXDestructorDecl *CreateDeserialized(ASTContext | + static CXXDestructorDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
void setOperatorDelet | void setOperatorDelet | ||
@@ -2881,7 +2884,7 @@ public: | |||
bool UsesFPIntrin, bool isInline, ExplicitSpecifie | bool UsesFPIntrin, bool isInline, ExplicitSpecifie | ||
ConstexprSpecKin | ConstexprSpecKin | ||
Expr *TrailingRequires | Expr *TrailingRequires | ||
- static CXXConversionDecl *CreateDeserialized(ASTContext &C, | + static CXXConversionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
ExplicitSpecifie | ExplicitSpecifie | ||
return getCanonicalDecl | return getCanonicalDecl | ||
@@ -2948,7 +2951,7 @@ public: | |||
SourceLocation ExternLoc, | SourceLocation ExternLoc, | ||
SourceLocation LangLoc, | SourceLocation LangLoc, | ||
LinkageSpecLangu | LinkageSpecLangu | ||
- static LinkageSpecDecl *CreateDeserialized(ASTContext &C, | + static LinkageSpecDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
/// Return the language specified by this linkage specification. | /// Return the language specified by this linkage specification. | ||
LinkageSpecLangu | LinkageSpecLangu | ||
@@ -3096,7 +3099,7 @@ public: | |||
SourceLocation IdentLoc, | SourceLocation IdentLoc, | ||
NamedDecl *Nominated, | NamedDecl *Nominated, | ||
DeclContext *CommonAncestor); | DeclContext *CommonAncestor); | ||
- static UsingDirectiveDecl *CreateDeserialized(ASTContext &C, | + static UsingDirectiveDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
SourceRange getSourceRange() const override LLVM_READONLY { | SourceRange getSourceRange() const override LLVM_READONLY { | ||
return SourceRange(UsingLoc, getLocation()); | return SourceRange(UsingLoc, getLocation()); | ||
@@ -3157,7 +3160,7 @@ public: | |||
SourceLocation IdentLoc, | SourceLocation IdentLoc, | ||
NamedDecl *Namespace); | NamedDecl *Namespace); | ||
- static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, | + static NamespaceAliasDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
using redecl_range = redeclarable_bas | using redecl_range = redeclarable_bas | ||
using redecl_iterator = redeclarable_bas | using redecl_iterator = redeclarable_bas | ||
@@ -3254,7 +3257,7 @@ public: | |||
LifetimeExtended | LifetimeExtended | ||
} | } | ||
static LifetimeExtended | static LifetimeExtended | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) LifetimeExtended | return new (C, ID) LifetimeExtended | ||
} | } | ||
@@ -3357,7 +3360,7 @@ public: | |||
UsingShadowDecl(UsingShadow, C, DC, Loc, Name, Introducer, Target); | UsingShadowDecl(UsingShadow, C, DC, Loc, Name, Introducer, Target); | ||
} | } | ||
- static UsingShadowDecl *CreateDeserialized(ASTContext &C, | + static UsingShadowDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
using redecl_range = redeclarable_bas | using redecl_range = redeclarable_bas | ||
using redecl_iterator = redeclarable_bas | using redecl_iterator = redeclarable_bas | ||
@@ -3566,7 +3569,7 @@ public: | |||
const DeclarationNameI | const DeclarationNameI | ||
bool HasTypenameKeywo | bool HasTypenameKeywo | ||
- static UsingDecl *CreateDeserialized(ASTContext &C, | + static UsingDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
SourceRange getSourceRange() const override LLVM_READONLY; | SourceRange getSourceRange() const override LLVM_READONLY; | ||
@@ -3645,7 +3648,7 @@ public: | |||
UsingDecl *Using, NamedDecl *Target, | UsingDecl *Using, NamedDecl *Target, | ||
bool IsVirtual); | bool IsVirtual); | ||
static ConstructorUsing | static ConstructorUsing | ||
- | + GlobalDeclID ID); | ||
/// Override the UsingShadowDecl's getIntroducer, returning the UsingDecl that | /// Override the UsingShadowDecl's getIntroducer, returning the UsingDecl that | ||
/// introduced this. | /// introduced this. | ||
@@ -3757,7 +3760,7 @@ public: | |||
SourceLocation UsingL, SourceLocation EnumL, | SourceLocation UsingL, SourceLocation EnumL, | ||
SourceLocation NameL, TypeSourceInfo *EnumType); | SourceLocation NameL, TypeSourceInfo *EnumType); | ||
- static UsingEnumDecl *CreateDeserialized(ASTContext &C, | + static UsingEnumDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
SourceRange getSourceRange() const override LLVM_READONLY; | SourceRange getSourceRange() const override LLVM_READONLY; | ||
@@ -3830,7 +3833,7 @@ public: | |||
NamedDecl *InstantiatedFrom | NamedDecl *InstantiatedFrom | ||
ArrayRef<NamedDecl *> UsingDecls); | ArrayRef<NamedDecl *> UsingDecls); | ||
- static UsingPackDecl *CreateDeserialized(ASTContext &C, | + static UsingPackDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
unsigned NumExpansions); | unsigned NumExpansions); | ||
SourceRange getSourceRange() const override LLVM_READONLY { | SourceRange getSourceRange() const override LLVM_READONLY { | ||
@@ -3923,8 +3926,8 @@ public: | |||
NestedNameSpecif | NestedNameSpecif | ||
const DeclarationNameI | const DeclarationNameI | ||
- static UnresolvedUsingValueDecl * | + static UnresolvedUsingValueDecl *CreateDeserialized(ASTContext &C, | ||
- CreateDeserializ | + GlobalDeclID ID); | ||
SourceRange getSourceRange() const override LLVM_READONLY; | SourceRange getSourceRange() const override LLVM_READONLY; | ||
@@ -4014,8 +4017,8 @@ public: | |||
SourceLocation TargetNameLoc, DeclarationName TargetName, | SourceLocation TargetNameLoc, DeclarationName TargetName, | ||
SourceLocation EllipsisLoc); | SourceLocation EllipsisLoc); | ||
- static UnresolvedUsingTypenameDecl * | + static UnresolvedUsingTypenameDecl *CreateDeserialized(ASTContext &C, | ||
- CreateDeserializ | + GlobalDeclID ID); | ||
/// Retrieves the canonical declaration of this declaration. | /// Retrieves the canonical declaration of this declaration. | ||
UnresolvedUsingT | UnresolvedUsingT | ||
@@ -4045,7 +4048,7 @@ public: | |||
SourceLocation Loc, | SourceLocation Loc, | ||
DeclarationName Name); | DeclarationName Name); | ||
static UnresolvedUsingI | static UnresolvedUsingI | ||
- | + GlobalDeclID ID); | ||
static bool classof(const Decl *D) { return classofKind(D->getKind()); } | static bool classof(const Decl *D) { return classofKind(D->getKind()); } | ||
static bool classofKind(Kind K) { return K == Decl::UnresolvedUsingI | static bool classofKind(Kind K) { return K == Decl::UnresolvedUsingI | ||
@@ -4073,7 +4076,7 @@ public: | |||
SourceLocation StaticAssertLoc, | SourceLocation StaticAssertLoc, | ||
Expr *AssertExpr, Expr *Message, | Expr *AssertExpr, Expr *Message, | ||
SourceLocation RParenLoc, bool Failed); | SourceLocation RParenLoc, bool Failed); | ||
- static StaticAssertDecl *CreateDeserialized(ASTContext &C, | + static StaticAssertDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
Expr *getAssertExpr() { return AssertExprAndFai | Expr *getAssertExpr() { return AssertExprAndFai | ||
const Expr *getAssertExpr() const { return AssertExprAndFai | const Expr *getAssertExpr() const { return AssertExprAndFai | ||
@@ -4120,7 +4123,7 @@ public: | |||
static BindingDecl *Create(ASTContext &C, DeclContext *DC, | static BindingDecl *Create(ASTContext &C, DeclContext *DC, | ||
SourceLocation IdLoc, IdentifierInfo *Id); | SourceLocation IdLoc, IdentifierInfo *Id); | ||
- static BindingDecl *CreateDeserialized(ASTContext &C, | + static BindingDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
/// Get the expression to which this declaration is bound. This may be null | /// Get the expression to which this declaration is bound. This may be null | ||
/// in two different cases: while parsing the initializer for the | /// in two different cases: while parsing the initializer for the | ||
@@ -4189,7 +4192,7 @@ public: | |||
QualType T, TypeSourceInfo *TInfo, | QualType T, TypeSourceInfo *TInfo, | ||
StorageClass S, | StorageClass S, | ||
ArrayRef<BindingDecl *> Bindings); | ArrayRef<BindingDecl *> Bindings); | ||
- static DecompositionDecl *CreateDeserialized(ASTContext &C, | + static DecompositionDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
unsigned NumBindings); | unsigned NumBindings); | ||
ArrayRef<BindingDecl *> bindings() const { | ArrayRef<BindingDecl *> bindings() const { | ||
@@ -4246,7 +4249,7 @@ public: | |||
SourceLocation L, DeclarationName N, QualType T, | SourceLocation L, DeclarationName N, QualType T, | ||
TypeSourceInfo *TInfo, SourceLocation StartL, | TypeSourceInfo *TInfo, SourceLocation StartL, | ||
IdentifierInfo *Getter, IdentifierInfo *Setter); | IdentifierInfo *Getter, IdentifierInfo *Setter); | ||
- static MSPropertyDecl *CreateDeserialized(ASTContext &C, | + static MSPropertyDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
static bool classof(const Decl *D) { return D->getKind() == MSProperty; } | static bool classof(const Decl *D) { return D->getKind() == MSProperty; } | ||
@@ -4300,7 +4303,7 @@ private: | |||
MSGuidDecl(DeclContext *DC, QualType T, Parts P); | MSGuidDecl(DeclContext *DC, QualType T, Parts P); | ||
static MSGuidDecl *Create(const ASTContext &C, QualType T, Parts P); | static MSGuidDecl *Create(const ASTContext &C, QualType T, Parts P); | ||
- static MSGuidDecl *CreateDeserialized(ASTContext &C, | + static MSGuidDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
// Only ASTContext::getMSGuidDecl and deserialization create these. | // Only ASTContext::getMSGuidDecl and deserialization create these. | ||
friend class ASTContext; | friend class ASTContext; | ||
@@ -4353,7 +4356,7 @@ class UnnamedGlobalCon | |||
static UnnamedGlobalCon | static UnnamedGlobalCon | ||
const APValue &APVal); | const APValue &APVal); | ||
static UnnamedGlobalCon | static UnnamedGlobalCon | ||
- | + GlobalDeclID ID); | ||
// Only ASTContext::getUnnamedGlobal | // Only ASTContext::getUnnamedGlobal | ||
// these. | // these. |
@@ -42,11 +42,12 @@ class StoredDeclsList { | |||
/// external declarations. | /// external declarations. | ||
DeclsAndHasExter | DeclsAndHasExter | ||
- template<typename Fn> | + template <typename Fn> DeclListNode::Decls *erase_if(Fn ShouldErase) { | ||
- void erase_if(Fn ShouldErase) { | |||
Decls List = Data.getPointer(); | Decls List = Data.getPointer(); | ||
+ | |||
if (!List) | if (!List) | ||
- | + return nullptr; | ||
+ | |||
ASTContext &C = getASTContext(); | ASTContext &C = getASTContext(); | ||
DeclListNode::Decls NewHead = nullptr; | DeclListNode::Decls NewHead = nullptr; | ||
DeclListNode::Decls *NewLast = nullptr; | DeclListNode::Decls *NewLast = nullptr; | ||
@@ -79,6 +80,17 @@ class StoredDeclsList { | |||
Data.setPointer(NewHead); | Data.setPointer(NewHead); | ||
assert(llvm::none_of(getLookupResult(), ShouldErase) && "Still exists!"); | assert(llvm::none_of(getLookupResult(), ShouldErase) && "Still exists!"); | ||
+ | |||
+ if (!Data.getPointer()) | |||
+ // All declarations are erased. | |||
+ return nullptr; | |||
+ else if (NewHead.is<NamedDecl *>()) | |||
+ // The list only contains a declaration, the header itself. | |||
+ return (DeclListNode::Decls *)&Data; | |||
+ else { | |||
+ assert(NewLast && NewLast->is<NamedDecl *>() && "Not the tail?"); | |||
+ return NewLast; | |||
+ } | |||
} | } | ||
void erase(NamedDecl *ND) { | void erase(NamedDecl *ND) { | ||
@@ -160,12 +172,16 @@ public: | |||
void replaceExternalD | void replaceExternalD | ||
// Remove all declarations that are either external or are replaced with | // Remove all declarations that are either external or are replaced with | ||
- // external declarations. | + // external declarations with higher visibilities. | ||
- erase_if([Decls](NamedDecl *ND) { | + DeclListNode::Decls *Tail = erase_if([Decls](NamedDecl *ND) { | ||
if (ND->isFromASTFile()) | if (ND->isFromASTFile()) | ||
return true; | return true; | ||
+ // FIXME: Can we get rid of this loop completely? | |||
for (NamedDecl *D : Decls) | for (NamedDecl *D : Decls) | ||
- if (D->declarationRepla | + // Only replace the local declaration if the external declaration has | ||
+ // higher visibilities. | |||
+ if (D->getModuleOwnersh | |||
+ D->declarationRepla | |||
return true; | return true; | ||
return false; | return false; | ||
}); | }); | ||
@@ -185,24 +201,15 @@ public: | |||
DeclsAsList = Node; | DeclsAsList = Node; | ||
} | } | ||
- DeclListNode::Decls Head = Data.getPointer(); | + if (!Data.getPointer()) { | ||
- if (Head.isNull()) { | |||
Data.setPointer(DeclsAsList); | Data.setPointer(DeclsAsList); | ||
return; | return; | ||
} | } | ||
- // Find the end of the existing list. | |||
- // FIXME: It would be possible to preserve information from erase_if to | |||
- // avoid this rescan looking for the end of the list. | |||
- DeclListNode::Decls *Tail = &Head; | |||
- while (DeclListNode *Node = Tail->dyn_cast<DeclListNode *>()) | |||
- Tail = &Node->Rest; | |||
- | |||
// Append the Decls. | // Append the Decls. | ||
DeclListNode *Node = C.AllocateDeclList | DeclListNode *Node = C.AllocateDeclList | ||
Node->Rest = DeclsAsList; | Node->Rest = DeclsAsList; | ||
*Tail = Node; | *Tail = Node; | ||
- Data.setPointer(Head); | |||
} | } | ||
/// Return the list of all the decls. | /// Return the list of all the decls. |
@@ -112,7 +112,7 @@ public: | |||
Create(ASTContext &C, DeclContext *DC, SourceLocation L, FriendUnion Friend_, | Create(ASTContext &C, DeclContext *DC, SourceLocation L, FriendUnion Friend_, | ||
SourceLocation FriendL, | SourceLocation FriendL, | ||
ArrayRef<TemplateParamete | ArrayRef<TemplateParamete | ||
- static FriendDecl *CreateDeserialized(ASTContext &C, | + static FriendDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
unsigned FriendTypeNumTPL | unsigned FriendTypeNumTPL | ||
/// If this friend declaration names an (untemplated but possibly | /// If this friend declaration names an (untemplated but possibly |
@@ -0,0 +1,227 @@ | |||
+//===--- DeclID.h - ID number for deserialized declarations ----*- C++ -*-===// | |||
+// | |||
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
+// See https://llvm.org/LICENSE.txt for license information. | |||
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
+// | |||
+//===----------------------------------------------------------------------===// | |||
+// | |||
+// This file defines DeclID class family to describe the deserialized | |||
+// declarations. The DeclID is widely used in AST via LazyDeclPtr, or calls to | |||
+// `ExternalASTSourc | |||
+// require the use of `DeclID` to explicit. | |||
+// | |||
+//===----------------------------------------------------------------------===// | |||
+ | |||
+#ifndef LLVM_CLANG_AST_D | |||
+#define LLVM_CLANG_AST_D | |||
+ | |||
+#include "llvm/ADT/DenseMapInfo.h" | |||
+#include "llvm/ADT/iterator.h" | |||
+ | |||
+namespace clang { | |||
+ | |||
+/// Predefined declaration IDs. | |||
+/// | |||
+/// These declaration IDs correspond to predefined declarations in the AST | |||
+/// context, such as the NULL declaration ID. Such declarations are never | |||
+/// actually serialized, since they will be built by the AST context when | |||
+/// it is created. | |||
+enum PredefinedDeclID | |||
+ /// The NULL declaration. | |||
+ PREDEF_DECL_NULL | |||
+ | |||
+ /// The translation unit. | |||
+ PREDEF_DECL_TRAN | |||
+ | |||
+ /// The Objective-C 'id' type. | |||
+ PREDEF_DECL_OBJC | |||
+ | |||
+ /// The Objective-C 'SEL' type. | |||
+ PREDEF_DECL_OBJC | |||
+ | |||
+ /// The Objective-C 'Class' type. | |||
+ PREDEF_DECL_OBJC | |||
+ | |||
+ /// The Objective-C 'Protocol' type. | |||
+ PREDEF_DECL_OBJC | |||
+ | |||
+ /// The signed 128-bit integer type. | |||
+ PREDEF_DECL_INT_ | |||
+ | |||
+ /// The unsigned 128-bit integer type. | |||
+ PREDEF_DECL_UNSI | |||
+ | |||
+ /// The internal 'instancetype' typedef. | |||
+ PREDEF_DECL_OBJC | |||
+ | |||
+ /// The internal '__builtin_va_lis | |||
+ PREDEF_DECL_BUIL | |||
+ | |||
+ /// The internal '__va_list_tag' struct, if any. | |||
+ PREDEF_DECL_VA_L | |||
+ | |||
+ /// The internal '__builtin_ms_va_ | |||
+ PREDEF_DECL_BUIL | |||
+ | |||
+ /// The predeclared '_GUID' struct. | |||
+ PREDEF_DECL_BUIL | |||
+ | |||
+ /// The extern "C" context. | |||
+ PREDEF_DECL_EXTE | |||
+ | |||
+ /// The internal '__make_integer_s | |||
+ PREDEF_DECL_MAKE | |||
+ | |||
+ /// The internal '__NSConstantStri | |||
+ PREDEF_DECL_CF_C | |||
+ | |||
+ /// The internal '__NSConstantStri | |||
+ PREDEF_DECL_CF_C | |||
+ | |||
+ /// The internal '__type_pack_elem | |||
+ PREDEF_DECL_TYPE | |||
+}; | |||
+ | |||
+/// The number of declaration IDs that are predefined. | |||
+/// | |||
+/// For more information about predefined declarations, see the | |||
+/// \c PredefinedDeclID | |||
+const unsigned int NUM_PREDEF_DECL_ | |||
+ | |||
+/// GlobalDeclID means DeclID in the current ASTContext and LocalDeclID means | |||
+/// DeclID specific to a certain ModuleFile. Specially, in ASTWriter, the | |||
+/// LocalDeclID to the ModuleFile been writting is equal to the GlobalDeclID. | |||
+/// Outside the serializer, all the DeclID been used should be GlobalDeclID. | |||
+/// We can translate a LocalDeclID to the GlobalDeclID by | |||
+/// `ASTReader::getGlobalDeclID()`. | |||
+ | |||
+class DeclIDBase { | |||
+public: | |||
+ /// An ID number that refers to a declaration in an AST file. | |||
+ /// | |||
+ /// The ID numbers of declarations are consecutive (in order of | |||
+ /// discovery), with values below NUM_PREDEF_DECL_ | |||
+ /// At the start of a chain of precompiled headers, declaration ID 1 is | |||
+ /// used for the translation unit declaration. | |||
+ /// | |||
+ /// DeclID should only be used directly in serialization. All other users | |||
+ /// should use LocalDeclID or GlobalDeclID. | |||
+ using DeclID = uint32_t; | |||
+ | |||
+protected: | |||
+ DeclIDBase() : ID(PREDEF_DECL_NULL | |||
+ explicit DeclIDBase(DeclID ID) : ID(ID) {} | |||
+ | |||
+public: | |||
+ DeclID get() const { return ID; } | |||
+ | |||
+ explicit operator DeclID() const { return ID; } | |||
+ | |||
+ explicit operator PredefinedDeclID | |||
+ | |||
+ bool isValid() const { return ID != PREDEF_DECL_NULL | |||
+ | |||
+ bool isInvalid() const { return ID == PREDEF_DECL_NULL | |||
+ | |||
+ friend bool operator==(const DeclIDBase &LHS, const DeclIDBase &RHS) { | |||
+ return LHS.ID == RHS.ID; | |||
+ } | |||
+ friend bool operator!=(const DeclIDBase &LHS, const DeclIDBase &RHS) { | |||
+ return LHS.ID != RHS.ID; | |||
+ } | |||
+ // We may sort the decl ID. | |||
+ friend bool operator<(const DeclIDBase &LHS, const DeclIDBase &RHS) { | |||
+ return LHS.ID < RHS.ID; | |||
+ } | |||
+ friend bool operator>(const DeclIDBase &LHS, const DeclIDBase &RHS) { | |||
+ return LHS.ID > RHS.ID; | |||
+ } | |||
+ friend bool operator<=(const DeclIDBase &LHS, const DeclIDBase &RHS) { | |||
+ return LHS.ID <= RHS.ID; | |||
+ } | |||
+ friend bool operator>=(const DeclIDBase &LHS, const DeclIDBase &RHS) { | |||
+ return LHS.ID >= RHS.ID; | |||
+ } | |||
+ | |||
+protected: | |||
+ DeclID ID; | |||
+}; | |||
+ | |||
+class LocalDeclID : public DeclIDBase { | |||
+ using Base = DeclIDBase; | |||
+ | |||
+public: | |||
+ LocalDeclID() : Base() {} | |||
+ LocalDeclID(PredefinedDeclID | |||
+ explicit LocalDeclID(DeclID ID) : Base(ID) {} | |||
+ | |||
+ LocalDeclID &operator++() { | |||
+ ++ID; | |||
+ return *this; | |||
+ } | |||
+ | |||
+ LocalDeclID operator++(int) { | |||
+ LocalDeclID Ret = *this; | |||
+ ++(*this); | |||
+ return Ret; | |||
+ } | |||
+}; | |||
+ | |||
+class GlobalDeclID : public DeclIDBase { | |||
+ using Base = DeclIDBase; | |||
+ | |||
+public: | |||
+ GlobalDeclID() : Base() {} | |||
+ explicit GlobalDeclID(DeclID ID) : Base(ID) {} | |||
+ | |||
+ // For DeclIDIterator<GlobalDeclID> to be able to convert a GlobalDeclID | |||
+ // to a LocalDeclID. | |||
+ explicit operator LocalDeclID() const { return LocalDeclID(this->ID); } | |||
+}; | |||
+ | |||
+/// A helper iterator adaptor to convert the iterators to | |||
+/// `SmallVector<SomeDeclID>` to the iterators to `SmallVector<OtherDeclID>`. | |||
+template <class FromTy, class ToTy> | |||
+class DeclIDIterator | |||
+ : public llvm::iterator_adaptor | |||
+ const FromTy *, | |||
+ std::forward_iterator | |||
+public: | |||
+ DeclIDIterator() : DeclIDIterator::iterator_adaptor | |||
+ | |||
+ DeclIDIterator(const FromTy *ID) | |||
+ : DeclIDIterator::iterator_adaptor | |||
+ | |||
+ ToTy operator*() const { return ToTy(*this->I); } | |||
+ | |||
+ bool operator==(const DeclIDIterator &RHS) const { return this->I == RHS.I; } | |||
+}; | |||
+ | |||
+} // namespace clang | |||
+ | |||
+namespace llvm { | |||
+template <> struct DenseMapInfo<clang::GlobalDeclID> { | |||
+ using GlobalDeclID = clang::GlobalDeclID; | |||
+ using DeclID = GlobalDeclID::DeclID; | |||
+ | |||
+ static GlobalDeclID getEmptyKey() { | |||
+ return GlobalDeclID(DenseMapInfo<DeclID>::getEmptyKey()); | |||
+ } | |||
+ | |||
+ static GlobalDeclID getTombstoneKey() { | |||
+ return GlobalDeclID(DenseMapInfo<DeclID>::getTombstoneKey()); | |||
+ } | |||
+ | |||
+ static unsigned getHashValue(const GlobalDeclID &Key) { | |||
+ return DenseMapInfo<DeclID>::getHashValue(Key.get()); | |||
+ } | |||
+ | |||
+ static bool isEqual(const GlobalDeclID &L, const GlobalDeclID &R) { | |||
+ return L == R; | |||
+ } | |||
+}; | |||
+ | |||
+} // namespace llvm | |||
+ | |||
+#endif |
@@ -236,7 +236,7 @@ public: | |||
ObjCImplementati | ObjCImplementati | ||
bool HasRelatedResult | bool HasRelatedResult | ||
- static ObjCMethodDecl *CreateDeserialized(ASTContext &C, | + static ObjCMethodDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
ObjCMethodDecl *getCanonicalDecl | ObjCMethodDecl *getCanonicalDecl | ||
const ObjCMethodDecl *getCanonicalDecl | const ObjCMethodDecl *getCanonicalDecl | ||
@@ -614,7 +614,8 @@ public: | |||
IdentifierInfo *name, | IdentifierInfo *name, | ||
SourceLocation colonLoc, | SourceLocation colonLoc, | ||
TypeSourceInfo *boundInfo); | TypeSourceInfo *boundInfo); | ||
- static ObjCTypeParamDecl *CreateDeserialized(ASTContext &ctx, | + static ObjCTypeParamDecl *CreateDeserialized(ASTContext &ctx, | ||
+ GlobalDeclID ID); | |||
SourceRange getSourceRange() const override LLVM_READONLY; | SourceRange getSourceRange() const override LLVM_READONLY; | ||
@@ -789,7 +790,7 @@ public: | |||
TypeSourceInfo *TSI, | TypeSourceInfo *TSI, | ||
PropertyControl propControl = None); | PropertyControl propControl = None); | ||
- static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, | + static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
SourceLocation getAtLoc() const { return AtLoc; } | SourceLocation getAtLoc() const { return AtLoc; } | ||
void setAtLoc(SourceLocation L) { AtLoc = L; } | void setAtLoc(SourceLocation L) { AtLoc = L; } | ||
@@ -1279,7 +1280,8 @@ public: | |||
ObjCInterfaceDec | ObjCInterfaceDec | ||
SourceLocation ClassLoc = SourceLocation(), bool isInternal = false); | SourceLocation ClassLoc = SourceLocation(), bool isInternal = false); | ||
- static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C, | + static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C, | ||
+ GlobalDeclID ID); | |||
/// Retrieve the type parameters of this class. | /// Retrieve the type parameters of this class. | ||
/// | /// | ||
@@ -1969,7 +1971,7 @@ public: | |||
TypeSourceInfo *TInfo, AccessControl ac, | TypeSourceInfo *TInfo, AccessControl ac, | ||
Expr *BW = nullptr, bool synthesized = false); | Expr *BW = nullptr, bool synthesized = false); | ||
- static ObjCIvarDecl *CreateDeserialized(ASTContext &C, | + static ObjCIvarDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
/// Return the class interface that this ivar is logically contained | /// Return the class interface that this ivar is logically contained | ||
/// in; this is either the interface where the ivar was declared, or the | /// in; this is either the interface where the ivar was declared, or the | ||
@@ -2039,7 +2041,8 @@ public: | |||
SourceLocation IdLoc, IdentifierInfo *Id, | SourceLocation IdLoc, IdentifierInfo *Id, | ||
QualType T, Expr *BW); | QualType T, Expr *BW); | ||
- static ObjCAtDefsFieldDecl *CreateDeserialized(ASTContext &C, | + static ObjCAtDefsFieldDecl *CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID); | |||
// Implement isa/cast/dyncast/etc. | // Implement isa/cast/dyncast/etc. | ||
static bool classof(const Decl *D) { return classofKind(D->getKind()); } | static bool classof(const Decl *D) { return classofKind(D->getKind()); } | ||
@@ -2142,7 +2145,7 @@ public: | |||
SourceLocation atStartLoc, | SourceLocation atStartLoc, | ||
ObjCProtocolDecl | ObjCProtocolDecl | ||
- static ObjCProtocolDecl *CreateDeserialized(ASTContext &C, | + static ObjCProtocolDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
const ObjCProtocolList | const ObjCProtocolList | ||
assert(hasDefinition() && "No definition available!"); | assert(hasDefinition() && "No definition available!"); | ||
@@ -2361,7 +2364,7 @@ public: | |||
ObjCTypeParamLis | ObjCTypeParamLis | ||
SourceLocation IvarLBraceLoc = SourceLocation(), | SourceLocation IvarLBraceLoc = SourceLocation(), | ||
SourceLocation IvarRBraceLoc = SourceLocation()); | SourceLocation IvarRBraceLoc = SourceLocation()); | ||
- static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, | + static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
ObjCInterfaceDec | ObjCInterfaceDec | ||
const ObjCInterfaceDec | const ObjCInterfaceDec | ||
@@ -2558,7 +2561,8 @@ public: | |||
Create(ASTContext &C, DeclContext *DC, const IdentifierInfo *Id, | Create(ASTContext &C, DeclContext *DC, const IdentifierInfo *Id, | ||
ObjCInterfaceDec | ObjCInterfaceDec | ||
SourceLocation atStartLoc, SourceLocation CategoryNameLoc); | SourceLocation atStartLoc, SourceLocation CategoryNameLoc); | ||
- static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, | + static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID); | |||
ObjCCategoryDecl | ObjCCategoryDecl | ||
@@ -2640,7 +2644,8 @@ public: | |||
SourceLocation IvarLBraceLoc=SourceLocation(), | SourceLocation IvarLBraceLoc=SourceLocation(), | ||
SourceLocation IvarRBraceLoc=SourceLocation()); | SourceLocation IvarRBraceLoc=SourceLocation()); | ||
- static ObjCImplementationDecl *CreateDeserialized(ASTContext &C, | + static ObjCImplementationDecl *CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID); | |||
/// init_iterator - Iterates through the ivar initializer list. | /// init_iterator - Iterates through the ivar initializer list. | ||
using init_iterator = CXXCtorInitializ | using init_iterator = CXXCtorInitializ | ||
@@ -2780,7 +2785,7 @@ public: | |||
ObjCInterfaceDec | ObjCInterfaceDec | ||
static ObjCCompatibleAl | static ObjCCompatibleAl | ||
- | + GlobalDeclID ID); | ||
const ObjCInterfaceDec | const ObjCInterfaceDec | ||
ObjCInterfaceDec | ObjCInterfaceDec | ||
@@ -2851,7 +2856,8 @@ public: | |||
ObjCIvarDecl *ivarDecl, | ObjCIvarDecl *ivarDecl, | ||
SourceLocation ivarLoc); | SourceLocation ivarLoc); | ||
- static ObjCPropertyImplDecl *CreateDeserialized(ASTContext &C, | + static ObjCPropertyImplDecl *CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID); | |||
SourceRange getSourceRange() const override LLVM_READONLY; | SourceRange getSourceRange() const override LLVM_READONLY; | ||
@@ -59,7 +59,7 @@ protected: | |||
} | } | ||
template <typename T, typename... Params> | template <typename T, typename... Params> | ||
- static T *createEmptyDirective(const ASTContext &C, | + static T *createEmptyDirective(const ASTContext &C, GlobalDeclID ID, | ||
unsigned NumClauses, unsigned NumChildren, | unsigned NumClauses, unsigned NumChildren, | ||
Params &&... P) { | Params &&... P) { | ||
auto *Inst = new (C, ID, size(NumClauses, NumChildren)) | auto *Inst = new (C, ID, size(NumClauses, NumChildren)) | ||
@@ -133,7 +133,7 @@ public: | |||
SourceLocation L, | SourceLocation L, | ||
ArrayRef<Expr *> VL); | ArrayRef<Expr *> VL); | ||
static OMPThreadPrivate | static OMPThreadPrivate | ||
- | + GlobalDeclID ID, unsigned N); | ||
typedef MutableArrayRef<Expr *>::iterator varlist_iterator | typedef MutableArrayRef<Expr *>::iterator varlist_iterator | ||
typedef ArrayRef<const Expr *>::iterator varlist_const_it | typedef ArrayRef<const Expr *>::iterator varlist_const_it | ||
@@ -214,7 +214,7 @@ public: | |||
QualType T, OMPDeclareReduct | QualType T, OMPDeclareReduct | ||
/// Create deserialized declare reduction node. | /// Create deserialized declare reduction node. | ||
static OMPDeclareReduct | static OMPDeclareReduct | ||
- | + GlobalDeclID ID); | ||
/// Get combiner expression of the declare reduction construct. | /// Get combiner expression of the declare reduction construct. | ||
Expr *getCombiner() { return Combiner; } | Expr *getCombiner() { return Combiner; } | ||
@@ -318,8 +318,8 @@ public: | |||
ArrayRef<OMPClause *> Clauses, | ArrayRef<OMPClause *> Clauses, | ||
OMPDeclareMapper | OMPDeclareMapper | ||
/// Creates deserialized declare mapper node. | /// Creates deserialized declare mapper node. | ||
- static OMPDeclareMapperDecl *CreateDeserialized(ASTContext &C, | + static OMPDeclareMapperDecl *CreateDeserialized(ASTContext &C, | ||
- unsigned N); | + GlobalDeclID ID, unsigned N); | ||
using clauselist_itera | using clauselist_itera | ||
using clauselist_const | using clauselist_const | ||
@@ -397,7 +397,8 @@ public: | |||
IdentifierInfo *Id, QualType T, | IdentifierInfo *Id, QualType T, | ||
SourceLocation StartLoc); | SourceLocation StartLoc); | ||
- static OMPCapturedExprDecl *CreateDeserialized(ASTContext &C, | + static OMPCapturedExprDecl *CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID); | |||
SourceRange getSourceRange() const override LLVM_READONLY; | SourceRange getSourceRange() const override LLVM_READONLY; | ||
@@ -427,7 +428,7 @@ public: | |||
static OMPRequiresDecl *Create(ASTContext &C, DeclContext *DC, | static OMPRequiresDecl *Create(ASTContext &C, DeclContext *DC, | ||
SourceLocation L, ArrayRef<OMPClause *> CL); | SourceLocation L, ArrayRef<OMPClause *> CL); | ||
/// Create deserialized requires node. | /// Create deserialized requires node. | ||
- static OMPRequiresDecl *CreateDeserialized(ASTContext &C, | + static OMPRequiresDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
unsigned N); | unsigned N); | ||
using clauselist_itera | using clauselist_itera | ||
@@ -495,7 +496,7 @@ public: | |||
static OMPAllocateDecl *Create(ASTContext &C, DeclContext *DC, | static OMPAllocateDecl *Create(ASTContext &C, DeclContext *DC, | ||
SourceLocation L, ArrayRef<Expr *> VL, | SourceLocation L, ArrayRef<Expr *> VL, | ||
ArrayRef<OMPClause *> CL); | ArrayRef<OMPClause *> CL); | ||
- static OMPAllocateDecl *CreateDeserialized(ASTContext &C, | + static OMPAllocateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
unsigned NVars, unsigned NClauses); | unsigned NVars, unsigned NClauses); | ||
typedef MutableArrayRef<Expr *>::iterator varlist_iterator | typedef MutableArrayRef<Expr *>::iterator varlist_iterator |
@@ -797,7 +797,7 @@ protected: | |||
/// | /// | ||
/// The first value in the array is the number of specializations/partial | /// The first value in the array is the number of specializations/partial | ||
/// specializations that follow. | /// specializations that follow. | ||
- | + GlobalDeclID *LazySpecializations = nullptr; | ||
/// The set of "injected" template arguments used within this | /// The set of "injected" template arguments used within this | ||
/// template. | /// template. | ||
@@ -1087,7 +1087,8 @@ public: | |||
NamedDecl *Decl); | NamedDecl *Decl); | ||
/// Create an empty function template node. | /// Create an empty function template node. | ||
- static FunctionTemplateDecl *CreateDeserialized(ASTContext &C, | + static FunctionTemplateDecl *CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID); | |||
// Implement isa/cast/dyncast support | // Implement isa/cast/dyncast support | ||
static bool classof(const Decl *D) { return classofKind(D->getKind()); } | static bool classof(const Decl *D) { return classofKind(D->getKind()); } | ||
@@ -1204,9 +1205,9 @@ public: | |||
bool Typename, bool ParameterPack, bool HasTypeConstrain | bool Typename, bool ParameterPack, bool HasTypeConstrain | ||
std::optional<unsigned> NumExpanded = std::nullopt); | std::optional<unsigned> NumExpanded = std::nullopt); | ||
static TemplateTypeParm | static TemplateTypeParm | ||
- | + GlobalDeclID ID); | ||
static TemplateTypeParm | static TemplateTypeParm | ||
- | + GlobalDeclID ID, | ||
bool HasTypeConstrain | bool HasTypeConstrain | ||
/// Whether this template type parameter was declared with | /// Whether this template type parameter was declared with | ||
@@ -1413,11 +1414,10 @@ public: | |||
QualType T, TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes, | QualType T, TypeSourceInfo *TInfo, ArrayRef<QualType> ExpandedTypes, | ||
ArrayRef<TypeSourceInfo *> ExpandedTInfos); | ArrayRef<TypeSourceInfo *> ExpandedTInfos); | ||
+ static NonTypeTemplateP | |||
+ CreateDeserializ | |||
static NonTypeTemplateP | static NonTypeTemplateP | ||
- | + GlobalDeclID ID, | ||
- bool HasTypeConstrain | |||
- static NonTypeTemplateP | |||
- DeclID ID, | |||
unsigned NumExpandedTypes | unsigned NumExpandedTypes | ||
bool HasTypeConstrain | bool HasTypeConstrain | ||
@@ -1632,10 +1632,9 @@ public: | |||
ArrayRef<TemplateParamete | ArrayRef<TemplateParamete | ||
static TemplateTemplate | static TemplateTemplate | ||
- | + GlobalDeclID ID); | ||
- static TemplateTemplateParmDecl * | + static TemplateTemplateParmDecl * | ||
- DeclID ID, | + CreateDeserializ | ||
- unsigned NumExpansions); | |||
using TemplateParmPosi | using TemplateParmPosi | ||
using TemplateParmPosi | using TemplateParmPosi | ||
@@ -1857,8 +1856,8 @@ public: | |||
ClassTemplateDec | ClassTemplateDec | ||
ArrayRef<TemplateArgument | ArrayRef<TemplateArgument | ||
ClassTemplateSpe | ClassTemplateSpe | ||
- static ClassTemplateSpecializationDecl * | + static ClassTemplateSpecializationDecl *CreateDeserialized(ASTContext &C, | ||
- CreateDeserializ | + GlobalDeclID ID); | ||
void getNameForDiagno | void getNameForDiagno | ||
bool Qualified) const override; | bool Qualified) const override; | ||
@@ -2110,7 +2109,7 @@ public: | |||
ClassTemplatePar | ClassTemplatePar | ||
static ClassTemplatePar | static ClassTemplatePar | ||
- CreateDeserialized(ASTContext &C, | + CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
ClassTemplatePar | ClassTemplatePar | ||
return cast<ClassTemplatePar | return cast<ClassTemplatePar | ||
@@ -2306,7 +2305,7 @@ public: | |||
NamedDecl *Decl); | NamedDecl *Decl); | ||
/// Create an empty class template node. | /// Create an empty class template node. | ||
- static ClassTemplateDecl *CreateDeserialized(ASTContext &C, | + static ClassTemplateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
/// Return the specialization with the provided arguments if it exists, | /// Return the specialization with the provided arguments if it exists, | ||
/// otherwise return the insertion point. | /// otherwise return the insertion point. | ||
@@ -2472,7 +2471,7 @@ public: | |||
MutableArrayRef<TemplateParamete | MutableArrayRef<TemplateParamete | ||
SourceLocation FriendLoc); | SourceLocation FriendLoc); | ||
- static FriendTemplateDecl *CreateDeserialized(ASTContext &C, | + static FriendTemplateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
/// If this friend declaration names a templated type (or | /// If this friend declaration names a templated type (or | ||
/// a dependent member type of a templated type), return that | /// a dependent member type of a templated type), return that | ||
@@ -2573,7 +2572,8 @@ public: | |||
NamedDecl *Decl); | NamedDecl *Decl); | ||
/// Create an empty alias template node. | /// Create an empty alias template node. | ||
- static TypeAliasTemplateDecl *CreateDeserialized(ASTContext &C, | + static TypeAliasTemplateDecl *CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID); | |||
// Implement isa/cast/dyncast support | // Implement isa/cast/dyncast support | ||
static bool classof(const Decl *D) { return classofKind(D->getKind()); } | static bool classof(const Decl *D) { return classofKind(D->getKind()); } | ||
@@ -2670,7 +2670,7 @@ public: | |||
TypeSourceInfo *TInfo, StorageClass S, | TypeSourceInfo *TInfo, StorageClass S, | ||
ArrayRef<TemplateArgument | ArrayRef<TemplateArgument | ||
static VarTemplateSpeci | static VarTemplateSpeci | ||
- | + GlobalDeclID ID); | ||
void getNameForDiagno | void getNameForDiagno | ||
bool Qualified) const override; | bool Qualified) const override; | ||
@@ -2900,8 +2900,8 @@ public: | |||
TypeSourceInfo *TInfo, StorageClass S, ArrayRef<TemplateArgument | TypeSourceInfo *TInfo, StorageClass S, ArrayRef<TemplateArgument | ||
const TemplateArgument | const TemplateArgument | ||
- static VarTemplatePartialSpecializationDecl * | + static VarTemplatePartialSpecializationDecl * | ||
- DeclID ID); | + CreateDeserializ | ||
VarTemplateParti | VarTemplateParti | ||
return cast<VarTemplateParti | return cast<VarTemplateParti | ||
@@ -3078,7 +3078,7 @@ public: | |||
VarDecl *Decl); | VarDecl *Decl); | ||
/// Create an empty variable template node. | /// Create an empty variable template node. | ||
- static VarTemplateDecl *CreateDeserialized(ASTContext &C, | + static VarTemplateDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
/// Return the specialization with the provided arguments if it exists, | /// Return the specialization with the provided arguments if it exists, | ||
/// otherwise return the insertion point. | /// otherwise return the insertion point. | ||
@@ -3183,7 +3183,7 @@ public: | |||
SourceLocation L, DeclarationName Name, | SourceLocation L, DeclarationName Name, | ||
TemplateParamete | TemplateParamete | ||
Expr *ConstraintExpr); | Expr *ConstraintExpr); | ||
- static ConceptDecl *CreateDeserialized(ASTContext &C, | + static ConceptDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); | ||
Expr *getConstraintExp | Expr *getConstraintExp | ||
return ConstraintExpr; | return ConstraintExpr; | ||
@@ -3232,7 +3232,7 @@ public: | |||
Create(const ASTContext &C, DeclContext *DC, SourceLocation SL, | Create(const ASTContext &C, DeclContext *DC, SourceLocation SL, | ||
ArrayRef<TemplateArgument | ArrayRef<TemplateArgument | ||
static ImplicitConceptS | static ImplicitConceptS | ||
- CreateDeserialized(const ASTContext &C, | + CreateDeserialized(const ASTContext &C, GlobalDeclID ID, | ||
unsigned NumTemplateArgs); | unsigned NumTemplateArgs); | ||
ArrayRef<TemplateArgument | ArrayRef<TemplateArgument | ||
@@ -3275,7 +3275,7 @@ private: | |||
static TemplateParamObj | static TemplateParamObj | ||
const APValue &V); | const APValue &V); | ||
static TemplateParamObj | static TemplateParamObj | ||
- | + GlobalDeclID ID); | ||
/// Only ASTContext::getTemplateParam | /// Only ASTContext::getTemplateParam | ||
/// create these. | /// create these. |
@@ -6610,6 +6610,275 @@ public: | |||
}; | }; | ||
+/// This class represents BOTH the OpenMP Array Section and OpenACC 'subarray', | |||
+/// with a boolean differentiator. | |||
+/// OpenMP 5.0 [2.1.5, Array Sections]. | |||
+/// To specify an array section in an OpenMP construct, array subscript | |||
+/// expressions are extended with the following syntax: | |||
+/// \code | |||
+/// [ lower-bound : length : stride ] | |||
+/// [ lower-bound : length : ] | |||
+/// [ lower-bound : length ] | |||
+/// [ lower-bound : : stride ] | |||
+/// [ lower-bound : : ] | |||
+/// [ lower-bound : ] | |||
+/// [ : length : stride ] | |||
+/// [ : length : ] | |||
+/// [ : length ] | |||
+/// [ : : stride ] | |||
+/// [ : : ] | |||
+/// [ : ] | |||
+/// \endcode | |||
+/// The array section must be a subset of the original array. | |||
+/// Array sections are allowed on multidimensional | |||
+/// subscript expressions can be used to specify length-one dimensions of | |||
+/// multidimensional | |||
+/// Each of the lower-bound, length, and stride expressions if specified must be | |||
+/// an integral type expressions of the base language. When evaluated | |||
+/// they represent a set of integer values as follows: | |||
+/// \code | |||
+/// { lower-bound, lower-bound + stride, lower-bound + 2 * stride,... , | |||
+/// lower-bound + ((length - 1) * stride) } | |||
+/// \endcode | |||
+/// The lower-bound and length must evaluate to non-negative integers. | |||
+/// The stride must evaluate to a positive integer. | |||
+/// When the size of the array dimension is not known, the length must be | |||
+/// specified explicitly. | |||
+/// When the stride is absent it defaults to 1. | |||
+/// When the length is absent it defaults to ⌈(size − lower-bound)/stride⌉, | |||
+/// where size is the size of the array dimension. When the lower-bound is | |||
+/// absent it defaults to 0. | |||
+/// | |||
+/// | |||
+/// OpenACC 3.3 [2.7.1 Data Specification in Data Clauses] | |||
+/// In C and C++, a subarray is an array name followed by an extended array | |||
+/// range specification in brackets, with start and length, such as | |||
+/// | |||
+/// AA[2:n] | |||
+/// | |||
+/// If the lower bound is missing, zero is used. If the length is missing and | |||
+/// the array has known size, the size of the array is used; otherwise the | |||
+/// length is required. The subarray AA[2:n] means elements AA[2], AA[3], . . . | |||
+/// , AA[2+n-1]. In C and C++, a two dimensional array may be declared in at | |||
+/// least four ways: | |||
+/// | |||
+/// -Statically-sized array: float AA[100][200]; | |||
+/// -Pointer to statically sized rows: typedef float row[200]; row* BB; | |||
+/// -Statically-sized array of pointers: float* CC[200]; | |||
+/// -Pointer to pointers: float** DD; | |||
+/// | |||
+/// Each dimension may be statically sized, or a pointer to dynamically | |||
+/// allocated memory. Each of these may be included in a data clause using | |||
+/// subarray notation to specify a rectangular array: | |||
+/// | |||
+/// -AA[2:n][0:200] | |||
+/// -BB[2:n][0:m] | |||
+/// -CC[2:n][0:m] | |||
+/// -DD[2:n][0:m] | |||
+/// | |||
+/// Multidimensional | |||
+/// array with any combination of statically-sized or dynamically-allocated | |||
+/// dimensions. For statically sized dimensions, all dimensions except the first | |||
+/// must specify the whole extent to preserve the contiguous data restriction, | |||
+/// discussed below. For dynamically allocated dimensions, the implementation | |||
+/// will allocate pointers in device memory corresponding to the pointers in | |||
+/// local memory and will fill in those pointers as appropriate. | |||
+/// | |||
+/// In Fortran, a subarray is an array name followed by a comma-separated list | |||
+/// of range specifications in parentheses, with lower and upper bound | |||
+/// subscripts, such as | |||
+/// | |||
+/// arr(1:high,low:100) | |||
+/// | |||
+/// If either the lower or upper bounds are missing, the declared or allocated | |||
+/// bounds of the array, if known, are used. All dimensions except the last must | |||
+/// specify the whole extent, to preserve the contiguous data restriction, | |||
+/// discussed below. | |||
+/// | |||
+/// Restrictions | |||
+/// | |||
+/// -In Fortran, the upper bound for the last dimension of an assumed-size dummy | |||
+/// array must be specified. | |||
+/// | |||
+/// -In C and C++, the length for dynamically allocated dimensions of an array | |||
+/// must be explicitly specified. | |||
+/// | |||
+/// -In C and C++, modifying pointers in pointer arrays during the data | |||
+/// lifetime, either on the host or on the device, may result in undefined | |||
+/// behavior. | |||
+/// | |||
+/// -If a subarray appears in a data clause, the implementation may choose to | |||
+/// allocate memory for only that subarray on the accelerator. | |||
+/// | |||
+/// -In Fortran, array pointers may appear, but pointer association is not | |||
+/// preserved in device memory. | |||
+/// | |||
+/// -Any array or subarray in a data clause, including Fortran array pointers, | |||
+/// must be a contiguous section of memory, except for dynamic multidimensional | |||
+/// C arrays. | |||
+/// | |||
+/// -In C and C++, if a variable or array of composite type appears, all the | |||
+/// data members of the struct or class are allocated and copied, as | |||
+/// appropriate. If a composite member is a pointer type, the data addressed by | |||
+/// that pointer are not implicitly copied. | |||
+/// | |||
+/// -In Fortran, if a variable or array of composite type appears, all the | |||
+/// members of that derived type are allocated and copied, as appropriate. If | |||
+/// any member has the allocatable or pointer attribute, the data accessed | |||
+/// through that member are not copied. | |||
+/// | |||
+/// -If an expression is used in a subscript or subarray expression in a clause | |||
+/// on a data construct, the same value is used when copying data at the end of | |||
+/// the data region, even if the values of variables in the expression change | |||
+/// during the data region. | |||
+class ArraySectionExpr | |||
+ friend class ASTStmtReader; | |||
+ friend class ASTStmtWriter; | |||
+ | |||
+public: | |||
+ enum ArraySectionType | |||
+ | |||
+private: | |||
+ enum { | |||
+ BASE, | |||
+ LOWER_BOUND, | |||
+ LENGTH, | |||
+ STRIDE, | |||
+ END_EXPR, | |||
+ OPENACC_END_EXPR | |||
+ }; | |||
+ | |||
+ ArraySectionType | |||
+ Stmt *SubExprs[END_EXPR] = {nullptr}; | |||
+ SourceLocation ColonLocFirst; | |||
+ SourceLocation ColonLocSecond; | |||
+ SourceLocation RBracketLoc; | |||
+ | |||
+public: | |||
+ // Constructor for OMP array sections, which include a 'stride'. | |||
+ ArraySectionExpr | |||
+ QualType Type, ExprValueKind VK, ExprObjectKind OK, | |||
+ SourceLocation ColonLocFirst, SourceLocation ColonLocSecond, | |||
+ SourceLocation RBracketLoc) | |||
+ : Expr(ArraySectionExpr | |||
+ ColonLocFirst(ColonLocFirst), ColonLocSecond(ColonLocSecond), | |||
+ RBracketLoc(RBracketLoc) { | |||
+ setBase(Base); | |||
+ setLowerBound(LowerBound); | |||
+ setLength(Length); | |||
+ setStride(Stride); | |||
+ setDependence(computeDependenc | |||
+ } | |||
+ | |||
+ // Constructor for OpenACC sub-arrays, which do not permit a 'stride'. | |||
+ ArraySectionExpr | |||
+ ExprValueKind VK, ExprObjectKind OK, SourceLocation ColonLoc, | |||
+ SourceLocation RBracketLoc) | |||
+ : Expr(ArraySectionExpr | |||
+ ColonLocFirst(ColonLoc), RBracketLoc(RBracketLoc) { | |||
+ setBase(Base); | |||
+ setLowerBound(LowerBound); | |||
+ setLength(Length); | |||
+ setDependence(computeDependenc | |||
+ } | |||
+ | |||
+ /// Create an empty array section expression. | |||
+ explicit ArraySectionExpr | |||
+ : Expr(ArraySectionExpr | |||
+ | |||
+ /// Return original type of the base expression for array section. | |||
+ static QualType getBaseOriginalT | |||
+ | |||
+ static bool classof(const Stmt *T) { | |||
+ return T->getStmtClass() == ArraySectionExpr | |||
+ } | |||
+ | |||
+ bool isOMPArraySectio | |||
+ bool isOpenACCArraySe | |||
+ | |||
+ /// Get base of the array section. | |||
+ Expr *getBase() { return cast<Expr>(SubExprs[BASE]); } | |||
+ const Expr *getBase() const { return cast<Expr>(SubExprs[BASE]); } | |||
+ | |||
+ /// Get lower bound of array section. | |||
+ Expr *getLowerBound() { return cast_or_null<Expr>(SubExprs[LOWER_BOUND]); } | |||
+ const Expr *getLowerBound() const { | |||
+ return cast_or_null<Expr>(SubExprs[LOWER_BOUND]); | |||
+ } | |||
+ | |||
+ /// Get length of array section. | |||
+ Expr *getLength() { return cast_or_null<Expr>(SubExprs[LENGTH]); } | |||
+ const Expr *getLength() const { return cast_or_null<Expr>(SubExprs[LENGTH]); } | |||
+ | |||
+ /// Get stride of array section. | |||
+ Expr *getStride() { | |||
+ assert(ASType != OpenACCArraySect | |||
+ "Stride not valid in OpenACC subarrays"); | |||
+ return cast_or_null<Expr>(SubExprs[STRIDE]); | |||
+ } | |||
+ | |||
+ const Expr *getStride() const { | |||
+ assert(ASType != OpenACCArraySect | |||
+ "Stride not valid in OpenACC subarrays"); | |||
+ return cast_or_null<Expr>(SubExprs[STRIDE]); | |||
+ } | |||
+ | |||
+ SourceLocation getBeginLoc() const LLVM_READONLY { | |||
+ return getBase()->getBeginLoc(); | |||
+ } | |||
+ SourceLocation getEndLoc() const LLVM_READONLY { return RBracketLoc; } | |||
+ | |||
+ SourceLocation getColonLocFirst | |||
+ SourceLocation getColonLocSecon | |||
+ assert(ASType != OpenACCArraySect | |||
+ "second colon for stride not valid in OpenACC subarrays"); | |||
+ return ColonLocSecond; | |||
+ } | |||
+ SourceLocation getRBracketLoc() const { return RBracketLoc; } | |||
+ | |||
+ SourceLocation getExprLoc() const LLVM_READONLY { | |||
+ return getBase()->getExprLoc(); | |||
+ } | |||
+ | |||
+ child_range children() { | |||
+ return child_range( | |||
+ &SubExprs[BASE], | |||
+ &SubExprs[ASType == OMPArraySection ? END_EXPR : OPENACC_END_EXPR | |||
+ } | |||
+ | |||
+ const_child_rang | |||
+ return const_child_rang | |||
+ &SubExprs[BASE], | |||
+ &SubExprs[ASType == OMPArraySection ? END_EXPR : OPENACC_END_EXPR | |||
+ } | |||
+ | |||
+private: | |||
+ /// Set base of the array section. | |||
+ void setBase(Expr *E) { SubExprs[BASE] = E; } | |||
+ | |||
+ /// Set lower bound of the array section. | |||
+ void setLowerBound(Expr *E) { SubExprs[LOWER_BOUND] = E; } | |||
+ | |||
+ /// Set length of the array section. | |||
+ void setLength(Expr *E) { SubExprs[LENGTH] = E; } | |||
+ | |||
+ /// Set length of the array section. | |||
+ void setStride(Expr *E) { | |||
+ assert(ASType != OpenACCArraySect | |||
+ "Stride not valid in OpenACC subarrays"); | |||
+ SubExprs[STRIDE] = E; | |||
+ } | |||
+ | |||
+ void setColonLocFirst | |||
+ | |||
+ void setColonLocSecon | |||
+ assert(ASType != OpenACCArraySect | |||
+ "second colon for stride not valid in OpenACC subarrays"); | |||
+ ColonLocSecond = L; | |||
+ } | |||
+ void setRBracketLoc(SourceLocation L) { RBracketLoc = L; } | |||
+}; | |||
+ | |||
/// Frontend produces RecoveryExprs on semantic errors that prevent creating | /// Frontend produces RecoveryExprs on semantic errors that prevent creating | ||
/// other well-formed expressions. E.g. when type-checking of a binary operator | /// other well-formed expressions. E.g. when type-checking of a binary operator | ||
/// fails, we cannot produce a BinaryOperator expression. Instead, we can choose | /// fails, we cannot produce a BinaryOperator expression. Instead, we can choose |
@@ -1482,6 +1482,8 @@ public: | |||
/// const S &s_ref = S(); // Requires a CXXBindTemporary | /// const S &s_ref = S(); // Requires a CXXBindTemporary | ||
/// } | /// } | ||
/// \endcode | /// \endcode | ||
+/// | |||
+/// Destructor might be null if destructor declaration is not valid. | |||
class CXXBindTemporary | class CXXBindTemporary | ||
CXXTemporary *Temp = nullptr; | CXXTemporary *Temp = nullptr; | ||
Stmt *SubExpr = nullptr; | Stmt *SubExpr = nullptr; |
@@ -17,130 +17,6 @@ | |||
#include "clang/AST/Expr.h" | #include "clang/AST/Expr.h" | ||
namespace clang { | namespace clang { | ||
-/// OpenMP 5.0 [2.1.5, Array Sections]. | |||
-/// To specify an array section in an OpenMP construct, array subscript | |||
-/// expressions are extended with the following syntax: | |||
-/// \code | |||
-/// [ lower-bound : length : stride ] | |||
-/// [ lower-bound : length : ] | |||
-/// [ lower-bound : length ] | |||
-/// [ lower-bound : : stride ] | |||
-/// [ lower-bound : : ] | |||
-/// [ lower-bound : ] | |||
-/// [ : length : stride ] | |||
-/// [ : length : ] | |||
-/// [ : length ] | |||
-/// [ : : stride ] | |||
-/// [ : : ] | |||
-/// [ : ] | |||
-/// \endcode | |||
-/// The array section must be a subset of the original array. | |||
-/// Array sections are allowed on multidimensional | |||
-/// subscript expressions can be used to specify length-one dimensions of | |||
-/// multidimensional | |||
-/// Each of the lower-bound, length, and stride expressions if specified must be | |||
-/// an integral type expressions of the base language. When evaluated | |||
-/// they represent a set of integer values as follows: | |||
-/// \code | |||
-/// { lower-bound, lower-bound + stride, lower-bound + 2 * stride,... , | |||
-/// lower-bound + ((length - 1) * stride) } | |||
-/// \endcode | |||
-/// The lower-bound and length must evaluate to non-negative integers. | |||
-/// The stride must evaluate to a positive integer. | |||
-/// When the size of the array dimension is not known, the length must be | |||
-/// specified explicitly. | |||
-/// When the stride is absent it defaults to 1. | |||
-/// When the length is absent it defaults to ⌈(size − lower-bound)/stride⌉, | |||
-/// where size is the size of the array dimension. When the lower-bound is | |||
-/// absent it defaults to 0. | |||
-class OMPArraySectionE | |||
- enum { BASE, LOWER_BOUND, LENGTH, STRIDE, END_EXPR }; | |||
- Stmt *SubExprs[END_EXPR]; | |||
- SourceLocation ColonLocFirst; | |||
- SourceLocation ColonLocSecond; | |||
- SourceLocation RBracketLoc; | |||
- | |||
-public: | |||
- OMPArraySectionE | |||
- QualType Type, ExprValueKind VK, ExprObjectKind OK, | |||
- SourceLocation ColonLocFirst, | |||
- SourceLocation ColonLocSecond, SourceLocation RBracketLoc) | |||
- : Expr(OMPArraySectionE | |||
- ColonLocFirst(ColonLocFirst), ColonLocSecond(ColonLocSecond), | |||
- RBracketLoc(RBracketLoc) { | |||
- SubExprs[BASE] = Base; | |||
- SubExprs[LOWER_BOUND] = LowerBound; | |||
- SubExprs[LENGTH] = Length; | |||
- SubExprs[STRIDE] = Stride; | |||
- setDependence(computeDependenc | |||
- } | |||
- | |||
- /// Create an empty array section expression. | |||
- explicit OMPArraySectionE | |||
- : Expr(OMPArraySectionE | |||
- | |||
- /// An array section can be written only as Base[LowerBound:Length]. | |||
- | |||
- /// Get base of the array section. | |||
- Expr *getBase() { return cast<Expr>(SubExprs[BASE]); } | |||
- const Expr *getBase() const { return cast<Expr>(SubExprs[BASE]); } | |||
- /// Set base of the array section. | |||
- void setBase(Expr *E) { SubExprs[BASE] = E; } | |||
- | |||
- /// Return original type of the base expression for array section. | |||
- static QualType getBaseOriginalT | |||
- | |||
- /// Get lower bound of array section. | |||
- Expr *getLowerBound() { return cast_or_null<Expr>(SubExprs[LOWER_BOUND]); } | |||
- const Expr *getLowerBound() const { | |||
- return cast_or_null<Expr>(SubExprs[LOWER_BOUND]); | |||
- } | |||
- /// Set lower bound of the array section. | |||
- void setLowerBound(Expr *E) { SubExprs[LOWER_BOUND] = E; } | |||
- | |||
- /// Get length of array section. | |||
- Expr *getLength() { return cast_or_null<Expr>(SubExprs[LENGTH]); } | |||
- const Expr *getLength() const { return cast_or_null<Expr>(SubExprs[LENGTH]); } | |||
- /// Set length of the array section. | |||
- void setLength(Expr *E) { SubExprs[LENGTH] = E; } | |||
- | |||
- /// Get stride of array section. | |||
- Expr *getStride() { return cast_or_null<Expr>(SubExprs[STRIDE]); } | |||
- const Expr *getStride() const { return cast_or_null<Expr>(SubExprs[STRIDE]); } | |||
- /// Set length of the array section. | |||
- void setStride(Expr *E) { SubExprs[STRIDE] = E; } | |||
- | |||
- SourceLocation getBeginLoc() const LLVM_READONLY { | |||
- return getBase()->getBeginLoc(); | |||
- } | |||
- SourceLocation getEndLoc() const LLVM_READONLY { return RBracketLoc; } | |||
- | |||
- SourceLocation getColonLocFirst | |||
- void setColonLocFirst | |||
- | |||
- SourceLocation getColonLocSecon | |||
- void setColonLocSecon | |||
- | |||
- SourceLocation getRBracketLoc() const { return RBracketLoc; } | |||
- void setRBracketLoc(SourceLocation L) { RBracketLoc = L; } | |||
- | |||
- SourceLocation getExprLoc() const LLVM_READONLY { | |||
- return getBase()->getExprLoc(); | |||
- } | |||
- | |||
- static bool classof(const Stmt *T) { | |||
- return T->getStmtClass() == OMPArraySectionE | |||
- } | |||
- | |||
- child_range children() { | |||
- return child_range(&SubExprs[BASE], &SubExprs[END_EXPR]); | |||
- } | |||
- | |||
- const_child_rang | |||
- return const_child_rang | |||
- } | |||
-}; | |||
- | |||
/// An explicit cast in C or a C-style cast in C++, which uses the syntax | /// An explicit cast in C or a C-style cast in C++, which uses the syntax | ||
/// ([s1][s2]...[sn])expr. For example: @c ([3][3])f. | /// ([s1][s2]...[sn])expr. For example: @c ([3][3])f. | ||
class OMPArrayShapingE | class OMPArrayShapingE |
@@ -99,7 +99,7 @@ public: | |||
/// passes back decl sets as VisibleDeclarati | /// passes back decl sets as VisibleDeclarati | ||
/// | /// | ||
/// The default implementation of this method is a no-op. | /// The default implementation of this method is a no-op. | ||
- virtual Decl *GetExternalDecl( | + virtual Decl *GetExternalDecl(GlobalDeclID ID); | ||
/// Resolve a selector ID into a selector. | /// Resolve a selector ID into a selector. | ||
/// | /// | ||
@@ -375,7 +375,7 @@ public: | |||
if (isOffset()) { | if (isOffset()) { | ||
assert(Source && | assert(Source && | ||
"Cannot deserialize a lazy pointer without an AST source"); | "Cannot deserialize a lazy pointer without an AST source"); | ||
- Ptr = reinterpret_cast<uint64_t>((Source->*Get)(Ptr >> 1)); | + Ptr = reinterpret_cast<uint64_t>((Source->*Get)(OffsT(Ptr >> 1))); | ||
} | } | ||
return reinterpret_cast | return reinterpret_cast | ||
} | } | ||
@@ -579,7 +579,7 @@ using LazyDeclStmtPtr = | |||
/// A lazy pointer to a declaration. | /// A lazy pointer to a declaration. | ||
using LazyDeclPtr = | using LazyDeclPtr = | ||
- LazyOffsetPtr<Decl, | + LazyOffsetPtr<Decl, GlobalDeclID, &ExternalASTSource::GetExternalDecl>; | ||
/// A lazy pointer to a set of CXXCtorInitializ | /// A lazy pointer to a set of CXXCtorInitializ | ||
using LazyCXXCtorIniti | using LazyCXXCtorIniti |
@@ -266,7 +266,7 @@ public: | |||
explicit operator bool() const { return Qualifier; } | explicit operator bool() const { return Qualifier; } | ||
/// Evaluates true when this nested-name-specifier location is | /// Evaluates true when this nested-name-specifier location is | ||
- /// empty. | + /// non-empty. | ||
bool hasQualifier() const { return Qualifier; } | bool hasQualifier() const { return Qualifier; } | ||
/// Retrieve the nested-name-specifier to which this instance | /// Retrieve the nested-name-specifier to which this instance |
@@ -156,51 +156,50 @@ public: | |||
Expr *ConditionExpr, SourceLocation EndLoc); | Expr *ConditionExpr, SourceLocation EndLoc); | ||
}; | }; | ||
-/// Represents a clause that has one or more | +/// Represents a clause that has one or more expressions associated with it. | ||
-/// IntExprs, but provides 'children' and other accessors. | +class OpenACCClauseWit | ||
-class OpenACCClauseWit | + MutableArrayRef<Expr *> Exprs; | ||
- MutableArrayRef<Expr *> IntExprs; | |||
protected: | protected: | ||
- | + OpenACCClauseWithExprs(OpenACCClauseKind K, SourceLocation BeginLoc, | ||
- | + SourceLocation LParenLoc, SourceLocation EndLoc) | ||
: OpenACCClauseWit | : OpenACCClauseWit | ||
/// Used only for initialization, the leaf class can initialize this to | /// Used only for initialization, the leaf class can initialize this to | ||
/// trailing storage. | /// trailing storage. | ||
- void | + void setExprs(MutableArrayRef<Expr *> NewExprs) { | ||
- assert( | + assert(Exprs.empty() && "Cannot change Exprs list"); | ||
- | + Exprs = NewExprs; | ||
} | } | ||
- /// Gets the entire list of | + /// Gets the entire list of expressions, but leave it to the | ||
/// individual clauses to expose this how they'd like. | /// individual clauses to expose this how they'd like. | ||
- llvm::ArrayRef<Expr *> | + llvm::ArrayRef<Expr *> getExprs() const { return Exprs; } | ||
public: | public: | ||
child_range children() { | child_range children() { | ||
- return child_range(reinterpret_cast<Stmt **>( | + return child_range(reinterpret_cast<Stmt **>(Exprs.begin()), | ||
- reinterpret_cast<Stmt **>( | + reinterpret_cast<Stmt **>(Exprs.end())); | ||
} | } | ||
const_child_rang | const_child_rang | ||
child_range Children = | child_range Children = | ||
- | + const_cast<OpenACCClauseWithExprs *>(this)->children(); | ||
return const_child_rang | return const_child_rang | ||
} | } | ||
}; | }; | ||
class OpenACCNumGangsC | class OpenACCNumGangsC | ||
- : public | + : public OpenACCClauseWithExprs, | ||
public llvm::TrailingObjects<OpenACCNumGangsC | public llvm::TrailingObjects<OpenACCNumGangsC | ||
OpenACCNumGangsC | OpenACCNumGangsC | ||
ArrayRef<Expr *> IntExprs, SourceLocation EndLoc) | ArrayRef<Expr *> IntExprs, SourceLocation EndLoc) | ||
- : | + : OpenACCClauseWithExprs(OpenACCClauseKind::NumGangs, BeginLoc, LParenLoc, | ||
- | + EndLoc) { | ||
std::uninitialized_co | std::uninitialized_co | ||
getTrailingObjec | getTrailingObjec | ||
- | + setExprs(MutableArrayRef(getTrailingObjects<Expr *>(), IntExprs.size())); | ||
} | } | ||
public: | public: | ||
@@ -209,35 +208,35 @@ public: | |||
ArrayRef<Expr *> IntExprs, SourceLocation EndLoc); | ArrayRef<Expr *> IntExprs, SourceLocation EndLoc); | ||
llvm::ArrayRef<Expr *> getIntExprs() { | llvm::ArrayRef<Expr *> getIntExprs() { | ||
- return | + return OpenACCClauseWithExprs::getExprs(); | ||
} | } | ||
llvm::ArrayRef<Expr *> getIntExprs() const { | llvm::ArrayRef<Expr *> getIntExprs() const { | ||
- return | + return OpenACCClauseWithExprs::getExprs(); | ||
} | } | ||
}; | }; | ||
/// Represents one of a handful of clauses that have a single integer | /// Represents one of a handful of clauses that have a single integer | ||
/// expression. | /// expression. | ||
-class OpenACCClauseWithSingleIntExpr : public | +class OpenACCClauseWithSingleIntExpr : public OpenACCClauseWithExprs { | ||
Expr *IntExpr; | Expr *IntExpr; | ||
protected: | protected: | ||
OpenACCClauseWit | OpenACCClauseWit | ||
SourceLocation LParenLoc, Expr *IntExpr, | SourceLocation LParenLoc, Expr *IntExpr, | ||
SourceLocation EndLoc) | SourceLocation EndLoc) | ||
- : | + : OpenACCClauseWithExprs(K, BeginLoc, LParenLoc, EndLoc), | ||
IntExpr(IntExpr) { | IntExpr(IntExpr) { | ||
- | + setExprs(MutableArrayRef<Expr *>{&this->IntExpr, 1}); | ||
} | } | ||
public: | public: | ||
- bool hasIntExpr() const { return | + bool hasIntExpr() const { return !getExprs().empty(); } | ||
const Expr *getIntExpr() const { | const Expr *getIntExpr() const { | ||
- return hasIntExpr() ? | + return hasIntExpr() ? getExprs()[0] : nullptr; | ||
} | } | ||
- Expr *getIntExpr() { return hasIntExpr() ? | + Expr *getIntExpr() { return hasIntExpr() ? getExprs()[0] : nullptr; }; | ||
}; | }; | ||
class OpenACCNumWorker | class OpenACCNumWorker | ||
@@ -261,6 +260,40 @@ public: | |||
Expr *IntExpr, SourceLocation EndLoc); | Expr *IntExpr, SourceLocation EndLoc); | ||
}; | }; | ||
+/// Represents a clause with one or more 'var' objects, represented as an expr, | |||
+/// as its arguments. Var-list is expected to be stored in trailing storage. | |||
+/// For now, we're just storing the original expression in its entirety, unlike | |||
+/// OMP which has to do a bunch of work to create a private. | |||
+class OpenACCClauseWit | |||
+protected: | |||
+ OpenACCClauseWit | |||
+ SourceLocation LParenLoc, SourceLocation EndLoc) | |||
+ : OpenACCClauseWit | |||
+ | |||
+public: | |||
+ ArrayRef<Expr *> getVarList() { return getExprs(); } | |||
+ ArrayRef<Expr *> getVarList() const { return getExprs(); } | |||
+}; | |||
+ | |||
+class OpenACCPrivateCl | |||
+ : public OpenACCClauseWit | |||
+ public llvm::TrailingObjects<OpenACCPrivateCl | |||
+ | |||
+ OpenACCPrivateCl | |||
+ ArrayRef<Expr *> VarList, SourceLocation EndLoc) | |||
+ : OpenACCClauseWit | |||
+ LParenLoc, EndLoc) { | |||
+ std::uninitialized_co | |||
+ getTrailingObjec | |||
+ setExprs(MutableArrayRef(getTrailingObjec | |||
+ } | |||
+ | |||
+public: | |||
+ static OpenACCPrivateCl | |||
+ Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc, | |||
+ ArrayRef<Expr *> VarList, SourceLocation EndLoc); | |||
+}; | |||
+ | |||
template <class Impl> class OpenACCClauseVis | template <class Impl> class OpenACCClauseVis | ||
Impl &getDerived() { return static_cast<Impl &>(*this); } | Impl &getDerived() { return static_cast<Impl &>(*this); } | ||
@@ -299,6 +332,9 @@ public: | |||
class OpenACCClausePri | class OpenACCClausePri | ||
: public OpenACCClauseVis | : public OpenACCClauseVis | ||
raw_ostream &OS; | raw_ostream &OS; | ||
+ const PrintingPolicy &Policy; | |||
+ | |||
+ void printExpr(const Expr *E); | |||
public: | public: | ||
void VisitClauseList(ArrayRef<const OpenACCClause *> List) { | void VisitClauseList(ArrayRef<const OpenACCClause *> List) { | ||
@@ -309,7 +345,8 @@ public: | |||
OS << ' '; | OS << ' '; | ||
} | } | ||
} | } | ||
- OpenACCClausePrinter(raw_ostream &OS | + OpenACCClausePrinter(raw_ostream &OS, const PrintingPolicy &Policy) | ||
+ : OS(OS), Policy(Policy) {} | |||
#define VISIT_CLAUSE(CLAUSE_NAME) \ | #define VISIT_CLAUSE(CLAUSE_NAME) \ | ||
void Visit##CLAUSE_NAME##Clause(const OpenACC##CLAUSE_NAME##Clause &Clause); | void Visit##CLAUSE_NAME##Clause(const OpenACC##CLAUSE_NAME##Clause &Clause); |
@@ -2740,7 +2740,7 @@ DEF_TRAVERSE_STM | |||
DEF_TRAVERSE_STM | DEF_TRAVERSE_STM | ||
DEF_TRAVERSE_STM | DEF_TRAVERSE_STM | ||
DEF_TRAVERSE_STM | DEF_TRAVERSE_STM | ||
-DEF_TRAVERSE_STMT( | +DEF_TRAVERSE_STMT(ArraySectionExpr, {}) | ||
DEF_TRAVERSE_STM | DEF_TRAVERSE_STM | ||
DEF_TRAVERSE_STM | DEF_TRAVERSE_STM | ||
@@ -25,8 +25,10 @@ | |||
#include "clang/Basic/Diagnostic.h" | #include "clang/Basic/Diagnostic.h" | ||
#include "clang/Basic/ExceptionSpecifi | #include "clang/Basic/ExceptionSpecifi | ||
#include "clang/Basic/LLVM.h" | #include "clang/Basic/LLVM.h" | ||
+#include "clang/Basic/LangOptions.h" | |||
#include "clang/Basic/Linkage.h" | #include "clang/Basic/Linkage.h" | ||
#include "clang/Basic/PartialDiagnosti | #include "clang/Basic/PartialDiagnosti | ||
+#include "clang/Basic/PointerAuthOptio | |||
#include "clang/Basic/SourceLocation.h" | #include "clang/Basic/SourceLocation.h" | ||
#include "clang/Basic/Specifiers.h" | #include "clang/Basic/Specifiers.h" | ||
#include "clang/Basic/Visibility.h" | #include "clang/Basic/Visibility.h" | ||
@@ -139,6 +141,174 @@ using CanQualType = CanQual<Type>; | |||
#define TYPE(Class, Base) class Class##Type; | #define TYPE(Class, Base) class Class##Type; | ||
#include "clang/AST/TypeNodes.inc" | #include "clang/AST/TypeNodes.inc" | ||
+/// Pointer-authentication qualifiers. | |||
+class PointerAuthQuali | |||
+ enum : uint32_t { | |||
+ EnabledShift = 0, | |||
+ EnabledBits = 1, | |||
+ EnabledMask = 1 << EnabledShift, | |||
+ AddressDiscrimin | |||
+ AddressDiscrimin | |||
+ AddressDiscrimin | |||
+ AuthenticationMo | |||
+ AddressDiscrimin | |||
+ AuthenticationMo | |||
+ AuthenticationMo | |||
+ << AuthenticationMo | |||
+ IsaPointerShift = AuthenticationMo | |||
+ IsaPointerBits = 1, | |||
+ IsaPointerMask = ((1 << IsaPointerBits) - 1) << IsaPointerShift, | |||
+ AuthenticatesNul | |||
+ AuthenticatesNul | |||
+ AuthenticatesNul | |||
+ << AuthenticatesNul | |||
+ KeyShift = AuthenticatesNul | |||
+ KeyBits = 10, | |||
+ KeyMask = ((1 << KeyBits) - 1) << KeyShift, | |||
+ DiscriminatorShi | |||
+ DiscriminatorBit | |||
+ DiscriminatorMas | |||
+ }; | |||
+ | |||
+ // bits: |0 |1 |2..3 |4 | | |||
+ // |Enabled|Address|AuthenticationMo | |||
+ // bits: |5 |6..15| 16...31 | | |||
+ // |AuthenticatesNul | |||
+ uint32_t Data = 0; | |||
+ | |||
+ // The following static assertions check that each of the 32 bits is present | |||
+ // exactly in one of the constants. | |||
+ static_assert((EnabledBits + AddressDiscrimin | |||
+ AuthenticationMo | |||
+ AuthenticatesNul | |||
+ 32, | |||
+ "PointerAuthQuali | |||
+ static_assert((EnabledMask + AddressDiscrimin | |||
+ AuthenticationMo | |||
+ AuthenticatesNul | |||
+ 0xFFFFFFFF, | |||
+ "All masks should cover the entire bits"); | |||
+ static_assert((EnabledMask ^ AddressDiscrimin | |||
+ AuthenticationMo | |||
+ AuthenticatesNul | |||
+ 0xFFFFFFFF, | |||
+ "All masks should cover the entire bits"); | |||
+ | |||
+ PointerAuthQuali | |||
+ unsigned ExtraDiscriminat | |||
+ PointerAuthentic | |||
+ bool IsIsaPointer, bool AuthenticatesNul | |||
+ : Data(EnabledMask | | |||
+ (IsAddressDiscrim | |||
+ ? llvm::to_underlying(AddressDiscrimin | |||
+ : 0) | | |||
+ (Key << KeyShift) | | |||
+ (llvm::to_underlying(AuthenticationMo | |||
+ << AuthenticationMo | |||
+ (ExtraDiscriminat | |||
+ (IsIsaPointer << IsaPointerShift) | | |||
+ (AuthenticatesNul | |||
+ assert(Key <= KeyNoneInternal); | |||
+ assert(ExtraDiscriminat | |||
+ assert((Data == 0) == | |||
+ (getAuthenticatio | |||
+ } | |||
+ | |||
+public: | |||
+ enum { | |||
+ KeyNoneInternal = (1u << KeyBits) - 1, | |||
+ | |||
+ /// The maximum supported pointer-authentication key. | |||
+ MaxKey = KeyNoneInternal - 1, | |||
+ | |||
+ /// The maximum supported pointer-authentication discriminator. | |||
+ MaxDiscriminator | |||
+ }; | |||
+ | |||
+public: | |||
+ PointerAuthQuali | |||
+ | |||
+ static PointerAuthQuali | |||
+ Create(unsigned Key, bool IsAddressDiscrim | |||
+ PointerAuthentic | |||
+ bool AuthenticatesNul | |||
+ if (Key == PointerAuthKeyNo | |||
+ Key = KeyNoneInternal; | |||
+ assert(Key <= KeyNoneInternal && "out-of-range key value"); | |||
+ return PointerAuthQuali | |||
+ AuthenticationMo | |||
+ AuthenticatesNul | |||
+ } | |||
+ | |||
+ bool isPresent() const { | |||
+ assert((Data == 0) == | |||
+ (getAuthenticatio | |||
+ return Data != 0; | |||
+ } | |||
+ | |||
+ explicit operator bool() const { return isPresent(); } | |||
+ | |||
+ unsigned getKey() const { | |||
+ assert(isPresent()); | |||
+ return (Data & KeyMask) >> KeyShift; | |||
+ } | |||
+ | |||
+ bool hasKeyNone() const { return isPresent() && getKey() == KeyNoneInternal; } | |||
+ | |||
+ bool isAddressDiscrim | |||
+ assert(isPresent()); | |||
+ return (Data & AddressDiscrimin | |||
+ } | |||
+ | |||
+ unsigned getExtraDiscrimi | |||
+ assert(isPresent()); | |||
+ return (Data >> DiscriminatorShi | |||
+ } | |||
+ | |||
+ PointerAuthentic | |||
+ return PointerAuthentic | |||
+ AuthenticationMo | |||
+ } | |||
+ | |||
+ bool isIsaPointer() const { | |||
+ assert(isPresent()); | |||
+ return (Data & IsaPointerMask) >> IsaPointerShift; | |||
+ } | |||
+ | |||
+ bool authenticatesNul | |||
+ assert(isPresent()); | |||
+ return (Data & AuthenticatesNul | |||
+ } | |||
+ | |||
+ PointerAuthQuali | |||
+ return hasKeyNone() ? PointerAuthQuali | |||
+ } | |||
+ | |||
+ friend bool operator==(PointerAuthQuali | |||
+ return Lhs.Data == Rhs.Data; | |||
+ } | |||
+ friend bool operator!=(PointerAuthQuali | |||
+ return Lhs.Data != Rhs.Data; | |||
+ } | |||
+ | |||
+ bool isEquivalent(PointerAuthQuali | |||
+ return withoutKeyNone() == Other.withoutKeyNone(); | |||
+ } | |||
+ | |||
+ uint32_t getAsOpaqueValue | |||
+ | |||
+ // Deserialize pointer-auth qualifiers from an opaque representation. | |||
+ static PointerAuthQuali | |||
+ PointerAuthQuali | |||
+ Result.Data = Opaque; | |||
+ assert((Result.Data == 0) == | |||
+ (Result.getAuthenticatio | |||
+ return Result; | |||
+ } | |||
+ | |||
+ void Profile(llvm::FoldingSetNodeID | |||
+}; | |||
+ | |||
/// The collection of all-type qualifiers we support. | /// The collection of all-type qualifiers we support. | ||
/// Clang supports five independent qualifiers: | /// Clang supports five independent qualifiers: | ||
/// * C99: const, volatile, and restrict | /// * C99: const, volatile, and restrict | ||
@@ -147,8 +317,9 @@ using CanQualType = CanQual<Type>; | |||
/// * Objective C: the GC attributes (none, weak, or strong) | /// * Objective C: the GC attributes (none, weak, or strong) | ||
class Qualifiers { | class Qualifiers { | ||
public: | public: | ||
- enum TQ { // NOTE: These flags must be kept in sync with DeclSpec::TQ. | + enum TQ : uint64_t { | ||
- Const = 0x1, | + // NOTE: These flags must be kept in sync with DeclSpec::TQ. | ||
+ Const = 0x1, | |||
Restrict = 0x2, | Restrict = 0x2, | ||
Volatile = 0x4, | Volatile = 0x4, | ||
CVRMask = Const | Volatile | Restrict | CVRMask = Const | Volatile | Restrict | ||
@@ -182,7 +353,7 @@ public: | |||
OCL_Autoreleasin | OCL_Autoreleasin | ||
}; | }; | ||
- enum { | + enum : uint64_t { | ||
/// The maximum supported address space number. | /// The maximum supported address space number. | ||
/// 23 bits should be enough for anyone. | /// 23 bits should be enough for anyone. | ||
MaxAddressSpace = 0x7fffffu, | MaxAddressSpace = 0x7fffffu, | ||
@@ -197,16 +368,25 @@ public: | |||
/// Returns the common set of qualifiers while removing them from | /// Returns the common set of qualifiers while removing them from | ||
/// the given sets. | /// the given sets. | ||
static Qualifiers removeCommonQual | static Qualifiers removeCommonQual | ||
+ Qualifiers Q; | |||
+ PointerAuthQuali | |||
+ if (LPtrAuth.isPresent() && | |||
+ LPtrAuth.getKey() != PointerAuthQuali | |||
+ LPtrAuth == R.getPointerAuth()) { | |||
+ Q.setPointerAuth(LPtrAuth); | |||
+ PointerAuthQuali | |||
+ L.setPointerAuth(Empty); | |||
+ R.setPointerAuth(Empty); | |||
+ } | |||
+ | |||
// If both are only CVR-qualified, bit operations are sufficient. | // If both are only CVR-qualified, bit operations are sufficient. | ||
if (!(L.Mask & ~CVRMask) && !(R.Mask & ~CVRMask)) { | if (!(L.Mask & ~CVRMask) && !(R.Mask & ~CVRMask)) { | ||
- Qualifiers Q; | |||
Q.Mask = L.Mask & R.Mask; | Q.Mask = L.Mask & R.Mask; | ||
L.Mask &= ~Q.Mask; | L.Mask &= ~Q.Mask; | ||
R.Mask &= ~Q.Mask; | R.Mask &= ~Q.Mask; | ||
return Q; | return Q; | ||
} | } | ||
- Qualifiers Q; | |||
unsigned CommonCRV = L.getCVRQualifiers | unsigned CommonCRV = L.getCVRQualifiers | ||
Q.addCVRQualifiers | Q.addCVRQualifiers | ||
L.removeCVRQualifi | L.removeCVRQualifi | ||
@@ -251,16 +431,14 @@ public: | |||
} | } | ||
// Deserialize qualifiers from an opaque representation. | // Deserialize qualifiers from an opaque representation. | ||
- static Qualifiers fromOpaqueValue( | + static Qualifiers fromOpaqueValue(uint64_t opaque) { | ||
Qualifiers Qs; | Qualifiers Qs; | ||
Qs.Mask = opaque; | Qs.Mask = opaque; | ||
return Qs; | return Qs; | ||
} | } | ||
// Serialize these qualifiers into an opaque representation. | // Serialize these qualifiers into an opaque representation. | ||
- | + uint64_t getAsOpaqueValue() const { return Mask; } | ||
- return Mask; | |||
- } | |||
bool hasConst() const { return Mask & Const; } | bool hasConst() const { return Mask & Const; } | ||
bool hasOnlyConst() const { return Mask == Const; } | bool hasOnlyConst() const { return Mask == Const; } | ||
@@ -302,7 +480,7 @@ public: | |||
} | } | ||
void removeCVRQualifi | void removeCVRQualifi | ||
assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); | assert(!(mask & ~CVRMask) && "bitmask contains non-CVR bits"); | ||
- Mask &= ~mask; | + Mask &= ~static_cast<uint64_t>(mask); | ||
} | } | ||
void removeCVRQualifi | void removeCVRQualifi | ||
removeCVRQualifi | removeCVRQualifi | ||
@@ -407,6 +585,20 @@ public: | |||
setAddressSpace(space); | setAddressSpace(space); | ||
} | } | ||
+ bool hasPointerAuth() const { return Mask & PtrAuthMask; } | |||
+ PointerAuthQuali | |||
+ return PointerAuthQuali | |||
+ } | |||
+ void setPointerAuth(PointerAuthQuali | |||
+ Mask = (Mask & ~PtrAuthMask) | | |||
+ (uint64_t(Q.getAsOpaqueValue | |||
+ } | |||
+ void removePointerAut | |||
+ void addPointerAuth(PointerAuthQuali | |||
+ assert(Q.isPresent()); | |||
+ setPointerAuth(Q); | |||
+ } | |||
+ | |||
// Fast qualifiers are those that can be allocated directly | // Fast qualifiers are those that can be allocated directly | ||
// on a QualType object. | // on a QualType object. | ||
bool hasFastQualifier | bool hasFastQualifier | ||
@@ -417,7 +609,7 @@ public: | |||
} | } | ||
void removeFastQualif | void removeFastQualif | ||
assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); | assert(!(mask & ~FastMask) && "bitmask contains non-fast qualifier bits"); | ||
- Mask &= ~mask; | + Mask &= ~static_cast<uint64_t>(mask); | ||
} | } | ||
void removeFastQualif | void removeFastQualif | ||
removeFastQualif | removeFastQualif | ||
@@ -454,6 +646,8 @@ public: | |||
addObjCGCAttr(Q.getObjCGCAttr()); | addObjCGCAttr(Q.getObjCGCAttr()); | ||
if (Q.hasObjCLifetime()) | if (Q.hasObjCLifetime()) | ||
addObjCLifetime(Q.getObjCLifetime()); | addObjCLifetime(Q.getObjCLifetime()); | ||
+ if (Q.hasPointerAuth()) | |||
+ addPointerAuth(Q.getPointerAuth()); | |||
} | } | ||
} | } | ||
@@ -471,6 +665,8 @@ public: | |||
removeObjCLifeti | removeObjCLifeti | ||
if (getAddressSpace() == Q.getAddressSpace()) | if (getAddressSpace() == Q.getAddressSpace()) | ||
removeAddressSpa | removeAddressSpa | ||
+ if (getPointerAuth() == Q.getPointerAuth()) | |||
+ removePointerAut | |||
} | } | ||
} | } | ||
@@ -483,6 +679,8 @@ public: | |||
!hasObjCGCAttr() || !qs.hasObjCGCAttr()); | !hasObjCGCAttr() || !qs.hasObjCGCAttr()); | ||
assert(getObjCLifetime() == qs.getObjCLifetime() || | assert(getObjCLifetime() == qs.getObjCLifetime() || | ||
!hasObjCLifetime() || !qs.hasObjCLifetime()); | !hasObjCLifetime() || !qs.hasObjCLifetime()); | ||
+ assert(!hasPointerAuth() || !qs.hasPointerAuth() || | |||
+ getPointerAuth() == qs.getPointerAuth()); | |||
Mask |= qs.Mask; | Mask |= qs.Mask; | ||
} | } | ||
@@ -536,6 +734,8 @@ public: | |||
// be changed. | // be changed. | ||
(getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() || | (getObjCGCAttr() == other.getObjCGCAttr() || !hasObjCGCAttr() || | ||
!other.hasObjCGCAttr()) && | !other.hasObjCGCAttr()) && | ||
+ // Pointer-auth qualifiers must match exactly. | |||
+ getPointerAuth() == other.getPointerAuth() && | |||
// ObjC lifetime qualifiers must match exactly. | // ObjC lifetime qualifiers must match exactly. | ||
getObjCLifetime() == other.getObjCLifetime() && | getObjCLifetime() == other.getObjCLifetime() && | ||
// CVR qualifiers may subset. | // CVR qualifiers may subset. | ||
@@ -605,24 +805,26 @@ public: | |||
void print(raw_ostream &OS, const PrintingPolicy &Policy, | void print(raw_ostream &OS, const PrintingPolicy &Policy, | ||
bool appendSpaceIfNon | bool appendSpaceIfNon | ||
- void Profile(llvm::FoldingSetNodeID &ID) const { | + void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Mask); } | ||
- ID.AddInteger(Mask); | |||
- } | |||
private: | private: | ||
- // bits: |0 1 2|3|4 .. 5|6 .. 8|9 ... | + // bits: |0 1 2|3|4 .. 5|6 .. 8|9 ... 31|32 ... 63| | ||
- // |C R V|U|GCAttr|Lifetime|AddressSpace| | + // |C R V|U|GCAttr|Lifetime|AddressSpace| PtrAuth | | ||
- | + uint64_t Mask = 0; | ||
- | + static_assert(sizeof(PointerAuthQuali | ||
- static const uint32_t UMask = 0x8; | + "PointerAuthQuali | ||
- static const uint32_t UShift = 3; | + | ||
- static | + static constexpr uint64_t UMask = 0x8; | ||
- static | + static constexpr uint64_t UShift = 3; | ||
- static | + static constexpr uint64_t GCAttrMask = 0x30; | ||
- static | + static constexpr uint64_t GCAttrShift = 4; | ||
- static | + static constexpr uint64_t LifetimeMask = 0x1C0; | ||
+ static constexpr uint64_t LifetimeShift = 6; | |||
+ static constexpr uint64_t AddressSpaceMask | |||
~(CVRMask | UMask | GCAttrMask | LifetimeMask); | ~(CVRMask | UMask | GCAttrMask | LifetimeMask); | ||
- static | + static constexpr uint64_t AddressSpaceShift = 9; | ||
+ static constexpr uint64_t PtrAuthShift = 32; | |||
+ static constexpr uint64_t PtrAuthMask = uint64_t(0xffffffff) << PtrAuthShift; | |||
}; | }; | ||
class QualifiersAndAto | class QualifiersAndAto | ||
@@ -1242,6 +1444,10 @@ public: | |||
// true when Type is objc's weak and weak is enabled but ARC isn't. | // true when Type is objc's weak and weak is enabled but ARC isn't. | ||
bool isNonWeakInMRRWi | bool isNonWeakInMRRWi | ||
+ PointerAuthQuali | |||
+ return getQualifiers().getPointerAuth(); | |||
+ } | |||
+ | |||
enum PrimitiveDefault | enum PrimitiveDefault | ||
/// The type does not fall into any of the following categories. Note that | /// The type does not fall into any of the following categories. Note that | ||
/// this case is zero-valued so that values of this enum can be used as a | /// this case is zero-valued so that values of this enum can be used as a | ||
@@ -2172,6 +2378,10 @@ public: | |||
/// 'riscv_rvv_vector | /// 'riscv_rvv_vector | ||
QualType getRVVEltType(const ASTContext &Ctx) const; | QualType getRVVEltType(const ASTContext &Ctx) const; | ||
+ /// Returns the representative type for the element of a sizeless vector | |||
+ /// builtin type. | |||
+ QualType getSizelessVecto | |||
+ | |||
/// Types are partitioned into 3 broad categories (C99 6.2.5p1): | /// Types are partitioned into 3 broad categories (C99 6.2.5p1): | ||
/// object types, function types, and incomplete types. | /// object types, function types, and incomplete types. | ||
@@ -592,6 +592,49 @@ class AttrSubjectMatch | |||
def SubjectMatcherFo | def SubjectMatcherFo | ||
+// Enumeration specifying what kind of behavior should be used for late | |||
+// parsing of attributes. | |||
+class LateAttrParseKin | |||
+ int Kind = val; | |||
+} | |||
+ | |||
+// Never late parsed | |||
+def LateAttrParseNev | |||
+ | |||
+// Standard late attribute parsing | |||
+// | |||
+// This is language dependent. For example: | |||
+// | |||
+// * For C++ enables late parsing of a declaration attributes | |||
+// * For C does not enable late parsing of attributes | |||
+// | |||
+def LateAttrParseSta | |||
+ | |||
+// Experimental extension to standard late attribute parsing | |||
+// | |||
+// This extension behaves like `LateAttrParseSta | |||
+// late parsing attributes in more contexts. | |||
+// | |||
+// In contexts where `LateAttrParseSta | |||
+// parsed, `LateAttrParseExp | |||
+// be late parsed. | |||
+// | |||
+// In contexts that only late parse `LateAttrParseExp | |||
+// (see `LateParsedAttrLi | |||
+// | |||
+// * If `-fexperimental-late-parse-attributes` | |||
+// (`LangOpts.ExperimentalLate | |||
+// will be late parsed. | |||
+// * If `-fexperimental-late-parse-attributes` | |||
+// (`LangOpts.ExperimentalLate | |||
+// will **not** be late parsed (i.e parsed immediately). | |||
+// | |||
+// The following contexts are supported: | |||
+// | |||
+// * TODO: Add contexts here when they are implemented. | |||
+// | |||
+def LateAttrParseExp | |||
+ | |||
class Attr { | class Attr { | ||
// The various ways in which an attribute can be spelled in source | // The various ways in which an attribute can be spelled in source | ||
list<Spelling> Spellings; | list<Spelling> Spellings; | ||
@@ -603,8 +646,8 @@ class Attr { | |||
list<Accessor> Accessors = []; | list<Accessor> Accessors = []; | ||
// Specify targets for spellings. | // Specify targets for spellings. | ||
list<TargetSpecificSp | list<TargetSpecificSp | ||
- // Set to true for attributes with arguments which require delayed parsing. | + // Specifies the late parsing kind. | ||
- bit LateParsed = 0; | + LateAttrParseKin | ||
// Set to false to prevent an attribute from being propagated from a template | // Set to false to prevent an attribute from being propagated from a template | ||
// to the instantiation. | // to the instantiation. | ||
bit Clone = 1; | bit Clone = 1; | ||
@@ -3173,7 +3216,7 @@ def DiagnoseIf : InheritableAttr { | |||
BoolArgument<"ArgDependent", 0, /*fake*/ 1>, | BoolArgument<"ArgDependent", 0, /*fake*/ 1>, | ||
DeclArgument<Named, "Parent", 0, /*fake*/ 1>]; | DeclArgument<Named, "Parent", 0, /*fake*/ 1>]; | ||
let InheritEvenIfAlr | let InheritEvenIfAlr | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let AdditionalMember | let AdditionalMember | ||
bool isError() const { return diagnosticType == DT_Error; } | bool isError() const { return diagnosticType == DT_Error; } | ||
bool isWarning() const { return diagnosticType == DT_Warning; } | bool isWarning() const { return diagnosticType == DT_Warning; } | ||
@@ -3211,7 +3254,7 @@ def ObjCRequiresProp | |||
def Unused : InheritableAttr { | def Unused : InheritableAttr { | ||
let Spellings = [CXX11<"", "maybe_unused", 201603>, GCC<"unused">, | let Spellings = [CXX11<"", "maybe_unused", 201603>, GCC<"unused">, | ||
C23<"", "maybe_unused", 202106>]; | C23<"", "maybe_unused", 202106>]; | ||
- let Subjects = SubjectList<[Var, ObjCIvar, Type, Enum, EnumConstant, Label, | + let Subjects = SubjectList<[Var, Binding, ObjCIvar, Type, Enum, EnumConstant, Label, | ||
Field, ObjCMethod, FunctionLike]>; | Field, ObjCMethod, FunctionLike]>; | ||
let Documentation = [WarnMaybeUnusedD | let Documentation = [WarnMaybeUnusedD | ||
} | } | ||
@@ -3472,7 +3515,7 @@ def AssertCapability | |||
let Spellings = [Clang<"assert_capabilit | let Spellings = [Clang<"assert_capabilit | ||
Clang<"assert_shared_ca | Clang<"assert_shared_ca | ||
let Subjects = SubjectList<[Function]>; | let Subjects = SubjectList<[Function]>; | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let TemplateDependen | let TemplateDependen | ||
let ParseArgumentsAs | let ParseArgumentsAs | ||
let InheritEvenIfAlr | let InheritEvenIfAlr | ||
@@ -3488,7 +3531,7 @@ def AcquireCapabilit | |||
GNU<"exclusive_lock_f | GNU<"exclusive_lock_f | ||
GNU<"shared_lock_func | GNU<"shared_lock_func | ||
let Subjects = SubjectList<[Function]>; | let Subjects = SubjectList<[Function]>; | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let TemplateDependen | let TemplateDependen | ||
let ParseArgumentsAs | let ParseArgumentsAs | ||
let InheritEvenIfAlr | let InheritEvenIfAlr | ||
@@ -3504,7 +3547,7 @@ def TryAcquireCapabi | |||
Clang<"try_acquire_shar | Clang<"try_acquire_shar | ||
let Subjects = SubjectList<[Function], | let Subjects = SubjectList<[Function], | ||
ErrorDiag>; | ErrorDiag>; | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let TemplateDependen | let TemplateDependen | ||
let ParseArgumentsAs | let ParseArgumentsAs | ||
let InheritEvenIfAlr | let InheritEvenIfAlr | ||
@@ -3520,7 +3563,7 @@ def ReleaseCapabilit | |||
Clang<"release_generic_ | Clang<"release_generic_ | ||
Clang<"unlock_function", 0>]; | Clang<"unlock_function", 0>]; | ||
let Subjects = SubjectList<[Function]>; | let Subjects = SubjectList<[Function]>; | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let TemplateDependen | let TemplateDependen | ||
let ParseArgumentsAs | let ParseArgumentsAs | ||
let InheritEvenIfAlr | let InheritEvenIfAlr | ||
@@ -3539,7 +3582,7 @@ def RequiresCapabili | |||
Clang<"requires_shared_ | Clang<"requires_shared_ | ||
Clang<"shared_locks_req | Clang<"shared_locks_req | ||
let Args = [VariadicExprArgu | let Args = [VariadicExprArgu | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let TemplateDependen | let TemplateDependen | ||
let ParseArgumentsAs | let ParseArgumentsAs | ||
let InheritEvenIfAlr | let InheritEvenIfAlr | ||
@@ -3559,7 +3602,7 @@ def NoThreadSafetyAn | |||
def GuardedBy : InheritableAttr { | def GuardedBy : InheritableAttr { | ||
let Spellings = [GNU<"guarded_by">]; | let Spellings = [GNU<"guarded_by">]; | ||
let Args = [ExprArgument<"Arg">]; | let Args = [ExprArgument<"Arg">]; | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let TemplateDependen | let TemplateDependen | ||
let ParseArgumentsAs | let ParseArgumentsAs | ||
let InheritEvenIfAlr | let InheritEvenIfAlr | ||
@@ -3570,7 +3613,7 @@ def GuardedBy : InheritableAttr { | |||
def PtGuardedBy : InheritableAttr { | def PtGuardedBy : InheritableAttr { | ||
let Spellings = [GNU<"pt_guarded_by">]; | let Spellings = [GNU<"pt_guarded_by">]; | ||
let Args = [ExprArgument<"Arg">]; | let Args = [ExprArgument<"Arg">]; | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let TemplateDependen | let TemplateDependen | ||
let ParseArgumentsAs | let ParseArgumentsAs | ||
let InheritEvenIfAlr | let InheritEvenIfAlr | ||
@@ -3581,7 +3624,7 @@ def PtGuardedBy : InheritableAttr { | |||
def AcquiredAfter : InheritableAttr { | def AcquiredAfter : InheritableAttr { | ||
let Spellings = [GNU<"acquired_after">]; | let Spellings = [GNU<"acquired_after">]; | ||
let Args = [VariadicExprArgu | let Args = [VariadicExprArgu | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let TemplateDependen | let TemplateDependen | ||
let ParseArgumentsAs | let ParseArgumentsAs | ||
let InheritEvenIfAlr | let InheritEvenIfAlr | ||
@@ -3592,7 +3635,7 @@ def AcquiredAfter : InheritableAttr { | |||
def AcquiredBefore : InheritableAttr { | def AcquiredBefore : InheritableAttr { | ||
let Spellings = [GNU<"acquired_before">]; | let Spellings = [GNU<"acquired_before">]; | ||
let Args = [VariadicExprArgu | let Args = [VariadicExprArgu | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let TemplateDependen | let TemplateDependen | ||
let ParseArgumentsAs | let ParseArgumentsAs | ||
let InheritEvenIfAlr | let InheritEvenIfAlr | ||
@@ -3603,7 +3646,7 @@ def AcquiredBefore : InheritableAttr { | |||
def AssertExclusiveL | def AssertExclusiveL | ||
let Spellings = [GNU<"assert_exclusive | let Spellings = [GNU<"assert_exclusive | ||
let Args = [VariadicExprArgu | let Args = [VariadicExprArgu | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let TemplateDependen | let TemplateDependen | ||
let ParseArgumentsAs | let ParseArgumentsAs | ||
let InheritEvenIfAlr | let InheritEvenIfAlr | ||
@@ -3614,7 +3657,7 @@ def AssertExclusiveL | |||
def AssertSharedLock | def AssertSharedLock | ||
let Spellings = [GNU<"assert_shared_lo | let Spellings = [GNU<"assert_shared_lo | ||
let Args = [VariadicExprArgu | let Args = [VariadicExprArgu | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let TemplateDependen | let TemplateDependen | ||
let ParseArgumentsAs | let ParseArgumentsAs | ||
let InheritEvenIfAlr | let InheritEvenIfAlr | ||
@@ -3627,7 +3670,7 @@ def AssertSharedLock | |||
def ExclusiveTrylock | def ExclusiveTrylock | ||
let Spellings = [GNU<"exclusive_tryloc | let Spellings = [GNU<"exclusive_tryloc | ||
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgu | let Args = [ExprArgument<"SuccessValue">, VariadicExprArgu | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let TemplateDependen | let TemplateDependen | ||
let ParseArgumentsAs | let ParseArgumentsAs | ||
let InheritEvenIfAlr | let InheritEvenIfAlr | ||
@@ -3640,7 +3683,7 @@ def ExclusiveTrylock | |||
def SharedTrylockFun | def SharedTrylockFun | ||
let Spellings = [GNU<"shared_trylock_f | let Spellings = [GNU<"shared_trylock_f | ||
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgu | let Args = [ExprArgument<"SuccessValue">, VariadicExprArgu | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let TemplateDependen | let TemplateDependen | ||
let ParseArgumentsAs | let ParseArgumentsAs | ||
let InheritEvenIfAlr | let InheritEvenIfAlr | ||
@@ -3651,7 +3694,7 @@ def SharedTrylockFun | |||
def LockReturned : InheritableAttr { | def LockReturned : InheritableAttr { | ||
let Spellings = [GNU<"lock_returned">]; | let Spellings = [GNU<"lock_returned">]; | ||
let Args = [ExprArgument<"Arg">]; | let Args = [ExprArgument<"Arg">]; | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let TemplateDependen | let TemplateDependen | ||
let ParseArgumentsAs | let ParseArgumentsAs | ||
let Subjects = SubjectList<[Function]>; | let Subjects = SubjectList<[Function]>; | ||
@@ -3661,7 +3704,7 @@ def LockReturned : InheritableAttr { | |||
def LocksExcluded : InheritableAttr { | def LocksExcluded : InheritableAttr { | ||
let Spellings = [GNU<"locks_excluded">]; | let Spellings = [GNU<"locks_excluded">]; | ||
let Args = [VariadicExprArgu | let Args = [VariadicExprArgu | ||
- let LateParsed = | + let LateParsed = LateAttrParseStandard; | ||
let TemplateDependen | let TemplateDependen | ||
let ParseArgumentsAs | let ParseArgumentsAs | ||
let InheritEvenIfAlr | let InheritEvenIfAlr |
@@ -370,4 +370,7 @@ def warn_missing_sym | |||
"Missing symbol graph output directory, defaulting to working directory">, | "Missing symbol graph output directory, defaulting to working directory">, | ||
InGroup<ExtractAPIMisuse | InGroup<ExtractAPIMisuse | ||
+def err_ast_action_o | |||
+ "cannot apply AST actions to LLVM IR file '%0'">, | |||
+ DefaultFatal; | |||
} | } |
@@ -24,7 +24,7 @@ def err_no_matching_ | |||
def err_unsupported_ | def err_unsupported_ | ||
def err_unsupported_ | def err_unsupported_ | ||
def err_unsupported_ | def err_unsupported_ | ||
-def | +def err_cannot_read_input_list : Error<"could not read %select{alias list|filelist}0 '%1': %2">; | ||
} // end of command line category. | } // end of command line category. | ||
let CategoryName = "Verification" in { | let CategoryName = "Verification" in { |
@@ -478,6 +478,15 @@ def ext_decomp_decl_ | |||
"ISO C++17 does not allow a decomposition group to be empty">, | "ISO C++17 does not allow a decomposition group to be empty">, | ||
InGroup<DiagGroup<"empty-decomposition">>; | InGroup<DiagGroup<"empty-decomposition">>; | ||
+// C++26 structured bindings | |||
+def ext_decl_attrs_o | |||
+ "an attribute specifier sequence attached to a structured binding declaration " | |||
+ "is a C++2c extension">, InGroup<CXX26>; | |||
+def warn_cxx23_compa | |||
+ "an attribute specifier sequence attached to a structured binding declaration " | |||
+ "is incompatible with C++ standards before C++2c">, | |||
+ InGroup<CXXPre26Compat>, DefaultIgnore; | |||
+ | |||
/// Objective-C parser diagnostics | /// Objective-C parser diagnostics | ||
def err_expected_min | def err_expected_min | ||
"method type specifier must start with '-' or '+'">; | "method type specifier must start with '-' or '+'">; | ||
@@ -1429,6 +1438,9 @@ def err_omp_decl_in_ | |||
def err_omp_sink_and | def err_omp_sink_and | ||
def err_omp_unknown_ | def err_omp_unknown_ | ||
"incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'">; | "incorrect map type, expected one of 'to', 'from', 'tofrom', 'alloc', 'release', or 'delete'">; | ||
+def err_omp_more_one | |||
+def note_previous_ma | |||
+ : Note<"map type '%0' is previous specified here">; | |||
def err_omp_unknown_ | def err_omp_unknown_ | ||
"incorrect map type modifier, expected one of: 'always', 'close', 'mapper'" | "incorrect map type modifier, expected one of: 'always', 'close', 'mapper'" | ||
"%select{|, 'present'|, 'present', 'iterator'}0%select{|, 'ompx_hold'}1">; | "%select{|, 'present'|, 'present', 'iterator'}0%select{|, 'ompx_hold'}1">; | ||
@@ -1436,6 +1448,8 @@ def err_omp_map_type | |||
"missing map type">; | "missing map type">; | ||
def err_omp_map_type | def err_omp_map_type | ||
"missing map type modifier">; | "missing map type modifier">; | ||
+def err_omp_map_modi | |||
+ "empty modifier-specification-list is not allowed">; | |||
def err_omp_declare_ | def err_omp_declare_ | ||
"unexpected '%0' clause, '%1' is specified already">; | "unexpected '%0' clause, '%1' is specified already">; | ||
def err_omp_expected | def err_omp_expected |
@@ -307,6 +307,8 @@ def err_invalid_vect | |||
"POWER7 or later) to be enabled">; | "POWER7 or later) to be enabled">; | ||
def err_invalid_vect | def err_invalid_vect | ||
"cannot use 'long double' with '__vector'">; | "cannot use 'long double' with '__vector'">; | ||
+def err_invalid_vect | |||
+ "cannot use '_Complex' with '__vector'">; | |||
def warn_vector_long | def warn_vector_long | ||
"Use of 'long' with '__vector' is deprecated">, InGroup<Deprecated>; | "Use of 'long' with '__vector' is deprecated">, InGroup<Deprecated>; | ||
@@ -9901,6 +9903,9 @@ def warn_format_inva | |||
def warn_format_P_no | def warn_format_P_no | ||
"using '%%P' format specifier without precision">, | "using '%%P' format specifier without precision">, | ||
InGroup<Format>; | InGroup<Format>; | ||
+def warn_format_P_wi | |||
+ "using '%%P' format specifier with an Objective-C pointer results in dumping runtime object structure, not object value">, | |||
+ InGroup<Format>; | |||
def warn_printf_igno | def warn_printf_igno | ||
"flag '%0' is ignored when flag '%1' is present">, | "flag '%0' is ignored when flag '%1' is present">, | ||
InGroup<Format>; | InGroup<Format>; | ||
@@ -9950,6 +9955,8 @@ def warn_ret_stack_a | |||
def warn_ret_local_t | def warn_ret_local_t | ||
"returning %select{address of|reference to}0 local temporary object">, | "returning %select{address of|reference to}0 local temporary object">, | ||
InGroup<ReturnStackAddre | InGroup<ReturnStackAddre | ||
+def err_ret_local_te | |||
+ "returning reference to local temporary object">; | |||
def warn_ret_addr_la | def warn_ret_addr_la | ||
"returning address of label, which is local">, | "returning address of label, which is local">, | ||
InGroup<ReturnStackAddre | InGroup<ReturnStackAddre | ||
@@ -10328,9 +10335,13 @@ def err_shufflevecto | |||
def err_shufflevecto | def err_shufflevecto | ||
"index for __builtin_shuffl | "index for __builtin_shuffl | ||
"of vector elements">; | "of vector elements">; | ||
+def err_shufflevecto | |||
+ "index for __builtin_shuffl | |||
def err_convertvecto | def err_convertvecto | ||
"first argument to __builtin_conver | "first argument to __builtin_conver | ||
+def err_convertvecto | |||
+ "unsupported vector cast from %0 to %1 in a constant expression.">; | |||
def err_builtin_non_ | def err_builtin_non_ | ||
"%0 argument to %1 must be of vector type">; | "%0 argument to %1 must be of vector type">; | ||
def err_convertvecto | def err_convertvecto | ||
@@ -11161,7 +11172,7 @@ def err_omp_declare_ | |||
"redefinition of user-defined mapper for type %0 with name %1">; | "redefinition of user-defined mapper for type %0 with name %1">; | ||
def err_omp_invalid_ | def err_omp_invalid_ | ||
"cannot find a valid user-defined mapper for type %0 with name %1">; | "cannot find a valid user-defined mapper for type %0 with name %1">; | ||
-def | +def err_array_section_use : Error<"%select{OpenACC sub-array|OpenMP array section}0 is not allowed here">; | ||
def err_omp_array_sh | def err_omp_array_sh | ||
def err_omp_iterator | def err_omp_iterator | ||
def err_omp_typechec | def err_omp_typechec | ||
@@ -12296,4 +12307,7 @@ def err_acc_num_gang | |||
"OpenACC 'num_gangs' " | "OpenACC 'num_gangs' " | ||
"%select{|clause: '%1' directive expects maximum of %2, %3 were " | "%select{|clause: '%1' directive expects maximum of %2, %3 were " | ||
"provided}0">; | "provided}0">; | ||
+def err_acc_not_a_va | |||
+ : Error<"OpenACC variable is not a valid variable name, sub-array, array " | |||
+ "element, or composite variable member">; | |||
} // end of sema component. | } // end of sema component. |
@@ -114,6 +114,12 @@ class FileManager : public RefCountedBase<F | |||
/// | /// | ||
unsigned NextFileUID; | unsigned NextFileUID; | ||
+ /// Statistics gathered during the lifetime of the FileManager. | |||
+ unsigned NumDirLookups = 0; | |||
+ unsigned NumFileLookups = 0; | |||
+ unsigned NumDirCacheMisse | |||
+ unsigned NumFileCacheMiss | |||
+ | |||
// Caching. | // Caching. | ||
std::unique_ptr<FileSystemStatCa | std::unique_ptr<FileSystemStatCa | ||
@@ -341,6 +347,10 @@ private: | |||
public: | public: | ||
void PrintStats() const; | void PrintStats() const; | ||
+ | |||
+ /// Import statistics from a child FileManager and add them to this current | |||
+ /// FileManager. | |||
+ void AddStats(const FileManager &Other); | |||
}; | }; | ||
} // end namespace clang | } // end namespace clang |
@@ -164,6 +164,7 @@ LANGOPT(Experime | |||
LANGOPT(PointerAuthIntri | LANGOPT(PointerAuthIntri | ||
LANGOPT(DoubleSquareBrac | LANGOPT(DoubleSquareBrac | ||
+LANGOPT(ExperimentalLate | |||
COMPATIBLE_LANGO | COMPATIBLE_LANGO | ||
COMPATIBLE_LANGO | COMPATIBLE_LANGO |
@@ -57,6 +57,13 @@ enum class ShaderStage { | |||
Invalid, | Invalid, | ||
}; | }; | ||
+enum class PointerAuthentic | |||
+ None, | |||
+ Strip, | |||
+ SignAndStrip, | |||
+ SignAndAuth | |||
+}; | |||
+ | |||
/// Bitfields of LangOptions, split out from LangOptions in order to ensure that | /// Bitfields of LangOptions, split out from LangOptions in order to ensure that | ||
/// this large collection of bitfields is a trivial class type. | /// this large collection of bitfields is a trivial class type. | ||
class LangOptionsBase { | class LangOptionsBase { |
@@ -20,6 +20,7 @@ VISIT_CLAUSE(If) | |||
VISIT_CLAUSE(Self) | VISIT_CLAUSE(Self) | ||
VISIT_CLAUSE(NumGangs) | VISIT_CLAUSE(NumGangs) | ||
VISIT_CLAUSE(NumWorkers) | VISIT_CLAUSE(NumWorkers) | ||
+VISIT_CLAUSE(Private) | |||
VISIT_CLAUSE(VectorLength) | VISIT_CLAUSE(VectorLength) | ||
#undef VISIT_CLAUSE | #undef VISIT_CLAUSE |
@@ -0,0 +1,23 @@ | |||
+//===--- PointerAuthOptio | |||
+// | |||
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
+// See https://llvm.org/LICENSE.txt for license information. | |||
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
+// | |||
+//===----------------------------------------------------------------------===// | |||
+// | |||
+// This file defines options for configuring pointer-auth technologies | |||
+// like ARMv8.3. | |||
+// | |||
+//===----------------------------------------------------------------------===// | |||
+ | |||
+#ifndef LLVM_CLANG_BASIC | |||
+#define LLVM_CLANG_BASIC | |||
+ | |||
+namespace clang { | |||
+ | |||
+constexpr unsigned PointerAuthKeyNo | |||
+ | |||
+} // end namespace clang | |||
+ | |||
+#endif |
@@ -71,7 +71,7 @@ def OffsetOfExpr : StmtNode<Expr>; | |||
def UnaryExprOrTypeT | def UnaryExprOrTypeT | ||
def ArraySubscriptEx | def ArraySubscriptEx | ||
def MatrixSubscriptE | def MatrixSubscriptE | ||
-def | +def ArraySectionExpr : StmtNode<Expr>; | ||
def OMPIteratorExpr : StmtNode<Expr>; | def OMPIteratorExpr : StmtNode<Expr>; | ||
def CallExpr : StmtNode<Expr>; | def CallExpr : StmtNode<Expr>; | ||
def MemberExpr : StmtNode<Expr>; | def MemberExpr : StmtNode<Expr>; |
@@ -40,6 +40,7 @@ | |||
#include <cassert> | #include <cassert> | ||
#include <optional> | #include <optional> | ||
#include <string> | #include <string> | ||
+#include <utility> | |||
#include <vector> | #include <vector> | ||
namespace llvm { | namespace llvm { | ||
@@ -1792,6 +1793,15 @@ public: | |||
/// Whether to support HIP image/texture API's. | /// Whether to support HIP image/texture API's. | ||
virtual bool hasHIPImageSuppo | virtual bool hasHIPImageSuppo | ||
+ /// The first value in the pair is the minimum offset between two objects to | |||
+ /// avoid false sharing (destructive interference). The second value in the | |||
+ /// pair is maximum size of contiguous memory to promote true sharing | |||
+ /// (constructive interference). Neither of these values are considered part | |||
+ /// of the ABI and can be changed by targets at any time. | |||
+ virtual std::pair<unsigned, unsigned> hardwareInterfer | |||
+ return std::make_pair(64, 64); | |||
+ } | |||
+ | |||
protected: | protected: | ||
/// Copy type and layout related info. | /// Copy type and layout related info. | ||
void copyAuxTarget(const TargetInfo *Aux); | void copyAuxTarget(const TargetInfo *Aux); |
@@ -275,7 +275,7 @@ def OP_VCVT_BF16_F32 | |||
(call "vget_low", $p0))>; | (call "vget_low", $p0))>; | ||
def OP_CVT_F32_BF16 | def OP_CVT_F32_BF16 | ||
- : Op<(bitcast "R", (op "<<", ( | + : Op<(bitcast "R", (op "<<", (cast "int32_t", (bitcast "int16_t", $p0)), | ||
(literal "int32_t", "16")))>; | (literal "int32_t", "16")))>; | ||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// |
@@ -1961,19 +1961,20 @@ def SVPSEL_D : SInst<"svpsel_la | |||
// Standalone sve2.1 builtins | // Standalone sve2.1 builtins | ||
let TargetGuard = "sve2p1" in { | let TargetGuard = "sve2p1" in { | ||
-def SVORQV : SInst<"svorqv[_{d}]", | +def SVORQV : SInst<"svorqv[_{d}]", "{Pd", "csilUcUsUiUl", MergeNone, "aarch64_sve_orqv", [IsReductionQV]>; | ||
-def SVEORQV : SInst<"sveorqv[_{d}]", "{Pd", "csilUcUsUiUl", MergeNone, "aarch64_sve_eorqv", | +def SVEORQV : SInst<"sveorqv[_{d}]", "{Pd", "csilUcUsUiUl", MergeNone, "aarch64_sve_eorqv", [IsReductionQV]>; | ||
-def SVADDQV : SInst<"svaddqv[_{d}]", "{Pd", | +def SVADDQV : SInst<"svaddqv[_{d}]", "{Pd", "csilUcUsUiUl", MergeNone, "aarch64_sve_addqv", [IsReductionQV]>; | ||
-def SVANDQV : SInst<"svandqv[_{d}]", "{Pd", "csilUcUsUiUl", MergeNone, "aarch64_sve_andqv", | +def SVANDQV : SInst<"svandqv[_{d}]", "{Pd", "csilUcUsUiUl", MergeNone, "aarch64_sve_andqv", [IsReductionQV]>; | ||
-def SVSMAXQV : SInst<"svmaxqv[_{d}]", "{Pd", "csil", | +def SVSMAXQV : SInst<"svmaxqv[_{d}]", "{Pd", "csil", MergeNone, "aarch64_sve_smaxqv", [IsReductionQV]>; | ||
-def SVUMAXQV : SInst<"svmaxqv[_{d}]", "{Pd", "UcUsUiUl", | +def SVUMAXQV : SInst<"svmaxqv[_{d}]", "{Pd", "UcUsUiUl", MergeNone, "aarch64_sve_umaxqv", [IsReductionQV]>; | ||
-def SVSMINQV : SInst<"svminqv[_{d}]", "{Pd", "csil", | +def SVSMINQV : SInst<"svminqv[_{d}]", "{Pd", "csil", MergeNone, "aarch64_sve_sminqv", [IsReductionQV]>; | ||
-def SVUMINQV : SInst<"svminqv[_{d}]", "{Pd", "UcUsUiUl", | +def SVUMINQV : SInst<"svminqv[_{d}]", "{Pd", "UcUsUiUl", MergeNone, "aarch64_sve_uminqv", [IsReductionQV]>; | ||
- | + | ||
-def | +def SVFADDQV : SInst<"svaddqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_faddqv", [IsReductionQV]>; | ||
-def | +def SVFMAXNMQV : SInst<"svmaxnmqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_fmaxnmqv", [IsReductionQV]>; | ||
-def | +def SVFMINNMQV : SInst<"svminnmqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_fminnmqv", [IsReductionQV]>; | ||
-def | +def SVFMAXQV : SInst<"svmaxqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_fmaxqv", [IsReductionQV]>; | ||
+def SVFMINQV : SInst<"svminqv[_{d}]", "{Pd", "hfd", MergeNone, "aarch64_sve_fmin | |||
} | } | ||
let TargetGuard = "sve2p1|sme2" in { | let TargetGuard = "sve2p1|sme2" in { |
@@ -0,0 +1,6 @@ | |||
+set(MLIR_INCLUDE_DIR | |||
+set(MLIR_TABLEGEN_OU | |||
+include_director | |||
+include_director | |||
+ | |||
+add_subdirectory |
@@ -0,0 +1 @@ | |||
+add_subdirectory |
@@ -0,0 +1,16 @@ | |||
+//===- CIRDialect.h - CIR dialect -------------------------------*- C++ -*-===// | |||
+// | |||
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
+// See https://llvm.org/LICENSE.txt for license information. | |||
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
+// | |||
+//===----------------------------------------------------------------------===// | |||
+// | |||
+// This file declares the CIR dialect. | |||
+// | |||
+//===----------------------------------------------------------------------===// | |||
+ | |||
+#ifndef LLVM_CLANG_CIR_D | |||
+#define LLVM_CLANG_CIR_D | |||
+ | |||
+#endif // LLVM_CLANG_CIR_D |
@@ -0,0 +1,44 @@ | |||
+//===- CIRDialect.td - CIR dialect -------------------------*- tablegen -*-===// | |||
+// | |||
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
+// See https://llvm.org/LICENSE.txt for license information. | |||
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
+// | |||
+//===----------------------------------------------------------------------===// | |||
+// | |||
+// This file declares the CIR dialect. | |||
+// | |||
+//===----------------------------------------------------------------------===// | |||
+ | |||
+#ifndef LLVM_CLANG_CIR_D | |||
+#define LLVM_CLANG_CIR_D | |||
+ | |||
+include "mlir/IR/OpBase.td" | |||
+ | |||
+def CIR_Dialect : Dialect { | |||
+ let name = "cir"; | |||
+ | |||
+ // A short one-line summary of our dialect. | |||
+ let summary = "A high-level dialect for analyzing and optimizing Clang " | |||
+ "supported languages"; | |||
+ | |||
+ let cppNamespace = "::mlir::cir"; | |||
+ | |||
+ let useDefaultAttrib | |||
+ let useDefaultTypePr | |||
+ | |||
+ let extraClassDeclar | |||
+ void registerAttribut | |||
+ void registerTypes(); | |||
+ | |||
+ Type parseType(DialectAsmParser | |||
+ void printType(Type type, DialectAsmPrinte | |||
+ | |||
+ Attribute parseAttribute(DialectAsmParser | |||
+ Type type) const override; | |||
+ | |||
+ void printAttribute(Attribute attr, DialectAsmPrinte | |||
+ }]; | |||
+} | |||
+ | |||
+#endif // LLVM_CLANG_CIR_D |
@@ -0,0 +1,19 @@ | |||
+//===-- CIROps.td - CIR dialect definition -----------------*- tablegen -*-===// | |||
+// | |||
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |||
+// See https://llvm.org/LICENSE.txt for license information. | |||
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |||
+// | |||
+//===----------------------------------------------------------------------===// | |||
+/// | |||
+/// \file | |||
+/// Definition of the CIR dialect | |||
+/// | |||
+//===----------------------------------------------------------------------===// | |||
+ | |||
+#ifndef LLVM_CLANG_CIR_D | |||
+#define LLVM_CLANG_CIR_D | |||
+ | |||
+include "clang/CIR/Dialect/IR/CIRDialect.td" | |||
+ | |||
+#endif // LLVM_CLANG_CIR_D |
@@ -0,0 +1,16 @@ | |||
+# This replicates part of the add_mlir_dialect | |||
+# cannot be used here. This happens because it expects to be run inside MLIR | |||
+# directory which is not the case for CIR (and also FIR, both have similar | |||
+# workarounds). | |||
+ | |||
+# Equivalent to add_mlir_dialect | |||
+set(LLVM_TARGET_DEFI | |||
+mlir_tablegen(CIROps.h.inc -gen-op-decls) | |||
+mlir_tablegen(CIROps.cpp.inc -gen-op-defs) | |||
+mlir_tablegen(CIROpsTypes.h.inc -gen-typedef-decls) | |||
+mlir_tablegen(CIROpsTypes.cpp.inc -gen-typedef-defs) | |||
+mlir_tablegen(CIROpsDialect.h.inc -gen-dialect-decls) | |||
+mlir_tablegen(CIROpsDialect.cpp.inc -gen-dialect-defs) | |||
+add_public_table | |||
+add_dependencies | |||
+ |
@@ -1608,6 +1608,13 @@ defm double_square_br | |||
LangOpts<"DoubleSquareBrac | LangOpts<"DoubleSquareBrac | ||
NegFlag<SetFalse>>; | NegFlag<SetFalse>>; | ||
+defm experimental_lat | |||
+ LangOpts<"ExperimentalLate | |||
+ PosFlag<SetTrue, [], [ClangOption], "Enable">, | |||
+ NegFlag<SetFalse, [], [ClangOption], "Disable">, | |||
+ BothFlags<[], [ClangOption, CC1Option], | |||
+ " experimental late parsing of attributes">>; | |||
+ | |||
defm autolink : BoolFOption<"autolink", | defm autolink : BoolFOption<"autolink", | ||
CodeGenOpts<"Autolink">, DefaultTrue, | CodeGenOpts<"Autolink">, DefaultTrue, | ||
NegFlag<SetFalse, [], [ClangOption, CC1Option], | NegFlag<SetFalse, [], [ClangOption, CC1Option], | ||
@@ -2615,6 +2622,11 @@ defm protect_parens : BoolFOption<"pro | |||
"floating-point expressions are evaluated">, | "floating-point expressions are evaluated">, | ||
NegFlag<SetFalse>>; | NegFlag<SetFalse>>; | ||
+defm daz_ftz : SimpleMFlag<"daz-ftz", | |||
+ "Globally set", "Do not globally set", | |||
+ " the denormals-are-zero (DAZ) and flush-to-zero (FTZ) bits in the " | |||
+ "floating-point control register on program startup">; | |||
+ | |||
def ffor_scope : Flag<["-"], "ffor-scope">, Group<f_Group>; | def ffor_scope : Flag<["-"], "ffor-scope">, Group<f_Group>; | ||
def fno_for_scope : Flag<["-"], "fno-for-scope">, Group<f_Group>; | def fno_for_scope : Flag<["-"], "fno-for-scope">, Group<f_Group>; | ||
@@ -2881,6 +2893,17 @@ def flax_vector_conv | |||
def flimited_precisi | def flimited_precisi | ||
def fapple_link_rtli | def fapple_link_rtli | ||
HelpText<"Force linking the clang builtins runtime library">; | HelpText<"Force linking the clang builtins runtime library">; | ||
+ | |||
+/// ClangIR-specific options - BEGIN | |||
+defm clangir : BoolFOption<"clangir", | |||
+ FrontendOpts<"UseClangIRPipeli | |||
+ PosFlag<SetTrue, [], [ClangOption, CC1Option], "Use the ClangIR pipeline to compile">, | |||
+ NegFlag<SetFalse, [], [ClangOption, CC1Option], "Use the AST -> LLVM pipeline to compile">, | |||
+ BothFlags<[], [ClangOption, CC1Option], "">>; | |||
+def emit_cir : Flag<["-"], "emit-cir">, Visibility<[CC1Option]>, | |||
+ Group<Action_Group>, HelpText<"Build ASTs and then lower to ClangIR">; | |||
+/// ClangIR-specific options - END | |||
+ | |||
def flto_EQ : Joined<["-"], "flto=">, | def flto_EQ : Joined<["-"], "flto=">, | ||
Visibility<[ClangOption, CLOption, CC1Option, FC1Option, FlangOption]>, | Visibility<[ClangOption, CLOption, CC1Option, FC1Option, FlangOption]>, | ||
Group<f_Group>, | Group<f_Group>, | ||
@@ -4880,6 +4903,8 @@ def msimd128 : Flag<["-"], "msimd128">, Group<m_wasm_Fea | |||
def mno_simd128 : Flag<["-"], "mno-simd128">, Group<m_wasm_Features_ | def mno_simd128 : Flag<["-"], "mno-simd128">, Group<m_wasm_Features_ | ||
def mrelaxed_simd : Flag<["-"], "mrelaxed-simd">, Group<m_wasm_Features_ | def mrelaxed_simd : Flag<["-"], "mrelaxed-simd">, Group<m_wasm_Features_ | ||
def mno_relaxed_simd | def mno_relaxed_simd | ||
+def mhalf_precision : Flag<["-"], "mhalf-precision">, Group<m_wasm_Features_ | |||
+def mno_half_precisi | |||
def mnontrapping_fpt | def mnontrapping_fpt | ||
def mno_nontrapping_ | def mno_nontrapping_ | ||
def msign_ext : Flag<["-"], "msign-ext">, Group<m_wasm_Features_ | def msign_ext : Flag<["-"], "msign-ext">, Group<m_wasm_Features_ | ||
@@ -6586,12 +6611,6 @@ def J : JoinedOrSeparate | |||
Group<gfortran_Group>, | Group<gfortran_Group>, | ||
Alias<module_dir>; | Alias<module_dir>; | ||
-let Visibility = [FlangOption] in { | |||
-def no_fortran_main : Flag<["-"], "fno-fortran-main">, | |||
- Visibility<[FlangOption]>, Group<f_Group>, | |||
- HelpText<"Do not include Fortran_main.a (provided by Flang) when linking">; | |||
-} // let Visibility = [ FlangOption ] | |||
- | |||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||
// FC1 Options | // FC1 Options | ||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// |
@@ -241,7 +241,7 @@ private: | |||
/// A list of the serialization ID numbers for each of the top-level | /// A list of the serialization ID numbers for each of the top-level | ||
/// declarations parsed within the precompiled preamble. | /// declarations parsed within the precompiled preamble. | ||
- | + std::vector<LocalDeclID> TopLevelDeclsInPreamble; | ||
/// Whether we should be caching code-completion results. | /// Whether we should be caching code-completion results. | ||
bool ShouldCacheCodeC | bool ShouldCacheCodeC |
@@ -65,6 +65,9 @@ enum ActionKind { | |||
/// Translate input source into HTML. | /// Translate input source into HTML. | ||
EmitHTML, | EmitHTML, | ||
+ /// Emit a .cir file | |||
+ EmitCIR, | |||
+ | |||
/// Emit a .ll file. | /// Emit a .ll file. | ||
EmitLLVM, | EmitLLVM, | ||
@@ -408,6 +411,10 @@ public: | |||
LLVM_PREFERRED_T | LLVM_PREFERRED_T | ||
unsigned GenReducedBMI : 1; | unsigned GenReducedBMI : 1; | ||
+ /// Use Clang IR pipeline to emit code | |||
+ LLVM_PREFERRED_T | |||
+ unsigned UseClangIRPipeli | |||
+ | |||
CodeCompleteOpti | CodeCompleteOpti | ||
/// Specifies the output format of the AST. | /// Specifies the output format of the AST. | ||
@@ -590,7 +597,7 @@ public: | |||
EmitSymbolGraph(false), EmitExtensionSym | EmitSymbolGraph(false), EmitExtensionSym | ||
EmitSymbolGraphS | EmitSymbolGraphS | ||
EmitPrettySymbol | EmitPrettySymbol | ||
- TimeTraceGranularity(500) {} | + UseClangIRPipeline(false), TimeTraceGranularity(500) {} | ||
/// getInputKindForE | /// getInputKindForE | ||
/// extension. For example, "c" would return Language::C. | /// extension. For example, "c" would return Language::C. |
@@ -35,7 +35,7 @@ public: | |||
void IdentifierRead(serialization::IdentID ID, IdentifierInfo *II) override; | void IdentifierRead(serialization::IdentID ID, IdentifierInfo *II) override; | ||
void MacroRead(serialization::MacroID ID, MacroInfo *MI) override; | void MacroRead(serialization::MacroID ID, MacroInfo *MI) override; | ||
void TypeRead(serialization::TypeIdx Idx, QualType T) override; | void TypeRead(serialization::TypeIdx Idx, QualType T) override; | ||
- void DeclRead( | + void DeclRead(GlobalDeclID ID, const Decl *D) override; | ||
void SelectorRead(serialization::SelectorID iD, Selector Sel) override; | void SelectorRead(serialization::SelectorID iD, Selector Sel) override; | ||
void MacroDefinitionR | void MacroDefinitionR | ||
MacroDefinitionR | MacroDefinitionR |
@@ -29,9 +29,10 @@ public: | |||
/// | /// | ||
/// \param InputBuffer JSON input data. | /// \param InputBuffer JSON input data. | ||
/// \param Destination Container to load headers into. | /// \param Destination Container to load headers into. | ||
+ /// \param FM Optional File Manager to validate input files exist. | |||
static llvm::Error | static llvm::Error | ||
loadHeaders(std::unique_ptr<llvm::MemoryBuffer> InputBuffer, | loadHeaders(std::unique_ptr<llvm::MemoryBuffer> InputBuffer, | ||
- HeaderSeq &Destination); | + HeaderSeq &Destination, clang::FileManager *FM = nullptr); | ||
FileListReader() = delete; | FileListReader() = delete; | ||
}; | }; |
@@ -1398,12 +1398,21 @@ private: | |||
// A list of late-parsed attributes. Used by ParseGNUAttribut | // A list of late-parsed attributes. Used by ParseGNUAttribut | ||
class LateParsedAttrLi | class LateParsedAttrLi | ||
public: | public: | ||
- LateParsedAttrList(bool PSoon = false | + LateParsedAttrList(bool PSoon = false, | ||
+ bool LateAttrParseExp | |||
+ : ParseSoon(PSoon), | |||
+ LateAttrParseExp | |||
bool parseSoon() { return ParseSoon; } | bool parseSoon() { return ParseSoon; } | ||
+ /// returns true iff the attribute to be parsed should only be late parsed | |||
+ /// if it is annotated with `LateAttrParseExp | |||
+ bool lateAttrParseExp | |||
+ return LateAttrParseExp | |||
+ } | |||
private: | private: | ||
- bool ParseSoon; | + bool ParseSoon; // Are we planning to parse these shortly after creation? | ||
+ bool LateAttrParseExp | |||
}; | }; | ||
/// Contains the lexed tokens of a member function definition | /// Contains the lexed tokens of a member function definition | ||
@@ -3645,11 +3654,12 @@ private: | |||
ExprResult ParseOpenACCIDEx | ExprResult ParseOpenACCIDEx | ||
/// Parses the variable list for the `cache` construct. | /// Parses the variable list for the `cache` construct. | ||
void ParseOpenACCCach | void ParseOpenACCCach | ||
+ | |||
+ using OpenACCVarParseR | |||
/// Parses a single variable in a variable list for OpenACC. | /// Parses a single variable in a variable list for OpenACC. | ||
- bool ParseOpenACCVar(); | + OpenACCVarParseR | ||
- /// Parses the variable list for the variety of | + /// Parses the variable list for the variety of places that take a var-list. | ||
- /// including the optional Special Token listed for some,based on clause type. | + llvm::SmallVector<Expr *> ParseOpenACCVarL | ||
- bool ParseOpenACCClau | |||
/// Parses any parameters for an OpenACC Clause, including required/optional | /// Parses any parameters for an OpenACC Clause, including required/optional | ||
/// parens. | /// parens. | ||
OpenACCClausePar | OpenACCClausePar |
@@ -36,6 +36,7 @@ | |||
#include "llvm/ADT/SmallVector.h" | #include "llvm/ADT/SmallVector.h" | ||
#include "llvm/Support/Compiler.h" | #include "llvm/Support/Compiler.h" | ||
#include "llvm/Support/ErrorHandling.h" | #include "llvm/Support/ErrorHandling.h" | ||
+#include <optional> | |||
namespace clang { | namespace clang { | ||
class ASTContext; | class ASTContext; | ||
@@ -1790,6 +1791,7 @@ public: | |||
struct Binding { | struct Binding { | ||
IdentifierInfo *Name; | IdentifierInfo *Name; | ||
SourceLocation NameLoc; | SourceLocation NameLoc; | ||
+ std::optional<ParsedAttributes | |||
}; | }; | ||
private: | private: | ||
@@ -1809,15 +1811,15 @@ public: | |||
: Bindings(nullptr), NumBindings(0), DeleteBindings(false) {} | : Bindings(nullptr), NumBindings(0), DeleteBindings(false) {} | ||
DecompositionDec | DecompositionDec | ||
DecompositionDec | DecompositionDec | ||
- ~DecompositionDeclarator() { | + ~DecompositionDeclarator() { clear(); } | ||
- if (DeleteBindings) | |||
- delete[] Bindings; | |||
- } | |||
void clear() { | void clear() { | ||
LSquareLoc = RSquareLoc = SourceLocation(); | LSquareLoc = RSquareLoc = SourceLocation(); | ||
if (DeleteBindings) | if (DeleteBindings) | ||
delete[] Bindings; | delete[] Bindings; | ||
+ else | |||
+ llvm::for_each(llvm::MutableArrayRef(Bindings, NumBindings), | |||
+ [](Binding &B) { B.Attrs.reset(); }); | |||
Bindings = nullptr; | Bindings = nullptr; | ||
NumBindings = 0; | NumBindings = 0; | ||
DeleteBindings = false; | DeleteBindings = false; | ||
@@ -2339,10 +2341,10 @@ public: | |||
} | } | ||
/// Set the decomposition bindings for this declarator. | /// Set the decomposition bindings for this declarator. | ||
- void | + void setDecomposition | ||
- setDecomposition | + SourceLocation LSquareLoc, | ||
- | + MutableArrayRef<DecompositionDeclarator::Binding> Bindings, | ||
- | + SourceLocation RSquareLoc); | ||
/// AddTypeInfo - Add a chunk to this declarator. Also extend the range to | /// AddTypeInfo - Add a chunk to this declarator. Also extend the range to | ||
/// EndLoc, which should be the last token of the chunk. | /// EndLoc, which should be the last token of the chunk. |
@@ -499,7 +499,9 @@ public: | |||
/// Note that while no result was found in the current instantiation, | /// Note that while no result was found in the current instantiation, | ||
/// there were dependent base classes that could not be searched. | /// there were dependent base classes that could not be searched. | ||
void setNotFoundInCur | void setNotFoundInCur | ||
- assert(ResultKind == NotFound | + assert((ResultKind == NotFound || | ||
+ ResultKind == NotFoundInCurren | |||
+ Decls.empty()); | |||
ResultKind = NotFoundInCurren | ResultKind = NotFoundInCurren | ||
} | } | ||
@@ -65,7 +65,7 @@ public: | |||
/// Resolve a declaration ID into a declaration, potentially | /// Resolve a declaration ID into a declaration, potentially | ||
/// building a new declaration. | /// building a new declaration. | ||
- Decl *GetExternalDecl( | + Decl *GetExternalDecl(GlobalDeclID ID) override; | ||
/// Complete the redeclaration chain if it's been extended since the | /// Complete the redeclaration chain if it's been extended since the | ||
/// previous generation of the AST source. | /// previous generation of the AST source. |
@@ -948,6 +948,7 @@ public: | |||
ParsedAttributes | ParsedAttributes | ||
ParsedAttributes | ParsedAttributes | ||
ParsedAttributes | ParsedAttributes | ||
+ ParsedAttributes | |||
AttributePool &getPool() const { return pool; } | AttributePool &getPool() const { return pool; } | ||
@@ -4097,12 +4097,12 @@ public: | |||
SmallVectorImpl<QualType> &Exceptions, | SmallVectorImpl<QualType> &Exceptions, | ||
FunctionProtoTyp | FunctionProtoTyp | ||
- /// Add an exception-specification to the given member function | + /// Add an exception-specification to the given member or friend function | ||
- /// (or | + /// (or function template). The exception-specification was parsed | ||
- /// after the | + /// after the function itself was declared. | ||
void actOnDelayedExce | void actOnDelayedExce | ||
- Decl * | + Decl *D, ExceptionSpecificationType EST, SourceRange SpecificationRange, | ||
- | + ArrayRef<ParsedType> DynamicExceptions, | ||
ArrayRef<SourceRange> DynamicException | ArrayRef<SourceRange> DynamicException | ||
class InheritedConstru | class InheritedConstru | ||
@@ -6978,12 +6978,6 @@ public: | |||
SourceLocation TemplateKWLoc, | SourceLocation TemplateKWLoc, | ||
UnqualifiedId &Member, Decl *ObjCImpDecl); | UnqualifiedId &Member, Decl *ObjCImpDecl); | ||
- MemberExpr *BuildMemberExpr( | |||
- Expr *Base, bool IsArrow, SourceLocation OpLoc, const CXXScopeSpec *SS, | |||
- SourceLocation TemplateKWLoc, ValueDecl *Member, DeclAccessPair FoundDecl, | |||
- bool HadMultipleCandi | |||
- QualType Ty, ExprValueKind VK, ExprObjectKind OK, | |||
- const TemplateArgument | |||
MemberExpr * | MemberExpr * | ||
BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc, | BuildMemberExpr(Expr *Base, bool IsArrow, SourceLocation OpLoc, | ||
NestedNameSpecif | NestedNameSpecif | ||
@@ -7472,7 +7466,7 @@ public: | |||
bool LookupQualifiedN | bool LookupQualifiedN | ||
CXXScopeSpec &SS); | CXXScopeSpec &SS); | ||
bool LookupParsedName | bool LookupParsedName | ||
- bool AllowBuiltinCreation = false, | + QualType ObjectType, bool AllowBuiltinCreation = false, | ||
bool EnteringContext = false); | bool EnteringContext = false); | ||
ObjCProtocolDecl | ObjCProtocolDecl | ||
IdentifierInfo *II, SourceLocation IdLoc, | IdentifierInfo *II, SourceLocation IdLoc, | ||
@@ -8881,11 +8875,13 @@ public: | |||
/// functions (but no function templates). | /// functions (but no function templates). | ||
FoundFunctions, | FoundFunctions, | ||
}; | }; | ||
- bool LookupTemplateNa | + | ||
- LookupResult &R, Scope *S, CXXScopeSpec &SS, QualType ObjectType, | + bool | ||
- bool EnteringContext, | + LookupTemplateNa | ||
- RequiredTemplate | + QualType ObjectType, bool EnteringContext, | ||
- AssumedTemplateK | + RequiredTemplate | ||
+ AssumedTemplateK | |||
+ bool AllowTypoCorrect | |||
TemplateNameKind | TemplateNameKind | ||
bool hasTemplateKeywo | bool hasTemplateKeywo | ||
@@ -9249,7 +9245,8 @@ public: | |||
void NoteTemplatePara | void NoteTemplatePara | ||
ExprResult BuildExpressionF | ExprResult BuildExpressionF | ||
- const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc | + const TemplateArgument &Arg, QualType ParamType, SourceLocation Loc, | ||
+ NamedDecl *TemplateParam = nullptr); | |||
ExprResult | ExprResult | ||
BuildExpressionF | BuildExpressionF | ||
SourceLocation Loc); | SourceLocation Loc); | ||
@@ -9572,9 +9569,10 @@ public: | |||
bool isSameOrCompatib | bool isSameOrCompatib | ||
- TemplateArgumentLoc | + TemplateArgumentLoc | ||
- QualType NTTPType, | + getTrivialTempla | ||
- | + SourceLocation Loc, | ||
+ NamedDecl *TemplateParam = nullptr); | |||
/// Get a template argument mapping the given template parameter to itself, | /// Get a template argument mapping the given template parameter to itself, | ||
/// e.g. for X in \c template<int X>, this would return an expression template | /// e.g. for X in \c template<int X>, this would return an expression template |
@@ -48,8 +48,12 @@ public: | |||
SmallVector<Expr *> IntExprs; | SmallVector<Expr *> IntExprs; | ||
}; | }; | ||
+ struct VarListDetails { | |||
+ SmallVector<Expr *> VarList; | |||
+ }; | |||
+ | |||
std::variant<std::monostate, DefaultDetails, ConditionDetails | std::variant<std::monostate, DefaultDetails, ConditionDetails | ||
- | + IntExprDetails, VarListDetails> | ||
Details = std::monostate{}; | Details = std::monostate{}; | ||
public: | public: | ||
@@ -112,6 +116,16 @@ public: | |||
return const_cast<OpenACCParsedCla | return const_cast<OpenACCParsedCla | ||
} | } | ||
+ ArrayRef<Expr *> getVarList() { | |||
+ assert(ClauseKind == OpenACCClauseKin | |||
+ "Parsed clause kind does not have a var-list"); | |||
+ return std::get<VarListDetails>(Details).VarList; | |||
+ } | |||
+ | |||
+ ArrayRef<Expr *> getVarList() const { | |||
+ return const_cast<OpenACCParsedCla | |||
+ } | |||
+ | |||
void setLParenLoc(SourceLocation EndLoc) { LParenLoc = EndLoc; } | void setLParenLoc(SourceLocation EndLoc) { LParenLoc = EndLoc; } | ||
void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); } | void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); } | ||
@@ -147,7 +161,19 @@ public: | |||
ClauseKind == OpenACCClauseKin | ClauseKind == OpenACCClauseKin | ||
ClauseKind == OpenACCClauseKin | ClauseKind == OpenACCClauseKin | ||
"Parsed clause kind does not have a int exprs"); | "Parsed clause kind does not have a int exprs"); | ||
- Details = IntExprDetails{IntExprs}; | + Details = IntExprDetails{std::move(IntExprs)}; | ||
+ } | |||
+ | |||
+ void setVarListDetail | |||
+ assert(ClauseKind == OpenACCClauseKin | |||
+ "Parsed clause kind does not have a var-list"); | |||
+ Details = VarListDetails{{VarList.begin(), VarList.end()}}; | |||
+ } | |||
+ | |||
+ void setVarListDetail | |||
+ assert(ClauseKind == OpenACCClauseKin | |||
+ "Parsed clause kind does not have a var-list"); | |||
+ Details = VarListDetails{std::move(VarList)}; | |||
} | } | ||
}; | }; | ||
@@ -193,6 +219,16 @@ public: | |||
/// conversions and diagnostics to 'int'. | /// conversions and diagnostics to 'int'. | ||
ExprResult ActOnIntExpr(OpenACCDirective | ExprResult ActOnIntExpr(OpenACCDirective | ||
SourceLocation Loc, Expr *IntExpr); | SourceLocation Loc, Expr *IntExpr); | ||
+ | |||
+ /// Called when encountering a 'var' for OpenACC, ensures it is actually a | |||
+ /// declaration reference to a variable of the correct type. | |||
+ ExprResult ActOnVar(Expr *VarExpr); | |||
+ | |||
+ /// Checks and creates an Array Section used in an OpenACC construct/clause. | |||
+ ExprResult ActOnArraySectio | |||
+ Expr *LowerBound, | |||
+ SourceLocation ColonLocFirst, Expr *Length, | |||
+ SourceLocation RBLoc); | |||
}; | }; | ||
} // namespace clang | } // namespace clang |
@@ -17,6 +17,7 @@ | |||
#ifndef LLVM_CLANG_SERIA | #ifndef LLVM_CLANG_SERIA | ||
#define LLVM_CLANG_SERIA | #define LLVM_CLANG_SERIA | ||
+#include "clang/AST/DeclID.h" | |||
#include "clang/AST/DeclarationName.h" | #include "clang/AST/DeclarationName.h" | ||
#include "clang/AST/Type.h" | #include "clang/AST/Type.h" | ||
#include "clang/Basic/IdentifierTable.h" | #include "clang/Basic/IdentifierTable.h" | ||
@@ -59,91 +60,9 @@ const unsigned VERSION_MINOR = 1; | |||
/// and start at 1. 0 is reserved for NULL. | /// and start at 1. 0 is reserved for NULL. | ||
using IdentifierID = uint32_t; | using IdentifierID = uint32_t; | ||
-/// An ID number that refers to a declaration in an AST file. | +/// An ID number that refers to a declaration in an AST file. See the comments | ||
-/// | +/// in DeclIDBase for details. | ||
-/// The ID numbers of declarations are consecutive (in order of | +using DeclID = DeclIDBase::DeclID; | ||
-/// discovery), with values below NUM_PREDEF_DECL_ | |||
-/// At the start of a chain of precompiled headers, declaration ID 1 is | |||
-/// used for the translation unit declaration. | |||
-/// | |||
-/// FIXME: Merge with Decl::DeclID | |||
-using DeclID = uint32_t; | |||
- | |||
-class LocalDeclID { | |||
-public: | |||
- explicit LocalDeclID(DeclID ID) : ID(ID) {} | |||
- | |||
- DeclID get() const { return ID; } | |||
- | |||
-private: | |||
- DeclID ID; | |||
-}; | |||
- | |||
-/// Wrapper class for DeclID. This is helpful to not mix the use of LocalDeclID | |||
-/// and GlobalDeclID to improve the type safety. | |||
-class GlobalDeclID { | |||
-public: | |||
- GlobalDeclID() : ID(0) {} | |||
- explicit GlobalDeclID(DeclID ID) : ID(ID) {} | |||
- | |||
- DeclID get() const { return ID; } | |||
- | |||
- explicit operator DeclID() const { return ID; } | |||
- | |||
- friend bool operator==(const GlobalDeclID &LHS, const GlobalDeclID &RHS) { | |||
- return LHS.ID == RHS.ID; | |||
- } | |||
- friend bool operator!=(const GlobalDeclID &LHS, const GlobalDeclID &RHS) { | |||
- return LHS.ID != RHS.ID; | |||
- } | |||
- // We may sort the global decl ID. | |||
- friend bool operator<(const GlobalDeclID &LHS, const GlobalDeclID &RHS) { | |||
- return LHS.ID < RHS.ID; | |||
- } | |||
- friend bool operator>(const GlobalDeclID &LHS, const GlobalDeclID &RHS) { | |||
- return LHS.ID > RHS.ID; | |||
- } | |||
- friend bool operator<=(const GlobalDeclID &LHS, const GlobalDeclID &RHS) { | |||
- return LHS.ID <= RHS.ID; | |||
- } | |||
- friend bool operator>=(const GlobalDeclID &LHS, const GlobalDeclID &RHS) { | |||
- return LHS.ID >= RHS.ID; | |||
- } | |||
- | |||
-private: | |||
- DeclID ID; | |||
-}; | |||
- | |||
-/// A helper iterator adaptor to convert the iterators to `SmallVector<DeclID>` | |||
-/// to the iterators to `SmallVector<GlobalDeclID>`. | |||
-class GlobalDeclIDIter | |||
- : public llvm::iterator_adaptor | |||
- std::forward_iterator | |||
- GlobalDeclID> { | |||
-public: | |||
- GlobalDeclIDIter | |||
- | |||
- GlobalDeclIDIter | |||
- | |||
- value_type operator*() const { return GlobalDeclID(*I); } | |||
- | |||
- bool operator==(const GlobalDeclIDIter | |||
-}; | |||
- | |||
-/// A helper iterator adaptor to convert the iterators to | |||
-/// `SmallVector<GlobalDeclID>` to the iterators to `SmallVector<DeclID>`. | |||
-class DeclIDIterator | |||
- : public llvm::iterator_adaptor | |||
- std::forward_iterator | |||
-public: | |||
- DeclIDIterator() : iterator_adaptor | |||
- | |||
- DeclIDIterator(const GlobalDeclID *ID) : iterator_adaptor | |||
- | |||
- value_type operator*() const { return DeclID(*I); } | |||
- | |||
- bool operator==(const DeclIDIterator &RHS) const { return I == RHS.I; } | |||
-}; | |||
/// An ID number that refers to a type in an AST file. | /// An ID number that refers to a type in an AST file. | ||
/// | /// | ||
@@ -1054,8 +973,8 @@ enum PredefinedTypeID | |||
/// OpenCL reserve_id type. | /// OpenCL reserve_id type. | ||
PREDEF_TYPE_RESE | PREDEF_TYPE_RESE | ||
- /// The placeholder type for | + /// The placeholder type for an array section. | ||
- | + PREDEF_TYPE_ARRAY_SECTION = 42, | ||
/// The '__float128' type | /// The '__float128' type | ||
PREDEF_TYPE_FLOA | PREDEF_TYPE_FLOA | ||
@@ -1238,74 +1157,6 @@ enum SpecialTypeIDs { | |||
/// The number of special type IDs. | /// The number of special type IDs. | ||
const unsigned NumSpecialTypeID | const unsigned NumSpecialTypeID | ||
-/// Predefined declaration IDs. | |||
-/// | |||
-/// These declaration IDs correspond to predefined declarations in the AST | |||
-/// context, such as the NULL declaration ID. Such declarations are never | |||
-/// actually serialized, since they will be built by the AST context when | |||
-/// it is created. | |||
-enum PredefinedDeclID | |||
- /// The NULL declaration. | |||
- PREDEF_DECL_NULL | |||
- | |||
- /// The translation unit. | |||
- PREDEF_DECL_TRAN | |||
- | |||
- /// The Objective-C 'id' type. | |||
- PREDEF_DECL_OBJC | |||
- | |||
- /// The Objective-C 'SEL' type. | |||
- PREDEF_DECL_OBJC | |||
- | |||
- /// The Objective-C 'Class' type. | |||
- PREDEF_DECL_OBJC | |||
- | |||
- /// The Objective-C 'Protocol' type. | |||
- PREDEF_DECL_OBJC | |||
- | |||
- /// The signed 128-bit integer type. | |||
- PREDEF_DECL_INT_ | |||
- | |||
- /// The unsigned 128-bit integer type. | |||
- PREDEF_DECL_UNSI | |||
- | |||
- /// The internal 'instancetype' typedef. | |||
- PREDEF_DECL_OBJC | |||
- | |||
- /// The internal '__builtin_va_lis | |||
- PREDEF_DECL_BUIL | |||
- | |||
- /// The internal '__va_list_tag' struct, if any. | |||
- PREDEF_DECL_VA_L | |||
- | |||
- /// The internal '__builtin_ms_va_ | |||
- PREDEF_DECL_BUIL | |||
- | |||
- /// The predeclared '_GUID' struct. | |||
- PREDEF_DECL_BUIL | |||
- | |||
- /// The extern "C" context. | |||
- PREDEF_DECL_EXTE | |||
- | |||
- /// The internal '__make_integer_s | |||
- PREDEF_DECL_MAKE | |||
- | |||
- /// The internal '__NSConstantStri | |||
- PREDEF_DECL_CF_C | |||
- | |||
- /// The internal '__NSConstantStri | |||
- PREDEF_DECL_CF_C | |||
- | |||
- /// The internal '__type_pack_elem | |||
- PREDEF_DECL_TYPE | |||
-}; | |||
- | |||
-/// The number of declaration IDs that are predefined. | |||
-/// | |||
-/// For more information about predefined declarations, see the | |||
-/// \c PredefinedDeclID | |||
-const unsigned int NUM_PREDEF_DECL_ | |||
- | |||
/// Record of updates for a declaration that was modified after | /// Record of updates for a declaration that was modified after | ||
/// being deserialized. This can occur within DECLTYPES_BLOCK_ | /// being deserialized. This can occur within DECLTYPES_BLOCK_ | ||
const unsigned int DECL_UPDATES = 49; | const unsigned int DECL_UPDATES = 49; | ||
@@ -2075,7 +1926,7 @@ enum StmtCode { | |||
STMT_OMP_TARGET_ | STMT_OMP_TARGET_ | ||
STMT_OMP_PARALLE | STMT_OMP_PARALLE | ||
STMT_OMP_TARGET_ | STMT_OMP_TARGET_ | ||
- | + EXPR_ARRAY_SECTION, | ||
EXPR_OMP_ARRAY_S | EXPR_OMP_ARRAY_S | ||
EXPR_OMP_ITERATO | EXPR_OMP_ITERATO | ||
@@ -2132,7 +1983,7 @@ enum CleanupObjectKin | |||
/// Describes the categories of an Objective-C class. | /// Describes the categories of an Objective-C class. | ||
struct ObjCCategoriesIn | struct ObjCCategoriesIn | ||
// The ID of the definition | // The ID of the definition | ||
- | + LocalDeclID DefinitionID; | ||
// Offset into the array of category lists. | // Offset into the array of category lists. | ||
unsigned Offset; | unsigned Offset; | ||
@@ -2231,27 +2082,6 @@ template <> struct DenseMapInfo<cla | |||
} | } | ||
}; | }; | ||
-template <> struct DenseMapInfo<clang::serialization::GlobalDeclID> { | |||
- using DeclID = clang::serialization::DeclID; | |||
- using GlobalDeclID = clang::serialization::GlobalDeclID; | |||
- | |||
- static GlobalDeclID getEmptyKey() { | |||
- return GlobalDeclID(DenseMapInfo<DeclID>::getEmptyKey()); | |||
- } | |||
- | |||
- static GlobalDeclID getTombstoneKey() { | |||
- return GlobalDeclID(DenseMapInfo<DeclID>::getTombstoneKey()); | |||
- } | |||
- | |||
- static unsigned getHashValue(const GlobalDeclID &Key) { | |||
- return DenseMapInfo<DeclID>::getHashValue(Key.get()); | |||
- } | |||
- | |||
- static bool isEqual(const GlobalDeclID &L, const GlobalDeclID &R) { | |||
- return L == R; | |||
- } | |||
-}; | |||
- | |||
} // namespace llvm | } // namespace llvm | ||
#endif // LLVM_CLANG_SERIA | #endif // LLVM_CLANG_SERIA |
@@ -44,7 +44,7 @@ public: | |||
/// unqualified. | /// unqualified. | ||
virtual void TypeRead(serialization::TypeIdx Idx, QualType T) { } | virtual void TypeRead(serialization::TypeIdx Idx, QualType T) { } | ||
/// A decl was deserialized from the AST file. | /// A decl was deserialized from the AST file. | ||
- virtual void DeclRead( | + virtual void DeclRead(GlobalDeclID ID, const Decl *D) {} | ||
/// A selector was read from the AST file. | /// A selector was read from the AST file. | ||
virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) {} | virtual void SelectorRead(serialization::SelectorID iD, Selector Sel) {} | ||
/// A macro definition was read from the AST file. | /// A macro definition was read from the AST file. |
@@ -501,10 +501,7 @@ private: | |||
/// = I + 1 has already been loaded. | /// = I + 1 has already been loaded. | ||
llvm::PagedVector<Decl *> DeclsLoaded; | llvm::PagedVector<Decl *> DeclsLoaded; | ||
- static_assert(std::is_same_v<serialization::DeclID, Decl::DeclID>); | + using GlobalDeclMapTyp | ||
- | |||
- using GlobalDeclMapTyp | |||
- ContinuousRangeM | |||
/// Mapping from global declaration IDs to the module in which the | /// Mapping from global declaration IDs to the module in which the | ||
/// declaration resides. | /// declaration resides. | ||
@@ -512,16 +509,15 @@ private: | |||
using FileOffset = std::pair<ModuleFile *, uint64_t>; | using FileOffset = std::pair<ModuleFile *, uint64_t>; | ||
using FileOffsetsTy = SmallVector<FileOffset, 2>; | using FileOffsetsTy = SmallVector<FileOffset, 2>; | ||
- using DeclUpdateOffsetsMap = | + using DeclUpdateOffsetsMap = llvm::DenseMap<GlobalDeclID, FileOffsetsTy>; | ||
- llvm::DenseMap<serialization::GlobalDeclID, FileOffsetsTy>; | |||
/// Declarations that have modifications residing in a later file | /// Declarations that have modifications residing in a later file | ||
/// in the chain. | /// in the chain. | ||
DeclUpdateOffset | DeclUpdateOffset | ||
- using DelayedNamespaceOffsetMapTy = | + using DelayedNamespaceOffsetMapTy = | ||
- serialization::GlobalDeclID, | + llvm::DenseMap<GlobalDeclID, std::pair</*LexicalOffset*/ uint64_t, | ||
- std::pair</*LexicalOffset*/ uint64_t, /*VisibleOffset*/ uint64_t>>; | + /*VisibleOffset*/ uint64_t>>; | ||
/// Mapping from global declaration IDs to the lexical and visible block | /// Mapping from global declaration IDs to the lexical and visible block | ||
/// offset for delayed namespace in reduced BMI. | /// offset for delayed namespace in reduced BMI. | ||
@@ -535,13 +531,12 @@ private: | |||
struct PendingUpdateRec | struct PendingUpdateRec | ||
Decl *D; | Decl *D; | ||
- | + GlobalDeclID ID; | ||
// Whether the declaration was just deserialized. | // Whether the declaration was just deserialized. | ||
bool JustLoaded; | bool JustLoaded; | ||
- PendingUpdateRecord( | + PendingUpdateRecord(GlobalDeclID ID, Decl *D, bool JustLoaded) | ||
- bool JustLoaded) | |||
: D(D), ID(ID), JustLoaded(JustLoaded) {} | : D(D), ID(ID), JustLoaded(JustLoaded) {} | ||
}; | }; | ||
@@ -594,10 +589,10 @@ private: | |||
struct FileDeclsInfo { | struct FileDeclsInfo { | ||
ModuleFile *Mod = nullptr; | ModuleFile *Mod = nullptr; | ||
- | + ArrayRef<LocalDeclID> Decls; | ||
FileDeclsInfo() = default; | FileDeclsInfo() = default; | ||
- FileDeclsInfo(ModuleFile *Mod, | + FileDeclsInfo(ModuleFile *Mod, ArrayRef<LocalDeclID> Decls) | ||
: Mod(Mod), Decls(Decls) {} | : Mod(Mod), Decls(Decls) {} | ||
}; | }; | ||
@@ -635,8 +630,7 @@ private: | |||
/// Updates to the visible declarations of declaration contexts that | /// Updates to the visible declarations of declaration contexts that | ||
/// haven't been loaded yet. | /// haven't been loaded yet. | ||
- | + llvm::DenseMap<GlobalDeclID, DeclContextVisibleUpdates> PendingVisibleUpdates; | ||
- PendingVisibleUp | |||
/// The set of C++ or Objective-C classes that have forward | /// The set of C++ or Objective-C classes that have forward | ||
/// declarations that have not yet been linked to their definitions. | /// declarations that have not yet been linked to their definitions. | ||
@@ -662,8 +656,7 @@ private: | |||
/// Read the record that describes the visible contents of a DC. | /// Read the record that describes the visible contents of a DC. | ||
bool ReadVisibleDeclC | bool ReadVisibleDeclC | ||
llvm::BitstreamCursor &Cursor, | llvm::BitstreamCursor &Cursor, | ||
- uint64_t Offset, | + uint64_t Offset, GlobalDeclID ID); | ||
- serialization::GlobalDeclID ID); | |||
/// A vector containing identifiers that have already been | /// A vector containing identifiers that have already been | ||
/// loaded. | /// loaded. | ||
@@ -816,14 +809,14 @@ private: | |||
/// This contains the data loaded from all EAGERLY_DESERIAL | /// This contains the data loaded from all EAGERLY_DESERIAL | ||
/// in the chain. The referenced declarations are deserialized and passed to | /// in the chain. The referenced declarations are deserialized and passed to | ||
/// the consumer eagerly. | /// the consumer eagerly. | ||
- | + SmallVector<GlobalDeclID, 16> EagerlyDeserializedDecls; | ||
/// The IDs of all tentative definitions stored in the chain. | /// The IDs of all tentative definitions stored in the chain. | ||
/// | /// | ||
/// Sema keeps track of all tentative definitions in a TU because it has to | /// Sema keeps track of all tentative definitions in a TU because it has to | ||
/// complete them and pass them on to CodeGen. Thus, tentative definitions in | /// complete them and pass them on to CodeGen. Thus, tentative definitions in | ||
/// the PCH chain must be eagerly deserialized. | /// the PCH chain must be eagerly deserialized. | ||
- | + SmallVector<GlobalDeclID, 16> TentativeDefinitions; | ||
/// The IDs of all CXXRecordDecls stored in the chain whose VTables are | /// The IDs of all CXXRecordDecls stored in the chain whose VTables are | ||
/// used. | /// used. | ||
@@ -831,7 +824,7 @@ private: | |||
/// CodeGen has to emit VTables for these records, so they have to be eagerly | /// CodeGen has to emit VTables for these records, so they have to be eagerly | ||
/// deserialized. | /// deserialized. | ||
struct VTableUse { | struct VTableUse { | ||
- | + GlobalDeclID ID; | ||
SourceLocation::UIntTy RawLoc; | SourceLocation::UIntTy RawLoc; | ||
bool Used; | bool Used; | ||
}; | }; | ||
@@ -844,7 +837,7 @@ private: | |||
/// instantiation where the first value is the ID of the decl and the second | /// instantiation where the first value is the ID of the decl and the second | ||
/// is the instantiation location. | /// is the instantiation location. | ||
struct PendingInstantia | struct PendingInstantia | ||
- | + GlobalDeclID ID; | ||
SourceLocation::UIntTy RawLoc; | SourceLocation::UIntTy RawLoc; | ||
}; | }; | ||
SmallVector<PendingInstantia | SmallVector<PendingInstantia | ||
@@ -857,11 +850,11 @@ private: | |||
/// A snapshot of Sema's unused file-scoped variable tracking, for | /// A snapshot of Sema's unused file-scoped variable tracking, for | ||
/// generating warnings. | /// generating warnings. | ||
- | + SmallVector<GlobalDeclID, 16> UnusedFileScopedDecls; | ||
/// A list of all the delegating constructors we've seen, to diagnose | /// A list of all the delegating constructors we've seen, to diagnose | ||
/// cycles. | /// cycles. | ||
- | + SmallVector<GlobalDeclID, 4> DelegatingCtorDecls; | ||
/// Method selectors used in a @selector expression. Used for | /// Method selectors used in a @selector expression. Used for | ||
/// implementation of -Wselector. | /// implementation of -Wselector. | ||
@@ -874,7 +867,7 @@ private: | |||
/// The IDs of type aliases for ext_vectors that exist in the chain. | /// The IDs of type aliases for ext_vectors that exist in the chain. | ||
/// | /// | ||
/// Used by Sema for finding sugared names for ext_vectors in diagnostics. | /// Used by Sema for finding sugared names for ext_vectors in diagnostics. | ||
- | + SmallVector<GlobalDeclID, 4> ExtVectorDecls; | ||
//@} | //@} | ||
@@ -885,7 +878,7 @@ private: | |||
/// The IDs of all potentially unused typedef names in the chain. | /// The IDs of all potentially unused typedef names in the chain. | ||
/// | /// | ||
/// Sema tracks these to emit warnings. | /// Sema tracks these to emit warnings. | ||
- | + SmallVector<GlobalDeclID, 16> UnusedLocalTypedefNameCandidates; | ||
/// Our current depth in #pragma cuda force_host_devic | /// Our current depth in #pragma cuda force_host_devic | ||
/// macros. | /// macros. | ||
@@ -894,7 +887,7 @@ private: | |||
/// The IDs of the declarations Sema stores directly. | /// The IDs of the declarations Sema stores directly. | ||
/// | /// | ||
/// Sema tracks a few important decls, such as namespace std, directly. | /// Sema tracks a few important decls, such as namespace std, directly. | ||
- | + SmallVector<GlobalDeclID, 4> SemaDeclRefs; | ||
/// The IDs of the types ASTContext stores directly. | /// The IDs of the types ASTContext stores directly. | ||
/// | /// | ||
@@ -905,7 +898,7 @@ private: | |||
/// | /// | ||
/// The AST context tracks a few important decls, currently cudaConfigureCal | /// The AST context tracks a few important decls, currently cudaConfigureCal | ||
/// directly. | /// directly. | ||
- | + SmallVector<GlobalDeclID, 2> CUDASpecialDeclRefs; | ||
/// The floating point pragma option settings. | /// The floating point pragma option settings. | ||
SmallVector<uint64_t, 1> FPPragmaOptions; | SmallVector<uint64_t, 1> FPPragmaOptions; | ||
@@ -954,12 +947,12 @@ private: | |||
llvm::DenseMap<const Decl *, std::set<std::string>> OpenCLDeclExtMap | llvm::DenseMap<const Decl *, std::set<std::string>> OpenCLDeclExtMap | ||
/// A list of the namespaces we've seen. | /// A list of the namespaces we've seen. | ||
- | + SmallVector<GlobalDeclID, 4> KnownNamespaces; | ||
/// A list of undefined decls with internal linkage followed by the | /// A list of undefined decls with internal linkage followed by the | ||
/// SourceLocation of a matching ODR-use. | /// SourceLocation of a matching ODR-use. | ||
struct UndefinedButUsed | struct UndefinedButUsed | ||
- | + GlobalDeclID ID; | ||
SourceLocation::UIntTy RawLoc; | SourceLocation::UIntTy RawLoc; | ||
}; | }; | ||
SmallVector<UndefinedButUsed | SmallVector<UndefinedButUsed | ||
@@ -974,8 +967,7 @@ private: | |||
/// The IDs of all decls to be checked for deferred diags. | /// The IDs of all decls to be checked for deferred diags. | ||
/// | /// | ||
/// Sema tracks these to emit deferred diags. | /// Sema tracks these to emit deferred diags. | ||
- | + llvm::SmallSetVector<GlobalDeclID, 4> DeclsToCheckForDeferredDiags; | ||
- DeclsToCheckForD | |||
private: | private: | ||
struct ImportedSubmodul | struct ImportedSubmodul | ||
@@ -1112,7 +1104,7 @@ private: | |||
/// | /// | ||
/// The declarations on the identifier chain for these identifiers will be | /// The declarations on the identifier chain for these identifiers will be | ||
/// loaded once the recursive loading has completed. | /// loaded once the recursive loading has completed. | ||
- llvm::MapVector<IdentifierInfo *, | + llvm::MapVector<IdentifierInfo *, SmallVector<GlobalDeclID, 4>> | ||
PendingIdentifie | PendingIdentifie | ||
/// The set of lookup results that we have faked in order to support | /// The set of lookup results that we have faked in order to support | ||
@@ -1157,8 +1149,8 @@ private: | |||
/// been loaded but its DeclContext was not set yet. | /// been loaded but its DeclContext was not set yet. | ||
struct PendingDeclConte | struct PendingDeclConte | ||
Decl *D; | Decl *D; | ||
- | + GlobalDeclID SemaDC; | ||
- | + GlobalDeclID LexicalDC; | ||
}; | }; | ||
/// The set of Decls that have been loaded but their DeclContexts are | /// The set of Decls that have been loaded but their DeclContexts are | ||
@@ -1239,8 +1231,7 @@ private: | |||
/// module is loaded. | /// module is loaded. | ||
SmallVector<ObjCInterfaceDec | SmallVector<ObjCInterfaceDec | ||
- using KeyDeclsMap = | + using KeyDeclsMap = llvm::DenseMap<Decl *, SmallVector<GlobalDeclID, 2>>; | ||
- llvm::DenseMap<Decl *, SmallVector<serialization::GlobalDeclID, 2>>; | |||
/// A mapping from canonical declarations to the set of global | /// A mapping from canonical declarations to the set of global | ||
/// declaration IDs for key declaration that have been merged with that | /// declaration IDs for key declaration that have been merged with that | ||
@@ -1449,7 +1440,7 @@ private: | |||
QualType readTypeRecord(unsigned Index); | QualType readTypeRecord(unsigned Index); | ||
RecordLocation TypeCursorForInd | RecordLocation TypeCursorForInd | ||
void LoadedDecl(unsigned Index, Decl *D); | void LoadedDecl(unsigned Index, Decl *D); | ||
- Decl *ReadDeclRecord( | + Decl *ReadDeclRecord(GlobalDeclID ID); | ||
void markIncompleteDe | void markIncompleteDe | ||
/// Returns the most recent declaration of a declaration (which must be | /// Returns the most recent declaration of a declaration (which must be | ||
@@ -1457,11 +1448,10 @@ private: | |||
/// merged into its redecl chain. | /// merged into its redecl chain. | ||
Decl *getMostRecentExi | Decl *getMostRecentExi | ||
- RecordLocation DeclCursorForID( | + RecordLocation DeclCursorForID(GlobalDeclID ID, SourceLocation &Location); | ||
- SourceLocation &Location); | |||
void loadDeclUpdateRe | void loadDeclUpdateRe | ||
void loadPendingDeclC | void loadPendingDeclC | ||
- void loadObjCCategories( | + void loadObjCCategories(GlobalDeclID ID, ObjCInterfaceDecl *D, | ||
unsigned PreviousGenerati | unsigned PreviousGenerati | ||
RecordLocation getLocalBitOffse | RecordLocation getLocalBitOffse | ||
@@ -1496,11 +1486,10 @@ private: | |||
unsigned ClientLoadCapabi | unsigned ClientLoadCapabi | ||
public: | public: | ||
- class ModuleDeclIterator | + class ModuleDeclIterator : public llvm::iterator_adaptor_base< | ||
- : public llvm::iterator_adaptor | + ModuleDeclIterat | ||
- ModuleDeclIterat | + std::random_access_it | ||
- std::random_access_it | + ptrdiff_t, const Decl *, const Decl *> { | ||
- const Decl *, const Decl *> { | |||
ASTReader *Reader = nullptr; | ASTReader *Reader = nullptr; | ||
ModuleFile *Mod = nullptr; | ModuleFile *Mod = nullptr; | ||
@@ -1508,7 +1497,7 @@ public: | |||
ModuleDeclIterat | ModuleDeclIterat | ||
ModuleDeclIterat | ModuleDeclIterat | ||
- const | + const LocalDeclID *Pos) | ||
: iterator_adaptor | : iterator_adaptor | ||
value_type operator*() const { | value_type operator*() const { | ||
@@ -1536,9 +1525,8 @@ private: | |||
void pushExternalDecl | void pushExternalDecl | ||
- void addPendingDeclContextInfo(Decl *D, | + void addPendingDeclContextInfo(Decl *D, GlobalDeclID SemaDC, | ||
- | + GlobalDeclID LexicalDC) { | ||
- serialization::GlobalDeclID LexicalDC) { | |||
assert(D); | assert(D); | ||
PendingDeclConte | PendingDeclConte | ||
PendingDeclConte | PendingDeclConte | ||
@@ -1916,38 +1904,36 @@ public: | |||
/// Map from a local declaration ID within a given module to a | /// Map from a local declaration ID within a given module to a | ||
/// global declaration ID. | /// global declaration ID. | ||
- serialization::GlobalDeclID | + GlobalDeclID getGlobalDeclID(ModuleFile &F, LocalDeclID LocalID) const; | ||
- getGlobalDeclID(ModuleFile &F, serialization::LocalDeclID LocalID) const; | |||
/// Returns true if global DeclID \p ID originated from module \p M. | /// Returns true if global DeclID \p ID originated from module \p M. | ||
- bool isDeclIDFromModule( | + bool isDeclIDFromModule(GlobalDeclID ID, ModuleFile &M) const; | ||
/// Retrieve the module file that owns the given declaration, or NULL | /// Retrieve the module file that owns the given declaration, or NULL | ||
/// if the declaration is not from a module file. | /// if the declaration is not from a module file. | ||
ModuleFile *getOwningModuleF | ModuleFile *getOwningModuleF | ||
/// Returns the source location for the decl \p ID. | /// Returns the source location for the decl \p ID. | ||
- SourceLocation getSourceLocationForDeclID( | + SourceLocation getSourceLocationForDeclID(GlobalDeclID ID); | ||
/// Resolve a declaration ID into a declaration, potentially | /// Resolve a declaration ID into a declaration, potentially | ||
/// building a new declaration. | /// building a new declaration. | ||
- Decl *GetDecl( | + Decl *GetDecl(GlobalDeclID ID); | ||
- Decl *GetExternalDecl( | + Decl *GetExternalDecl(GlobalDeclID ID) override; | ||
/// Resolve a declaration ID into a declaration. Return 0 if it's not | /// Resolve a declaration ID into a declaration. Return 0 if it's not | ||
/// been loaded yet. | /// been loaded yet. | ||
- Decl *GetExistingDecl( | + Decl *GetExistingDecl(GlobalDeclID ID); | ||
/// Reads a declaration with the given local ID in the given module. | /// Reads a declaration with the given local ID in the given module. | ||
- Decl *GetLocalDecl(ModuleFile &F, | + Decl *GetLocalDecl(ModuleFile &F, LocalDeclID LocalID) { | ||
return GetDecl(getGlobalDeclID(F, LocalID)); | return GetDecl(getGlobalDeclID(F, LocalID)); | ||
} | } | ||
/// Reads a declaration with the given local ID in the given module. | /// Reads a declaration with the given local ID in the given module. | ||
/// | /// | ||
/// \returns The requested declaration, casted to the given return type. | /// \returns The requested declaration, casted to the given return type. | ||
- template <typename T> | + template <typename T> T *GetLocalDeclAs(ModuleFile &F, LocalDeclID LocalID) { | ||
- T *GetLocalDeclAs(ModuleFile &F, serialization::LocalDeclID LocalID) { | |||
return cast_or_null<T>(GetLocalDecl(F, LocalID)); | return cast_or_null<T>(GetLocalDecl(F, LocalID)); | ||
} | } | ||
@@ -1956,16 +1942,15 @@ public: | |||
/// | /// | ||
/// \returns the global ID of the given declaration as known in the given | /// \returns the global ID of the given declaration as known in the given | ||
/// module file. | /// module file. | ||
- serialization::DeclID | + LocalDeclID mapGlobalIDToMod | ||
- mapGlobalIDToMod | + GlobalDeclID GlobalID); | ||
- serialization::GlobalDeclID GlobalID); | |||
/// Reads a declaration ID from the given position in a record in the | /// Reads a declaration ID from the given position in a record in the | ||
/// given module. | /// given module. | ||
/// | /// | ||
/// \returns The declaration ID read from the record, adjusted to a global ID. | /// \returns The declaration ID read from the record, adjusted to a global ID. | ||
- serialization::GlobalDeclID | + GlobalDeclID ReadDeclID(ModuleFile &F, const RecordData &Record, | ||
- ReadDeclID(ModuleFile &F, const RecordData &Record, unsigned &Idx); | + unsigned &Idx); | ||
/// Reads a declaration from the given position in a record in the | /// Reads a declaration from the given position in a record in the | ||
/// given module. | /// given module. | ||
@@ -2139,10 +2124,9 @@ public: | |||
void LoadSelector(Selector Sel); | void LoadSelector(Selector Sel); | ||
void SetIdentifierInf | void SetIdentifierInf | ||
- void SetGloballyVisibleDecls( | + void SetGloballyVisibleDecls(IdentifierInfo *II, | ||
- IdentifierInfo *II, | + const SmallVectorImpl<GlobalDeclID> &DeclIDs, | ||
- const SmallVectorImpl<serialization::GlobalDeclID> &DeclIDs, | + SmallVectorImpl<Decl *> *Decls = nullptr); | ||
- SmallVectorImpl<Decl *> *Decls = nullptr); | |||
/// Report a diagnostic. | /// Report a diagnostic. | ||
DiagnosticBuilde | DiagnosticBuilde | ||
@@ -2383,7 +2367,7 @@ public: | |||
// Contains the IDs for declarations that were requested before we have | // Contains the IDs for declarations that were requested before we have | ||
// access to a Sema object. | // access to a Sema object. | ||
- | + SmallVector<GlobalDeclID, 16> PreloadedDeclIDs; | ||
/// Retrieve the semantic analysis object used to analyze the | /// Retrieve the semantic analysis object used to analyze the | ||
/// translation unit in which the precompiled header is being | /// translation unit in which the precompiled header is being |
@@ -136,7 +136,7 @@ public: | |||
/// Reads a declaration with the given local ID in the given module. | /// Reads a declaration with the given local ID in the given module. | ||
/// | /// | ||
/// \returns The requested declaration, casted to the given return type. | /// \returns The requested declaration, casted to the given return type. | ||
- template <typename T> T *GetLocalDeclAs( | + template <typename T> T *GetLocalDeclAs(LocalDeclID LocalID) { | ||
return cast_or_null<T>(Reader->GetLocalDecl(*F, LocalID)); | return cast_or_null<T>(Reader->GetLocalDecl(*F, LocalID)); | ||
} | } | ||
@@ -182,9 +182,7 @@ public: | |||
/// Reads a declaration ID from the given position in this record. | /// Reads a declaration ID from the given position in this record. | ||
/// | /// | ||
/// \returns The declaration ID read from the record, adjusted to a global ID. | /// \returns The declaration ID read from the record, adjusted to a global ID. | ||
- serialization::GlobalDeclID readDeclID() { | + GlobalDeclID readDeclID() { return Reader->ReadDeclID(*F, Record, Idx); } | ||
- return Reader->ReadDeclID(*F, Record, Idx); | |||
- } | |||
/// Reads a declaration from the given position in a record in the | /// Reads a declaration from the given position in a record in the | ||
/// given module, advancing Idx. | /// given module, advancing Idx. | ||
@@ -271,6 +269,9 @@ public: | |||
/// Read an OpenMP children, advancing Idx. | /// Read an OpenMP children, advancing Idx. | ||
void readOMPChildren(OMPChildren *Data); | void readOMPChildren(OMPChildren *Data); | ||
+ /// Read a list of Exprs used for a var-list. | |||
+ llvm::SmallVector<Expr *> readOpenACCVarLi | |||
+ | |||
/// Read an OpenACC clause, advancing Idx. | /// Read an OpenACC clause, advancing Idx. | ||
OpenACCClause *readOpenACCClaus | OpenACCClause *readOpenACCClaus | ||
@@ -15,6 +15,7 @@ | |||
#define LLVM_CLANG_SERIA | #define LLVM_CLANG_SERIA | ||
#include "clang/AST/AbstractBasicWri | #include "clang/AST/AbstractBasicWri | ||
+#include "clang/AST/OpenACCClause.h" | |||
#include "clang/AST/OpenMPClause.h" | #include "clang/AST/OpenMPClause.h" | ||
#include "clang/Serialization/ASTWriter.h" | #include "clang/Serialization/ASTWriter.h" | ||
#include "clang/Serialization/SourceLocationEn | #include "clang/Serialization/SourceLocationEn | ||
@@ -293,6 +294,8 @@ public: | |||
/// Writes data related to the OpenMP directives. | /// Writes data related to the OpenMP directives. | ||
void writeOMPChildren | void writeOMPChildren | ||
+ void writeOpenACCVarL | |||
+ | |||
/// Writes out a single OpenACC Clause. | /// Writes out a single OpenACC Clause. | ||
void writeOpenACCClau | void writeOpenACCClau | ||
@@ -76,6 +76,10 @@ class StoredDeclsList; | |||
class SwitchCase; | class SwitchCase; | ||
class Token; | class Token; | ||
+namespace SrcMgr { | |||
+class FileInfo; | |||
+} // namespace SrcMgr | |||
+ | |||
/// Writes an AST file containing the contents of a translation unit. | /// Writes an AST file containing the contents of a translation unit. | ||
/// | /// | ||
/// The ASTWriter class produces a bitstream containing the serialized | /// The ASTWriter class produces a bitstream containing the serialized | ||
@@ -212,10 +216,10 @@ private: | |||
llvm::SmallVector<NamespaceDecl *, 16> DelayedNamespace | llvm::SmallVector<NamespaceDecl *, 16> DelayedNamespace | ||
/// The first ID number we can use for our own declarations. | /// The first ID number we can use for our own declarations. | ||
- serialization::DeclID FirstDeclID = serialization::NUM_PREDEF_DECL_ | + LocalDeclID FirstDeclID = LocalDeclID(clang::NUM_PREDEF_DECL_ | ||
/// The decl ID that will be assigned to the next new decl. | /// The decl ID that will be assigned to the next new decl. | ||
- | + LocalDeclID NextDeclID = FirstDeclID; | ||
/// Map that provides the ID numbers of each declaration within | /// Map that provides the ID numbers of each declaration within | ||
/// the output stream, as well as those deserialized from a chained PCH. | /// the output stream, as well as those deserialized from a chained PCH. | ||
@@ -223,7 +227,7 @@ private: | |||
/// The ID numbers of declarations are consecutive (in order of | /// The ID numbers of declarations are consecutive (in order of | ||
/// discovery) and start at 2. 1 is reserved for the translation | /// discovery) and start at 2. 1 is reserved for the translation | ||
/// unit, while 0 is reserved for NULL. | /// unit, while 0 is reserved for NULL. | ||
- llvm::DenseMap<const Decl *, | + llvm::DenseMap<const Decl *, LocalDeclID> DeclIDs; | ||
/// Offset of each declaration in the bitstream, indexed by | /// Offset of each declaration in the bitstream, indexed by | ||
/// the declaration's ID. | /// the declaration's ID. | ||
@@ -233,9 +237,8 @@ private: | |||
/// are relative to this value. | /// are relative to this value. | ||
uint64_t DeclTypesBlockSt | uint64_t DeclTypesBlockSt | ||
- /// Sorted (by file offset) vector of pairs of file offset/ | + /// Sorted (by file offset) vector of pairs of file offset/LocalDeclID. | ||
- using LocDeclIDsTy = | + using LocDeclIDsTy = SmallVector<std::pair<unsigned, LocalDeclID>, 64>; | ||
- SmallVector<std::pair<unsigned, serialization::DeclID>, 64>; | |||
struct DeclIDInFileInfo | struct DeclIDInFileInfo | ||
LocDeclIDsTy DeclIDs; | LocDeclIDsTy DeclIDs; | ||
@@ -250,7 +253,7 @@ private: | |||
/// that it contains. | /// that it contains. | ||
FileDeclIDsTy FileDeclIDs; | FileDeclIDsTy FileDeclIDs; | ||
- void associateDeclWithFile(const Decl *D, | + void associateDeclWithFile(const Decl *D, LocalDeclID); | ||
/// The first ID number we can use for our own types. | /// The first ID number we can use for our own types. | ||
serialization::TypeID FirstTypeID = serialization::NUM_PREDEF_TYPE_ | serialization::TypeID FirstTypeID = serialization::NUM_PREDEF_TYPE_ | ||
@@ -421,8 +424,8 @@ private: | |||
/// headers. The declarations themselves are stored as declaration | /// headers. The declarations themselves are stored as declaration | ||
/// IDs, since they will be written out to an EAGERLY_DESERIAL | /// IDs, since they will be written out to an EAGERLY_DESERIAL | ||
/// record. | /// record. | ||
- SmallVector<serialization::DeclID, 16> EagerlyDeseriali | + RecordData EagerlyDeseriali | ||
- SmallVector<serialization::DeclID, 16> ModularCodegenDe | + RecordData ModularCodegenDe | ||
/// DeclContexts that have received extensions since their serialized | /// DeclContexts that have received extensions since their serialized | ||
/// form. | /// form. | ||
@@ -491,6 +494,11 @@ private: | |||
/// during \c SourceManager serialization. | /// during \c SourceManager serialization. | ||
void computeNonAffect | void computeNonAffect | ||
+ /// Some affecting files can be included from files that are not affecting. | |||
+ /// This function erases source locations pointing into such files. | |||
+ SourceLocation getAffectingIncl | |||
+ const SrcMgr::FileInfo &File); | |||
+ | |||
/// Returns an adjusted \c FileID, accounting for any non-affecting input | /// Returns an adjusted \c FileID, accounting for any non-affecting input | ||
/// files. | /// files. | ||
FileID getAdjustedFileI | FileID getAdjustedFileI | ||
@@ -526,6 +534,7 @@ private: | |||
/// Calculate hash of the pcm content. | /// Calculate hash of the pcm content. | ||
std::pair<ASTFileSignature | std::pair<ASTFileSignature | ||
+ ASTFileSignature | |||
void WriteInputFiles(SourceManager &SourceMgr, HeaderSearchOpti | void WriteInputFiles(SourceManager &SourceMgr, HeaderSearchOpti | ||
void WriteSourceManag | void WriteSourceManag | ||
@@ -709,7 +718,7 @@ public: | |||
return false; | return false; | ||
auto I = DeclIDs.find(D); | auto I = DeclIDs.find(D); | ||
return (I == DeclIDs.end() || | return (I == DeclIDs.end() || | ||
- I->second >= | + I->second.get() >= clang::NUM_PREDEF_DECL_IDS); | ||
}; | }; | ||
/// Emit a reference to a declaration. | /// Emit a reference to a declaration. | ||
@@ -717,12 +726,13 @@ public: | |||
// Emit a reference to a declaration if the declaration was emitted. | // Emit a reference to a declaration if the declaration was emitted. | ||
void AddEmittedDeclRe | void AddEmittedDeclRe | ||
- /// Force a declaration to be emitted and get its ID | + /// Force a declaration to be emitted and get its local ID to the module file | ||
- serialization::DeclID GetDeclRef(const Decl *D); | + /// been writing. | ||
+ LocalDeclID GetDeclRef(const Decl *D); | |||
- /// Determine the declaration ID of an already-emitted | + /// Determine the local declaration ID of an already-emitted | ||
/// declaration. | /// declaration. | ||
- | + LocalDeclID getDeclID(const Decl *D); | ||
/// Whether or not the declaration got emitted. If not, it wouldn't be | /// Whether or not the declaration got emitted. If not, it wouldn't be | ||
/// emitted. | /// emitted. | ||
@@ -885,6 +895,8 @@ private: | |||
/// AST and semantic-analysis consumer that generates a | /// AST and semantic-analysis consumer that generates a | ||
/// precompiled header from the parsed source code. | /// precompiled header from the parsed source code. | ||
class PCHGenerator : public SemaConsumer { | class PCHGenerator : public SemaConsumer { | ||
+ void anchor() override; | |||
+ | |||
Preprocessor &PP; | Preprocessor &PP; | ||
std::string OutputFile; | std::string OutputFile; | ||
std::string isysroot; | std::string isysroot; | ||
@@ -928,17 +940,34 @@ public: | |||
bool hasEmittedPCH() const { return Buffer->IsComplete; } | bool hasEmittedPCH() const { return Buffer->IsComplete; } | ||
}; | }; | ||
-class | +class CXX20ModulesGenerator : public PCHGenerator { | ||
+ void anchor() override; | |||
+ | |||
protected: | protected: | ||
virtual Module *getEmittingModul | virtual Module *getEmittingModul | ||
+ CXX20ModulesGene | |||
+ StringRef OutputFile, bool GeneratingReduce | |||
+ | |||
public: | public: | ||
- | + CXX20ModulesGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache, | ||
- | + StringRef OutputFile) | ||
+ : CXX20ModulesGene | |||
+ /*GeneratingReduce | |||
void HandleTranslatio | void HandleTranslatio | ||
}; | }; | ||
+class ReducedBMIGenera | |||
+ void anchor() override; | |||
+ | |||
+public: | |||
+ ReducedBMIGenera | |||
+ StringRef OutputFile) | |||
+ : CXX20ModulesGene | |||
+ /*GeneratingReduce | |||
+}; | |||
+ | |||
/// If we can elide the definition of \param D in reduced BMI. | /// If we can elide the definition of \param D in reduced BMI. | ||
/// | /// | ||
/// Generally, we can elide the definition of a declaration if it won't affect | /// Generally, we can elide the definition of a declaration if it won't affect |
@@ -474,7 +474,7 @@ public: | |||
llvm::DenseMap<ModuleFile *, serialization::DeclID> GlobalToLocalDec | llvm::DenseMap<ModuleFile *, serialization::DeclID> GlobalToLocalDec | ||
/// Array of file-level DeclIDs sorted by file. | /// Array of file-level DeclIDs sorted by file. | ||
- const | + const LocalDeclID *FileSortedDecls = nullptr; | ||
unsigned NumFileSortedDec | unsigned NumFileSortedDec | ||
/// Array of category list location information within this | /// Array of category list location information within this |
@@ -563,6 +563,20 @@ def MismatchedDeallo | |||
Dependencies<[DynamicMemoryMod | Dependencies<[DynamicMemoryMod | ||
Documentation<HasDocumentation | Documentation<HasDocumentation | ||
+// This must appear before StdCLibraryFunct | |||
+def StreamChecker : Checker<"Stream">, | |||
+ HelpText<"Check stream handling functions">, | |||
+ WeakDependencies | |||
+ CheckerOptions<[ | |||
+ CmdLineOption<Boolean, | |||
+ "Pedantic", | |||
+ "If false, assume that stream operations which are often not " | |||
+ "checked for error do not fail.", | |||
+ "false", | |||
+ InAlpha> | |||
+ ]>, | |||
+ Documentation<HasDocumentation | |||
+ | |||
def StdCLibraryFunct | def StdCLibraryFunct | ||
HelpText<"Check for invalid arguments of C standard library functions, " | HelpText<"Check for invalid arguments of C standard library functions, " | ||
"and apply relations between arguments and return value">, | "and apply relations between arguments and return value">, | ||
@@ -581,7 +595,7 @@ def StdCLibraryFunct | |||
"true", | "true", | ||
InAlpha> | InAlpha> | ||
]>, | ]>, | ||
- WeakDependencies<[CallAndMessageChecker, NonNullParamChecker]>, | + WeakDependencies<[CallAndMessageChecker, NonNullParamChecker, StreamChecker]>, | ||
Documentation<HasDocumentation | Documentation<HasDocumentation | ||
def VforkChecker : Checker<"Vfork">, | def VforkChecker : Checker<"Vfork">, | ||
@@ -601,20 +615,6 @@ def PthreadLockCheck | |||
Dependencies<[PthreadLockBase]>, | Dependencies<[PthreadLockBase]>, | ||
Documentation<HasDocumentation | Documentation<HasDocumentation | ||
-def StreamChecker : Checker<"Stream">, | |||
- HelpText<"Check stream handling functions">, | |||
- WeakDependencies | |||
- CheckerOptions<[ | |||
- CmdLineOption<Boolean, | |||
- "Pedantic", | |||
- "If false, assume that stream operations which are often not " | |||
- "checked for error do not fail." | |||
- "fail.", | |||
- "false", | |||
- InAlpha> | |||
- ]>, | |||
- Documentation<HasDocumentation | |||
- | |||
def SimpleStreamChec | def SimpleStreamChec | ||
HelpText<"Check for misuses of stream APIs">, | HelpText<"Check for misuses of stream APIs">, | ||
Documentation<HasDocumentation | Documentation<HasDocumentation | ||
@@ -1628,6 +1628,7 @@ def TaintTesterCheck | |||
def StreamTesterChec | def StreamTesterChec | ||
HelpText<"Add test functions to StreamChecker for test and debugging " | HelpText<"Add test functions to StreamChecker for test and debugging " | ||
"purposes.">, | "purposes.">, | ||
+ WeakDependencies | |||
Documentation<NotDocumented>; | Documentation<NotDocumented>; | ||
def ErrnoTesterCheck | def ErrnoTesterCheck |
@@ -225,15 +225,11 @@ public: | |||
/// invalidated. This should include any regions explicitly invalidated | /// invalidated. This should include any regions explicitly invalidated | ||
/// even if they do not currently have bindings. Pass \c NULL if this | /// even if they do not currently have bindings. Pass \c NULL if this | ||
/// information will not be used. | /// information will not be used. | ||
- virtual StoreRef invalidateRegions( | + virtual StoreRef invalidateRegions( | ||
- ArrayRef<SVal> Values, | + Store store, ArrayRef<SVal> Values, const Expr *Ex, unsigned Count, | ||
- const Expr *E, unsigned Count, | + const LocationContext *LCtx, const CallEvent *Call, | ||
- const LocationContext *LCtx, | + InvalidatedSymbo | ||
- const CallEvent *Call, | + InvalidatedRegio | ||
- InvalidatedSymbo | |||
- RegionAndSymbolI | |||
- InvalidatedRegio | |||
- InvalidatedRegio | |||
/// enterStackFrame - Let the StoreManager to do something when execution | /// enterStackFrame - Let the StoreManager to do something when execution | ||
/// engine is about to execute into a callee. | /// engine is about to execute into a callee. |
@@ -49,17 +49,22 @@ namespace tooling { | |||
/// using namespace clang::tooling; | /// using namespace clang::tooling; | ||
/// using namespace llvm; | /// using namespace llvm; | ||
/// | /// | ||
-/// static cl::OptionCategory MyToolCategory( | +/// static cl::OptionCategory MyToolCategory("my-tool options"); | ||
/// static cl::extrahelp CommonHelp(CommonOptionsPar | /// static cl::extrahelp CommonHelp(CommonOptionsPar | ||
/// static cl::extrahelp MoreHelp("\nMore help text...\n"); | /// static cl::extrahelp MoreHelp("\nMore help text...\n"); | ||
-/// static cl::opt<bool> YourOwnOption(...); | |||
-/// ... | |||
/// | /// | ||
/// int main(int argc, const char **argv) { | /// int main(int argc, const char **argv) { | ||
-/// CommonOptionsPar | +/// auto ExpectedParser = | ||
+/// CommonOptionsPar | |||
+/// if (!ExpectedParser) { | |||
+/// llvm::errs() << ExpectedParser.takeError(); | |||
+/// return 1; | |||
+/// } | |||
+/// CommonOptionsPar | |||
/// ClangTool Tool(OptionsParser.getCompilations(), | /// ClangTool Tool(OptionsParser.getCompilations(), | ||
/// OptionsParser.getSourcePathLis | /// OptionsParser.getSourcePathLis | ||
-/// return Tool.run( | +/// return Tool.run( | ||
+/// newFrontendActio | |||
/// } | /// } | ||
/// \endcode | /// \endcode | ||
class CommonOptionsPar | class CommonOptionsPar |
@@ -24,7 +24,10 @@ const uint16_t VERSION_MAJOR = 0; | |||
/// API notes file minor version number. | /// API notes file minor version number. | ||
/// | /// | ||
/// When the format changes IN ANY WAY, this number should be incremented. | /// When the format changes IN ANY WAY, this number should be incremented. | ||
-const uint16_t VERSION_MINOR = | +const uint16_t VERSION_MINOR = 26; // SwiftCopyable | ||
+ | |||
+const uint8_t kSwiftCopyable = 1; | |||
+const uint8_t kSwiftNonCopyabl | |||
using IdentifierID = llvm::PointerEmbeddedI | using IdentifierID = llvm::PointerEmbeddedI | ||
using IdentifierIDFiel | using IdentifierIDFiel |
@@ -527,6 +527,13 @@ public: | |||
Info.EnumExtensibilit | Info.EnumExtensibilit | ||
static_cast<EnumExtensibilit | static_cast<EnumExtensibilit | ||
+ uint8_t Copyable = | |||
+ endian::readNext<uint8_t, llvm::endianness::little>(Data); | |||
+ if (Copyable == kSwiftNonCopyabl | |||
+ Info.setSwiftCopyable | |||
+ else if (Copyable == kSwiftCopyable) | |||
+ Info.setSwiftCopyable | |||
+ | |||
unsigned ImportAsLength = | unsigned ImportAsLength = | ||
endian::readNext<uint16_t, llvm::endianness::little>(Data); | endian::readNext<uint16_t, llvm::endianness::little>(Data); | ||
if (ImportAsLength > 0) { | if (ImportAsLength > 0) { |
@@ -1128,7 +1128,7 @@ public: | |||
return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) + | return 2 + (TI.SwiftImportAs ? TI.SwiftImportAs->size() : 0) + | ||
2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) + | 2 + (TI.SwiftRetainOp ? TI.SwiftRetainOp->size() : 0) + | ||
2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) + | 2 + (TI.SwiftReleaseOp ? TI.SwiftReleaseOp->size() : 0) + | ||
- | + 2 + getCommonTypeInfoSize(TI); | ||
} | } | ||
void emitUnversionedI | void emitUnversionedI | ||
@@ -1146,6 +1146,11 @@ public: | |||
writer.write<uint8_t>(Flags); | writer.write<uint8_t>(Flags); | ||
+ if (auto Copyable = TI.isSwiftCopyable()) | |||
+ writer.write<uint8_t>(*Copyable ? kSwiftCopyable : kSwiftNonCopyabl | |||
+ else | |||
+ writer.write<uint8_t>(0); | |||
+ | |||
if (auto ImportAs = TI.SwiftImportAs) { | if (auto ImportAs = TI.SwiftImportAs) { | ||
writer.write<uint16_t>(ImportAs->size() + 1); | writer.write<uint16_t>(ImportAs->size() + 1); | ||
OS.write(ImportAs->c_str(), ImportAs->size()); | OS.write(ImportAs->c_str(), ImportAs->size()); |
@@ -419,6 +419,7 @@ struct Tag { | |||
std::optional<EnumExtensibilit | std::optional<EnumExtensibilit | ||
std::optional<bool> FlagEnum; | std::optional<bool> FlagEnum; | ||
std::optional<EnumConvenienceA | std::optional<EnumConvenienceA | ||
+ std::optional<bool> SwiftCopyable; | |||
}; | }; | ||
typedef std::vector<Tag> TagsSeq; | typedef std::vector<Tag> TagsSeq; | ||
@@ -452,6 +453,7 @@ template <> struct MappingTraits<Ta | |||
IO.mapOptional("EnumExtensibilit | IO.mapOptional("EnumExtensibilit | ||
IO.mapOptional("FlagEnum", T.FlagEnum); | IO.mapOptional("FlagEnum", T.FlagEnum); | ||
IO.mapOptional("EnumKind", T.EnumConvenienceK | IO.mapOptional("EnumKind", T.EnumConvenienceK | ||
+ IO.mapOptional("SwiftCopyable", T.SwiftCopyable); | |||
} | } | ||
}; | }; | ||
} // namespace yaml | } // namespace yaml | ||
@@ -1009,6 +1011,9 @@ public: | |||
if (Tag.SwiftReleaseOp) | if (Tag.SwiftReleaseOp) | ||
TI.SwiftReleaseOp = Tag.SwiftReleaseOp; | TI.SwiftReleaseOp = Tag.SwiftReleaseOp; | ||
+ if (Tag.SwiftCopyable) | |||
+ TI.setSwiftCopyable | |||
+ | |||
if (Tag.EnumConvenienceK | if (Tag.EnumConvenienceK | ||
if (Tag.EnumExtensibilit | if (Tag.EnumExtensibilit | ||
emitError( | emitError( |
@@ -1084,7 +1084,7 @@ void ASTContext::addM | |||
} | } | ||
void ASTContext::addLazyModuleIni | void ASTContext::addLazyModuleIni | ||
- | + ArrayRef<GlobalDeclID> IDs) { | ||
auto *&Inits = ModuleInitialize | auto *&Inits = ModuleInitialize | ||
if (!Inits) | if (!Inits) | ||
Inits = new (*this) PerModuleInitial | Inits = new (*this) PerModuleInitial | ||
@@ -1321,16 +1321,14 @@ void ASTContext::Init | |||
// Placeholder type for OMP array sections. | // Placeholder type for OMP array sections. | ||
if (LangOpts.OpenMP) { | if (LangOpts.OpenMP) { | ||
- InitBuiltinType( | + InitBuiltinType(ArraySectionTy, BuiltinType::ArraySection); | ||
InitBuiltinType(OMPArrayShapingT | InitBuiltinType(OMPArrayShapingT | ||
InitBuiltinType(OMPIteratorTy, BuiltinType::OMPIterator); | InitBuiltinType(OMPIteratorTy, BuiltinType::OMPIterator); | ||
} | } | ||
- // Placeholder type for OpenACC array sections | + // Placeholder type for OpenACC array sections, if we are ALSO in OMP mode, | ||
- if (LangOpts.OpenACC) { | + // don't bother, as we're just using the same type as OMP. | ||
- // FIXME: Once we implement OpenACC array sections in Sema, this will either | + if (LangOpts.OpenACC && !LangOpts.OpenMP) { | ||
- // be combined with the OpenMP type, or given its own type. In the meantime, | + InitBuiltinType(ArraySectionTy, BuiltinType::ArraySection); | ||
- // just use the OpenMP type so that parsing can work. | |||
- InitBuiltinType(OMPArraySectionT | |||
} | } | ||
if (LangOpts.MatrixTypes) | if (LangOpts.MatrixTypes) | ||
InitBuiltinType(IncompleteMatrix | InitBuiltinType(IncompleteMatrix |
@@ -443,12 +443,17 @@ ExprDependence clang::computeDe | |||
return E->getSubExpr()->getDependence(); | return E->getSubExpr()->getDependence(); | ||
} | } | ||
-ExprDependence clang::computeDependence( | +ExprDependence clang::computeDependence(ArraySectionExpr *E) { | ||
auto D = E->getBase()->getDependence(); | auto D = E->getBase()->getDependence(); | ||
if (auto *LB = E->getLowerBound()) | if (auto *LB = E->getLowerBound()) | ||
D |= LB->getDependence(); | D |= LB->getDependence(); | ||
if (auto *Len = E->getLength()) | if (auto *Len = E->getLength()) | ||
D |= Len->getDependence(); | D |= Len->getDependence(); | ||
+ | |||
+ if (E->isOMPArraySectio | |||
+ if (auto *Stride = E->getStride()) | |||
+ D |= Stride->getDependence(); | |||
+ } | |||
return D; | return D; | ||
} | } | ||
@@ -2151,7 +2151,7 @@ VarDecl *VarDecl::Create | |||
return new (C, DC) VarDecl(Var, C, DC, StartL, IdL, Id, T, TInfo, S); | return new (C, DC) VarDecl(Var, C, DC, StartL, IdL, Id, T, TInfo, S); | ||
} | } | ||
-VarDecl *VarDecl::CreateDeserialized(ASTContext &C, | +VarDecl *VarDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) | return new (C, ID) | ||
VarDecl(Var, C, nullptr, SourceLocation(), SourceLocation(), nullptr, | VarDecl(Var, C, nullptr, SourceLocation(), SourceLocation(), nullptr, | ||
QualType(), nullptr, SC_None); | QualType(), nullptr, SC_None); | ||
@@ -2929,7 +2929,7 @@ QualType ParmVarDecl::get | |||
return T; | return T; | ||
} | } | ||
-ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, | +ParmVarDecl *ParmVarDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) | return new (C, ID) | ||
ParmVarDecl(ParmVar, C, nullptr, SourceLocation(), SourceLocation(), | ParmVarDecl(ParmVar, C, nullptr, SourceLocation(), SourceLocation(), | ||
nullptr, QualType(), nullptr, SC_None, nullptr); | nullptr, QualType(), nullptr, SC_None, nullptr); | ||
@@ -4553,7 +4553,7 @@ FieldDecl *FieldDecl::Crea | |||
BW, Mutable, InitStyle); | BW, Mutable, InitStyle); | ||
} | } | ||
-FieldDecl *FieldDecl::CreateDeserialized(ASTContext &C, | +FieldDecl *FieldDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) FieldDecl(Field, nullptr, SourceLocation(), | return new (C, ID) FieldDecl(Field, nullptr, SourceLocation(), | ||
SourceLocation(), nullptr, QualType(), nullptr, | SourceLocation(), nullptr, QualType(), nullptr, | ||
nullptr, false, ICIS_NoInit); | nullptr, false, ICIS_NoInit); | ||
@@ -4863,7 +4863,7 @@ EnumDecl *EnumDecl::Creat | |||
return Enum; | return Enum; | ||
} | } | ||
-EnumDecl *EnumDecl::CreateDeserialized(ASTContext &C, | +EnumDecl *EnumDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
EnumDecl *Enum = | EnumDecl *Enum = | ||
new (C, ID) EnumDecl(C, nullptr, SourceLocation(), SourceLocation(), | new (C, ID) EnumDecl(C, nullptr, SourceLocation(), SourceLocation(), | ||
nullptr, nullptr, false, false, false); | nullptr, nullptr, false, false, false); | ||
@@ -5025,7 +5025,8 @@ RecordDecl *RecordDecl::Cre | |||
return R; | return R; | ||
} | } | ||
-RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, | +RecordDecl *RecordDecl::CreateDeserialized(const ASTContext &C, | ||
+ GlobalDeclID ID) { | |||
RecordDecl *R = new (C, ID) | RecordDecl *R = new (C, ID) | ||
RecordDecl(Record, TagTypeKind::Struct, C, nullptr, SourceLocation(), | RecordDecl(Record, TagTypeKind::Struct, C, nullptr, SourceLocation(), | ||
SourceLocation(), nullptr, nullptr); | SourceLocation(), nullptr, nullptr); | ||
@@ -5297,7 +5298,7 @@ PragmaCommentDec | |||
} | } | ||
PragmaCommentDec | PragmaCommentDec | ||
- | + GlobalDeclID ID, | ||
unsigned ArgSize) { | unsigned ArgSize) { | ||
return new (C, ID, additionalSizeTo | return new (C, ID, additionalSizeTo | ||
PragmaCommentDec | PragmaCommentDec | ||
@@ -5322,7 +5323,7 @@ PragmaDetectMism | |||
} | } | ||
PragmaDetectMism | PragmaDetectMism | ||
-PragmaDetectMismatchDecl::CreateDeserialized(ASTContext &C, | +PragmaDetectMismatchDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
unsigned NameValueSize) { | unsigned NameValueSize) { | ||
return new (C, ID, additionalSizeTo | return new (C, ID, additionalSizeTo | ||
PragmaDetectMism | PragmaDetectMism | ||
@@ -5349,7 +5350,7 @@ LabelDecl *LabelDecl::Crea | |||
return new (C, DC) LabelDecl(DC, IdentL, II, nullptr, GnuLabelL); | return new (C, DC) LabelDecl(DC, IdentL, II, nullptr, GnuLabelL); | ||
} | } | ||
-LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, | +LabelDecl *LabelDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) LabelDecl(nullptr, SourceLocation(), nullptr, nullptr, | return new (C, ID) LabelDecl(nullptr, SourceLocation(), nullptr, nullptr, | ||
SourceLocation()); | SourceLocation()); | ||
} | } | ||
@@ -5390,7 +5391,7 @@ ImplicitParamDec | |||
} | } | ||
ImplicitParamDec | ImplicitParamDec | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) ImplicitParamDec | return new (C, ID) ImplicitParamDec | ||
} | } | ||
@@ -5408,7 +5409,7 @@ FunctionDecl::Cr | |||
return New; | return New; | ||
} | } | ||
-FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, | +FunctionDecl *FunctionDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) FunctionDecl( | return new (C, ID) FunctionDecl( | ||
Function, C, nullptr, SourceLocation(), DeclarationNameI | Function, C, nullptr, SourceLocation(), DeclarationNameI | ||
nullptr, SC_None, false, false, ConstexprSpecKin | nullptr, SC_None, false, false, ConstexprSpecKin | ||
@@ -5418,7 +5419,7 @@ BlockDecl *BlockDecl::Crea | |||
return new (C, DC) BlockDecl(DC, L); | return new (C, DC) BlockDecl(DC, L); | ||
} | } | ||
-BlockDecl *BlockDecl::CreateDeserialized(ASTContext &C, | +BlockDecl *BlockDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) BlockDecl(nullptr, SourceLocation()); | return new (C, ID) BlockDecl(nullptr, SourceLocation()); | ||
} | } | ||
@@ -5432,7 +5433,7 @@ CapturedDecl *CapturedDecl::C | |||
CapturedDecl(DC, NumParams); | CapturedDecl(DC, NumParams); | ||
} | } | ||
-CapturedDecl *CapturedDecl::CreateDeserialized(ASTContext &C, | +CapturedDecl *CapturedDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
unsigned NumParams) { | unsigned NumParams) { | ||
return new (C, ID, additionalSizeTo | return new (C, ID, additionalSizeTo | ||
CapturedDecl(nullptr, NumParams); | CapturedDecl(nullptr, NumParams); | ||
@@ -5458,8 +5459,8 @@ EnumConstantDecl | |||
return new (C, CD) EnumConstantDecl | return new (C, CD) EnumConstantDecl | ||
} | } | ||
-EnumConstantDecl * | +EnumConstantDecl *EnumConstantDecl::CreateDeserialized(ASTContext &C, | ||
-EnumConstantDecl | + GlobalDeclID ID) { | ||
return new (C, ID) EnumConstantDecl | return new (C, ID) EnumConstantDecl | ||
QualType(), nullptr, llvm::APSInt()); | QualType(), nullptr, llvm::APSInt()); | ||
} | } | ||
@@ -5486,7 +5487,7 @@ IndirectFieldDec | |||
} | } | ||
IndirectFieldDec | IndirectFieldDec | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) | return new (C, ID) | ||
IndirectFieldDec | IndirectFieldDec | ||
QualType(), std::nullopt); | QualType(), std::nullopt); | ||
@@ -5547,7 +5548,7 @@ bool TypedefNameDecl: | |||
return isTransparent; | return isTransparent; | ||
} | } | ||
-TypedefDecl *TypedefDecl::CreateDeserialized(ASTContext &C, | +TypedefDecl *TypedefDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) TypedefDecl(C, nullptr, SourceLocation(), SourceLocation(), | return new (C, ID) TypedefDecl(C, nullptr, SourceLocation(), SourceLocation(), | ||
nullptr, nullptr); | nullptr, nullptr); | ||
} | } | ||
@@ -5560,7 +5561,8 @@ TypeAliasDecl *TypeAliasDecl:: | |||
return new (C, DC) TypeAliasDecl(C, DC, StartLoc, IdLoc, Id, TInfo); | return new (C, DC) TypeAliasDecl(C, DC, StartLoc, IdLoc, Id, TInfo); | ||
} | } | ||
-TypeAliasDecl *TypeAliasDecl::CreateDeserialized(ASTContext &C, | +TypeAliasDecl *TypeAliasDecl::CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID) { | |||
return new (C, ID) TypeAliasDecl(C, nullptr, SourceLocation(), | return new (C, ID) TypeAliasDecl(C, nullptr, SourceLocation(), | ||
SourceLocation(), nullptr, nullptr); | SourceLocation(), nullptr, nullptr); | ||
} | } | ||
@@ -5591,7 +5593,7 @@ FileScopeAsmDecl | |||
} | } | ||
FileScopeAsmDecl | FileScopeAsmDecl | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) FileScopeAsmDecl | return new (C, ID) FileScopeAsmDecl | ||
SourceLocation()); | SourceLocation()); | ||
} | } | ||
@@ -5609,7 +5611,7 @@ TopLevelStmtDecl | |||
} | } | ||
TopLevelStmtDecl | TopLevelStmtDecl | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) | return new (C, ID) | ||
TopLevelStmtDecl | TopLevelStmtDecl | ||
} | } | ||
@@ -5630,7 +5632,7 @@ EmptyDecl *EmptyDecl::Crea | |||
return new (C, DC) EmptyDecl(DC, L); | return new (C, DC) EmptyDecl(DC, L); | ||
} | } | ||
-EmptyDecl *EmptyDecl::CreateDeserialized(ASTContext &C, | +EmptyDecl *EmptyDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) EmptyDecl(nullptr, SourceLocation()); | return new (C, ID) EmptyDecl(nullptr, SourceLocation()); | ||
} | } | ||
@@ -5663,7 +5665,8 @@ HLSLBufferDecl *HLSLBufferDecl: | |||
return Result; | return Result; | ||
} | } | ||
-HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C, | +HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID) { | |||
return new (C, ID) HLSLBufferDecl(nullptr, false, SourceLocation(), nullptr, | return new (C, ID) HLSLBufferDecl(nullptr, false, SourceLocation(), nullptr, | ||
SourceLocation(), SourceLocation()); | SourceLocation(), SourceLocation()); | ||
} | } | ||
@@ -5719,7 +5722,7 @@ ImportDecl *ImportDecl::Cre | |||
return Import; | return Import; | ||
} | } | ||
-ImportDecl *ImportDecl::CreateDeserialized(ASTContext &C, | +ImportDecl *ImportDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
unsigned NumLocations) { | unsigned NumLocations) { | ||
return new (C, ID, additionalSizeTo | return new (C, ID, additionalSizeTo | ||
ImportDecl(EmptyShell()); | ImportDecl(EmptyShell()); | ||
@@ -5752,6 +5755,6 @@ ExportDecl *ExportDecl::Cre | |||
return new (C, DC) ExportDecl(DC, ExportLoc); | return new (C, DC) ExportDecl(DC, ExportLoc); | ||
} | } | ||
-ExportDecl *ExportDecl::CreateDeserialized(ASTContext &C, | +ExportDecl *ExportDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) ExportDecl(nullptr, SourceLocation()); | return new (C, ID) ExportDecl(nullptr, SourceLocation()); | ||
} | } |
@@ -71,7 +71,7 @@ void Decl::updateOutO | |||
#include "clang/AST/DeclNodes.inc" | #include "clang/AST/DeclNodes.inc" | ||
void *Decl::operator new(std::size_t Size, const ASTContext &Context, | void *Decl::operator new(std::size_t Size, const ASTContext &Context, | ||
- | + GlobalDeclID ID, std::size_t Extra) { | ||
// Allocate an extra 8 bytes worth of storage, which ensures that the | // Allocate an extra 8 bytes worth of storage, which ensures that the | ||
// resulting pointer will still be 8-byte aligned. | // resulting pointer will still be 8-byte aligned. | ||
static_assert(sizeof(unsigned) * 2 >= alignof(Decl), | static_assert(sizeof(unsigned) * 2 >= alignof(Decl), | ||
@@ -85,7 +85,7 @@ void *Decl::operator new(std::size_t Size, const ASTContext &Context, | |||
PrefixPtr[0] = 0; | PrefixPtr[0] = 0; | ||
// Store the global declaration ID in the second 4 bytes. | // Store the global declaration ID in the second 4 bytes. | ||
- PrefixPtr[1] = | + PrefixPtr[1] = ID.get(); | ||
return Result; | return Result; | ||
} | } | ||
@@ -1115,7 +1115,9 @@ int64_t Decl::getID() const { | |||
const FunctionType *Decl::getFunctionType(bool BlocksToo) const { | const FunctionType *Decl::getFunctionType(bool BlocksToo) const { | ||
QualType Ty; | QualType Ty; | ||
- if (const auto *D = dyn_cast<ValueDecl>(this)) | + if (isa<BindingDecl>(this)) | ||
+ return nullptr; | |||
+ else if (const auto *D = dyn_cast<ValueDecl>(this)) | |||
Ty = D->getType(); | Ty = D->getType(); | ||
else if (const auto *D = dyn_cast<TypedefNameDecl>(this)) | else if (const auto *D = dyn_cast<TypedefNameDecl>(this)) | ||
Ty = D->getUnderlyingTyp | Ty = D->getUnderlyingTyp |
@@ -57,7 +57,8 @@ using namespace clang; | |||
void AccessSpecDecl::anchor() {} | void AccessSpecDecl::anchor() {} | ||
-AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, | +AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID) { | |||
return new (C, ID) AccessSpecDecl(EmptyShell()); | return new (C, ID) AccessSpecDecl(EmptyShell()); | ||
} | } | ||
@@ -68,7 +69,7 @@ void LazyASTUnresolve | |||
for (ASTUnresolvedSet | for (ASTUnresolvedSet | ||
I.setDecl(cast<NamedDecl>(Source->GetExternalDecl( | I.setDecl(cast<NamedDecl>(Source->GetExternalDecl( | ||
- reinterpret_cast<uintptr_t>(I.getDecl()) >> 2))); | + GlobalDeclID(reinterpret_cast<uintptr_t>(I.getDecl()) >> 2)))); | ||
Impl.Decls.setLazy(false); | Impl.Decls.setLazy(false); | ||
} | } | ||
@@ -160,8 +161,8 @@ CXXRecordDecl::C | |||
return R; | return R; | ||
} | } | ||
-CXXRecordDecl * | +CXXRecordDecl *CXXRecordDecl::CreateDeserialized(const ASTContext &C, | ||
-CXXRecordDecl::CreateDeserializ | + GlobalDeclID ID) { | ||
auto *R = new (C, ID) | auto *R = new (C, ID) | ||
CXXRecordDecl(CXXRecord, TagTypeKind::Struct, C, nullptr, | CXXRecordDecl(CXXRecord, TagTypeKind::Struct, C, nullptr, | ||
SourceLocation(), SourceLocation(), nullptr, nullptr); | SourceLocation(), SourceLocation(), nullptr, nullptr); | ||
@@ -2162,8 +2163,8 @@ CXXDeductionGuid | |||
TInfo, EndLocation, Ctor, Kind); | TInfo, EndLocation, Ctor, Kind); | ||
} | } | ||
-CXXDeductionGuideDecl * | +CXXDeductionGuideDecl * | ||
- Decl::DeclID ID) { | +CXXDeductionGuid | ||
return new (C, ID) CXXDeductionGuid | return new (C, ID) CXXDeductionGuid | ||
C, nullptr, SourceLocation(), ExplicitSpecifie | C, nullptr, SourceLocation(), ExplicitSpecifie | ||
QualType(), nullptr, SourceLocation(), nullptr, | QualType(), nullptr, SourceLocation(), nullptr, | ||
@@ -2175,8 +2176,8 @@ RequiresExprBody | |||
return new (C, DC) RequiresExprBody | return new (C, DC) RequiresExprBody | ||
} | } | ||
-RequiresExprBodyDecl * | +RequiresExprBodyDecl * | ||
- Decl::DeclID ID) { | +RequiresExprBody | ||
return new (C, ID) RequiresExprBody | return new (C, ID) RequiresExprBody | ||
} | } | ||
@@ -2281,7 +2282,8 @@ CXXMethodDecl::C | |||
isInline, ConstexprKind, EndLocation, TrailingRequires | isInline, ConstexprKind, EndLocation, TrailingRequires | ||
} | } | ||
-CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, | +CXXMethodDecl *CXXMethodDecl::CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID) { | |||
return new (C, ID) CXXMethodDecl( | return new (C, ID) CXXMethodDecl( | ||
CXXMethod, C, nullptr, SourceLocation(), DeclarationNameI | CXXMethod, C, nullptr, SourceLocation(), DeclarationNameI | ||
QualType(), nullptr, SC_None, false, false, | QualType(), nullptr, SC_None, false, false, | ||
@@ -2699,7 +2701,7 @@ CXXConstructorDe | |||
void CXXConstructorDe | void CXXConstructorDe | ||
CXXConstructorDe | CXXConstructorDe | ||
- | + GlobalDeclID ID, | ||
uint64_t AllocKind) { | uint64_t AllocKind) { | ||
bool hasTrailingExpli | bool hasTrailingExpli | ||
bool isInheritingCons | bool isInheritingCons | ||
@@ -2845,8 +2847,8 @@ bool CXXConstructorDe | |||
void CXXDestructorDec | void CXXDestructorDec | ||
-CXXDestructorDecl * | +CXXDestructorDecl *CXXDestructorDecl::CreateDeserialized(ASTContext &C, | ||
-CXXDestructorDec | + GlobalDeclID ID) { | ||
return new (C, ID) CXXDestructorDec | return new (C, ID) CXXDestructorDec | ||
C, nullptr, SourceLocation(), DeclarationNameI | C, nullptr, SourceLocation(), DeclarationNameI | ||
false, false, false, ConstexprSpecKin | false, false, false, ConstexprSpecKin | ||
@@ -2877,8 +2879,8 @@ void CXXDestructorDec | |||
void CXXConversionDec | void CXXConversionDec | ||
-CXXConversionDecl * | +CXXConversionDecl *CXXConversionDecl::CreateDeserialized(ASTContext &C, | ||
-CXXConversionDec | + GlobalDeclID ID) { | ||
return new (C, ID) CXXConversionDec | return new (C, ID) CXXConversionDec | ||
C, nullptr, SourceLocation(), DeclarationNameI | C, nullptr, SourceLocation(), DeclarationNameI | ||
false, false, ExplicitSpecifie | false, false, ExplicitSpecifie | ||
@@ -2924,7 +2926,7 @@ LinkageSpecDecl *LinkageSpecDecl | |||
} | } | ||
LinkageSpecDecl *LinkageSpecDecl::CreateDeserializ | LinkageSpecDecl *LinkageSpecDecl::CreateDeserializ | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) | return new (C, ID) | ||
LinkageSpecDecl(nullptr, SourceLocation(), SourceLocation(), | LinkageSpecDecl(nullptr, SourceLocation(), SourceLocation(), | ||
LinkageSpecLangu | LinkageSpecLangu | ||
@@ -2946,7 +2948,7 @@ UsingDirectiveDe | |||
} | } | ||
UsingDirectiveDe | UsingDirectiveDe | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) UsingDirectiveDe | return new (C, ID) UsingDirectiveDe | ||
SourceLocation(), | SourceLocation(), | ||
NestedNameSpecif | NestedNameSpecif | ||
@@ -2985,7 +2987,8 @@ NamespaceDecl *NamespaceDecl:: | |||
NamespaceDecl(C, DC, Inline, StartLoc, IdLoc, Id, PrevDecl, Nested); | NamespaceDecl(C, DC, Inline, StartLoc, IdLoc, Id, PrevDecl, Nested); | ||
} | } | ||
-NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C, | +NamespaceDecl *NamespaceDecl::CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID) { | |||
return new (C, ID) NamespaceDecl(C, nullptr, false, SourceLocation(), | return new (C, ID) NamespaceDecl(C, nullptr, false, SourceLocation(), | ||
SourceLocation(), nullptr, nullptr, false); | SourceLocation(), nullptr, nullptr, false); | ||
} | } | ||
@@ -3046,8 +3049,8 @@ NamespaceAliasDe | |||
QualifierLoc, IdentLoc, Namespace); | QualifierLoc, IdentLoc, Namespace); | ||
} | } | ||
-NamespaceAliasDecl * | +NamespaceAliasDecl *NamespaceAliasDecl::CreateDeserialized(ASTContext &C, | ||
-NamespaceAliasDe | + GlobalDeclID ID) { | ||
return new (C, ID) NamespaceAliasDe | return new (C, ID) NamespaceAliasDe | ||
SourceLocation(), nullptr, | SourceLocation(), nullptr, | ||
NestedNameSpecif | NestedNameSpecif | ||
@@ -3102,8 +3105,8 @@ UsingShadowDecl: | |||
: NamedDecl(K, nullptr, SourceLocation(), DeclarationName()), | : NamedDecl(K, nullptr, SourceLocation(), DeclarationName()), | ||
redeclarable_bas | redeclarable_bas | ||
-UsingShadowDecl * | +UsingShadowDecl *UsingShadowDecl::CreateDeserialized(ASTContext &C, | ||
-UsingShadowDecl::CreateDeserializ | + GlobalDeclID ID) { | ||
return new (C, ID) UsingShadowDecl(UsingShadow, C, EmptyShell()); | return new (C, ID) UsingShadowDecl(UsingShadow, C, EmptyShell()); | ||
} | } | ||
@@ -3126,7 +3129,7 @@ ConstructorUsing | |||
} | } | ||
ConstructorUsing | ConstructorUsing | ||
-ConstructorUsingShadowDecl::CreateDeserialized(ASTContext &C, | +ConstructorUsingShadowDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) ConstructorUsing | return new (C, ID) ConstructorUsing | ||
} | } | ||
@@ -3174,7 +3177,7 @@ UsingDecl *UsingDecl::Crea | |||
return new (C, DC) UsingDecl(DC, UL, QualifierLoc, NameInfo, HasTypename); | return new (C, DC) UsingDecl(DC, UL, QualifierLoc, NameInfo, HasTypename); | ||
} | } | ||
-UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, | +UsingDecl *UsingDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) UsingDecl(nullptr, SourceLocation(), | return new (C, ID) UsingDecl(nullptr, SourceLocation(), | ||
NestedNameSpecif | NestedNameSpecif | ||
false); | false); | ||
@@ -3198,7 +3201,8 @@ UsingEnumDecl *UsingEnumDecl:: | |||
UsingEnumDecl(DC, EnumType->getType()->getAsTagDecl()->getDeclName(), UL, EL, NL, EnumType); | UsingEnumDecl(DC, EnumType->getType()->getAsTagDecl()->getDeclName(), UL, EL, NL, EnumType); | ||
} | } | ||
-UsingEnumDecl *UsingEnumDecl::CreateDeserialized(ASTContext &C, | +UsingEnumDecl *UsingEnumDecl::CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID) { | |||
return new (C, ID) | return new (C, ID) | ||
UsingEnumDecl(nullptr, DeclarationName(), SourceLocation(), | UsingEnumDecl(nullptr, DeclarationName(), SourceLocation(), | ||
SourceLocation(), SourceLocation(), nullptr); | SourceLocation(), SourceLocation(), nullptr); | ||
@@ -3217,7 +3221,7 @@ UsingPackDecl *UsingPackDecl:: | |||
return new (C, DC, Extra) UsingPackDecl(DC, InstantiatedFrom | return new (C, DC, Extra) UsingPackDecl(DC, InstantiatedFrom | ||
} | } | ||
-UsingPackDecl *UsingPackDecl::CreateDeserialized(ASTContext &C, | +UsingPackDecl *UsingPackDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
unsigned NumExpansions) { | unsigned NumExpansions) { | ||
size_t Extra = additionalSizeTo | size_t Extra = additionalSizeTo | ||
auto *Result = | auto *Result = | ||
@@ -3243,7 +3247,7 @@ UnresolvedUsingV | |||
} | } | ||
UnresolvedUsingV | UnresolvedUsingV | ||
-UnresolvedUsingValueDecl::CreateDeserialized(ASTContext &C, | +UnresolvedUsingValueDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) UnresolvedUsingV | return new (C, ID) UnresolvedUsingV | ||
SourceLocation(), | SourceLocation(), | ||
NestedNameSpecif | NestedNameSpecif | ||
@@ -3273,7 +3277,8 @@ UnresolvedUsingT | |||
} | } | ||
UnresolvedUsingT | UnresolvedUsingT | ||
-UnresolvedUsingTypenameDecl::CreateDeserialized(ASTContext &C, | +UnresolvedUsingTypenameDecl::CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID) { | |||
return new (C, ID) UnresolvedUsingT | return new (C, ID) UnresolvedUsingT | ||
nullptr, SourceLocation(), SourceLocation(), NestedNameSpecif | nullptr, SourceLocation(), SourceLocation(), NestedNameSpecif | ||
SourceLocation(), nullptr, SourceLocation()); | SourceLocation(), nullptr, SourceLocation()); | ||
@@ -3286,7 +3291,8 @@ UnresolvedUsingI | |||
} | } | ||
UnresolvedUsingI | UnresolvedUsingI | ||
-UnresolvedUsingIfExistsDecl::CreateDeserialized(ASTContext &Ctx, | +UnresolvedUsingIfExistsDecl::CreateDeserialized(ASTContext &Ctx, | ||
+ GlobalDeclID ID) { | |||
return new (Ctx, ID) | return new (Ctx, ID) | ||
UnresolvedUsingI | UnresolvedUsingI | ||
} | } | ||
@@ -3310,7 +3316,7 @@ StaticAssertDecl | |||
} | } | ||
StaticAssertDecl | StaticAssertDecl | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) StaticAssertDecl | return new (C, ID) StaticAssertDecl | ||
nullptr, SourceLocation(), false); | nullptr, SourceLocation(), false); | ||
} | } | ||
@@ -3332,7 +3338,7 @@ BindingDecl *BindingDecl::Cr | |||
return new (C, DC) BindingDecl(DC, IdLoc, Id); | return new (C, DC) BindingDecl(DC, IdLoc, Id); | ||
} | } | ||
-BindingDecl *BindingDecl::CreateDeserialized(ASTContext &C, | +BindingDecl *BindingDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) BindingDecl(nullptr, SourceLocation(), nullptr); | return new (C, ID) BindingDecl(nullptr, SourceLocation(), nullptr); | ||
} | } | ||
@@ -3363,7 +3369,7 @@ DecompositionDec | |||
} | } | ||
DecompositionDec | DecompositionDec | ||
- | + GlobalDeclID ID, | ||
unsigned NumBindings) { | unsigned NumBindings) { | ||
size_t Extra = additionalSizeTo | size_t Extra = additionalSizeTo | ||
auto *Result = new (C, ID, Extra) | auto *Result = new (C, ID, Extra) | ||
@@ -3402,7 +3408,7 @@ MSPropertyDecl *MSPropertyDecl: | |||
} | } | ||
MSPropertyDecl *MSPropertyDecl::CreateDeserializ | MSPropertyDecl *MSPropertyDecl::CreateDeserializ | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) MSPropertyDecl(nullptr, SourceLocation(), | return new (C, ID) MSPropertyDecl(nullptr, SourceLocation(), | ||
DeclarationName(), QualType(), nullptr, | DeclarationName(), QualType(), nullptr, | ||
SourceLocation(), nullptr, nullptr); | SourceLocation(), nullptr, nullptr); | ||
@@ -3419,7 +3425,7 @@ MSGuidDecl *MSGuidDecl::Cre | |||
return new (C, DC) MSGuidDecl(DC, T, P); | return new (C, DC) MSGuidDecl(DC, T, P); | ||
} | } | ||
-MSGuidDecl *MSGuidDecl::CreateDeserialized(ASTContext &C, | +MSGuidDecl *MSGuidDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) MSGuidDecl(nullptr, QualType(), Parts()); | return new (C, ID) MSGuidDecl(nullptr, QualType(), Parts()); | ||
} | } | ||
@@ -3529,7 +3535,7 @@ UnnamedGlobalCon | |||
} | } | ||
UnnamedGlobalCon | UnnamedGlobalCon | ||
-UnnamedGlobalConstantDecl::CreateDeserialized(ASTContext &C, | +UnnamedGlobalConstantDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) | return new (C, ID) | ||
UnnamedGlobalCon | UnnamedGlobalCon | ||
} | } |
@@ -62,7 +62,7 @@ FriendDecl *FriendDecl::Cre | |||
return FD; | return FD; | ||
} | } | ||
-FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, | +FriendDecl *FriendDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
unsigned FriendTypeNumTPL | unsigned FriendTypeNumTPL | ||
std::size_t Extra = | std::size_t Extra = | ||
additionalSizeTo | additionalSizeTo |
@@ -862,7 +862,8 @@ ObjCMethodDecl *ObjCMethodDecl: | |||
isImplicitlyDecl | isImplicitlyDecl | ||
} | } | ||
-ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, | +ObjCMethodDecl *ObjCMethodDecl::CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID) { | |||
return new (C, ID) ObjCMethodDecl(SourceLocation(), SourceLocation(), | return new (C, ID) ObjCMethodDecl(SourceLocation(), SourceLocation(), | ||
Selector(), QualType(), nullptr, nullptr); | Selector(), QualType(), nullptr, nullptr); | ||
} | } | ||
@@ -1486,7 +1487,7 @@ ObjCTypeParamDec | |||
} | } | ||
ObjCTypeParamDec | ObjCTypeParamDec | ||
- | + GlobalDeclID ID) { | ||
return new (ctx, ID) ObjCTypeParamDec | return new (ctx, ID) ObjCTypeParamDec | ||
ObjCTypeParamVar | ObjCTypeParamVar | ||
SourceLocation(), 0, SourceLocation(), | SourceLocation(), 0, SourceLocation(), | ||
@@ -1551,7 +1552,7 @@ ObjCInterfaceDec | |||
} | } | ||
ObjCInterfaceDec | ObjCInterfaceDec | ||
- | + GlobalDeclID ID) { | ||
auto *Result = new (C, ID) | auto *Result = new (C, ID) | ||
ObjCInterfaceDec | ObjCInterfaceDec | ||
SourceLocation(), nullptr, false); | SourceLocation(), nullptr, false); | ||
@@ -1865,7 +1866,7 @@ ObjCIvarDecl *ObjCIvarDecl::C | |||
synthesized); | synthesized); | ||
} | } | ||
-ObjCIvarDecl *ObjCIvarDecl::CreateDeserialized(ASTContext &C, | +ObjCIvarDecl *ObjCIvarDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) ObjCIvarDecl(nullptr, SourceLocation(), SourceLocation(), | return new (C, ID) ObjCIvarDecl(nullptr, SourceLocation(), SourceLocation(), | ||
nullptr, QualType(), nullptr, | nullptr, QualType(), nullptr, | ||
ObjCIvarDecl::None, nullptr, false); | ObjCIvarDecl::None, nullptr, false); | ||
@@ -1914,7 +1915,7 @@ ObjCAtDefsFieldD | |||
} | } | ||
ObjCAtDefsFieldD | ObjCAtDefsFieldD | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) ObjCAtDefsFieldD | return new (C, ID) ObjCAtDefsFieldD | ||
SourceLocation(), nullptr, QualType(), | SourceLocation(), nullptr, QualType(), | ||
nullptr); | nullptr); | ||
@@ -1949,7 +1950,7 @@ ObjCProtocolDecl | |||
} | } | ||
ObjCProtocolDecl | ObjCProtocolDecl | ||
- | + GlobalDeclID ID) { | ||
ObjCProtocolDecl | ObjCProtocolDecl | ||
new (C, ID) ObjCProtocolDecl | new (C, ID) ObjCProtocolDecl | ||
SourceLocation(), nullptr); | SourceLocation(), nullptr); | ||
@@ -2148,7 +2149,7 @@ ObjCCategoryDecl | |||
} | } | ||
ObjCCategoryDecl | ObjCCategoryDecl | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) ObjCCategoryDecl | return new (C, ID) ObjCCategoryDecl | ||
SourceLocation(), SourceLocation(), | SourceLocation(), SourceLocation(), | ||
nullptr, nullptr, nullptr); | nullptr, nullptr, nullptr); | ||
@@ -2188,8 +2189,8 @@ ObjCCategoryImpl | |||
atStartLoc, CategoryNameLoc); | atStartLoc, CategoryNameLoc); | ||
} | } | ||
-ObjCCategoryImplDecl * | +ObjCCategoryImplDecl * | ||
- Decl::DeclID ID) { | +ObjCCategoryImpl | ||
return new (C, ID) ObjCCategoryImpl | return new (C, ID) ObjCCategoryImpl | ||
SourceLocation(), SourceLocation(), | SourceLocation(), SourceLocation(), | ||
SourceLocation()); | SourceLocation()); | ||
@@ -2296,7 +2297,7 @@ ObjCImplementati | |||
} | } | ||
ObjCImplementati | ObjCImplementati | ||
-ObjCImplementationDecl::CreateDeserialized(ASTContext &C, | +ObjCImplementationDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) ObjCImplementati | return new (C, ID) ObjCImplementati | ||
SourceLocation(), SourceLocation()); | SourceLocation(), SourceLocation()); | ||
} | } | ||
@@ -2339,7 +2340,7 @@ ObjCCompatibleAl | |||
} | } | ||
ObjCCompatibleAl | ObjCCompatibleAl | ||
-ObjCCompatibleAliasDecl::CreateDeserialized(ASTContext &C, | +ObjCCompatibleAliasDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) ObjCCompatibleAl | return new (C, ID) ObjCCompatibleAl | ||
nullptr, nullptr); | nullptr, nullptr); | ||
} | } | ||
@@ -2360,7 +2361,7 @@ ObjCPropertyDecl | |||
} | } | ||
ObjCPropertyDecl | ObjCPropertyDecl | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) ObjCPropertyDecl | return new (C, ID) ObjCPropertyDecl | ||
SourceLocation(), SourceLocation(), | SourceLocation(), SourceLocation(), | ||
QualType(), nullptr, None); | QualType(), nullptr, None); | ||
@@ -2392,8 +2393,8 @@ ObjCPropertyImpl | |||
ivarLoc); | ivarLoc); | ||
} | } | ||
-ObjCPropertyImplDecl * | +ObjCPropertyImplDecl * | ||
- Decl::DeclID ID) { | +ObjCPropertyImpl | ||
return new (C, ID) ObjCPropertyImpl | return new (C, ID) ObjCPropertyImpl | ||
SourceLocation(), nullptr, Dynamic, | SourceLocation(), nullptr, Dynamic, | ||
nullptr, SourceLocation()); | nullptr, SourceLocation()); |
@@ -36,7 +36,7 @@ OMPThreadPrivate | |||
} | } | ||
OMPThreadPrivate | OMPThreadPrivate | ||
- | + GlobalDeclID ID, | ||
unsigned N) { | unsigned N) { | ||
return OMPDeclarativeDi | return OMPDeclarativeDi | ||
C, ID, 0, N); | C, ID, 0, N); | ||
@@ -63,7 +63,8 @@ OMPAllocateDecl *OMPAllocateDecl | |||
return D; | return D; | ||
} | } | ||
-OMPAllocateDecl *OMPAllocateDecl::CreateDeserialized(ASTContext &C, | +OMPAllocateDecl *OMPAllocateDecl::CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID, | |||
unsigned NVars, | unsigned NVars, | ||
unsigned NClauses) { | unsigned NClauses) { | ||
return OMPDeclarativeDi | return OMPDeclarativeDi | ||
@@ -89,7 +90,8 @@ OMPRequiresDecl *OMPRequiresDecl | |||
L); | L); | ||
} | } | ||
-OMPRequiresDecl *OMPRequiresDecl::CreateDeserialized(ASTContext &C, | +OMPRequiresDecl *OMPRequiresDecl::CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID, | |||
unsigned N) { | unsigned N) { | ||
return OMPDeclarativeDi | return OMPDeclarativeDi | ||
C, ID, N, 0, SourceLocation()); | C, ID, N, 0, SourceLocation()); | ||
@@ -117,7 +119,7 @@ OMPDeclareReduct | |||
} | } | ||
OMPDeclareReduct | OMPDeclareReduct | ||
-OMPDeclareReductionDecl::CreateDeserialized(ASTContext &C, | +OMPDeclareReductionDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) OMPDeclareReduct | return new (C, ID) OMPDeclareReduct | ||
OMPDeclareReduct | OMPDeclareReduct | ||
QualType(), /*PrevDeclInScope=*/nullptr); | QualType(), /*PrevDeclInScope=*/nullptr); | ||
@@ -148,7 +150,7 @@ OMPDeclareMapper | |||
} | } | ||
OMPDeclareMapper | OMPDeclareMapper | ||
- | + GlobalDeclID ID, | ||
unsigned N) { | unsigned N) { | ||
return OMPDeclarativeDi | return OMPDeclarativeDi | ||
C, ID, N, 1, SourceLocation(), DeclarationName(), QualType(), | C, ID, N, 1, SourceLocation(), DeclarationName(), QualType(), | ||
@@ -179,7 +181,7 @@ OMPCapturedExprD | |||
} | } | ||
OMPCapturedExprD | OMPCapturedExprD | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) OMPCapturedExprD | return new (C, ID) OMPCapturedExprD | ||
/*TInfo=*/nullptr, SourceLocation()); | /*TInfo=*/nullptr, SourceLocation()); | ||
} | } |
@@ -337,9 +337,10 @@ void RedeclarableTemp | |||
CommonBase *CommonBasePtr = getMostRecentDec | CommonBase *CommonBasePtr = getMostRecentDec | ||
if (CommonBasePtr->LazySpecializati | if (CommonBasePtr->LazySpecializati | ||
ASTContext &Context = getASTContext(); | ASTContext &Context = getASTContext(); | ||
- | + GlobalDeclID *Specs = CommonBasePtr->LazySpecializations; | ||
CommonBasePtr->LazySpecializati | CommonBasePtr->LazySpecializati | ||
- for (uint32_t I = 0, N = *Specs++; I != N; ++I) | + unsigned SpecSize = (*Specs++).get(); | ||
+ for (unsigned I = 0; I != SpecSize; ++I) | |||
(void)Context.getExternalSourc | (void)Context.getExternalSourc | ||
} | } | ||
} | } | ||
@@ -417,8 +418,8 @@ FunctionTemplate | |||
return TD; | return TD; | ||
} | } | ||
-FunctionTemplateDecl * | +FunctionTemplateDecl * | ||
- Decl::DeclID ID) { | +FunctionTemplate | ||
return new (C, ID) FunctionTemplate | return new (C, ID) FunctionTemplate | ||
DeclarationName(), nullptr, nullptr); | DeclarationName(), nullptr, nullptr); | ||
} | } | ||
@@ -503,7 +504,7 @@ ClassTemplateDec | |||
} | } | ||
ClassTemplateDec | ClassTemplateDec | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) ClassTemplateDec | return new (C, ID) ClassTemplateDec | ||
DeclarationName(), nullptr, nullptr); | DeclarationName(), nullptr, nullptr); | ||
} | } | ||
@@ -652,14 +653,14 @@ TemplateTypeParm | |||
} | } | ||
TemplateTypeParm | TemplateTypeParm | ||
-TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, | +TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) | return new (C, ID) | ||
TemplateTypeParm | TemplateTypeParm | ||
false, false, std::nullopt); | false, false, std::nullopt); | ||
} | } | ||
TemplateTypeParm | TemplateTypeParm | ||
-TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, | +TemplateTypeParmDecl::CreateDeserialized(const ASTContext &C, GlobalDeclID ID, | ||
bool HasTypeConstrain | bool HasTypeConstrain | ||
return new (C, ID, | return new (C, ID, | ||
additionalSizeTo | additionalSizeTo | ||
@@ -759,7 +760,7 @@ NonTypeTemplateP | |||
} | } | ||
NonTypeTemplateP | NonTypeTemplateP | ||
-NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, | +NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
bool HasTypeConstrain | bool HasTypeConstrain | ||
return new (C, ID, additionalSizeTo | return new (C, ID, additionalSizeTo | ||
TypeSourceInfo *>, | TypeSourceInfo *>, | ||
@@ -770,7 +771,7 @@ NonTypeTemplateP | |||
} | } | ||
NonTypeTemplateP | NonTypeTemplateP | ||
-NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, | +NonTypeTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
unsigned NumExpandedTypes | unsigned NumExpandedTypes | ||
bool HasTypeConstrain | bool HasTypeConstrain | ||
auto *NTTP = | auto *NTTP = | ||
@@ -836,13 +837,13 @@ TemplateTemplate | |||
} | } | ||
TemplateTemplate | TemplateTemplate | ||
-TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, | +TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
return new (C, ID) TemplateTemplate | return new (C, ID) TemplateTemplate | ||
false, nullptr, false, nullptr); | false, nullptr, false, nullptr); | ||
} | } | ||
TemplateTemplate | TemplateTemplate | ||
-TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, | +TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID, | ||
unsigned NumExpansions) { | unsigned NumExpansions) { | ||
auto *TTP = | auto *TTP = | ||
new (C, ID, additionalSizeTo | new (C, ID, additionalSizeTo | ||
@@ -949,7 +950,7 @@ ClassTemplateSpe | |||
ClassTemplateSpe | ClassTemplateSpe | ||
ClassTemplateSpe | ClassTemplateSpe | ||
- | + GlobalDeclID ID) { | ||
auto *Result = | auto *Result = | ||
new (C, ID) ClassTemplateSpe | new (C, ID) ClassTemplateSpe | ||
Result->setMayHaveOutOfD | Result->setMayHaveOutOfD | ||
@@ -1035,8 +1036,7 @@ ConceptDecl *ConceptDecl::Cr | |||
return TD; | return TD; | ||
} | } | ||
-ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C, | +ConceptDecl *ConceptDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
- Decl::DeclID ID) { | |||
ConceptDecl *Result = new (C, ID) ConceptDecl(nullptr, SourceLocation(), | ConceptDecl *Result = new (C, ID) ConceptDecl(nullptr, SourceLocation(), | ||
DeclarationName(), | DeclarationName(), | ||
nullptr, nullptr); | nullptr, nullptr); | ||
@@ -1070,7 +1070,7 @@ ImplicitConceptS | |||
ImplicitConceptS | ImplicitConceptS | ||
ImplicitConceptS | ImplicitConceptS | ||
- const ASTContext &C, | + const ASTContext &C, GlobalDeclID ID, unsigned NumTemplateArgs) { | ||
return new (C, ID, additionalSizeTo | return new (C, ID, additionalSizeTo | ||
ImplicitConceptS | ImplicitConceptS | ||
} | } | ||
@@ -1133,7 +1133,7 @@ Create(ASTContex | |||
ClassTemplatePar | ClassTemplatePar | ||
ClassTemplatePar | ClassTemplatePar | ||
- | + GlobalDeclID ID) { | ||
auto *Result = new (C, ID) ClassTemplatePar | auto *Result = new (C, ID) ClassTemplatePar | ||
Result->setMayHaveOutOfD | Result->setMayHaveOutOfD | ||
return Result; | return Result; | ||
@@ -1160,7 +1160,7 @@ FriendTemplateDe | |||
} | } | ||
FriendTemplateDe | FriendTemplateDe | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) FriendTemplateDe | return new (C, ID) FriendTemplateDe | ||
} | } | ||
@@ -1179,8 +1179,8 @@ TypeAliasTemplat | |||
return TD; | return TD; | ||
} | } | ||
-TypeAliasTemplateDecl * | +TypeAliasTemplateDecl * | ||
- Decl::DeclID ID) { | +TypeAliasTemplat | ||
return new (C, ID) TypeAliasTemplat | return new (C, ID) TypeAliasTemplat | ||
DeclarationName(), nullptr, nullptr); | DeclarationName(), nullptr, nullptr); | ||
} | } | ||
@@ -1218,7 +1218,7 @@ VarTemplateDecl *VarTemplateDecl | |||
} | } | ||
VarTemplateDecl *VarTemplateDecl::CreateDeserializ | VarTemplateDecl *VarTemplateDecl::CreateDeserializ | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) VarTemplateDecl(C, nullptr, SourceLocation(), | return new (C, ID) VarTemplateDecl(C, nullptr, SourceLocation(), | ||
DeclarationName(), nullptr, nullptr); | DeclarationName(), nullptr, nullptr); | ||
} | } | ||
@@ -1340,7 +1340,8 @@ VarTemplateSpeci | |||
} | } | ||
VarTemplateSpeci | VarTemplateSpeci | ||
-VarTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, | +VarTemplateSpecializationDecl::CreateDeserialized(ASTContext &C, | ||
+ GlobalDeclID ID) { | |||
return new (C, ID) | return new (C, ID) | ||
VarTemplateSpeci | VarTemplateSpeci | ||
} | } | ||
@@ -1432,7 +1433,7 @@ VarTemplateParti | |||
VarTemplateParti | VarTemplateParti | ||
VarTemplateParti | VarTemplateParti | ||
- | + GlobalDeclID ID) { | ||
return new (C, ID) VarTemplateParti | return new (C, ID) VarTemplateParti | ||
} | } | ||
@@ -1546,7 +1547,7 @@ TemplateParamObj | |||
} | } | ||
TemplateParamObj | TemplateParamObj | ||
-TemplateParamObjectDecl::CreateDeserialized(ASTContext &C, | +TemplateParamObjectDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { | ||
auto *TPOD = new (C, ID) TemplateParamObj | auto *TPOD = new (C, ID) TemplateParamObj | ||
C.addDestruction(&TPOD->Value); | C.addDestruction(&TPOD->Value); | ||
return TPOD; | return TPOD; |
@@ -103,7 +103,7 @@ const Expr *Expr::skipRValu | |||
} | } | ||
} else if (const auto *ME = dyn_cast<MemberExpr>(E)) { | } else if (const auto *ME = dyn_cast<MemberExpr>(E)) { | ||
if (!ME->isArrow()) { | if (!ME->isArrow()) { | ||
- assert(ME->getBase()->getType()- | + assert(ME->getBase()->getType()->getAsRecordDecl()); | ||
if (const auto *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) { | if (const auto *Field = dyn_cast<FieldDecl>(ME->getMemberDecl())) { | ||
if (!Field->isBitField() && !Field->getType()->isReferenceType()) { | if (!Field->isBitField() && !Field->getType()->isReferenceType()) { | ||
E = ME->getBase(); | E = ME->getBase(); | ||
@@ -3680,7 +3680,7 @@ bool Expr::HasSideEff | |||
case ParenExprClass: | case ParenExprClass: | ||
case ArraySubscriptEx | case ArraySubscriptEx | ||
case MatrixSubscriptE | case MatrixSubscriptE | ||
- case | + case ArraySectionExprClass: | ||
case OMPArrayShapingE | case OMPArrayShapingE | ||
case OMPIteratorExprC | case OMPIteratorExprC | ||
case MemberExprClass: | case MemberExprClass: | ||
@@ -3893,9 +3893,14 @@ namespace { | |||
} | } | ||
void VisitCXXBindTemp | void VisitCXXBindTemp | ||
- if (E->getTemporary()->getDestructor()->isTrivial()) { | + // Destructor of the temporary might be null if destructor declaration | ||
- Inherited::VisitStmt(E); | + // is not valid. | ||
- return; | + if (const CXXDestructorDec | ||
+ E->getTemporary()->getDestructor()) { | |||
+ if (DtorDecl->isTrivial()) { | |||
+ Inherited::VisitStmt(E); | |||
+ return; | |||
+ } | |||
} | } | ||
NonTrivial = true; | NonTrivial = true; | ||
@@ -5060,9 +5065,9 @@ QualType AtomicExpr::getV | |||
return T; | return T; | ||
} | } | ||
-QualType | +QualType ArraySectionExpr::getBaseOriginalType(const Expr *Base) { | ||
unsigned ArraySectionCoun | unsigned ArraySectionCoun | ||
- while (auto *OASE = | + while (auto *OASE = dyn_cast<ArraySectionExpr>(Base->IgnoreParens())) { | ||
Base = OASE->getBase(); | Base = OASE->getBase(); | ||
++ArraySectionCoun | ++ArraySectionCoun | ||
} | } |
@@ -145,7 +145,7 @@ static Cl::Kinds ClassifyInternal | |||
case Expr::FunctionParmPack | case Expr::FunctionParmPack | ||
case Expr::MSPropertyRefExp | case Expr::MSPropertyRefExp | ||
case Expr::MSPropertySubscr | case Expr::MSPropertySubscr | ||
- case | + case Expr::ArraySectionExprClass: | ||
case Expr::OMPArrayShapingE | case Expr::OMPArrayShapingE | ||
case Expr::OMPIteratorExprC | case Expr::OMPIteratorExprC | ||
return Cl::CL_LValue; | return Cl::CL_LValue; | ||
@@ -216,8 +216,13 @@ static Cl::Kinds ClassifyInternal | |||
return ClassifyInternal | return ClassifyInternal | ||
cast<SubstNonTypeTemp | cast<SubstNonTypeTemp | ||
- case Expr::PackIndexingExprClass: | + case Expr::PackIndexingExprClass: { | ||
+ // A pack-index-expression always expands to an id-expression. | |||
+ // Consider it as an LValue expression. | |||
+ if (cast<PackIndexingExpr | |||
+ return Cl::CL_LValue; | |||
return ClassifyInternal | return ClassifyInternal | ||
+ } | |||
// C, C++98 [expr.sub]p1: The result is an lvalue of type "T". | // C, C++98 [expr.sub]p1: The result is an lvalue of type "T". | ||
// C++11 (DR1213): in the case of an array operand, the result is an lvalue | // C++11 (DR1213): in the case of an array operand, the result is an lvalue |
@@ -2706,7 +2706,11 @@ static bool checkFloatingPoi | |||
static bool HandleFloatToFlo | static bool HandleFloatToFlo | ||
QualType SrcType, QualType DestType, | QualType SrcType, QualType DestType, | ||
APFloat &Result) { | APFloat &Result) { | ||
- assert(isa<CastExpr>(E) || isa<CompoundAssignOperator>(E) | + assert((isa<CastExpr>(E) || isa<CompoundAssignOperator>(E) || | ||
+ isa<ConvertVectorExp | |||
+ "HandleFloatToFlo | |||
+ "CompoundAssignOp | |||
+ "the new expression or address the root cause of this usage."); | |||
llvm::RoundingMode RM = getActiveRoundin | llvm::RoundingMode RM = getActiveRoundin | ||
APFloat::opStatus St; | APFloat::opStatus St; | ||
APFloat Value = Result; | APFloat Value = Result; | ||
@@ -9237,9 +9241,10 @@ bool PointerExprEvalu | |||
bool HasValidResult = !Result.InvalidBase && !Result.Designator.Invalid && | bool HasValidResult = !Result.InvalidBase && !Result.Designator.Invalid && | ||
!Result.IsNullPtr; | !Result.IsNullPtr; | ||
bool VoidPtrCastMaybe | bool VoidPtrCastMaybe | ||
- | + Result.IsNullPtr || | ||
- Info.Ctx.hasSameUnqualifi | + (HasValidResult && | ||
- E->getType()->getPointeeType()); | + Info.Ctx.hasSimilarType(Result.Designator.getType(Info.Ctx), | ||
+ E->getType()->getPointeeType())); | |||
// 1. We'll allow it in std::allocator::allocate, and anything which that | // 1. We'll allow it in std::allocator::allocate, and anything which that | ||
// calls. | // calls. | ||
// 2. HACK 2022-03-28: Work around an issue with libstdc++'s | // 2. HACK 2022-03-28: Work around an issue with libstdc++'s | ||
@@ -10709,8 +10714,11 @@ namespace { | |||
bool VisitUnaryImag(const UnaryOperator *E); | bool VisitUnaryImag(const UnaryOperator *E); | ||
bool VisitBinaryOpera | bool VisitBinaryOpera | ||
bool VisitUnaryOperat | bool VisitUnaryOperat | ||
+ bool VisitConvertVect | |||
+ bool VisitShuffleVect | |||
+ | |||
// FIXME: Missing: conditional operator (for GNU | // FIXME: Missing: conditional operator (for GNU | ||
- // conditional select), | + // conditional select), ExtVectorElementExpr | ||
}; | }; | ||
} // end anonymous namespace | } // end anonymous namespace | ||
@@ -10961,6 +10969,122 @@ bool VectorExprEvalua | |||
return Success(APValue(ResultElements.data(), ResultElements.size()), E); | return Success(APValue(ResultElements.data(), ResultElements.size()), E); | ||
} | } | ||
+static bool handleVectorElem | |||
+ const Expr *E, QualType SourceTy, | |||
+ QualType DestTy, APValue const &Original, | |||
+ APValue &Result) { | |||
+ if (SourceTy->isIntegerType()) { | |||
+ if (DestTy->isRealFloatingTy | |||
+ Result = APValue(APFloat(0.0)); | |||
+ return HandleIntToFloat | |||
+ DestTy, Result.getFloat()); | |||
+ } | |||
+ if (DestTy->isIntegerType()) { | |||
+ Result = APValue( | |||
+ HandleIntToIntCa | |||
+ return true; | |||
+ } | |||
+ } else if (SourceTy->isRealFloatingTy | |||
+ if (DestTy->isRealFloatingTy | |||
+ Result = Original; | |||
+ return HandleFloatToFlo | |||
+ Result.getFloat()); | |||
+ } | |||
+ if (DestTy->isIntegerType()) { | |||
+ Result = APValue(APSInt()); | |||
+ return HandleFloatToInt | |||
+ DestTy, Result.getInt()); | |||
+ } | |||
+ } | |||
+ | |||
+ Info.FFDiag(E, diag::err_convertvecto | |||
+ << SourceTy << DestTy; | |||
+ return false; | |||
+} | |||
+ | |||
+bool VectorExprEvalua | |||
+ APValue Source; | |||
+ QualType SourceVecType = E->getSrcExpr()->getType(); | |||
+ if (!EvaluateAsRValue | |||
+ return false; | |||
+ | |||
+ QualType DestTy = E->getType()->castAs<VectorType>()->getElementType(); | |||
+ QualType SourceTy = SourceVecType->castAs<VectorType>()->getElementType(); | |||
+ | |||
+ const FPOptions FPO = E->getFPFeaturesInE | |||
+ | |||
+ auto SourceLen = Source.getVectorLength(); | |||
+ SmallVector<APValue, 4> ResultElements; | |||
+ ResultElements.reserve(SourceLen); | |||
+ for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { | |||
+ APValue Elt; | |||
+ if (!handleVectorElem | |||
+ Source.getVectorElt(EltNum), Elt)) | |||
+ return false; | |||
+ ResultElements.push_back(std::move(Elt)); | |||
+ } | |||
+ | |||
+ return Success(APValue(ResultElements.data(), ResultElements.size()), E); | |||
+} | |||
+ | |||
+static bool handleVectorShuf | |||
+ QualType ElemType, APValue const &VecVal1, | |||
+ APValue const &VecVal2, unsigned EltNum, | |||
+ APValue &Result) { | |||
+ unsigned const TotalElementsInI | |||
+ unsigned const TotalElementsInI | |||
+ | |||
+ APSInt IndexVal = E->getShuffleMaskId | |||
+ int64_t index = IndexVal.getExtValue(); | |||
+ // The spec says that -1 should be treated as undef for optimizations, | |||
+ // but in constexpr we'd have to produce an APValue::Indeterminate, | |||
+ // which is prohibited from being a top-level constant value. Emit a | |||
+ // diagnostic instead. | |||
+ if (index == -1) { | |||
+ Info.FFDiag( | |||
+ E, diag::err_shufflevecto | |||
+ << EltNum; | |||
+ return false; | |||
+ } | |||
+ | |||
+ if (index < 0 || | |||
+ index >= TotalElementsInI | |||
+ llvm_unreachable | |||
+ | |||
+ if (index >= TotalElementsInI | |||
+ Result = VecVal2.getVectorElt(index - TotalElementsInI | |||
+ else | |||
+ Result = VecVal1.getVectorElt(index); | |||
+ return true; | |||
+} | |||
+ | |||
+bool VectorExprEvalua | |||
+ APValue VecVal1; | |||
+ const Expr *Vec1 = E->getExpr(0); | |||
+ if (!EvaluateAsRValue | |||
+ return false; | |||
+ APValue VecVal2; | |||
+ const Expr *Vec2 = E->getExpr(1); | |||
+ if (!EvaluateAsRValue | |||
+ return false; | |||
+ | |||
+ VectorType const *DestVecTy = E->getType()->castAs<VectorType>(); | |||
+ QualType DestElTy = DestVecTy->getElementType(); | |||
+ | |||
+ auto TotalElementsInO | |||
+ | |||
+ SmallVector<APValue, 4> ResultElements; | |||
+ ResultElements.reserve(TotalElementsInO | |||
+ for (unsigned EltNum = 0; EltNum < TotalElementsInO | |||
+ APValue Elt; | |||
+ if (!handleVectorShuf | |||
+ return false; | |||
+ ResultElements.push_back(std::move(Elt)); | |||
+ } | |||
+ | |||
+ return Success(APValue(ResultElements.data(), ResultElements.size()), E); | |||
+} | |||
+ | |||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||
// Array Evaluation | // Array Evaluation | ||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||
@@ -16130,7 +16254,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { | |||
case Expr::StringLiteralCla | case Expr::StringLiteralCla | ||
case Expr::ArraySubscriptEx | case Expr::ArraySubscriptEx | ||
case Expr::MatrixSubscriptE | case Expr::MatrixSubscriptE | ||
- case | + case Expr::ArraySectionExprClass: | ||
case Expr::OMPArrayShapingE | case Expr::OMPArrayShapingE | ||
case Expr::OMPIteratorExprC | case Expr::OMPIteratorExprC | ||
case Expr::MemberExprClass: | case Expr::MemberExprClass: |
@@ -68,7 +68,7 @@ bool ExternalASTSourc | |||
return false; | return false; | ||
} | } | ||
-Decl *ExternalASTSource::GetExternalDecl( | +Decl *ExternalASTSource::GetExternalDecl(GlobalDeclID ID) { return nullptr; } | ||
Selector ExternalASTSourc | Selector ExternalASTSourc | ||
return Selector(); | return Selector(); |
@@ -110,18 +110,37 @@ bool ByteCodeExprGen< | |||
if (!this->visit(SubExpr)) | if (!this->visit(SubExpr)) | ||
return false; | return false; | ||
- unsigned DerivedOffset = collectBaseOffse | + const auto extractRecordDec | ||
- getRecordTy(SubExpr->getType())); | + if (const auto *PT = dyn_cast<PointerType>(Ty)) | ||
+ return PT->getPointeeType()->getAsCXXRecordDe | |||
+ return Ty->getAsCXXRecordDe | |||
+ }; | |||
- return this->emitGetPtrBasePo | + // FIXME: We can express a series of non-virtual casts as a single | ||
+ // GetPtrBasePop op. | |||
+ QualType CurType = SubExpr->getType(); | |||
+ for (const CXXBaseSpecifier | |||
+ if (B->isVirtual()) { | |||
+ if (!this->emitGetPtrVirtBa | |||
+ return false; | |||
+ CurType = B->getType(); | |||
+ } else { | |||
+ unsigned DerivedOffset = collectBaseOffse | |||
+ if (!this->emitGetPtrBasePo | |||
+ return false; | |||
+ CurType = B->getType(); | |||
+ } | |||
+ } | |||
+ | |||
+ return true; | |||
} | } | ||
case CK_BaseToDerived | case CK_BaseToDerived | ||
if (!this->visit(SubExpr)) | if (!this->visit(SubExpr)) | ||
return false; | return false; | ||
- unsigned DerivedOffset = | + unsigned DerivedOffset = | ||
- getRecordTy(CE->getType())); | + collectBaseOffse | ||
return this->emitGetPtrDerive | return this->emitGetPtrDerive | ||
} | } | ||
@@ -193,6 +212,13 @@ bool ByteCodeExprGen< | |||
if (!this->visit(SubExpr)) | if (!this->visit(SubExpr)) | ||
return false; | return false; | ||
+ // If SubExpr doesn't result in a pointer, make it one. | |||
+ if (PrimType FromT = classifyPrim(SubExpr->getType()); FromT != PT_Ptr) { | |||
+ assert(isPtrType(FromT)); | |||
+ if (!this->emitDecayPtr(FromT, PT_Ptr, CE)) | |||
+ return false; | |||
+ } | |||
+ | |||
PrimType T = classifyPrim(CE->getType()); | PrimType T = classifyPrim(CE->getType()); | ||
if (T == PT_IntAP) | if (T == PT_IntAP) | ||
return this->emitCastPointerI | return this->emitCastPointerI | ||
@@ -905,8 +931,31 @@ bool ByteCodeExprGen< | |||
if (std::optional<PrimType> T = classify(QT)) | if (std::optional<PrimType> T = classify(QT)) | ||
return this->visitZeroInitial | return this->visitZeroInitial | ||
- if (QT->isRecordType()) | + if (QT->isRecordType()) { | ||
- return false; | + const RecordDecl *RD = QT->getAsRecordDecl(); | ||
+ assert(RD); | |||
+ if (RD->isInvalidDecl()) | |||
+ return false; | |||
+ if (RD->isUnion()) { | |||
+ // C++11 [dcl.init]p5: If T is a (possibly cv-qualified) union type, the | |||
+ // object's first non-static named data member is zero-initialized | |||
+ // FIXME | |||
+ return false; | |||
+ } | |||
+ | |||
+ if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(RD); | |||
+ CXXRD && CXXRD->getNumVBases() > 0) { | |||
+ // TODO: Diagnose. | |||
+ return false; | |||
+ } | |||
+ | |||
+ const Record *R = getRecord(QT); | |||
+ if (!R) | |||
+ return false; | |||
+ | |||
+ assert(Initializing); | |||
+ return this->visitZeroRecordI | |||
+ } | |||
if (QT->isIncompleteArra | if (QT->isIncompleteArra | ||
return true; | return true; | ||
@@ -981,122 +1030,98 @@ bool ByteCodeExprGen< | |||
template <class Emitter> | template <class Emitter> | ||
bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, | bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits, | ||
+ const Expr *ArrayFiller, | |||
const Expr *E) { | const Expr *E) { | ||
- assert(E->getType()->isRecordType()); | + if (E->getType()->isVoidType()) | ||
- const Record *R = getRecord(E->getType()); | + return this->emitInvalid(E); | ||
- if (Inits.size() == 1 && E->getType() == Inits[0]->getType()) { | + // Handle discarding first. | ||
- return this->visitInitializer | + if (DiscardResult) { | ||
+ for (const Expr *Init : Inits) { | |||
+ if (!this->discard(Init)) | |||
+ return false; | |||
+ } | |||
+ return true; | |||
} | } | ||
- unsigned InitIndex = 0; | + // Primitive values. | ||
- for (const Expr *Init : Inits) { | + if (std::optional<PrimType> T = classify(E->getType())) { | ||
- // Skip unnamed bitfields. | + assert(!DiscardResult); | ||
- while (InitIndex < R->getNumFields() && | + if (Inits.size() == 0) | ||
- R->getField(InitIndex)->Decl->isUnnamedBitFiel | + return this->visitZeroInitial | ||
- ++InitIndex; | + assert(Inits.size() == 1); | ||
+ return this->delegate(Inits[0]); | |||
+ } | |||
- if (!this->emitDupPtr(E)) | + QualType T = E->getType(); | ||
- return false; | + if (T->isRecordType()) { | ||
+ const Record *R = getRecord(E->getType()); | |||
- if (std::optional<PrimType> T = classify(Init)) { | + if (Inits.size() == 1 && E->getType() == Inits[0]->getType()) { | ||
- const Record::Field *FieldToInit = R->getField(InitIndex); | + return this->visitInitializer | ||
- if (!this->visit(Init)) | + } | ||
- return false; | |||
- if (FieldToInit->isBitField()) { | + unsigned InitIndex = 0; | ||
- if (!this->emitInitBitField | + for (const Expr *Init : Inits) { | ||
- return false; | + // Skip unnamed bitfields. | ||
- } else { | + while (InitIndex < R->getNumFields() && | ||
- if (!this->emitInitField(*T, FieldToInit->Offset, E)) | + R->getField(InitIndex)->Decl->isUnnamedBitFiel | ||
- return false; | + ++InitIndex; | ||
- } | |||
- if (!this- | + if (!this->emitDupPtr(E)) | ||
return false; | return false; | ||
- ++InitIndex; | |||
- } else { | |||
- // Initializer for a direct base class. | |||
- if (const Record::Base *B = R->getBase(Init->getType())) { | |||
- if (!this->emitGetPtrBasePo | |||
- return false; | |||
- | |||
- if (!this->visitInitializer | |||
- return false; | |||
- if (!this->emitFinishInitPo | + if (std::optional<PrimType> T = classify(Init)) { | ||
- return false; | |||
- // Base initializers don't increase InitIndex, since they don't count | |||
- // into the Record's fields. | |||
- } else { | |||
const Record::Field *FieldToInit = R->getField(InitIndex); | const Record::Field *FieldToInit = R->getField(InitIndex); | ||
- // Non-primitive case. Get a pointer to the field-to-initialize | + if (!this->visit(Init)) | ||
- // on the stack and recurse into visitInitializer | |||
- if (!this->emitGetPtrField(FieldToInit->Offset, Init)) | |||
return false; | return false; | ||
- if ( | + if (FieldToInit->isBitField()) { | ||
- return false; | + if (!this->emitInitBitField | ||
+ return false; | |||
+ } else { | |||
+ if (!this->emitInitField(*T, FieldToInit->Offset, E)) | |||
+ return false; | |||
+ } | |||
if (!this->emitPopPtr(E)) | if (!this->emitPopPtr(E)) | ||
return false; | return false; | ||
++InitIndex; | ++InitIndex; | ||
- } | + } else { | ||
- } | + // Initializer for a direct base class. | ||
- } | + if (const Record::Base *B = R->getBase(Init->getType())) { | ||
- return true; | + if (!this->emitGetPtrBasePo | ||
-} | + return false; | ||
-/// Pointer to the array(not the element!) must be on the stack when calling | + if (!this->visitInitializer | ||
-/// this. | + return false; | ||
-template <class Emitter> | |||
-bool ByteCodeExprGen<Emitter>::visitArrayElemIn | |||
- const Expr *Init) { | |||
- if (std::optional<PrimType> T = classify(Init->getType())) { | |||
- // Visit the primitive element like normal. | |||
- if (!this->visit(Init)) | |||
- return false; | |||
- return this->emitInitElem(*T, ElemIndex, Init); | |||
- } | |||
- // Advance the pointer currently on the stack to the given | + if (!this->emitFinishInitPo | ||
- // dimension. | + return false; | ||
- if (!this->emitConstUint32(ElemIndex, Init)) | + // Base initializers don't increase InitIndex, since they don't count | ||
- return false; | + // into the Record's fields. | ||
- if (!this->emitArrayElemPtr | + } else { | ||
- return false; | + const Record::Field *FieldToInit = R->getField(InitIndex); | ||
- if (!this->visitInitializer | + // Non-primitive case. Get a pointer to the field-to-initialize | ||
- return false; | + // on the stack and recurse into visitInitializer | ||
- return this->emitFinishInitPo | + if (!this->emitGetPtrField(FieldToInit->Offset, Init)) | ||
-} | + return false; | ||
-template <class Emitter> | + if (!this->visitInitializer | ||
-bool ByteCodeExprGen<Emitter>::VisitInitListExp | + return false; | ||
- // Handle discarding first. | + | ||
- if (DiscardResult) { | + if (!this->emitPopPtr(E)) | ||
- for (const Expr *Init : E->inits()) { | + return false; | ||
- if (!this->discard(Init)) | + ++InitIndex; | ||
- | + } | ||
+ } | |||
} | } | ||
return true; | return true; | ||
} | } | ||
- // Primitive values. | |||
- if (std::optional<PrimType> T = classify(E->getType())) { | |||
- assert(!DiscardResult); | |||
- if (E->getNumInits() == 0) | |||
- return this->visitZeroInitial | |||
- assert(E->getNumInits() == 1); | |||
- return this->delegate(E->inits()[0]); | |||
- } | |||
- | |||
- QualType T = E->getType(); | |||
- if (T->isRecordType()) | |||
- return this->visitInitList(E->inits(), E); | |||
- | |||
if (T->isArrayType()) { | if (T->isArrayType()) { | ||
unsigned ElementIndex = 0; | unsigned ElementIndex = 0; | ||
- for (const Expr *Init : | + for (const Expr *Init : Inits) { | ||
[diff truncated] |