335 changes: 335 additions & 0 deletions .ci/metrics/requirements.lock.txt

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions .ci/metrics/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pygithub==2.5.0
7 changes: 3 additions & 4 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@
# to receive an approval from a "code owner" in particular -- any LLVM project
# member can approve pull requests.
#
# Note that GitHub's concept of "code owner" is independent from LLVM's own
# "code owner" concept, they merely happen to share terminology. See
# https://llvm.org/docs/DeveloperPolicy.html#code-owners, as well as the
# CODE_OWNERS.txt files in the respective subproject directories.
# This is independent of LLVM's own "maintainer" concept.
# See https://llvm.org/docs/DeveloperPolicy.html#maintainers as well as the
# Maintainers.* files in the the respective subproject directories.

/libcxx/ @llvm/reviewers-libcxx
/libcxxabi/ @llvm/reviewers-libcxxabi
Expand Down
78 changes: 78 additions & 0 deletions .github/workflows/build-metrics-container.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: Build Metrics Container

permissions:
contents: read

on:
push:
branches:
- main
paths:
- .github/workflows/build-metrics-container.yml
- '.ci/metrics/**'
pull_request:
branches:
- main
paths:
- .github/workflows/build-metrics-container.yml
- '.ci/metrics/**'

jobs:
build-metrics-container:
if: github.repository_owner == 'llvm'
runs-on: ubuntu-latest
outputs:
container-name: ${{ steps.vars.outputs.container-name }}
container-name-tag: ${{ steps.vars.outputs.container-name-tag }}
container-filename: ${{ steps.vars.outputs.container-filename }}
steps:
- name: Checkout LLVM
uses: actions/checkout@v4
with:
sparse-checkout: .ci/metrics/
- name: Write Variables
id: vars
run: |
tag=`date +%s`
container_name="ghcr.io/$GITHUB_REPOSITORY_OWNER/metrics"
echo "container-name=$container_name" >> $GITHUB_OUTPUT
echo "container-name-tag=$container_name:$tag" >> $GITHUB_OUTPUT
echo "container-filename=$(echo $container_name:$tag | sed -e 's/\//-/g' -e 's/:/-/g').tar" >> $GITHUB_OUTPUT
- name: Build Container
working-directory: ./.ci/metrics
run: |
podman build -t ${{ steps.vars.outputs.container-name-tag }} -f Dockerfile .
# Save the container so we have it in case the push fails. This also
# allows us to separate the push step into a different job so we can
# maintain minimal permissions while building the container.
- name: Save Container Image
run: |
podman save ${{ steps.vars.outputs.container-name-tag }} > ${{ steps.vars.outputs.container-filename }}
- name: Upload Container Image
uses: actions/upload-artifact@v4
with:
name: container
path: ${{ steps.vars.outputs.container-filename }}
retention-days: 14

push-metrics-container:
if: github.event_name == 'push'
needs:
- build-metrics-container
permissions:
packages: write
runs-on: ubuntu-24.04
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Download Container
uses: actions/download-artifact@v4
with:
name: container
- name: Push Container
run: |
podman load -i ${{ needs.build-metrics-container.outputs.container-filename }}
podman tag ${{ needs.build-metrics-container.outputs.container-name-tag }} ${{ needs.build-metrics-container.outputs.container-name }}:latest
podman login -u ${{ github.actor }} -p $GITHUB_TOKEN ghcr.io
podman push ${{ needs.build-metrics-container.outputs.container-name-tag }}
podman push ${{ needs.build-metrics-container.outputs.container-name }}:latest
29 changes: 29 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,58 +112,87 @@ jobs:
sudo apt-get update
# swig and graphviz are lldb specific dependencies
sudo apt-get install -y cmake ninja-build swig graphviz
- name: Setup output folder
run: mkdir built-docs
- name: Build LLVM docs
if: steps.docs-changed-subprojects.outputs.llvm_any_changed == 'true'
run: |
cmake -B llvm-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C llvm-build docs-llvm-html docs-llvm-man
mkdir built-docs/llvm
cp -r llvm-build/docs/* built-docs/llvm/
- name: Build Clang docs
if: steps.docs-changed-subprojects.outputs.clang_any_changed == 'true'
run: |
cmake -B clang-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang" -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C clang-build docs-clang-html docs-clang-man
mkdir built-docs/clang
cp -r clang-build/docs/* built-docs/clang/
- name: Build clang-tools-extra docs
if: steps.docs-changed-subprojects.outputs.clang-tools-extra_any_changed == 'true'
run: |
cmake -B clang-tools-extra-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra" -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C clang-tools-extra-build docs-clang-tools-html docs-clang-tools-man
mkdir built-docs/clang-tools-extra
cp -r clang-tools-extra-build/docs/* built-docs/clang-tools-extra/
- name: Build LLDB docs
if: steps.docs-changed-subprojects.outputs.lldb_any_changed == 'true'
run: |
cmake -B lldb-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;lldb" -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C lldb-build docs-lldb-html docs-lldb-man
mkdir built-docs/lldb
cp -r lldb-build/docs/* built-docs/lldb/
- name: Build libunwind docs
if: steps.docs-changed-subprojects.outputs.libunwind_any_changed == 'true'
run: |
cmake -B libunwind-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_RUNTIMES="libunwind" -DLLVM_ENABLE_SPHINX=ON ./runtimes
TZ=UTC ninja -C libunwind-build docs-libunwind-html
mkdir built-docs/libunwind
cp -r libunwind-build/libunwind/docs/* built-docs/libunwind
- name: Build libcxx docs
if: steps.docs-changed-subprojects.outputs.libcxx_any_changed == 'true'
run: |
cmake -B libcxx-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_RUNTIMES="libcxxabi;libcxx;libunwind" -DLLVM_ENABLE_SPHINX=ON ./runtimes
TZ=UTC ninja -C libcxx-build docs-libcxx-html
mkdir built-docs/libcxx
cp -r libcxx-build/libcxx/docs/* built-docs/libcxx/
- name: Build libc docs
if: steps.docs-changed-subprojects.outputs.libc_any_changed == 'true'
run: |
cmake -B libc-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_RUNTIMES="libc" -DLLVM_ENABLE_SPHINX=ON ./runtimes
TZ=UTC ninja -C libc-build docs-libc-html
mkdir built-docs/libc
cp -r libc-build/libc/docs/* built-docs/libc/
- name: Build LLD docs
if: steps.docs-changed-subprojects.outputs.lld_any_changed == 'true'
run: |
cmake -B lld-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="lld" -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C lld-build docs-lld-html
mkdir built-docs/lld
cp -r lld-build/docs/* built-docs/lld/
- name: Build OpenMP docs
if: steps.docs-changed-subprojects.outputs.openmp_any_changed == 'true'
run: |
cmake -B openmp-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;openmp" -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C openmp-build docs-openmp-html
mkdir built-docs/openmp
cp -r openmp-build/docs/* built-docs/openmp/
- name: Build Polly docs
if: steps.docs-changed-subprojects.outputs.polly_any_changed == 'true'
run: |
cmake -B polly-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="polly" -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C polly-build docs-polly-html docs-polly-man
mkdir built-docs/polly
cp -r polly-build/docs/* built-docs/polly/
- name: Build Flang docs
if: steps.docs-changed-subprojects.outputs.flang_any_changed == 'true'
run: |
cmake -B flang-build -GNinja -DCMAKE_BUILD_TYPE=Release -DLLVM_ENABLE_PROJECTS="clang;mlir;flang" -DLLVM_ENABLE_SPHINX=ON ./llvm
TZ=UTC ninja -C flang-build docs-flang-html
mkdir built-docs/flang
cp -r flang-build/docs/* built-docs/flang/
- name: Upload docs
uses: actions/upload-artifact@v4
with:
name: docs-output
path: built-docs/
88 changes: 88 additions & 0 deletions .github/workflows/libcxx-restart-preempted-jobs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,91 @@ jobs:
run_id: context.payload.workflow_run.id
})
await create_check_run('success', 'Restarted workflow run due to preempted job')
restart-test:
if: github.repository_owner == 'llvm' && (github.event.workflow_run.conclusion == 'failure' || github.event.workflow_run.conclusion == 'cancelled') && github.event.actor.login == 'ldionne' # TESTING ONLY
name: "Restart Job"
permissions:
statuses: read
checks: write
actions: write
runs-on: ubuntu-latest
steps:
- name: "Restart Job"
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea #v7.0.1
with:
script: |
const FAILURE_REGEX = /Process completed with exit code 1./
const PREEMPTION_REGEX = /The runner has received a shutdown signal|The operation was canceled/
function log(msg) {
core.notice(msg)
}
const wf_run = context.payload.workflow_run
log(`Running on "${wf_run.display_title}" by @${wf_run.actor.login} (event: ${wf_run.event})\nWorkflow run URL: ${wf_run.html_url}`)
log('Listing check runs for suite')
const check_suites = await github.rest.checks.listForSuite({
owner: context.repo.owner,
repo: context.repo.repo,
check_suite_id: context.payload.workflow_run.check_suite_id,
per_page: 100 // FIXME: We don't have 100 check runs yet, but we should handle this better.
})
preemptions = [];
legitimate_failures = [];
for (check_run of check_suites.data.check_runs) {
log(`Checking check run: ${check_run.id}`);
if (check_run.status != 'completed') {
log('Check run was not completed. Skipping.');
continue;
}
if (check_run.conclusion != 'failure' && check_run.conclusion != 'cancelled') {
log(`Check run had conclusion: ${check_run.conclusion}. Skipping.`);
continue;
}
annotations = await github.rest.checks.listAnnotations({
owner: context.repo.owner,
repo: context.repo.repo,
check_run_id: check_run.id
})
preemption_annotation = annotations.data.find(function(annotation) {
return annotation.annotation_level == 'failure' &&
annotation.message.match(PREEMPTION_REGEX) != null;
});
if (preemption_annotation != null) {
log(`Found preemption message: ${preemption_annotation.message}`);
preemptions.push(check_run);
break;
}
failure_annotation = annotations.data.find(function(annotation) {
return annotation.annotation_level == 'failure' &&
annotation.message.match(FAILURE_REGEX) != null;
});
if (failure_annotation != null) {
log(`Found legitimate failure annotation: ${failure_annotation.message}`);
legitimate_failures.push(check_run);
break;
}
}
if (preemptions) {
log('Found some preempted jobs');
if (legitimate_failures) {
log('Also found some legitimate failures, so not restarting the workflow.');
} else {
log('Did not find any legitimate failures. Restarting workflow.');
await github.rest.actions.reRunWorkflowFailedJobs({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id
})
}
} else {
log('Did not find any preempted jobs. Not restarting the workflow.');
}
File renamed without changes.
8 changes: 8 additions & 0 deletions bolt/include/bolt/Profile/DataAggregator.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ class DataAggregator : public DataReader {
std::string BuildIDBinaryName;

/// Memory map info for a single file as recorded in perf.data
/// When a binary has multiple text segments, the Size is computed as the
/// difference of the last address of these segments from the BaseAddress.
/// The base addresses of all text segments must be the same.
struct MMapInfo {
uint64_t BaseAddress{0}; /// Base address of the mapped binary.
uint64_t MMapAddress{0}; /// Address of the executable segment.
Expand Down Expand Up @@ -493,6 +496,11 @@ class DataAggregator : public DataReader {
/// and return a file name matching a given \p FileBuildID.
std::optional<StringRef> getFileNameForBuildID(StringRef FileBuildID);

/// Get a constant reference to the parsed binary mmap entries.
const std::unordered_map<uint64_t, MMapInfo> &getBinaryMMapInfo() {
return BinaryMMapInfo;
}

friend class YAMLProfileWriter;
};
} // namespace bolt
Expand Down
11 changes: 6 additions & 5 deletions bolt/lib/Passes/VeneerElimination.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,16 +46,17 @@ Error VeneerElimination::runOnFunctions(BinaryContext &BC) {
if (BF.isIgnored())
continue;

MCInst &FirstInstruction = *(BF.begin()->begin());
const MCSymbol *VeneerTargetSymbol = 0;
uint64_t TargetAddress;
if (BC.MIB->matchAbsLongVeneer(BF, TargetAddress)) {
if (BC.MIB->isTailCall(FirstInstruction)) {
VeneerTargetSymbol = BC.MIB->getTargetSymbol(FirstInstruction);
} else if (BC.MIB->matchAbsLongVeneer(BF, TargetAddress)) {
if (BinaryFunction *TargetBF =
BC.getBinaryFunctionAtAddress(TargetAddress))
VeneerTargetSymbol = TargetBF->getSymbol();
} else {
MCInst &FirstInstruction = *(BF.begin()->begin());
if (BC.MIB->hasAnnotation(FirstInstruction, "AArch64Veneer"))
VeneerTargetSymbol = BC.MIB->getTargetSymbol(FirstInstruction, 1);
} else if (BC.MIB->hasAnnotation(FirstInstruction, "AArch64Veneer")) {
VeneerTargetSymbol = BC.MIB->getTargetSymbol(FirstInstruction, 1);
}

if (!VeneerTargetSymbol)
Expand Down
43 changes: 29 additions & 14 deletions bolt/lib/Profile/DataAggregator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ cl::opt<bool> ReadPreAggregated(
"pa", cl::desc("skip perf and read data from a pre-aggregated file format"),
cl::cat(AggregatorCategory));

cl::opt<std::string>
ReadPerfEvents("perf-script-events",
cl::desc("skip perf event collection by supplying a "
"perf-script output in a textual format"),
cl::ReallyHidden, cl::init(""), cl::cat(AggregatorCategory));

static cl::opt<bool>
TimeAggregator("time-aggr",
cl::desc("time BOLT aggregator"),
Expand Down Expand Up @@ -167,8 +173,9 @@ void DataAggregator::findPerfExecutable() {
void DataAggregator::start() {
outs() << "PERF2BOLT: Starting data aggregation job for " << Filename << "\n";

// Don't launch perf for pre-aggregated files
if (opts::ReadPreAggregated)
// Don't launch perf for pre-aggregated files or when perf input is specified
// by the user.
if (opts::ReadPreAggregated || !opts::ReadPerfEvents.empty())
return;

findPerfExecutable();
Expand Down Expand Up @@ -464,6 +471,13 @@ void DataAggregator::filterBinaryMMapInfo() {

int DataAggregator::prepareToParse(StringRef Name, PerfProcessInfo &Process,
PerfProcessErrorCallbackTy Callback) {
if (!opts::ReadPerfEvents.empty()) {
outs() << "PERF2BOLT: using pre-processed perf events for '" << Name
<< "' (perf-script-events)\n";
ParsingBuf = opts::ReadPerfEvents;
return 0;
}

std::string Error;
outs() << "PERF2BOLT: waiting for perf " << Name
<< " collection to finish...\n";
Expand Down Expand Up @@ -2056,15 +2070,6 @@ std::error_code DataAggregator::parseMMapEvents() {
if (FileMMapInfo.first == "(deleted)")
continue;

// Consider only the first mapping of the file for any given PID
auto Range = GlobalMMapInfo.equal_range(FileMMapInfo.first);
bool PIDExists = llvm::any_of(make_range(Range), [&](const auto &MI) {
return MI.second.PID == FileMMapInfo.second.PID;
});

if (PIDExists)
continue;

GlobalMMapInfo.insert(FileMMapInfo);
}

Expand Down Expand Up @@ -2116,12 +2121,22 @@ std::error_code DataAggregator::parseMMapEvents() {
<< " using file offset 0x" << Twine::utohexstr(MMapInfo.Offset)
<< ". Ignoring profile data for this mapping\n";
continue;
} else {
MMapInfo.BaseAddress = *BaseAddress;
}
MMapInfo.BaseAddress = *BaseAddress;
}

BinaryMMapInfo.insert(std::make_pair(MMapInfo.PID, MMapInfo));
// Try to add MMapInfo to the map and update its size. Large binaries may
// span to multiple text segments, so the mapping is inserted only on the
// first occurrence.
if (!BinaryMMapInfo.insert(std::make_pair(MMapInfo.PID, MMapInfo)).second)
assert(MMapInfo.BaseAddress == BinaryMMapInfo[MMapInfo.PID].BaseAddress &&
"Base address on multiple segment mappings should match");

// Update mapping size.
const uint64_t EndAddress = MMapInfo.MMapAddress + MMapInfo.Size;
const uint64_t Size = EndAddress - BinaryMMapInfo[MMapInfo.PID].BaseAddress;
if (Size > BinaryMMapInfo[MMapInfo.PID].Size)
BinaryMMapInfo[MMapInfo.PID].Size = Size;
}

if (BinaryMMapInfo.empty()) {
Expand Down
59 changes: 41 additions & 18 deletions bolt/test/AArch64/veneer-lld-abs.s
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
## Check that llvm-bolt correctly recognizes long absolute thunks generated
## by LLD.
## Check that llvm-bolt correctly recognizes veneers/thunks for absolute code
## generated by LLD.

# RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o
# RUN: %clang %cflags -fno-PIC -no-pie %t.o -o %t.exe -nostdlib \
Expand All @@ -12,40 +12,63 @@

.text
.balign 4
.global foo
.type foo, %function
foo:
adrp x1, foo
.global far_function
.type far_function, %function
far_function:
ret
.size foo, .-foo
.size far_function, .-far_function

.global near_function
.type near_function, %function
near_function:
ret
.size near_function, .-near_function

## Force relocations against .text.
.reloc 0, R_AARCH64_NONE

.section ".mytext", "ax"
.balign 4

.global __AArch64AbsLongThunk_foo
.type __AArch64AbsLongThunk_foo, %function
__AArch64AbsLongThunk_foo:
## This version of a thunk is always generated by LLD for function calls
## spanning more than 256MB.
.global __AArch64AbsLongThunk_far_function
.type __AArch64AbsLongThunk_far_function, %function
__AArch64AbsLongThunk_far_function:
ldr x16, .L1
br x16
# CHECK-INPUT-LABEL: <__AArch64AbsLongThunk_foo>:
# CHECK-INPUT-LABEL: <__AArch64AbsLongThunk_far_function>:
# CHECK-INPUT-NEXT: ldr
# CHECK-INPUT-NEXT: br
.L1:
.quad foo
.size __AArch64AbsLongThunk_foo, .-__AArch64AbsLongThunk_foo
.quad far_function
.size __AArch64AbsLongThunk_far_function, .-__AArch64AbsLongThunk_far_function

## If a callee is closer than 256MB away, LLD may generate a thunk with a direct
## jump to the callee. Note, that the name might still include "AbsLong".
.global __AArch64AbsLongThunk_near_function
.type __AArch64AbsLongThunk_near_function, %function
__AArch64AbsLongThunk_near_function:
b near_function
# CHECK-INPUT-LABEL: <__AArch64AbsLongThunk_near_function>:
# CHECK-INPUT-NEXT: b {{.*}} <near_function>
.size __AArch64AbsLongThunk_near_function, .-__AArch64AbsLongThunk_near_function

## Check that the thunk was removed from .text and _start() calls foo()
## Check that thunks were removed from .text, and _start calls functions
## directly.

# CHECK-OUTPUT-NOT: __AArch64AbsLongThunk_foo
# CHECK-OUTPUT-NOT: __AArch64AbsLongThunk_{{.*}}

.global _start
.type _start, %function
_start:
# CHECK-INPUT-LABEL: <_start>:
# CHECK-OUTPUT-LABEL: <_start>:
bl __AArch64AbsLongThunk_foo
# CHECK-INPUT-NEXT: bl {{.*}} <__AArch64AbsLongThunk_foo>
# CHECK-OUTPUT-NEXT: bl {{.*}} <foo>
bl __AArch64AbsLongThunk_far_function
bl __AArch64AbsLongThunk_near_function
# CHECK-INPUT-NEXT: bl {{.*}} <__AArch64AbsLongThunk_far_function>
# CHECK-INPUT-NEXT: bl {{.*}} <__AArch64AbsLongThunk_near_function>
# CHECK-OUTPUT-NEXT: bl {{.*}} <far_function>
# CHECK-OUTPUT-NEXT: bl {{.*}} <near_function>
ret
.size _start, .-_start
3 changes: 3 additions & 0 deletions bolt/unittests/Core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ set(LLVM_LINK_COMPONENTS
add_bolt_unittest(CoreTests
BinaryContext.cpp
MCPlusBuilder.cpp
MemoryMaps.cpp
DynoStats.cpp

DISABLE_LLVM_LINK_LLVM_DYLIB
Expand All @@ -17,6 +18,8 @@ target_link_libraries(CoreTests
PRIVATE
LLVMBOLTCore
LLVMBOLTRewrite
LLVMBOLTProfile
LLVMTestingSupport
)

foreach (tgt ${BOLT_TARGETS_TO_BUILD})
Expand Down
142 changes: 142 additions & 0 deletions bolt/unittests/Core/MemoryMaps.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//===- bolt/unittest/Core/MemoryMaps.cpp ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "bolt/Core/BinaryContext.h"
#include "bolt/Profile/DataAggregator.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/DebugInfo/DWARF/DWARFContext.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"

using namespace llvm;
using namespace llvm::object;
using namespace llvm::ELF;
using namespace bolt;

namespace opts {
extern cl::opt<std::string> ReadPerfEvents;
} // namespace opts

namespace {

/// Perform checks on memory map events normally captured in perf. Tests use
/// the 'opts::ReadPerfEvents' flag to emulate these events, passing a custom
/// 'perf script' output to DataAggregator.
struct MemoryMapsTester : public testing::TestWithParam<Triple::ArchType> {
void SetUp() override {
initalizeLLVM();
prepareElf();
initializeBOLT();
}

protected:
void initalizeLLVM() {
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
llvm::InitializeAllDisassemblers();
llvm::InitializeAllTargets();
llvm::InitializeAllAsmPrinters();
}

void prepareElf() {
memcpy(ElfBuf, "\177ELF", 4);
ELF64LE::Ehdr *EHdr = reinterpret_cast<typename ELF64LE::Ehdr *>(ElfBuf);
EHdr->e_ident[llvm::ELF::EI_CLASS] = llvm::ELF::ELFCLASS64;
EHdr->e_ident[llvm::ELF::EI_DATA] = llvm::ELF::ELFDATA2LSB;
EHdr->e_machine = GetParam() == Triple::aarch64 ? EM_AARCH64 : EM_X86_64;
MemoryBufferRef Source(StringRef(ElfBuf, sizeof(ElfBuf)), "ELF");
ObjFile = cantFail(ObjectFile::createObjectFile(Source));
}

void initializeBOLT() {
Relocation::Arch = ObjFile->makeTriple().getArch();
BC = cantFail(BinaryContext::createBinaryContext(
ObjFile->makeTriple(), ObjFile->getFileName(), nullptr, true,
DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()}));
ASSERT_FALSE(!BC);
}

char ElfBuf[sizeof(typename ELF64LE::Ehdr)] = {};
std::unique_ptr<ObjectFile> ObjFile;
std::unique_ptr<BinaryContext> BC;
};
} // namespace

#ifdef X86_AVAILABLE

INSTANTIATE_TEST_SUITE_P(X86, MemoryMapsTester,
::testing::Values(Triple::x86_64));

#endif

#ifdef AARCH64_AVAILABLE

INSTANTIATE_TEST_SUITE_P(AArch64, MemoryMapsTester,
::testing::Values(Triple::aarch64));

#endif

/// Check that the correct mmap size is computed when we have multiple text
/// segment mappings.
TEST_P(MemoryMapsTester, ParseMultipleSegments) {
const int Pid = 1234;
StringRef Filename = "BINARY";
opts::ReadPerfEvents = formatv(
"name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
"[0xabc0000000(0x1000000) @ 0x11c0000 103:01 1573523 0]: r-xp {1}\n"
"name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
"[0xabc2000000(0x8000000) @ 0x31d0000 103:01 1573523 0]: r-xp {1}\n",
Pid, Filename);

BC->SegmentMapInfo[0x11da000] =
SegmentInfo{0x11da000, 0x10da000, 0x11ca000, 0x10da000, 0x10000, true};
BC->SegmentMapInfo[0x31d0000] =
SegmentInfo{0x31d0000, 0x51ac82c, 0x31d0000, 0x3000000, 0x200000, true};

DataAggregator DA("");
BC->setFilename(Filename);
Error Err = DA.preprocessProfile(*BC);

// Ignore errors from perf2bolt when parsing memory events later on.
ASSERT_THAT_ERROR(std::move(Err), Succeeded());

auto &BinaryMMapInfo = DA.getBinaryMMapInfo();
auto El = BinaryMMapInfo.find(Pid);
// Check that memory mapping is present and has the expected size.
ASSERT_NE(El, BinaryMMapInfo.end());
ASSERT_EQ(El->second.Size, static_cast<uint64_t>(0xb1d0000));
}

/// Check that DataAggregator aborts when pre-processing an input binary
/// with multiple text segments that have different base addresses.
TEST_P(MemoryMapsTester, MultipleSegmentsMismatchedBaseAddress) {
const int Pid = 1234;
StringRef Filename = "BINARY";
opts::ReadPerfEvents = formatv(
"name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
"[0xabc0000000(0x1000000) @ 0x11c0000 103:01 1573523 0]: r-xp {1}\n"
"name 0 [000] 0.000000: PERF_RECORD_MMAP2 {0}/{0}: "
"[0xabc2000000(0x8000000) @ 0x31d0000 103:01 1573523 0]: r-xp {1}\n",
Pid, Filename);

BC->SegmentMapInfo[0x11da000] =
SegmentInfo{0x11da000, 0x10da000, 0x11ca000, 0x10da000, 0x10000, true};
// Using '0x31d0fff' FileOffset which triggers a different base address
// for this second text segment.
BC->SegmentMapInfo[0x31d0000] =
SegmentInfo{0x31d0000, 0x51ac82c, 0x31d0fff, 0x3000000, 0x200000, true};

DataAggregator DA("");
BC->setFilename(Filename);
ASSERT_DEBUG_DEATH(
{ Error Err = DA.preprocessProfile(*BC); },
"Base address on multiple segment mappings should match");
}
29 changes: 26 additions & 3 deletions clang-tools-extra/clang-reorder-fields/ReorderFieldsAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,28 @@ findMembersUsedInInitExpr(const CXXCtorInitializer *Initializer,
return Results;
}

/// Returns the full source range for the field declaration up to (not
/// including) the trailing semicolumn, including potential macro invocations,
/// e.g. `int a GUARDED_BY(mu);`.
static SourceRange getFullFieldSourceRange(const FieldDecl &Field,
const ASTContext &Context) {
SourceRange Range = Field.getSourceRange();
SourceLocation End = Range.getEnd();
const SourceManager &SM = Context.getSourceManager();
const LangOptions &LangOpts = Context.getLangOpts();
while (true) {
std::optional<Token> CurrentToken = Lexer::findNextToken(End, SM, LangOpts);

if (!CurrentToken || CurrentToken->is(tok::semi))
break;

if (CurrentToken->is(tok::eof))
return Range; // Something is wrong, return the original range.
End = CurrentToken->getLastLoc();
}
return SourceRange(Range.getBegin(), End);
}

/// Reorders fields in the definition of a struct/class.
///
/// At the moment reordering of fields with
Expand Down Expand Up @@ -145,9 +167,10 @@ static bool reorderFieldsInDefinition(
const auto FieldIndex = Field->getFieldIndex();
if (FieldIndex == NewFieldsOrder[FieldIndex])
continue;
addReplacement(Field->getSourceRange(),
Fields[NewFieldsOrder[FieldIndex]]->getSourceRange(),
Context, Replacements);
addReplacement(
getFullFieldSourceRange(*Field, Context),
getFullFieldSourceRange(*Fields[NewFieldsOrder[FieldIndex]], Context),
Context, Replacements);
}
return true;
}
Expand Down
221 changes: 221 additions & 0 deletions clang-tools-extra/clang-tidy/bugprone/BranchCloneCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,212 @@ void BranchCloneCheck::registerMatchers(MatchFinder *Finder) {
this);
Finder->addMatcher(switchStmt().bind("switch"), this);
Finder->addMatcher(conditionalOperator().bind("condOp"), this);
Finder->addMatcher(
ifStmt((hasThen(hasDescendant(ifStmt())))).bind("ifWithDescendantIf"),
this);
}

/// Determines whether two statement trees are identical regarding
/// operators and symbols.
///
/// Exceptions: expressions containing macros or functions with possible side
/// effects are never considered identical.
/// Limitations: (t + u) and (u + t) are not considered identical.
/// t*(u + t) and t*u + t*t are not considered identical.
///
static bool isIdenticalStmt(const ASTContext &Ctx, const Stmt *Stmt1,
const Stmt *Stmt2, bool IgnoreSideEffects) {

if (!Stmt1 || !Stmt2)
return !Stmt1 && !Stmt2;

// If Stmt1 & Stmt2 are of different class then they are not
// identical statements.
if (Stmt1->getStmtClass() != Stmt2->getStmtClass())
return false;

const auto *Expr1 = dyn_cast<Expr>(Stmt1);
const auto *Expr2 = dyn_cast<Expr>(Stmt2);

if (Expr1 && Expr2) {
// If Stmt1 has side effects then don't warn even if expressions
// are identical.
if (!IgnoreSideEffects && Expr1->HasSideEffects(Ctx) &&
Expr2->HasSideEffects(Ctx))
return false;
// If either expression comes from a macro then don't warn even if
// the expressions are identical.
if ((Expr1->getExprLoc().isMacroID()) || (Expr2->getExprLoc().isMacroID()))
return false;

// If all children of two expressions are identical, return true.
Expr::const_child_iterator I1 = Expr1->child_begin();
Expr::const_child_iterator I2 = Expr2->child_begin();
while (I1 != Expr1->child_end() && I2 != Expr2->child_end()) {
if (!isIdenticalStmt(Ctx, *I1, *I2, IgnoreSideEffects))
return false;
++I1;
++I2;
}
// If there are different number of children in the statements, return
// false.
if (I1 != Expr1->child_end())
return false;
if (I2 != Expr2->child_end())
return false;
}

switch (Stmt1->getStmtClass()) {
default:
return false;
case Stmt::CallExprClass:
case Stmt::ArraySubscriptExprClass:
case Stmt::ArraySectionExprClass:
case Stmt::OMPArrayShapingExprClass:
case Stmt::OMPIteratorExprClass:
case Stmt::ImplicitCastExprClass:
case Stmt::ParenExprClass:
case Stmt::BreakStmtClass:
case Stmt::ContinueStmtClass:
case Stmt::NullStmtClass:
return true;
case Stmt::CStyleCastExprClass: {
const auto *CastExpr1 = cast<CStyleCastExpr>(Stmt1);
const auto *CastExpr2 = cast<CStyleCastExpr>(Stmt2);

return CastExpr1->getTypeAsWritten() == CastExpr2->getTypeAsWritten();
}
case Stmt::ReturnStmtClass: {
const auto *ReturnStmt1 = cast<ReturnStmt>(Stmt1);
const auto *ReturnStmt2 = cast<ReturnStmt>(Stmt2);

return isIdenticalStmt(Ctx, ReturnStmt1->getRetValue(),
ReturnStmt2->getRetValue(), IgnoreSideEffects);
}
case Stmt::ForStmtClass: {
const auto *ForStmt1 = cast<ForStmt>(Stmt1);
const auto *ForStmt2 = cast<ForStmt>(Stmt2);

if (!isIdenticalStmt(Ctx, ForStmt1->getInit(), ForStmt2->getInit(),
IgnoreSideEffects))
return false;
if (!isIdenticalStmt(Ctx, ForStmt1->getCond(), ForStmt2->getCond(),
IgnoreSideEffects))
return false;
if (!isIdenticalStmt(Ctx, ForStmt1->getInc(), ForStmt2->getInc(),
IgnoreSideEffects))
return false;
if (!isIdenticalStmt(Ctx, ForStmt1->getBody(), ForStmt2->getBody(),
IgnoreSideEffects))
return false;
return true;
}
case Stmt::DoStmtClass: {
const auto *DStmt1 = cast<DoStmt>(Stmt1);
const auto *DStmt2 = cast<DoStmt>(Stmt2);

if (!isIdenticalStmt(Ctx, DStmt1->getCond(), DStmt2->getCond(),
IgnoreSideEffects))
return false;
if (!isIdenticalStmt(Ctx, DStmt1->getBody(), DStmt2->getBody(),
IgnoreSideEffects))
return false;
return true;
}
case Stmt::WhileStmtClass: {
const auto *WStmt1 = cast<WhileStmt>(Stmt1);
const auto *WStmt2 = cast<WhileStmt>(Stmt2);

if (!isIdenticalStmt(Ctx, WStmt1->getCond(), WStmt2->getCond(),
IgnoreSideEffects))
return false;
if (!isIdenticalStmt(Ctx, WStmt1->getBody(), WStmt2->getBody(),
IgnoreSideEffects))
return false;
return true;
}
case Stmt::IfStmtClass: {
const auto *IStmt1 = cast<IfStmt>(Stmt1);
const auto *IStmt2 = cast<IfStmt>(Stmt2);

if (!isIdenticalStmt(Ctx, IStmt1->getCond(), IStmt2->getCond(),
IgnoreSideEffects))
return false;
if (!isIdenticalStmt(Ctx, IStmt1->getThen(), IStmt2->getThen(),
IgnoreSideEffects))
return false;
if (!isIdenticalStmt(Ctx, IStmt1->getElse(), IStmt2->getElse(),
IgnoreSideEffects))
return false;
return true;
}
case Stmt::CompoundStmtClass: {
const auto *CompStmt1 = cast<CompoundStmt>(Stmt1);
const auto *CompStmt2 = cast<CompoundStmt>(Stmt2);

if (CompStmt1->size() != CompStmt2->size())
return false;

if (!llvm::all_of(llvm::zip(CompStmt1->body(), CompStmt2->body()),
[&Ctx, IgnoreSideEffects](
std::tuple<const Stmt *, const Stmt *> stmtPair) {
const Stmt *stmt0 = std::get<0>(stmtPair);
const Stmt *stmt1 = std::get<1>(stmtPair);
return isIdenticalStmt(Ctx, stmt0, stmt1,
IgnoreSideEffects);
})) {
return false;
}

return true;
}
case Stmt::CompoundAssignOperatorClass:
case Stmt::BinaryOperatorClass: {
const auto *BinOp1 = cast<BinaryOperator>(Stmt1);
const auto *BinOp2 = cast<BinaryOperator>(Stmt2);
return BinOp1->getOpcode() == BinOp2->getOpcode();
}
case Stmt::CharacterLiteralClass: {
const auto *CharLit1 = cast<CharacterLiteral>(Stmt1);
const auto *CharLit2 = cast<CharacterLiteral>(Stmt2);
return CharLit1->getValue() == CharLit2->getValue();
}
case Stmt::DeclRefExprClass: {
const auto *DeclRef1 = cast<DeclRefExpr>(Stmt1);
const auto *DeclRef2 = cast<DeclRefExpr>(Stmt2);
return DeclRef1->getDecl() == DeclRef2->getDecl();
}
case Stmt::IntegerLiteralClass: {
const auto *IntLit1 = cast<IntegerLiteral>(Stmt1);
const auto *IntLit2 = cast<IntegerLiteral>(Stmt2);

llvm::APInt I1 = IntLit1->getValue();
llvm::APInt I2 = IntLit2->getValue();
if (I1.getBitWidth() != I2.getBitWidth())
return false;
return I1 == I2;
}
case Stmt::FloatingLiteralClass: {
const auto *FloatLit1 = cast<FloatingLiteral>(Stmt1);
const auto *FloatLit2 = cast<FloatingLiteral>(Stmt2);
return FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue());
}
case Stmt::StringLiteralClass: {
const auto *StringLit1 = cast<StringLiteral>(Stmt1);
const auto *StringLit2 = cast<StringLiteral>(Stmt2);
return StringLit1->getBytes() == StringLit2->getBytes();
}
case Stmt::MemberExprClass: {
const auto *MemberStmt1 = cast<MemberExpr>(Stmt1);
const auto *MemberStmt2 = cast<MemberExpr>(Stmt2);
return MemberStmt1->getMemberDecl() == MemberStmt2->getMemberDecl();
}
case Stmt::UnaryOperatorClass: {
const auto *UnaryOp1 = cast<UnaryOperator>(Stmt1);
const auto *UnaryOp2 = cast<UnaryOperator>(Stmt2);
return UnaryOp1->getOpcode() == UnaryOp2->getOpcode();
}
}
}

void BranchCloneCheck::check(const MatchFinder::MatchResult &Result) {
Expand Down Expand Up @@ -269,6 +475,21 @@ void BranchCloneCheck::check(const MatchFinder::MatchResult &Result) {
return;
}

if (const auto *IS = Result.Nodes.getNodeAs<IfStmt>("ifWithDescendantIf")) {
const Stmt *Then = IS->getThen();
auto CS = dyn_cast<CompoundStmt>(Then);
if (CS && (!CS->body_empty())) {
const auto *InnerIf = dyn_cast<IfStmt>(*CS->body_begin());
if (InnerIf && isIdenticalStmt(Context, IS->getCond(), InnerIf->getCond(),
/*IgnoreSideEffects=*/false)) {
diag(IS->getBeginLoc(), "if with identical inner if statement");
diag(InnerIf->getBeginLoc(), "inner if starts here",
DiagnosticIDs::Note);
}
}
return;
}

llvm_unreachable("No if statement and no switch statement.");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "ReturnConstRefFromParameterCheck.h"
#include "clang/AST/Attrs.inc"
#include "clang/AST/Expr.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/ASTMatchers/ASTMatchers.h"
Expand All @@ -15,17 +16,28 @@ using namespace clang::ast_matchers;

namespace clang::tidy::bugprone {

namespace {

AST_MATCHER(ParmVarDecl, hasLifetimeBoundAttr) {
return Node.hasAttr<LifetimeBoundAttr>();
}

} // namespace

void ReturnConstRefFromParameterCheck::registerMatchers(MatchFinder *Finder) {
const auto DRef = ignoringParens(
declRefExpr(
to(parmVarDecl(hasType(hasCanonicalType(
qualType(lValueReferenceType(pointee(
qualType(isConstQualified()))))
.bind("type"))))
.bind("type"))),
hasDeclContext(functionDecl().bind("owner")),
unless(hasLifetimeBoundAttr()))
.bind("param")))
.bind("dref"));
const auto Func =
functionDecl(hasReturnTypeLoc(loc(
functionDecl(equalsBoundNode("owner"),
hasReturnTypeLoc(loc(
qualType(hasCanonicalType(equalsBoundNode("type"))))))
.bind("func");

Expand Down
70 changes: 54 additions & 16 deletions clang-tools-extra/clang-tidy/misc/RedundantExpressionCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -855,9 +855,6 @@ static bool areExprsMacroAndNonMacro(const Expr *&LhsExpr,
} // namespace

void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
const auto AnyLiteralExpr = ignoringParenImpCasts(
anyOf(cxxBoolLiteral(), characterLiteral(), integerLiteral()));

const auto BannedIntegerLiteral =
integerLiteral(expandedByMacro(KnownBannedMacroNames));
const auto IsInUnevaluatedContext = expr(anyOf(
Expand All @@ -866,19 +863,16 @@ void RedundantExpressionCheck::registerMatchers(MatchFinder *Finder) {
// Binary with equivalent operands, like (X != 2 && X != 2).
Finder->addMatcher(
traverse(TK_AsIs,
binaryOperator(
anyOf(isComparisonOperator(),
hasAnyOperatorName("-", "/", "%", "|", "&", "^", "&&",
"||", "=")),
operandsAreEquivalent(),
// Filter noisy false positives.
unless(isInTemplateInstantiation()),
unless(binaryOperatorIsInMacro()),
unless(hasType(realFloatingPointType())),
unless(hasEitherOperand(hasType(realFloatingPointType()))),
unless(hasLHS(AnyLiteralExpr)),
unless(hasDescendant(BannedIntegerLiteral)),
unless(IsInUnevaluatedContext))
binaryOperator(anyOf(isComparisonOperator(),
hasAnyOperatorName("-", "/", "%", "|", "&",
"^", "&&", "||", "=")),
operandsAreEquivalent(),
// Filter noisy false positives.
unless(isInTemplateInstantiation()),
unless(binaryOperatorIsInMacro()),
unless(hasAncestor(arraySubscriptExpr())),
unless(hasDescendant(BannedIntegerLiteral)),
unless(IsInUnevaluatedContext))
.bind("binary")),
this);

Expand Down Expand Up @@ -1238,6 +1232,50 @@ void RedundantExpressionCheck::check(const MatchFinder::MatchResult &Result) {
if (const auto *BinOp = Result.Nodes.getNodeAs<BinaryOperator>("binary")) {
// If the expression's constants are macros, check whether they are
// intentional.

//
// Special case for floating-point representation.
//
// If expressions on both sides of comparison operator are of type float,
// then for some comparison operators no warning shall be
// reported even if the expressions are identical from a symbolic point of
// view. Comparison between expressions, declared variables and literals
// are treated differently.
//
// != and == between float literals that have the same value should NOT
// warn. < > between float literals that have the same value SHOULD warn.
//
// != and == between the same float declaration should NOT warn.
// < > between the same float declaration SHOULD warn.
//
// != and == between eq. expressions that evaluates into float
// should NOT warn.
// < > between eq. expressions that evaluates into float
// should NOT warn.
//
const Expr *LHS = BinOp->getLHS()->IgnoreParenImpCasts();
const Expr *RHS = BinOp->getRHS()->IgnoreParenImpCasts();
const BinaryOperator::Opcode Op = BinOp->getOpcode();
const bool OpEqualEQorNE = ((Op == BO_EQ) || (Op == BO_NE));

const auto *DeclRef1 = dyn_cast<DeclRefExpr>(LHS);
const auto *DeclRef2 = dyn_cast<DeclRefExpr>(RHS);
const auto *FloatLit1 = dyn_cast<FloatingLiteral>(LHS);
const auto *FloatLit2 = dyn_cast<FloatingLiteral>(RHS);

if (DeclRef1 && DeclRef2 &&
DeclRef1->getType()->hasFloatingRepresentation() &&
DeclRef2->getType()->hasFloatingRepresentation() &&
(DeclRef1->getDecl() == DeclRef2->getDecl()) && OpEqualEQorNE) {
return;
}

if (FloatLit1 && FloatLit2 &&
FloatLit1->getValue().bitwiseIsEqual(FloatLit2->getValue()) &&
OpEqualEQorNE) {
return;
}

if (areSidesBinaryConstExpressions(BinOp, Result.Context)) {
const Expr *LhsConst = nullptr, *RhsConst = nullptr;
BinaryOperatorKind MainOpcode{}, SideOpcode{};
Expand Down
30 changes: 27 additions & 3 deletions clang-tools-extra/clang-tidy/misc/UseInternalLinkageCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Basic/Specifiers.h"
#include "clang/Lex/Token.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"

using namespace clang::ast_matchers;

Expand Down Expand Up @@ -78,6 +80,22 @@ AST_POLYMORPHIC_MATCHER(isExternStorageClass,
return Node.getStorageClass() == SC_Extern;
}

AST_MATCHER(FunctionDecl, isAllocationOrDeallocationOverloadedFunction) {
// [basic.stc.dynamic.allocation]
// An allocation function that is not a class member function shall belong to
// the global scope and not have a name with internal linkage.
// [basic.stc.dynamic.deallocation]
// A deallocation function that is not a class member function shall belong to
// the global scope and not have a name with internal linkage.
static const llvm::DenseSet<OverloadedOperatorKind> OverloadedOperators{
OverloadedOperatorKind::OO_New,
OverloadedOperatorKind::OO_Array_New,
OverloadedOperatorKind::OO_Delete,
OverloadedOperatorKind::OO_Array_Delete,
};
return OverloadedOperators.contains(Node.getOverloadedOperator());
}

} // namespace

UseInternalLinkageCheck::UseInternalLinkageCheck(StringRef Name,
Expand All @@ -100,10 +118,16 @@ void UseInternalLinkageCheck::registerMatchers(MatchFinder *Finder) {
isExternStorageClass(), isExternC(),
// 3. template
isExplicitTemplateSpecialization(),
// 4. friend
hasAncestor(friendDecl()))));
hasAncestor(decl(anyOf(
// 4. friend
friendDecl(),
// 5. module export decl
exportDecl()))))));
Finder->addMatcher(
functionDecl(Common, hasBody(), unless(cxxMethodDecl()), unless(isMain()))
functionDecl(Common, hasBody(),
unless(anyOf(cxxMethodDecl(),
isAllocationOrDeallocationOverloadedFunction(),
isMain())))
.bind("fn"),
this);
Finder->addMatcher(varDecl(Common, hasGlobalStorage()).bind("var"), this);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,10 @@ namespace clang::tidy::readability {
/// a call to `empty()`.
///
/// The emptiness of a container should be checked using the `empty()` method
/// instead of the `size()` method. It is not guaranteed that `size()` is a
/// constant-time function, and it is generally more efficient and also shows
/// clearer intent to use `empty()`. Furthermore some containers may implement
/// the `empty()` method but not implement the `size()` method. Using `empty()`
/// whenever possible makes it easier to switch to another container in the
/// future.
/// instead of the `size()` method. It shows clearer intent to use `empty()`.
/// Furthermore some containers may implement the `empty()` method but not
/// implement the `size()` method. Using `empty()` whenever possible makes it
/// easier to switch to another container in the future.
class ContainerSizeEmptyCheck : public ClangTidyCheck {
public:
ContainerSizeEmptyCheck(StringRef Name, ClangTidyContext *Context);
Expand Down
22 changes: 4 additions & 18 deletions clang-tools-extra/clangd/XRefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,31 +121,17 @@ void logIfOverflow(const SymbolLocation &Loc) {

// Convert a SymbolLocation to LSP's Location.
// TUPath is used to resolve the path of URI.
// FIXME: figure out a good home for it, and share the implementation with
// FindSymbols.
std::optional<Location> toLSPLocation(const SymbolLocation &Loc,
llvm::StringRef TUPath) {
if (!Loc)
return std::nullopt;
auto Uri = URI::parse(Loc.FileURI);
if (!Uri) {
elog("Could not parse URI {0}: {1}", Loc.FileURI, Uri.takeError());
auto LSPLoc = indexToLSPLocation(Loc, TUPath);
if (!LSPLoc) {
elog("{0}", LSPLoc.takeError());
return std::nullopt;
}
auto U = URIForFile::fromURI(*Uri, TUPath);
if (!U) {
elog("Could not resolve URI {0}: {1}", Loc.FileURI, U.takeError());
return std::nullopt;
}

Location LSPLoc;
LSPLoc.uri = std::move(*U);
LSPLoc.range.start.line = Loc.Start.line();
LSPLoc.range.start.character = Loc.Start.column();
LSPLoc.range.end.line = Loc.End.line();
LSPLoc.range.end.character = Loc.End.column();
logIfOverflow(Loc);
return LSPLoc;
return *LSPLoc;
}

SymbolLocation toIndexLocation(const Location &Loc, std::string &URIStorage) {
Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/clangd/index/BackgroundRebuild.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//===-- BackgroundRebuild.cpp - when to rebuild thei background index -----===//
//===-- BackgroundRebuild.cpp - when to rebuild the background index ------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand Down
17 changes: 15 additions & 2 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ Changes in existing checks
<clang-tidy/checks/altera/id-dependent-backward-branch>` check by fixing
crashes from invalid code.

- Improved :doc:`bugprone-branch-clone
<clang-tidy/checks/bugprone/branch-clone>` check to improve detection of
branch clones by now detecting duplicate inner and outer if statements.

- Improved :doc:`bugprone-casting-through-void
<clang-tidy/checks/bugprone/casting-through-void>` check to suggest replacing
the offending code with ``reinterpret_cast``, to more clearly express intent.
Expand All @@ -179,7 +183,9 @@ Changes in existing checks
- Improved :doc:`bugprone-return-const-ref-from-parameter
<clang-tidy/checks/bugprone/return-const-ref-from-parameter>` check to
diagnose potential dangling references when returning a ``const &`` parameter
by using the conditional operator ``cond ? var1 : var2``.
by using the conditional operator ``cond ? var1 : var2`` and no longer giving
false positives for functions which contain lambda and ignore parameters
with ``[[clang::lifetimebound]]`` attribute.

- Improved :doc:`bugprone-sizeof-expression
<clang-tidy/checks/bugprone/sizeof-expression>` check to find suspicious
Expand Down Expand Up @@ -230,14 +236,21 @@ Changes in existing checks
<clang-tidy/checks/misc/definitions-in-headers>` check by rewording the
diagnostic note that suggests adding ``inline``.

- Improved :doc:`misc-redundant-expression
<clang-tidy/checks/misc/redundant-expression>` check by extending the
checker to detect floating point and integer literals in redundant
expressions.

- Improved :doc:`misc-unconventional-assign-operator
<clang-tidy/checks/misc/unconventional-assign-operator>` check to avoid
false positive for C++23 deducing this.

- Improved :doc:`misc-use-internal-linkage
<clang-tidy/checks/misc/use-internal-linkage>` check to insert ``static``
keyword before type qualifiers such as ``const`` and ``volatile`` and fix
false positives for function declaration without body.
false positives for function declaration without body and fix false positives
for C++20 export declarations and fix false positives for global scoped
overloaded ``operator new`` and ``operator delete``.

- Improved :doc:`modernize-avoid-c-arrays
<clang-tidy/checks/modernize/avoid-c-arrays>` check to suggest using
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,28 @@ If this is the intended behavior, then there is no reason to use a conditional
statement; otherwise the issue can be solved by fixing the branch that is
handled incorrectly.

The check also detects repeated branches in longer ``if/else if/else`` chains
The check detects repeated branches in longer ``if/else if/else`` chains
where it would be even harder to notice the problem.

The check also detects repeated inner and outer ``if`` statements that may
be a result of a copy-paste error. This check cannot currently detect
identical inner and outer ``if`` statements if code is between the ``if``
conditions. An example is as follows.

.. code-block:: c++

void test_warn_inner_if_1(int x) {
if (x == 1) { // warns, if with identical inner if
if (x == 1) // inner if is here
;
if (x == 1) { // does not warn, cannot detect
int y = x;
if (x == 1)
;
}
}


In ``switch`` statements the check only reports repeated branches when they are
consecutive, because it is relatively common that the ``case:`` labels have
some natural ordering and rearranging them would decrease the readability of
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,6 @@ after the call. When the function returns such a parameter also as constant refe
then the returned reference can be used after the object it refers to has been
destroyed.

This issue can be resolved by declaring an overload of the problematic function
where the ``const &`` parameter is instead declared as ``&&``. The developer has
to ensure that the implementation of that function does not produce a
use-after-free, the exact error that this check is warning against.
Marking such an ``&&`` overload as ``deleted``, will silence the warning as
well. In the case of different ``const &`` parameters being returned depending
on the control flow of the function, an overload where all problematic
``const &`` parameters have been declared as ``&&`` will resolve the issue.

Example
-------

Expand All @@ -38,3 +29,23 @@ Example

const S& s = fn(S{1});
s.v; // use after free


This issue can be resolved by declaring an overload of the problematic function
where the ``const &`` parameter is instead declared as ``&&``. The developer has
to ensure that the implementation of that function does not produce a
use-after-free, the exact error that this check is warning against.
Marking such an ``&&`` overload as ``deleted``, will silence the warning as
well. In the case of different ``const &`` parameters being returned depending
on the control flow of the function, an overload where all problematic
``const &`` parameters have been declared as ``&&`` will resolve the issue.

This issue can also be resolved by adding ``[[clang::lifetimebound]]``. Clang
enable ``-Wdangling`` warning by default which can detect mis-uses of the
annotated function. See `lifetimebound attribute <https://clang.llvm.org/docs/AttributeReference.html#id11>`_
for details.

.. code-block:: c++

const int &f(const int &a [[clang::lifetimebound]]) { return a; } // no warning
const int &v = f(1); // warning: temporary bound to local reference 'v' will be destroyed at the end of the full-expression [-Wdangling]
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,22 @@ Examples:
(p->x == p->x) // always true
(p->x < p->x) // always false
(speed - speed + 1 == 12) // speed - speed is always zero
int b = a | 4 | a // identical expr on both sides
((x=1) | (x=1)) // expression is identical

Floats are handled except in the case that NaNs are checked like so:

.. code-block:: c++

int TestFloat(float F) {
if (F == F) // Identical float values used
return 1;
return 0;
}

int TestFloat(float F) {
// Testing NaN.
if (F != F && F == F) // does not warn
return 1;
return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ Example:
void fn3(); // without function body in all declaration, maybe external linkage
void fn3();

// export declarations
export void fn4() {}
export namespace t { void fn5() {} }
export int v2;

Options
-------

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,10 @@ Checks whether a call to the ``size()``/``length()`` method can be replaced
with a call to ``empty()``.

The emptiness of a container should be checked using the ``empty()`` method
instead of the ``size()``/``length()`` method. It is not guaranteed that
``size()``/``length()`` is a constant-time function, and it is generally more
efficient and also shows clearer intent to use ``empty()``. Furthermore some
containers may implement the ``empty()`` method but not implement the ``size()``
or ``length()`` method. Using ``empty()`` whenever possible makes it easier to
switch to another container in the future.
instead of the ``size()``/``length()`` method. It shows clearer intent to use
``empty()``. Furthermore some containers may implement the ``empty()`` method
but not implement the ``size()`` or ``length()`` method. Using ``empty()``
whenever possible makes it easier to switch to another container in the future.

The check issues warning if a container has ``empty()`` and ``size()`` or
``length()`` methods matching following signatures:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// RUN: clang-reorder-fields -record-name Foo -fields-order y,x %s -- | FileCheck %s

#define GUARDED_BY(x) __attribute__((guarded_by(x)))

class Foo {
int x GUARDED_BY(x); // CHECK: {{^ int y;}}
int y; // CHECK-NEXT: {{^ int x GUARDED_BY\(x\);}}
};

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ struct C {
// CHECK-MESSAGES: :[[@LINE-1]]:38: warning: returning a constant reference parameter
};

const auto Lf1 = [](const T& t) -> const T& { return t; };
// CHECK-MESSAGES: :[[@LINE-1]]:54: warning: returning a constant reference parameter

} // namespace invalid

namespace false_negative_because_dependent_and_not_instantiated {
Expand Down Expand Up @@ -151,6 +154,14 @@ void instantiate(const int &param, const float &paramf, int &mut_param, float &m
itf6(mut_paramf);
}

template<class T>
void f(const T& t) {
const auto get = [&t] -> const T& { return t; };
return T{};
}

const auto Lf1 = [](T& t) -> const T& { return t; };

} // namespace valid

namespace overload {
Expand Down Expand Up @@ -186,3 +197,9 @@ int const &overload_params_difference3(int p1, int const &a, int p2) { return a;
int const &overload_params_difference3(int p1, long &&a, int p2);

} // namespace overload

namespace gh117696 {
namespace use_lifetime_bound_attr {
int const &f(int const &a [[clang::lifetimebound]]) { return a; }
} // namespace use_lifetime_bound_attr
} // namespace gh117696
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,13 @@ void func_with_body() {}
void func_without_body();
void func_without_body();
}

// gh117489 start
namespace std {
using size_t = decltype(sizeof(int));
}
void * operator new(std::size_t) { return nullptr; }
void * operator new[](std::size_t) { return nullptr; }
void operator delete(void*) noexcept {}
void operator delete[](void*) noexcept {}
// gh117489 end
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// RUN: %check_clang_tidy -std=c++20 %s misc-use-internal-linkage %t -- -- -I%S/Inputs/use-internal-linkage

module;

export module test;

export void single_export_fn() {}
export int single_export_var;

export {
void group_export_fn1() {}
void group_export_fn2() {}
int group_export_var1;
int group_export_var2;
}

export namespace aa {
void namespace_export_fn() {}
int namespace_export_var;
} // namespace aa
10 changes: 7 additions & 3 deletions clang/cmake/caches/CrossWinToARMLinux.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,11 @@ endif()
if (NOT DEFINED TOOLCHAIN_SHARED_LIBS)
set(TOOLCHAIN_SHARED_LIBS OFF)
endif()

# Enable usage of the static libunwind and libc++abi libraries.
if (NOT DEFINED TOOLCHAIN_USE_STATIC_LIBS)
set(TOOLCHAIN_USE_STATIC_LIBS ON)
endif()

if (NOT DEFINED LLVM_TARGETS_TO_BUILD)
if ("${TOOLCHAIN_TARGET_TRIPLE}" MATCHES "^(armv|arm32)+")
set(LLVM_TARGETS_TO_BUILD "ARM" CACHE STRING "")
Expand Down Expand Up @@ -206,7 +210,7 @@ set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_USE_COMPILER_RT
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_ENABLE_SHARED ${TOOLCHAIN_SHARED_LIBS} CACHE BOOL "")

set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_USE_LLVM_UNWINDER ON CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_ENABLE_STATIC_UNWINDER ON CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_ENABLE_STATIC_UNWINDER ${TOOLCHAIN_USE_STATIC_LIBS} CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_USE_COMPILER_RT ON CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_ENABLE_NEW_DELETE_DEFINITIONS OFF CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_ENABLE_SHARED ${TOOLCHAIN_SHARED_LIBS} CACHE BOOL "")
Expand All @@ -217,7 +221,7 @@ set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ABI_VERSION
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_CXX_ABI "libcxxabi" CACHE STRING "") #!!!
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS ON CACHE BOOL "")
# Merge libc++ and libc++abi libraries into the single libc++ library file.
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_STATIC_ABI_LIBRARY ON CACHE BOOL "")
set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_STATIC_ABI_LIBRARY ${TOOLCHAIN_USE_STATIC_LIBS} CACHE BOOL "")
# Forcely disable the libc++ benchmarks on Windows build hosts
# (current benchmark test configuration does not support the cross builds there).
if (WIN32)
Expand Down
4 changes: 1 addition & 3 deletions clang/cmake/caches/Fuchsia-stage2.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ set(LLVM_TARGETS_TO_BUILD X86;ARM;AArch64;RISCV CACHE STRING "")

set(PACKAGE_VENDOR Fuchsia CACHE STRING "")

set(_FUCHSIA_ENABLE_PROJECTS "bolt;clang;clang-tools-extra;libc;lld;llvm;polly")
set(_FUCHSIA_ENABLE_PROJECTS "bolt;clang;clang-tools-extra;lld;llvm;polly")
set(LLVM_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi;libunwind" CACHE STRING "")

set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "")
Expand All @@ -25,8 +25,6 @@ set(LLVM_ENABLE_ZLIB ON CACHE BOOL "")
set(LLVM_FORCE_BUILD_RUNTIME ON CACHE BOOL "")
set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "")
set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "")
set(LLVM_LIBC_FULL_BUILD ON CACHE BOOL "")
set(LIBC_HDRGEN_ONLY ON CACHE BOOL "")
set(LLVM_STATIC_LINK_CXX_STDLIB ON CACHE BOOL "")
set(LLVM_USE_RELATIVE_PATHS_IN_FILES ON CACHE BOOL "")
set(LLDB_ENABLE_CURSES OFF CACHE BOOL "")
Expand Down
3 changes: 1 addition & 2 deletions clang/cmake/caches/Fuchsia.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ set(LLVM_TARGETS_TO_BUILD X86;ARM;AArch64;RISCV CACHE STRING "")

set(PACKAGE_VENDOR Fuchsia CACHE STRING "")

set(_FUCHSIA_ENABLE_PROJECTS "bolt;clang;clang-tools-extra;libc;lld;llvm;polly")
set(_FUCHSIA_ENABLE_PROJECTS "bolt;clang;clang-tools-extra;lld;llvm;polly")

set(LLVM_ENABLE_DIA_SDK OFF CACHE BOOL "")
set(LLVM_ENABLE_LIBEDIT OFF CACHE BOOL "")
Expand All @@ -17,7 +17,6 @@ set(LLVM_ENABLE_Z3_SOLVER OFF CACHE BOOL "")
set(LLVM_ENABLE_ZLIB OFF CACHE BOOL "")
set(LLVM_INCLUDE_DOCS OFF CACHE BOOL "")
set(LLVM_INCLUDE_EXAMPLES OFF CACHE BOOL "")
set(LIBC_HDRGEN_ONLY ON CACHE BOOL "")
set(LLVM_USE_RELATIVE_PATHS_IN_FILES ON CACHE BOOL "")
set(LLDB_ENABLE_CURSES OFF CACHE BOOL "")
set(LLDB_ENABLE_LIBEDIT OFF CACHE BOOL "")
Expand Down
2 changes: 1 addition & 1 deletion clang/docs/ClangFormat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ to format C/C++/Java/JavaScript/JSON/Objective-C/Protobuf/C# code.
supported:
CSharp: .cs
Java: .java
JavaScript: .mjs .js .ts
JavaScript: .js .mjs .cjs .ts
Json: .json
Objective-C: .m .mm
Proto: .proto .protodevel
Expand Down
41 changes: 20 additions & 21 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3759,9 +3759,9 @@ the configuration (without a prefix: ``Auto``).
lists.

Important differences:
- No spaces inside the braced list.
- No line break before the closing brace.
- Indentation with the continuation indent, not with the block indent.
* No spaces inside the braced list.
* No line break before the closing brace.
* Indentation with the continuation indent, not with the block indent.

Fundamentally, C++11 braced lists are formatted exactly like function
calls would be formatted in their place. If the braced list follows a name
Expand Down Expand Up @@ -4104,10 +4104,10 @@ the configuration (without a prefix: ``Auto``).
When guessing whether a #include is the "main" include (to assign
category 0, see above), use this regex of allowed suffixes to the header
stem. A partial match is done, so that:
- "" means "arbitrary suffix"
- "$" means "no suffix"
* ``""`` means "arbitrary suffix"
* ``"$"`` means "no suffix"

For example, if configured to "(_test)?$", then a header a.h would be seen
For example, if configured to ``"(_test)?$"``, then a header a.h would be seen
as the "main" include in both a.cc and a_test.cc.

.. _IncludeIsMainSourceRegex:
Expand Down Expand Up @@ -5313,21 +5313,21 @@ the configuration (without a prefix: ``Auto``).

**QualifierOrder** (``List of Strings``) :versionbadge:`clang-format 14` :ref:`¶ <QualifierOrder>`
The order in which the qualifiers appear.
Order is an array that can contain any of the following:
The order is an array that can contain any of the following:

* const
* inline
* static
* friend
* constexpr
* volatile
* restrict
* type
* ``const``
* ``inline``
* ``static``
* ``friend``
* ``constexpr``
* ``volatile``
* ``restrict``
* ``type``


.. note::

It **must** contain ``type``.
It must contain ``type``.

Items to the left of ``type`` will be placed to the left of the type and
aligned in the order supplied. Items to the right of ``type`` will be
Expand Down Expand Up @@ -6645,12 +6645,11 @@ the configuration (without a prefix: ``Auto``).
.. _StatementMacros:

**StatementMacros** (``List of Strings``) :versionbadge:`clang-format 8` :ref:`¶ <StatementMacros>`
A vector of macros that should be interpreted as complete
statements.
A vector of macros that should be interpreted as complete statements.

Typical macros are expressions, and require a semi-colon to be
added; sometimes this is not the case, and this allows to make
clang-format aware of such cases.
Typical macros are expressions and require a semicolon to be added.
Sometimes this is not the case, and this allows to make clang-format aware
of such cases.

For example: Q_UNUSED

Expand Down
12 changes: 10 additions & 2 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -648,7 +648,7 @@ elementwise to the input.
Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±infinity

The integer elementwise intrinsics, including ``__builtin_elementwise_popcount``,
can be called in a ``constexpr`` context.
``__builtin_elementwise_bitreverse``, can be called in a ``constexpr`` context.

============================================== ====================================================================== =========================================
Name Operation Supported element types
Expand Down Expand Up @@ -1989,7 +1989,7 @@ Enumerations with a fixed underlying type
-----------------------------------------
Clang provides support for C++11 enumerations with a fixed underlying type
within Objective-C. For example, one can write an enumeration type as:
within Objective-C and C `prior to C23 <https://open-std.org/JTC1/SC22/WG14/www/docs/n3030.htm>`_. For example, one can write an enumeration type as:
.. code-block:: c++
Expand All @@ -2001,6 +2001,14 @@ value, is ``unsigned char``.
Use ``__has_feature(objc_fixed_enum)`` to determine whether support for fixed
underlying types is available in Objective-C.
Use ``__has_extension(c_fixed_enum)`` to determine whether support for fixed
underlying types is available in C prior to C23. This will also report ``true`` in C23
and later modes as the functionality is available even if it's not an extension in
those modes.
Use ``__has_feature(c_fixed_enum)`` to determine whether support for fixed
underlying types is available in C23 and later.
Interoperability with C++11 lambdas
-----------------------------------
Expand Down
11 changes: 11 additions & 0 deletions clang/docs/LibASTMatchersReference.html
Original file line number Diff line number Diff line change
Expand Up @@ -804,6 +804,17 @@ <h2 id="decl-matchers">Node Matchers</h2>
</pre></td></tr>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('exportDecl0')"><a name="exportDecl0Anchor">exportDecl</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ExportDecl.html">ExportDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="exportDecl0"><pre>Matches any export declaration.

Example matches following declarations.
export void foo();
export { void foo(); }
export namespace { void foo(); }
export int v;
</pre></td></tr>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('fieldDecl0')"><a name="fieldDecl0Anchor">fieldDecl</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1FieldDecl.html">FieldDecl</a>&gt;...</td></tr>
<tr><td colspan="4" class="doc" id="fieldDecl0"><pre>Matches field declarations.

Expand Down
63 changes: 56 additions & 7 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ code bases.
`migrate to Vulkan <https://developer.android.com/guide/topics/renderscript/migrate>`_
or other options.

- Clang now emits distinct type-based alias analysis tags for incompatible
pointers by default, enabling more powerful alias analysis when accessing
pointer types. This change may silently change code behavior for code
containing strict-aliasing violations. The new default behavior can be
disabled using ``-fno-pointer-tbaa``.

C/C++ Language Potentially Breaking Changes
-------------------------------------------

Expand Down Expand Up @@ -256,6 +262,8 @@ C++2c Feature Support
- Added the ``__builtin_is_within_lifetime`` builtin, which supports
`P2641R4 Checking if a union alternative is active <https://wg21.link/p2641r4>`_

- Implemented `P3176R1 The Oxford variadic comma <https://wg21.link/P3176R1>`_

C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Removed the restriction to literal types in constexpr functions in C++23 mode.
Expand Down Expand Up @@ -308,6 +316,9 @@ Resolutions to C++ Defect Reports
by default.
(`CWG2521: User-defined literals and reserved identifiers <https://cplusplus.github.io/CWG/issues/2521.html>`_).

- Fix name lookup for a dependent base class that is the current instantiation.
(`CWG591: When a dependent base class is the current instantiation <https://cplusplus.github.io/CWG/issues/591.html>`_).

C Language Changes
------------------

Expand Down Expand Up @@ -376,7 +387,7 @@ Non-comprehensive list of changes in this release

- The new builtin ``__builtin_counted_by_ref`` was added. In contexts where the
programmer needs access to the ``counted_by`` attribute's field, but it's not
available --- e.g. in macros. For instace, it can be used to automatically
available --- e.g. in macros. For instance, it can be used to automatically
set the counter during allocation in the Linux kernel:

.. code-block:: c
Expand All @@ -402,6 +413,7 @@ Non-comprehensive list of changes in this release
- ``__builtin_reduce_and`` function can now be used in constant expressions.
- ``__builtin_reduce_or`` and ``__builtin_reduce_xor`` functions can now be used in constant expressions.
- ``__builtin_elementwise_popcount`` function can now be used in constant expressions.
- ``__builtin_elementwise_bitreverse`` function can now be used in constant expressions.

New Compiler Flags
------------------
Expand All @@ -413,6 +425,9 @@ New Compiler Flags
existing ``-fno-c++-static-destructors`` flag) skips all static
destructors registration.

- The ``-Warray-compare`` warning has been added to warn about array comparison
on versions older than C++20.

Deprecated Compiler Flags
-------------------------

Expand All @@ -437,7 +452,7 @@ Modified Compiler Flags
libraries remains unchanged.

- The ``-Wnontrivial-memcall`` warning has been added to warn about
passing non-trivially-copyable destrination parameter to ``memcpy``,
passing non-trivially-copyable destination parameter to ``memcpy``,
``memset`` and similar functions for which it is a documented undefined
behavior. It is implied by ``-Wnontrivial-memaccess``

Expand Down Expand Up @@ -624,8 +639,7 @@ Improvements to Clang's diagnostics

- Fixed a false negative ``-Wunused-private-field`` diagnostic when a defaulted comparison operator is defined out of class (#GH116961).

- Clang now supports using alias templates in deduction guides, aligning with the C++ standard,
which treats alias templates as synonyms for their underlying types (#GH54909).
- Clang now diagnoses dangling references for C++20's parenthesized aggregate initialization (#101957).

Improvements to Clang's time-trace
----------------------------------
Expand Down Expand Up @@ -673,7 +687,7 @@ Bug Fixes to C++ Support
- Fixed a failed assertion when checking invalid delete operator declaration. (#GH96191)
- Fix a crash when checking destructor reference with an invalid initializer. (#GH97230)
- Clang now correctly parses potentially declarative nested-name-specifiers in pointer-to-member declarators.
- Fix a crash when checking the initialzier of an object that was initialized
- Fix a crash when checking the initializer of an object that was initialized
with a string literal. (#GH82167)
- Fix a crash when matching template template parameters with templates which have
parameters of different class type. (#GH101394)
Expand Down Expand Up @@ -717,7 +731,7 @@ Bug Fixes to C++ Support
- Fix a crash when using ``source_location`` in the trailing return type of a lambda expression. (#GH67134)
- A follow-up fix was added for (#GH61460), as the previous fix was not entirely correct. (#GH86361), (#GH112352)
- Fixed a crash in the typo correction of an invalid CTAD guide. (#GH107887)
- Fixed a crash when clang tries to subtitute parameter pack while retaining the parameter
- Fixed a crash when clang tries to substitute parameter pack while retaining the parameter
pack. (#GH63819), (#GH107560)
- Fix a crash when a static assert declaration has an invalid close location. (#GH108687)
- Avoided a redundant friend declaration instantiation under a certain ``consteval`` context. (#GH107175)
Expand Down Expand Up @@ -756,10 +770,16 @@ Bug Fixes to C++ Support
- Name independent data members were not correctly initialized from default member initializers. (#GH114069)
- Fixed expression transformation for ``[[assume(...)]]``, allowing using pack indexing expressions within the
assumption if they also occur inside of a dependent lambda. (#GH114787)
- Lambdas now capture function types without considering top-level const qualifiers. (#GH84961)
- Clang now uses valid deduced type locations when diagnosing functions with trailing return type
missing placeholder return type. (#GH78694)
- Fixed a bug where bounds of partially expanded pack indexing expressions were checked too early. (#GH116105)
- Fixed an assertion failure caused by using ``consteval`` in condition in consumed analyses. (#GH117385)
- Fix a crash caused by incorrect argument position in merging deduced template arguments. (#GH113659)
- Fixed an assertion failure caused by mangled names with invalid identifiers. (#GH112205)
- Fixed an incorrect lambda scope of generic lambdas that caused Clang to crash when computing potential lambda
captures at the end of a full expression. (#GH115931)
- Clang no longer rejects deleting a pointer of incomplete enumeration type. (#GH99278)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -771,6 +791,7 @@ Bug Fixes to AST Handling
and ``relatedalso`` comment commands.
- Clang now uses the location of the begin of the member expression for ``CallExpr``
involving deduced ``this``. (#GH116928)
- Fixed printout of AST that uses pack indexing expression. (#GH116486)

Miscellaneous Bug Fixes
^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -925,9 +946,15 @@ and `-mbulk-memory` flags, which correspond to the [Bulk Memory Operations]
and [Non-trapping float-to-int Conversions] language features, which are
[widely implemented in engines].

A new Lime1 target CPU is added, -mcpu=lime1. This CPU follows the definition of
the Lime1 CPU [here], and enables -mmultivalue, -mmutable-globals,
-mcall-indirect-overlong, -msign-ext, -mbulk-memory-opt, -mnontrapping-fptoint,
and -mextended-const.

[Bulk Memory Operations]: https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md
[Non-trapping float-to-int Conversions]: https://github.com/WebAssembly/spec/blob/master/proposals/nontrapping-float-to-int-conversion/Overview.md
[widely implemented in engines]: https://webassembly.org/features/
[here]: https://github.com/WebAssembly/tool-conventions/blob/main/Lime.md#lime1

AVR Support
^^^^^^^^^^^
Expand Down Expand Up @@ -961,6 +988,14 @@ AST Matchers
- Ensure ``hasName`` matches template specializations across inline namespaces,
making `matchesNodeFullSlow` and `matchesNodeFullFast` consistent.

- Improved the performance of the ``getExpansionLocOfMacro`` by tracking already processed macros during recursion.

- Add ``exportDecl`` matcher to match export declaration.

- Ensure ``hasType`` and ``hasDeclaration`` match Objective-C interface declarations.

- Ensure ``pointee`` matches Objective-C pointer types.

clang-format
------------

Expand Down Expand Up @@ -1012,8 +1047,12 @@ Improvements
Moved checkers
^^^^^^^^^^^^^^

- The checker ``alpha.core.IdenticalExpr`` was deleted because it was
duplicated in the clang-tidy checkers ``misc-redundant-expression`` and
``bugprone-branch-clone``.

- The checker ``alpha.security.MallocOverflow`` was deleted because it was
badly implemented and its agressive logic produced too many false positives.
badly implemented and its aggressive logic produced too many false positives.
To detect too large arguments passed to malloc, consider using the checker
``alpha.taint.TaintedAlloc``.

Expand All @@ -1023,6 +1062,16 @@ Moved checkers
original checkers were implemented only using AST matching and make more
sense as a single clang-tidy check.

- The checker ``alpha.unix.Chroot`` was modernized, improved and moved to
``unix.Chroot``. Testing was done on open source projects that use chroot(),
and false issues addressed in the improvements based on real use cases. Open
source projects used for testing include nsjail, lxroot, dive and ruri.
This checker conforms to SEI Cert C recommendation `POS05-C. Limit access to
files by creating a jail
<https://wiki.sei.cmu.edu/confluence/display/c/POS05-C.+Limit+access+to+files+by+creating+a+jail>`_.
Fixes (#GH34697).
(#GH117791) [Documentation](https://clang.llvm.org/docs/analyzer/checkers.html#unix-chroot-c).

.. _release-notes-sanitizers:

Sanitizers
Expand Down
76 changes: 31 additions & 45 deletions clang/docs/analyzer/checkers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1750,6 +1750,37 @@ Critical section handling functions modeled by this checker:
}
}
.. _unix-Chroot:
unix.Chroot (C)
"""""""""""""""
Check improper use of chroot described by SEI Cert C recommendation `POS05-C.
Limit access to files by creating a jail
<https://wiki.sei.cmu.edu/confluence/display/c/POS05-C.+Limit+access+to+files+by+creating+a+jail>`_.
The checker finds usage patterns where ``chdir("/")`` is not called immediately
after a call to ``chroot(path)``.
.. code-block:: c
void f();
void test_bad() {
chroot("/usr/local");
f(); // warn: no call of chdir("/") immediately after chroot
}
void test_bad_path() {
chroot("/usr/local");
chdir("/usr"); // warn: no call of chdir("/") immediately after chroot
f();
}
void test_good() {
chroot("/usr/local");
chdir("/"); // no warning
f();
}
.. _unix-Errno:
unix.Errno (C)
Expand Down Expand Up @@ -2811,36 +2842,6 @@ Check for assignment of a fixed address to a pointer.
p = (int *) 0x10000; // warn
}
.. _alpha-core-IdenticalExpr:
alpha.core.IdenticalExpr (C, C++)
"""""""""""""""""""""""""""""""""
Warn about unintended use of identical expressions in operators.
.. code-block:: cpp
// C
void test() {
int a = 5;
int b = a | 4 | a; // warn: identical expr on both sides
}
// C++
bool f(void);
void test(bool b) {
int i = 10;
if (f()) { // warn: true and false branches are identical
do {
i--;
} while (f());
} else {
do {
i--;
} while (f());
}
}
.. _alpha-core-PointerArithm:
alpha.core.PointerArithm (C)
Expand Down Expand Up @@ -3298,21 +3299,6 @@ SEI CERT checkers which tries to find errors based on their `C coding rules <htt
alpha.unix
^^^^^^^^^^
.. _alpha-unix-Chroot:
alpha.unix.Chroot (C)
"""""""""""""""""""""
Check improper use of chroot.
.. code-block:: c
void f();
void test() {
chroot("/usr/local");
f(); // warn: no call of chdir("/") immediately after chroot
}
.. _alpha-unix-PthreadLock:
alpha.unix.PthreadLock (C)
Expand Down
9 changes: 7 additions & 2 deletions clang/docs/tools/dump_ast_matchers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

import collections
import re
import os

try:
from urllib.request import urlopen
Expand All @@ -18,7 +19,11 @@
CLASS_INDEX_PAGE = None
print("Unable to get %s: %s" % (CLASS_INDEX_PAGE_URL, e))

MATCHERS_FILE = "../../include/clang/ASTMatchers/ASTMatchers.h"
CURRENT_DIR = os.path.dirname(__file__)
MATCHERS_FILE = os.path.join(
CURRENT_DIR, "../../include/clang/ASTMatchers/ASTMatchers.h"
)
HTML_FILE = os.path.join(CURRENT_DIR, "../LibASTMatchersReference.html")

# Each matcher is documented in one row of the form:
# result | name | argA
Expand Down Expand Up @@ -590,7 +595,7 @@ def sort_table(matcher_type, matcher_map):
narrowing_matcher_table = sort_table("NARROWING", narrowing_matchers)
traversal_matcher_table = sort_table("TRAVERSAL", traversal_matchers)

reference = open("../LibASTMatchersReference.html").read()
reference = open(HTML_FILE).read()
reference = re.sub(
r"<!-- START_DECL_MATCHERS.*END_DECL_MATCHERS -->",
node_matcher_table,
Expand Down
3 changes: 2 additions & 1 deletion clang/docs/tools/dump_format_style.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,5 +487,6 @@ class State:

contents = substitute(contents, "FORMAT_STYLE_OPTIONS", options_text)

with open(DOC_FILE, "wb") as output:
output_file_path = sys.argv[1] if len(sys.argv) == 2 else DOC_FILE
with open(output_file_path, "wb") as output:
output.write(contents.encode())
16 changes: 9 additions & 7 deletions clang/include/clang/AST/AttrIterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@
#define LLVM_CLANG_AST_ATTRITERATOR_H

#include "clang/Basic/LLVM.h"
#include "llvm/ADT/ADL.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include <cassert>
#include <cstddef>
#include <iterator>
#include <type_traits>

namespace clang {

Expand Down Expand Up @@ -113,13 +115,13 @@ inline bool hasSpecificAttr(const Container& container) {
specific_attr_end<SpecificAttr>(container);
}
template <typename SpecificAttr, typename Container>
inline SpecificAttr *getSpecificAttr(const Container& container) {
specific_attr_iterator<SpecificAttr, Container> i =
specific_attr_begin<SpecificAttr>(container);
if (i != specific_attr_end<SpecificAttr>(container))
return *i;
else
return nullptr;
inline auto *getSpecificAttr(const Container &container) {
using ValueTy = llvm::detail::ValueOfRange<Container>;
using ValuePointeeTy = std::remove_pointer_t<ValueTy>;
using IterTy = std::conditional_t<std::is_const_v<ValuePointeeTy>,
const SpecificAttr, SpecificAttr>;
auto It = specific_attr_begin<IterTy>(container);
return It != specific_attr_end<IterTy>(container) ? *It : nullptr;
}

} // namespace clang
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -3754,6 +3754,8 @@ class ArrayParameterType : public ConstantArrayType {
static bool classof(const Type *T) {
return T->getTypeClass() == ArrayParameter;
}

QualType getConstantArrayType(const ASTContext &Ctx) const;
};

/// Represents a C array with an unspecified size. For example 'int A[]' has
Expand Down
16 changes: 14 additions & 2 deletions clang/include/clang/ASTMatchers/ASTMatchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -1236,6 +1236,17 @@ AST_MATCHER_P(TemplateArgument, equalsIntegralValue,
extern const internal::VariadicDynCastAllOfMatcher<Stmt,
ObjCAutoreleasePoolStmt> autoreleasePoolStmt;

/// Matches any export declaration.
///
/// Example matches following declarations.
/// \code
/// export void foo();
/// export { void foo(); }
/// export namespace { void foo(); }
/// export int v;
/// \endcode
extern const internal::VariadicDynCastAllOfMatcher<Decl, ExportDecl> exportDecl;

/// Matches any value declaration.
///
/// Example matches A, B, C and F
Expand Down Expand Up @@ -4033,7 +4044,7 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
hasType,
AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, FriendDecl, ValueDecl,
CXXBaseSpecifier),
CXXBaseSpecifier, ObjCInterfaceDecl),
internal::Matcher<Decl>, InnerMatcher, 1) {
QualType QT = internal::getUnderlyingType(Node);
if (!QT.isNull())
Expand Down Expand Up @@ -7434,7 +7445,8 @@ extern const AstTypeMatcher<RValueReferenceType> rValueReferenceType;
AST_TYPELOC_TRAVERSE_MATCHER_DECL(
pointee, getPointee,
AST_POLYMORPHIC_SUPPORTED_TYPES(BlockPointerType, MemberPointerType,
PointerType, ReferenceType));
PointerType, ReferenceType,
ObjCObjectPointerType));

/// Matches typedef types.
///
Expand Down
10 changes: 9 additions & 1 deletion clang/include/clang/ASTMatchers/ASTMatchersInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,9 @@ inline QualType getUnderlyingType(const FriendDecl &Node) {
inline QualType getUnderlyingType(const CXXBaseSpecifier &Node) {
return Node.getType();
}
inline QualType getUnderlyingType(const ObjCInterfaceDecl &Node) {
return Node.getTypeForDecl()->getPointeeType();
}

/// Unifies obtaining a `TypeSourceInfo` from different node types.
template <typename T,
Expand Down Expand Up @@ -1113,6 +1116,11 @@ class HasDeclarationMatcher : public MatcherInterface<T> {
return matchesDecl(Node.getDecl(), Finder, Builder);
}

bool matchesSpecialized(const ObjCInterfaceDecl &Node, ASTMatchFinder *Finder,
BoundNodesTreeBuilder *Builder) const {
return matchesDecl(Node.getCanonicalDecl(), Finder, Builder);
}

/// Extracts the operator new of the new call and returns whether the
/// inner matcher matches on it.
bool matchesSpecialized(const CXXNewExpr &Node,
Expand Down Expand Up @@ -1213,7 +1221,7 @@ using HasDeclarationSupportedTypes =
ElaboratedType, InjectedClassNameType, LabelStmt, AddrLabelExpr,
MemberExpr, QualType, RecordType, TagType,
TemplateSpecializationType, TemplateTypeParmType, TypedefType,
UnresolvedUsingType, ObjCIvarRefExpr>;
UnresolvedUsingType, ObjCIvarRefExpr, ObjCInterfaceDecl>;

/// A Matcher that allows binding the node it matches to an id.
///
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ class Documentation {
// When set, specifies that the attribute is deprecated and can optionally
// specify a replacement attribute.
DocDeprecated Deprecated;

// When set, specifies a label that can be used to reference the documentation.
string Label = "";
}

// Specifies that the attribute is explicitly omitted from the documentation,
Expand Down
12 changes: 4 additions & 8 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -3360,9 +3360,8 @@ def NoSanitizeAddressDocs : Documentation {
// This function has multiple distinct spellings, and so it requires a custom
// heading to be specified. The most common spelling is sufficient.
let Heading = "no_sanitize_address, no_address_safety_analysis";
let Label = "langext-address_sanitizer";
let Content = [{
.. _langext-address_sanitizer:

Use ``__attribute__((no_sanitize_address))`` on a function or a global
variable declaration to specify that address safety instrumentation
(e.g. AddressSanitizer) should not be applied.
Expand All @@ -3372,9 +3371,8 @@ variable declaration to specify that address safety instrumentation
def NoSanitizeThreadDocs : Documentation {
let Category = DocCatFunction;
let Heading = "no_sanitize_thread";
let Label = "langext-thread_sanitizer";
let Content = [{
.. _langext-thread_sanitizer:

Use ``__attribute__((no_sanitize_thread))`` on a function declaration to
specify that checks for data races on plain (non-atomic) memory accesses should
not be inserted by ThreadSanitizer. The function is still instrumented by the
Expand All @@ -3385,9 +3383,8 @@ tool to avoid false positives and provide meaningful stack traces.
def NoSanitizeMemoryDocs : Documentation {
let Category = DocCatFunction;
let Heading = "no_sanitize_memory";
let Label = "langext-memory_sanitizer";
let Content = [{
.. _langext-memory_sanitizer:

Use ``__attribute__((no_sanitize_memory))`` on a function declaration to
specify that checks for uninitialized memory should not be inserted
(e.g. by MemorySanitizer). The function may still be instrumented by the tool
Expand All @@ -3398,9 +3395,8 @@ to avoid false positives in other places.
def CFICanonicalJumpTableDocs : Documentation {
let Category = DocCatFunction;
let Heading = "cfi_canonical_jump_table";
let Label = "langext-cfi_canonical_jump_table";
let Content = [{
.. _langext-cfi_canonical_jump_table:

Use ``__attribute__((cfi_canonical_jump_table))`` on a function declaration to
make the function's CFI jump table canonical. See :ref:`the CFI documentation
<cfi-canonical-jump-tables>` for more details.
Expand Down
14 changes: 13 additions & 1 deletion clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -1270,7 +1270,7 @@ def ElementwiseATan2 : Builtin {

def ElementwiseBitreverse : Builtin {
let Spellings = ["__builtin_elementwise_bitreverse"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

Expand Down Expand Up @@ -4738,6 +4738,12 @@ def GetDeviceSideMangledName : LangBuiltin<"CUDA_LANG"> {
}

// HLSL
def HLSLResourceGetPointer : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_resource_getpointer"];
let Attributes = [NoThrow];
let Prototype = "void(...)";
}

def HLSLAll : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_all"];
let Attributes = [NoThrow, Const];
Expand Down Expand Up @@ -4924,6 +4930,12 @@ def HLSLClip: LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}

def HLSLGroupMemoryBarrierWithGroupSync: LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_group_memory_barrier_with_group_sync"];
let Attributes = [NoThrow, Const];
let Prototype = "void()";
}

// Builtins for XRay.
def XRayCustomEvent : Builtin {
let Spellings = ["__xray_customevent"];
Expand Down
15 changes: 15 additions & 0 deletions clang/include/clang/Basic/BuiltinsAArch64.def
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ TARGET_HEADER_BUILTIN(_InterlockedExchange_rel, "NiNiD*Ni", "nh", INTRIN_H,
TARGET_HEADER_BUILTIN(_InterlockedExchange64_acq, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange64_nf, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange64_rel, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchangePointer_acq, "v*v*D*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchangePointer_nf, "v*v*D*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchangePointer_rel, "v*v*D*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")

TARGET_HEADER_BUILTIN(_InterlockedCompareExchange8_acq, "ccD*cc", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange8_nf, "ccD*cc", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
Expand All @@ -195,6 +198,8 @@ TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_rel, "NiNiD*NiNi", "nh",
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_acq, "LLiLLiD*LLiLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_nf, "LLiLLiD*LLiLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_rel, "LLiLLiD*LLiLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchangePointer_acq, "v*v*D*v*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchangePointer_rel, "v*v*D*v*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")

TARGET_HEADER_BUILTIN(_InterlockedCompareExchange128, "UcLLiD*LLiLLiLLi*", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange128_acq,"UcLLiD*LLiLLiLLi*", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
Expand Down Expand Up @@ -281,6 +286,16 @@ TARGET_HEADER_BUILTIN(__readx18word, "UsUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES,
TARGET_HEADER_BUILTIN(__readx18dword, "UNiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__readx18qword, "ULLiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")

TARGET_HEADER_BUILTIN(__addx18byte, "vUNiUc", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__addx18word, "vUNiUs", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__addx18dword, "vUNiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__addx18qword, "vUNiULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")

TARGET_HEADER_BUILTIN(__incx18byte, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__incx18word, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__incx18dword, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(__incx18qword, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")

TARGET_HEADER_BUILTIN(_CopyDoubleFromInt64, "dSLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_CopyFloatFromInt32, "fSi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_CopyInt32FromFloat, "Sif", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
Expand Down
6 changes: 4 additions & 2 deletions clang/include/clang/Basic/BuiltinsAMDGPU.def
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,8 @@ TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr4_b64_v2i32, "V2iV2i*3", "nc", "gfx950
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr6_b96_v3i32, "V3iV3i*3", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr8_b64_v2i32, "V2iV2i*3", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr16_b64_v4i16, "V4sV4s*3", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr16_b64_v4f16, "V4hV4h*3", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr16_b64_v4bf16, "V4yV4y*3", "nc", "gfx950-insts")

TARGET_BUILTIN(__builtin_amdgcn_ashr_pk_i8_i32, "UsUiUiUi", "nc", "ashr-pk-insts")
TARGET_BUILTIN(__builtin_amdgcn_ashr_pk_u8_i32, "UsUiUiUi", "nc", "ashr-pk-insts")
Expand Down Expand Up @@ -614,8 +616,8 @@ TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk32_bf6_f32, "V6UiV32fUif", "nc
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_bf16, "V6UiV32yUif", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_f16, "V6UiV32hUif", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_scalef32_sr_pk32_fp6_f32, "V6UiV32fUif", "nc", "f16bf16-to-fp6bf6-cvt-scale-insts")
TARGET_BUILTIN(__builtin_amdgcn_bitop3_b32, "iiiiIUc", "nc", "bitop3-insts")
TARGET_BUILTIN(__builtin_amdgcn_bitop3_b16, "ssssIUc", "nc", "bitop3-insts")
TARGET_BUILTIN(__builtin_amdgcn_bitop3_b32, "iiiiIUi", "nc", "bitop3-insts")
TARGET_BUILTIN(__builtin_amdgcn_bitop3_b16, "ssssIUi", "nc", "bitop3-insts")

TARGET_BUILTIN(__builtin_amdgcn_cvt_sr_bf16_f32, "V2yV2yfUiIb", "nc", "f32-to-f16bf16-cvt-sr-insts")
TARGET_BUILTIN(__builtin_amdgcn_cvt_sr_f16_f32, "V2hV2hfUiIb", "nc", "f32-to-f16bf16-cvt-sr-insts")
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/BuiltinsARM.def
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,9 @@ TARGET_HEADER_BUILTIN(_InterlockedExchange_rel, "NiNiD*Ni", "nh", INTRIN_H,
TARGET_HEADER_BUILTIN(_InterlockedExchange64_acq, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange64_nf, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchange64_rel, "LLiLLiD*LLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchangePointer_acq, "v*v*D*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchangePointer_nf, "v*v*D*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedExchangePointer_rel, "v*v*D*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")

TARGET_HEADER_BUILTIN(_InterlockedCompareExchange8_acq, "ccD*cc", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange8_nf, "ccD*cc", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
Expand All @@ -283,6 +286,8 @@ TARGET_HEADER_BUILTIN(_InterlockedCompareExchange_rel, "NiNiD*NiNi", "nh",
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_acq, "LLiLLiD*LLiLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_nf, "LLiLLiD*LLiLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchange64_rel, "LLiLLiD*LLiLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchangePointer_acq, "v*v*D*v*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedCompareExchangePointer_rel, "v*v*D*v*v*","nh", INTRIN_H, ALL_MS_LANGUAGES, "")

TARGET_HEADER_BUILTIN(_InterlockedOr8_acq, "ccD*c", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
TARGET_HEADER_BUILTIN(_InterlockedOr8_nf, "ccD*c", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Defa

CODEGENOPT(RelaxAll , 1, 0) ///< Relax all machine code instructions.
CODEGENOPT(RelaxedAliasing , 1, 0) ///< Set when -fno-strict-aliasing is enabled.
CODEGENOPT(PointerTBAA, 1, 0) ///< Whether or not to use distinct TBAA tags for pointers.
CODEGENOPT(PointerTBAA , 1, 1) ///< Whether or not to use distinct TBAA tags for pointers.
CODEGENOPT(StructPathTBAA , 1, 0) ///< Whether or not to use struct-path TBAA.
CODEGENOPT(NewStructPathTBAA , 1, 0) ///< Whether or not to use enhanced struct-path TBAA.
CODEGENOPT(SaveTempLabels , 1, 0) ///< Save temporary labels.
Expand Down
14 changes: 9 additions & 5 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings",
[CXX11CompatDeprecatedWritableStr]>;
def DeprecatedPragma : DiagGroup<"deprecated-pragma">;
def DeprecatedType : DiagGroup<"deprecated-type">;
def DeprecatedMissingCommaVariadicParam : DiagGroup<"deprecated-missing-comma-variadic-parameter">;
// FIXME: Why is DeprecatedImplementations not in this group?
def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
DeprecatedArrayCompare,
Expand All @@ -235,7 +236,8 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
DeprecatedType,
DeprecatedVolatile,
DeprecatedWritableStr,
DeprecatedRedundantConstexprStaticDef
DeprecatedRedundantConstexprStaticDef,
DeprecatedMissingCommaVariadicParam
]>,
DiagCategory<"Deprecations">;

Expand Down Expand Up @@ -292,11 +294,13 @@ def : DiagGroup<"c++1z-compat-mangling", [CXX17CompatMangling]>;
// Name of this warning in GCC.
def NoexceptType : DiagGroup<"noexcept-type", [CXX17CompatMangling]>;

def VariadicMacroArgumentsOmitted : DiagGroup<"variadic-macro-arguments-omitted">;

// Warnings for C code which is not compatible with previous C standards.
def CPre11Compat : DiagGroup<"pre-c11-compat">;
def CPre11CompatPedantic : DiagGroup<"pre-c11-compat-pedantic",
[CPre11Compat]>;
def CPre23Compat : DiagGroup<"pre-c23-compat">;
def CPre23Compat : DiagGroup<"pre-c23-compat", [VariadicMacroArgumentsOmitted]>;
def CPre23CompatPedantic : DiagGroup<"pre-c23-compat-pedantic",
[CPre23Compat]>;
def : DiagGroup<"pre-c2x-compat", [CPre23Compat]>;
Expand Down Expand Up @@ -904,7 +908,7 @@ def VolatileRegisterVar : DiagGroup<"volatile-register-var">;
def Visibility : DiagGroup<"visibility">;
def ZeroLengthArray : DiagGroup<"zero-length-array">;
def GNUZeroLineDirective : DiagGroup<"gnu-zero-line-directive">;
def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments">;
def GNUZeroVariadicMacroArguments : DiagGroup<"gnu-zero-variadic-macro-arguments", [VariadicMacroArgumentsOmitted]>;
def MisleadingIndentation : DiagGroup<"misleading-indentation">;
def PtrAuthNullPointers : DiagGroup<"ptrauth-null-pointers">;

Expand Down Expand Up @@ -1197,7 +1201,7 @@ def CXX17 : DiagGroup<"c++17-extensions", [CXX17Attrs]>;

// A warning group for warnings about using C++20 features as extensions in
// earlier C++ versions.
def CXX20 : DiagGroup<"c++20-extensions", [CXX20Designator, CXX20Attrs]>;
def CXX20 : DiagGroup<"c++20-extensions", [CXX20Designator, CXX20Attrs, VariadicMacroArgumentsOmitted]>;

// A warning group for warnings about using C++23 features as extensions in
// earlier C++ versions.
Expand All @@ -1224,7 +1228,7 @@ def C11 : DiagGroup<"c11-extensions">;
def C99 : DiagGroup<"c99-extensions", [C99Designator]>;

// A warning group for warnings about using C23 features as extensions.
def C23 : DiagGroup<"c23-extensions">;
def C23 : DiagGroup<"c23-extensions", [VariadicMacroArgumentsOmitted]>;

def : DiagGroup<"c2x-extensions", [C23]>;

Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/Basic/DiagnosticLexKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -486,14 +486,14 @@ def ext_embedded_directive : Extension<
InGroup<DiagGroup<"embedded-directive">>;
def ext_c_missing_varargs_arg : Extension<
"passing no argument for the '...' parameter of a variadic macro is "
"a C23 extension">, InGroup<C23>;
"a C23 extension">, InGroup<VariadicMacroArgumentsOmitted>;
def ext_cxx_missing_varargs_arg : Extension<
"passing no argument for the '...' parameter of a variadic macro is "
"a C++20 extension">, InGroup<CXX20>;
"a C++20 extension">, InGroup<VariadicMacroArgumentsOmitted>;
def warn_c17_compat_missing_varargs_arg : Warning<
"passing no argument for the '...' parameter of a variadic macro is "
"incompatible with C standards before C23">,
InGroup<CPre23Compat>, DefaultIgnore;
InGroup<VariadicMacroArgumentsOmitted>, DefaultIgnore;
def warn_cxx17_compat_missing_varargs_arg : Warning<
"passing no argument for the '...' parameter of a variadic macro is "
"incompatible with C++ standards before C++20">,
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,9 @@ def err_function_scope_depth_exceeded : Error<
"function scope depth exceeded maximum of %0">, DefaultFatal;
def err_missing_comma_before_ellipsis : Error<
"C requires a comma prior to the ellipsis in a variadic function type">;
def warn_deprecated_missing_comma_before_ellipsis : Warning<
"declaration of a variadic function without a comma before '...' is deprecated">,
InGroup<DeprecatedMissingCommaVariadicParam>;
def err_unexpected_typedef_ident : Error<
"unexpected type name %0: expected identifier">;
def warn_cxx98_compat_decltype : Warning<
Expand Down
Loading