diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0f178df1d18f8c46a2b06aa00667e81f3a1be32a..6adae58832e191f107a10f8fc9f4c009082d3b20 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -23,6 +23,7 @@ /llvm/lib/Analysis/ScalarEvolution.cpp @nikic /llvm/lib/Analysis/ValueTracking.cpp @nikic /llvm/lib/IR/ConstantRange.cpp @nikic +/llvm/lib/IR/Core.cpp @nikic /llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @nikic /llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp @nikic /llvm/lib/Transforms/InstCombine/ @nikic @@ -63,8 +64,8 @@ clang/test/AST/Interp/ @tbaederr /mlir/Dialect/*/Transforms/Bufferize.cpp @matthias-springer # Linalg Dialect in MLIR. -/mlir/include/mlir/Dialect/Linalg/* @dcaballe @nicolasvasilache -/mlir/lib/Dialect/Linalg/* @dcaballe @nicolasvasilache +/mlir/include/mlir/Dialect/Linalg/* @dcaballe @nicolasvasilache @rengolin +/mlir/lib/Dialect/Linalg/* @dcaballe @nicolasvasilache @rengolin /mlir/lib/Dialect/Linalg/Transforms/DecomposeLinalgOps.cpp @MaheshRavishankar @nicolasvasilache /mlir/lib/Dialect/Linalg/Transforms/DropUnitDims.cpp @MaheshRavishankar @nicolasvasilache /mlir/lib/Dialect/Linalg/Transforms/ElementwiseOpFusion.cpp @MaheshRavishankar @nicolasvasilache @@ -131,7 +132,7 @@ clang/test/AST/Interp/ @tbaederr /bolt/ @aaupov @maksfb @rafaelauler @ayermolo @dcci # Bazel build system. -/utils/bazel/ @rupprecht +/utils/bazel/ @rupprecht @keith # InstallAPI and TextAPI /llvm/**/TextAPI/ @cyndyishida diff --git a/.github/new-prs-labeler.yml b/.github/new-prs-labeler.yml index d608ea449f1d40c841e2ae356f4a0fa8431d2d48..a57ba28faf160b7b6df2ac5ba8f89e9cb3a54b6e 100644 --- a/.github/new-prs-labeler.yml +++ b/.github/new-prs-labeler.yml @@ -239,7 +239,7 @@ mlir:dlti: - mlir/**/DLTI/** mlir:emitc: - - mlir/**/EmitC/** + - mlir/**/*EmitC*/** - mlir/lib/Target/Cpp/** mlir:func: @@ -306,7 +306,7 @@ mlir:tensor: - mlir/**/Tensor/** mlir:tosa: - - mlir/**/Tosa/** + - mlir/**/*Tosa*/** mlir:ub: - mlir/**/UB/** diff --git a/.github/workflows/issue-release-workflow.yml b/.github/workflows/issue-release-workflow.yml index eb88ec6e43c57409b6656c9b3e21bdc7cf76fede..5027d4f3ea6f10a6b56341386e9b44070e206436 100644 --- a/.github/workflows/issue-release-workflow.yml +++ b/.github/workflows/issue-release-workflow.yml @@ -53,7 +53,7 @@ jobs: - name: Setup Environment run: | - pip install -r ./llvm/utils/git/requirements.txt + pip install --require-hashes -r ./llvm/utils/git/requirements.txt ./llvm/utils/git/github-automation.py --token ${{ github.token }} setup-llvmbot-git - name: Backport Commits diff --git a/.github/workflows/issue-subscriber.yml b/.github/workflows/issue-subscriber.yml index ef6cd0674e8085c19d56b27f428f788066a05b59..ef4fdf44181938dea5d002cd0a63c64120eb7270 100644 --- a/.github/workflows/issue-subscriber.yml +++ b/.github/workflows/issue-subscriber.yml @@ -22,7 +22,7 @@ jobs: - name: Setup Automation Script working-directory: ./llvm/utils/git/ run: | - pip install -r requirements.txt + pip install --require-hashes -r requirements.txt - name: Update watchers working-directory: ./llvm/utils/git/ diff --git a/.github/workflows/libclang-abi-tests.yml b/.github/workflows/libclang-abi-tests.yml index ccfc1e5fb8a742db287f7d1bb9ef60d0974b9dfa..972d21c3bcedf9249d280f1247a5a28693a5e6f5 100644 --- a/.github/workflows/libclang-abi-tests.yml +++ b/.github/workflows/libclang-abi-tests.yml @@ -33,7 +33,6 @@ jobs: ABI_HEADERS: ${{ steps.vars.outputs.ABI_HEADERS }} ABI_LIBS: ${{ steps.vars.outputs.ABI_LIBS }} BASELINE_VERSION_MAJOR: ${{ steps.vars.outputs.BASELINE_VERSION_MAJOR }} - BASELINE_VERSION_MINOR: ${{ steps.vars.outputs.BASELINE_VERSION_MINOR }} LLVM_VERSION_MAJOR: ${{ steps.version.outputs.LLVM_VERSION_MAJOR }} LLVM_VERSION_MINOR: ${{ steps.version.outputs.LLVM_VERSION_MINOR }} LLVM_VERSION_PATCH: ${{ steps.version.outputs.LLVM_VERSION_PATCH }} @@ -51,9 +50,9 @@ jobs: id: vars run: | remote_repo='https://github.com/llvm/llvm-project' - if [ ${{ steps.version.outputs.LLVM_VERSION_MINOR }} -ne 0 ] || [ ${{ steps.version.outputs.LLVM_VERSION_PATCH }} -eq 0 ]; then + if [ ${{ steps.version.outputs.LLVM_VERSION_PATCH }} -eq 0 ]; then major_version=$(( ${{ steps.version.outputs.LLVM_VERSION_MAJOR }} - 1)) - baseline_ref="llvmorg-$major_version.0.0" + baseline_ref="llvmorg-$major_version.1.0" # If there is a minor release, we want to use that as the base line. minor_ref=$(git ls-remote --refs -t "$remote_repo" llvmorg-"$major_version".[1-9].[0-9] | tail -n1 | grep -o 'llvmorg-.\+' || true) @@ -75,7 +74,7 @@ jobs: else { echo "BASELINE_VERSION_MAJOR=${{ steps.version.outputs.LLVM_VERSION_MAJOR }}" - echo "BASELINE_REF=llvmorg-${{ steps.version.outputs.LLVM_VERSION_MAJOR }}.0.0" + echo "BASELINE_REF=llvmorg-${{ steps.version.outputs.LLVM_VERSION_MAJOR }}.1.0" echo "ABI_HEADERS=." echo "ABI_LIBS=libclang.so libclang-cpp.so" } >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/llvm-bugs.yml b/.github/workflows/llvm-bugs.yml index f592dd6ccd90331cf1338b8ce803faefe56da874..c392078fa45251355e0226e42eefdbfef01ee814 100644 --- a/.github/workflows/llvm-bugs.yml +++ b/.github/workflows/llvm-bugs.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest if: github.repository == 'llvm/llvm-project' steps: - - uses: actions/setup-node@v3 + - uses: actions/setup-node@v4 with: node-version: 18 check-latest: true diff --git a/.github/workflows/merged-prs.yml b/.github/workflows/merged-prs.yml index 37fc6c67f000baa4da677313bbe7e316ccaaa14c..e29afd4097f9fbe5adf22ae77d5d0cf9f3fa3186 100644 --- a/.github/workflows/merged-prs.yml +++ b/.github/workflows/merged-prs.yml @@ -29,7 +29,7 @@ jobs: - name: Setup Automation Script working-directory: ./llvm/utils/git/ run: | - pip install -r requirements.txt + pip install --require-hashes -r requirements.txt - name: Add Buildbot information comment working-directory: ./llvm/utils/git/ diff --git a/.github/workflows/new-prs.yml b/.github/workflows/new-prs.yml index a60f82ce35d1f317ae474a74fec036294326da0e..88175d6f8d64d4bbbb034ae4985eefa8427e2550 100644 --- a/.github/workflows/new-prs.yml +++ b/.github/workflows/new-prs.yml @@ -43,7 +43,7 @@ jobs: - name: Setup Automation Script working-directory: ./llvm/utils/git/ run: | - pip install -r requirements.txt + pip install --require-hashes -r requirements.txt - name: Greet Author working-directory: ./llvm/utils/git/ diff --git a/.github/workflows/pr-request-release-note.yml b/.github/workflows/pr-request-release-note.yml new file mode 100644 index 0000000000000000000000000000000000000000..5e48ce7aee2e2b32d1f2fc3a086358454e63c056 --- /dev/null +++ b/.github/workflows/pr-request-release-note.yml @@ -0,0 +1,43 @@ +name: PR Request Release Note + +permissions: + contents: read + pull-requests: write + +on: + pull_request: + types: + - closed + +jobs: + request-release-note: + if: >- + github.repository_owner == 'llvm' && + startsWith(github.ref, 'refs/heads/release') + + runs-on: ubuntu-latest + steps: + # We need to pull the script from the main branch, so that we ensure + # we get the latest version of this script. + - name: Checkout Scripts + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + sparse-checkout: | + llvm/utils/git/requirements.txt + llvm/utils/git/github-automation.py + sparse-checkout-cone-mode: false + + - name: Install Dependencies + run: | + pip install --require-hashes -r llvm/utils/git/requirements.txt + + - name: Request Release Note + env: + # We need to use an llvmbot token here, because we are mentioning a user. + GITHUB_TOKEN: ${{ github.token }} + run: | + python3 llvm/utils/git/github-automation.py \ + --repo "$GITHUB_REPOSITORY" \ + --token "$GITHUB_TOKEN" \ + request-release-note \ + --pr-number ${{ github.event.pull_request.number}} diff --git a/.github/workflows/pr-subscriber.yml b/.github/workflows/pr-subscriber.yml index 3952493bb698fe707f75b2ab437a7f8c195bba67..272d3e2f9ef8a31da37ab1301be79227dc23c96c 100644 --- a/.github/workflows/pr-subscriber.yml +++ b/.github/workflows/pr-subscriber.yml @@ -22,7 +22,7 @@ jobs: - name: Setup Automation Script working-directory: ./llvm/utils/git/ run: | - pip install -r requirements.txt + pip install --require-hashes -r requirements.txt - name: Update watchers working-directory: ./llvm/utils/git/ diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml index 131ad3004f457743403fbc07a64193cf53262c6a..fc497a7de94f7a629c71d0908ed2fbd6193bd4ea 100644 --- a/.github/workflows/release-binaries.yml +++ b/.github/workflows/release-binaries.yml @@ -38,9 +38,6 @@ jobs: if: github.repository == 'llvm/llvm-project' outputs: release-version: ${{ steps.vars.outputs.release-version }} - flags: ${{ steps.vars.outputs.flags }} - build-dir: ${{ steps.vars.outputs.build-dir }} - rc-flags: ${{ steps.vars.outputs.rc-flags }} ref: ${{ steps.vars.outputs.ref }} upload: ${{ steps.vars.outputs.upload }} @@ -50,7 +47,7 @@ jobs: - name: Install Dependencies run: | - pip install -r ./llvm/utils/git/requirements.txt + pip install --require-hashes -r ./llvm/utils/git/requirements.txt - name: Check Permissions env: @@ -85,17 +82,11 @@ jobs: fi bash .github/workflows/set-release-binary-outputs.sh "$tag" "$upload" - # Try to get around the 6 hour timeout by first running a job to fill - # the build cache. - fill-cache: - name: "Fill Cache ${{ matrix.os }}" + build-stage1-linux: + name: "Build Stage 1 Linux" needs: prepare - runs-on: ${{ matrix.os }} + runs-on: ubuntu-22.04 if: github.repository == 'llvm/llvm-project' - strategy: - matrix: - os: - - ubuntu-22.04 steps: - name: Checkout LLVM uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 @@ -109,81 +100,207 @@ jobs: uses: hendrikmuhs/ccache-action@ca3acd2731eef11f1572ccb126356c2f9298d35e # v1.2.9 with: max-size: 250M - key: sccache-${{ matrix.os }}-release + key: sccache-${{ runner.os }}-release variant: sccache - - name: Build Clang + - name: Build Stage 1 Clang run: | - cmake -G Ninja -C clang/cmake/caches/Release.cmake -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DCMAKE_POSITION_INDEPENDENT_CODE=ON -S llvm -B build - ninja -v -C build clang + sudo chown $USER:$USER /mnt/ + cmake -G Ninja -C clang/cmake/caches/Release.cmake -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -S llvm -B /mnt/build + ninja -v -C /mnt/build + # We need to create an archive of the build directory, because it has too + # many files to upload. + - name: Package Build and Source Directories + run: | + tar -c . | zstd -T0 -c > llvm-project.tar.zst + tar -C /mnt/ -c build/ | zstd -T0 -c > build.tar.zst - build-binaries: - name: ${{ matrix.target.triple }} - permissions: - contents: write # To upload assets to release. + - name: Upload Stage 1 Source + uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0 + with: + name: stage1-source + path: llvm-project.tar.zst + retention-days: 2 + + - name: Upload Stage 1 Build Dir + uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0 + with: + name: stage1-build + path: build.tar.zst + retention-days: 2 + + build-stage2-linux: + name: "Build Stage 2 Linux" needs: - prepare - - fill-cache - runs-on: ${{ matrix.target.runs-on }} + - build-stage1-linux + runs-on: ubuntu-22.04 if: github.repository == 'llvm/llvm-project' - strategy: - fail-fast: false - matrix: - target: - - triple: x86_64-linux-gnu-ubuntu-22.04 - os: ubuntu-22.04 - runs-on: ubuntu-22.04-16x64 - debian-build-deps: > - chrpath - gcc-multilib - ninja-build - steps: - - name: Checkout LLVM - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - name: Install Ninja + uses: llvm/actions/install-ninja@22e9f909d35b50bd1181709564bfe816eaeaae81 # main + + - name: Download Stage 1 Artifacts + uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 with: - ref: ${{ needs.prepare.outputs.ref }} - path: ${{ needs.prepare.outputs.build-dir }}/llvm-project + pattern: stage1-* + merge-multiple: true - - name: Setup sccache - uses: hendrikmuhs/ccache-action@ca3acd2731eef11f1572ccb126356c2f9298d35e # v1.2.9 + - name: Unpack Artifacts + run: | + tar --zstd -xf llvm-project.tar.zst + rm llvm-project.tar.zst + sudo chown $USER:$USER /mnt/ + tar --zstd -C /mnt -xf build.tar.zst + rm build.tar.zst + + - name: Build Stage 2 + run: | + ninja -C /mnt/build stage2-instrumented + + # We need to create an archive of the build directory, because it has too + # many files to upload. + - name: Save Build and Source Directories + run: | + tar -c . | zstd -T0 -c > llvm-project.tar.zst + tar -C /mnt/ -c build/ | zstd -T0 -c > build.tar.zst + + - name: Upload Stage 2 Source + uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0 with: - max-size: 250M - key: sccache-${{ matrix.target.os }}-release - save: false - variant: sccache + name: stage2-source + path: ${{ github.workspace }}/llvm-project.tar.zst + retention-days: 2 + + - name: Upload Stage 2 Build Dir + uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0 + with: + name: stage2-build + path: ${{ github.workspace }}/build.tar.zst + retention-days: 2 - - name: Install Brew build dependencies - if: matrix.target.brew-build-deps != '' - run: brew install ${{ matrix.target.brew-build-deps }} - - name: Install Debian build dependencies - if: matrix.target.debian-build-deps != '' - run: sudo apt install ${{ matrix.target.debian-build-deps }} + build-stage3-linux: + name: "Build Stage 3 Linux" + needs: + - prepare + - build-stage2-linux + outputs: + filename: ${{ steps.package-info.outputs.release-filename }} + runs-on: ubuntu-22.04-16x64 + if: github.repository == 'llvm/llvm-project' + steps: + - name: Install Ninja + uses: llvm/actions/install-ninja@22e9f909d35b50bd1181709564bfe816eaeaae81 # main + + - name: 'Download artifact' + uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 + with: + pattern: stage2-* + merge-multiple: true - - name: Set macOS build env variables - if: runner.os == 'macOS' + - name: Unpack Artifact run: | - echo "MACOSX_DEPLOYMENT_TARGET=10.9" >> "$GITHUB_ENV" + tar --zstd -xf llvm-project.tar.zst + rm llvm-project.tar.zst + sudo chown $USER:$USER /mnt/ + tar --zstd -C /mnt -xf build.tar.zst + rm build.tar.zst - - name: Build and test release + - name: Build Release Package run: | - ${{ needs.prepare.outputs.build-dir }}/llvm-project/llvm/utils/release/test-release.sh \ - ${{ needs.prepare.outputs.flags }} \ - -triple ${{ matrix.target.triple }} \ - -use-ninja \ - -no-checkout \ - -use-cmake-cache \ - -no-test-suite \ - -configure-flags "-DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache" + ninja -C /mnt/build stage2-package - - name: Upload binaries - if: ${{ always() && needs.prepare.outputs.upload == 'true' }} + - id: package-info + run: | + filename="LLVM-${{ needs.prepare.outputs.release-version }}-Linux.tar.gz" + echo "filename=$filename" >> $GITHUB_OUTPUT + echo "path=/mnt/build/tools/clang/stage2-bins/$filename" >> $GITHUB_OUTPUT + + - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0 + if: always() + with: + name: release-binary + path: ${{ steps.package-info.outputs.path }} + + # Clean up some build files to reduce size of artifact. + - name: Clean Up Build Directory + run: | + find /mnt/build -iname ${{ steps.package-info.outputs.filename }} -delete + + # We need to create an archive of the build directory, because it has too + # many files to upload. + - name: Save Build and Source Directories + run: | + tar -c . | zstd -T0 -c > llvm-project.tar.zst + tar -C /mnt/ -c build/ | zstd -T0 -c > build.tar.zst + + - name: Upload Stage 3 Source + uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0 + with: + name: stage3-source + path: llvm-project.tar.zst + retention-days: 2 + + - name: Upload Stage 3 Build Dir + uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0 + with: + name: stage3-build + path: build.tar.zst + retention-days: 2 + + upload-release-binaries-linux: + name: "Upload Linux Release Binaries" + needs: + - prepare + - build-stage3-linux + if : ${{ needs.prepare.outputs.upload == 'true' }} + runs-on: ubuntu-22.04 + permissions: + contents: write # For release uploads + + steps: + - name: 'Download artifact' + uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 + with: + name: release-binary + + - name: Upload Release run: | sudo apt install python3-github - ${{ needs.prepare.outputs.build-dir }}/llvm-project/llvm/utils/release/github-upload-release.py \ + ./llvm-project/llvm/utils/release/github-upload-release.py \ --token ${{ github.token }} \ --release ${{ needs.prepare.outputs.release-version }} \ upload \ - --files ${{ needs.prepare.outputs.build-dir }}/clang+llvm-${{ needs.prepare.outputs.release-version }}-${{ matrix.target.triple }}.tar.xz + --files ${{ needs.build-stage3-linux.outputs.release-filename }} + + + test-stage3-linux: + name: "Test Stage 3 Linux" + needs: + - prepare + - build-stage3-linux + runs-on: ubuntu-22.04 + if: github.repository == 'llvm/llvm-project' + steps: + - name: Install Ninja + uses: llvm/actions/install-ninja@22e9f909d35b50bd1181709564bfe816eaeaae81 # main + + - name: 'Download artifact' + uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 + with: + pattern: stage3-* + merge-multiple: true + + - name: Unpack Artifact + run: | + tar --zstd -xf llvm-project.tar.zst + rm llvm-project.tar.zst + sudo chown $USER:$USER /mnt/ + tar --zstd -C /mnt -xf build.tar.zst + rm build.tar.zst + + - name: Run Tests + run: | + ninja -C /mnt/build stage2-check-all diff --git a/.github/workflows/release-doxygen.yml b/.github/workflows/release-doxygen.yml index 5e322849a1d093fd775066c7a1768b00f52501c6..12c14bea52f624925e1b9ee5f6e108a24e066197 100644 --- a/.github/workflows/release-doxygen.yml +++ b/.github/workflows/release-doxygen.yml @@ -56,12 +56,12 @@ jobs: pip3 install --user -r ./llvm/docs/requirements.txt - name: Build Doxygen - env: - GITHUB_TOKEN: ${{ github.token }} run: | ./llvm/utils/release/build-docs.sh -release "${{ inputs.release-version }}" -no-sphinx - name: Upload Doxygen if: env.upload + env: + GITHUB_TOKEN: ${{ github.token }} run: | ./llvm/utils/release/github-upload-release.py --token "$GITHUB_TOKEN" --release "${{ inputs.release-version }}" --user "${{ github.actor }}" upload --files ./*doxygen*.tar.xz diff --git a/.github/workflows/release-tasks.yml b/.github/workflows/release-tasks.yml index 53da8662b0203a87d29e5ed33f678478db02b8bf..29049ff014288733e638b4f434543e44722c5d6d 100644 --- a/.github/workflows/release-tasks.yml +++ b/.github/workflows/release-tasks.yml @@ -1,7 +1,7 @@ name: Release Task permissions: - contents: write + contents: read on: push: @@ -27,6 +27,8 @@ jobs: release-create: name: Create a New Release runs-on: ubuntu-latest + permissions: + contents: write # For creating the release. needs: validate-tag steps: @@ -55,6 +57,8 @@ jobs: release-doxygen: name: Build and Upload Release Doxygen + permissions: + contents: write needs: - validate-tag - release-create @@ -72,6 +76,8 @@ jobs: release-binaries: name: Build Release Binaries + permissions: + contents: write needs: - validate-tag - release-create diff --git a/.github/workflows/set-release-binary-outputs.sh b/.github/workflows/set-release-binary-outputs.sh index 59470cf83ba75525f543230a94f2340ca11f32e0..14d0798364e914124cdaf46813e9a4c5dae652ec 100644 --- a/.github/workflows/set-release-binary-outputs.sh +++ b/.github/workflows/set-release-binary-outputs.sh @@ -15,10 +15,8 @@ if echo $tag | grep -e '^[0-9a-f]\+$'; then # This is a plain commit. # TODO: Don't hardcode this. release_version="18" - build_dir="$tag" upload='false' ref="$tag" - flags="-git-ref $tag -test-asserts" else @@ -30,12 +28,7 @@ else fi release_version=`echo "$tag" | sed 's/llvmorg-//g'` release=`echo "$release_version" | sed 's/-.*//g'` - build_dir=`echo "$release_version" | sed 's,^[^-]\+,final,' | sed 's,[^-]\+-rc\(.\+\),rc\1,'` - rc_flags=`echo "$release_version" | sed 's,^[^-]\+,-final,' | sed 's,[^-]\+-rc\(.\+\),-rc \1 -test-asserts,' | sed 's,--,-,'` - flags="-release $release $rc_flags" fi echo "release-version=$release_version" >> $GITHUB_OUTPUT -echo "build-dir=$build_dir" >> $GITHUB_OUTPUT -echo "flags=$flags" >> $GITHUB_OUTPUT echo "upload=$upload" >> $GITHUB_OUTPUT echo "ref=$tag" >> $GITHUB_OUTPUT diff --git a/.github/workflows/version-check.yml b/.github/workflows/version-check.yml index c6d779080bbe73b0c15f812556a1d3881f0ba0ef..4ce6119a407f52897b68fcd9efcf3b4ed5a9c862 100644 --- a/.github/workflows/version-check.yml +++ b/.github/workflows/version-check.yml @@ -23,7 +23,7 @@ jobs: - name: Install dependencies run: | - pip install -r ./llvm/utils/git/requirements.txt + pip install --require-hashes -r ./llvm/utils/git/requirements.txt - name: Version Check run: | diff --git a/bolt/docs/CommandLineArgumentReference.md b/bolt/docs/CommandLineArgumentReference.md new file mode 100644 index 0000000000000000000000000000000000000000..1951ad5a2dc5eb8997f32ef25e51cd6e807a6e5f --- /dev/null +++ b/bolt/docs/CommandLineArgumentReference.md @@ -0,0 +1,1213 @@ +# BOLT - a post-link optimizer developed to speed up large applications + +## SYNOPSIS + +`llvm-bolt [-o outputfile] .bolt [-data=perf.fdata] [options]` + +## OPTIONS + +### Generic options + +- `-h` + + Alias for `--help` + +- `--help` + + Display available options (`--help-hidden` for more). + +- `--help-hidden` + + Display all available options. + +- `--help-list` + + Display list of available options (`--help-list-hidden` for more). + +- `--help-list-hidden` + + Display list of all available options. + +- `--print-all-options` + + Print all option values after command line parsing. + +- `--print-options` + + Print non-default options after command line parsing. + +- `--version` + + Display the version of this program. + +### Output options + +- `-o ` + + output file + +- `-w ` + + Save recorded profile to a file + +### BOLT generic options + +- `--align-text=` + + Alignment of .text section + +- `--allow-stripped` + + Allow processing of stripped binaries + +- `--asm-dump[=]` + + Dump function into assembly + +- `-b` + + Alias for -data + +- `--bolt-id=` + + Add any string to tag this execution in the output binary via bolt info section + +- `--break-funcs=` + + List of functions to core dump on (debugging) + +- `--check-encoding` + + Perform verification of LLVM instruction encoding/decoding. Every instruction + in the input is decoded and re-encoded. If the resulting bytes do not match + the input, a warning message is printed. + +- `--cu-processing-batch-size=` + + Specifies the size of batches for processing CUs. Higher number has better + performance, but more memory usage. Default value is 1. + +- `--data=` + + + +- `--debug-skeleton-cu` + + Prints out offsets for abbrev and debug_info of Skeleton CUs that get patched. + +- `--deterministic-debuginfo` + + Disables parallel execution of tasks that may produce nondeterministic debug info + +- `--dot-tooltip-code` + + Add basic block instructions as tool tips on nodes + +- `--dump-cg=` + + Dump callgraph to the given file + +- `--dump-data` + + Dump parsed bolt data for debugging + +- `--dump-dot-all` + + Dump function CFGs to graphviz format after each stage; enable '-print-loops' + for color-coded blocks + +- `--dump-orc` + + Dump raw ORC unwind information (sorted) + +- `--dwarf-output-path=` + + Path to where .dwo files or dwp file will be written out to. + +- `--dwp=` + + Path and name to DWP file. + +- `--dyno-stats` + + Print execution info based on profile + +- `--dyno-stats-all` + + Print dyno stats after each stage + +- `--dyno-stats-scale=` + + Scale to be applied while reporting dyno stats + +- `--enable-bat` + + Write BOLT Address Translation tables + +- `--force-data-relocations` + + Force relocations to data sections to always be processed + +- `--force-patch` + + Force patching of original entry points + +- `--funcs=` + + Limit optimizations to functions from the list + +- `--funcs-file=` + + File with list of functions to optimize + +- `--funcs-file-no-regex=` + + File with list of functions to optimize (non-regex) + +- `--funcs-no-regex=` + + Limit optimizations to functions from the list (non-regex) + +- `--hot-data` + + Hot data symbols support (relocation mode) + +- `--hot-functions-at-end` + + If reorder-functions is used, order functions putting hottest last + +- `--hot-text` + + Generate hot text symbols. Apply this option to a precompiled binary that + manually calls into hugify, such that at runtime hugify call will put hot + code into 2M pages. This requires relocation. + +- `--hot-text-move-sections=` + + List of sections containing functions used for hugifying hot text. BOLT makes + sure these functions are not placed on the same page as the hot text. + (default='.stub,.mover'). + +- `--insert-retpolines` + + Run retpoline insertion pass + +- `--keep-aranges` + + Keep or generate .debug_aranges section if .gdb_index is written + +- `--keep-tmp` + + Preserve intermediate .o file + +- `--lite` + + Skip processing of cold functions + +- `--max-data-relocations=` + + Maximum number of data relocations to process + +- `--max-funcs=` + + Maximum number of functions to process + +- `--no-huge-pages` + + Use regular size pages for code alignment + +- `--no-threads` + + Disable multithreading + +- `--pad-funcs=` + + List of functions to pad with amount of bytes + +- `--profile-format=` + + Format to dump profile output in aggregation mode, default is fdata + - `=fdata`: offset-based plaintext format + - `=yaml`: dense YAML representation + +- `--r11-availability=` + + Determine the availability of r11 before indirect branches + - `=never`: r11 not available + - `=always`: r11 available before calls and jumps + - `=abi`r11 available before calls but not before jumps + +- `--relocs` + + Use relocations in the binary (default=autodetect) + +- `--remove-symtab` + + Remove .symtab section + +- `--reorder-skip-symbols=` + + List of symbol names that cannot be reordered + +- `--reorder-symbols=` + + List of symbol names that can be reordered + +- `--retpoline-lfence` + + Determine if lfence instruction should exist in the retpoline + +- `--skip-funcs=` + + List of functions to skip + +- `--skip-funcs-file=` + + File with list of functions to skip + +- `--strict` + + Trust the input to be from a well-formed source + +- `--tasks-per-thread=` + + Number of tasks to be created per thread + +- `--thread-count=` + + Number of threads + +- `--top-called-limit=` + + Maximum number of functions to print in top called functions section + +- `--trap-avx512` + + In relocation mode trap upon entry to any function that uses AVX-512 instructions + +- `--trap-old-code` + + Insert traps in old function bodies (relocation mode) + +- `--update-debug-sections` + + Update DWARF debug sections of the executable + +- `--use-gnu-stack` + + Use GNU_STACK program header for new segment (workaround for issues with + strip/objcopy) + +- `--use-old-text` + + Re-use space in old .text if possible (relocation mode) + +- `-v ` + + Set verbosity level for diagnostic output + +- `--write-dwp` + + Output a single dwarf package file (dwp) instead of multiple non-relocatable + dwarf object files (dwo). + +### BOLT optimization options + +- `--align-blocks` + + Align basic blocks + +- `--align-blocks-min-size=` + + Minimal size of the basic block that should be aligned + +- `--align-blocks-threshold=` + + Align only blocks with frequency larger than containing function execution + frequency specified in percent. E.g. 1000 means aligning blocks that are 10 + times more frequently executed than the containing function. + +- `--align-functions=` + + Align functions at a given value (relocation mode) + +- `--align-functions-max-bytes=` + + Maximum number of bytes to use to align functions + +- `--assume-abi` + + Assume the ABI is never violated + +- `--block-alignment=` + + Boundary to use for alignment of basic blocks + +- `--bolt-seed=` + + Seed for randomization + +- `--cg-from-perf-data` + + Use perf data directly when constructing the call graph for stale functions + +- `--cg-ignore-recursive-calls` + + Ignore recursive calls when constructing the call graph + +- `--cg-use-split-hot-size` + + Use hot/cold data on basic blocks to determine hot sizes for call graph functions + +- `--cold-threshold=` + + Tenths of percents of main entry frequency to use as a threshold when + evaluating whether a basic block is cold (0 means it is only considered + cold if the block has zero samples). Default: 0 + +- `--elim-link-veneers` + + Run veneer elimination pass + +- `--eliminate-unreachable` + + Eliminate unreachable code + +- `--equalize-bb-counts` + + Use same count for BBs that should have equivalent count (used in non-LBR + and shrink wrapping) + +- `--execution-count-threshold=` + + Perform profiling accuracy-sensitive optimizations only if function execution + count >= the threshold (default: 0) + +- `--fix-block-counts` + + Adjust block counts based on outgoing branch counts + +- `--fix-func-counts` + + Adjust function counts based on basic blocks execution count + +- `--force-inline=` + + List of functions to always consider for inlining + +- `--frame-opt=` + + Optimize stack frame accesses + - `none`: do not perform frame optimization + - `hot`: perform FOP on hot functions + - `all`: perform FOP on all functions + +- `--frame-opt-rm-stores` + + Apply additional analysis to remove stores (experimental) + +- `--function-order=` + + File containing an ordered list of functions to use for function reordering + +- `--generate-function-order=` + + File to dump the ordered list of functions to use for function reordering + +- `--generate-link-sections=` + + Generate a list of function sections in a format suitable for inclusion in a + linker script + +- `--group-stubs` + + Share stubs across functions + +- `--hugify` + + Automatically put hot code on 2MB page(s) (hugify) at runtime. No manual call + to hugify is needed in the binary (which is what --hot-text relies on). + +- `--icf` + + Fold functions with identical code + +- `--icp` + + Alias for --indirect-call-promotion + +- `--icp-calls-remaining-percent-threshold=` + + The percentage threshold against remaining unpromoted indirect call count + for the promotion for calls + +- `--icp-calls-topn` + + Alias for --indirect-call-promotion-calls-topn + +- `--icp-calls-total-percent-threshold=` + + The percentage threshold against total count for the promotion for calls + +- `--icp-eliminate-loads` + + Enable load elimination using memory profiling data when performing ICP + +- `--icp-funcs=` + + List of functions to enable ICP for + +- `--icp-inline` + + Only promote call targets eligible for inlining + +- `--icp-jt-remaining-percent-threshold=` + + The percentage threshold against remaining unpromoted indirect call count for + the promotion for jump tables + +- `--icp-jt-targets` + + Alias for --icp-jump-tables-targets + +- `--icp-jt-topn` + + Alias for --indirect-call-promotion-jump-tables-topn + +- `--icp-jt-total-percent-threshold=` + + The percentage threshold against total count for the promotion for jump tables + +- `--icp-jump-tables-targets` + + For jump tables, optimize indirect jmp targets instead of indices + +- `--icp-mp-threshold` + + Alias for --indirect-call-promotion-mispredict-threshold + +- `--icp-old-code-sequence` + + Use old code sequence for promoted calls + +- `--icp-top-callsites=` + + Optimize hottest calls until at least this percentage of all indirect calls + frequency is covered. 0 = all callsites + +- `--icp-topn` + + Alias for --indirect-call-promotion-topn + +- `--icp-use-mp` + + Alias for --indirect-call-promotion-use-mispredicts + +- `--indirect-call-promotion=` + + Indirect call promotion + - `none`: do not perform indirect call promotion + - `calls`: perform ICP on indirect calls + - `jump-tables`: perform ICP on jump tables + - `all`: perform ICP on calls and jump tables + +- `--indirect-call-promotion-calls-topn=` + + Limit number of targets to consider when doing indirect call promotion on + calls. 0 = no limit + +- `--indirect-call-promotion-jump-tables-topn=` + + Limit number of targets to consider when doing indirect call promotion on + jump tables. 0 = no limit + +- `--indirect-call-promotion-mispredict-threshold=` + + Misprediction threshold for skipping ICP on an indirect call + +- `--indirect-call-promotion-topn=` + + Limit number of targets to consider when doing indirect call promotion. + 0 = no limit + +- `--indirect-call-promotion-use-mispredicts` + + Use misprediction frequency for determining whether or not ICP should be + applied at a callsite. The `-indirect-call-promotion-mispredict-threshold` + value will be used by this heuristic + +- `--infer-fall-throughs` + + Infer execution count for fall-through blocks + +- `--infer-stale-profile` + + Infer counts from stale profile data. + +- `--inline-all` + + Inline all functions + +- `--inline-ap` + + Adjust function profile after inlining + +- `--inline-limit=` + + Maximum number of call sites to inline + +- `--inline-max-iters=` + + Maximum number of inline iterations + +- `--inline-memcpy` + + Inline memcpy using 'rep movsb' instruction (X86-only) + +- `--inline-small-functions` + + Inline functions if increase in size is less than defined by `-inline-small-functions-bytes` + +- `--inline-small-functions-bytes=` + + Max number of bytes for the function to be considered small for inlining purposes + +- `--instrument` + + Instrument code to generate accurate profile data + +- `--iterative-guess` + + In non-LBR mode, guess edge counts using iterative technique + +- `--jt-footprint-optimize-for-icache` + + With jt-footprint-reduction, only process PIC jumptables and turn off other + transformations that increase code size + +- `--jt-footprint-reduction` + + Make jump tables size smaller at the cost of using more instructions at jump + sites + +- `-jump-tables=` + + Jump tables support (default=basic) + - `none`: do not optimize functions with jump tables + - `basic`: optimize functions with jump tables + - `move`: move jump tables to a separate section + - `split`: split jump tables section into hot and cold based on function + execution frequency + - `aggressive`: aggressively split jump tables section based on usage of the + tables + +- `--keep-nops` + + Keep no-op instructions. By default they are removed. + +- `--lite-threshold-count=` + + Similar to '-lite-threshold-pct' but specify threshold using absolute function + call count. I.e. limit processing to functions executed at least the specified + number of times. + +- `--lite-threshold-pct=` + + Threshold (in percent) for selecting functions to process in lite mode. Higher + threshold means fewer functions to process. E.g threshold of 90 means only top + 10 percent of functions with profile will be processed. + +- `--mcf-use-rarcs` + + In MCF, consider the possibility of cancelling flow to balance edges + +- `--memcpy1-spec=` + + List of functions with call sites for which to specialize memcpy() for size 1 + +- `--min-branch-clusters` + + Use a modified clustering algorithm geared towards minimizing branches + +- `--no-inline` + + Disable all inlining (overrides other inlining options) + +- `--no-scan` + + Do not scan cold functions for external references (may result in slower binary) + +- `--peepholes=` + + Enable peephole optimizations + - `none`: disable peepholes + - `double-jumps`: remove double jumps when able + - `tailcall-traps`: insert tail call traps + - `useless-branches`: remove useless conditional branches + - `all`: enable all peephole optimizations + +- `--plt=` + + Optimize PLT calls (requires linking with -znow) + - `none`: do not optimize PLT calls + - `hot`: optimize executed (hot) PLT calls + - `all`: optimize all PLT calls + +- `--preserve-blocks-alignment` + + Try to preserve basic block alignment + +- `--profile-ignore-hash` + + Ignore hash while reading function profile + +- `--profile-use-dfs` + + Use DFS order for YAML profile + +- `--reg-reassign` + + Reassign registers so as to avoid using REX prefixes in hot code + +- `--reorder-blocks=` + + Change layout of basic blocks in a function + - `none`: do not reorder basic blocks + - `reverse`: layout blocks in reverse order + - `normal`: perform optimal layout based on profile + - `branch-predictor`: perform optimal layout prioritizing branch predictions + - `cache`: perform optimal layout prioritizing I-cache behavior + - `cache+`: perform layout optimizing I-cache behavior + - `ext-tsp`: perform layout optimizing I-cache behavior + - `cluster-shuffle`: perform random layout of clusters + +- `--reorder-data=` + + List of sections to reorder + +- `--reorder-data-algo=` + + Algorithm used to reorder data sections + - `count`: sort hot data by read counts + - `funcs`: sort hot data by hot function usage and count + +- `--reorder-data-inplace` + + Reorder data sections in place + +- `--reorder-data-max-bytes=` + + Maximum number of bytes to reorder + +- `--reorder-data-max-symbols=` + + Maximum number of symbols to reorder + +- `--reorder-functions=` + + Reorder and cluster functions (works only with relocations) + - `none`: do not reorder functions + - `exec-count`: order by execution count + - `hfsort`: use hfsort algorithm + - `hfsort+`: use hfsort+ algorithm + - `cdsort`: use cache-directed sort + - `pettis-hansen`: use Pettis-Hansen algorithm + - `random`: reorder functions randomly + - `user`: use function order specified by -function-order + +- `--reorder-functions-use-hot-size` + + Use a function's hot size when doing clustering + +- `--report-bad-layout=` + + Print top functions with suboptimal code layout on input + +- `--report-stale` + + Print the list of functions with stale profile + +- `--runtime-hugify-lib=` + + Specify file name of the runtime hugify library + +- `--runtime-instrumentation-lib=` + + Specify file name of the runtime instrumentation library + +- `--sctc-mode=` + + Mode for simplify conditional tail calls + - `always`: always perform sctc + - `preserve`: only perform sctc when branch direction is preserved + - `heuristic`: use branch prediction data to control sctc + +- `--sequential-disassembly` + + Performs disassembly sequentially + +- `--shrink-wrapping-threshold=` + + Percentage of prologue execution count to use as threshold when evaluating + whether a block is cold enough to be profitable to move eligible spills there + +- `--simplify-conditional-tail-calls` + + Simplify conditional tail calls by removing unnecessary jumps + +- `--simplify-rodata-loads` + + Simplify loads from read-only sections by replacing the memory operand with + the constant found in the corresponding section + +- `--split-align-threshold=` + + When deciding to split a function, apply this alignment while doing the size + comparison (see -split-threshold). Default value: 2. + +- `--split-all-cold` + + Outline as many cold basic blocks as possible + +- `--split-eh` + + Split C++ exception handling code + +- `--split-functions` + + Split functions into fragments + +- `--split-strategy=` + + Strategy used to partition blocks into fragments + + - `profile2`: split each function into a hot and cold fragment using + profiling information + - `cdsplit`: split each function into a hot, warm, and cold fragment using + profiling information + - `random2`: split each function into a hot and cold fragment at a randomly + chosen split point (ignoring any available profiling information) + - `randomN`: split each function into N fragments at randomly chosen split + points (ignoring any available profiling information) + - `all`: split all basic blocks of each function into fragments such that + each fragment contains exactly a single basic block + +- `--split-threshold=` + + Split function only if its main size is reduced by more than given amount of + bytes. Default value: 0, i.e. split iff the size is reduced. Note that on + some architectures the size can increase after splitting. + +- `--stale-matching-max-func-size=` + + The maximum size of a function to consider for inference. + +- `--stale-threshold=` + + Maximum percentage of stale functions to tolerate (default: 100) + +- `--stoke` + + Turn on the stoke analysis + +- `--strip-rep-ret` + + Strip 'repz' prefix from 'repz retq' sequence (on by default) + +- `--tail-duplication=` + + Duplicate unconditional branches that cross a cache line + + - `none` do not apply + - `aggressive` aggressive strategy + - `moderate` moderate strategy + - `cache` cache-aware duplication strategy + +- `--tsp-threshold=` + + Maximum number of hot basic blocks in a function for which to use a precise TSP solution while re-ordering basic blocks + +- `--use-aggr-reg-reassign` + + Use register liveness analysis to try to find more opportunities for -reg-reassign optimization + +- `--use-compact-aligner` + + Use compact approach for aligning functions + +- `--use-edge-counts` + + Use edge count data when doing clustering + +- `--verify-cfg` + + Verify the CFG after every pass + +- `--x86-align-branch-boundary-hot-only` + + Only apply branch boundary alignment in hot code + +- `--x86-strip-redundant-address-size` + + Remove redundant Address-Size override prefix + +### BOLT options in relocation mode + +- `-align-macro-fusion=` + + Fix instruction alignment for macro-fusion (x86 relocation mode) + + - `none`: do not insert alignment no-ops for macro-fusion + - `hot`: only insert alignment no-ops on hot execution paths (default) + - `all`: always align instructions to allow macro-fusion + +### BOLT instrumentation options + +`llvm-bolt -instrument [-o outputfile] ` + +- `--conservative-instrumentation` + + Disable instrumentation optimizations that sacrifice profile accuracy (for + debugging, default: false) + +- `--instrument-calls` + + Record profile for inter-function control flow activity (default: true) + +- `--instrument-hot-only` + + Only insert instrumentation on hot functions (needs profile, default: false) + +- `--instrumentation-binpath=` + + Path to instrumented binary in case if /proc/self/map_files is not accessible + due to access restriction issues + +- `--instrumentation-file=` + + File name where instrumented profile will be saved (default: /tmp/prof.fdata) + +- `--instrumentation-file-append-pid` + + Append PID to saved profile file name (default: false) + +- `--instrumentation-no-counters-clear` + + Don't clear counters across dumps (use with `instrumentation-sleep-time` option) + +- `--instrumentation-sleep-time=` + + Interval between profile writes (default: 0 = write only at program end). + This is useful for service workloads when you want to dump profile every X + minutes or if you are killing the program and the profile is not being + dumped at the end. + +- `--instrumentation-wait-forks` + + Wait until all forks of instrumented process will finish (use with + `instrumentation-sleep-time` option) + +### Data aggregation options (perf2bolt) + +`perf2bolt -p perf.data [-o outputfile] perf.fdata ` + +- `--autofdo` + + Generate autofdo textual data instead of bolt data + +- `--filter-mem-profile` + + If processing a memory profile, filter out stack or heap accesses that won't + be useful for BOLT to reduce profile file size + +- `--ignore-build-id` + + Continue even if build-ids in input binary and perf.data mismatch + +- `--ignore-interrupt-lbr` + + Ignore kernel interrupt LBR that happens asynchronously + +- `--itrace=` + + Generate LBR info with perf itrace argument + +- `--nl` + + Aggregate basic samples (without LBR info) + +- `--pa` + + Skip perf and read data from a pre-aggregated file format + +- `--perfdata=` + + Data file + +- `--pid=` + + Only use samples from process with specified PID + +- `--time-aggr` + + Time BOLT aggregator + +- `--use-event-pc` + + Use event PC in combination with LBR sampling + +### BOLT printing options + +#### Generic options + +- `--print-aliases` + + Print aliases when printing objects + +- `--print-all` + + Print functions after each stage + +- `--print-cfg` + + Print functions after CFG construction + +- `--print-debug-info` + + Print debug info when printing functions + +- `--print-disasm` + + Print function after disassembly + +- `--print-dyno-opcode-stats=` + + Print per instruction opcode dyno stats and the functionnames:BB offsets of + the nth highest execution counts + +- `--print-dyno-stats-only` + + While printing functions output dyno-stats and skip instructions + +- `--print-exceptions` + + Print exception handling data + +- `--print-globals` + + Print global symbols after disassembly + +- `--print-jump-tables` + + Print jump tables + +- `--print-loops` + + Print loop related information + +- `--print-mem-data` + + Print memory data annotations when printing functions + +- `--print-normalized` + + Print functions after CFG is normalized + +- `--print-only=` + + List of functions to print + +- `--print-orc` + + Print ORC unwind information for instructions + +- `--print-profile` + + Print functions after attaching profile + +- `--print-profile-stats` + + Print profile quality/bias analysis + +- `--print-pseudo-probes=` + + Print pseudo probe info + - `=decode`: decode probes section from binary + - `=address_conversion`: update address2ProbesMap with output block address + - `=encoded_probes`: display the encoded probes in binary section + - `=all`: enable all debugging printout + +- `--print-relocations` + + Print relocations when printing functions/objects + +- `--print-reordered-data` + + Print section contents after reordering + +- `--print-retpoline-insertion` + + Print functions after retpoline insertion pass + +- `--print-sdt` + + Print all SDT markers + +- `--print-sections` + + Print all registered sections + +- `--print-unknown` + + Print names of functions with unknown control flow + +- `--time-opts` + + Print time spent in each optimization + +#### Optimization options + +- `--print-after-branch-fixup` + + Print function after fixing local branches + +- `--print-after-jt-footprint-reduction` + + Print function after jt-footprint-reduction pass + +- `--print-after-lowering` + + Print function after instruction lowering + +- `--print-cache-metrics` + + Calculate and print various metrics for instruction cache + +- `--print-clusters` + + Print clusters + +- `--print-finalized` + + Print function after CFG is finalized + +- `--print-fix-relaxations` + + Print functions after fix relaxations pass + +- `--print-fix-riscv-calls` + + Print functions after fix RISCV calls pass + +- `--print-fop` + + Print functions after frame optimizer pass + +- `--print-function-statistics=` + + Print statistics about basic block ordering + +- `--print-icf` + + Print functions after ICF optimization + +- `--print-icp` + + Print functions after indirect call promotion + +- `--print-inline` + + Print functions after inlining optimization + +- `--print-longjmp` + + Print functions after longjmp pass + +- `--print-optimize-bodyless` + + Print functions after bodyless optimization + +- `--print-output-address-range` + + Print output address range for each basic block in the function + whenBinaryFunction::print is called + +- `--print-peepholes` + + Print functions after peephole optimization + +- `--print-plt` + + Print functions after PLT optimization + +- `--print-regreassign` + + Print functions after regreassign pass + +- `--print-reordered` + + Print functions after layout optimization + +- `--print-reordered-functions` + + Print functions after clustering + +- `--print-sctc` + + Print functions after conditional tail call simplification + +- `--print-simplify-rodata-loads` + + Print functions after simplification of RO data loads + +- `--print-sorted-by=` + + Print functions sorted by order of dyno stats + - `executed-forward-branches`: executed forward branches + - `taken-forward-branches`: taken forward branches + - `executed-backward-branches`: executed backward branches + - `taken-backward-branches`: taken backward branches + - `executed-unconditional-branches`: executed unconditional branches + - `all-function-calls`: all function calls + - `indirect-calls`: indirect calls + - `PLT-calls`: PLT calls + - `executed-instructions`: executed instructions + - `executed-load-instructions`: executed load instructions + - `executed-store-instructions`: executed store instructions + - `taken-jump-table-branches`: taken jump table branches + - `taken-unknown-indirect-branches`: taken unknown indirect branches + - `total-branches`: total branches + - `taken-branches`: taken branches + - `non-taken-conditional-branches`: non-taken conditional branches + - `taken-conditional-branches`: taken conditional branches + - `all-conditional-branches`: all conditional branches + - `linker-inserted-veneer-calls`: linker-inserted veneer calls + - `all`: sorted by all names + +- `--print-sorted-by-order=` + + Use ascending or descending order when printing functions ordered by dyno stats + +- `--print-split` + + Print functions after code splitting + +- `--print-stoke` + + Print functions after stoke analysis + +- `--print-uce` + + Print functions after unreachable code elimination + +- `--print-veneer-elimination` + + Print functions after veneer elimination pass + +- `--time-build` + + Print time spent constructing binary functions + +- `--time-rewrite` + + Print time spent in rewriting passes diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h index 8b1af9e8153925760985efcb954e87a046b2c1f2..75765819ac464eb83bec5d5643d50195ee07a88e 100644 --- a/bolt/include/bolt/Core/BinaryContext.h +++ b/bolt/include/bolt/Core/BinaryContext.h @@ -20,6 +20,7 @@ #include "bolt/Core/JumpTable.h" #include "bolt/Core/MCPlusBuilder.h" #include "bolt/RuntimeLibs/RuntimeLibrary.h" +#include "llvm/ADT/AddressRanges.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/iterator.h" @@ -726,6 +727,9 @@ public: uint64_t OldTextSectionOffset{0}; uint64_t OldTextSectionSize{0}; + /// Area in the input binary reserved for BOLT. + AddressRange BOLTReserved; + /// Address of the code/function that is executed before any other code in /// the binary. std::optional StartFunctionAddress; diff --git a/bolt/include/bolt/Core/BinaryFunction.h b/bolt/include/bolt/Core/BinaryFunction.h index 26d2d01f86267127f4c4bea9daa5862b4b412738..3c641581e247a84b918f975b1a8524c2a9401b7b 100644 --- a/bolt/include/bolt/Core/BinaryFunction.h +++ b/bolt/include/bolt/Core/BinaryFunction.h @@ -930,6 +930,8 @@ public: return const_cast(this)->getInstructionAtOffset(Offset); } + std::optional disassembleInstructionAtOffset(uint64_t Offset) const; + /// Return offset for the first instruction. If there is data at the /// beginning of a function then offset of the first instruction could /// be different from 0 diff --git a/bolt/include/bolt/Core/DIEBuilder.h b/bolt/include/bolt/Core/DIEBuilder.h index 06084819ec0b3ab96daa83f071a5594e8d7efcd0..c5ad0ac18339ab6fd667e27dd5ac95e46c8d625f 100644 --- a/bolt/include/bolt/Core/DIEBuilder.h +++ b/bolt/include/bolt/Core/DIEBuilder.h @@ -129,6 +129,9 @@ private: uint64_t UnitSize{0}; llvm::DenseSet AllProcessed; DWARF5AcceleratorTable &DebugNamesTable; + // Unordered map to handle name collision if output DWO directory is + // specified. + std::unordered_map NameToIndexMap; /// Returns current state of the DIEBuilder State &getState() { return *BuilderState.get(); } @@ -384,6 +387,17 @@ public: bool deleteValue(DIEValueList *Die, dwarf::Attribute Attribute) { return Die->deleteValue(Attribute); } + /// Updates DWO Name and Compilation directory for Skeleton CU \p Unit. + std::string updateDWONameCompDir(DebugStrOffsetsWriter &StrOffstsWriter, + DebugStrWriter &StrWriter, + DWARFUnit &SkeletonCU, + std::optional DwarfOutputPath, + std::optional DWONameToUse); + /// Updates DWO Name and Compilation directory for Type Units. + void updateDWONameCompDirForTypes(DebugStrOffsetsWriter &StrOffstsWriter, + DebugStrWriter &StrWriter, DWARFUnit &Unit, + std::optional DwarfOutputPath, + const StringRef DWOName); }; } // namespace bolt } // namespace llvm diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h index 166bb3617e57f68448eb662348e2e414ed885b32..585bafa0888496ff15c8ce5c5610738c303eb51d 100644 --- a/bolt/include/bolt/Core/DebugData.h +++ b/bolt/include/bolt/Core/DebugData.h @@ -430,7 +430,7 @@ protected: using DebugStrOffsetsBufferVector = SmallVector; class DebugStrOffsetsWriter { public: - DebugStrOffsetsWriter() { + DebugStrOffsetsWriter(BinaryContext &BC) : BC(BC) { StrOffsetsBuffer = std::make_unique(); StrOffsetsStream = std::make_unique(*StrOffsetsBuffer); } @@ -460,6 +460,10 @@ public: StrOffsets.clear(); } + bool isStrOffsetsSectionModified() const { + return StrOffsetSectionWasModified; + } + private: std::unique_ptr StrOffsetsBuffer; std::unique_ptr StrOffsetsStream; @@ -467,13 +471,16 @@ private: SmallVector StrOffsets; std::unordered_map ProcessedBaseOffsets; bool StrOffsetSectionWasModified = false; + BinaryContext &BC; }; using DebugStrBufferVector = SmallVector; class DebugStrWriter { public: DebugStrWriter() = delete; - DebugStrWriter(BinaryContext &BC) : BC(BC) { create(); } + DebugStrWriter(DWARFContext &DwCtx, bool IsDWO) : DwCtx(DwCtx), IsDWO(IsDWO) { + create(); + } std::unique_ptr releaseBuffer() { return std::move(StrBuffer); } @@ -495,7 +502,8 @@ private: void create(); std::unique_ptr StrBuffer; std::unique_ptr StrStream; - BinaryContext &BC; + DWARFContext &DwCtx; + bool IsDWO; }; enum class LocWriterKind { DebugLocWriter, DebugLoclistWriter }; diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h index f7614cf9ac9777be6812e228190cc20c810b4c3d..f7cf538bd0e867eba4f11636b45361a2280c4706 100644 --- a/bolt/include/bolt/Core/MCPlusBuilder.h +++ b/bolt/include/bolt/Core/MCPlusBuilder.h @@ -438,8 +438,8 @@ public: return false; } - /// Check whether we support inverting this branch - virtual bool isUnsupportedBranch(const MCInst &Inst) const { return false; } + /// Check whether this conditional branch can be reversed + virtual bool isReversibleBranch(const MCInst &Inst) const { return true; } /// Return true of the instruction is of pseudo kind. virtual bool isPseudo(const MCInst &Inst) const { diff --git a/bolt/include/bolt/Passes/FrameAnalysis.h b/bolt/include/bolt/Passes/FrameAnalysis.h index 66246bd6647bb3202a2778b63efe9de27adf08af..44b54d4ed45d4d7a84914f811ca21618fe0a87dc 100644 --- a/bolt/include/bolt/Passes/FrameAnalysis.h +++ b/bolt/include/bolt/Passes/FrameAnalysis.h @@ -170,10 +170,6 @@ class FrameAnalysis { std::unique_ptr> SPTMap; - /// A vector that stores ids of the allocators that are used in SPT - /// computation - std::vector SPTAllocatorsId; - public: explicit FrameAnalysis(BinaryContext &BC, BinaryFunctionCallGraph &CG); diff --git a/bolt/include/bolt/Passes/IndirectCallPromotion.h b/bolt/include/bolt/Passes/IndirectCallPromotion.h index adc58d70ec0f4d9e5bb09765d1ce863c0bdf15df..8ec160b867cf8ce143b0227e7e3ef0c1adfadf0a 100644 --- a/bolt/include/bolt/Passes/IndirectCallPromotion.h +++ b/bolt/include/bolt/Passes/IndirectCallPromotion.h @@ -104,7 +104,7 @@ class IndirectCallPromotion : public BinaryFunctionPass { struct Location { MCSymbol *Sym{nullptr}; uint64_t Addr{0}; - bool isValid() const { return Sym || (!Sym && Addr != 0); } + bool isValid() const { return Sym || Addr != 0; } Location() {} explicit Location(MCSymbol *Sym) : Sym(Sym) {} explicit Location(uint64_t Addr) : Addr(Addr) {} diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h index f2fa59bcaa1a3ace0d96446bba629992700ea362..c158a9bb3e3f253f5d0e60f4f22c8bb53c42b12b 100644 --- a/bolt/include/bolt/Profile/DataAggregator.h +++ b/bolt/include/bolt/Profile/DataAggregator.h @@ -122,14 +122,14 @@ private: uint64_t ExternCount{0}; }; - struct BranchInfo { + struct TakenBranchInfo { uint64_t TakenCount{0}; uint64_t MispredCount{0}; }; /// Intermediate storage for profile data. We save the results of parsing /// and use them later for processing and assigning profile. - std::unordered_map BranchLBRs; + std::unordered_map BranchLBRs; std::unordered_map FallthroughLBRs; std::vector AggregatedLBRs; std::unordered_map BasicSamples; diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h index 2c482bd2b9ea965ff1bc289ead744bfe3f19737d..8dec32de9008e5e692a3f61a8ac1b655a3af6d66 100644 --- a/bolt/include/bolt/Rewrite/DWARFRewriter.h +++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h @@ -177,13 +177,6 @@ private: DIEValue &HighPCAttrInfo, std::optional RangesBase = std::nullopt); - /// Adds a \p Str to .debug_str section. - /// Uses \p AttrInfoVal to either update entry in a DIE for legacy DWARF using - /// \p DebugInfoPatcher, or for DWARF5 update an index in .debug_str_offsets - /// for this contribution of \p Unit. - void addStringHelper(DIEBuilder &DIEBldr, DIE &Die, const DWARFUnit &Unit, - DIEValue &DIEAttrInfo, StringRef Str); - public: DWARFRewriter(BinaryContext &BC) : BC(BC) {} @@ -210,13 +203,16 @@ public: using OverriddenSectionsMap = std::unordered_map; /// Output .dwo files. void writeDWOFiles(DWARFUnit &, const OverriddenSectionsMap &, - const std::string &, DebugLocWriter &); + const std::string &, DebugLocWriter &, + DebugStrOffsetsWriter &, DebugStrWriter &); using KnownSectionsEntry = std::pair; struct DWPState { std::unique_ptr Out; std::unique_ptr TmpBC; std::unique_ptr Streamer; std::unique_ptr Strings; + /// Used to store String sections for .dwo files if they are being modified. + std::vector> StrSections; const MCObjectFileInfo *MCOFI = nullptr; const DWARFUnitIndex *CUIndex = nullptr; std::deque> UncompressedSections; @@ -237,7 +233,8 @@ public: /// add content of dwo to .dwp file. void updateDWP(DWARFUnit &, const OverriddenSectionsMap &, const UnitMeta &, - UnitMetaVectorType &, DWPState &, DebugLocWriter &); + UnitMetaVectorType &, DWPState &, DebugLocWriter &, + DebugStrOffsetsWriter &, DebugStrWriter &); }; } // namespace bolt diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h index 41a92e7ba01e8495bc0a6b4329017d2f1e2c40fd..64113bd026012e8a66c29c0442039348baf71385 100644 --- a/bolt/include/bolt/Rewrite/RewriteInstance.h +++ b/bolt/include/bolt/Rewrite/RewriteInstance.h @@ -97,6 +97,10 @@ private: /// from meta data in the file. void discoverFileObjects(); + /// Check if the input binary has a space reserved for BOLT and use it for new + /// section allocations if found. + void discoverBOLTReserved(); + /// Check whether we should use DT_FINI or DT_FINI_ARRAY for instrumentation. /// DT_FINI is preferred; DT_FINI_ARRAY is only used when no DT_FINI entry was /// found. diff --git a/bolt/lib/Core/BinaryBasicBlock.cpp b/bolt/lib/Core/BinaryBasicBlock.cpp index 4a83fece0e43d4eba92e95afd17c5988092be72a..a4b9a7f558cd80da7f115ae0deaf96dc348bc64d 100644 --- a/bolt/lib/Core/BinaryBasicBlock.cpp +++ b/bolt/lib/Core/BinaryBasicBlock.cpp @@ -131,11 +131,10 @@ bool BinaryBasicBlock::validateSuccessorInvariants() { break; } case 2: - Valid = (CondBranch && - (TBB == getConditionalSuccessor(true)->getLabel() && - ((!UncondBranch && !FBB) || - (UncondBranch && - FBB == getConditionalSuccessor(false)->getLabel())))); + Valid = + CondBranch && TBB == getConditionalSuccessor(true)->getLabel() && + (UncondBranch ? FBB == getConditionalSuccessor(false)->getLabel() + : !FBB); break; } } diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index 1fa96dfaabde819eeb3ff70e5340cc46af5ed49a..10b93e702984fb180f8d38e652b07340cc5a2846 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -1167,6 +1167,21 @@ void BinaryFunction::handleAArch64IndirectCall(MCInst &Instruction, } } +std::optional +BinaryFunction::disassembleInstructionAtOffset(uint64_t Offset) const { + assert(CurrentState == State::Empty && "Function should not be disassembled"); + assert(Offset < MaxSize && "Invalid offset"); + ErrorOr> FunctionData = getData(); + assert(FunctionData && "Cannot get function as data"); + MCInst Instr; + uint64_t InstrSize = 0; + const uint64_t InstrAddress = getAddress() + Offset; + if (BC.DisAsm->getInstruction(Instr, InstrSize, FunctionData->slice(Offset), + InstrAddress, nulls())) + return Instr; + return std::nullopt; +} + Error BinaryFunction::disassemble() { NamedRegionTimer T("disassemble", "Disassemble function", "buildfuncs", "Build Binary Functions", opts::TimeBuild); @@ -1269,7 +1284,7 @@ Error BinaryFunction::disassemble() { const bool IsCondBranch = MIB->isConditionalBranch(Instruction); MCSymbol *TargetSymbol = nullptr; - if (BC.MIB->isUnsupportedBranch(Instruction)) { + if (!BC.MIB->isReversibleBranch(Instruction)) { setIgnored(); if (BinaryFunction *TargetFunc = BC.getBinaryFunctionContainingAddress(TargetAddress)) @@ -3237,12 +3252,9 @@ bool BinaryFunction::validateCFG() const { if (CurrentState == State::CFG_Finalized) return true; - bool Valid = true; for (BinaryBasicBlock *BB : BasicBlocks) - Valid &= BB->validateSuccessorInvariants(); - - if (!Valid) - return Valid; + if (!BB->validateSuccessorInvariants()) + return false; // Make sure all blocks in CFG are valid. auto validateBlock = [this](const BinaryBasicBlock *BB, StringRef Desc) { @@ -3311,7 +3323,7 @@ bool BinaryFunction::validateCFG() const { } } - return Valid; + return true; } void BinaryFunction::fixBranches() { @@ -3369,7 +3381,7 @@ void BinaryFunction::fixBranches() { // Reverse branch condition and swap successors. auto swapSuccessors = [&]() { - if (MIB->isUnsupportedBranch(*CondBranch)) { + if (!MIB->isReversibleBranch(*CondBranch)) { if (opts::Verbosity) { BC.outs() << "BOLT-INFO: unable to swap successors in " << *this << '\n'; diff --git a/bolt/lib/Core/DIEBuilder.cpp b/bolt/lib/Core/DIEBuilder.cpp index c4b0b251c1201fcf9f27454b3b26fc861d5235bb..34c455a36cce4c98fa302d27a3071d5a3bfa09ff 100644 --- a/bolt/lib/Core/DIEBuilder.cpp +++ b/bolt/lib/Core/DIEBuilder.cpp @@ -22,6 +22,7 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/LEB128.h" #include @@ -41,6 +42,90 @@ extern cl::opt Verbosity; namespace llvm { namespace bolt { +/// Returns DWO Name to be used to update DW_AT_dwo_name/DW_AT_GNU_dwo_name +/// either in CU or TU unit die. Handles case where user specifies output DWO +/// directory, and there are duplicate names. Assumes DWO ID is unique. +static std::string +getDWOName(llvm::DWARFUnit &CU, + std::unordered_map &NameToIndexMap, + std::optional &DwarfOutputPath) { + assert(CU.getDWOId() && "DWO ID not found."); + std::string DWOName = dwarf::toString( + CU.getUnitDIE().find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), + ""); + assert(!DWOName.empty() && + "DW_AT_dwo_name/DW_AT_GNU_dwo_name does not exist."); + if (DwarfOutputPath) { + DWOName = std::string(sys::path::filename(DWOName)); + auto Iter = NameToIndexMap.find(DWOName); + if (Iter == NameToIndexMap.end()) + Iter = NameToIndexMap.insert({DWOName, 0}).first; + DWOName.append(std::to_string(Iter->second)); + ++Iter->second; + } + DWOName.append(".dwo"); + return DWOName; +} + +/// Adds a \p Str to .debug_str section. +/// Uses \p AttrInfoVal to either update entry in a DIE for legacy DWARF using +/// \p DebugInfoPatcher, or for DWARF5 update an index in .debug_str_offsets +/// for this contribution of \p Unit. +static void addStringHelper(DebugStrOffsetsWriter &StrOffstsWriter, + DebugStrWriter &StrWriter, DIEBuilder &DIEBldr, + DIE &Die, const DWARFUnit &Unit, + DIEValue &DIEAttrInfo, StringRef Str) { + uint32_t NewOffset = StrWriter.addString(Str); + if (Unit.getVersion() >= 5) { + StrOffstsWriter.updateAddressMap(DIEAttrInfo.getDIEInteger().getValue(), + NewOffset); + return; + } + DIEBldr.replaceValue(&Die, DIEAttrInfo.getAttribute(), DIEAttrInfo.getForm(), + DIEInteger(NewOffset)); +} + +std::string DIEBuilder::updateDWONameCompDir( + DebugStrOffsetsWriter &StrOffstsWriter, DebugStrWriter &StrWriter, + DWARFUnit &SkeletonCU, std::optional DwarfOutputPath, + std::optional DWONameToUse) { + DIE &UnitDIE = *getUnitDIEbyUnit(SkeletonCU); + DIEValue DWONameAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_dwo_name); + if (!DWONameAttrInfo) + DWONameAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_GNU_dwo_name); + if (!DWONameAttrInfo) + return ""; + std::string ObjectName; + if (DWONameToUse) + ObjectName = *DWONameToUse; + else + ObjectName = getDWOName(SkeletonCU, NameToIndexMap, DwarfOutputPath); + addStringHelper(StrOffstsWriter, StrWriter, *this, UnitDIE, SkeletonCU, + DWONameAttrInfo, ObjectName); + + DIEValue CompDirAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_comp_dir); + assert(CompDirAttrInfo && "DW_AT_comp_dir is not in Skeleton CU."); + + if (DwarfOutputPath) { + if (!sys::fs::exists(*DwarfOutputPath)) + sys::fs::create_directory(*DwarfOutputPath); + addStringHelper(StrOffstsWriter, StrWriter, *this, UnitDIE, SkeletonCU, + CompDirAttrInfo, *DwarfOutputPath); + } + return ObjectName; +} + +void DIEBuilder::updateDWONameCompDirForTypes( + DebugStrOffsetsWriter &StrOffstsWriter, DebugStrWriter &StrWriter, + DWARFUnit &Unit, std::optional DwarfOutputPath, + const StringRef DWOName) { + for (DWARFUnit *DU : getState().DWARF5TUVector) + updateDWONameCompDir(StrOffstsWriter, StrWriter, *DU, DwarfOutputPath, + DWOName); + if (StrOffstsWriter.isStrOffsetsSectionModified()) + StrOffstsWriter.finalizeSection(Unit, *this); +} + void DIEBuilder::updateReferences() { for (auto &[SrcDIEInfo, ReferenceInfo] : getState().AddrReferences) { DIEInfo *DstDIEInfo = ReferenceInfo.Dst; diff --git a/bolt/lib/Core/DebugData.cpp b/bolt/lib/Core/DebugData.cpp index a987a103a08b93ad7311fc81efb752ca15bac303..f502a503124702a1ecf63b31c33c8ae06e794833 100644 --- a/bolt/lib/Core/DebugData.cpp +++ b/bolt/lib/Core/DebugData.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -867,10 +868,17 @@ void DebugStrOffsetsWriter::finalizeSection(DWARFUnit &Unit, DIEBuilder &DIEBldr) { std::optional AttrVal = findAttributeInfo(Unit.getUnitDIE(), dwarf::DW_AT_str_offsets_base); - if (!AttrVal) + if (!AttrVal && !Unit.isDWOUnit()) return; - std::optional Val = AttrVal->V.getAsSectionOffset(); - assert(Val && "DW_AT_str_offsets_base Value not present."); + std::optional Val = std::nullopt; + if (AttrVal) { + Val = AttrVal->V.getAsSectionOffset(); + } else { + if (!Unit.isDWOUnit()) + BC.errs() << "BOLT-WARNING: [internal-dwarf-error]: " + "DW_AT_str_offsets_base Value not present\n"; + Val = 0; + } DIE &Die = *DIEBldr.getUnitDIEbyUnit(Unit); DIEValue StrListBaseAttrInfo = Die.findAttribute(dwarf::DW_AT_str_offsets_base); @@ -915,7 +923,11 @@ void DebugStrWriter::create() { } void DebugStrWriter::initialize() { - auto StrSection = BC.DwCtx->getDWARFObj().getStrSection(); + StringRef StrSection; + if (IsDWO) + StrSection = DwCtx.getDWARFObj().getStrDWOSection(); + else + StrSection = DwCtx.getDWARFObj().getStrSection(); (*StrStream) << StrSection; } diff --git a/bolt/lib/Core/ParallelUtilities.cpp b/bolt/lib/Core/ParallelUtilities.cpp index 5f5e96e0e7881c56eedd33db06782f9ad9bdf301..a24c37c06f1ac1ce4d0b49e697b8e876864cd81b 100644 --- a/bolt/lib/Core/ParallelUtilities.cpp +++ b/bolt/lib/Core/ParallelUtilities.cpp @@ -188,8 +188,20 @@ void runOnEachFunctionWithUniqueAllocId( LLVM_DEBUG(T.stopTimer()); }; + unsigned AllocId = 1; + auto EnsureAllocatorExists = [&BC](unsigned AllocId) { + if (!BC.MIB->checkAllocatorExists(AllocId)) { + MCPlusBuilder::AllocatorIdTy Id = + BC.MIB->initializeNewAnnotationAllocator(); + (void)Id; + assert(AllocId == Id && "unexpected allocator id created"); + } + }; + if (opts::NoThreads || ForceSequential) { - runBlock(BC.getBinaryFunctions().begin(), BC.getBinaryFunctions().end(), 0); + EnsureAllocatorExists(AllocId); + runBlock(BC.getBinaryFunctions().begin(), BC.getBinaryFunctions().end(), + AllocId); return; } // This lock is used to postpone task execution @@ -205,19 +217,13 @@ void runOnEachFunctionWithUniqueAllocId( ThreadPoolInterface &Pool = getThreadPool(); auto BlockBegin = BC.getBinaryFunctions().begin(); unsigned CurrentCost = 0; - unsigned AllocId = 1; for (auto It = BC.getBinaryFunctions().begin(); It != BC.getBinaryFunctions().end(); ++It) { BinaryFunction &BF = It->second; CurrentCost += computeCostFor(BF, SkipPredicate, SchedPolicy); if (CurrentCost >= BlockCost) { - if (!BC.MIB->checkAllocatorExists(AllocId)) { - MCPlusBuilder::AllocatorIdTy Id = - BC.MIB->initializeNewAnnotationAllocator(); - (void)Id; - assert(AllocId == Id && "unexpected allocator id created"); - } + EnsureAllocatorExists(AllocId); Pool.async(runBlock, BlockBegin, std::next(It), AllocId); AllocId++; BlockBegin = std::next(It); @@ -225,12 +231,7 @@ void runOnEachFunctionWithUniqueAllocId( } } - if (!BC.MIB->checkAllocatorExists(AllocId)) { - MCPlusBuilder::AllocatorIdTy Id = - BC.MIB->initializeNewAnnotationAllocator(); - (void)Id; - assert(AllocId == Id && "unexpected allocator id created"); - } + EnsureAllocatorExists(AllocId); Pool.async(runBlock, BlockBegin, BC.getBinaryFunctions().end(), AllocId); Lock.unlock(); diff --git a/bolt/lib/Passes/BinaryPasses.cpp b/bolt/lib/Passes/BinaryPasses.cpp index c0ba73108f5778b4e385560c2129e6ef3bb056c8..298ba29ff5b3ff0404a9815f2a17cf95efa23ffc 100644 --- a/bolt/lib/Passes/BinaryPasses.cpp +++ b/bolt/lib/Passes/BinaryPasses.cpp @@ -674,7 +674,8 @@ static uint64_t fixDoubleJumps(BinaryFunction &Function, bool MarkInvalid) { MCPlusBuilder *MIB = Function.getBinaryContext().MIB.get(); for (BinaryBasicBlock &BB : Function) { auto checkAndPatch = [&](BinaryBasicBlock *Pred, BinaryBasicBlock *Succ, - const MCSymbol *SuccSym) { + const MCSymbol *SuccSym, + std::optional Offset) { // Ignore infinite loop jumps or fallthrough tail jumps. if (Pred == Succ || Succ == &BB) return false; @@ -715,6 +716,11 @@ static uint64_t fixDoubleJumps(BinaryFunction &Function, bool MarkInvalid) { Pred->removeSuccessor(&BB); Pred->eraseInstruction(Pred->findInstruction(Branch)); Pred->addTailCallInstruction(SuccSym); + if (Offset) { + MCInst *TailCall = Pred->getLastNonPseudoInstr(); + assert(TailCall); + MIB->setOffset(*TailCall, *Offset); + } } else { return false; } @@ -757,7 +763,8 @@ static uint64_t fixDoubleJumps(BinaryFunction &Function, bool MarkInvalid) { if (Pred->getSuccessor() == &BB || (Pred->getConditionalSuccessor(true) == &BB && !IsTailCall) || Pred->getConditionalSuccessor(false) == &BB) - if (checkAndPatch(Pred, Succ, SuccSym) && MarkInvalid) + if (checkAndPatch(Pred, Succ, SuccSym, MIB->getOffset(*Inst)) && + MarkInvalid) BB.markValid(BB.pred_size() != 0 || BB.isLandingPad() || BB.isEntryPoint()); } @@ -910,6 +917,11 @@ uint64_t SimplifyConditionalTailCalls::fixTailCalls(BinaryFunction &BF) { auto &CTCAnnotation = MIB->getOrCreateAnnotationAs(*CondBranch, "CTCTakenCount"); CTCAnnotation = CTCTakenFreq; + // Preserve Offset annotation, used in BAT. + // Instr is a direct tail call instruction that was created when CTCs are + // first expanded, and has the original CTC offset set. + if (std::optional Offset = MIB->getOffset(*Instr)) + MIB->setOffset(*CondBranch, *Offset); // Remove the unused successor which may be eliminated later // if there are no other users. diff --git a/bolt/lib/Passes/FrameAnalysis.cpp b/bolt/lib/Passes/FrameAnalysis.cpp index 7f1245e39f567b933ade802d06597c09f6edfe56..4ebfd8f158f7f56dbf632974f74cbd079f9cd265 100644 --- a/bolt/lib/Passes/FrameAnalysis.cpp +++ b/bolt/lib/Passes/FrameAnalysis.cpp @@ -561,11 +561,6 @@ FrameAnalysis::FrameAnalysis(BinaryContext &BC, BinaryFunctionCallGraph &CG) NamedRegionTimer T1("clearspt", "clear spt", "FA", "FA breakdown", opts::TimeFA); clearSPTMap(); - - // Clean up memory allocated for annotation values - if (!opts::NoThreads) - for (MCPlusBuilder::AllocatorIdTy Id : SPTAllocatorsId) - BC.MIB->freeValuesAllocator(Id); } } diff --git a/bolt/lib/Passes/Instrumentation.cpp b/bolt/lib/Passes/Instrumentation.cpp index 68acff7e6a867ccd94180651a6e54f36b83cffe8..14f506f9ca9689ad6ebb9735e24ac5c93b77b72a 100644 --- a/bolt/lib/Passes/Instrumentation.cpp +++ b/bolt/lib/Passes/Instrumentation.cpp @@ -480,7 +480,7 @@ void Instrumentation::instrumentFunction(BinaryFunction &Function, else if (BC.MIB->isUnconditionalBranch(Inst)) HasUnconditionalBranch = true; else if ((!BC.MIB->isCall(Inst) && !BC.MIB->isConditionalBranch(Inst)) || - BC.MIB->isUnsupportedBranch(Inst)) + !BC.MIB->isReversibleBranch(Inst)) continue; const uint32_t FromOffset = *BC.MIB->getOffset(Inst); diff --git a/bolt/lib/Passes/SplitFunctions.cpp b/bolt/lib/Passes/SplitFunctions.cpp index f9e634d15a97244c58adf185c0ea4ec80017079c..bd0b6dea0e065a0b9c723523692761f2c365977e 100644 --- a/bolt/lib/Passes/SplitFunctions.cpp +++ b/bolt/lib/Passes/SplitFunctions.cpp @@ -715,6 +715,12 @@ Error SplitFunctions::runOnFunctions(BinaryContext &BC) { if (!opts::SplitFunctions) return Error::success(); + if (BC.IsLinuxKernel && BC.BOLTReserved.empty()) { + BC.errs() << "BOLT-ERROR: split functions require reserved space in the " + "Linux kernel binary\n"; + exit(1); + } + // If split strategy is not CDSplit, then a second run of the pass is not // needed after function reordering. if (BC.HasFinalizedFunctionOrder && @@ -829,6 +835,13 @@ void SplitFunctions::splitFunction(BinaryFunction &BF, SplitStrategy &S) { } } } + + // Outlining blocks with dynamic branches is not supported yet. + if (BC.IsLinuxKernel) { + if (llvm::any_of( + *BB, [&](MCInst &Inst) { return BC.MIB->isDynamicBranch(Inst); })) + BB->setCanOutline(false); + } } BF.getLayout().updateLayoutIndices(); diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp index 5108392c824c1073638c4dcbb4b870b61dc8d5f4..e06debcee741e1270cf5f81d4afcc92e25a516f7 100644 --- a/bolt/lib/Profile/DataAggregator.cpp +++ b/bolt/lib/Profile/DataAggregator.cpp @@ -23,6 +23,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" @@ -773,9 +774,19 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc, bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count, uint64_t Mispreds) { + bool IsReturn = false; auto handleAddress = [&](uint64_t &Addr, bool IsFrom) -> BinaryFunction * { if (BinaryFunction *Func = getBinaryFunctionContainingAddress(Addr)) { Addr -= Func->getAddress(); + if (IsFrom) { + auto checkReturn = [&](auto MaybeInst) { + IsReturn = MaybeInst && BC->MIB->isReturn(*MaybeInst); + }; + if (Func->hasInstructions()) + checkReturn(Func->getInstructionAtOffset(Addr)); + else + checkReturn(Func->disassembleInstructionAtOffset(Addr)); + } if (BAT) Addr = BAT->translate(Func->getAddress(), Addr, IsFrom); @@ -792,6 +803,9 @@ bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count, }; BinaryFunction *FromFunc = handleAddress(From, /*IsFrom=*/true); + // Ignore returns. + if (IsReturn) + return true; BinaryFunction *ToFunc = handleAddress(To, /*IsFrom=*/false); if (!FromFunc && !ToFunc) return false; @@ -1450,7 +1464,7 @@ uint64_t DataAggregator::parseLBRSample(const PerfBranchSample &Sample, uint64_t To = getBinaryFunctionContainingAddress(LBR.To) ? LBR.To : 0; if (!From && !To) continue; - BranchInfo &Info = BranchLBRs[Trace(From, To)]; + TakenBranchInfo &Info = BranchLBRs[Trace(From, To)]; ++Info.TakenCount; Info.MispredCount += LBR.Mispred; } @@ -1595,7 +1609,7 @@ void DataAggregator::processBranchEvents() { for (const auto &AggrLBR : BranchLBRs) { const Trace &Loc = AggrLBR.first; - const BranchInfo &Info = AggrLBR.second; + const TakenBranchInfo &Info = AggrLBR.second; doBranch(Loc.From, Loc.To, Info.TakenCount, Info.MispredCount); } } @@ -1986,7 +2000,7 @@ std::error_code DataAggregator::parseMMapEvents() { std::pair FileMMapInfo = FileMMapInfoRes.get(); if (FileMMapInfo.second.PID == -1) continue; - if (FileMMapInfo.first.equals("(deleted)")) + if (FileMMapInfo.first == "(deleted)") continue; // Consider only the first mapping of the file for any given PID @@ -2239,13 +2253,13 @@ DataAggregator::writeAggregatedFile(StringRef OutputFilename) const { } else { for (const auto &KV : NamesToBranches) { const FuncBranchData &FBD = KV.second; - for (const llvm::bolt::BranchInfo &BI : FBD.Data) { + for (const BranchInfo &BI : FBD.Data) { writeLocation(BI.From); writeLocation(BI.To); OutFile << BI.Mispreds << " " << BI.Branches << "\n"; ++BranchValues; } - for (const llvm::bolt::BranchInfo &BI : FBD.EntryData) { + for (const BranchInfo &BI : FBD.EntryData) { // Do not output if source is a known symbol, since this was already // accounted for in the source function if (BI.From.IsSymbol) @@ -2326,7 +2340,7 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC, continue; BinaryFunction *BF = BC.getBinaryFunctionAtAddress(FuncAddress); assert(BF); - YamlBF.Name = FuncName.str(); + YamlBF.Name = getLocationName(*BF); YamlBF.Id = BF->getFunctionNumber(); YamlBF.Hash = BAT->getBFHash(FuncAddress); YamlBF.ExecCount = BF->getKnownExecutionCount(); @@ -2341,54 +2355,48 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC, for (auto BI = BlockMap.begin(), BE = BlockMap.end(); BI != BE; ++BI) YamlBF.Blocks[BI->second.getBBIndex()].Hash = BI->second.getBBHash(); - auto getSuccessorInfo = [&](uint32_t SuccOffset, unsigned SuccDataIdx) { - const llvm::bolt::BranchInfo &BI = Branches.Data.at(SuccDataIdx); - yaml::bolt::SuccessorInfo SI; - SI.Index = BlockMap.getBBIndex(SuccOffset); - SI.Count = BI.Branches; - SI.Mispreds = BI.Mispreds; - return SI; - }; - - auto getCallSiteInfo = [&](Location CallToLoc, unsigned CallToIdx, - uint32_t Offset) { - const llvm::bolt::BranchInfo &BI = Branches.Data.at(CallToIdx); - yaml::bolt::CallSiteInfo CSI; - CSI.DestId = 0; // designated for unknown functions - CSI.EntryDiscriminator = 0; - CSI.Count = BI.Branches; - CSI.Mispreds = BI.Mispreds; - CSI.Offset = Offset; - if (BinaryData *BD = BC.getBinaryDataByName(CallToLoc.Name)) - YAMLProfileWriter::setCSIDestination(BC, CSI, BD->getSymbol(), BAT, - CallToLoc.Offset); - return CSI; + // Lookup containing basic block offset and index + auto getBlock = [&BlockMap](uint32_t Offset) { + auto BlockIt = BlockMap.upper_bound(Offset); + if (LLVM_UNLIKELY(BlockIt == BlockMap.begin())) { + errs() << "BOLT-ERROR: invalid BAT section\n"; + exit(1); + } + --BlockIt; + return std::pair(BlockIt->first, BlockIt->second.getBBIndex()); }; - for (const auto &[FromOffset, SuccKV] : Branches.IntraIndex) { - if (!BlockMap.isInputBlock(FromOffset)) - continue; - const unsigned Index = BlockMap.getBBIndex(FromOffset); - yaml::bolt::BinaryBasicBlockProfile &YamlBB = YamlBF.Blocks[Index]; - for (const auto &[SuccOffset, SuccDataIdx] : SuccKV) - if (BlockMap.isInputBlock(SuccOffset)) - YamlBB.Successors.emplace_back( - getSuccessorInfo(SuccOffset, SuccDataIdx)); + for (const BranchInfo &BI : Branches.Data) { + using namespace yaml::bolt; + const auto &[BlockOffset, BlockIndex] = getBlock(BI.From.Offset); + BinaryBasicBlockProfile &YamlBB = YamlBF.Blocks[BlockIndex]; + if (BI.To.IsSymbol && BI.To.Name == BI.From.Name && BI.To.Offset != 0) { + // Internal branch + const unsigned SuccIndex = getBlock(BI.To.Offset).second; + auto &SI = YamlBB.Successors.emplace_back(SuccessorInfo{SuccIndex}); + SI.Count = BI.Branches; + SI.Mispreds = BI.Mispreds; + } else { + // Call + const uint32_t Offset = BI.From.Offset - BlockOffset; + auto &CSI = YamlBB.CallSites.emplace_back(CallSiteInfo{Offset}); + CSI.Count = BI.Branches; + CSI.Mispreds = BI.Mispreds; + if (const BinaryData *BD = BC.getBinaryDataByName(BI.To.Name)) + YAMLProfileWriter::setCSIDestination(BC, CSI, BD->getSymbol(), BAT, + BI.To.Offset); + } } - for (const auto &[FromOffset, CallTo] : Branches.InterIndex) { - auto BlockIt = BlockMap.upper_bound(FromOffset); - --BlockIt; - const unsigned BlockOffset = BlockIt->first; - const unsigned BlockIndex = BlockIt->second.getBBIndex(); - yaml::bolt::BinaryBasicBlockProfile &YamlBB = YamlBF.Blocks[BlockIndex]; - const uint32_t Offset = FromOffset - BlockOffset; - for (const auto &[CallToLoc, CallToIdx] : CallTo) - YamlBB.CallSites.emplace_back( - getCallSiteInfo(CallToLoc, CallToIdx, Offset)); - llvm::sort(YamlBB.CallSites, [](yaml::bolt::CallSiteInfo &A, - yaml::bolt::CallSiteInfo &B) { - return A.Offset < B.Offset; - }); + // Set entry counts, similar to DataReader::readProfile. + for (const BranchInfo &BI : Branches.EntryData) { + if (!BlockMap.isInputBlock(BI.To.Offset)) { + if (opts::Verbosity >= 1) + errs() << "BOLT-WARNING: Unexpected EntryData in " << FuncName + << " at 0x" << Twine::utohexstr(BI.To.Offset) << '\n'; + continue; + } + const unsigned BlockIndex = BlockMap.getBBIndex(BI.To.Offset); + YamlBF.Blocks[BlockIndex].ExecCount += BI.Branches; } // Drop blocks without a hash, won't be useful for stale matching. llvm::erase_if(YamlBF.Blocks, diff --git a/bolt/lib/Profile/DataReader.cpp b/bolt/lib/Profile/DataReader.cpp index 67f357fe4d3f0c42f704a52ca163e328652e7136..06c5e96b780643a947b6851ba8c36ca3b988f322 100644 --- a/bolt/lib/Profile/DataReader.cpp +++ b/bolt/lib/Profile/DataReader.cpp @@ -775,6 +775,7 @@ bool DataReader::recordBranch(BinaryFunction &BF, uint64_t From, uint64_t To, if (collectedInBoltedBinary() && FromBB == ToBB) return true; + // Allow passthrough blocks. BinaryBasicBlock *FTSuccessor = FromBB->getConditionalSuccessor(false); if (FTSuccessor && FTSuccessor->succ_size() == 1 && FTSuccessor->getSuccessor(ToBB->getLabel())) { @@ -1205,8 +1206,7 @@ std::error_code DataReader::parse() { // Add entry data for branches to another function or branches // to entry points (including recursive calls) - if (BI.To.IsSymbol && - (!BI.From.Name.equals(BI.To.Name) || BI.To.Offset == 0)) { + if (BI.To.IsSymbol && (BI.From.Name != BI.To.Name || BI.To.Offset == 0)) { I = GetOrCreateFuncEntry(BI.To.Name); I->second.EntryData.emplace_back(std::move(BI)); } diff --git a/bolt/lib/Profile/YAMLProfileReader.cpp b/bolt/lib/Profile/YAMLProfileReader.cpp index e4673f6e3c301dc2c385cac687b5b24a9e3e925b..29d94067f459fc0500211679083607b4cc8cfcc3 100644 --- a/bolt/lib/Profile/YAMLProfileReader.cpp +++ b/bolt/lib/Profile/YAMLProfileReader.cpp @@ -99,6 +99,9 @@ bool YAMLProfileReader::parseFunctionProfile( FuncRawBranchCount += YamlSI.Count; BF.setRawBranchCount(FuncRawBranchCount); + if (BF.empty()) + return true; + if (!opts::IgnoreHash && YamlBF.Hash != BF.computeHash(IsDFSOrder, HashFunction)) { if (opts::Verbosity >= 1) @@ -218,17 +221,28 @@ bool YAMLProfileReader::parseFunctionProfile( continue; } - BinaryBasicBlock &SuccessorBB = *Order[YamlSI.Index]; - if (!BB.getSuccessor(SuccessorBB.getLabel())) { - if (opts::Verbosity >= 1) - errs() << "BOLT-WARNING: no successor for block " << BB.getName() - << " that matches index " << YamlSI.Index << " or block " - << SuccessorBB.getName() << '\n'; - ++MismatchedEdges; - continue; + BinaryBasicBlock *ToBB = Order[YamlSI.Index]; + if (!BB.getSuccessor(ToBB->getLabel())) { + // Allow passthrough blocks. + BinaryBasicBlock *FTSuccessor = BB.getConditionalSuccessor(false); + if (FTSuccessor && FTSuccessor->succ_size() == 1 && + FTSuccessor->getSuccessor(ToBB->getLabel())) { + BinaryBasicBlock::BinaryBranchInfo &FTBI = + FTSuccessor->getBranchInfo(*ToBB); + FTBI.Count += YamlSI.Count; + FTBI.MispredictedCount += YamlSI.Mispreds; + ToBB = FTSuccessor; + } else { + if (opts::Verbosity >= 1) + errs() << "BOLT-WARNING: no successor for block " << BB.getName() + << " that matches index " << YamlSI.Index << " or block " + << ToBB->getName() << '\n'; + ++MismatchedEdges; + continue; + } } - BinaryBasicBlock::BinaryBranchInfo &BI = BB.getBranchInfo(SuccessorBB); + BinaryBasicBlock::BinaryBranchInfo &BI = BB.getBranchInfo(*ToBB); BI.Count += YamlSI.Count; BI.MispredictedCount += YamlSI.Mispreds; } diff --git a/bolt/lib/Rewrite/CMakeLists.txt b/bolt/lib/Rewrite/CMakeLists.txt index 6890f52e2b28bbf8a3bc4c9b569b157a4c432f68..578f1763bfe4ec9e5e345c4d5cc5ca102188400e 100644 --- a/bolt/lib/Rewrite/CMakeLists.txt +++ b/bolt/lib/Rewrite/CMakeLists.txt @@ -1,4 +1,5 @@ set(LLVM_LINK_COMPONENTS + Core DebugInfoDWARF DWP JITLink diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp index feeba89a40dc4d03c48b3836c0e27fa5f68903d7..d582ce7b33a27fbc56b4cbb8ac8a6cad88aa7645 100644 --- a/bolt/lib/Rewrite/DWARFRewriter.cpp +++ b/bolt/lib/Rewrite/DWARFRewriter.cpp @@ -458,32 +458,6 @@ static std::optional getAsAddress(const DWARFUnit &DU, return std::nullopt; } -/// Returns DWO Name to be used. Handles case where user specifies output DWO -/// directory, and there are duplicate names. Assumes DWO ID is unique. -static std::string -getDWOName(llvm::DWARFUnit &CU, - std::unordered_map &NameToIndexMap) { - std::optional DWOId = CU.getDWOId(); - assert(DWOId && "DWO ID not found."); - (void)DWOId; - - std::string DWOName = dwarf::toString( - CU.getUnitDIE().find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), - ""); - assert(!DWOName.empty() && - "DW_AT_dwo_name/DW_AT_GNU_dwo_name does not exists."); - if (!opts::DwarfOutputPath.empty()) { - DWOName = std::string(sys::path::filename(DWOName)); - auto Iter = NameToIndexMap.find(DWOName); - if (Iter == NameToIndexMap.end()) - Iter = NameToIndexMap.insert({DWOName, 0}).first; - DWOName.append(std::to_string(Iter->second)); - ++Iter->second; - } - DWOName.append(".dwo"); - return DWOName; -} - static std::unique_ptr createDIEStreamer(const Triple &TheTriple, raw_pwrite_stream &OutFile, StringRef Swift5ReflectionSegmentName, DIEBuilder &DIEBldr, @@ -515,7 +489,9 @@ static void emitDWOBuilder(const std::string &DWOName, DIEBuilder &DWODIEBuilder, DWARFRewriter &Rewriter, DWARFUnit &SplitCU, DWARFUnit &CU, DWARFRewriter::DWPState &State, - DebugLocWriter &LocWriter) { + DebugLocWriter &LocWriter, + DebugStrOffsetsWriter &StrOffstsWriter, + DebugStrWriter &StrWriter) { // Populate debug_info and debug_abbrev for current dwo into StringRef. DWODIEBuilder.generateAbbrevs(); DWODIEBuilder.finish(); @@ -577,22 +553,10 @@ static void emitDWOBuilder(const std::string &DWOName, } if (opts::WriteDWP) Rewriter.updateDWP(CU, OverriddenSections, CUMI, TUMetaVector, State, - LocWriter); + LocWriter, StrOffstsWriter, StrWriter); else - Rewriter.writeDWOFiles(CU, OverriddenSections, DWOName, LocWriter); -} - -void DWARFRewriter::addStringHelper(DIEBuilder &DIEBldr, DIE &Die, - const DWARFUnit &Unit, - DIEValue &DIEAttrInfo, StringRef Str) { - uint32_t NewOffset = StrWriter->addString(Str); - if (Unit.getVersion() >= 5) { - StrOffstsWriter->updateAddressMap(DIEAttrInfo.getDIEInteger().getValue(), - NewOffset); - return; - } - DIEBldr.replaceValue(&Die, DIEAttrInfo.getAttribute(), DIEAttrInfo.getForm(), - DIEInteger(NewOffset)); + Rewriter.writeDWOFiles(CU, OverriddenSections, DWOName, LocWriter, + StrOffstsWriter, StrWriter); } using DWARFUnitVec = std::vector; @@ -641,9 +605,8 @@ void DWARFRewriter::updateDebugInfo() { return; ARangesSectionWriter = std::make_unique(); - StrWriter = std::make_unique(BC); - - StrOffstsWriter = std::make_unique(); + StrWriter = std::make_unique(*BC.DwCtx, false); + StrOffstsWriter = std::make_unique(BC); if (!opts::DeterministicDebugInfo) { opts::DeterministicDebugInfo = true; @@ -688,37 +651,6 @@ void DWARFRewriter::updateDebugInfo() { return LocListWritersByCU[CUIndex++].get(); }; - // Unordered maps to handle name collision if output DWO directory is - // specified. - std::unordered_map NameToIndexMap; - - auto updateDWONameCompDir = [&](DWARFUnit &Unit, DIEBuilder &DIEBldr, - DIE &UnitDIE) -> std::string { - DIEValue DWONameAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_dwo_name); - if (!DWONameAttrInfo) - DWONameAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_GNU_dwo_name); - assert(DWONameAttrInfo && "DW_AT_dwo_name is not in Skeleton CU."); - std::string ObjectName; - - { - std::lock_guard Lock(AccessMutex); - ObjectName = getDWOName(Unit, NameToIndexMap); - } - addStringHelper(DIEBldr, UnitDIE, Unit, DWONameAttrInfo, - ObjectName.c_str()); - - DIEValue CompDirAttrInfo = UnitDIE.findAttribute(dwarf::DW_AT_comp_dir); - assert(CompDirAttrInfo && "DW_AT_comp_dir is not in Skeleton CU."); - - if (!opts::DwarfOutputPath.empty()) { - if (!sys::fs::exists(opts::DwarfOutputPath)) - sys::fs::create_directory(opts::DwarfOutputPath); - addStringHelper(DIEBldr, UnitDIE, Unit, CompDirAttrInfo, - opts::DwarfOutputPath.c_str()); - } - return ObjectName; - }; - DWARF5AcceleratorTable DebugNamesTable(opts::CreateDebugNames, BC, *StrWriter); DWPState State; @@ -741,9 +673,21 @@ void DWARFRewriter::updateDebugInfo() { DIEBuilder DWODIEBuilder(BC, &(*SplitCU)->getContext(), DebugNamesTable, Unit); DWODIEBuilder.buildDWOUnit(**SplitCU); - std::string DWOName = updateDWONameCompDir( - *Unit, *DIEBlder, *DIEBlder->getUnitDIEbyUnit(*Unit)); - + std::string DWOName = ""; + std::optional DwarfOutputPath = + opts::DwarfOutputPath.empty() + ? std::nullopt + : std::optional(opts::DwarfOutputPath.c_str()); + { + std::lock_guard Lock(AccessMutex); + DWOName = DIEBlder->updateDWONameCompDir( + *StrOffstsWriter, *StrWriter, *Unit, DwarfOutputPath, std::nullopt); + } + DebugStrOffsetsWriter DWOStrOffstsWriter(BC); + DebugStrWriter DWOStrWriter((*SplitCU)->getContext(), true); + DWODIEBuilder.updateDWONameCompDirForTypes(DWOStrOffstsWriter, + DWOStrWriter, **SplitCU, + DwarfOutputPath, DWOName); DebugLoclistWriter DebugLocDWoWriter(*Unit, Unit->getVersion(), true); DebugRangesSectionWriter *TempRangesSectionWriter = RangesSectionWriter; if (Unit->getVersion() >= 5) { @@ -761,7 +705,7 @@ void DWARFRewriter::updateDebugInfo() { TempRangesSectionWriter->finalizeSection(); emitDWOBuilder(DWOName, DWODIEBuilder, *this, **SplitCU, *Unit, State, - DebugLocDWoWriter); + DebugLocDWoWriter, DWOStrOffstsWriter, DWOStrWriter); } if (Unit->getVersion() >= 5) { @@ -1540,7 +1484,7 @@ CUOffsetMap DWARFRewriter::finalizeTypeSections(DIEBuilder &DIEBlder, for (const SectionRef &Section : Obj->sections()) { StringRef Contents = cantFail(Section.getContents()); StringRef Name = cantFail(Section.getName()); - if (Name.equals(".debug_types")) + if (Name == ".debug_types") BC.registerOrUpdateNoteSection(".debug_types", copyByteArray(Contents), Contents.size()); } @@ -1623,10 +1567,10 @@ void DWARFRewriter::finalizeDebugSections( for (const SectionRef &Secs : Obj->sections()) { StringRef Contents = cantFail(Secs.getContents()); StringRef Name = cantFail(Secs.getName()); - if (Name.equals(".debug_abbrev")) { + if (Name == ".debug_abbrev") { BC.registerOrUpdateNoteSection(".debug_abbrev", copyByteArray(Contents), Contents.size()); - } else if (Name.equals(".debug_info")) { + } else if (Name == ".debug_info") { BC.registerOrUpdateNoteSection(".debug_info", copyByteArray(Contents), Contents.size()); } @@ -1726,6 +1670,7 @@ std::optional updateDebugData( const DWARFUnitIndex::Entry *CUDWOEntry, uint64_t DWOId, std::unique_ptr &OutputBuffer, DebugRangeListsSectionWriter *RangeListsWriter, DebugLocWriter &LocWriter, + DebugStrOffsetsWriter &StrOffstsWriter, DebugStrWriter &StrWriter, const llvm::bolt::DWARFRewriter::OverriddenSectionsMap &OverridenSections) { using DWOSectionContribution = @@ -1761,9 +1706,14 @@ std::optional updateDebugData( }; switch (SectionIter->second.second) { default: { - if (!SectionName.equals("debug_str.dwo")) + if (SectionName != "debug_str.dwo") errs() << "BOLT-WARNING: unsupported debug section: " << SectionName << "\n"; + if (StrWriter.isInitialized()) { + OutputBuffer = StrWriter.releaseBuffer(); + return StringRef(reinterpret_cast(OutputBuffer->data()), + OutputBuffer->size()); + } return SectionContents; } case DWARFSectionKind::DW_SECT_INFO: { @@ -1773,6 +1723,11 @@ std::optional updateDebugData( return getOverridenSection(DWARFSectionKind::DW_SECT_EXT_TYPES); } case DWARFSectionKind::DW_SECT_STR_OFFSETS: { + if (StrOffstsWriter.isFinalized()) { + OutputBuffer = StrOffstsWriter.releaseBuffer(); + return StringRef(reinterpret_cast(OutputBuffer->data()), + OutputBuffer->size()); + } return getSliceData(CUDWOEntry, SectionContents, DWARFSectionKind::DW_SECT_STR_OFFSETS, DWPOffset); } @@ -1874,7 +1829,9 @@ void DWARFRewriter::updateDWP(DWARFUnit &CU, const OverriddenSectionsMap &OverridenSections, const DWARFRewriter::UnitMeta &CUMI, DWARFRewriter::UnitMetaVectorType &TUMetaVector, - DWPState &State, DebugLocWriter &LocWriter) { + DWPState &State, DebugLocWriter &LocWriter, + DebugStrOffsetsWriter &StrOffstsWriter, + DebugStrWriter &StrWriter) { const uint64_t DWOId = *CU.getDWOId(); MCSection *const StrOffsetSection = State.MCOFI->getDwarfStrOffDWOSection(); assert(StrOffsetSection && "StrOffsetSection does not exist."); @@ -1931,15 +1888,18 @@ void DWARFRewriter::updateDWP(DWARFUnit &CU, TUEntry.Contributions[Index].getLength32(); State.TypeIndexEntries.insert(std::make_pair(Hash, TUEntry)); }; + std::unique_ptr StrOffsetsOutputData; + std::unique_ptr StrOutputData; for (const SectionRef &Section : DWOFile->sections()) { - std::unique_ptr OutputData; + std::unique_ptr OutputData = nullptr; StringRef SectionName = getSectionName(Section); Expected ContentsExp = Section.getContents(); assert(ContentsExp && "Invalid contents."); - std::optional TOutData = updateDebugData( - (*DWOCU)->getContext(), SectionName, *ContentsExp, State.KnownSections, - *State.Streamer, *this, CUDWOEntry, DWOId, OutputData, - RangeListssWriter, LocWriter, OverridenSections); + std::optional TOutData = + updateDebugData((*DWOCU)->getContext(), SectionName, *ContentsExp, + State.KnownSections, *State.Streamer, *this, CUDWOEntry, + DWOId, OutputData, RangeListssWriter, LocWriter, + StrOffstsWriter, StrWriter, OverridenSections); if (!TOutData) continue; @@ -1949,16 +1909,19 @@ void DWARFRewriter::updateDWP(DWARFUnit &CU, continue; } - if (SectionName.equals("debug_str.dwo")) { + if (SectionName == "debug_str.dwo") { CurStrSection = OutData; + StrOutputData = std::move(OutputData); } else { // Since handleDebugDataPatching returned true, we already know this is // a known section. auto SectionIter = State.KnownSections.find(SectionName); - if (SectionIter->second.second == DWARFSectionKind::DW_SECT_STR_OFFSETS) + if (SectionIter->second.second == DWARFSectionKind::DW_SECT_STR_OFFSETS) { CurStrOffsetSection = OutData; - else + StrOffsetsOutputData = std::move(OutputData); + } else { State.Streamer->emitBytes(OutData); + } unsigned int Index = getContributionIndex(SectionIter->second.second, State.IndexVersion); uint64_t Offset = State.ContributionOffsets[Index]; @@ -1982,6 +1945,10 @@ void DWARFRewriter::updateDWP(DWARFUnit &CU, // based on hash. if (!StrSectionWrittenOut && !CurStrOffsetSection.empty() && !CurStrSection.empty()) { + // If debug_str.dwo section was modified storing it until dwp is written + // out. DWPStringPool stores raw pointers to strings. + if (StrOutputData) + State.StrSections.push_back(std::move(StrOutputData)); writeStringsAndOffsets(*State.Streamer.get(), *State.Strings.get(), StrOffsetSection, CurStrSection, CurStrOffsetSection, CU.getVersion()); @@ -2007,7 +1974,8 @@ void DWARFRewriter::updateDWP(DWARFUnit &CU, void DWARFRewriter::writeDWOFiles( DWARFUnit &CU, const OverriddenSectionsMap &OverridenSections, - const std::string &DWOName, DebugLocWriter &LocWriter) { + const std::string &DWOName, DebugLocWriter &LocWriter, + DebugStrOffsetsWriter &StrOffstsWriter, DebugStrWriter &StrWriter) { // Setup DWP code once. DWARFContext *DWOCtx = BC.getDWOContext(); const uint64_t DWOId = *CU.getDWOId(); @@ -2062,10 +2030,11 @@ void DWARFRewriter::writeDWOFiles( // have .debug_rnglists so won't be part of the loop below. if (!RangeListssWriter->empty()) { std::unique_ptr OutputData; - if (std::optional OutData = updateDebugData( - (*DWOCU)->getContext(), "debug_rnglists.dwo", "", KnownSections, - *Streamer, *this, CUDWOEntry, DWOId, OutputData, - RangeListssWriter, LocWriter, OverridenSections)) + if (std::optional OutData = + updateDebugData((*DWOCU)->getContext(), "debug_rnglists.dwo", "", + KnownSections, *Streamer, *this, CUDWOEntry, + DWOId, OutputData, RangeListssWriter, LocWriter, + StrOffstsWriter, StrWriter, OverridenSections)) Streamer->emitBytes(*OutData); } } @@ -2080,7 +2049,7 @@ void DWARFRewriter::writeDWOFiles( if (std::optional OutData = updateDebugData( (*DWOCU)->getContext(), SectionName, *ContentsExp, KnownSections, *Streamer, *this, CUDWOEntry, DWOId, OutputData, RangeListssWriter, - LocWriter, OverridenSections)) + LocWriter, StrOffstsWriter, StrWriter, OverridenSections)) Streamer->emitBytes(*OutData); } Streamer->finish(); diff --git a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp index 17077b4fa2487adfaf2c05a514fb48c750751d38..99775ccfe38d30f427915d3f015397cc37726756 100644 --- a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp +++ b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp @@ -62,6 +62,11 @@ static cl::opt cl::desc("dump Linux kernel PCI fixup table"), cl::init(false), cl::Hidden, cl::cat(BoltCategory)); +static cl::opt DumpSMPLocks("dump-smp-locks", + cl::desc("dump Linux kernel SMP locks"), + cl::init(false), cl::Hidden, + cl::cat(BoltCategory)); + static cl::opt DumpStaticCalls("dump-static-calls", cl::desc("dump Linux kernel static calls"), cl::init(false), cl::Hidden, @@ -119,19 +124,18 @@ inline raw_ostream &operator<<(raw_ostream &OS, const ORCState &E) { namespace { class LinuxKernelRewriter final : public MetadataRewriter { - /// Linux Kernel special sections point to a specific instruction in many - /// cases. Unlike SDTMarkerInfo, these markers can come from different - /// sections. - struct LKInstructionMarkerInfo { - uint64_t SectionOffset; - int32_t PCRelativeOffset; - bool IsPCRelative; - StringRef SectionName; + /// Information required for updating metadata referencing an instruction. + struct InstructionFixup { + BinarySection &Section; // Section referencing the instruction. + uint64_t Offset; // Offset in the section above. + BinaryFunction &BF; // Function containing the instruction. + MCSymbol &Label; // Label marking the instruction. + bool IsPCRelative; // If the reference type is relative. }; + std::vector Fixups; - /// Map linux kernel program locations/instructions to their pointers in - /// special linux kernel sections - std::unordered_map> LKMarkers; + /// Size of an entry in .smp_locks section. + static constexpr size_t SMP_LOCKS_ENTRY_SIZE = 4; /// Linux ORC sections. ErrorOr ORCUnwindSection = std::errc::bad_address; @@ -221,23 +225,20 @@ class LinuxKernelRewriter final : public MetadataRewriter { ErrorOr PCIFixupSection = std::errc::bad_address; static constexpr size_t PCI_FIXUP_ENTRY_SIZE = 16; - /// Insert an LKMarker for a given code pointer \p PC from a non-code section - /// \p SectionName. - void insertLKMarker(uint64_t PC, uint64_t SectionOffset, - int32_t PCRelativeOffset, bool IsPCRelative, - StringRef SectionName); - /// Process linux kernel special sections and their relocations. void processLKSections(); /// Process __ksymtab and __ksymtab_gpl. void processLKKSymtab(bool IsGPL = false); - /// Process special linux kernel section, .smp_locks. - void processLKSMPLocks(); + // Create relocations in sections requiring fixups. + // + // Make sure functions that will not be emitted are marked as such before this + // function is executed. + void processInstructionFixups(); - /// Update LKMarkers' locations for the output binary. - void updateLKMarkers(); + /// Process .smp_locks section. + Error processSMPLocks(); /// Read ORC unwind information and annotate instructions. Error readORCTables(); @@ -282,16 +283,14 @@ class LinuxKernelRewriter final : public MetadataRewriter { Error rewriteStaticKeysJumpTable(); Error updateStaticKeysJumpTablePostEmit(); - /// Mark instructions referenced by kernel metadata. - Error markInstructions(); - public: LinuxKernelRewriter(BinaryContext &BC) : MetadataRewriter("linux-kernel-rewriter", BC) {} Error preCFGInitializer() override { processLKSections(); - if (Error E = markInstructions()) + + if (Error E = processSMPLocks()) return E; if (Error E = readORCTables()) @@ -352,12 +351,12 @@ public: if (Error E = rewriteBugTable()) return E; + processInstructionFixups(); + return Error::success(); } Error postEmitFinalizer() override { - updateLKMarkers(); - if (Error E = updateStaticKeysJumpTablePostEmit()) return E; @@ -368,39 +367,9 @@ public: } }; -Error LinuxKernelRewriter::markInstructions() { - for (const uint64_t PC : llvm::make_first_range(LKMarkers)) { - BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(PC); - - if (!BF || !BC.shouldEmit(*BF)) - continue; - - const uint64_t Offset = PC - BF->getAddress(); - MCInst *Inst = BF->getInstructionAtOffset(Offset); - if (!Inst) - return createStringError(errc::executable_format_error, - "no instruction matches kernel marker offset"); - - BC.MIB->setOffset(*Inst, static_cast(Offset)); - - BF->setHasSDTMarker(true); - } - - return Error::success(); -} - -void LinuxKernelRewriter::insertLKMarker(uint64_t PC, uint64_t SectionOffset, - int32_t PCRelativeOffset, - bool IsPCRelative, - StringRef SectionName) { - LKMarkers[PC].emplace_back(LKInstructionMarkerInfo{ - SectionOffset, PCRelativeOffset, IsPCRelative, SectionName}); -} - void LinuxKernelRewriter::processLKSections() { processLKKSymtab(); processLKKSymtab(true); - processLKSMPLocks(); } /// Process __ksymtab[_gpl] sections of Linux Kernel. @@ -439,79 +408,73 @@ void LinuxKernelRewriter::processLKKSymtab(bool IsGPL) { /// .smp_locks section contains PC-relative references to instructions with LOCK /// prefix. The prefix can be converted to NOP at boot time on non-SMP systems. -void LinuxKernelRewriter::processLKSMPLocks() { - ErrorOr SectionOrError = +Error LinuxKernelRewriter::processSMPLocks() { + ErrorOr SMPLocksSection = BC.getUniqueSectionByName(".smp_locks"); - if (!SectionOrError) - return; + if (!SMPLocksSection) + return Error::success(); - uint64_t SectionSize = SectionOrError->getSize(); - const uint64_t SectionAddress = SectionOrError->getAddress(); - assert((SectionSize % 4) == 0 && - "The size of the .smp_locks section should be a multiple of 4"); + const uint64_t SectionSize = SMPLocksSection->getSize(); + const uint64_t SectionAddress = SMPLocksSection->getAddress(); + if (SectionSize % SMP_LOCKS_ENTRY_SIZE) + return createStringError(errc::executable_format_error, + "bad size of .smp_locks section"); - for (uint64_t I = 0; I < SectionSize; I += 4) { - const uint64_t EntryAddress = SectionAddress + I; - ErrorOr Offset = BC.getSignedValueAtAddress(EntryAddress, 4); - assert(Offset && "Reading valid PC-relative offset for a .smp_locks entry"); - int32_t SignedOffset = *Offset; - uint64_t RefAddress = EntryAddress + SignedOffset; + DataExtractor DE = DataExtractor(SMPLocksSection->getContents(), + BC.AsmInfo->isLittleEndian(), + BC.AsmInfo->getCodePointerSize()); + DataExtractor::Cursor Cursor(0); + while (Cursor && Cursor.tell() < SectionSize) { + const uint64_t Offset = Cursor.tell(); + const uint64_t IP = SectionAddress + Offset + (int32_t)DE.getU32(Cursor); + + // Consume the status of the cursor. + if (!Cursor) + return createStringError(errc::executable_format_error, + "error while reading .smp_locks: %s", + toString(Cursor.takeError()).c_str()); + + if (opts::DumpSMPLocks) + BC.outs() << "SMP lock at 0x: " << Twine::utohexstr(IP) << '\n'; - BinaryFunction *ContainingBF = - BC.getBinaryFunctionContainingAddress(RefAddress); - if (!ContainingBF) + BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(IP); + if (!BF || !BC.shouldEmit(*BF)) continue; - insertLKMarker(RefAddress, I, SignedOffset, true, ".smp_locks"); - } -} + MCInst *Inst = BF->getInstructionAtOffset(IP - BF->getAddress()); + if (!Inst) + return createStringError(errc::executable_format_error, + "no instruction matches lock at 0x%" PRIx64, IP); -void LinuxKernelRewriter::updateLKMarkers() { - if (LKMarkers.size() == 0) - return; + // Check for duplicate entries. + if (BC.MIB->hasAnnotation(*Inst, "SMPLock")) + return createStringError(errc::executable_format_error, + "duplicate SMP lock at 0x%" PRIx64, IP); - std::unordered_map PatchCounts; - for (std::pair> - &LKMarkerInfoKV : LKMarkers) { - const uint64_t OriginalAddress = LKMarkerInfoKV.first; - const BinaryFunction *BF = - BC.getBinaryFunctionContainingAddress(OriginalAddress, false, true); - if (!BF) - continue; + BC.MIB->addAnnotation(*Inst, "SMPLock", true); + MCSymbol *Label = + BC.MIB->getOrCreateInstLabel(*Inst, "__SMPLock_", BC.Ctx.get()); - uint64_t NewAddress = BF->translateInputToOutputAddress(OriginalAddress); - if (NewAddress == 0) - continue; + Fixups.push_back({*SMPLocksSection, Offset, *BF, *Label, + /*IsPCRelative*/ true}); + } - // Apply base address. - if (OriginalAddress >= 0xffffffff00000000 && NewAddress < 0xffffffff) - NewAddress = NewAddress + 0xffffffff00000000; + const uint64_t NumEntries = SectionSize / SMP_LOCKS_ENTRY_SIZE; + BC.outs() << "BOLT-INFO: parsed " << NumEntries << " SMP lock entries\n"; - if (OriginalAddress == NewAddress) + return Error::success(); +} + +void LinuxKernelRewriter::processInstructionFixups() { + for (InstructionFixup &Fixup : Fixups) { + if (!BC.shouldEmit(Fixup.BF)) continue; - for (LKInstructionMarkerInfo &LKMarkerInfo : LKMarkerInfoKV.second) { - StringRef SectionName = LKMarkerInfo.SectionName; - SimpleBinaryPatcher *LKPatcher; - ErrorOr BSec = BC.getUniqueSectionByName(SectionName); - assert(BSec && "missing section info for kernel section"); - if (!BSec->getPatcher()) - BSec->registerPatcher(std::make_unique()); - LKPatcher = static_cast(BSec->getPatcher()); - PatchCounts[std::string(SectionName)]++; - if (LKMarkerInfo.IsPCRelative) - LKPatcher->addLE32Patch(LKMarkerInfo.SectionOffset, - NewAddress - OriginalAddress + - LKMarkerInfo.PCRelativeOffset); - else - LKPatcher->addLE64Patch(LKMarkerInfo.SectionOffset, NewAddress); - } + Fixup.Section.addRelocation(Fixup.Offset, &Fixup.Label, + Fixup.IsPCRelative ? ELF::R_X86_64_PC32 + : ELF::R_X86_64_64, + /*Addend*/ 0); } - BC.outs() << "BOLT-INFO: patching linux kernel sections. Total patches per " - "section are as follows:\n"; - for (const std::pair &KV : PatchCounts) - BC.outs() << " Section: " << KV.first << ", patch-counts: " << KV.second - << '\n'; } Error LinuxKernelRewriter::readORCTables() { @@ -783,11 +746,9 @@ Error LinuxKernelRewriter::rewriteORCTables() { }; // Emit new ORC entries for the emitted function. - auto emitORC = [&](const BinaryFunction &BF) -> Error { - assert(!BF.isSplit() && "Split functions not supported by ORC writer yet."); - + auto emitORC = [&](const FunctionFragment &FF) -> Error { ORCState CurrentState = NullORC; - for (BinaryBasicBlock *BB : BF.getLayout().blocks()) { + for (BinaryBasicBlock *BB : FF) { for (MCInst &Inst : *BB) { ErrorOr ErrorOrState = BC.MIB->tryGetAnnotationAs(Inst, "ORC"); @@ -808,7 +769,36 @@ Error LinuxKernelRewriter::rewriteORCTables() { return Error::success(); }; + // Emit ORC entries for cold fragments. We assume that these fragments are + // emitted contiguously in memory using reserved space in the kernel. This + // assumption is validated in post-emit pass validateORCTables() where we + // check that ORC entries are sorted by their addresses. + auto emitColdORC = [&]() -> Error { + for (BinaryFunction &BF : + llvm::make_second_range(BC.getBinaryFunctions())) { + if (!BC.shouldEmit(BF)) + continue; + for (FunctionFragment &FF : BF.getLayout().getSplitFragments()) + if (Error E = emitORC(FF)) + return E; + } + + return Error::success(); + }; + + bool ShouldEmitCold = !BC.BOLTReserved.empty(); for (ORCListEntry &Entry : ORCEntries) { + if (ShouldEmitCold && Entry.IP > BC.BOLTReserved.start()) { + if (Error E = emitColdORC()) + return E; + + // Emit terminator entry at the end of the reserved region. + if (Error E = emitORCEntry(BC.BOLTReserved.end(), NullORC)) + return E; + + ShouldEmitCold = false; + } + // Emit original entries for functions that we haven't modified. if (!Entry.BF || !BC.shouldEmit(*Entry.BF)) { // Emit terminator only if it marks the start of a function. @@ -822,7 +812,7 @@ Error LinuxKernelRewriter::rewriteORCTables() { // Emit all ORC entries for a function referenced by an entry and skip over // the rest of entries for this function by resetting its ORC attribute. if (Entry.BF->hasORC()) { - if (Error E = emitORC(*Entry.BF)) + if (Error E = emitORC(Entry.BF->getLayout().getMainFragment())) return E; Entry.BF->setHasORC(false); } @@ -831,10 +821,9 @@ Error LinuxKernelRewriter::rewriteORCTables() { LLVM_DEBUG(dbgs() << "BOLT-DEBUG: emitted " << NumEmitted << " ORC entries\n"); - // Replicate terminator entry at the end of sections to match the original - // table sizes. - const BinaryFunction &LastBF = BC.getBinaryFunctions().rbegin()->second; - const uint64_t LastIP = LastBF.getAddress() + LastBF.getMaxSize(); + // Populate ORC tables with a terminator entry with max address to match the + // original table sizes. + const uint64_t LastIP = std::numeric_limits::max(); while (UnwindWriter.bytesRemaining()) { if (Error E = emitORCEntry(LastIP, NullORC, nullptr, /*Force*/ true)) return E; @@ -1696,6 +1685,9 @@ Error LinuxKernelRewriter::readStaticKeysJumpTable() { if (!BC.MIB->getSize(*Inst)) BC.MIB->setSize(*Inst, Size); + if (!BC.MIB->getOffset(*Inst)) + BC.MIB->setOffset(*Inst, JumpAddress - BF->getAddress()); + if (opts::LongJumpLabels) BC.MIB->setSize(*Inst, 5); } diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 23f79e3c135a78f7b7f82e25d91c8987f31775b6..85b39176754b64187b37542f8bb866a22f87cbd1 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -1347,6 +1347,35 @@ void RewriteInstance::discoverFileObjects() { registerFragments(); FileSymbols.clear(); + + discoverBOLTReserved(); +} + +void RewriteInstance::discoverBOLTReserved() { + BinaryData *StartBD = BC->getBinaryDataByName(getBOLTReservedStart()); + BinaryData *EndBD = BC->getBinaryDataByName(getBOLTReservedEnd()); + if (!StartBD != !EndBD) { + BC->errs() << "BOLT-ERROR: one of the symbols is missing from the binary: " + << getBOLTReservedStart() << ", " << getBOLTReservedEnd() + << '\n'; + exit(1); + } + + if (!StartBD) + return; + + if (StartBD->getAddress() >= EndBD->getAddress()) { + BC->errs() << "BOLT-ERROR: invalid reserved space boundaries\n"; + exit(1); + } + BC->BOLTReserved = AddressRange(StartBD->getAddress(), EndBD->getAddress()); + BC->outs() << "BOLT-INFO: using reserved space for allocating new sections\n"; + + PHDRTableOffset = 0; + PHDRTableAddress = 0; + NewTextSegmentAddress = 0; + NewTextSegmentOffset = 0; + NextAvailableAddress = BC->BOLTReserved.start(); } Error RewriteInstance::discoverRtFiniAddress() { @@ -3617,26 +3646,6 @@ void RewriteInstance::updateMetadata() { void RewriteInstance::mapFileSections(BOLTLinker::SectionMapper MapSection) { BC->deregisterUnusedSections(); - // Check if the input has a space reserved for BOLT. - BinaryData *StartBD = BC->getBinaryDataByName(getBOLTReservedStart()); - BinaryData *EndBD = BC->getBinaryDataByName(getBOLTReservedEnd()); - if (!StartBD != !EndBD) { - BC->errs() << "BOLT-ERROR: one of the symbols is missing from the binary: " - << getBOLTReservedStart() << ", " << getBOLTReservedEnd() - << '\n'; - exit(1); - } - - if (StartBD) { - PHDRTableOffset = 0; - PHDRTableAddress = 0; - NewTextSegmentAddress = 0; - NewTextSegmentOffset = 0; - NextAvailableAddress = StartBD->getAddress(); - BC->outs() - << "BOLT-INFO: using reserved space for allocating new sections\n"; - } - // If no new .eh_frame was written, remove relocated original .eh_frame. BinarySection *RelocatedEHFrameSection = getSection(".relocated" + getEHFrameSectionName()); @@ -3657,12 +3666,12 @@ void RewriteInstance::mapFileSections(BOLTLinker::SectionMapper MapSection) { // Map the rest of the sections. mapAllocatableSections(MapSection); - if (StartBD) { - const uint64_t ReservedSpace = EndBD->getAddress() - StartBD->getAddress(); - const uint64_t AllocatedSize = NextAvailableAddress - StartBD->getAddress(); - if (ReservedSpace < AllocatedSize) { - BC->errs() << "BOLT-ERROR: reserved space (" << ReservedSpace << " byte" - << (ReservedSpace == 1 ? "" : "s") + if (!BC->BOLTReserved.empty()) { + const uint64_t AllocatedSize = + NextAvailableAddress - BC->BOLTReserved.start(); + if (BC->BOLTReserved.size() < AllocatedSize) { + BC->errs() << "BOLT-ERROR: reserved space (" << BC->BOLTReserved.size() + << " byte" << (BC->BOLTReserved.size() == 1 ? "" : "s") << ") is smaller than required for new allocations (" << AllocatedSize << " bytes)\n"; exit(1); @@ -5852,13 +5861,11 @@ void RewriteInstance::writeEHFrameHeader() { NextAvailableAddress += EHFrameHdrSec.getOutputSize(); - if (const BinaryData *ReservedEnd = - BC->getBinaryDataByName(getBOLTReservedEnd())) { - if (NextAvailableAddress > ReservedEnd->getAddress()) { - BC->errs() << "BOLT-ERROR: unable to fit " << getEHFrameHdrSectionName() - << " into reserved space\n"; - exit(1); - } + if (!BC->BOLTReserved.empty() && + (NextAvailableAddress > BC->BOLTReserved.end())) { + BC->errs() << "BOLT-ERROR: unable to fit " << getEHFrameHdrSectionName() + << " into reserved space\n"; + exit(1); } // Merge new .eh_frame with the relocated original so that gdb can locate all @@ -5892,7 +5899,7 @@ uint64_t RewriteInstance::getNewValueForSymbol(const StringRef Name) { uint64_t RewriteInstance::getFileOffsetForAddress(uint64_t Address) const { // Check if it's possibly part of the new segment. - if (Address >= NewTextSegmentAddress) + if (NewTextSegmentAddress && Address >= NewTextSegmentAddress) return Address - NewTextSegmentAddress + NewTextSegmentOffset; // Find an existing segment that matches the address. diff --git a/bolt/lib/Rewrite/SDTRewriter.cpp b/bolt/lib/Rewrite/SDTRewriter.cpp index cc663b28990f8efbc0af0287184a9aff40b63a0e..a3928c554ad66c2c65b6cd3b39c4f070ef37e862 100644 --- a/bolt/lib/Rewrite/SDTRewriter.cpp +++ b/bolt/lib/Rewrite/SDTRewriter.cpp @@ -87,7 +87,7 @@ void SDTRewriter::readSection() { StringRef Name = DE.getCStr(&Offset); - if (!Name.equals("stapsdt")) + if (Name != "stapsdt") errs() << "BOLT-WARNING: SDT note name \"" << Name << "\" is not expected\n"; diff --git a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp index 8b1894953f3757f036aa2d7e58f2f033861b0efd..8fdacffcb147b69ef8306fd915cb4c9929d4cb66 100644 --- a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp +++ b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp @@ -328,19 +328,19 @@ public: return false; } - bool isUnsupportedBranch(const MCInst &Inst) const override { + bool isReversibleBranch(const MCInst &Inst) const override { if (isDynamicBranch(Inst)) - return true; + return false; switch (Inst.getOpcode()) { default: - return false; + return true; case X86::LOOP: case X86::LOOPE: case X86::LOOPNE: case X86::JECXZ: case X86::JRCXZ: - return true; + return false; } } @@ -1874,7 +1874,7 @@ public: } // Handle conditional branches and ignore indirect branches - if (!isUnsupportedBranch(*I) && getCondCode(*I) == X86::COND_INVALID) { + if (isReversibleBranch(*I) && getCondCode(*I) == X86::COND_INVALID) { // Indirect branch return false; } diff --git a/bolt/test/X86/Inputs/blarge_new_bat_branchentry.preagg.txt b/bolt/test/X86/Inputs/blarge_new_bat_branchentry.preagg.txt new file mode 100644 index 0000000000000000000000000000000000000000..546da92f94dbae31f997def130516d8a9d793c42 --- /dev/null +++ b/bolt/test/X86/Inputs/blarge_new_bat_branchentry.preagg.txt @@ -0,0 +1 @@ +B 80010c 800194 1 0 diff --git a/bolt/test/X86/Inputs/blarge_new_bat_order.preagg.txt b/bolt/test/X86/Inputs/blarge_new_bat_order.preagg.txt new file mode 100644 index 0000000000000000000000000000000000000000..e4e1f170343c62e7fcaad9d5fa16f5a47316f5dd --- /dev/null +++ b/bolt/test/X86/Inputs/blarge_new_bat_order.preagg.txt @@ -0,0 +1,2 @@ +B 800154 401050 20 0 +F 800159 800193 7 diff --git a/bolt/test/X86/Inputs/dwarf5-df-types-debug-names-main.s b/bolt/test/X86/Inputs/dwarf5-df-types-debug-names-main.s index f89f28ec13f4eb8612a1c32bbade9cd4b7bd6606..34ba21f695177474c9bd27d33f47e3578621eecb 100644 --- a/bolt/test/X86/Inputs/dwarf5-df-types-debug-names-main.s +++ b/bolt/test/X86/Inputs/dwarf5-df-types-debug-names-main.s @@ -207,7 +207,7 @@ main: # @main .Linfo_string5: .asciz "f2" # string offset=24 .Linfo_string6: - .asciz "/home/ayermolo/local/tasks/T138552329/typeDedupSplit" # string offset=27 + .asciz "." # string offset=27 .Linfo_string7: .asciz "main.dwo" # string offset=80 .Linfo_string8: @@ -234,15 +234,15 @@ main: # @main .long 19 .long 24 .long 27 - .long 80 - .long 89 - .long 92 - .long 97 - .long 100 - .long 103 - .long 106 - .long 112 - .long 220 + .long 29 + .long 38 + .long 41 + .long 46 + .long 49 + .long 52 + .long 55 + .long 61 + .long 169 .section .debug_info.dwo,"e",@progbits .long .Ldebug_info_dwo_end2-.Ldebug_info_dwo_start2 # Length of Unit .Ldebug_info_dwo_start2: @@ -474,7 +474,7 @@ main: # @main .byte 1 .byte 8 .byte 2 - .ascii "/home/ayermolo/local/tasks/T138552329/typeDedupSplit" + .ascii "." .byte 0 .byte 46 .byte 0 diff --git a/bolt/test/X86/Inputs/jump-table-fixed-ref-pic.s b/bolt/test/X86/Inputs/jump-table-fixed-ref-pic.s new file mode 100644 index 0000000000000000000000000000000000000000..66629a4880e6433c8f1cbdf5af4d6c93574df026 --- /dev/null +++ b/bolt/test/X86/Inputs/jump-table-fixed-ref-pic.s @@ -0,0 +1,35 @@ + .globl main + .type main, %function +main: + .cfi_startproc + cmpq $0x3, %rdi + jae .L4 + cmpq $0x1, %rdi + jne .L4 + mov .Ljt_pic+8(%rip), %rax + lea .Ljt_pic(%rip), %rdx + add %rdx, %rax + jmpq *%rax +.L1: + movq $0x1, %rax + jmp .L5 +.L2: + movq $0x0, %rax + jmp .L5 +.L3: + movq $0x2, %rax + jmp .L5 +.L4: + mov $0x3, %rax +.L5: + retq + .cfi_endproc + + .section .rodata + .align 16 +.Ljt_pic: + .long .L1 - .Ljt_pic + .long .L2 - .Ljt_pic + .long .L3 - .Ljt_pic + .long .L4 - .Ljt_pic + diff --git a/bolt/test/X86/bb-with-two-tail-calls.s b/bolt/test/X86/bb-with-two-tail-calls.s index caad7b3d735f5f8d1ba64660f61a27231acd62ff..b6703e352ff4bfdd6a29cfc74343c745b826fde6 100644 --- a/bolt/test/X86/bb-with-two-tail-calls.s +++ b/bolt/test/X86/bb-with-two-tail-calls.s @@ -1,19 +1,17 @@ # This reproduces a bug with dynostats when trying to compute branch stats # at a block with two tails calls (one conditional and one unconditional). -# REQUIRES: system-linux - # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown \ # RUN: %s -o %t.o # RUN: link_fdata %s %t.o %t.fdata # RUN: llvm-strip --strip-unneeded %t.o # RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -nostdlib # RUN: llvm-bolt %t.exe -o %t.out --data %t.fdata --lite=0 --dyno-stats \ -# RUN: --print-sctc --print-only=_start 2>&1 | FileCheck %s +# RUN: --print-sctc --print-only=_start -enable-bat 2>&1 | FileCheck %s # CHECK-NOT: Assertion `BranchInfo.size() == 2 && "could only be called for blocks with 2 successors"' failed. # Two tail calls in the same basic block after SCTC: -# CHECK: {{.*}}: ja {{.*}} # TAILCALL # CTCTakenCount: {{.*}} -# CHECK-NEXT: {{.*}}: jmp {{.*}} # TAILCALL +# CHECK: {{.*}}: ja {{.*}} # TAILCALL # Offset: 7 # CTCTakenCount: 4 +# CHECK-NEXT: {{.*}}: jmp {{.*}} # TAILCALL # Offset: 13 .globl _start _start: @@ -23,7 +21,9 @@ a: ja b x: ret # FDATA: 1 _start #a# 1 _start #b# 2 4 b: jmp e -c: jmp f +c: + .nops 1 + jmp f .globl e e: diff --git a/bolt/test/X86/bolt-address-translation-yaml.test b/bolt/test/X86/bolt-address-translation-yaml.test index af24c3d84a0f15f9f8d68eabf7b42daac3e39e69..e21513b7dfe592cb5a2bc14f6aab74564440259a 100644 --- a/bolt/test/X86/bolt-address-translation-yaml.test +++ b/bolt/test/X86/bolt-address-translation-yaml.test @@ -5,6 +5,28 @@ RUN: llvm-bolt %t.exe -o %t.out --pa -p %p/Inputs/blarge_new.preagg.txt \ RUN: --reorder-blocks=ext-tsp --split-functions --split-strategy=cdsplit \ RUN: --reorder-functions=cdsort --enable-bat --dyno-stats --skip-funcs=main \ RUN: 2>&1 | FileCheck --check-prefix WRITE-BAT-CHECK %s +# Check that branch with entry in BAT is accounted for. +RUN: perf2bolt %t.out --pa -p %p/Inputs/blarge_new_bat_branchentry.preagg.txt \ +RUN: -w %t.yaml -o %t.fdata +RUN: llvm-bolt %t.exe -data %t.fdata -w %t.yaml-fdata -o %t.null +RUN: FileCheck --input-file %t.yaml --check-prefix BRANCHENTRY-YAML-CHECK %s +RUN: FileCheck --input-file %t.yaml-fdata --check-prefix BRANCHENTRY-YAML-CHECK %s +BRANCHENTRY-YAML-CHECK: - name: SolveCubic +BRANCHENTRY-YAML-CHECK: bid: 0 +BRANCHENTRY-YAML-CHECK: hash: 0x700F19D24600000 +BRANCHENTRY-YAML-CHECK-NEXT: succ: [ { bid: 7, cnt: 1 } +# Check that the order is correct between BAT YAML and FDATA->YAML. +RUN: perf2bolt %t.out --pa -p %p/Inputs/blarge_new_bat_order.preagg.txt \ +RUN: -w %t.yaml -o %t.fdata +RUN: llvm-bolt %t.exe -data %t.fdata -w %t.yaml-fdata -o %t.null +RUN: FileCheck --input-file %t.yaml --check-prefix ORDER-YAML-CHECK %s +RUN: FileCheck --input-file %t.yaml-fdata --check-prefix ORDER-YAML-CHECK %s +ORDER-YAML-CHECK: - name: SolveCubic +ORDER-YAML-CHECK: bid: 3 +ORDER-YAML-CHECK: hash: 0xDDA1DC5F69F900AC +ORDER-YAML-CHECK-NEXT: calls: [ { off: 0x26, fid: [[#]], cnt: 20 } ] +ORDER-YAML-CHECK-NEXT: succ: [ { bid: 5, cnt: 7 } +# Large profile test RUN: perf2bolt %t.out --pa -p %p/Inputs/blarge_new_bat.preagg.txt -w %t.yaml -o %t.fdata \ RUN: 2>&1 | FileCheck --check-prefix READ-BAT-CHECK %s RUN: FileCheck --input-file %t.yaml --check-prefix YAML-BAT-CHECK %s @@ -13,7 +35,7 @@ RUN: llvm-bolt %t.exe -data %t.fdata -w %t.yaml-fdata -o /dev/null RUN: FileCheck --input-file %t.yaml-fdata --check-prefix YAML-BAT-CHECK %s # Test resulting YAML profile with the original binary (no-stale mode) -RUN: llvm-bolt %t.exe -data %t.yaml -o %t.null -dyno-stats \ +RUN: llvm-bolt %t.exe -data %t.yaml -o %t.null -dyno-stats 2>&1 \ RUN: | FileCheck --check-prefix CHECK-BOLT-YAML %s WRITE-BAT-CHECK: BOLT-INFO: Wrote 5 BAT maps @@ -48,6 +70,10 @@ YAML-BAT-CHECK-NEXT: hash: 0x6AF7E61EA3966722 YAML-BAT-CHECK-NEXT: exec: 25 YAML-BAT-CHECK-NEXT: nblocks: 15 YAML-BAT-CHECK-NEXT: blocks: +YAML-BAT-CHECK-NEXT: - bid: 0 +YAML-BAT-CHECK-NEXT: insns: [[#]] +YAML-BAT-CHECK-NEXT: hash: 0x700F19D24600000 +YAML-BAT-CHECK-NEXT: exec: 25 YAML-BAT-CHECK: - bid: 3 YAML-BAT-CHECK-NEXT: insns: [[#]] YAML-BAT-CHECK-NEXT: hash: 0xDDA1DC5F69F900AC @@ -63,7 +89,8 @@ YAML-BAT-CHECK-NEXT: blocks: YAML-BAT-CHECK: - bid: 1 YAML-BAT-CHECK-NEXT: insns: [[#]] YAML-BAT-CHECK-NEXT: hash: 0xD70DC695320E0010 -YAML-BAT-CHECK-NEXT: succ: {{.*}} { bid: 2, cnt: [[#]] } +YAML-BAT-CHECK-NEXT: succ: {{.*}} { bid: 2, cnt: [[#]] CHECK-BOLT-YAML: pre-processing profile using YAML profile reader CHECK-BOLT-YAML-NEXT: 5 out of 16 functions in the binary (31.2%) have non-empty execution profile +CHECK-BOLT-YAML-NOT: invalid (possibly stale) profile diff --git a/bolt/test/X86/dwarf5-df-types-modify-dwo-name-mixed.test b/bolt/test/X86/dwarf5-df-types-modify-dwo-name-mixed.test new file mode 100644 index 0000000000000000000000000000000000000000..a4f5ee77ab565a559878b507dea2be70d516266f --- /dev/null +++ b/bolt/test/X86/dwarf5-df-types-modify-dwo-name-mixed.test @@ -0,0 +1,198 @@ +; RUN: rm -rf %t +; RUN: mkdir %t +; RUN: cd %t +; RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-df-types-debug-names-main.s \ +; RUN: -split-dwarf-file=main.dwo -o main.o +; RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-df-types-dup-helper.s \ +; RUN: -split-dwarf-file=helper.dwo -o helper.o +; RUN: %clang %cflags -gdwarf-5 -gsplit-dwarf=split main.o helper.o -o main.exe +; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections +; RUN: llvm-dwarfdump --debug-info -r 0 main.exe.bolt > log.txt +; RUN: llvm-dwarfdump --debug-info -r 0 main.dwo.dwo >> log.txt +; RUN: llvm-dwarfdump --debug-info -r 0 helper.dwo.dwo >> log.txt +; RUN: llvm-dwarfdump --debug-str-offsets main.dwo.dwo >> log.txt +; RUN: llvm-dwarfdump --debug-str-offsets helper.dwo.dwo >> log.txt +; RUN: cat log.txt | FileCheck -check-prefix=BOLT %s + +;; Test is a mix of DWARF5 TUs where one has DW_AT_comp_dir/DW_AT_dwo_name, and another one doesn't. +;; Tests that BOLT correctly updates DW_AT_dwo_name for TUs. + +; BOLT: DW_TAG_skeleton_unit +; BOLT: DW_AT_comp_dir (".") +; BOLT: DW_AT_dwo_name ("main.dwo.dwo") +; BOLT: DW_TAG_skeleton_unit +; BOLT: DW_AT_comp_dir (".") +; BOLT: DW_AT_dwo_name ("helper.dwo.dwo") +; BOLT: DW_TAG_type_unit +; BOLT: DW_AT_comp_dir (".") +; BOLT: DW_AT_dwo_name ("main.dwo.dwo") +; BOLT: DW_TAG_type_unit +; BOLT: DW_AT_comp_dir (".") +; BOLT: DW_AT_dwo_name ("main.dwo.dwo") +; BOLT: DW_TAG_type_unit +; BOLT-NOT: DW_AT_dwo_name +; BOLT: DW_TAG_type_unit +; BOLT-NOT: DW_AT_dwo_name +; BOLT: DW_TAG_compile_unit +; BOLT: .debug_str_offsets.dwo contents: +; BOLT-NEXT: 0x00000000: Contribution size = 68, Format = DWARF32, Version = 5 +; BOLT-NEXT: "main" +; BOLT-NEXT: "int" +; BOLT-NEXT: "argc" +; BOLT-NEXT: "argv" +; BOLT-NEXT: "char" +; BOLT-NEXT: "f2" +; BOLT-NEXT: "." +; BOLT-NEXT: "main.dwo.dwo" +; BOLT-NEXT: "c1" +; BOLT-NEXT: "Foo2" +; BOLT-NEXT: "f3" +; BOLT-NEXT: "c2" +; BOLT-NEXT: "c3" +; BOLT-NEXT: "Foo2a" +; BOLT-NEXT: "clang version 18.0.0git (git@github.com:ayermolo/llvm-project.git db35fa8fc524127079662802c4735dbf397f86d0)" +; BOLT-NEXT: "main.cpp" +; BOLT-NEXT: helper.dwo.dwo: file format elf64-x86-64 + +; BOLT: .debug_str_offsets.dwo contents: +; BOLT-NEXT: 0x00000000: Contribution size = 64, Format = DWARF32, Version = 5 +; BOLT-NEXT: "fooint" +; BOLT-NEXT: "int" +; BOLT-NEXT: "_Z3foov" +; BOLT-NEXT: "foo" +; BOLT-NEXT: "fint" +; BOLT-NEXT: "c1" +; BOLT-NEXT: "c2" +; BOLT-NEXT: "Foo2Int" +; BOLT-NEXT: "f" +; BOLT-NEXT: "char" +; BOLT-NEXT: "c3" +; BOLT-NEXT: "Foo2a" +; BOLT-NEXT: "clang version 18.0.0" +; BOLT-NEXT: "helper.cpp" +; BOLT-NEXT: "helper.dwo" + + +;; Tests that BOLT correctly handles updating DW_AT_dwo_name when it outputs a DWP file. +;; Currently skipping one of Type units because it is not being de-dupped. +;; In the tu-index this TU is not present. +; RUN: rm main.exe.bolt +; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections --write-dwp +; RUN: llvm-dwarfdump --debug-info -r 0 main.exe.bolt.dwp > logDWP.txt +; RUN: llvm-dwarfdump --debug-str-offsets main.exe.bolt.dwp >> logDWP.txt +; RUN: cat logDWP.txt | FileCheck -check-prefix=BOLT-DWP %s +; BOLT-DWP: DW_TAG_type_unit +; BOLT-DWP: DW_AT_comp_dir (".") +; BOLT-DWP: DW_AT_dwo_name ("main.dwo.dwo") +; BOLT-DWP: DW_TAG_type_unit +; BOLT-DWP: DW_AT_comp_dir (".") +; BOLT-DWP: DW_AT_dwo_name ("main.dwo.dwo") +; BOLT-DWP: DW_TAG_compile_unit +; BOLT-DWP: DW_AT_dwo_name ("main.dwo.dwo") +; BOLT-DWP: DW_TAG_type_unit +; BOLT-DW-NOT: DW_AT_dwo_name +; BOLT-DWP: Contribution size = 68, Format = DWARF32, Version = 5 +; BOLT-DWP-NEXT: "main" +; BOLT-DWP-NEXT: "int" +; BOLT-DWP-NEXT: "argc" +; BOLT-DWP-NEXT: "argv" +; BOLT-DWP-NEXT: "char" +; BOLT-DWP-NEXT: "f2" +; BOLT-DWP-NEXT: "." +; BOLT-DWP-NEXT: "main.dwo.dwo" +; BOLT-DWP-NEXT: "c1" +; BOLT-DWP-NEXT: "Foo2" +; BOLT-DWP-NEXT: "f3" +; BOLT-DWP-NEXT: "c2" +; BOLT-DWP-NEXT: "c3" +; BOLT-DWP-NEXT: "Foo2a" +; BOLT-DWP-NEXT: "clang version 18.0.0git (git@github.com:ayermolo/llvm-project.git db35fa8fc524127079662802c4735dbf397f86d0)" +; BOLT-DWP-NEXT: "main.cpp" +; BOLT-DWP-NEXT: Contribution size = 64, Format = DWARF32, Version = 5 +; BOLT-DWP-NEXT: "fooint" +; BOLT-DWP-NEXT: "int" +; BOLT-DWP-NEXT: "_Z3foov" +; BOLT-DWP-NEXT: "foo" +; BOLT-DWP-NEXT: "fint" +; BOLT-DWP-NEXT: "c1" +; BOLT-DWP-NEXT: "c2" +; BOLT-DWP-NEXT: "Foo2Int" +; BOLT-DWP-NEXT: "f" +; BOLT-DWP-NEXT: "char" +; BOLT-DWP-NEXT: "c3" +; BOLT-DWP-NEXT: "Foo2a" +; BOLT-DWP-NEXT: "clang version 18.0.0" +; BOLT-DWP-NEXT: "helper.cpp" +; BOLT-DWP-NEXT: "helper.dwo + +;; Tests that BOLT correctly handles updating DW_AT_comp_dir/DW_AT_dwo_name when outptut directory is specified. + +; RUN: mkdir DWOOut +; RUN: rm main.exe.bolt +; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections --dwarf-output-path=%t/DWOOut +; RUN: cd DWOOut +; RUN: llvm-dwarfdump --debug-info -r 0 ../main.exe.bolt > log.txt +; RUN: llvm-dwarfdump --debug-info -r 0 main.dwo0.dwo >> log.txt +; RUN: llvm-dwarfdump --debug-info -r 0 helper.dwo0.dwo >> log.txt +; RUN: llvm-dwarfdump --debug-str-offsets main.dwo0.dwo >> log.txt +; RUN: llvm-dwarfdump --debug-str-offsets helper.dwo0.dwo >> log.txt +; RUN: cat log.txt | FileCheck -check-prefix=BOLT-PATH %s + +; BOLT-PATH: DW_TAG_skeleton_unit +; BOLT-PATH: DW_AT_comp_dir (" +; BOLT-PATH-SAME: dwarf5-df-types-modify-dwo-name-mixed.test.tmp/DWOOut +; BOLT-PATH: DW_AT_dwo_name ("main.dwo0.dwo") +; BOLT-PATH: DW_TAG_skeleton_unit +; BOLT-PATH: DW_AT_comp_dir (" +; BOLT-PATH-SAME: dwarf5-df-types-modify-dwo-name-mixed.test.tmp/DWOOut +; BOLT-PATH: DW_AT_dwo_name ("helper.dwo0.dwo") +; BOLT-PATH: DW_TAG_type_unit +; BOLT-PATH: DW_AT_comp_dir (" +; BOLT-PATH-SAME: dwarf5-df-types-modify-dwo-name-mixed.test.tmp/DWOOut +; BOLT-PATH: DW_AT_dwo_name ("main.dwo0.dwo") +; BOLT-PATH: DW_TAG_type_unit +; BOLT-PATH: DW_AT_comp_dir (" +; BOLT-PATH-SAME: dwarf5-df-types-modify-dwo-name-mixed.test.tmp/DWOOut +; BOLT-PATH: DW_AT_dwo_name ("main.dwo0.dwo") +; BOLT-PATH: DW_TAG_type_unit +; BOLT-PATH-NOT: DW_AT_comp_dir +; BOLT-PATH: DW_TAG_type_unit +; BOLT-PATH-NOT: DW_AT_comp_dir +; BOLT-PATH: DW_TAG_compile_unit +; BOLT-PATH: .debug_str_offsets.dwo contents: +; BOLT-PATH-NEXT: 0x00000000: Contribution size = 68, Format = DWARF32, Version = 5 +; BOLT-PATH-NEXT: "main" +; BOLT-PATH-NEXT: "int" +; BOLT-PATH-NEXT: "argc" +; BOLT-PATH-NEXT: "argv" +; BOLT-PATH-NEXT: "char" +; BOLT-PATH-NEXT: "f2" +; BOLT-PATH-NEXT: dwarf5-df-types-modify-dwo-name-mixed.test.tmp/DWOOut" +; BOLT-PATH-NEXT: "main.dwo0.dwo" +; BOLT-PATH-NEXT: "c1" +; BOLT-PATH-NEXT: "Foo2" +; BOLT-PATH-NEXT: "f3" +; BOLT-PATH-NEXT: "c2" +; BOLT-PATH-NEXT: "c3" +; BOLT-PATH-NEXT: "Foo2a" +; BOLT-PATH-NEXT: "clang version 18.0.0git (git@github.com:ayermolo/llvm-project.git db35fa8fc524127079662802c4735dbf397f86d0)" +; BOLT-PATH-NEXT: "main.cpp" +; BOLT-PATH-NEXT: helper.dwo0.dwo: file format elf64-x86-64 + +; BOLT-PATH: .debug_str_offsets.dwo contents: +; BOLT-PATH-NEXT: Contribution size = 64, Format = DWARF32, Version = 5 +; BOLT-PATH-NEXT: "fooint" +; BOLT-PATH-NEXT: "int" +; BOLT-PATH-NEXT: "_Z3foov" +; BOLT-PATH-NEXT: "foo" +; BOLT-PATH-NEXT: "fint" +; BOLT-PATH-NEXT: "c1" +; BOLT-PATH-NEXT: "c2" +; BOLT-PATH-NEXT: "Foo2Int" +; BOLT-PATH-NEXT: "f" +; BOLT-PATH-NEXT: "char" +; BOLT-PATH-NEXT: "c3" +; BOLT-PATH-NEXT: "Foo2a" +; BOLT-PATH-NEXT: "clang version 18.0.0" +; BOLT-PATH-NEXT: "helper.cpp" +; BOLT-PATH-NEXT: "helper.dwo" diff --git a/bolt/test/X86/dwarf5-df-types-modify-dwo-name.test b/bolt/test/X86/dwarf5-df-types-modify-dwo-name.test new file mode 100644 index 0000000000000000000000000000000000000000..086f8f8139628e46bc614c4a36d53ccca1924d03 --- /dev/null +++ b/bolt/test/X86/dwarf5-df-types-modify-dwo-name.test @@ -0,0 +1,175 @@ +; RUN: rm -rf %t +; RUN: mkdir %t +; RUN: cd %t +; RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-df-types-debug-names-main.s \ +; RUN: -split-dwarf-file=main.dwo -o main.o +; RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-df-types-debug-names-helper.s \ +; RUN: -split-dwarf-file=helper.dwo -o helper.o +; RUN: %clang %cflags -gdwarf-5 -gsplit-dwarf=split main.o helper.o -o main.exe +; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections +; RUN: llvm-dwarfdump --debug-info -r 0 main.exe.bolt > log.txt +; RUN: llvm-dwarfdump --debug-info -r 0 main.dwo.dwo >> log.txt +; RUN: llvm-dwarfdump --debug-info -r 0 helper.dwo.dwo >> log.txt +; RUN: llvm-dwarfdump --debug-str-offsets main.dwo.dwo >> log.txt +; RUN: llvm-dwarfdump --debug-str-offsets helper.dwo.dwo >> log.txt +; RUN: cat log.txt | FileCheck -check-prefix=BOLT %s + +;; Tests that BOLT correctly updates DW_AT_dwo_name for TU Untis. + +; BOLT: DW_TAG_skeleton_unit +; BOLT: DW_AT_comp_dir (".") +; BOLT: DW_AT_dwo_name ("main.dwo.dwo") +; BOLT: DW_TAG_skeleton_unit +; BOLT: DW_AT_comp_dir (".") +; BOLT: DW_AT_dwo_name ("helper.dwo.dwo") +; BOLT: DW_TAG_type_unit +; BOLT: DW_AT_comp_dir (".") +; BOLT: DW_AT_dwo_name ("main.dwo.dwo") +; BOLT: DW_TAG_type_unit +; BOLT: DW_AT_comp_dir (".") +; BOLT: DW_AT_dwo_name ("main.dwo.dwo") +; BOLT: DW_TAG_type_unit +; BOLT: DW_AT_comp_dir (".") +; BOLT: DW_AT_dwo_name ("helper.dwo.dwo") +; BOLT: DW_TAG_type_unit +; BOLT: DW_AT_comp_dir (".") +; BOLT: DW_AT_dwo_name ("helper.dwo.dwo") +; BOLT: .debug_str_offsets.dwo contents: +; BOLT-NEXT: 0x00000000: Contribution size = 68, Format = DWARF32, Version = 5 +; BOLT-NEXT: "main" +; BOLT-NEXT: "int" +; BOLT-NEXT: "argc" +; BOLT-NEXT: "argv" +; BOLT-NEXT: "char" +; BOLT-NEXT: "f2" +; BOLT-NEXT: "." +; BOLT-NEXT: "main.dwo.dwo" +; BOLT-NEXT: "c1" +; BOLT-NEXT: "Foo2" +; BOLT-NEXT: "f3" +; BOLT-NEXT: "c2" +; BOLT-NEXT: "c3" +; BOLT-NEXT: "Foo2a" +; BOLT-NEXT: "clang version 18.0.0git (git@github.com:ayermolo/llvm-project.git db35fa8fc524127079662802c4735dbf397f86d0)" +; BOLT-NEXT: "main.cpp" +; BOLT-NEXT: helper.dwo.dwo: file format elf64-x86-64 + +; BOLT: .debug_str_offsets.dwo contents: +; BOLT-NEXT: 0x00000000: Contribution size = 68, Format = DWARF32, Version = 5 +; BOLT-NEXT: "fooint" +; BOLT-NEXT: "int" +; BOLT-NEXT: "_Z3foov" +; BOLT-NEXT: "foo" +; BOLT-NEXT: "fint" +; BOLT-NEXT: "." +; BOLT-NEXT: "helper.dwo.dwo" +; BOLT-NEXT: "c1" +; BOLT-NEXT: "c2" +; BOLT-NEXT: "Foo2Int" +; BOLT-NEXT: "f" +; BOLT-NEXT: "char" +; BOLT-NEXT: "c3" +; BOLT-NEXT: "Foo2a" +; BOLT-NEXT: "clang version 18.0.0git (git@github.com:ayermolo/llvm-project.git db35fa8fc524127079662802c4735dbf397f86d0)" +; BOLT-NEXT: "helper.cpp" + + +;; Tests that BOLT correctly handles updating DW_AT_dwo_name when it outputs a DWP file. +;; Currently skipping one of Type units because it is not being de-dupped. +;; In the tu-index this TU is not present. +; RUN: rm main.exe.bolt +; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections --write-dwp +; RUN: llvm-dwarfdump --debug-info -r 0 main.exe.bolt.dwp > logDWP.txt +; RUN: llvm-dwarfdump --debug-str-offsets main.exe.bolt.dwp >> logDWP.txt +; RUN: cat logDWP.txt | FileCheck -check-prefix=BOLT-DWP %s +; BOLT-DWP: DW_TAG_type_unit +; BOLT-DWP: DW_AT_comp_dir (".") +; BOLT-DWP: DW_AT_dwo_name ("main.dwo.dwo") +; BOLT-DWP: DW_TAG_type_unit +; BOLT-DWP: DW_AT_comp_dir (".") +; BOLT-DWP: DW_AT_dwo_name ("main.dwo.dwo") +; BOLT-DWP: DW_TAG_compile_unit +; BOLT-DWP: DW_AT_dwo_name ("main.dwo.dwo") +; BOLT-DWP: DW_TAG_type_unit +; BOLT-DWP: DW_AT_comp_dir (".") +; BOLT-DWP: DW_AT_dwo_name ("helper.dwo.dwo") +; BOLT-DWP: DW_TAG_type_unit +; BOLT-DWP: DW_TAG_compile_unit +; BOLT-DWP: DW_AT_name ("helper.cpp") +; BOLT-DWP: DW_AT_dwo_name ("helper.dwo.dwo") + +;; Tests that BOLT correctly handles updating DW_AT_comp_dir/DW_AT_dwo_name when outptut directory is specified. + +; RUN: mkdir DWOOut +; RUN: rm main.exe.bolt +; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections --dwarf-output-path=%t/DWOOut +; RUN: cd DWOOut +; RUN: llvm-dwarfdump --debug-info -r 0 ../main.exe.bolt > log.txt +; RUN: llvm-dwarfdump --debug-info -r 0 main.dwo0.dwo >> log.txt +; RUN: llvm-dwarfdump --debug-info -r 0 helper.dwo0.dwo >> log.txt +; RUN: llvm-dwarfdump --debug-str-offsets main.dwo0.dwo >> log.txt +; RUN: llvm-dwarfdump --debug-str-offsets helper.dwo0.dwo >> log.txt +; RUN: cat log.txt | FileCheck -check-prefix=BOLT-PATH %s + +; BOLT-PATH: DW_TAG_skeleton_unit +; BOLT-PATH: DW_AT_comp_dir (" +; BOLT-PATH-SAME: dwarf5-df-types-modify-dwo-name.test.tmp/DWOOut +; BOLT-PATH: DW_AT_dwo_name ("main.dwo0.dwo") +; BOLT-PATH: DW_TAG_skeleton_unit +; BOLT-PATH: DW_AT_comp_dir (" +; BOLT-PATH-SAME: dwarf5-df-types-modify-dwo-name.test.tmp/DWOOut +; BOLT-PATH: DW_AT_dwo_name ("helper.dwo0.dwo") +; BOLT-PATH: DW_TAG_type_unit +; BOLT-PATH: DW_AT_comp_dir (" +; BOLT-PATH-SAME: dwarf5-df-types-modify-dwo-name.test.tmp/DWOOut +; BOLT-PATH: DW_AT_dwo_name ("main.dwo0.dwo") +; BOLT-PATH: DW_TAG_type_unit +; BOLT-PATH: DW_AT_comp_dir (" +; BOLT-PATH-SAME: dwarf5-df-types-modify-dwo-name.test.tmp/DWOOut +; BOLT-PATH: DW_AT_dwo_name ("main.dwo0.dwo") +; BOLT-PATH: DW_TAG_type_unit +; BOLT-PATH: DW_AT_comp_dir (" +; BOLT-PATH-SAME: dwarf5-df-types-modify-dwo-name.test.tmp/DWOOut +; BOLT-PATH: DW_AT_dwo_name ("helper.dwo0.dwo") +; BOLT-PATH: DW_TAG_type_unit +; BOLT-PATH: DW_AT_comp_dir (" +; BOLT-PATH-SAME: dwarf5-df-types-modify-dwo-name.test.tmp/DWOOut +; BOLT-PATH: DW_AT_dwo_name ("helper.dwo0.dwo") +; BOLT-PATH: .debug_str_offsets.dwo contents: +; BOLT-PATH-NEXT: 0x00000000: Contribution size = 68, Format = DWARF32, Version = 5 +; BOLT-PATH-NEXT: "main" +; BOLT-PATH-NEXT: "int" +; BOLT-PATH-NEXT: "argc" +; BOLT-PATH-NEXT: "argv" +; BOLT-PATH-NEXT: "char" +; BOLT-PATH-NEXT: "f2" +; BOLT-PATH-NEXT: dwarf5-df-types-modify-dwo-name.test.tmp/DWOOut" +; BOLT-PATH-NEXT: "main.dwo0.dwo" +; BOLT-PATH-NEXT: "c1" +; BOLT-PATH-NEXT: "Foo2" +; BOLT-PATH-NEXT: "f3" +; BOLT-PATH-NEXT: "c2" +; BOLT-PATH-NEXT: "c3" +; BOLT-PATH-NEXT: "Foo2a" +; BOLT-PATH-NEXT: "clang version 18.0.0git (git@github.com:ayermolo/llvm-project.git db35fa8fc524127079662802c4735dbf397f86d0)" +; BOLT-PATH-NEXT: "main.cpp" +; BOLT-PATH-NEXT: helper.dwo0.dwo: file format elf64-x86-64 + +; BOLT-PATH: .debug_str_offsets.dwo contents: +; BOLT-PATH-NEXT: 0x00000000: Contribution size = 68, Format = DWARF32, Version = 5 +; BOLT-PATH-NEXT: "fooint" +; BOLT-PATH-NEXT: "int" +; BOLT-PATH-NEXT: "_Z3foov" +; BOLT-PATH-NEXT: "foo" +; BOLT-PATH-NEXT: "fint" +; BOLT-PATH-NEXT: dwarf5-df-types-modify-dwo-name.test.tmp/DWOOut" +; BOLT-PATH-NEXT: "helper.dwo0.dwo" +; BOLT-PATH-NEXT: "c1" +; BOLT-PATH-NEXT: "c2" +; BOLT-PATH-NEXT: "Foo2Int" +; BOLT-PATH-NEXT: "f" +; BOLT-PATH-NEXT: "char" +; BOLT-PATH-NEXT: "c3" +; BOLT-PATH-NEXT: "Foo2a" +; BOLT-PATH-NEXT: "clang version 18.0.0git (git@github.com:ayermolo/llvm-project.git db35fa8fc524127079662802c4735dbf397f86d0)" +; BOLT-PATH-NEXT: "helper.cpp" diff --git a/bolt/test/X86/jump-table-fixed-ref-pic.test b/bolt/test/X86/jump-table-fixed-ref-pic.test new file mode 100644 index 0000000000000000000000000000000000000000..4195b97aac501ebc4a77a22f1c3efb601400a529 --- /dev/null +++ b/bolt/test/X86/jump-table-fixed-ref-pic.test @@ -0,0 +1,9 @@ +# Verify that BOLT detects fixed destination of indirect jump for PIC +# case. + +XFAIL: * + +RUN: %clang %cflags -no-pie %S/Inputs/jump-table-fixed-ref-pic.s -Wl,-q -o %t +RUN: llvm-bolt %t --relocs -o %t.null 2>&1 | FileCheck %s + +CHECK: BOLT-INFO: fixed indirect branch detected in main diff --git a/bolt/test/X86/linux-smp-locks.s b/bolt/test/X86/linux-smp-locks.s new file mode 100644 index 0000000000000000000000000000000000000000..5f4410d14fc6b08c38dbd13c1a6b234c88ca1d2b --- /dev/null +++ b/bolt/test/X86/linux-smp-locks.s @@ -0,0 +1,40 @@ +# REQUIRES: system-linux + +## Check that BOLT correctly parses and updates the Linux kernel .smp_locks +## section. + +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o +# RUN: %clang %cflags -nostdlib %t.o -o %t.exe \ +# RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie +# RUN: llvm-bolt %t.exe --print-normalized --keep-nops=0 --bolt-info=0 -o %t.out \ +# RUN: |& FileCheck %s + +## Check the output of BOLT with NOPs removed. + +# RUN: llvm-bolt %t.out -o %t.out.1 --print-normalized |& FileCheck %s + +# CHECK: BOLT-INFO: Linux kernel binary detected +# CHECK: BOLT-INFO: parsed 2 SMP lock entries + + .text + .globl _start + .type _start, %function +_start: + nop + nop +.L0: + lock incl (%rdi) +# CHECK: lock {{.*}} SMPLock +.L1: + lock orb $0x40, 0x4(%rsi) +# CHECK: lock {{.*}} SMPLock + ret + .size _start, .-_start + + .section .smp_locks,"a",@progbits + .long .L0 - . + .long .L1 - . + +## Fake Linux Kernel sections. + .section __ksymtab,"a",@progbits + .section __ksymtab_gpl,"a",@progbits diff --git a/bolt/test/X86/linux-static-keys.s b/bolt/test/X86/linux-static-keys.s index 08454bf9763193d2de46005cd470d38f5661a959..fb419e0f76275590da3b2a72449db8239b104b56 100644 --- a/bolt/test/X86/linux-static-keys.s +++ b/bolt/test/X86/linux-static-keys.s @@ -3,6 +3,8 @@ ## Check that BOLT correctly updates the Linux kernel static keys jump table. # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o +# RUN: link_fdata %s %t.o %t.fdata +# RUN: llvm-strip --strip-unneeded %t.o # RUN: %clang %cflags -nostdlib %t.o -o %t.exe \ # RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr @@ -11,6 +13,12 @@ # RUN: llvm-bolt %t.exe --print-normalized -o %t.out --keep-nops=0 \ # RUN: --bolt-info=0 |& FileCheck %s +## Verify that profile is matched correctly. + +# RUN: llvm-bolt %t.exe --print-normalized -o %t.out --keep-nops=0 \ +# RUN: --bolt-info=0 --data %t.fdata |& \ +# RUN: FileCheck --check-prefix=CHECK-FDATA %s + ## Verify the bindings again on the rewritten binary with nops removed. # RUN: llvm-bolt %t.out -o %t.out.1 --print-normalized |& FileCheck %s @@ -25,15 +33,24 @@ _start: # CHECK: Binary Function "_start" nop .L0: - jmp .L1 + jmp L1 # CHECK: jit # CHECK-SAME: # ID: 1 {{.*}} # Likely: 0 # InitValue: 1 nop -.L1: +L1: .nops 5 + jmp .L0 # CHECK: jit # CHECK-SAME: # ID: 2 {{.*}} # Likely: 1 # InitValue: 1 -.L2: + +## Check that a branch profile associated with a NOP is handled properly when +## dynamic branch is created. + +# FDATA: 1 _start #L1# 1 _start #L2# 3 42 +# CHECK-FDATA: jit {{.*}} # ID: 2 +# CHECK-FDATA-NEXT: jmp +# CHECK-FDATA-NEXT: Successors: {{.*}} (mispreds: 3, count: 42) +L2: nop .size _start, .-_start @@ -51,11 +68,11 @@ foo: __start___jump_table: .long .L0 - . # Jump address - .long .L1 - . # Target address + .long L1 - . # Target address .quad 1 # Key address - .long .L1 - . # Jump address - .long .L2 - . # Target address + .long L1 - . # Jump address + .long L2 - . # Target address .quad 0 # Key address .globl __stop___jump_table diff --git a/bolt/test/X86/profile-passthrough-block.test b/bolt/test/X86/profile-passthrough-block.test new file mode 100644 index 0000000000000000000000000000000000000000..1b875885260dc8bdf629cabb7d63d392d89d8124 --- /dev/null +++ b/bolt/test/X86/profile-passthrough-block.test @@ -0,0 +1,67 @@ +## Test YAMLProfileReader support for pass-through blocks in non-matching edges: +## match the profile edge A -> C to the CFG with blocks A -> B -> C. + +# REQUIRES: system-linux +# RUN: split-file %s %t +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/main.s -o %t.o +# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -nostdlib +# RUN: llvm-bolt %t.exe -o %t.out --data %t/yaml --profile-ignore-hash -v=1 \ +# RUN: --print-cfg 2>&1 | FileCheck %s + +# CHECK: Binary Function "main" after building cfg +# CHECK: Profile Acc : 100.0% +# CHECK-NOT: BOLT-WARNING: no successor for block .LFT0 that matches index 3 or block .Ltmp0 + +#--- main.s +.globl main +.type main, @function +main: + .cfi_startproc +.LBB00: + pushq %rbp + movq %rsp, %rbp + subq $16, %rsp + testq %rax, %rax + js .LBB03 +.LBB01: + jne .LBB04 +.LBB02: + nop +.LBB03: + xorl %eax, %eax + addq $16, %rsp + popq %rbp + retq +.LBB04: + xorl %eax, %eax + addq $16, %rsp + popq %rbp + retq +## For relocations against .text +.LBB05: + call exit + .cfi_endproc + .size main, .-main + +#--- yaml +--- +header: + profile-version: 1 + binary-name: 'profile-passthrough-block.s.tmp.exe' + binary-build-id: '' + profile-flags: [ lbr ] + profile-origin: branch profile reader + profile-events: '' + dfs-order: false + hash-func: xxh3 +functions: + - name: main + fid: 0 + hash: 0x0000000000000000 + exec: 1 + nblocks: 6 + blocks: + - bid: 1 + insns: 1 + succ: [ { bid: 3, cnt: 1} ] +... diff --git a/bolt/test/X86/register-fragments-bolt-symbols.s b/bolt/test/X86/register-fragments-bolt-symbols.s index fa9b70e0b2d8919a371b609263e03c1d902547bb..6478adf19372b2938061dd36389330e4b6ebe79d 100644 --- a/bolt/test/X86/register-fragments-bolt-symbols.s +++ b/bolt/test/X86/register-fragments-bolt-symbols.s @@ -15,6 +15,8 @@ # PREAGG: B X:0 #chain.cold.0# 1 0 # RUN: perf2bolt %t.bolt -p %t.preagg --pa -o %t.bat.fdata -w %t.bat.yaml -v=1 \ # RUN: | FileCheck %s --check-prefix=CHECK-REGISTER +# RUN: FileCheck --input-file %t.bat.fdata --check-prefix=CHECK-FDATA %s +# RUN: FileCheck --input-file %t.bat.yaml --check-prefix=CHECK-YAML %s # CHECK-SYMS: l df *ABS* [[#]] chain.s # CHECK-SYMS: l F .bolt.org.text [[#]] chain @@ -24,6 +26,9 @@ # CHECK-REGISTER: BOLT-INFO: marking chain.cold.0/1(*2) as a fragment of chain/2(*2) +# CHECK-FDATA: 0 [unknown] 0 1 chain/chain.s/2 10 0 1 +# CHECK-YAML: - name: 'chain/chain.s/2' + .file "chain.s" .text .type chain, @function diff --git a/bolt/test/X86/sctc-bug4.test b/bolt/test/X86/sctc-bug4.test index 00f5ee429b635e089c9bcf0693ba3a0e99fe6f07..92aca5110059f4a7fd5ef9cc43db9e1c22286c35 100644 --- a/bolt/test/X86/sctc-bug4.test +++ b/bolt/test/X86/sctc-bug4.test @@ -1,20 +1,23 @@ -# Check that fallthrough blocks are handled properly. +# Check that fallthrough blocks are handled properly and Offset annotation is +# set for conditional tail calls. RUN: %clang %cflags %S/Inputs/sctc_bug4.s -o %t -RUN: llvm-bolt %t -o %t.null \ +RUN: llvm-bolt %t -o %t.null --enable-bat \ RUN: -funcs=test_func -print-sctc -sequential-disassembly 2>&1 | FileCheck %s CHECK: .Ltmp2 (3 instructions, align : 1) CHECK-NEXT: CFI State : 0 +CHECK-NEXT: Input offset: 0x24 CHECK-NEXT: Predecessors: .LFT1 CHECK-NEXT: 00000024: cmpq $0x20, %rsi -CHECK-NEXT: 00000028: ja dummy # TAILCALL {{.*}}# CTCTakenCount: 0 +CHECK-NEXT: 00000028: ja dummy # TAILCALL # Offset: 53 # CTCTakenCount: 0 CHECK-NEXT: 0000002a: jmp .Ltmp4 CHECK-NEXT: Successors: .Ltmp4 CHECK-NEXT: CFI State: 0 CHECK: .Ltmp1 (2 instructions, align : 1) CHECK-NEXT: CFI State : 0 +CHECK-NEXT: Input offset: 0x2c CHECK-NEXT: Predecessors: .LFT0 CHECK-NEXT: 0000002c: xorq %r11, %rax CHECK-NEXT: 0000002f: retq @@ -22,4 +25,5 @@ CHECK-NEXT: CFI State: 0 CHECK: .Ltmp4 (4 instructions, align : 1) CHECK-NEXT: CFI State : 0 +CHECK-NEXT: Input offset: 0x3a CHECK-NEXT: Predecessors: .Ltmp2 diff --git a/bolt/test/X86/yaml-non-simple.test b/bolt/test/X86/yaml-non-simple.test new file mode 100644 index 0000000000000000000000000000000000000000..fef98f692a71039f48563b1d5124f26b161c4225 --- /dev/null +++ b/bolt/test/X86/yaml-non-simple.test @@ -0,0 +1,71 @@ +## Check that YAML profile for non-simple function is not reported as stale. + +# RUN: split-file %s %t +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %t/main.s -o %t.o +# RUN: %clang %cflags %t.o -o %t.exe -nostdlib +# RUN: llvm-bolt %t.exe -o %t.out --data %t/yaml --profile-ignore-hash -v=1 \ +# RUN: --report-stale 2>&1 | FileCheck %s + +# CHECK: BOLT-INFO: could not disassemble function main. Will ignore. +# CHECK: BOLT-INFO: could not disassemble function main.cold. Will ignore. +# CHECK: BOLT-INFO: 0 out of 2 functions in the binary (0.0%) have non-empty execution profile +# CHECK: BOLT-INFO: 1 function with profile could not be optimized + +#--- main.s +.globl main +.type main, @function +main: + .cfi_startproc +.LBB00: + pushq %rbp + movq %rsp, %rbp + subq $16, %rsp + testq %rax, %rax + js .LBB03 +.LBB01: + jne .LBB04 +.LBB02: + nop +.LBB03: + xorl %eax, %eax + addq $16, %rsp + popq %rbp + retq +.LBB04: + xorl %eax, %eax + addq $16, %rsp + popq %rbp + retq + .cfi_endproc + .size main, .-main + +.globl main.cold +.type main.cold, @function +main.cold: + .cfi_startproc + nop + .cfi_endproc + .size main.cold, .-main.cold + +#--- yaml +--- +header: + profile-version: 1 + binary-name: 'yaml-non-simple.s.tmp.exe' + binary-build-id: '' + profile-flags: [ lbr ] + profile-origin: branch profile reader + profile-events: '' + dfs-order: false + hash-func: xxh3 +functions: + - name: main + fid: 0 + hash: 0x0000000000000000 + exec: 1 + nblocks: 5 + blocks: + - bid: 1 + insns: 1 + succ: [ { bid: 3, cnt: 1} ] +... diff --git a/bolt/test/runtime/bolt-reserved.cpp b/bolt/test/runtime/bolt-reserved.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c88b1e284d074ee3371ccfa2f28019dbce4b0daa --- /dev/null +++ b/bolt/test/runtime/bolt-reserved.cpp @@ -0,0 +1,40 @@ +// REQUIRES: system-linux + +/* + * Check that llvm-bolt uses reserved space in a binary for allocating + * new sections. + */ + +// RUN: %clang %s -o %t.exe -Wl,-q +// RUN: llvm-bolt %t.exe -o %t.bolt.exe 2>&1 | FileCheck %s +// RUN: %t.bolt.exe + +// CHECK: BOLT-INFO: using reserved space + +/* + * Check that llvm-bolt detects a condition when the reserved space is + * not enough for allocating new sections. + */ + +// RUN: %clang %s -o %t.tiny.exe -Wl,--no-eh-frame-hdr -Wl,-q -DTINY +// RUN: not llvm-bolt %t.tiny.exe -o %t.tiny.bolt.exe 2>&1 | \ +// RUN: FileCheck %s --check-prefix=CHECK-TINY + +// CHECK-TINY: BOLT-ERROR: reserved space (1 byte) is smaller than required + +#ifdef TINY +#define RSIZE "1" +#else +#define RSIZE "8192 * 1024" +#endif + +asm(".pushsection .text \n\ + .globl __bolt_reserved_start \n\ + .type __bolt_reserved_start, @object \n\ + __bolt_reserved_start: \n\ + .space " RSIZE " \n\ + .globl __bolt_reserved_end \n\ + __bolt_reserved_end: \n\ + .popsection"); + +int main() { return 0; } diff --git a/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp b/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp index df77bf7ea46da33cf655438e833b300ce159f0c9..469323f0ee9d7fa24295b0f5df0f6391a10df9a5 100644 --- a/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp +++ b/clang-tools-extra/clang-include-fixer/find-all-symbols/STLPostfixHeaderMap.cpp @@ -15,9 +15,11 @@ const HeaderMapCollector::RegexHeaderMap *getSTLPostfixHeaderMap() { static const HeaderMapCollector::RegexHeaderMap STLPostfixHeaderMap = { {"include/__stdarg___gnuc_va_list.h$", ""}, {"include/__stdarg___va_copy.h$", ""}, + {"include/__stdarg_header_macro.h$", ""}, {"include/__stdarg_va_arg.h$", ""}, {"include/__stdarg_va_copy.h$", ""}, {"include/__stdarg_va_list.h$", ""}, + {"include/__stddef_header_macro.h$", ""}, {"include/__stddef_max_align_t.h$", ""}, {"include/__stddef_null.h$", ""}, {"include/__stddef_nullptr_t.h$", ""}, diff --git a/clang-tools-extra/clang-query/CMakeLists.txt b/clang-tools-extra/clang-query/CMakeLists.txt index 8a58d4224e049d2485772bf69281ba535e145bc2..34f018c4a03f389c6cb6767f7cf293de64ea9aeb 100644 --- a/clang-tools-extra/clang-query/CMakeLists.txt +++ b/clang-tools-extra/clang-query/CMakeLists.txt @@ -20,7 +20,6 @@ clang_target_link_libraries(clangQuery clangBasic clangDynamicASTMatchers clangFrontend - clangTooling clangSerialization ) diff --git a/clang-tools-extra/clang-query/Query.cpp b/clang-tools-extra/clang-query/Query.cpp index c436d6fa9498688b82ee890b872ce5e2c3595a39..93f4104d39db8c95b8a840d4e29de278fabb0249 100644 --- a/clang-tools-extra/clang-query/Query.cpp +++ b/clang-tools-extra/clang-query/Query.cpp @@ -7,12 +7,12 @@ //===----------------------------------------------------------------------===// #include "Query.h" +#include "QueryParser.h" #include "QuerySession.h" #include "clang/AST/ASTDumper.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Frontend/TextDiagnostic.h" -#include "clang/Tooling/NodeIntrospection.h" #include "llvm/Support/raw_ostream.h" #include @@ -68,8 +68,6 @@ bool HelpQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { "Diagnostic location for bound nodes.\n" " detailed-ast " "Detailed AST output for bound nodes.\n" - " srcloc " - "Source locations and ranges for bound nodes.\n" " dump " "Detailed AST output for bound nodes (alias of detailed-ast).\n\n"; return true; @@ -90,90 +88,6 @@ struct CollectBoundNodes : MatchFinder::MatchCallback { } }; -void dumpLocations(llvm::raw_ostream &OS, DynTypedNode Node, ASTContext &Ctx, - const DiagnosticsEngine &Diags, SourceManager const &SM) { - auto Locs = clang::tooling::NodeIntrospection::GetLocations(Node); - - auto PrintLocations = [](llvm::raw_ostream &OS, auto Iter, auto End) { - auto CommonEntry = Iter->first; - auto Scout = Iter; - SmallVector LocationStrings; - while (Scout->first == CommonEntry) { - LocationStrings.push_back( - tooling::LocationCallFormatterCpp::format(*Iter->second)); - if (Scout == End) - break; - ++Scout; - if (Scout->first == CommonEntry) - ++Iter; - } - llvm::sort(LocationStrings); - for (auto &LS : LocationStrings) { - OS << " * \"" << LS << "\"\n"; - } - return Iter; - }; - - TextDiagnostic TD(OS, Ctx.getLangOpts(), &Diags.getDiagnosticOptions()); - - for (auto Iter = Locs.LocationAccessors.begin(); - Iter != Locs.LocationAccessors.end(); ++Iter) { - if (!Iter->first.isValid()) - continue; - - TD.emitDiagnostic(FullSourceLoc(Iter->first, SM), DiagnosticsEngine::Note, - "source locations here", std::nullopt, std::nullopt); - - Iter = PrintLocations(OS, Iter, Locs.LocationAccessors.end()); - OS << '\n'; - } - - for (auto Iter = Locs.RangeAccessors.begin(); - Iter != Locs.RangeAccessors.end(); ++Iter) { - - if (!Iter->first.getBegin().isValid()) - continue; - - if (SM.getPresumedLineNumber(Iter->first.getBegin()) != - SM.getPresumedLineNumber(Iter->first.getEnd())) - continue; - - TD.emitDiagnostic( - FullSourceLoc(Iter->first.getBegin(), SM), DiagnosticsEngine::Note, - "source ranges here " + Iter->first.printToString(SM), - CharSourceRange::getTokenRange(Iter->first), std::nullopt); - - Iter = PrintLocations(OS, Iter, Locs.RangeAccessors.end()); - } - for (auto Iter = Locs.RangeAccessors.begin(); - Iter != Locs.RangeAccessors.end(); ++Iter) { - - if (!Iter->first.getBegin().isValid()) - continue; - - if (SM.getPresumedLineNumber(Iter->first.getBegin()) == - SM.getPresumedLineNumber(Iter->first.getEnd())) - continue; - - TD.emitDiagnostic( - FullSourceLoc(Iter->first.getBegin(), SM), DiagnosticsEngine::Note, - "source range " + Iter->first.printToString(SM) + " starting here...", - CharSourceRange::getTokenRange(Iter->first), std::nullopt); - - auto ColNum = SM.getPresumedColumnNumber(Iter->first.getEnd()); - auto LastLineLoc = Iter->first.getEnd().getLocWithOffset(-(ColNum - 1)); - - TD.emitDiagnostic(FullSourceLoc(Iter->first.getEnd(), SM), - DiagnosticsEngine::Note, "... ending here", - CharSourceRange::getTokenRange( - SourceRange(LastLineLoc, Iter->first.getEnd())), - std::nullopt); - - Iter = PrintLocations(OS, Iter, Locs.RangeAccessors.end()); - } - OS << "\n"; -} - } // namespace bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { @@ -194,8 +108,7 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { return false; } - auto &Ctx = AST->getASTContext(); - const auto &SM = Ctx.getSourceManager(); + ASTContext &Ctx = AST->getASTContext(); Ctx.getParentMapContext().setTraversalKind(QS.TK); Finder.matchAST(Ctx); @@ -243,19 +156,11 @@ bool MatchQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { } if (QS.DetailedASTOutput) { OS << "Binding for \"" << BI->first << "\":\n"; - const ASTContext &Ctx = AST->getASTContext(); ASTDumper Dumper(OS, Ctx, AST->getDiagnostics().getShowColors()); Dumper.SetTraversalKind(QS.TK); Dumper.Visit(BI->second); OS << "\n"; } - if (QS.SrcLocOutput) { - OS << "\n \"" << BI->first << "\" Source locations\n"; - OS << " " << std::string(19 + BI->first.size(), '-') << '\n'; - - dumpLocations(OS, BI->second, Ctx, AST->getDiagnostics(), SM); - OS << "\n"; - } } if (MI->getMap().empty()) @@ -281,5 +186,26 @@ const QueryKind SetQueryKind::value; const QueryKind SetQueryKind::value; #endif +bool FileQuery::run(llvm::raw_ostream &OS, QuerySession &QS) const { + auto Buffer = llvm::MemoryBuffer::getFile(StringRef{File}.trim()); + if (!Buffer) { + if (Prefix.has_value()) + llvm::errs() << *Prefix << ": "; + llvm::errs() << "cannot open " << File << ": " + << Buffer.getError().message() << "\n"; + return false; + } + + StringRef FileContentRef(Buffer.get()->getBuffer()); + + while (!FileContentRef.empty()) { + QueryRef Q = QueryParser::parse(FileContentRef, QS); + if (!Q->run(llvm::outs(), QS)) + return false; + FileContentRef = Q->RemainingContent; + } + return true; +} + } // namespace query } // namespace clang diff --git a/clang-tools-extra/clang-query/Query.h b/clang-tools-extra/clang-query/Query.h index 7aefa6bb5ee0dd5a991c294ae6a09b5bce213723..af250fbe13ce3fa72e0b3b729392c5447655538e 100644 --- a/clang-tools-extra/clang-query/Query.h +++ b/clang-tools-extra/clang-query/Query.h @@ -17,7 +17,7 @@ namespace clang { namespace query { -enum OutputKind { OK_Diag, OK_Print, OK_DetailedAST, OK_SrcLoc }; +enum OutputKind { OK_Diag, OK_Print, OK_DetailedAST }; enum QueryKind { QK_Invalid, @@ -30,7 +30,8 @@ enum QueryKind { QK_SetTraversalKind, QK_EnableOutputKind, QK_DisableOutputKind, - QK_Quit + QK_Quit, + QK_File }; class QuerySession; @@ -148,7 +149,6 @@ struct SetExclusiveOutputQuery : Query { QS.DiagOutput = false; QS.DetailedASTOutput = false; QS.PrintOutput = false; - QS.SrcLocOutput = false; QS.*Var = true; return true; } @@ -188,6 +188,21 @@ struct DisableOutputQuery : SetNonExclusiveOutputQuery { } }; +struct FileQuery : Query { + FileQuery(StringRef File, StringRef Prefix = StringRef()) + : Query(QK_File), File(File), + Prefix(!Prefix.empty() ? std::optional(Prefix) + : std::nullopt) {} + + bool run(llvm::raw_ostream &OS, QuerySession &QS) const override; + + static bool classof(const Query *Q) { return Q->Kind == QK_File; } + +private: + std::string File; + std::optional Prefix; +}; + } // namespace query } // namespace clang diff --git a/clang-tools-extra/clang-query/QueryParser.cpp b/clang-tools-extra/clang-query/QueryParser.cpp index 162acc1a598dd58f36f5244abf70312b6e1bcd99..1d0b7d9bc6fc84350f0497da542603661a4da3c8 100644 --- a/clang-tools-extra/clang-query/QueryParser.cpp +++ b/clang-tools-extra/clang-query/QueryParser.cpp @@ -11,7 +11,6 @@ #include "QuerySession.h" #include "clang/ASTMatchers/Dynamic/Parser.h" #include "clang/Basic/CharInfo.h" -#include "clang/Tooling/NodeIntrospection.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include @@ -104,19 +103,16 @@ QueryRef QueryParser::parseSetBool(bool QuerySession::*Var) { template QueryRef QueryParser::parseSetOutputKind() { StringRef ValStr; - bool HasIntrospection = tooling::NodeIntrospection::hasIntrospectionSupport(); - unsigned OutKind = - LexOrCompleteWord(this, ValStr) - .Case("diag", OK_Diag) - .Case("print", OK_Print) - .Case("detailed-ast", OK_DetailedAST) - .Case("srcloc", OK_SrcLoc, /*IsCompletion=*/HasIntrospection) - .Case("dump", OK_DetailedAST) - .Default(~0u); + unsigned OutKind = LexOrCompleteWord(this, ValStr) + .Case("diag", OK_Diag) + .Case("print", OK_Print) + .Case("detailed-ast", OK_DetailedAST) + .Case("dump", OK_DetailedAST) + .Default(~0u); if (OutKind == ~0u) { - return new InvalidQuery("expected 'diag', 'print', 'detailed-ast'" + - StringRef(HasIntrospection ? ", 'srcloc'" : "") + - " or 'dump', got '" + ValStr + "'"); + return new InvalidQuery("expected 'diag', 'print', 'detailed-ast' or " + "'dump', got '" + + ValStr + "'"); } switch (OutKind) { @@ -126,10 +122,6 @@ template QueryRef QueryParser::parseSetOutputKind() { return new QueryType(&QuerySession::DiagOutput); case OK_Print: return new QueryType(&QuerySession::PrintOutput); - case OK_SrcLoc: - if (HasIntrospection) - return new QueryType(&QuerySession::SrcLocOutput); - return new InvalidQuery("'srcloc' output support is not available."); } llvm_unreachable("Invalid output kind"); @@ -183,7 +175,8 @@ enum ParsedQueryKind { PQK_Unlet, PQK_Quit, PQK_Enable, - PQK_Disable + PQK_Disable, + PQK_File }; enum ParsedQueryVariable { @@ -222,12 +215,14 @@ QueryRef QueryParser::doParse() { .Case("let", PQK_Let) .Case("m", PQK_Match, /*IsCompletion=*/false) .Case("match", PQK_Match) - .Case("q", PQK_Quit, /*IsCompletion=*/false) + .Case("q", PQK_Quit, /*IsCompletion=*/false) .Case("quit", PQK_Quit) .Case("set", PQK_Set) .Case("enable", PQK_Enable) .Case("disable", PQK_Disable) .Case("unlet", PQK_Unlet) + .Case("f", PQK_File, /*IsCompletion=*/false) + .Case("file", PQK_File) .Default(PQK_Invalid); switch (QKind) { @@ -351,6 +346,9 @@ QueryRef QueryParser::doParse() { return endQuery(new LetQuery(Name, VariantValue())); } + case PQK_File: + return new FileQuery(Line); + case PQK_Invalid: return new InvalidQuery("unknown command: " + CommandStr); } diff --git a/clang-tools-extra/clang-query/QuerySession.h b/clang-tools-extra/clang-query/QuerySession.h index 9a08289a253449193d9a0a0868d8ec93a24dd244..31a4900e26190b13354c5101ef8ddb0fecd61e36 100644 --- a/clang-tools-extra/clang-query/QuerySession.h +++ b/clang-tools-extra/clang-query/QuerySession.h @@ -25,15 +25,14 @@ class QuerySession { public: QuerySession(llvm::ArrayRef> ASTs) : ASTs(ASTs), PrintOutput(false), DiagOutput(true), - DetailedASTOutput(false), SrcLocOutput(false), BindRoot(true), - PrintMatcher(false), Terminate(false), TK(TK_AsIs) {} + DetailedASTOutput(false), BindRoot(true), PrintMatcher(false), + Terminate(false), TK(TK_AsIs) {} llvm::ArrayRef> ASTs; bool PrintOutput; bool DiagOutput; bool DetailedASTOutput; - bool SrcLocOutput; bool BindRoot; bool PrintMatcher; diff --git a/clang-tools-extra/clang-query/tool/ClangQuery.cpp b/clang-tools-extra/clang-query/tool/ClangQuery.cpp index da7ac27014480966c13035bd676acb5825339fcb..a2de7a2dced86e1ccb0f118676a658562f07d3ee 100644 --- a/clang-tools-extra/clang-query/tool/ClangQuery.cpp +++ b/clang-tools-extra/clang-query/tool/ClangQuery.cpp @@ -74,22 +74,8 @@ static cl::opt PreloadFile( bool runCommandsInFile(const char *ExeName, std::string const &FileName, QuerySession &QS) { - auto Buffer = llvm::MemoryBuffer::getFile(FileName); - if (!Buffer) { - llvm::errs() << ExeName << ": cannot open " << FileName << ": " - << Buffer.getError().message() << "\n"; - return true; - } - - StringRef FileContentRef(Buffer.get()->getBuffer()); - - while (!FileContentRef.empty()) { - QueryRef Q = QueryParser::parse(FileContentRef, QS); - if (!Q->run(llvm::outs(), QS)) - return true; - FileContentRef = Q->RemainingContent; - } - return false; + FileQuery Query(FileName, ExeName); + return !Query.run(llvm::errs(), QS); } int main(int argc, const char **argv) { diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index b877ea06dc05cd78b5536155efb25afa4ae32906..1cd7cdd10bc25f2402bb3d71692b017644cf41f6 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -373,11 +373,11 @@ static CheckersList getAnalyzerCheckersAndPackages(ClangTidyContext &Context, const auto &RegisteredCheckers = AnalyzerOptions::getRegisteredCheckers(IncludeExperimental); - bool AnalyzerChecksEnabled = false; - for (StringRef CheckName : RegisteredCheckers) { - std::string ClangTidyCheckName((AnalyzerCheckNamePrefix + CheckName).str()); - AnalyzerChecksEnabled |= Context.isCheckEnabled(ClangTidyCheckName); - } + const bool AnalyzerChecksEnabled = + llvm::any_of(RegisteredCheckers, [&](StringRef CheckName) -> bool { + return Context.isCheckEnabled( + (AnalyzerCheckNamePrefix + CheckName).str()); + }); if (!AnalyzerChecksEnabled) return List; diff --git a/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp index 710b361e16c0a717b562fa32aee9f332032430cb..6028bb2258136bb7bd8336968ed721bcd081d420 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyCheck.cpp @@ -171,7 +171,7 @@ std::optional ClangTidyCheck::OptionsView::getEnumInt( if (IgnoreCase) { if (Value.equals_insensitive(NameAndEnum.second)) return NameAndEnum.first; - } else if (Value.equals(NameAndEnum.second)) { + } else if (Value == NameAndEnum.second) { return NameAndEnum.first; } else if (Value.equals_insensitive(NameAndEnum.second)) { Closest = NameAndEnum.second; diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp index de2a3b51422a5c3bbe20aa2da2d8e3cabfcd3452..200bb87a5ac3cbc6c90c8d207a10371a2e4ab629 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.cpp @@ -311,7 +311,18 @@ ClangTidyDiagnosticConsumer::ClangTidyDiagnosticConsumer( : Context(Ctx), ExternalDiagEngine(ExternalDiagEngine), RemoveIncompatibleErrors(RemoveIncompatibleErrors), GetFixesFromNotes(GetFixesFromNotes), - EnableNolintBlocks(EnableNolintBlocks) {} + EnableNolintBlocks(EnableNolintBlocks) { + + if (Context.getOptions().HeaderFilterRegex && + !Context.getOptions().HeaderFilterRegex->empty()) + HeaderFilter = + std::make_unique(*Context.getOptions().HeaderFilterRegex); + + if (Context.getOptions().ExcludeHeaderFilterRegex && + !Context.getOptions().ExcludeHeaderFilterRegex->empty()) + ExcludeHeaderFilter = std::make_unique( + *Context.getOptions().ExcludeHeaderFilterRegex); +} void ClangTidyDiagnosticConsumer::finalizeLastError() { if (!Errors.empty()) { @@ -562,22 +573,17 @@ void ClangTidyDiagnosticConsumer::checkFilters(SourceLocation Location, } StringRef FileName(File->getName()); - LastErrorRelatesToUserCode = LastErrorRelatesToUserCode || - Sources.isInMainFile(Location) || - getHeaderFilter()->match(FileName); + LastErrorRelatesToUserCode = + LastErrorRelatesToUserCode || Sources.isInMainFile(Location) || + (HeaderFilter && + (HeaderFilter->match(FileName) && + !(ExcludeHeaderFilter && ExcludeHeaderFilter->match(FileName)))); unsigned LineNumber = Sources.getExpansionLineNumber(Location); LastErrorPassesLineFilter = LastErrorPassesLineFilter || passesLineFilter(FileName, LineNumber); } -llvm::Regex *ClangTidyDiagnosticConsumer::getHeaderFilter() { - if (!HeaderFilter) - HeaderFilter = - std::make_unique(*Context.getOptions().HeaderFilterRegex); - return HeaderFilter.get(); -} - void ClangTidyDiagnosticConsumer::removeIncompatibleErrors() { // Each error is modelled as the set of intervals in which it applies // replacements. To detect overlapping replacements, we use a sweep line diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h index 9280eb1e1f218dfb22c3fb8e6025db9d882733bd..97e16a12febd04a8b4f43ee215d49954a3721101 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h +++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h @@ -313,6 +313,7 @@ private: bool EnableNolintBlocks; std::vector Errors; std::unique_ptr HeaderFilter; + std::unique_ptr ExcludeHeaderFilter; bool LastErrorRelatesToUserCode = false; bool LastErrorPassesLineFilter = false; bool LastErrorWasIgnored = false; diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp index cbf21a0e2ae344b5dc32c1c0c43920c1d3cb5e66..445c7f85c900c66507e271ebabf9c6780fca3bcf 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.cpp @@ -170,6 +170,8 @@ template <> struct MappingTraits { IO.mapOptional("ImplementationFileExtensions", Options.ImplementationFileExtensions); IO.mapOptional("HeaderFilterRegex", Options.HeaderFilterRegex); + IO.mapOptional("ExcludeHeaderFilterRegex", + Options.ExcludeHeaderFilterRegex); IO.mapOptional("FormatStyle", Options.FormatStyle); IO.mapOptional("User", Options.User); IO.mapOptional("CheckOptions", Options.CheckOptions); @@ -191,7 +193,8 @@ ClangTidyOptions ClangTidyOptions::getDefaults() { Options.WarningsAsErrors = ""; Options.HeaderFileExtensions = {"", "h", "hh", "hpp", "hxx"}; Options.ImplementationFileExtensions = {"c", "cc", "cpp", "cxx"}; - Options.HeaderFilterRegex = ""; + Options.HeaderFilterRegex = std::nullopt; + Options.ExcludeHeaderFilterRegex = std::nullopt; Options.SystemHeaders = false; Options.FormatStyle = "none"; Options.User = std::nullopt; @@ -231,6 +234,7 @@ ClangTidyOptions &ClangTidyOptions::mergeWith(const ClangTidyOptions &Other, overrideValue(ImplementationFileExtensions, Other.ImplementationFileExtensions); overrideValue(HeaderFilterRegex, Other.HeaderFilterRegex); + overrideValue(ExcludeHeaderFilterRegex, Other.ExcludeHeaderFilterRegex); overrideValue(SystemHeaders, Other.SystemHeaders); overrideValue(FormatStyle, Other.FormatStyle); overrideValue(User, Other.User); diff --git a/clang-tools-extra/clang-tidy/ClangTidyOptions.h b/clang-tools-extra/clang-tidy/ClangTidyOptions.h index e7636cb5d9b06312171f73adeb529d549b744603..85d5a02ebbc1bc9a2ef19e4d7e742ecab86d51ff 100644 --- a/clang-tools-extra/clang-tidy/ClangTidyOptions.h +++ b/clang-tools-extra/clang-tidy/ClangTidyOptions.h @@ -83,6 +83,10 @@ struct ClangTidyOptions { /// main files will always be displayed. std::optional HeaderFilterRegex; + /// \brief Exclude warnings from headers matching this filter, even if they + /// match \c HeaderFilterRegex. + std::optional ExcludeHeaderFilterRegex; + /// Output warnings from system headers matching \c HeaderFilterRegex. std::optional SystemHeaders; diff --git a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp index 4c2416a89aef9b74cc1d7dc33022e4acc71ce2ca..9e714b4be4dfea31dcfd83f0f9a7c1d31e725532 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/CastingThroughVoidCheck.cpp @@ -7,12 +7,10 @@ //===----------------------------------------------------------------------===// #include "CastingThroughVoidCheck.h" -#include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "clang/AST/Type.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" -#include "llvm/ADT/StringSet.h" using namespace clang::ast_matchers; @@ -27,7 +25,8 @@ void CastingThroughVoidCheck::registerMatchers(MatchFinder *Finder) { hasSourceExpression( explicitCastExpr( hasSourceExpression( - expr(hasType(qualType().bind("source_type")))), + expr(hasType(qualType(unless(pointsTo(voidType()))) + .bind("source_type")))), hasDestinationType( qualType(pointsTo(voidType())).bind("void_type"))) .bind("cast"))), diff --git a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp index e7be8134781e48de409fcd36a0e7d9dfe10a06d1..36687a8e761e85fce8b52494d2c68fb20051c2e5 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ForwardingReferenceOverloadCheck.cpp @@ -25,8 +25,8 @@ AST_MATCHER(QualType, isEnableIf) { const NamedDecl *TypeDecl = Spec->getTemplateName().getAsTemplateDecl()->getTemplatedDecl(); return TypeDecl->isInStdNamespace() && - (TypeDecl->getName().equals("enable_if") || - TypeDecl->getName().equals("enable_if_t")); + (TypeDecl->getName() == "enable_if" || + TypeDecl->getName() == "enable_if_t"); }; const Type *BaseType = Node.getTypePtr(); // Case: pointer or reference to enable_if. diff --git a/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp index 6f22f02f301835e4ef94f8afed89edbe918b5544..f99beac668ce72e12314cb8f245274c7e8d3b291 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ImplicitWideningOfMultiplicationResultCheck.cpp @@ -9,20 +9,20 @@ #include "ImplicitWideningOfMultiplicationResultCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchersMacros.h" #include "clang/Lex/Lexer.h" #include using namespace clang::ast_matchers; -namespace clang { +namespace clang::tidy::bugprone { + namespace { AST_MATCHER(ImplicitCastExpr, isPartOfExplicitCast) { return Node.isPartOfExplicitCast(); } +AST_MATCHER(Expr, containsErrors) { return Node.containsErrors(); } } // namespace -} // namespace clang - -namespace clang::tidy::bugprone { static const Expr *getLHSOfMulBinOp(const Expr *E) { assert(E == E->IgnoreParens() && "Already skipped all parens!"); @@ -250,7 +250,8 @@ void ImplicitWideningOfMultiplicationResultCheck::handlePointerOffsetting( void ImplicitWideningOfMultiplicationResultCheck::registerMatchers( MatchFinder *Finder) { - Finder->addMatcher(implicitCastExpr(unless(anyOf(isInTemplateInstantiation(), + Finder->addMatcher(implicitCastExpr(unless(anyOf(containsErrors(), + isInTemplateInstantiation(), isPartOfExplicitCast())), hasCastKind(CK_IntegralCast)) .bind("x"), diff --git a/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp index 9ab59e6b0474f0b70d5d9654a72df2c230b56cc6..600eab37552766ba1fec108bf83a4d642c9437ff 100644 --- a/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp @@ -71,7 +71,9 @@ void OptionalValueConversionCheck::registerMatchers(MatchFinder *Finder) { ofClass(matchers::matchesAnyListedName(OptionalTypes)))), hasType(ConstructTypeMatcher), hasArgument(0U, ignoringImpCasts(anyOf(OptionalDereferenceMatcher, - StdMoveCallMatcher)))) + StdMoveCallMatcher))), + unless(anyOf(hasAncestor(typeLoc()), + hasAncestor(expr(matchers::hasUnevaluatedContext()))))) .bind("expr"), this); } diff --git a/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp index f6714d056518daf5d3672de30bd1fd6d0c6e8d10..53956661d57d1364bcb61b37d8afa93bac27bcd1 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ReservedIdentifierCheck.cpp @@ -178,8 +178,11 @@ std::optional ReservedIdentifierCheck::getDeclFailureInfo(const NamedDecl *Decl, const SourceManager &) const { assert(Decl && Decl->getIdentifier() && !Decl->getName().empty() && - !Decl->isImplicit() && "Decl must be an explicit identifier with a name."); + // Implicit identifiers cannot fail. + if (Decl->isImplicit()) + return std::nullopt; + return getFailureInfoImpl( Decl->getName(), isa(Decl->getDeclContext()), /*IsMacro = */ false, getLangOpts(), Invert, AllowedIdentifiers); diff --git a/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp index 8ae37d4f774d23041cb9b9816ae6e0d0e2c792d7..cacba38b4a5aa88b7b70619519a310e8dbc90294 100644 --- a/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp @@ -17,8 +17,11 @@ namespace clang::tidy::bugprone { void ReturnConstRefFromParameterCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( - returnStmt(hasReturnValue(declRefExpr(to(parmVarDecl(hasType( - hasCanonicalType(matchers::isReferenceToConst()))))))) + returnStmt( + hasReturnValue(declRefExpr(to(parmVarDecl(hasType(hasCanonicalType( + qualType(matchers::isReferenceToConst()).bind("type"))))))), + hasAncestor(functionDecl(hasReturnTypeLoc( + loc(qualType(hasCanonicalType(equalsBoundNode("type")))))))) .bind("ret"), this); } @@ -26,9 +29,13 @@ void ReturnConstRefFromParameterCheck::registerMatchers(MatchFinder *Finder) { void ReturnConstRefFromParameterCheck::check( const MatchFinder::MatchResult &Result) { const auto *R = Result.Nodes.getNodeAs("ret"); - diag(R->getRetValue()->getBeginLoc(), - "returning a constant reference parameter may cause a use-after-free " - "when the parameter is constructed from a temporary"); + const SourceRange Range = R->getRetValue()->getSourceRange(); + if (Range.isInvalid()) + return; + diag(Range.getBegin(), + "returning a constant reference parameter may cause use-after-free " + "when the parameter is constructed from a temporary") + << Range; } } // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousEnumUsageCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousEnumUsageCheck.cpp index ca1ae551cc632af3da4bd0d12b4697a8892ff985..2fca7ae2e7eee884dce290c95e6bf131a5f27a99 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousEnumUsageCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousEnumUsageCheck.cpp @@ -171,8 +171,7 @@ void SuspiciousEnumUsageCheck::check(const MatchFinder::MatchResult &Result) { // Skip when one of the parameters is an empty enum. The // hasDisjointValueRange function could not decide the values properly in // case of an empty enum. - if (EnumDec->enumerator_begin() == EnumDec->enumerator_end() || - OtherEnumDec->enumerator_begin() == OtherEnumDec->enumerator_end()) + if (EnumDec->enumerators().empty() || OtherEnumDec->enumerators().empty()) return; if (!hasDisjointValueRange(EnumDec, OtherEnumDec)) diff --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp index b06a903f92b3e2d6bd8013f6f197293355f2321f..00370ee9b3004caa62e2431a0c0727253af2836c 100644 --- a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp @@ -25,6 +25,7 @@ #include "../misc/StaticAssertCheck.h" #include "../misc/ThrowByValueCatchByReferenceCheck.h" #include "../performance/MoveConstructorInitCheck.h" +#include "../readability/EnumInitialValueCheck.h" #include "../readability/UppercaseLiteralSuffixCheck.h" #include "CommandProcessorCheck.h" #include "DefaultOperatorNewAlignmentCheck.h" @@ -299,6 +300,9 @@ public: "cert-flp37-c"); // FIO CheckFactories.registerCheck("cert-fio38-c"); + // INT + CheckFactories.registerCheck( + "cert-int09-c"); // MSC CheckFactories.registerCheck( "cert-msc24-c"); diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/MisleadingCaptureDefaultByValueCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/MisleadingCaptureDefaultByValueCheck.cpp index 00dfa17a1ccf611e0eeb8928028581da3dc51f75..5dee7f91a93410bdf36a6effb6feab2ab8d2a1f1 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/MisleadingCaptureDefaultByValueCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/MisleadingCaptureDefaultByValueCheck.cpp @@ -67,8 +67,7 @@ static std::string createReplacementText(const LambdaExpr *Lambda) { AppendName("this"); } } - if (!Replacement.empty() && - Lambda->explicit_capture_begin() != Lambda->explicit_capture_end()) { + if (!Replacement.empty() && !Lambda->explicit_captures().empty()) { // Add back separator if we are adding explicit capture variables. Stream << ", "; } diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp index d2117c67a76d0b6bba43d0cabbf62b4dc20808ad..ed76ac665049d1cf3af0fb61a1950932c3ae89f0 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.cpp @@ -25,7 +25,9 @@ SpecialMemberFunctionsCheck::SpecialMemberFunctionsCheck( "AllowMissingMoveFunctions", false)), AllowSoleDefaultDtor(Options.get("AllowSoleDefaultDtor", false)), AllowMissingMoveFunctionsWhenCopyIsDeleted( - Options.get("AllowMissingMoveFunctionsWhenCopyIsDeleted", false)) {} + Options.get("AllowMissingMoveFunctionsWhenCopyIsDeleted", false)), + AllowImplicitlyDeletedCopyOrMove( + Options.get("AllowImplicitlyDeletedCopyOrMove", false)) {} void SpecialMemberFunctionsCheck::storeOptions( ClangTidyOptions::OptionMap &Opts) { @@ -33,17 +35,34 @@ void SpecialMemberFunctionsCheck::storeOptions( Options.store(Opts, "AllowSoleDefaultDtor", AllowSoleDefaultDtor); Options.store(Opts, "AllowMissingMoveFunctionsWhenCopyIsDeleted", AllowMissingMoveFunctionsWhenCopyIsDeleted); + Options.store(Opts, "AllowImplicitlyDeletedCopyOrMove", + AllowImplicitlyDeletedCopyOrMove); +} + +std::optional +SpecialMemberFunctionsCheck::getCheckTraversalKind() const { + return AllowImplicitlyDeletedCopyOrMove ? TK_AsIs + : TK_IgnoreUnlessSpelledInSource; } void SpecialMemberFunctionsCheck::registerMatchers(MatchFinder *Finder) { + auto IsNotImplicitOrDeleted = anyOf(unless(isImplicit()), isDeleted()); + Finder->addMatcher( cxxRecordDecl( - eachOf(has(cxxDestructorDecl().bind("dtor")), - has(cxxConstructorDecl(isCopyConstructor()).bind("copy-ctor")), - has(cxxMethodDecl(isCopyAssignmentOperator()) + unless(isImplicit()), + eachOf(has(cxxDestructorDecl(unless(isImplicit())).bind("dtor")), + has(cxxConstructorDecl(isCopyConstructor(), + IsNotImplicitOrDeleted) + .bind("copy-ctor")), + has(cxxMethodDecl(isCopyAssignmentOperator(), + IsNotImplicitOrDeleted) .bind("copy-assign")), - has(cxxConstructorDecl(isMoveConstructor()).bind("move-ctor")), - has(cxxMethodDecl(isMoveAssignmentOperator()) + has(cxxConstructorDecl(isMoveConstructor(), + IsNotImplicitOrDeleted) + .bind("move-ctor")), + has(cxxMethodDecl(isMoveAssignmentOperator(), + IsNotImplicitOrDeleted) .bind("move-assign")))) .bind("class-def"), this); @@ -127,7 +146,8 @@ void SpecialMemberFunctionsCheck::check( for (const auto &KV : Matchers) if (const auto *MethodDecl = Result.Nodes.getNodeAs(KV.first)) { - StoreMember({KV.second, MethodDecl->isDeleted()}); + StoreMember( + {KV.second, MethodDecl->isDeleted(), MethodDecl->isImplicit()}); } } @@ -144,7 +164,13 @@ void SpecialMemberFunctionsCheck::checkForMissingMembers( auto HasMember = [&](SpecialMemberFunctionKind Kind) { return llvm::any_of(DefinedMembers, [Kind](const auto &Data) { - return Data.FunctionKind == Kind; + return Data.FunctionKind == Kind && !Data.IsImplicit; + }); + }; + + auto HasImplicitDeletedMember = [&](SpecialMemberFunctionKind Kind) { + return llvm::any_of(DefinedMembers, [Kind](const auto &Data) { + return Data.FunctionKind == Kind && Data.IsImplicit && Data.IsDeleted; }); }; @@ -154,9 +180,17 @@ void SpecialMemberFunctionsCheck::checkForMissingMembers( }); }; - auto RequireMember = [&](SpecialMemberFunctionKind Kind) { - if (!HasMember(Kind)) - MissingMembers.push_back(Kind); + auto RequireMembers = [&](SpecialMemberFunctionKind Kind1, + SpecialMemberFunctionKind Kind2) { + if (AllowImplicitlyDeletedCopyOrMove && HasImplicitDeletedMember(Kind1) && + HasImplicitDeletedMember(Kind2)) + return; + + if (!HasMember(Kind1)) + MissingMembers.push_back(Kind1); + + if (!HasMember(Kind2)) + MissingMembers.push_back(Kind2); }; bool RequireThree = @@ -180,8 +214,8 @@ void SpecialMemberFunctionsCheck::checkForMissingMembers( !HasMember(SpecialMemberFunctionKind::NonDefaultDestructor)) MissingMembers.push_back(SpecialMemberFunctionKind::Destructor); - RequireMember(SpecialMemberFunctionKind::CopyConstructor); - RequireMember(SpecialMemberFunctionKind::CopyAssignment); + RequireMembers(SpecialMemberFunctionKind::CopyConstructor, + SpecialMemberFunctionKind::CopyAssignment); } if (RequireFive && @@ -189,14 +223,16 @@ void SpecialMemberFunctionsCheck::checkForMissingMembers( (IsDeleted(SpecialMemberFunctionKind::CopyConstructor) && IsDeleted(SpecialMemberFunctionKind::CopyAssignment)))) { assert(RequireThree); - RequireMember(SpecialMemberFunctionKind::MoveConstructor); - RequireMember(SpecialMemberFunctionKind::MoveAssignment); + RequireMembers(SpecialMemberFunctionKind::MoveConstructor, + SpecialMemberFunctionKind::MoveAssignment); } if (!MissingMembers.empty()) { llvm::SmallVector DefinedMemberKinds; - llvm::transform(DefinedMembers, std::back_inserter(DefinedMemberKinds), - [](const auto &Data) { return Data.FunctionKind; }); + for (const auto &Data : DefinedMembers) { + if (!Data.IsImplicit) + DefinedMemberKinds.push_back(Data.FunctionKind); + } diag(ID.first, "class '%0' defines %1 but does not define %2") << ID.second << cppcoreguidelines::join(DefinedMemberKinds, " and ") << cppcoreguidelines::join(MissingMembers, " or "); diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.h b/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.h index 6042f0fd6cb05432f378744a944001b5175f967a..9ebc03ed2fa139dd67bf33dcf4c90fbf79f48360 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.h +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/SpecialMemberFunctionsCheck.h @@ -30,9 +30,8 @@ public: void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; void onEndOfTranslationUnit() override; - std::optional getCheckTraversalKind() const override { - return TK_IgnoreUnlessSpelledInSource; - } + std::optional getCheckTraversalKind() const override; + enum class SpecialMemberFunctionKind : uint8_t { Destructor, DefaultDestructor, @@ -46,6 +45,7 @@ public: struct SpecialMemberFunctionData { SpecialMemberFunctionKind FunctionKind; bool IsDeleted; + bool IsImplicit = false; bool operator==(const SpecialMemberFunctionData &Other) const { return (Other.FunctionKind == FunctionKind) && @@ -67,6 +67,7 @@ private: const bool AllowMissingMoveFunctions; const bool AllowSoleDefaultDtor; const bool AllowMissingMoveFunctionsWhenCopyIsDeleted; + const bool AllowImplicitlyDeletedCopyOrMove; ClassDefiningSpecialMembersMap ClassWithSpecialMembers; }; diff --git a/clang-tools-extra/clang-tidy/hicpp/SignedBitwiseCheck.cpp b/clang-tools-extra/clang-tidy/hicpp/SignedBitwiseCheck.cpp index 51cc26400f7f382e915af6751daa3ea6ba494353..bf09a6662d9552e59f37611451e3ab2edf50e244 100644 --- a/clang-tools-extra/clang-tidy/hicpp/SignedBitwiseCheck.cpp +++ b/clang-tools-extra/clang-tidy/hicpp/SignedBitwiseCheck.cpp @@ -9,6 +9,7 @@ #include "SignedBitwiseCheck.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" using namespace clang::ast_matchers; using namespace clang::ast_matchers::internal; @@ -29,8 +30,8 @@ void SignedBitwiseCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { void SignedBitwiseCheck::registerMatchers(MatchFinder *Finder) { const auto SignedIntegerOperand = (IgnorePositiveIntegerLiterals - ? expr(ignoringImpCasts(hasType(isSignedInteger())), - unless(integerLiteral())) + ? expr(ignoringImpCasts( + allOf(hasType(isSignedInteger()), unless(integerLiteral())))) : expr(ignoringImpCasts(hasType(isSignedInteger())))) .bind("signed-operand"); diff --git a/clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp b/clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp index 3f1d2f9f58099112c0d65a6c87cd7e3f215a1be7..c2d9286312dc4ac26ee5ee158ac4b253470ccb5a 100644 --- a/clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp +++ b/clang-tools-extra/clang-tidy/misc/UnusedParametersCheck.cpp @@ -192,9 +192,7 @@ void UnusedParametersCheck::check(const MatchFinder::MatchResult &Result) { // In non-strict mode ignore function definitions with empty bodies // (constructor initializer counts for non-empty body). - if (StrictMode || - (Function->getBody()->child_begin() != - Function->getBody()->child_end()) || + if (StrictMode || !Function->getBody()->children().empty() || (isa(Function) && cast(Function)->getNumCtorInitializers() > 0)) warnOnUnusedParameter(Result, Function, I); diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt index 8005d6e91c060c6e9b0e08d8f11cffb094c5fa4e..576805c4c7f1811cca003beca447dd4ab4d8608d 100644 --- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt @@ -41,6 +41,7 @@ add_clang_library(clangTidyModernizeModule UseNullptrCheck.cpp UseOverrideCheck.cpp UseStartsEndsWithCheck.cpp + UseStdFormatCheck.cpp UseStdNumbersCheck.cpp UseStdPrintCheck.cpp UseTrailingReturnTypeCheck.cpp diff --git a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp index 3229e302eb4322197e1b1369a7fe901e7168d42b..a1786ba5acfdf5f43117d4dafde939d8043b999a 100644 --- a/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/LoopConvertCheck.cpp @@ -421,7 +421,7 @@ getContainerFromBeginEndCall(const Expr *Init, bool IsBegin, bool *IsArrow, return {}; if (IsReverse && !Call->Name.consume_back("r")) return {}; - if (!Call->Name.empty() && !Call->Name.equals("c")) + if (!Call->Name.empty() && Call->Name != "c") return {}; return std::make_pair(Call->Container, Call->CallKind); } diff --git a/clang-tools-extra/clang-tidy/modernize/MinMaxUseInitializerListCheck.cpp b/clang-tools-extra/clang-tidy/modernize/MinMaxUseInitializerListCheck.cpp index 45f7700463d5708673a78d5caf31cea9a3d0dd17..418699ffbc4d1a636f8c9702b35f20156390f5c3 100644 --- a/clang-tools-extra/clang-tidy/modernize/MinMaxUseInitializerListCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/MinMaxUseInitializerListCheck.cpp @@ -129,17 +129,17 @@ generateReplacements(const MatchFinder::MatchResult &Match, continue; } + // if the nested call is not the same as the top call + if (InnerCall->getDirectCallee()->getQualifiedNameAsString() != + TopCall->getDirectCallee()->getQualifiedNameAsString()) + continue; + const FindArgsResult InnerResult = findArgs(InnerCall); // if the nested call doesn't have arguments skip it if (!InnerResult.First || !InnerResult.Last) continue; - // if the nested call is not the same as the top call - if (InnerCall->getDirectCallee()->getQualifiedNameAsString() != - TopCall->getDirectCallee()->getQualifiedNameAsString()) - continue; - // if the nested call doesn't have the same compare function if ((Result.Compare || InnerResult.Compare) && !utils::areStatementsIdentical(Result.Compare, InnerResult.Compare, diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp index 776558433c5baa492e8f33637becee5d85775de1..b9c7a2dc383e88360ea3fa6483c6c8c1f9ac7d63 100644 --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -42,6 +42,7 @@ #include "UseNullptrCheck.h" #include "UseOverrideCheck.h" #include "UseStartsEndsWithCheck.h" +#include "UseStdFormatCheck.h" #include "UseStdNumbersCheck.h" #include "UseStdPrintCheck.h" #include "UseTrailingReturnTypeCheck.h" @@ -76,6 +77,7 @@ public: "modernize-use-designated-initializers"); CheckFactories.registerCheck( "modernize-use-starts-ends-with"); + CheckFactories.registerCheck("modernize-use-std-format"); CheckFactories.registerCheck( "modernize-use-std-numbers"); CheckFactories.registerCheck("modernize-use-std-print"); diff --git a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp index 6d7d1d6b87c60acb66b3de1001c3901d6a5a78a3..7a021fe14436a102037f442433db810ff0ef3366 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseConstraintsCheck.cpp @@ -41,6 +41,8 @@ AST_MATCHER(FunctionDecl, hasOtherDeclarations) { void UseConstraintsCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( functionTemplateDecl( + // Skip external libraries included as system headers + unless(isExpansionInSystemHeader()), has(functionDecl(unless(hasOtherDeclarations()), isDefinition(), hasReturnTypeLoc(typeLoc().bind("return"))) .bind("function"))) @@ -57,6 +59,8 @@ matchEnableIfSpecializationImplTypename(TypeLoc TheType) { return std::nullopt; } TheType = Dep.getQualifierLoc().getTypeLoc(); + if (TheType.isNull()) + return std::nullopt; } if (const auto SpecializationLoc = @@ -254,7 +258,7 @@ findInsertionForConstraint(const FunctionDecl *Function, ASTContext &Context) { return utils::lexer::findPreviousTokenKind(Init->getSourceLocation(), SM, LangOpts, tok::colon); } - if (Constructor->init_begin() != Constructor->init_end()) + if (!Constructor->inits().empty()) return std::nullopt; } if (Function->isDeleted()) { diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6cef21f1318a2a96fa11a2b5d366dc74b723e824 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.cpp @@ -0,0 +1,107 @@ +//===--- UseStdFormatCheck.cpp - clang-tidy -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "UseStdFormatCheck.h" +#include "../utils/FormatStringConverter.h" +#include "../utils/Matchers.h" +#include "../utils/OptionsUtils.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" +#include "clang/Tooling/FixIt.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +namespace { +AST_MATCHER(StringLiteral, isOrdinary) { return Node.isOrdinary(); } +} // namespace + +UseStdFormatCheck::UseStdFormatCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + StrictMode(Options.getLocalOrGlobal("StrictMode", false)), + StrFormatLikeFunctions(utils::options::parseStringList( + Options.get("StrFormatLikeFunctions", ""))), + ReplacementFormatFunction( + Options.get("ReplacementFormatFunction", "std::format")), + IncludeInserter(Options.getLocalOrGlobal("IncludeStyle", + utils::IncludeSorter::IS_LLVM), + areDiagsSelfContained()), + MaybeHeaderToInclude(Options.get("FormatHeader")) { + if (StrFormatLikeFunctions.empty()) + StrFormatLikeFunctions.push_back("absl::StrFormat"); + + if (!MaybeHeaderToInclude && ReplacementFormatFunction == "std::format") + MaybeHeaderToInclude = ""; +} + +void UseStdFormatCheck::registerPPCallbacks(const SourceManager &SM, + Preprocessor *PP, + Preprocessor *ModuleExpanderPP) { + IncludeInserter.registerPreprocessor(PP); +} + +void UseStdFormatCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + callExpr(argumentCountAtLeast(1), + hasArgument(0, stringLiteral(isOrdinary())), + callee(functionDecl(unless(cxxMethodDecl()), + matchers::matchesAnyListedName( + StrFormatLikeFunctions)) + .bind("func_decl"))) + .bind("strformat"), + this); +} + +void UseStdFormatCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + using utils::options::serializeStringList; + Options.store(Opts, "StrictMode", StrictMode); + Options.store(Opts, "StrFormatLikeFunctions", + serializeStringList(StrFormatLikeFunctions)); + Options.store(Opts, "ReplacementFormatFunction", ReplacementFormatFunction); + Options.store(Opts, "IncludeStyle", IncludeInserter.getStyle()); + if (MaybeHeaderToInclude) + Options.store(Opts, "FormatHeader", *MaybeHeaderToInclude); +} + +void UseStdFormatCheck::check(const MatchFinder::MatchResult &Result) { + const unsigned FormatArgOffset = 0; + const auto *OldFunction = Result.Nodes.getNodeAs("func_decl"); + const auto *StrFormat = Result.Nodes.getNodeAs("strformat"); + + utils::FormatStringConverter::Configuration ConverterConfig; + ConverterConfig.StrictMode = StrictMode; + utils::FormatStringConverter Converter(Result.Context, StrFormat, + FormatArgOffset, ConverterConfig, + getLangOpts()); + const Expr *StrFormatCall = StrFormat->getCallee(); + if (!Converter.canApply()) { + diag(StrFormat->getBeginLoc(), + "unable to use '%0' instead of %1 because %2") + << StrFormatCall->getSourceRange() << ReplacementFormatFunction + << OldFunction->getIdentifier() + << Converter.conversionNotPossibleReason(); + return; + } + + DiagnosticBuilder Diag = + diag(StrFormatCall->getBeginLoc(), "use '%0' instead of %1") + << ReplacementFormatFunction << OldFunction->getIdentifier(); + Diag << FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(StrFormatCall->getSourceRange()), + ReplacementFormatFunction); + Converter.applyFixes(Diag, *Result.SourceManager); + + if (MaybeHeaderToInclude) + Diag << IncludeInserter.createIncludeInsertion( + Result.Context->getSourceManager().getFileID( + StrFormatCall->getBeginLoc()), + *MaybeHeaderToInclude); +} + +} // namespace clang::tidy::modernize diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.h b/clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.h new file mode 100644 index 0000000000000000000000000000000000000000..b59a4708c6e4bc6d492581a90ab50a6bb10a715a --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/UseStdFormatCheck.h @@ -0,0 +1,51 @@ +//===--- UseStdFormatCheck.h - clang-tidy -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDFORMATCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDFORMATCHECK_H + +#include "../ClangTidyCheck.h" +#include "../utils/IncludeInserter.h" + +namespace clang::tidy::modernize { + +/// Converts calls to absl::StrFormat, or other functions via configuration +/// options, to C++20's std::format, or another function via a configuration +/// option, modifying the format string appropriately and removing +/// now-unnecessary calls to std::string::c_str() and std::string::data(). +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/modernize/use-std-format.html +class UseStdFormatCheck : public ClangTidyCheck { +public: + UseStdFormatCheck(StringRef Name, ClangTidyContext *Context); + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + if (ReplacementFormatFunction == "std::format") + return LangOpts.CPlusPlus20; + return LangOpts.CPlusPlus; + } + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + std::optional getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } + +private: + bool StrictMode; + std::vector StrFormatLikeFunctions; + StringRef ReplacementFormatFunction; + utils::IncludeInserter IncludeInserter; + std::optional MaybeHeaderToInclude; +}; + +} // namespace clang::tidy::modernize + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USESTDFORMATCHECK_H diff --git a/clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp index 660996aba7b70d6e28696f1e24f2cf7da3e4fa92..ff990feadc0c1d944f786b15eecd3f9d35a9a5be 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseStdPrintCheck.cpp @@ -129,8 +129,11 @@ void UseStdPrintCheck::check(const MatchFinder::MatchResult &Result) { FormatArgOffset = 1; } + utils::FormatStringConverter::Configuration ConverterConfig; + ConverterConfig.StrictMode = StrictMode; + ConverterConfig.AllowTrailingNewlineRemoval = true; utils::FormatStringConverter Converter( - Result.Context, Printf, FormatArgOffset, StrictMode, getLangOpts()); + Result.Context, Printf, FormatArgOffset, ConverterConfig, getLangOpts()); const Expr *PrintfCall = Printf->getCallee(); const StringRef ReplacementFunction = Converter.usePrintNewlineFunction() ? ReplacementPrintlnFunction @@ -138,7 +141,8 @@ void UseStdPrintCheck::check(const MatchFinder::MatchResult &Result) { if (!Converter.canApply()) { diag(PrintfCall->getBeginLoc(), "unable to use '%0' instead of %1 because %2") - << ReplacementFunction << OldFunction->getIdentifier() + << PrintfCall->getSourceRange() << ReplacementFunction + << OldFunction->getIdentifier() << Converter.conversionNotPossibleReason(); return; } diff --git a/clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp b/clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp index e92350632b556be086736385b72e1b7c430c925c..c13a8010c22210d59b028c54ff054b264898dcda 100644 --- a/clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ConstReturnTypeCheck.cpp @@ -55,14 +55,6 @@ AST_MATCHER(QualType, isLocalConstQualified) { return Node.isLocalConstQualified(); } -AST_MATCHER(QualType, isTypeOfType) { - return isa(Node.getTypePtr()); -} - -AST_MATCHER(QualType, isTypeOfExprType) { - return isa(Node.getTypePtr()); -} - struct CheckResult { // Source range of the relevant `const` token in the definition being checked. CharSourceRange ConstRange; @@ -110,16 +102,11 @@ void ConstReturnTypeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { void ConstReturnTypeCheck::registerMatchers(MatchFinder *Finder) { // Find all function definitions for which the return types are `const` // qualified, ignoring decltype types. - auto NonLocalConstType = - qualType(unless(isLocalConstQualified()), - anyOf(decltypeType(), autoType(), isTypeOfType(), - isTypeOfExprType(), substTemplateTypeParmType())); Finder->addMatcher( - functionDecl( - returns(allOf(isConstQualified(), unless(NonLocalConstType))), - anyOf(isDefinition(), cxxMethodDecl(isPure())), - // Overridden functions are not actionable. - unless(cxxMethodDecl(isOverride()))) + functionDecl(returns(isLocalConstQualified()), + anyOf(isDefinition(), cxxMethodDecl(isPure())), + // Overridden functions are not actionable. + unless(cxxMethodDecl(isOverride()))) .bind("func"), this); } diff --git a/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp b/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp index 1e85caf688355948562524918c132b9b55861818..2b185e7594addc6ba8f5d3453440dbba8cca7861 100644 --- a/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/ElseAfterReturnCheck.cpp @@ -113,7 +113,7 @@ static bool containsDeclInScope(const Stmt *Node) { } static void removeElseAndBrackets(DiagnosticBuilder &Diag, ASTContext &Context, - const Stmt *Else, SourceLocation ElseLoc) { + const Stmt *Else, SourceLocation ElseLoc) { auto Remap = [&](SourceLocation Loc) { return Context.getSourceManager().getExpansionLoc(Loc); }; @@ -172,7 +172,7 @@ void ElseAfterReturnCheck::registerMatchers(MatchFinder *Finder) { breakStmt().bind(InterruptingStr), cxxThrowExpr().bind(InterruptingStr))); Finder->addMatcher( compoundStmt( - forEach(ifStmt(unless(isConstexpr()), + forEach(ifStmt(unless(isConstexpr()), unless(isConsteval()), hasThen(stmt( anyOf(InterruptsControlFlow, compoundStmt(has(InterruptsControlFlow))))), diff --git a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp index dc30531ebda0e98fe18e2f325111ba8d303598b4..c3208392df1566f98b38933a71fe40d9cf26d976 100644 --- a/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/IdentifierNamingCheck.cpp @@ -1358,7 +1358,7 @@ IdentifierNamingCheck::getFailureInfo( std::replace(KindName.begin(), KindName.end(), '_', ' '); std::string Fixup = fixupWithStyle(Type, Name, Style, HNOption, ND); - if (StringRef(Fixup).equals(Name)) { + if (StringRef(Fixup) == Name) { if (!IgnoreFailedSplit) { LLVM_DEBUG(Location.print(llvm::dbgs(), SM); llvm::dbgs() @@ -1374,6 +1374,10 @@ IdentifierNamingCheck::getFailureInfo( std::optional IdentifierNamingCheck::getDeclFailureInfo(const NamedDecl *Decl, const SourceManager &SM) const { + // Implicit identifiers cannot be renamed. + if (Decl->isImplicit()) + return std::nullopt; + SourceLocation Loc = Decl->getLocation(); const FileStyle &FileStyle = getStyleForFile(SM.getFilename(Loc)); if (!FileStyle.isActive()) diff --git a/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp b/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp index edb67614bd5585de8fa974f8fb3b129ab6360682..fd4730d9c8b9c8652e92743769bb3bb5df1193c3 100644 --- a/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "SimplifyBooleanExprCheck.h" +#include "clang/AST/Expr.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Lex/Lexer.h" #include "llvm/Support/SaveAndRestore.h" @@ -280,9 +281,8 @@ public: if (!S) { return true; } - if (Check->IgnoreMacros && S->getBeginLoc().isMacroID()) { + if (Check->canBeBypassed(S)) return false; - } if (!shouldIgnore(S)) StmtStack.push_back(S); return true; @@ -513,17 +513,23 @@ public: return true; } - static bool isUnaryLNot(const Expr *E) { - return isa(E) && + bool isExpectedUnaryLNot(const Expr *E) { + return !Check->canBeBypassed(E) && isa(E) && cast(E)->getOpcode() == UO_LNot; } + bool isExpectedBinaryOp(const Expr *E) { + const auto *BinaryOp = dyn_cast(E); + return !Check->canBeBypassed(E) && BinaryOp && BinaryOp->isLogicalOp() && + BinaryOp->getType()->isBooleanType(); + } + template static bool checkEitherSide(const BinaryOperator *BO, Functor Func) { return Func(BO->getLHS()) || Func(BO->getRHS()); } - static bool nestedDemorgan(const Expr *E, unsigned NestingLevel) { + bool nestedDemorgan(const Expr *E, unsigned NestingLevel) { const auto *BO = dyn_cast(E->IgnoreUnlessSpelledInSource()); if (!BO) return false; @@ -539,15 +545,13 @@ public: return true; case BO_LAnd: case BO_LOr: - if (checkEitherSide(BO, isUnaryLNot)) - return true; - if (NestingLevel) { - if (checkEitherSide(BO, [NestingLevel](const Expr *E) { - return nestedDemorgan(E, NestingLevel - 1); - })) - return true; - } - return false; + return checkEitherSide( + BO, + [this](const Expr *E) { return isExpectedUnaryLNot(E); }) || + (NestingLevel && + checkEitherSide(BO, [this, NestingLevel](const Expr *E) { + return nestedDemorgan(E, NestingLevel - 1); + })); default: return false; } @@ -556,19 +560,19 @@ public: bool TraverseUnaryOperator(UnaryOperator *Op) { if (!Check->SimplifyDeMorgan || Op->getOpcode() != UO_LNot) return Base::TraverseUnaryOperator(Op); - Expr *SubImp = Op->getSubExpr()->IgnoreImplicit(); - auto *Parens = dyn_cast(SubImp); - auto *BinaryOp = - Parens - ? dyn_cast(Parens->getSubExpr()->IgnoreImplicit()) - : dyn_cast(SubImp); - if (!BinaryOp || !BinaryOp->isLogicalOp() || - !BinaryOp->getType()->isBooleanType()) + const Expr *SubImp = Op->getSubExpr()->IgnoreImplicit(); + const auto *Parens = dyn_cast(SubImp); + const Expr *SubExpr = + Parens ? Parens->getSubExpr()->IgnoreImplicit() : SubImp; + if (!isExpectedBinaryOp(SubExpr)) return Base::TraverseUnaryOperator(Op); + const auto *BinaryOp = cast(SubExpr); if (Check->SimplifyDeMorganRelaxed || - checkEitherSide(BinaryOp, isUnaryLNot) || - checkEitherSide(BinaryOp, - [](const Expr *E) { return nestedDemorgan(E, 1); })) { + checkEitherSide( + BinaryOp, + [this](const Expr *E) { return isExpectedUnaryLNot(E); }) || + checkEitherSide( + BinaryOp, [this](const Expr *E) { return nestedDemorgan(E, 1); })) { if (Check->reportDeMorgan(Context, Op, BinaryOp, !IsProcessing, parent(), Parens) && !Check->areDiagsSelfContained()) { @@ -694,6 +698,10 @@ void SimplifyBooleanExprCheck::check(const MatchFinder::MatchResult &Result) { Visitor(this, *Result.Context).traverse(); } +bool SimplifyBooleanExprCheck::canBeBypassed(const Stmt *S) const { + return IgnoreMacros && S->getBeginLoc().isMacroID(); +} + void SimplifyBooleanExprCheck::issueDiag(const ASTContext &Context, SourceLocation Loc, StringRef Description, diff --git a/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h b/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h index ccc6f3d879fc02f4a3698ca67643081c0075ac91..63c3caa01e01a7e43f13eff769db763d9a5c8ce5 100644 --- a/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h +++ b/clang-tools-extra/clang-tidy/readability/SimplifyBooleanExprCheck.h @@ -64,6 +64,8 @@ private: StringRef Description, SourceRange ReplacementRange, StringRef Replacement); + bool canBeBypassed(const Stmt *S) const; + const bool IgnoreMacros; const bool ChainedConditionalReturn; const bool ChainedConditionalAssignment; diff --git a/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp b/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp index 65356cc3929c54e7a28d2c63e2244d60a53d4dc3..08adc7134cfea2ef2ae2cd413da443612c377696 100644 --- a/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StaticAccessedThroughInstanceCheck.cpp @@ -59,10 +59,6 @@ void StaticAccessedThroughInstanceCheck::check( const Expr *BaseExpr = MemberExpression->getBase(); - // Do not warn for overloaded -> operators. - if (isa(BaseExpr)) - return; - const QualType BaseType = BaseExpr->getType()->isPointerType() ? BaseExpr->getType()->getPointeeType().getUnqualifiedType() @@ -89,17 +85,30 @@ void StaticAccessedThroughInstanceCheck::check( return; SourceLocation MemberExprStartLoc = MemberExpression->getBeginLoc(); - auto Diag = - diag(MemberExprStartLoc, "static member accessed through instance"); - - if (BaseExpr->HasSideEffects(*AstContext) || - getNameSpecifierNestingLevel(BaseType) > NameSpecifierNestingThreshold) - return; + auto CreateFix = [&] { + return FixItHint::CreateReplacement( + CharSourceRange::getCharRange(MemberExprStartLoc, + MemberExpression->getMemberLoc()), + BaseTypeName + "::"); + }; + + { + auto Diag = + diag(MemberExprStartLoc, "static member accessed through instance"); + + if (getNameSpecifierNestingLevel(BaseType) > NameSpecifierNestingThreshold) + return; + + if (!BaseExpr->HasSideEffects(*AstContext, + /* IncludePossibleEffects =*/true)) { + Diag << CreateFix(); + return; + } + } - Diag << FixItHint::CreateReplacement( - CharSourceRange::getCharRange(MemberExprStartLoc, - MemberExpression->getMemberLoc()), - BaseTypeName + "::"); + diag(MemberExprStartLoc, "member base expression may carry some side effects", + DiagnosticIDs::Level::Note) + << BaseExpr->getSourceRange() << CreateFix(); } } // namespace clang::tidy::readability diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp index 3b5d89c8c647196ec57c779e7a93de23d3052994..7c0bbef3ca0878e758a39c21e31f6b93e2a45157 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.cpp @@ -7,12 +7,15 @@ //===----------------------------------------------------------------------===// #include "StringCompareCheck.h" -#include "../utils/FixItHintUtils.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include "clang/Tooling/FixIt.h" +#include "llvm/ADT/StringRef.h" using namespace clang::ast_matchers; +namespace optutils = clang::tidy::utils::options; namespace clang::tidy::readability { @@ -20,11 +23,27 @@ static const StringRef CompareMessage = "do not use 'compare' to test equality " "of strings; use the string equality " "operator instead"; +static const StringRef DefaultStringLikeClasses = "::std::basic_string;" + "::std::basic_string_view"; + +StringCompareCheck::StringCompareCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + StringLikeClasses(optutils::parseStringList( + Options.get("StringLikeClasses", DefaultStringLikeClasses))) {} + +void StringCompareCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "StringLikeClasses", + optutils::serializeStringList(StringLikeClasses)); +} + void StringCompareCheck::registerMatchers(MatchFinder *Finder) { + if (StringLikeClasses.empty()) { + return; + } const auto StrCompare = cxxMemberCallExpr( - callee(cxxMethodDecl(hasName("compare"), - ofClass(classTemplateSpecializationDecl( - hasName("::std::basic_string"))))), + callee(cxxMethodDecl(hasName("compare"), ofClass(cxxRecordDecl(hasAnyName( + StringLikeClasses))))), hasArgument(0, expr().bind("str2")), argumentCountIs(1), callee(memberExpr().bind("str1"))); diff --git a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.h b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.h index 812736d806b71da25c9bc1ac433bbb2c47b544fe..150090901a6e97a139078f7d6c635d9b58804f4c 100644 --- a/clang-tools-extra/clang-tidy/readability/StringCompareCheck.h +++ b/clang-tools-extra/clang-tidy/readability/StringCompareCheck.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_STRINGCOMPARECHECK_H #include "../ClangTidyCheck.h" +#include namespace clang::tidy::readability { @@ -20,13 +21,18 @@ namespace clang::tidy::readability { /// http://clang.llvm.org/extra/clang-tidy/checks/readability/string-compare.html class StringCompareCheck : public ClangTidyCheck { public: - StringCompareCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + StringCompareCheck(StringRef Name, ClangTidyContext *Context); + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { return LangOpts.CPlusPlus; } + void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + +private: + const std::vector StringLikeClasses; }; } // namespace clang::tidy::readability diff --git a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp index 3eb80019ae753e69eacdbd53efffba7de747d3c6..18420d0c8488d2192b23e9033c7827a88021fdc9 100644 --- a/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/SuspiciousCallArgumentCheck.cpp @@ -138,11 +138,11 @@ static bool applyAbbreviationHeuristic( const llvm::StringMap &AbbreviationDictionary, StringRef Arg, StringRef Param) { if (AbbreviationDictionary.contains(Arg) && - Param.equals(AbbreviationDictionary.lookup(Arg))) + Param == AbbreviationDictionary.lookup(Arg)) return true; if (AbbreviationDictionary.contains(Param) && - Arg.equals(AbbreviationDictionary.lookup(Param))) + Arg == AbbreviationDictionary.lookup(Param)) return true; return false; diff --git a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp index f82f4417141d3df287dfafb5182715aa09be7352..7388f20ef288eb68c877bf26a2130a17edd8967b 100644 --- a/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp +++ b/clang-tools-extra/clang-tidy/tool/ClangTidyMain.cpp @@ -53,6 +53,7 @@ Configuration files: Checks - Same as '--checks'. Additionally, the list of globs can be specified as a list instead of a string. + ExcludeHeaderFilterRegex - Same as '--exclude-header-filter'. ExtraArgs - Same as '--extra-args'. ExtraArgsBefore - Same as '--extra-args-before'. FormatStyle - Same as '--format-style'. @@ -132,6 +133,20 @@ option in .clang-tidy file, if any. cl::init(""), cl::cat(ClangTidyCategory)); +static cl::opt ExcludeHeaderFilter("exclude-header-filter", + desc(R"( +Regular expression matching the names of the +headers to exclude diagnostics from. Diagnostics +from the main file of each translation unit are +always displayed. +Must be used together with --header-filter. +Can be used together with -line-filter. +This option overrides the 'ExcludeHeaderFilterRegex' +option in .clang-tidy file, if any. +)"), + cl::init(""), + cl::cat(ClangTidyCategory)); + static cl::opt SystemHeaders("system-headers", desc(R"( Display the errors from system headers. This option overrides the 'SystemHeaders' option @@ -353,6 +368,7 @@ static std::unique_ptr createOptionsProvider( DefaultOptions.Checks = DefaultChecks; DefaultOptions.WarningsAsErrors = ""; DefaultOptions.HeaderFilterRegex = HeaderFilter; + DefaultOptions.ExcludeHeaderFilterRegex = ExcludeHeaderFilter; DefaultOptions.SystemHeaders = SystemHeaders; DefaultOptions.FormatStyle = FormatStyle; DefaultOptions.User = llvm::sys::Process::GetEnv("USER"); @@ -367,6 +383,8 @@ static std::unique_ptr createOptionsProvider( OverrideOptions.WarningsAsErrors = WarningsAsErrors; if (HeaderFilter.getNumOccurrences() > 0) OverrideOptions.HeaderFilterRegex = HeaderFilter; + if (ExcludeHeaderFilter.getNumOccurrences() > 0) + OverrideOptions.ExcludeHeaderFilterRegex = ExcludeHeaderFilter; if (SystemHeaders.getNumOccurrences() > 0) OverrideOptions.SystemHeaders = SystemHeaders; if (FormatStyle.getNumOccurrences() > 0) diff --git a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py index 1bd4a5b283091c0ebeadf08ae56cf571362c1519..4dd20bec81d3be95722f409e541735a52f60674b 100755 --- a/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py +++ b/clang-tools-extra/clang-tidy/tool/run-clang-tidy.py @@ -106,11 +106,14 @@ def get_tidy_invocation( use_color, plugins, warnings_as_errors, + exclude_header_filter, ): """Gets a command line for clang-tidy.""" start = [clang_tidy_binary] if allow_enabling_alpha_checkers: start.append("-allow-enabling-analyzer-alpha-checkers") + if exclude_header_filter is not None: + start.append("--exclude-header-filter=" + exclude_header_filter) if header_filter is not None: start.append("-header-filter=" + header_filter) if line_filter is not None: @@ -228,6 +231,7 @@ def run_tidy(args, clang_tidy_binary, tmpdir, build_path, queue, lock, failed_fi args.use_color, args.plugins, args.warnings_as_errors, + args.exclude_header_filter, ) proc = subprocess.Popen( @@ -292,6 +296,14 @@ def main(): "-config option after reading specified config file. " "Use either -config-file or -config, not both.", ) + parser.add_argument( + "-exclude-header-filter", + default=None, + help="Regular expression matching the names of the " + "headers to exclude diagnostics from. Diagnostics from " + "the main file of each translation unit are always " + "displayed.", + ) parser.add_argument( "-header-filter", default=None, @@ -450,6 +462,7 @@ def main(): args.use_color, args.plugins, args.warnings_as_errors, + args.exclude_header_filter, ) invocation.append("-list-checks") invocation.append("-") diff --git a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp index ad10f745b6acfb704ac5f7dfefd8ac2c1781d365..845e71c5003b80bbdb2cfc8ecb8bb9751f04dd2f 100644 --- a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp +++ b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.cpp @@ -198,10 +198,11 @@ static bool castMismatchedIntegerTypes(const CallExpr *Call, bool StrictMode) { FormatStringConverter::FormatStringConverter(ASTContext *ContextIn, const CallExpr *Call, unsigned FormatArgOffset, - bool StrictMode, + const Configuration ConfigIn, const LangOptions &LO) - : Context(ContextIn), - CastMismatchedIntegerTypes(castMismatchedIntegerTypes(Call, StrictMode)), + : Context(ContextIn), Config(ConfigIn), + CastMismatchedIntegerTypes( + castMismatchedIntegerTypes(Call, ConfigIn.StrictMode)), Args(Call->getArgs()), NumArgs(Call->getNumArgs()), ArgsOffset(FormatArgOffset + 1), LangOpts(LO) { assert(ArgsOffset <= NumArgs); @@ -627,9 +628,12 @@ void FormatStringConverter::finalizeFormatText() { // It's clearer to convert printf("Hello\r\n"); to std::print("Hello\r\n") // than to std::println("Hello\r"); - if (StringRef(StandardFormatString).ends_with("\\n") && - !StringRef(StandardFormatString).ends_with("\\\\n") && - !StringRef(StandardFormatString).ends_with("\\r\\n")) { + // Use StringRef until C++20 std::string::ends_with() is available. + const auto StandardFormatStringRef = StringRef(StandardFormatString); + if (Config.AllowTrailingNewlineRemoval && + StandardFormatStringRef.ends_with("\\n") && + !StandardFormatStringRef.ends_with("\\\\n") && + !StandardFormatStringRef.ends_with("\\r\\n")) { UsePrintNewlineFunction = true; FormatStringNeededRewriting = true; StandardFormatString.erase(StandardFormatString.end() - 2, diff --git a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.h b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.h index 1949870f62ed68c181dbeddfecf8f2644a1e8804..1109a0b602262fe9793de1e30423aee2565cdbd5 100644 --- a/clang-tools-extra/clang-tidy/utils/FormatStringConverter.h +++ b/clang-tools-extra/clang-tidy/utils/FormatStringConverter.h @@ -32,8 +32,14 @@ class FormatStringConverter public: using ConversionSpecifier = clang::analyze_format_string::ConversionSpecifier; using PrintfSpecifier = analyze_printf::PrintfSpecifier; + + struct Configuration { + bool StrictMode = false; + bool AllowTrailingNewlineRemoval = false; + }; + FormatStringConverter(ASTContext *Context, const CallExpr *Call, - unsigned FormatArgOffset, bool StrictMode, + unsigned FormatArgOffset, Configuration Config, const LangOptions &LO); bool canApply() const { return ConversionNotPossibleReason.empty(); } @@ -45,6 +51,7 @@ public: private: ASTContext *Context; + const Configuration Config; const bool CastMismatchedIntegerTypes; const Expr *const *Args; const unsigned NumArgs; diff --git a/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp b/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp index a44720c47eca2d7eb9ef815d7cea3dc18a44c616..0fa54b3847ebc22f6cbcfc90ecfa1a63cab10a91 100644 --- a/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp +++ b/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp @@ -88,8 +88,7 @@ determineIncludeKind(StringRef CanonicalFile, StringRef IncludeFile, if (FileCopy.consume_front(Parts.first) && FileCopy.consume_back(Parts.second)) { // Determine the kind of this inclusion. - if (FileCopy.equals("/internal/") || - FileCopy.equals("/proto/")) { + if (FileCopy == "/internal/" || FileCopy == "/proto/") { return IncludeSorter::IK_MainTUInclude; } } diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp index 962a243ce94d48bfcf3e9ed1ffa3278749cbb35a..e811f5519de2c136c2789aeb26fb569f2095832c 100644 --- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp @@ -61,6 +61,7 @@ struct DenseMapInfo { namespace clang::tidy { namespace { + class NameLookup { llvm::PointerIntPair Data; @@ -78,19 +79,58 @@ public: operator bool() const { return !hasMultipleResolutions(); } const NamedDecl *operator*() const { return getDecl(); } }; + } // namespace static const NamedDecl *findDecl(const RecordDecl &RecDecl, StringRef DeclName) { for (const Decl *D : RecDecl.decls()) { if (const auto *ND = dyn_cast(D)) { - if (ND->getDeclName().isIdentifier() && ND->getName().equals(DeclName)) + if (ND->getDeclName().isIdentifier() && ND->getName() == DeclName) return ND; } } return nullptr; } +/// Returns the function that \p Method is overridding. If There are none or +/// multiple overrides it returns nullptr. If the overridden function itself is +/// overridding then it will recurse up to find the first decl of the function. +static const CXXMethodDecl *getOverrideMethod(const CXXMethodDecl *Method) { + if (Method->size_overridden_methods() != 1) + return nullptr; + + while (true) { + Method = *Method->begin_overridden_methods(); + assert(Method && "Overridden method shouldn't be null"); + unsigned NumOverrides = Method->size_overridden_methods(); + if (NumOverrides == 0) + return Method; + if (NumOverrides > 1) + return nullptr; + } +} + +static bool hasNoName(const NamedDecl *Decl) { + return !Decl->getIdentifier() || Decl->getName().empty(); +} + +static const NamedDecl *getFailureForNamedDecl(const NamedDecl *ND) { + const auto *Canonical = cast(ND->getCanonicalDecl()); + if (Canonical != ND) + return Canonical; + + if (const auto *Method = dyn_cast(ND)) { + if (const CXXMethodDecl *Overridden = getOverrideMethod(Method)) + Canonical = cast(Overridden->getCanonicalDecl()); + + if (Canonical != ND) + return Canonical; + } + + return ND; +} + /// Returns a decl matching the \p DeclName in \p Parent or one of its base /// classes. If \p AggressiveTemplateLookup is `true` then it will check /// template dependent base classes as well. @@ -132,24 +172,6 @@ static NameLookup findDeclInBases(const CXXRecordDecl &Parent, return NameLookup(Found); // If nullptr, decl wasn't found. } -/// Returns the function that \p Method is overridding. If There are none or -/// multiple overrides it returns nullptr. If the overridden function itself is -/// overridding then it will recurse up to find the first decl of the function. -static const CXXMethodDecl *getOverrideMethod(const CXXMethodDecl *Method) { - if (Method->size_overridden_methods() != 1) - return nullptr; - - while (true) { - Method = *Method->begin_overridden_methods(); - assert(Method && "Overridden method shouldn't be null"); - unsigned NumOverrides = Method->size_overridden_methods(); - if (NumOverrides == 0) - return Method; - if (NumOverrides > 1) - return nullptr; - } -} - namespace { /// Callback supplies macros to RenamerClangTidyCheck::checkMacro @@ -192,10 +214,6 @@ public: : Check(Check), SM(SM), AggressiveDependentMemberLookup(AggressiveDependentMemberLookup) {} - static bool hasNoName(const NamedDecl *Decl) { - return !Decl->getIdentifier() || Decl->getName().empty(); - } - bool shouldVisitTemplateInstantiations() const { return true; } bool shouldVisitImplicitCode() const { return false; } @@ -246,29 +264,10 @@ public: } bool VisitNamedDecl(NamedDecl *Decl) { - if (hasNoName(Decl)) - return true; - - const auto *Canonical = cast(Decl->getCanonicalDecl()); - if (Canonical != Decl) { - Check->addUsage(Canonical, Decl->getLocation(), SM); - return true; - } - - // Fix overridden methods - if (const auto *Method = dyn_cast(Decl)) { - if (const CXXMethodDecl *Overridden = getOverrideMethod(Method)) { - Check->addUsage(Overridden, Method->getLocation(), SM); - return true; // Don't try to add the actual decl as a Failure. - } - } - - // Ignore ClassTemplateSpecializationDecl which are creating duplicate - // replacements with CXXRecordDecl. - if (isa(Decl)) - return true; - - Check->checkNamedDecl(Decl, SM); + SourceRange UsageRange = + DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation()) + .getSourceRange(); + Check->addUsage(Decl, UsageRange, SM); return true; } @@ -413,82 +412,97 @@ void RenamerClangTidyCheck::registerPPCallbacks( std::make_unique(SM, this)); } -void RenamerClangTidyCheck::addUsage( - const RenamerClangTidyCheck::NamingCheckId &Decl, SourceRange Range, - const SourceManager &SourceMgr) { +std::pair +RenamerClangTidyCheck::addUsage( + const RenamerClangTidyCheck::NamingCheckId &FailureId, + SourceRange UsageRange, const SourceManager &SourceMgr) { // Do nothing if the provided range is invalid. - if (Range.isInvalid()) - return; + if (UsageRange.isInvalid()) + return {NamingCheckFailures.end(), false}; - // If we have a source manager, use it to convert to the spelling location for - // performing the fix. This is necessary because macros can map the same - // spelling location to different source locations, and we only want to fix - // the token once, before it is expanded by the macro. - SourceLocation FixLocation = Range.getBegin(); + // Get the spelling location for performing the fix. This is necessary because + // macros can map the same spelling location to different source locations, + // and we only want to fix the token once, before it is expanded by the macro. + SourceLocation FixLocation = UsageRange.getBegin(); FixLocation = SourceMgr.getSpellingLoc(FixLocation); if (FixLocation.isInvalid()) - return; + return {NamingCheckFailures.end(), false}; + + auto EmplaceResult = NamingCheckFailures.try_emplace(FailureId); + NamingCheckFailure &Failure = EmplaceResult.first->second; // Try to insert the identifier location in the Usages map, and bail out if it // is already in there - RenamerClangTidyCheck::NamingCheckFailure &Failure = - NamingCheckFailures[Decl]; if (!Failure.RawUsageLocs.insert(FixLocation).second) - return; + return EmplaceResult; - if (!Failure.shouldFix()) - return; + if (Failure.FixStatus != RenamerClangTidyCheck::ShouldFixStatus::ShouldFix) + return EmplaceResult; if (SourceMgr.isWrittenInScratchSpace(FixLocation)) Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro; - if (!utils::rangeCanBeFixed(Range, &SourceMgr)) + if (!utils::rangeCanBeFixed(UsageRange, &SourceMgr)) Failure.FixStatus = RenamerClangTidyCheck::ShouldFixStatus::InsideMacro; + + return EmplaceResult; } -void RenamerClangTidyCheck::addUsage(const NamedDecl *Decl, SourceRange Range, +void RenamerClangTidyCheck::addUsage(const NamedDecl *Decl, + SourceRange UsageRange, const SourceManager &SourceMgr) { - // Don't keep track for non-identifier names. - auto *II = Decl->getIdentifier(); - if (!II) + if (hasNoName(Decl)) + return; + + // Ignore ClassTemplateSpecializationDecl which are creating duplicate + // replacements with CXXRecordDecl. + if (isa(Decl)) return; - if (const auto *Method = dyn_cast(Decl)) { - if (const CXXMethodDecl *Overridden = getOverrideMethod(Method)) - Decl = Overridden; - } - Decl = cast(Decl->getCanonicalDecl()); - return addUsage( - RenamerClangTidyCheck::NamingCheckId(Decl->getLocation(), II->getName()), - Range, SourceMgr); -} -void RenamerClangTidyCheck::checkNamedDecl(const NamedDecl *Decl, - const SourceManager &SourceMgr) { - std::optional MaybeFailure = getDeclFailureInfo(Decl, SourceMgr); + // We don't want to create a failure for every NamedDecl we find. Ideally + // there is just one NamedDecl in every group of "related" NamedDecls that + // becomes the failure. This NamedDecl and all of its related NamedDecls + // become usages. E.g. Since NamedDecls are Redeclarable, only the canonical + // NamedDecl becomes the failure and all redeclarations become usages. + const NamedDecl *FailureDecl = getFailureForNamedDecl(Decl); + + std::optional MaybeFailure = + getDeclFailureInfo(FailureDecl, SourceMgr); if (!MaybeFailure) return; - FailureInfo &Info = *MaybeFailure; - NamingCheckFailure &Failure = - NamingCheckFailures[NamingCheckId(Decl->getLocation(), Decl->getName())]; - SourceRange Range = - DeclarationNameInfo(Decl->getDeclName(), Decl->getLocation()) - .getSourceRange(); - - const IdentifierTable &Idents = Decl->getASTContext().Idents; - auto CheckNewIdentifier = Idents.find(Info.Fixup); + NamingCheckId FailureId(FailureDecl->getLocation(), FailureDecl->getName()); + + auto [FailureIter, NewFailure] = addUsage(FailureId, UsageRange, SourceMgr); + + if (FailureIter == NamingCheckFailures.end()) { + // Nothing to do if the usage wasn't accepted. + return; + } + if (!NewFailure) { + // FailureInfo has already been provided. + return; + } + + // Update the stored failure with info regarding the FailureDecl. + NamingCheckFailure &Failure = FailureIter->second; + Failure.Info = std::move(*MaybeFailure); + + // Don't overwritte the failure status if it was already set. + if (!Failure.shouldFix()) { + return; + } + const IdentifierTable &Idents = FailureDecl->getASTContext().Idents; + auto CheckNewIdentifier = Idents.find(Failure.Info.Fixup); if (CheckNewIdentifier != Idents.end()) { const IdentifierInfo *Ident = CheckNewIdentifier->second; if (Ident->isKeyword(getLangOpts())) Failure.FixStatus = ShouldFixStatus::ConflictsWithKeyword; else if (Ident->hasMacroDefinition()) Failure.FixStatus = ShouldFixStatus::ConflictsWithMacroDefinition; - } else if (!isValidAsciiIdentifier(Info.Fixup)) { + } else if (!isValidAsciiIdentifier(Failure.Info.Fixup)) { Failure.FixStatus = ShouldFixStatus::FixInvalidIdentifier; } - - Failure.Info = std::move(Info); - addUsage(Decl, Range, SourceMgr); } void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h index be5b6f0c7f76785d7f2aada7dd394cf3a568ddd4..3d5721b789ac2e63ac2e161e3a1d8fd8bb1ec881 100644 --- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h +++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.h @@ -115,15 +115,9 @@ public: void expandMacro(const Token &MacroNameTok, const MacroInfo *MI, const SourceManager &SourceMgr); - void addUsage(const RenamerClangTidyCheck::NamingCheckId &Decl, - SourceRange Range, const SourceManager &SourceMgr); - - /// Convenience method when the usage to be added is a NamedDecl. void addUsage(const NamedDecl *Decl, SourceRange Range, const SourceManager &SourceMgr); - void checkNamedDecl(const NamedDecl *Decl, const SourceManager &SourceMgr); - protected: /// Overridden by derived classes, returns information about if and how a Decl /// failed the check. A 'std::nullopt' result means the Decl did not fail the @@ -158,6 +152,14 @@ protected: const NamingCheckFailure &Failure) const = 0; private: + // Manage additions to the Failure/usage map + // + // return the result of NamingCheckFailures::try_emplace() if the usage was + // accepted. + std::pair + addUsage(const RenamerClangTidyCheck::NamingCheckId &FailureId, + SourceRange UsageRange, const SourceManager &SourceMgr); + NamingCheckFailureMap NamingCheckFailures; const bool AggressiveDependentMemberLookup; }; diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp index 1b86ea19cf28daa75cea3c9deb39e4191d797c22..fda1e5fdf8d82c944ae0e628158fd0554b8248a0 100644 --- a/clang-tools-extra/clangd/AST.cpp +++ b/clang-tools-extra/clangd/AST.cpp @@ -50,16 +50,11 @@ getTemplateSpecializationArgLocs(const NamedDecl &ND) { if (const ASTTemplateArgumentListInfo *Args = Func->getTemplateSpecializationArgsAsWritten()) return Args->arguments(); - } else if (auto *Cls = - llvm::dyn_cast(&ND)) { + } else if (auto *Cls = llvm::dyn_cast(&ND)) { if (auto *Args = Cls->getTemplateArgsAsWritten()) return Args->arguments(); - } else if (auto *Var = - llvm::dyn_cast(&ND)) { - if (auto *Args = Var->getTemplateArgsAsWritten()) - return Args->arguments(); } else if (auto *Var = llvm::dyn_cast(&ND)) { - if (auto *Args = Var->getTemplateArgsInfo()) + if (auto *Args = Var->getTemplateArgsAsWritten()) return Args->arguments(); } // We return std::nullopt for ClassTemplateSpecializationDecls because it does @@ -270,22 +265,10 @@ std::string printTemplateSpecializationArgs(const NamedDecl &ND) { getTemplateSpecializationArgLocs(ND)) { printTemplateArgumentList(OS, *Args, Policy); } else if (auto *Cls = llvm::dyn_cast(&ND)) { - if (const TypeSourceInfo *TSI = Cls->getTypeAsWritten()) { - // ClassTemplateSpecializationDecls do not contain - // TemplateArgumentTypeLocs, they only have TemplateArgumentTypes. So we - // create a new argument location list from TypeSourceInfo. - auto STL = TSI->getTypeLoc().getAs(); - llvm::SmallVector ArgLocs; - ArgLocs.reserve(STL.getNumArgs()); - for (unsigned I = 0; I < STL.getNumArgs(); ++I) - ArgLocs.push_back(STL.getArgLoc(I)); - printTemplateArgumentList(OS, ArgLocs, Policy); - } else { - // FIXME: Fix cases when getTypeAsWritten returns null inside clang AST, - // e.g. friend decls. Currently we fallback to Template Arguments without - // location information. - printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy); - } + // FIXME: Fix cases when getTypeAsWritten returns null inside clang AST, + // e.g. friend decls. Currently we fallback to Template Arguments without + // location information. + printTemplateArgumentList(OS, Cls->getTemplateArgs().asArray(), Policy); } OS.flush(); return TemplateArgs; @@ -453,10 +436,12 @@ bool hasReservedScope(const DeclContext &DC) { } QualType declaredType(const TypeDecl *D) { + ASTContext &Context = D->getASTContext(); if (const auto *CTSD = llvm::dyn_cast(D)) - if (const auto *TSI = CTSD->getTypeAsWritten()) - return TSI->getType(); - return D->getASTContext().getTypeDeclType(D); + if (const auto *Args = CTSD->getTemplateArgsAsWritten()) + return Context.getTemplateSpecializationType( + TemplateName(CTSD->getSpecializedTemplate()), Args->arguments()); + return Context.getTypeDeclType(D); } namespace { diff --git a/clang-tools-extra/clangd/Preamble.cpp b/clang-tools-extra/clangd/Preamble.cpp index d5818e0ca309b03fafadc20f1fbdfe4f902ab615..ecd490145dd3c4583443b2978a018dc128f220f0 100644 --- a/clang-tools-extra/clangd/Preamble.cpp +++ b/clang-tools-extra/clangd/Preamble.cpp @@ -918,7 +918,9 @@ void PreamblePatch::apply(CompilerInvocation &CI) const { // no guarantees around using arbitrary options when reusing PCHs, and // different target opts can result in crashes, see // ParsedASTTest.PreambleWithDifferentTarget. - CI.TargetOpts = Baseline->TargetOpts; + // Make sure this is a deep copy, as the same Baseline might be used + // concurrently. + *CI.TargetOpts = *Baseline->TargetOpts; // No need to map an empty file. if (PatchContents.empty()) diff --git a/clang-tools-extra/clangd/SemanticHighlighting.cpp b/clang-tools-extra/clangd/SemanticHighlighting.cpp index 08f99e11ac9be183a832c67fa649088aa41bb8a8..eb025f21f3616126ee7e0a22d0019f95bdae0073 100644 --- a/clang-tools-extra/clangd/SemanticHighlighting.cpp +++ b/clang-tools-extra/clangd/SemanticHighlighting.cpp @@ -693,17 +693,22 @@ public: return true; } + bool + VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *D) { + if (auto *Args = D->getTemplateArgsAsWritten()) + H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc()); + return true; + } + bool VisitClassTemplatePartialSpecializationDecl( ClassTemplatePartialSpecializationDecl *D) { if (auto *TPL = D->getTemplateParameters()) H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc()); - if (auto *Args = D->getTemplateArgsAsWritten()) - H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc()); return true; } bool VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D) { - if (auto *Args = D->getTemplateArgsInfo()) + if (auto *Args = D->getTemplateArgsAsWritten()) H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc()); return true; } @@ -712,8 +717,6 @@ public: VarTemplatePartialSpecializationDecl *D) { if (auto *TPL = D->getTemplateParameters()) H.addAngleBracketTokens(TPL->getLAngleLoc(), TPL->getRAngleLoc()); - if (auto *Args = D->getTemplateArgsAsWritten()) - H.addAngleBracketTokens(Args->getLAngleLoc(), Args->getRAngleLoc()); return true; } diff --git a/clang-tools-extra/clangd/index/CanonicalIncludes.cpp b/clang-tools-extra/clangd/index/CanonicalIncludes.cpp index 42eeba36a80e43eaa5bc9f87f454297f8ea409f1..785ec4086ea7606e2258e0d842f8bfa60f99147a 100644 --- a/clang-tools-extra/clangd/index/CanonicalIncludes.cpp +++ b/clang-tools-extra/clangd/index/CanonicalIncludes.cpp @@ -18,9 +18,11 @@ namespace { const std::pair IncludeMappings[] = { {"include/__stdarg___gnuc_va_list.h", ""}, {"include/__stdarg___va_copy.h", ""}, + {"include/__stdarg_header_macro.h", ""}, {"include/__stdarg_va_arg.h", ""}, {"include/__stdarg_va_copy.h", ""}, {"include/__stdarg_va_list.h", ""}, + {"include/__stddef_header_macro.h", ""}, {"include/__stddef_max_align_t.h", ""}, {"include/__stddef_null.h", ""}, {"include/__stddef_nullptr_t.h", ""}, diff --git a/clang-tools-extra/clangd/refactor/Rename.cpp b/clang-tools-extra/clangd/refactor/Rename.cpp index 75b30e66d63761fd4bcbc007c97a1f299d947409..c0fc4453a3fccc61bb8abe75c7abf139b98e10ca 100644 --- a/clang-tools-extra/clangd/refactor/Rename.cpp +++ b/clang-tools-extra/clangd/refactor/Rename.cpp @@ -1090,11 +1090,10 @@ llvm::Expected rename(const RenameInputs &RInputs) { return MainFileRenameEdit.takeError(); llvm::DenseSet RenamedRanges; - if (const auto *MD = dyn_cast(&RenameDecl)) { + if (!isa(RenameDecl)) { // TODO: Insert the ranges from the ObjCMethodDecl/ObjCMessageExpr selector // pieces which are being renamed. This will require us to make changes to // locateDeclAt to preserve this AST node. - } else { RenamedRanges.insert(CurrentIdentifier); } diff --git a/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp b/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp index e36b3249bc7b92948c4bf1a5dc2169c025606302..44080802a28958ec1f3670019f6da43d69aa8097 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/ScopifyEnum.cpp @@ -40,15 +40,12 @@ namespace { /// void f() { E e1 = EV1; } /// /// After: -/// enum class E { EV1, EV2 }; -/// void f() { E e1 = E::EV1; } +/// enum class E { V1, V2 }; +/// void f() { E e1 = E::V1; } /// /// Note that the respective project code might not compile anymore /// if it made use of the now-gone implicit conversion to int. /// This is out of scope for this tweak. -/// -/// TODO: In the above example, we could detect that the values -/// start with the enum name, and remove that prefix. class ScopifyEnum : public Tweak { const char *id() const final; @@ -63,14 +60,13 @@ class ScopifyEnum : public Tweak { std::function; llvm::Error addClassKeywordToDeclarations(); llvm::Error scopifyEnumValues(); - llvm::Error scopifyEnumValue(const EnumConstantDecl &CD, StringRef Prefix); + llvm::Error scopifyEnumValue(const EnumConstantDecl &CD, StringRef EnumName, + bool StripPrefix); llvm::Expected getContentForFile(StringRef FilePath); - unsigned getOffsetFromPosition(const Position &Pos, StringRef Content) const; llvm::Error addReplacementForReference(const ReferencesResult::Reference &Ref, const MakeReplacement &GetReplacement); llvm::Error addReplacement(StringRef FilePath, StringRef Content, const tooling::Replacement &Replacement); - Position getPosition(const Decl &D) const; const EnumDecl *D = nullptr; const Selection *S = nullptr; @@ -109,7 +105,8 @@ Expected ScopifyEnum::apply(const Selection &Inputs) { llvm::Error ScopifyEnum::addClassKeywordToDeclarations() { for (const auto &Ref : - findReferences(*S->AST, getPosition(*D), 0, S->Index, false) + findReferences(*S->AST, sourceLocToPosition(*SM, D->getBeginLoc()), 0, + S->Index, false) .References) { if (!(Ref.Attributes & ReferencesResult::Declaration)) continue; @@ -125,25 +122,46 @@ llvm::Error ScopifyEnum::addClassKeywordToDeclarations() { } llvm::Error ScopifyEnum::scopifyEnumValues() { - std::string PrefixToInsert(D->getName()); - PrefixToInsert += "::"; - for (auto E : D->enumerators()) { - if (auto Err = scopifyEnumValue(*E, PrefixToInsert)) + StringRef EnumName(D->getName()); + bool StripPrefix = true; + for (const EnumConstantDecl *E : D->enumerators()) { + if (!E->getName().starts_with(EnumName)) { + StripPrefix = false; + break; + } + } + for (const EnumConstantDecl *E : D->enumerators()) { + if (auto Err = scopifyEnumValue(*E, EnumName, StripPrefix)) return Err; } return llvm::Error::success(); } llvm::Error ScopifyEnum::scopifyEnumValue(const EnumConstantDecl &CD, - StringRef Prefix) { + StringRef EnumName, + bool StripPrefix) { for (const auto &Ref : - findReferences(*S->AST, getPosition(CD), 0, S->Index, false) + findReferences(*S->AST, sourceLocToPosition(*SM, CD.getBeginLoc()), 0, + S->Index, false) .References) { - if (Ref.Attributes & ReferencesResult::Declaration) + if (Ref.Attributes & ReferencesResult::Declaration) { + if (StripPrefix) { + const auto MakeReplacement = [&EnumName](StringRef FilePath, + StringRef Content, + unsigned Offset) { + unsigned Length = EnumName.size(); + if (Content[Offset + Length] == '_') + ++Length; + return tooling::Replacement(FilePath, Offset, Length, {}); + }; + if (auto Err = addReplacementForReference(Ref, MakeReplacement)) + return Err; + } continue; + } - const auto MakeReplacement = [&Prefix](StringRef FilePath, - StringRef Content, unsigned Offset) { + const auto MakeReplacement = [&](StringRef FilePath, StringRef Content, + unsigned Offset) { const auto IsAlreadyScoped = [Content, Offset] { if (Offset < 2) return false; @@ -164,9 +182,18 @@ llvm::Error ScopifyEnum::scopifyEnumValue(const EnumConstantDecl &CD, } return false; }; - return IsAlreadyScoped() - ? tooling::Replacement() - : tooling::Replacement(FilePath, Offset, 0, Prefix); + if (StripPrefix) { + const int ExtraLength = + Content[Offset + EnumName.size()] == '_' ? 1 : 0; + if (IsAlreadyScoped()) + return tooling::Replacement(FilePath, Offset, + EnumName.size() + ExtraLength, {}); + return tooling::Replacement(FilePath, Offset + EnumName.size(), + ExtraLength, "::"); + } + return IsAlreadyScoped() ? tooling::Replacement() + : tooling::Replacement(FilePath, Offset, 0, + EnumName.str() + "::"); }; if (auto Err = addReplacementForReference(Ref, MakeReplacement)) return Err; @@ -187,27 +214,19 @@ llvm::Expected ScopifyEnum::getContentForFile(StringRef FilePath) { return Content; } -unsigned int ScopifyEnum::getOffsetFromPosition(const Position &Pos, - StringRef Content) const { - unsigned int Offset = 0; - - for (std::size_t LinesRemaining = Pos.line; - Offset < Content.size() && LinesRemaining;) { - if (Content[Offset++] == '\n') - --LinesRemaining; - } - return Offset + Pos.character; -} - llvm::Error ScopifyEnum::addReplacementForReference(const ReferencesResult::Reference &Ref, const MakeReplacement &GetReplacement) { StringRef FilePath = Ref.Loc.uri.file(); - auto Content = getContentForFile(FilePath); + llvm::Expected Content = getContentForFile(FilePath); if (!Content) return Content.takeError(); - unsigned Offset = getOffsetFromPosition(Ref.Loc.range.start, *Content); - tooling::Replacement Replacement = GetReplacement(FilePath, *Content, Offset); + llvm::Expected Offset = + positionToOffset(*Content, Ref.Loc.range.start); + if (!Offset) + return Offset.takeError(); + tooling::Replacement Replacement = + GetReplacement(FilePath, *Content, *Offset); if (Replacement.isApplicable()) return addReplacement(FilePath, *Content, Replacement); return llvm::Error::success(); @@ -223,13 +242,5 @@ ScopifyEnum::addReplacement(StringRef FilePath, StringRef Content, return llvm::Error::success(); } -Position ScopifyEnum::getPosition(const Decl &D) const { - const SourceLocation Loc = D.getLocation(); - Position Pos; - Pos.line = SM->getSpellingLineNumber(Loc) - 1; - Pos.character = SM->getSpellingColumnNumber(Loc) - 1; - return Pos; -} - } // namespace } // namespace clang::clangd diff --git a/clang-tools-extra/clangd/test/delimited-input-comment-at-the-end.test b/clang-tools-extra/clangd/test/delimited-input-comment-at-the-end.test index bbbd72f8c59f6f28e3ed947b7eb2c75341876122..85a1f2199fadf903bf3d5b00dadeeeb380a7519d 100644 --- a/clang-tools-extra/clangd/test/delimited-input-comment-at-the-end.test +++ b/clang-tools-extra/clangd/test/delimited-input-comment-at-the-end.test @@ -1,11 +1,11 @@ -# RUN: clangd -input-style=delimited -sync -input-mirror-file %t < %s -# RUN: grep '{"jsonrpc":"2.0","id":3,"method":"exit"}' %t -# -# RUN: clangd -lit-test -input-mirror-file %t < %s -# RUN: grep '{"jsonrpc":"2.0","id":3,"method":"exit"}' %t -# -{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} ---- -{"jsonrpc":"2.0","id":3,"method":"shutdown"} ---- -{"jsonrpc":"2.0","method":"exit"} +# RUN: clangd -input-style=delimited -sync -input-mirror-file %t < %s +# RUN: grep '{"jsonrpc":"2.0","id":3,"method":"exit"}' %t +# +# RUN: clangd -lit-test -input-mirror-file %t < %s +# RUN: grep '{"jsonrpc":"2.0","id":3,"method":"exit"}' %t +# +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} +--- +{"jsonrpc":"2.0","id":3,"method":"shutdown"} +--- +{"jsonrpc":"2.0","method":"exit"} diff --git a/clang-tools-extra/clangd/test/hover.test b/clang-tools-extra/clangd/test/hover.test index ec8d0488fa5ed119f9ed03d472f4f8d358f6f196..dc76ae85fa41dd34a3ceeb2e7fa0de8226bc9751 100644 --- a/clang-tools-extra/clangd/test/hover.test +++ b/clang-tools-extra/clangd/test/hover.test @@ -1,57 +1,57 @@ -# RUN: clangd -lit-test < %s | FileCheck %s -{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} ---- -{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"void foo(); int main() { foo(); }\n"}}} ---- -{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":27}}} -# CHECK: "id": 1, -# CHECK-NEXT: "jsonrpc": "2.0", -# CHECK-NEXT: "result": { -# CHECK-NEXT: "contents": { -# CHECK-NEXT: "kind": "plaintext", -# CHECK-NEXT: "value": "function foo\n\n→ void\n\nvoid foo()" -# CHECK-NEXT: }, -# CHECK-NEXT: "range": { -# CHECK-NEXT: "end": { -# CHECK-NEXT: "character": 28, -# CHECK-NEXT: "line": 0 -# CHECK-NEXT: }, -# CHECK-NEXT: "start": { -# CHECK-NEXT: "character": 25, -# CHECK-NEXT: "line": 0 -# CHECK-NEXT: } -# CHECK-NEXT: } -# CHECK-NEXT: } -# CHECK-NEXT:} ---- -{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":10}}} -# CHECK: "id": 1, -# CHECK-NEXT: "jsonrpc": "2.0", -# CHECK-NEXT: "result": null ---- -{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main2.cpp","languageId":"cpp","version":1,"text":"enum foo{}; int main() { foo f; }\n"}}} ---- -{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"test:///main2.cpp"},"position":{"line":0,"character":27}}} -# CHECK: "id": 1, -# CHECK-NEXT: "jsonrpc": "2.0", -# CHECK-NEXT: "result": { -# CHECK-NEXT: "contents": { -# CHECK-NEXT: "kind": "plaintext", -# CHECK-NEXT: "value": "enum foo\n\nenum foo {}" -# CHECK-NEXT: }, -# CHECK-NEXT: "range": { -# CHECK-NEXT: "end": { -# CHECK-NEXT: "character": 28, -# CHECK-NEXT: "line": 0 -# CHECK-NEXT: }, -# CHECK-NEXT: "start": { -# CHECK-NEXT: "character": 25, -# CHECK-NEXT: "line": 0 -# CHECK-NEXT: } -# CHECK-NEXT: } -# CHECK-NEXT: } -# CHECK-NEXT:} ---- -{"jsonrpc":"2.0","id":3,"method":"shutdown"} ---- -{"jsonrpc":"2.0","method":"exit"} +# RUN: clangd -lit-test < %s | FileCheck %s +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} +--- +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"void foo(); int main() { foo(); }\n"}}} +--- +{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":27}}} +# CHECK: "id": 1, +# CHECK-NEXT: "jsonrpc": "2.0", +# CHECK-NEXT: "result": { +# CHECK-NEXT: "contents": { +# CHECK-NEXT: "kind": "plaintext", +# CHECK-NEXT: "value": "function foo\n\n→ void\n\nvoid foo()" +# CHECK-NEXT: }, +# CHECK-NEXT: "range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT: "character": 28, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: "start": { +# CHECK-NEXT: "character": 25, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT:} +--- +{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"test:///main.cpp"},"position":{"line":0,"character":10}}} +# CHECK: "id": 1, +# CHECK-NEXT: "jsonrpc": "2.0", +# CHECK-NEXT: "result": null +--- +{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main2.cpp","languageId":"cpp","version":1,"text":"enum foo{}; int main() { foo f; }\n"}}} +--- +{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"test:///main2.cpp"},"position":{"line":0,"character":27}}} +# CHECK: "id": 1, +# CHECK-NEXT: "jsonrpc": "2.0", +# CHECK-NEXT: "result": { +# CHECK-NEXT: "contents": { +# CHECK-NEXT: "kind": "plaintext", +# CHECK-NEXT: "value": "enum foo\n\nenum foo {}" +# CHECK-NEXT: }, +# CHECK-NEXT: "range": { +# CHECK-NEXT: "end": { +# CHECK-NEXT: "character": 28, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: }, +# CHECK-NEXT: "start": { +# CHECK-NEXT: "character": 25, +# CHECK-NEXT: "line": 0 +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT:} +--- +{"jsonrpc":"2.0","id":3,"method":"shutdown"} +--- +{"jsonrpc":"2.0","method":"exit"} diff --git a/clang-tools-extra/clangd/test/spaces-in-delimited-input.test b/clang-tools-extra/clangd/test/spaces-in-delimited-input.test index dc2e2f5ea0f64dd4dad1a3d3055cffd9e44b3cc0..aa191b6f2097f97b4a3f74c1f90049c28945f657 100644 --- a/clang-tools-extra/clangd/test/spaces-in-delimited-input.test +++ b/clang-tools-extra/clangd/test/spaces-in-delimited-input.test @@ -1,13 +1,13 @@ -# RUN: clangd -input-style=delimited -sync < %s 2>&1 | FileCheck %s -# RUN: clangd -lit-test -sync < %s 2>&1 | FileCheck %s -# -{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} - ---- - -{"jsonrpc":"2.0","id":3,"method":"shutdown"} - ---- - -{"jsonrpc":"2.0","method":"exit"} -# CHECK-NOT: JSON parse error +# RUN: clangd -input-style=delimited -sync < %s 2>&1 | FileCheck %s +# RUN: clangd -lit-test -sync < %s 2>&1 | FileCheck %s +# +{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}} + +--- + +{"jsonrpc":"2.0","id":3,"method":"shutdown"} + +--- + +{"jsonrpc":"2.0","method":"exit"} +# CHECK-NOT: JSON parse error diff --git a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp index 94437857cecca6a94df8ad316b29b6302d812cd1..0b2273f0a9a6e36f218c9c06382fa6cee6f2ad80 100644 --- a/clang-tools-extra/clangd/unittests/FindTargetTests.cpp +++ b/clang-tools-extra/clangd/unittests/FindTargetTests.cpp @@ -642,10 +642,7 @@ TEST_F(TargetDeclTest, RewrittenBinaryOperator) { bool x = (Foo(1) [[!=]] Foo(2)); )cpp"; EXPECT_DECLS("CXXRewrittenBinaryOperator", - {"std::strong_ordering operator<=>(const Foo &) const = default", - Rel::TemplatePattern}, - {"bool operator==(const Foo &) const noexcept = default", - Rel::TemplateInstantiation}); + {"bool operator==(const Foo &) const noexcept = default"}); } TEST_F(TargetDeclTest, FunctionTemplate) { diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index 5ead74748f550cb4536c7edf9cc246a4d41b5a42..d9e97e5215a2612666fecd077eb0156005e33cc0 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -965,6 +965,19 @@ class Foo final {})cpp"; // Bindings are in theory public members of an anonymous struct. HI.AccessSpecifier = "public"; }}, + {// Don't crash on invalid decl with invalid init expr. + R"cpp( + Unknown [[^abc]] = invalid; + // error-ok + )cpp", + [](HoverInfo &HI) { + HI.Name = "abc"; + HI.Kind = index::SymbolKind::Variable; + HI.NamespaceScope = ""; + HI.Definition = "int abc = ()"; + HI.Type = "int"; + HI.AccessSpecifier = "public"; + }}, {// Extra info for function call. R"cpp( void fun(int arg_a, int &arg_b) {}; @@ -3078,7 +3091,7 @@ TEST(Hover, All) { HI.NamespaceScope = ""; HI.Definition = "bool operator==(const Foo &) const noexcept = default"; - HI.Documentation = "Foo spaceship"; + HI.Documentation = ""; }}, }; @@ -3881,7 +3894,7 @@ TEST(Hover, SpaceshipTemplateNoCrash) { TU.ExtraArgs.push_back("-std=c++20"); auto AST = TU.build(); auto HI = getHover(AST, T.point(), format::getLLVMStyle(), nullptr); - EXPECT_EQ(HI->Documentation, "Foo bar baz"); + EXPECT_EQ(HI->Documentation, ""); } TEST(Hover, ForwardStructNoCrash) { diff --git a/clang-tools-extra/clangd/unittests/SelectionTests.cpp b/clang-tools-extra/clangd/unittests/SelectionTests.cpp index db516a1f62a35773b9e46932fec066984afb8a93..aaaf758e72236b556ac522105bb2deabba932fe2 100644 --- a/clang-tools-extra/clangd/unittests/SelectionTests.cpp +++ b/clang-tools-extra/clangd/unittests/SelectionTests.cpp @@ -589,6 +589,12 @@ TEST(SelectionTest, CommonAncestor) { auto x = [[ns::^C]]; )cpp", "ConceptReference"}, + {R"cpp( + template + concept D = true; + template void g(D<[[^T]]> auto abc) {} + )cpp", + "TemplateTypeParmTypeLoc"}, }; for (const Case &C : Cases) { diff --git a/clang-tools-extra/clangd/unittests/tweaks/ScopifyEnumTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/ScopifyEnumTests.cpp index b5a964a5a26d8074260215f3a2ffcee041811bdc..5da059faaf5e8c2dcc8990cd6f42282413320117 100644 --- a/clang-tools-extra/clangd/unittests/tweaks/ScopifyEnumTests.cpp +++ b/clang-tools-extra/clangd/unittests/tweaks/ScopifyEnumTests.cpp @@ -26,7 +26,7 @@ enum ^E; )cpp"); } -TEST_F(ScopifyEnumTest, ApplyTest) { +TEST_F(ScopifyEnumTest, ApplyTestWithPrefix) { std::string Original = R"cpp( enum ^E { EV1, EV2, EV3 }; enum E; @@ -39,13 +39,69 @@ E func(E in) } )cpp"; std::string Expected = R"cpp( -enum class E { EV1, EV2, EV3 }; +enum class E { V1, V2, V3 }; enum class E; E func(E in) { - E out = E::EV1; - if (in == E::EV2) - out = E::EV3; + E out = E::V1; + if (in == E::V2) + out = E::V3; + return out; +} +)cpp"; + FileName = "Test.cpp"; + SCOPED_TRACE(Original); + EXPECT_EQ(apply(Original), Expected); +} + +TEST_F(ScopifyEnumTest, ApplyTestWithPrefixAndUnderscore) { + std::string Original = R"cpp( +enum ^E { E_V1, E_V2, E_V3 }; +enum E; +E func(E in) +{ + E out = E_V1; + if (in == E_V2) + out = E::E_V3; + return out; +} +)cpp"; + std::string Expected = R"cpp( +enum class E { V1, V2, V3 }; +enum class E; +E func(E in) +{ + E out = E::V1; + if (in == E::V2) + out = E::V3; + return out; +} +)cpp"; + FileName = "Test.cpp"; + SCOPED_TRACE(Original); + EXPECT_EQ(apply(Original), Expected); +} + +TEST_F(ScopifyEnumTest, ApplyTestWithoutPrefix) { + std::string Original = R"cpp( +enum ^E { V1, V2, V3 }; +enum E; +E func(E in) +{ + E out = V1; + if (in == V2) + out = E::V3; + return out; +} +)cpp"; + std::string Expected = R"cpp( +enum class E { V1, V2, V3 }; +enum class E; +E func(E in) +{ + E out = E::V1; + if (in == E::V2) + out = E::V3; return out; } )cpp"; diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 5956ccb925485c77c941029282d5dcac3fde9185..6a9892bada9155e4ee87ceef384e1937f0e2cfa9 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -69,6 +69,9 @@ Code completion Code actions ^^^^^^^^^^^^ +- The tweak for turning unscoped into scoped enums now removes redundant prefixes + from the enum values. + Signature help ^^^^^^^^^^^^^^ @@ -87,7 +90,11 @@ Improvements to clang-doc Improvements to clang-query --------------------------- -The improvements are... +- Added the `file` command to dynamically load a list of commands and matchers + from an external file, allowing the cost of reading the compilation database + and building the AST to be imposed just once for faster prototyping. + +- Removed support for ``enable output srcloc``. Fixes #GH82591 Improvements to clang-rename ---------------------------- @@ -110,6 +117,9 @@ Improvements to clang-tidy - Fixed `--verify-config` option not properly parsing checks when using the literal operator in the `.clang-tidy` config. +- Added argument `--exclude-header-filter` and config option `ExcludeHeaderFilterRegex` + to exclude headers from analysis via a RegEx. + New checks ^^^^^^^^^^ @@ -145,6 +155,15 @@ New checks Finds initializer lists for aggregate types that could be written as designated initializers instead. +- New :doc:`modernize-use-std-format + ` check. + + Converts calls to ``absl::StrFormat``, or other functions via + configuration options, to C++20's ``std::format``, or another function + via a configuration option, modifying the format string appropriately and + removing now-unnecessary calls to ``std::string::c_str()`` and + ``std::string::data()``. + - New :doc:`readability-enum-initial-value ` check. @@ -166,6 +185,10 @@ New checks New check aliases ^^^^^^^^^^^^^^^^^ +- New alias :doc:`cert-int09-c ` to + :doc:`readability-enum-initial-value ` + was added. + Changes in existing checks ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -173,6 +196,11 @@ Changes in existing checks ` check by detecting side effect from calling a method with non-const reference parameters. +- Improved :doc:`bugprone-casting-through-void + ` check by ignoring casts + where source is already a ``void``` pointer, making middle ``void`` pointer + casts bug-free. + - Improved :doc:`bugprone-forwarding-reference-overload ` check to ignore deleted constructors which won't hide other overloads. @@ -190,6 +218,10 @@ Changes in existing checks eliminating false positives resulting from direct usage of bitwise operators within parentheses. +- Improved :doc:`bugprone-optional-value-conversion + ` check by eliminating + false positives resulting from use of optionals in unevaluated context. + - Improved :doc:`bugprone-suspicious-include ` check by replacing the local options `HeaderFileExtensions` and `ImplementationFileExtensions` by the @@ -232,6 +264,12 @@ Changes in existing checks `. Fixed incorrect hints when using list-initialization. +- Improved :doc:`cppcoreguidelines-special-member-functions + ` check with a + new option `AllowImplicitlyDeletedCopyOrMove`, which removes the requirement + for explicit copy or move special member functions when they are already + implicitly deleted. + - Improved :doc:`google-build-namespaces ` check by replacing the local option `HeaderFileExtensions` by the global option of the same name. @@ -247,6 +285,10 @@ Changes in existing checks - Improved :doc:`google-runtime-int ` check performance through optimizations. +- Improved :doc:`hicpp-signed-bitwise ` + check by ignoring false positives involving positive integer literals behind + implicit casts when `IgnorePositiveIntegerLiterals` is enabled. + - Improved :doc:`hicpp-ignored-remove-result ` check by ignoring other functions with same prefixes as the target specific functions. @@ -288,6 +330,10 @@ Changes in existing checks don't remove parentheses used in ``sizeof`` calls when they have array index accesses as arguments. +- Improved :doc:`modernize-use-constraints + ` check by fixing a crash that + occurred in some scenarios and excluding system headers from analysis. + - Improved :doc:`modernize-use-nullptr ` check to include support for C23, which also has introduced the ``nullptr`` keyword. @@ -313,10 +359,18 @@ Changes in existing checks ` check by adding fix-its. +- Improved :doc:`readability-const-return-type + ` check to eliminate false + positives when returning types with const not at the top level. + - Improved :doc:`readability-duplicate-include ` check by excluding include directives that form the filename using macro. +- Improved :doc:`readability-else-after-return + ` check to ignore + `if consteval` statements, for which the `else` branch must not be removed. + - Improved :doc:`readability-identifier-naming ` check in `GetConfigPerFile` mode by resolving symbolic links to header files. Fixed handling of Hungarian @@ -332,11 +386,25 @@ Changes in existing checks ` check to properly emit warnings for static data member with an in-class initializer. +- Improved :doc:`readability-static-accessed-through-instance + ` check to + support calls to overloaded operators as base expression and provide fixes to + expressions with side-effects. + +- Improved :doc:`readability-simplify-boolean-expr + ` check to avoid to emit + warning for macro when IgnoreMacro option is enabled. + - Improved :doc:`readability-static-definition-in-anonymous-namespace ` check by resolving fix-it overlaps in template code by disregarding implicit instances. +- Improved :doc:`readability-string-compare + ` check to also detect + usages of ``std::string_view::compare``. Added a `StringLikeClasses` option + to detect usages of ``compare`` method in custom string-like classes. + Removed checks ^^^^^^^^^^^^^^ diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/bad-signal-to-kill-thread.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/bad-signal-to-kill-thread.rst index 24b08da6c5c30b4a22e656aa8bc1026c501edc41..365624a8b1a0ad5ea841835b9d4eb2f6566b3129 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/bad-signal-to-kill-thread.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/bad-signal-to-kill-thread.rst @@ -14,3 +14,5 @@ just the individual thread. Use any signal except ``SIGTERM``. This check corresponds to the CERT C Coding Standard rule `POS44-C. Do not use signals to terminate threads `_. + +`cert-pos44-c` redirects here as an alias of this check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/macro-parentheses.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/macro-parentheses.rst index b6bafcec1644f7454dc9afcca09bc19f705814b4..80cea089564e4b558df97759815ccbfdfe1eac90 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/macro-parentheses.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/macro-parentheses.rst @@ -17,3 +17,7 @@ completely before it is used. It is also recommended to surround macro arguments in the replacement list with parentheses. This ensures that the argument value is calculated properly. + +This check corresponds to the CERT C Coding Standard rule +`PRE20-C. Macro replacement lists should be parenthesized. +`_ diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-memory-comparison.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-memory-comparison.rst index 549e214b241b116341cb236c3e8bbac96d6e6a0d..f82863f7c2f18f1e3804482d01a8a0fa52c6a94c 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-memory-comparison.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-memory-comparison.rst @@ -29,3 +29,5 @@ This check is also related to and partially overlaps the CERT C++ Coding Standar and `EXP62-CPP. Do not access the bits of an object representation that are not part of the object's value representation `_ + +`cert-exp42-c` redirects here as an alias of this check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert/int09-c.rst b/clang-tools-extra/docs/clang-tidy/checks/cert/int09-c.rst new file mode 100644 index 0000000000000000000000000000000000000000..74c606929547db263c5b9f2b95940fb6a56f6d8b --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/cert/int09-c.rst @@ -0,0 +1,10 @@ +.. title:: clang-tidy - cert-int09-c +.. meta:: + :http-equiv=refresh: 5;URL=../readability/enum-initial-value.html + +cert-int09-c +============ + +The `cert-int09-c` check is an alias, please see +:doc:`readability-enum-initial-value <../readability/enum-initial-value>` for +more information. diff --git a/clang-tools-extra/docs/clang-tidy/checks/concurrency/thread-canceltype-asynchronous.rst b/clang-tools-extra/docs/clang-tidy/checks/concurrency/thread-canceltype-asynchronous.rst index 11edd001365d1414f6a00a60dbf5f474eef47c1d..5e4d980077d507fcb0bbfa7d6e4ef1a196265b91 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/concurrency/thread-canceltype-asynchronous.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/concurrency/thread-canceltype-asynchronous.rst @@ -17,3 +17,5 @@ be acted upon and the effect is as if it was an asynchronous cancellation. This check corresponds to the CERT C Coding Standard rule `POS47-C. Do not use threads that can be canceled asynchronously `_. + +`cert-pos47-c` redirects here as an alias of this check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/special-member-functions.rst b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/special-member-functions.rst index 176956d6cb2bd725e7ff96d83de36a6eff80b9ce..20f898fdab93053e803b186d346a2995a4a26e8b 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/special-member-functions.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/cppcoreguidelines/special-member-functions.rst @@ -45,9 +45,10 @@ Options .. option:: AllowMissingMoveFunctions - When set to `true` (default is `false`), this check doesn't flag classes which define no move - operations at all. It still flags classes which define only one of either - move constructor or move assignment operator. With this option enabled, the following class won't be flagged: + When set to `true` (default is `false`), this check doesn't flag classes + which define no move operations at all. It still flags classes which define + only one of either move constructor or move assignment operator. With this + option enabled, the following class won't be flagged: .. code-block:: c++ @@ -59,10 +60,11 @@ Options .. option:: AllowMissingMoveFunctionsWhenCopyIsDeleted - When set to `true` (default is `false`), this check doesn't flag classes which define deleted copy - operations but don't define move operations. This flag is related to Google C++ Style Guide - https://google.github.io/styleguide/cppguide.html#Copyable_Movable_Types. With this option enabled, the - following class won't be flagged: + When set to `true` (default is `false`), this check doesn't flag classes + which define deleted copy operations but don't define move operations. This + flag is related to Google C++ Style Guide `Copyable and Movable Types + `_. + With this option enabled, the following class won't be flagged: .. code-block:: c++ @@ -71,3 +73,15 @@ Options A& operator=(const A&) = delete; ~A(); }; + +.. option:: AllowImplicitlyDeletedCopyOrMove + + When set to `true` (default is `false`), this check doesn't flag classes + which implicitly delete copy or move operations. + With this option enabled, the following class won't be flagged: + + .. code-block:: c++ + + struct A : boost::noncopyable { + ~A() { std::cout << "dtor\n"; } + }; diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 49747ff896ba5c6f8556af99a0993090328e406b..85e4f0352ac22b2b4e23cc36eb6b14814b48a08b 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -120,7 +120,7 @@ Clang-Tidy Checks :doc:`bugprone-posix-return `, "Yes" :doc:`bugprone-redundant-branch-condition `, "Yes" :doc:`bugprone-reserved-identifier `, "Yes" - :doc:`bugprone-return-const-ref-from-parameter ` + :doc:`bugprone-return-const-ref-from-parameter `, :doc:`bugprone-shared-ptr-array-mismatch `, "Yes" :doc:`bugprone-signal-handler `, :doc:`bugprone-signed-char-misuse `, @@ -300,6 +300,7 @@ Clang-Tidy Checks :doc:`modernize-use-nullptr `, "Yes" :doc:`modernize-use-override `, "Yes" :doc:`modernize-use-starts-ends-with `, "Yes" + :doc:`modernize-use-std-format `, "Yes" :doc:`modernize-use-std-numbers `, "Yes" :doc:`modernize-use-std-print `, "Yes" :doc:`modernize-use-trailing-return-type `, "Yes" @@ -395,8 +396,10 @@ Clang-Tidy Checks :doc:`readability-use-std-min-max `, "Yes" :doc:`zircon-temporary-objects `, +Check aliases +------------- -.. csv-table:: Aliases.. +.. csv-table:: :header: "Name", "Redirect", "Offers fixes" :doc:`bugprone-narrowing-conversions `, :doc:`cppcoreguidelines-narrowing-conversions `, @@ -413,6 +416,7 @@ Clang-Tidy Checks :doc:`cert-exp42-c `, :doc:`bugprone-suspicious-memory-comparison `, :doc:`cert-fio38-c `, :doc:`misc-non-copyable-objects `, :doc:`cert-flp37-c `, :doc:`bugprone-suspicious-memory-comparison `, + :doc:`cert-int09-c `, :doc:`readability-enum-initial-value `, "Yes" :doc:`cert-msc24-c `, :doc:`bugprone-unsafe-functions `, :doc:`cert-msc30-c `, :doc:`cert-msc50-cpp `, :doc:`cert-msc32-c `, :doc:`cert-msc51-cpp `, diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/throw-by-value-catch-by-reference.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/throw-by-value-catch-by-reference.rst index af6ec1416e5e270f30f0e3669d560e38515e20c3..b89fbe8b44665e0892ea32837bc54e9a4237b141 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/misc/throw-by-value-catch-by-reference.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/misc/throw-by-value-catch-by-reference.rst @@ -3,8 +3,7 @@ misc-throw-by-value-catch-by-reference ====================================== -`cert-err09-cpp` redirects here as an alias for this check. -`cert-err61-cpp` redirects here as an alias for this check. +`cert-err09-cpp` and `cert-err61-cpp` redirect here as aliases of this check. Finds violations of the rule "Throw by value, catch by reference" presented for example in "C++ Coding Standards" by H. Sutter and A. Alexandrescu, as well as diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constraints.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constraints.rst index be62dd5823d552ce8d46ff3cf4765ca41ae87aa3..a8b31b80e580b0679f272d6e7ffd38bf2e05a429 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constraints.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-constraints.rst @@ -68,3 +68,7 @@ The tool will replace the above code with, // The tool will not emit a diagnostic or attempt to replace the code. template = 0> struct my_class {}; + +.. note:: + + System headers are not analyzed by this check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-format.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-format.rst new file mode 100644 index 0000000000000000000000000000000000000000..a1599f0fc58fe68df702d446ffd6cb6523e084ba --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-format.rst @@ -0,0 +1,84 @@ +.. title:: clang-tidy - modernize-use-std-format + +modernize-use-std-format +======================== + +Converts calls to ``absl::StrFormat``, or other functions via +configuration options, to C++20's ``std::format``, or another function +via a configuration option, modifying the format string appropriately and +removing now-unnecessary calls to ``std::string::c_str()`` and +``std::string::data()``. + +For example, it turns lines like + +.. code-block:: c++ + + return absl::StrFormat("The %s is %3d", description.c_str(), value); + +into: + +.. code-block:: c++ + + return std::format("The {} is {:3}", description, value); + +The check uses the same format-string-conversion algorithm as +`modernize-use-std-print <../modernize/use-std-print.html>`_ and its +shortcomings are described in the documentation for that check. + +Options +------- + +.. option:: StrictMode + + When `true`, the check will add casts when converting from variadic + functions and printing signed or unsigned integer types (including + fixed-width integer types from ````, ``ptrdiff_t``, ``size_t`` + and ``ssize_t``) as the opposite signedness to ensure that the output + would matches that of a simple wrapper for ``std::sprintf`` that + accepted a C-style variable argument list. For example, with + `StrictMode` enabled, + + .. code-block:: c++ + + extern std::string strprintf(const char *format, ...); + int i = -42; + unsigned int u = 0xffffffff; + return strprintf("%d %u\n", i, u); + + would be converted to + + .. code-block:: c++ + + return std::format("{} {}\n", static_cast(i), static_cast(u)); + + to ensure that the output will continue to be the unsigned representation + of -42 and the signed representation of 0xffffffff (often 4294967254 + and -1 respectively). When `false` (which is the default), these casts + will not be added which may cause a change in the output. Note that this + option makes no difference for the default value of + `StrFormatLikeFunctions` since ``absl::StrFormat`` takes a function + parameter pack and is not a variadic function. + +.. option:: StrFormatLikeFunctions + + A semicolon-separated list of (fully qualified) function names to + replace, with the requirement that the first parameter contains the + printf-style format string and the arguments to be formatted follow + immediately afterwards. The default value for this option is + `absl::StrFormat`. + +.. option:: ReplacementFormatFunction + + The function that will be used to replace the function set by the + `StrFormatLikeFunctions` option rather than the default + `std::format`. It is expected that the function provides an interface + that is compatible with ``std::format``. A suitable candidate would be + `fmt::format`. + +.. option:: FormatHeader + + The header that must be included for the declaration of + `ReplacementFormatFunction` so that a ``#include`` directive can be added if + required. If `ReplacementFormatFunction` is `std::format` then this option will + default to ````, otherwise this option will default to nothing + and no ``#include`` directive will be added. diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst index 9bb691e9d9512e41a2d79399ef12d23414996a26..79648a1104bca237f0bcb5e518f0e27c2a6827db 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-std-print.rst @@ -118,7 +118,7 @@ Options .. option:: PrintfLikeFunctions - A semicolon-separated list of (fully qualified) extra function names to + A semicolon-separated list of (fully qualified) function names to replace, with the requirement that the first parameter contains the printf-style format string and the arguments to be formatted follow immediately afterwards. If neither this option nor @@ -128,7 +128,7 @@ Options .. option:: FprintfLikeFunctions - A semicolon-separated list of (fully qualified) extra function names to + A semicolon-separated list of (fully qualified) function names to replace, with the requirement that the first parameter is retained, the second parameter contains the printf-style format string and the arguments to be formatted follow immediately afterwards. If neither this diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/enum-initial-value.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/enum-initial-value.rst index 660efc1eaff3e53527aad41a19151be0fe13062d..b27e10d5c13369e54279056f76d5f7d248cf616d 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/enum-initial-value.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/enum-initial-value.rst @@ -6,70 +6,83 @@ readability-enum-initial-value Enforces consistent style for enumerators' initialization, covering three styles: none, first only, or all initialized explicitly. -When adding new enumerations, inconsistent initial value will cause potential -enumeration value conflicts. +An inconsistent style and strictness to defining the initializing value of +enumerators may cause issues if the enumeration is extended with new +enumerators that obtain their integer representation implicitly. -In an enumeration, the following three cases are accepted. -1. none of enumerators are explicit initialized. -2. the first enumerator is explicit initialized. -3. all of enumerators are explicit initialized. +The following three cases are accepted: + +#. **No** enumerators are explicit initialized. +#. Exactly **the first** enumerator is explicit initialized. +#. **All** enumerators are explicit initialized. .. code-block:: c++ - // valid, none of enumerators are initialized. - enum A { - e0, - e1, - e2, + enum A { // (1) Valid, none of enumerators are initialized. + a0, + a1, + a2, }; - // valid, the first enumerator is initialized. - enum A { - e0 = 0, - e1, - e2, + enum B { // (2) Valid, the first enumerator is initialized. + b0 = 0, + b1, + b2, }; - // valid, all of enumerators are initialized. - enum A { - e0 = 0, - e1 = 1, - e2 = 2, + enum C { // (3) Valid, all of enumerators are initialized. + c0 = 0, + c1 = 1, + c2 = 2, }; - // invalid, e1 is not explicit initialized. - enum A { + enum D { // Invalid, d1 is not explicitly initialized! + d0 = 0, + d1, + d2 = 2, + }; + + enum E { // Invalid, e1, e3, and e5 are not explicitly initialized. e0 = 0, e1, e2 = 2, + e3, // Dangerous, as the numeric values of e3 and e5 are both 3, and this is not explicitly visible in the code! + e4 = 2, + e5, }; +This check corresponds to the CERT C Coding Standard recommendation `INT09-C. Ensure enumeration constants map to unique values +`_. + +`cert-int09-c` redirects here as an alias of this check. + Options ------- .. option:: AllowExplicitZeroFirstInitialValue - If set to `false`, the first enumerator must not be explicitly initialized. - See examples below. Default is `true`. + If set to `false`, the first enumerator must not be explicitly initialized to + a literal ``0``. + Default is `true`. .. code-block:: c++ - enum A { - e0 = 0, // not allowed if AllowExplicitZeroFirstInitialValue is false - e1, - e2, + enum F { + f0 = 0, // Not allowed if AllowExplicitZeroFirstInitialValue is false. + f1, + f2, }; .. option:: AllowExplicitSequentialInitialValues - If set to `false`, sequential initializations are not allowed. - See examples below. Default is `true`. + If set to `false`, explicit initialization to sequential values are not + allowed. + Default is `true`. .. code-block:: c++ - enum A { - e0 = 1, // not allowed if AllowExplicitSequentialInitialValues is false - e1 = 2, - e2 = 3, - }; + enum G { + g0 = 1, // Not allowed if AllowExplicitSequentialInitialValues is false. + g1 = 2, + g2 = 3, diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/static-accessed-through-instance.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/static-accessed-through-instance.rst index 23d12f418366402bb1d97517e19a8c04cbd354fb..ffb3738bf72c92aff474e7bed546843c345f4bb9 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/static-accessed-through-instance.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/static-accessed-through-instance.rst @@ -35,3 +35,6 @@ is changed to: C::E1; C::E2; +The `--fix` commandline option provides default support for safe fixes, whereas +`--fix-notes` enables fixes that may replace expressions with side effects, +potentially altering the program's behavior. diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/string-compare.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/string-compare.rst index 268632eee61a278ce7899ccc81c1163c5b07879b..4be2473bed2d74808e609e935295b78425077282 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/readability/string-compare.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/string-compare.rst @@ -14,10 +14,12 @@ recommended to avoid the risk of incorrect interpretation of the return value and to simplify the code. The string equality and inequality operators can also be faster than the ``compare`` method due to early termination. -Examples: +Example +------- .. code-block:: c++ + // The same rules apply to std::string_view. std::string str1{"a"}; std::string str2{"b"}; @@ -50,5 +52,36 @@ Examples: } The above code examples show the list of if-statements that this check will -give a warning for. All of them uses ``compare`` to check if equality or +give a warning for. All of them use ``compare`` to check equality or inequality of two strings instead of using the correct operators. + +Options +------- + +.. option:: StringLikeClasses + + A string containing semicolon-separated names of string-like classes. + By default contains only ``::std::basic_string`` + and ``::std::basic_string_view``. If a class from this list has + a ``compare`` method similar to that of ``std::string``, it will be checked + in the same way. + +Example +^^^^^^^ + +.. code-block:: c++ + + struct CustomString { + public: + int compare (const CustomString& other) const; + } + + CustomString str1; + CustomString str2; + + // use str1 != str2 instead. + if (str1.compare(str2)) { + } + +If `StringLikeClasses` contains ``CustomString``, the check will suggest +replacing ``compare`` with equality operator. diff --git a/clang-tools-extra/docs/clang-tidy/index.rst b/clang-tools-extra/docs/clang-tidy/index.rst index 852566f26672385553b1445d0863c640a97f10a6..9ccacefa3c2c5999bfdff1a874d74699144833a0 100644 --- a/clang-tools-extra/docs/clang-tidy/index.rst +++ b/clang-tools-extra/docs/clang-tidy/index.rst @@ -116,122 +116,130 @@ An overview of all the command-line options: Generic Options: - --help - Display available options (--help-hidden for more) - --help-list - Display list of available options (--help-list-hidden for more) - --version - Display the version of this program + --help - Display available options (--help-hidden for more) + --help-list - Display list of available options (--help-list-hidden for more) + --version - Display the version of this program clang-tidy options: - --checks= - Comma-separated list of globs with optional '-' - prefix. Globs are processed in order of - appearance in the list. Globs without '-' - prefix add checks with matching names to the - set, globs with the '-' prefix remove checks - with matching names from the set of enabled - checks. This option's value is appended to the - value of the 'Checks' option in .clang-tidy - file, if any. - --config= - Specifies a configuration in YAML/JSON format: - -config="{Checks: '*', - CheckOptions: {x: y}}" - When the value is empty, clang-tidy will - attempt to find a file named .clang-tidy for - each source file in its parent directories. - --config-file= - Specify the path of .clang-tidy or custom config file: - e.g. --config-file=/some/path/myTidyConfigFile - This option internally works exactly the same way as - --config option after reading specified config file. - Use either --config-file or --config, not both. - --dump-config - Dumps configuration in the YAML format to - stdout. This option can be used along with a - file name (and '--' if the file is outside of a - project with configured compilation database). - The configuration used for this file will be - printed. - Use along with -checks=* to include - configuration of all checks. - --enable-check-profile - Enable per-check timing profiles, and print a - report to stderr. - --enable-module-headers-parsing - Enables preprocessor-level module header parsing - for C++20 and above, empowering specific checks - to detect macro definitions within modules. This - feature may cause performance and parsing issues - and is therefore considered experimental. - --explain-config - For each enabled check explains, where it is - enabled, i.e. in clang-tidy binary, command - line or a specific configuration file. - --export-fixes= - YAML file to store suggested fixes in. The - stored fixes can be applied to the input source - code with clang-apply-replacements. - --extra-arg= - Additional argument to append to the compiler command line - --extra-arg-before= - Additional argument to prepend to the compiler command line - --fix - Apply suggested fixes. Without -fix-errors - clang-tidy will bail out if any compilation - errors were found. - --fix-errors - Apply suggested fixes even if compilation - errors were found. If compiler errors have - attached fix-its, clang-tidy will apply them as - well. - --fix-notes - If a warning has no fix, but a single fix can - be found through an associated diagnostic note, - apply the fix. - Specifying this flag will implicitly enable the - '--fix' flag. - --format-style= - Style for formatting code around applied fixes: - - 'none' (default) turns off formatting - - 'file' (literally 'file', not a placeholder) - uses .clang-format file in the closest parent - directory - - '{ }' specifies options inline, e.g. - -format-style='{BasedOnStyle: llvm, IndentWidth: 8}' - - 'llvm', 'google', 'webkit', 'mozilla' - See clang-format documentation for the up-to-date - information about formatting styles and options. - This option overrides the 'FormatStyle` option in - .clang-tidy file, if any. - --header-filter= - Regular expression matching the names of the - headers to output diagnostics from. Diagnostics - from the main file of each translation unit are - always displayed. - Can be used together with -line-filter. - This option overrides the 'HeaderFilterRegex' - option in .clang-tidy file, if any. - --line-filter= - List of files with line ranges to filter the - warnings. Can be used together with - -header-filter. The format of the list is a - JSON array of objects: - [ - {"name":"file1.cpp","lines":[[1,3],[5,7]]}, - {"name":"file2.h"} - ] - --list-checks - List all enabled checks and exit. Use with - -checks=* to list all available checks. - --load= - Load the specified plugin - -p - Build path - --quiet - Run clang-tidy in quiet mode. This suppresses - printing statistics about ignored warnings and - warnings treated as errors if the respective - options are specified. - --store-check-profile= - By default reports are printed in tabulated - format to stderr. When this option is passed, - these per-TU profiles are instead stored as JSON. - --system-headers - Display the errors from system headers. - This option overrides the 'SystemHeaders' option - in .clang-tidy file, if any. - --use-color - Use colors in diagnostics. If not set, colors - will be used if the terminal connected to - standard output supports colors. - This option overrides the 'UseColor' option in - .clang-tidy file, if any. - --verify-config - Check the config files to ensure each check and - option is recognized. - --vfsoverlay= - Overlay the virtual filesystem described by file - over the real file system. - --warnings-as-errors= - Upgrades warnings to errors. Same format as - '-checks'. - This option's value is appended to the value of - the 'WarningsAsErrors' option in .clang-tidy - file, if any. + --checks= - Comma-separated list of globs with optional '-' + prefix. Globs are processed in order of + appearance in the list. Globs without '-' + prefix add checks with matching names to the + set, globs with the '-' prefix remove checks + with matching names from the set of enabled + checks. This option's value is appended to the + value of the 'Checks' option in .clang-tidy + file, if any. + --config= - Specifies a configuration in YAML/JSON format: + -config="{Checks: '*', + CheckOptions: {x: y}}" + When the value is empty, clang-tidy will + attempt to find a file named .clang-tidy for + each source file in its parent directories. + --config-file= - Specify the path of .clang-tidy or custom config file: + e.g. --config-file=/some/path/myTidyConfigFile + This option internally works exactly the same way as + --config option after reading specified config file. + Use either --config-file or --config, not both. + --dump-config - Dumps configuration in the YAML format to + stdout. This option can be used along with a + file name (and '--' if the file is outside of a + project with configured compilation database). + The configuration used for this file will be + printed. + Use along with -checks=* to include + configuration of all checks. + --enable-check-profile - Enable per-check timing profiles, and print a + report to stderr. + --enable-module-headers-parsing - Enables preprocessor-level module header parsing + for C++20 and above, empowering specific checks + to detect macro definitions within modules. This + feature may cause performance and parsing issues + and is therefore considered experimental. + --exclude-header-filter= - Regular expression matching the names of the + headers to exclude diagnostics from. Diagnostics + from the main file of each translation unit are + always displayed. + Must be used together with --header-filter. + Can be used together with -line-filter. + This option overrides the 'ExcludeHeaderFilterRegex' + option in .clang-tidy file, if any. + --explain-config - For each enabled check explains, where it is + enabled, i.e. in clang-tidy binary, command + line or a specific configuration file. + --export-fixes= - YAML file to store suggested fixes in. The + stored fixes can be applied to the input source + code with clang-apply-replacements. + --extra-arg= - Additional argument to append to the compiler command line + --extra-arg-before= - Additional argument to prepend to the compiler command line + --fix - Apply suggested fixes. Without -fix-errors + clang-tidy will bail out if any compilation + errors were found. + --fix-errors - Apply suggested fixes even if compilation + errors were found. If compiler errors have + attached fix-its, clang-tidy will apply them as + well. + --fix-notes - If a warning has no fix, but a single fix can + be found through an associated diagnostic note, + apply the fix. + Specifying this flag will implicitly enable the + '--fix' flag. + --format-style= - Style for formatting code around applied fixes: + - 'none' (default) turns off formatting + - 'file' (literally 'file', not a placeholder) + uses .clang-format file in the closest parent + directory + - '{ }' specifies options inline, e.g. + -format-style='{BasedOnStyle: llvm, IndentWidth: 8}' + - 'llvm', 'google', 'webkit', 'mozilla' + See clang-format documentation for the up-to-date + information about formatting styles and options. + This option overrides the 'FormatStyle` option in + .clang-tidy file, if any. + --header-filter= - Regular expression matching the names of the + headers to output diagnostics from. Diagnostics + from the main file of each translation unit are + always displayed. + Can be used together with -line-filter. + This option overrides the 'HeaderFilterRegex' + option in .clang-tidy file, if any. + --line-filter= - List of files with line ranges to filter the + warnings. Can be used together with + -header-filter. The format of the list is a + JSON array of objects: + [ + {"name":"file1.cpp","lines":[[1,3],[5,7]]}, + {"name":"file2.h"} + ] + --list-checks - List all enabled checks and exit. Use with + -checks=* to list all available checks. + --load= - Load the specified plugin + -p - Build path + --quiet - Run clang-tidy in quiet mode. This suppresses + printing statistics about ignored warnings and + warnings treated as errors if the respective + options are specified. + --store-check-profile= - By default reports are printed in tabulated + format to stderr. When this option is passed, + these per-TU profiles are instead stored as JSON. + --system-headers - Display the errors from system headers. + This option overrides the 'SystemHeaders' option + in .clang-tidy file, if any. + --use-color - Use colors in diagnostics. If not set, colors + will be used if the terminal connected to + standard output supports colors. + This option overrides the 'UseColor' option in + .clang-tidy file, if any. + --verify-config - Check the config files to ensure each check and + option is recognized. + --vfsoverlay= - Overlay the virtual filesystem described by file + over the real file system. + --warnings-as-errors= - Upgrades warnings to errors. Same format as + '-checks'. + This option's value is appended to the value of + the 'WarningsAsErrors' option in .clang-tidy + file, if any. -p is used to read a compile command database. @@ -269,6 +277,7 @@ An overview of all the command-line options: Checks - Same as '--checks'. Additionally, the list of globs can be specified as a list instead of a string. + ExcludeHeaderFilterRegex - Same as '--exclude-header-filter'. ExtraArgs - Same as '--extra-args'. ExtraArgsBefore - Same as '--extra-args-before'. FormatStyle - Same as '--format-style'. diff --git a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp index 878067aca0173feec649a575c865d0dbb241e860..f7cc9d19123635d9a5c3c79655ca4b0c6d038cb5 100644 --- a/clang-tools-extra/include-cleaner/lib/WalkAST.cpp +++ b/clang-tools-extra/include-cleaner/lib/WalkAST.cpp @@ -267,18 +267,21 @@ public: return true; } - // Report a reference from explicit specializations to the specialized - // template. Implicit ones are filtered out by RAV and explicit instantiations - // are already traversed through typelocs. + // Report a reference from explicit specializations/instantiations to the + // specialized template. Implicit ones are filtered out by RAV. bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *CTSD) { - if (CTSD->isExplicitSpecialization()) + // if (CTSD->isExplicitSpecialization()) + if (clang::isTemplateExplicitInstantiationOrSpecialization( + CTSD->getTemplateSpecializationKind())) report(CTSD->getLocation(), CTSD->getSpecializedTemplate()->getTemplatedDecl()); return true; } bool VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *VTSD) { - if (VTSD->isExplicitSpecialization()) + // if (VTSD->isExplicitSpecialization()) + if (clang::isTemplateExplicitInstantiationOrSpecialization( + VTSD->getTemplateSpecializationKind())) report(VTSD->getLocation(), VTSD->getSpecializedTemplate()->getTemplatedDecl()); return true; diff --git a/clang-tools-extra/modularize/ModularizeUtilities.cpp b/clang-tools-extra/modularize/ModularizeUtilities.cpp index 53e8a49d1a54893316d52ed1de4c176a61673e99..b202b3aae8f8a3a5488bb019a30553ef3fa0df2e 100644 --- a/clang-tools-extra/modularize/ModularizeUtilities.cpp +++ b/clang-tools-extra/modularize/ModularizeUtilities.cpp @@ -435,11 +435,9 @@ static std::string replaceDotDot(StringRef Path) { llvm::sys::path::const_iterator B = llvm::sys::path::begin(Path), E = llvm::sys::path::end(Path); while (B != E) { - if (B->compare(".") == 0) { - } - else if (B->compare("..") == 0) + if (*B == "..") llvm::sys::path::remove_filename(Buffer); - else + else if (*B != ".") llvm::sys::path::append(Buffer, *B); ++B; } diff --git a/clang-tools-extra/test/clang-query/Inputs/empty.script b/clang-tools-extra/test/clang-query/Inputs/empty.script new file mode 100644 index 0000000000000000000000000000000000000000..3c30abd1ae5d1526771c5a4ce09674ea6ba01c56 --- /dev/null +++ b/clang-tools-extra/test/clang-query/Inputs/empty.script @@ -0,0 +1 @@ +# This file intentionally has no queries diff --git a/clang-tools-extra/test/clang-query/Inputs/file.script b/clang-tools-extra/test/clang-query/Inputs/file.script new file mode 100644 index 0000000000000000000000000000000000000000..b58e7bbc24bfb917e979c1946e9efae7dfa40f97 --- /dev/null +++ b/clang-tools-extra/test/clang-query/Inputs/file.script @@ -0,0 +1 @@ +f DIRECTORY/runtime_file.script diff --git a/clang-tools-extra/test/clang-query/Inputs/runtime_file.script b/clang-tools-extra/test/clang-query/Inputs/runtime_file.script new file mode 100644 index 0000000000000000000000000000000000000000..714d7f03b1bf6aaa4dc6b40d1c048de29cfd7f20 --- /dev/null +++ b/clang-tools-extra/test/clang-query/Inputs/runtime_file.script @@ -0,0 +1,5 @@ +set bind-root false + +l func functionDecl(hasName("bar")) +m func.bind("f") +m varDecl().bind("v") \ No newline at end of file diff --git a/clang-tools-extra/test/clang-query/errors.c b/clang-tools-extra/test/clang-query/errors.c index bbb742125744f9bc96ad36b22302fa794a67332b..3b9059ab0257f4448a525ee60ad5cb1f2f1cf0c3 100644 --- a/clang-tools-extra/test/clang-query/errors.c +++ b/clang-tools-extra/test/clang-query/errors.c @@ -1,10 +1,12 @@ // RUN: not clang-query -c foo -c bar %s -- | FileCheck %s // RUN: not clang-query -f %S/Inputs/foo.script %s -- | FileCheck %s // RUN: not clang-query -f %S/Inputs/nonexistent.script %s -- 2>&1 | FileCheck --check-prefix=CHECK-NONEXISTENT %s +// RUN: not clang-query -c 'file %S/Inputs/nonexistent.script' %s -- 2>&1 | FileCheck --check-prefix=CHECK-NONEXISTENT-FILEQUERY %s // RUN: not clang-query -c foo -f foo %s -- 2>&1 | FileCheck --check-prefix=CHECK-BOTH %s // CHECK: unknown command: foo // CHECK-NOT: unknown command: bar // CHECK-NONEXISTENT: cannot open {{.*}}nonexistent.script +// CHECK-NONEXISTENT-FILEQUERY: cannot open {{.*}}nonexistent.script // CHECK-BOTH: cannot specify both -c and -f diff --git a/clang-tools-extra/test/clang-query/file-empty.c b/clang-tools-extra/test/clang-query/file-empty.c new file mode 100644 index 0000000000000000000000000000000000000000..15137c57e915ea561e85201d8427021f18bc4336 --- /dev/null +++ b/clang-tools-extra/test/clang-query/file-empty.c @@ -0,0 +1,2 @@ +// RUN: clang-query -c 'file %S/Inputs/empty.script' %s -- +// COM: no output expected; nothing to CHECK diff --git a/clang-tools-extra/test/clang-query/file-query.c b/clang-tools-extra/test/clang-query/file-query.c new file mode 100644 index 0000000000000000000000000000000000000000..10a44e7aaccf24f14d6668620c7ed1251d3fa7ca --- /dev/null +++ b/clang-tools-extra/test/clang-query/file-query.c @@ -0,0 +1,14 @@ +// RUN: rm -rf %/t +// RUN: mkdir %/t +// RUN: cp %/S/Inputs/file.script %/t/file.script +// RUN: cp %/S/Inputs/runtime_file.script %/t/runtime_file.script +// Need to embed the correct temp path in the actual JSON-RPC requests. +// RUN: sed -e "s|DIRECTORY|%/t|" %/t/file.script > %/t/file.script.temp + +// RUN: clang-query -c 'file %/t/file.script.temp' %s -- | FileCheck %s + +// CHECK: file-query.c:11:1: note: "f" binds here +void bar(void) {} + +// CHECK: file-query.c:14:1: note: "v" binds here +int baz{1}; diff --git a/clang-tools-extra/test/clang-tidy/check_clang_tidy.py b/clang-tools-extra/test/clang-tidy/check_clang_tidy.py index 6d4b466afa691a74b59185e360f0b9a8b6597261..e92179ac82c6a06ddccbb670c17c28c19a72cf2b 100755 --- a/clang-tools-extra/test/clang-tidy/check_clang_tidy.py +++ b/clang-tools-extra/test/clang-tidy/check_clang_tidy.py @@ -99,6 +99,7 @@ class CheckRunner: self.has_check_fixes = False self.has_check_messages = False self.has_check_notes = False + self.expect_no_diagnosis = False self.export_fixes = args.export_fixes self.fixes = MessagePrefix("CHECK-FIXES") self.messages = MessagePrefix("CHECK-MESSAGES") @@ -172,12 +173,21 @@ class CheckRunner: ) if not has_check_fix and not has_check_message and not has_check_note: - sys.exit( - "%s, %s or %s not found in the input" - % (self.fixes.prefix, self.messages.prefix, self.notes.prefix) - ) + self.expect_no_diagnosis = True - assert self.has_check_fixes or self.has_check_messages or self.has_check_notes + expect_diagnosis = ( + self.has_check_fixes or self.has_check_messages or self.has_check_notes + ) + if self.expect_no_diagnosis and expect_diagnosis: + sys.exit( + "%s, %s or %s not found in the input" + % ( + self.fixes.prefix, + self.messages.prefix, + self.notes.prefix, + ) + ) + assert expect_diagnosis or self.expect_no_diagnosis def prepare_test_inputs(self): # Remove the contents of the CHECK lines to avoid CHECKs matching on @@ -226,6 +236,10 @@ class CheckRunner: print("------------------------------------------------------------------") return clang_tidy_output + def check_no_diagnosis(self, clang_tidy_output): + if clang_tidy_output != "": + sys.exit("No diagnostics were expected, but found the ones above") + def check_fixes(self): if self.has_check_fixes: try_run( @@ -277,7 +291,9 @@ class CheckRunner: self.get_prefixes() self.prepare_test_inputs() clang_tidy_output = self.run_clang_tidy() - if self.export_fixes is None: + if self.expect_no_diagnosis: + self.check_no_diagnosis(clang_tidy_output) + elif self.export_fixes is None: self.check_fixes() self.check_messages(clang_tidy_output) self.check_notes(clang_tidy_output) diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string b/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string index d031f27beb9dfef99d61b44bff19a6dc8e1a885f..0c160bc182b6ebdf4ddce7f460ad38c8fd8a99a4 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string +++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/Headers/string @@ -108,6 +108,8 @@ struct basic_string_view { constexpr bool starts_with(C ch) const noexcept; constexpr bool starts_with(const C* s) const; + constexpr int compare(basic_string_view sv) const noexcept; + static constexpr size_t npos = -1; }; @@ -132,6 +134,14 @@ bool operator==(const std::wstring&, const std::wstring&); bool operator==(const std::wstring&, const wchar_t*); bool operator==(const wchar_t*, const std::wstring&); +bool operator==(const std::string_view&, const std::string_view&); +bool operator==(const std::string_view&, const char*); +bool operator==(const char*, const std::string_view&); + +bool operator!=(const std::string_view&, const std::string_view&); +bool operator!=(const std::string_view&, const char*); +bool operator!=(const char*, const std::string_view&); + size_t strlen(const char* str); } diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp index 3913d2d8a295c75e75c49c0503fa32a364959a33..a784e498858738967066381585b8c958140182ca 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/casting-through-void.cpp @@ -89,3 +89,10 @@ void bit_cast() { __builtin_bit_cast(int *, static_cast(&d)); // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: do not cast 'double *' to 'int *' through 'void *' [bugprone-casting-through-void] } + +namespace PR87069 { + void castconstVoidToVoid() { + const void* ptr = nullptr; + int* numberPtr = static_cast(const_cast(ptr)); + } +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/optional-value-conversion.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/optional-value-conversion.cpp index 72ef35c956d2e868849e9bd679e7d09d7d8022b0..1228d64bb6909e93da78943e81a6422da1fc2202 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/optional-value-conversion.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/optional-value-conversion.cpp @@ -210,4 +210,6 @@ void correct(std::optional param) std::optional* p2 = &p; takeOptionalValue(p2->value_or(5U)); takeOptionalRef(p2->value_or(5U)); + + using Type = decltype(takeOptionalValue(*param)); } diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/return-const-ref-from-parameter.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/return-const-ref-from-parameter.cpp index a83a019ec7437da6ccda446b20af87f0639ee303..ca41bdf74a1073d1dc1dfb125f1b13944bdc835d 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/return-const-ref-from-parameter.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/return-const-ref-from-parameter.cpp @@ -1,9 +1,18 @@ -// RUN: %check_clang_tidy %s bugprone-return-const-ref-from-parameter %t +// RUN: %check_clang_tidy %s bugprone-return-const-ref-from-parameter %t -- -- -fno-delayed-template-parsing using T = int; using TConst = int const; using TConstRef = int const&; +template +struct Wrapper { Wrapper(T); }; + +template +struct Identity { using type = T; }; + +template +struct ConstRef { using type = const T&; }; + namespace invalid { int const &f1(int const &a) { return a; } @@ -18,8 +27,59 @@ int const &f3(TConstRef a) { return a; } int const &f4(TConst &a) { return a; } // CHECK-MESSAGES: :[[@LINE-1]]:35: warning: returning a constant reference parameter +template +const T& tf1(const T &a) { return a; } +// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: returning a constant reference parameter + +template +const T& itf1(const T &a) { return a; } +// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: returning a constant reference parameter + +template +typename ConstRef::type itf2(const T &a) { return a; } +// CHECK-MESSAGES: :[[@LINE-1]]:54: warning: returning a constant reference parameter + +template +typename ConstRef::type itf3(typename ConstRef::type a) { return a; } +// CHECK-MESSAGES: :[[@LINE-1]]:72: warning: returning a constant reference parameter + +template +const T& itf4(typename ConstRef::type a) { return a; } +// CHECK-MESSAGES: :[[@LINE-1]]:54: warning: returning a constant reference parameter + +void instantiate(const int ¶m, const float ¶mf, int &mut_param, float &mut_paramf) { + itf1(0); + itf1(param); + itf1(paramf); + itf2(0); + itf2(param); + itf2(paramf); + itf3(0); + itf3(param); + itf3(paramf); + itf4(0); + itf4(param); + itf4(paramf); +} + +struct C { + const C& foo(const C&c) { return c; } +// CHECK-MESSAGES: :[[@LINE-1]]:38: warning: returning a constant reference parameter +}; + } // namespace invalid +namespace false_negative_because_dependent_and_not_instantiated { +template +typename ConstRef::type tf2(const T &a) { return a; } + +template +typename ConstRef::type tf3(typename ConstRef::type a) { return a; } + +template +const T& tf4(typename ConstRef::type a) { return a; } +} // false_negative_because_dependent_and_not_instantiated + namespace valid { int const &f1(int &a) { return a; } @@ -28,4 +88,58 @@ int const &f2(int &&a) { return a; } int f1(int const &a) { return a; } +template +T tf1(T a) { return a; } + +template +T tf2(const T a) { return a; } + +template +T tf3(const T &a) { return a; } + +template +Identity::type tf4(const T &a) { return a; } + +template +T itf1(T a) { return a; } + +template +T itf2(const T a) { return a; } + +template +T itf3(const T &a) { return a; } + +template +Wrapper itf4(const T& a) { return a; } + +template +const T& itf5(T& a) { return a; } + +template +T itf6(T& a) { return a; } + +void instantiate(const int ¶m, const float ¶mf, int &mut_param, float &mut_paramf) { + itf1(0); + itf1(param); + itf1(paramf); + itf2(0); + itf2(param); + itf2(paramf); + itf3(0); + itf3(param); + itf3(paramf); + itf2(0); + itf2(param); + itf2(paramf); + itf3(0); + itf3(param); + itf3(paramf); + itf4(param); + itf4(paramf); + itf5(mut_param); + itf5(mut_paramf); + itf6(mut_param); + itf6(mut_paramf); +} + } // namespace valid diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init-no-crash.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init-no-crash.cpp index 300fff6cb179bfc00b7e48635af8efbcedaf9891..2e2964dda1dafdd996e1def36fa0463aecb72cb5 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init-no-crash.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init-no-crash.cpp @@ -5,3 +5,11 @@ struct X { // CHECK-MESSAGES: :[[@LINE-1]]:5: error: field has incomplete type 'X' [clang-diagnostic-error] int a = 10; }; + +template class NoCrash { + // CHECK-MESSAGES: :[[@LINE+2]]:20: error: base class has incomplete type + // CHECK-MESSAGES: :[[@LINE-2]]:29: note: definition of 'NoCrash' is not complete until the closing '}' + class B : public NoCrash { + template B(U u) {} + }; +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp index 8d6992afef08a977ee35673db604369ae866927e..eaa73b906ce09289c56f18b8d916b00334954d1c 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/pro-type-member-init.cpp @@ -463,12 +463,6 @@ struct NegativeIncompleteArrayMember { char e[]; }; -template class NoCrash { - class B : public NoCrash { - template B(U u) {} - }; -}; - struct PositiveBitfieldMember { PositiveBitfieldMember() {} // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constructor does not initialize these fields: F diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/special-member-functions-relaxed.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/special-member-functions-relaxed.cpp index 0c17f57968a990b3d62c7d9e0cf392536803e935..26142ccc835f2948fc63fe4652b8e882894f591a 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/special-member-functions-relaxed.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/special-member-functions-relaxed.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s cppcoreguidelines-special-member-functions %t -- -config="{CheckOptions: {cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions: true, cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor: true}}" -- +// RUN: %check_clang_tidy %s cppcoreguidelines-special-member-functions %t -- -config="{CheckOptions: {cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions: true, cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor: true, cppcoreguidelines-special-member-functions.AllowImplicitlyDeletedCopyOrMove: true}}" -- // Don't warn on destructors without definitions, they might be defaulted in another TU. class DeclaresDestructor { @@ -34,12 +34,13 @@ class DefinesCopyAssignment { class DefinesMoveConstructor { DefinesMoveConstructor(DefinesMoveConstructor &&); }; -// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveConstructor' defines a move constructor but does not define a destructor, a copy constructor, a copy assignment operator or a move assignment operator [cppcoreguidelines-special-member-functions] +// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveConstructor' defines a move constructor but does not define a destructor or a move assignment operator [cppcoreguidelines-special-member-functions] class DefinesMoveAssignment { DefinesMoveAssignment &operator=(DefinesMoveAssignment &&); }; -// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveAssignment' defines a move assignment operator but does not define a destructor, a copy constructor, a copy assignment operator or a move constructor [cppcoreguidelines-special-member-functions] +// CHECK-MESSAGES: [[@LINE-3]]:7: warning: class 'DefinesMoveAssignment' defines a move assignment operator but does not define a destructor or a move constructor [cppcoreguidelines-special-member-functions] + class DefinesNothing { }; @@ -81,3 +82,22 @@ struct TemplateClass { // This should not cause problems. TemplateClass InstantiationWithInt; TemplateClass InstantiationWithDouble; + +struct NoCopy +{ + NoCopy() = default; + ~NoCopy() = default; + + NoCopy(const NoCopy&) = delete; + NoCopy(NoCopy&&) = delete; + + NoCopy& operator=(const NoCopy&) = delete; + NoCopy& operator=(NoCopy&&) = delete; +}; + +// CHECK-MESSAGES: [[@LINE+1]]:8: warning: class 'NonCopyable' defines a copy constructor but does not define a destructor or a copy assignment operator [cppcoreguidelines-special-member-functions] +struct NonCopyable : NoCopy +{ + NonCopyable() = default; + NonCopyable(const NonCopyable&) = delete; +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/hicpp/signed-bitwise-integer-literals.cpp b/clang-tools-extra/test/clang-tidy/checkers/hicpp/signed-bitwise-integer-literals.cpp index edbb56f90cb0e1ea421676b90dd4444b8a638184..aca7ae1fd76fbe6172c9d5b264703cc1d44c0450 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/hicpp/signed-bitwise-integer-literals.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/hicpp/signed-bitwise-integer-literals.cpp @@ -11,6 +11,7 @@ void examples() { // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use of a signed integer operand with a binary bitwise operator unsigned URes2 = URes << 1; //Ok + unsigned URes3 = URes & 1; //Ok int IResult; IResult = 10 & 2; //Ok @@ -21,6 +22,8 @@ void examples() { IResult = Int << 1; // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator IResult = ~0; //Ok + IResult = -1 & 1; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator [hicpp-signed-bitwise] } enum EnumConstruction { diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/unused-using-decls.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/unused-using-decls.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4918aae16cb94a1720708a55bdd816a69c9763dc --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/unused-using-decls.hpp @@ -0,0 +1,6 @@ +// RUN: %check_clang_tidy %s misc-unused-using-decls %t + +// Verify that we don't generate the warnings on header files. +namespace foo { class Foo {}; } + +using foo::Foo; diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/unused-using-decls.hxx b/clang-tools-extra/test/clang-tidy/checkers/misc/unused-using-decls.hxx deleted file mode 100644 index f15e4fae80c0bc40a86cf47412213cabb5eaeaf3..0000000000000000000000000000000000000000 --- a/clang-tools-extra/test/clang-tidy/checkers/misc/unused-using-decls.hxx +++ /dev/null @@ -1,6 +0,0 @@ -// RUN: %check_clang_tidy %s misc-unused-using-decls %t -- --fix-notes -- -fno-delayed-template-parsing -isystem %S/Inputs - -// Verify that we don't generate the warnings on header files. -namespace foo { class Foo {}; } - -using foo::Foo; diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/make-unique.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/make-unique.cpp index 7934c6e93ffbd38a7ae4eaa1b11215172da557a9..fe512a8f3bf3211668961c9da8632783315aeb54 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/make-unique.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/make-unique.cpp @@ -606,11 +606,8 @@ void invoke_template() { template_fun(foo); } -void no_fix_for_invalid_new_loc() { - // FIXME: Although the code is valid, the end location of `new struct Base` is - // invalid. Correct it once https://bugs.llvm.org/show_bug.cgi?id=35952 is - // fixed. +void fix_for_c_style_struct() { auto T = std::unique_ptr(new struct Base); // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use std::make_unique instead - // CHECK-FIXES: auto T = std::unique_ptr(new struct Base); + // CHECK-FIXES: auto T = std::make_unique(); } diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/min-max-use-initializer-list.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/min-max-use-initializer-list.cpp index 51ab9bda975f10baba00221fe02a6ab13f07ae90..1f2dad2b933ca70d7957d967f94bcecb8027681d 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/min-max-use-initializer-list.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/min-max-use-initializer-list.cpp @@ -300,6 +300,27 @@ B maxTT2 = std::max(B(), std::max(B(), B())); B maxTT3 = std::max(B(), std::max(B(), B()), [](const B &lhs, const B &rhs) { return lhs.a[0] < rhs.a[0]; }); // CHECK-FIXES: B maxTT3 = std::max(B(), std::max(B(), B()), [](const B &lhs, const B &rhs) { return lhs.a[0] < rhs.a[0]; }); +struct GH91982 { + int fun0Args(); + int fun1Arg(int a); + int fun2Args(int a, int b); + int fun3Args(int a, int b, int c); + int fun4Args(int a, int b, int c, int d); + + int foo() { + return std::max( + fun0Args(), + std::max(fun1Arg(0), + std::max(fun2Args(0, 1), + std::max(fun3Args(0, 1, 2), fun4Args(0, 1, 2, 3))))); +// CHECK-MESSAGES: :[[@LINE-5]]:12: warning: do not use nested 'std::max' calls, use an initializer list instead [modernize-min-max-use-initializer-list] +// CHECK-FIXES: return std::max( +// CHECK-FIXES-NEXT: {fun0Args(), +// CHECK-FIXES-NEXT: fun1Arg(0), +// CHECK-FIXES-NEXT: fun2Args(0, 1), +// CHECK-FIXES-NEXT: fun3Args(0, 1, 2), fun4Args(0, 1, 2, 3)}); + } +}; } // namespace diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp index 3ec44be8a1c8c3ca5f0c520e274b889293174550..3bcd5cd74024eaf1ba29f9d20dca2c9c9739fd00 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-constraints.cpp @@ -724,3 +724,35 @@ void not_last_param() { } } // namespace enable_if_trailing_type_parameter + + +// Issue fixes: + +namespace PR91872 { + +enum expression_template_option { value1, value2 }; + +template struct number_category { + static const int value = 0; +}; + +constexpr int number_kind_complex = 1; + +template +struct number { + using type = T; +}; + +template struct component_type { + using type = T; +}; + +template +inline typename std::enable_if< + number_category::value == number_kind_complex, + component_type>>::type::type +abs(const number &v) { + return {}; +} + +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp new file mode 100644 index 0000000000000000000000000000000000000000..815e22b29155153b392a34e5238fc8deba9bb6a9 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-custom.cpp @@ -0,0 +1,52 @@ +// RUN: %check_clang_tidy -check-suffixes=,STRICT \ +// RUN: -std=c++20 %s modernize-use-std-format %t -- \ +// RUN: -config="{CheckOptions: { \ +// RUN: modernize-use-std-format.StrictMode: true, \ +// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2', \ +// RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \ +// RUN: modernize-use-std-format.FormatHeader: '' \ +// RUN: }}" \ +// RUN: -- -isystem %clang_tidy_headers +// RUN: %check_clang_tidy -check-suffixes=,NOTSTRICT \ +// RUN: -std=c++20 %s modernize-use-std-format %t -- \ +// RUN: -config="{CheckOptions: { \ +// RUN: modernize-use-std-format.StrFormatLikeFunctions: '::strprintf; mynamespace::strprintf2', \ +// RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \ +// RUN: modernize-use-std-format.FormatHeader: '' \ +// RUN: }}" \ +// RUN: -- -isystem %clang_tidy_headers + +#include +#include +// CHECK-FIXES: #include + +std::string strprintf(const char *, ...); + +namespace mynamespace { + std::string strprintf2(const char *, ...); +} + +std::string strprintf_test(const std::string &name, double value) { + return strprintf("'%s'='%f'\n", name.c_str(), value); + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'fmt::format' instead of 'strprintf' [modernize-use-std-format] + // CHECK-FIXES: return fmt::format("'{}'='{:f}'\n", name, value); + + return mynamespace::strprintf2("'%s'='%f'\n", name.c_str(), value); + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'fmt::format' instead of 'strprintf2' [modernize-use-std-format] + // CHECK-FIXES: return fmt::format("'{}'='{:f}'\n", name, value); +} + +std::string StrFormat_strict_conversion() { + const unsigned char uc = 'A'; + return strprintf("Integer %hhd from unsigned char\n", uc); + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'fmt::format' instead of 'strprintf' [modernize-use-std-format] + // CHECK-FIXES-NOTSTRICT: return fmt::format("Integer {} from unsigned char\n", uc); + // CHECK-FIXES-STRICT: return fmt::format("Integer {} from unsigned char\n", static_cast(uc)); +} + +// Ensure that MatchesAnyListedNameMatcher::NameMatcher::match() can cope with a +// NamedDecl that has no name when we're trying to match unqualified_strprintf. +std::string A(const std::string &in) +{ + return "_" + in; +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-fmt.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-fmt.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d136cf309168d5eac9bd00468e817b902fe6d71 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format-fmt.cpp @@ -0,0 +1,24 @@ +// RUN: %check_clang_tidy %s modernize-use-std-format %t -- \ +// RUN: -config="{CheckOptions: { \ +// RUN: StrictMode: true, \ +// RUN: modernize-use-std-format.StrFormatLikeFunctions: 'fmt::sprintf', \ +// RUN: modernize-use-std-format.ReplacementFormatFunction: 'fmt::format', \ +// RUN: modernize-use-std-format.FormatHeader: '' \ +// RUN: }}" \ +// RUN: -- -isystem %clang_tidy_headers + +// CHECK-FIXES: #include +#include + +namespace fmt +{ +// Use const char * for the format since the real type is hard to mock up. +template +std::string sprintf(const char *format, const Args&... args); +} // namespace fmt + +std::string fmt_sprintf_simple() { + return fmt::sprintf("Hello %s %d", "world", 42); + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'fmt::format' instead of 'sprintf' [modernize-use-std-format] + // CHECK-FIXES: fmt::format("Hello {} {}", "world", 42); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e8dea1dce2c97222c790adc29504db76cc2c432e --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-std-format.cpp @@ -0,0 +1,120 @@ +// RUN: %check_clang_tidy \ +// RUN: -std=c++20 %s modernize-use-std-format %t -- \ +// RUN: -config="{CheckOptions: {StrictMode: true}}" \ +// RUN: -- -isystem %clang_tidy_headers +// RUN: %check_clang_tidy \ +// RUN: -std=c++20 %s modernize-use-std-format %t -- \ +// RUN: -config="{CheckOptions: {StrictMode: false}}" \ +// RUN: -- -isystem %clang_tidy_headers +#include +// CHECK-FIXES: #include + +namespace absl +{ +// Use const char * for the format since the real type is hard to mock up. +template +std::string StrFormat(const char *format, const Args&... args); +} // namespace absl + +template +struct iterator { + T *operator->(); + T &operator*(); +}; + +std::string StrFormat_simple() { + return absl::StrFormat("Hello"); + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] + // CHECK-FIXES: return std::format("Hello"); +} + +std::string StrFormat_complex(const char *name, double value) { + return absl::StrFormat("'%s'='%f'", name, value); + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] + // CHECK-FIXES: return std::format("'{}'='{:f}'", name, value); +} + +std::string StrFormat_integer_conversions() { + return absl::StrFormat("int:%d int:%d char:%c char:%c", 65, 'A', 66, 'B'); + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] + // CHECK-FIXES: return std::format("int:{} int:{:d} char:{:c} char:{}", 65, 'A', 66, 'B'); +} + +// FormatConverter is capable of removing newlines from the end of the format +// string. Ensure that isn't incorrectly happening for std::format. +std::string StrFormat_no_newline_removal() { + return absl::StrFormat("a line\n"); + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] + // CHECK-FIXES: return std::format("a line\n"); +} + +// FormatConverter is capable of removing newlines from the end of the format +// string. Ensure that isn't incorrectly happening for std::format. +std::string StrFormat_cstr_removal(const std::string &s1, const std::string *s2) { + return absl::StrFormat("%s %s %s %s", s1.c_str(), s1.data(), s2->c_str(), s2->data()); + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] + // CHECK-FIXES: return std::format("{} {} {} {}", s1, s1, *s2, *s2); +} + +std::string StrFormat_strict_conversion() { + const unsigned char uc = 'A'; + return absl::StrFormat("Integer %hhd from unsigned char\n", uc); + // CHECK-MESSAGES: [[@LINE-1]]:10: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] + // CHECK-FIXES: return std::format("Integer {} from unsigned char\n", uc); +} + +std::string StrFormat_field_width_and_precision() { + auto s1 = absl::StrFormat("width only:%*d width and precision:%*.*f precision only:%.*f", 3, 42, 4, 2, 3.14159265358979323846, 5, 2.718); + // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] + // CHECK-FIXES: std::format("width only:{:{}} width and precision:{:{}.{}f} precision only:{:.{}f}", 42, 3, 3.14159265358979323846, 4, 2, 2.718, 5); + + auto s2 = absl::StrFormat("width and precision positional:%1$*2$.*3$f after", 3.14159265358979323846, 4, 2); + // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] + // CHECK-FIXES: std::format("width and precision positional:{0:{1}.{2}f} after", 3.14159265358979323846, 4, 2); + + const int width = 10, precision = 3; + const unsigned int ui1 = 42, ui2 = 43, ui3 = 44; + auto s3 = absl::StrFormat("casts width only:%*d width and precision:%*.*d precision only:%.*d\n", 3, ui1, 4, 2, ui2, 5, ui3); + // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] + // CHECK-FIXES-NOTSTRICT: std::format("casts width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", ui1, 3, ui2, 4, 2, ui3, 5); + // CHECK-FIXES-STRICT: std::format("casts width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", static_cast(ui1), 3, static_cast(ui2), 4, 2, static_cast(ui3), 5); + + auto s4 = absl::StrFormat("c_str removal width only:%*s width and precision:%*.*s precision only:%.*s", 3, s1.c_str(), 4, 2, s2.c_str(), 5, s3.c_str()); + // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] + // CHECK-FIXES: std::format("c_str removal width only:{:>{}} width and precision:{:>{}.{}} precision only:{:.{}}", s1, 3, s2, 4, 2, s3, 5); + + const std::string *ps1 = &s1, *ps2 = &s2, *ps3 = &s3; + auto s5 = absl::StrFormat("c_str() removal pointer width only:%-*s width and precision:%-*.*s precision only:%-.*s", 3, ps1->c_str(), 4, 2, ps2->c_str(), 5, ps3->c_str()); + // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] + // CHECK-FIXES: std::format("c_str() removal pointer width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", *ps1, 3, *ps2, 4, 2, *ps3, 5); + + iterator is1, is2, is3; + auto s6 = absl::StrFormat("c_str() removal iterator width only:%-*s width and precision:%-*.*s precision only:%-.*s", 3, is1->c_str(), 4, 2, is2->c_str(), 5, is3->c_str()); + // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] + // CHECK-FIXES: std::format("c_str() removal iterator width only:{:{}} width and precision:{:{}.{}} precision only:{:.{}}", *is1, 3, *is2, 4, 2, *is3, 5); + + return s1 + s2 + s3 + s4 + s5 + s6; +} + +std::string StrFormat_macros() { + // The function call is replaced even though it comes from a macro. +#define FORMAT absl::StrFormat + auto s1 = FORMAT("Hello %d", 42); + // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] + // CHECK-FIXES: std::format("Hello {}", 42); + + // The format string is replaced even though it comes from a macro, this + // behaviour is required so that that macros are replaced. +#define FORMAT_STRING "Hello %s" + auto s2 = absl::StrFormat(FORMAT_STRING, 42); + // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] + // CHECK-FIXES: std::format("Hello {}", 42); + + // Arguments that are macros aren't replaced with their value, even if they are rearranged. +#define VALUE 3.14159265358979323846 +#define WIDTH 10 +#define PRECISION 4 + auto s3 = absl::StrFormat("Hello %*.*f", WIDTH, PRECISION, VALUE); + // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use 'std::format' instead of 'StrFormat' [modernize-use-std-format] + // CHECK-FIXES: std::format("Hello {:{}.{}f}", VALUE, WIDTH, PRECISION); +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/duplicate-include.h b/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/duplicate-include.h index bf288023274b155ccbe453d79097a67a09884f7e..22d3a3acbc916ed7bf889572da8d7efa9b026697 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/duplicate-include.h +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/duplicate-include.h @@ -1,15 +1,15 @@ -#ifndef READABILITY_DUPLICATE_INCLUDE_H -#define READABILITY_DUPLICATE_INCLUDE_H - -extern int g; -#include "duplicate-include2.h" -extern int h; -#include "duplicate-include2.h" -extern int i; -// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: duplicate include -// CHECK-FIXES: {{^extern int g;$}} -// CHECK-FIXES-NEXT: {{^#include "duplicate-include2.h"$}} -// CHECK-FIXES-NEXT: {{^extern int h;$}} -// CHECK-FIXES-NEXT: {{^extern int i;$}} - -#endif +#ifndef READABILITY_DUPLICATE_INCLUDE_H +#define READABILITY_DUPLICATE_INCLUDE_H + +extern int g; +#include "duplicate-include2.h" +extern int h; +#include "duplicate-include2.h" +extern int i; +// CHECK-MESSAGES: :[[@LINE-2]]:1: warning: duplicate include +// CHECK-FIXES: {{^extern int g;$}} +// CHECK-FIXES-NEXT: {{^#include "duplicate-include2.h"$}} +// CHECK-FIXES-NEXT: {{^extern int h;$}} +// CHECK-FIXES-NEXT: {{^extern int i;$}} + +#endif diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/duplicate-include2.h b/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/duplicate-include2.h index 58dfa757ee7aedd584aca417031b86f8b2c9e79b..fcbabe12fc378aae5a59689b70b776cb80892088 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/duplicate-include2.h +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/duplicate-include2.h @@ -1 +1 @@ -// This file is intentionally empty. +// This file is intentionally empty. diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/system/sys/types.h b/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/system/sys/types.h index 58dfa757ee7aedd584aca417031b86f8b2c9e79b..fcbabe12fc378aae5a59689b70b776cb80892088 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/system/sys/types.h +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/Inputs/duplicate-include/system/sys/types.h @@ -1 +1 @@ -// This file is intentionally empty. +// This file is intentionally empty. diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp index 10b2858c9caa820dbc3d54cae6cc36678afc92e2..76a3555663b180e72e8da519b5a7f26308624eb0 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/const-return-type.cpp @@ -215,11 +215,9 @@ CREATE_FUNCTION(); using ty = const int; ty p21() {} -// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'ty' (aka 'const int') is typedef const int ty2; ty2 p22() {} -// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'ty2' (aka 'const int') i // Declaration uses a macro, while definition doesn't. In this case, we won't // fix the declaration, and will instead issue a warning. @@ -249,7 +247,6 @@ auto p27() -> int const { return 3; } // CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'const int' is 'const'-qu std::add_const::type p28() { return 3; } -// CHECK-MESSAGES: [[@LINE-1]]:1: warning: return type 'std::add_const::typ // p29, p30 are based on // llvm/projects/test-suite/SingleSource/Benchmarks/Misc-C++-EH/spirit.cpp: @@ -355,3 +352,20 @@ struct p41 { // CHECK-FIXES: T foo() const { return 2; } }; template struct p41; + +namespace PR73270 { + template + struct Pair { + using first_type = const K; + using second_type = V; + }; + + template + typename PairType::first_type getFirst() { + return {}; + } + + void test() { + getFirst>(); + } +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return-if-consteval.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return-if-consteval.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8810d215ee97fc5da4273a6b15421db0caf84231 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return-if-consteval.cpp @@ -0,0 +1,17 @@ +// RUN: %check_clang_tidy -std=c++23 %s readability-else-after-return %t + +// Consteval if is an exception to the rule, we cannot remove the else. +void f() { + if (sizeof(int) > 4) { + return; + } else { + return; + } + // CHECK-MESSAGES: [[@LINE-3]]:5: warning: do not use 'else' after 'return' + + if consteval { + return; + } else { + return; + } +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return-if-constexpr.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return-if-constexpr.cpp index 6532940eaf2314b2e2621246e2bbe57bc8c88a4c..1edb3237eaf4d6a380c5abbf191e4bac5e30758a 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return-if-constexpr.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/else-after-return-if-constexpr.cpp @@ -1,22 +1,22 @@ -// RUN: %check_clang_tidy %s readability-else-after-return %t -- -- -std=c++17 - -// Constexpr if is an exception to the rule, we cannot remove the else. -void f() { - if (sizeof(int) > 4) - return; - else - return; - // CHECK-MESSAGES: [[@LINE-2]]:3: warning: do not use 'else' after 'return' - - if constexpr (sizeof(int) > 4) - return; - else - return; - - if constexpr (sizeof(int) > 4) - return; - else if constexpr (sizeof(long) > 4) - return; - else - return; -} +// RUN: %check_clang_tidy %s readability-else-after-return %t -- -- -std=c++17 + +// Constexpr if is an exception to the rule, we cannot remove the else. +void f() { + if (sizeof(int) > 4) + return; + else + return; + // CHECK-MESSAGES: [[@LINE-2]]:3: warning: do not use 'else' after 'return' + + if constexpr (sizeof(int) > 4) + return; + else + return; + + if constexpr (sizeof(int) > 4) + return; + else if constexpr (sizeof(long) > 4) + return; + else + return; +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/magic-numbers-todo.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/magic-numbers-todo.cpp deleted file mode 100644 index 99d9be262a8979d40d65508615795014403f719a..0000000000000000000000000000000000000000 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/magic-numbers-todo.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: %check_clang_tidy %s readability-magic-numbers %t -- -// XFAIL: * - -int ProcessSomething(int input); - -int DoWork() -{ - if (((int)4) > ProcessSomething(10)) - // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 4 is a magic number; consider replacing it with a named constant [readability-magic-numbers] - return 0; - - return 0; -} - - diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr-macros.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr-macros.cpp index 7d0cfe7e27dc2206e673d7c590992b342a09bf9b..d1df79e23a1e6f9402e3056f1941b482e19aebab 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr-macros.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/simplify-boolean-expr-macros.cpp @@ -6,6 +6,7 @@ // RUN: -- #define NEGATE(expr) !(expr) +#define NOT_AND_NOT(a, b) (!a && !b) bool without_macro(bool a, bool b) { return !(!a && b); @@ -13,8 +14,17 @@ bool without_macro(bool a, bool b) { // CHECK-FIXES: return a || !b; } -bool macro(bool a, bool b) { - return NEGATE(!a && b); - // CHECK-MESSAGES-MACROS: :[[@LINE-1]]:12: warning: boolean expression can be simplified by DeMorgan's theorem - // CHECK-FIXES: return NEGATE(!a && b); +void macro(bool a, bool b) { + NEGATE(!a && b); + // CHECK-MESSAGES-MACROS: :[[@LINE-1]]:5: warning: boolean expression can be simplified by DeMorgan's theorem + // CHECK-FIXES: NEGATE(!a && b); + !NOT_AND_NOT(a, b); + // CHECK-MESSAGES-MACROS: :[[@LINE-1]]:5: warning: boolean expression can be simplified by DeMorgan's theorem + // CHECK-FIXES: !NOT_AND_NOT(a, b); + !(NEGATE(a) && b); + // CHECK-MESSAGES-MACROS: :[[@LINE-1]]:5: warning: boolean expression can be simplified by DeMorgan's theorem + // CHECK-FIXES: !(NEGATE(a) && b); + !(a && NEGATE(b)); + // CHECK-MESSAGES-MACROS: :[[@LINE-1]]:5: warning: boolean expression can be simplified by DeMorgan's theorem + // CHECK-FIXES: !(a && NEGATE(b)); } diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/static-accessed-through-instance.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/static-accessed-through-instance.cpp index 81c1cecf607f660548ac7eb351a58c306262a4b1..202fe9be6d00c530e7cce1fadda783101bef9fb4 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/static-accessed-through-instance.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/static-accessed-through-instance.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t -- -- -isystem %S/Inputs/static-accessed-through-instance +// RUN: %check_clang_tidy %s readability-static-accessed-through-instance %t -- --fix-notes -- -isystem %S/Inputs/static-accessed-through-instance #include <__clang_cuda_builtin_vars.h> enum OutEnum { @@ -47,7 +47,8 @@ C &f(int, int, int, int); void g() { f(1, 2, 3, 4).x; // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance] - // CHECK-FIXES: {{^}} f(1, 2, 3, 4).x;{{$}} + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: member base expression may carry some side effects + // CHECK-FIXES: {{^}} C::x;{{$}} } int i(int &); @@ -59,12 +60,14 @@ int k(bool); void f(C c) { j(i(h().x)); // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: static member - // CHECK-FIXES: {{^}} j(i(h().x));{{$}} + // CHECK-MESSAGES: :[[@LINE-2]]:7: note: member base expression may carry some side effects + // CHECK-FIXES: {{^}} j(i(C::x));{{$}} // The execution of h() depends on the return value of a(). j(k(a() && h().x)); // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: static member - // CHECK-FIXES: {{^}} j(k(a() && h().x));{{$}} + // CHECK-MESSAGES: :[[@LINE-2]]:14: note: member base expression may carry some side effects + // CHECK-FIXES: {{^}} j(k(a() && C::x));{{$}} if ([c]() { c.ns(); @@ -72,7 +75,8 @@ void f(C c) { }().x == 15) ; // CHECK-MESSAGES: :[[@LINE-5]]:7: warning: static member - // CHECK-FIXES: {{^}} if ([c]() {{{$}} + // CHECK-MESSAGES: :[[@LINE-6]]:7: note: member base expression may carry some side effects + // CHECK-FIXES: {{^}} if (C::x == 15){{$}} } // Nested specifiers @@ -261,8 +265,11 @@ struct Qptr { }; int func(Qptr qp) { - qp->y = 10; // OK, the overloaded operator might have side-effects. - qp->K = 10; // + qp->y = 10; + qp->K = 10; + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: static member accessed through instance [readability-static-accessed-through-instance] + // CHECK-MESSAGES: :[[@LINE-2]]:3: note: member base expression may carry some side effects + // CHECK-FIXES: {{^}} Q::K = 10; } namespace { @@ -380,3 +387,20 @@ namespace PR51861 { // CHECK-FIXES: {{^}} PR51861::Foo::getBar();{{$}} } } + +namespace PR75163 { + struct Static { + static void call(); + }; + + struct Ptr { + Static* operator->(); + }; + + void test(Ptr& ptr) { + ptr->call(); + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: static member accessed through instance [readability-static-accessed-through-instance] + // CHECK-MESSAGES: :[[@LINE-2]]:5: note: member base expression may carry some side effects + // CHECK-FIXES: {{^}} PR75163::Static::call();{{$}} + } +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/string-compare-custom-string-classes.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/string-compare-custom-string-classes.cpp new file mode 100644 index 0000000000000000000000000000000000000000..faf135833ee15dd823bfcba4f33c0a973db34acf --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/string-compare-custom-string-classes.cpp @@ -0,0 +1,35 @@ +// RUN: %check_clang_tidy %s readability-string-compare %t -- -config='{CheckOptions: {readability-string-compare.StringLikeClasses: "CustomStringTemplateBase;CustomStringNonTemplateBase"}}' -- -isystem %clang_tidy_headers +#include + +struct CustomStringNonTemplateBase { + int compare(const CustomStringNonTemplateBase& Other) const { + return 123; // value is not important for check + } +}; + +template +struct CustomStringTemplateBase { + int compare(const CustomStringTemplateBase& Other) const { + return 123; + } +}; + +struct CustomString1 : CustomStringNonTemplateBase {}; +struct CustomString2 : CustomStringTemplateBase {}; + +void CustomStringClasses() { + std::string_view sv1("a"); + std::string_view sv2("b"); + if (sv1.compare(sv2)) { // No warning - if a std class is not listed in StringLikeClasses, it won't be checked. + } + + CustomString1 custom1; + if (custom1.compare(custom1)) { + } + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings; use the string equality operator instead [readability-string-compare] + + CustomString2 custom2; + if (custom2.compare(custom2)) { + } + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings; use the string equality operator instead [readability-string-compare] +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/string-compare.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/string-compare.cpp index 2c08b86cf72fa02c6d0db353c897bf19e9e903ff..c4fea4341617b8c4d59a53ebe07d3ee5fb7e064f 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/string-compare.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/string-compare.cpp @@ -67,11 +67,27 @@ void Test() { if (str1.compare(comp())) { } // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings; + + std::string_view sv1("a"); + std::string_view sv2("b"); + if (sv1.compare(sv2)) { + } + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings; use the string equality operator instead [readability-string-compare] +} + +struct DerivedFromStdString : std::string {}; + +void TestDerivedClass() { + DerivedFromStdString derived; + if (derived.compare(derived)) { + } + // CHECK-MESSAGES: [[@LINE-2]]:7: warning: do not use 'compare' to test equality of strings; use the string equality operator instead [readability-string-compare] } void Valid() { std::string str1("a", 1); std::string str2("b", 1); + if (str1 == str2) { } if (str1 != str2) { @@ -96,4 +112,11 @@ void Valid() { } if (str1.compare(str2) == -1) { } + + std::string_view sv1("a"); + std::string_view sv2("b"); + if (sv1 == sv2) { + } + if (sv1.compare(sv2) > 0) { + } } diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/config-files/.clang-tidy b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/config-files/.clang-tidy index 942169f2ec42989e4153cb84281c764d206308a1..83605c85dd92cb8ec84ae3971c87db2ac9320b01 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/config-files/.clang-tidy +++ b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/config-files/.clang-tidy @@ -1,2 +1,3 @@ Checks: 'from-parent' HeaderFilterRegex: 'parent' +ExcludeHeaderFilterRegex: 'exc-parent' diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/config-files/1/.clang-tidy b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/config-files/1/.clang-tidy index 800fd4e8eb2a942b52f7abec528efffccf693b81..c37f16bc2d7d258bbfb73dc2618bb4f1358579f0 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/config-files/1/.clang-tidy +++ b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/config-files/1/.clang-tidy @@ -1,2 +1,3 @@ Checks: 'from-child1' HeaderFilterRegex: 'child1' +ExcludeHeaderFilterRegex: 'exc-child1' diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/config-files/3/.clang-tidy b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/config-files/3/.clang-tidy index 28dc8517ac9fe86ae836349cf6e0d07a4fbc82d2..9365108255bd8b9fa6adda6460e74d286b54f13f 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/config-files/3/.clang-tidy +++ b/clang-tools-extra/test/clang-tidy/infrastructure/Inputs/config-files/3/.clang-tidy @@ -1,3 +1,4 @@ InheritParentConfig: true Checks: 'from-child3' HeaderFilterRegex: 'child3' +ExcludeHeaderFilterRegex: 'exc-child3' diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/config-files.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/config-files.cpp index cb0f0bc4d133085e71d01dd9b96032f75166f887..44d43ebbf8d2041fc662ed31ca8a27a5b4008b04 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/config-files.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/config-files.cpp @@ -1,18 +1,23 @@ // RUN: clang-tidy -dump-config %S/Inputs/config-files/- -- | FileCheck %s -check-prefix=CHECK-BASE // CHECK-BASE: Checks: {{.*}}from-parent // CHECK-BASE: HeaderFilterRegex: parent +// CHECK-BASE: ExcludeHeaderFilterRegex: exc-parent // RUN: clang-tidy -dump-config %S/Inputs/config-files/1/- -- | FileCheck %s -check-prefix=CHECK-CHILD1 // CHECK-CHILD1: Checks: {{.*}}from-child1 // CHECK-CHILD1: HeaderFilterRegex: child1 +// CHECK-CHILD1: ExcludeHeaderFilterRegex: exc-child1 // RUN: clang-tidy -dump-config %S/Inputs/config-files/2/- -- | FileCheck %s -check-prefix=CHECK-CHILD2 // CHECK-CHILD2: Checks: {{.*}}from-parent // CHECK-CHILD2: HeaderFilterRegex: parent +// CHECK-CHILD2: ExcludeHeaderFilterRegex: exc-parent // RUN: clang-tidy -dump-config %S/Inputs/config-files/3/- -- | FileCheck %s -check-prefix=CHECK-CHILD3 // CHECK-CHILD3: Checks: {{.*}}from-parent,from-child3 // CHECK-CHILD3: HeaderFilterRegex: child3 -// RUN: clang-tidy -dump-config -checks='from-command-line' -header-filter='from command line' %S/Inputs/config-files/- -- | FileCheck %s -check-prefix=CHECK-COMMAND-LINE +// CHECK-CHILD3: ExcludeHeaderFilterRegex: exc-child3 +// RUN: clang-tidy -dump-config -checks='from-command-line' -header-filter='from command line' -exclude-header-filter='from_command_line' %S/Inputs/config-files/- -- | FileCheck %s -check-prefix=CHECK-COMMAND-LINE // CHECK-COMMAND-LINE: Checks: {{.*}}from-parent,from-command-line // CHECK-COMMAND-LINE: HeaderFilterRegex: from command line +// CHECK-COMMAND-LINE: ExcludeHeaderFilterRegex: from_command_line // For this test we have to use names of the real checks because otherwise values are ignored. // Running with the old key: , value: CheckOptions @@ -66,9 +71,13 @@ // RUN: clang-tidy --checks="-*,readability-identifier-naming" --dump-config %S/Inputs/config-files/- -- | grep "readability-identifier-naming\." | sort --check // Dumped config does not overflow for unsigned options -// RUN: clang-tidy --dump-config \ -// RUN: --checks="-*,misc-throw-by-value-catch-by-reference" \ -// RUN: -- | grep -v -q "misc-throw-by-value-catch-by-reference.MaxSize: '-1'" +// RUN: clang-tidy --dump-config %S/Inputs/config-files/5/- -- | FileCheck %s -check-prefix=CHECK-OVERFLOW +// CHECK-OVERFLOW: misc-throw-by-value-catch-by-reference.MaxSize: '1152921504606846976' -// RUN: clang-tidy --dump-config %S/Inputs/config-files/5/- \ -// RUN: -- | grep -q "misc-throw-by-value-catch-by-reference.MaxSize: '1152921504606846976'" +// RUN: clang-tidy -dump-config -checks='readability-function-size' -header-filter='foo/*' -exclude-header-filter='bar*' %S/Inputs/config-files/- -- | FileCheck %s -check-prefix=CHECK-EXCLUDE-HEADERS +// CHECK-EXCLUDE-HEADERS: HeaderFilterRegex: 'foo/*' +// CHECK-EXCLUDE-HEADERS: ExcludeHeaderFilterRegex: 'bar*' + +// RUN: clang-tidy -dump-config -checks='readability-function-size' -header-filter='' -exclude-header-filter='' %S/Inputs/config-files/- -- | FileCheck %s -check-prefix=EMPTY-CHECK-EXCLUDE-HEADERS +// EMPTY-CHECK-EXCLUDE-HEADERS: HeaderFilterRegex: '' +// EMPTY-CHECK-EXCLUDE-HEADERS: ExcludeHeaderFilterRegex: '' diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/file-filter.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/file-filter.cpp index a7498723de2bf5c328d47124d428bf1bb37fafa3..448ef9ddf166ccc1dca385907074f79d91f22064 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/file-filter.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/file-filter.cpp @@ -11,6 +11,7 @@ // RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' -system-headers -quiet %s -- -I %S/Inputs/file-filter/system/.. -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK4-QUIET %s // RUN: clang-tidy -checks='-*,cppcoreguidelines-pro-type-cstyle-cast' -header-filter='.*' -system-headers %s -- -I %S/Inputs/file-filter/system/.. -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK5 %s // RUN: clang-tidy -checks='-*,cppcoreguidelines-pro-type-cstyle-cast' -header-filter='.*' %s -- -I %S/Inputs/file-filter/system/.. -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK5-NO-SYSTEM-HEADERS %s +// RUN: clang-tidy -checks='-*,google-explicit-constructor' -header-filter='.*' -exclude-header-filter='header1\.h' %s -- -I %S/Inputs/file-filter/ -isystem %S/Inputs/file-filter/system 2>&1 | FileCheck --check-prefix=CHECK6 %s #include "header1.h" // CHECK-NOT: warning: @@ -21,6 +22,7 @@ // CHECK3-QUIET-NOT: warning: // CHECK4: header1.h:1:12: warning: single-argument constructors // CHECK4-QUIET: header1.h:1:12: warning: single-argument constructors +// CHECK6-NOT: warning: #include "header2.h" // CHECK-NOT: warning: @@ -31,6 +33,7 @@ // CHECK3-QUIET: header2.h:1:12: warning: single-argument constructors // CHECK4: header2.h:1:12: warning: single-argument constructors // CHECK4-QUIET: header2.h:1:12: warning: single-argument constructors +// CHECK6: header2.h:1:12: warning: single-argument constructors #include // CHECK-NOT: warning: @@ -41,6 +44,7 @@ // CHECK3-QUIET-NOT: warning: // CHECK4: system-header.h:1:12: warning: single-argument constructors // CHECK4-QUIET: system-header.h:1:12: warning: single-argument constructors +// CHECK6-NOT: warning: class A { A(int); }; // CHECK: :[[@LINE-1]]:11: warning: single-argument constructors @@ -51,6 +55,7 @@ class A { A(int); }; // CHECK3-QUIET: :[[@LINE-6]]:11: warning: single-argument constructors // CHECK4: :[[@LINE-7]]:11: warning: single-argument constructors // CHECK4-QUIET: :[[@LINE-8]]:11: warning: single-argument constructors +// CHECK6: :[[@LINE-9]]:11: warning: single-argument constructors // CHECK-NOT: warning: // CHECK-QUIET-NOT: warning: @@ -73,6 +78,8 @@ class A { A(int); }; // CHECK4-NOT: Suppressed {{.*}} warnings // CHECK4-NOT: Use -header-filter=.* {{.*}} // CHECK4-QUIET-NOT: Suppressed +// CHECK6: Suppressed 2 warnings (2 in non-user code) +// CHECK6: Use -header-filter=.* {{.*}} int x = 123; auto x_ptr = TO_FLOAT_PTR(&x); diff --git a/clang-tools-extra/test/modularize/Inputs/CompileError/module.modulemap b/clang-tools-extra/test/modularize/Inputs/CompileError/module.modulemap index 64180adf5beb358bc34636b89a7ee8f71d34b8b1..f71b66f148ed1920bede5f2c47216a0d396f77d8 100644 --- a/clang-tools-extra/test/modularize/Inputs/CompileError/module.modulemap +++ b/clang-tools-extra/test/modularize/Inputs/CompileError/module.modulemap @@ -1,10 +1,10 @@ -// module.modulemap - -module Level1A { - header "Level1A.h" - export * -} -module HasError { - header "HasError.h" - export * -} +// module.modulemap + +module Level1A { + header "Level1A.h" + export * +} +module HasError { + header "HasError.h" + export * +} diff --git a/clang-tools-extra/test/modularize/Inputs/MissingHeader/module.modulemap b/clang-tools-extra/test/modularize/Inputs/MissingHeader/module.modulemap index 9acb4923f9ac3747548fc900c2c01ab138a08b23..330e13f5ee1558a11f96a2ee83f5222237c5cd51 100644 --- a/clang-tools-extra/test/modularize/Inputs/MissingHeader/module.modulemap +++ b/clang-tools-extra/test/modularize/Inputs/MissingHeader/module.modulemap @@ -1,10 +1,10 @@ -// module.modulemap - -module Level1A { - header "Level1A.h" - export * -} -module Missing { - header "Missing.h" - export * -} +// module.modulemap + +module Level1A { + header "Level1A.h" + export * +} +module Missing { + header "Missing.h" + export * +} diff --git a/clang-tools-extra/test/pp-trace/Inputs/module.modulemap b/clang-tools-extra/test/pp-trace/Inputs/module.modulemap index f16bbc6e2e05b4d50ab56ce84b9efa1b5cffad06..415c874f09d373a3d929f2f2d76cd28a79484622 100644 --- a/clang-tools-extra/test/pp-trace/Inputs/module.modulemap +++ b/clang-tools-extra/test/pp-trace/Inputs/module.modulemap @@ -1,18 +1,18 @@ -// module.modulemap - -module Level1A { - header "Level1A.h" - export * -} -module Level1B { - header "Level1B.h" - export * - module Level2B { - header "Level2B.h" - export * - } -} -module Level2A { - header "Level2A.h" - export * -} +// module.modulemap + +module Level1A { + header "Level1A.h" + export * +} +module Level1B { + header "Level1B.h" + export * + module Level2B { + header "Level2B.h" + export * + } +} +module Level2A { + header "Level2A.h" + export * +} diff --git a/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp b/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp index 06b0d7b365904e74840a2cd4bb6d4135b179d6eb..e414587c568b73eadcc56aad35d2e4ffd79ddebe 100644 --- a/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp +++ b/clang-tools-extra/unittests/clang-query/QueryParserTest.cpp @@ -9,7 +9,6 @@ #include "QueryParser.h" #include "Query.h" #include "QuerySession.h" -#include "clang/Tooling/NodeIntrospection.h" #include "llvm/LineEditor/LineEditor.h" #include "gtest/gtest.h" @@ -61,7 +60,6 @@ TEST_F(QueryParserTest, Quit) { TEST_F(QueryParserTest, Set) { - bool HasIntrospection = tooling::NodeIntrospection::hasIntrospectionSupport(); QueryRef Q = parse("set"); ASSERT_TRUE(isa(Q)); EXPECT_EQ("expected variable name", cast(Q)->ErrStr); @@ -72,13 +70,8 @@ TEST_F(QueryParserTest, Set) { Q = parse("set output"); ASSERT_TRUE(isa(Q)); - if (HasIntrospection) - EXPECT_EQ( - "expected 'diag', 'print', 'detailed-ast', 'srcloc' or 'dump', got ''", - cast(Q)->ErrStr); - else - EXPECT_EQ("expected 'diag', 'print', 'detailed-ast' or 'dump', got ''", - cast(Q)->ErrStr); + EXPECT_EQ("expected 'diag', 'print', 'detailed-ast' or 'dump', got ''", + cast(Q)->ErrStr); Q = parse("set bind-root true foo"); ASSERT_TRUE(isa(Q)); @@ -86,13 +79,8 @@ TEST_F(QueryParserTest, Set) { Q = parse("set output foo"); ASSERT_TRUE(isa(Q)); - if (HasIntrospection) - EXPECT_EQ("expected 'diag', 'print', 'detailed-ast', 'srcloc' or 'dump', " - "got 'foo'", - cast(Q)->ErrStr); - else - EXPECT_EQ("expected 'diag', 'print', 'detailed-ast' or 'dump', got 'foo'", - cast(Q)->ErrStr); + EXPECT_EQ("expected 'diag', 'print', 'detailed-ast' or 'dump', got 'foo'", + cast(Q)->ErrStr); Q = parse("set output dump"); ASSERT_TRUE(isa(Q)); @@ -197,7 +185,7 @@ TEST_F(QueryParserTest, Comment) { TEST_F(QueryParserTest, Complete) { std::vector Comps = QueryParser::complete("", 0, QS); - ASSERT_EQ(8u, Comps.size()); + ASSERT_EQ(9u, Comps.size()); EXPECT_EQ("help ", Comps[0].TypedText); EXPECT_EQ("help", Comps[0].DisplayText); EXPECT_EQ("let ", Comps[1].TypedText); @@ -214,6 +202,8 @@ TEST_F(QueryParserTest, Complete) { EXPECT_EQ("disable", Comps[6].DisplayText); EXPECT_EQ("unlet ", Comps[7].TypedText); EXPECT_EQ("unlet", Comps[7].DisplayText); + EXPECT_EQ("file ", Comps[8].TypedText); + EXPECT_EQ("file", Comps[8].DisplayText); Comps = QueryParser::complete("set o", 5, QS); ASSERT_EQ(1u, Comps.size()); @@ -230,10 +220,8 @@ TEST_F(QueryParserTest, Complete) { EXPECT_EQ("output ", Comps[0].TypedText); EXPECT_EQ("output", Comps[0].DisplayText); - bool HasIntrospection = tooling::NodeIntrospection::hasIntrospectionSupport(); - Comps = QueryParser::complete("enable output ", 14, QS); - ASSERT_EQ(HasIntrospection ? 5u : 4u, Comps.size()); + ASSERT_EQ(4u, Comps.size()); EXPECT_EQ("diag ", Comps[0].TypedText); EXPECT_EQ("diag", Comps[0].DisplayText); @@ -241,12 +229,8 @@ TEST_F(QueryParserTest, Complete) { EXPECT_EQ("print", Comps[1].DisplayText); EXPECT_EQ("detailed-ast ", Comps[2].TypedText); EXPECT_EQ("detailed-ast", Comps[2].DisplayText); - if (HasIntrospection) { - EXPECT_EQ("srcloc ", Comps[3].TypedText); - EXPECT_EQ("srcloc", Comps[3].DisplayText); - } - EXPECT_EQ("dump ", Comps[HasIntrospection ? 4 : 3].TypedText); - EXPECT_EQ("dump", Comps[HasIntrospection ? 4 : 3].DisplayText); + EXPECT_EQ("dump ", Comps[3].TypedText); + EXPECT_EQ("dump", Comps[3].DisplayText); Comps = QueryParser::complete("set traversal ", 14, QS); ASSERT_EQ(2u, Comps.size()); diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index cf97e3c6e851aee92dd5378b85515304fc875999..c20ce47a12abbd8390ce66a57efde38ac6b52125 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -523,6 +523,8 @@ endif() if( CLANG_INCLUDE_TESTS ) + find_package(Perl) + add_subdirectory(unittests) list(APPEND CLANG_TEST_DEPS ClangUnitTests) list(APPEND CLANG_TEST_PARAMS diff --git a/clang/cmake/caches/HLSL.cmake b/clang/cmake/caches/HLSL.cmake index 84850c86f12cd7ab92237452ce8b2bd8fdfb0dce..ed813f60c9c69970e8c93784b39cc3955693a062 100644 --- a/clang/cmake/caches/HLSL.cmake +++ b/clang/cmake/caches/HLSL.cmake @@ -8,6 +8,12 @@ set(LLVM_EXPERIMENTAL_TARGETS_TO_BUILD "DirectX;SPIRV" CACHE STRING "") # HLSL support is currently limted to clang, eventually it will expand to # clang-tools-extra too. -set(LLVM_ENABLE_PROJECTS "clang" CACHE STRING "") +set(LLVM_ENABLE_PROJECTS "clang;clang-tools-extra" CACHE STRING "") set(CLANG_ENABLE_HLSL On CACHE BOOL "") + +if (HLSL_ENABLE_DISTRIBUTION) + set(LLVM_DISTRIBUTION_COMPONENTS + "clang;hlsl-resource-headers;clangd" + CACHE STRING "") +endif() diff --git a/clang/docs/Block-ABI-Apple.rst b/clang/docs/Block-ABI-Apple.rst index 68f7a3819ca22e81d055566478b9b407f68cdef2..f46f2f991ad7f1d085414e7e77058d0b26686b96 100644 --- a/clang/docs/Block-ABI-Apple.rst +++ b/clang/docs/Block-ABI-Apple.rst @@ -80,7 +80,7 @@ The following flags bits are in use thusly for a possible ABI.2010.3.16: In 10.6.ABI the (1<<29) was usually set and was always ignored by the runtime - it had been a transitional marker that did not get deleted after the transition. This bit is now paired with (1<<30), and represented as the pair -(3<<30), for the following combinations of valid bit settings, and their +(3<<29), for the following combinations of valid bit settings, and their meanings: .. code-block:: c diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index 39f7cded36edbff5846925aa56319682a04ed476..6d092219877f91f68d46025cf550e37531f029d5 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -861,7 +861,8 @@ the configuration (without a prefix: ``Auto``). **AlignConsecutiveShortCaseStatements** (``ShortCaseStatementsAlignmentStyle``) :versionbadge:`clang-format 17` :ref:`¶ ` Style of aligning consecutive short case labels. - Only applies if ``AllowShortCaseLabelsOnASingleLine`` is ``true``. + Only applies if ``AllowShortCaseExpressionOnASingleLine`` or + ``AllowShortCaseLabelsOnASingleLine`` is ``true``. .. code-block:: yaml @@ -935,8 +936,26 @@ the configuration (without a prefix: ``Auto``). default: return ""; } - * ``bool AlignCaseColons`` Whether aligned case labels are aligned on the colon, or on the - , or on the tokens after the colon. + * ``bool AlignCaseArrows`` Whether to align the case arrows when aligning short case expressions. + + .. code-block:: java + + true: + i = switch (day) { + case THURSDAY, SATURDAY -> 8; + case WEDNESDAY -> 9; + default -> 0; + }; + + false: + i = switch (day) { + case THURSDAY, SATURDAY -> 8; + case WEDNESDAY -> 9; + default -> 0; + }; + + * ``bool AlignCaseColons`` Whether aligned case labels are aligned on the colon, or on the tokens + after the colon. .. code-block:: c++ @@ -1692,6 +1711,21 @@ the configuration (without a prefix: ``Auto``). +.. _AllowShortCaseExpressionOnASingleLine: + +**AllowShortCaseExpressionOnASingleLine** (``Boolean``) :versionbadge:`clang-format 19` :ref:`¶ ` + Whether to merge a short switch labeled rule into a single line. + + .. code-block:: java + + true: false: + switch (a) { vs. switch (a) { + case 1 -> 1; case 1 -> + default -> 0; 1; + }; default -> + 0; + }; + .. _AllowShortCaseLabelsOnASingleLine: **AllowShortCaseLabelsOnASingleLine** (``Boolean``) :versionbadge:`clang-format 3.6` :ref:`¶ ` diff --git a/clang/docs/ClangLinkerWrapper.rst b/clang/docs/ClangLinkerWrapper.rst index 3bef558475735115fba43d0290bdd9c0d76dbca7..99352863b4773a38d33ce168a297fe1f2f4199b9 100644 --- a/clang/docs/ClangLinkerWrapper.rst +++ b/clang/docs/ClangLinkerWrapper.rst @@ -46,6 +46,8 @@ only for the linker wrapper will be forwarded to the wrapped linker job. -l Search for library --opt-level= Optimization level for LTO + --override-image= + Uses the provided file as if it were the output of the device link step -o Path to file to write output --pass-remarks-analysis= Pass remarks for LTO @@ -87,6 +89,42 @@ other. Generally, this requires that the target triple and architecture match. An exception is made when the architecture is listed as ``generic``, which will cause it be linked with any other device code with the same target triple. +Debugging +========= + +The linker wrapper performs a lot of steps internally, such as input matching, +symbol resolution, and image registration. This makes it difficult to debug in +some scenarios. The behavior of the linker-wrapper is controlled mostly through +metadata, described in `clang documentation +`_. Intermediate output can +be obtained from the linker-wrapper using the ``--save-temps`` flag. These files +can then be modified. + +.. code-block:: sh + + $> clang openmp.c -fopenmp --offload-arch=gfx90a -c + $> clang openmp.o -fopenmp --offload-arch=gfx90a -Wl,--save-temps + $> ; Modify temp files. + $> llvm-objcopy --update-section=.llvm.offloading=out.bc openmp.o + +Doing this will allow you to override one of the input files by replacing its +embedded offloading metadata with a user-modified version. However, this will be +more difficult when there are multiple input files. For a very large hammer, the +``--override-image==`` flag can be used. + +In the following example, we use the ``--save-temps`` to obtain the LLVM-IR just +before running the backend. We then modify it to test altered behavior, and then +compile it to a binary. This can then be passed to the linker-wrapper which will +then ignore all embedded metadata and use the provided image as if it were the +result of the device linking phase. + +.. code-block:: sh + + $> clang openmp.c -fopenmp --offload-arch=gfx90a -Wl,--save-temps + $> ; Modify temp files. + $> clang --target=amdgcn-amd-amdhsa -mcpu=gfx90a -nogpulib out.bc -o a.out + $> clang openmp.c -fopenmp --offload-arch=gfx90a -Wl,--override-image=openmp=a.out + Example ======= diff --git a/clang/docs/ClangOffloadBundler.rst b/clang/docs/ClangOffloadBundler.rst index 515e6c00a3b8003083508e562812317338314206..3c241027d405cae7c32b33eca7b528ab4ad3a994 100644 --- a/clang/docs/ClangOffloadBundler.rst +++ b/clang/docs/ClangOffloadBundler.rst @@ -245,7 +245,7 @@ Where: object as a data section with the name ``.hip_fatbin``. hipv4 Offload code object for the HIP language. Used for AMD GPU - code objects with at least ABI version V4 when the + code objects with at least ABI version V4 and above when the ``clang-offload-bundler`` is used to create a *fat binary* to be loaded by the HIP runtime. The fat binary can be loaded directly from a file, or be embedded in the host code @@ -254,6 +254,14 @@ Where: openmp Offload code object for the OpenMP language extension. ============= ============================================================== +Note: The distinction between the `hip` and `hipv4` offload kinds is historically based. +Originally, these designations might have indicated different versions of the +code object ABI. However, as the system has evolved, the ABI version is now embedded +directly within the code object itself, making these historical distinctions irrelevant +during the unbundling process. Consequently, `hip` and `hipv4` are treated as compatible +in current implementations, facilitating interchangeable handling of code objects +without differentiation based on offload kind. + **target-triple** The target triple of the code object. See `Target Triple `_. @@ -295,7 +303,7 @@ Compatibility Rules for Bundle Entry ID A code object, specified using its Bundle Entry ID, can be loaded and executed on a target processor, if: - * Their offload kinds are the same. + * Their offload kinds are the same or comptible. * Their target triples are compatible. * Their Target IDs are compatible as defined in :ref:`compatibility-target-id`. diff --git a/clang/docs/HLSL/AvailabilityDiagnostics.rst b/clang/docs/HLSL/AvailabilityDiagnostics.rst new file mode 100644 index 0000000000000000000000000000000000000000..bb9d02f21dde626cf999c6f58818301d8f133c1f --- /dev/null +++ b/clang/docs/HLSL/AvailabilityDiagnostics.rst @@ -0,0 +1,137 @@ +============================= +HLSL Availability Diagnostics +============================= + +.. contents:: + :local: + +Introduction +============ + +HLSL availability diagnostics emits errors or warning when unavailable shader APIs are used. Unavailable shader APIs are APIs that are exposed in HLSL code but are not available in the target shader stage or shader model version. + +There are three modes of HLSL availability diagnostic: + +#. **Default mode** - compiler emits an error when an unavailable API is found in a code that is reachable from the shader entry point function or from an exported library function (when compiling a shader library) + +#. **Relaxed mode** - same as default mode except the compiler emits a warning. This mode is enabled by ``-Wno-error=hlsl-availability``. + +#. **Strict mode** - compiler emits an error when an unavailable API is found in parsed code regardless of whether it can be reached from the shader entry point or exported functions, or not. This mode is enabled by ``-fhlsl-strict-availability``. + +Implementation Details +====================== + +Environment Parameter +--------------------- + +In order to encode API availability based on the shader model version and shader model stage a new ``environment`` parameter was added to the existing Clang ``availability`` attribute. + +The values allowed for this parameter are a subset of values allowed as the ``llvm::Triple`` environment component. If the environment parameters is present, the declared availability attribute applies only to targets with the same platform and environment. + +Default and Relaxed Diagnostic Modes +------------------------------------ + +This mode is implemented in ``DiagnoseHLSLAvailability`` class in ``SemaHLSL.cpp`` and it is invoked after the whole translation unit is parsed (from ``Sema::ActOnEndOfTranslationUnit``). The implementation iterates over all shader entry points and exported library functions in the translation unit and performs an AST traversal of each function body. + +When a reference to another function or member method is found (``DeclRefExpr`` or ``MemberExpr``) and it has a body, the AST of the referenced function is also scanned. This chain of AST traversals will reach all of the code that is reachable from the initial shader entry point or exported library function and avoids the need to generate a call graph. + +All shader APIs have an availability attribute that specifies the shader model version (and environment, if applicable) when this API was first introduced.When a reference to a function without a definition is found and it has an availability attribute, the version of the attribute is checked against the target shader model version and shader stage (if shader stage context is known), and an appropriate diagnostic is generated as needed. + +All shader entry functions have ``HLSLShaderAttr`` attribute that specifies what type of shader this function represents. However, for exported library functions the target shader stage is unknown, so in this case the HLSL API availability will be only checked against the shader model version. It means that for exported library functions the diagnostic of APIs with availability specific to shader stage will be deferred until DXIL linking time. + +A list of functions that were already scanned is kept in order to avoid duplicate scans and diagnostics (see ``DiagnoseHLSLAvailability::ScannedDecls``). It might happen that a shader library has multiple shader entry points for different shader stages that all call into the same shared function. It is therefore important to record not just that a function has been scanned, but also in which shader stage context. This is done by using ``llvm::DenseMap`` that maps ``FunctionDecl *`` to a ``unsigned`` bitmap that represents a set of shader stages (or environments) the function has been scanned for. The ``N``'th bit in the set is set if the function has been scanned in shader environment whose ``HLSLShaderAttr::ShaderType`` integer value equals ``N``. + +The emitted diagnostic messages belong to ``hlsl-availability`` diagnostic group and are reported as errors by default. With ``-Wno-error=hlsl-availability`` flag they become warning, making it relaxed HLSL diagnostics mode. + +Strict Diagnostic Mode +---------------------- + +When strict HLSL availability diagnostic mode is enabled the compiler must report all HLSL API availability issues regardless of code reachability. The implementation of this mode takes advantage of an existing diagnostic scan in ``DiagnoseUnguardedAvailability`` class which is already traversing AST of each function as soon as the function body has been parsed. For HLSL, this pass was only slightly modified, such as making sure diagnostic messages are in the ``hlsl-availability`` group and that availability checks based on shader stage are not included if the shader stage context is unknown. + +If the compilation target is a shader library, only availability based on shader model version can be diagnosed during this scan. To diagnose availability based on shader stage, the compiler needs to run the AST traversals implementated in ``DiagnoseHLSLAvailability`` at the end of the translation unit as described above. + +As a result, availability based on specific shader stage will only be diagnosed in code that is reachable from a shader entry point or library export function. It also means that function bodies might be scanned multiple time. When that happens, care should be taken not to produce duplicated diagnostics. + +======== +Examples +======== + +**Note** +For the example below, the ``WaveActiveCountBits`` API function became available in shader model 6.0 and ``WaveMultiPrefixSum`` in shader model 6.5. + +The availability of ``ddx`` function depends on a shader stage. It is available for pixel shaders in shader model 2.1 and higher, for compute, mesh and amplification shaders in shader model 6.6 and higher. For any other shader stages it is not available. + +Compute shader example +====================== + +.. code-block:: c++ + + float unusedFunction(float f) { + return ddx(f); + } + + [numthreads(4, 4, 1)] + void main(uint3 threadId : SV_DispatchThreadId) { + float f1 = ddx(threadId.x); + float f2 = WaveActiveCountBits(threadId.y == 1.0); + } + +When compiled as compute shader for shader model version 5.0, Clang will emit the following error by default: + +.. code-block:: console + + <>:7:13: error: 'ddx' is only available in compute shader environment on Shader Model 6.6 or newer + <>:8:13: error: 'WaveActiveCountBits' is only available on Shader Model 6.5 or newer + +With relaxed diagnostic mode this errors will become warnings. + +With strict diagnostic mode, in addition to the 2 errors above Clang will also emit error for the ``ddx`` call in ``unusedFunction``.: + +.. code-block:: console + + <>:2:9: error: 'ddx' is only available in compute shader environment on Shader Model 6.5 or newer + <>:7:13: error: 'ddx' is only available in compute shader environment on Shader Model 6.5 or newer + <>:7:13: error: 'WaveActiveCountBits' is only available on Shader Model 6.5 or newer + +Shader library example +====================== + +.. code-block:: c++ + + float myFunction(float f) { + return ddx(f); + } + + float unusedFunction(float f) { + return WaveMultiPrefixSum(f, 1.0); + } + + [shader("compute")] + [numthreads(4, 4, 1)] + void main(uint3 threadId : SV_DispatchThreadId) { + float f = 3; + float e = myFunction(f); + } + + [shader("pixel")] + void main() { + float f = 3; + float e = myFunction(f); + } + +When compiled as shader library vshader model version 6.4, Clang will emit the following error by default: + +.. code-block:: console + + <>:2:9: error: 'ddx' is only available in compute shader environment on Shader Model 6.5 or newer + +With relaxed diagnostic mode this errors will become warnings. + +With strict diagnostic mode Clang will also emit errors for availability issues in code that is not used by any of the entry points: + +.. code-block:: console + + <>2:9: error: 'ddx' is only available in compute shader environment on Shader Model 6.6 or newer + <>:6:9: error: 'WaveActiveCountBits' is only available on Shader Model 6.5 or newer + +Note that ``myFunction`` is reachable from both pixel and compute shader entry points is therefore scanned twice - once for each context. The diagnostic is emitted only for the compute shader context. diff --git a/clang/docs/HLSL/HLSLDocs.rst b/clang/docs/HLSL/HLSLDocs.rst index 97b2425f013b3453cc06b2f61a5846414033880c..1e50a66d984b53b1d39845c2c6a3a7b5b37d6a09 100644 --- a/clang/docs/HLSL/HLSLDocs.rst +++ b/clang/docs/HLSL/HLSLDocs.rst @@ -16,3 +16,4 @@ HLSL Design and Implementation ResourceTypes EntryFunctions FunctionCalls + AvailabilityDiagnostics diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index c2e90f4e7d587ada3c26a321def23227b56ed95f..a09c409f8f91a3da3b3a47ba15b846fd8103a5a6 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -656,6 +656,7 @@ Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±in T __builtin_elementwise_ceil(T x) return the smallest integral value greater than or equal to x floating point types T __builtin_elementwise_sin(T x) return the sine of x interpreted as an angle in radians floating point types T __builtin_elementwise_cos(T x) return the cosine of x interpreted as an angle in radians floating point types + T __builtin_elementwise_tan(T x) return the tangent of x interpreted as an angle in radians floating point types T __builtin_elementwise_floor(T x) return the largest integral value less than or equal to x floating point types T __builtin_elementwise_log(T x) return the natural logarithm of x floating point types T __builtin_elementwise_log2(T x) return the base 2 logarithm of x floating point types @@ -1661,8 +1662,11 @@ The following type trait primitives are supported by Clang. Those traits marked ``T`` from ``U`` is ill-formed. Deprecated, use ``__reference_constructs_from_temporary``. * ``__reference_constructs_from_temporary(T, U)`` (C++) - Returns true if a reference ``T`` can be constructed from a temporary of type + Returns true if a reference ``T`` can be direct-initialized from a temporary of type a non-cv-qualified ``U``. +* ``__reference_converts_from_temporary(T, U)`` (C++) + Returns true if a reference ``T`` can be copy-initialized from a temporary of type + a non-cv-qualified ``U``. * ``__underlying_type`` (C++, GNU, Microsoft) In addition, the following expression traits are supported: diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index bb1b68f6671b1a7a3058968ce28671dc58c9eeaa..a16b9c44ef0eab493d07b6a148ee20519430da03 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -3546,33 +3546,35 @@ cxxMethodDecl(isConst()) matches A::foo() but not A::bar() -Matcher<CXXMethodDecl>isExplicitObjectMemberFunction -
Matches if the given method declaration declares a member function with an explicit object parameter.
+Matcher<CXXMethodDecl>isCopyAssignmentOperator
+
Matches if the given method declaration declares a copy assignment
+operator.
 
 Given
 struct A {
-  int operator-(this A, int);
-  void fun(this A &&self);
-  static int operator()(int);
-  int operator+(int);
+  A &operator=(const A &);
+  A &operator=(A &&);
 };
 
-cxxMethodDecl(isExplicitObjectMemberFunction()) matches the first two methods but not the last two.
+cxxMethodDecl(isCopyAssignmentOperator()) matches the first method but not
+the second one.
 
-Matcher<CXXMethodDecl>isCopyAssignmentOperator -
Matches if the given method declaration declares a copy assignment
-operator.
+Matcher<CXXMethodDecl>isExplicitObjectMemberFunction
+
Matches if the given method declaration declares a member function with an
+explicit object parameter.
 
 Given
 struct A {
-  A &operator=(const A &);
-  A &operator=(A &&);
+ int operator-(this A, int);
+ void fun(this A &&self);
+ static int operator()(int);
+ int operator+(int);
 };
 
-cxxMethodDecl(isCopyAssignmentOperator()) matches the first method but not
-the second one.
+cxxMethodDecl(isExplicitObjectMemberFunction()) matches the first two
+methods but not the last two.
 
@@ -6713,7 +6715,7 @@ Usable as: Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>, Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>, Matcher<CXXUnresolvedConstructExpr>, - Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>, + Matcher<CompoundLiteralExpr>, Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>, Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>, Matcher<TypedefNameDecl> @@ -6757,7 +6759,7 @@ Usable as: Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>, Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>, Matcher<CXXUnresolvedConstructExpr>, - Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>, + Matcher<CompoundLiteralExpr>, Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>, Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>, Matcher<TypedefNameDecl> @@ -6985,7 +6987,7 @@ Usable as: Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>, Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>, Matcher<CXXUnresolvedConstructExpr>, - Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>, + Matcher<CompoundLiteralExpr>, Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>, Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>, Matcher<TypedefNameDecl> @@ -7219,7 +7221,7 @@ Usable as: Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>, Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>, Matcher<CXXUnresolvedConstructExpr>, - Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>, + Matcher<CompoundLiteralExpr>, Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>, Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>, Matcher<TypedefNameDecl> @@ -7416,7 +7418,7 @@ Usable as: Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>, Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>, Matcher<CXXUnresolvedConstructExpr>, - Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>, + Matcher<CompoundLiteralExpr>, Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>, Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>, Matcher<TypedefNameDecl> @@ -7620,7 +7622,7 @@ Usable as: Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>, Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>, Matcher<CXXUnresolvedConstructExpr>, - Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>, + Matcher<CompoundLiteralExpr>, Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>, Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>, Matcher<TypedefNameDecl> @@ -7677,7 +7679,7 @@ Usable as: Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>, Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>, Matcher<CXXUnresolvedConstructExpr>, - Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>, + Matcher<CompoundLiteralExpr>, Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>, Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>, Matcher<TypedefNameDecl> @@ -7875,9 +7877,10 @@ int a = b ?: 1; Matcher<ClassTemplateSpecializationDecl>forEachTemplateArgumentMatcher<TemplateArgument> InnerMatcher -
Matches classTemplateSpecialization, templateSpecializationType and
-functionDecl nodes where the template argument matches the inner matcher.
-This matcher may produce multiple matches.
+
Matches templateSpecializationType, class template specialization,
+variable template specialization, and function template specialization
+nodes where the template argument matches the inner matcher. This matcher
+may produce multiple matches.
 
 Given
   template <typename T, unsigned N, unsigned M>
@@ -7899,10 +7902,25 @@ functionDecl(forEachTemplateArgument(refersToType(builtinType())))
 
+Matcher<ClassTemplateSpecializationDecl>hasAnyTemplateArgumentLocMatcher<TemplateArgumentLoc> InnerMatcher +
Matches template specialization `TypeLoc`s, class template specializations,
+variable template specializations, and function template specializations
+that have at least one `TemplateArgumentLoc` matching the given
+`InnerMatcher`.
+
+Given
+  template<typename T> class A {};
+  A<int> a;
+varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
+  hasTypeLoc(loc(asString("int")))))))
+  matches `A<int> a`.
+
+ + Matcher<ClassTemplateSpecializationDecl>hasAnyTemplateArgumentMatcher<TemplateArgument> InnerMatcher -
Matches classTemplateSpecializations, templateSpecializationType and
-functionDecl that have at least one TemplateArgument matching the given
-InnerMatcher.
+
Matches templateSpecializationTypes, class template specializations,
+variable template specializations, and function template specializations
+that have at least one TemplateArgument matching the given InnerMatcher.
 
 Given
   template<typename T> class A {};
@@ -7933,9 +7951,25 @@ classTemplateSpecializationDecl(hasSpecializedTemplate(classTemplateDecl()))
 
+Matcher<ClassTemplateSpecializationDecl>hasTemplateArgumentLocunsigned Index, Matcher<TemplateArgumentLoc> InnerMatcher +
Matches template specialization `TypeLoc`s, class template specializations,
+variable template specializations, and function template specializations
+where the n'th `TemplateArgumentLoc` matches the given `InnerMatcher`.
+
+Given
+  template<typename T, typename U> class A {};
+  A<double, int> b;
+  A<int, double> c;
+varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0,
+  hasTypeLoc(loc(asString("double")))))))
+  matches `A<double, int> b`, but not `A<int, double> c`.
+
+ + Matcher<ClassTemplateSpecializationDecl>hasTemplateArgumentunsigned N, Matcher<TemplateArgument> InnerMatcher -
Matches classTemplateSpecializations, templateSpecializationType and
-functionDecl where the n'th TemplateArgument matches the given InnerMatcher.
+
Matches templateSpecializationType, class template specializations,
+variable template specializations, and function template specializations
+where the n'th TemplateArgument matches the given InnerMatcher.
 
 Given
   template<typename T, typename U> class A {};
@@ -7953,34 +7987,6 @@ functionDecl(hasTemplateArgument(0, refersToType(asString("int"))))
 
-Matcher<ClassTemplateSpecializationDecl>hasTypeLocMatcher<TypeLoc> Inner -
Matches if the type location of a node matches the inner matcher.
-
-Examples:
-  int x;
-declaratorDecl(hasTypeLoc(loc(asString("int"))))
-  matches int x
-
-auto x = int(3);
-cxxTemporaryObjectExpr(hasTypeLoc(loc(asString("int"))))
-  matches int(3)
-
-struct Foo { Foo(int, int); };
-auto x = Foo(1, 2);
-cxxFunctionalCastExpr(hasTypeLoc(loc(asString("struct Foo"))))
-  matches Foo(1, 2)
-
-Usable as: Matcher<BlockDecl>, Matcher<CXXBaseSpecifier>,
-  Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
-  Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>,
-  Matcher<CXXUnresolvedConstructExpr>,
-  Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>,
-  Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>,
-  Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
-  Matcher<TypedefNameDecl>
-
- - Matcher<ComplexType>hasElementTypeMatcher<Type>
Matches arrays and C99 complex types that have a specific element
 type.
@@ -7996,8 +8002,8 @@ Usable as: Matcher<CompoundLiteralExpr>hasTypeLocMatcher<TypeLoc> Inner
-
Matches if the type location of a node matches the inner matcher.
+Matcher<CompoundLiteralExpr>hasTypeLocMatcher<TypeLoc> Inner
+
Matches if the type location of a node matches the inner matcher.
 
 Examples:
   int x;
@@ -8017,7 +8023,7 @@ Usable as: Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
   Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>,
   Matcher<CXXUnresolvedConstructExpr>,
-  Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>,
+  Matcher<CompoundLiteralExpr>,
   Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>,
   Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
   Matcher<TypedefNameDecl>
@@ -8066,6 +8072,21 @@ with compoundStmt()
 
+Matcher<DeclRefExpr>hasAnyTemplateArgumentLocMatcher<TemplateArgumentLoc> InnerMatcher +
Matches template specialization `TypeLoc`s, class template specializations,
+variable template specializations, and function template specializations
+that have at least one `TemplateArgumentLoc` matching the given
+`InnerMatcher`.
+
+Given
+  template<typename T> class A {};
+  A<int> a;
+varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
+  hasTypeLoc(loc(asString("int")))))))
+  matches `A<int> a`.
+
+ + Matcher<DeclRefExpr>hasDeclarationMatcher<Decl> InnerMatcher
Matches a node if the declaration associated with that node
 matches the given matcher.
@@ -8100,9 +8121,10 @@ Usable as: Matcher<DeclRefExpr>hasTemplateArgumentLocunsigned Index, Matcher<TemplateArgumentLoc> InnerMatcher
-
Matches template specialization `TypeLoc`s where the n'th
-`TemplateArgumentLoc` matches the given `InnerMatcher`.
+Matcher<DeclRefExpr>hasTemplateArgumentLocunsigned Index, Matcher<TemplateArgumentLoc> InnerMatcher
+
Matches template specialization `TypeLoc`s, class template specializations,
+variable template specializations, and function template specializations
+where the n'th `TemplateArgumentLoc` matches the given `InnerMatcher`.
 
 Given
   template<typename T, typename U> class A {};
@@ -8176,8 +8198,8 @@ declStmt(hasSingleDecl(anything()))
 
-Matcher<DeclaratorDecl>hasTypeLocMatcher<TypeLoc> Inner -
Matches if the type location of a node matches the inner matcher.
+Matcher<DeclaratorDecl>hasTypeLocMatcher<TypeLoc> Inner
+
Matches if the type location of a node matches the inner matcher.
 
 Examples:
   int x;
@@ -8197,7 +8219,7 @@ Usable as: Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
   Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>,
   Matcher<CXXUnresolvedConstructExpr>,
-  Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>,
+  Matcher<CompoundLiteralExpr>,
   Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>,
   Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
   Matcher<TypedefNameDecl>
@@ -8393,8 +8415,8 @@ actual casts "explicit" casts.)
 
-Matcher<ExplicitCastExpr>hasTypeLocMatcher<TypeLoc> Inner -
Matches if the type location of a node matches the inner matcher.
+Matcher<ExplicitCastExpr>hasTypeLocMatcher<TypeLoc> Inner
+
Matches if the type location of a node matches the inner matcher.
 
 Examples:
   int x;
@@ -8414,7 +8436,7 @@ Usable as: Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
   Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>,
   Matcher<CXXUnresolvedConstructExpr>,
-  Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>,
+  Matcher<CompoundLiteralExpr>,
   Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>,
   Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
   Matcher<TypedefNameDecl>
@@ -8707,9 +8729,10 @@ Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
 
 
 Matcher<FunctionDecl>forEachTemplateArgumentMatcher<TemplateArgument> InnerMatcher
-
Matches classTemplateSpecialization, templateSpecializationType and
-functionDecl nodes where the template argument matches the inner matcher.
-This matcher may produce multiple matches.
+
Matches templateSpecializationType, class template specialization,
+variable template specialization, and function template specialization
+nodes where the template argument matches the inner matcher. This matcher
+may produce multiple matches.
 
 Given
   template <typename T, unsigned N, unsigned M>
@@ -8778,10 +8801,25 @@ matching y.
 
+Matcher<FunctionDecl>hasAnyTemplateArgumentLocMatcher<TemplateArgumentLoc> InnerMatcher +
Matches template specialization `TypeLoc`s, class template specializations,
+variable template specializations, and function template specializations
+that have at least one `TemplateArgumentLoc` matching the given
+`InnerMatcher`.
+
+Given
+  template<typename T> class A {};
+  A<int> a;
+varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
+  hasTypeLoc(loc(asString("int")))))))
+  matches `A<int> a`.
+
+ + Matcher<FunctionDecl>hasAnyTemplateArgumentMatcher<TemplateArgument> InnerMatcher -
Matches classTemplateSpecializations, templateSpecializationType and
-functionDecl that have at least one TemplateArgument matching the given
-InnerMatcher.
+
Matches templateSpecializationTypes, class template specializations,
+variable template specializations, and function template specializations
+that have at least one TemplateArgument matching the given InnerMatcher.
 
 Given
   template<typename T> class A {};
@@ -8878,9 +8916,25 @@ functionDecl(hasReturnTypeLoc(loc(asString("int"))))
 
+Matcher<FunctionDecl>hasTemplateArgumentLocunsigned Index, Matcher<TemplateArgumentLoc> InnerMatcher +
Matches template specialization `TypeLoc`s, class template specializations,
+variable template specializations, and function template specializations
+where the n'th `TemplateArgumentLoc` matches the given `InnerMatcher`.
+
+Given
+  template<typename T, typename U> class A {};
+  A<double, int> b;
+  A<int, double> c;
+varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0,
+  hasTypeLoc(loc(asString("double")))))))
+  matches `A<double, int> b`, but not `A<int, double> c`.
+
+ + Matcher<FunctionDecl>hasTemplateArgumentunsigned N, Matcher<TemplateArgument> InnerMatcher -
Matches classTemplateSpecializations, templateSpecializationType and
-functionDecl where the n'th TemplateArgument matches the given InnerMatcher.
+
Matches templateSpecializationType, class template specializations,
+variable template specializations, and function template specializations
+where the n'th TemplateArgument matches the given InnerMatcher.
 
 Given
   template<typename T, typename U> class A {};
@@ -9473,8 +9527,8 @@ matching y.
 
-Matcher<ObjCPropertyDecl>hasTypeLocMatcher<TypeLoc> Inner -
Matches if the type location of a node matches the inner matcher.
+Matcher<ObjCPropertyDecl>hasTypeLocMatcher<TypeLoc> Inner
+
Matches if the type location of a node matches the inner matcher.
 
 Examples:
   int x;
@@ -9494,7 +9548,7 @@ Usable as: Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
   Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>,
   Matcher<CXXUnresolvedConstructExpr>,
-  Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>,
+  Matcher<CompoundLiteralExpr>,
   Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>,
   Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
   Matcher<TypedefNameDecl>
@@ -9919,8 +9973,8 @@ Usable as: Matcher<TemplateArgumentLoc>hasTypeLocMatcher<TypeLoc> Inner
-
Matches if the type location of a node matches the inner matcher.
+Matcher<TemplateArgumentLoc>hasTypeLocMatcher<TypeLoc> Inner
+
Matches if the type location of a node matches the inner matcher.
 
 Examples:
   int x;
@@ -9940,7 +9994,7 @@ Usable as: Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
   Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>,
   Matcher<CXXUnresolvedConstructExpr>,
-  Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>,
+  Matcher<CompoundLiteralExpr>,
   Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>,
   Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
   Matcher<TypedefNameDecl>
@@ -10014,9 +10068,11 @@ matches the specialization of struct A generated by A<X>.
 
-Matcher<TemplateSpecializationTypeLoc>hasAnyTemplateArgumentLocMatcher<TemplateArgumentLoc> InnerMatcher -
Matches template specialization `TypeLoc`s that have at least one
-`TemplateArgumentLoc` matching the given `InnerMatcher`.
+Matcher<TemplateSpecializationTypeLoc>hasAnyTemplateArgumentLocMatcher<TemplateArgumentLoc> InnerMatcher
+
Matches template specialization `TypeLoc`s, class template specializations,
+variable template specializations, and function template specializations
+that have at least one `TemplateArgumentLoc` matching the given
+`InnerMatcher`.
 
 Given
   template<typename T> class A {};
@@ -10027,9 +10083,10 @@ varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
 
-Matcher<TemplateSpecializationTypeLoc>hasTemplateArgumentLocunsigned Index, Matcher<TemplateArgumentLoc> InnerMatcher -
Matches template specialization `TypeLoc`s where the n'th
-`TemplateArgumentLoc` matches the given `InnerMatcher`.
+Matcher<TemplateSpecializationTypeLoc>hasTemplateArgumentLocunsigned Index, Matcher<TemplateArgumentLoc> InnerMatcher
+
Matches template specialization `TypeLoc`s, class template specializations,
+variable template specializations, and function template specializations
+where the n'th `TemplateArgumentLoc` matches the given `InnerMatcher`.
 
 Given
   template<typename T, typename U> class A {};
@@ -10041,10 +10098,11 @@ varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0,
 
-Matcher<TemplateSpecializationType>forEachTemplateArgumentMatcher<TemplateArgument> InnerMatcher -
Matches classTemplateSpecialization, templateSpecializationType and
-functionDecl nodes where the template argument matches the inner matcher.
-This matcher may produce multiple matches.
+Matcher<TemplateSpecializationType>forEachTemplateArgumentMatcher<TemplateArgument> InnerMatcher
+
Matches templateSpecializationType, class template specialization,
+variable template specialization, and function template specialization
+nodes where the template argument matches the inner matcher. This matcher
+may produce multiple matches.
 
 Given
   template <typename T, unsigned N, unsigned M>
@@ -10066,10 +10124,10 @@ functionDecl(forEachTemplateArgument(refersToType(builtinType())))
 
-Matcher<TemplateSpecializationType>hasAnyTemplateArgumentMatcher<TemplateArgument> InnerMatcher -
Matches classTemplateSpecializations, templateSpecializationType and
-functionDecl that have at least one TemplateArgument matching the given
-InnerMatcher.
+Matcher<TemplateSpecializationType>hasAnyTemplateArgumentMatcher<TemplateArgument> InnerMatcher
+
Matches templateSpecializationTypes, class template specializations,
+variable template specializations, and function template specializations
+that have at least one TemplateArgument matching the given InnerMatcher.
 
 Given
   template<typename T> class A {};
@@ -10122,9 +10180,10 @@ Usable as: Matcher<TemplateSpecializationType>hasTemplateArgumentunsigned N, Matcher<TemplateArgument> InnerMatcher
-
Matches classTemplateSpecializations, templateSpecializationType and
-functionDecl where the n'th TemplateArgument matches the given InnerMatcher.
+Matcher<TemplateSpecializationType>hasTemplateArgumentunsigned N, Matcher<TemplateArgument> InnerMatcher
+
Matches templateSpecializationType, class template specializations,
+variable template specializations, and function template specializations
+where the n'th TemplateArgument matches the given InnerMatcher.
 
 Given
   template<typename T, typename U> class A {};
@@ -10182,8 +10241,8 @@ QualType-matcher matches.
 
-Matcher<TypedefNameDecl>hasTypeLocMatcher<TypeLoc> Inner -
Matches if the type location of a node matches the inner matcher.
+Matcher<TypedefNameDecl>hasTypeLocMatcher<TypeLoc> Inner
+
Matches if the type location of a node matches the inner matcher.
 
 Examples:
   int x;
@@ -10203,7 +10262,7 @@ Usable as: Matcher<CXXCtorInitializer>, Matcher<CXXFunctionalCastExpr>,
   Matcher<CXXNewExpr>, Matcher<CXXTemporaryObjectExpr>,
   Matcher<CXXUnresolvedConstructExpr>,
-  Matcher<ClassTemplateSpecializationDecl>, Matcher<CompoundLiteralExpr>,
+  Matcher<CompoundLiteralExpr>,
   Matcher<DeclaratorDecl>, Matcher<ExplicitCastExpr>,
   Matcher<ObjCPropertyDecl>, Matcher<TemplateArgumentLoc>,
   Matcher<TypedefNameDecl>
@@ -10449,6 +10508,105 @@ Example matches x (matcher = varDecl(hasInitializer(callExpr())))
 
+Matcher<VarTemplateSpecializationDecl>forEachTemplateArgumentMatcher<TemplateArgument> InnerMatcher +
Matches templateSpecializationType, class template specialization,
+variable template specialization, and function template specialization
+nodes where the template argument matches the inner matcher. This matcher
+may produce multiple matches.
+
+Given
+  template <typename T, unsigned N, unsigned M>
+  struct Matrix {};
+
+  constexpr unsigned R = 2;
+  Matrix<int, R * 2, R * 4> M;
+
+  template <typename T, typename U>
+  void f(T&& t, U&& u) {}
+
+  bool B = false;
+  f(R, B);
+templateSpecializationType(forEachTemplateArgument(isExpr(expr())))
+  matches twice, with expr() matching 'R * 2' and 'R * 4'
+functionDecl(forEachTemplateArgument(refersToType(builtinType())))
+  matches the specialization f<unsigned, bool> twice, for 'unsigned'
+  and 'bool'
+
+ + +Matcher<VarTemplateSpecializationDecl>hasAnyTemplateArgumentLocMatcher<TemplateArgumentLoc> InnerMatcher +
Matches template specialization `TypeLoc`s, class template specializations,
+variable template specializations, and function template specializations
+that have at least one `TemplateArgumentLoc` matching the given
+`InnerMatcher`.
+
+Given
+  template<typename T> class A {};
+  A<int> a;
+varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
+  hasTypeLoc(loc(asString("int")))))))
+  matches `A<int> a`.
+
+ + +Matcher<VarTemplateSpecializationDecl>hasAnyTemplateArgumentMatcher<TemplateArgument> InnerMatcher +
Matches templateSpecializationTypes, class template specializations,
+variable template specializations, and function template specializations
+that have at least one TemplateArgument matching the given InnerMatcher.
+
+Given
+  template<typename T> class A {};
+  template<> class A<double> {};
+  A<int> a;
+
+  template<typename T> f() {};
+  void func() { f<int>(); };
+
+classTemplateSpecializationDecl(hasAnyTemplateArgument(
+    refersToType(asString("int"))))
+  matches the specialization A<int>
+
+functionDecl(hasAnyTemplateArgument(refersToType(asString("int"))))
+  matches the specialization f<int>
+
+ + +Matcher<VarTemplateSpecializationDecl>hasTemplateArgumentLocunsigned Index, Matcher<TemplateArgumentLoc> InnerMatcher +
Matches template specialization `TypeLoc`s, class template specializations,
+variable template specializations, and function template specializations
+where the n'th `TemplateArgumentLoc` matches the given `InnerMatcher`.
+
+Given
+  template<typename T, typename U> class A {};
+  A<double, int> b;
+  A<int, double> c;
+varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasTemplateArgumentLoc(0,
+  hasTypeLoc(loc(asString("double")))))))
+  matches `A<double, int> b`, but not `A<int, double> c`.
+
+ + +Matcher<VarTemplateSpecializationDecl>hasTemplateArgumentunsigned N, Matcher<TemplateArgument> InnerMatcher +
Matches templateSpecializationType, class template specializations,
+variable template specializations, and function template specializations
+where the n'th TemplateArgument matches the given InnerMatcher.
+
+Given
+  template<typename T, typename U> class A {};
+  A<bool, int> b;
+  A<int, bool> c;
+
+  template<typename T> void f() {}
+  void func() { f<int>(); };
+classTemplateSpecializationDecl(hasTemplateArgument(
+    1, refersToType(asString("int"))))
+  matches the specialization A<bool, int>
+
+functionDecl(hasTemplateArgument(0, refersToType(asString("int"))))
+  matches the specialization f<int>
+
+ + Matcher<VariableArrayType>hasSizeExprMatcher<Expr> InnerMatcher
Matches VariableArrayType nodes that have a specific size
 expression.
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0e3f7cf89ca88517c78e4d0cb32b3198d3d7d9e8..81e9d0423f96aecced463f43e5ffadb4efde3288 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -48,6 +48,17 @@ C++ Specific Potentially Breaking Changes
 - Clang now diagnoses function/variable templates that shadow their own template parameters, e.g. ``template void T();``.
   This error can be disabled via `-Wno-strict-primary-template-shadow` for compatibility with previous versions of clang.
 
+- The behavior controlled by the `-frelaxed-template-template-args` flag is now
+  on by default, and the flag is deprecated. Until the flag is finally removed,
+  it's negative spelling can be used to obtain compatibility with previous
+  versions of clang. The deprecation warning for the negative spelling can be
+  disabled with `-Wno-deprecated-no-relaxed-template-template-args`.
+
+- Clang now rejects pointer to member from parenthesized expression in unevaluated context such as ``decltype(&(foo::bar))``. (#GH40906).
+
+- Clang now performs semantic analysis for unary operators with dependent operands
+  that are known to be of non-class non-enumeration type prior to instantiation.
+
 ABI Changes in This Version
 ---------------------------
 - Fixed Microsoft name mangling of implicitly defined variables used for thread
@@ -69,6 +80,9 @@ ABI Changes in This Version
   returning a class in a register. This affects some uses of std::pair.
   (#GH86384).
 
+- Fixed Microsoft calling convention when returning classes that have a deleted
+  copy assignment operator. Such a class should be returned indirectly.
+
 AST Dumping Potentially Breaking Changes
 ----------------------------------------
 
@@ -85,6 +99,28 @@ Clang Frontend Potentially Breaking Changes
   of ``-Wno-gnu-binary-literal`` will no longer silence this pedantic warning,
   which may break existing uses with ``-Werror``.
 
+- The normalization of 3 element target triples where ``-none-`` is the middle
+  element has changed. For example, ``armv7m-none-eabi`` previously normalized
+  to ``armv7m-none-unknown-eabi``, with ``none`` for the vendor and ``unknown``
+  for the operating system. It now normalizes to ``armv7m-unknown-none-eabi``,
+  which has ``unknown`` vendor and ``none`` operating system.
+
+  The affected triples are primarily for bare metal Arm where it is intended
+  that ``none`` means that there is no operating system. As opposed to an unknown
+  type of operating system.
+
+  This change my cause clang to not find libraries, or libraries to be built at
+  different file system locations. This can be fixed by changing your builds to
+  use the new normalized triple. However, we recommend instead getting the
+  normalized triple from clang itself, as this will make your builds more
+  robust in case of future changes::
+
+    $ clang --target= -print-target-triple
+    
+
+- The ``hasTypeLoc`` AST matcher will no longer match a ``classTemplateSpecializationDecl``;
+  existing uses should switch to ``templateArgumentLoc`` or ``hasAnyTemplateArgumentLoc`` instead.
+
 What's New in Clang |release|?
 ==============================
 Some of the major new features and improvements to Clang are listed
@@ -94,6 +130,17 @@ sections with improvements to Clang's support for those languages.
 
 C++ Language Changes
 --------------------
+- C++17 support is now completed, with the enablement of the
+  relaxed temlate template argument matching rules introduced in P0522,
+  which was retroactively applied as a defect report.
+  While the implementation already existed since Clang 4, it was turned off by
+  default, and was controlled with the `-frelaxed-template-template-args` flag.
+  In this release, we implement provisional wording for a core defect on
+  P0522 (CWG2398), which avoids the most serious compatibility issues caused
+  by it, allowing us to enable it by default in this release.
+  The flag is now deprecated, and will be removed in the next release, but can
+  still be used to turn it off and regain compatibility with previous versions
+  (#GH36505).
 - Implemented ``_BitInt`` literal suffixes ``__wb`` or ``__WB`` as a Clang extension with ``unsigned`` modifiers also allowed. (#GH85223).
 
 C++17 Feature Support
@@ -142,6 +189,9 @@ C++23 Feature Support
 
 - Implemented `P2448R2: Relaxing some constexpr restrictions `_.
 
+- Added a ``__reference_converts_from_temporary`` builtin, completing the necessary compiler support for
+  `P2255R2: Type trait to determine if a reference binds to a temporary `_.
+
 C++2c Feature Support
 ^^^^^^^^^^^^^^^^^^^^^
 
@@ -153,6 +203,9 @@ C++2c Feature Support
 
 - Implemented `P2748R5 Disallow Binding a Returned Glvalue to a Temporary `_.
 
+- Implemented `P2809R3: Trivial infinite loops are not Undefined Behavior `_.
+
+
 Resolutions to C++ Defect Reports
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 - Substitute template parameter pack, when it is not explicitly specified
@@ -173,6 +226,12 @@ Resolutions to C++ Defect Reports
 - Clang now diagnoses declarative nested-name-specifiers with pack-index-specifiers.
   (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers `_).
 
+- Clang now allows attributes on concepts.
+  (`CWG2428: Deprecating a concept `_).
+
+- P0522 implementation is enabled by default in all language versions, and
+  provisional wording for CWG2398 is implemented.
+
 C Language Changes
 ------------------
 
@@ -260,6 +319,11 @@ New Compiler Flags
   allow late parsing certain attributes in specific contexts where they would
   not normally be late parsed.
 
+- ``-fseparate-named-sections`` uses separate unique sections for global
+  symbols in named special sections (i.e. symbols annotated with
+  ``__attribute__((section(...)))``. This enables linker GC to collect unused
+  symbols without having to use a per-symbol section.
+
 Deprecated Compiler Flags
 -------------------------
 
@@ -294,6 +358,10 @@ Modified Compiler Flags
 - Carved out ``-Wformat`` warning about scoped enums into a subwarning and
   make it controlled by ``-Wformat-pedantic``. Fixes #GH88595.
 
+- Trivial infinite loops (i.e loops with a constant controlling expresion
+  evaluating to ``true`` and an empty body such as ``while(1);``)
+  are considered infinite, even when the ``-ffinite-loop`` flag is set.
+
 Removed Compiler Flags
 -------------------------
 
@@ -335,6 +403,10 @@ Attribute Changes in Clang
 - Clang now warns that the ``exclude_from_explicit_instantiation`` attribute
   is ignored when applied to a local class or a member thereof.
 
+- The ``clspv_libclc_builtin`` attribute has been added to allow clspv
+  (`OpenCL-C to Vulkan SPIR-V compiler `_) to identify functions coming from libclc
+  (`OpenCL-C builtin library `_).
+
 Improvements to Clang's diagnostics
 -----------------------------------
 - Clang now applies syntax highlighting to the code snippets it
@@ -426,9 +498,15 @@ Improvements to Clang's diagnostics
        }
      };
 
+- Clang emits a ``-Wparentheses`` warning for expressions with consecutive comparisons like ``x < y < z``.
+  Fixes #GH20456.
+
 Improvements to Clang's time-trace
 ----------------------------------
 
+- Clang now specifies that using ``auto`` in a lambda parameter is a C++14 extension when
+  appropriate. (`#46059: `_).
+
 Bug Fixes in This Version
 -------------------------
 - Clang's ``-Wundefined-func-template`` no longer warns on pure virtual
@@ -502,6 +580,15 @@ Bug Fixes in This Version
   The values of 0 and 1 block any unrolling of the loop. This keeps the same behavior with GCC.
   Fixes (`#88624 `_).
 
+- Clang will no longer emit a duplicate -Wunused-value warning for an expression
+  `(A, B)` which evaluates to glvalue `B` that can be converted to non ODR-use. (#GH45783)
+
+- Clang now correctly disallows VLA type compound literals, e.g. ``(int[size]){}``,
+  as the C standard mandates. (#GH89835)
+
+- ``__is_array`` and ``__is_bounded_array`` no longer return ``true`` for
+  zero-sized arrays. Fixes (#GH54705).
+
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
@@ -630,11 +717,44 @@ Bug Fixes to C++ Support
 - Fix a bug on template partial specialization with issue on deduction of nontype template parameter
   whose type is `decltype(auto)`. Fixes (#GH68885).
 - Clang now correctly treats the noexcept-specifier of a friend function to be a complete-class context.
+- Fix an assertion failure when parsing an invalid members of an anonymous class. (#GH85447)
+- Fixed a misuse of ``UnresolvedLookupExpr`` for ill-formed templated expressions. Fixes (#GH48673), (#GH63243)
+  and (#GH88832).
+- Clang now defers all substitution into the exception specification of a function template specialization
+  until the noexcept-specifier is instantiated.
+- Fix a crash when an implicitly declared ``operator==`` function with a trailing requires-clause has its
+  constraints compared to that of another declaration.
+- Fix a bug where explicit specializations of member functions/function templates would have substitution
+  performed incorrectly when checking constraints. Fixes (#GH90349).
+- Clang now allows constrained member functions to be explicitly specialized for an implicit instantiation
+  of a class template.
+- Fix a C++23 bug in implementation of P2564R3 which evaluates immediate invocations in place
+  within initializers for variables that are usable in constant expressions or are constant
+  initialized, rather than evaluating them as a part of the larger manifestly constant evaluated
+  expression.
+- Fix a bug in access control checking due to dealyed checking of friend declaration. Fixes (#GH12361).
+- Correctly treat the compound statement of an ``if consteval`` as an immediate context. Fixes (#GH91509).
+- When partial ordering alias templates against template template parameters,
+  allow pack expansions when the alias has a fixed-size parameter list. Fixes (#GH62529).
+- Clang now ignores template parameters only used within the exception specification of candidate function
+  templates during partial ordering when deducing template arguments from a function declaration or when
+  taking the address of a function template.
+- Fix a bug with checking constrained non-type template parameters for equivalence. Fixes (#GH77377).
+- Fix a bug where the last argument was not considered when considering the most viable function for
+  explicit object argument member functions. Fixes (#GH92188).
+- Fix a C++11 crash when a non-const non-static member function is defined out-of-line with
+  the ``constexpr`` specifier. Fixes (#GH61004).
+- Clang no longer transforms dependent qualified names into implicit class member access expressions
+  until it can be determined whether the name is that of a non-static member.
+- Clang now correctly diagnoses when the current instantiation is used as an incomplete base class.
+- Clang no longer treats ``constexpr`` class scope function template specializations of non-static members
+  as implicitly ``const`` in language modes after C++11.
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 - Clang now properly preserves ``FoundDecls`` within a ``ConceptReference``. (#GH82628)
 - The presence of the ``typename`` keyword is now stored in ``TemplateTemplateParmDecl``.
+- Fixed malformed AST generated for anonymous union access in templates. (#GH90842)
 
 Miscellaneous Bug Fixes
 ^^^^^^^^^^^^^^^^^^^^^^^
@@ -729,6 +849,7 @@ CUDA/HIP Language Changes
 
 CUDA Support
 ^^^^^^^^^^^^
+- Clang now supports CUDA SDK up to 12.4
 
 AIX Support
 ^^^^^^^^^^^
@@ -781,6 +902,9 @@ clang-format
   ``BreakTemplateDeclarations``.
 - ``AlwaysBreakAfterReturnType`` is deprecated and renamed to
   ``BreakAfterReturnType``.
+- Handles Java ``switch`` expressions.
+- Adds ``AllowShortCaseExpressionOnASingleLine`` option.
+- Adds ``AlignCaseArrows`` suboption to ``AlignConsecutiveShortCaseStatements``.
 
 libclang
 --------
diff --git a/clang/docs/StandardCPlusPlusModules.rst b/clang/docs/StandardCPlusPlusModules.rst
index ee57fb5da6485769213f8485ac0e7a7f9fbd774d..1c3c4d319c0e18970a82c83af65fba33cfd9cd89 100644
--- a/clang/docs/StandardCPlusPlusModules.rst
+++ b/clang/docs/StandardCPlusPlusModules.rst
@@ -8,109 +8,92 @@ Standard C++ Modules
 Introduction
 ============
 
-The term ``modules`` has a lot of meanings. For the users of Clang, modules may
-refer to ``Objective-C Modules``, ``Clang C++ Modules`` (or ``Clang Header Modules``,
-etc.) or ``Standard C++ Modules``. The implementation of all these kinds of modules in Clang
-has a lot of shared code, but from the perspective of users, their semantics and
-command line interfaces are very different. This document focuses on
-an introduction of how to use standard C++ modules in Clang.
-
-There is already a detailed document about `Clang modules `_, it
-should be helpful to read `Clang modules `_ if you want to know
-more about the general idea of modules. Since standard C++ modules have different semantics
-(and work flows) from `Clang modules`, this page describes the background and use of
-Clang with standard C++ modules.
-
-Modules exist in two forms in the C++ Language Specification. They can refer to
-either "Named Modules" or to "Header Units". This document covers both forms.
+The term ``module`` is ambiguous, as it is used to mean multiple things in
+Clang. For Clang users, a module may refer to an ``Objective-C Module``,
+`Clang Module `_ (also called a ``Clang Header Module``) or a
+``C++20 Module`` (or a ``Standard C++ Module``). The implementation of all
+these kinds of modules in Clang shares a lot of code, but from the perspective
+of users their semantics and command line interfaces are very different. This
+document is an introduction to the use of C++20 modules in Clang. In the
+remainder of this document, the term ``module`` will refer to Standard C++20
+modules and the term ``Clang module`` will refer to the Clang Modules
+extension.
+
+In terms of the C++ Standard, modules consist of two components: "Named
+Modules" or "Header Units". This document covers both.
 
 Standard C++ Named modules
 ==========================
 
-This document was intended to be a manual first and foremost, however, we consider it helpful to
-introduce some language background here for readers who are not familiar with
-the new language feature. This document is not intended to be a language
-tutorial; it will only introduce necessary concepts about the
-structure and building of the project.
+In order to better understand the compiler's behavior, it is helpful to
+understand some terms and definitions for readers who are not familiar with the
+C++ feature. This document is not a tutorial on C++; it only introduces
+necessary concepts to better understand use of modules in a project.
 
 Background and terminology
 --------------------------
 
-Modules
-~~~~~~~
-
-In this document, the term ``Modules``/``modules`` refers to standard C++ modules
-feature if it is not decorated by ``Clang``.
-
-Clang Modules
-~~~~~~~~~~~~~
-
-In this document, the term ``Clang Modules``/``Clang modules`` refer to Clang
-c++ modules extension. These are also known as ``Clang header modules``,
-``Clang module map modules`` or ``Clang c++ modules``.
-
 Module and module unit
 ~~~~~~~~~~~~~~~~~~~~~~
 
-A module consists of one or more module units. A module unit is a special
-translation unit. Every module unit must have a module declaration. The syntax
-of the module declaration is:
+A module consists of one or more module units. A module unit is a special kind
+of translation unit. A module unit should almost always start with a module
+declaration. The syntax of the module declaration is:
 
 .. code-block:: c++
 
   [export] module module_name[:partition_name];
 
-Terms enclosed in ``[]`` are optional. The syntax of ``module_name`` and ``partition_name``
-in regex form corresponds to ``[a-zA-Z_][a-zA-Z_0-9\.]*``. In particular, a literal dot ``.``
-in the name has no semantic meaning (e.g. implying a hierarchy).
+Terms enclosed in ``[]`` are optional. ``module_name`` and ``partition_name``
+follow the rules for a C++ identifier, except that they may contain one or more
+period (``.``) characters. Note that a ``.`` in the name has no semantic
+meaning and does not imply any hierarchy.
 
-In this document, module units are classified into:
+In this document, module units are classified as:
 
-* Primary module interface unit.
-
-* Module implementation unit.
-
-* Module interface partition unit.
-
-* Internal module partition unit.
+* Primary module interface unit
+* Module implementation unit
+* Module partition interface unit
+* Internal module partition unit
 
 A primary module interface unit is a module unit whose module declaration is
-``export module module_name;``. The ``module_name`` here denotes the name of the
+``export module module_name;`` where ``module_name`` denotes the name of the
 module. A module should have one and only one primary module interface unit.
 
 A module implementation unit is a module unit whose module declaration is
-``module module_name;``. A module could have multiple module implementation
-units with the same declaration.
+``module module_name;``. Multiple module implementation units can be declared
+in the same module.
 
-A module interface partition unit is a module unit whose module declaration is
+A module partition interface unit is a module unit whose module declaration is
 ``export module module_name:partition_name;``. The ``partition_name`` should be
 unique within any given module.
 
-An internal module partition unit is a module unit whose module declaration
-is ``module module_name:partition_name;``. The ``partition_name`` should be
-unique within any given module.
+An internal module partition unit is a module unit whose module
+declaration is ``module module_name:partition_name;``. The ``partition_name``
+should be unique within any given module.
 
-In this document, we use the following umbrella terms:
+In this document, we use the following terms:
 
 * A ``module interface unit`` refers to either a ``primary module interface unit``
-  or a ``module interface partition unit``.
+  or a ``module partition interface unit``.
 
-* An ``importable module unit`` refers to either a ``module interface unit``
-  or a ``internal module partition unit``.
+* An ``importable module unit`` refers to either a ``module interface unit`` or
+  an ``internal module partition unit``.
 
-* A ``module partition unit`` refers to either a ``module interface partition unit``
-  or a ``internal module partition unit``.
+* A ``module partition unit`` refers to either a ``module partition interface unit``
+  or an ``internal module partition unit``.
 
-Built Module Interface file
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Built Module Interface
+~~~~~~~~~~~~~~~~~~~~~~
 
-A ``Built Module Interface file`` stands for the precompiled result of an importable module unit.
-It is also called the acronym ``BMI`` generally.
+A ``Built Module Interface`` (or ``BMI``) is the precompiled result of an
+importable module unit.
 
 Global module fragment
 ~~~~~~~~~~~~~~~~~~~~~~
 
-In a module unit, the section from ``module;`` to the module declaration is called the global module fragment.
+The ``global module fragment`` (or ``GMF``) is the code between the ``module;``
+and the module declaration within a module unit.
 
 
 How to build projects using modules
@@ -138,7 +121,7 @@ Let's see a "hello world" example that uses modules.
     return 0;
   }
 
-Then we type:
+Then, on the command line, invoke Clang like:
 
 .. code-block:: console
 
@@ -148,9 +131,9 @@ Then we type:
   Hello World!
 
 In this example, we make and use a simple module ``Hello`` which contains only a
-primary module interface unit ``Hello.cppm``.
+primary module interface unit named ``Hello.cppm``.
 
-Then let's see a little bit more complex "hello world" example which uses the 4 kinds of module units.
+A more complex "hello world" example which uses the 4 kinds of module units is:
 
 .. code-block:: c++
 
@@ -192,7 +175,7 @@ Then let's see a little bit more complex "hello world" example which uses the 4
     return 0;
   }
 
-Then we are able to compile the example by the following command:
+Then, back on the command line, invoke Clang with:
 
 .. code-block:: console
 
@@ -216,51 +199,57 @@ We explain the options in the following sections.
 How to enable standard C++ modules
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Currently, standard C++ modules are enabled automatically
-if the language standard is ``-std=c++20`` or newer.
+Standard C++ modules are enabled automatically when the language standard mode
+is ``-std=c++20`` or newer.
 
 How to produce a BMI
 ~~~~~~~~~~~~~~~~~~~~
 
-We can generate a BMI for an importable module unit by either ``--precompile``
-or ``-fmodule-output`` flags.
+To generate a BMI for an importable module unit, use either the ``--precompile``
+or ``-fmodule-output`` command line options.
 
-The ``--precompile`` option generates the BMI as the output of the compilation and the output path
-can be specified using the ``-o`` option.
+The ``--precompile`` option generates the BMI as the output of the compilation
+with the output path specified using the ``-o`` option.
 
-The ``-fmodule-output`` option generates the BMI as a by-product of the compilation.
-If ``-fmodule-output=`` is specified, the BMI will be emitted the specified location. Then if
-``-fmodule-output`` and ``-c`` are specified, the BMI will be emitted in the directory of the
-output file with the name of the input file with the new extension ``.pcm``. Otherwise, the BMI
-will be emitted in the working directory with the name of the input file with the new extension
+The ``-fmodule-output`` option generates the BMI as a by-product of the
+compilation. If ``-fmodule-output=`` is specified, the BMI will be emitted to
+the specified location. If ``-fmodule-output`` and ``-c`` are specified, the
+BMI will be emitted in the directory of the output file with the name of the
+input file with the extension ``.pcm``. Otherwise, the BMI will be emitted in
+the working directory with the name of the input file with the extension
 ``.pcm``.
 
-The style to generate BMIs by ``--precompile`` is called two-phase compilation since it takes
-2 steps to compile a source file to an object file. The style to generate BMIs by ``-fmodule-output``
-is called one-phase compilation respectively. The one-phase compilation model is simpler
-for build systems to implement and the two-phase compilation has the potential to compile faster due
-to higher parallelism. As an example, if there are two module units A and B, and B depends on A, the
-one-phase compilation model would need to compile them serially, whereas the two-phase compilation
-model may be able to compile them simultaneously if the compilation from A.pcm to A.o takes a long
-time.
-
-File name requirement
-~~~~~~~~~~~~~~~~~~~~~
-
-The file name of an ``importable module unit`` should end with ``.cppm``
-(or ``.ccm``, ``.cxxm``, ``.c++m``). The file name of a ``module implementation unit``
-should end with ``.cpp`` (or ``.cc``, ``.cxx``, ``.c++``).
-
-The file name of BMIs should end with ``.pcm``.
-The file name of the BMI of a ``primary module interface unit`` should be ``module_name.pcm``.
-The file name of BMIs of ``module partition unit`` should be ``module_name-partition_name.pcm``.
-
-If the file names use different extensions, Clang may fail to build the module.
-For example, if the filename of an ``importable module unit`` ends with ``.cpp`` instead of ``.cppm``,
-then we can't generate a BMI for the ``importable module unit`` by ``--precompile`` option
-since ``--precompile`` option now would only run preprocessor, which is equal to `-E` now.
-If we want the filename of an ``importable module unit`` ends with other suffixes instead of ``.cppm``,
-we could put ``-x c++-module`` in front of the file. For example,
+Generating BMIs with ``--precompile`` is referred to as two-phase compilation
+because it takes two steps to compile a source file to an object file.
+Generating BMIs with ``-fmodule-output`` is called one-phase compilation. The
+one-phase compilation model is simpler for build systems to implement while the
+two-phase compilation has the potential to compile faster due to higher
+parallelism. As an example, if there are two module units ``A`` and ``B``, and
+``B`` depends on ``A``, the one-phase compilation model needs to compile them
+serially, whereas the two-phase compilation model is able to be compiled as
+soon as ``A.pcm`` is available, and thus can be compiled simultaneously as the
+``A.pcm`` to ``A.o`` compilation step.
+
+File name requirements
+~~~~~~~~~~~~~~~~~~~~~~
+
+By convention, ``importable module unit`` files should use ``.cppm`` (or
+``.ccm``, ``.cxxm``, or ``.c++m``) as a file extension.
+``Module implementation unit`` files should use ``.cpp`` (or ``.cc``, ``.cxx``,
+or ``.c++``) as a file extension.
+
+A BMI should use ``.pcm`` as a file extension. The file name of the BMI for a
+``primary module interface unit`` should be ``module_name.pcm``. The file name
+of a BMI for a ``module partition unit`` should be
+``module_name-partition_name.pcm``.
+
+Clang may fail to build the module if different extensions are used. For
+example, if the filename of an ``importable module unit`` ends with ``.cpp``
+instead of ``.cppm``, then Clang cannot generate a BMI for the
+``importable module unit`` with the ``--precompile`` option because the
+``--precompile`` option would only run the preprocessor (``-E``). If using a
+different extension than the conventional one for an ``importable module unit``
+you can specify ``-x c++-module`` before the file. For example,
 
 .. code-block:: c++
 
@@ -279,8 +268,9 @@ we could put ``-x c++-module`` in front of the file. For example,
     return 0;
   }
 
-Now the filename of the ``module interface`` ends with ``.cpp`` instead of ``.cppm``,
-we can't compile them by the original command lines. But we are still able to do it by:
+In this example, the extension used by the ``module interface`` is ``.cpp``
+instead of ``.cppm``, so it cannot be compiled like the previous example, but
+it can be compiled with:
 
 .. code-block:: console
 
@@ -289,12 +279,12 @@ we can't compile them by the original command lines. But we are still able to do
   $ ./Hello.out
   Hello World!
 
-Module name requirement
-~~~~~~~~~~~~~~~~~~~~~~~
+Module name requirements
+~~~~~~~~~~~~~~~~~~~~~~~~
 
-[module.unit]p1 says:
+..
 
-.. code-block:: text
+  [module.unit]p1:
 
   All module-names either beginning with an identifier consisting of std followed by zero
   or more digits or containing a reserved identifier ([lex.name]) are reserved and shall not
@@ -302,7 +292,7 @@ Module name requirement
   module-name is a reserved identifier, the module name is reserved for use by C++ implementations;
   otherwise it is reserved for future standardization.
 
-So all of the following name is not valid by default:
+Therefore, none of the following names are valid by default:
 
 .. code-block:: text
 
@@ -312,75 +302,74 @@ So all of the following name is not valid by default:
     __test
     // and so on ...
 
-If you still want to use the reserved module names for any reason, use
-``-Wno-reserved-module-identifier`` to suppress the warning.
+Using a reserved module name is strongly discouraged, but
+``-Wno-reserved-module-identifier`` can be used to suppress the warning.
 
-How to specify the dependent BMIs
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Specifying dependent BMIs
+~~~~~~~~~~~~~~~~~~~~~~~~~
 
-There are 3 methods to specify the dependent BMIs:
+There are 3 ways to specify a dependent BMI:
 
-* (1) ``-fprebuilt-module-path=``.
-* (2) ``-fmodule-file=`` (Deprecated).
-* (3) ``-fmodule-file==``.
+1. ``-fprebuilt-module-path=``.
+2. ``-fmodule-file=`` (Deprecated).
+3. ``-fmodule-file==``.
 
-The option ``-fprebuilt-module-path`` tells the compiler the path where to search for dependent BMIs.
-It may be used multiple times just like ``-I`` for specifying paths for header files. The look up rule here is:
+The ``-fprebuilt-module-path`` option specifies the path to search for
+dependent BMIs. Multiple paths may be specified, similar to using ``-I`` to
+specify a search path for header files. When importing a module ``M``, the
+compiler looks for ``M.pcm`` in the directories specified by
+``-fprebuilt-module-path``. Similarly, when importing a partition module unit
+``M:P``, the compiler looks for ``M-P.pcm`` in the directories specified by
+``-fprebuilt-module-path``.
 
-* (1) When we import module M. The compiler would look up M.pcm in the directories specified
-  by ``-fprebuilt-module-path``.
-* (2) When we import partition module unit M:P. The compiler would look up M-P.pcm in the
-  directories specified by ``-fprebuilt-module-path``.
-
-The option ``-fmodule-file=`` tells the compiler to load the specified BMI directly.
-The option ``-fmodule-file==`` tells the compiler to load the specified BMI
-for the module specified by ```` when necessary. The main difference is that
+The ``-fmodule-file=`` option causes the compiler to load the
+specified BMI directly. The ``-fmodule-file==``
+option causes the compiler to load the specified BMI for the module specified
+by ```` when necessary. The main difference is that
 ``-fmodule-file=`` will load the BMI eagerly, whereas
-``-fmodule-file==`` will only load the BMI lazily, which is similar
-with ``-fprebuilt-module-path``. The option ``-fmodule-file=`` for named modules is deprecated
-and is planning to be removed in future versions.
+``-fmodule-file==`` will only load the BMI lazily,
+as will ``-fprebuilt-module-path``. The ``-fmodule-file=`` option
+for named modules is deprecated and will be removed in a future version of
+Clang.
 
-In case all ``-fprebuilt-module-path=``, ``-fmodule-file=`` and
-``-fmodule-file==`` exist, the ``-fmodule-file=`` option
-takes highest precedence and ``-fmodule-file==`` will take the second
-highest precedence.
+When these options are specified in the same invocation of the compiler, the
+``-fmodule-file=`` option takes precedence over
+``-fmodule-file==``, which takes precedence over
+``-fprebuilt-module-path=``.
 
-We need to specify all the dependent (directly and indirectly) BMIs.
-See https://github.com/llvm/llvm-project/issues/62707 for detail.
+Note: all dependant BMIs must be specified explicitly, either directly or
+indirectly dependent BMIs explicitly. See
+https://github.com/llvm/llvm-project/issues/62707 for details.
 
-When we compile a ``module implementation unit``, we must specify the BMI of the corresponding
-``primary module interface unit``.
-Since the language specification says a module implementation unit implicitly imports
-the primary module interface unit.
+When compiling a ``module implementation unit``, the BMI of the corresponding
+``primary module interface unit`` must be specified because a module
+implementation unit implicitly imports the primary module interface unit.
 
   [module.unit]p8
 
   A module-declaration that contains neither an export-keyword nor a module-partition implicitly
   imports the primary module interface unit of the module as if by a module-import-declaration.
 
-All of the 3 options ``-fprebuilt-module-path=``, ``-fmodule-file=``
-and ``-fmodule-file==`` may occur multiple times.
-For example, the command line to compile ``M.cppm`` in
-the above example could be rewritten into:
+The ``-fprebuilt-module-path=``, ``-fmodule-file=``,
+and ``-fmodule-file==`` options may be specified
+multiple times. For example, the command line to compile ``M.cppm`` in
+the previous example could be rewritten as:
 
 .. code-block:: console
 
   $ clang++ -std=c++20 M.cppm --precompile -fmodule-file=M:interface_part=M-interface_part.pcm -fmodule-file=M:impl_part=M-impl_part.pcm -o M.pcm
 
 When there are multiple ``-fmodule-file==`` options for the same
-````, the last ``-fmodule-file==`` will override the previous
-``-fmodule-file==`` options.
-
-``-fprebuilt-module-path`` is more convenient and ``-fmodule-file`` is faster since
-it saves time for file lookup.
+````, the last ``-fmodule-file==`` overrides the
+previous ``-fmodule-file==`` option.
 
 Remember that module units still have an object counterpart to the BMI
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-It is easy to forget to compile BMIs at first since we may envision module interfaces like headers.
-However, this is not true.
-Module units are translation units. We need to compile them to object files
-and link the object files like the example shows.
+While module interfaces resemble traditional header files, they still require
+compilation. Module units are translation units, and need to be compiled to
+object files, which then need to be linked together as the following examples
+show.
 
 For example, the traditional compilation processes for headers are like:
 
@@ -400,24 +389,27 @@ And the compilation process for module units are like:
                 mod1.cppm -> clang++ mod1.cppm ... -> mod1.pcm --,--> clang++ mod1.pcm ... -> mod1.o -+
                 src2.cpp ----------------------------------------+> clang++ src2.cpp -------> src2.o -'
 
-As the diagrams show, we need to compile the BMI from module units to object files and link the object files.
-(But we can't do this for the BMI from header units. See the later section for the definition of header units)
+As the diagrams show, we need to compile the BMI from module units to object
+files and then link the object files. (However, this cannot be done for the BMI
+from header units. See the section on :ref:`header units ` for
+more details.
 
-If we want to create a module library, we can't just ship the BMIs in an archive.
-We must compile these BMIs(``*.pcm``) into object files(``*.o``) and add those object files to the archive instead.
+BMIs cannot be shipped in an archive to create a module library. Instead, the
+BMIs(``*.pcm``) are compiled into object files(``*.o``) and those object files
+are added to the archive instead.
 
-Consistency Requirement
-~~~~~~~~~~~~~~~~~~~~~~~
+Consistency Requirements
+~~~~~~~~~~~~~~~~~~~~~~~~
 
-If we envision modules as a cache to speed up compilation, then - as with other caching techniques -
-it is important to keep cache consistency.
-So **currently** Clang will do very strict check for consistency.
+Modules can be viewed as a kind of cache to speed up compilation. Thus, like
+other caching techniques, it is important to maintain cache consistency which
+is why Clang does very strict checking for consistency.
 
 Options consistency
 ^^^^^^^^^^^^^^^^^^^
 
-The language option of module units and their non-module-unit users should be consistent.
-The following example is not allowed:
+Compiler options related to the language dialect for a module unit and its
+non-module-unit uses need to be consistent. Consider the following example:
 
 .. code-block:: c++
 
@@ -432,9 +424,8 @@ The following example is not allowed:
   $ clang++ -std=c++20 M.cppm --precompile -o M.pcm
   $ clang++ -std=c++23 Use.cpp -fprebuilt-module-path=.
 
-The compiler would reject the example due to the inconsistent language options.
-Not all options are language options.
-For example, the following example is allowed:
+Clang rejects the example due to the inconsistent language standard modes. Not
+all compiler options are language dialect options, though. For example:
 
 .. code-block:: console
 
@@ -444,9 +435,12 @@ For example, the following example is allowed:
   # Inconsistent debugging level.
   $ clang++ -std=c++20 -g Use.cpp -fprebuilt-module-path=.
 
-Although the two examples have inconsistent optimization and debugging level, both of them are accepted.
+Although the optimization and debugging levels are inconsistent, these
+compilations are accepted because the compiler options do not impact the
+language dialect.
 
-Note that **currently** the compiler doesn't consider inconsistent macro definition a problem. For example:
+Note that the compiler **currently** doesn't reject inconsistent macro
+definitions (this may change in the future). For example:
 
 .. code-block:: console
 
@@ -454,43 +448,43 @@ Note that **currently** the compiler doesn't consider inconsistent macro definit
   # Inconsistent optimization level.
   $ clang++ -std=c++20 -O3 -DNDEBUG Use.cpp -fprebuilt-module-path=.
 
-Currently Clang would accept the above example. But it may produce surprising results if the
-debugging code depends on consistent use of ``NDEBUG`` also in other translation units.
+Currently, Clang accepts the above example, though it may produce surprising
+results if the debugging code depends on consistent use of ``NDEBUG`` in other
+translation units.
 
-Definitions consistency
-^^^^^^^^^^^^^^^^^^^^^^^
+Object definition consistency
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The C++ language requires that declarations of the same entity in different
+translation units have the same definition, which is known as the One
+Definition Rule (ODR). Without modules, the compiler cannot perform strong ODR
+violation checking because it only sees one translation unit at a time. With
+the use of modules, the compiler can perform checks for ODR violations across
+translation units.
 
-The C++ language defines that same declarations in different translation units should have
-the same definition, as known as ODR (One Definition Rule). Prior to modules, the translation
-units don't dependent on each other and the compiler itself can't perform a strong
-ODR violation check. With the introduction of modules, now the compiler have
-the chance to perform ODR violations with language semantics across translation units.
-
-However, in the practice, we found the existing ODR checking mechanism is not stable
-enough. Many people suffers from the false positive ODR violation diagnostics, AKA,
-the compiler are complaining two identical declarations have different definitions
-incorrectly. Also the true positive ODR violations are rarely reported.
-Also we learned that MSVC don't perform ODR check for declarations in the global module
-fragment.
-
-So in order to get better user experience, save the time checking ODR and keep consistent
-behavior with MSVC, we disabled the ODR check for the declarations in the global module
-fragment by default. Users who want more strict check can still use the
-``-Xclang -fno-skip-odr-check-in-gmf`` flag to get the ODR check enabled. It is also
-encouraged to report issues if users find false positive ODR violations or false negative ODR
-violations with the flag enabled.
+However, the current ODR checking mechanisms are not perfect. There are a
+significant number of false positive ODR violation diagnostics, where the
+compiler incorrectly diagnoses two identical declarations as having different
+definitions. Further, true positive ODR violations are not always reported.
+
+To give a better user experience, improve compilation performance, and for
+consistency with MSVC, ODR checking of declarations in the global module
+fragment is disabled by default. These checks can be enabled by specifying
+``-Xclang -fno-skip-odr-check-in-gmf`` when compiling. If the check is enabled
+and you encounter incorrect or missing diagnostics, please report them via the
+`community issue tracker `_.
 
 ABI Impacts
 -----------
 
-This section describes the new ABI changes brought by modules.
-
-Only Itanium C++ ABI related change are mentioned
+This section describes the new ABI changes brought by modules. Only changes to
+the Itanium C++ ABI are covered.
 
-Mangling Names
-~~~~~~~~~~~~~~
+Name Mangling
+~~~~~~~~~~~~~
 
-The declarations in a module unit which are not in the global module fragment have new linkage names.
+The declarations in a module unit which are not in the global module fragment
+have new linkage names.
 
 For example,
 
@@ -501,22 +495,24 @@ For example,
     export int foo();
   }
 
-The linkage name of ``NS::foo()`` would be ``_ZN2NSW1M3fooEv``.
-This couldn't be demangled by previous versions of the debugger or demangler.
-As of LLVM 15.x, users can utilize ``llvm-cxxfilt`` to demangle this:
+The linkage name of ``NS::foo()`` is ``_ZN2NSW1M3fooEv``. This couldn't be
+demangled by previous versions of the debugger or demangler. As of LLVM 15.x,
+``llvm-cxxfilt`` can be used to demangle this:
 
 .. code-block:: console
 
   $ llvm-cxxfilt _ZN2NSW1M3fooEv
+    NS::foo@M()
 
-The result would be ``NS::foo@M()``, which reads as ``NS::foo()`` in module ``M``.
+The result should be read as ``NS::foo()`` in module ``M``.
 
-The ABI implies that we can't declare something in a module unit and define it in a non-module unit (or vice-versa),
-as this would result in linking errors.
+The ABI implies that something cannot be declared in a module unit and defined
+in a non-module unit (or vice-versa), as this would result in linking errors.
 
-If we still want to implement declarations within the compatible ABI in module unit,
-we can use the language-linkage specifier. Since the declarations in the language-linkage specifier
-is attached to the global module fragments. For example:
+Despite this, it is possible to implement declarations with a compatible ABI in
+a module unit by using a language linkage specifier because the declarations in
+the language linkage specifier are attached to the global module fragment. For
+example:
 
 .. code-block:: c++
 
@@ -530,43 +526,47 @@ Now the linkage name of ``NS::foo()`` will be ``_ZN2NS3fooEv``.
 Module Initializers
 ~~~~~~~~~~~~~~~~~~~
 
-All the importable module units are required to emit an initializer function.
-The initializer function should contain calls to importing modules first and
-all the dynamic-initializers in the current module unit then.
+All importable module units are required to emit an initializer function to
+handle the dynamic initialization of non-inline variables in the module unit.
+The importable module unit has to emit the initializer even if there is no
+dynamic initialization; otherwise, the importer may call a nonexistent
+function. The initializer function emits calls to imported modules first
+followed by calls to all to of the dynamic initializers in the current module
+unit.
 
-Translation units explicitly or implicitly importing named modules must call
-the initializer functions of the imported named modules within the sequence of
-the dynamic-initializers in the TU. Initializations of entities at namespace
-scope are appearance-ordered. This (recursively) extends into imported modules
-at the point of appearance of the import declaration.
+Translation units that explicitly or implicitly import a named module must call
+the initializer functions of the imported named module within the sequence of
+the dynamic initializers in the translation unit. Initializations of entities
+at namespace scope are appearance-ordered. This (recursively) extends to
+imported modules at the point of appearance of the import declaration.
 
-It is allowed to omit calls to importing modules if it is known empty.
-
-It is allowed to omit calls to importing modules for which is known to be called.
+If the imported module is known to be empty, the call to its initializer may be
+omitted. Additionally, if the imported module is known to have already been
+imported, the call to its initializer may be omitted.
 
 Reduced BMI
 -----------
 
-To support the 2 phase compilation model, Clang chose to put everything needed to
-produce an object into the BMI. But every consumer of the BMI, except itself, doesn't
-need such informations. It makes the BMI to larger and so may introduce unnecessary
-dependencies into the BMI. To mitigate the problem, we decided to reduce the information
-contained in the BMI.
-
-To be clear, we call the default BMI as Full BMI and the new introduced BMI as Reduced
-BMI.
+To support the two-phase compilation model, Clang puts everything needed to
+produce an object into the BMI. However, other consumers of the BMI generally
+don't need that information. This makes the BMI larger and may introduce
+unnecessary dependencies for the BMI. To mitigate the problem, Clang has a
+compiler option to reduce the information contained in the BMI. These two
+formats are known as Full BMI and Reduced BMI, respectively.
 
-Users can use ``-fexperimental-modules-reduced-bmi`` flag to enable the Reduced BMI.
+Users can use the ``-fexperimental-modules-reduced-bmi`` option to produce a
+Reduced BMI.
 
-For one phase compilation model (CMake implements this model), with
-``-fexperimental-modules-reduced-bmi``, the generated BMI will be Reduced BMI automatically.
-(The output path of the BMI is specified by ``-fmodule-output=`` as usual one phase
-compilation model).
+For the one-phase compilation model (CMake implements this model), with
+``-fexperimental-modules-reduced-bmi``, the generated BMI will be a Reduced
+BMI automatically. (The output path of the BMI is specified by
+``-fmodule-output=`` as usual with the one-phase compilation model).
 
-It is still possible to support Reduced BMI in two phase compilation model. With
-``-fexperimental-modules-reduced-bmi``, ``--precompile`` and ``-fmodule-output=`` specified,
-the generated BMI specified by ``-o`` will be full BMI and the BMI specified by
-``-fmodule-output=`` will be Reduced BMI. The dependency graph may be:
+It is also possible to produce a Reduced BMI with the two-phase compilation
+model. When ``-fexperimental-modules-reduced-bmi``, ``--precompile``, and
+``-fmodule-output=`` are specified, the generated BMI specified by ``-o`` will
+be a full BMI and the BMI specified by ``-fmodule-output=`` will be a Reduced
+BMI. The dependency graph in this case would look like:
 
 .. code-block:: none
 
@@ -577,15 +577,16 @@ the generated BMI specified by ``-o`` will be full BMI and the BMI specified by
                                                -> ...
                                                -> consumer_n.cpp
 
-We don't emit diagnostics if ``-fexperimental-modules-reduced-bmi`` is used with a non-module
-unit. This design helps the end users of one phase compilation model to perform experiments
-early without asking for the help of build systems. The users of build systems which supports
-two phase compilation model still need helps from build systems.
+Clang does not emit diagnostics when ``-fexperimental-modules-reduced-bmi`` is
+used with a non-module unit. This design permits users of the one-phase
+compilation model to try using reduced BMIs without needing to modify the build
+system. The two-phase compilation module requires build system support.
 
-Within Reduced BMI, we won't write unreachable entities from GMF, definitions of non-inline
-functions and non-inline variables. This may not be a transparent change.
-`[module.global.frag]ex2 `_ may be a good
-example:
+In a Reduced BMI, Clang does not emit unreachable entities from the global
+module fragment, or definitions of non-inline functions and non-inline
+variables. This may not be a transparent change.
+
+Consider the following example:
 
 .. code-block:: c++
 
@@ -633,22 +634,23 @@ example:
                                   // module M's interface, so is discarded
   int c = use_h();           // OK
 
-In the above example, the function definition of ``N::g`` is elided from the Reduced
-BMI of ``M.cppm``. Then the use of ``use_g`` in ``M-impl.cpp`` fails
-to instantiate. For such issues, users can add references to ``N::g`` in the module purview
-of ``M.cppm`` to make sure it is reachable, e.g., ``using N::g;``.
+In the above example, the function definition of ``N::g`` is elided from the
+Reduced BMI of ``M.cppm``. Then the use of ``use_g`` in ``M-impl.cpp``
+fails to instantiate. For such issues, users can add references to ``N::g`` in
+the `module purview `_ of ``M.cppm`` to
+ensure it is reachable, e.g. ``using N::g;``.
 
-We think the Reduced BMI is the correct direction. But given it is a drastic change,
-we'd like to make it experimental first to avoid breaking existing users. The roadmap
-of Reduced BMI may be:
+Support for Reduced BMIs is still experimental, but it may become the default
+in the future. The expected roadmap for Reduced BMIs as of Clang 19.x is:
 
-1. ``-fexperimental-modules-reduced-bmi`` is opt in for 1~2 releases. The period depends
-on testing feedbacks.
-2. We would announce Reduced BMI is not experimental and introduce ``-fmodules-reduced-bmi``.
-and suggest users to enable this mode. This may takes 1~2 releases too.
-3. Finally we will enable this by default. When that time comes, the term BMI will refer to
-the reduced BMI today and the Full BMI will only be meaningful to build systems which
-loves to support two phase compilations.
+1. ``-fexperimental-modules-reduced-bmi`` is opt-in for 1~2 releases. The period depends
+   on user feedback and may be extended.
+2. Announce that Reduced BMIs are no longer experimental and introduce
+   ``-fmodules-reduced-bmi`` as a new option, and recommend use of the new
+   option. This transition is expected to take 1~2 additional releases as well.
+3. Finally, ``-fmodules-reduced-bmi`` will be the default. When that time
+   comes, the term BMI will refer to the Reduced BMI and the Full BMI will only
+   be meaningful to build systems which elect to support two-phase compilation.
 
 Performance Tips
 ----------------
@@ -656,13 +658,11 @@ Performance Tips
 Reduce duplications
 ~~~~~~~~~~~~~~~~~~~
 
-While it is legal to have duplicated declarations in the global module fragments
-of different module units, it is not free for clang to deal with the duplicated
-declarations. In other word, for a translation unit, it will compile slower if the
-translation unit itself and its importing module units contains a lot duplicated
-declarations.
-
-For example,
+While it is valid to have duplicated declarations in the global module fragments
+of different module units, it is not free for Clang to deal with the duplicated
+declarations. A translation unit will compile more slowly if there is a lot of
+duplicated declarations between the translation unit and modules it imports.
+For example:
 
 .. code-block:: c++
 
@@ -698,9 +698,9 @@ For example,
   import M;
   ... // use declarations from module M.
 
-When ``big.header.h`` is big enough and there are a lot of partitions,
-the compilation of ``use.cpp`` may be slower than
-the following style significantly:
+When ``big.header.h`` is big enough and there are a lot of partitions, the
+compilation of ``use.cpp`` may be significantly slower than the following
+approach:
 
 .. code-block:: c++
 
@@ -738,22 +738,21 @@ the following style significantly:
   import M;
   ... // use declarations from module M.
 
-The key part of the tip is to reduce the duplications from the text includes.
-
-Ideas for converting to modules
--------------------------------
+Reducing the duplication from textual includes is what improves compile-time
+performance.
 
-For new libraries, we encourage them to use modules completely from day one if possible.
-This will be pretty helpful to make the whole ecosystems to get ready.
+Transitioning to modules
+------------------------
 
-For many existing libraries, it may be a breaking change to refactor themselves
-into modules completely. So that many existing libraries need to provide headers and module
-interfaces for a while to not break existing users.
-Here we provide some ideas to ease the transition process for existing libraries.
-**Note that the this section is only about helping ideas instead of requirement from clang**.
+It is best for new code and libraries to use modules from the start if
+possible. However, it may be a breaking change for existing code or libraries
+to switch to modules. As a result, many existing libraries need to provide
+both headers and module interfaces for a while to not break existing users.
 
-Let's start with the case that there is no dependency or no dependent libraries providing
-modules for your library.
+This section suggests some suggestions on how to ease the transition process
+for existing libraries. **Note that this information is only intended as
+guidance, rather than as requirements to use modules in Clang.** It presumes
+the project is starting with no module-based dependencies.
 
 ABI non-breaking styles
 ~~~~~~~~~~~~~~~~~~~~~~~
@@ -776,9 +775,9 @@ export-using style
     using decl_n;
   }
 
-As the example shows, you need to include all the headers containing declarations needs
-to be exported and `using` such declarations in an `export` block. Then, basically,
-we're done.
+This example shows how to include all the headers containing declarations which
+need to be exported, and uses `using` declarations in an `export` block to
+produce the module interface.
 
 export extern-C++ style
 ^^^^^^^^^^^^^^^^^^^^^^^
@@ -799,7 +798,7 @@ export extern-C++ style
     #include "header_n.h"
   }
 
-Then in your headers (from ``header_1.h`` to ``header_n.h``), you need to define the macro:
+Headers (from ``header_1.h`` to ``header_n.h``) need to define the macro:
 
 .. code-block:: c++
 
@@ -809,9 +808,10 @@ Then in your headers (from ``header_1.h`` to ``header_n.h``), you need to define
   #define EXPORT
   #endif
 
-And you should put ``EXPORT`` to the beginning of the declarations you want to export.
+and put ``EXPORT`` on the declarations you want to export.
 
-Also it is suggested to refactor your headers to include thirdparty headers conditionally:
+Also, it is recommended to refactor headers to include third-party headers
+conditionally:
 
 .. code-block:: c++
 
@@ -823,26 +823,25 @@ Also it is suggested to refactor your headers to include thirdparty headers cond
 
   ...
 
-This may be helpful to get better diagnostic messages if you forgot to update your module
-interface unit file during maintaining.
+This can be helpful because it gives better diagnostic messages if the module
+interface unit is not properly updated when modifying code.
 
-The reasoning for the practice is that the declarations in the language linkage are considered
-to be attached to the global module. So the ABI of your library in the modular version
-wouldn't change.
+This approach works because the declarations with language linkage are attached
+to the global module. Thus, the ABI of the modular form of the library does not
+change.
 
-While this style looks not as convenient as the export-using style, it is easier to convert
-to other styles.
+While this style is more involved than the export-using style, it makes it
+easier to further refactor the library to other styles.
 
 ABI breaking style
 ~~~~~~~~~~~~~~~~~~
 
-The term ``ABI breaking`` sounds terrifying generally. But you may want it here if you want
-to force your users to introduce your library in a consistent way. E.g., they either include
-your headers all the way or import your modules all the way.
-The style prevents the users to include your headers and import your modules at the same time
-in the same repo.
+The term ``ABI breaking`` may sound like a bad approach. However, this style
+forces consumers of the library use it in a consistent way. e.g., either always
+include headers for the library or always import modules. The style prevents
+the ability to mix includes and imports for the library.
 
-The pattern for ABI breaking style is similar with export extern-C++ style.
+The pattern for ABI breaking style is similar to the export extern-C++ style.
 
 .. code-block:: c++
 
@@ -865,7 +864,7 @@ The pattern for ABI breaking style is similar with export extern-C++ style.
   ...
   #include "source_n.cpp"
   #else // the number of .cpp files in your project are a lot
-  // Using all the declarations from thirdparty libraries which are
+  // Using all the declarations from third-party libraries which are
   // used in the .cpp files.
   namespace third_party_namespace {
     using third_party_decl_used_in_cpp_1;
@@ -875,11 +874,11 @@ The pattern for ABI breaking style is similar with export extern-C++ style.
   }
   #endif
 
-(And add `EXPORT` and conditional include to the headers as suggested in the export
-extern-C++ style section)
+(And add `EXPORT` and conditional include to the headers as suggested in the
+export extern-C++ style section.)
 
-Remember that the ABI get changed and we need to compile our source files into the
-new ABI format. This is the job of the additional part of the interface unit:
+The ABI with modules is different and thus we need to compile the source files
+into the new ABI. This is done by an additional part of the interface unit:
 
 .. code-block:: c++
 
@@ -890,7 +889,7 @@ new ABI format. This is the job of the additional part of the interface unit:
   ...
   #include "source_n.cpp"
   #else // the number of .cpp files in your project are a lot
-  // Using all the declarations from thirdparty libraries which are
+  // Using all the declarations from third-party libraries which are
   // used in the .cpp files.
   namespace third_party_namespace {
     using third_party_decl_used_in_cpp_1;
@@ -900,16 +899,17 @@ new ABI format. This is the job of the additional part of the interface unit:
   }
   #endif
 
-In case the number of your source files are small, we may put everything in the private
-module fragment directly. (it is suggested to add conditional include to the source
-files too). But it will make the compilation of the module interface unit to be slow
-when the number of the source files are not small enough.
+If the number of source files is small, everything can be put in the private
+module fragment directly (it is recommended to add conditional includes to the
+source files as well). However, compile time performance will be bad if there
+are a lot of source files to compile.
 
-**Note that the private module fragment can only be in the primary module interface unit
-and the primary module interface unit containing private module fragment should be the only
-module unit of the corresponding module.**
+**Note that the private module fragment can only be in the primary module
+interface unit and the primary module interface unit containing the private
+module fragment should be the only module unit of the corresponding module.**
 
-In that case, you need to convert your source files (.cpp files) to module implementation units:
+In this case, source files (.cpp files) must be converted to module
+implementation units:
 
 .. code-block:: c++
 
@@ -925,45 +925,40 @@ In that case, you need to convert your source files (.cpp files) to module imple
   // Following off should be unchanged.
   ...
 
-The module implementation unit will import the primary module implicitly.
-We don't include any headers in the module implementation units
-here since we want to avoid duplicated declarations between translation units.
-This is the reason why we add non-exported using declarations from the third
-party libraries in the primary module interface unit.
-
-And if you provide your library as ``libyour_library.so``, you probably need to
-provide a modular one ``libyour_library_modules.so`` since you changed the ABI.
-
-What if there are headers only inclued by the source files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+The module implementation unit will import the primary module implicitly. Do
+not include any headers in the module implementation units as it avoids
+duplicated declarations between translation units. This is why non-exported
+using declarations should be added from third-party libraries in the primary
+module interface unit.
 
-The above practice may be problematic if there are headers only included by the source
-files. If you're using private module fragment, you may solve the issue by including them
-in the private module fragment. While it is OK to solve it by including the implementation
-headers in the module purview if you're using implementation module units, it may be
-suboptimal since the primary module interface units now containing entities not belongs
-to the interface.
+If the library is provided as ``libyour_library.so``, a modular library (e.g.,
+``libyour_library_modules.so``) may also need to be provided for ABI
+compatibility.
 
-If you're a perfectionist, maybe you can improve it by introducing internal module partition unit.
+What if there are headers only included by the source files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-The internal module partition unit is an importable module unit which is internal
-to the module itself. The concept just meets the headers only included by the source files.
+The above practice may be problematic if there are headers only included by the
+source files. When using a private module fragment, this issue may be solved by
+including those headers in the private module fragment. While it is OK to solve
+it by including the implementation headers in the module purview when using
+implementation module units, it may be suboptimal because the primary module
+interface units now contain entities that do not belong to the interface.
 
-We don't show code snippet since it may be too verbose or not good or not general.
-But it may not be too hard if you can understand the points of the section.
+This can potentially be improved by introducing a module partition
+implementation unit. An internal module partition unit is an importable
+module unit which is internal to the module itself.
 
 Providing a header to skip parsing redundant headers
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-It is a problem for clang to handle redeclarations between translation units.
-Also there is a long standing issue in clang (`problematic include after import `_).
-But even if the issue get fixed in clang someday, the users may still get slower compilation speed
-and larger BMI size. So it is suggested to not include headers after importing the corresponding
-library.
-
-However, it is not easy for users if your library are included by other dependencies.
-
-So the users may have to write codes like:
+Many redeclarations shared between translation units causes Clang to have
+slower compile-time performance. Further, there are known issues with
+`include after import `_.
+Even when that issue is resolved, users may still get slower compilation speed
+and larger BMIs. For these reasons, it is recommended to not include headers
+after importing the corresponding module. However, it is not always easy if the
+library is included by other dependencies, as in:
 
 .. code-block:: c++
 
@@ -977,9 +972,9 @@ or
   import your_library;
   #include "third_party/A.h" // #include "your_library/a_header.h"
 
-For such cases, we suggest the libraries providing modules and the headers at the same time
-to provide a header to skip parsing all the headers in your libraries. So the users can
-import your library as the following style to skip redundant handling:
+For such cases, it is best if the library providing both module and header
+interfaces also provides a header which skips parsing so that the library can
+be imported with the following approach that skips redundant redeclarations:
 
 .. code-block:: c++
 
@@ -987,9 +982,9 @@ import your library as the following style to skip redundant handling:
   #include "your_library_imported.h"
   #include "third_party/A.h" // #include "your_library/a_header.h" but got skipped
 
-The implementation of ``your_library_imported.h`` can be a set of controlling macros or
-an overall controlling macro if you're using `#pragma once`. So you can convert your
-headers to:
+The implementation of ``your_library_imported.h`` can be a set of controlling
+macros or an overall controlling macro if using `#pragma once`. Then headers
+can be refactored to:
 
 .. code-block:: c++
 
@@ -998,25 +993,24 @@ headers to:
   ...
   #endif
 
-If the modules imported by your library provides such headers too, remember to add them to
-your ``your_library_imported.h`` too.
+If the modules imported by the library provide such headers, remember to add
+them to ``your_library_imported.h`` too.
 
 Importing modules
 ~~~~~~~~~~~~~~~~~
 
-When there are dependent libraries providing modules, we suggest you to import that in
-your module.
-
-Most of the existing libraries would fall into this catagory once the std module gets available.
+When there are dependent libraries providing modules, they should be imported
+in your module as well. Many existing libraries will fall into this category
+once the ``std`` module is more widely available.
 
 All dependent libraries providing modules
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Life gets easier if all the dependent libraries providing modules.
+Of course, most of the complexity disappears if all the dependent libraries
+provide modules.
 
-You need to convert your headers to include thirdparty headers conditionally.
-
-Then for export-using style:
+Headers need to be converted to include third-party headers conditionally. Then,
+for the export-using style:
 
 .. code-block:: c++
 
@@ -1035,7 +1029,7 @@ Then for export-using style:
     using decl_n;
   }
 
-For export extern-C++ style:
+or, for the export extern-C++ style:
 
 .. code-block:: c++
 
@@ -1049,7 +1043,7 @@ For export extern-C++ style:
     #include "header_n.h"
   }
 
-For ABI breaking style,
+or, for the ABI-breaking style,
 
 .. code-block:: c++
 
@@ -1069,35 +1063,39 @@ For ABI breaking style,
   #include "source_n.cpp"
   #endif
 
-We don't need the non-exported using declarations if we're using implementation module
-units now. We can import thirdparty modules directly in the implementation module
-units.
+Non-exported ``using`` declarations are unnecessary if using implementation
+module units. Instead, third-party modules can be imported directly in
+implementation module units.
 
 Partial dependent libraries providing modules
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-In this case, we have to mix the use of ``include`` and ``import`` in the module of our
-library. The key point here is still to remove duplicated declarations in translation
-units as much as possible. If the imported modules provide headers to skip parsing their
-headers, we should include that after the including. If the imported modules don't provide
-the headers, we can make it ourselves if we still want to optimize it.
-
-Known Problems
---------------
-
-The following describes issues in the current implementation of modules.
-Please see https://github.com/llvm/llvm-project/labels/clang%3Amodules for more issues
-or file a new issue if you don't find an existing one.
-If you're going to create a new issue for standard C++ modules,
-please start the title with ``[C++20] [Modules]`` (or ``[C++23] [Modules]``, etc)
-and add the label ``clang:modules`` (if you have permissions for that).
-
-For higher level support for proposals, you could visit https://clang.llvm.org/cxx_status.html.
-
-Including headers after import is problematic
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If the library has to mix the use of ``include`` and ``import`` in its module,
+the primary goal is still the removal of duplicated declarations in translation
+units as much as possible. If the imported modules provide headers to skip
+parsing their headers, those should be included after the import. If the
+imported modules don't provide such a header, one can be made manually for
+improved compile time performance.
+
+Known Issues
+------------
+
+The following describes issues in the current implementation of modules. Please
+see
+`the issues list for modules `_
+for a list of issues or to file a new issue if you don't find an existing one.
+When creating a new issue for standard C++ modules, please start the title with
+``[C++20] [Modules]`` (or ``[C++23] [Modules]``, etc) and add the label
+``clang:modules`` if possible.
+
+A high-level overview of support for standards features, including modules, can
+be found on the `C++ Feature Status `_
+page.
+
+Including headers after import is not well-supported
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-For example, the following example can be accept:
+The following example is accepted:
 
 .. code-block:: c++
 
@@ -1110,8 +1108,8 @@ For example, the following example can be accept:
       return 0;
   }
 
-but it will get rejected if we reverse the order of ``#include `` and
-``import foo;``:
+but if the order of ``#include `` and ``import foo;`` is reversed,
+then the code is currently rejected:
 
 .. code-block:: c++
 
@@ -1126,33 +1124,31 @@ but it will get rejected if we reverse the order of ``#include `` and
 
 Both of the above examples should be accepted.
 
-This is a limitation in the implementation. In the first example,
-the compiler will see and parse  first then the compiler will see the import.
-So the ODR Checking and declarations merging will happen in the deserializer.
-In the second example, the compiler will see the import first and the include second.
-As a result, the ODR Checking and declarations merging will happen in the semantic analyzer.
+This is a limitation of the implementation. In the first example, the compiler
+will see and parse ```` first then it will see the ``import``. In
+this case, ODR checking and declaration merging will happen in the
+deserializer. In the second example, the compiler will see the ``import`` first
+and the ``#include`` second which results in ODR checking and declarations
+merging happening in the semantic analyzer. This is due to a divergence in the
+implementation path. This is tracked by
+`#61465 `_.
 
-So there is divergence in the implementation path. It might be understandable that why
-the orders matter here in the case.
-(Note that "understandable" is different from "makes sense").
-
-This is tracked in: https://github.com/llvm/llvm-project/issues/61465
-
-Ignored PreferredName Attribute
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Due to a tricky problem, when Clang writes BMIs, Clang will ignore the ``preferred_name`` attribute, if any.
-This implies that the ``preferred_name`` wouldn't show in debugger or dumping.
+Ignored ``preferred_name`` Attribute
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-This is tracked in: https://github.com/llvm/llvm-project/issues/56490
+When Clang writes BMIs, it will ignore the ``preferred_name`` attribute on
+declarations which use it. Thus, the preferred name will not be displayed in
+the debugger as expected. This is tracked by
+`#56490 `_.
 
 Don't emit macros about module declaration
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-This is covered by P1857R3. We mention it again here since users may abuse it before we implement it.
+This is covered by `P1857R3 `_. It is mentioned here
+because we want users to be aware that we don't yet implement it.
 
-Someone may want to write code which could be compiled both by modules or non-modules.
-A direct idea would be use macros like:
+A direct approach to write code that can be compiled by both modules and
+non-module builds may look like:
 
 .. code-block:: c++
 
@@ -1162,39 +1158,37 @@ A direct idea would be use macros like:
   IMPORT header_name
   EXPORT ...
 
-So this file could be triggered like a module unit or a non-module unit depending on the definition
-of some macros.
-However, this kind of usage is forbidden by P1857R3 but we haven't implemented P1857R3 yet.
-This means that is possible to write illegal modules code now, and obviously this will stop working
-once P1857R3 is implemented.
-A simple suggestion would be "Don't play macro tricks with module declarations".
+The intent of this is that this file can be compiled like a module unit or a
+non-module unit depending on the definition of some macros. However, this usage
+is forbidden by P1857R3 which is not yet implemented in Clang. This means that
+is possible to write invalid modules which will no longer be accepted once
+P1857R3 is implemented. This is tracked by
+`#56917 `_.
+
+Until then, it is recommended not to mix macros with module declarations.
 
-This is tracked in: https://github.com/llvm/llvm-project/issues/56917
 
 In consistent filename suffix requirement for importable module units
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Currently, clang requires the file name of an ``importable module unit`` should end with ``.cppm``
-(or ``.ccm``, ``.cxxm``, ``.c++m``). However, the behavior is inconsistent with other compilers.
-
-This is tracked in: https://github.com/llvm/llvm-project/issues/57416
-
-clang-cl is not compatible with the standard C++ modules
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Now we can't use the `/clang:-fmodule-file` or `/clang:-fprebuilt-module-path` to specify
-the BMI within ``clang-cl.exe``.
+Currently, Clang requires the file name of an ``importable module unit`` to
+have ``.cppm`` (or ``.ccm``, ``.cxxm``, ``.c++m``) as the file extension.
+However, the behavior is inconsistent with other compilers. This is tracked by
+`#57416 `_.
 
-This is tracked in: https://github.com/llvm/llvm-project/issues/64118
+clang-cl is not compatible with standard C++ modules
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-false positive ODR violation diagnostic due to using inconsistent qualified but the same type
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+``/clang:-fmodule-file`` and ``/clang:-fprebuilt-module-path`` cannot be used
+to specify the BMI with ``clang-cl.exe``. This is tracked by
+`#64118 `_.
 
-ODR violation is a pretty common issue when using modules.
-Sometimes the program violated the One Definition Rule actually.
-But sometimes it shows the compiler gives false positive diagnostics.
+Incorrect ODR violation diagnostics
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-One often reported example is:
+ODR violations are a common issue when using modules. Clang sometimes produces
+false-positive diagnostics or fails to produce true-positive diagnostics of the
+One Definition Rule. One often-reported example is:
 
 .. code-block:: c++
 
@@ -1222,51 +1216,49 @@ One often reported example is:
   export module repro;
   export import :part;
 
-Currently the compiler complains about the inconsistent definition of `fun()` in
-2 module units. This is incorrect. Since both definitions of `fun()` has the same
-spelling and `T` refers to the same type entity finally. So the program should be
-fine.
-
-This is tracked in https://github.com/llvm/llvm-project/issues/78850.
+Currently the compiler incorrectly diagnoses the inconsistent definition of
+``fun()`` in two module units. Because both definitions of ``fun()`` have the
+same spelling and ``T`` refers to the same type entity, there is no ODR
+violation. This is tracked by
+`#78850 `_.
 
 Using TU-local entity in other units
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Module units are translation units. So the entities which should only be local to the
-module unit itself shouldn't be used by other units in any means.
+Module units are translation units, so the entities which should be local to
+the module unit itself should never be used by other units.
 
-In the language side, to address the idea formally, the language specification defines
-the concept of ``TU-local`` and ``exposure`` in
+The C++ standard defines the concept of ``TU-local`` and ``exposure`` in
 `basic.link/p14 `_,
 `basic.link/p15 `_,
 `basic.link/p16 `_,
-`basic.link/p17 `_ and
+`basic.link/p17 `_, and
 `basic.link/p18 `_.
 
-However, the compiler doesn't support these 2 ideas formally.
-This results in unclear and confusing diagnostic messages.
-And it is worse that the compiler may import TU-local entities to other units without any
-diagnostics.
+However, Clang doesn't formally support these two concepts. This results in
+unclear or confusing diagnostic messages. Further, Clang may import
+``TU-local`` entities to other units without any diagnostics. This is tracked
+by `#78173 `_.
 
-This is tracked in https://github.com/llvm/llvm-project/issues/78173.
+.. _header-units:
 
 Header Units
 ============
 
-How to build projects using header unit
----------------------------------------
+How to build projects using header units
+----------------------------------------
 
 .. warning::
 
-   The user interfaces of header units is highly experimental. There are still
-   many unanswered question about how tools should interact with header units.
-   The user interfaces described here may change after we have progress on how
-   tools should support for header units.
+   The support for header units, including related command line options, is
+   experimental. There are still many unanswered question about how tools
+   should interact with header units. The details described here may change in
+   the future.
 
 Quick Start
 ~~~~~~~~~~~
 
-For the following example,
+The following example:
 
 .. code-block:: c++
 
@@ -1275,7 +1267,7 @@ For the following example,
     std::cout << "Hello World.\n";
   }
 
-we could compile it as
+could be compiled with:
 
 .. code-block:: console
 
@@ -1285,14 +1277,14 @@ we could compile it as
 How to produce BMIs
 ~~~~~~~~~~~~~~~~~~~
 
-Similar to named modules, we could use ``--precompile`` to produce the BMI.
-But we need to specify that the input file is a header by ``-xc++-system-header`` or ``-xc++-user-header``.
+Similar to named modules, ``--precompile`` can be used to produce a BMI.
+However, that requires specifying that the input file is a header by using
+``-xc++-system-header`` or ``-xc++-user-header``.
 
-Also we could use `-fmodule-header={user,system}` option to produce the BMI for header units
-which has suffix like `.h` or `.hh`.
-The value of `-fmodule-header` means the user search path or the system search path.
-The default value for `-fmodule-header` is `user`.
-For example,
+The ``-fmodule-header={user,system}`` option can also be used to produce a BMI
+for header units which have a file extension like `.h` or `.hh`. The argument to
+``-fmodule-header`` specifies either the user search path or the system search
+path. The default value for ``-fmodule-header`` is ``user``. For example:
 
 .. code-block:: c++
 
@@ -1308,16 +1300,16 @@ For example,
     Hello();
   }
 
-We could compile it as:
+could be compiled with:
 
 .. code-block:: console
 
   $ clang++ -std=c++20 -fmodule-header foo.h -o foo.pcm
   $ clang++ -std=c++20 -fmodule-file=foo.pcm use.cpp
 
-For headers which don't have a suffix, we need to pass ``-xc++-header``
-(or ``-xc++-system-header`` or ``-xc++-user-header``) to mark it as a header.
-For example,
+For headers which do not have a file extension, ``-xc++-header`` (or
+``-xc++-system-header``, ``-xc++-user-header``) must be used to specify the
+file as a header. For example:
 
 .. code-block:: c++
 
@@ -1332,23 +1324,25 @@ For example,
   $ clang++ -std=c++20 -fmodule-header=system -xc++-header iostream -o iostream.pcm
   $ clang++ -std=c++20 -fmodule-file=iostream.pcm use.cpp
 
-How to specify the dependent BMIs
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+How to specify dependent BMIs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-We could use ``-fmodule-file`` to specify the BMIs, and this option may occur multiple times as well.
+``-fmodule-file`` can be used to specify a dependent BMI (or multiple times for
+more than one dependent BMI).
 
-With the existing implementation ``-fprebuilt-module-path`` cannot be used for header units
-(since they are nominally anonymous).
-For header units, use  ``-fmodule-file`` to include the relevant PCM file for each header unit.
+With the existing implementation, ``-fprebuilt-module-path`` cannot be used for
+header units (because they are nominally anonymous). For header units, use
+``-fmodule-file`` to include the relevant PCM file for each header unit.
 
-This is expect to be solved in future editions of the compiler either by the tooling finding and specifying
-the -fmodule-file or by the use of a module-mapper that understands how to map the header name to their PCMs.
+This is expect to be solved in a future version of Clang either by the compiler
+finding and specifying ``-fmodule-file`` automatically, or by the use of a
+module-mapper that understands how to map the header name to their PCMs.
 
-Don't compile the BMI
-~~~~~~~~~~~~~~~~~~~~~
+Compiling a header unit to an object file
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-Another difference with modules is that we can't compile the BMI from a header unit.
-For example:
+A header unit cannot be compiled to an object file due to the semantics of
+header units. For example:
 
 .. code-block:: console
 
@@ -1356,15 +1350,13 @@ For example:
   # This is not allowed!
   $ clang++ iostream.pcm -c -o iostream.o
 
-It makes sense due to the semantics of header units, which are just like headers.
-
 Include translation
 ~~~~~~~~~~~~~~~~~~~
 
-The C++ spec allows the vendors to convert ``#include header-name`` to ``import header-name;`` when possible.
-Currently, Clang would do this translation for the ``#include`` in the global module fragment.
-
-For example, the following two examples are the same:
+The C++ standard allows vendors to convert ``#include header-name`` to
+``import header-name;`` when possible. Currently, Clang does this translation
+for the ``#include`` in the global module fragment. For example, the following
+example:
 
 .. code-block:: c++
 
@@ -1375,7 +1367,7 @@ For example, the following two examples are the same:
     std::cout << "Hello.\n";
   }
 
-with the following one:
+is the same as this example:
 
 .. code-block:: c++
 
@@ -1391,17 +1383,17 @@ with the following one:
   $ clang++ -std=c++20 -xc++-system-header --precompile iostream -o iostream.pcm
   $ clang++ -std=c++20 -fmodule-file=iostream.pcm --precompile M.cppm -o M.cpp
 
-In the latter example, the Clang could find the BMI for the ````
-so it would try to replace the ``#include `` to ``import ;`` automatically.
+In the latter example, Clang can find the BMI for ```` and so it
+tries to replace the ``#include `` with ``import ;``
+automatically.
 
 
-Relationships between Clang modules
------------------------------------
+Differences between Clang modules and header units
+--------------------------------------------------
 
-Header units have pretty similar semantics with Clang modules.
-The semantics of both of them are like headers.
-
-In fact, we could even "mimic" the sytle of header units by Clang modules:
+Header units have similar semantics to Clang modules. The semantics of both are
+like headers. Therefore, header units can be mimicked by Clang modules as in
+the following example:
 
 .. code-block:: c++
 
@@ -1414,46 +1406,45 @@ In fact, we could even "mimic" the sytle of header units by Clang modules:
 
   $ clang++ -std=c++20 -fimplicit-modules -fmodule-map-file=.modulemap main.cpp
 
-It would be simpler if we are using libcxx:
+This example is simplified when using libc++:
 
 .. code-block:: console
 
   $ clang++ -std=c++20 main.cpp -fimplicit-modules -fimplicit-module-maps
 
-Since there is already one
-`module map `_
-in the source of libcxx.
-
-Then immediately leads to the question: why don't we implement header units through Clang header modules?
+because libc++ already supplies a
+`module map `_.
 
-The main reason for this is that Clang modules have more semantics like hierarchy or
-wrapping multiple headers together as a big module.
-However, these things are not part of Standard C++ Header units,
-and we want to avoid the impression that these additional semantics get interpreted as Standard C++ behavior.
+This raises the question: why are header units not implemented through Clang
+modules?
 
-Another reason is that there are proposals to introduce module mappers to the C++ standard
-(for example, https://wg21.link/p1184r2).
-If we decide to reuse Clang's modulemap, we may get in trouble once we need to introduce another module mapper.
+This is primarily because Clang modules have more hierarchical semantics when
+wrapping multiple headers together as one module, which is not supported by
+Standard C++ Header units. We want to avoid the impression that these
+additional semantics get interpreted as Standard C++ behavior.
 
-So the final answer for why we don't reuse the interface of Clang modules for header units is that
-there are some differences between header units and Clang modules and that ignoring those
-differences now would likely become a problem in the future.
+Another reason is that there are proposals to introduce module mappers to the
+C++ standard (for example, https://wg21.link/p1184r2). Reusing Clang's
+``modulemap`` may be more difficult if we need to introduce another module
+mapper.
 
-Discover Dependencies
-=====================
+Discovering Dependencies
+========================
 
-Prior to modules, all the translation units can be compiled parallelly.
-But it is not true for the module units. The presence of module units requires
-us to compile the translation units in a (topological) order.
+Without use of modules, all the translation units in a project can be compiled
+in parallel. However, the presence of module units requires compiling the
+translation units in a topological order.
 
-The clang-scan-deps scanner implemented
-`P1689 paper `_
-to describe the order. Only named modules are supported now.
+The ``clang-scan-deps`` tool can extract dependency information and produce a
+JSON file conforming to the specification described in
+`P1689 `_.
+Only named modules are supported currently.
 
-We need a compilation database to use clang-scan-deps. See
+A compilation database is needed when using ``clang-scan-deps``. See
 `JSON Compilation Database Format Specification `_
-for example. Note that the ``output`` entry is necessary for clang-scan-deps
-to scan P1689 format. Here is an example:
+for more information about compilation databases. Note that the ``output``
+JSON attribute is necessary for ``clang-scan-deps`` to scan using the P1689
+format. For example:
 
 .. code-block:: c++
 
@@ -1533,13 +1524,13 @@ And here is the compilation database:
   }
   ]
 
-And we can get the dependency information in P1689 format by:
+To get the dependency information in P1689 format, use:
 
 .. code-block:: console
 
   $ clang-scan-deps -format=p1689 -compilation-database P1689.json
 
-And we will get:
+to get:
 
 .. code-block:: text
 
@@ -1619,14 +1610,14 @@ And we will get:
 
 See the P1689 paper for the meaning of the fields.
 
-And if the user want a finer-grained control for any reason, e.g., to scan the generated source files,
-the user can choose to get the dependency information per file. For example:
+Getting dependency information per file with finer-grained control (such as
+scanning generated source files) is possible. For example:
 
 .. code-block:: console
 
   $ clang-scan-deps -format=p1689 -- /clang++ -std=c++20 impl_part.cppm -c -o impl_part.o
 
-And we'll get:
+will produce:
 
 .. code-block:: text
 
@@ -1652,22 +1643,23 @@ And we'll get:
     "version": 1
   }
 
-In this way, we can pass the single command line options after the ``--``.
-Then clang-scan-deps will extract the necessary information from the options.
-Note that we need to specify the path to the compiler executable instead of saying
-``clang++`` simply.
+Individual command line options can be specified after ``--``.
+``clang-scan-deps`` will extract the necessary information from the specified
+options. Note that the path to the compiler executable needs to be specified
+explicitly instead of using ``clang++`` directly.
 
-The users may want the scanner to get the transitional dependency information for headers.
-Otherwise, the users have to scan twice for the project, once for headers and once for modules.
-To address the requirement, clang-scan-deps will recognize the specified preprocessor options
-in the given command line and generate the corresponding dependency information. For example,
+Users may want the scanner to get the transitional dependency information for
+headers. Otherwise, the project has to be scanned twice, once for headers and
+once for modules. To address this, ``clang-scan-deps`` will recognize the
+specified preprocessor options in the given command line and generate the
+corresponding dependency information. For example:
 
 .. code-block:: console
 
   $ clang-scan-deps -format=p1689 -- ../bin/clang++ -std=c++20 impl_part.cppm -c -o impl_part.o -MD -MT impl_part.ddi -MF impl_part.dep
   $ cat impl_part.dep
 
-We will get:
+will produce:
 
 .. code-block:: text
 
@@ -1679,41 +1671,41 @@ We will get:
     /usr/include/bits/types/__locale_t.h \
     ...
 
-When clang-scan-deps detects ``-MF`` option, clang-scan-deps will try to write the
+When ``clang-scan-deps`` detects the ``-MF`` option, it will try to write the
 dependency information for headers to the file specified by ``-MF``.
 
 Possible Issues: Failed to find system headers
 ----------------------------------------------
 
-In case the users encounter errors like ``fatal error: 'stddef.h' file not found``,
-probably the specified ``/clang++`` refers to a symlink
-instead a real binary. There are 4 potential solutions to the problem:
-
-* (1) End users can resolve the issue by pointing the specified compiler executable to
-  the real binary instead of the symlink.
-* (2) End users can invoke ``/clang++ -print-resource-dir``
-  to get the corresponding resource directory for your compiler and add that directory
-  to the include search paths manually in the build scripts.
-* (3) Build systems that use a compilation database as the input for clang-scan-deps
-  scanner, the build system can add the flag ``--resource-dir-recipe invoke-compiler`` to
-  the clang-scan-deps scanner to calculate the resources directory dynamically.
-  The calculation happens only once for a unique ``/clang++``.
-* (4) For build systems that invokes the clang-scan-deps scanner per file, repeatedly
-  calculating the resource directory may be inefficient. In such cases, the build
-  system can cache the resource directory by itself and pass ``-resource-dir ``
-  explicitly in the command line options:
+If encountering an error like ``fatal error: 'stddef.h' file not found``,
+the specified ``/clang++`` probably refers to a
+symlink instead a real binary. There are four potential solutions to the
+problem:
 
-.. code-block:: console
+1. Point the specified compiler executable to the real binary instead of the
+   symlink.
+2. Invoke ``/clang++ -print-resource-dir`` to get
+   the corresponding resource directory for your compiler and add that
+   directory to the include search paths manually in the build scripts.
+3. For build systems that use a compilation database as the input for
+   ``clang-scan-deps``, the build system can add the
+   ``--resource-dir-recipe invoke-compiler`` option when executing
+   ``clang-scan-deps`` to calculate the resource directory dynamically.
+   The calculation happens only once for a unique ``/clang++``.
+4. For build systems that invoke ``clang-scan-deps`` per file, repeatedly
+   calculating the resource directory may be inefficient. In such cases, the
+   build system can cache the resource directory and specify
+   ``-resource-dir `` explicitly, as in:
+
+   .. code-block:: console
 
-  $ clang-scan-deps -format=p1689 -- /clang++ -std=c++20 -resource-dir  mod.cppm -c -o mod.o
+     $ clang-scan-deps -format=p1689 -- /clang++ -std=c++20 -resource-dir  mod.cppm -c -o mod.o
 
 
 Import modules with clang-repl
 ==============================
 
-We're able to import C++20 named modules with clang-repl.
-
-Let's start with a simple example:
+``clang-repl`` supports importing C++20 named modules. For example:
 
 .. code-block:: c++
 
@@ -1723,7 +1715,7 @@ Let's start with a simple example:
       return "Hello Interpreter for Modules!";
   }
 
-We still need to compile the named module in ahead.
+The named module still needs to be compiled ahead of time.
 
 .. code-block:: console
 
@@ -1731,10 +1723,9 @@ We still need to compile the named module in ahead.
   $ clang++ M.pcm -c -o M.o
   $ clang++ -shared M.o -o libM.so
 
-Note that we need to compile the module unit into a dynamic library so that the clang-repl
-can load the object files of the module units.
-
-Then we are able to import module ``M`` in clang-repl.
+Note that the module unit needs to be compiled as a dynamic library so that
+``clang-repl`` can load the object files of the module units. Then it is
+possible to import module ``M`` in clang-repl.
 
 .. code-block:: console
 
@@ -1753,17 +1744,18 @@ Possible Questions
 How modules speed up compilation
 --------------------------------
 
-A classic theory for the reason why modules speed up the compilation is:
-if there are ``n`` headers and ``m`` source files and each header is included by each source file,
-then the complexity of the compilation is ``O(n*m)``;
-But if there are ``n`` module interfaces and ``m`` source files, the complexity of the compilation is
-``O(n+m)``. So, using modules would be a big win when scaling.
-In a simpler word, we could get rid of many redundant compilations by using modules.
+A classic theory for the reason why modules speed up the compilation is: if
+there are ``n`` headers and ``m`` source files and each header is included by
+each source file, then the complexity of the compilation is ``O(n*m)``.
+However, if there are ``n`` module interfaces and ``m`` source files, the
+complexity of the compilation is ``O(n+m)``. Therefore, using modules would be
+a significant improvement at scale. More simply, use of modules causes many of
+the redundant compilations to no longer be necessary.
 
-Roughly, this theory is correct. But the problem is that it is too rough.
-The behavior depends on the optimization level, as we will illustrate below.
+While this is accurate at a high level, this depends greatly on the
+optimization level, as illustrated below.
 
-First is ``O0``. The compilation process is described in the following graph.
+First is ``-O0``. The compilation process is described in the following graph.
 
 .. code-block:: none
 
@@ -1771,13 +1763,13 @@ First is ``O0``. The compilation process is described in the following graph.
   │                               │                                       │               │
   └---parsing----sema----codegen--┴----- transformations ---- codegen ----┴---- codegen --┘
 
-  ┌---------------------------------------------------------------------------------------┐
+  ├---------------------------------------------------------------------------------------┐
   |                                                                                       │
   |                                     source file                                       │
   |                                                                                       │
   └---------------------------------------------------------------------------------------┘
 
-              ┌--------┐
+              ├--------┐
               │        │
               │imported│
               │        │
@@ -1785,18 +1777,17 @@ First is ``O0``. The compilation process is described in the following graph.
               │        │
               └--------┘
 
-Here we can see that the source file (could be a non-module unit or a module unit) would get processed by the
-whole pipeline.
-But the imported code would only get involved in semantic analysis, which is mainly about name lookup,
-overload resolution and template instantiation.
-All of these processes are fast relative to the whole compilation process.
-More importantly, the imported code only needs to be processed once in frontend code generation,
-as well as the whole middle end and backend.
-So we could get a big win for the compilation time in O0.
+In this case, the source file (which could be a non-module unit or a module
+unit) would get processed by the entire pipeline. However, the imported code
+would only get involved in semantic analysis, which, for the most part, is name
+lookup, overload resolution, and template instantiation. All of these processes
+are fast relative to the whole compilation process. More importantly, the
+imported code only needs to be processed once during frontend code generation,
+as well as the whole middle end and backend. So we could get a big win for the
+compilation time in ``-O0``.
 
-But with optimizations, things are different:
-
-(we omit ``code generation`` part for each end due to the limited space)
+But with optimizations, things are different (the ``code generation`` part for
+each end is omitted due to limited space):
 
 .. code-block:: none
 
@@ -1804,12 +1795,12 @@ But with optimizations, things are different:
   │                           │                                               │                   │
   └--- parsing ---- sema -----┴--- optimizations --- IPO ---- optimizations---┴--- optimizations -┘
 
-  ┌-----------------------------------------------------------------------------------------------┐
+  ├-----------------------------------------------------------------------------------------------┐
   │                                                                                               │
   │                                         source file                                           │
   │                                                                                               │
   └-----------------------------------------------------------------------------------------------┘
-                ┌---------------------------------------┐
+                ├---------------------------------------┐
                 │                                       │
                 │                                       │
                 │            imported code              │
@@ -1817,27 +1808,29 @@ But with optimizations, things are different:
                 │                                       │
                 └---------------------------------------┘
 
-It would be very unfortunate if we end up with worse performance after using modules.
-The main concern is that when we compile a source file, the compiler needs to see the function body
-of imported module units so that it can perform IPO (InterProcedural Optimization, primarily inlining
-in practice) to optimize functions in current source file with the help of the information provided by
-the imported module units.
-In other words, the imported code would be processed again and again in importee units
-by optimizations (including IPO itself).
-The optimizations before IPO and the IPO itself are the most time-consuming part in whole compilation process.
-So from this perspective, we might not be able to get the improvements described in the theory.
-But we could still save the time for optimizations after IPO and the whole backend.
-
-Overall, at ``O0`` the implementations of functions defined in a module will not impact module users,
-but at higher optimization levels the definitions of such functions are provided to user compilations for the
-purposes of optimization (but definitions of these functions are still not included in the use's object file)-
-this means the build speedup at higher optimization levels may be lower than expected given ``O0`` experience,
-but does provide by more optimization opportunities.
+It would be very unfortunate if we end up with worse performance when using
+modules. The main concern is that when a source file is compiled, the compiler
+needs to see the body of imported module units so that it can perform IPO
+(InterProcedural Optimization, primarily inlining in practice) to optimize
+functions in the current source file with the help of the information provided
+by the imported module units. In other words, the imported code would be
+processed again and again in importee units by optimizations (including IPO
+itself). The optimizations before IPO and IPO itself are the most time-consuming
+part in whole compilation process. So from this perspective, it might not be
+possible to get the compile time improvements described, but there could be
+time savings for optimizations after IPO and the whole backend.
+
+Overall, at ``-O0`` the implementations of functions defined in a module will
+not impact module users, but at higher optimization levels the definitions of
+such functions are provided to user compilations for the purposes of
+optimization (but definitions of these functions are still not included in the
+use's object file). This means the build speedup at higher optimization levels
+may be lower than expected given ``-O0`` experience, but does provide more
+optimization opportunities.
 
 Interoperability with Clang Modules
 -----------------------------------
 
-We **wish** to support clang modules and standard c++ modules at the same time,
-but the mixed using form is not well used/tested yet.
-
-Please file new github issues as you find interoperability problems.
+We **wish** to support Clang modules and standard C++ modules at the same time,
+but the mixing them together is not well used/tested yet. Please file new
+GitHub issues as you find interoperability problems.
diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst
index 370de7d9c769e8173b7dc3ddcc6f70d9e12ef115..80ba70f67126fa23543819655e98e2fcb7d46a32 100644
--- a/clang/docs/UsersManual.rst
+++ b/clang/docs/UsersManual.rst
@@ -3504,7 +3504,7 @@ Differences between ``*17`` and ``*23`` modes:
 - ``nullptr`` and ``nullptr_t`` are supported, only in ``*23`` mode.
 - ``ATOMIC_VAR_INIT`` is removed from ``*23`` mode.
 - ``bool``, ``true``, ``false``, ``alignas``, ``alignof``, ``static_assert``,
-  and ``thread_local` are now first-class keywords, only in ``*23`` mode.
+  and ``thread_local`` are now first-class keywords, only in ``*23`` mode.
 - ``typeof`` and ``typeof_unqual`` are supported, only ``*23`` mode.
 - Bit-precise integers (``_BitInt(N)``) are supported by default in ``*23``
   mode, and as an extension in ``*17`` and earlier modes.
diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst
index 0d87df36ced0e91fdd6953ca4e5e352ea5e16c4d..eb8b58323da4d783695c73310f717cb32feb2d05 100644
--- a/clang/docs/analyzer/checkers.rst
+++ b/clang/docs/analyzer/checkers.rst
@@ -3033,13 +3033,6 @@ Further examples of injection vulnerabilities this checker can find.
     sprintf(buf, s); // warn: untrusted data used as a format string
   }
 
-  void test() {
-    size_t ts;
-    scanf("%zd", &ts); // 'ts' marked as tainted
-    int *p = (int *)malloc(ts * sizeof(int));
-      // warn: untrusted data used as buffer size
-  }
-
 There are built-in sources, propagations and sinks even if no external taint
 configuration is provided.
 
@@ -3067,9 +3060,7 @@ Default propagations rules:
 
 Default sinks:
  ``printf``, ``setproctitle``, ``system``, ``popen``, ``execl``, ``execle``,
- ``execlp``, ``execv``, ``execvp``, ``execvP``, ``execve``, ``dlopen``,
- ``memcpy``, ``memmove``, ``strncpy``, ``strndup``, ``malloc``, ``calloc``,
- ``alloca``, ``memccpy``, ``realloc``, ``bcopy``
+ ``execlp``, ``execv``, ``execvp``, ``execvP``, ``execve``, ``dlopen``
 
 Please note that there are no built-in filter functions.
 
diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt
index 2252d0ccde96d235a7e45df500ee14a77cfc4340..b747adfb6992e3bc75d17e575457ab47fce07115 100644
--- a/clang/docs/tools/clang-formatted-files.txt
+++ b/clang/docs/tools/clang-formatted-files.txt
@@ -252,7 +252,6 @@ clang/include/clang/Tooling/CompilationDatabasePluginRegistry.h
 clang/include/clang/Tooling/DiagnosticsYaml.h
 clang/include/clang/Tooling/Execution.h
 clang/include/clang/Tooling/JSONCompilationDatabase.h
-clang/include/clang/Tooling/NodeIntrospection.h
 clang/include/clang/Tooling/Refactoring.h
 clang/include/clang/Tooling/StandaloneExecution.h
 clang/include/clang/Tooling/ToolExecutorPluginRegistry.h
@@ -562,15 +561,11 @@ clang/lib/Tooling/Execution.cpp
 clang/lib/Tooling/ExpandResponseFilesCompilationDatabase.cpp
 clang/lib/Tooling/FixIt.cpp
 clang/lib/Tooling/GuessTargetAndModeCompilationDatabase.cpp
-clang/lib/Tooling/NodeIntrospection.cpp
 clang/lib/Tooling/StandaloneExecution.cpp
 clang/lib/Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
 clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp
 clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
 clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp
-clang/lib/Tooling/DumpTool/APIData.h
-clang/lib/Tooling/DumpTool/ASTSrcLocProcessor.h
-clang/lib/Tooling/DumpTool/ClangSrcLocDump.cpp
 clang/lib/Tooling/Inclusions/HeaderIncludes.cpp
 clang/lib/Tooling/Inclusions/IncludeStyle.cpp
 clang/lib/Tooling/Inclusions/StandardLibrary.cpp
@@ -632,11 +627,12 @@ clang/unittests/Analysis/FlowSensitive/MapLatticeTest.cpp
 clang/unittests/Analysis/FlowSensitive/MatchSwitchTest.cpp
 clang/unittests/Analysis/FlowSensitive/MultiVarConstantPropagationTest.cpp
 clang/unittests/Analysis/FlowSensitive/SingleVarConstantPropagationTest.cpp
-clang/unittests/Analysis/FlowSensitive/SolverTest.cpp
+clang/unittests/Analysis/FlowSensitive/SolverTest.h
 clang/unittests/Analysis/FlowSensitive/TestingSupport.cpp
 clang/unittests/Analysis/FlowSensitive/TestingSupport.h
 clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp
 clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
+clang/unittests/Analysis/FlowSensitive/WatchedLiteralsSolverTest.cpp
 clang/unittests/AST/ASTImporterFixtures.cpp
 clang/unittests/AST/ASTImporterFixtures.h
 clang/unittests/AST/ASTImporterObjCTest.cpp
diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 6dbd06251ddad69d94ba95c5f57b061e775968cf..2ce2b810d3636498cb8f8fe27a427d22cb0ee612 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1116,7 +1116,8 @@ public:
   CanQualType BFloat16Ty;
   CanQualType Float16Ty; // C11 extension ISO/IEC TS 18661-3
   CanQualType VoidPtrTy, NullPtrTy;
-  CanQualType DependentTy, OverloadTy, BoundMemberTy, UnknownAnyTy;
+  CanQualType DependentTy, OverloadTy, BoundMemberTy, UnresolvedTemplateTy,
+      UnknownAnyTy;
   CanQualType BuiltinFnTy;
   CanQualType PseudoObjectTy, ARCUnbridgedCastTy;
   CanQualType ObjCBuiltinIdTy, ObjCBuiltinClassTy, ObjCBuiltinSelTy;
@@ -2610,7 +2611,7 @@ public:
   ///
   /// \returns if this is an array type, the completely unqualified array type
   /// that corresponds to it. Otherwise, returns T.getUnqualifiedType().
-  QualType getUnqualifiedArrayType(QualType T, Qualifiers &Quals);
+  QualType getUnqualifiedArrayType(QualType T, Qualifiers &Quals) const;
 
   /// Determine whether the given types are equivalent after
   /// cvr-qualifiers have been removed.
diff --git a/clang/include/clang/AST/BuiltinTypes.def b/clang/include/clang/AST/BuiltinTypes.def
index 0a36fdc5d9c0f7ee7f12405d7bf04f2fd7aef666..444be4311a7431ab56a2f828a31d03a6303b84ac 100644
--- a/clang/include/clang/AST/BuiltinTypes.def
+++ b/clang/include/clang/AST/BuiltinTypes.def
@@ -285,6 +285,9 @@ PLACEHOLDER_TYPE(Overload, OverloadTy)
 //   x->foo       # if only contains non-static members
 PLACEHOLDER_TYPE(BoundMember, BoundMemberTy)
 
+// The type of an unresolved template. Used in UnresolvedLookupExpr.
+PLACEHOLDER_TYPE(UnresolvedTemplate, UnresolvedTemplateTy)
+
 // The type of an expression which refers to a pseudo-object,
 // such as those introduced by Objective C's @property or
 // VS.NET's __property declarations.  A placeholder type.  The
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index a53c27a99a8c3645c48c8ff2554e0ebf67cd38f1..5e485ccb85a1391c936b0ec803c96d927caa5033 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -2096,13 +2096,12 @@ private:
   ///
   /// \param PointOfInstantiation point at which the function template
   /// specialization was first instantiated.
-  void setFunctionTemplateSpecialization(ASTContext &C,
-                                         FunctionTemplateDecl *Template,
-                                       const TemplateArgumentList *TemplateArgs,
-                                         void *InsertPos,
-                                         TemplateSpecializationKind TSK,
-                          const TemplateArgumentListInfo *TemplateArgsAsWritten,
-                                         SourceLocation PointOfInstantiation);
+  void setFunctionTemplateSpecialization(
+      ASTContext &C, FunctionTemplateDecl *Template,
+      TemplateArgumentList *TemplateArgs, void *InsertPos,
+      TemplateSpecializationKind TSK,
+      const TemplateArgumentListInfo *TemplateArgsAsWritten,
+      SourceLocation PointOfInstantiation);
 
   /// Specify that this record is an instantiation of the
   /// member function FD.
@@ -2981,12 +2980,12 @@ public:
   ///
   /// \param PointOfInstantiation point at which the function template
   /// specialization was first instantiated.
-  void setFunctionTemplateSpecialization(FunctionTemplateDecl *Template,
-                const TemplateArgumentList *TemplateArgs,
-                void *InsertPos,
-                TemplateSpecializationKind TSK = TSK_ImplicitInstantiation,
-                const TemplateArgumentListInfo *TemplateArgsAsWritten = nullptr,
-                SourceLocation PointOfInstantiation = SourceLocation()) {
+  void setFunctionTemplateSpecialization(
+      FunctionTemplateDecl *Template, TemplateArgumentList *TemplateArgs,
+      void *InsertPos,
+      TemplateSpecializationKind TSK = TSK_ImplicitInstantiation,
+      TemplateArgumentListInfo *TemplateArgsAsWritten = nullptr,
+      SourceLocation PointOfInstantiation = SourceLocation()) {
     setFunctionTemplateSpecialization(getASTContext(), Template, TemplateArgs,
                                       InsertPos, TSK, TemplateArgsAsWritten,
                                       PointOfInstantiation);
@@ -5049,6 +5048,11 @@ static constexpr StringRef getOpenMPVariantManglingSeparatorStr() {
   return "$ompvariant";
 }
 
+/// Returns whether the given FunctionDecl has an __arm[_locally]_streaming
+/// attribute.
+bool IsArmStreamingFunction(const FunctionDecl *FD,
+                            bool IncludeLocallyStreaming);
+
 } // namespace clang
 
 #endif // LLVM_CLANG_AST_DECL_H
diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h
index 3ee03eebdb8ca45d48358b8e52d2cce85553c5bf..f3d6a321ecf104c279a0b855f4e21c46474e7596 100644
--- a/clang/include/clang/AST/DeclTemplate.h
+++ b/clang/include/clang/AST/DeclTemplate.h
@@ -478,7 +478,7 @@ class FunctionTemplateSpecializationInfo final
 public:
   /// The template arguments used to produce the function template
   /// specialization from the function template.
-  const TemplateArgumentList *TemplateArguments;
+  TemplateArgumentList *TemplateArguments;
 
   /// The template arguments as written in the sources, if provided.
   /// FIXME: Normally null; tail-allocate this.
@@ -491,7 +491,7 @@ public:
 private:
   FunctionTemplateSpecializationInfo(
       FunctionDecl *FD, FunctionTemplateDecl *Template,
-      TemplateSpecializationKind TSK, const TemplateArgumentList *TemplateArgs,
+      TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
       const ASTTemplateArgumentListInfo *TemplateArgsAsWritten,
       SourceLocation POI, MemberSpecializationInfo *MSInfo)
       : Function(FD, MSInfo ? true : false), Template(Template, TSK - 1),
@@ -511,8 +511,7 @@ public:
 
   static FunctionTemplateSpecializationInfo *
   Create(ASTContext &C, FunctionDecl *FD, FunctionTemplateDecl *Template,
-         TemplateSpecializationKind TSK,
-         const TemplateArgumentList *TemplateArgs,
+         TemplateSpecializationKind TSK, TemplateArgumentList *TemplateArgs,
          const TemplateArgumentListInfo *TemplateArgsAsWritten,
          SourceLocation POI, MemberSpecializationInfo *MSInfo);
 
@@ -1776,6 +1775,25 @@ public:
   BuiltinTemplateKind getBuiltinTemplateKind() const { return BTK; }
 };
 
+/// Provides information about an explicit instantiation of a variable or class
+/// template.
+struct ExplicitInstantiationInfo {
+  /// The template arguments as written..
+  const ASTTemplateArgumentListInfo *TemplateArgsAsWritten = nullptr;
+
+  /// The location of the extern keyword.
+  SourceLocation ExternKeywordLoc;
+
+  /// The location of the template keyword.
+  SourceLocation TemplateKeywordLoc;
+
+  ExplicitInstantiationInfo() = default;
+};
+
+using SpecializationOrInstantiationInfo =
+    llvm::PointerUnion;
+
 /// Represents a class template specialization, which refers to
 /// a class template with a given set of template arguments.
 ///
@@ -1789,8 +1807,8 @@ public:
 /// template<>
 /// class array { }; // class template specialization array
 /// \endcode
-class ClassTemplateSpecializationDecl
-  : public CXXRecordDecl, public llvm::FoldingSetNode {
+class ClassTemplateSpecializationDecl : public CXXRecordDecl,
+                                        public llvm::FoldingSetNode {
   /// Structure that stores information about a class template
   /// specialization that was instantiated from a class template partial
   /// specialization.
@@ -1808,23 +1826,9 @@ class ClassTemplateSpecializationDecl
   llvm::PointerUnion
     SpecializedTemplate;
 
-  /// Further info for explicit template specialization/instantiation.
-  struct ExplicitSpecializationInfo {
-    /// The type-as-written.
-    TypeSourceInfo *TypeAsWritten = nullptr;
-
-    /// The location of the extern keyword.
-    SourceLocation ExternLoc;
-
-    /// The location of the template keyword.
-    SourceLocation TemplateKeywordLoc;
-
-    ExplicitSpecializationInfo() = default;
-  };
-
   /// Further info for explicit template specialization/instantiation.
   /// Does not apply to implicit specializations.
-  ExplicitSpecializationInfo *ExplicitInfo = nullptr;
+  SpecializationOrInstantiationInfo ExplicitInfo = nullptr;
 
   /// The template arguments used to describe this specialization.
   const TemplateArgumentList *TemplateArgs;
@@ -2001,44 +2005,49 @@ public:
     SpecializedTemplate = TemplDecl;
   }
 
-  /// Sets the type of this specialization as it was written by
-  /// the user. This will be a class template specialization type.
-  void setTypeAsWritten(TypeSourceInfo *T) {
-    if (!ExplicitInfo)
-      ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
-    ExplicitInfo->TypeAsWritten = T;
+  /// Retrieve the template argument list as written in the sources,
+  /// if any.
+  const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
+    if (auto *Info = ExplicitInfo.dyn_cast())
+      return Info->TemplateArgsAsWritten;
+    return ExplicitInfo.get();
   }
 
-  /// Gets the type of this specialization as it was written by
-  /// the user, if it was so written.
-  TypeSourceInfo *getTypeAsWritten() const {
-    return ExplicitInfo ? ExplicitInfo->TypeAsWritten : nullptr;
+  /// Set the template argument list as written in the sources.
+  void
+  setTemplateArgsAsWritten(const ASTTemplateArgumentListInfo *ArgsWritten) {
+    if (auto *Info = ExplicitInfo.dyn_cast())
+      Info->TemplateArgsAsWritten = ArgsWritten;
+    else
+      ExplicitInfo = ArgsWritten;
   }
 
-  /// Gets the location of the extern keyword, if present.
-  SourceLocation getExternLoc() const {
-    return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation();
+  /// Set the template argument list as written in the sources.
+  void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
+    setTemplateArgsAsWritten(
+        ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
   }
 
-  /// Sets the location of the extern keyword.
-  void setExternLoc(SourceLocation Loc) {
-    if (!ExplicitInfo)
-      ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
-    ExplicitInfo->ExternLoc = Loc;
+  /// Gets the location of the extern keyword, if present.
+  SourceLocation getExternKeywordLoc() const {
+    if (auto *Info = ExplicitInfo.dyn_cast())
+      return Info->ExternKeywordLoc;
+    return SourceLocation();
   }
 
-  /// Sets the location of the template keyword.
-  void setTemplateKeywordLoc(SourceLocation Loc) {
-    if (!ExplicitInfo)
-      ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
-    ExplicitInfo->TemplateKeywordLoc = Loc;
-  }
+  /// Sets the location of the extern keyword.
+  void setExternKeywordLoc(SourceLocation Loc);
 
   /// Gets the location of the template keyword, if present.
   SourceLocation getTemplateKeywordLoc() const {
-    return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
+    if (auto *Info = ExplicitInfo.dyn_cast())
+      return Info->TemplateKeywordLoc;
+    return SourceLocation();
   }
 
+  /// Sets the location of the template keyword.
+  void setTemplateKeywordLoc(SourceLocation Loc);
+
   SourceRange getSourceRange() const override LLVM_READONLY;
 
   void Profile(llvm::FoldingSetNodeID &ID) const {
@@ -2066,10 +2075,6 @@ class ClassTemplatePartialSpecializationDecl
   /// The list of template parameters
   TemplateParameterList* TemplateParams = nullptr;
 
-  /// The source info for the template arguments as written.
-  /// FIXME: redundant with TypeAsWritten?
-  const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
-
   /// The class template partial specialization from which this
   /// class template partial specialization was instantiated.
   ///
@@ -2078,15 +2083,11 @@ class ClassTemplatePartialSpecializationDecl
   llvm::PointerIntPair
       InstantiatedFromMember;
 
-  ClassTemplatePartialSpecializationDecl(ASTContext &Context, TagKind TK,
-                                         DeclContext *DC,
-                                         SourceLocation StartLoc,
-                                         SourceLocation IdLoc,
-                                         TemplateParameterList *Params,
-                                         ClassTemplateDecl *SpecializedTemplate,
-                                         ArrayRef Args,
-                               const ASTTemplateArgumentListInfo *ArgsAsWritten,
-                               ClassTemplatePartialSpecializationDecl *PrevDecl);
+  ClassTemplatePartialSpecializationDecl(
+      ASTContext &Context, TagKind TK, DeclContext *DC, SourceLocation StartLoc,
+      SourceLocation IdLoc, TemplateParameterList *Params,
+      ClassTemplateDecl *SpecializedTemplate, ArrayRef Args,
+      ClassTemplatePartialSpecializationDecl *PrevDecl);
 
   ClassTemplatePartialSpecializationDecl(ASTContext &C)
     : ClassTemplateSpecializationDecl(C, ClassTemplatePartialSpecialization),
@@ -2101,11 +2102,8 @@ public:
   static ClassTemplatePartialSpecializationDecl *
   Create(ASTContext &Context, TagKind TK, DeclContext *DC,
          SourceLocation StartLoc, SourceLocation IdLoc,
-         TemplateParameterList *Params,
-         ClassTemplateDecl *SpecializedTemplate,
-         ArrayRef Args,
-         const TemplateArgumentListInfo &ArgInfos,
-         QualType CanonInjectedType,
+         TemplateParameterList *Params, ClassTemplateDecl *SpecializedTemplate,
+         ArrayRef Args, QualType CanonInjectedType,
          ClassTemplatePartialSpecializationDecl *PrevDecl);
 
   static ClassTemplatePartialSpecializationDecl *
@@ -2136,11 +2134,6 @@ public:
     return TemplateParams->hasAssociatedConstraints();
   }
 
-  /// Get the template arguments as written.
-  const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
-    return ArgsAsWritten;
-  }
-
   /// Retrieve the member class template partial specialization from
   /// which this particular class template partial specialization was
   /// instantiated.
@@ -2193,7 +2186,7 @@ public:
   /// template<> template
   /// struct X::Inner { /* ... */ };
   /// \endcode
-  bool isMemberSpecialization() {
+  bool isMemberSpecialization() const {
     const auto *First =
         cast(getFirstDecl());
     return First->InstantiatedFromMember.getInt();
@@ -2216,6 +2209,8 @@ public:
              ->getInjectedSpecializationType();
   }
 
+  SourceRange getSourceRange() const override LLVM_READONLY;
+
   void Profile(llvm::FoldingSetNodeID &ID) const {
     Profile(ID, getTemplateArgs().asArray(), getTemplateParameters(),
             getASTContext());
@@ -2613,27 +2608,12 @@ class VarTemplateSpecializationDecl : public VarDecl,
   llvm::PointerUnion
   SpecializedTemplate;
 
-  /// Further info for explicit template specialization/instantiation.
-  struct ExplicitSpecializationInfo {
-    /// The type-as-written.
-    TypeSourceInfo *TypeAsWritten = nullptr;
-
-    /// The location of the extern keyword.
-    SourceLocation ExternLoc;
-
-    /// The location of the template keyword.
-    SourceLocation TemplateKeywordLoc;
-
-    ExplicitSpecializationInfo() = default;
-  };
-
   /// Further info for explicit template specialization/instantiation.
   /// Does not apply to implicit specializations.
-  ExplicitSpecializationInfo *ExplicitInfo = nullptr;
+  SpecializationOrInstantiationInfo ExplicitInfo = nullptr;
 
   /// The template arguments used to describe this specialization.
   const TemplateArgumentList *TemplateArgs;
-  const ASTTemplateArgumentListInfo *TemplateArgsInfo = nullptr;
 
   /// The point where this template was instantiated (if any).
   SourceLocation PointOfInstantiation;
@@ -2687,14 +2667,6 @@ public:
   /// specialization.
   const TemplateArgumentList &getTemplateArgs() const { return *TemplateArgs; }
 
-  // TODO: Always set this when creating the new specialization?
-  void setTemplateArgsInfo(const TemplateArgumentListInfo &ArgsInfo);
-  void setTemplateArgsInfo(const ASTTemplateArgumentListInfo *ArgsInfo);
-
-  const ASTTemplateArgumentListInfo *getTemplateArgsInfo() const {
-    return TemplateArgsInfo;
-  }
-
   /// Determine the kind of specialization that this
   /// declaration represents.
   TemplateSpecializationKind getSpecializationKind() const {
@@ -2798,44 +2770,49 @@ public:
     SpecializedTemplate = TemplDecl;
   }
 
-  /// Sets the type of this specialization as it was written by
-  /// the user.
-  void setTypeAsWritten(TypeSourceInfo *T) {
-    if (!ExplicitInfo)
-      ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
-    ExplicitInfo->TypeAsWritten = T;
+  /// Retrieve the template argument list as written in the sources,
+  /// if any.
+  const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
+    if (auto *Info = ExplicitInfo.dyn_cast())
+      return Info->TemplateArgsAsWritten;
+    return ExplicitInfo.get();
+  }
+
+  /// Set the template argument list as written in the sources.
+  void
+  setTemplateArgsAsWritten(const ASTTemplateArgumentListInfo *ArgsWritten) {
+    if (auto *Info = ExplicitInfo.dyn_cast())
+      Info->TemplateArgsAsWritten = ArgsWritten;
+    else
+      ExplicitInfo = ArgsWritten;
   }
 
-  /// Gets the type of this specialization as it was written by
-  /// the user, if it was so written.
-  TypeSourceInfo *getTypeAsWritten() const {
-    return ExplicitInfo ? ExplicitInfo->TypeAsWritten : nullptr;
+  /// Set the template argument list as written in the sources.
+  void setTemplateArgsAsWritten(const TemplateArgumentListInfo &ArgsInfo) {
+    setTemplateArgsAsWritten(
+        ASTTemplateArgumentListInfo::Create(getASTContext(), ArgsInfo));
   }
 
   /// Gets the location of the extern keyword, if present.
-  SourceLocation getExternLoc() const {
-    return ExplicitInfo ? ExplicitInfo->ExternLoc : SourceLocation();
+  SourceLocation getExternKeywordLoc() const {
+    if (auto *Info = ExplicitInfo.dyn_cast())
+      return Info->ExternKeywordLoc;
+    return SourceLocation();
   }
 
   /// Sets the location of the extern keyword.
-  void setExternLoc(SourceLocation Loc) {
-    if (!ExplicitInfo)
-      ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
-    ExplicitInfo->ExternLoc = Loc;
-  }
-
-  /// Sets the location of the template keyword.
-  void setTemplateKeywordLoc(SourceLocation Loc) {
-    if (!ExplicitInfo)
-      ExplicitInfo = new (getASTContext()) ExplicitSpecializationInfo;
-    ExplicitInfo->TemplateKeywordLoc = Loc;
-  }
+  void setExternKeywordLoc(SourceLocation Loc);
 
   /// Gets the location of the template keyword, if present.
   SourceLocation getTemplateKeywordLoc() const {
-    return ExplicitInfo ? ExplicitInfo->TemplateKeywordLoc : SourceLocation();
+    if (auto *Info = ExplicitInfo.dyn_cast())
+      return Info->TemplateKeywordLoc;
+    return SourceLocation();
   }
 
+  /// Sets the location of the template keyword.
+  void setTemplateKeywordLoc(SourceLocation Loc);
+
   SourceRange getSourceRange() const override LLVM_READONLY;
 
   void Profile(llvm::FoldingSetNodeID &ID) const {
@@ -2863,10 +2840,6 @@ class VarTemplatePartialSpecializationDecl
   /// The list of template parameters
   TemplateParameterList *TemplateParams = nullptr;
 
-  /// The source info for the template arguments as written.
-  /// FIXME: redundant with TypeAsWritten?
-  const ASTTemplateArgumentListInfo *ArgsAsWritten = nullptr;
-
   /// The variable template partial specialization from which this
   /// variable template partial specialization was instantiated.
   ///
@@ -2879,8 +2852,7 @@ class VarTemplatePartialSpecializationDecl
       ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
       SourceLocation IdLoc, TemplateParameterList *Params,
       VarTemplateDecl *SpecializedTemplate, QualType T, TypeSourceInfo *TInfo,
-      StorageClass S, ArrayRef Args,
-      const ASTTemplateArgumentListInfo *ArgInfos);
+      StorageClass S, ArrayRef Args);
 
   VarTemplatePartialSpecializationDecl(ASTContext &Context)
       : VarTemplateSpecializationDecl(VarTemplatePartialSpecialization,
@@ -2897,8 +2869,8 @@ public:
   Create(ASTContext &Context, DeclContext *DC, SourceLocation StartLoc,
          SourceLocation IdLoc, TemplateParameterList *Params,
          VarTemplateDecl *SpecializedTemplate, QualType T,
-         TypeSourceInfo *TInfo, StorageClass S, ArrayRef Args,
-         const TemplateArgumentListInfo &ArgInfos);
+         TypeSourceInfo *TInfo, StorageClass S,
+         ArrayRef Args);
 
   static VarTemplatePartialSpecializationDecl *
   CreateDeserialized(ASTContext &C, GlobalDeclID ID);
@@ -2914,11 +2886,6 @@ public:
     return TemplateParams;
   }
 
-  /// Get the template arguments as written.
-  const ASTTemplateArgumentListInfo *getTemplateArgsAsWritten() const {
-    return ArgsAsWritten;
-  }
-
   /// \brief All associated constraints of this partial specialization,
   /// including the requires clause and any constraints derived from
   /// constrained-parameters.
@@ -2981,7 +2948,7 @@ public:
   /// template<> template
   /// U* X::Inner = (T*)(0) + 1;
   /// \endcode
-  bool isMemberSpecialization() {
+  bool isMemberSpecialization() const {
     const auto *First =
         cast(getFirstDecl());
     return First->InstantiatedFromMember.getInt();
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index ab3f810b45192b5ca9e98b734aa872ab1402c48d..fac65628ffede8329b71c9d850502a743087a47c 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -3163,8 +3163,30 @@ public:
 /// This arises in several ways:
 ///   * we might be waiting for argument-dependent lookup;
 ///   * the name might resolve to an overloaded function;
+///   * the name might resolve to a non-function template; for example, in the
+///   following snippet, the return expression of the member function
+///   'foo()' might remain unresolved until instantiation:
+///
+/// \code
+/// struct P {
+///   template  using I = T;
+/// };
+///
+/// struct Q {
+///   template  int foo() {
+///     return T::template I;
+///   }
+/// };
+/// \endcode
+///
+/// ...which is distinct from modeling function overloads, and therefore we use
+/// a different builtin type 'UnresolvedTemplate' to avoid confusion. This is
+/// done in Sema::BuildTemplateIdExpr.
+///
 /// and eventually:
 ///   * the lookup might have included a function template.
+///   * the unresolved template gets transformed in an instantiation or gets
+///   diagnosed for its direct use.
 ///
 /// These never include UnresolvedUsingValueDecls, which are always class
 /// members and therefore appear only in UnresolvedMemberLookupExprs.
diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h
index bb4cb1f5d5080bd33103645e267b1e948e91d6ca..607a2b9d653678836264e0742840d24d1dc69ec4 100644
--- a/clang/include/clang/AST/OpenACCClause.h
+++ b/clang/include/clang/AST/OpenACCClause.h
@@ -17,6 +17,8 @@
 #include "clang/AST/StmtIterator.h"
 #include "clang/Basic/OpenACCKinds.h"
 
+#include 
+
 namespace clang {
 /// This is the base type for all OpenACC Clauses.
 class OpenACCClause {
@@ -26,14 +28,17 @@ class OpenACCClause {
 protected:
   OpenACCClause(OpenACCClauseKind K, SourceLocation BeginLoc,
                 SourceLocation EndLoc)
-      : Kind(K), Location(BeginLoc, EndLoc) {}
+      : Kind(K), Location(BeginLoc, EndLoc) {
+    assert(!BeginLoc.isInvalid() && !EndLoc.isInvalid() &&
+           "Begin and end location must be valid for OpenACCClause");
+      }
 
 public:
   OpenACCClauseKind getClauseKind() const { return Kind; }
   SourceLocation getBeginLoc() const { return Location.getBegin(); }
   SourceLocation getEndLoc() const { return Location.getEnd(); }
 
-  static bool classof(const OpenACCClause *) { return true; }
+  static bool classof(const OpenACCClause *) { return false; }
 
   using child_iterator = StmtIterator;
   using const_child_iterator = ConstStmtIterator;
@@ -60,6 +65,8 @@ protected:
       : OpenACCClause(K, BeginLoc, EndLoc), LParenLoc(LParenLoc) {}
 
 public:
+  static bool classof(const OpenACCClause *C);
+
   SourceLocation getLParenLoc() const { return LParenLoc; }
 
   child_range children() {
@@ -70,6 +77,63 @@ public:
   }
 };
 
+using DeviceTypeArgument = std::pair;
+/// A 'device_type' or 'dtype' clause, takes a list of either an 'asterisk' or
+/// an identifier. The 'asterisk' means 'the rest'.
+class OpenACCDeviceTypeClause final
+    : public OpenACCClauseWithParams,
+      public llvm::TrailingObjects {
+  // Data stored in trailing objects as IdentifierInfo* /SourceLocation pairs. A
+  // nullptr IdentifierInfo* represents an asterisk.
+  unsigned NumArchs;
+  OpenACCDeviceTypeClause(OpenACCClauseKind K, SourceLocation BeginLoc,
+                          SourceLocation LParenLoc,
+                          ArrayRef Archs,
+                          SourceLocation EndLoc)
+      : OpenACCClauseWithParams(K, BeginLoc, LParenLoc, EndLoc),
+        NumArchs(Archs.size()) {
+    assert(
+        (K == OpenACCClauseKind::DeviceType || K == OpenACCClauseKind::DType) &&
+        "Invalid clause kind for device-type");
+
+    assert(!llvm::any_of(Archs, [](const DeviceTypeArgument &Arg) {
+      return Arg.second.isInvalid();
+    }) && "Invalid SourceLocation for an argument");
+
+    assert(
+        (Archs.size() == 1 || !llvm::any_of(Archs,
+                                            [](const DeviceTypeArgument &Arg) {
+                                              return Arg.first == nullptr;
+                                            })) &&
+        "Only a single asterisk version is permitted, and must be the "
+        "only one");
+
+    std::uninitialized_copy(Archs.begin(), Archs.end(),
+                            getTrailingObjects());
+  }
+
+public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::DType ||
+           C->getClauseKind() == OpenACCClauseKind::DeviceType;
+  }
+  bool hasAsterisk() const {
+    return getArchitectures().size() > 0 &&
+           getArchitectures()[0].first == nullptr;
+  }
+
+  ArrayRef getArchitectures() const {
+    return ArrayRef(
+        getTrailingObjects(), NumArchs);
+  }
+
+  static OpenACCDeviceTypeClause *
+  Create(const ASTContext &C, OpenACCClauseKind K, SourceLocation BeginLoc,
+         SourceLocation LParenLoc, ArrayRef Archs,
+         SourceLocation EndLoc);
+};
+
 /// A 'default' clause, has the optional 'none' or 'present' argument.
 class OpenACCDefaultClause : public OpenACCClauseWithParams {
   friend class ASTReaderStmt;
@@ -89,6 +153,9 @@ protected:
   }
 
 public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::Default;
+  }
   OpenACCDefaultClauseKind getDefaultClauseKind() const {
     return DefaultClauseKind;
   }
@@ -113,6 +180,8 @@ protected:
         ConditionExpr(ConditionExpr) {}
 
 public:
+  static bool classof(const OpenACCClause *C);
+
   bool hasConditionExpr() const { return ConditionExpr; }
   const Expr *getConditionExpr() const { return ConditionExpr; }
   Expr *getConditionExpr() { return ConditionExpr; }
@@ -140,6 +209,9 @@ protected:
                   Expr *ConditionExpr, SourceLocation EndLoc);
 
 public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::If;
+  }
   static OpenACCIfClause *Create(const ASTContext &C, SourceLocation BeginLoc,
                                  SourceLocation LParenLoc, Expr *ConditionExpr,
                                  SourceLocation EndLoc);
@@ -151,6 +223,9 @@ class OpenACCSelfClause : public OpenACCClauseWithCondition {
                     Expr *ConditionExpr, SourceLocation EndLoc);
 
 public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::Self;
+  }
   static OpenACCSelfClause *Create(const ASTContext &C, SourceLocation BeginLoc,
                                    SourceLocation LParenLoc,
                                    Expr *ConditionExpr, SourceLocation EndLoc);
@@ -177,6 +252,7 @@ protected:
   llvm::ArrayRef getExprs() const { return Exprs; }
 
 public:
+  static bool classof(const OpenACCClause *C);
   child_range children() {
     return child_range(reinterpret_cast(Exprs.begin()),
                        reinterpret_cast(Exprs.end()));
@@ -189,6 +265,49 @@ public:
   }
 };
 
+// Represents the 'devnum' and expressions lists for the 'wait' clause.
+class OpenACCWaitClause final
+    : public OpenACCClauseWithExprs,
+      public llvm::TrailingObjects {
+  SourceLocation QueuesLoc;
+  OpenACCWaitClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
+                    Expr *DevNumExpr, SourceLocation QueuesLoc,
+                    ArrayRef QueueIdExprs, SourceLocation EndLoc)
+      : OpenACCClauseWithExprs(OpenACCClauseKind::Wait, BeginLoc, LParenLoc,
+                               EndLoc),
+        QueuesLoc(QueuesLoc) {
+    // The first element of the trailing storage is always the devnum expr,
+    // whether it is used or not.
+    std::uninitialized_copy(&DevNumExpr, &DevNumExpr + 1,
+                            getTrailingObjects());
+    std::uninitialized_copy(QueueIdExprs.begin(), QueueIdExprs.end(),
+                            getTrailingObjects() + 1);
+    setExprs(
+        MutableArrayRef(getTrailingObjects(), QueueIdExprs.size() + 1));
+  }
+
+public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::Wait;
+  }
+  static OpenACCWaitClause *Create(const ASTContext &C, SourceLocation BeginLoc,
+                                   SourceLocation LParenLoc, Expr *DevNumExpr,
+                                   SourceLocation QueuesLoc,
+                                   ArrayRef QueueIdExprs,
+                                   SourceLocation EndLoc);
+
+  bool hasQueuesTag() const { return !QueuesLoc.isInvalid(); }
+  SourceLocation getQueuesLoc() const { return QueuesLoc; }
+  bool hasDevNumExpr() const { return getExprs()[0]; }
+  Expr *getDevNumExpr() const { return getExprs()[0]; }
+  llvm::ArrayRef getQueueIdExprs() {
+    return OpenACCClauseWithExprs::getExprs().drop_front();
+  }
+  llvm::ArrayRef getQueueIdExprs() const {
+    return OpenACCClauseWithExprs::getExprs().drop_front();
+  }
+};
+
 class OpenACCNumGangsClause final
     : public OpenACCClauseWithExprs,
       public llvm::TrailingObjects {
@@ -203,6 +322,9 @@ class OpenACCNumGangsClause final
   }
 
 public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::NumGangs;
+  }
   static OpenACCNumGangsClause *
   Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
          ArrayRef IntExprs, SourceLocation EndLoc);
@@ -227,10 +349,12 @@ protected:
                                  SourceLocation EndLoc)
       : OpenACCClauseWithExprs(K, BeginLoc, LParenLoc, EndLoc),
         IntExpr(IntExpr) {
-    setExprs(MutableArrayRef{&this->IntExpr, 1});
+    if (IntExpr)
+      setExprs(MutableArrayRef{&this->IntExpr, 1});
   }
 
 public:
+  static bool classof(const OpenACCClause *C);
   bool hasIntExpr() const { return !getExprs().empty(); }
   const Expr *getIntExpr() const {
     return hasIntExpr() ? getExprs()[0] : nullptr;
@@ -244,6 +368,9 @@ class OpenACCNumWorkersClause : public OpenACCClauseWithSingleIntExpr {
                           Expr *IntExpr, SourceLocation EndLoc);
 
 public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::NumWorkers;
+  }
   static OpenACCNumWorkersClause *Create(const ASTContext &C,
                                          SourceLocation BeginLoc,
                                          SourceLocation LParenLoc,
@@ -255,11 +382,28 @@ class OpenACCVectorLengthClause : public OpenACCClauseWithSingleIntExpr {
                             Expr *IntExpr, SourceLocation EndLoc);
 
 public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::VectorLength;
+  }
   static OpenACCVectorLengthClause *
   Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
          Expr *IntExpr, SourceLocation EndLoc);
 };
 
+class OpenACCAsyncClause : public OpenACCClauseWithSingleIntExpr {
+  OpenACCAsyncClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
+                     Expr *IntExpr, SourceLocation EndLoc);
+
+public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::Async;
+  }
+  static OpenACCAsyncClause *Create(const ASTContext &C,
+                                    SourceLocation BeginLoc,
+                                    SourceLocation LParenLoc, Expr *IntExpr,
+                                    SourceLocation EndLoc);
+};
+
 /// Represents a clause with one or more 'var' objects, represented as an expr,
 /// as its arguments. Var-list is expected to be stored in trailing storage.
 /// For now, we're just storing the original expression in its entirety, unlike
@@ -271,6 +415,7 @@ protected:
       : OpenACCClauseWithExprs(K, BeginLoc, LParenLoc, EndLoc) {}
 
 public:
+  static bool classof(const OpenACCClause *C);
   ArrayRef getVarList() { return getExprs(); }
   ArrayRef getVarList() const { return getExprs(); }
 };
@@ -289,11 +434,249 @@ class OpenACCPrivateClause final
   }
 
 public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::Private;
+  }
   static OpenACCPrivateClause *
   Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
          ArrayRef VarList, SourceLocation EndLoc);
 };
 
+class OpenACCFirstPrivateClause final
+    : public OpenACCClauseWithVarList,
+      public llvm::TrailingObjects {
+
+  OpenACCFirstPrivateClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
+                            ArrayRef VarList, SourceLocation EndLoc)
+      : OpenACCClauseWithVarList(OpenACCClauseKind::FirstPrivate, BeginLoc,
+                                 LParenLoc, EndLoc) {
+    std::uninitialized_copy(VarList.begin(), VarList.end(),
+                            getTrailingObjects());
+    setExprs(MutableArrayRef(getTrailingObjects(), VarList.size()));
+  }
+
+public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::FirstPrivate;
+  }
+  static OpenACCFirstPrivateClause *
+  Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
+         ArrayRef VarList, SourceLocation EndLoc);
+};
+
+class OpenACCDevicePtrClause final
+    : public OpenACCClauseWithVarList,
+      public llvm::TrailingObjects {
+
+  OpenACCDevicePtrClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
+                         ArrayRef VarList, SourceLocation EndLoc)
+      : OpenACCClauseWithVarList(OpenACCClauseKind::DevicePtr, BeginLoc,
+                                 LParenLoc, EndLoc) {
+    std::uninitialized_copy(VarList.begin(), VarList.end(),
+                            getTrailingObjects());
+    setExprs(MutableArrayRef(getTrailingObjects(), VarList.size()));
+  }
+
+public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::DevicePtr;
+  }
+  static OpenACCDevicePtrClause *
+  Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
+         ArrayRef VarList, SourceLocation EndLoc);
+};
+
+class OpenACCAttachClause final
+    : public OpenACCClauseWithVarList,
+      public llvm::TrailingObjects {
+
+  OpenACCAttachClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
+                      ArrayRef VarList, SourceLocation EndLoc)
+      : OpenACCClauseWithVarList(OpenACCClauseKind::Attach, BeginLoc, LParenLoc,
+                                 EndLoc) {
+    std::uninitialized_copy(VarList.begin(), VarList.end(),
+                            getTrailingObjects());
+    setExprs(MutableArrayRef(getTrailingObjects(), VarList.size()));
+  }
+
+public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::Attach;
+  }
+  static OpenACCAttachClause *
+  Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
+         ArrayRef VarList, SourceLocation EndLoc);
+};
+
+class OpenACCNoCreateClause final
+    : public OpenACCClauseWithVarList,
+      public llvm::TrailingObjects {
+
+  OpenACCNoCreateClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
+                        ArrayRef VarList, SourceLocation EndLoc)
+      : OpenACCClauseWithVarList(OpenACCClauseKind::NoCreate, BeginLoc,
+                                 LParenLoc, EndLoc) {
+    std::uninitialized_copy(VarList.begin(), VarList.end(),
+                            getTrailingObjects());
+    setExprs(MutableArrayRef(getTrailingObjects(), VarList.size()));
+  }
+
+public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::NoCreate;
+  }
+  static OpenACCNoCreateClause *
+  Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
+         ArrayRef VarList, SourceLocation EndLoc);
+};
+
+class OpenACCPresentClause final
+    : public OpenACCClauseWithVarList,
+      public llvm::TrailingObjects {
+
+  OpenACCPresentClause(SourceLocation BeginLoc, SourceLocation LParenLoc,
+                       ArrayRef VarList, SourceLocation EndLoc)
+      : OpenACCClauseWithVarList(OpenACCClauseKind::Present, BeginLoc,
+                                 LParenLoc, EndLoc) {
+    std::uninitialized_copy(VarList.begin(), VarList.end(),
+                            getTrailingObjects());
+    setExprs(MutableArrayRef(getTrailingObjects(), VarList.size()));
+  }
+
+public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::Present;
+  }
+  static OpenACCPresentClause *
+  Create(const ASTContext &C, SourceLocation BeginLoc, SourceLocation LParenLoc,
+         ArrayRef VarList, SourceLocation EndLoc);
+};
+
+class OpenACCCopyClause final
+    : public OpenACCClauseWithVarList,
+      public llvm::TrailingObjects {
+
+  OpenACCCopyClause(OpenACCClauseKind Spelling, SourceLocation BeginLoc,
+                    SourceLocation LParenLoc, ArrayRef VarList,
+                    SourceLocation EndLoc)
+      : OpenACCClauseWithVarList(Spelling, BeginLoc, LParenLoc, EndLoc) {
+    assert((Spelling == OpenACCClauseKind::Copy ||
+            Spelling == OpenACCClauseKind::PCopy ||
+            Spelling == OpenACCClauseKind::PresentOrCopy) &&
+           "Invalid clause kind for copy-clause");
+    std::uninitialized_copy(VarList.begin(), VarList.end(),
+                            getTrailingObjects());
+    setExprs(MutableArrayRef(getTrailingObjects(), VarList.size()));
+  }
+
+public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::Copy ||
+           C->getClauseKind() == OpenACCClauseKind::PCopy ||
+           C->getClauseKind() == OpenACCClauseKind::PresentOrCopy;
+  }
+  static OpenACCCopyClause *
+  Create(const ASTContext &C, OpenACCClauseKind Spelling,
+         SourceLocation BeginLoc, SourceLocation LParenLoc,
+         ArrayRef VarList, SourceLocation EndLoc);
+};
+
+class OpenACCCopyInClause final
+    : public OpenACCClauseWithVarList,
+      public llvm::TrailingObjects {
+  bool IsReadOnly;
+
+  OpenACCCopyInClause(OpenACCClauseKind Spelling, SourceLocation BeginLoc,
+                      SourceLocation LParenLoc, bool IsReadOnly,
+                      ArrayRef VarList, SourceLocation EndLoc)
+      : OpenACCClauseWithVarList(Spelling, BeginLoc, LParenLoc, EndLoc),
+        IsReadOnly(IsReadOnly) {
+    assert((Spelling == OpenACCClauseKind::CopyIn ||
+            Spelling == OpenACCClauseKind::PCopyIn ||
+            Spelling == OpenACCClauseKind::PresentOrCopyIn) &&
+           "Invalid clause kind for copyin-clause");
+    std::uninitialized_copy(VarList.begin(), VarList.end(),
+                            getTrailingObjects());
+    setExprs(MutableArrayRef(getTrailingObjects(), VarList.size()));
+  }
+
+public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::CopyIn ||
+           C->getClauseKind() == OpenACCClauseKind::PCopyIn ||
+           C->getClauseKind() == OpenACCClauseKind::PresentOrCopyIn;
+  }
+  bool isReadOnly() const { return IsReadOnly; }
+  static OpenACCCopyInClause *
+  Create(const ASTContext &C, OpenACCClauseKind Spelling,
+         SourceLocation BeginLoc, SourceLocation LParenLoc, bool IsReadOnly,
+         ArrayRef VarList, SourceLocation EndLoc);
+};
+
+class OpenACCCopyOutClause final
+    : public OpenACCClauseWithVarList,
+      public llvm::TrailingObjects {
+  bool IsZero;
+
+  OpenACCCopyOutClause(OpenACCClauseKind Spelling, SourceLocation BeginLoc,
+                       SourceLocation LParenLoc, bool IsZero,
+                       ArrayRef VarList, SourceLocation EndLoc)
+      : OpenACCClauseWithVarList(Spelling, BeginLoc, LParenLoc, EndLoc),
+        IsZero(IsZero) {
+    assert((Spelling == OpenACCClauseKind::CopyOut ||
+            Spelling == OpenACCClauseKind::PCopyOut ||
+            Spelling == OpenACCClauseKind::PresentOrCopyOut) &&
+           "Invalid clause kind for copyout-clause");
+    std::uninitialized_copy(VarList.begin(), VarList.end(),
+                            getTrailingObjects());
+    setExprs(MutableArrayRef(getTrailingObjects(), VarList.size()));
+  }
+
+public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::CopyOut ||
+           C->getClauseKind() == OpenACCClauseKind::PCopyOut ||
+           C->getClauseKind() == OpenACCClauseKind::PresentOrCopyOut;
+  }
+  bool isZero() const { return IsZero; }
+  static OpenACCCopyOutClause *
+  Create(const ASTContext &C, OpenACCClauseKind Spelling,
+         SourceLocation BeginLoc, SourceLocation LParenLoc, bool IsZero,
+         ArrayRef VarList, SourceLocation EndLoc);
+};
+
+class OpenACCCreateClause final
+    : public OpenACCClauseWithVarList,
+      public llvm::TrailingObjects {
+  bool IsZero;
+
+  OpenACCCreateClause(OpenACCClauseKind Spelling, SourceLocation BeginLoc,
+                      SourceLocation LParenLoc, bool IsZero,
+                      ArrayRef VarList, SourceLocation EndLoc)
+      : OpenACCClauseWithVarList(Spelling, BeginLoc, LParenLoc, EndLoc),
+        IsZero(IsZero) {
+    assert((Spelling == OpenACCClauseKind::Create ||
+            Spelling == OpenACCClauseKind::PCreate ||
+            Spelling == OpenACCClauseKind::PresentOrCreate) &&
+           "Invalid clause kind for create-clause");
+    std::uninitialized_copy(VarList.begin(), VarList.end(),
+                            getTrailingObjects());
+    setExprs(MutableArrayRef(getTrailingObjects(), VarList.size()));
+  }
+
+public:
+  static bool classof(const OpenACCClause *C) {
+    return C->getClauseKind() == OpenACCClauseKind::Create ||
+           C->getClauseKind() == OpenACCClauseKind::PCreate ||
+           C->getClauseKind() == OpenACCClauseKind::PresentOrCreate;
+  }
+  bool isZero() const { return IsZero; }
+  static OpenACCCreateClause *
+  Create(const ASTContext &C, OpenACCClauseKind Spelling,
+         SourceLocation BeginLoc, SourceLocation LParenLoc, bool IsZero,
+         ArrayRef VarList, SourceLocation EndLoc);
+};
+
 template  class OpenACCClauseVisitor {
   Impl &getDerived() { return static_cast(*this); }
 
@@ -312,6 +695,10 @@ public:
   case OpenACCClauseKind::CLAUSE_NAME:                                         \
     Visit##CLAUSE_NAME##Clause(*cast(C));        \
     return;
+#define CLAUSE_ALIAS(ALIAS_NAME, CLAUSE_NAME)                                  \
+  case OpenACCClauseKind::ALIAS_NAME:                                          \
+    Visit##CLAUSE_NAME##Clause(*cast(C));        \
+    return;
 #include "clang/Basic/OpenACCClauses.def"
 
     default:
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index f9b145b4e86a5579dc13760ecce791468620c681..f5cefedb07e0eba340bd950b3c36769b5a39a774 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -736,13 +736,27 @@ bool RecursiveASTVisitor::TraverseDecl(Decl *D) {
 
   // As a syntax visitor, by default we want to ignore declarations for
   // implicit declarations (ones not typed explicitly by the user).
-  if (!getDerived().shouldVisitImplicitCode() && D->isImplicit()) {
-    // For an implicit template type parameter, its type constraints are not
-    // implicit and are not represented anywhere else. We still need to visit
-    // them.
-    if (auto *TTPD = dyn_cast(D))
-      return TraverseTemplateTypeParamDeclConstraints(TTPD);
-    return true;
+  if (!getDerived().shouldVisitImplicitCode()) {
+    if (D->isImplicit()) {
+      // For an implicit template type parameter, its type constraints are not
+      // implicit and are not represented anywhere else. We still need to visit
+      // them.
+      if (auto *TTPD = dyn_cast(D))
+        return TraverseTemplateTypeParamDeclConstraints(TTPD);
+      return true;
+    }
+
+    // Deduction guides for alias templates are always synthesized, so they
+    // should not be traversed unless shouldVisitImplicitCode() returns true.
+    //
+    // It's important to note that checking the implicit bit is not efficient
+    // for the alias case. For deduction guides synthesized from explicit
+    // user-defined deduction guides, we must maintain the explicit bit to
+    // ensure correct overload resolution.
+    if (auto *FTD = dyn_cast(D))
+      if (llvm::isa_and_present(
+              FTD->getDeclName().getCXXDeductionGuideTemplate()))
+        return true;
   }
 
   switch (D->getKind()) {
@@ -2030,6 +2044,15 @@ DEF_TRAVERSE_DECL(RecordDecl, { TRY_TO(TraverseRecordHelper(D)); })
 
 DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); })
 
+template 
+bool RecursiveASTVisitor::TraverseTemplateArgumentLocsHelper(
+    const TemplateArgumentLoc *TAL, unsigned Count) {
+  for (unsigned I = 0; I < Count; ++I) {
+    TRY_TO(TraverseTemplateArgumentLoc(TAL[I]));
+  }
+  return true;
+}
+
 #define DEF_TRAVERSE_TMPL_SPEC_DECL(TMPLDECLKIND, DECLKIND)                    \
   DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplateSpecializationDecl, {                \
     /* For implicit instantiations ("set x;"), we don't want to           \
@@ -2039,9 +2062,12 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); })
        TemplateSpecializationType).  For explicit instantiations               \
        ("template set;"), we do need a callback, since this               \
        is the only callback that's made for this instantiation.                \
-       We use getTypeAsWritten() to distinguish. */                            \
-    if (TypeSourceInfo *TSI = D->getTypeAsWritten())                           \
-      TRY_TO(TraverseTypeLoc(TSI->getTypeLoc()));                              \
+       We use getTemplateArgsAsWritten() to distinguish. */                    \
+    if (const auto *ArgsWritten = D->getTemplateArgsAsWritten()) {             \
+      /* The args that remains unspecialized. */                               \
+      TRY_TO(TraverseTemplateArgumentLocsHelper(                               \
+          ArgsWritten->getTemplateArgs(), ArgsWritten->NumTemplateArgs));      \
+    }                                                                          \
                                                                                \
     if (getDerived().shouldVisitTemplateInstantiations() ||                    \
         D->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {    \
@@ -2061,15 +2087,6 @@ DEF_TRAVERSE_DECL(CXXRecordDecl, { TRY_TO(TraverseCXXRecordHelper(D)); })
 DEF_TRAVERSE_TMPL_SPEC_DECL(Class, CXXRecord)
 DEF_TRAVERSE_TMPL_SPEC_DECL(Var, Var)
 
-template 
-bool RecursiveASTVisitor::TraverseTemplateArgumentLocsHelper(
-    const TemplateArgumentLoc *TAL, unsigned Count) {
-  for (unsigned I = 0; I < Count; ++I) {
-    TRY_TO(TraverseTemplateArgumentLoc(TAL[I]));
-  }
-  return true;
-}
-
 #define DEF_TRAVERSE_TMPL_PART_SPEC_DECL(TMPLDECLKIND, DECLKIND)               \
   DEF_TRAVERSE_DECL(TMPLDECLKIND##TemplatePartialSpecializationDecl, {         \
     /* The partial specialization. */                                          \
diff --git a/clang/include/clang/AST/StmtOpenACC.h b/clang/include/clang/AST/StmtOpenACC.h
index 66f8f844e0b29e1ef34c202751784224809882b7..b706864798baaf3f156aafcd1aafc848261f2944 100644
--- a/clang/include/clang/AST/StmtOpenACC.h
+++ b/clang/include/clang/AST/StmtOpenACC.h
@@ -93,6 +93,10 @@ protected:
   }
 
 public:
+  static bool classof(const Stmt *T) {
+    return false;
+  }
+
   child_range children() {
     if (getAssociatedStmt())
       return child_range(&AssociatedStmt, &AssociatedStmt + 1);
diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h
index e6643469e0b3344937d69beeee77e37d8bfed37e..da3834f19ca04466ab9574c8fdbcfd737539bcfe 100644
--- a/clang/include/clang/AST/Type.h
+++ b/clang/include/clang/AST/Type.h
@@ -8044,7 +8044,10 @@ inline bool Type::isUndeducedType() const {
 /// Determines whether this is a type for which one can define
 /// an overloaded operator.
 inline bool Type::isOverloadableType() const {
-  return isDependentType() || isRecordType() || isEnumeralType();
+  if (!CanonicalType->isDependentType())
+    return isRecordType() || isEnumeralType();
+  return !isArrayType() && !isFunctionType() && !isAnyPointerType() &&
+         !isMemberPointerType();
 }
 
 /// Determines whether this type is written as a typedef-name.
diff --git a/clang/include/clang/AST/VTTBuilder.h b/clang/include/clang/AST/VTTBuilder.h
index 4acbc1f9e96b2838274721637f5cf30bd1a8c3ec..3c19e61a8701ca8442844181921a298b480382cf 100644
--- a/clang/include/clang/AST/VTTBuilder.h
+++ b/clang/include/clang/AST/VTTBuilder.h
@@ -92,7 +92,7 @@ class VTTBuilder {
   using AddressPointsMapTy = llvm::DenseMap;
 
   /// The sub-VTT indices for the bases of the most derived class.
-  llvm::DenseMap SubVTTIndicies;
+  llvm::DenseMap SubVTTIndices;
 
   /// The secondary virtual pointer indices of all subobjects of
   /// the most derived class.
@@ -148,8 +148,8 @@ public:
   }
 
   /// Returns a reference to the sub-VTT indices.
-  const llvm::DenseMap &getSubVTTIndicies() const {
-    return SubVTTIndicies;
+  const llvm::DenseMap &getSubVTTIndices() const {
+    return SubVTTIndices;
   }
 
   /// Returns a reference to the secondary virtual pointer indices.
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 8a2bbfff9e9e6b0025c5af3cb7d94c0017038efa..0f3257db6f415fd7e8a6cda8f34f9cbb46a2df89 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -764,9 +764,9 @@ AST_POLYMORPHIC_MATCHER(isImplicit,
   return Node.isImplicit();
 }
 
-/// Matches classTemplateSpecializations, templateSpecializationType and
-/// functionDecl that have at least one TemplateArgument matching the given
-/// InnerMatcher.
+/// Matches templateSpecializationTypes, class template specializations,
+/// variable template specializations, and function template specializations
+/// that have at least one TemplateArgument matching the given InnerMatcher.
 ///
 /// Given
 /// \code
@@ -788,8 +788,8 @@ AST_POLYMORPHIC_MATCHER(isImplicit,
 AST_POLYMORPHIC_MATCHER_P(
     hasAnyTemplateArgument,
     AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
-                                    TemplateSpecializationType,
-                                    FunctionDecl),
+                                    VarTemplateSpecializationDecl, FunctionDecl,
+                                    TemplateSpecializationType),
     internal::Matcher, InnerMatcher) {
   ArrayRef List =
       internal::getTemplateSpecializationArgs(Node);
@@ -1047,8 +1047,9 @@ AST_MATCHER(Expr, isTypeDependent) { return Node.isTypeDependent(); }
 /// expr(isValueDependent()) matches return Size
 AST_MATCHER(Expr, isValueDependent) { return Node.isValueDependent(); }
 
-/// Matches classTemplateSpecializations, templateSpecializationType and
-/// functionDecl where the n'th TemplateArgument matches the given InnerMatcher.
+/// Matches templateSpecializationType, class template specializations,
+/// variable template specializations, and function template specializations
+/// where the n'th TemplateArgument matches the given InnerMatcher.
 ///
 /// Given
 /// \code
@@ -1068,8 +1069,8 @@ AST_MATCHER(Expr, isValueDependent) { return Node.isValueDependent(); }
 AST_POLYMORPHIC_MATCHER_P2(
     hasTemplateArgument,
     AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
-                                    TemplateSpecializationType,
-                                    FunctionDecl),
+                                    VarTemplateSpecializationDecl, FunctionDecl,
+                                    TemplateSpecializationType),
     unsigned, N, internal::Matcher, InnerMatcher) {
   ArrayRef List =
       internal::getTemplateSpecializationArgs(Node);
@@ -4066,7 +4067,7 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
 ///   Matcher, Matcher,
 ///   Matcher, Matcher,
 ///   Matcher,
-///   Matcher, Matcher,
+///   Matcher,
 ///   Matcher, Matcher,
 ///   Matcher, Matcher,
 ///   Matcher
@@ -4075,9 +4076,8 @@ AST_POLYMORPHIC_MATCHER_P(
     AST_POLYMORPHIC_SUPPORTED_TYPES(
         BlockDecl, CXXBaseSpecifier, CXXCtorInitializer, CXXFunctionalCastExpr,
         CXXNewExpr, CXXTemporaryObjectExpr, CXXUnresolvedConstructExpr,
-        ClassTemplateSpecializationDecl, CompoundLiteralExpr, DeclaratorDecl,
-        ExplicitCastExpr, ObjCPropertyDecl, TemplateArgumentLoc,
-        TypedefNameDecl),
+        CompoundLiteralExpr, DeclaratorDecl, ExplicitCastExpr, ObjCPropertyDecl,
+        TemplateArgumentLoc, TypedefNameDecl),
     internal::Matcher, Inner) {
   TypeSourceInfo *source = internal::GetTypeSourceInfo(Node);
   if (source == nullptr) {
@@ -5304,9 +5304,10 @@ AST_POLYMORPHIC_MATCHER_P(parameterCountIs,
   return Node.getNumParams() == N;
 }
 
-/// Matches classTemplateSpecialization, templateSpecializationType and
-/// functionDecl nodes where the template argument matches the inner matcher.
-/// This matcher may produce multiple matches.
+/// Matches templateSpecializationType, class template specialization,
+/// variable template specialization, and function template specialization
+/// nodes where the template argument matches the inner matcher. This matcher
+/// may produce multiple matches.
 ///
 /// Given
 /// \code
@@ -5330,7 +5331,8 @@ AST_POLYMORPHIC_MATCHER_P(parameterCountIs,
 AST_POLYMORPHIC_MATCHER_P(
     forEachTemplateArgument,
     AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
-                                    TemplateSpecializationType, FunctionDecl),
+                                    VarTemplateSpecializationDecl, FunctionDecl,
+                                    TemplateSpecializationType),
     internal::Matcher, InnerMatcher) {
   ArrayRef TemplateArgs =
       clang::ast_matchers::internal::getTemplateSpecializationArgs(Node);
@@ -6905,8 +6907,10 @@ extern const internal::VariadicDynCastAllOfMatcher<
     TypeLoc, TemplateSpecializationTypeLoc>
     templateSpecializationTypeLoc;
 
-/// Matches template specialization `TypeLoc`s that have at least one
-/// `TemplateArgumentLoc` matching the given `InnerMatcher`.
+/// Matches template specialization `TypeLoc`s, class template specializations,
+/// variable template specializations, and function template specializations
+/// that have at least one `TemplateArgumentLoc` matching the given
+/// `InnerMatcher`.
 ///
 /// Given
 /// \code
@@ -6916,20 +6920,21 @@ extern const internal::VariadicDynCastAllOfMatcher<
 /// varDecl(hasTypeLoc(templateSpecializationTypeLoc(hasAnyTemplateArgumentLoc(
 ///   hasTypeLoc(loc(asString("int")))))))
 ///   matches `A a`.
-AST_MATCHER_P(TemplateSpecializationTypeLoc, hasAnyTemplateArgumentLoc,
-              internal::Matcher, InnerMatcher) {
-  for (unsigned Index = 0, N = Node.getNumArgs(); Index < N; ++Index) {
-    clang::ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);
-    if (InnerMatcher.matches(Node.getArgLoc(Index), Finder, &Result)) {
-      *Builder = std::move(Result);
-      return true;
-    }
-  }
+AST_POLYMORPHIC_MATCHER_P(
+    hasAnyTemplateArgumentLoc,
+    AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
+                                    VarTemplateSpecializationDecl, FunctionDecl,
+                                    DeclRefExpr, TemplateSpecializationTypeLoc),
+    internal::Matcher, InnerMatcher) {
+  auto Args = internal::getTemplateArgsWritten(Node);
+  return matchesFirstInRange(InnerMatcher, Args.begin(), Args.end(), Finder,
+                             Builder) != Args.end();
   return false;
 }
 
-/// Matches template specialization `TypeLoc`s where the n'th
-/// `TemplateArgumentLoc` matches the given `InnerMatcher`.
+/// Matches template specialization `TypeLoc`s, class template specializations,
+/// variable template specializations, and function template specializations
+/// where the n'th `TemplateArgumentLoc` matches the given `InnerMatcher`.
 ///
 /// Given
 /// \code
@@ -6942,10 +6947,13 @@ AST_MATCHER_P(TemplateSpecializationTypeLoc, hasAnyTemplateArgumentLoc,
 ///   matches `A b`, but not `A c`.
 AST_POLYMORPHIC_MATCHER_P2(
     hasTemplateArgumentLoc,
-    AST_POLYMORPHIC_SUPPORTED_TYPES(DeclRefExpr, TemplateSpecializationTypeLoc),
+    AST_POLYMORPHIC_SUPPORTED_TYPES(ClassTemplateSpecializationDecl,
+                                    VarTemplateSpecializationDecl, FunctionDecl,
+                                    DeclRefExpr, TemplateSpecializationTypeLoc),
     unsigned, Index, internal::Matcher, InnerMatcher) {
-  return internal::MatchTemplateArgLocAt(Node, Index, InnerMatcher, Finder,
-                                         Builder);
+  auto Args = internal::getTemplateArgsWritten(Node);
+  return Index < Args.size() &&
+         InnerMatcher.matches(Args[Index], Finder, Builder);
 }
 
 /// Matches C or C++ elaborated `TypeLoc`s.
diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
index 47d912c73dd7eb491eeef5103012233f84a838ae..c1cc63fdb7433f7c01a771521bde51f41e8a24b0 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -186,10 +186,6 @@ inline TypeSourceInfo *GetTypeSourceInfo(const BlockDecl &Node) {
 inline TypeSourceInfo *GetTypeSourceInfo(const CXXNewExpr &Node) {
   return Node.getAllocatedTypeSourceInfo();
 }
-inline TypeSourceInfo *
-GetTypeSourceInfo(const ClassTemplateSpecializationDecl &Node) {
-  return Node.getTypeAsWritten();
-}
 
 /// Unifies obtaining the FunctionProtoType pointer from both
 /// FunctionProtoType and FunctionDecl nodes..
@@ -1939,6 +1935,11 @@ getTemplateSpecializationArgs(const ClassTemplateSpecializationDecl &D) {
   return D.getTemplateArgs().asArray();
 }
 
+inline ArrayRef
+getTemplateSpecializationArgs(const VarTemplateSpecializationDecl &D) {
+  return D.getTemplateArgs().asArray();
+}
+
 inline ArrayRef
 getTemplateSpecializationArgs(const TemplateSpecializationType &T) {
   return T.template_arguments();
@@ -1948,7 +1949,46 @@ inline ArrayRef
 getTemplateSpecializationArgs(const FunctionDecl &FD) {
   if (const auto* TemplateArgs = FD.getTemplateSpecializationArgs())
     return TemplateArgs->asArray();
-  return ArrayRef();
+  return std::nullopt;
+}
+
+inline ArrayRef
+getTemplateArgsWritten(const ClassTemplateSpecializationDecl &D) {
+  if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
+    return Args->arguments();
+  return std::nullopt;
+}
+
+inline ArrayRef
+getTemplateArgsWritten(const VarTemplateSpecializationDecl &D) {
+  if (const ASTTemplateArgumentListInfo *Args = D.getTemplateArgsAsWritten())
+    return Args->arguments();
+  return std::nullopt;
+}
+
+inline ArrayRef
+getTemplateArgsWritten(const FunctionDecl &FD) {
+  if (const auto *Args = FD.getTemplateSpecializationArgsAsWritten())
+    return Args->arguments();
+  return std::nullopt;
+}
+
+inline ArrayRef
+getTemplateArgsWritten(const DeclRefExpr &DRE) {
+  if (const auto *Args = DRE.getTemplateArgs())
+    return {Args, DRE.getNumTemplateArgs()};
+  return std::nullopt;
+}
+
+inline SmallVector
+getTemplateArgsWritten(const TemplateSpecializationTypeLoc &T) {
+  SmallVector Args;
+  if (!T.isNull()) {
+    Args.reserve(T.getNumArgs());
+    for (unsigned I = 0; I < T.getNumArgs(); ++I)
+      Args.emplace_back(T.getArgLoc(I));
+  }
+  return Args;
 }
 
 struct NotEqualsBoundNodePredicate {
diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
index 5d16dcc824c50c581b7a109d8d0fa9f9b3b19886..228b4ae1e3e1155008c33cd0691e36a63b155744 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
@@ -106,6 +106,11 @@ public:
   virtual void handleUnsafeOperation(const Stmt *Operation,
                                      bool IsRelatedToDecl, ASTContext &Ctx) = 0;
 
+  /// Invoked when an unsafe operation with a std container is found.
+  virtual void handleUnsafeOperationInContainer(const Stmt *Operation,
+                                                bool IsRelatedToDecl,
+                                                ASTContext &Ctx) = 0;
+
   /// Invoked when a fix is suggested against a variable. This function groups
   /// all variables that must be fixed together (i.e their types must be changed
   /// to the same target type to prevent type mismatches) into a single fixit.
diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
index 3273c642eed517cacbd16252fc78f79e656a5de2..242ad763ba62b9a806f605f97022a8280ad3d152 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsageGadgets.def
@@ -36,6 +36,7 @@ WARNING_GADGET(Decrement)
 WARNING_GADGET(ArraySubscript)
 WARNING_GADGET(PointerArithmetic)
 WARNING_GADGET(UnsafeBufferUsageAttr)
+WARNING_GADGET(UnsafeBufferUsageCtorAttr)
 WARNING_GADGET(DataInvocation)
 WARNING_CONTAINER_GADGET(SpanTwoParamConstructor) // Uses of `std::span(arg0, arg1)`
 FIXABLE_GADGET(ULCArraySubscript)          // `DRE[any]` in an Unspecified Lvalue Context
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
index 67eccdd030dcdd43f9488c902db5da658550eb1d..763af244547647ce5a8d2af5e4fc67cc0f423a85 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h
@@ -283,9 +283,8 @@ llvm::Expected> diagnoseFunction(
   if (!Context)
     return Context.takeError();
 
-  auto OwnedSolver = std::make_unique(MaxSATIterations);
-  const WatchedLiteralsSolver *Solver = OwnedSolver.get();
-  DataflowAnalysisContext AnalysisContext(std::move(OwnedSolver));
+  auto Solver = std::make_unique(MaxSATIterations);
+  DataflowAnalysisContext AnalysisContext(*Solver);
   Environment Env(AnalysisContext, FuncDecl);
   AnalysisT Analysis = createAnalysis(ASTCtx, Env);
   llvm::SmallVector Diagnostics;
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
index aa2c366cb164a92612088bbcefae8f897ca84898..5be4a1145f40d7158cf727c3cb5666f1304f4fb9 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h
@@ -67,7 +67,19 @@ public:
   DataflowAnalysisContext(std::unique_ptr S,
                           Options Opts = Options{
                               /*ContextSensitiveOpts=*/std::nullopt,
-                              /*Logger=*/nullptr});
+                              /*Logger=*/nullptr})
+      : DataflowAnalysisContext(*S, std::move(S), Opts) {}
+
+  /// Constructs a dataflow analysis context.
+  ///
+  /// Requirements:
+  ///
+  ///  `S` must outlive the `DataflowAnalysisContext`.
+  DataflowAnalysisContext(Solver &S, Options Opts = Options{
+                                         /*ContextSensitiveOpts=*/std::nullopt,
+                                         /*Logger=*/nullptr})
+      : DataflowAnalysisContext(S, nullptr, Opts) {}
+
   ~DataflowAnalysisContext();
 
   /// Sets a callback that returns the names and types of the synthetic fields
@@ -209,6 +221,13 @@ private:
     using DenseMapInfo::isEqual;
   };
 
+  /// `S` is the solver to use. `OwnedSolver` may be:
+  /// *  Null (in which case `S` is non-onwed and must outlive this object), or
+  /// *  Non-null (in which case it must refer to `S`, and the
+  ///    `DataflowAnalysisContext will take ownership of `OwnedSolver`).
+  DataflowAnalysisContext(Solver &S, std::unique_ptr &&OwnedSolver,
+                          Options Opts);
+
   // Extends the set of modeled field declarations.
   void addModeledFields(const FieldSet &Fields);
 
@@ -232,7 +251,8 @@ private:
            Solver::Result::Status::Unsatisfiable;
   }
 
-  std::unique_ptr S;
+  Solver &S;
+  std::unique_ptr OwnedSolver;
   std::unique_ptr A;
 
   // Maps from program declarations and statements to storage locations that are
diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
index cdf89c7def2c9185803af843f14fcbd88e59f5f5..097ff2bdfe7ada5a89e3842cbc848fcdd5df4ad4 100644
--- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
+++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h
@@ -19,6 +19,7 @@
 #include "clang/AST/DeclBase.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/Type.h"
+#include "clang/Analysis/FlowSensitive/ASTOps.h"
 #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"
 #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
 #include "clang/Analysis/FlowSensitive/Formula.h"
@@ -30,9 +31,11 @@
 #include "llvm/ADT/MapVector.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/ErrorHandling.h"
+#include 
 #include 
 #include 
 #include 
+#include 
 
 namespace clang {
 namespace dataflow {
@@ -155,7 +158,28 @@ public:
 
   /// Creates an environment that uses `DACtx` to store objects that encompass
   /// the state of a program.
-  explicit Environment(DataflowAnalysisContext &DACtx);
+  explicit Environment(DataflowAnalysisContext &DACtx)
+      : DACtx(&DACtx),
+        FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {}
+
+  /// Creates an environment that uses `DACtx` to store objects that encompass
+  /// the state of a program, with `S` as the statement to analyze.
+  Environment(DataflowAnalysisContext &DACtx, Stmt &S) : Environment(DACtx) {
+    InitialTargetStmt = &S;
+  }
+
+  /// Creates an environment that uses `DACtx` to store objects that encompass
+  /// the state of a program, with `FD` as the function to analyze.
+  ///
+  /// Requirements:
+  ///
+  ///  The function must have a body, i.e.
+  ///  `FunctionDecl::doesThisDecalarationHaveABody()` must be true.
+  Environment(DataflowAnalysisContext &DACtx, const FunctionDecl &FD)
+      : Environment(DACtx, *FD.getBody()) {
+    assert(FD.doesThisDeclarationHaveABody());
+    InitialTargetFunc = &FD;
+  }
 
   // Copy-constructor is private, Environments should not be copied. See fork().
   Environment &operator=(const Environment &Other) = delete;
@@ -163,24 +187,11 @@ public:
   Environment(Environment &&Other) = default;
   Environment &operator=(Environment &&Other) = default;
 
-  /// Creates an environment that uses `DACtx` to store objects that encompass
-  /// the state of a program.
-  ///
-  /// If `DeclCtx` is a function, initializes the environment with symbolic
-  /// representations of the function parameters.
-  ///
-  /// If `DeclCtx` is a non-static member function, initializes the environment
-  /// with a symbolic representation of the `this` pointee.
-  Environment(DataflowAnalysisContext &DACtx, const DeclContext &DeclCtx);
-
   /// Assigns storage locations and values to all parameters, captures, global
-  /// variables, fields and functions referenced in the function currently being
-  /// analyzed.
-  ///
-  /// Requirements:
+  /// variables, fields and functions referenced in the `Stmt` or `FunctionDecl`
+  /// passed to the constructor.
   ///
-  ///  The function must have a body, i.e.
-  ///  `FunctionDecl::doesThisDecalarationHaveABody()` must be true.
+  /// If no `Stmt` or `FunctionDecl` was supplied, this function does nothing.
   void initialize();
 
   /// Returns a new environment that is a copy of this one.
@@ -193,7 +204,7 @@ public:
   /// forked flow condition references the original).
   Environment fork() const;
 
-  /// Creates and returns an environment to use for an inline analysis  of the
+  /// Creates and returns an environment to use for an inline analysis of the
   /// callee. Uses the storage location from each argument in the `Call` as the
   /// storage location for the corresponding parameter in the callee.
   ///
@@ -365,46 +376,51 @@ public:
   RecordStorageLocation &
   getResultObjectLocation(const Expr &RecordPRValue) const;
 
-  /// Returns the return value of the current function. This can be null if:
+  /// Returns the return value of the function currently being analyzed.
+  /// This can be null if:
   /// - The function has a void return type
   /// - No return value could be determined for the function, for example
   ///   because it calls a function without a body.
   ///
   /// Requirements:
-  ///  The current function must have a non-reference return type.
+  ///  The current analysis target must be a function and must have a
+  ///  non-reference return type.
   Value *getReturnValue() const {
     assert(getCurrentFunc() != nullptr &&
            !getCurrentFunc()->getReturnType()->isReferenceType());
     return ReturnVal;
   }
 
-  /// Returns the storage location for the reference returned by the current
-  /// function. This can be null if function doesn't return a single consistent
-  /// reference.
+  /// Returns the storage location for the reference returned by the function
+  /// currently being analyzed. This can be null if the function doesn't return
+  /// a single consistent reference.
   ///
   /// Requirements:
-  ///  The current function must have a reference return type.
+  ///  The current analysis target must be a function and must have a reference
+  ///  return type.
   StorageLocation *getReturnStorageLocation() const {
     assert(getCurrentFunc() != nullptr &&
            getCurrentFunc()->getReturnType()->isReferenceType());
     return ReturnLoc;
   }
 
-  /// Sets the return value of the current function.
+  /// Sets the return value of the function currently being analyzed.
   ///
   /// Requirements:
-  ///  The current function must have a non-reference return type.
+  ///  The current analysis target must be a function and must have a
+  ///  non-reference return type.
   void setReturnValue(Value *Val) {
     assert(getCurrentFunc() != nullptr &&
            !getCurrentFunc()->getReturnType()->isReferenceType());
     ReturnVal = Val;
   }
 
-  /// Sets the storage location for the reference returned by the current
-  /// function.
+  /// Sets the storage location for the reference returned by the function
+  /// currently being analyzed.
   ///
   /// Requirements:
-  ///  The current function must have a reference return type.
+  ///  The current analysis target must be a function and must have a reference
+  ///  return type.
   void setReturnStorageLocation(StorageLocation *Loc) {
     assert(getCurrentFunc() != nullptr &&
            getCurrentFunc()->getReturnType()->isReferenceType());
@@ -641,23 +657,21 @@ public:
   /// (or the flow condition is overly constraining) or if the solver times out.
   bool allows(const Formula &) const;
 
-  /// Returns the `DeclContext` of the block being analysed, if any. Otherwise,
-  /// returns null.
-  const DeclContext *getDeclCtx() const { return CallStack.back(); }
-
   /// Returns the function currently being analyzed, or null if the code being
   /// analyzed isn't part of a function.
   const FunctionDecl *getCurrentFunc() const {
-    return dyn_cast(getDeclCtx());
+    return CallStack.empty() ? InitialTargetFunc : CallStack.back();
   }
 
-  /// Returns the size of the call stack.
+  /// Returns the size of the call stack, not counting the initial analysis
+  /// target.
   size_t callStackSize() const { return CallStack.size(); }
 
   /// Returns whether this `Environment` can be extended to analyze the given
-  /// `Callee` (i.e. if `pushCall` can be used), with recursion disallowed and a
-  /// given `MaxDepth`.
-  bool canDescend(unsigned MaxDepth, const DeclContext *Callee) const;
+  /// `Callee` (i.e. if `pushCall` can be used).
+  /// Recursion is not allowed. `MaxDepth` is the maximum size of the call stack
+  /// (i.e. the maximum value that `callStackSize()` may assume after the call).
+  bool canDescend(unsigned MaxDepth, const FunctionDecl *Callee) const;
 
   /// Returns the `DataflowAnalysisContext` used by the environment.
   DataflowAnalysisContext &getDataflowAnalysisContext() const { return *DACtx; }
@@ -719,8 +733,8 @@ private:
                         ArrayRef Args);
 
   /// Assigns storage locations and values to all global variables, fields
-  /// and functions referenced in `FuncDecl`. `FuncDecl` must have a body.
-  void initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl);
+  /// and functions in `Referenced`.
+  void initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced);
 
   static PrValueToResultObject
   buildResultObjectMap(DataflowAnalysisContext *DACtx,
@@ -728,6 +742,11 @@ private:
                        RecordStorageLocation *ThisPointeeLoc,
                        RecordStorageLocation *LocForRecordReturnVal);
 
+  static PrValueToResultObject
+  buildResultObjectMap(DataflowAnalysisContext *DACtx, Stmt *S,
+                       RecordStorageLocation *ThisPointeeLoc,
+                       RecordStorageLocation *LocForRecordReturnVal);
+
   // `DACtx` is not null and not owned by this object.
   DataflowAnalysisContext *DACtx;
 
@@ -736,11 +755,20 @@ private:
   // shared between environments in the same call.
   // https://github.com/llvm/llvm-project/issues/59005
 
-  // `DeclContext` of the block being analysed if provided.
-  std::vector CallStack;
+  // The stack of functions called from the initial analysis target.
+  std::vector CallStack;
+
+  // Initial function to analyze, if a function was passed to the constructor.
+  // Null otherwise.
+  const FunctionDecl *InitialTargetFunc = nullptr;
+  // Top-level statement of the initial analysis target.
+  // If a function was passed to the constructor, this is its body.
+  // If a statement was passed to the constructor, this is that statement.
+  // Null if no analysis target was passed to the constructor.
+  Stmt *InitialTargetStmt = nullptr;
 
   // Maps from prvalues of record type to their result objects. Shared between
-  // all environments for the same function.
+  // all environments for the same analysis target.
   // FIXME: It's somewhat unsatisfactory that we have to use a `shared_ptr`
   // here, though the cost is acceptable: The overhead of a `shared_ptr` is
   // incurred when it is copied, and this happens only relatively rarely (when
@@ -749,7 +777,7 @@ private:
   std::shared_ptr ResultObjectMap;
 
   // The following three member variables handle various different types of
-  // return values.
+  // return values when the current analysis target is a function.
   // - If the return type is not a reference and not a record: Value returned
   //   by the function.
   Value *ReturnVal = nullptr;
@@ -762,7 +790,7 @@ private:
   RecordStorageLocation *LocForRecordReturnVal = nullptr;
 
   // The storage location of the `this` pointee. Should only be null if the
-  // function being analyzed is only a function and not a method.
+  // analysis target is not a method.
   RecordStorageLocation *ThisPointeeLoc = nullptr;
 
   // Maps from declarations and glvalue expression to storage locations that are
diff --git a/clang/include/clang/Analysis/FlowSensitive/Solver.h b/clang/include/clang/Analysis/FlowSensitive/Solver.h
index 079f6802f241eead339cdcf0718d796512e03492..6166a503ab413aef748119cf85b6b861141e5014 100644
--- a/clang/include/clang/Analysis/FlowSensitive/Solver.h
+++ b/clang/include/clang/Analysis/FlowSensitive/Solver.h
@@ -87,6 +87,9 @@ public:
   ///
   ///  All elements in `Vals` must not be null.
   virtual Result solve(llvm::ArrayRef Vals) = 0;
+
+  // Did the solver reach its resource limit?
+  virtual bool reachedLimit() const = 0;
 };
 
 llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Solver::Result &);
diff --git a/clang/include/clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h b/clang/include/clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h
index 5448eecf6d41a25e2f253ae4eaf9e44296c84ddd..b5cd7aa10fd7d2502376049dded4f5c693d26008 100644
--- a/clang/include/clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h
+++ b/clang/include/clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h
@@ -48,8 +48,7 @@ public:
 
   Result solve(llvm::ArrayRef Vals) override;
 
-  // The solver reached its maximum number of iterations.
-  bool reachedLimit() const { return MaxIterations == 0; }
+  bool reachedLimit() const override { return MaxIterations == 0; }
 };
 
 } // namespace dataflow
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 0225598cbbe8ad8f1d5e8085688e22fda4ef75b1..7008bea483c8723ee70efce35f207972fcaadea3 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -999,7 +999,7 @@ def Availability : InheritableAttr {
               VersionArgument<"deprecated">, VersionArgument<"obsoleted">,
               BoolArgument<"unavailable">, StringArgument<"message">,
               BoolArgument<"strict">, StringArgument<"replacement">,
-              IntArgument<"priority">];
+              IntArgument<"priority">, IdentifierArgument<"environment">];
   let AdditionalMembers =
 [{static llvm::StringRef getPrettyPlatformName(llvm::StringRef Platform) {
     return llvm::StringSwitch(Platform)
@@ -1019,7 +1019,7 @@ def Availability : InheritableAttr {
              .Case("xros", "visionOS")
              .Case("xros_app_extension", "visionOS (App Extension)")
              .Case("swift", "Swift")
-             .Case("shadermodel", "HLSL ShaderModel")
+             .Case("shadermodel", "Shader Model")
              .Case("ohos", "OpenHarmony OS")
              .Default(llvm::StringRef());
 }
@@ -1059,7 +1059,34 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) {
              .Case("visionos_app_extension", "xros_app_extension")
              .Case("ShaderModel", "shadermodel")
              .Default(Platform);
-} }];
+}
+static llvm::StringRef getPrettyEnviromentName(llvm::StringRef Environment) {
+    return llvm::StringSwitch(Environment)
+             .Case("pixel", "pixel shader")
+             .Case("vertex", "vertex shader")
+             .Case("geometry", "geometry shader")
+             .Case("hull", "hull shader")
+             .Case("domain", "domain shader")
+             .Case("compute", "compute shader")
+             .Case("mesh", "mesh shader")
+             .Case("amplification", "amplification shader")
+             .Case("library", "shader library")
+             .Default(Environment);
+}
+static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef Environment) {
+    return llvm::StringSwitch(Environment)
+             .Case("pixel", llvm::Triple::Pixel)
+             .Case("vertex", llvm::Triple::Vertex)
+             .Case("geometry", llvm::Triple::Geometry)
+             .Case("hull", llvm::Triple::Hull)
+             .Case("domain", llvm::Triple::Domain)
+             .Case("compute", llvm::Triple::Compute)
+             .Case("mesh", llvm::Triple::Mesh)
+             .Case("amplification", llvm::Triple::Amplification)
+             .Case("library", llvm::Triple::Library)
+             .Default(llvm::Triple::UnknownEnvironment);
+}
+}];
   let HasCustomParsing = 1;
   let InheritEvenIfAlreadyPresent = 1;
   let Subjects = SubjectList<[Named]>;
@@ -4415,6 +4442,18 @@ def HLSLResourceBinding: InheritableAttr {
   let Documentation = [HLSLResourceBindingDocs];
 }
 
+def HLSLPackOffset: HLSLAnnotationAttr {
+  let Spellings = [HLSLAnnotation<"packoffset">];
+  let LangOpts = [HLSL];
+  let Args = [IntArgument<"Subcomponent">, IntArgument<"Component">];
+  let Documentation = [HLSLPackOffsetDocs];
+  let AdditionalMembers = [{
+      unsigned getOffset() {
+        return subcomponent * 4 + component;
+      }
+  }];
+}
+
 def HLSLSV_DispatchThreadID: HLSLAnnotationAttr {
   let Spellings = [HLSLAnnotation<"SV_DispatchThreadID">];
   let Subjects = SubjectList<[ParmVar, Field]>;
@@ -4549,3 +4588,10 @@ def CodeAlign: StmtAttr {
     static constexpr int MaximumAlignment = 4096;
   }];
 }
+
+def ClspvLibclcBuiltin: InheritableAttr {
+  let Spellings = [Clang<"clspv_libclc_builtin">];
+  let Subjects = SubjectList<[Function]>;
+  let Documentation = [ClspvLibclcBuiltinDoc];
+  let SimpleHandler = 1;
+}
diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index a0bbe5861c5722dea021d62fb609ec98b5db7031..54197d588eb45084e93e3d8b5eeec277feeee035 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -1593,6 +1593,11 @@ replacement=\ *string-literal*
   a warning about use of a deprecated declaration. The Fix-It will replace
   the deprecated declaration with the new declaration specified.
 
+environment=\ *identifier*
+  Target environment in which this declaration is available. If present,
+  the availability attribute applies only to targets with the same platform
+  and environment. The parameter is currently supported only in HLSL.
+
 Multiple availability attributes can be placed on a declaration, which may
 correspond to different platforms. For most platforms, the availability
 attribute with the platform corresponding to the target platform will be used;
@@ -2527,6 +2532,9 @@ Example "subtarget features" from the x86 backend include: "mmx", "sse", "sse4.2
 "avx", "xop" and largely correspond to the machine specific options handled by
 the front end.
 
+Note that this attribute does not apply transitively to nested functions such
+as blocks or C++ lambdas.
+
 Additionally, this attribute supports function multiversioning for ELF based
 x86/x86-64 targets, which can be used to create multiple implementations of the
 same function that will be resolved at runtime based on the priority of their
@@ -3782,6 +3790,12 @@ for that function.
 
 This attribute is incompatible with the ``always_inline`` and ``minsize``
 attributes.
+
+Note that this attribute does not apply recursively to nested functions such as
+lambdas or blocks when using declaration-specific attribute syntaxes such as double
+square brackets (``[[]]``) or ``__attribute__``. The ``#pragma`` syntax can be
+used to apply the attribute to all functions, including nested functions, in a
+range of source code.
   }];
 }
 
@@ -5654,11 +5668,12 @@ The ``preserve_none`` calling convention tries to preserve as few general
 registers as possible. So all general registers are caller saved registers. It
 also uses more general registers to pass arguments. This attribute doesn't
 impact floating-point registers (XMMs/YMMs). Floating-point registers still
-follow the c calling convention.
+follow the c calling convention. ``preserve_none``'s ABI is still unstable, and
+may be changed in the future.
 
 - Only RSP and RBP are preserved by callee.
 
-- Register RDI, RSI, RDX, RCX, R8, R9, R11, R12, R13, R14, R15 and RAX now can
+- Register R12, R13, R14, R15, RDI, RSI, RDX, RCX, R8, R9, R11, and RAX now can
   be used to pass function arguments.
   }];
 }
@@ -7398,6 +7413,26 @@ The full documentation is available here: https://docs.microsoft.com/en-us/windo
   }];
 }
 
+def HLSLPackOffsetDocs : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+The packoffset attribute is used to change the layout of a cbuffer.
+Attribute spelling in HLSL is: ``packoffset( c[Subcomponent][.component] )``.
+A subcomponent is a register number, which is an integer. A component is in the form of [.xyzw].
+
+Examples:
+
+.. code-block:: c++
+
+  cbuffer A {
+    float3 a : packoffset(c0.y);
+    float4 b : packoffset(c4);
+  }
+
+The full documentation is available here: https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-variable-packoffset
+  }];
+}
+
 def HLSLSV_DispatchThreadIDDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{
@@ -8057,3 +8092,17 @@ requirement:
   }
   }];
 }
+
+def ClspvLibclcBuiltinDoc : Documentation {
+  let Category = DocCatFunction;
+  let Content = [{
+Attribute used by `clspv`_ (OpenCL-C to Vulkan SPIR-V compiler) to identify functions coming from `libclc`_ (OpenCL-C builtin library).
+
+.. code-block:: c
+
+  void __attribute__((clspv_libclc_builtin)) libclc_builtin() {}
+
+.. _`clspv`: https://github.com/google/clspv
+.. _`libclc`: https://libclc.llvm.org
+}];
+}
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index de721a87b3341def3eaeacd12f68e9d7653c95c0..11982af3fa609bea617811b4b550954da698258e 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -1326,6 +1326,12 @@ def ElementwiseSqrt : Builtin {
   let Prototype = "void(...)";
 }
 
+def ElementwiseTan : Builtin {
+  let Spellings = ["__builtin_elementwise_tan"];
+  let Attributes = [NoThrow, Const, CustomTypeChecking];
+  let Prototype = "void(...)";
+}
+
 def ElementwiseTrunc : Builtin {
   let Spellings = ["__builtin_elementwise_trunc"];
   let Attributes = [NoThrow, Const, CustomTypeChecking];
diff --git a/clang/include/clang/Basic/BuiltinsNVPTX.def b/clang/include/clang/Basic/BuiltinsNVPTX.def
index 8d3c5e69d55cf492f27e65fee1aa3a6a9bc9d011..9e243d740ed7aec7e7b8b94f305478e6eba9011d 100644
--- a/clang/include/clang/Basic/BuiltinsNVPTX.def
+++ b/clang/include/clang/Basic/BuiltinsNVPTX.def
@@ -61,7 +61,9 @@
 #pragma push_macro("PTX81")
 #pragma push_macro("PTX82")
 #pragma push_macro("PTX83")
-#define PTX83 "ptx83"
+#pragma push_macro("PTX84")
+#define PTX84 "ptx84"
+#define PTX83 "ptx83|" PTX84
 #define PTX82 "ptx82|" PTX83
 #define PTX81 "ptx81|" PTX82
 #define PTX80 "ptx80|" PTX81
@@ -1091,3 +1093,4 @@ TARGET_BUILTIN(__nvvm_getctarank_shared_cluster, "iv*3", "", AND(SM_90,PTX78))
 #pragma pop_macro("PTX81")
 #pragma pop_macro("PTX82")
 #pragma pop_macro("PTX83")
+#pragma pop_macro("PTX84")
diff --git a/clang/include/clang/Basic/BuiltinsWebAssembly.def b/clang/include/clang/Basic/BuiltinsWebAssembly.def
index 7e950914ad946d07d2b55711362399771dd28c4c..8645cff1e8679f36d8595f19a165f9236014e71d 100644
--- a/clang/include/clang/Basic/BuiltinsWebAssembly.def
+++ b/clang/include/clang/Basic/BuiltinsWebAssembly.def
@@ -190,6 +190,10 @@ TARGET_BUILTIN(__builtin_wasm_relaxed_dot_i8x16_i7x16_s_i16x8, "V8sV16ScV16Sc",
 TARGET_BUILTIN(__builtin_wasm_relaxed_dot_i8x16_i7x16_add_s_i32x4, "V4iV16ScV16ScV4i", "nc", "relaxed-simd")
 TARGET_BUILTIN(__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4, "V4fV8UsV8UsV4f", "nc", "relaxed-simd")
 
+// Half-Precision (fp16)
+TARGET_BUILTIN(__builtin_wasm_loadf16_f32, "fh*", "nU", "half-precision")
+TARGET_BUILTIN(__builtin_wasm_storef16_f32, "vfh*", "n", "half-precision")
+
 // Reference Types builtins
 // Some builtins are custom type-checked - see 't' as part of the third argument,
 // in which case the argument spec (second argument) is unused.
diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def
index 340b08dd7e2a33422dfc4680ff71d2f6152a709d..07b0ca1691a679a2148a72734e2a658bb5286d58 100644
--- a/clang/include/clang/Basic/CodeGenOptions.def
+++ b/clang/include/clang/Basic/CodeGenOptions.def
@@ -57,6 +57,7 @@ CODEGENOPT(UniqueSectionNames, 1, 1) ///< Set for -funique-section-names.
 CODEGENOPT(UniqueBasicBlockSectionNames, 1, 1) ///< Set for -funique-basic-block-section-names,
                                                ///< Produce unique section names with
                                                ///< basic block sections.
+CODEGENOPT(SeparateNamedSections, 1, 0) ///< Set for -fseparate-named-sections.
 CODEGENOPT(EnableAIXExtendedAltivecABI, 1, 0) ///< Set for -mabi=vec-extabi. Enables the extended Altivec ABI on AIX.
 CODEGENOPT(XCOFFReadOnlyPointers, 1, 0) ///< Set for -mxcoff-roptr.
 CODEGENOPT(AllTocData, 1, 0) ///< AIX -mtocdata
@@ -308,6 +309,7 @@ CODEGENOPT(UnrollLoops       , 1, 0) ///< Control whether loops are unrolled.
 CODEGENOPT(RerollLoops       , 1, 0) ///< Control whether loops are rerolled.
 CODEGENOPT(NoUseJumpTables   , 1, 0) ///< Set when -fno-jump-tables is enabled.
 VALUE_CODEGENOPT(UnwindTables, 2, 0) ///< Unwind tables (1) or asynchronous unwind tables (2)
+CODEGENOPT(LinkBitcodePostopt, 1, 0) ///< Link builtin bitcodes after optimization pipeline.
 CODEGENOPT(VectorizeLoop     , 1, 0) ///< Run loop vectorizer.
 CODEGENOPT(VectorizeSLP      , 1, 0) ///< Run SLP vectorizer.
 CODEGENOPT(ProfileSampleAccurate, 1, 0) ///< Sample profile is accurate.
diff --git a/clang/include/clang/Basic/Cuda.h b/clang/include/clang/Basic/Cuda.h
index ba0e4465a0f5a0a2f7673d549c7228406be6a9d4..2d67c4181d12957e0e1df2429e3c6a3f6935c40c 100644
--- a/clang/include/clang/Basic/Cuda.h
+++ b/clang/include/clang/Basic/Cuda.h
@@ -41,9 +41,10 @@ enum class CudaVersion {
   CUDA_121,
   CUDA_122,
   CUDA_123,
+  CUDA_124,
   FULLY_SUPPORTED = CUDA_123,
   PARTIALLY_SUPPORTED =
-      CUDA_123, // Partially supported. Proceed with a warning.
+      CUDA_124, // Partially supported. Proceed with a warning.
   NEW = 10000,  // Too new. Issue a warning, but allow using it.
 };
 const char *CudaVersionToString(CudaVersion V);
diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td
index ed3fd9b1c4a55b6a9a3694ecd54575bd1056de36..9d97a75f696f668ac858ce08919b2f7339150d1f 100644
--- a/clang/include/clang/Basic/DiagnosticDriverKinds.td
+++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td
@@ -435,7 +435,10 @@ def warn_drv_diagnostics_misexpect_requires_pgo : Warning<
 def warn_drv_clang_unsupported : Warning<
   "the clang compiler does not support '%0'">;
 def warn_drv_deprecated_arg : Warning<
-  "argument '%0' is deprecated, use '%1' instead">, InGroup;
+  "argument '%0' is deprecated%select{|, use '%2' instead}1">, InGroup;
+def warn_drv_deprecated_arg_no_relaxed_template_template_args : Warning<
+  "argument '-fno-relaxed-template-template-args' is deprecated">,
+  InGroup;
 def warn_drv_deprecated_custom : Warning<
   "argument '%0' is deprecated, %1">, InGroup;
 def warn_drv_assuming_mfloat_abi_is : Warning<
diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
index fcffadacc8e631ebbd7b3d54368b02a50c815b29..e456ec2cac461c2bd39e67be8a87870ca7f23376 100644
--- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td
+++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td
@@ -134,6 +134,8 @@ def err_fe_no_pch_in_dir : Error<
     "no suitable precompiled header file found in directory '%0'">;
 def err_fe_action_not_available : Error<
     "action %0 not compiled in">;
+def err_fe_invalid_multiple_actions : Error<
+    "'%0' action ignored; '%1' action specified previously">;
 def err_fe_invalid_alignment : Error<
     "invalid value '%1' in '%0'; alignment must be a power of 2">;
 def err_fe_invalid_exception_model
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 60f87da2a7387c25fff72fefb54d5852e627e299..4cb4f3d999f7ab466de3794c11bb7692109ee801 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -104,6 +104,7 @@ def EnumConversion : DiagGroup<"enum-conversion",
                                [EnumEnumConversion,
                                 EnumFloatConversion,
                                 EnumCompareConditional]>;
+def DeprecatedNoRelaxedTemplateTemplateArgs : DiagGroup<"deprecated-no-relaxed-template-template-args">;
 def ObjCSignedCharBoolImplicitIntConversion :
   DiagGroup<"objc-signed-char-bool-implicit-int-conversion">;
 def Shorten64To32 : DiagGroup<"shorten-64-to-32">;
@@ -228,6 +229,7 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
                                           DeprecatedLiteralOperator,
                                           DeprecatedPragma,
                                           DeprecatedRegister,
+                                          DeprecatedNoRelaxedTemplateTemplateArgs,
                                           DeprecatedThisCapture,
                                           DeprecatedType,
                                           DeprecatedVolatile,
@@ -1507,6 +1509,9 @@ def BranchProtection : DiagGroup<"branch-protection">;
 // Warnings for HLSL Clang extensions
 def HLSLExtension : DiagGroup<"hlsl-extensions">;
 
+// Warning for mix packoffset and non-packoffset.
+def HLSLMixPackOffset : DiagGroup<"mix-packoffset">;
+
 // Warnings for DXIL validation
 def DXILValidation : DiagGroup<"dxil-validation">;
 
diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
index 6896e0f5aa593c2e598bec39e2b331a089352bce..674742431dcb2d7dfff7284ca8d071d361275388 100644
--- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
+++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td
@@ -25,6 +25,7 @@ def err_unsupported_vendor : Error<"vendor '%0' is not supported: '%1'">;
 def err_unsupported_environment : Error<"environment '%0' is not supported: '%1'">;
 def err_unsupported_os : Error<"os '%0' is not supported: '%1'">;
 def err_cannot_read_input_list : Error<"could not read %select{alias list|filelist}0 '%1': %2">;
+def err_invalid_label: Error<"label '%0' is reserved: use a different label name for -X