diff --git a/.ci/generate-buildkite-pipeline-premerge b/.ci/generate-buildkite-pipeline-premerge
index 2e503c867403bcf6fc56f6eed024229b82a0cc1d..81e9246de9b5895d1ab099a6b8a9919f2f569416 100755
--- a/.ci/generate-buildkite-pipeline-premerge
+++ b/.ci/generate-buildkite-pipeline-premerge
@@ -108,7 +108,7 @@ function add-dependencies() {
compiler-rt|libc|openmp)
echo clang lld
;;
- flang|lldb)
+ flang|lldb|libclc)
for p in llvm clang; do
echo $p
done
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 76b8266cae87c4b0b3fbf90e4bf72626aad7c9f3..37aea5f6657f01f9b3da1a81bedf3103ad8bddd1 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -113,7 +113,11 @@ clang/test/AST/Interp/ @tbaederr
# MLIR NVVM Dialect in MLIR
/mlir/**/LLVMIR/**/BasicPtxBuilderInterface* @grypp
-/mlir/**/NVVM*/ @grypp
+/mlir/**/NVVM* @grypp
+
+# MLIR Python Bindings
+/mlir/test/python/ @ftynse @makslevental @stellaraccident
+/mlir/python/ @ftynse @makslevental @stellaraccident
# BOLT
/bolt/ @aaupov @maksfb @rafaelauler @ayermolo @dcci
diff --git a/.github/new-prs-labeler.yml b/.github/new-prs-labeler.yml
index a0428336d300f9ac3d4eaff2f2daf4100e4ccdfc..9cf64417d3cb2cce3a61707ae1693e692c6e1a0e 100644
--- a/.github/new-prs-labeler.yml
+++ b/.github/new-prs-labeler.yml
@@ -1,3 +1,9 @@
+ClangIR:
+ - clang/include/clang/CIR/**/*
+ - clang/lib/CIR/**/*
+ - clang/tools/cir-*/**/*
+ - clang/test/CIR/**/*
+
clang:dataflow:
- clang/include/clang/Analysis/FlowSensitive/**/*
- clang/lib/Analysis/FlowSensitive/**/*
@@ -938,3 +944,6 @@ openmp:libomptarget:
bazel:
- utils/bazel/**
+
+offload:
+ - offload/**
diff --git a/.github/workflows/email-check.yaml b/.github/workflows/email-check.yaml
index ac53b5e527b0949020e0e73d90def5d2b6295cd0..8f32d020975f5d70e7eead9c34a0ea86fb836e81 100644
--- a/.github/workflows/email-check.yaml
+++ b/.github/workflows/email-check.yaml
@@ -1,7 +1,7 @@
name: "Check for private emails used in PRs"
on:
- pull_request_target:
+ pull_request:
types:
- opened
@@ -10,8 +10,6 @@ permissions:
jobs:
validate_email:
- permissions:
- pull-requests: write
runs-on: ubuntu-latest
if: github.repository == 'llvm/llvm-project'
steps:
@@ -25,20 +23,24 @@ jobs:
run: |
git log -1
echo "EMAIL=$(git show -s --format='%ae' HEAD~0)" >> $GITHUB_OUTPUT
+ # Create empty comment file
+ echo "[]" > comments
- name: Validate author email
if: ${{ endsWith(steps.author.outputs.EMAIL, 'noreply.github.com') }}
- uses: actions/github-script@v6
env:
- EMAIL: ${{ steps.author.outputs.EMAIL }}
+ COMMENT: >-
+ ⚠️ We detected that you are using a GitHub private e-mail address to contribute to the repo.
+ Please turn off [Keep my email addresses private](https://github.com/settings/emails) setting in your account.
+ See [LLVM Discourse](https://discourse.llvm.org/t/hidden-emails-on-github-should-we-do-something-about-it) for more information.
+ run: |
+ cat << EOF > comments
+ [{"body" : "$COMMENT"}]
+ EOF
+
+ - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0
+ if: always()
with:
- script: |
- const { EMAIL } = process.env
- await github.rest.issues.createComment({
- issue_number: context.issue.number,
- owner: context.repo.owner,
- repo: context.repo.repo,
- body: `⚠️ We detected that you are using a GitHub private e-mail address to contribute to the repo.
- Please turn off [Keep my email addresses private](https://github.com/settings/emails) setting in your account.
- See [LLVM Discourse](https://discourse.llvm.org/t/hidden-emails-on-github-should-we-do-something-about-it) for more information.
- `})
+ name: workflow-args
+ path: |
+ comments
diff --git a/.github/workflows/issue-write.yml b/.github/workflows/issue-write.yml
index 4a564a5076bac9a7855d69b59a1a60f088300163..e003be006c4e15405bd977e277b0f9a64e69d2af 100644
--- a/.github/workflows/issue-write.yml
+++ b/.github/workflows/issue-write.yml
@@ -2,7 +2,9 @@ name: Comment on an issue
on:
workflow_run:
- workflows: ["Check code formatting"]
+ workflows:
+ - "Check code formatting"
+ - "Check for private emails used in PRs"
types:
- completed
diff --git a/.github/workflows/libcxx-build-and-test.yaml b/.github/workflows/libcxx-build-and-test.yaml
index 4a881ef5ff56af432500413950890ee8d6563dbc..1e9367732e591118445fef2c69acf3339c2cbf5d 100644
--- a/.github/workflows/libcxx-build-and-test.yaml
+++ b/.github/workflows/libcxx-build-and-test.yaml
@@ -38,11 +38,11 @@ env:
# LLVM POST-BRANCH bump version
# LLVM POST-BRANCH add compiler test for ToT - 1, e.g. "Clang 17"
# LLVM RELEASE bump remove compiler ToT - 3, e.g. "Clang 15"
- LLVM_HEAD_VERSION: "18" # Used compiler, update POST-BRANCH.
- LLVM_PREVIOUS_VERSION: "17"
- LLVM_OLDEST_VERSION: "16"
+ LLVM_HEAD_VERSION: "19" # Used compiler, update POST-BRANCH.
+ LLVM_PREVIOUS_VERSION: "18"
+ LLVM_OLDEST_VERSION: "17"
GCC_STABLE_VERSION: "13"
- LLVM_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer-18"
+ LLVM_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer-19"
CLANG_CRASH_DIAGNOSTICS_DIR: "crash_diagnostics"
@@ -59,8 +59,8 @@ jobs:
'generic-cxx26',
'generic-modules'
]
- cc: [ 'clang-18' ]
- cxx: [ 'clang++-18' ]
+ cc: [ 'clang-19' ]
+ cxx: [ 'clang++-19' ]
clang_tidy: [ 'ON' ]
include:
- config: 'generic-gcc'
@@ -100,22 +100,22 @@ jobs:
'generic-cxx20',
'generic-cxx23'
]
- cc: [ 'clang-18' ]
- cxx: [ 'clang++-18' ]
+ cc: [ 'clang-19' ]
+ cxx: [ 'clang++-19' ]
clang_tidy: [ 'ON' ]
include:
- config: 'generic-gcc-cxx11'
cc: 'gcc-13'
cxx: 'g++-13'
clang_tidy: 'OFF'
- - config: 'generic-cxx23'
- cc: 'clang-16'
- cxx: 'clang++-16'
- clang_tidy: 'OFF'
- config: 'generic-cxx23'
cc: 'clang-17'
cxx: 'clang++-17'
clang_tidy: 'OFF'
+ - config: 'generic-cxx26'
+ cc: 'clang-18'
+ cxx: 'clang++-18'
+ clang_tidy: 'ON'
steps:
- uses: actions/checkout@v4
- name: ${{ matrix.config }}
@@ -186,8 +186,8 @@ jobs:
- name: ${{ matrix.config }}
run: libcxx/utils/ci/run-buildbot ${{ matrix.config }}
env:
- CC: clang-18
- CXX: clang++-18
+ CC: clang-19
+ CXX: clang++-19
ENABLE_CLANG_TIDY: "OFF"
- uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
if: always()
diff --git a/.github/workflows/pr-code-format.yml b/.github/workflows/pr-code-format.yml
index 10b18f245d8965a69251038f44f1505fc40c0cf0..983838858ba43ed90cca953b6b00668d6746f5df 100644
--- a/.github/workflows/pr-code-format.yml
+++ b/.github/workflows/pr-code-format.yml
@@ -1,4 +1,8 @@
name: "Check code formatting"
+
+permissions:
+ contents: read
+
on:
pull_request:
branches:
diff --git a/.github/workflows/release-lit.yml b/.github/workflows/release-lit.yml
index 36b0b6edd518fc74fecf397c8947ff706066a52e..0316ba406041d6fc63c812da994ea662276bee6e 100644
--- a/.github/workflows/release-lit.yml
+++ b/.github/workflows/release-lit.yml
@@ -58,7 +58,7 @@ jobs:
cd llvm/utils/lit
# Remove 'dev' suffix from lit version.
sed -i 's/ + "dev"//g' lit/__init__.py
- python3 setup.py sdist
+ python3 setup.py sdist bdist_wheel
- name: Upload lit to test.pypi.org
uses: pypa/gh-action-pypi-publish@release/v1
diff --git a/bolt/docs/BAT.md b/bolt/docs/BAT.md
index f23ef1abf8761cc58fc2249ef0da43ae0034e114..7ffb5d7c00816e11df469e3de6372e462d1eb616 100644
--- a/bolt/docs/BAT.md
+++ b/bolt/docs/BAT.md
@@ -81,9 +81,10 @@ Hot indices are delta encoded, implicitly starting at zero.
| `FuncHash` | 8b | Function hash for input function | Hot |
| `NumBlocks` | ULEB128 | Number of basic blocks in the original function | Hot |
| `NumSecEntryPoints` | ULEB128 | Number of secondary entry points in the original function | Hot |
+| `ColdInputSkew` | ULEB128 | Skew to apply to all input offsets | Cold |
| `NumEntries` | ULEB128 | Number of address translation entries for a function | Both |
-| `EqualElems` | ULEB128 | Number of equal offsets in the beginning of a function | Hot |
-| `BranchEntries` | Bitmask, `alignTo(EqualElems, 8)` bits | If `EqualElems` is non-zero, bitmask denoting entries with `BRANCHENTRY` bit | Hot |
+| `EqualElems` | ULEB128 | Number of equal offsets in the beginning of a function | Both |
+| `BranchEntries` | Bitmask, `alignTo(EqualElems, 8)` bits | If `EqualElems` is non-zero, bitmask denoting entries with `BRANCHENTRY` bit | Both |
Function header is followed by *Address Translation Table* with `NumEntries`
total entries, and *Secondary Entry Points* table with `NumSecEntryPoints`
@@ -99,8 +100,8 @@ entry is encoded. Input offsets implicitly start at zero.
| `BBHash` | Optional, 8b | Basic block hash in input binary | BB |
| `BBIdx` | Optional, Delta, ULEB128 | Basic block index in input binary | BB |
-For hot fragments, the table omits the first `EqualElems` input offsets
-where the input offset equals output offset.
+The table omits the first `EqualElems` input offsets where the input offset
+equals output offset.
`BRANCHENTRY` bit denotes whether a given offset pair is a control flow source
(branch or call instruction). If not set, it signifies a control flow target
diff --git a/bolt/include/bolt/Core/BinaryData.h b/bolt/include/bolt/Core/BinaryData.h
index 495163f1b61aafd2360b9699fcda4f95844f1dd3..8a67b3e73b802d2a2a620f13bb59b58c7689aa9f 100644
--- a/bolt/include/bolt/Core/BinaryData.h
+++ b/bolt/include/bolt/Core/BinaryData.h
@@ -107,7 +107,6 @@ public:
std::vector &getSymbols() { return Symbols; }
bool hasName(StringRef Name) const;
- bool hasNameRegex(StringRef Name) const;
bool nameStartsWith(StringRef Prefix) const;
bool hasSymbol(const MCSymbol *Symbol) const {
diff --git a/bolt/include/bolt/Core/BinaryFunction.h b/bolt/include/bolt/Core/BinaryFunction.h
index bc047fefa3151c9d32050e71ed3d182005665923..26d2d01f86267127f4c4bea9daa5862b4b412738 100644
--- a/bolt/include/bolt/Core/BinaryFunction.h
+++ b/bolt/include/bolt/Core/BinaryFunction.h
@@ -1402,7 +1402,8 @@ public:
/// Return true if the function has CFI instructions
bool hasCFI() const {
- return !FrameInstructions.empty() || !CIEFrameInstructions.empty();
+ return !FrameInstructions.empty() || !CIEFrameInstructions.empty() ||
+ IsInjected;
}
/// Return unique number associated with the function.
diff --git a/bolt/include/bolt/Profile/BoltAddressTranslation.h b/bolt/include/bolt/Profile/BoltAddressTranslation.h
index caf907cc43da3e8d4af24c6b5be5b5c41293e65c..68b993ee363cc0d0a3bbd59113e4a42c896da4cb 100644
--- a/bolt/include/bolt/Profile/BoltAddressTranslation.h
+++ b/bolt/include/bolt/Profile/BoltAddressTranslation.h
@@ -19,6 +19,7 @@
#include
namespace llvm {
+class MCSymbol;
class raw_ostream;
namespace object {
@@ -118,10 +119,12 @@ public:
/// True if a given \p Address is a function with translation table entry.
bool isBATFunction(uint64_t Address) const { return Maps.count(Address); }
- /// Returns branch offsets grouped by containing basic block in a given
- /// function.
- std::unordered_map>
- getBFBranches(uint64_t FuncOutputAddress) const;
+ /// For a given \p Symbol in the output binary and known \p InputOffset
+ /// return a corresponding pair of parent BinaryFunction and secondary entry
+ /// point in it.
+ std::pair
+ translateSymbol(const BinaryContext &BC, const MCSymbol &Symbol,
+ uint32_t InputOffset) const;
private:
/// Helper to update \p Map by inserting one or more BAT entries reflecting
@@ -146,9 +149,9 @@ private:
/// entries in function address translation map.
APInt calculateBranchEntriesBitMask(MapTy &Map, size_t EqualElems);
- /// Calculate the number of equal offsets (output = input) in the beginning
- /// of the function.
- size_t getNumEqualOffsets(const MapTy &Map) const;
+ /// Calculate the number of equal offsets (output = input - skew) in the
+ /// beginning of the function.
+ size_t getNumEqualOffsets(const MapTy &Map, uint32_t Skew) const;
std::map Maps;
@@ -158,6 +161,10 @@ private:
/// Map a function to its secondary entry points vector
std::unordered_map> SecondaryEntryPointsMap;
+ /// Return a secondary entry point ID for a function located at \p Address and
+ /// \p Offset within that function.
+ unsigned getSecondaryEntryPointId(uint64_t Address, uint32_t Offset) const;
+
/// Links outlined cold bocks to their original function
std::map ColdPartSource;
@@ -181,7 +188,7 @@ public:
EntryTy(unsigned Index, size_t Hash) : Index(Index), Hash(Hash) {}
};
- std::unordered_map Map;
+ std::map Map;
const EntryTy &getEntry(uint32_t BBInputOffset) const {
auto It = Map.find(BBInputOffset);
assert(It != Map.end());
@@ -206,6 +213,10 @@ public:
}
size_t getNumBasicBlocks() const { return Map.size(); }
+
+ auto begin() const { return Map.begin(); }
+ auto end() const { return Map.end(); }
+ auto upper_bound(uint32_t Offset) const { return Map.upper_bound(Offset); }
};
/// Map function output address to its hash and basic blocks hash map.
diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h
index 4fbe524b1c385d24d10cd3a0ea33ca53580f0fc9..84f76caae9dbb01ea38e59f5eb629e0492ddb800 100644
--- a/bolt/include/bolt/Profile/DataAggregator.h
+++ b/bolt/include/bolt/Profile/DataAggregator.h
@@ -225,6 +225,10 @@ private:
/// Aggregation statistics
uint64_t NumInvalidTraces{0};
uint64_t NumLongRangeTraces{0};
+ /// Specifies how many samples were recorded in cold areas if we are dealing
+ /// with profiling data collected in a bolted binary. For LBRs, incremented
+ /// for the source of the branch to avoid counting cold activity twice (one
+ /// for source and another for destination).
uint64_t NumColdSamples{0};
/// Looks into system PATH for Linux Perf and set up the aggregator to use it
@@ -245,14 +249,12 @@ private:
/// disassembled BinaryFunctions
BinaryFunction *getBinaryFunctionContainingAddress(uint64_t Address) const;
+ /// Perform BAT translation for a given \p Func and return the parent
+ /// BinaryFunction or nullptr.
+ BinaryFunction *getBATParentFunction(const BinaryFunction &Func) const;
+
/// Retrieve the location name to be used for samples recorded in \p Func.
- /// If doing BAT translation, link cold parts to the hot part names (used by
- /// the original binary). \p Count specifies how many samples were recorded
- /// at that location, so we can tally total activity in cold areas if we are
- /// dealing with profiling data collected in a bolted binary. For LBRs,
- /// \p Count should only be used for the source of the branch to avoid
- /// counting cold activity twice (one for source and another for destination).
- StringRef getLocationName(BinaryFunction &Func, uint64_t Count);
+ StringRef getLocationName(const BinaryFunction &Func) const;
/// Semantic actions - parser hooks to interpret parsed perf samples
/// Register a sample (non-LBR mode), i.e. a new hit at \p Address
@@ -467,9 +469,6 @@ private:
std::error_code writeBATYAML(BinaryContext &BC,
StringRef OutputFilename) const;
- /// Fixup profile collected on BOLTed binary, namely handle split functions.
- void fixupBATProfile(BinaryContext &BC);
-
/// Filter out binaries based on PID
void filterBinaryMMapInfo();
diff --git a/bolt/include/bolt/Profile/YAMLProfileWriter.h b/bolt/include/bolt/Profile/YAMLProfileWriter.h
index 882748627e7f54aec2a5d0b85d738ce93cf292ee..4a9355dfceac9ec174729553d7b80006a8429d80 100644
--- a/bolt/include/bolt/Profile/YAMLProfileWriter.h
+++ b/bolt/include/bolt/Profile/YAMLProfileWriter.h
@@ -15,6 +15,7 @@
namespace llvm {
namespace bolt {
+class BoltAddressTranslation;
class RewriteInstance;
class YAMLProfileWriter {
@@ -31,8 +32,16 @@ public:
/// Save execution profile for that instance.
std::error_code writeProfile(const RewriteInstance &RI);
- static yaml::bolt::BinaryFunctionProfile convert(const BinaryFunction &BF,
- bool UseDFS);
+ static yaml::bolt::BinaryFunctionProfile
+ convert(const BinaryFunction &BF, bool UseDFS,
+ const BoltAddressTranslation *BAT = nullptr);
+
+ /// Set CallSiteInfo destination fields from \p Symbol and return a target
+ /// BinaryFunction for that symbol.
+ static const BinaryFunction *
+ setCSIDestination(const BinaryContext &BC, yaml::bolt::CallSiteInfo &CSI,
+ const MCSymbol *Symbol, const BoltAddressTranslation *BAT,
+ uint32_t Offset = 0);
};
} // namespace bolt
diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h
index 826677cd63b22b1a0abef55837f4c254a7b7ee84..af832b4c7c84cf32b059f99adba4ed4df6fc5b19 100644
--- a/bolt/include/bolt/Rewrite/RewriteInstance.h
+++ b/bolt/include/bolt/Rewrite/RewriteInstance.h
@@ -368,13 +368,6 @@ private:
/// rewritten binary.
void patchBuildID();
- /// Return file offset corresponding to a given virtual address.
- uint64_t getFileOffsetFor(uint64_t Address) {
- assert(Address >= NewTextSegmentAddress &&
- "address in not in the new text segment");
- return Address - NewTextSegmentAddress + NewTextSegmentOffset;
- }
-
/// Return file offset corresponding to a virtual \p Address.
/// Return 0 if the address has no mapping in the file, including being
/// part of .bss section.
@@ -398,9 +391,6 @@ public:
/// Return true if the section holds debug information.
static bool isDebugSection(StringRef SectionName);
- /// Return true if the section holds linux kernel symbol information.
- static bool isKSymtabSection(StringRef SectionName);
-
/// Adds Debug section to overwrite.
static void addToDebugSectionsToOverwrite(const char *Section) {
DebugSectionsToOverwrite.emplace_back(Section);
diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp
index 47eae964e816c5565697bdc2ef974bdfecdff4dc..ad2eb18caf109b0c987b1e568404649142599c9c 100644
--- a/bolt/lib/Core/BinaryContext.cpp
+++ b/bolt/lib/Core/BinaryContext.cpp
@@ -555,6 +555,9 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
const uint64_t NextJTAddress,
JumpTable::AddressesType *EntriesAsAddress,
bool *HasEntryInFragment) const {
+ // Target address of __builtin_unreachable.
+ const uint64_t UnreachableAddress = BF.getAddress() + BF.getSize();
+
// Is one of the targets __builtin_unreachable?
bool HasUnreachable = false;
@@ -564,9 +567,15 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
// Number of targets other than __builtin_unreachable.
uint64_t NumRealEntries = 0;
- auto addEntryAddress = [&](uint64_t EntryAddress) {
- if (EntriesAsAddress)
- EntriesAsAddress->emplace_back(EntryAddress);
+ // Size of the jump table without trailing __builtin_unreachable entries.
+ size_t TrimmedSize = 0;
+
+ auto addEntryAddress = [&](uint64_t EntryAddress, bool Unreachable = false) {
+ if (!EntriesAsAddress)
+ return;
+ EntriesAsAddress->emplace_back(EntryAddress);
+ if (!Unreachable)
+ TrimmedSize = EntriesAsAddress->size();
};
ErrorOr Section = getSectionForAddress(Address);
@@ -618,8 +627,8 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
: *getPointerAtAddress(EntryAddress);
// __builtin_unreachable() case.
- if (Value == BF.getAddress() + BF.getSize()) {
- addEntryAddress(Value);
+ if (Value == UnreachableAddress) {
+ addEntryAddress(Value, /*Unreachable*/ true);
HasUnreachable = true;
LLVM_DEBUG(dbgs() << formatv("OK: {0:x} __builtin_unreachable\n", Value));
continue;
@@ -673,6 +682,13 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
addEntryAddress(Value);
}
+ // Trim direct/normal jump table to exclude trailing unreachable entries that
+ // can collide with a function address.
+ if (Type == JumpTable::JTT_NORMAL && EntriesAsAddress &&
+ TrimmedSize != EntriesAsAddress->size() &&
+ getBinaryFunctionAtAddress(UnreachableAddress))
+ EntriesAsAddress->resize(TrimmedSize);
+
// It's a jump table if the number of real entries is more than 1, or there's
// one real entry and one or more special targets. If there are only multiple
// special targets, then it's not a jump table.
@@ -1864,7 +1880,7 @@ MarkerSymType BinaryContext::getMarkerType(const SymbolRef &Symbol) const {
// For aarch64 and riscv, the ABI defines mapping symbols so we identify data
// in the code section (see IHI0056B). $x identifies a symbol starting code or
// the end of a data chunk inside code, $d identifies start of data.
- if ((!isAArch64() && !isRISCV()) || ELFSymbolRef(Symbol).getSize())
+ if (isX86() || ELFSymbolRef(Symbol).getSize())
return MarkerSymType::NONE;
Expected NameOrError = Symbol.getName();
diff --git a/bolt/lib/Core/BinaryData.cpp b/bolt/lib/Core/BinaryData.cpp
index 0068a935800429f6b9f4cf0c56cef813f0af0486..e9ddf08d8695f468907a34db47610ea2cd9865de 100644
--- a/bolt/lib/Core/BinaryData.cpp
+++ b/bolt/lib/Core/BinaryData.cpp
@@ -55,14 +55,6 @@ bool BinaryData::hasName(StringRef Name) const {
return false;
}
-bool BinaryData::hasNameRegex(StringRef NameRegex) const {
- Regex MatchName(NameRegex);
- for (const MCSymbol *Symbol : Symbols)
- if (MatchName.match(Symbol->getName()))
- return true;
- return false;
-}
-
bool BinaryData::nameStartsWith(StringRef Prefix) const {
for (const MCSymbol *Symbol : Symbols)
if (Symbol->getName().starts_with(Prefix))
diff --git a/bolt/lib/Core/BinaryEmitter.cpp b/bolt/lib/Core/BinaryEmitter.cpp
index 97d19b75200f51d0a4f6ea928e75cb2e8c70d222..6f86ddc774544a6e7a65d098b0c22e2962cbf2fd 100644
--- a/bolt/lib/Core/BinaryEmitter.cpp
+++ b/bolt/lib/Core/BinaryEmitter.cpp
@@ -512,7 +512,7 @@ void BinaryEmitter::emitFunctionBody(BinaryFunction &BF, FunctionFragment &FF,
// Emit sized NOPs via MCAsmBackend::writeNopData() interface on x86.
// This is a workaround for invalid NOPs handling by asm/disasm layer.
- if (BC.MIB->isNoop(Instr) && BC.isX86()) {
+ if (BC.isX86() && BC.MIB->isNoop(Instr)) {
if (std::optional Size = BC.MIB->getSize(Instr)) {
SmallString<15> Code;
raw_svector_ostream VecOS(Code);
diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp
index cbf95a7db08b52bc95856a90fd5266560fef7c2a..4e888a5b147aca41eb24a0b2237e21f80c38c0a6 100644
--- a/bolt/lib/Core/Relocation.cpp
+++ b/bolt/lib/Core/Relocation.cpp
@@ -774,60 +774,95 @@ static bool isPCRelativeRISCV(uint64_t Type) {
}
bool Relocation::isSupported(uint64_t Type) {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ return false;
+ case Triple::aarch64:
return isSupportedAArch64(Type);
- if (Arch == Triple::riscv64)
+ case Triple::riscv64:
return isSupportedRISCV(Type);
- return isSupportedX86(Type);
+ case Triple::x86_64:
+ return isSupportedX86(Type);
+ }
}
size_t Relocation::getSizeForType(uint64_t Type) {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
return getSizeForTypeAArch64(Type);
- if (Arch == Triple::riscv64)
+ case Triple::riscv64:
return getSizeForTypeRISCV(Type);
- return getSizeForTypeX86(Type);
+ case Triple::x86_64:
+ return getSizeForTypeX86(Type);
+ }
}
bool Relocation::skipRelocationType(uint64_t Type) {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
return skipRelocationTypeAArch64(Type);
- if (Arch == Triple::riscv64)
+ case Triple::riscv64:
return skipRelocationTypeRISCV(Type);
- return skipRelocationTypeX86(Type);
+ case Triple::x86_64:
+ return skipRelocationTypeX86(Type);
+ }
}
bool Relocation::skipRelocationProcess(uint64_t &Type, uint64_t Contents) {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
return skipRelocationProcessAArch64(Type, Contents);
- if (Arch == Triple::riscv64)
- skipRelocationProcessRISCV(Type, Contents);
- return skipRelocationProcessX86(Type, Contents);
+ case Triple::riscv64:
+ return skipRelocationProcessRISCV(Type, Contents);
+ case Triple::x86_64:
+ return skipRelocationProcessX86(Type, Contents);
+ }
}
uint64_t Relocation::encodeValue(uint64_t Type, uint64_t Value, uint64_t PC) {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
return encodeValueAArch64(Type, Value, PC);
- if (Arch == Triple::riscv64)
+ case Triple::riscv64:
return encodeValueRISCV(Type, Value, PC);
- return encodeValueX86(Type, Value, PC);
+ case Triple::x86_64:
+ return encodeValueX86(Type, Value, PC);
+ }
}
uint64_t Relocation::extractValue(uint64_t Type, uint64_t Contents,
uint64_t PC) {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
return extractValueAArch64(Type, Contents, PC);
- if (Arch == Triple::riscv64)
+ case Triple::riscv64:
return extractValueRISCV(Type, Contents, PC);
- return extractValueX86(Type, Contents, PC);
+ case Triple::x86_64:
+ return extractValueX86(Type, Contents, PC);
+ }
}
bool Relocation::isGOT(uint64_t Type) {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
return isGOTAArch64(Type);
- if (Arch == Triple::riscv64)
+ case Triple::riscv64:
return isGOTRISCV(Type);
- return isGOTX86(Type);
+ case Triple::x86_64:
+ return isGOTX86(Type);
+ }
}
bool Relocation::isX86GOTPCRELX(uint64_t Type) {
@@ -845,27 +880,42 @@ bool Relocation::isX86GOTPC64(uint64_t Type) {
bool Relocation::isNone(uint64_t Type) { return Type == getNone(); }
bool Relocation::isRelative(uint64_t Type) {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
return Type == ELF::R_AARCH64_RELATIVE;
- if (Arch == Triple::riscv64)
+ case Triple::riscv64:
return Type == ELF::R_RISCV_RELATIVE;
- return Type == ELF::R_X86_64_RELATIVE;
+ case Triple::x86_64:
+ return Type == ELF::R_X86_64_RELATIVE;
+ }
}
bool Relocation::isIRelative(uint64_t Type) {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
return Type == ELF::R_AARCH64_IRELATIVE;
- if (Arch == Triple::riscv64)
+ case Triple::riscv64:
llvm_unreachable("not implemented");
- return Type == ELF::R_X86_64_IRELATIVE;
+ case Triple::x86_64:
+ return Type == ELF::R_X86_64_IRELATIVE;
+ }
}
bool Relocation::isTLS(uint64_t Type) {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
return isTLSAArch64(Type);
- if (Arch == Triple::riscv64)
+ case Triple::riscv64:
return isTLSRISCV(Type);
- return isTLSX86(Type);
+ case Triple::x86_64:
+ return isTLSX86(Type);
+ }
}
bool Relocation::isInstructionReference(uint64_t Type) {
@@ -882,49 +932,81 @@ bool Relocation::isInstructionReference(uint64_t Type) {
}
uint64_t Relocation::getNone() {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
return ELF::R_AARCH64_NONE;
- if (Arch == Triple::riscv64)
+ case Triple::riscv64:
return ELF::R_RISCV_NONE;
- return ELF::R_X86_64_NONE;
+ case Triple::x86_64:
+ return ELF::R_X86_64_NONE;
+ }
}
uint64_t Relocation::getPC32() {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
return ELF::R_AARCH64_PREL32;
- if (Arch == Triple::riscv64)
+ case Triple::riscv64:
return ELF::R_RISCV_32_PCREL;
- return ELF::R_X86_64_PC32;
+ case Triple::x86_64:
+ return ELF::R_X86_64_PC32;
+ }
}
uint64_t Relocation::getPC64() {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
return ELF::R_AARCH64_PREL64;
- if (Arch == Triple::riscv64)
+ case Triple::riscv64:
llvm_unreachable("not implemented");
- return ELF::R_X86_64_PC64;
+ case Triple::x86_64:
+ return ELF::R_X86_64_PC64;
+ }
}
bool Relocation::isPCRelative(uint64_t Type) {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
return isPCRelativeAArch64(Type);
- if (Arch == Triple::riscv64)
+ case Triple::riscv64:
return isPCRelativeRISCV(Type);
- return isPCRelativeX86(Type);
+ case Triple::x86_64:
+ return isPCRelativeX86(Type);
+ }
}
uint64_t Relocation::getAbs64() {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
return ELF::R_AARCH64_ABS64;
- if (Arch == Triple::riscv64)
+ case Triple::riscv64:
return ELF::R_RISCV_64;
- return ELF::R_X86_64_64;
+ case Triple::x86_64:
+ return ELF::R_X86_64_64;
+ }
}
uint64_t Relocation::getRelative() {
- if (Arch == Triple::aarch64)
+ switch (Arch) {
+ default:
+ llvm_unreachable("Unsupported architecture");
+ case Triple::aarch64:
return ELF::R_AARCH64_RELATIVE;
- return ELF::R_X86_64_RELATIVE;
+ case Triple::riscv64:
+ llvm_unreachable("not implemented");
+ case Triple::x86_64:
+ return ELF::R_X86_64_RELATIVE;
+ }
}
size_t Relocation::emit(MCStreamer *Streamer) const {
@@ -982,32 +1064,47 @@ MCBinaryExpr::Opcode Relocation::getComposeOpcodeFor(uint64_t Type) {
}
}
-#define ELF_RELOC(name, value) #name,
-
void Relocation::print(raw_ostream &OS) const {
- static const char *X86RelocNames[] = {
-#include "llvm/BinaryFormat/ELFRelocs/x86_64.def"
- };
- static const char *AArch64RelocNames[] = {
+ switch (Arch) {
+ default:
+ OS << "RType:" << Twine::utohexstr(Type);
+ break;
+
+ case Triple::aarch64:
+ static const char *const AArch64RelocNames[] = {
+#define ELF_RELOC(name, value) #name,
#include "llvm/BinaryFormat/ELFRelocs/AArch64.def"
- };
- if (Arch == Triple::aarch64)
+#undef ELF_RELOC
+ };
+ assert(Type < ArrayRef(AArch64RelocNames).size());
OS << AArch64RelocNames[Type];
- else if (Arch == Triple::riscv64) {
+ break;
+
+ case Triple::riscv64:
// RISC-V relocations are not sequentially numbered so we cannot use an
// array
switch (Type) {
default:
llvm_unreachable("illegal RISC-V relocation");
-#undef ELF_RELOC
#define ELF_RELOC(name, value) \
case value: \
OS << #name; \
break;
#include "llvm/BinaryFormat/ELFRelocs/RISCV.def"
+#undef ELF_RELOC
}
- } else
+ break;
+
+ case Triple::x86_64:
+ static const char *const X86RelocNames[] = {
+#define ELF_RELOC(name, value) #name,
+#include "llvm/BinaryFormat/ELFRelocs/x86_64.def"
+#undef ELF_RELOC
+ };
+ assert(Type < ArrayRef(X86RelocNames).size());
OS << X86RelocNames[Type];
+ break;
+ }
OS << ", 0x" << Twine::utohexstr(Offset);
if (Symbol) {
OS << ", " << Symbol->getName();
diff --git a/bolt/lib/Profile/BoltAddressTranslation.cpp b/bolt/lib/Profile/BoltAddressTranslation.cpp
index bcd4a457ce3b491908b0a1617e66bee322cdd7c6..7cfb9c132c2c68f98c59df0ada96c7820ef7eb94 100644
--- a/bolt/lib/Profile/BoltAddressTranslation.cpp
+++ b/bolt/lib/Profile/BoltAddressTranslation.cpp
@@ -100,7 +100,7 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) {
LLVM_DEBUG(dbgs() << "Function name: " << Function.getPrintName() << "\n");
LLVM_DEBUG(dbgs() << " Address reference: 0x"
<< Twine::utohexstr(Function.getOutputAddress()) << "\n");
- LLVM_DEBUG(dbgs() << formatv(" Hash: {0:x}\n", getBFHash(OutputAddress)));
+ LLVM_DEBUG(dbgs() << formatv(" Hash: {0:x}\n", getBFHash(InputAddress)));
LLVM_DEBUG(dbgs() << " Secondary Entry Points: " << NumSecondaryEntryPoints
<< '\n');
@@ -153,12 +153,13 @@ APInt BoltAddressTranslation::calculateBranchEntriesBitMask(MapTy &Map,
return BitMask;
}
-size_t BoltAddressTranslation::getNumEqualOffsets(const MapTy &Map) const {
+size_t BoltAddressTranslation::getNumEqualOffsets(const MapTy &Map,
+ uint32_t Skew) const {
size_t EqualOffsets = 0;
for (const std::pair &KeyVal : Map) {
const uint32_t OutputOffset = KeyVal.first;
const uint32_t InputOffset = KeyVal.second >> 1;
- if (OutputOffset == InputOffset)
+ if (OutputOffset == InputOffset - Skew)
++EqualOffsets;
else
break;
@@ -196,18 +197,24 @@ void BoltAddressTranslation::writeMaps(std::map &Maps,
SecondaryEntryPointsMap.count(Address)
? SecondaryEntryPointsMap[Address].size()
: 0;
+ uint32_t Skew = 0;
if (Cold) {
- size_t HotIndex =
- std::distance(ColdPartSource.begin(), ColdPartSource.find(Address));
+ auto HotEntryIt = Maps.find(ColdPartSource[Address]);
+ assert(HotEntryIt != Maps.end());
+ size_t HotIndex = std::distance(Maps.begin(), HotEntryIt);
encodeULEB128(HotIndex - PrevIndex, OS);
PrevIndex = HotIndex;
+ // Skew of all input offsets for cold fragments is simply the first input
+ // offset.
+ Skew = Map.begin()->second >> 1;
+ encodeULEB128(Skew, OS);
} else {
// Function hash
size_t BFHash = getBFHash(HotInputAddress);
LLVM_DEBUG(dbgs() << "Hash: " << formatv("{0:x}\n", BFHash));
OS.write(reinterpret_cast(&BFHash), 8);
// Number of basic blocks
- size_t NumBasicBlocks = getBBHashMap(HotInputAddress).getNumBasicBlocks();
+ size_t NumBasicBlocks = NumBasicBlocksMap[HotInputAddress];
LLVM_DEBUG(dbgs() << "Basic blocks: " << NumBasicBlocks << '\n');
encodeULEB128(NumBasicBlocks, OS);
// Secondary entry points
@@ -216,24 +223,21 @@ void BoltAddressTranslation::writeMaps(std::map &Maps,
<< '\n');
}
encodeULEB128(NumEntries, OS);
- // For hot fragments only: encode the number of equal offsets
- // (output = input) in the beginning of the function. Only encode one offset
- // in these cases.
- const size_t EqualElems = Cold ? 0 : getNumEqualOffsets(Map);
- if (!Cold) {
- encodeULEB128(EqualElems, OS);
- if (EqualElems) {
- const size_t BranchEntriesBytes = alignTo(EqualElems, 8) / 8;
- APInt BranchEntries = calculateBranchEntriesBitMask(Map, EqualElems);
- OS.write(reinterpret_cast(BranchEntries.getRawData()),
- BranchEntriesBytes);
- LLVM_DEBUG({
- dbgs() << "BranchEntries: ";
- SmallString<8> BitMaskStr;
- BranchEntries.toString(BitMaskStr, 2, false);
- dbgs() << BitMaskStr << '\n';
- });
- }
+ // Encode the number of equal offsets (output = input - skew) in the
+ // beginning of the function. Only encode one offset in these cases.
+ const size_t EqualElems = getNumEqualOffsets(Map, Skew);
+ encodeULEB128(EqualElems, OS);
+ if (EqualElems) {
+ const size_t BranchEntriesBytes = alignTo(EqualElems, 8) / 8;
+ APInt BranchEntries = calculateBranchEntriesBitMask(Map, EqualElems);
+ OS.write(reinterpret_cast(BranchEntries.getRawData()),
+ BranchEntriesBytes);
+ LLVM_DEBUG({
+ dbgs() << "BranchEntries: ";
+ SmallString<8> BitMaskStr;
+ BranchEntries.toString(BitMaskStr, 2, false);
+ dbgs() << BitMaskStr << '\n';
+ });
}
const BBHashMapTy &BBHashMap = getBBHashMap(HotInputAddress);
size_t Index = 0;
@@ -314,10 +318,12 @@ void BoltAddressTranslation::parseMaps(std::vector &HotFuncs,
uint64_t HotAddress = Cold ? 0 : Address;
PrevAddress = Address;
uint32_t SecondaryEntryPoints = 0;
+ uint64_t ColdInputSkew = 0;
if (Cold) {
HotIndex += DE.getULEB128(&Offset, &Err);
HotAddress = HotFuncs[HotIndex];
ColdPartSource.emplace(Address, HotAddress);
+ ColdInputSkew = DE.getULEB128(&Offset, &Err);
} else {
HotFuncs.push_back(Address);
// Function hash
@@ -338,28 +344,25 @@ void BoltAddressTranslation::parseMaps(std::vector &HotFuncs,
getULEB128Size(SecondaryEntryPoints)));
}
const uint32_t NumEntries = DE.getULEB128(&Offset, &Err);
- // Equal offsets, hot fragments only.
- size_t EqualElems = 0;
+ // Equal offsets.
+ const size_t EqualElems = DE.getULEB128(&Offset, &Err);
APInt BEBitMask;
- if (!Cold) {
- EqualElems = DE.getULEB128(&Offset, &Err);
- LLVM_DEBUG(dbgs() << formatv("Equal offsets: {0}, {1} bytes\n",
- EqualElems, getULEB128Size(EqualElems)));
- if (EqualElems) {
- const size_t BranchEntriesBytes = alignTo(EqualElems, 8) / 8;
- BEBitMask = APInt(alignTo(EqualElems, 8), 0);
- LoadIntFromMemory(
- BEBitMask,
- reinterpret_cast(
- DE.getBytes(&Offset, BranchEntriesBytes, &Err).data()),
- BranchEntriesBytes);
- LLVM_DEBUG({
- dbgs() << "BEBitMask: ";
- SmallString<8> BitMaskStr;
- BEBitMask.toString(BitMaskStr, 2, false);
- dbgs() << BitMaskStr << ", " << BranchEntriesBytes << " bytes\n";
- });
- }
+ LLVM_DEBUG(dbgs() << formatv("Equal offsets: {0}, {1} bytes\n", EqualElems,
+ getULEB128Size(EqualElems)));
+ if (EqualElems) {
+ const size_t BranchEntriesBytes = alignTo(EqualElems, 8) / 8;
+ BEBitMask = APInt(alignTo(EqualElems, 8), 0);
+ LoadIntFromMemory(
+ BEBitMask,
+ reinterpret_cast(
+ DE.getBytes(&Offset, BranchEntriesBytes, &Err).data()),
+ BranchEntriesBytes);
+ LLVM_DEBUG({
+ dbgs() << "BEBitMask: ";
+ SmallString<8> BitMaskStr;
+ BEBitMask.toString(BitMaskStr, 2, false);
+ dbgs() << BitMaskStr << ", " << BranchEntriesBytes << " bytes\n";
+ });
}
MapTy Map;
@@ -374,7 +377,7 @@ void BoltAddressTranslation::parseMaps(std::vector &HotFuncs,
PrevAddress = OutputAddress;
int64_t InputDelta = 0;
if (J < EqualElems) {
- InputOffset = (OutputOffset << 1) | BEBitMask[J];
+ InputOffset = ((OutputOffset + ColdInputSkew) << 1) | BEBitMask[J];
} else {
InputDelta = DE.getSLEB128(&Offset, &Err);
InputOffset += InputDelta;
@@ -425,8 +428,9 @@ void BoltAddressTranslation::dump(raw_ostream &OS) {
for (const auto &MapEntry : Maps) {
const uint64_t Address = MapEntry.first;
const uint64_t HotAddress = fetchParentAddress(Address);
+ const bool IsHotFunction = HotAddress == 0;
OS << "Function Address: 0x" << Twine::utohexstr(Address);
- if (HotAddress == 0)
+ if (IsHotFunction)
OS << formatv(", hash: {0:x}", getBFHash(Address));
OS << "\n";
OS << "BB mappings:\n";
@@ -443,6 +447,8 @@ void BoltAddressTranslation::dump(raw_ostream &OS) {
OS << formatv(" hash: {0:x}", BBHashMap.getBBHash(Val));
OS << "\n";
}
+ if (IsHotFunction)
+ OS << "NumBlocks: " << NumBasicBlocksMap[Address] << '\n';
if (SecondaryEntryPointsMap.count(Address)) {
const std::vector &SecondaryEntryPoints =
SecondaryEntryPointsMap[Address];
@@ -574,27 +580,52 @@ void BoltAddressTranslation::saveMetadata(BinaryContext &BC) {
// Set BF/BB metadata
for (const BinaryBasicBlock &BB : BF)
BBHashMap.addEntry(BB.getInputOffset(), BB.getIndex(), BB.getHash());
+ NumBasicBlocksMap.emplace(BF.getAddress(), BF.size());
}
}
-std::unordered_map>
-BoltAddressTranslation::getBFBranches(uint64_t OutputAddress) const {
- std::unordered_map> Branches;
- auto FuncIt = Maps.find(OutputAddress);
- assert(FuncIt != Maps.end());
- std::vector InputOffsets;
- for (const auto &KV : FuncIt->second)
- InputOffsets.emplace_back(KV.second);
- // Sort with LSB BRANCHENTRY bit.
- llvm::sort(InputOffsets);
- uint32_t BBOffset{0};
- for (uint32_t InOffset : InputOffsets) {
- if (InOffset & BRANCHENTRY)
- Branches[BBOffset].push_back(InOffset >> 1);
- else
- BBOffset = InOffset >> 1;
- }
- return Branches;
+unsigned
+BoltAddressTranslation::getSecondaryEntryPointId(uint64_t Address,
+ uint32_t Offset) const {
+ auto FunctionIt = SecondaryEntryPointsMap.find(Address);
+ if (FunctionIt == SecondaryEntryPointsMap.end())
+ return 0;
+ const std::vector &Offsets = FunctionIt->second;
+ auto OffsetIt = std::find(Offsets.begin(), Offsets.end(), Offset);
+ if (OffsetIt == Offsets.end())
+ return 0;
+ // Adding one here because main entry point is not stored in BAT, and
+ // enumeration for secondary entry points starts with 1.
+ return OffsetIt - Offsets.begin() + 1;
+}
+
+std::pair
+BoltAddressTranslation::translateSymbol(const BinaryContext &BC,
+ const MCSymbol &Symbol,
+ uint32_t Offset) const {
+ // The symbol could be a secondary entry in a cold fragment.
+ uint64_t SymbolValue = cantFail(errorOrToExpected(BC.getSymbolValue(Symbol)));
+
+ const BinaryFunction *Callee = BC.getFunctionForSymbol(&Symbol);
+ assert(Callee);
+
+ // Containing function, not necessarily the same as symbol value.
+ const uint64_t CalleeAddress = Callee->getAddress();
+ const uint32_t OutputOffset = SymbolValue - CalleeAddress;
+
+ const uint64_t ParentAddress = fetchParentAddress(CalleeAddress);
+ const uint64_t HotAddress = ParentAddress ? ParentAddress : CalleeAddress;
+
+ const BinaryFunction *ParentBF = BC.getBinaryFunctionAtAddress(HotAddress);
+
+ const uint32_t InputOffset =
+ translate(CalleeAddress, OutputOffset, /*IsBranchSrc*/ false) + Offset;
+
+ unsigned SecondaryEntryId{0};
+ if (InputOffset)
+ SecondaryEntryId = getSecondaryEntryPointId(HotAddress, InputOffset);
+
+ return std::pair(ParentBF, SecondaryEntryId);
}
} // namespace bolt
diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp
index 05099aa25ce22738687c0e3106e63302fadc0540..0b2a4e86561f3aaa56a7385bf4fd8e5439f2d56a 100644
--- a/bolt/lib/Profile/DataAggregator.cpp
+++ b/bolt/lib/Profile/DataAggregator.cpp
@@ -604,8 +604,6 @@ Error DataAggregator::readProfile(BinaryContext &BC) {
// BAT YAML is handled by DataAggregator since normal YAML output requires
// CFG which is not available in BAT mode.
if (usesBAT()) {
- // Postprocess split function profile for BAT
- fixupBATProfile(BC);
if (opts::ProfileFormat == opts::ProfileFormatKind::PF_YAML)
if (std::error_code EC = writeBATYAML(BC, opts::OutputFilename))
report_error("cannot create output data file", EC);
@@ -664,18 +662,19 @@ DataAggregator::getBinaryFunctionContainingAddress(uint64_t Address) const {
/*UseMaxSize=*/true);
}
-StringRef DataAggregator::getLocationName(BinaryFunction &Func,
- uint64_t Count) {
+BinaryFunction *
+DataAggregator::getBATParentFunction(const BinaryFunction &Func) const {
+ if (BAT)
+ if (const uint64_t HotAddr = BAT->fetchParentAddress(Func.getAddress()))
+ return getBinaryFunctionContainingAddress(HotAddr);
+ return nullptr;
+}
+
+StringRef DataAggregator::getLocationName(const BinaryFunction &Func) const {
if (!BAT)
return Func.getOneName();
const BinaryFunction *OrigFunc = &Func;
- if (const uint64_t HotAddr = BAT->fetchParentAddress(Func.getAddress())) {
- NumColdSamples += Count;
- BinaryFunction *HotFunc = getBinaryFunctionContainingAddress(HotAddr);
- if (HotFunc)
- OrigFunc = HotFunc;
- }
// If it is a local function, prefer the name containing the file name where
// the local function was declared
for (StringRef AlternativeName : OrigFunc->getNames()) {
@@ -690,12 +689,17 @@ StringRef DataAggregator::getLocationName(BinaryFunction &Func,
return OrigFunc->getOneName();
}
-bool DataAggregator::doSample(BinaryFunction &Func, uint64_t Address,
+bool DataAggregator::doSample(BinaryFunction &OrigFunc, uint64_t Address,
uint64_t Count) {
+ BinaryFunction *ParentFunc = getBATParentFunction(OrigFunc);
+ BinaryFunction &Func = ParentFunc ? *ParentFunc : OrigFunc;
+ if (ParentFunc)
+ NumColdSamples += Count;
+
auto I = NamesToSamples.find(Func.getOneName());
if (I == NamesToSamples.end()) {
bool Success;
- StringRef LocName = getLocationName(Func, Count);
+ StringRef LocName = getLocationName(Func);
std::tie(I, Success) = NamesToSamples.insert(
std::make_pair(Func.getOneName(),
FuncSampleData(LocName, FuncSampleData::ContainerTy())));
@@ -715,22 +719,12 @@ bool DataAggregator::doIntraBranch(BinaryFunction &Func, uint64_t From,
FuncBranchData *AggrData = getBranchData(Func);
if (!AggrData) {
AggrData = &NamesToBranches[Func.getOneName()];
- AggrData->Name = getLocationName(Func, Count);
+ AggrData->Name = getLocationName(Func);
setBranchData(Func, AggrData);
}
- From -= Func.getAddress();
- To -= Func.getAddress();
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: bumpBranchCount: "
<< formatv("{0} @ {1:x} -> {0} @ {2:x}\n", Func, From, To));
- if (BAT) {
- From = BAT->translate(Func.getAddress(), From, /*IsBranchSrc=*/true);
- To = BAT->translate(Func.getAddress(), To, /*IsBranchSrc=*/false);
- LLVM_DEBUG(
- dbgs() << "BOLT-DEBUG: BAT translation on bumpBranchCount: "
- << formatv("{0} @ {1:x} -> {0} @ {2:x}\n", Func, From, To));
- }
-
AggrData->bumpBranchCount(From, To, Count, Mispreds);
return true;
}
@@ -744,30 +738,24 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc,
StringRef SrcFunc;
StringRef DstFunc;
if (FromFunc) {
- SrcFunc = getLocationName(*FromFunc, Count);
+ SrcFunc = getLocationName(*FromFunc);
FromAggrData = getBranchData(*FromFunc);
if (!FromAggrData) {
FromAggrData = &NamesToBranches[FromFunc->getOneName()];
FromAggrData->Name = SrcFunc;
setBranchData(*FromFunc, FromAggrData);
}
- From -= FromFunc->getAddress();
- if (BAT)
- From = BAT->translate(FromFunc->getAddress(), From, /*IsBranchSrc=*/true);
recordExit(*FromFunc, From, Mispreds, Count);
}
if (ToFunc) {
- DstFunc = getLocationName(*ToFunc, 0);
+ DstFunc = getLocationName(*ToFunc);
ToAggrData = getBranchData(*ToFunc);
if (!ToAggrData) {
ToAggrData = &NamesToBranches[ToFunc->getOneName()];
ToAggrData->Name = DstFunc;
setBranchData(*ToFunc, ToAggrData);
}
- To -= ToFunc->getAddress();
- if (BAT)
- To = BAT->translate(ToFunc->getAddress(), To, /*IsBranchSrc=*/false);
recordEntry(*ToFunc, To, Mispreds, Count);
}
@@ -783,15 +771,32 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc,
bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count,
uint64_t Mispreds) {
- BinaryFunction *FromFunc = getBinaryFunctionContainingAddress(From);
- BinaryFunction *ToFunc = getBinaryFunctionContainingAddress(To);
+ auto handleAddress = [&](uint64_t &Addr, bool IsFrom) -> BinaryFunction * {
+ if (BinaryFunction *Func = getBinaryFunctionContainingAddress(Addr)) {
+ Addr -= Func->getAddress();
+
+ if (BAT)
+ Addr = BAT->translate(Func->getAddress(), Addr, IsFrom);
+
+ if (BinaryFunction *ParentFunc = getBATParentFunction(*Func)) {
+ Func = ParentFunc;
+ if (IsFrom)
+ NumColdSamples += Count;
+ }
+
+ return Func;
+ }
+ return nullptr;
+ };
+
+ BinaryFunction *FromFunc = handleAddress(From, /*IsFrom=*/true);
+ BinaryFunction *ToFunc = handleAddress(To, /*IsFrom=*/false);
if (!FromFunc && !ToFunc)
return false;
// Treat recursive control transfers as inter-branches.
- if (FromFunc == ToFunc && (To != ToFunc->getAddress())) {
- recordBranch(*FromFunc, From - FromFunc->getAddress(),
- To - FromFunc->getAddress(), Count, Mispreds);
+ if (FromFunc == ToFunc && To != 0) {
+ recordBranch(*FromFunc, From, To, Count, Mispreds);
return doIntraBranch(*FromFunc, From, To, Count, Mispreds);
}
@@ -842,9 +847,14 @@ bool DataAggregator::doTrace(const LBREntry &First, const LBREntry &Second,
<< FromFunc->getPrintName() << ":"
<< Twine::utohexstr(First.To) << " to "
<< Twine::utohexstr(Second.From) << ".\n");
- for (const std::pair &Pair : *FTs)
- doIntraBranch(*FromFunc, Pair.first + FromFunc->getAddress(),
- Pair.second + FromFunc->getAddress(), Count, false);
+ BinaryFunction *ParentFunc = getBATParentFunction(*FromFunc);
+ for (auto [From, To] : *FTs) {
+ if (BAT) {
+ From = BAT->translate(FromFunc->getAddress(), From, /*IsBranchSrc=*/true);
+ To = BAT->translate(FromFunc->getAddress(), To, /*IsBranchSrc=*/false);
+ }
+ doIntraBranch(ParentFunc ? *ParentFunc : *FromFunc, From, To, Count, false);
+ }
return true;
}
@@ -2273,29 +2283,6 @@ DataAggregator::writeAggregatedFile(StringRef OutputFilename) const {
return std::error_code();
}
-void DataAggregator::fixupBATProfile(BinaryContext &BC) {
- for (auto &[FuncName, Branches] : NamesToBranches) {
- BinaryData *BD = BC.getBinaryDataByName(FuncName);
- assert(BD);
- uint64_t FuncAddress = BD->getAddress();
- if (!BAT->isBATFunction(FuncAddress))
- continue;
- // Filter out cold fragments
- if (!BD->getSectionName().equals(BC.getMainCodeSectionName()))
- continue;
- // Convert inter-branches between hot and cold fragments into
- // intra-branches.
- for (auto &[OffsetFrom, CallToMap] : Branches.InterIndex) {
- for (auto &[CallToLoc, CallToIdx] : CallToMap) {
- if (CallToLoc.Name != FuncName)
- continue;
- Branches.IntraIndex[OffsetFrom][CallToLoc.Offset] = CallToIdx;
- Branches.InterIndex[OffsetFrom].erase(CallToLoc);
- }
- }
- }
-}
-
std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,
StringRef OutputFilename) const {
std::error_code EC;
@@ -2333,7 +2320,7 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,
if (BAT->isBATFunction(Function.getAddress()))
continue;
BP.Functions.emplace_back(
- YAMLProfileWriter::convert(Function, /*UseDFS=*/false));
+ YAMLProfileWriter::convert(Function, /*UseDFS=*/false, BAT));
}
for (const auto &KV : NamesToBranches) {
@@ -2345,9 +2332,6 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,
uint64_t FuncAddress = BD->getAddress();
if (!BAT->isBATFunction(FuncAddress))
continue;
- // Filter out cold fragments
- if (!BD->getSectionName().equals(BC.getMainCodeSectionName()))
- continue;
BinaryFunction *BF = BC.getBinaryFunctionAtAddress(FuncAddress);
assert(BF);
YamlBF.Name = FuncName.str();
@@ -2357,87 +2341,68 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,
YamlBF.NumBasicBlocks = BAT->getNumBasicBlocks(FuncAddress);
const BoltAddressTranslation::BBHashMapTy &BlockMap =
BAT->getBBHashMap(FuncAddress);
+ YamlBF.Blocks.resize(YamlBF.NumBasicBlocks);
- auto addSuccProfile = [&](yaml::bolt::BinaryBasicBlockProfile &YamlBB,
- uint64_t SuccOffset, unsigned SuccDataIdx) {
+ for (auto &&[Idx, YamlBB] : llvm::enumerate(YamlBF.Blocks))
+ YamlBB.Index = Idx;
+
+ for (auto BI = BlockMap.begin(), BE = BlockMap.end(); BI != BE; ++BI)
+ YamlBF.Blocks[BI->second.getBBIndex()].Hash = BI->second.getBBHash();
+
+ auto getSuccessorInfo = [&](uint32_t SuccOffset, unsigned SuccDataIdx) {
const llvm::bolt::BranchInfo &BI = Branches.Data.at(SuccDataIdx);
yaml::bolt::SuccessorInfo SI;
SI.Index = BlockMap.getBBIndex(SuccOffset);
SI.Count = BI.Branches;
SI.Mispreds = BI.Mispreds;
- YamlBB.Successors.emplace_back(SI);
+ return SI;
};
- std::unordered_map> BFBranches =
- BAT->getBFBranches(FuncAddress);
-
- auto addCallsProfile = [&](yaml::bolt::BinaryBasicBlockProfile &YamlBB,
- uint64_t Offset) {
- // Iterate over BRANCHENTRY records in the current block
- for (uint32_t BranchOffset : BFBranches[Offset]) {
- if (!Branches.InterIndex.contains(BranchOffset))
- continue;
- for (const auto &[CallToLoc, CallToIdx] :
- Branches.InterIndex.at(BranchOffset)) {
- const llvm::bolt::BranchInfo &BI = Branches.Data.at(CallToIdx);
- yaml::bolt::CallSiteInfo YamlCSI;
- YamlCSI.DestId = 0; // designated for unknown functions
- YamlCSI.EntryDiscriminator = 0;
- YamlCSI.Count = BI.Branches;
- YamlCSI.Mispreds = BI.Mispreds;
- YamlCSI.Offset = BranchOffset - Offset;
- BinaryData *CallTargetBD = BC.getBinaryDataByName(CallToLoc.Name);
- if (!CallTargetBD) {
- YamlBB.CallSites.emplace_back(YamlCSI);
- continue;
- }
- uint64_t CallTargetAddress = CallTargetBD->getAddress();
- BinaryFunction *CallTargetBF =
- BC.getBinaryFunctionAtAddress(CallTargetAddress);
- if (!CallTargetBF) {
- YamlBB.CallSites.emplace_back(YamlCSI);
- continue;
- }
- // Calls between hot and cold fragments must be handled in
- // fixupBATProfile.
- assert(CallTargetBF != BF && "invalid CallTargetBF");
- YamlCSI.DestId = CallTargetBF->getFunctionNumber();
- if (CallToLoc.Offset) {
- if (BAT->isBATFunction(CallTargetAddress)) {
- LLVM_DEBUG(dbgs() << "BOLT-DEBUG: Unsupported secondary "
- "entry point in BAT function "
- << CallToLoc.Name << '\n');
- } else if (const BinaryBasicBlock *CallTargetBB =
- CallTargetBF->getBasicBlockAtOffset(
- CallToLoc.Offset)) {
- // Only record true call information, ignoring returns (normally
- // won't have a target basic block) and jumps to the landing
- // pads (not an entry point).
- if (CallTargetBB->isEntryPoint()) {
- YamlCSI.EntryDiscriminator =
- CallTargetBF->getEntryIDForSymbol(
- CallTargetBB->getLabel());
- }
- }
- }
- YamlBB.CallSites.emplace_back(YamlCSI);
- }
- }
+ auto getCallSiteInfo = [&](Location CallToLoc, unsigned CallToIdx,
+ uint32_t Offset) {
+ const llvm::bolt::BranchInfo &BI = Branches.Data.at(CallToIdx);
+ yaml::bolt::CallSiteInfo CSI;
+ CSI.DestId = 0; // designated for unknown functions
+ CSI.EntryDiscriminator = 0;
+ CSI.Count = BI.Branches;
+ CSI.Mispreds = BI.Mispreds;
+ CSI.Offset = Offset;
+ if (BinaryData *BD = BC.getBinaryDataByName(CallToLoc.Name))
+ YAMLProfileWriter::setCSIDestination(BC, CSI, BD->getSymbol(), BAT,
+ CallToLoc.Offset);
+ return CSI;
};
for (const auto &[FromOffset, SuccKV] : Branches.IntraIndex) {
- yaml::bolt::BinaryBasicBlockProfile YamlBB;
if (!BlockMap.isInputBlock(FromOffset))
continue;
- YamlBB.Index = BlockMap.getBBIndex(FromOffset);
- YamlBB.Hash = BlockMap.getBBHash(FromOffset);
+ const unsigned Index = BlockMap.getBBIndex(FromOffset);
+ yaml::bolt::BinaryBasicBlockProfile &YamlBB = YamlBF.Blocks[Index];
for (const auto &[SuccOffset, SuccDataIdx] : SuccKV)
- addSuccProfile(YamlBB, SuccOffset, SuccDataIdx);
- addCallsProfile(YamlBB, FromOffset);
- if (YamlBB.ExecCount || !YamlBB.Successors.empty() ||
- !YamlBB.CallSites.empty())
- YamlBF.Blocks.emplace_back(YamlBB);
+ if (BlockMap.isInputBlock(SuccOffset))
+ YamlBB.Successors.emplace_back(
+ getSuccessorInfo(SuccOffset, SuccDataIdx));
+ }
+ for (const auto &[FromOffset, CallTo] : Branches.InterIndex) {
+ auto BlockIt = BlockMap.upper_bound(FromOffset);
+ --BlockIt;
+ const unsigned BlockOffset = BlockIt->first;
+ const unsigned BlockIndex = BlockIt->second.getBBIndex();
+ yaml::bolt::BinaryBasicBlockProfile &YamlBB = YamlBF.Blocks[BlockIndex];
+ const uint32_t Offset = FromOffset - BlockOffset;
+ for (const auto &[CallToLoc, CallToIdx] : CallTo)
+ YamlBB.CallSites.emplace_back(
+ getCallSiteInfo(CallToLoc, CallToIdx, Offset));
+ llvm::sort(YamlBB.CallSites, [](yaml::bolt::CallSiteInfo &A,
+ yaml::bolt::CallSiteInfo &B) {
+ return A.Offset < B.Offset;
+ });
}
+ // Drop blocks without a hash, won't be useful for stale matching.
+ llvm::erase_if(YamlBF.Blocks,
+ [](const yaml::bolt::BinaryBasicBlockProfile &YamlBB) {
+ return YamlBB.Hash == (yaml::Hex64)0;
+ });
BP.Functions.emplace_back(YamlBF);
}
}
diff --git a/bolt/lib/Profile/YAMLProfileWriter.cpp b/bolt/lib/Profile/YAMLProfileWriter.cpp
index 0f082086c1fc24810d97e2a078c6648eda753585..ef04ba0d21ad75cf29421c24922738e9f0cba1d9 100644
--- a/bolt/lib/Profile/YAMLProfileWriter.cpp
+++ b/bolt/lib/Profile/YAMLProfileWriter.cpp
@@ -9,6 +9,7 @@
#include "bolt/Profile/YAMLProfileWriter.h"
#include "bolt/Core/BinaryBasicBlock.h"
#include "bolt/Core/BinaryFunction.h"
+#include "bolt/Profile/BoltAddressTranslation.h"
#include "bolt/Profile/ProfileReaderBase.h"
#include "bolt/Rewrite/RewriteInstance.h"
#include "llvm/Support/CommandLine.h"
@@ -25,17 +26,19 @@ extern llvm::cl::opt ProfileUseDFS;
namespace llvm {
namespace bolt {
-/// Set CallSiteInfo destination fields from \p Symbol and return a target
-/// BinaryFunction for that symbol.
-static const BinaryFunction *setCSIDestination(const BinaryContext &BC,
- yaml::bolt::CallSiteInfo &CSI,
- const MCSymbol *Symbol) {
+const BinaryFunction *YAMLProfileWriter::setCSIDestination(
+ const BinaryContext &BC, yaml::bolt::CallSiteInfo &CSI,
+ const MCSymbol *Symbol, const BoltAddressTranslation *BAT,
+ uint32_t Offset) {
CSI.DestId = 0; // designated for unknown functions
CSI.EntryDiscriminator = 0;
+
if (Symbol) {
uint64_t EntryID = 0;
- if (const BinaryFunction *const Callee =
+ if (const BinaryFunction *Callee =
BC.getFunctionForSymbol(Symbol, &EntryID)) {
+ if (BAT && BAT->isBATFunction(Callee->getAddress()))
+ std::tie(Callee, EntryID) = BAT->translateSymbol(BC, *Symbol, Offset);
CSI.DestId = Callee->getFunctionNumber();
CSI.EntryDiscriminator = EntryID;
return Callee;
@@ -45,7 +48,8 @@ static const BinaryFunction *setCSIDestination(const BinaryContext &BC,
}
yaml::bolt::BinaryFunctionProfile
-YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS) {
+YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS,
+ const BoltAddressTranslation *BAT) {
yaml::bolt::BinaryFunctionProfile YamlBF;
const BinaryContext &BC = BF.getBinaryContext();
@@ -98,7 +102,8 @@ YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS) {
continue;
for (const IndirectCallProfile &CSP : ICSP.get()) {
StringRef TargetName = "";
- const BinaryFunction *Callee = setCSIDestination(BC, CSI, CSP.Symbol);
+ const BinaryFunction *Callee =
+ setCSIDestination(BC, CSI, CSP.Symbol, BAT);
if (Callee)
TargetName = Callee->getOneName();
CSI.Count = CSP.Count;
@@ -109,7 +114,7 @@ YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS) {
StringRef TargetName = "";
const MCSymbol *CalleeSymbol = BC.MIB->getTargetSymbol(Instr);
const BinaryFunction *const Callee =
- setCSIDestination(BC, CSI, CalleeSymbol);
+ setCSIDestination(BC, CSI, CalleeSymbol, BAT);
if (Callee)
TargetName = Callee->getOneName();
diff --git a/bolt/lib/Rewrite/BinaryPassManager.cpp b/bolt/lib/Rewrite/BinaryPassManager.cpp
index 6c26bb7957269d71c06da0d33bfe80984b0f4e16..be4888ccfa56457fe2f59dcee91abdd05b947021 100644
--- a/bolt/lib/Rewrite/BinaryPassManager.cpp
+++ b/bolt/lib/Rewrite/BinaryPassManager.cpp
@@ -377,8 +377,9 @@ Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) {
Manager.registerPass(std::make_unique(PrintNormalized));
- Manager.registerPass(std::make_unique(NeverPrint),
- opts::StripRepRet);
+ if (BC.isX86())
+ Manager.registerPass(std::make_unique(NeverPrint),
+ opts::StripRepRet);
Manager.registerPass(std::make_unique(PrintICF),
opts::ICF);
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index 0c8ee0d417233bb5617cb7a9fc2ddfa59a3dd710..4e0096cf988aed4031523e3a8343023f88ed7322 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -556,7 +556,7 @@ Error RewriteInstance::discoverStorage() {
if (Error E = SectionNameOrErr.takeError())
return E;
StringRef SectionName = SectionNameOrErr.get();
- if (SectionName == ".text") {
+ if (SectionName == BC->getMainCodeSectionName()) {
BC->OldTextSectionAddress = Section.getAddress();
BC->OldTextSectionSize = Section.getSize();
@@ -1670,7 +1670,9 @@ void RewriteInstance::disassemblePLT() {
return disassemblePLTSectionAArch64(Section);
if (BC->isRISCV())
return disassemblePLTSectionRISCV(Section);
- return disassemblePLTSectionX86(Section, EntrySize);
+ if (BC->isX86())
+ return disassemblePLTSectionX86(Section, EntrySize);
+ llvm_unreachable("Unmplemented PLT");
};
for (BinarySection &Section : BC->allocatableSections()) {
@@ -1864,7 +1866,8 @@ Error RewriteInstance::readSpecialSections() {
"Use -update-debug-sections to keep it.\n";
}
- HasTextRelocations = (bool)BC->getUniqueSectionByName(".rela.text");
+ HasTextRelocations = (bool)BC->getUniqueSectionByName(
+ ".rela" + std::string(BC->getMainCodeSectionName()));
HasSymbolTable = (bool)BC->getUniqueSectionByName(".symtab");
EHFrameSection = BC->getUniqueSectionByName(".eh_frame");
BuildIDSection = BC->getUniqueSectionByName(".note.gnu.build-id");
@@ -2305,9 +2308,13 @@ void RewriteInstance::processRelocations() {
return;
for (const SectionRef &Section : InputFile->sections()) {
- if (cantFail(Section.getRelocatedSection()) != InputFile->section_end() &&
- !BinarySection(*BC, Section).isAllocatable())
- readRelocations(Section);
+ section_iterator SecIter = cantFail(Section.getRelocatedSection());
+ if (SecIter == InputFile->section_end())
+ continue;
+ if (BinarySection(*BC, Section).isAllocatable())
+ continue;
+
+ readRelocations(Section);
}
if (NumFailedRelocations)
@@ -2600,7 +2607,7 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
const bool IsToCode = ReferencedSection && ReferencedSection->isText();
// Special handling of PC-relative relocations.
- if (!IsAArch64 && !BC->isRISCV() && Relocation::isPCRelative(RType)) {
+ if (BC->isX86() && Relocation::isPCRelative(RType)) {
if (!IsFromCode && IsToCode) {
// PC-relative relocations from data to code are tricky since the
// original information is typically lost after linking, even with
@@ -2854,15 +2861,14 @@ void RewriteInstance::handleRelocation(const SectionRef &RelocatedSection,
BC->isRISCV())
ForceRelocation = true;
- if (IsFromCode) {
+ if (IsFromCode)
ContainingBF->addRelocation(Rel.getOffset(), ReferencedSymbol, RType,
Addend, ExtractedValue);
- } else if (IsToCode || ForceRelocation) {
+ else if (IsToCode || ForceRelocation)
BC->addRelocation(Rel.getOffset(), ReferencedSymbol, RType, Addend,
ExtractedValue);
- } else {
+ else
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: ignoring relocation from data to data\n");
- }
}
void RewriteInstance::selectFunctionsToProcess() {
@@ -3441,7 +3447,8 @@ void RewriteInstance::emitAndLink() {
ErrorOr TextSection =
BC->getUniqueSectionByName(BC->getMainCodeSectionName());
if (BC->HasRelocations && TextSection)
- BC->renameSection(*TextSection, getOrgSecPrefix() + ".text");
+ BC->renameSection(*TextSection,
+ getOrgSecPrefix() + BC->getMainCodeSectionName());
//////////////////////////////////////////////////////////////////////////////
// Assign addresses to new sections.
@@ -4298,7 +4305,7 @@ RewriteInstance::getOutputSections(ELFObjectFile *File,
for (auto &SectionKV : OutputSections) {
ELFShdrTy &Section = SectionKV.second;
- // Ignore TLS sections as they don't take any space in the file.
+ // Ignore NOBITS sections as they don't take any space in the file.
if (Section.sh_type == ELF::SHT_NOBITS)
continue;
@@ -4306,10 +4313,9 @@ RewriteInstance::getOutputSections(ELFObjectFile *File,
// placed in different loadable segments.
if (PrevSection &&
PrevSection->sh_offset + PrevSection->sh_size > Section.sh_offset) {
- if (opts::Verbosity > 1) {
+ if (opts::Verbosity > 1)
BC->outs() << "BOLT-INFO: adjusting size for section "
<< PrevBinSec->getOutputName() << '\n';
- }
PrevSection->sh_size = Section.sh_offset - PrevSection->sh_offset;
}
@@ -4417,6 +4423,7 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile *File) {
raw_fd_ostream &OS = Out->os();
const ELFFile &Obj = File->getELFFile();
+ // Mapping from old section indices to new ones
std::vector NewSectionIndex;
std::vector OutputSections =
getOutputSections(File, NewSectionIndex);
@@ -4434,10 +4441,8 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile *File) {
// Write all section header entries while patching section references.
for (ELFShdrTy &Section : OutputSections) {
Section.sh_link = NewSectionIndex[Section.sh_link];
- if (Section.sh_type == ELF::SHT_REL || Section.sh_type == ELF::SHT_RELA) {
- if (Section.sh_info)
- Section.sh_info = NewSectionIndex[Section.sh_info];
- }
+ if (Section.sh_type == ELF::SHT_REL || Section.sh_type == ELF::SHT_RELA)
+ Section.sh_info = NewSectionIndex[Section.sh_info];
OS.write(reinterpret_cast(&Section), sizeof(Section));
}
@@ -5762,10 +5767,3 @@ bool RewriteInstance::isDebugSection(StringRef SectionName) {
return false;
}
-
-bool RewriteInstance::isKSymtabSection(StringRef SectionName) {
- if (SectionName.starts_with("__ksymtab"))
- return true;
-
- return false;
-}
diff --git a/bolt/test/X86/bolt-address-translation-yaml.test b/bolt/test/X86/bolt-address-translation-yaml.test
index 7fdf7709a8b9da3d2f103ec88c9b8ad1191893e7..af24c3d84a0f15f9f8d68eabf7b42daac3e39e69 100644
--- a/bolt/test/X86/bolt-address-translation-yaml.test
+++ b/bolt/test/X86/bolt-address-translation-yaml.test
@@ -36,9 +36,14 @@ YAML-BAT-CHECK-NEXT: - bid: 0
YAML-BAT-CHECK-NEXT: insns: 26
YAML-BAT-CHECK-NEXT: hash: 0xA900AE79CFD40000
YAML-BAT-CHECK-NEXT: succ: [ { bid: 3, cnt: 0 }, { bid: 1, cnt: 0 } ]
+# Calls from no-BAT to BAT function
+YAML-BAT-CHECK: - bid: 28
+YAML-BAT-CHECK-NEXT: insns: 13
+YAML-BAT-CHECK-NEXT: hash: 0xB2F04C1F25F00400
+YAML-BAT-CHECK-NEXT: calls: [ { off: 0x21, fid: [[#SOLVECUBIC:]], cnt: 25 }, { off: 0x2D, fid: [[#]], cnt: 9 } ]
# Function covered by BAT with calls
YAML-BAT-CHECK: - name: SolveCubic
-YAML-BAT-CHECK-NEXT: fid: [[#]]
+YAML-BAT-CHECK-NEXT: fid: [[#SOLVECUBIC]]
YAML-BAT-CHECK-NEXT: hash: 0x6AF7E61EA3966722
YAML-BAT-CHECK-NEXT: exec: 25
YAML-BAT-CHECK-NEXT: nblocks: 15
diff --git a/bolt/test/X86/bolt-address-translation.test b/bolt/test/X86/bolt-address-translation.test
index 63234b4c1d21851f447fa804669e780774a6e9c8..e6b21c14077b454e9d3e1719da8dc3c2f896b322 100644
--- a/bolt/test/X86/bolt-address-translation.test
+++ b/bolt/test/X86/bolt-address-translation.test
@@ -37,7 +37,7 @@
# CHECK: BOLT: 3 out of 7 functions were overwritten.
# CHECK: BOLT-INFO: Wrote 6 BAT maps
# CHECK: BOLT-INFO: Wrote 3 function and 58 basic block hashes
-# CHECK: BOLT-INFO: BAT section size (bytes): 924
+# CHECK: BOLT-INFO: BAT section size (bytes): 928
#
# usqrt mappings (hot part). We match against any key (left side containing
# the bolted binary offsets) because BOLT may change where it puts instructions
diff --git a/bolt/test/X86/patch-entries.test b/bolt/test/X86/patch-entries.test
index 54f358f273e793c30da84fe3a6134e77d4cb4759..4a725412dd616adeb760df155837c17b003213e0 100644
--- a/bolt/test/X86/patch-entries.test
+++ b/bolt/test/X86/patch-entries.test
@@ -7,4 +7,25 @@ REQUIRES: system-linux
RUN: %clang %cflags -no-pie -g %p/Inputs/patch-entries.c -fuse-ld=lld -o %t.exe \
RUN: -Wl,-q -I%p/../Inputs
-RUN: llvm-bolt -relocs %t.exe -o %t.out --update-debug-sections --force-patch
+RUN: llvm-bolt -relocs %t.exe -o %t.out --update-debug-sections --force-patch \
+RUN: --enable-bat
+
+# Check that patched functions can be disassembled (override FDE from the
+# original function)
+# PREAGG: B X:0 #foo.org.0# 1 0
+RUN: link_fdata %s %t.out %t.preagg PREAGG
+RUN: perf2bolt %t.out -p %t.preagg --pa -o %t.yaml --profile-format=yaml \
+RUN: -print-disasm -print-only=foo.org.0/1 2>&1 | FileCheck %s
+CHECK-NOT: BOLT-WARNING: sizes differ for function foo.org.0/1
+CHECK: Binary Function "foo.org.0/1(*2)" after disassembly {
+
+# Check the expected eh_frame contents
+RUN: llvm-nm --print-size %t.out > %t.foo
+RUN: llvm-objdump %t.out --dwarf=frames >> %t.foo
+RUN: FileCheck %s --input-file %t.foo --check-prefix=CHECK-FOO
+CHECK-FOO: 0000000000[[#%x,FOO:]] [[#%x,OPTSIZE:]] t foo
+CHECK-FOO: 0000000000[[#%x,ORG:]] [[#%x,ORGSIZE:]] t foo.org.0
+# patched FDE comes first
+CHECK-FOO: FDE {{.*}} pc=00[[#%x,ORG]]...00[[#%x,ORG+ORGSIZE]]
+# original FDE comes second
+CHECK-FOO: FDE {{.*}} pc=00[[#%x,ORG]]...00[[#%x,ORG+OPTSIZE]]
diff --git a/bolt/test/X86/yaml-secondary-entry-discriminator.s b/bolt/test/X86/yaml-secondary-entry-discriminator.s
index 43c2e2a7f05549289293a39808762cc5a68cc285..5d6e291fd7c22a79594afa6b5daa7d828bacc082 100644
--- a/bolt/test/X86/yaml-secondary-entry-discriminator.s
+++ b/bolt/test/X86/yaml-secondary-entry-discriminator.s
@@ -1,5 +1,5 @@
-# This reproduces a bug with BOLT setting incorrect discriminator for
-# secondary entry points in YAML profile.
+## This reproduces a bug with BOLT setting incorrect discriminator for
+## secondary entry points in YAML profile.
# REQUIRES: system-linux
# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
@@ -11,20 +11,20 @@
# RUN: FileCheck %s -input-file %t.yaml
# CHECK: - name: main
# CHECK-NEXT: fid: 2
-# CHECK-NEXT: hash: 0xADF270D550151185
+# CHECK-NEXT: hash: {{.*}}
# CHECK-NEXT: exec: 0
# CHECK-NEXT: nblocks: 4
# CHECK-NEXT: blocks:
# CHECK: - bid: 1
# CHECK-NEXT: insns: 1
-# CHECK-NEXT: hash: 0x36A303CBA4360014
+# CHECK-NEXT: hash: {{.*}}
# CHECK-NEXT: calls: [ { off: 0x0, fid: 1, disc: 1, cnt: 1 } ]
# CHECK: - bid: 2
# CHECK-NEXT: insns: 5
-# CHECK-NEXT: hash: 0x8B2F5747CD0019
+# CHECK-NEXT: hash: {{.*}}
# CHECK-NEXT: calls: [ { off: 0x0, fid: 1, disc: 1, cnt: 1, mis: 1 } ]
-# Make sure that the profile is attached correctly
+## Make sure that the profile is attached correctly
# RUN: llvm-bolt %t.exe -o %t.out --data %t.yaml --print-profile \
# RUN: --print-only=main | FileCheck %s --check-prefix=CHECK-CFG
@@ -33,15 +33,80 @@
# CHECK-CFG: callq *%rax # Offset: [[#]] # CallProfile: 1 (1 misses) :
# CHECK-CFG-NEXT: { secondary_entry: 1 (1 misses) }
+## YAML BAT test of calling BAT secondary entry from non-BAT function
+## Now force-split func and skip main (making it call secondary entries)
+# RUN: llvm-bolt %t.exe -o %t.bat --data %t.fdata --funcs=func \
+# RUN: --split-functions --split-strategy=all --split-all-cold --enable-bat
+
+## Prepare pre-aggregated profile using %t.bat
+# RUN: link_fdata %s %t.bat %t.preagg PREAGG
+## Strip labels used for pre-aggregated profile
+# RUN: llvm-strip -NLcall -NLindcall %t.bat
+
+## Convert pre-aggregated profile using BAT
+# RUN: perf2bolt %t.bat -p %t.preagg --pa -o %t.bat.fdata -w %t.bat.yaml
+
+## Convert BAT fdata into YAML
+# RUN: llvm-bolt %t.exe -data %t.bat.fdata -w %t.bat.fdata-yaml -o /dev/null
+
+## Check fdata YAML - make sure that a direct call has discriminator field
+# RUN: FileCheck %s --input-file %t.bat.fdata-yaml -check-prefix CHECK-BAT-YAML
+
+## Check BAT YAML - make sure that a direct call has discriminator field
+# RUN: FileCheck %s --input-file %t.bat.yaml --check-prefix CHECK-BAT-YAML
+
+## YAML BAT test of calling BAT secondary entry from BAT function
+# RUN: llvm-bolt %t.exe -o %t.bat2 --data %t.fdata --funcs=main,func \
+# RUN: --split-functions --split-strategy=all --split-all-cold --enable-bat
+
+## Prepare pre-aggregated profile using %t.bat
+# RUN: link_fdata %s %t.bat2 %t.preagg2 PREAGG2
+
+## Strip labels used for pre-aggregated profile
+# RUN: llvm-strip -NLcall -NLindcall %t.bat2
+
+## Convert pre-aggregated profile using BAT
+# RUN: perf2bolt %t.bat2 -p %t.preagg2 --pa -o %t.bat2.fdata -w %t.bat2.yaml
+
+## Convert BAT fdata into YAML
+# RUN: llvm-bolt %t.exe -data %t.bat2.fdata -w %t.bat2.fdata-yaml -o /dev/null
+
+## Check fdata YAML - make sure that a direct call has discriminator field
+# RUN: FileCheck %s --input-file %t.bat2.fdata-yaml -check-prefix CHECK-BAT-YAML
+
+## Check BAT YAML - make sure that a direct call has discriminator field
+# RUN: FileCheck %s --input-file %t.bat2.yaml --check-prefix CHECK-BAT-YAML
+
+# CHECK-BAT-YAML: - name: main
+# CHECK-BAT-YAML-NEXT: fid: [[#]]
+# CHECK-BAT-YAML-NEXT: hash: 0xADF270D550151185
+# CHECK-BAT-YAML-NEXT: exec: 0
+# CHECK-BAT-YAML-NEXT: nblocks: 4
+# CHECK-BAT-YAML-NEXT: blocks:
+# CHECK-BAT-YAML: - bid: 1
+# CHECK-BAT-YAML-NEXT: insns: [[#]]
+# CHECK-BAT-YAML-NEXT: hash: 0x36A303CBA4360018
+# CHECK-BAT-YAML-NEXT: calls: [ { off: 0x0, fid: [[#]], disc: 1, cnt: 1
+
.globl func
.type func, @function
func:
# FDATA: 0 [unknown] 0 1 func 0 1 0
+# PREAGG: B X:0 #func# 1 1
+# PREAGG2: B X:0 #func# 1 1
.cfi_startproc
pushq %rbp
movq %rsp, %rbp
+## Placeholder code to make splitting profitable
+.rept 5
+ testq %rax, %rax
+.endr
.globl secondary_entry
secondary_entry:
+## Placeholder code to make splitting profitable
+.rept 5
+ testq %rax, %rax
+.endr
popq %rbp
retq
nopl (%rax)
@@ -58,17 +123,23 @@ main:
movl $0, -4(%rbp)
testq %rax, %rax
jne Lindcall
+.globl Lcall
Lcall:
call secondary_entry
# FDATA: 1 main #Lcall# 1 secondary_entry 0 1 1
+# PREAGG: B #Lcall# #secondary_entry# 1 1
+# PREAGG2: B #main.cold.0# #func.cold.0# 1 1
+.globl Lindcall
Lindcall:
callq *%rax
# FDATA: 1 main #Lindcall# 1 secondary_entry 0 1 1
+# PREAGG: B #Lindcall# #secondary_entry# 1 1
+# PREAGG2: B #main.cold.1# #func.cold.0# 1 1
xorl %eax, %eax
addq $16, %rsp
popq %rbp
retq
-# For relocations against .text
+## For relocations against .text
call exit
.cfi_endproc
.size main, .-main
diff --git a/bolt/test/runtime/X86/jt-confusion.s b/bolt/test/runtime/X86/jt-confusion.s
new file mode 100644
index 0000000000000000000000000000000000000000..f15c83b35b6a44e8e4733c66aad055be9fbe6a79
--- /dev/null
+++ b/bolt/test/runtime/X86/jt-confusion.s
@@ -0,0 +1,164 @@
+# REQUIRES: system-linux
+
+# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
+# RUN: llvm-strip --strip-unneeded %t.o
+# RUN: %clang %cflags -no-pie -nostartfiles -nostdlib -lc %t.o -o %t.exe -Wl,-q
+
+# RUN: llvm-bolt %t.exe -o %t.exe.bolt --relocs=1 --lite=0
+
+# RUN: %t.exe.bolt
+
+## Check that BOLT's jump table detection diffrentiates between
+## __builtin_unreachable() targets and function pointers.
+
+## The test case was built from the following two source files and
+## modiffied for standalone build. main became _start, etc.
+## $ $(CC) a.c -O1 -S -o a.s
+## $ $(CC) b.c -O0 -S -o b.s
+
+## a.c:
+
+## typedef int (*fptr)(int);
+## void check_fptr(fptr, int);
+##
+## int foo(int a) {
+## check_fptr(foo, 0);
+## switch (a) {
+## default:
+## __builtin_unreachable();
+## case 0:
+## return 3;
+## case 1:
+## return 5;
+## case 2:
+## return 7;
+## case 3:
+## return 11;
+## case 4:
+## return 13;
+## case 5:
+## return 17;
+## }
+## return 0;
+## }
+##
+## int main(int argc) {
+## check_fptr(main, 1);
+## return foo(argc);
+## }
+##
+## const fptr funcs[2] = {foo, main};
+
+## b.c.:
+
+## typedef int (*fptr)(int);
+## extern const fptr funcs[2];
+##
+## #define assert(C) { if (!(C)) (*(unsigned long long *)0) = 0; }
+## void check_fptr(fptr f, int i) {
+## assert(f == funcs[i]);
+## }
+
+
+ .text
+ .globl foo
+ .type foo, @function
+foo:
+.LFB0:
+ .cfi_startproc
+ pushq %rbx
+ .cfi_def_cfa_offset 16
+ .cfi_offset 3, -16
+ movl %edi, %ebx
+ movl $0, %esi
+ movl $foo, %edi
+ call check_fptr
+ movl %ebx, %ebx
+ jmp *.L4(,%rbx,8)
+.L8:
+ movl $5, %eax
+ jmp .L1
+.L7:
+ movl $7, %eax
+ jmp .L1
+.L6:
+ movl $11, %eax
+ jmp .L1
+.L5:
+ movl $13, %eax
+ jmp .L1
+.L3:
+ movl $17, %eax
+ jmp .L1
+.L10:
+ movl $3, %eax
+.L1:
+ popq %rbx
+ .cfi_def_cfa_offset 8
+ ret
+ .cfi_endproc
+.LFE0:
+ .size foo, .-foo
+ .globl _start
+ .type _start, @function
+_start:
+.LFB1:
+ .cfi_startproc
+ pushq %rbx
+ .cfi_def_cfa_offset 16
+ .cfi_offset 3, -16
+ movl %edi, %ebx
+ movl $1, %esi
+ movl $_start, %edi
+ call check_fptr
+ movl $1, %edi
+ call foo
+ popq %rbx
+ .cfi_def_cfa_offset 8
+ callq exit@PLT
+ .cfi_endproc
+.LFE1:
+ .size _start, .-_start
+ .globl check_fptr
+ .type check_fptr, @function
+check_fptr:
+.LFB2:
+ .cfi_startproc
+ pushq %rbp
+ .cfi_def_cfa_offset 16
+ .cfi_offset 6, -16
+ movq %rsp, %rbp
+ .cfi_def_cfa_register 6
+ movq %rdi, -8(%rbp)
+ movl %esi, -12(%rbp)
+ movl -12(%rbp), %eax
+ cltq
+ movq funcs(,%rax,8), %rax
+ cmpq %rax, -8(%rbp)
+ je .L33
+ movl $0, %eax
+ movq $0, (%rax)
+.L33:
+ nop
+ popq %rbp
+ .cfi_def_cfa 7, 8
+ ret
+ .cfi_endproc
+
+ .section .rodata
+ .align 8
+ .align 4
+.L4:
+ .quad .L10
+ .quad .L8
+ .quad .L7
+ .quad .L6
+ .quad .L5
+ .quad .L3
+
+ .globl funcs
+ .type funcs, @object
+ .size funcs, 16
+funcs:
+ .quad foo
+ .quad _start
diff --git a/clang-tools-extra/clang-tidy/add_new_check.py b/clang-tools-extra/clang-tidy/add_new_check.py
index a6af76809af02a2c7e6e46187208138148e8f00f..3b14d5d158d2d0a5e800075b6e96289e6e07ce5a 100755
--- a/clang-tools-extra/clang-tidy/add_new_check.py
+++ b/clang-tools-extra/clang-tidy/add_new_check.py
@@ -211,7 +211,7 @@ def adapt_module(module_path, module, check_name, check_name_camel):
f.write(check_decl)
else:
match = re.search(
- 'registerCheck<(.*)> *\( *(?:"([^"]*)")?', line
+ r'registerCheck<(.*)> *\( *(?:"([^"]*)")?', line
)
prev_line = None
if match:
@@ -383,7 +383,7 @@ def update_checks_list(clang_tidy_path):
if stmt_start_pos == -1:
return ""
stmt = code[stmt_start_pos + 1 : stmt_end_pos]
- matches = re.search('registerCheck<([^>:]*)>\(\s*"([^"]*)"\s*\)', stmt)
+ matches = re.search(r'registerCheck<([^>:]*)>\(\s*"([^"]*)"\s*\)', stmt)
if matches and matches[2] == full_check_name:
class_name = matches[1]
if "::" in class_name:
@@ -401,8 +401,8 @@ def update_checks_list(clang_tidy_path):
# Examine code looking for a c'tor definition to get the base class name.
def get_base_class(code, check_file):
check_class_name = os.path.splitext(os.path.basename(check_file))[0]
- ctor_pattern = check_class_name + "\([^:]*\)\s*:\s*([A-Z][A-Za-z0-9]*Check)\("
- matches = re.search("\s+" + check_class_name + "::" + ctor_pattern, code)
+ ctor_pattern = check_class_name + r"\([^:]*\)\s*:\s*([A-Z][A-Za-z0-9]*Check)\("
+ matches = re.search(r"\s+" + check_class_name + "::" + ctor_pattern, code)
# The constructor might be inline in the header.
if not matches:
@@ -476,7 +476,7 @@ def update_checks_list(clang_tidy_path):
# Orphan page, don't list it.
return "", ""
- match = re.search(".*:http-equiv=refresh: \d+;URL=(.*).html(.*)", content)
+ match = re.search(r".*:http-equiv=refresh: \d+;URL=(.*).html(.*)", content)
# Is it a redirect?
return check_name, match
@@ -505,7 +505,7 @@ def update_checks_list(clang_tidy_path):
ref_begin = ""
ref_end = "_"
else:
- redirect_parts = re.search("^\.\./([^/]*)/([^/]*)$", match.group(1))
+ redirect_parts = re.search(r"^\.\./([^/]*)/([^/]*)$", match.group(1))
title = redirect_parts[1] + "-" + redirect_parts[2]
target = redirect_parts[1] + "/" + redirect_parts[2]
autofix = has_auto_fix(title)
diff --git a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp
index c608fe713f9f5b8d9f34dcff8b26e2655da595a2..e7be8134781e48de409fcd36a0e7d9dfe10a06d1 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp
@@ -72,7 +72,7 @@ void ForwardingReferenceOverloadCheck::registerMatchers(MatchFinder *Finder) {
DeclarationMatcher FindOverload =
cxxConstructorDecl(
- hasParameter(0, ForwardingRefParm),
+ hasParameter(0, ForwardingRefParm), unless(isDeleted()),
unless(hasAnyParameter(
// No warning: enable_if as constructor parameter.
parmVarDecl(hasType(isEnableIf())))),
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
index 87fd8adf997082593a28d680478c06f06fcfd9fc..bbb35228ce47fbb168a5a0c779177d0ae1510058 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
@@ -9,8 +9,8 @@
#include "MissingStdForwardCheck.h"
#include "../utils/Matchers.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/ExprConcepts.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/IdentifierTable.h"
using namespace clang::ast_matchers;
@@ -79,6 +79,11 @@ AST_MATCHER_P(LambdaExpr, hasCaptureDefaultKind, LambdaCaptureDefault, Kind) {
return Node.getCaptureDefault() == Kind;
}
+AST_MATCHER(VarDecl, hasIdentifier) {
+ const IdentifierInfo *ID = Node.getIdentifier();
+ return ID != NULL && !ID->isPlaceholder();
+}
+
} // namespace
void MissingStdForwardCheck::registerMatchers(MatchFinder *Finder) {
@@ -125,12 +130,14 @@ void MissingStdForwardCheck::registerMatchers(MatchFinder *Finder) {
hasAncestor(expr(hasUnevaluatedContext())))));
Finder->addMatcher(
- parmVarDecl(parmVarDecl().bind("param"), isTemplateTypeParameter(),
- hasAncestor(functionDecl().bind("func")),
- hasAncestor(functionDecl(
- isDefinition(), equalsBoundNode("func"), ToParam,
- unless(anyOf(isDeleted(), hasDescendant(std::move(
- ForwardCallMatcher))))))),
+ parmVarDecl(
+ parmVarDecl().bind("param"), hasIdentifier(),
+ unless(hasAttr(attr::Kind::Unused)), isTemplateTypeParameter(),
+ hasAncestor(functionDecl().bind("func")),
+ hasAncestor(functionDecl(
+ isDefinition(), equalsBoundNode("func"), ToParam,
+ unless(anyOf(isDeleted(),
+ hasDescendant(std::move(ForwardCallMatcher))))))),
this);
}
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
index 855c4a2efc373edeac6c01f48fb2e527e6231a87..9c3c7cc70c187b2e0bb43f1e18280492b79e91ab 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/ProTypeMemberInitCheck.cpp
@@ -444,7 +444,7 @@ void ProTypeMemberInitCheck::checkMissingMemberInitializer(
if (!F->hasInClassInitializer() &&
utils::type_traits::isTriviallyDefaultConstructible(F->getType(),
Context) &&
- !isEmpty(Context, F->getType()) && !F->isUnnamedBitfield() &&
+ !isEmpty(Context, F->getType()) && !F->isUnnamedBitField() &&
!AnyMemberHasInitPerUnion)
FieldsToInit.insert(F);
});
diff --git a/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.cpp b/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.cpp
index 8020f8cd062510b5ac677cf1d73de8d8c38800f1..b1a18485ce168d2bf94528d1c5a6f453537c6e79 100644
--- a/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.cpp
+++ b/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.cpp
@@ -14,9 +14,9 @@ IgnoredRemoveResultCheck::IgnoredRemoveResultCheck(llvm::StringRef Name,
ClangTidyContext *Context)
: UnusedReturnValueCheck(Name, Context,
{
- "::std::remove",
- "::std::remove_if",
- "::std::unique",
+ "::std::remove$",
+ "::std::remove_if$",
+ "::std::unique$",
}) {
// The constructor for ClangTidyCheck needs to have been called
// before we can access options via Options.get().
diff --git a/clang-tools-extra/clang-tidy/linuxkernel/MustCheckErrsCheck.h b/clang-tools-extra/clang-tidy/linuxkernel/MustCheckErrsCheck.h
index f08fed47983924d0f8cbb98e1a8789892d3b7ceb..7406aaead836e0c47e3b98b7d96eba3416e0a768 100644
--- a/clang-tools-extra/clang-tidy/linuxkernel/MustCheckErrsCheck.h
+++ b/clang-tools-extra/clang-tidy/linuxkernel/MustCheckErrsCheck.h
@@ -17,15 +17,8 @@ namespace clang::tidy::linuxkernel {
/// linux/err.h. Also checks to see if code uses the results from functions that
/// directly return a value from one of these error functions.
///
-/// This is important in the Linux kernel because ERR_PTR, PTR_ERR, IS_ERR,
-/// IS_ERR_OR_NULL, ERR_CAST, and PTR_ERR_OR_ZERO return values must be checked,
-/// since positive pointers and negative error codes are being used in the same
-/// context. These functions are marked with
-/// __attribute__((warn_unused_result)), but some kernel versions do not have
-/// this warning enabled for clang.
-///
/// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/linuxkernel/must-use-errs.html
+/// http://clang.llvm.org/extra/clang-tidy/checks/linuxkernel/must-check-errs.html
class MustCheckErrsCheck : public ClangTidyCheck {
public:
MustCheckErrsCheck(StringRef Name, ClangTidyContext *Context)
diff --git a/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
index 5134eb51a03226caa33aa14f6c195d9e2c2375b0..93151024064b42a72cc478d125e558d0e0eb3572 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseEqualsDefaultCheck.cpp
@@ -26,7 +26,7 @@ getAllNamedFields(const CXXRecordDecl *Record) {
std::set Result;
for (const auto *Field : Record->fields()) {
// Static data members are not in this range.
- if (Field->isUnnamedBitfield())
+ if (Field->isUnnamedBitField())
continue;
Result.insert(Field);
}
diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp
index b299afd540b9a3cf4a71babcc04e8077988ef235..1548fc454cfb3765eb1aaf30ffa5afc8d7001fe5 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseStdNumbersCheck.cpp
@@ -29,6 +29,7 @@
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/MathExtras.h"
#include
+#include
#include
#include
#include
diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
index 2fa7cd0baf98f69c906731220a9566fd3a05153c..c507043c367a86579598f63a38af2dbc8863742c 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
@@ -85,10 +85,10 @@ void UnnecessaryValueParamCheck::check(const MatchFinder::MatchResult &Result) {
TraversalKindScope RAII(*Result.Context, TK_AsIs);
- FunctionParmMutationAnalyzer &Analyzer =
- MutationAnalyzers.try_emplace(Function, *Function, *Result.Context)
- .first->second;
- if (Analyzer.isMutated(Param))
+ FunctionParmMutationAnalyzer *Analyzer =
+ FunctionParmMutationAnalyzer::getFunctionParmMutationAnalyzer(
+ *Function, *Result.Context, MutationAnalyzerCache);
+ if (Analyzer->isMutated(Param))
return;
const bool IsConstQualified =
@@ -169,7 +169,7 @@ void UnnecessaryValueParamCheck::storeOptions(
}
void UnnecessaryValueParamCheck::onEndOfTranslationUnit() {
- MutationAnalyzers.clear();
+ MutationAnalyzerCache.clear();
}
void UnnecessaryValueParamCheck::handleMoveFix(const ParmVarDecl &Var,
diff --git a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
index 1872e3bc9bf29cfa5becc2e23d6556f2ae07f208..7250bffd20b2f9e4d816f6b41a2260c0a6582202 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
@@ -37,8 +37,7 @@ private:
void handleMoveFix(const ParmVarDecl &Var, const DeclRefExpr &CopyArgument,
const ASTContext &Context);
- llvm::DenseMap
- MutationAnalyzers;
+ ExprMutationAnalyzer::Memoized MutationAnalyzerCache;
utils::IncludeInserter Inserter;
const std::vector AllowedTypes;
};
diff --git a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
index e3400f614fa5640784b1d6dee31caade6a5a2c8b..48bca41f4a3b1e87dbd7488617702f17e5f6e15a 100644
--- a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp
@@ -7,19 +7,18 @@
//===----------------------------------------------------------------------===//
#include "AvoidReturnWithVoidValueCheck.h"
-#include "clang/AST/Stmt.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/ASTMatchers/ASTMatchers.h"
+#include "../utils/BracesAroundStatement.h"
+#include "../utils/LexerUtils.h"
using namespace clang::ast_matchers;
namespace clang::tidy::readability {
-static constexpr auto IgnoreMacrosName = "IgnoreMacros";
-static constexpr auto IgnoreMacrosDefault = true;
+static constexpr char IgnoreMacrosName[] = "IgnoreMacros";
+static const bool IgnoreMacrosDefault = true;
-static constexpr auto StrictModeName = "StrictMode";
-static constexpr auto StrictModeDefault = true;
+static constexpr char StrictModeName[] = "StrictMode";
+static const bool StrictModeDefault = true;
AvoidReturnWithVoidValueCheck::AvoidReturnWithVoidValueCheck(
StringRef Name, ClangTidyContext *Context)
@@ -32,7 +31,10 @@ void AvoidReturnWithVoidValueCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
returnStmt(
hasReturnValue(allOf(hasType(voidType()), unless(initListExpr()))),
- optionally(hasParent(compoundStmt().bind("compound_parent"))))
+ optionally(hasParent(
+ compoundStmt(
+ optionally(hasParent(functionDecl().bind("function_parent"))))
+ .bind("compound_parent"))))
.bind("void_return"),
this);
}
@@ -42,10 +44,30 @@ void AvoidReturnWithVoidValueCheck::check(
const auto *VoidReturn = Result.Nodes.getNodeAs("void_return");
if (IgnoreMacros && VoidReturn->getBeginLoc().isMacroID())
return;
- if (!StrictMode && !Result.Nodes.getNodeAs("compound_parent"))
+ const auto *SurroundingBlock =
+ Result.Nodes.getNodeAs("compound_parent");
+ if (!StrictMode && !SurroundingBlock)
return;
- diag(VoidReturn->getBeginLoc(), "return statement within a void function "
- "should not have a specified return value");
+ DiagnosticBuilder Diag = diag(VoidReturn->getBeginLoc(),
+ "return statement within a void function "
+ "should not have a specified return value");
+ const SourceLocation SemicolonPos = utils::lexer::findNextTerminator(
+ VoidReturn->getEndLoc(), *Result.SourceManager, getLangOpts());
+ if (SemicolonPos.isInvalid())
+ return;
+ if (!SurroundingBlock) {
+ const auto BraceInsertionHints = utils::getBraceInsertionsHints(
+ VoidReturn, getLangOpts(), *Result.SourceManager,
+ VoidReturn->getBeginLoc());
+ if (BraceInsertionHints)
+ Diag << BraceInsertionHints.openingBraceFixIt()
+ << BraceInsertionHints.closingBraceFixIt();
+ }
+ Diag << FixItHint::CreateRemoval(VoidReturn->getReturnLoc());
+ if (!Result.Nodes.getNodeAs("function_parent") ||
+ SurroundingBlock->body_back() != VoidReturn)
+ Diag << FixItHint::CreateInsertion(SemicolonPos.getLocWithOffset(1),
+ " return;", true);
}
void AvoidReturnWithVoidValueCheck::storeOptions(
diff --git a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp
index 81ca33cbbdfb4b5461b54b8a0b5903c0d1186942..85bd9c1e4f9a043074963487e72077c55bc089b3 100644
--- a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "BracesAroundStatementsCheck.h"
+#include "../utils/BracesAroundStatement.h"
#include "../utils/LexerUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchers.h"
@@ -17,12 +18,10 @@ using namespace clang::ast_matchers;
namespace clang::tidy::readability {
static tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM,
- const ASTContext *Context) {
+ const LangOptions &LangOpts) {
Token Tok;
- SourceLocation Beginning =
- Lexer::GetBeginningOfToken(Loc, SM, Context->getLangOpts());
- const bool Invalid =
- Lexer::getRawToken(Beginning, Tok, SM, Context->getLangOpts());
+ SourceLocation Beginning = Lexer::GetBeginningOfToken(Loc, SM, LangOpts);
+ const bool Invalid = Lexer::getRawToken(Beginning, Tok, SM, LangOpts);
assert(!Invalid && "Expected a valid token.");
if (Invalid)
@@ -33,64 +32,21 @@ static tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM,
static SourceLocation
forwardSkipWhitespaceAndComments(SourceLocation Loc, const SourceManager &SM,
- const ASTContext *Context) {
+ const LangOptions &LangOpts) {
assert(Loc.isValid());
for (;;) {
while (isWhitespace(*SM.getCharacterData(Loc)))
Loc = Loc.getLocWithOffset(1);
- tok::TokenKind TokKind = getTokenKind(Loc, SM, Context);
+ tok::TokenKind TokKind = getTokenKind(Loc, SM, LangOpts);
if (TokKind != tok::comment)
return Loc;
// Fast-forward current token.
- Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts());
+ Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts);
}
}
-static SourceLocation findEndLocation(const Stmt &S, const SourceManager &SM,
- const ASTContext *Context) {
- SourceLocation Loc =
- utils::lexer::getUnifiedEndLoc(S, SM, Context->getLangOpts());
- if (!Loc.isValid())
- return Loc;
-
- // Start searching right after S.
- Loc = Loc.getLocWithOffset(1);
-
- for (;;) {
- assert(Loc.isValid());
- while (isHorizontalWhitespace(*SM.getCharacterData(Loc))) {
- Loc = Loc.getLocWithOffset(1);
- }
-
- if (isVerticalWhitespace(*SM.getCharacterData(Loc))) {
- // EOL, insert brace before.
- break;
- }
- tok::TokenKind TokKind = getTokenKind(Loc, SM, Context);
- if (TokKind != tok::comment) {
- // Non-comment token, insert brace before.
- break;
- }
-
- SourceLocation TokEndLoc =
- Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts());
- SourceRange TokRange(Loc, TokEndLoc);
- StringRef Comment = Lexer::getSourceText(
- CharSourceRange::getTokenRange(TokRange), SM, Context->getLangOpts());
- if (Comment.starts_with("/*") && Comment.contains('\n')) {
- // Multi-line block comment, insert brace before.
- break;
- }
- // else: Trailing comment, insert brace after the newline.
-
- // Fast-forward current token.
- Loc = TokEndLoc;
- }
- return Loc;
-}
-
BracesAroundStatementsCheck::BracesAroundStatementsCheck(
StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context),
@@ -124,7 +80,7 @@ void BracesAroundStatementsCheck::check(
} else if (const auto *S = Result.Nodes.getNodeAs("do")) {
checkStmt(Result, S->getBody(), S->getDoLoc(), S->getWhileLoc());
} else if (const auto *S = Result.Nodes.getNodeAs("while")) {
- SourceLocation StartLoc = findRParenLoc(S, SM, Context);
+ SourceLocation StartLoc = findRParenLoc(S, SM, Context->getLangOpts());
if (StartLoc.isInvalid())
return;
checkStmt(Result, S->getBody(), StartLoc);
@@ -133,7 +89,7 @@ void BracesAroundStatementsCheck::check(
if (S->isConsteval())
return;
- SourceLocation StartLoc = findRParenLoc(S, SM, Context);
+ SourceLocation StartLoc = findRParenLoc(S, SM, Context->getLangOpts());
if (StartLoc.isInvalid())
return;
if (ForceBracesStmts.erase(S))
@@ -156,7 +112,7 @@ template
SourceLocation
BracesAroundStatementsCheck::findRParenLoc(const IfOrWhileStmt *S,
const SourceManager &SM,
- const ASTContext *Context) {
+ const LangOptions &LangOpts) {
// Skip macros.
if (S->getBeginLoc().isMacroID())
return {};
@@ -170,14 +126,14 @@ BracesAroundStatementsCheck::findRParenLoc(const IfOrWhileStmt *S,
}
SourceLocation PastCondEndLoc =
- Lexer::getLocForEndOfToken(CondEndLoc, 0, SM, Context->getLangOpts());
+ Lexer::getLocForEndOfToken(CondEndLoc, 0, SM, LangOpts);
if (PastCondEndLoc.isInvalid())
return {};
SourceLocation RParenLoc =
- forwardSkipWhitespaceAndComments(PastCondEndLoc, SM, Context);
+ forwardSkipWhitespaceAndComments(PastCondEndLoc, SM, LangOpts);
if (RParenLoc.isInvalid())
return {};
- tok::TokenKind TokKind = getTokenKind(RParenLoc, SM, Context);
+ tok::TokenKind TokKind = getTokenKind(RParenLoc, SM, LangOpts);
if (TokKind != tok::r_paren)
return {};
return RParenLoc;
@@ -188,86 +144,23 @@ BracesAroundStatementsCheck::findRParenLoc(const IfOrWhileStmt *S,
bool BracesAroundStatementsCheck::checkStmt(
const MatchFinder::MatchResult &Result, const Stmt *S,
SourceLocation StartLoc, SourceLocation EndLocHint) {
-
while (const auto *AS = dyn_cast(S))
S = AS->getSubStmt();
- const SourceManager &SM = *Result.SourceManager;
- const ASTContext *Context = Result.Context;
-
- // 1) If there's a corresponding "else" or "while", the check inserts "} "
- // right before that token.
- // 2) If there's a multi-line block comment starting on the same line after
- // the location we're inserting the closing brace at, or there's a non-comment
- // token, the check inserts "\n}" right before that token.
- // 3) Otherwise the check finds the end of line (possibly after some block or
- // line comments) and inserts "\n}" right before that EOL.
- if (!S || isa(S)) {
- // Already inside braces.
- return false;
- }
-
- // When TreeTransform, Stmt in constexpr IfStmt will be transform to NullStmt.
- // This NullStmt can be detected according to beginning token.
- const SourceLocation StmtBeginLoc = S->getBeginLoc();
- if (isa(S) && StmtBeginLoc.isValid() &&
- getTokenKind(StmtBeginLoc, SM, Context) == tok::l_brace)
- return false;
-
- if (StartLoc.isInvalid())
- return false;
-
- // Convert StartLoc to file location, if it's on the same macro expansion
- // level as the start of the statement. We also need file locations for
- // Lexer::getLocForEndOfToken working properly.
- StartLoc = Lexer::makeFileCharRange(
- CharSourceRange::getCharRange(StartLoc, S->getBeginLoc()), SM,
- Context->getLangOpts())
- .getBegin();
- if (StartLoc.isInvalid())
- return false;
- StartLoc =
- Lexer::getLocForEndOfToken(StartLoc, 0, SM, Context->getLangOpts());
-
- // StartLoc points at the location of the opening brace to be inserted.
- SourceLocation EndLoc;
- std::string ClosingInsertion;
- if (EndLocHint.isValid()) {
- EndLoc = EndLocHint;
- ClosingInsertion = "} ";
- } else {
- EndLoc = findEndLocation(*S, SM, Context);
- ClosingInsertion = "\n}";
- }
-
- assert(StartLoc.isValid());
-
- // Don't require braces for statements spanning less than certain number of
- // lines.
- if (ShortStatementLines && !ForceBracesStmts.erase(S)) {
- unsigned StartLine = SM.getSpellingLineNumber(StartLoc);
- unsigned EndLine = SM.getSpellingLineNumber(EndLoc);
- if (EndLine - StartLine < ShortStatementLines)
+ const auto BraceInsertionHints = utils::getBraceInsertionsHints(
+ S, Result.Context->getLangOpts(), *Result.SourceManager, StartLoc,
+ EndLocHint);
+ if (BraceInsertionHints) {
+ if (ShortStatementLines && !ForceBracesStmts.erase(S) &&
+ BraceInsertionHints.resultingCompoundLineExtent(*Result.SourceManager) <
+ ShortStatementLines)
return false;
+ auto Diag = diag(BraceInsertionHints.DiagnosticPos,
+ "statement should be inside braces");
+ if (BraceInsertionHints.offersFixIts())
+ Diag << BraceInsertionHints.openingBraceFixIt()
+ << BraceInsertionHints.closingBraceFixIt();
}
-
- auto Diag = diag(StartLoc, "statement should be inside braces");
-
- // Change only if StartLoc and EndLoc are on the same macro expansion level.
- // This will also catch invalid EndLoc.
- // Example: LLVM_DEBUG( for(...) do_something() );
- // In this case fix-it cannot be provided as the semicolon which is not
- // visible here is part of the macro. Adding braces here would require adding
- // another semicolon.
- if (Lexer::makeFileCharRange(
- CharSourceRange::getTokenRange(SourceRange(
- SM.getSpellingLoc(StartLoc), SM.getSpellingLoc(EndLoc))),
- SM, Context->getLangOpts())
- .isInvalid())
- return false;
-
- Diag << FixItHint::CreateInsertion(StartLoc, " {")
- << FixItHint::CreateInsertion(EndLoc, ClosingInsertion);
return true;
}
diff --git a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h
index 249aa1aaaa91545549c847912feb3415a381e8cf..4cd37a7b2dd6cc169f9301d6a21b1613748399db 100644
--- a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h
@@ -52,7 +52,7 @@ private:
SourceLocation EndLocHint = SourceLocation());
template
SourceLocation findRParenLoc(const IfOrWhileStmt *S, const SourceManager &SM,
- const ASTContext *Context);
+ const LangOptions &LangOpts);
std::optional getCheckTraversalKind() const override {
return TK_IgnoreUnlessSpelledInSource;
}
diff --git a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp
index 67147164946ab405138aeafbb361f490f4382ad6..229e5583846b96c0a4ddc537bc78d7a4467fa355 100644
--- a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp
@@ -79,6 +79,10 @@ void DuplicateIncludeCallbacks::InclusionDirective(
bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File,
StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule,
bool ModuleImported, SrcMgr::CharacteristicKind FileType) {
+ // Skip includes behind macros
+ if (FilenameRange.getBegin().isMacroID() ||
+ FilenameRange.getEnd().isMacroID())
+ return;
if (llvm::is_contained(Files.back(), FileName)) {
// We want to delete the entire line, so make sure that [Start,End] covers
// everything.
diff --git a/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.cpp b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2a3b7bed08c1e00363d9ad2c899528d8e150f61e
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.cpp
@@ -0,0 +1,168 @@
+//===--- BracesAroundStatement.cpp - clang-tidy -------- ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file provides utilities to put braces around a statement.
+///
+//===----------------------------------------------------------------------===//
+
+#include "BracesAroundStatement.h"
+#include "../utils/LexerUtils.h"
+#include "LexerUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Basic/CharInfo.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Lex/Lexer.h"
+
+namespace clang::tidy::utils {
+
+BraceInsertionHints::operator bool() const { return DiagnosticPos.isValid(); }
+
+bool BraceInsertionHints::offersFixIts() const {
+ return OpeningBracePos.isValid() && ClosingBracePos.isValid();
+}
+
+unsigned BraceInsertionHints::resultingCompoundLineExtent(
+ const SourceManager &SourceMgr) const {
+ return SourceMgr.getSpellingLineNumber(ClosingBracePos) -
+ SourceMgr.getSpellingLineNumber(OpeningBracePos);
+}
+
+FixItHint BraceInsertionHints::openingBraceFixIt() const {
+ return OpeningBracePos.isValid()
+ ? FixItHint::CreateInsertion(OpeningBracePos, " {")
+ : FixItHint();
+}
+
+FixItHint BraceInsertionHints::closingBraceFixIt() const {
+ return ClosingBracePos.isValid()
+ ? FixItHint::CreateInsertion(ClosingBracePos, ClosingBrace)
+ : FixItHint();
+}
+
+static tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ Token Tok;
+ SourceLocation Beginning = Lexer::GetBeginningOfToken(Loc, SM, LangOpts);
+ const bool Invalid = Lexer::getRawToken(Beginning, Tok, SM, LangOpts);
+ assert(!Invalid && "Expected a valid token.");
+
+ if (Invalid)
+ return tok::NUM_TOKENS;
+
+ return Tok.getKind();
+}
+
+static SourceLocation findEndLocation(const Stmt &S, const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ SourceLocation Loc = lexer::getUnifiedEndLoc(S, SM, LangOpts);
+ if (!Loc.isValid())
+ return Loc;
+
+ // Start searching right after S.
+ Loc = Loc.getLocWithOffset(1);
+
+ for (;;) {
+ assert(Loc.isValid());
+ while (isHorizontalWhitespace(*SM.getCharacterData(Loc))) {
+ Loc = Loc.getLocWithOffset(1);
+ }
+
+ if (isVerticalWhitespace(*SM.getCharacterData(Loc))) {
+ // EOL, insert brace before.
+ break;
+ }
+ tok::TokenKind TokKind = getTokenKind(Loc, SM, LangOpts);
+ if (TokKind != tok::comment) {
+ // Non-comment token, insert brace before.
+ break;
+ }
+
+ SourceLocation TokEndLoc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts);
+ SourceRange TokRange(Loc, TokEndLoc);
+ StringRef Comment = Lexer::getSourceText(
+ CharSourceRange::getTokenRange(TokRange), SM, LangOpts);
+ if (Comment.starts_with("/*") && Comment.contains('\n')) {
+ // Multi-line block comment, insert brace before.
+ break;
+ }
+ // else: Trailing comment, insert brace after the newline.
+
+ // Fast-forward current token.
+ Loc = TokEndLoc;
+ }
+ return Loc;
+}
+
+BraceInsertionHints getBraceInsertionsHints(const Stmt *const S,
+ const LangOptions &LangOpts,
+ const SourceManager &SM,
+ SourceLocation StartLoc,
+ SourceLocation EndLocHint) {
+ // 1) If there's a corresponding "else" or "while", the check inserts "} "
+ // right before that token.
+ // 2) If there's a multi-line block comment starting on the same line after
+ // the location we're inserting the closing brace at, or there's a non-comment
+ // token, the check inserts "\n}" right before that token.
+ // 3) Otherwise the check finds the end of line (possibly after some block or
+ // line comments) and inserts "\n}" right before that EOL.
+ if (!S || isa(S)) {
+ // Already inside braces.
+ return {};
+ }
+
+ // When TreeTransform, Stmt in constexpr IfStmt will be transform to NullStmt.
+ // This NullStmt can be detected according to beginning token.
+ const SourceLocation StmtBeginLoc = S->getBeginLoc();
+ if (isa(S) && StmtBeginLoc.isValid() &&
+ getTokenKind(StmtBeginLoc, SM, LangOpts) == tok::l_brace)
+ return {};
+
+ if (StartLoc.isInvalid())
+ return {};
+
+ // Convert StartLoc to file location, if it's on the same macro expansion
+ // level as the start of the statement. We also need file locations for
+ // Lexer::getLocForEndOfToken working properly.
+ StartLoc = Lexer::makeFileCharRange(
+ CharSourceRange::getCharRange(StartLoc, S->getBeginLoc()), SM,
+ LangOpts)
+ .getBegin();
+ if (StartLoc.isInvalid())
+ return {};
+ StartLoc = Lexer::getLocForEndOfToken(StartLoc, 0, SM, LangOpts);
+
+ // StartLoc points at the location of the opening brace to be inserted.
+ SourceLocation EndLoc;
+ std::string ClosingInsertion;
+ if (EndLocHint.isValid()) {
+ EndLoc = EndLocHint;
+ ClosingInsertion = "} ";
+ } else {
+ EndLoc = findEndLocation(*S, SM, LangOpts);
+ ClosingInsertion = "\n}";
+ }
+
+ assert(StartLoc.isValid());
+
+ // Change only if StartLoc and EndLoc are on the same macro expansion level.
+ // This will also catch invalid EndLoc.
+ // Example: LLVM_DEBUG( for(...) do_something() );
+ // In this case fix-it cannot be provided as the semicolon which is not
+ // visible here is part of the macro. Adding braces here would require adding
+ // another semicolon.
+ if (Lexer::makeFileCharRange(
+ CharSourceRange::getTokenRange(SourceRange(
+ SM.getSpellingLoc(StartLoc), SM.getSpellingLoc(EndLoc))),
+ SM, LangOpts)
+ .isInvalid())
+ return {StartLoc};
+ return {StartLoc, EndLoc, ClosingInsertion};
+}
+
+} // namespace clang::tidy::utils
diff --git a/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.h b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.h
new file mode 100644
index 0000000000000000000000000000000000000000..cb1c06c7aa1a1a9d5bdd56cd805aa26f19e56c8d
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.h
@@ -0,0 +1,75 @@
+//===--- BracesAroundStatement.h - clang-tidy ------- -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file provides utilities to put braces around a statement.
+///
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/Stmt.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+
+namespace clang::tidy::utils {
+
+/// A provider of fix-it hints to insert opening and closing braces. An instance
+/// of this type is the result of calling `getBraceInsertionsHints` below.
+struct BraceInsertionHints {
+ /// The position of a potential diagnostic. It coincides with the position of
+ /// the opening brace to insert, but can also just be the place to show a
+ /// diagnostic in case braces cannot be inserted automatically.
+ SourceLocation DiagnosticPos;
+
+ /// Constructor for a no-hint.
+ BraceInsertionHints() = default;
+
+ /// Constructor for a valid hint that cannot insert braces automatically.
+ BraceInsertionHints(SourceLocation DiagnosticPos)
+ : DiagnosticPos(DiagnosticPos) {}
+
+ /// Constructor for a hint offering fix-its for brace insertion. Both
+ /// positions must be valid.
+ BraceInsertionHints(SourceLocation OpeningBracePos,
+ SourceLocation ClosingBracePos, std::string ClosingBrace)
+ : DiagnosticPos(OpeningBracePos), OpeningBracePos(OpeningBracePos),
+ ClosingBracePos(ClosingBracePos), ClosingBrace(ClosingBrace) {
+ assert(offersFixIts());
+ }
+
+ /// Indicates whether the hint provides at least the position of a diagnostic.
+ operator bool() const;
+
+ /// Indicates whether the hint provides fix-its to insert braces.
+ bool offersFixIts() const;
+
+ /// The number of lines between the inserted opening brace and its closing
+ /// counterpart.
+ unsigned resultingCompoundLineExtent(const SourceManager &SourceMgr) const;
+
+ /// Fix-it to insert an opening brace.
+ FixItHint openingBraceFixIt() const;
+
+ /// Fix-it to insert a closing brace.
+ FixItHint closingBraceFixIt() const;
+
+private:
+ SourceLocation OpeningBracePos;
+ SourceLocation ClosingBracePos;
+ std::string ClosingBrace;
+};
+
+/// Create fix-it hints for braces that wrap the given statement when applied.
+/// The algorithm computing them respects comment before and after the statement
+/// and adds line breaks before the braces accordingly.
+BraceInsertionHints
+getBraceInsertionsHints(const Stmt *const S, const LangOptions &LangOpts,
+ const SourceManager &SM, SourceLocation StartLoc,
+ SourceLocation EndLocHint = SourceLocation());
+
+} // namespace clang::tidy::utils
diff --git a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt
index f0160fa9df74879429e6f6be554d43bf633af0d6..9cff7d475425d792c2c2f373a3e88d34f7216513 100644
--- a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt
@@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangTidyUtils
Aliasing.cpp
ASTUtils.cpp
+ BracesAroundStatement.cpp
DeclRefExprUtils.cpp
DesignatedInitializers.cpp
ExceptionAnalyzer.cpp
diff --git a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp
index 1dde0490517852d91cd427790371c222c1a9f779..4a9426ee7e8bbbe35f46cfbc1a9670833aab123d 100644
--- a/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp
+++ b/clang-tools-extra/clang-tidy/utils/ExceptionSpecAnalyzer.cpp
@@ -99,7 +99,7 @@ ExceptionSpecAnalyzer::analyzeRecord(const CXXRecordDecl *RecordDecl,
}
for (const auto *FDecl : RecordDecl->fields())
- if (!FDecl->isInvalidDecl() && !FDecl->isUnnamedBitfield()) {
+ if (!FDecl->isInvalidDecl() && !FDecl->isUnnamedBitField()) {
State Result = analyzeFieldDecl(FDecl, Kind);
if (Result == State::Throwing || Result == State::Unknown)
return Result;
diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
index da1433aa2d05d472f5f581973fead7993d468794..962a243ce94d48bfcf3e9ed1ffa3278749cbb35a 100644
--- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
@@ -31,13 +31,12 @@ struct DenseMapInfo {
using NamingCheckId = clang::tidy::RenamerClangTidyCheck::NamingCheckId;
static inline NamingCheckId getEmptyKey() {
- return {DenseMapInfo::getEmptyKey(),
- "EMPTY"};
+ return {DenseMapInfo::getEmptyKey(), "EMPTY"};
}
static inline NamingCheckId getTombstoneKey() {
return {DenseMapInfo::getTombstoneKey(),
- "TOMBSTONE"};
+ "TOMBSTONE"};
}
static unsigned getHashValue(NamingCheckId Val) {
@@ -170,14 +169,14 @@ public:
return;
if (SM.isWrittenInCommandLineFile(MacroNameTok.getLocation()))
return;
- Check->checkMacro(SM, MacroNameTok, Info);
+ Check->checkMacro(MacroNameTok, Info, SM);
}
/// MacroExpands calls expandMacro for macros in the main file
void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
SourceRange /*Range*/,
const MacroArgs * /*Args*/) override {
- Check->expandMacro(MacroNameTok, MD.getMacroInfo());
+ Check->expandMacro(MacroNameTok, MD.getMacroInfo(), SM);
}
private:
@@ -188,7 +187,7 @@ private:
class RenamerClangTidyVisitor
: public RecursiveASTVisitor {
public:
- RenamerClangTidyVisitor(RenamerClangTidyCheck *Check, const SourceManager *SM,
+ RenamerClangTidyVisitor(RenamerClangTidyCheck *Check, const SourceManager &SM,
bool AggressiveDependentMemberLookup)
: Check(Check), SM(SM),
AggressiveDependentMemberLookup(AggressiveDependentMemberLookup) {}
@@ -259,7 +258,7 @@ public:
// Fix overridden methods
if (const auto *Method = dyn_cast(Decl)) {
if (const CXXMethodDecl *Overridden = getOverrideMethod(Method)) {
- Check->addUsage(Overridden, Method->getLocation());
+ Check->addUsage(Overridden, Method->getLocation(), SM);
return true; // Don't try to add the actual decl as a Failure.
}
}
@@ -269,7 +268,7 @@ public:
if (isa(Decl))
return true;
- Check->checkNamedDecl(Decl, *SM);
+ Check->checkNamedDecl(Decl, SM);
return true;
}
@@ -367,9 +366,26 @@ public:
return true;
}
+ bool VisitDesignatedInitExpr(DesignatedInitExpr *Expr) {
+ for (const DesignatedInitExpr::Designator &D : Expr->designators()) {
+ if (!D.isFieldDesignator())
+ continue;
+ const FieldDecl *FD = D.getFieldDecl();
+ if (!FD)
+ continue;
+ const IdentifierInfo *II = FD->getIdentifier();
+ if (!II)
+ continue;
+ SourceRange FixLocation{D.getFieldLoc(), D.getFieldLoc()};
+ Check->addUsage(FD, FixLocation, SM);
+ }
+
+ return true;
+ }
+
private:
RenamerClangTidyCheck *Check;
- const SourceManager *SM;
+ const SourceManager &SM;
const bool AggressiveDependentMemberLookup;
};
@@ -399,7 +415,7 @@ void RenamerClangTidyCheck::registerPPCallbacks(
void RenamerClangTidyCheck::addUsage(
const RenamerClangTidyCheck::NamingCheckId &Decl, SourceRange Range,
- const SourceManager *SourceMgr) {
+ const SourceManager &SourceMgr) {
// Do nothing if the provided range is invalid.
if (Range.isInvalid())
return;
@@ -409,8 +425,7 @@ void RenamerClangTidyCheck::addUsage(
// spelling location to different source locations, and we only want to fix
// the token once, before it is expanded by the macro.
SourceLocation FixLocation = Range.getBegin();
- if (SourceMgr)
- FixLocation = SourceMgr->getSpellingLoc(FixLocation);
+ FixLocation = SourceMgr.getSpellingLoc(FixLocation);
if (FixLocation.isInvalid())
return;
@@ -424,15 +439,15 @@ void RenamerClangTidyCheck::addUsage(
if (!Failure.shouldFix())
return;
- if (SourceMgr && SourceMgr->isWrittenInScratchSpace(FixLocation))
+ if (SourceMgr.isWrittenInScratchSpace(FixLocation))
Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro;
- if (!utils::rangeCanBeFixed(Range, SourceMgr))
+ if (!utils::rangeCanBeFixed(Range, &SourceMgr))
Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro;
}
void RenamerClangTidyCheck::addUsage(const NamedDecl *Decl, SourceRange Range,
- const SourceManager *SourceMgr) {
+ const SourceManager &SourceMgr) {
// Don't keep track for non-identifier names.
auto *II = Decl->getIdentifier();
if (!II)
@@ -473,18 +488,24 @@ void RenamerClangTidyCheck::checkNamedDecl(const NamedDecl *Decl,
}
Failure.Info = std::move(Info);
- addUsage(Decl, Range);
+ addUsage(Decl, Range, SourceMgr);
}
void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) {
- RenamerClangTidyVisitor Visitor(this, Result.SourceManager,
+ if (!Result.SourceManager) {
+ // In principle SourceManager is not null but going only by the definition
+ // of MatchResult it must be handled. Cannot rename anything without a
+ // SourceManager.
+ return;
+ }
+ RenamerClangTidyVisitor Visitor(this, *Result.SourceManager,
AggressiveDependentMemberLookup);
Visitor.TraverseAST(*Result.Context);
}
-void RenamerClangTidyCheck::checkMacro(const SourceManager &SourceMgr,
- const Token &MacroNameTok,
- const MacroInfo *MI) {
+void RenamerClangTidyCheck::checkMacro(const Token &MacroNameTok,
+ const MacroInfo *MI,
+ const SourceManager &SourceMgr) {
std::optional MaybeFailure =
getMacroFailureInfo(MacroNameTok, SourceMgr);
if (!MaybeFailure)
@@ -499,11 +520,12 @@ void RenamerClangTidyCheck::checkMacro(const SourceManager &SourceMgr,
Failure.FixStatus = ShouldFixStatus::FixInvalidIdentifier;
Failure.Info = std::move(Info);
- addUsage(ID, Range);
+ addUsage(ID, Range, SourceMgr);
}
void RenamerClangTidyCheck::expandMacro(const Token &MacroNameTok,
- const MacroInfo *MI) {
+ const MacroInfo *MI,
+ const SourceManager &SourceMgr) {
StringRef Name = MacroNameTok.getIdentifierInfo()->getName();
NamingCheckId ID(MI->getDefinitionLoc(), Name);
@@ -512,7 +534,7 @@ void RenamerClangTidyCheck::expandMacro(const Token &MacroNameTok,
return;
SourceRange Range(MacroNameTok.getLocation(), MacroNameTok.getEndLoc());
- addUsage(ID, Range);
+ addUsage(ID, Range, SourceMgr);
}
static std::string
diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h
index 38228fb59bf62487674a5ba28bbe8449956d37e2..be5b6f0c7f76785d7f2aada7dd394cf3a568ddd4 100644
--- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h
+++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h
@@ -108,18 +108,19 @@ public:
llvm::DenseMap;
/// Check Macros for style violations.
- void checkMacro(const SourceManager &SourceMgr, const Token &MacroNameTok,
- const MacroInfo *MI);
+ void checkMacro(const Token &MacroNameTok, const MacroInfo *MI,
+ const SourceManager &SourceMgr);
/// Add a usage of a macro if it already has a violation.
- void expandMacro(const Token &MacroNameTok, const MacroInfo *MI);
+ void expandMacro(const Token &MacroNameTok, const MacroInfo *MI,
+ const SourceManager &SourceMgr);
void addUsage(const RenamerClangTidyCheck::NamingCheckId &Decl,
- SourceRange Range, const SourceManager *SourceMgr = nullptr);
+ SourceRange Range, const SourceManager &SourceMgr);
/// Convenience method when the usage to be added is a NamedDecl.
void addUsage(const NamedDecl *Decl, SourceRange Range,
- const SourceManager *SourceMgr = nullptr);
+ const SourceManager &SourceMgr);
void checkNamedDecl(const NamedDecl *Decl, const SourceManager &SourceMgr);
diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp
index 5790273d625ef14f7ae06ff608b88cd65926e808..1c4c2a79b5c05103cef3b9273f63dec556b9a584 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -30,6 +30,7 @@
#include "refactor/Rename.h"
#include "refactor/Tweak.h"
#include "support/Cancellation.h"
+#include "support/Context.h"
#include "support/Logger.h"
#include "support/MemoryTree.h"
#include "support/ThreadsafeFS.h"
@@ -112,7 +113,12 @@ struct UpdateIndexCallbacks : public ParsingCallbacks {
// Index outlives TUScheduler (declared first)
FIndex(FIndex),
// shared_ptr extends lifetime
- Stdlib(Stdlib)]() mutable {
+ Stdlib(Stdlib),
+ // We have some FS implementations that rely on information in
+ // the context.
+ Ctx(Context::current().clone())]() mutable {
+ // Make sure we install the context into current thread.
+ WithContext C(std::move(Ctx));
clang::noteBottomOfStack();
IndexFileIn IF;
IF.Symbols = indexStandardLibrary(std::move(CI), Loc, *TFS);
diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp
index 9e321dce4c5041901ef21708b2366f2722514b7a..89eee392837af4955a584fca6c0515949924baa1 100644
--- a/clang-tools-extra/clangd/CodeComplete.cpp
+++ b/clang-tools-extra/clangd/CodeComplete.cpp
@@ -89,7 +89,11 @@ const CodeCompleteOptions::CodeCompletionRankingModel
namespace {
-CompletionItemKind toCompletionItemKind(index::SymbolKind Kind) {
+// Note: changes to this function should also be reflected in the
+// CodeCompletionResult overload where appropriate.
+CompletionItemKind
+toCompletionItemKind(index::SymbolKind Kind,
+ const llvm::StringRef *Signature = nullptr) {
using SK = index::SymbolKind;
switch (Kind) {
case SK::Unknown:
@@ -99,7 +103,10 @@ CompletionItemKind toCompletionItemKind(index::SymbolKind Kind) {
case SK::NamespaceAlias:
return CompletionItemKind::Module;
case SK::Macro:
- return CompletionItemKind::Text;
+ // Use macro signature (if provided) to tell apart function-like and
+ // object-like macros.
+ return Signature && Signature->contains('(') ? CompletionItemKind::Function
+ : CompletionItemKind::Constant;
case SK::Enum:
return CompletionItemKind::Enum;
case SK::Struct:
@@ -150,6 +157,8 @@ CompletionItemKind toCompletionItemKind(index::SymbolKind Kind) {
llvm_unreachable("Unhandled clang::index::SymbolKind.");
}
+// Note: changes to this function should also be reflected in the
+// index::SymbolKind overload where appropriate.
CompletionItemKind toCompletionItemKind(const CodeCompletionResult &Res,
CodeCompletionContext::Kind CtxKind) {
if (Res.Declaration)
@@ -379,7 +388,8 @@ struct CodeCompletionBuilder {
if (Completion.Scope.empty())
Completion.Scope = std::string(C.IndexResult->Scope);
if (Completion.Kind == CompletionItemKind::Missing)
- Completion.Kind = toCompletionItemKind(C.IndexResult->SymInfo.Kind);
+ Completion.Kind = toCompletionItemKind(C.IndexResult->SymInfo.Kind,
+ &C.IndexResult->Signature);
if (Completion.Name.empty())
Completion.Name = std::string(C.IndexResult->Name);
if (Completion.FilterText.empty())
diff --git a/clang-tools-extra/clangd/CompileCommands.cpp b/clang-tools-extra/clangd/CompileCommands.cpp
index 5b8128fca62668ca555f049b7652369cd11be39e..fddfffe7523d9516037e310bd0d20b0c9520d100 100644
--- a/clang-tools-extra/clangd/CompileCommands.cpp
+++ b/clang-tools-extra/clangd/CompileCommands.cpp
@@ -466,7 +466,8 @@ llvm::ArrayRef ArgStripper::rulesFor(llvm::StringRef Arg) {
static constexpr llvm::ArrayRef NAME( \
NAME##_init, std::size(NAME##_init) - 1);
#define OPTION(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \
- FLAGS, VISIBILITY, PARAM, HELP, METAVAR, VALUES) \
+ FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, \
+ METAVAR, VALUES) \
Prefixes[DriverID::OPT_##ID] = PREFIX;
#include "clang/Driver/Options.inc"
#undef OPTION
@@ -478,7 +479,8 @@ llvm::ArrayRef ArgStripper::rulesFor(llvm::StringRef Arg) {
const void *AliasArgs;
} AliasTable[] = {
#define OPTION(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \
- FLAGS, VISIBILITY, PARAM, HELP, METAVAR, VALUES) \
+ FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, \
+ METAVAR, VALUES) \
{DriverID::OPT_##ID, DriverID::OPT_##ALIAS, ALIASARGS},
#include "clang/Driver/Options.inc"
#undef OPTION
diff --git a/clang-tools-extra/clangd/IncludeCleaner.h b/clang-tools-extra/clangd/IncludeCleaner.h
index 387763de340767be7e3cf8598db2b1a6c7076fd5..624e2116be7da3015816dfec628d8de6ac7f363c 100644
--- a/clang-tools-extra/clangd/IncludeCleaner.h
+++ b/clang-tools-extra/clangd/IncludeCleaner.h
@@ -62,15 +62,6 @@ issueIncludeCleanerDiagnostics(ParsedAST &AST, llvm::StringRef Code,
const ThreadsafeFS &TFS,
HeaderFilter IgnoreHeader = {});
-/// Affects whether standard library includes should be considered for
-/// removal. This is off by default for now due to implementation limitations:
-/// - macros are not tracked
-/// - symbol names without a unique associated header are not tracked
-/// - references to std-namespaced C types are not properly tracked:
-/// instead of std::size_t -> we see ::size_t ->
-/// FIXME: remove this hack once the implementation is good enough.
-void setIncludeCleanerAnalyzesStdlib(bool B);
-
/// Converts the clangd include representation to include-cleaner
/// include representation.
include_cleaner::Includes convertIncludes(const ParsedAST &);
diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp
index f181c7befec156a9afba0548da585ecc55010c9a..d5818e0ca309b03fafadc20f1fbdfe4f902ab615 100644
--- a/clang-tools-extra/clangd/Preamble.cpp
+++ b/clang-tools-extra/clangd/Preamble.cpp
@@ -700,6 +700,7 @@ buildPreamble(PathRef FileName, CompilerInvocation CI,
Result->Marks = CapturedInfo.takeMarks();
Result->StatCache = StatCache;
Result->MainIsIncludeGuarded = CapturedInfo.isMainFileIncludeGuarded();
+ Result->TargetOpts = CI.TargetOpts;
if (PreambleCallback) {
trace::Span Tracer("Running PreambleCallback");
auto Ctx = CapturedInfo.takeLife();
@@ -913,6 +914,12 @@ PreamblePatch PreamblePatch::createMacroPatch(llvm::StringRef FileName,
}
void PreamblePatch::apply(CompilerInvocation &CI) const {
+ // Make sure the compilation uses same target opts as the preamble. Clang has
+ // no guarantees around using arbitrary options when reusing PCHs, and
+ // different target opts can result in crashes, see
+ // ParsedASTTest.PreambleWithDifferentTarget.
+ CI.TargetOpts = Baseline->TargetOpts;
+
// No need to map an empty file.
if (PatchContents.empty())
return;
diff --git a/clang-tools-extra/clangd/Preamble.h b/clang-tools-extra/clangd/Preamble.h
index 37da3833748a9c6e1357bdba3cbf509b31686414..160b884beb56bb78f1b0e79d435a6c352e90e73a 100644
--- a/clang-tools-extra/clangd/Preamble.h
+++ b/clang-tools-extra/clangd/Preamble.h
@@ -30,6 +30,7 @@
#include "clang-include-cleaner/Record.h"
#include "support/Path.h"
#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetOptions.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/PrecompiledPreamble.h"
#include "clang/Lex/Lexer.h"
@@ -97,6 +98,10 @@ struct PreambleData {
// Version of the ParseInputs this preamble was built from.
std::string Version;
tooling::CompileCommand CompileCommand;
+ // Target options used when building the preamble. Changes in target can cause
+ // crashes when deserializing preamble, this enables consumers to use the
+ // same target (without reparsing CompileCommand).
+ std::shared_ptr TargetOpts = nullptr;
PrecompiledPreamble Preamble;
std::vector Diags;
// Processes like code completions and go-to-definitions will need #include
diff --git a/clang-tools-extra/clangd/index/SymbolCollector.cpp b/clang-tools-extra/clangd/index/SymbolCollector.cpp
index 85b8fc549b016e4dc159ddf591266dba80511fbb..5c4e2150cf3123bb11ecb567887ee269ec6f0ca7 100644
--- a/clang-tools-extra/clangd/index/SymbolCollector.cpp
+++ b/clang-tools-extra/clangd/index/SymbolCollector.cpp
@@ -409,7 +409,7 @@ private:
// Framework headers are spelled as , not
// "path/FrameworkName.framework/Headers/Foo.h".
auto &HS = PP->getHeaderSearchInfo();
- if (const auto *HFI = HS.getExistingFileInfo(*FE, /*WantExternal*/ false))
+ if (const auto *HFI = HS.getExistingFileInfo(*FE))
if (!HFI->Framework.empty())
if (auto Spelling =
getFrameworkHeaderIncludeSpelling(*FE, HFI->Framework, HS))
diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 49337bddf98d5d93c22f75169844bc08ded35426..96d1ee1f0add7359e30dc7435d76d4e8c295cb7e 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -671,7 +671,8 @@ TEST(CompletionTest, Kinds) {
#define MACRO 10
int X = ^
)cpp",
- {func("indexFunction"), var("indexVariable"), cls("indexClass")});
+ {func("indexFunction"), var("indexVariable"), cls("indexClass"),
+ macro("indexObjMacro"), macro("indexFuncMacro", "(x, y)")});
EXPECT_THAT(Results.Completions,
AllOf(has("function", CompletionItemKind::Function),
has("variable", CompletionItemKind::Variable),
@@ -680,7 +681,9 @@ TEST(CompletionTest, Kinds) {
has("MACRO", CompletionItemKind::Constant),
has("indexFunction", CompletionItemKind::Function),
has("indexVariable", CompletionItemKind::Variable),
- has("indexClass", CompletionItemKind::Class)));
+ has("indexClass", CompletionItemKind::Class),
+ has("indexObjMacro", CompletionItemKind::Constant),
+ has("indexFuncMacro", CompletionItemKind::Function)));
Results = completions("nam^");
EXPECT_THAT(Results.Completions,
@@ -4157,7 +4160,32 @@ TEST(CompletionTest, DoNotCrash) {
auto Completions = completions(Case);
}
}
+TEST(CompletionTest, PreambleFromDifferentTarget) {
+ constexpr std::string_view PreambleTarget = "x86_64";
+ constexpr std::string_view Contents =
+ "int foo(int); int num; int num2 = foo(n^";
+ Annotations Test(Contents);
+ auto TU = TestTU::withCode(Test.code());
+ TU.ExtraArgs.emplace_back("-target");
+ TU.ExtraArgs.emplace_back(PreambleTarget);
+ auto Preamble = TU.preamble();
+ ASSERT_TRUE(Preamble);
+ // Switch target to wasm.
+ TU.ExtraArgs.pop_back();
+ TU.ExtraArgs.emplace_back("wasm32");
+
+ MockFS FS;
+ auto Inputs = TU.inputs(FS);
+ auto Result = codeComplete(testPath(TU.Filename), Test.point(),
+ Preamble.get(), Inputs, {});
+ auto Signatures =
+ signatureHelp(testPath(TU.Filename), Test.point(), *Preamble, Inputs, {});
+
+ // Make sure we don't crash.
+ EXPECT_THAT(Result.Completions, Not(testing::IsEmpty()));
+ EXPECT_THAT(Signatures.signatures, Not(testing::IsEmpty()));
+}
} // namespace
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp
index 35db757b9c15b5d3258552783cbbe5351c8d1a3c..5ead74748f550cb4536c7edf9cc246a4d41b5a42 100644
--- a/clang-tools-extra/clangd/unittests/HoverTests.cpp
+++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp
@@ -1983,10 +1983,14 @@ TEST(Hover, All) {
HI.Kind = index::SymbolKind::Macro;
HI.Definition =
R"cpp(#define MACRO \
- { return 0; }
+ { \
+ return 0; \
+ }
// Expands to
-{ return 0; })cpp";
+{
+ return 0;
+})cpp";
}},
{
R"cpp(// Forward class declaration
diff --git a/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp b/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp
index 500b72b9b327a04fad77afdf27697decdda408ba..4bb76cd6ab8304af8586316441c3cd06fd5bbc7d 100644
--- a/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ParsedASTTests.cpp
@@ -12,10 +12,7 @@
//===----------------------------------------------------------------------===//
#include "../../clang-tidy/ClangTidyCheck.h"
-#include "../../clang-tidy/ClangTidyModule.h"
-#include "../../clang-tidy/ClangTidyModuleRegistry.h"
#include "AST.h"
-#include "CompileCommands.h"
#include "Compiler.h"
#include "Config.h"
#include "Diagnostics.h"
@@ -32,7 +29,6 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/TokenKinds.h"
-#include "clang/Lex/PPCallbacks.h"
#include "clang/Tooling/Syntax/Tokens.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Testing/Annotations/Annotations.h"
@@ -41,6 +37,7 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include
+#include
#include
#include
@@ -347,9 +344,8 @@ TEST(ParsedASTTest, CollectsMainFileMacroExpansions) {
}
for (const auto &R : AST.getMacros().UnknownMacros)
MacroExpansionPositions.push_back(R.StartOffset);
- EXPECT_THAT(
- MacroExpansionPositions,
- testing::UnorderedElementsAreArray(TestCase.points()));
+ EXPECT_THAT(MacroExpansionPositions,
+ testing::UnorderedElementsAreArray(TestCase.points()));
}
MATCHER_P(withFileName, Inc, "") { return arg.FileName == Inc; }
@@ -768,6 +764,35 @@ main:
<< "Should not try to build AST for assembly source file";
}
+TEST(ParsedASTTest, PreambleWithDifferentTarget) {
+ constexpr std::string_view kPreambleTarget = "x86_64";
+ // Specifically picking __builtin_va_list as it triggers crashes when
+ // switching to wasm.
+ // It's due to different predefined types in different targets.
+ auto TU = TestTU::withHeaderCode("void foo(__builtin_va_list);");
+ TU.Code = "void bar() { foo(2); }";
+ TU.ExtraArgs.emplace_back("-target");
+ TU.ExtraArgs.emplace_back(kPreambleTarget);
+ const auto Preamble = TU.preamble();
+
+ // Switch target to wasm.
+ TU.ExtraArgs.pop_back();
+ TU.ExtraArgs.emplace_back("wasm32");
+
+ IgnoreDiagnostics Diags;
+ MockFS FS;
+ auto Inputs = TU.inputs(FS);
+ auto CI = buildCompilerInvocation(Inputs, Diags);
+ ASSERT_TRUE(CI) << "Failed to build compiler invocation";
+
+ auto AST = ParsedAST::build(testPath(TU.Filename), std::move(Inputs),
+ std::move(CI), {}, Preamble);
+
+ ASSERT_TRUE(AST);
+ // We use the target from preamble, not with the most-recent flags.
+ EXPECT_EQ(AST->getASTContext().getTargetInfo().getTriple().getArchName(),
+ llvm::StringRef(kPreambleTarget));
+}
} // namespace
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/unittests/TestIndex.cpp b/clang-tools-extra/clangd/unittests/TestIndex.cpp
index 278336bdde2ee5cd2f50a36eb8ffb892490f44c0..b13a5d32d175245b64a830189afc0d843d51ac68 100644
--- a/clang-tools-extra/clangd/unittests/TestIndex.cpp
+++ b/clang-tools-extra/clangd/unittests/TestIndex.cpp
@@ -38,7 +38,7 @@ static std::string replace(llvm::StringRef Haystack, llvm::StringRef Needle,
// Helpers to produce fake index symbols for memIndex() or completions().
// USRFormat is a regex replacement string for the unqualified part of the USR.
Symbol sym(llvm::StringRef QName, index::SymbolKind Kind,
- llvm::StringRef USRFormat) {
+ llvm::StringRef USRFormat, llvm::StringRef Signature) {
Symbol Sym;
std::string USR = "c:"; // We synthesize a few simple cases of USRs by hand!
size_t Pos = QName.rfind("::");
@@ -55,6 +55,7 @@ Symbol sym(llvm::StringRef QName, index::SymbolKind Kind,
Sym.SymInfo.Kind = Kind;
Sym.Flags |= Symbol::IndexedForCodeCompletion;
Sym.Origin = SymbolOrigin::Static;
+ Sym.Signature = Signature;
return Sym;
}
@@ -86,6 +87,10 @@ Symbol conceptSym(llvm::StringRef Name) {
return sym(Name, index::SymbolKind::Concept, "@CT@\\0");
}
+Symbol macro(llvm::StringRef Name, llvm::StringRef ArgList) {
+ return sym(Name, index::SymbolKind::Macro, "@macro@\\0", ArgList);
+}
+
Symbol objcSym(llvm::StringRef Name, index::SymbolKind Kind,
llvm::StringRef USRPrefix) {
Symbol Sym;
diff --git a/clang-tools-extra/clangd/unittests/TestIndex.h b/clang-tools-extra/clangd/unittests/TestIndex.h
index 9280b0b12a67fe7a9f57e4e2344f32d84febc953..0699b29392d720dfad46335e823b837724f36316 100644
--- a/clang-tools-extra/clangd/unittests/TestIndex.h
+++ b/clang-tools-extra/clangd/unittests/TestIndex.h
@@ -20,7 +20,7 @@ Symbol symbol(llvm::StringRef QName);
// Helpers to produce fake index symbols with proper SymbolID.
// USRFormat is a regex replacement string for the unqualified part of the USR.
Symbol sym(llvm::StringRef QName, index::SymbolKind Kind,
- llvm::StringRef USRFormat);
+ llvm::StringRef USRFormat, llvm::StringRef Signature = {});
// Creats a function symbol assuming no function arg.
Symbol func(llvm::StringRef Name);
// Creates a class symbol.
@@ -35,6 +35,8 @@ Symbol var(llvm::StringRef Name);
Symbol ns(llvm::StringRef Name);
// Create a C++20 concept symbol.
Symbol conceptSym(llvm::StringRef Name);
+// Create a macro symbol.
+Symbol macro(llvm::StringRef Name, llvm::StringRef ArgList = {});
// Create an Objective-C symbol.
Symbol objcSym(llvm::StringRef Name, index::SymbolKind Kind,
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 309b844615a1212c4983815ae6eabee086e68e3c..a457e6fcae946256ee907b33a206542f29f1c055 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -100,6 +100,8 @@ Improvements to clang-tidy
- Improved :program:`run-clang-tidy.py` script. Added argument `-source-filter`
to filter source files from the compilation database, via a RegEx. In a
similar fashion to what `-header-filter` does for header files.
+- Improved :program:`check_clang_tidy.py` script. Added argument `-export-fixes`
+ to aid in clang-tidy and test development.
New checks
^^^^^^^^^^
@@ -145,6 +147,10 @@ Changes in existing checks
` check by detecting side
effect from calling a method with non-const reference parameters.
+- Improved :doc:`bugprone-forwarding-reference-overload
+ `
+ check to ignore deleted constructors which won't hide other overloads.
+
- Improved :doc:`bugprone-inc-dec-in-conditions
` check to ignore code
within unevaluated contexts, such as ``decltype``.
@@ -179,8 +185,9 @@ Changes in existing checks
- Improved :doc:`cppcoreguidelines-missing-std-forward
` check by no longer
- giving false positives for deleted functions and fix false negative when some
- parameters are forwarded, but other aren't.
+ giving false positives for deleted functions, by fixing false negatives when only
+ a few parameters are forwarded and by ignoring parameters without a name (unused
+ arguments).
- Improved :doc:`cppcoreguidelines-owning-memory
` check to properly handle
@@ -210,10 +217,18 @@ Changes in existing checks
- Improved :doc:`google-runtime-int `
check performance through optimizations.
+- Improved :doc:`hicpp-ignored-remove-result `
+ check by ignoring other functions with same prefixes as the target specific
+ functions.
+
- Improved :doc:`llvm-header-guard
` check by replacing the local
option `HeaderFileExtensions` by the global option of the same name.
+- Improved :doc:`misc-const-correctness
+ ` check by avoiding infinite recursion
+ for recursive forwarding reference.
+
- Improved :doc:`misc-definitions-in-headers
` check by replacing the local
option `HeaderFileExtensions` by the global option of the same name.
@@ -251,10 +266,19 @@ Changes in existing checks
analyzed, se the check now handles the common patterns
`const auto e = (*vector_ptr)[i]` and `const auto e = vector_ptr->at(i);`.
+- Improved :doc:`readability-avoid-return-with-void-value
+ ` check by adding
+ fix-its.
+
+- Improved :doc:`readability-duplicate-include
+ ` check by excluding include
+ directives that form the filename using macro.
+
- Improved :doc:`readability-identifier-naming
` check in `GetConfigPerFile`
mode by resolving symbolic links to header files. Fixed handling of Hungarian
- Prefix when configured to `LowerCase`.
+ Prefix when configured to `LowerCase`. Added support for renaming designated
+ initializers. Added support for renaming macro arguments.
- Improved :doc:`readability-implicit-bool-conversion
` check to provide
@@ -283,6 +307,10 @@ Miscellaneous
``--format`` option is specified. Now :program:`clang-apply-replacements`
applies formatting only with the option.
+- Fixed the :doc:`linuxkernel-must-check-errs
+ ` documentation to consistently
+ use the check's proper name.
+
Improvements to include-fixer
-----------------------------
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/sizeof-expression.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sizeof-expression.rst
index a3e88b837d3758b94631769e6aa307c78ed1a38f..c37df1706eb4e19e0a310b91a259ea241403067f 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/sizeof-expression.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sizeof-expression.rst
@@ -190,6 +190,6 @@ Options
.. option:: WarnOnSizeOfPointerToAggregate
- When `true, the check will warn on an expression like
+ When `true`, the check will warn on an expression like
``sizeof(expr)`` where the expression is a pointer
to aggregate. Default is `true`.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/linuxkernel/must-use-errs.rst b/clang-tools-extra/docs/clang-tidy/checks/linuxkernel/must-check-errs.rst
similarity index 88%
rename from clang-tools-extra/docs/clang-tidy/checks/linuxkernel/must-use-errs.rst
rename to clang-tools-extra/docs/clang-tidy/checks/linuxkernel/must-check-errs.rst
index 8a85426880987ea9ce31c6f10738b01075d15532..cef5a70db309e1b4bca6498d34062d956b680e95 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/linuxkernel/must-use-errs.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/linuxkernel/must-check-errs.rst
@@ -1,7 +1,7 @@
-.. title:: clang-tidy - linuxkernel-must-use-errs
+.. title:: clang-tidy - linuxkernel-must-check-errs
-linuxkernel-must-use-errs
-=========================
+linuxkernel-must-check-errs
+===========================
Checks Linux kernel code to see if it uses the results from the functions in
``linux/err.h``. Also checks to see if code uses the results from functions that
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 188a42bfddd383619ed1e143543bf5a5201c7881..8bc46acad56c8416ba8fad3bf592be0fc021e20e 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -233,7 +233,7 @@ Clang-Tidy Checks
:doc:`hicpp-multiway-paths-covered `,
:doc:`hicpp-no-assembler `,
:doc:`hicpp-signed-bitwise `,
- :doc:`linuxkernel-must-use-errs `,
+ :doc:`linuxkernel-must-check-errs `,
:doc:`llvm-header-guard `,
:doc:`llvm-include-order `, "Yes"
:doc:`llvm-namespace-comment `,
diff --git a/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp b/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
index fd2de6a17ad4a53c009c9c5d1337cce4da9f0d52..7b28d1c252d715e1eb8501a25ead5f1abc41b2ef 100644
--- a/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
+++ b/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp
@@ -275,6 +275,12 @@ llvm::SmallVector headersForSymbol(const Symbol &S,
// are already ranked in the stdlib mapping.
if (H.kind() == Header::Standard)
continue;
+ // Don't apply name match hints to exporting headers. As they usually have
+ // names similar to the original header, e.g. foo_wrapper/foo.h vs
+ // foo/foo.h, but shouldn't be preferred (unless marked as the public
+ // interface).
+ if ((H.Hint & Hints::OriginHeader) == Hints::None)
+ continue;
if (nameMatch(SymbolName, H))
H.Hint |= Hints::PreferredHeader;
}
diff --git a/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp b/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
index 5a2a41b2d99bdd78b52b63fda3ce5db38394d404..07302142a13e363730f6a3713b9e8df806e2efdf 100644
--- a/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
+++ b/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp
@@ -628,5 +628,24 @@ TEST_F(HeadersForSymbolTest, StandardHeaders) {
tooling::stdlib::Header::named("")));
}
+TEST_F(HeadersForSymbolTest, ExporterNoNameMatch) {
+ Inputs.Code = R"cpp(
+ #include "exporter/foo.h"
+ #include "foo_public.h"
+ )cpp";
+ Inputs.ExtraArgs.emplace_back("-I.");
+ // Deliberately named as foo_public to make sure it doesn't get name-match
+ // boost and also gets lexicographically bigger order than "exporter/foo.h".
+ Inputs.ExtraFiles["foo_public.h"] = guard(R"cpp(
+ struct foo {};
+ )cpp");
+ Inputs.ExtraFiles["exporter/foo.h"] = guard(R"cpp(
+ #include "foo_public.h" // IWYU pragma: export
+ )cpp");
+ buildAST();
+ EXPECT_THAT(headersForFoo(), ElementsAre(physicalHeader("foo_public.h"),
+ physicalHeader("exporter/foo.h")));
+}
+
} // namespace
} // namespace clang::include_cleaner
diff --git a/clang-tools-extra/test/clang-tidy/check_clang_tidy.py b/clang-tools-extra/test/clang-tidy/check_clang_tidy.py
index 53ffca0bad8d06fd92d0e9c5663ecc8acc464208..6d4b466afa691a74b59185e360f0b9a8b6597261 100755
--- a/clang-tools-extra/test/clang-tidy/check_clang_tidy.py
+++ b/clang-tools-extra/test/clang-tidy/check_clang_tidy.py
@@ -8,25 +8,35 @@
#
# ===------------------------------------------------------------------------===#
-r"""
+"""
ClangTidy Test Helper
=====================
-This script runs clang-tidy in fix mode and verify fixes, messages or both.
+This script is used to simplify writing, running, and debugging tests compatible
+with llvm-lit. By default it runs clang-tidy in fix mode and uses FileCheck to
+verify messages and/or fixes.
+
+For debugging, with --export-fixes, the tool simply exports fixes to a provided
+file and does not run FileCheck.
-Usage:
- check_clang_tidy.py [-resource-dir=] \
- [-assume-filename=] \
- [-check-suffix=] \
- [-check-suffixes=] \
- [-std=c++(98|11|14|17|20)[-or-later]] \
- \
- -- [optional clang-tidy arguments]
+Extra arguments, those after the first -- if any, are passed to either
+clang-tidy or clang:
+* Arguments between the first -- and second -- are clang-tidy arguments.
+ * May be only whitespace if there are no clang-tidy arguments.
+ * clang-tidy's --config would go here.
+* Arguments after the second -- are clang arguments
+
+Examples
+--------
-Example:
// RUN: %check_clang_tidy %s llvm-include-order %t -- -- -isystem %S/Inputs
-Notes:
+or
+
+ // RUN: %check_clang_tidy %s llvm-include-order --export-fixes=fixes.yaml %t -std=c++20
+
+Notes
+-----
-std=c++(98|11|14|17|20)-or-later:
This flag will cause multiple runs within the same check_clang_tidy
execution. Make sure you don't have shared state across these runs.
@@ -34,6 +44,7 @@ Notes:
import argparse
import os
+import pathlib
import re
import subprocess
import sys
@@ -88,6 +99,7 @@ class CheckRunner:
self.has_check_fixes = False
self.has_check_messages = False
self.has_check_notes = False
+ self.export_fixes = args.export_fixes
self.fixes = MessagePrefix("CHECK-FIXES")
self.messages = MessagePrefix("CHECK-MESSAGES")
self.notes = MessagePrefix("CHECK-NOTES")
@@ -181,7 +193,13 @@ class CheckRunner:
[
"clang-tidy",
self.temp_file_name,
- "-fix",
+ ]
+ + [
+ "-fix"
+ if self.export_fixes is None
+ else "--export-fixes=" + self.export_fixes
+ ]
+ + [
"--checks=-*," + self.check_name,
]
+ self.clang_tidy_extra_args
@@ -255,12 +273,14 @@ class CheckRunner:
def run(self):
self.read_input()
- self.get_prefixes()
+ if self.export_fixes is None:
+ self.get_prefixes()
self.prepare_test_inputs()
clang_tidy_output = self.run_clang_tidy()
- self.check_fixes()
- self.check_messages(clang_tidy_output)
- self.check_notes(clang_tidy_output)
+ if self.export_fixes is None:
+ self.check_fixes()
+ self.check_messages(clang_tidy_output)
+ self.check_notes(clang_tidy_output)
def expand_std(std):
@@ -284,7 +304,11 @@ def csv(string):
def parse_arguments():
- parser = argparse.ArgumentParser()
+ parser = argparse.ArgumentParser(
+ prog=pathlib.Path(__file__).stem,
+ description=__doc__,
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+ )
parser.add_argument("-expect-clang-tidy-error", action="store_true")
parser.add_argument("-resource-dir")
parser.add_argument("-assume-filename")
@@ -298,7 +322,19 @@ def parse_arguments():
type=csv,
help="comma-separated list of FileCheck suffixes",
)
- parser.add_argument("-std", type=csv, default=["c++11-or-later"])
+ parser.add_argument(
+ "-export-fixes",
+ default=None,
+ type=str,
+ metavar="file",
+ help="A file to export fixes into instead of fixing.",
+ )
+ parser.add_argument(
+ "-std",
+ type=csv,
+ default=["c++11-or-later"],
+ help="Passed to clang. Special -or-later values are expanded.",
+ )
return parser.parse_known_args()
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/forwarding-reference-overload.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/forwarding-reference-overload.cpp
index 38b0691bc9f1ecb8de9ddcc1f5fd1654d44739e1..92dfb718bb51b7bda177f254233b28856755e198 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/forwarding-reference-overload.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/forwarding-reference-overload.cpp
@@ -251,3 +251,13 @@ public:
Test10(T &&Item, E e)
: e(e){}
};
+
+// A deleted ctor cannot hide anything
+class Test11 {
+public:
+ template
+ Test11(T&&) = delete;
+
+ Test11(const Test11 &) = default;
+ Test11(Test11 &&) = default;
+};
diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp
index 9a50eabf619bd57a8f18091b48796e2ef7a479f1..8116db58c937d44524b6f6e3b7dd26273bc2a288 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp
@@ -198,3 +198,16 @@ struct S {
};
} // namespace deleted_functions
+
+namespace unused_arguments {
+
+template
+void unused_argument1(F&&) {}
+
+template
+void unused_argument2([[maybe_unused]] F&& f) {}
+
+template
+void unused_argument3(F&& _) {}
+
+} // namespace unused_arguments
diff --git a/clang-tools-extra/test/clang-tidy/checkers/hicpp/ignored-remove-result.cpp b/clang-tools-extra/test/clang-tidy/checkers/hicpp/ignored-remove-result.cpp
index b068f08590989394dc5702f310515d9c4b7f8793..fc431024303ab2d39f1b2d50fbba01503b3b1ead 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/hicpp/ignored-remove-result.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/hicpp/ignored-remove-result.cpp
@@ -15,6 +15,10 @@ ForwardIt unique(ForwardIt, ForwardIt);
template
InputIt find(InputIt, InputIt, const T&);
+struct unique_disposable {
+ void* release();
+};
+
class error_code {
};
@@ -63,4 +67,6 @@ void noWarning() {
// bugprone-unused-return-value's checked return types.
errorFunc();
(void) errorFunc();
+
+ std::unique_disposable{}.release();
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
index 9da468128743e909b7dfb10976c5598a15bf45be..248374a71dd40ba9bcba9d6f00825ef21cbbb34b 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
@@ -58,3 +58,18 @@ void concatenate3(Args... args)
(..., (stream << args));
}
} // namespace gh70323
+
+namespace gh60895 {
+
+template void f1(T &&a);
+template void f2(T &&a);
+template void f1(T &&a) { f2(a); }
+template void f2(T &&a) { f1(a); }
+void f() {
+ int x = 0;
+ // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'x' of type 'int' can be declared 'const'
+ // CHECK-FIXES: int const x = 0;
+ f1(x);
+}
+
+} // namespace gh60895
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp
index f00407c99ce57021a4be3fcad13feaa9bbd24140..7c948dba3e8f7c0d4991270f3647761ec3de3dbb 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp
@@ -12,23 +12,30 @@ void f2() {
return f1();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: f1();
}
void f3(bool b) {
if (b) return f1();
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: if (b) { f1(); return;
+ // CHECK-NEXT: }
return f2();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: f2();
+ // CHECK-FIXES-LENIENT: f2();
}
template
T f4() {}
void f5() {
- return f4();
- // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
- // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ { return f4(); }
+ // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:7: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: { f4(); return; }
+ // CHECK-FIXES-LENIENT: { f4(); return; }
}
void f6() { return; }
@@ -41,6 +48,8 @@ void f9() {
return (void)f7();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: (void)f7();
+ // CHECK-FIXES-LENIENT: (void)f7();
}
#define RETURN_VOID return (void)1
@@ -50,12 +59,12 @@ void f10() {
// CHECK-MESSAGES-INCLUDE-MACROS: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
}
-template
+template
struct C {
C(A) {}
};
-template
+template
C f11() { return {}; }
using VOID = void;
@@ -66,4 +75,36 @@ VOID f13() {
return f12();
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
// CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: f12(); return;
+ // CHECK-FIXES-LENIENT: f12(); return;
+ (void)1;
+}
+
+void f14() {
+ return /* comment */ f1() /* comment */ ;
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: /* comment */ f1() /* comment */ ; return;
+ // CHECK-FIXES-LENIENT: /* comment */ f1() /* comment */ ; return;
+ (void)1;
+}
+
+void f15() {
+ return/*comment*/f1()/*comment*/;//comment
+ // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: /*comment*/f1()/*comment*/; return;//comment
+ // CHECK-FIXES-LENIENT: /*comment*/f1()/*comment*/; return;//comment
+ (void)1;
+}
+
+void f16(bool b) {
+ if (b) return f1();
+ // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: if (b) { f1(); return;
+ // CHECK-NEXT: }
+ else return f2();
+ // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value]
+ // CHECK-FIXES: else { f2(); return;
+ // CHECK-NEXT: }
}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp
index dd954c705514fb777bb5e0570623f076fb5a7070..2119602ba454b49d111524fd42730f41e76b8ede 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp
@@ -70,3 +70,18 @@ int r;
// CHECK-FIXES: {{^int q;$}}
// CHECK-FIXES-NEXT: {{^#include $}}
// CHECK-FIXES-NEXT: {{^int r;$}}
+
+namespace Issue_87303 {
+#define RESET_INCLUDE_CACHE
+// Expect no warnings
+
+#define MACRO_FILENAME "duplicate-include.h"
+#include MACRO_FILENAME
+#include "duplicate-include.h"
+
+#define MACRO_FILENAME_2
+#include
+#include MACRO_FILENAME_2
+
+#undef RESET_INCLUDE_CACHE
+} // Issue_87303
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp
index d2e89a7c9855c9a8b9407406cbc7227b9c24ef44..99149fe86aceecf662ead7f674103230bb263630 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp
@@ -108,10 +108,12 @@ USER_NS::object g_s2;
// NO warnings or fixes expected as USER_NS and object are declared in a header file
SYSTEM_MACRO(var1);
-// NO warnings or fixes expected as var1 is from macro expansion
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: invalid case style for global variable 'var1' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}SYSTEM_MACRO(g_var1);
USER_MACRO(var2);
-// NO warnings or fixes expected as var2 is declared in a macro expansion
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: invalid case style for global variable 'var2' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}USER_MACRO(g_var2);
#define BLA int FOO_bar
BLA;
@@ -602,9 +604,20 @@ static void static_Function() {
// CHECK-FIXES: {{^}}#define MY_TEST_MACRO(X) X()
void MY_TEST_Macro(function) {}
-// CHECK-FIXES: {{^}}void MY_TEST_MACRO(function) {}
-}
-}
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: invalid case style for global function 'function' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}void MY_TEST_MACRO(Function) {}
+
+#define MY_CAT_IMPL(l, r) l ## r
+#define MY_CAT(l, r) MY_CAT_IMPL(l, r)
+#define MY_MACRO2(foo) int MY_CAT(awesome_, MY_CAT(foo, __COUNTER__)) = 0
+#define MY_MACRO3(foo) int MY_CAT(awesome_, foo) = 0
+MY_MACRO2(myglob);
+MY_MACRO3(myglob);
+// No suggestions should occur even though the resulting decl of awesome_myglob#
+// or awesome_myglob are not entirely within a macro argument.
+
+} // namespace InlineNamespace
+} // namespace FOO_NS
template struct a {
// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: invalid case style for struct 'a'
@@ -766,3 +779,13 @@ STATIC_MACRO void someFunc(MyFunPtr, const MyFunPtr****) {}
// CHECK-FIXES: {{^}}STATIC_MACRO void someFunc(my_fun_ptr_t, const my_fun_ptr_t****) {}
#undef STATIC_MACRO
}
+
+struct Some_struct {
+ int SomeMember;
+// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for public member 'SomeMember' [readability-identifier-naming]
+// CHECK-FIXES: {{^}} int some_member;
+};
+Some_struct g_s1{ .SomeMember = 1 };
+// CHECK-FIXES: {{^}}Some_struct g_s1{ .some_member = 1 };
+Some_struct g_s2{.SomeMember=1};
+// CHECK-FIXES: {{^}}Some_struct g_s2{.some_member=1};
diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt
index 284b2af24ddaa0405398e8ea1826856e93401ba6..f092766fa19f07f754960ec9524078d6b65070d4 100644
--- a/clang/CMakeLists.txt
+++ b/clang/CMakeLists.txt
@@ -165,6 +165,13 @@ if(CLANG_ENABLE_LIBXML2)
endif()
endif()
+if(CLANG_ENABLE_CIR)
+ if (NOT "${LLVM_ENABLE_PROJECTS}" MATCHES "MLIR|mlir")
+ message(FATAL_ERROR
+ "Cannot build ClangIR without MLIR in LLVM_ENABLE_PROJECTS")
+ endif()
+endif()
+
include(CheckIncludeFile)
check_include_file(sys/resource.h CLANG_HAVE_RLIMITS)
diff --git a/clang/cmake/caches/Apple-stage2.cmake b/clang/cmake/caches/Apple-stage2.cmake
index 72cdedd611bc9600c0aecbef59060bee7d22b6be..ede256a2da6b8fd6864bd8584aeddf5126dd5bb9 100644
--- a/clang/cmake/caches/Apple-stage2.cmake
+++ b/clang/cmake/caches/Apple-stage2.cmake
@@ -15,6 +15,7 @@ set(LLVM_ENABLE_ZLIB ON CACHE BOOL "")
set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
set(LLVM_ENABLE_MODULES ON CACHE BOOL "")
set(LLVM_EXTERNALIZE_DEBUGINFO ON CACHE BOOL "")
+set(LLVM_ENABLE_EXPORTED_SYMBOLS_IN_EXECUTABLES OFF CACHE BOOL "")
set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "")
set(CLANG_SPAWN_CC1 ON CACHE BOOL "")
set(BUG_REPORT_URL "http://developer.apple.com/bugreporter/" CACHE STRING "")
diff --git a/clang/cmake/caches/Fuchsia.cmake b/clang/cmake/caches/Fuchsia.cmake
index df69d7d0dd414beb8be6752acae171cf6fd5272e..30a3b9116a461f3f65d2bfdfab0f5aaecccc2e6c 100644
--- a/clang/cmake/caches/Fuchsia.cmake
+++ b/clang/cmake/caches/Fuchsia.cmake
@@ -65,12 +65,13 @@ set(_FUCHSIA_BOOTSTRAP_PASSTHROUGH
LLDB_EMBED_PYTHON_HOME
LLDB_PYTHON_HOME
LLDB_PYTHON_RELATIVE_PATH
- LLDB_TEST_USE_VENDOR_PACKAGES
LLDB_TEST_USER_ARGS
Python3_EXECUTABLE
Python3_LIBRARIES
Python3_INCLUDE_DIRS
Python3_RPATH
+ SWIG_DIR
+ SWIG_EXECUTABLE
CMAKE_FIND_PACKAGE_PREFER_CONFIG
CMAKE_SYSROOT
CMAKE_MODULE_LINKER_FLAGS
diff --git a/clang/cmake/caches/Release.cmake b/clang/cmake/caches/Release.cmake
index 1ca9138b98073118184385ba6eb6a8a0690132ad..bd1f688d61a7ea2aaa475aaec7d6a0970c12139f 100644
--- a/clang/cmake/caches/Release.cmake
+++ b/clang/cmake/caches/Release.cmake
@@ -4,7 +4,7 @@
# General Options
set(LLVM_RELEASE_ENABLE_LTO THIN CACHE STRING "")
-set(LLVM_RELEASE_ENABLE_PGO ON CACHE BOOL "")
+set(LLVM_RELEASE_ENABLE_PGO OFF CACHE BOOL "")
set(CMAKE_BUILD_TYPE RELEASE CACHE STRING "")
diff --git a/clang/docs/ClangFormat.rst b/clang/docs/ClangFormat.rst
index 80dc38a075c8fcf572ce093da3893007e23342b4..dbd9c91ae508e5d8175c5e1734e4fcdb34c80090 100644
--- a/clang/docs/ClangFormat.rst
+++ b/clang/docs/ClangFormat.rst
@@ -54,7 +54,7 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code.
Objective-C: .m .mm
Proto: .proto .protodevel
TableGen: .td
- TextProto: .textpb .pb.txt .textproto .asciipb
+ TextProto: .txtpb .textpb .pb.txt .textproto .asciipb
Verilog: .sv .svh .v .vh
--cursor= - The position of the cursor when invoking
clang-format from an editor integration
diff --git a/clang/docs/HIPSupport.rst b/clang/docs/HIPSupport.rst
index 543c82cf90244945a7cf08b89009a6a37e5c34bf..5ba84c2f670556491b51f3d716be759d8f653fec 100644
--- a/clang/docs/HIPSupport.rst
+++ b/clang/docs/HIPSupport.rst
@@ -208,6 +208,20 @@ Host Code Compilation
- These relocatable objects are then linked together.
- Host code within a TU can call host functions and launch kernels from another TU.
+Syntax Difference with CUDA
+===========================
+
+Clang's front end, used for both CUDA and HIP programming models, shares the same parsing and semantic analysis mechanisms. This includes the resolution of overloads concerning device and host functions. While there exists a comprehensive documentation on the syntax differences between Clang and NVCC for CUDA at `Dialect Differences Between Clang and NVCC `_, it is important to note that these differences also apply to HIP code compilation.
+
+Predefined Macros for Differentiation
+-------------------------------------
+
+To facilitate differentiation between HIP and CUDA code, as well as between device and host compilations within HIP, Clang defines specific macros:
+
+- ``__HIP__`` : This macro is defined only when compiling HIP code. It can be used to conditionally compile code specific to HIP, enabling developers to write portable code that can be compiled for both CUDA and HIP.
+
+- ``__HIP_DEVICE_COMPILE__`` : Defined exclusively during HIP device compilation, this macro allows for conditional compilation of device-specific code. It provides a mechanism to segregate device and host code, ensuring that each can be optimized for their respective execution environments.
+
Function Pointers Support
=========================
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 7b23e4d1c2f30c1544b2eba17b2a53849a6bc6a9..3bead159c8f9467dd876174beff98787eb6a890b 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1493,6 +1493,7 @@ Conditional ``explicit`` __cpp_conditional_explicit C+
``if consteval`` __cpp_if_consteval C++23 C++20
``static operator()`` __cpp_static_call_operator C++23 C++03
Attributes on Lambda-Expressions C++23 C++11
+``= delete ("should have a reason");`` __cpp_deleted_function C++26 C++03
-------------------------------------------- -------------------------------- ------------- -------------
Designated initializers (N494) C99 C89
Array & element qualification (N2607) C23 C89
@@ -1610,6 +1611,7 @@ The following type trait primitives are supported by Clang. Those traits marked
* ``__is_pod`` (C++, GNU, Microsoft, Embarcadero):
Note, the corresponding standard trait was deprecated in C++20.
* ``__is_pointer`` (C++, Embarcadero)
+* ``__is_pointer_interconvertible_base_of`` (C++, GNU, Microsoft)
* ``__is_polymorphic`` (C++, GNU, Microsoft, Embarcadero)
* ``__is_reference`` (C++, Embarcadero)
* ``__is_referenceable`` (C++, GNU, Microsoft, Embarcadero):
@@ -3464,6 +3466,54 @@ Query for this feature with ``__has_builtin(__builtin_trap)``.
``__builtin_arm_trap`` is lowered to the ``llvm.aarch64.break`` builtin, and then to ``brk #payload``.
+``__builtin_allow_runtime_check``
+---------------------------------
+
+``__builtin_allow_runtime_check`` return true if the check at the current
+program location should be executed. It is expected to be used to implement
+``assert`` like checks which can be safely removed by optimizer.
+
+**Syntax**:
+
+.. code-block:: c++
+
+ bool __builtin_allow_runtime_check(const char* kind)
+
+**Example of use**:
+
+.. code-block:: c++
+
+ if (__builtin_allow_runtime_check("mycheck") && !ExpensiveCheck()) {
+ abort();
+ }
+
+**Description**
+
+``__builtin_allow_runtime_check`` is lowered to ` ``llvm.allow.runtime.check``
+`_
+builtin.
+
+The ``__builtin_allow_runtime_check()`` is expected to be used with control
+flow conditions such as in ``if`` to guard expensive runtime checks. The
+specific rules for selecting permitted checks can differ and are controlled by
+the compiler options.
+
+Flags to control checks:
+* ``-mllvm -lower-allow-check-percentile-cutoff-hot=N`` where N is PGO hotness
+cutoff in range ``[0, 999999]`` to disallow checks in hot code.
+* ``-mllvm -lower-allow-check-random-rate=P`` where P is number in range
+``[0.0, 1.0]`` representation probability of keeping a check.
+* If both flags are specified, ``-lower-allow-check-random-rate`` takes
+precedence.
+* If none is specified, ``__builtin_allow_runtime_check`` is lowered as
+``true``, allowing all checks.
+
+Parameter ``kind`` is a string literal representing a user selected kind for
+guarded check. It's unused now. It will enable kind-specific lowering in future.
+E.g. a higher hotness cutoff can be used for more expensive kind of check.
+
+Query for this feature with ``__has_builtin(__builtin_allow_runtime_check)``.
+
``__builtin_nondeterministic_value``
------------------------------------
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d5ce54e185600cab7885936d6442910aabbcc576..205c6e573d567cef26cc570c25a96452be30881e 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -68,7 +68,7 @@ AST Dumping Potentially Breaking Changes
Clang Frontend Potentially Breaking Changes
-------------------------------------------
-- Removed support for constructing on-stack ``TemplateArgumentList``s; interfaces should instead
+- Removed support for constructing on-stack ``TemplateArgumentList``\ s; interfaces should instead
use ``ArrayRef`` to pass template arguments. Transitioning internal uses to
``ArrayRef`` reduces AST memory usage by 0.4% when compiling clang, and is
expected to show similar improvements on other workloads.
@@ -98,18 +98,22 @@ C++20 Feature Support
behavior can use the flag '-Xclang -fno-skip-odr-check-in-gmf'.
(#GH79240).
-- Implemented the `__is_layout_compatible` intrinsic to support
+- Implemented the `__is_layout_compatible` and `__is_pointer_interconvertible_base_of`
+ intrinsics to support
`P0466R5: Layout-compatibility and Pointer-interconvertibility Traits `_.
- Clang now implements [module.import]p7 fully. Clang now will import module
units transitively for the module units coming from the same module of the
- current module units.
- Fixes `#84002 `_.
+ current module units. Fixes #GH84002
- Initial support for class template argument deduction (CTAD) for type alias
templates (`P1814R0 `_).
(#GH54051).
+- We have sufficient confidence and experience with the concepts implementation
+ to update the ``__cpp_concepts`` macro to `202002L`. This enables
+ ```` from libstdc++ to work correctly with Clang.
+
C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^
@@ -124,12 +128,13 @@ C++2c Feature Support
- Implemented `P2662R3 Pack Indexing `_.
+- Implemented `P2573R2: = delete("should have a reason"); `_
+
Resolutions to C++ Defect Reports
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Substitute template parameter pack, when it is not explicitly specified
- in the template parameters, but is deduced from a previous argument.
- (`#78449: `_).
+ in the template parameters, but is deduced from a previous argument. (#GH78449)
- Type qualifications are now ignored when evaluating layout compatibility
of two types.
@@ -143,6 +148,9 @@ Resolutions to C++ Defect Reports
compatibility of two types.
(`CWG2759: [[no_unique_address] and common initial sequence `_).
+- Clang now diagnoses declarative nested-name-specifiers with pack-index-specifiers.
+ (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers `_).
+
C Language Changes
------------------
@@ -166,8 +174,7 @@ C23 Feature Support
- Clang now generates predefined macros of the form ``__TYPE_FMTB__`` and
``__TYPE_FMTb__`` (e.g., ``__UINT_FAST64_FMTB__``) in C23 mode for use with
- macros typically exposed from ````, such as ``PRIb8``.
- (`#81896: `_).
+ macros typically exposed from ````, such as ``PRIb8``. (#GH81896)
- Clang now supports `N3018 The constexpr specifier for object definitions`
`_.
@@ -193,12 +200,22 @@ Non-comprehensive list of changes in this release
with support for any unsigned integer type. Like the previous builtins, these
new builtins are constexpr and may be used in constant expressions.
+- ``__typeof_unqual__`` is available in all C modes as an extension, which behaves
+ like ``typeof_unqual`` from C23, similar to ``__typeof__`` and ``typeof``.
+
New Compiler Flags
------------------
+- ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and
+ sign change.
+- ``-fsanitize=implicit-integer-conversion`` a group that replaces the previous
+ group ``-fsanitize=implicit-conversion``.
- ``-Wmissing-designated-field-initializers``, grouped under ``-Wmissing-field-initializers``.
This diagnostic can be disabled to make ``-Wmissing-field-initializers`` behave
- like it did before Clang 18.x. Fixes (`#56628 `_)
+ like it did before Clang 18.x. Fixes #GH56628
+
+- ``-fexperimental-modules-reduced-bmi`` enables the Reduced BMI for C++20 named modules.
+ See the document of standard C++ modules for details.
Deprecated Compiler Flags
-------------------------
@@ -208,6 +225,9 @@ Modified Compiler Flags
- Added a new diagnostic flag ``-Wreturn-mismatch`` which is grouped under
``-Wreturn-type``, and moved some of the diagnostics previously controlled by
``-Wreturn-type`` under this new flag. Fixes #GH72116.
+- ``-fsanitize=implicit-conversion`` is now a group for both
+ ``-fsanitize=implicit-integer-conversion`` and
+ ``-fsanitize=implicit-bitfield-conversion``.
- Added ``-Wcast-function-type-mismatch`` under the ``-Wcast-function-type``
warning group. Moved the diagnostic previously controlled by
@@ -234,8 +254,7 @@ Removed Compiler Flags
- The ``-freroll-loops`` flag has been removed. It had no effect since Clang 13.
- ``-m[no-]unaligned-access`` is removed for RISC-V and LoongArch.
- ``-m[no-]strict-align``, also supported by GCC, should be used instead.
- (`#85350 `_.)
+ ``-m[no-]strict-align``, also supported by GCC, should be used instead. (#GH85350)
Attribute Changes in Clang
--------------------------
@@ -268,6 +287,9 @@ Attribute Changes in Clang
This allows the ``_Nullable`` and ``_Nonnull`` family of type attributes to
apply to this class.
+- Clang now warns that the ``exclude_from_explicit_instantiation`` attribute
+ is ignored when applied to a local class or a member thereof.
+
Improvements to Clang's diagnostics
-----------------------------------
- Clang now applies syntax highlighting to the code snippets it
@@ -305,8 +327,7 @@ Improvements to Clang's diagnostics
Fixes #GH82512.
- Clang now provides improved warnings for the ``cleanup`` attribute to detect misuse scenarios,
- such as attempting to call ``free`` on an unallocated object. Fixes
- `#79443 `_.
+ such as attempting to call ``free`` on an unallocated object. Fixes #GH79443.
- Clang no longer warns when the ``bitand`` operator is used with boolean
operands, distinguishing it from potential typographical errors or unintended
@@ -328,13 +349,36 @@ Improvements to Clang's diagnostics
- New ``-Wformat-signedness`` diagnostic that warn if the format string requires an
unsigned argument and the argument is signed and vice versa.
+- Clang now emits ``unused argument`` warning when the -fmodule-output flag is used
+ with an input that is not of type c++-module.
+
+- Clang emits a ``-Wreturn-stack-address`` warning if a function returns a pointer or
+ reference to a struct literal. Fixes #GH8678
+
+- Clang emits a ``-Wunused-but-set-variable`` warning on C++ variables whose declaration
+ (with initializer) entirely consist the condition expression of a if/while/for construct
+ but are not actually used in the body of the if/while/for construct. Fixes #GH41447
+
+- Clang emits a diagnostic when a tentative array definition is assumed to have
+ a single element, but that diagnostic was never given a diagnostic group.
+ Added the ``-Wtentative-definition-array`` warning group to cover this.
+ Fixes #GH87766
+
+- Clang now uses the correct type-parameter-key (``class`` or ``typename``) when printing
+ template template parameter declarations.
+
+- Clang now diagnoses requires expressions with explicit object parameters.
+
Improvements to Clang's time-trace
----------------------------------
Bug Fixes in This Version
-------------------------
+- Clang's ``-Wundefined-func-template`` no longer warns on pure virtual
+ functions. (#GH74016)
+
- Fixed missing warnings when comparing mismatched enumeration constants
- in C (`#29217 `).
+ in C (#GH29217)
- Clang now accepts elaborated-type-specifiers that explicitly specialize
a member class template for an implicit instantiation of a class template.
@@ -373,7 +417,7 @@ Bug Fixes in This Version
type only rather than to the complex type (e.g. ``_Complex float / int`` is now evaluated
as ``_Complex float / float`` rather than ``_Complex float / _Complex float``), as mandated
by the C standard. This significantly improves codegen of `*` and `/` especially.
- Fixes (`#31205 `_).
+ Fixes #GH31205.
- Fixes an assertion failure on invalid code when trying to define member
functions in lambdas.
@@ -381,6 +425,12 @@ Bug Fixes in This Version
- Fixed a regression in CTAD that a friend declaration that befriends itself may cause
incorrect constraint substitution. (#GH86769).
+- Fixed an assertion failure on invalid InitListExpr in C89 mode (#GH88008).
+
+- Clang will no longer diagnose an erroneous non-dependent ``switch`` condition
+ during instantiation, and instead will only diagnose it once, during checking
+ of the function template.
+
Bug Fixes to Compiler Builtins
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -422,8 +472,7 @@ Bug Fixes to C++ Support
- Fix a crash when trying to call a varargs function that also has an explicit object parameter. (#GH80971)
- Fixed a bug where abbreviated function templates would append their invented template parameters to
an empty template parameter lists.
-- Fix parsing of abominable function types inside type traits.
- Fixes (`#77585 `_)
+- Fix parsing of abominable function types inside type traits. Fixes #GH77585
- Clang now classifies aggregate initialization in C++17 and newer as constant
or non-constant more accurately. Previously, only a subset of the initializer
elements were considered, misclassifying some initializers as constant. Partially fixes
@@ -464,9 +513,9 @@ Bug Fixes to C++ Support
- Fix a bug where overload resolution falsely reported an ambiguity when it was comparing
a member-function against a non member function or a member-function with an
explicit object parameter against a member function with no explicit object parameter
- when one of the function had more specialized templates.
- Fixes (`#82509 `_)
- and (`#74494 `_)
+ when one of the function had more specialized templates. Fixes #GH82509 and #GH74494
+- Clang now supports direct lambda calls inside of a type alias template declarations.
+ This addresses (#GH70601), (#GH76674), (#GH79555), (#GH81145) and (#GH82104).
- Allow access to a public template alias declaration that refers to friend's
private nested type. (#GH25708).
- Fixed a crash in constant evaluation when trying to access a
@@ -486,12 +535,21 @@ Bug Fixes to C++ Support
- Fixed a bug that prevented member function templates of class templates declared with a deduced return type
from being explicitly specialized for a given implicit instantiation of the class template.
-- Fix crash when inheriting from a cv-qualified type. Fixes:
- (`#35603 `_)
+- Fix crash when inheriting from a cv-qualified type. Fixes #GH35603
+- Fix a crash when the using enum declaration uses an anonymous enumeration. Fixes (#GH86790).
+- Handled an edge case in ``getFullyPackExpandedSize`` so that we now avoid a false-positive diagnostic. (#GH84220)
+- Clang now correctly tracks type dependence of by-value captures in lambdas with an explicit
+ object parameter.
+ Fixes (#GH70604), (#GH79754), (#GH84163), (#GH84425), (#GH86054), (#GH86398), and (#GH86399).
+- Fix a crash when deducing ``auto`` from an invalid dereference (#GH88329).
+- Fix a crash in requires expression with templated base class member function. Fixes (#GH84020).
+- Fix a crash caused by defined struct in a type alias template when the structure
+ has fields with dependent type. Fixes (#GH75221).
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
- Clang now properly preserves ``FoundDecls`` within a ``ConceptReference``. (#GH82628)
+- The presence of the ``typename`` keyword is now stored in ``TemplateTemplateParmDecl``.
Miscellaneous Bug Fixes
^^^^^^^^^^^^^^^^^^^^^^^
@@ -500,8 +558,7 @@ Miscellaneous Clang Crashes Fixed
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- Do not attempt to dump the layout of dependent types or invalid declarations
- when ``-fdump-record-layouts-complete`` is passed.
- Fixes (`#83684 `_).
+ when ``-fdump-record-layouts-complete`` is passed. Fixes #GH83684.
OpenACC Specific Changes
------------------------
@@ -551,8 +608,7 @@ Windows Support
would only be included if AVX was enabled at compile time. This was done to work
around include times from MSVC STL including ``intrin.h`` under clang-cl.
Clang-cl now provides ``intrin0.h`` for MSVC STL and therefore all intrinsic
- features without requiring enablement at compile time.
- Fixes: (`#53520 `_)
+ features without requiring enablement at compile time. Fixes #GH53520
- Improved compile times with MSVC STL. MSVC provides ``intrin0.h`` which is a
header that only includes intrinsics that are used by MSVC STL to avoid the
@@ -606,10 +662,14 @@ Fixed Point Support in Clang
AST Matchers
------------
+- Fixes a long-standing performance issue in parent map generation for
+ ancestry-based matchers such as ``hasParent`` and ``hasAncestor``, making
+ them significantly faster.
- ``isInStdNamespace`` now supports Decl declared with ``extern "C++"``.
- Add ``isExplicitObjectMemberFunction``.
- Fixed ``forEachArgumentWithParam`` and ``forEachArgumentWithParamType`` to
not skip the explicit object parameter for operator calls.
+- Fixed captureVars assertion failure if not capturesVariables. (#GH76425)
clang-format
------------
@@ -629,6 +689,8 @@ Static Analyzer
but not under any case blocks if ``unroll-loops=true`` analyzer config is
set. (#GH68819)
- Support C++23 static operator calls. (#GH84972)
+- Fixed a crash in ``security.cert.env.InvalidPtr`` checker when accidentally
+ matched user-defined ``strerror`` and similar library functions. (GH#88181)
New features
^^^^^^^^^^^^
diff --git a/clang/docs/StandardCPlusPlusModules.rst b/clang/docs/StandardCPlusPlusModules.rst
index c5478bba45f389c44af7949453af5ed8b0de1ba7..ee57fb5da6485769213f8485ac0e7a7f9fbd774d 100644
--- a/clang/docs/StandardCPlusPlusModules.rst
+++ b/clang/docs/StandardCPlusPlusModules.rst
@@ -483,6 +483,13 @@ violations with the flag enabled.
ABI Impacts
-----------
+This section describes the new ABI changes brought by modules.
+
+Only Itanium C++ ABI related change are mentioned
+
+Mangling Names
+~~~~~~~~~~~~~~
+
The declarations in a module unit which are not in the global module fragment have new linkage names.
For example,
@@ -520,6 +527,129 @@ is attached to the global module fragments. For example:
Now the linkage name of ``NS::foo()`` will be ``_ZN2NS3fooEv``.
+Module Initializers
+~~~~~~~~~~~~~~~~~~~
+
+All the importable module units are required to emit an initializer function.
+The initializer function should contain calls to importing modules first and
+all the dynamic-initializers in the current module unit then.
+
+Translation units explicitly or implicitly importing named modules must call
+the initializer functions of the imported named modules within the sequence of
+the dynamic-initializers in the TU. Initializations of entities at namespace
+scope are appearance-ordered. This (recursively) extends into imported modules
+at the point of appearance of the import declaration.
+
+It is allowed to omit calls to importing modules if it is known empty.
+
+It is allowed to omit calls to importing modules for which is known to be called.
+
+Reduced BMI
+-----------
+
+To support the 2 phase compilation model, Clang chose to put everything needed to
+produce an object into the BMI. But every consumer of the BMI, except itself, doesn't
+need such informations. It makes the BMI to larger and so may introduce unnecessary
+dependencies into the BMI. To mitigate the problem, we decided to reduce the information
+contained in the BMI.
+
+To be clear, we call the default BMI as Full BMI and the new introduced BMI as Reduced
+BMI.
+
+Users can use ``-fexperimental-modules-reduced-bmi`` flag to enable the Reduced BMI.
+
+For one phase compilation model (CMake implements this model), with
+``-fexperimental-modules-reduced-bmi``, the generated BMI will be Reduced BMI automatically.
+(The output path of the BMI is specified by ``-fmodule-output=`` as usual one phase
+compilation model).
+
+It is still possible to support Reduced BMI in two phase compilation model. With
+``-fexperimental-modules-reduced-bmi``, ``--precompile`` and ``-fmodule-output=`` specified,
+the generated BMI specified by ``-o`` will be full BMI and the BMI specified by
+``-fmodule-output=`` will be Reduced BMI. The dependency graph may be:
+
+.. code-block:: none
+
+ module-unit.cppm --> module-unit.full.pcm -> module-unit.o
+ |
+ -> module-unit.reduced.pcm -> consumer1.cpp
+ -> consumer2.cpp
+ -> ...
+ -> consumer_n.cpp
+
+We don't emit diagnostics if ``-fexperimental-modules-reduced-bmi`` is used with a non-module
+unit. This design helps the end users of one phase compilation model to perform experiments
+early without asking for the help of build systems. The users of build systems which supports
+two phase compilation model still need helps from build systems.
+
+Within Reduced BMI, we won't write unreachable entities from GMF, definitions of non-inline
+functions and non-inline variables. This may not be a transparent change.
+`[module.global.frag]ex2 `_ may be a good
+example:
+
+.. code-block:: c++
+
+ // foo.h
+ namespace N {
+ struct X {};
+ int d();
+ int e();
+ inline int f(X, int = d()) { return e(); }
+ int g(X);
+ int h(X);
+ }
+
+ // M.cppm
+ module;
+ #include "foo.h"
+ export module M;
+ template int use_f() {
+ N::X x; // N::X, N, and :: are decl-reachable from use_f
+ return f(x, 123); // N::f is decl-reachable from use_f,
+ // N::e is indirectly decl-reachable from use_f
+ // because it is decl-reachable from N::f, and
+ // N::d is decl-reachable from use_f
+ // because it is decl-reachable from N::f
+ // even though it is not used in this call
+ }
+ template int use_g() {
+ N::X x; // N::X, N, and :: are decl-reachable from use_g
+ return g((T(), x)); // N::g is not decl-reachable from use_g
+ }
+ template int use_h() {
+ N::X x; // N::X, N, and :: are decl-reachable from use_h
+ return h((T(), x)); // N::h is not decl-reachable from use_h, but
+ // N::h is decl-reachable from use_h
+ }
+ int k = use_h();
+ // use_h is decl-reachable from k, so
+ // N::h is decl-reachable from k
+
+ // M-impl.cpp
+ module M;
+ int a = use_f(); // OK
+ int b = use_g(); // error: no viable function for call to g;
+ // g is not decl-reachable from purview of
+ // module M's interface, so is discarded
+ int c = use_h(); // OK
+
+In the above example, the function definition of ``N::g`` is elided from the Reduced
+BMI of ``M.cppm``. Then the use of ``use_g`` in ``M-impl.cpp`` fails
+to instantiate. For such issues, users can add references to ``N::g`` in the module purview
+of ``M.cppm`` to make sure it is reachable, e.g., ``using N::g;``.
+
+We think the Reduced BMI is the correct direction. But given it is a drastic change,
+we'd like to make it experimental first to avoid breaking existing users. The roadmap
+of Reduced BMI may be:
+
+1. ``-fexperimental-modules-reduced-bmi`` is opt in for 1~2 releases. The period depends
+on testing feedbacks.
+2. We would announce Reduced BMI is not experimental and introduce ``-fmodules-reduced-bmi``.
+and suggest users to enable this mode. This may takes 1~2 releases too.
+3. Finally we will enable this by default. When that time comes, the term BMI will refer to
+the reduced BMI today and the Full BMI will only be meaningful to build systems which
+loves to support two phase compilations.
+
Performance Tips
----------------
diff --git a/clang/docs/UndefinedBehaviorSanitizer.rst b/clang/docs/UndefinedBehaviorSanitizer.rst
index 8f58c92bd2a1634f50e357905ba7b4738e36b64a..531d56e313826c766e0d8b7c5a41c4792dca1c2f 100644
--- a/clang/docs/UndefinedBehaviorSanitizer.rst
+++ b/clang/docs/UndefinedBehaviorSanitizer.rst
@@ -148,6 +148,11 @@ Available checks are:
Issues caught by this sanitizer are not undefined behavior,
but are often unintentional.
- ``-fsanitize=integer-divide-by-zero``: Integer division by zero.
+ - ``-fsanitize=implicit-bitfield-conversion``: Implicit conversion from
+ integer of larger bit width to smaller bitfield, if that results in data
+ loss. This includes unsigned/signed truncations and sign changes, similarly
+ to how the ``-fsanitize=implicit-integer-conversion`` group works, but
+ explicitly for bitfields.
- ``-fsanitize=nonnull-attribute``: Passing null pointer as a function
parameter which is declared to never be null.
- ``-fsanitize=null``: Use of a null pointer or creation of a null
@@ -193,8 +198,8 @@ Available checks are:
signed division overflow (``INT_MIN/-1``). Note that checks are still
added even when ``-fwrapv`` is enabled. This sanitizer does not check for
lossy implicit conversions performed before the computation (see
- ``-fsanitize=implicit-conversion``). Both of these two issues are handled
- by ``-fsanitize=implicit-conversion`` group of checks.
+ ``-fsanitize=implicit-integer-conversion``). Both of these two issues are handled
+ by ``-fsanitize=implicit-integer-conversion`` group of checks.
- ``-fsanitize=unreachable``: If control flow reaches an unreachable
program point.
- ``-fsanitize=unsigned-integer-overflow``: Unsigned integer overflow, where
@@ -202,7 +207,7 @@ Available checks are:
type. Unlike signed integer overflow, this is not undefined behavior, but
it is often unintentional. This sanitizer does not check for lossy implicit
conversions performed before such a computation
- (see ``-fsanitize=implicit-conversion``).
+ (see ``-fsanitize=implicit-integer-conversion``).
- ``-fsanitize=vla-bound``: A variable-length array whose bound
does not evaluate to a positive value.
- ``-fsanitize=vptr``: Use of an object whose vptr indicates that it is of
@@ -224,11 +229,15 @@ You can also use the following check groups:
- ``-fsanitize=implicit-integer-arithmetic-value-change``: Catches implicit
conversions that change the arithmetic value of the integer. Enables
``implicit-signed-integer-truncation`` and ``implicit-integer-sign-change``.
- - ``-fsanitize=implicit-conversion``: Checks for suspicious
- behavior of implicit conversions. Enables
+ - ``-fsanitize=implicit-integer-conversion``: Checks for suspicious
+ behavior of implicit integer conversions. Enables
``implicit-unsigned-integer-truncation``,
``implicit-signed-integer-truncation``, and
``implicit-integer-sign-change``.
+ - ``-fsanitize=implicit-conversion``: Checks for suspicious
+ behavior of implicit conversions. Enables
+ ``implicit-integer-conversion``, and
+ ``implicit-bitfield-conversion``.
- ``-fsanitize=integer``: Checks for undefined or suspicious integer
behavior (e.g. unsigned integer overflow).
Enables ``signed-integer-overflow``, ``unsigned-integer-overflow``,
diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index f188f18ba5557e48efe4b5586e93cf90e1b1fafe..fb748d23a53d01ce04c607f38d605c3ac7b26de8 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -3138,10 +3138,16 @@ are detected:
allowed in this state.
* Invalid 3rd ("``whence``") argument to ``fseek``.
-The checker does not track the correspondence between integer file descriptors
-and ``FILE *`` pointers. Operations on standard streams like ``stdin`` are not
-treated specially and are therefore often not recognized (because these streams
-are usually not opened explicitly by the program, and are global variables).
+The stream operations are by this checker usually split into two cases, a success
+and a failure case. However, in the case of write operations (like ``fwrite``,
+``fprintf`` and even ``fsetpos``) this behavior could produce a large amount of
+unwanted reports on projects that don't have error checks around the write
+operations, so by default the checker assumes that write operations always succeed.
+This behavior can be controlled by the ``Pedantic`` flag: With
+``-analyzer-config alpha.unix.Stream:Pedantic=true`` the checker will model the
+cases where a write operation fails and report situations where this leads to
+erroneous behavior. (The default is ``Pedantic=false``, where write operations
+are assumed to succeed.)
.. code-block:: c
@@ -3196,6 +3202,13 @@ are usually not opened explicitly by the program, and are global variables).
fclose(p);
}
+**Limitations**
+
+The checker does not track the correspondence between integer file descriptors
+and ``FILE *`` pointers. Operations on standard streams like ``stdin`` are not
+treated specially and are therefore often not recognized (because these streams
+are usually not opened explicitly by the program, and are global variables).
+
.. _alpha-unix-cstring-BufferOverlap:
alpha.unix.cstring.BufferOverlap (C)
diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt
index 70687c23b15e61e3417ff09cf32b78781b7e9c18..2252d0ccde96d235a7e45df500ee14a77cfc4340 100644
--- a/clang/docs/tools/clang-formatted-files.txt
+++ b/clang/docs/tools/clang-formatted-files.txt
@@ -123,7 +123,7 @@ clang/include/clang/Analysis/Analyses/CalledOnceCheck.h
clang/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h
clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
clang/include/clang/Analysis/FlowSensitive/AdornedCFG.h
-clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h
+clang/include/clang/Analysis/FlowSensitive/ASTOps.h
clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -308,6 +308,7 @@ clang/lib/Analysis/CalledOnceCheck.cpp
clang/lib/Analysis/CloneDetection.cpp
clang/lib/Analysis/CodeInjector.cpp
clang/lib/Analysis/FlowSensitive/AdornedCFG.cpp
+clang/lib/Analysis/FlowSensitive/ASTOps.cpp
clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp
clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
clang/lib/Analysis/FlowSensitive/DebugSupport.cpp
@@ -2147,8 +2148,10 @@ flang/include/flang/Parser/message.h
flang/include/flang/Parser/parse-state.h
flang/include/flang/Parser/parse-tree-visitor.h
flang/include/flang/Parser/parsing.h
+flang/include/flang/Parser/preprocessor.h
flang/include/flang/Parser/provenance.h
flang/include/flang/Parser/source.h
+flang/include/flang/Parser/token-sequence.h
flang/include/flang/Parser/tools.h
flang/include/flang/Parser/unparse.h
flang/include/flang/Parser/user-state.h
@@ -2319,7 +2322,6 @@ flang/lib/Parser/openmp-parsers.cpp
flang/lib/Parser/parse-tree.cpp
flang/lib/Parser/parsing.cpp
flang/lib/Parser/preprocessor.cpp
-flang/lib/Parser/preprocessor.h
flang/lib/Parser/prescan.cpp
flang/lib/Parser/prescan.h
flang/lib/Parser/program-parsers.cpp
@@ -2328,7 +2330,6 @@ flang/lib/Parser/source.cpp
flang/lib/Parser/stmt-parser.h
flang/lib/Parser/token-parsers.h
flang/lib/Parser/token-sequence.cpp
-flang/lib/Parser/token-sequence.h
flang/lib/Parser/tools.cpp
flang/lib/Parser/type-parser-implementation.h
flang/lib/Parser/type-parsers.h
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 08f71051e6cbf32c20830d2503f8c511099f8908..28f8d67811f0a2517fba976008f0849b4793f25a 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -3411,13 +3411,13 @@ const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB,
/// Utility function for constructing a nullary selector.
inline Selector GetNullarySelector(StringRef name, ASTContext &Ctx) {
- IdentifierInfo* II = &Ctx.Idents.get(name);
+ const IdentifierInfo *II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(0, &II);
}
/// Utility function for constructing an unary selector.
inline Selector GetUnarySelector(StringRef name, ASTContext &Ctx) {
- IdentifierInfo* II = &Ctx.Idents.get(name);
+ const IdentifierInfo *II = &Ctx.Idents.get(name);
return Ctx.Selectors.getSelector(1, &II);
}
diff --git a/clang/include/clang/AST/ASTMutationListener.h b/clang/include/clang/AST/ASTMutationListener.h
index 8879f9f3229ff3f755162bf9cbd200df07e2d641..2c4ec2ce67f36bb3b705b99dd257230a3adcd60b 100644
--- a/clang/include/clang/AST/ASTMutationListener.h
+++ b/clang/include/clang/AST/ASTMutationListener.h
@@ -27,6 +27,7 @@ namespace clang {
class FunctionTemplateDecl;
class Module;
class NamedDecl;
+ class NamespaceDecl;
class ObjCCategoryDecl;
class ObjCContainerDecl;
class ObjCInterfaceDecl;
@@ -35,6 +36,7 @@ namespace clang {
class QualType;
class RecordDecl;
class TagDecl;
+ class TranslationUnitDecl;
class ValueDecl;
class VarDecl;
class VarTemplateDecl;
@@ -147,6 +149,31 @@ public:
virtual void AddedAttributeToRecord(const Attr *Attr,
const RecordDecl *Record) {}
+ /// The parser find the named module declaration.
+ virtual void EnteringModulePurview() {}
+
+ /// An mangling number was added to a Decl
+ ///
+ /// \param D The decl that got a mangling number
+ ///
+ /// \param Number The mangling number that was added to the Decl
+ virtual void AddedManglingNumber(const Decl *D, unsigned Number) {}
+
+ /// An static local number was added to a Decl
+ ///
+ /// \param D The decl that got a static local number
+ ///
+ /// \param Number The static local number that was added to the Decl
+ virtual void AddedStaticLocalNumbers(const Decl *D, unsigned Number) {}
+
+ /// An anonymous namespace was added the translation unit decl
+ ///
+ /// \param TU The translation unit decl that got a new anonymous namespace
+ ///
+ /// \param AnonNamespace The anonymous namespace that was added
+ virtual void AddedAnonymousNamespace(const TranslationUnitDecl *TU,
+ NamespaceDecl *AnonNamespace) {}
+
// NOTE: If new methods are added they should also be added to
// MultiplexASTMutationListener.
};
diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h
index 06d67e9cba95363a72c1c28ed8fb53f052fc630f..f5c47d8a7c2113ab5e3303fda5e86dbb27f029d2 100644
--- a/clang/include/clang/AST/ASTNodeTraverser.h
+++ b/clang/include/clang/AST/ASTNodeTraverser.h
@@ -53,6 +53,7 @@ struct {
void Visit(TypeLoc);
void Visit(const Decl *D);
void Visit(const CXXCtorInitializer *Init);
+ void Visit(const OpenACCClause *C);
void Visit(const OMPClause *C);
void Visit(const BlockDecl::Capture &C);
void Visit(const GenericSelectionExpr::ConstAssociation &A);
@@ -239,6 +240,14 @@ public:
});
}
+ void Visit(const OpenACCClause *C) {
+ getNodeDelegate().AddChild([=] {
+ getNodeDelegate().Visit(C);
+ for (const auto *S : C->children())
+ Visit(S);
+ });
+ }
+
void Visit(const OMPClause *C) {
getNodeDelegate().AddChild([=] {
getNodeDelegate().Visit(C);
@@ -799,6 +808,11 @@ public:
Visit(C);
}
+ void VisitOpenACCConstructStmt(const OpenACCConstructStmt *Node) {
+ for (const auto *C : Node->clauses())
+ Visit(C);
+ }
+
void VisitInitListExpr(const InitListExpr *ILE) {
if (auto *Filler = ILE->getArrayFiller()) {
Visit(Filler, "array_filler");
@@ -919,6 +933,14 @@ public:
Visit(TArg);
}
+ void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node) {
+ Visit(Node->getExpr());
+ }
+
+ void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node) {
+ Visit(Node->getExpr());
+ }
+
// Implements Visit methods for Attrs.
#include "clang/AST/AttrNodeTraverse.inc"
};
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index a5879591f4c65965b4ebd4b391c26f8e7fd6224c..0a9c9e17d3f9f91f8c22608e17de36235afaf2cf 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -120,7 +120,7 @@ public:
ASTContext &getASTContext() const { return Ctx; }
NamespaceDecl *getAnonymousNamespace() const { return AnonymousNamespace; }
- void setAnonymousNamespace(NamespaceDecl *D) { AnonymousNamespace = D; }
+ void setAnonymousNamespace(NamespaceDecl *D);
static TranslationUnitDecl *Create(ASTContext &C);
@@ -1100,6 +1100,9 @@ protected:
LLVM_PREFERRED_TYPE(bool)
unsigned EscapingByref : 1;
+
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned IsCXXCondDecl : 1;
};
union {
@@ -1589,6 +1592,15 @@ public:
NonParmVarDeclBits.EscapingByref = true;
}
+ bool isCXXCondDecl() const {
+ return isa(this) ? false : NonParmVarDeclBits.IsCXXCondDecl;
+ }
+
+ void setCXXCondDecl() {
+ assert(!isa(this));
+ NonParmVarDeclBits.IsCXXCondDecl = true;
+ }
+
/// Determines if this variable's alignment is dependent.
bool hasDependentAlignment() const;
@@ -1719,7 +1731,7 @@ public:
static ImplicitParamDecl *CreateDeserialized(ASTContext &C, unsigned ID);
ImplicitParamDecl(ASTContext &C, DeclContext *DC, SourceLocation IdLoc,
- IdentifierInfo *Id, QualType Type,
+ const IdentifierInfo *Id, QualType Type,
ImplicitParamKind ParamKind)
: VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type,
/*TInfo=*/nullptr, SC_None) {
@@ -1753,7 +1765,7 @@ public:
protected:
ParmVarDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
- SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
+ SourceLocation IdLoc, const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg)
: VarDecl(DK, C, DC, StartLoc, IdLoc, Id, T, TInfo, S) {
assert(ParmVarDeclBits.HasInheritedDefaultArg == false);
@@ -1765,10 +1777,10 @@ protected:
public:
static ParmVarDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation StartLoc,
- SourceLocation IdLoc, IdentifierInfo *Id,
- QualType T, TypeSourceInfo *TInfo,
- StorageClass S, Expr *DefArg);
+ SourceLocation StartLoc, SourceLocation IdLoc,
+ const IdentifierInfo *Id, QualType T,
+ TypeSourceInfo *TInfo, StorageClass S,
+ Expr *DefArg);
static ParmVarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -1981,21 +1993,35 @@ public:
};
- /// Stashed information about a defaulted function definition whose body has
- /// not yet been lazily generated.
- class DefaultedFunctionInfo final
- : llvm::TrailingObjects {
+ /// Stashed information about a defaulted/deleted function body.
+ class DefaultedOrDeletedFunctionInfo final
+ : llvm::TrailingObjects {
friend TrailingObjects;
unsigned NumLookups;
+ bool HasDeletedMessage;
+
+ size_t numTrailingObjects(OverloadToken) const {
+ return NumLookups;
+ }
public:
- static DefaultedFunctionInfo *Create(ASTContext &Context,
- ArrayRef Lookups);
+ static DefaultedOrDeletedFunctionInfo *
+ Create(ASTContext &Context, ArrayRef Lookups,
+ StringLiteral *DeletedMessage = nullptr);
+
/// Get the unqualified lookup results that should be used in this
/// defaulted function definition.
ArrayRef getUnqualifiedLookups() const {
return {getTrailingObjects(), NumLookups};
}
+
+ StringLiteral *getDeletedMessage() const {
+ return HasDeletedMessage ? *getTrailingObjects()
+ : nullptr;
+ }
+
+ void setDeletedMessage(StringLiteral *Message);
};
private:
@@ -2005,12 +2031,12 @@ private:
ParmVarDecl **ParamInfo = nullptr;
/// The active member of this union is determined by
- /// FunctionDeclBits.HasDefaultedFunctionInfo.
+ /// FunctionDeclBits.HasDefaultedOrDeletedInfo.
union {
/// The body of the function.
LazyDeclStmtPtr Body;
/// Information about a future defaulted function definition.
- DefaultedFunctionInfo *DefaultedInfo;
+ DefaultedOrDeletedFunctionInfo *DefaultedOrDeletedInfo;
};
unsigned ODRHash;
@@ -2268,18 +2294,18 @@ public:
/// Returns whether this specific declaration of the function has a body.
bool doesThisDeclarationHaveABody() const {
- return (!FunctionDeclBits.HasDefaultedFunctionInfo && Body) ||
+ return (!FunctionDeclBits.HasDefaultedOrDeletedInfo && Body) ||
isLateTemplateParsed();
}
void setBody(Stmt *B);
void setLazyBody(uint64_t Offset) {
- FunctionDeclBits.HasDefaultedFunctionInfo = false;
+ FunctionDeclBits.HasDefaultedOrDeletedInfo = false;
Body = LazyDeclStmtPtr(Offset);
}
- void setDefaultedFunctionInfo(DefaultedFunctionInfo *Info);
- DefaultedFunctionInfo *getDefaultedFunctionInfo() const;
+ void setDefaultedOrDeletedInfo(DefaultedOrDeletedFunctionInfo *Info);
+ DefaultedOrDeletedFunctionInfo *getDefalutedOrDeletedInfo() const;
/// Whether this function is variadic.
bool isVariadic() const;
@@ -2482,7 +2508,7 @@ public:
return FunctionDeclBits.IsDeleted && !isDefaulted();
}
- void setDeletedAsWritten(bool D = true) { FunctionDeclBits.IsDeleted = D; }
+ void setDeletedAsWritten(bool D = true, StringLiteral *Message = nullptr);
/// Determines whether this function is "main", which is the
/// entry point into an executable program.
@@ -2638,6 +2664,13 @@ public:
AC.push_back(TRC);
}
+ /// Get the message that indicates why this function was deleted.
+ StringLiteral *getDeletedMessage() const {
+ return FunctionDeclBits.HasDefaultedOrDeletedInfo
+ ? DefaultedOrDeletedInfo->getDeletedMessage()
+ : nullptr;
+ }
+
void setPreviousDeclaration(FunctionDecl * PrevDecl);
FunctionDecl *getCanonicalDecl() override;
@@ -3083,7 +3116,7 @@ class FieldDecl : public DeclaratorDecl, public Mergeable {
protected:
FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc,
- SourceLocation IdLoc, IdentifierInfo *Id, QualType T,
+ SourceLocation IdLoc, const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
InClassInitStyle InitStyle)
: DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), BitField(false),
@@ -3099,7 +3132,7 @@ public:
static FieldDecl *Create(const ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
- IdentifierInfo *Id, QualType T,
+ const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo, Expr *BW, bool Mutable,
InClassInitStyle InitStyle);
@@ -3116,7 +3149,7 @@ public:
bool isBitField() const { return BitField; }
/// Determines whether this is an unnamed bitfield.
- bool isUnnamedBitfield() const { return isBitField() && !getDeclName(); }
+ bool isUnnamedBitField() const { return isBitField() && !getDeclName(); }
/// Determines whether this field is a
/// representative for an anonymous struct or union. Such fields are
@@ -3320,8 +3353,9 @@ public:
friend class ASTDeclReader;
static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation L, IdentifierInfo *Id,
- QualType T, llvm::MutableArrayRef CH);
+ SourceLocation L, const IdentifierInfo *Id,
+ QualType T,
+ llvm::MutableArrayRef CH);
static IndirectFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -3369,9 +3403,9 @@ class TypeDecl : public NamedDecl {
void anchor() override;
protected:
- TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
+ TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, const IdentifierInfo *Id,
SourceLocation StartL = SourceLocation())
- : NamedDecl(DK, DC, L, Id), LocStart(StartL) {}
+ : NamedDecl(DK, DC, L, Id), LocStart(StartL) {}
public:
// Low-level accessor. If you just want the type defined by this node,
@@ -3413,7 +3447,7 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable {
protected:
TypedefNameDecl(Kind DK, ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
- IdentifierInfo *Id, TypeSourceInfo *TInfo)
+ const IdentifierInfo *Id, TypeSourceInfo *TInfo)
: TypeDecl(DK, DC, IdLoc, Id, StartLoc), redeclarable_base(C),
MaybeModedTInfo(TInfo, 0) {}
@@ -3500,13 +3534,14 @@ private:
/// type specifier.
class TypedefDecl : public TypedefNameDecl {
TypedefDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
- SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo)
+ SourceLocation IdLoc, const IdentifierInfo *Id,
+ TypeSourceInfo *TInfo)
: TypedefNameDecl(Typedef, C, DC, StartLoc, IdLoc, Id, TInfo) {}
public:
static TypedefDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
- IdentifierInfo *Id, TypeSourceInfo *TInfo);
+ const IdentifierInfo *Id, TypeSourceInfo *TInfo);
static TypedefDecl *CreateDeserialized(ASTContext &C, unsigned ID);
SourceRange getSourceRange() const override LLVM_READONLY;
@@ -3523,14 +3558,15 @@ class TypeAliasDecl : public TypedefNameDecl {
TypeAliasTemplateDecl *Template;
TypeAliasDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
- SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo)
+ SourceLocation IdLoc, const IdentifierInfo *Id,
+ TypeSourceInfo *TInfo)
: TypedefNameDecl(TypeAlias, C, DC, StartLoc, IdLoc, Id, TInfo),
Template(nullptr) {}
public:
static TypeAliasDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
- IdentifierInfo *Id, TypeSourceInfo *TInfo);
+ const IdentifierInfo *Id, TypeSourceInfo *TInfo);
static TypeAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID);
SourceRange getSourceRange() const override LLVM_READONLY;
diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index 858450926455c602030671323257a4470bc096f7..1079993f4969456f87d9ba2e2e80fff8b0efa016 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -672,16 +672,6 @@ public:
/// Whether this declaration comes from explicit global module.
bool isFromExplicitGlobalModule() const;
- /// Check if we should skip checking ODRHash for declaration \param D.
- ///
- /// The existing ODRHash mechanism seems to be not stable enough and
- /// the false positive ODR violation reports are annoying and we rarely see
- /// true ODR violation reports. Also we learned that MSVC disabled ODR checks
- /// for declarations in GMF. So we try to disable ODR checks in the GMF to
- /// get better user experiences before we make the ODR violation checks stable
- /// enough.
- bool shouldSkipCheckingODR() const;
-
/// Return true if this declaration has an attribute which acts as
/// definition of the entity, such as 'alias' or 'ifunc'.
bool hasDefiningAttr() const;
@@ -1739,7 +1729,7 @@ class DeclContext {
LLVM_PREFERRED_TYPE(bool)
uint64_t IsExplicitlyDefaulted : 1;
LLVM_PREFERRED_TYPE(bool)
- uint64_t HasDefaultedFunctionInfo : 1;
+ uint64_t HasDefaultedOrDeletedInfo : 1;
/// For member functions of complete types, whether this is an ineligible
/// special member function or an unselected destructor. See
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h
index 9cebaff63bb0dbe77dfbaa4d441a4e26526db167..7aed4d5cbc002e2c60d743922f16d507bfb2a2dd 100644
--- a/clang/include/clang/AST/DeclCXX.h
+++ b/clang/include/clang/AST/DeclCXX.h
@@ -1869,6 +1869,10 @@ public:
DL.MethodTyInfo = TS;
}
+ void setLambdaDependencyKind(unsigned Kind) {
+ getLambdaData().DependencyKind = Kind;
+ }
+
void setLambdaIsGeneric(bool IsGeneric) {
assert(DefinitionData && DefinitionData->IsLambda &&
"setting lambda property of non-lambda class");
diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h
index f8f894b4b10d1919a484eae6b14adf45517166ea..b8d17dd06d1550082446496c9d02ef5fa9c759a5 100644
--- a/clang/include/clang/AST/DeclObjC.h
+++ b/clang/include/clang/AST/DeclObjC.h
@@ -772,7 +772,7 @@ private:
// Synthesize ivar for this property
ObjCIvarDecl *PropertyIvarDecl = nullptr;
- ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
+ ObjCPropertyDecl(DeclContext *DC, SourceLocation L, const IdentifierInfo *Id,
SourceLocation AtLocation, SourceLocation LParenLocation,
QualType T, TypeSourceInfo *TSI, PropertyControl propControl)
: NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation),
@@ -782,10 +782,12 @@ private:
PropertyImplementation(propControl) {}
public:
- static ObjCPropertyDecl *
- Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
- SourceLocation AtLocation, SourceLocation LParenLocation, QualType T,
- TypeSourceInfo *TSI, PropertyControl propControl = None);
+ static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC,
+ SourceLocation L, const IdentifierInfo *Id,
+ SourceLocation AtLocation,
+ SourceLocation LParenLocation, QualType T,
+ TypeSourceInfo *TSI,
+ PropertyControl propControl = None);
static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -952,7 +954,7 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext {
void anchor() override;
public:
- ObjCContainerDecl(Kind DK, DeclContext *DC, IdentifierInfo *Id,
+ ObjCContainerDecl(Kind DK, DeclContext *DC, const IdentifierInfo *Id,
SourceLocation nameLoc, SourceLocation atStartLoc);
// Iterator access to instance/class properties.
@@ -1240,7 +1242,7 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
llvm::PointerIntPair Data;
ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc,
- IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
+ const IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl,
bool IsInternal);
@@ -1271,13 +1273,11 @@ class ObjCInterfaceDecl : public ObjCContainerDecl
}
public:
- static ObjCInterfaceDecl *Create(const ASTContext &C, DeclContext *DC,
- SourceLocation atLoc,
- IdentifierInfo *Id,
- ObjCTypeParamList *typeParamList,
- ObjCInterfaceDecl *PrevDecl,
- SourceLocation ClassLoc = SourceLocation(),
- bool isInternal = false);
+ static ObjCInterfaceDecl *
+ Create(const ASTContext &C, DeclContext *DC, SourceLocation atLoc,
+ const IdentifierInfo *Id, ObjCTypeParamList *typeParamList,
+ ObjCInterfaceDecl *PrevDecl,
+ SourceLocation ClassLoc = SourceLocation(), bool isInternal = false);
static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C, unsigned ID);
@@ -1338,7 +1338,8 @@ public:
ObjCImplementationDecl *getImplementation() const;
void setImplementation(ObjCImplementationDecl *ImplD);
- ObjCCategoryDecl *FindCategoryDeclaration(IdentifierInfo *CategoryId) const;
+ ObjCCategoryDecl *
+ FindCategoryDeclaration(const IdentifierInfo *CategoryId) const;
// Get the local instance/class method declared in a category.
ObjCMethodDecl *getCategoryInstanceMethod(Selector Sel) const;
@@ -1794,9 +1795,9 @@ public:
data().CategoryList = category;
}
- ObjCPropertyDecl
- *FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId,
- ObjCPropertyQueryKind QueryKind) const;
+ ObjCPropertyDecl *
+ FindPropertyVisibleInPrimaryClass(const IdentifierInfo *PropertyId,
+ ObjCPropertyQueryKind QueryKind) const;
void collectPropertiesToImplement(PropertyMap &PM) const override;
@@ -1954,8 +1955,8 @@ public:
private:
ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc,
- SourceLocation IdLoc, IdentifierInfo *Id,
- QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
+ SourceLocation IdLoc, const IdentifierInfo *Id, QualType T,
+ TypeSourceInfo *TInfo, AccessControl ac, Expr *BW,
bool synthesized)
: FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW,
/*Mutable=*/false, /*HasInit=*/ICIS_NoInit),
@@ -1964,10 +1965,9 @@ private:
public:
static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC,
SourceLocation StartLoc, SourceLocation IdLoc,
- IdentifierInfo *Id, QualType T,
- TypeSourceInfo *TInfo,
- AccessControl ac, Expr *BW = nullptr,
- bool synthesized=false);
+ const IdentifierInfo *Id, QualType T,
+ TypeSourceInfo *TInfo, AccessControl ac,
+ Expr *BW = nullptr, bool synthesized = false);
static ObjCIvarDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -2343,7 +2343,7 @@ class ObjCCategoryDecl : public ObjCContainerDecl {
ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc,
SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
- IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
+ const IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
ObjCTypeParamList *typeParamList,
SourceLocation IvarLBraceLoc = SourceLocation(),
SourceLocation IvarRBraceLoc = SourceLocation());
@@ -2354,15 +2354,13 @@ public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
- static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC,
- SourceLocation AtLoc,
- SourceLocation ClassNameLoc,
- SourceLocation CategoryNameLoc,
- IdentifierInfo *Id,
- ObjCInterfaceDecl *IDecl,
- ObjCTypeParamList *typeParamList,
- SourceLocation IvarLBraceLoc=SourceLocation(),
- SourceLocation IvarRBraceLoc=SourceLocation());
+ static ObjCCategoryDecl *
+ Create(ASTContext &C, DeclContext *DC, SourceLocation AtLoc,
+ SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc,
+ const IdentifierInfo *Id, ObjCInterfaceDecl *IDecl,
+ ObjCTypeParamList *typeParamList,
+ SourceLocation IvarLBraceLoc = SourceLocation(),
+ SourceLocation IvarRBraceLoc = SourceLocation());
static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID);
ObjCInterfaceDecl *getClassInterface() { return ClassInterface; }
@@ -2472,10 +2470,9 @@ class ObjCImplDecl : public ObjCContainerDecl {
void anchor() override;
protected:
- ObjCImplDecl(Kind DK, DeclContext *DC,
- ObjCInterfaceDecl *classInterface,
- IdentifierInfo *Id,
- SourceLocation nameLoc, SourceLocation atStartLoc)
+ ObjCImplDecl(Kind DK, DeclContext *DC, ObjCInterfaceDecl *classInterface,
+ const IdentifierInfo *Id, SourceLocation nameLoc,
+ SourceLocation atStartLoc)
: ObjCContainerDecl(DK, DC, Id, nameLoc, atStartLoc),
ClassInterface(classInterface) {}
@@ -2543,12 +2540,12 @@ class ObjCCategoryImplDecl : public ObjCImplDecl {
// Category name location
SourceLocation CategoryNameLoc;
- ObjCCategoryImplDecl(DeclContext *DC, IdentifierInfo *Id,
+ ObjCCategoryImplDecl(DeclContext *DC, const IdentifierInfo *Id,
ObjCInterfaceDecl *classInterface,
SourceLocation nameLoc, SourceLocation atStartLoc,
SourceLocation CategoryNameLoc)
- : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id,
- nameLoc, atStartLoc),
+ : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id, nameLoc,
+ atStartLoc),
CategoryNameLoc(CategoryNameLoc) {}
void anchor() override;
@@ -2557,12 +2554,10 @@ public:
friend class ASTDeclReader;
friend class ASTDeclWriter;
- static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC,
- IdentifierInfo *Id,
- ObjCInterfaceDecl *classInterface,
- SourceLocation nameLoc,
- SourceLocation atStartLoc,
- SourceLocation CategoryNameLoc);
+ static ObjCCategoryImplDecl *
+ Create(ASTContext &C, DeclContext *DC, const IdentifierInfo *Id,
+ ObjCInterfaceDecl *classInterface, SourceLocation nameLoc,
+ SourceLocation atStartLoc, SourceLocation CategoryNameLoc);
static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, unsigned ID);
ObjCCategoryDecl *getCategoryDecl() const;
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index e3b6a7efb1127af56d594d8299f49a21ed38a43f..f24e71ff229648d80336e76faef5abbe850a0fe9 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -1389,14 +1389,14 @@ class NonTypeTemplateParmDecl final
NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, unsigned D, unsigned P,
- IdentifierInfo *Id, QualType T,
+ const IdentifierInfo *Id, QualType T,
bool ParameterPack, TypeSourceInfo *TInfo)
: DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc),
TemplateParmPosition(D, P), ParameterPack(ParameterPack) {}
NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc,
SourceLocation IdLoc, unsigned D, unsigned P,
- IdentifierInfo *Id, QualType T,
+ const IdentifierInfo *Id, QualType T,
TypeSourceInfo *TInfo,
ArrayRef ExpandedTypes,
ArrayRef ExpandedTInfos);
@@ -1404,12 +1404,12 @@ class NonTypeTemplateParmDecl final
public:
static NonTypeTemplateParmDecl *
Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
- SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id,
+ SourceLocation IdLoc, unsigned D, unsigned P, const IdentifierInfo *Id,
QualType T, bool ParameterPack, TypeSourceInfo *TInfo);
static NonTypeTemplateParmDecl *
Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc,
- SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id,
+ SourceLocation IdLoc, unsigned D, unsigned P, const IdentifierInfo *Id,
QualType T, TypeSourceInfo *TInfo, ArrayRef ExpandedTypes,
ArrayRef ExpandedTInfos);
@@ -1581,26 +1581,36 @@ class TemplateTemplateParmDecl final
DefaultArgStorage;
DefArgStorage DefaultArgument;
+ /// Whether this template template parameter was declaration with
+ /// the 'typename' keyword.
+ ///
+ /// If false, it was declared with the 'class' keyword.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned Typename : 1;
+
/// Whether this parameter is a parameter pack.
- bool ParameterPack;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned ParameterPack : 1;
/// Whether this template template parameter is an "expanded"
/// parameter pack, meaning that it is a pack expansion and we
/// already know the set of template parameters that expansion expands to.
- bool ExpandedParameterPack = false;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned ExpandedParameterPack : 1;
/// The number of parameters in an expanded parameter pack.
unsigned NumExpandedParams = 0;
- TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
- unsigned D, unsigned P, bool ParameterPack,
- IdentifierInfo *Id, TemplateParameterList *Params)
+ TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
+ unsigned P, bool ParameterPack, IdentifierInfo *Id,
+ bool Typename, TemplateParameterList *Params)
: TemplateDecl(TemplateTemplateParm, DC, L, Id, Params),
- TemplateParmPosition(D, P), ParameterPack(ParameterPack) {}
+ TemplateParmPosition(D, P), Typename(Typename),
+ ParameterPack(ParameterPack), ExpandedParameterPack(false) {}
- TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L,
- unsigned D, unsigned P,
- IdentifierInfo *Id, TemplateParameterList *Params,
+ TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D,
+ unsigned P, IdentifierInfo *Id, bool Typename,
+ TemplateParameterList *Params,
ArrayRef Expansions);
void anchor() override;
@@ -1613,14 +1623,13 @@ public:
static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
SourceLocation L, unsigned D,
unsigned P, bool ParameterPack,
- IdentifierInfo *Id,
+ IdentifierInfo *Id, bool Typename,
TemplateParameterList *Params);
- static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC,
- SourceLocation L, unsigned D,
- unsigned P,
- IdentifierInfo *Id,
- TemplateParameterList *Params,
- ArrayRef Expansions);
+ static TemplateTemplateParmDecl *
+ Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D,
+ unsigned P, IdentifierInfo *Id, bool Typename,
+ TemplateParameterList *Params,
+ ArrayRef Expansions);
static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C,
unsigned ID);
@@ -1634,6 +1643,14 @@ public:
using TemplateParmPosition::setPosition;
using TemplateParmPosition::getIndex;
+ /// Whether this template template parameter was declared with
+ /// the 'typename' keyword.
+ bool wasDeclaredWithTypename() const { return Typename; }
+
+ /// Set whether this template template parameter was declared with
+ /// the 'typename' or 'class' keyword.
+ void setDeclaredWithTypename(bool withTypename) { Typename = withTypename; }
+
/// Whether this template template parameter is a template
/// parameter pack.
///
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 6003b866c9f564519006077b3618fc324bd09bef..d28e5c3a78ee4bbb9c76ddb2d229a9d99372ab19 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -1149,6 +1149,7 @@ class CXXThisExpr : public Expr {
CXXThisExpr(SourceLocation L, QualType Ty, bool IsImplicit, ExprValueKind VK)
: Expr(CXXThisExprClass, Ty, VK, OK_Ordinary) {
CXXThisExprBits.IsImplicit = IsImplicit;
+ CXXThisExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter = false;
CXXThisExprBits.Loc = L;
setDependence(computeDependence(this));
}
@@ -1170,6 +1171,15 @@ public:
bool isImplicit() const { return CXXThisExprBits.IsImplicit; }
void setImplicit(bool I) { CXXThisExprBits.IsImplicit = I; }
+ bool isCapturedByCopyInLambdaWithExplicitObjectParameter() const {
+ return CXXThisExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter;
+ }
+
+ void setCapturedByCopyInLambdaWithExplicitObjectParameter(bool Set) {
+ CXXThisExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter = Set;
+ setDependence(computeDependence(this));
+ }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == CXXThisExprClass;
}
@@ -2549,7 +2559,7 @@ public:
class PseudoDestructorTypeStorage {
/// Either the type source information or the name of the type, if
/// it couldn't be resolved due to type-dependence.
- llvm::PointerUnion Type;
+ llvm::PointerUnion Type;
/// The starting source location of the pseudo-destructor type.
SourceLocation Location;
@@ -2557,7 +2567,7 @@ class PseudoDestructorTypeStorage {
public:
PseudoDestructorTypeStorage() = default;
- PseudoDestructorTypeStorage(IdentifierInfo *II, SourceLocation Loc)
+ PseudoDestructorTypeStorage(const IdentifierInfo *II, SourceLocation Loc)
: Type(II), Location(Loc) {}
PseudoDestructorTypeStorage(TypeSourceInfo *Info);
@@ -2566,8 +2576,8 @@ public:
return Type.dyn_cast();
}
- IdentifierInfo *getIdentifier() const {
- return Type.dyn_cast();
+ const IdentifierInfo *getIdentifier() const {
+ return Type.dyn_cast();
}
SourceLocation getLocation() const { return Location; }
@@ -2698,7 +2708,7 @@ public:
/// In a dependent pseudo-destructor expression for which we do not
/// have full type information on the destroyed type, provides the name
/// of the destroyed type.
- IdentifierInfo *getDestroyedTypeIdentifier() const {
+ const IdentifierInfo *getDestroyedTypeIdentifier() const {
return DestroyedType.getIdentifier();
}
diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h
index 8e573965b0a3360c2f70ea4cd95ec85fa718f925..230c83943c2224469f59e40d5eb264a262e453d3 100644
--- a/clang/include/clang/AST/ExternalASTSource.h
+++ b/clang/include/clang/AST/ExternalASTSource.h
@@ -138,7 +138,7 @@ public:
virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset);
/// Update an out-of-date identifier.
- virtual void updateOutOfDateIdentifier(IdentifierInfo &II) {}
+ virtual void updateOutOfDateIdentifier(const IdentifierInfo &II) {}
/// Find all declarations with the given name in the given context,
/// and add them to the context by calling SetExternalVisibleDeclsForName
diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h
index dde70dde2fa2be1aa8e17565cd6cfe7384ed03f2..55bd583e304e8b515b93fadb3b7da4664efabb5c 100644
--- a/clang/include/clang/AST/JSONNodeDumper.h
+++ b/clang/include/clang/AST/JSONNodeDumper.h
@@ -203,6 +203,7 @@ public:
void Visit(const TemplateArgument &TA, SourceRange R = {},
const Decl *From = nullptr, StringRef Label = {});
void Visit(const CXXCtorInitializer *Init);
+ void Visit(const OpenACCClause *C);
void Visit(const OMPClause *C);
void Visit(const BlockDecl::Capture &C);
void Visit(const GenericSelectionExpr::ConstAssociation &A);
@@ -309,6 +310,8 @@ public:
void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *MTE);
void VisitCXXDependentScopeMemberExpr(const CXXDependentScopeMemberExpr *ME);
void VisitRequiresExpr(const RequiresExpr *RE);
+ void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *Node);
+ void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *Node);
void VisitObjCEncodeExpr(const ObjCEncodeExpr *OEE);
void VisitObjCMessageExpr(const ObjCMessageExpr *OME);
diff --git a/clang/include/clang/AST/NestedNameSpecifier.h b/clang/include/clang/AST/NestedNameSpecifier.h
index 3b6cf97211850925e4b2392b56a1d88a16612161..7b0c21b9e7cfb1515789809bee50566bedbad480 100644
--- a/clang/include/clang/AST/NestedNameSpecifier.h
+++ b/clang/include/clang/AST/NestedNameSpecifier.h
@@ -124,7 +124,7 @@ public:
/// cannot be resolved.
static NestedNameSpecifier *Create(const ASTContext &Context,
NestedNameSpecifier *Prefix,
- IdentifierInfo *II);
+ const IdentifierInfo *II);
/// Builds a nested name specifier that names a namespace.
static NestedNameSpecifier *Create(const ASTContext &Context,
@@ -134,7 +134,7 @@ public:
/// Builds a nested name specifier that names a namespace alias.
static NestedNameSpecifier *Create(const ASTContext &Context,
NestedNameSpecifier *Prefix,
- NamespaceAliasDecl *Alias);
+ const NamespaceAliasDecl *Alias);
/// Builds a nested name specifier that names a type.
static NestedNameSpecifier *Create(const ASTContext &Context,
@@ -148,7 +148,7 @@ public:
/// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent
/// type.
static NestedNameSpecifier *Create(const ASTContext &Context,
- IdentifierInfo *II);
+ const IdentifierInfo *II);
/// Returns the nested name specifier representing the global
/// scope.
diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h
new file mode 100644
index 0000000000000000000000000000000000000000..8b6d3221aa066bcc73b9a2781d614c26707e2f54
--- /dev/null
+++ b/clang/include/clang/AST/OpenACCClause.h
@@ -0,0 +1,266 @@
+//===- OpenACCClause.h - Classes for OpenACC clauses ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// \file
+// This file defines OpenACC AST classes for clauses.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_AST_OPENACCCLAUSE_H
+#define LLVM_CLANG_AST_OPENACCCLAUSE_H
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/StmtIterator.h"
+#include "clang/Basic/OpenACCKinds.h"
+
+namespace clang {
+/// This is the base type for all OpenACC Clauses.
+class OpenACCClause {
+ OpenACCClauseKind Kind;
+ SourceRange Location;
+
+protected:
+ OpenACCClause(OpenACCClauseKind K, SourceLocation BeginLoc,
+ SourceLocation EndLoc)
+ : Kind(K), Location(BeginLoc, EndLoc) {}
+
+public:
+ OpenACCClauseKind getClauseKind() const { return Kind; }
+ SourceLocation getBeginLoc() const { return Location.getBegin(); }
+ SourceLocation getEndLoc() const { return Location.getEnd(); }
+
+ static bool classof(const OpenACCClause *) { return true; }
+
+ using child_iterator = StmtIterator;
+ using const_child_iterator = ConstStmtIterator;
+ using child_range = llvm::iterator_range;
+ using const_child_range = llvm::iterator_range;
+
+ child_range children();
+ const_child_range children() const {
+ auto Children = const_cast(this)->children();
+ return const_child_range(Children.begin(), Children.end());
+ }
+
+ virtual ~OpenACCClause() = default;
+};
+
+/// Represents a clause that has a list of parameters.
+class OpenACCClauseWithParams : public OpenACCClause {
+ /// Location of the '('.
+ SourceLocation LParenLoc;
+
+protected:
+ OpenACCClauseWithParams(OpenACCClauseKind K, SourceLocation BeginLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc)
+ : OpenACCClause(K, BeginLoc, EndLoc), LParenLoc(LParenLoc) {}
+
+public:
+ SourceLocation getLParenLoc() const { return LParenLoc; }
+
+ child_range children() {
+ return child_range(child_iterator(), child_iterator());
+ }
+ const_child_range children() const {
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+};
+
+/// A 'default' clause, has the optional 'none' or 'present' argument.
+class OpenACCDefaultClause : public OpenACCClauseWithParams {
+ friend class ASTReaderStmt;
+ friend class ASTWriterStmt;
+
+ OpenACCDefaultClauseKind DefaultClauseKind;
+
+protected:
+ OpenACCDefaultClause(OpenACCDefaultClauseKind K, SourceLocation BeginLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc)
+ : OpenACCClauseWithParams(OpenACCClauseKind::Default, BeginLoc, LParenLoc,
+ EndLoc),
+ DefaultClauseKind(K) {
+ assert((DefaultClauseKind == OpenACCDefaultClauseKind::None ||
+ DefaultClauseKind == OpenACCDefaultClauseKind::Present) &&
+ "Invalid Clause Kind");
+ }
+
+public:
+ OpenACCDefaultClauseKind getDefaultClauseKind() const {
+ return DefaultClauseKind;
+ }
+
+ static OpenACCDefaultClause *Create(const ASTContext &C,
+ OpenACCDefaultClauseKind K,
+ SourceLocation BeginLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
+};
+
+/// Represents one of the handful of classes that has an optional/required
+/// 'condition' expression as an argument.
+class OpenACCClauseWithCondition : public OpenACCClauseWithParams {
+ Expr *ConditionExpr = nullptr;
+
+protected:
+ OpenACCClauseWithCondition(OpenACCClauseKind K, SourceLocation BeginLoc,
+ SourceLocation LParenLoc, Expr *ConditionExpr,
+ SourceLocation EndLoc)
+ : OpenACCClauseWithParams(K, BeginLoc, LParenLoc, EndLoc),
+ ConditionExpr(ConditionExpr) {}
+
+public:
+ bool hasConditionExpr() const { return ConditionExpr; }
+ const Expr *getConditionExpr() const { return ConditionExpr; }
+ Expr *getConditionExpr() { return ConditionExpr; }
+
+ child_range children() {
+ if (ConditionExpr)
+ return child_range(reinterpret_cast(&ConditionExpr),
+ reinterpret_cast(&ConditionExpr + 1));
+ return child_range(child_iterator(), child_iterator());
+ }
+
+ const_child_range children() const {
+ if (ConditionExpr)
+ return const_child_range(
+ reinterpret_cast(&ConditionExpr),
+ reinterpret_cast(&ConditionExpr + 1));
+ return const_child_range(const_child_iterator(), const_child_iterator());
+ }
+};
+
+/// An 'if' clause, which has a required condition expression.
+class OpenACCIfClause : public OpenACCClauseWithCondition {
+protected:
+ OpenACCIfClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
+ Expr *ConditionExpr, SourceLocation EndLoc);
+
+public:
+ static OpenACCIfClause *Create(const ASTContext &C, SourceLocation BeginLoc,
+ SourceLocation LParenLoc, Expr *ConditionExpr,
+ SourceLocation EndLoc);
+};
+
+/// A 'self' clause, which has an optional condition expression.
+class OpenACCSelfClause : public OpenACCClauseWithCondition {
+ OpenACCSelfClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
+ Expr *ConditionExpr, SourceLocation EndLoc);
+
+public:
+ static OpenACCSelfClause *Create(const ASTContext &C, SourceLocation BeginLoc,
+ SourceLocation LParenLoc,
+ Expr *ConditionExpr, SourceLocation EndLoc);
+};
+
+/// Represents oen of a handful of classes that have a single integer
+/// expression.
+class OpenACCClauseWithSingleIntExpr : public OpenACCClauseWithParams {
+ Expr *IntExpr;
+
+protected:
+ OpenACCClauseWithSingleIntExpr(OpenACCClauseKind K, SourceLocation BeginLoc,
+ SourceLocation LParenLoc, Expr *IntExpr,
+ SourceLocation EndLoc)
+ : OpenACCClauseWithParams(K, BeginLoc, LParenLoc, EndLoc),
+ IntExpr(IntExpr) {}
+
+public:
+ bool hasIntExpr() const { return IntExpr; }
+ const Expr *getIntExpr() const { return IntExpr; }
+
+ Expr *getIntExpr() { return IntExpr; };
+
+ child_range children() {
+ return child_range(reinterpret_cast(&IntExpr),
+ reinterpret_cast(&IntExpr + 1));
+ }
+
+ const_child_range children() const {
+ return const_child_range(reinterpret_cast(&IntExpr),
+ reinterpret_cast(&IntExpr + 1));
+ }
+};
+
+class OpenACCNumWorkersClause : public OpenACCClauseWithSingleIntExpr {
+ OpenACCNumWorkersClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
+ Expr *IntExpr, SourceLocation EndLoc);
+
+public:
+ static OpenACCNumWorkersClause *Create(const ASTContext &C,
+ SourceLocation BeginLoc,
+ SourceLocation LParenLoc,
+ Expr *IntExpr, SourceLocation EndLoc);
+};
+
+class OpenACCVectorLengthClause : public OpenACCClauseWithSingleIntExpr {
+ OpenACCVectorLengthClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
+ Expr *IntExpr, SourceLocation EndLoc);
+
+public:
+ static OpenACCVectorLengthClause *
+ Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
+ Expr *IntExpr, SourceLocation EndLoc);
+};
+
+template class OpenACCClauseVisitor {
+ Impl &getDerived() { return static_cast(*this); }
+
+public:
+ void VisitClauseList(ArrayRef List) {
+ for (const OpenACCClause *Clause : List)
+ Visit(Clause);
+ }
+
+ void Visit(const OpenACCClause *C) {
+ if (!C)
+ return;
+
+ switch (C->getClauseKind()) {
+#define VISIT_CLAUSE(CLAUSE_NAME) \
+ case OpenACCClauseKind::CLAUSE_NAME: \
+ Visit##CLAUSE_NAME##Clause(*cast(C)); \
+ return;
+#include "clang/Basic/OpenACCClauses.def"
+
+ default:
+ llvm_unreachable("Clause visitor not yet implemented");
+ }
+ llvm_unreachable("Invalid Clause kind");
+ }
+
+#define VISIT_CLAUSE(CLAUSE_NAME) \
+ void Visit##CLAUSE_NAME##Clause( \
+ const OpenACC##CLAUSE_NAME##Clause &Clause) { \
+ return getDerived().Visit##CLAUSE_NAME##Clause(Clause); \
+ }
+
+#include "clang/Basic/OpenACCClauses.def"
+};
+
+class OpenACCClausePrinter final
+ : public OpenACCClauseVisitor {
+ raw_ostream &OS;
+
+public:
+ void VisitClauseList(ArrayRef List) {
+ for (const OpenACCClause *Clause : List) {
+ Visit(Clause);
+
+ if (Clause != List.back())
+ OS << ' ';
+ }
+ }
+ OpenACCClausePrinter(raw_ostream &OS) : OS(OS) {}
+
+#define VISIT_CLAUSE(CLAUSE_NAME) \
+ void Visit##CLAUSE_NAME##Clause(const OpenACC##CLAUSE_NAME##Clause &Clause);
+#include "clang/Basic/OpenACCClauses.def"
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_AST_OPENACCCLAUSE_H
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 8630317795a9ad94313f59bba25eac6db36422b6..7eb92e304a3856bcdbc70bb9733e108389df3778 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -509,6 +509,7 @@ private:
bool TraverseOpenACCConstructStmt(OpenACCConstructStmt *S);
bool
TraverseOpenACCAssociatedStmtConstruct(OpenACCAssociatedStmtConstruct *S);
+ bool VisitOpenACCClauseList(ArrayRef);
};
template
@@ -3936,8 +3937,8 @@ bool RecursiveASTVisitor::VisitOMPXBareClause(OMPXBareClause *C) {
template
bool RecursiveASTVisitor::TraverseOpenACCConstructStmt(
- OpenACCConstructStmt *) {
- // TODO OpenACC: When we implement clauses, ensure we traverse them here.
+ OpenACCConstructStmt *C) {
+ TRY_TO(VisitOpenACCClauseList(C->clauses()));
return true;
}
@@ -3949,6 +3950,14 @@ bool RecursiveASTVisitor::TraverseOpenACCAssociatedStmtConstruct(
return true;
}
+template
+bool RecursiveASTVisitor::VisitOpenACCClauseList(
+ ArrayRef) {
+ // TODO OpenACC: When we have Clauses with expressions, we should visit them
+ // here.
+ return true;
+}
+
DEF_TRAVERSE_STMT(OpenACCComputeConstruct,
{ TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); })
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 8892518d58e853230751cf3cf67d1eaff8258e5d..1b9c9231047717bd32f2c19d77f18264eed512bf 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -784,6 +784,11 @@ protected:
LLVM_PREFERRED_TYPE(bool)
unsigned IsImplicit : 1;
+ /// Whether there is a lambda with an explicit object parameter that
+ /// captures this "this" by copy.
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned CapturedByCopyInLambdaWithExplicitObjectParameter : 1;
+
/// The location of the "this".
SourceLocation Loc;
};
diff --git a/clang/include/clang/AST/StmtOpenACC.h b/clang/include/clang/AST/StmtOpenACC.h
index 19da66832c7374ca38048fb5b630cc6aee786281..66f8f844e0b29e1ef34c202751784224809882b7 100644
--- a/clang/include/clang/AST/StmtOpenACC.h
+++ b/clang/include/clang/AST/StmtOpenACC.h
@@ -13,9 +13,11 @@
#ifndef LLVM_CLANG_AST_STMTOPENACC_H
#define LLVM_CLANG_AST_STMTOPENACC_H
+#include "clang/AST/OpenACCClause.h"
#include "clang/AST/Stmt.h"
#include "clang/Basic/OpenACCKinds.h"
#include "clang/Basic/SourceLocation.h"
+#include
namespace clang {
/// This is the base class for an OpenACC statement-level construct, other
@@ -30,13 +32,23 @@ class OpenACCConstructStmt : public Stmt {
/// the directive.
SourceRange Range;
- // TODO OPENACC: Clauses should probably be collected in this class.
+ /// The list of clauses. This is stored here as an ArrayRef, as this is the
+ /// most convienient place to access the list, however the list itself should
+ /// be stored in leaf nodes, likely in trailing-storage.
+ MutableArrayRef Clauses;
protected:
OpenACCConstructStmt(StmtClass SC, OpenACCDirectiveKind K,
SourceLocation Start, SourceLocation End)
: Stmt(SC), Kind(K), Range(Start, End) {}
+ // Used only for initialization, the leaf class can initialize this to
+ // trailing storage.
+ void setClauseList(MutableArrayRef NewClauses) {
+ assert(Clauses.empty() && "Cannot change clause list");
+ Clauses = NewClauses;
+ }
+
public:
OpenACCDirectiveKind getDirectiveKind() const { return Kind; }
@@ -47,6 +59,7 @@ public:
SourceLocation getBeginLoc() const { return Range.getBegin(); }
SourceLocation getEndLoc() const { return Range.getEnd(); }
+ ArrayRef clauses() const { return Clauses; }
child_range children() {
return child_range(child_iterator(), child_iterator());
@@ -101,24 +114,44 @@ public:
/// those three, as they are semantically identical, and have only minor
/// differences in the permitted list of clauses, which can be differentiated by
/// the 'Kind'.
-class OpenACCComputeConstruct : public OpenACCAssociatedStmtConstruct {
+class OpenACCComputeConstruct final
+ : public OpenACCAssociatedStmtConstruct,
+ public llvm::TrailingObjects {
friend class ASTStmtWriter;
friend class ASTStmtReader;
friend class ASTContext;
- OpenACCComputeConstruct()
- : OpenACCAssociatedStmtConstruct(
- OpenACCComputeConstructClass, OpenACCDirectiveKind::Invalid,
- SourceLocation{}, SourceLocation{}, /*AssociatedStmt=*/nullptr) {}
+ OpenACCComputeConstruct(unsigned NumClauses)
+ : OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass,
+ OpenACCDirectiveKind::Invalid,
+ SourceLocation{}, SourceLocation{},
+ /*AssociatedStmt=*/nullptr) {
+ // We cannot send the TrailingObjects storage to the base class (which holds
+ // a reference to the data) until it is constructed, so we have to set it
+ // separately here.
+ std::uninitialized_value_construct(
+ getTrailingObjects(),
+ getTrailingObjects() + NumClauses);
+ setClauseList(MutableArrayRef(getTrailingObjects(),
+ NumClauses));
+ }
OpenACCComputeConstruct(OpenACCDirectiveKind K, SourceLocation Start,
- SourceLocation End, Stmt *StructuredBlock)
+ SourceLocation End,
+ ArrayRef Clauses,
+ Stmt *StructuredBlock)
: OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass, K, Start,
End, StructuredBlock) {
- assert((K == OpenACCDirectiveKind::Parallel ||
- K == OpenACCDirectiveKind::Serial ||
- K == OpenACCDirectiveKind::Kernels) &&
+ assert(isOpenACCComputeDirectiveKind(K) &&
"Only parallel, serial, and kernels constructs should be "
"represented by this type");
+
+ // Initialize the trailing storage.
+ std::uninitialized_copy(Clauses.begin(), Clauses.end(),
+ getTrailingObjects());
+
+ setClauseList(MutableArrayRef(getTrailingObjects(),
+ Clauses.size()));
}
void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); }
@@ -128,10 +161,12 @@ public:
return T->getStmtClass() == OpenACCComputeConstructClass;
}
- static OpenACCComputeConstruct *CreateEmpty(const ASTContext &C, EmptyShell);
+ static OpenACCComputeConstruct *CreateEmpty(const ASTContext &C,
+ unsigned NumClauses);
static OpenACCComputeConstruct *
Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc,
- SourceLocation EndLoc, Stmt *StructuredBlock);
+ SourceLocation EndLoc, ArrayRef Clauses,
+ Stmt *StructuredBlock);
Stmt *getStructuredBlock() { return getAssociatedStmt(); }
const Stmt *getStructuredBlock() const {
diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h
index 3cb3c1014d73b7526dcfe326f78482ff36e28829..f735fa5643aecf9631d1f5efc26a43c7cafe0866 100644
--- a/clang/include/clang/AST/StmtOpenMP.h
+++ b/clang/include/clang/AST/StmtOpenMP.h
@@ -6109,6 +6109,8 @@ public:
class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective {
friend class ASTStmtReader;
friend class OMPExecutableDirective;
+ /// true if loop directive's associated loop can be a parallel for.
+ bool CanBeParallelFor = false;
/// Build directive with the given start and end location.
///
/// \param StartLoc Starting location of the directive kind.
@@ -6131,6 +6133,9 @@ class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective {
llvm::omp::OMPD_target_teams_loop, SourceLocation(),
SourceLocation(), CollapsedNum) {}
+ /// Set whether associated loop can be a parallel for.
+ void setCanBeParallelFor(bool ParFor) { CanBeParallelFor = ParFor; }
+
public:
/// Creates directive with a list of \p Clauses.
///
@@ -6145,7 +6150,7 @@ public:
static OMPTargetTeamsGenericLoopDirective *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef Clauses,
- Stmt *AssociatedStmt, const HelperExprs &Exprs);
+ Stmt *AssociatedStmt, const HelperExprs &Exprs, bool CanBeParallelFor);
/// Creates an empty directive with the place
/// for \a NumClauses clauses.
@@ -6159,6 +6164,10 @@ public:
unsigned CollapsedNum,
EmptyShell);
+ /// Return true if current loop directive's associated loop can be a
+ /// parallel for.
+ bool canBeParallelFor() const { return CanBeParallelFor; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPTargetTeamsGenericLoopDirectiveClass;
}
diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h
index efb5bfe7f83d408717179e17a401dbb3075d1115..1fede6e462e9253c253cc7cc302900084c2d48d6 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -189,6 +189,8 @@ public:
void Visit(const OMPClause *C);
+ void Visit(const OpenACCClause *C);
+
void Visit(const BlockDecl::Capture &C);
void Visit(const GenericSelectionExpr::ConstAssociation &A);
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 2f71053d030f688f6921d15e265072a8b0cbf759..8a2bbfff9e9e6b0025c5af3cb7d94c0017038efa 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -4961,6 +4961,8 @@ AST_MATCHER_P(LambdaExpr, hasAnyCapture, internal::Matcher,
/// capturesVar(hasName("x")) matches `x` and `x = 1`.
AST_MATCHER_P(LambdaCapture, capturesVar, internal::Matcher,
InnerMatcher) {
+ if (!Node.capturesVariable())
+ return false;
auto *capturedVar = Node.getCapturedVar();
return capturedVar && InnerMatcher.matches(*capturedVar, Finder, Builder);
}
diff --git a/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h b/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
index 1ceef944fbc34ee82758ebddda509d861ae94442..117173ba9a09583e624208d91ba481912021c1d6 100644
--- a/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
+++ b/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
@@ -8,11 +8,9 @@
#ifndef LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
#define LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
-#include