diff --git a/.github/workflows/release-asset-audit.py b/.github/workflows/release-asset-audit.py new file mode 100644 index 000000000000000..355e7fee1dae013 --- /dev/null +++ b/.github/workflows/release-asset-audit.py @@ -0,0 +1,51 @@ +import github +import sys + +def main(): + token = sys.argv[1] + + gh = github.Github(login_or_token=token) + repo = gh.get_repo("llvm/llvm-project") + + uploaders = set( + [ + "DimitryAndric", + "stefanp-ibm", + "lei137", + "omjavaid", + "nicolerabjohn", + "amy-kwan", + "mandlebug", + "zmodem", + "androm3da", + "tru", + "rovka", + "rorth", + "quinnlp", + "kamaub", + "abrisco", + "jakeegan", + "maryammo", + "tstellar", + "github-actions[bot]", + ] + ) + + for release in repo.get_releases(): + print("Release:", release.title) + for asset in release.get_assets(): + created_at = asset.created_at + updated_at = ( + "" if asset.created_at == asset.updated_at else asset.updated_at + ) + print( + f"{asset.name} : {asset.uploader.login} [{created_at} {updated_at}] ( {asset.download_count} )" + ) + if asset.uploader.login not in uploaders: + with open('comment', 'w') as file: + file.write(f'@{asset.uploader.login} is not a valid uploader.') + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/release-asset-audit.yml b/.github/workflows/release-asset-audit.yml new file mode 100644 index 000000000000000..018c5d542f32eb1 --- /dev/null +++ b/.github/workflows/release-asset-audit.yml @@ -0,0 +1,54 @@ +name: Release Asset Audit + +on: + workflow_dispatch: + release: + schedule: + # * is a special character in YAML so you have to quote this string + # Run once an hour + - cron: '5 * * * *' + + pull_request: + paths: + - ".github/workflows/release-asset-audit.py" + - ".github/workflows/release-asset-audit.yml" + +permissions: + contents: read # Default everything to read-only + +jobs: + audit: + name: "Release Asset Audit" + runs-on: ubuntu-22.04 + if: github.repository == 'llvm/llvm-project' + steps: + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 #v4.1.6 + - name: "Run Audit Script" + env: + GITHUB_TOKEN: ${{ github.token }} + run: | + pip install --require-hashes -r ./llvm/utils/git/requirements.txt + python3 ./.github/workflows/release-asset-audit.py $GITHUB_TOKEN + - name: "File Issue" + if: >- + github.event_name != 'pull_request' && + failure() + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea #v7.0.1 + with: + github-token: ${{ secrets.ISSUE_SUBSCRIBER_TOKEN }} + script: | + var fs = require('fs'); + var body = '' + if (fs.existsSync('./comment')) { + body = fs.readFileSync('./comment') + "\n\n"; + } + body = body + `\n\nhttps://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}` + + const issue = await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: "Release Asset Audit Failed", + labels: ['infrastructure'], + body: body + }); + console.log(issue); diff --git a/.github/workflows/release-binaries-all.yml b/.github/workflows/release-binaries-all.yml new file mode 100644 index 000000000000000..73c9d96946e33a1 --- /dev/null +++ b/.github/workflows/release-binaries-all.yml @@ -0,0 +1,94 @@ +name: Release Binaries All + +permissions: + contents: read # Default everything to read-only + +on: + workflow_dispatch: + inputs: + release-version: + description: 'Release Version' + required: true + type: string + upload: + description: 'Upload binaries to the release page' + required: true + default: false + type: boolean + + workflow_call: + inputs: + release-version: + description: 'Release Version' + required: true + type: string + upload: + description: 'Upload binaries to the release page' + required: true + default: false + type: boolean + + pull_request: + types: + - opened + - synchronize + - reopened + # When a PR is closed, we still start this workflow, but then skip + # all the jobs, which makes it effectively a no-op. The reason to + # do this is that it allows us to take advantage of concurrency groups + # to cancel in progress CI jobs whenever the PR is closed. + - closed + paths: + - '.github/workflows/release-binaries-all.yml' + - '.github/workflows/release-binaries.yml' + - '.github/workflows/release-binaries-setup-stage/*' + - '.github/workflows/release-binaries-save-stage/*' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || 'dispatch' }} + cancel-in-progress: True + +jobs: + setup-variables: + if: >- + (github.event_name != 'pull_request' || github.event.action != 'closed') + runs-on: ubuntu-22.04 + outputs: + release-version: ${{ steps.vars.outputs.release-version }} + upload: ${{ steps.vars.outputs.upload }} + steps: + - shell: bash + id: vars + run: | + upload="${{ inputs.upload }}" + release_version="${{ inputs.release-version }}" + if [ "${{ github.event_name }}" = "pull_request" ]; then + upload="false" + release_version="" + fi + echo "release-version=$release_version" >> "$GITHUB_OUTPUT" + echo "upload=$upload" >> "$GITHUB_OUTPUT" + + release-binaries-all: + name: Build Release Binaries + needs: + - setup-variables + permissions: + contents: write # For release uploads + id-token: write # For artifact attestations + attestations: write # For artifact attestations + strategy: + fail-fast: false + matrix: + runs-on: + - ubuntu-22.04 + - windows-2022 + - macos-13 + - macos-14 + + uses: ./.github/workflows/release-binaries.yml + with: + release-version: "${{ needs.setup-variables.outputs.release-version }}" + upload: ${{ needs.setup-variables.outputs.upload == 'true'}} + runs-on: "${{ matrix.runs-on }}" + diff --git a/.github/workflows/release-binaries-save-stage/action.yml b/.github/workflows/release-binaries-save-stage/action.yml new file mode 100644 index 000000000000000..e2f3eeadd15bead --- /dev/null +++ b/.github/workflows/release-binaries-save-stage/action.yml @@ -0,0 +1,38 @@ +name: Save Stage +description: >- + Upload the source and binary directories from a build stage so that they + can be re-used in the next stage. This action is used to the release + binaries workflow into multiple stages to avoid the 6 hour timeout on + the GitHub hosted runners. +inputs: + build-prefix: + description: "Directory containing the build directory." + required: true + type: 'string' + +runs: + using: "composite" + steps: + # We need to create an archive of the build directory, because it has too + # many files to upload. + - name: Package Build and Source Directories + shell: bash + run: | + # Windows does not support symlinks, so we need to dereference them. + tar --exclude build/ ${{ (runner.os == 'Windows' && '-h') || '' }} -c . | zstd -T0 -c > ../llvm-project.tar.zst + mv ../llvm-project.tar.zst . + tar -C ${{ inputs.build-prefix }} -c build/ | zstd -T0 -c > build.tar.zst + + - name: Upload Stage 1 Source + uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0 + with: + name: ${{ runner.os }}-${{ runner.arch }}-${{ github.job }}-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: ${{ runner.os}}-${{ runner.arch }}-${{ github.job }}-build + path: build.tar.zst + retention-days: 2 diff --git a/.github/workflows/release-binaries-setup-stage/action.yml b/.github/workflows/release-binaries-setup-stage/action.yml new file mode 100644 index 000000000000000..f5e5db27e659523 --- /dev/null +++ b/.github/workflows/release-binaries-setup-stage/action.yml @@ -0,0 +1,59 @@ +name: Setup Stage +description: >- + Setup the next stage of the release binaries workflow. This sets up the + environment correctly for a new stage of the release binaries workflow + and also restores the source and build directory from the previous stage. + +inputs: + previous-artifact: + description: >- + A unique descriptor for the artifact from the previous stage. This will + be used to construct the final artifact pattern, which is: + $RUNNER_OS-$RUNNER_ARCH-$PREVIOUS_ARTIFACT-* + required: false + type: 'string' + +outputs: + build-prefix: + description: "Directory containing the build directory." + value: ${{ steps.build-prefix.outputs.build-prefix }} + +runs: + using: "composite" + steps: + - name: Install Ninja + uses: llvm/actions/install-ninja@22e9f909d35b50bd1181709564bfe816eaeaae81 # main + + - name: Setup Windows + if: startsWith(runner.os, 'Windows') + uses: llvm/actions/setup-windows@main + with: + arch: amd64 + + - name: Set Build Prefix + id: build-prefix + shell: bash + run: | + build_prefix=`pwd` + if [ "${{ runner.os }}" = "Linux" ]; then + sudo chown $USER:$USER /mnt/ + build_prefix=/mnt/ + fi + echo "build-prefix=$build_prefix" >> $GITHUB_OUTPUT + + - name: Download Previous Stage Artifact + if: ${{ inputs.previous-artifact }} + id: download + uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 + with: + pattern: ${{ runner.os }}-${{ runner.arch }}-${{ inputs.previous-artifact }}-* + merge-multiple: true + + - name: Unpack Artifact + if: ${{ steps.download.outputs.download-path }} + shell: bash + run: | + tar --zstd -xf llvm-project.tar.zst + rm llvm-project.tar.zst + tar --zstd -C ${{ steps.build-prefix.outputs.build-prefix}} -xf build.tar.zst + rm build.tar.zst diff --git a/.github/workflows/release-binaries.yml b/.github/workflows/release-binaries.yml index 7de4d00334d14a5..b1b046dbad5f8ba 100644 --- a/.github/workflows/release-binaries.yml +++ b/.github/workflows/release-binaries.yml @@ -5,28 +5,38 @@ on: inputs: release-version: description: 'Release Version' - required: true + required: false type: string upload: description: 'Upload binaries to the release page' required: true default: false type: boolean + runs-on: + description: "Runner to use for the build" + required: true + type: choice + options: + - ubuntu-22.04 + - windows-2022 + - macos-13 + - macos-14 workflow_call: inputs: release-version: description: 'Release Version' - required: true + required: false type: string upload: description: 'Upload binaries to the release page' required: true default: false type: boolean - schedule: - # * is a special character in YAML so you have to quote this string - - cron: '0 8 1 * *' + runs-on: + description: "Runner to use for the build" + required: true + type: string permissions: contents: read # Default everything to read-only @@ -34,30 +44,39 @@ permissions: jobs: prepare: name: Prepare to build binaries - runs-on: ubuntu-22.04 + runs-on: ${{ inputs.runs-on }} if: github.repository == 'llvm/llvm-project' outputs: release-version: ${{ steps.vars.outputs.release-version }} ref: ${{ steps.vars.outputs.ref }} upload: ${{ steps.vars.outputs.upload }} + target-cmake-flags: ${{ steps.vars.outputs.target-cmake-flags }} + build-flang: ${{ steps.vars.outputs.build-flang }} + enable-pgo: ${{ steps.vars.outputs.enable-pgo }} + release-binary-basename: ${{ steps.vars.outputs.release-binary-basename }} + release-binary-filename: ${{ steps.vars.outputs.release-binary-filename }} steps: - name: Checkout LLVM uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Install Dependencies + shell: bash run: | pip install --require-hashes -r ./llvm/utils/git/requirements.txt - name: Check Permissions + if: github.event_name != 'pull_request' env: GITHUB_TOKEN: ${{ github.token }} USER_TOKEN: ${{ secrets.RELEASE_TASKS_USER_TOKEN }} + shell: bash run: | ./llvm/utils/release/./github-upload-release.py --token "$GITHUB_TOKEN" --user ${{ github.actor }} --user-token "$USER_TOKEN" check-permissions - name: Collect Variables id: vars + shell: bash # In order for the test-release.sh script to run correctly, the LLVM # source needs to be at the following location relative to the build dir: # | X.Y.Z-rcN | ./rcN/llvm-project @@ -67,242 +86,393 @@ jobs: # | X.Y.Z-rcN | -rc N -test-asserts # | X.Y.Z | -final run: | - tag="${{ github.ref_name }}" trimmed=$(echo ${{ inputs.release-version }} | xargs) - [[ "$trimmed" != "" ]] && tag="llvmorg-$trimmed" - if [ "$tag" = "main" ]; then - # If tag is main, then we've been triggered by a scheduled so pass so - # use the head commit as the tag. - tag=`git rev-parse HEAD` + if [ -n "$trimmed" ]; then + release_version="$trimmed" + ref="llvmorg-$release_version" + else + release_version="${{ (github.event_name == 'pull_request' && format('PR{0}', github.event.pull_request.number)) || 'CI'}}-${{ github.sha }}" + ref=${{ github.sha }} fi if [ -n "${{ inputs.upload }}" ]; then upload="${{ inputs.upload }}" else upload="false" fi - bash .github/workflows/set-release-binary-outputs.sh "$tag" "$upload" + echo "release-version=$release_version">> $GITHUB_OUTPUT + echo "ref=$ref" >> $GITHUB_OUTPUT + echo "upload=$upload" >> $GITHUB_OUTPUT + + release_binary_basename="LLVM-$release_version-${{ runner.os }}-${{ runner.arch }}" + echo "release-binary-basename=$release_binary_basename" >> $GITHUB_OUTPUT + echo "release-binary-filename=$release_binary_basename.tar.xz" >> $GITHUB_OUTPUT + + # Detect necessary CMake flags + target="${{ runner.os }}-${{ runner.arch }}" + echo "enable-pgo=false" >> $GITHUB_OUTPUT + target_cmake_flags="-DLLVM_RELEASE_ENABLE_PGO=OFF" + # The macOS builds try to cross compile some libraries so we need to + # add extra CMake args to disable them. + # See https://github.com/llvm/llvm-project/issues/99767 + if [ "${{ runner.os }}" = "macOS" ]; then + target_cmake_flags="$target_cmake_flags -DBOOTSTRAP_COMPILER_RT_ENABLE_IOS=OFF" + if [ "${{ runner.arch }}" = "ARM64" ]; then + arches=arm64 + else + arches=x86_64 + fi + target_cmake_flags="$target_cmake_flags -DBOOTSTRAP_DARWIN_osx_ARCHS=$arches -DBOOTSTRAP_DARWIN_osx_BUILTIN_ARCHS=$arches" + fi + + # x86 macOS and x86 Windows have trouble building flang, so disable it. + # Windows: https://github.com/llvm/llvm-project/issues/100202 + # macOS: 'rebase opcodes terminated early at offset 1 of 80016' when building __fortran_builtins.mod + build_flang="true" + + if [ "$target" = "Windows-X64" ]; then + target_cmake_flags="$target_cmake_flags -DLLVM_RELEASE_ENABLE_PROJECTS=\"clang;lld;lldb;clang-tools-extra;bolt;polly;mlir\"" + build_flang="false" + fi + + if [ "${{ runner.os }}" = "Windows" ]; then + # The build times out on Windows, so we need to disable LTO. + target_cmake_flags="$target_cmake_flags -DLLVM_RELEASE_ENABLE_LTO=OFF" + fi - build-stage1-linux: - name: "Build Stage 1 Linux" + echo "target-cmake-flags=$target_cmake_flags" >> $GITHUB_OUTPUT + echo "build-flang=$build_flang" >> $GITHUB_OUTPUT + + build-stage1: + name: "Build Stage 1" needs: prepare - runs-on: ubuntu-22.04 if: github.repository == 'llvm/llvm-project' + runs-on: ${{ inputs.runs-on }} steps: + + - name: Checkout Actions + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + with: + ref: ${{ (github.event_name == 'pull_request' && github.sha) || 'main' }} + sparse-checkout: | + .github/workflows/ + sparse-checkout-cone-mode: false + # Check out outside of working directory so the source checkout doesn't + # remove it. + path: workflows + + # actions/checkout does not support paths outside of the GITHUB_WORKSPACE. + # Also, anything that we put inside of GITHUB_WORKSPACE will be overwritten + # by future actions/checkout steps. Therefore, in order to checkout the + # latest actions from main, we need to first checkout out the actions inside of + # GITHUB_WORKSPACE (see previous step), then use actions/checkout to checkout + # the code being built and the move the actions from main back into GITHUB_WORKSPACE, + # becasue the uses on composite actions only reads workflows from inside GITHUB_WORKSPACE. + - shell: bash + run: mv workflows ../workflows-main + - name: Checkout LLVM uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: ref: ${{ needs.prepare.outputs.ref }} - - name: Install Ninja - uses: llvm/actions/install-ninja@22e9f909d35b50bd1181709564bfe816eaeaae81 # main + - name: Copy main workflows + shell: bash + run: | + mv ../workflows-main . + + - name: Setup Stage + id: setup-stage + uses: ./workflows-main/.github/workflows/release-binaries-setup-stage - name: Setup sccache uses: hendrikmuhs/ccache-action@ca3acd2731eef11f1572ccb126356c2f9298d35e # v1.2.9 with: - max-size: 250M - key: sccache-${{ runner.os }}-release + # Default to 2G to workaround: https://github.com/hendrikmuhs/ccache-action/issues/174 + max-size: 2G + key: sccache-${{ runner.os }}-${{ runner.arch }}-release variant: sccache - name: Build Stage 1 Clang + id: build + shell: bash run: | - 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 - - - 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 + # There were some issues on the ARM64 MacOS runners with trying to build x86 object, + # so we need to set some extra cmake flags to disable this. + cmake -G Ninja -S llvm -B ${{ steps.setup-stage.outputs.build-prefix }}/build \ + ${{ needs.prepare.outputs.target-cmake-flags }} \ + -C clang/cmake/caches/Release.cmake \ + -DBOOTSTRAP_LLVM_PARALLEL_LINK_JOBS=1 \ + -DBOOTSTRAP_CPACK_PACKAGE_FILE_NAME="${{ needs.prepare.outputs.release-binary-basename }}" \ + -DCMAKE_C_COMPILER_LAUNCHER=sccache \ + -DCMAKE_CXX_COMPILER_LAUNCHER=sccache + ninja -v -C ${{ steps.setup-stage.outputs.build-prefix }}/build + # There is a race condition on the MacOS builders and this command is here + # to help debug that when it happens. + ls -ltr ${{ steps.setup-stage.outputs.build-prefix }}/build + + - name: Save Stage + uses: ./workflows-main/.github/workflows/release-binaries-save-stage with: - name: stage1-build - path: build.tar.zst - retention-days: 2 + build-prefix: ${{ steps.setup-stage.outputs.build-prefix }} - build-stage2-linux: - name: "Build Stage 2 Linux" + build-stage2: + name: "Build Stage 2" needs: - prepare - - build-stage1-linux - runs-on: ubuntu-22.04 + - build-stage1 if: github.repository == 'llvm/llvm-project' + runs-on: ${{ inputs.runs-on }} steps: - - name: Install Ninja - uses: llvm/actions/install-ninja@22e9f909d35b50bd1181709564bfe816eaeaae81 # main - - - name: Download Stage 1 Artifacts - uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 + - name: Checkout Actions + uses: actions/checkout@v4 with: - pattern: stage1-* - merge-multiple: true - - - 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 + ref: ${{ (github.event_name == 'pull_request' && github.sha) || 'main' }} + sparse-checkout: | + .github/workflows/ + sparse-checkout-cone-mode: false + path: workflows + - name: Setup Stage + id: setup-stage + uses: ./workflows/.github/workflows/release-binaries-setup-stage + with: + previous-artifact: build-stage1 - name: Build Stage 2 # Re-enable once PGO builds are supported. - if: false - 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 + if: needs.prepare.outputs.enable-pgo == 'true' + shell: bash run: | - tar -c . | zstd -T0 -c > llvm-project.tar.zst - tar -C /mnt/ -c build/ | zstd -T0 -c > build.tar.zst + ninja -C ${{ steps.setup-stage.outputs.build-prefix}}/build stage2-instrumented - - name: Upload Stage 2 Source - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0 + - name: Save Stage + uses: ./workflows/.github/workflows/release-binaries-save-stage with: - name: stage2-source - path: ${{ github.workspace }}/llvm-project.tar.zst - retention-days: 2 + build-prefix: ${{ steps.setup-stage.outputs.build-prefix }} - - name: Upload Stage 2 Build Dir - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0 + build-stage3-clang: + name: "Build Stage 3 LLVM/Clang" + needs: + - prepare + - build-stage2 + if: github.repository == 'llvm/llvm-project' + runs-on: ${{ inputs.runs-on }} + steps: + - name: Checkout Actions + uses: actions/checkout@v4 + with: + ref: ${{ (github.event_name == 'pull_request' && github.sha) || 'main' }} + sparse-checkout: | + .github/workflows/ + sparse-checkout-cone-mode: false + path: workflows + - name: Setup Stage + id: setup-stage + uses: ./workflows/.github/workflows/release-binaries-setup-stage with: - name: stage2-build - path: ${{ github.workspace }}/build.tar.zst - retention-days: 2 + previous-artifact: build-stage2 + - name: Build LLVM/Clang + shell: bash + run: | + # There is a race condition on the MacOS builders and this command is here + # to help debug that when it happens. + ls -ltr ${{ steps.setup-stage.outputs.build-prefix }}/build + ninja -C ${{ steps.setup-stage.outputs.build-prefix }}/build stage2-clang + # Build some of the larger binaries here too. + ninja -C ${{ steps.setup-stage.outputs.build-prefix }}/build/tools/clang/stage2-bins/ \ + clang-scan-deps \ + modularize clangd \ + clangd-indexer \ + clang-check \ + ${{ (runner.os == 'Linux' && 'clangd-fuzzer') || '' }} \ + clang-tidy \ + llc \ + lli \ + llvm-exegesis \ + llvm-opt-fuzzer \ + llvm-reduce \ + llvm-lto \ + dsymutil + + - name: Save Stage + uses: ./workflows/.github/workflows/release-binaries-save-stage + with: + build-prefix: ${{ steps.setup-stage.outputs.build-prefix }} - build-stage3-linux: - name: "Build Stage 3 Linux" + build-stage3-flang: + name: "Build Stage 3 Flang/MLIR/Bolt" 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' + - build-stage3-clang + runs-on: ${{ inputs.runs-on }} steps: - - name: Install Ninja - uses: llvm/actions/install-ninja@22e9f909d35b50bd1181709564bfe816eaeaae81 # main - - - name: 'Download artifact' - uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 + - name: Checkout Actions + uses: actions/checkout@v4 with: - pattern: stage2-* - merge-multiple: true + ref: ${{ (github.event_name == 'pull_request' && github.sha) || 'main' }} + sparse-checkout: | + .github/workflows/ + sparse-checkout-cone-mode: false + path: workflows + - name: Setup Stage + id: setup-stage + uses: ./workflows/.github/workflows/release-binaries-setup-stage + with: + previous-artifact: build-stage3-clang - - name: Unpack Artifact + - name: Build Flang / MLIR / Bolt + shell: bash 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 + # Build some of the mlir tools that take a long time to link + if [ "${{ needs.prepare.outputs.build-flang }}" = "true" ]; then + ninja -C ${{ steps.setup-stage.outputs.build-prefix }}/build/tools/clang/stage2-bins/ -j2 flang-new bbc + fi + ninja -C ${{ steps.setup-stage.outputs.build-prefix }}/build/tools/clang/stage2-bins/ \ + mlir-bytecode-parser-fuzzer \ + mlir-cpu-runner \ + mlir-lsp-server \ + mlir-opt \ + mlir-query \ + mlir-reduce \ + mlir-text-parser-fuzzer \ + mlir-translate \ + mlir-transform-opt \ + mlir-cat \ + mlir-minimal-opt \ + mlir-minimal-opt-canonicalize \ + mlir-pdll-lsp-server \ + llvm-bolt \ + llvm-bolt-heatmap + + - name: Save Stage + uses: ./workflows/.github/workflows/release-binaries-save-stage + with: + build-prefix: ${{ steps.setup-stage.outputs.build-prefix }} - - name: Build Release Package - run: | - ninja -C /mnt/build stage2-package + build-stage3-all: + name: "Build Stage 3" + needs: + - prepare + - build-stage3-flang + runs-on: ${{ inputs.runs-on }} + steps: + - name: Checkout Actions + uses: actions/checkout@v4 + with: + ref: ${{ (github.event_name == 'pull_request' && github.sha) || 'main' }} + sparse-checkout: | + .github/workflows/ + sparse-checkout-cone-mode: false + path: workflows + - name: Setup Stage + id: setup-stage + uses: ./workflows/.github/workflows/release-binaries-setup-stage + with: + previous-artifact: build-stage3-flang - - id: package-info + - name: Build Release Package + shell: bash run: | - filename="LLVM-${{ needs.prepare.outputs.release-version }}-Linux.tar.xz" - echo "filename=$filename" >> $GITHUB_OUTPUT - echo "path=/mnt/build/tools/clang/stage2-bins/$filename" >> $GITHUB_OUTPUT + which cmake + ninja -C ${{ steps.setup-stage.outputs.build-prefix }}/build stage2-package + # Copy Release artifact to the workspace so it is easier to upload. + # This is necessary, because on Windows, the build-prefix path can + # only be used on bash steps, because it uses the form of /d/files/ + # and other steps expect D:\files. + mv ${{ steps.setup-stage.outputs.build-prefix }}/build/tools/clang/stage2-bins/${{ needs.prepare.outputs.release-binary-filename }} . - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0 - if: always() with: - name: release-binary - path: ${{ steps.package-info.outputs.path }} + name: ${{ runner.os }}-${{ runner.arch }}-release-binary + # Due to path differences on Windows when running in bash vs running on node, + # we need to search for files in the current workspace. + path: | + ${{ needs.prepare.outputs.release-binary-filename }} # Clean up some build files to reduce size of artifact. - name: Clean Up Build Directory + shell: bash run: | - find /mnt/build -iname ${{ steps.package-info.outputs.filename }} -delete + find ${{ steps.setup-stage.outputs.build-prefix }}/build -iname ${{ needs.prepare.outputs.release-binary-filename }} -delete + rm -Rf ${{ steps.setup-stage.outputs.build-prefix }}/build/tools/clang/stage2-bins/_CPack_Packages - # 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 + - name: Save Stage + uses: ./workflows/.github/workflows/release-binaries-save-stage with: - name: stage3-build - path: build.tar.zst - retention-days: 2 + build-prefix: ${{ steps.setup-stage.outputs.build-prefix }} - upload-release-binaries-linux: - name: "Upload Linux Release Binaries" + upload-release-binaries: + name: "Upload Release Binaries" needs: - prepare - - build-stage3-linux - if : ${{ needs.prepare.outputs.upload == 'true' }} + - build-stage3-all + if: >- + always() && + github.event_name != 'pull_request' && + needs.prepare.outputs.upload == 'true' runs-on: ubuntu-22.04 permissions: contents: write # For release uploads + id-token: write # For artifact attestations + attestations: write # For artifact attestations steps: - name: 'Download artifact' uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 with: - name: release-binary + pattern: '*-release-binary' + merge-multiple: true + + - name: Attest Build Provenance + id: provenance + uses: actions/attest-build-provenance@897ed5eab6ed058a474202017ada7f40bfa52940 # v1.0.0 + with: + subject-path: ${{ needs.prepare.outputs.release-binary-filename }} + + - name: Rename attestation file + run: + mv ${{ steps.provenance.outputs.bundle-path }} ${{ needs.prepare.outputs.release-binary-filename }}.jsonl + + - name: Upload Build Provenance + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 #v4.3.3 + with: + name: ${{ runner.os }}-${{ runner.arch }}-release-binary-attestation + path: ${{ needs.prepare.outputs.release-binary-filename }}.jsonl - name: Upload Release + shell: bash run: | sudo apt install python3-github ./llvm-project/llvm/utils/release/github-upload-release.py \ --token ${{ github.token }} \ --release ${{ needs.prepare.outputs.release-version }} \ upload \ - --files ${{ needs.build-stage3-linux.outputs.release-filename }} - + --files ${{ needs.prepare.outputs.release-binary-filename }}* - test-stage3-linux: - name: "Test Stage 3 Linux" + test-stage3: + name: "Test Stage 3" needs: - prepare - - build-stage3-linux - runs-on: ubuntu-22.04 - if: github.repository == 'llvm/llvm-project' + - build-stage3-all + if: >- + github.repository == 'llvm/llvm-project' + runs-on: ${{ inputs.runs-on }} steps: - - name: Install Ninja - uses: llvm/actions/install-ninja@22e9f909d35b50bd1181709564bfe816eaeaae81 # main - - - name: 'Download artifact' - uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 + - name: Checkout Actions + uses: actions/checkout@v4 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 + ref: ${{ (github.event_name == 'pull_request' && github.sha) || 'main' }} + sparse-checkout: | + .github/workflows/ + sparse-checkout-cone-mode: false + path: workflows + - name: Setup Stage + id: setup-stage + uses: ./workflows/.github/workflows/release-binaries-setup-stage + with: + previous-artifact: build-stage3-all - name: Run Tests + shell: bash run: | - ninja -C /mnt/build stage2-check-all + ninja -C ${{ steps.setup-stage.outputs.build-prefix }}/build stage2-check-all diff --git a/.github/workflows/release-sources.yml b/.github/workflows/release-sources.yml index 9c5b1a9f017092c..b0c0b652f375857 100644 --- a/.github/workflows/release-sources.yml +++ b/.github/workflows/release-sources.yml @@ -47,7 +47,7 @@ jobs: steps: - id: inputs run: | - ref=${{ inputs.release-version || github.sha }} + ref=${{ (inputs.release-version && format('llvmorg-{0}', inputs.release-version)) || github.sha }} if [ -n "${{ inputs.release-version }}" ]; then export_args="-release ${{ inputs.release-version }} -final" else diff --git a/.github/workflows/release-tasks.yml b/.github/workflows/release-tasks.yml index 2ed56dace1d4c76..7dd4c306671b74f 100644 --- a/.github/workflows/release-tasks.yml +++ b/.github/workflows/release-tasks.yml @@ -81,10 +81,20 @@ jobs: needs: - validate-tag - release-create + strategy: + fail-fast: false + matrix: + runs-on: + - ubuntu-22.04 + - windows-2022 + - macos-13 + - macos-14 + uses: ./.github/workflows/release-binaries.yml with: release-version: ${{ needs.validate-tag.outputs.release-version }} upload: true + runs-on: ${{ matrix.runs-on }} release-sources: name: Package Release Sources diff --git a/bolt/CMakeLists.txt b/bolt/CMakeLists.txt index 74907ad118d12f2..9f5875dd212847c 100644 --- a/bolt/CMakeLists.txt +++ b/bolt/CMakeLists.txt @@ -1,6 +1,17 @@ +cmake_minimum_required(VERSION 3.20.0) + set(LLVM_SUBPROJECT_TITLE "BOLT") -include(ExternalProject) +if(NOT DEFINED LLVM_COMMON_CMAKE_UTILS) + set(LLVM_COMMON_CMAKE_UTILS ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) +endif() +include(${LLVM_COMMON_CMAKE_UTILS}/Modules/CMakePolicy.cmake + NO_POLICY_SCOPE) + +if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) + project(bolt) + set(BOLT_BUILT_STANDALONE TRUE) +endif() set(BOLT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(BOLT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) @@ -9,6 +20,42 @@ set(CMAKE_CXX_STANDARD 17) # Add path for custom modules. list(INSERT CMAKE_MODULE_PATH 0 "${BOLT_SOURCE_DIR}/cmake/modules") +include(GNUInstallDirs) + +# standalone build, copied from clang +if(BOLT_BUILT_STANDALONE) + set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to") + set(CMAKE_CXX_STANDARD_REQUIRED YES) + set(CMAKE_CXX_EXTENSIONS NO) + + if(NOT MSVC_IDE) + set(LLVM_ENABLE_ASSERTIONS ${ENABLE_ASSERTIONS} + CACHE BOOL "Enable assertions") + # Assertions should follow llvm-config's. + mark_as_advanced(LLVM_ENABLE_ASSERTIONS) + endif() + + find_package(LLVM REQUIRED HINTS "${LLVM_CMAKE_DIR}") + list(APPEND CMAKE_MODULE_PATH "${LLVM_DIR}") + + set(LLVM_MAIN_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../llvm" CACHE PATH "Path to LLVM source tree") + find_program(LLVM_TABLEGEN_EXE "llvm-tblgen" ${LLVM_TOOLS_BINARY_DIR} + NO_DEFAULT_PATH) + + # They are used as destination of target generators. + set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin) + set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib${LLVM_LIBDIR_SUFFIX}) + + include(AddLLVM) + include(TableGen) + include_directories(${LLVM_INCLUDE_DIRS}) + link_directories("${LLVM_LIBRARY_DIR}") + + set( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_INSTALL_BINDIR}" ) + set( CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_INSTALL_LIBDIR}/${LLVM_LIBDIR_SUFFIX}" ) + set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_INSTALL_LIBDIR}/${LLVM_LIBDIR_SUFFIX}") +endif() # standalone + # Determine default set of targets to build -- the intersection of # those BOLT supports and those LLVM is targeting. set(BOLT_TARGETS_TO_BUILD_all "AArch64;X86;RISCV") @@ -94,6 +141,8 @@ if (BOLT_ENABLE_RUNTIME) if(CMAKE_SYSROOT) list(APPEND extra_args -DCMAKE_SYSROOT=${CMAKE_SYSROOT}) endif() + + include(ExternalProject) ExternalProject_Add(bolt_rt SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/runtime" STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/bolt_rt-stamps @@ -104,6 +153,7 @@ if (BOLT_ENABLE_RUNTIME) -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} -DLLVM_LIBDIR_SUFFIX=${LLVM_LIBDIR_SUFFIX} -DLLVM_LIBRARY_DIR=${LLVM_LIBRARY_DIR} + -DBOLT_BUILT_STANDALONE=${BOLT_BUILT_STANDALONE} ${extra_args} INSTALL_COMMAND "" BUILD_ALWAYS True @@ -113,6 +163,8 @@ if (BOLT_ENABLE_RUNTIME) add_llvm_install_targets(install-bolt_rt DEPENDS bolt_rt bolt COMPONENT bolt) + set(LIBBOLT_RT_INSTR "${CMAKE_CURRENT_BINARY_DIR}/bolt_rt-bins/lib/libbolt_rt_instr.a") + set(LIBBOLT_RT_HUGIFY "${CMAKE_CURRENT_BINARY_DIR}/bolt_rt-bins/lib/libbolt_rt_hugify.a") endif() find_program(GNU_LD_EXECUTABLE NAMES ${LLVM_DEFAULT_TARGET_TRIPLE}-ld.bfd ld.bfd DOC "GNU ld") diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h index 5935ffaa46af7d0..6ea3b1af1024f3d 100644 --- a/bolt/include/bolt/Core/DebugData.h +++ b/bolt/include/bolt/Core/DebugData.h @@ -475,7 +475,8 @@ class DebugStrOffsetsWriter { } /// Update Str offset in .debug_str in .debug_str_offsets. - void updateAddressMap(uint32_t Index, uint32_t Address); + void updateAddressMap(uint32_t Index, uint32_t Address, + const DWARFUnit &Unit); /// Get offset for given index in original .debug_str_offsets section. uint64_t getOffset(uint32_t Index) const { return StrOffsets[Index]; } @@ -507,6 +508,8 @@ class DebugStrOffsetsWriter { std::unique_ptr StrOffsetsBuffer; std::unique_ptr StrOffsetsStream; std::map IndexToAddressMap; + [[maybe_unused]] + DenseSet DebugStrOffsetFinalized; SmallVector StrOffsets; std::unordered_map ProcessedBaseOffsets; bool StrOffsetSectionWasModified = false; diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h index b798c5b76fc28d9..deaf179140c0145 100644 --- a/bolt/include/bolt/Rewrite/DWARFRewriter.h +++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h @@ -15,7 +15,6 @@ #include "bolt/Core/GDBIndex.h" #include "llvm/ADT/StringRef.h" #include "llvm/CodeGen/DIE.h" -#include "llvm/DWP/DWP.h" #include "llvm/MC/MCContext.h" #include "llvm/Support/ToolOutputFile.h" #include @@ -41,13 +40,6 @@ class DWARFRewriter { uint64_t TypeHash; uint64_t TypeDIERelativeOffset; }; - /// Contains information for CU or TU so we can output correct {cu, tu}-index. - struct UnitMeta { - uint64_t Offset; - uint64_t Length; - uint64_t TUHash; - }; - using UnitMetaVectorType = std::vector; private: BinaryContext &BC; @@ -194,35 +186,6 @@ class DWARFRewriter { 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; - MapVector IndexEntries; - MapVector TypeIndexEntries; - StringMap KnownSections; - uint32_t ContributionOffsets[8] = {}; - uint32_t IndexVersion = 2; - uint64_t DebugInfoSize = 0; - uint16_t Version = 0; - bool IsDWP = false; - }; - /// Init .dwp file - void initDWPState(DWPState &); - - /// Write out .dwp File - void finalizeDWP(DWPState &); - - /// add content of dwo to .dwp file. - void updateDWP(DWARFUnit &, const OverriddenSectionsMap &, const UnitMeta &, - UnitMetaVectorType &, DWPState &, DebugLocWriter &, - DebugStrOffsetsWriter &, DebugStrWriter &); }; } // namespace bolt diff --git a/bolt/include/bolt/RuntimeLibs/RuntimeLibrary.h b/bolt/include/bolt/RuntimeLibs/RuntimeLibrary.h index e392029156bcea8..fc1db7369eb4a35 100644 --- a/bolt/include/bolt/RuntimeLibs/RuntimeLibrary.h +++ b/bolt/include/bolt/RuntimeLibs/RuntimeLibrary.h @@ -58,7 +58,16 @@ class RuntimeLibrary { uint64_t RuntimeFiniAddress{0}; uint64_t RuntimeStartAddress{0}; - /// Get the full path to a runtime library specified by \p LibFileName. + /// Get the full path to a runtime library specified by \p LibFileName and \p + /// ToolPath. + static std::string getLibPathByToolPath(StringRef ToolPath, + StringRef LibFileName); + + /// Get the full path to a runtime library by the install directory. + static std::string getLibPathByInstalled(StringRef LibFileName); + + /// Gets the full path to a runtime library based on whether it exists + /// in the install libdir or runtime libdir. static std::string getLibPath(StringRef ToolPath, StringRef LibFileName); /// Load a static runtime library specified by \p LibPath. diff --git a/bolt/lib/CMakeLists.txt b/bolt/lib/CMakeLists.txt index 22a6be44f6458cd..d0f921a1a1e2c40 100644 --- a/bolt/lib/CMakeLists.txt +++ b/bolt/lib/CMakeLists.txt @@ -1,3 +1,5 @@ +add_compile_definitions(CMAKE_INSTALL_FULL_LIBDIR="${CMAKE_INSTALL_FULL_LIBDIR}") + add_subdirectory(Core) add_subdirectory(Passes) add_subdirectory(Profile) diff --git a/bolt/lib/Core/DIEBuilder.cpp b/bolt/lib/Core/DIEBuilder.cpp index b0f550fd77318ed..8f6195f6b6ea191 100644 --- a/bolt/lib/Core/DIEBuilder.cpp +++ b/bolt/lib/Core/DIEBuilder.cpp @@ -78,7 +78,7 @@ static void addStringHelper(DebugStrOffsetsWriter &StrOffstsWriter, uint32_t NewOffset = StrWriter.addString(Str); if (Unit.getVersion() >= 5) { StrOffstsWriter.updateAddressMap(DIEAttrInfo.getDIEInteger().getValue(), - NewOffset); + NewOffset, Unit); return; } DIEBldr.replaceValue(&Die, DIEAttrInfo.getAttribute(), DIEAttrInfo.getForm(), diff --git a/bolt/lib/Core/DebugData.cpp b/bolt/lib/Core/DebugData.cpp index 002f58c4743466e..bd8aa807f1aaedd 100644 --- a/bolt/lib/Core/DebugData.cpp +++ b/bolt/lib/Core/DebugData.cpp @@ -851,7 +851,11 @@ void DebugStrOffsetsWriter::initialize(DWARFUnit &Unit) { StrOffsetsSection.Data.data() + Contr->Base + Offset)); } -void DebugStrOffsetsWriter::updateAddressMap(uint32_t Index, uint32_t Address) { +void DebugStrOffsetsWriter::updateAddressMap(uint32_t Index, uint32_t Address, + const DWARFUnit &Unit) { + assert(DebugStrOffsetFinalized.count(Unit.getOffset()) == 0 && + "Cannot update address map since debug_str_offsets was already " + "finalized for this CU."); IndexToAddressMap[Index] = Address; StrOffsetSectionWasModified = true; } @@ -906,6 +910,8 @@ void DebugStrOffsetsWriter::finalizeSection(DWARFUnit &Unit, } StrOffsetSectionWasModified = false; + assert(DebugStrOffsetFinalized.insert(Unit.getOffset()).second && + "debug_str_offsets was already finalized for this CU."); clear(); } diff --git a/bolt/lib/Rewrite/CMakeLists.txt b/bolt/lib/Rewrite/CMakeLists.txt index 34993af2623bfb8..5d114925f59b026 100644 --- a/bolt/lib/Rewrite/CMakeLists.txt +++ b/bolt/lib/Rewrite/CMakeLists.txt @@ -1,7 +1,6 @@ set(LLVM_LINK_COMPONENTS Core DebugInfoDWARF - DWP JITLink MC Object diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp index 674b5f17adb3fc6..3dfb65a744c8a4e 100644 --- a/bolt/lib/Rewrite/DWARFRewriter.cpp +++ b/bolt/lib/Rewrite/DWARFRewriter.cpp @@ -32,6 +32,7 @@ #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCObjectWriter.h" #include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCTargetOptionsCommandFlags.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" @@ -56,6 +57,8 @@ #undef DEBUG_TYPE #define DEBUG_TYPE "bolt" +static mc::RegisterMCTargetOptionsFlags MOF; + static void printDie(const DWARFDie &DIE) { DIDumpOptions DumpOpts; DumpOpts.ShowForm = true; @@ -328,14 +331,8 @@ static cl::opt KeepARanges( static cl::opt DwarfOutputPath( "dwarf-output-path", - cl::desc("Path to where .dwo files or dwp file will be written out to."), - cl::init(""), cl::cat(BoltCategory)); - -static cl::opt - WriteDWP("write-dwp", - cl::desc("output a single dwarf package file (dwp) instead of " - "multiple non-relocatable dwarf object files (dwo)."), - cl::init(false), cl::cat(BoltCategory)); + cl::desc("Path to where .dwo files will be written out to."), cl::init(""), + cl::cat(BoltCategory)); static cl::opt CreateDebugNames( "create-debug-names-section", @@ -467,23 +464,19 @@ createDIEStreamer(const Triple &TheTriple, raw_pwrite_stream &OutFile, return Streamer; } -static DWARFRewriter::UnitMeta -emitUnit(DIEBuilder &DIEBldr, DIEStreamer &Streamer, DWARFUnit &Unit) { +static void emitUnit(DIEBuilder &DIEBldr, DIEStreamer &Streamer, + DWARFUnit &Unit) { DIE *UnitDIE = DIEBldr.getUnitDIEbyUnit(Unit); - const DIEBuilder::DWARFUnitInfo &U = DIEBldr.getUnitInfoByDwarfUnit(Unit); Streamer.emitUnit(Unit, *UnitDIE); - uint64_t TypeHash = 0; - if (DWARFTypeUnit *DTU = dyn_cast_or_null(&Unit)) - TypeHash = DTU->getTypeHash(); - return {U.UnitOffset, U.UnitLength, TypeHash}; } -static void -emitDWOBuilder(const std::string &DWOName, DIEBuilder &DWODIEBuilder, - DWARFRewriter &Rewriter, DWARFUnit &SplitCU, DWARFUnit &CU, - DWARFRewriter::DWPState &State, DebugLocWriter &LocWriter, - DebugStrOffsetsWriter &StrOffstsWriter, - DebugStrWriter &StrWriter, GDBIndex &GDBIndexSection) { +static void emitDWOBuilder(const std::string &DWOName, + DIEBuilder &DWODIEBuilder, DWARFRewriter &Rewriter, + DWARFUnit &SplitCU, DWARFUnit &CU, + DebugLocWriter &LocWriter, + DebugStrOffsetsWriter &StrOffstsWriter, + DebugStrWriter &StrWriter, + GDBIndex &GDBIndexSection) { // Populate debug_info and debug_abbrev for current dwo into StringRef. DWODIEBuilder.generateAbbrevs(); DWODIEBuilder.finish(); @@ -496,28 +489,22 @@ emitDWOBuilder(const std::string &DWOName, DIEBuilder &DWODIEBuilder, std::unique_ptr Streamer = createDIEStreamer(*TheTriple, *ObjOS, "DwoStreamerInitAug2", DWODIEBuilder, GDBIndexSection); - DWARFRewriter::UnitMetaVectorType TUMetaVector; - DWARFRewriter::UnitMeta CUMI = {0, 0, 0}; if (SplitCU.getContext().getMaxDWOVersion() >= 5) { for (std::unique_ptr &CU : SplitCU.getContext().dwo_info_section_units()) { if (!CU->isTypeUnit()) continue; - DWARFRewriter::UnitMeta MI = - emitUnit(DWODIEBuilder, *Streamer, *CU.get()); - TUMetaVector.emplace_back(MI); + emitUnit(DWODIEBuilder, *Streamer, *CU.get()); } - CUMI = emitUnit(DWODIEBuilder, *Streamer, SplitCU); + emitUnit(DWODIEBuilder, *Streamer, SplitCU); } else { for (std::unique_ptr &CU : SplitCU.getContext().dwo_compile_units()) emitUnit(DWODIEBuilder, *Streamer, *CU.get()); // emit debug_types sections for dwarf4 - for (DWARFUnit *CU : DWODIEBuilder.getDWARF4TUVector()) { - DWARFRewriter::UnitMeta MI = emitUnit(DWODIEBuilder, *Streamer, *CU); - TUMetaVector.emplace_back(MI); - } + for (DWARFUnit *CU : DWODIEBuilder.getDWARF4TUVector()) + emitUnit(DWODIEBuilder, *Streamer, *CU); } Streamer->emitAbbrevs(DWODIEBuilder.getAbbrevs(), @@ -544,12 +531,8 @@ emitDWOBuilder(const std::string &DWOName, DIEBuilder &DWODIEBuilder, continue; OverriddenSections[Kind] = Contents; } - if (opts::WriteDWP) - Rewriter.updateDWP(CU, OverriddenSections, CUMI, TUMetaVector, State, - LocWriter, StrOffstsWriter, StrWriter); - else - Rewriter.writeDWOFiles(CU, OverriddenSections, DWOName, LocWriter, - StrOffstsWriter, StrWriter); + Rewriter.writeDWOFiles(CU, OverriddenSections, DWOName, LocWriter, + StrOffstsWriter, StrWriter); } using DWARFUnitVec = std::vector; @@ -662,9 +645,6 @@ void DWARFRewriter::updateDebugInfo() { DWARF5AcceleratorTable DebugNamesTable(opts::CreateDebugNames, BC, *StrWriter); GDBIndex GDBIndexSection(BC); - DWPState State; - if (opts::WriteDWP) - initDWPState(State); auto processSplitCU = [&](DWARFUnit &Unit, DWARFUnit &SplitCU, DIEBuilder &DIEBlder, DebugRangesSectionWriter &TempRangesSectionWriter, @@ -688,7 +668,7 @@ void DWARFRewriter::updateDebugInfo() { if (Unit.getVersion() >= 5) TempRangesSectionWriter.finalizeSection(); - emitDWOBuilder(DWOName, DWODIEBuilder, *this, SplitCU, Unit, State, + emitDWOBuilder(DWOName, DWODIEBuilder, *this, SplitCU, Unit, DebugLocDWoWriter, DWOStrOffstsWriter, DWOStrWriter, GDBIndexSection); }; @@ -711,7 +691,8 @@ void DWARFRewriter::updateDebugInfo() { RangesBase = RangesSectionWriter.getSectionOffset() + getDWARF5RngListLocListHeaderSize(); RangesSectionWriter.initSection(Unit); - StrOffstsWriter->finalizeSection(Unit, DIEBlder); + if (!SplitCU) + StrOffstsWriter->finalizeSection(Unit, DIEBlder); } else if (SplitCU) { RangesBase = LegacyRangesSectionWriter.get()->getSectionOffset(); } @@ -757,6 +738,8 @@ void DWARFRewriter::updateDebugInfo() { : std::optional(opts::DwarfOutputPath.c_str()); std::string DWOName = DIEBlder.updateDWONameCompDir( *StrOffstsWriter, *StrWriter, *CU, DwarfOutputPath, std::nullopt); + if (CU->getVersion() >= 5) + StrOffstsWriter->finalizeSection(*CU, DIEBlder); processSplitCU(*CU, **SplitCU, DIEBlder, *TempRangesSectionWriter, AddressWriter, DWOName, DwarfOutputPath); } @@ -768,9 +751,6 @@ void DWARFRewriter::updateDebugInfo() { DebugNamesTable.emitAccelTable(); - if (opts::WriteDWP) - finalizeDWP(State); - finalizeDebugSections(DIEBlder, DebugNamesTable, *Streamer, *ObjOS, OffsetMap, *FinalAddrWriter); GDBIndexSection.updateGdbIndexSection(OffsetMap, CUIndex, @@ -1816,220 +1796,6 @@ std::optional updateDebugData( } // namespace -void DWARFRewriter::initDWPState(DWPState &State) { - SmallString<0> OutputNameStr; - StringRef OutputName; - if (opts::DwarfOutputPath.empty()) { - OutputName = - Twine(opts::OutputFilename).concat(".dwp").toStringRef(OutputNameStr); - } else { - StringRef ExeFileName = llvm::sys::path::filename(opts::OutputFilename); - OutputName = Twine(opts::DwarfOutputPath) - .concat("/") - .concat(ExeFileName) - .concat(".dwp") - .toStringRef(OutputNameStr); - errs() << "BOLT-WARNING: dwarf-output-path is in effect and .dwp file will " - "possibly be written to another location that is not the same as " - "the executable\n"; - } - std::error_code EC; - State.Out = - std::make_unique(OutputName, EC, sys::fs::OF_None); - const object::ObjectFile *File = BC.DwCtx->getDWARFObj().getFile(); - State.TmpBC = createDwarfOnlyBC(*File); - State.Streamer = State.TmpBC->createStreamer(State.Out->os()); - State.MCOFI = State.Streamer->getContext().getObjectFileInfo(); - State.KnownSections = createKnownSectionsMap(*State.MCOFI); - MCSection *const StrSection = State.MCOFI->getDwarfStrDWOSection(); - - // Data Structures for DWP book keeping - // Size of array corresponds to the number of sections supported by DWO format - // in DWARF4/5. - - State.Strings = std::make_unique(*State.Streamer, StrSection); - - // Setup DWP code once. - DWARFContext *DWOCtx = BC.getDWOContext(); - - if (DWOCtx) { - State.CUIndex = &DWOCtx->getCUIndex(); - State.IsDWP = !State.CUIndex->getRows().empty(); - } -} - -void DWARFRewriter::finalizeDWP(DWPState &State) { - if (State.Version < 5) { - // Lie about there being no info contributions so the TU index only includes - // the type unit contribution for DWARF < 5. In DWARFv5 the TU index has a - // contribution to the info section, so we do not want to lie about it. - State.ContributionOffsets[0] = 0; - } - writeIndex(*State.Streamer.get(), State.MCOFI->getDwarfTUIndexSection(), - State.ContributionOffsets, State.TypeIndexEntries, - State.IndexVersion); - - if (State.Version < 5) { - // Lie about the type contribution for DWARF < 5. In DWARFv5 the type - // section does not exist, so no need to do anything about this. - State.ContributionOffsets[getContributionIndex(DW_SECT_EXT_TYPES, 2)] = 0; - // Unlie about the info contribution - State.ContributionOffsets[0] = 1; - } - writeIndex(*State.Streamer.get(), State.MCOFI->getDwarfCUIndexSection(), - State.ContributionOffsets, State.IndexEntries, State.IndexVersion); - - State.Streamer->finish(); - State.Out->keep(); -} - -void DWARFRewriter::updateDWP(DWARFUnit &CU, - const OverriddenSectionsMap &OverridenSections, - const DWARFRewriter::UnitMeta &CUMI, - DWARFRewriter::UnitMetaVectorType &TUMetaVector, - 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."); - // Skipping CUs that we failed to load. - std::optional DWOCU = BC.getDWOCU(DWOId); - if (!DWOCU) - return; - - if (State.Version == 0) { - State.Version = CU.getVersion(); - State.IndexVersion = State.Version < 5 ? 2 : 5; - } else if (State.Version != CU.getVersion()) { - errs() << "BOLT-ERROR: incompatible DWARF compile unit versions\n"; - exit(1); - } - - UnitIndexEntry CurEntry = {}; - CurEntry.DWOName = dwarf::toString( - CU.getUnitDIE().find({dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}), - ""); - const char *Name = CU.getUnitDIE().getShortName(); - if (Name) - CurEntry.Name = Name; - StringRef CurStrSection; - StringRef CurStrOffsetSection; - - // This maps each section contained in this file to its length. - // This information is later on used to calculate the contributions, - // i.e. offset and length, of each compile/type unit to a section. - std::vector> SectionLength; - - const DWARFUnitIndex::Entry *CUDWOEntry = nullptr; - if (State.IsDWP) - CUDWOEntry = State.CUIndex->getFromHash(DWOId); - - bool StrSectionWrittenOut = false; - const object::ObjectFile *DWOFile = - (*DWOCU)->getContext().getDWARFObj().getFile(); - - DebugRangeListsSectionWriter *RangeListssWriter = nullptr; - if (CU.getVersion() == 5) { - assert(RangeListsWritersByCU.count(DWOId) != 0 && - "No RangeListsWriter for DWO ID."); - RangeListssWriter = RangeListsWritersByCU[DWOId].get(); - } - auto AddType = [&](unsigned int Index, uint32_t IndexVersion, uint64_t Offset, - uint64_t Length, uint64_t Hash) -> void { - UnitIndexEntry TUEntry = CurEntry; - if (IndexVersion < 5) - TUEntry.Contributions[0] = {}; - TUEntry.Contributions[Index].setOffset(Offset); - TUEntry.Contributions[Index].setLength(Length); - State.ContributionOffsets[Index] += - 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 = 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, - StrOffstsWriter, StrWriter, OverridenSections); - if (!TOutData) - continue; - - StringRef OutData = *TOutData; - if (SectionName == "debug_types.dwo") { - State.Streamer->emitBytes(OutData); - continue; - } - - 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) { - CurStrOffsetSection = OutData; - StrOffsetsOutputData = std::move(OutputData); - } else { - State.Streamer->emitBytes(OutData); - } - unsigned int Index = - getContributionIndex(SectionIter->second.second, State.IndexVersion); - uint64_t Offset = State.ContributionOffsets[Index]; - uint64_t Length = OutData.size(); - if (CU.getVersion() >= 5 && - SectionIter->second.second == DWARFSectionKind::DW_SECT_INFO) { - for (UnitMeta &MI : TUMetaVector) - MI.Offset += State.DebugInfoSize; - - Offset = State.DebugInfoSize + CUMI.Offset; - Length = CUMI.Length; - State.DebugInfoSize += OutData.size(); - } - CurEntry.Contributions[Index].setOffset(Offset); - CurEntry.Contributions[Index].setLength(Length); - State.ContributionOffsets[Index] += - CurEntry.Contributions[Index].getLength32(); - } - - // Strings are combined in to a new string section, and de-duplicated - // 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()); - StrSectionWrittenOut = true; - } - } - CompileUnitIdentifiers CUI{DWOId, CurEntry.Name.c_str(), - CurEntry.DWOName.c_str()}; - auto P = State.IndexEntries.insert(std::make_pair(CUI.Signature, CurEntry)); - if (!P.second) { - Error Err = buildDuplicateError(*P.first, CUI, ""); - errs() << "BOLT-ERROR: " << toString(std::move(Err)) << "\n"; - return; - } - - // Handling TU - const unsigned Index = getContributionIndex( - State.IndexVersion < 5 ? DW_SECT_EXT_TYPES : DW_SECT_INFO, - State.IndexVersion); - for (UnitMeta &MI : TUMetaVector) - AddType(Index, State.IndexVersion, MI.Offset, MI.Length, MI.TUHash); -} - void DWARFRewriter::writeDWOFiles( DWARFUnit &CU, const OverriddenSectionsMap &OverridenSections, const std::string &DWOName, DebugLocWriter &LocWriter, diff --git a/bolt/lib/RuntimeLibs/HugifyRuntimeLibrary.cpp b/bolt/lib/RuntimeLibs/HugifyRuntimeLibrary.cpp index d114d70f2d37668..026f8d35c55c632 100644 --- a/bolt/lib/RuntimeLibs/HugifyRuntimeLibrary.cpp +++ b/bolt/lib/RuntimeLibs/HugifyRuntimeLibrary.cpp @@ -32,10 +32,10 @@ cl::opt "(which is what --hot-text relies on)."), cl::cat(BoltOptCategory)); -static cl::opt RuntimeHugifyLib( - "runtime-hugify-lib", - cl::desc("specify file name of the runtime hugify library"), - cl::init("libbolt_rt_hugify.a"), cl::cat(BoltOptCategory)); +static cl::opt + RuntimeHugifyLib("runtime-hugify-lib", + cl::desc("specify path of the runtime hugify library"), + cl::init("libbolt_rt_hugify.a"), cl::cat(BoltOptCategory)); } // namespace opts diff --git a/bolt/lib/RuntimeLibs/InstrumentationRuntimeLibrary.cpp b/bolt/lib/RuntimeLibs/InstrumentationRuntimeLibrary.cpp index cd1b975be7b90e6..53a0c811b41d580 100644 --- a/bolt/lib/RuntimeLibs/InstrumentationRuntimeLibrary.cpp +++ b/bolt/lib/RuntimeLibs/InstrumentationRuntimeLibrary.cpp @@ -26,7 +26,7 @@ namespace opts { cl::opt RuntimeInstrumentationLib( "runtime-instrumentation-lib", - cl::desc("specify file name of the runtime instrumentation library"), + cl::desc("specify path of the runtime instrumentation library"), cl::init("libbolt_rt_instr.a"), cl::cat(BoltOptCategory)); extern cl::opt InstrumentationFileAppendPID; diff --git a/bolt/lib/RuntimeLibs/RuntimeLibrary.cpp b/bolt/lib/RuntimeLibs/RuntimeLibrary.cpp index 276b034d71f96ad..336c6768a7f7126 100644 --- a/bolt/lib/RuntimeLibs/RuntimeLibrary.cpp +++ b/bolt/lib/RuntimeLibs/RuntimeLibrary.cpp @@ -26,8 +26,8 @@ using namespace bolt; void RuntimeLibrary::anchor() {} -std::string RuntimeLibrary::getLibPath(StringRef ToolPath, - StringRef LibFileName) { +std::string RuntimeLibrary::getLibPathByToolPath(StringRef ToolPath, + StringRef LibFileName) { StringRef Dir = llvm::sys::path::parent_path(ToolPath); SmallString<128> LibPath = llvm::sys::path::parent_path(Dir); llvm::sys::path::append(LibPath, "lib" LLVM_LIBDIR_SUFFIX); @@ -38,13 +38,36 @@ std::string RuntimeLibrary::getLibPath(StringRef ToolPath, llvm::sys::path::append(LibPath, "lib" LLVM_LIBDIR_SUFFIX); } llvm::sys::path::append(LibPath, LibFileName); - if (!llvm::sys::fs::exists(LibPath)) { - errs() << "BOLT-ERROR: library not found: " << LibPath << "\n"; - exit(1); - } return std::string(LibPath); } +std::string RuntimeLibrary::getLibPathByInstalled(StringRef LibFileName) { + SmallString<128> LibPath(CMAKE_INSTALL_FULL_LIBDIR); + llvm::sys::path::append(LibPath, LibFileName); + return std::string(LibPath); +} + +std::string RuntimeLibrary::getLibPath(StringRef ToolPath, + StringRef LibFileName) { + if (llvm::sys::fs::exists(LibFileName)) { + return std::string(LibFileName); + } + + std::string ByTool = getLibPathByToolPath(ToolPath, LibFileName); + if (llvm::sys::fs::exists(ByTool)) { + return ByTool; + } + + std::string ByInstalled = getLibPathByInstalled(LibFileName); + if (llvm::sys::fs::exists(ByInstalled)) { + return ByInstalled; + } + + errs() << "BOLT-ERROR: library not found: " << ByTool << ", " << ByInstalled + << ", or " << LibFileName << "\n"; + exit(1); +} + void RuntimeLibrary::loadLibrary(StringRef LibPath, BOLTLinker &Linker, BOLTLinker::SectionsMapper MapSections) { ErrorOr> MaybeBuf = diff --git a/bolt/lib/Target/AArch64/CMakeLists.txt b/bolt/lib/Target/AArch64/CMakeLists.txt index be03e247aa96b10..7e2d33e09b5a041 100644 --- a/bolt/lib/Target/AArch64/CMakeLists.txt +++ b/bolt/lib/Target/AArch64/CMakeLists.txt @@ -4,6 +4,18 @@ set(LLVM_LINK_COMPONENTS AArch64Desc ) +if(BOLT_BUILT_STANDALONE) + set(LLVM_TARGET_DEFINITIONS ${LLVM_MAIN_SRC_DIR}/lib/Target/AArch64/AArch64.td) + list(APPEND LLVM_TABLEGEN_FLAGS -I ${LLVM_MAIN_SRC_DIR}/lib/Target/AArch64) + tablegen(LLVM AArch64GenInstrInfo.inc -gen-instr-info) + tablegen(LLVM AArch64GenRegisterInfo.inc -gen-register-info) + tablegen(LLVM AArch64GenSystemOperands.inc -gen-searchable-tables) + tablegen(LLVM AArch64GenSubtargetInfo.inc -gen-subtarget) + + add_public_tablegen_target(AArch64CommonTableGen) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) +endif() + add_llvm_library(LLVMBOLTTargetAArch64 AArch64MCPlusBuilder.cpp diff --git a/bolt/lib/Target/RISCV/CMakeLists.txt b/bolt/lib/Target/RISCV/CMakeLists.txt index 7f9557606320088..5d19d38717de4ec 100644 --- a/bolt/lib/Target/RISCV/CMakeLists.txt +++ b/bolt/lib/Target/RISCV/CMakeLists.txt @@ -4,6 +4,19 @@ set(LLVM_LINK_COMPONENTS RISCVDesc ) +if(BOLT_BUILT_STANDALONE) + # tablegen, copied from llvm/lib/Target/RISCV/CMakeLists.txt + set(LLVM_TARGET_DEFINITIONS ${LLVM_MAIN_SRC_DIR}/lib/Target/RISCV/RISCV.td) + list(APPEND LLVM_TABLEGEN_FLAGS -I ${LLVM_MAIN_SRC_DIR}/lib/Target/RISCV) + tablegen(LLVM RISCVGenInstrInfo.inc -gen-instr-info) + tablegen(LLVM RISCVGenRegisterInfo.inc -gen-register-info) + tablegen(LLVM RISCVGenSearchableTables.inc -gen-searchable-tables) + tablegen(LLVM RISCVGenSubtargetInfo.inc -gen-subtarget) + + add_public_tablegen_target(RISCVCommonTableGen) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) +endif() + add_llvm_library(LLVMBOLTTargetRISCV RISCVMCPlusBuilder.cpp diff --git a/bolt/lib/Target/X86/CMakeLists.txt b/bolt/lib/Target/X86/CMakeLists.txt index 2b769bc7e7f5ce6..b274716e89a4c74 100644 --- a/bolt/lib/Target/X86/CMakeLists.txt +++ b/bolt/lib/Target/X86/CMakeLists.txt @@ -5,6 +5,18 @@ set(LLVM_LINK_COMPONENTS X86Desc ) +if(BOLT_BUILT_STANDALONE) + set(LLVM_TARGET_DEFINITIONS ${LLVM_MAIN_SRC_DIR}/lib/Target/X86/X86.td) + list(APPEND LLVM_TABLEGEN_FLAGS -I ${LLVM_MAIN_SRC_DIR}/lib/Target/X86) + tablegen(LLVM X86GenInstrInfo.inc -gen-instr-info -instr-info-expand-mi-operand-info=0) + tablegen(LLVM X86GenMnemonicTables.inc -gen-x86-mnemonic-tables -asmwriternum=1) + tablegen(LLVM X86GenRegisterInfo.inc -gen-register-info) + tablegen(LLVM X86GenSubtargetInfo.inc -gen-subtarget) + + add_public_tablegen_target(X86CommonTableGen) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) +endif() + add_llvm_library(LLVMBOLTTargetX86 X86MCPlusBuilder.cpp X86MCSymbolizer.cpp diff --git a/bolt/lib/Utils/CMakeLists.txt b/bolt/lib/Utils/CMakeLists.txt index d1403314274bd62..c452c1fac3772d1 100644 --- a/bolt/lib/Utils/CMakeLists.txt +++ b/bolt/lib/Utils/CMakeLists.txt @@ -1,15 +1,39 @@ +find_first_existing_vc_file("${LLVM_MAIN_SRC_DIR}" llvm_vc) +find_first_existing_vc_file("${BOLT_SOURCE_DIR}" bolt_vc) + +# The VC revision include that we want to generate. +set(version_inc "${CMAKE_CURRENT_BINARY_DIR}/VCSVersion.inc") + +set(generate_vcs_version_script "${LLVM_CMAKE_DIR}/GenerateVersionFromVCS.cmake") + +# Create custom target to generate the VC revision include. +add_custom_command(OUTPUT "${version_inc}" + DEPENDS "${llvm_vc}" "${bolt_vc}" "${generate_vcs_version_script}" + COMMAND ${CMAKE_COMMAND} "-DNAMES=BOLT" + "-DHEADER_FILE=${version_inc}" + "-DBOLT_SOURCE_DIR=${BOLT_SOURCE_DIR}" + "-DLLVM_VC_REPOSITORY=${llvm_vc_repository}" + "-DLLVM_VC_REVISION=${llvm_vc_revision}" + "-DLLVM_FORCE_VC_REVISION=${LLVM_FORCE_VC_REVISION}" + "-DLLVM_FORCE_VC_REPOSITORY=${LLVM_FORCE_VC_REPOSITORY}" + -P "${generate_vcs_version_script}") + +# Mark the generated header as being generated. +set_source_files_properties("${version_inc}" + PROPERTIES GENERATED TRUE + HEADER_FILE_ONLY TRUE) + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + add_llvm_library(LLVMBOLTUtils CommandLineOpts.cpp Utils.cpp - + ${version_inc} DISABLE_LLVM_LINK_LLVM_DYLIB LINK_LIBS ${LLVM_PTHREAD_LIB} - DEPENDS - llvm_vcsrevision_h - LINK_COMPONENTS Support ) diff --git a/bolt/lib/Utils/CommandLineOpts.cpp b/bolt/lib/Utils/CommandLineOpts.cpp index 47375abb2ad3b48..435a8fa9cafcaed 100644 --- a/bolt/lib/Utils/CommandLineOpts.cpp +++ b/bolt/lib/Utils/CommandLineOpts.cpp @@ -11,15 +11,15 @@ //===----------------------------------------------------------------------===// #include "bolt/Utils/CommandLineOpts.h" -#include "llvm/Support/VCSRevision.h" +#include "VCSVersion.inc" using namespace llvm; namespace llvm { namespace bolt { const char *BoltRevision = -#ifdef LLVM_REVISION - LLVM_REVISION; +#ifdef BOLT_REVISION + BOLT_REVISION; #else ""; #endif diff --git a/bolt/runtime/CMakeLists.txt b/bolt/runtime/CMakeLists.txt index 6a65f80fb9079f1..40f4fbc9f30d545 100644 --- a/bolt/runtime/CMakeLists.txt +++ b/bolt/runtime/CMakeLists.txt @@ -16,12 +16,19 @@ add_library(bolt_rt_instr STATIC instr.cpp ${CMAKE_CURRENT_BINARY_DIR}/config.h ) -set_target_properties(bolt_rt_instr PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${LLVM_LIBRARY_DIR}") +set_target_properties(bolt_rt_instr PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}") add_library(bolt_rt_hugify STATIC hugify.cpp ${CMAKE_CURRENT_BINARY_DIR}/config.h ) -set_target_properties(bolt_rt_hugify PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${LLVM_LIBRARY_DIR}") +set_target_properties(bolt_rt_hugify PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}") + +if(NOT BOLT_BUILT_STANDALONE) + add_custom_command(TARGET bolt_rt_instr POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/lib/libbolt_rt_instr.a" "${LLVM_LIBRARY_DIR}") + add_custom_command(TARGET bolt_rt_hugify POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/lib/libbolt_rt_hugify.a" "${LLVM_LIBRARY_DIR}") +endif() set(BOLT_RT_FLAGS -ffreestanding @@ -46,18 +53,23 @@ target_include_directories(bolt_rt_instr PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_compile_options(bolt_rt_hugify PRIVATE ${BOLT_RT_FLAGS}) target_include_directories(bolt_rt_hugify PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) -install(TARGETS bolt_rt_instr DESTINATION "lib${LLVM_LIBDIR_SUFFIX}") -install(TARGETS bolt_rt_hugify DESTINATION "lib${LLVM_LIBDIR_SUFFIX}") +install(TARGETS bolt_rt_instr DESTINATION "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}") +install(TARGETS bolt_rt_hugify DESTINATION "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}") if (CMAKE_CXX_COMPILER_ID MATCHES ".*Clang.*" AND CMAKE_SYSTEM_NAME STREQUAL "Darwin") add_library(bolt_rt_instr_osx STATIC instr.cpp ${CMAKE_CURRENT_BINARY_DIR}/config.h ) - set_target_properties(bolt_rt_instr_osx PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${LLVM_LIBRARY_DIR}") + set_target_properties(bolt_rt_instr_osx PROPERTIES ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}") target_include_directories(bolt_rt_instr_osx PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) target_compile_options(bolt_rt_instr_osx PRIVATE -target x86_64-apple-darwin19.6.0 ${BOLT_RT_FLAGS}) - install(TARGETS bolt_rt_instr_osx DESTINATION "lib${LLVM_LIBDIR_SUFFIX}") + install(TARGETS bolt_rt_instr_osx DESTINATION "${CMAKE_INSTALL_LIBDIR}${LLVM_LIBDIR_SUFFIX}") + + if(NOT BOLT_BUILT_STANDALONE) + add_custom_command(TARGET bolt_rt_instr_osx POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_CURRENT_BINARY_DIR}/lib/libbolt_rt_instr_osx.a" "${LLVM_LIBRARY_DIR}") + endif() endif() diff --git a/bolt/test/AArch64/dummy-return.s b/bolt/test/AArch64/dummy-return.s index a44634316173010..91f89dcb84762f0 100644 --- a/bolt/test/AArch64/dummy-return.s +++ b/bolt/test/AArch64/dummy-return.s @@ -1,4 +1,6 @@ -# REQUIRES: system-linux,target=aarch64{{.*}} +# This test checks instrumentation of static binary on AArch64. + +# REQUIRES: system-linux,bolt-runtime,target=aarch64{{.*}} # RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %s -o %t.o # RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -static diff --git a/bolt/test/X86/debug-fission-single-convert.s b/bolt/test/X86/debug-fission-single-convert.s index 5ea6eb8e353afba..02c9290211fc05e 100644 --- a/bolt/test/X86/debug-fission-single-convert.s +++ b/bolt/test/X86/debug-fission-single-convert.s @@ -41,19 +41,6 @@ # CHECK-ADDR-SEC: 0x00000000: Addrs: [ # CHECK-ADDR-SEC: 0x0000000000601000 -# RUN: llvm-bolt %t.exe --reorder-blocks=reverse --update-debug-sections --dwarf-output-path=%T -o %t.bolt.2.exe --write-dwp=true \ -# RUN: --always-convert-to-ranges=true -# RUN: not llvm-dwarfdump --show-form --verbose --debug-info %t.bolt.2.exe.dwp &> %tAddrIndexTestDwp -# RUN: cat %tAddrIndexTestDwp | FileCheck %s --check-prefix=CHECK-DWP-DEBUG - -# CHECK-DWP-DEBUG: DW_TAG_compile_unit [1] * -# CHECK-DWP-DEBUG: DW_AT_producer [DW_FORM_GNU_str_index] (indexed (0000000a) string = "clang version 13.0.0") -# CHECK-DWP-DEBUG: DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus) -# CHECK-DWP-DEBUG: DW_AT_name [DW_FORM_GNU_str_index] (indexed (0000000b) string = "foo") -# CHECK-DWP-DEBUG: DW_AT_GNU_dwo_name [DW_FORM_GNU_str_index] (indexed (0000000c) string = "foo") -# CHECK-DWP-DEBUG: DW_AT_GNU_dwo_id [DW_FORM_data8] (0x06105e732fad3796) - - //clang++ -ffunction-sections -fno-exceptions -g -gsplit-dwarf=split -S debug-fission-simple.cpp -o debug-fission-simple.s static int foo = 2; int doStuff(int val) { diff --git a/bolt/test/X86/debug-fission-single.s b/bolt/test/X86/debug-fission-single.s index 4350bd9ec18158b..1aa502fc9a84074 100644 --- a/bolt/test/X86/debug-fission-single.s +++ b/bolt/test/X86/debug-fission-single.s @@ -42,18 +42,6 @@ # CHECK-ADDR-SEC: 0x00000000: Addrs: [ # CHECK-ADDR-SEC: 0x0000000000601000 -# RUN: llvm-bolt %t.exe --reorder-blocks=reverse --update-debug-sections --dwarf-output-path=%T -o %t.bolt.2.exe --write-dwp=true -# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt.2.exe.dwp &> %tAddrIndexTestDwp -# RUN: cat %tAddrIndexTestDwp | FileCheck %s --check-prefix=CHECK-DWP-DEBUG - -# CHECK-DWP-DEBUG: DW_TAG_compile_unit [1] * -# CHECK-DWP-DEBUG: DW_AT_producer [DW_FORM_GNU_str_index] (indexed (0000000a) string = "clang version 13.0.0") -# CHECK-DWP-DEBUG: DW_AT_language [DW_FORM_data2] (DW_LANG_C_plus_plus) -# CHECK-DWP-DEBUG: DW_AT_name [DW_FORM_GNU_str_index] (indexed (0000000b) string = "foo") -# CHECK-DWP-DEBUG: DW_AT_GNU_dwo_name [DW_FORM_GNU_str_index] (indexed (0000000c) string = "foo") -# CHECK-DWP-DEBUG: DW_AT_GNU_dwo_id [DW_FORM_data8] (0x06105e732fad3796) - - //clang++ -ffunction-sections -fno-exceptions -g -gsplit-dwarf=split -S debug-fission-simple.cpp -o debug-fission-simple.s static int foo = 2; int doStuff(int val) { diff --git a/bolt/test/X86/dwarf4-ftypes-dwo-input-dwp-output.test b/bolt/test/X86/dwarf4-ftypes-dwo-input-dwp-output.test deleted file mode 100644 index d08b596ec8dd1f8..000000000000000 --- a/bolt/test/X86/dwarf4-ftypes-dwo-input-dwp-output.test +++ /dev/null @@ -1,30 +0,0 @@ -# REQUIRES: system-linux -; RUN: rm -rf %t -; RUN: mkdir %t -; RUN: cd %t -; RUN: llvm-mc --split-dwarf-file=main.dwo --triple=x86_64-unknown-linux-gnu \ -; RUN: --filetype=obj %p/Inputs/dwarf4-ftypes-split-dwarf.s -o=main.o -; RUN: %clang %cflags -gdwarf-4 -gsplit-dwarf=split main.o -o main.exe -; RUN: llvm-dwarfdump --show-form --verbose --debug-types main.dwo | FileCheck -check-prefix=PRE-BOLT %s -; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections --write-dwp -; RUN: llvm-dwarfdump --show-form --verbose --debug-types main.exe.bolt.dwp | FileCheck -check-prefix=BOLT %s -; RUN: llvm-dwarfdump --show-form --verbose --debug-tu-index main.exe.bolt.dwp | FileCheck -check-prefix=BOLT-DWP-TU-INDEX %s - -;; Test input into bolt a .dwo file with TU Index. -;; Make sure the output .dwp file has a type information. - -; PRE-BOLT: DW_TAG_type_unit -; PRE-BOLT: DW_TAG_type_unit - -; PRE-BOLT-DWP-TU-INDEX: version = 2, units = 2, slots = 4 -; PRE-BOLT-DWP-TU-INDEX: Index Signature -; PRE-BOLT-DWP-TU-INDEX: 0x675d23e4f33235f2 -; PRE-BOLT-DWP-TU-INDEX-NEXT: 0x49dc260088be7e56 - -; BOLT: DW_TAG_type_unit -; BOLT: DW_TAG_type_unit - -; BOLT-DWP-TU-INDEX: version = 2, units = 2, slots = 4 -; BOLT-DWP-TU-INDEX: Index Signature -; BOLT-DWP-TU-INDEX: 0x675d23e4f33235f2 -; BOLT-DWP-TU-INDEX-NEXT: 0x49dc260088be7e56 diff --git a/bolt/test/X86/dwarf4-ftypes-dwo-mono-input-dwp-output.test b/bolt/test/X86/dwarf4-ftypes-dwo-mono-input-dwp-output.test deleted file mode 100644 index 54382142afc8fb9..000000000000000 --- a/bolt/test/X86/dwarf4-ftypes-dwo-mono-input-dwp-output.test +++ /dev/null @@ -1,45 +0,0 @@ -# REQUIRES: system-linux -; RUN: rm -rf %t -; RUN: mkdir %t -; RUN: cd %t -; RUN: llvm-mc --split-dwarf-file=main.dwo -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-split-gdb-index-types-main.s -o main.o -; RUN: llvm-mc --split-dwarf-file=helper.dwo -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-split-gdb-index-types-helper.s -o helper1.o -; RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf4-types-helper2.s -o helper2.o -; RUN: %clang %cflags -gdwarf-4 -gsplit-dwarf=split main.o helper1.o helper2.o -o main.exe -; RUN: llvm-dwarfdump --show-form --verbose --debug-types main.dwo | FileCheck -check-prefix=PRE-BOLT %s -; RUN: llvm-dwarfdump --show-form --verbose --debug-types helper2.o | FileCheck -check-prefix=PRE-BOLT2 %s -; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections --write-dwp -; RUN: llvm-dwarfdump --show-form --verbose --debug-types main.exe.bolt.dwp | FileCheck -check-prefix=BOLT %s -; RUN: llvm-dwarfdump --show-form --verbose --debug-tu-index main.exe.bolt.dwp | FileCheck -check-prefix=BOLT-DWP-TU-INDEX %s - -;; Test input into bolt a .dwo file with TU Index. -;; Test split-dwarf and monolithic TUs. -;; Make sure the output .dwp file has a type information. - -; PRE-BOLT: 0x675d23e4f33235f2 -; PRE-BOLT: DW_TAG_type_unit -; PRE-BOLT: 0x49dc260088be7e56 -; PRE-BOLT: DW_TAG_type_unit - -; PRE-BOLT2: 0x8f55ac73549bc003 -; PRE-BOLT2: DW_TAG_type_unit -; PRE-BOLT2: 0xe7734af8fed0632e -; PRE-BOLT2: DW_TAG_type_unit - -; BOLT: 0x675d23e4f33235f2 -; BOLT: DW_TAG_type_unit -; BOLT: 0x49dc260088be7e56 -; BOLT: DW_TAG_type_unit -; BOLT: 0x104ec427d2ebea6f -; BOLT: DW_TAG_type_unit -; BOLT: 0xb4580bc1535df1e4 -; BOLT: DW_TAG_type_unit -; BOLT-NOT: 0x8f55ac73549bc003 -; BOLT-NOT: 0xe7734af8fed0632e - -; BOLT-DWP-TU-INDEX: version = 2, units = 4, slots = 8 -; BOLT-DWP-TU-INDEX: Index Signature -; BOLT-DWP-TU-INDEX: 0x675d23e4f33235f2 -; BOLT-DWP-TU-INDEX-NEXT: 0xb4580bc1535df1e4 -; BOLT-DWP-TU-INDEX-NEXT: 0x49dc260088be7e56 -; BOLT-DWP-TU-INDEX-NEXT: 0x104ec427d2ebea6f diff --git a/bolt/test/X86/dwarf5-df-larger-batch-size.test b/bolt/test/X86/dwarf5-df-larger-batch-size.test new file mode 100644 index 000000000000000..c2c5f63e07ad83b --- /dev/null +++ b/bolt/test/X86/dwarf5-df-larger-batch-size.test @@ -0,0 +1,28 @@ +; 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-input-lowpc-ranges-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-input-lowpc-ranges-other.s \ +; RUN: -split-dwarf-file=mainOther.dwo -o other.o +; RUN: %clang %cflags main.o other.o -o main.exe +; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections --cu-processing-batch-size=1 +; RUN: llvm-bolt main.exe -o main-batch.exe.bolt --update-debug-sections --cu-processing-batch-size=2 +; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt >> %t/foo.txt +; RUN: cat %t/foo.txt | FileCheck -check-prefix=BOLT %s +; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.exe.bolt >> %t/foo-batch.txt +; RUN: cat %t/foo-batch.txt | FileCheck -check-prefix=BOLT-BATCH %s + +;; Tests that BOLT correctly handles DWO name strings with larger batch sizes. + +; BOLT: DW_TAG_skeleton_unit +; BOLT: DW_AT_dwo_name [DW_FORM_strx1] (indexed (00000001) string = "main.dwo.dwo") + +; BOLT: DW_TAG_skeleton_unit +; BOLT: DW_AT_dwo_name [DW_FORM_strx1] (indexed (00000001) string = "mainOther.dwo.dwo") + +; BOLT-BATCH: DW_TAG_skeleton_unit +; BOLT-BATCH: DW_AT_dwo_name [DW_FORM_strx1] (indexed (00000001) string = "main.dwo.dwo") + +; BOLT-BATCH: DW_TAG_skeleton_unit +; BOLT-BATCH: DW_AT_dwo_name [DW_FORM_strx1] (indexed (00000001) string = "mainOther.dwo.dwo") 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 index 6c603ba4ee19d75..c8cfd82753d7795 100644 --- a/bolt/test/X86/dwarf5-df-types-modify-dwo-name-mixed.test +++ b/bolt/test/X86/dwarf5-df-types-modify-dwo-name-mixed.test @@ -72,59 +72,6 @@ ; 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-DWP-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 diff --git a/bolt/test/X86/dwarf5-df-types-modify-dwo-name.test b/bolt/test/X86/dwarf5-df-types-modify-dwo-name.test index 086f8f8139628e4..12a7f648c23257f 100644 --- a/bolt/test/X86/dwarf5-df-types-modify-dwo-name.test +++ b/bolt/test/X86/dwarf5-df-types-modify-dwo-name.test @@ -73,31 +73,6 @@ ; 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 diff --git a/bolt/test/X86/dwarf5-ftypes-dwo-mono-input-dwp-output.test b/bolt/test/X86/dwarf5-ftypes-dwo-mono-input-dwp-output.test deleted file mode 100644 index b6e9f60bbfc7079..000000000000000 --- a/bolt/test/X86/dwarf5-ftypes-dwo-mono-input-dwp-output.test +++ /dev/null @@ -1,55 +0,0 @@ -# REQUIRES: system-linux -; RUN: rm -rf %t -; RUN: mkdir %t -; RUN: cd %t -; RUN: llvm-mc --split-dwarf-file=main.dwo -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-split-gdb-index-types-main.s -o main.o -; RUN: llvm-mc --split-dwarf-file=helper.dwo -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-split-gdb-index-types-helper.s -o helper1.o -; RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-types-helper2.s -o helper2.o -; RUN: %clang %cflags -gdwarf-5 -gsplit-dwarf=split main.o helper1.o helper2.o -o main.exe -; RUN: llvm-dwarfdump --show-form --verbose --debug-info main.dwo | FileCheck -check-prefix=PRE-BOLT %s -; RUN: llvm-dwarfdump --show-form --verbose --debug-info helper2.o | FileCheck -check-prefix=PRE-BOLT2 %s -; RUN: llvm-bolt main.exe -o main.exe.bolt --update-debug-sections --write-dwp -; RUN: llvm-dwarfdump --show-form --verbose --debug-info -r 0 main.exe.bolt.dwp | FileCheck -check-prefix=BOLT %s -; RUN: llvm-dwarfdump --show-form --verbose --debug-tu-index main.exe.bolt.dwp | FileCheck -check-prefix=BOLT-DWP-TU-INDEX %s -; RUN: llvm-dwarfdump --show-form --verbose --debug-cu-index main.exe.bolt.dwp | FileCheck -check-prefix=BOLT-DWP-CU-INDEX %s - -;; Test input into bolt a .dwo file with TU Index. -;; Test split-dwarf and monolithic TUs. -;; Make sure the output .dwp file has a type and cu information. - -; PRE-BOLT: Type Unit -; PRE-BOLT-SAME: 0x675d23e4f33235f2 -; PRE-BOLT: Type Unit -; PRE-BOLT-SAME: 0x49dc260088be7e56 - -; PRE-BOLT2: 0x8f55ac73549bc003 -; PRE-BOLT2: DW_TAG_type_unit -; PRE-BOLT2: 0xe7734af8fed0632e -; PRE-BOLT2: DW_TAG_type_unit - -; BOLT: 0x00000000: Type Unit: length = 0x00000047 -; BOLT-SAME: 0x675d23e4f33235f2 -; BOLT: 0x0000004b: Type Unit: length = 0x0000003e -; BOLT-SAME: 0x49dc260088be7e56 -; BOLT: 0x0000008d: Compile Unit: length = 0x00000077 -; BOLT-SAME: 0x4257354d8bb35644 -; BOLT: 0x00000108: Type Unit: length = 0x00000047 -; BOLT-SAME: 0x104ec427d2ebea6f -; BOLT: 0x00000153: Type Unit: length = 0x0000003e -; BOLT-SAME: 0xb4580bc1535df1e4 -; BOLT: 0x00000195: Compile Unit: length = 0x00000054 -; BOLT-SAME: 0x7738bfb5f3edfb73 -; BOLT-NOT: 0x8f55ac73549bc003 -; BOLT-NOT: 0xe7734af8fed0632e - -; BOLT-DWP-TU-INDEX: version = 5, units = 4, slots = 8 -; BOLT-DWP-TU-INDEX: Index Signature -; BOLT-DWP-TU-INDEX: 3 0x675d23e4f33235f2 [0x0000000000000000, 0x000000000000004b) [0x00000000, 0x00000083) [0x00000000, 0x00000056) [0x00000000, 0x00000044) -; BOLT-DWP-TU-INDEX: 5 0xb4580bc1535df1e4 [0x0000000000000153, 0x0000000000000195) [0x00000083, 0x000000f9) [0x00000056, 0x000000ae) [0x00000044, 0x00000084) -; BOLT-DWP-TU-INDEX: 7 0x49dc260088be7e56 [0x000000000000004b, 0x000000000000008d) [0x00000000, 0x00000083) [0x00000000, 0x00000056) [0x00000000, 0x00000044) -; BOLT-DWP-TU-INDEX: 8 0x104ec427d2ebea6f [0x0000000000000108, 0x0000000000000153) [0x00000083, 0x000000f9) [0x00000056, 0x000000ae) [0x00000044, 0x00000084) - -; BOLT-DWP-CU-INDEX: version = 5, units = 2, slots = 4 -; BOLT-DWP-CU-INDEX: Index Signature -; BOLT-DWP-CU-INDEX: 1 0x4257354d8bb35644 [0x000000000000008d, 0x0000000000000108) [0x00000000, 0x00000083) [0x00000000, 0x00000056) [0x00000000, 0x00000044) -; BOLT-DWP-CU-INDEX: 4 0x7738bfb5f3edfb73 [0x0000000000000195, 0x00000000000001ed) [0x00000083, 0x000000f9) [0x00000056, 0x000000ae) [0x00000044, 0x00000084) diff --git a/bolt/test/lit.cfg.py b/bolt/test/lit.cfg.py index 3a6da210e01f080..da3ae34ba3bddb9 100644 --- a/bolt/test/lit.cfg.py +++ b/bolt/test/lit.cfg.py @@ -92,10 +92,22 @@ tool_dirs = [config.llvm_tools_dir, config.test_source_root] +llvm_bolt_args = [] + +if config.libbolt_rt_instr: + llvm_bolt_args.append(f"--runtime-instrumentation-lib={config.libbolt_rt_instr}") + +if config.libbolt_rt_hugify: + llvm_bolt_args.append(f"--runtime-hugify-lib={config.libbolt_rt_hugify}") + tools = [ ToolSubst("llc", unresolved="fatal"), ToolSubst("llvm-dwarfdump", unresolved="fatal"), - ToolSubst("llvm-bolt", unresolved="fatal"), + ToolSubst( + "llvm-bolt", + unresolved="fatal", + extra_args=llvm_bolt_args, + ), ToolSubst("llvm-boltdiff", unresolved="fatal"), ToolSubst("llvm-bolt-heatmap", unresolved="fatal"), ToolSubst("llvm-bat-dump", unresolved="fatal"), diff --git a/bolt/test/lit.site.cfg.py.in b/bolt/test/lit.site.cfg.py.in index 46cb326dfbae18b..457908fc7c44620 100644 --- a/bolt/test/lit.site.cfg.py.in +++ b/bolt/test/lit.site.cfg.py.in @@ -19,6 +19,8 @@ config.bolt_clang = "@BOLT_CLANG_EXE@" config.bolt_lld = "@BOLT_LLD_EXE@" config.targets_to_build = "@BOLT_TARGETS_TO_BUILD@" config.gnu_ld = "@GNU_LD_EXECUTABLE@" +config.libbolt_rt_instr = "@LIBBOLT_RT_INSTR@" +config.libbolt_rt_hugify = "@LIBBOLT_RT_HUGIFY@" import lit.llvm lit.llvm.initialize(lit_config, config) diff --git a/bolt/utils/docker/Dockerfile b/bolt/utils/docker/Dockerfile index 722a07e46f9e430..c2108f7aec53c08 100644 --- a/bolt/utils/docker/Dockerfile +++ b/bolt/utils/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:20.04 AS builder +FROM ubuntu:24.04 AS builder ARG DEBIAN_FRONTEND=noninteractive ENV TZ=UTC @@ -26,6 +26,6 @@ RUN mkdir build && \ ninja install-llvm-bolt install-perf2bolt install-merge-fdata \ install-llvm-boltdiff install-bolt_rt -FROM ubuntu:20.04 +FROM ubuntu:24.04 COPY --from=builder /home/bolt/install /usr/local diff --git a/clang-tools-extra/clang-doc/HTMLGenerator.cpp b/clang-tools-extra/clang-doc/HTMLGenerator.cpp index f6b5e8926f9032e..aef22453035c30a 100644 --- a/clang-tools-extra/clang-doc/HTMLGenerator.cpp +++ b/clang-tools-extra/clang-doc/HTMLGenerator.cpp @@ -16,6 +16,7 @@ #include "llvm/Support/JSON.h" #include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" +#include #include #include @@ -979,6 +980,18 @@ static llvm::Error serializeIndex(ClangDocContext &CDCtx) { "error creating index file: " + FileErr.message()); } + llvm::SmallString<128> RootPath(CDCtx.OutDirectory); + if (llvm::sys::path::is_relative(RootPath)) { + llvm::sys::fs::make_absolute(RootPath); + } + // Replace the escaped characters with a forward slash. It shouldn't matter + // when rendering the webpage in a web browser. This helps to prevent the + // JavaScript from escaping characters incorrectly, and introducing bad paths + // in the URLs. + std::string RootPathEscaped = RootPath.str().str(); + std::replace(RootPathEscaped.begin(), RootPathEscaped.end(), '\\', '/'); + OS << "var RootPath = \"" << RootPathEscaped << "\";\n"; + CDCtx.Idx.sort(); llvm::json::OStream J(OS, 2); std::function IndexToJSON = [&](const Index &I) { diff --git a/clang-tools-extra/clang-doc/assets/index.js b/clang-tools-extra/clang-doc/assets/index.js index 49818763a43935b..6a223de66f84ab1 100644 --- a/clang-tools-extra/clang-doc/assets/index.js +++ b/clang-tools-extra/clang-doc/assets/index.js @@ -1,42 +1,17 @@ -// Append using posix-style a file name or directory to Base -function append(Base, New) { - if (!New) - return Base; - if (Base) - Base += "/"; - Base += New; - return Base; -} - -// Get relative path to access FilePath from CurrentDirectory -function computeRelativePath(FilePath, CurrentDirectory) { - var Path = FilePath; - while (Path) { - if (CurrentDirectory == Path) - return FilePath.substring(Path.length + 1); - Path = Path.substring(0, Path.lastIndexOf("/")); - } - - var Dir = CurrentDirectory; - var Result = ""; - while (Dir) { - if (Dir == FilePath) - break; - Dir = Dir.substring(0, Dir.lastIndexOf("/")); - Result = append(Result, "..") +function genLink(Ref) { + // we treat the file paths different depending on if we're + // serving via a http server or viewing from a local + var Path = window.location.protocol.startsWith("file") ? + `${window.location.protocol}//${window.location.host}/${Ref.Path}` : + `${window.location.protocol}//${RootPath}/${Ref.Path}`; + if (Ref.RefType === "namespace") { + Path = `${Path}/index.html` + } else if (Ref.Path === "") { + Path = `${Path}${Ref.Name}.html`; + } else { + Path = `${Path}/${Ref.Name}.html`; } - Result = append(Result, FilePath.substring(Dir.length)) - return Result; -} - -function genLink(Ref, CurrentDirectory) { - var Path = computeRelativePath(Ref.Path, CurrentDirectory); - if (Ref.RefType == "namespace") - Path = append(Path, "index.html"); - else - Path = append(Path, Ref.Name + ".html") - - ANode = document.createElement("a"); + ANode = document.createElement("a"); ANode.setAttribute("href", Path); var TextNode = document.createTextNode(Ref.Name); ANode.appendChild(TextNode); diff --git a/clang-tools-extra/clang-tidy/add_new_check.py b/clang-tools-extra/clang-tidy/add_new_check.py index 3a62df1f510bac9..bd69bddcc682560 100755 --- a/clang-tools-extra/clang-tidy/add_new_check.py +++ b/clang-tools-extra/clang-tidy/add_new_check.py @@ -13,9 +13,12 @@ import argparse import io +import itertools import os import re import sys +import textwrap + # Adapts the module's CMakelist file. Returns 'True' if it could add a new # entry and 'False' if the entry already existed. @@ -53,7 +56,29 @@ def adapt_cmake(module_path, check_name_camel): # Adds a header for the new check. -def write_header(module_path, module, namespace, check_name, check_name_camel): +def write_header( + module_path, + module, + namespace, + check_name, + check_name_camel, + description, + lang_restrict, +): + wrapped_desc = "\n".join( + textwrap.wrap( + description, width=80, initial_indent="/// ", subsequent_indent="/// " + ) + ) + if lang_restrict: + override_supported = """ + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return %s; + }""" % ( + lang_restrict % {"lang": "LangOpts"} + ) + else: + override_supported = "" filename = os.path.join(module_path, check_name_camel) + ".h" print("Creating %s..." % filename) with io.open(filename, "w", encoding="utf8", newline="\n") as f: @@ -85,7 +110,7 @@ def write_header(module_path, module, namespace, check_name, check_name_camel): namespace clang::tidy::%(namespace)s { -/// FIXME: Write a short description. +%(description)s /// /// For the user-facing documentation see: /// http://clang.llvm.org/extra/clang-tidy/checks/%(module)s/%(check_name)s.html @@ -94,7 +119,7 @@ class %(check_name_camel)s : public ClangTidyCheck { %(check_name_camel)s(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context) {} void registerMatchers(ast_matchers::MatchFinder *Finder) override; - void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override;%(override_supported)s }; } // namespace clang::tidy::%(namespace)s @@ -107,6 +132,8 @@ class %(check_name_camel)s : public ClangTidyCheck { "check_name": check_name, "module": module, "namespace": namespace, + "description": wrapped_desc, + "override_supported": override_supported, } ) @@ -235,7 +262,12 @@ def adapt_module(module_path, module, check_name, check_name_camel): # Adds a release notes entry. -def add_release_notes(module_path, module, check_name): +def add_release_notes(module_path, module, check_name, description): + wrapped_desc = "\n".join( + textwrap.wrap( + description, width=80, initial_indent=" ", subsequent_indent=" " + ) + ) check_name_dashes = module + "-" + check_name filename = os.path.normpath( os.path.join(module_path, "../../docs/ReleaseNotes.rst") @@ -281,10 +313,10 @@ def add_release_notes(module_path, module, check_name): """- New :doc:`%s ` check. - FIXME: add release notes. +%s """ - % (check_name_dashes, module, check_name) + % (check_name_dashes, module, check_name, wrapped_desc) ) note_added = True @@ -292,7 +324,9 @@ def add_release_notes(module_path, module, check_name): # Adds a test for the check. -def write_test(module_path, module, check_name, test_extension): +def write_test(module_path, module, check_name, test_extension, test_standard): + if test_standard: + test_standard = f"-std={test_standard}-or-later " check_name_dashes = module + "-" + check_name filename = os.path.normpath( os.path.join( @@ -309,7 +343,7 @@ def write_test(module_path, module, check_name, test_extension): print("Creating %s..." % filename) with io.open(filename, "w", encoding="utf8", newline="\n") as f: f.write( - """// RUN: %%check_clang_tidy %%s %(check_name_dashes)s %%t + """// RUN: %%check_clang_tidy %(standard)s%%s %(check_name_dashes)s %%t // FIXME: Add something that triggers the check here. void f(); @@ -324,7 +358,7 @@ def write_test(module_path, module, check_name, test_extension): // FIXME: Add something that doesn't trigger the check here. void awesome_f2(); """ - % {"check_name_dashes": check_name_dashes} + % {"check_name_dashes": check_name_dashes, "standard": test_standard} ) @@ -497,7 +531,10 @@ def format_link_alias(doc_file): if (match or (check_name.startswith("clang-analyzer-"))) and check_name: module = doc_file[0] check_file = doc_file[1].replace(".rst", "") - if not match or match.group(1) == "https://clang.llvm.org/docs/analyzer/checkers": + if ( + not match + or match.group(1) == "https://clang.llvm.org/docs/analyzer/checkers" + ): title = "Clang Static Analyzer " + check_file # Preserve the anchor in checkers.html from group 2. target = "" if not match else match.group(1) + ".html" + match.group(2) @@ -515,7 +552,7 @@ def format_link_alias(doc_file): if target: # The checker is just a redirect. return ( - " :doc:`%(check_name)s <%(module)s/%(check_file)s>`, %(ref_begin)s`%(title)s <%(target)s>`%(ref_end)s,%(autofix)s\n" + " :doc:`%(check_name)s <%(module)s/%(check_file)s>`, %(ref_begin)s`%(title)s <%(target)s>`%(ref_end)s,%(autofix)s\n" % { "check_name": check_name, "module": module, @@ -523,13 +560,14 @@ def format_link_alias(doc_file): "target": target, "title": title, "autofix": autofix, - "ref_begin" : ref_begin, - "ref_end" : ref_end - }) + "ref_begin": ref_begin, + "ref_end": ref_end, + } + ) else: # The checker is just a alias without redirect. return ( - " :doc:`%(check_name)s <%(module)s/%(check_file)s>`, %(title)s,%(autofix)s\n" + " :doc:`%(check_name)s <%(module)s/%(check_file)s>`, %(title)s,%(autofix)s\n" % { "check_name": check_name, "module": module, @@ -537,7 +575,8 @@ def format_link_alias(doc_file): "target": target, "title": title, "autofix": autofix, - }) + } + ) return "" checks = map(format_link, doc_files) @@ -599,6 +638,22 @@ def main(): "objc": "m", "objc++": "mm", } + cpp_language_to_requirements = { + "c++98": "CPlusPlus", + "c++11": "CPlusPlus11", + "c++14": "CPlusPlus14", + "c++17": "CPlusPlus17", + "c++20": "CPlusPlus20", + "c++23": "CPlusPlus23", + "c++26": "CPlusPlus26", + } + c_language_to_requirements = { + "c99": None, + "c11": "C11", + "c17": "C17", + "c23": "C23", + "c27": "C2Y", + } parser = argparse.ArgumentParser() parser.add_argument( "--update-docs", @@ -609,9 +664,26 @@ def main(): "--language", help="language to use for new check (defaults to c++)", choices=language_to_extension.keys(), - default="c++", + default=None, metavar="LANG", ) + parser.add_argument( + "--description", + "-d", + help="short description of what the check does", + default="FIXME: Write a short description", + type=str, + ) + parser.add_argument( + "--standard", + help="Specify a specific version of the language", + choices=list( + itertools.chain( + cpp_language_to_requirements.keys(), c_language_to_requirements.keys() + ) + ), + default=None, + ) parser.add_argument( "module", nargs="?", @@ -652,12 +724,53 @@ def main(): else: namespace = module - write_header(module_path, module, namespace, check_name, check_name_camel) + description = args.description + if not description.endswith("."): + description += "." + + language = args.language + + if args.standard: + if args.standard in cpp_language_to_requirements: + if language and language != "c++": + raise ValueError("C++ standard chosen when language is not C++") + language = "c++" + elif args.standard in c_language_to_requirements: + if language and language != "c": + raise ValueError("C standard chosen when language is not C") + language = "c" + + if not language: + language = "c++" + + language_restrict = None + + if language == "c": + language_restrict = "!%(lang)s.CPlusPlus" + extra = c_language_to_requirements.get(args.standard, None) + if extra: + language_restrict += f" && %(lang)s.{extra}" + elif language == "c++": + language_restrict = ( + f"%(lang)s.{cpp_language_to_requirements.get(args.standard, 'CPlusPlus')}" + ) + elif language in ["objc", "objc++"]: + language_restrict = "%(lang)s.ObjC" + + write_header( + module_path, + module, + namespace, + check_name, + check_name_camel, + description, + language_restrict, + ) write_implementation(module_path, module, namespace, check_name_camel) adapt_module(module_path, module, check_name, check_name_camel) - add_release_notes(module_path, module, check_name) - test_extension = language_to_extension.get(args.language) - write_test(module_path, module, check_name, test_extension) + add_release_notes(module_path, module, check_name, description) + test_extension = language_to_extension.get(language) + write_test(module_path, module, check_name, test_extension, args.standard) write_docs(module_path, module, check_name) update_checks_list(clang_tidy_path) print("Done. Now it's your turn!") diff --git a/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp b/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp index 95a3a5165e2e82e..43b69a24bdb16d6 100644 --- a/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/NonConstParameterCheck.cpp @@ -157,9 +157,12 @@ void NonConstParameterCheck::diagnoseNonConstParameters() { if (!Function) continue; unsigned Index = Par->getFunctionScopeIndex(); - for (FunctionDecl *FnDecl : Function->redecls()) + for (FunctionDecl *FnDecl : Function->redecls()) { + if (FnDecl->getNumParams() <= Index) + continue; Fixes.push_back(FixItHint::CreateInsertion( FnDecl->getParamDecl(Index)->getBeginLoc(), "const ")); + } diag(Par->getLocation(), "pointer parameter '%0' can be pointer to const") << Par->getName() << Fixes; diff --git a/clang-tools-extra/clang-tidy/utils/UseRangesCheck.cpp b/clang-tools-extra/clang-tidy/utils/UseRangesCheck.cpp index e2daa5010e2aeba..aba4d17ccd035eb 100644 --- a/clang-tools-extra/clang-tidy/utils/UseRangesCheck.cpp +++ b/clang-tools-extra/clang-tidy/utils/UseRangesCheck.cpp @@ -39,12 +39,6 @@ static constexpr const char ArgName[] = "ArgName"; namespace clang::tidy::utils { -static bool operator==(const UseRangesCheck::Indexes &L, - const UseRangesCheck::Indexes &R) { - return std::tie(L.BeginArg, L.EndArg, L.ReplaceArg) == - std::tie(R.BeginArg, R.EndArg, R.ReplaceArg); -} - static std::string getFullPrefix(ArrayRef Signature) { std::string Output; llvm::raw_string_ostream OS(Output); @@ -54,15 +48,6 @@ static std::string getFullPrefix(ArrayRef Signature) { return Output; } -static llvm::hash_code hash_value(const UseRangesCheck::Indexes &Indexes) { - return llvm::hash_combine(Indexes.BeginArg, Indexes.EndArg, - Indexes.ReplaceArg); -} - -static llvm::hash_code hash_value(const UseRangesCheck::Signature &Sig) { - return llvm::hash_combine_range(Sig.begin(), Sig.end()); -} - namespace { AST_MATCHER(Expr, hasSideEffects) { @@ -123,24 +108,26 @@ makeMatcherPair(StringRef State, const UseRangesCheck::Indexes &Indexes, } void UseRangesCheck::registerMatchers(MatchFinder *Finder) { - Replaces = getReplacerMap(); + auto Replaces = getReplacerMap(); ReverseDescriptor = getReverseDescriptor(); auto BeginEndNames = getFreeBeginEndMethods(); llvm::SmallVector BeginNames{ llvm::make_first_range(BeginEndNames)}; llvm::SmallVector EndNames{ llvm::make_second_range(BeginEndNames)}; - llvm::DenseSet> Seen; + Replacers.clear(); + llvm::DenseSet SeenRepl; for (auto I = Replaces.begin(), E = Replaces.end(); I != E; ++I) { - const ArrayRef &Signatures = - I->getValue()->getReplacementSignatures(); - if (!Seen.insert(Signatures).second) + auto Replacer = I->getValue(); + if (!SeenRepl.insert(Replacer.get()).second) continue; - assert(!Signatures.empty() && - llvm::all_of(Signatures, [](auto Index) { return !Index.empty(); })); + Replacers.push_back(Replacer); + assert(!Replacer->getReplacementSignatures().empty() && + llvm::all_of(Replacer->getReplacementSignatures(), + [](auto Index) { return !Index.empty(); })); std::vector Names(1, I->getKey()); for (auto J = std::next(I); J != E; ++J) - if (J->getValue()->getReplacementSignatures() == Signatures) + if (J->getValue() == Replacer) Names.push_back(J->getKey()); std::vector TotalMatchers; @@ -148,7 +135,7 @@ void UseRangesCheck::registerMatchers(MatchFinder *Finder) { // signatures in order of length(longest to shortest). This way any // signature that is a subset of another signature will be matched after the // other. - SmallVector SigVec(Signatures); + SmallVector SigVec(Replacer->getReplacementSignatures()); llvm::sort(SigVec, [](auto &L, auto &R) { return R.size() < L.size(); }); for (const auto &Signature : SigVec) { std::vector Matchers; @@ -163,7 +150,8 @@ void UseRangesCheck::registerMatchers(MatchFinder *Finder) { } Finder->addMatcher( callExpr( - callee(functionDecl(hasAnyName(std::move(Names))).bind(FuncDecl)), + callee(functionDecl(hasAnyName(std::move(Names))) + .bind((FuncDecl + Twine(Replacers.size() - 1).str()))), ast_matchers::internal::DynTypedMatcher::constructVariadic( ast_matchers::internal::DynTypedMatcher::VO_AnyOf, ASTNodeKind::getFromNodeKind(), @@ -205,21 +193,33 @@ static void removeFunctionArgs(DiagnosticBuilder &Diag, const CallExpr &Call, } void UseRangesCheck::check(const MatchFinder::MatchResult &Result) { - const auto *Function = Result.Nodes.getNodeAs(FuncDecl); - std::string Qualified = "::" + Function->getQualifiedNameAsString(); - auto Iter = Replaces.find(Qualified); - assert(Iter != Replaces.end()); + Replacer *Replacer = nullptr; + const FunctionDecl *Function = nullptr; + for (auto [Node, Value] : Result.Nodes.getMap()) { + StringRef NodeStr(Node); + if (!NodeStr.consume_front(FuncDecl)) + continue; + Function = Value.get(); + size_t Index; + if (NodeStr.getAsInteger(10, Index)) { + llvm_unreachable("Unable to extract replacer index"); + } + assert(Index < Replacers.size()); + Replacer = Replacers[Index].get(); + break; + } + assert(Replacer && Function); SmallString<64> Buffer; - for (const Signature &Sig : Iter->getValue()->getReplacementSignatures()) { + for (const Signature &Sig : Replacer->getReplacementSignatures()) { Buffer.assign({BoundCall, getFullPrefix(Sig)}); const auto *Call = Result.Nodes.getNodeAs(Buffer); if (!Call) continue; auto Diag = createDiag(*Call); - if (auto ReplaceName = Iter->getValue()->getReplaceName(*Function)) + if (auto ReplaceName = Replacer->getReplaceName(*Function)) Diag << FixItHint::CreateReplacement(Call->getCallee()->getSourceRange(), *ReplaceName); - if (auto Include = Iter->getValue()->getHeaderInclusion(*Function)) + if (auto Include = Replacer->getHeaderInclusion(*Function)) Diag << Inserter.createIncludeInsertion( Result.SourceManager->getFileID(Call->getBeginLoc()), *Include); llvm::SmallVector ToRemove; diff --git a/clang-tools-extra/clang-tidy/utils/UseRangesCheck.h b/clang-tools-extra/clang-tidy/utils/UseRangesCheck.h index 927e9694b0ec7cf..3a454bcf0cf07a2 100644 --- a/clang-tools-extra/clang-tidy/utils/UseRangesCheck.h +++ b/clang-tools-extra/clang-tidy/utils/UseRangesCheck.h @@ -85,7 +85,7 @@ class UseRangesCheck : public ClangTidyCheck { std::optional getCheckTraversalKind() const override; private: - ReplacerMap Replaces; + std::vector> Replacers; std::optional ReverseDescriptor; IncludeInserter Inserter; }; diff --git a/clang-tools-extra/test/clang-doc/basic-project.test b/clang-tools-extra/test/clang-doc/basic-project.test index 51d3ac6ce6dcdbe..38569d824f1f04c 100644 --- a/clang-tools-extra/test/clang-doc/basic-project.test +++ b/clang-tools-extra/test/clang-doc/basic-project.test @@ -1,3 +1,6 @@ +// See https://github.com/llvm/llvm-project/issues/97507. +// UNSUPPORTED: target={{.*}} + // RUN: rm -rf %t && mkdir -p %t/docs %t/build // RUN: sed 's|$test_dir|%/S|g' %S/Inputs/basic-project/database_template.json > %t/build/compile_commands.json // RUN: clang-doc --format=html --output=%t/docs --executor=all-TUs %t/build/compile_commands.json diff --git a/clang-tools-extra/test/clang-doc/test-path-abs.cpp b/clang-tools-extra/test/clang-doc/test-path-abs.cpp new file mode 100644 index 000000000000000..f6cce95bbea0c55 --- /dev/null +++ b/clang-tools-extra/test/clang-doc/test-path-abs.cpp @@ -0,0 +1,6 @@ +// RUN: rm -rf %t && mkdir %t +// RUN: clang-doc --format=html --executor=standalone %s --output=%t +// RUN: FileCheck %s -input-file=%t/index_json.js -check-prefix=JSON-INDEX +// RUN: rm -rf %t + +// JSON-INDEX: var RootPath = "{{.*}}test-path-abs.cpp.tmp"; \ No newline at end of file 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 e92179ac82c6a06..5e39c05f76d866a 100755 --- a/clang-tools-extra/test/clang-tidy/check_clang_tidy.py +++ b/clang-tools-extra/test/clang-tidy/check_clang_tidy.py @@ -205,9 +205,11 @@ def run_clang_tidy(self): self.temp_file_name, ] + [ - "-fix" - if self.export_fixes is None - else "--export-fixes=" + self.export_fixes + ( + "-fix" + if self.export_fixes is None + else "--export-fixes=" + self.export_fixes + ) ] + [ "--checks=-*," + self.check_name, @@ -299,19 +301,37 @@ def run(self): self.check_notes(clang_tidy_output) +CPP_STANDARDS = [ + "c++98", + "c++11", + ("c++14", "c++1y"), + ("c++17", "c++1z"), + ("c++20", "c++2a"), + ("c++23", "c++2b"), + ("c++26", "c++2c"), +] +C_STANDARDS = ["c99", ("c11", "c1x"), "c17", ("c23", "c2x"), "c2y"] + + def expand_std(std): - if std == "c++98-or-later": - return ["c++98", "c++11", "c++14", "c++17", "c++20", "c++23", "c++2c"] - if std == "c++11-or-later": - return ["c++11", "c++14", "c++17", "c++20", "c++23", "c++2c"] - if std == "c++14-or-later": - return ["c++14", "c++17", "c++20", "c++23", "c++2c"] - if std == "c++17-or-later": - return ["c++17", "c++20", "c++23", "c++2c"] - if std == "c++20-or-later": - return ["c++20", "c++23", "c++2c"] - if std == "c++23-or-later": - return ["c++23", "c++2c"] + split_std, or_later, _ = std.partition("-or-later") + + if not or_later: + return [split_std] + + for standard_list in (CPP_STANDARDS, C_STANDARDS): + item = next( + ( + i + for i, v in enumerate(standard_list) + if (split_std in v if isinstance(v, (list, tuple)) else split_std == v) + ), + None, + ) + if item is not None: + return [split_std] + [ + x if isinstance(x, str) else x[0] for x in standard_list[item + 1 :] + ] return [std] diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/use-ranges/fake_std.h b/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/use-ranges/fake_std.h index 6596511c7a38bbe..69ac9954f4afa94 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/use-ranges/fake_std.h +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/Inputs/use-ranges/fake_std.h @@ -7,8 +7,8 @@ template class vector { public: using iterator = T *; using const_iterator = const T *; - using reverse_iterator = T*; - using reverse_const_iterator = const T*; + using reverse_iterator = T *; + using reverse_const_iterator = const T *; constexpr const_iterator begin() const; constexpr const_iterator end() const; @@ -72,8 +72,8 @@ template constexpr auto crend(const Container &Cont) { return Cont.crend(); } // Find -template< class InputIt, class T > -InputIt find( InputIt first, InputIt last, const T& value ); +template +InputIt find(InputIt first, InputIt last, const T &value); // Reverse template void reverse(Iter begin, Iter end); @@ -82,6 +82,7 @@ template void reverse(Iter begin, Iter end); template bool includes(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2); +inline namespace _V1 { // IsPermutation template bool is_permutation(ForwardIt1 first1, ForwardIt1 last1, ForwardIt2 first2); @@ -97,9 +98,10 @@ template bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2); template -bool equal(InputIt1 first1, InputIt1 last1, - InputIt2 first2, InputIt2 last2, BinaryPred p) { - // Need a definition to suppress undefined_internal_type when invoked with lambda +bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, + BinaryPred p) { + // Need a definition to suppress undefined_internal_type when invoked with + // lambda return true; } @@ -108,6 +110,7 @@ void iota(ForwardIt first, ForwardIt last, T value); template ForwardIt rotate(ForwardIt first, ForwardIt middle, ForwardIt last); +} // namespace _V1 } // namespace std diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.c b/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.c new file mode 100644 index 000000000000000..db50467f3dd94eb --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/non-const-parameter.c @@ -0,0 +1,11 @@ +// RUN: %check_clang_tidy %s readability-non-const-parameter %t + +static int f(); + +int f(p) + int *p; +// CHECK-MESSAGES: :[[@LINE-1]]:8: warning: pointer parameter 'p' can be pointer to const [readability-non-const-parameter] +// CHECK-FIXES: {{^}} const int *p;{{$}} +{ + return *p; +} diff --git a/clang/bindings/python/clang/cindex.py b/clang/bindings/python/clang/cindex.py index be024da5e005c8d..72509a8a54f2809 100644 --- a/clang/bindings/python/clang/cindex.py +++ b/clang/bindings/python/clang/cindex.py @@ -43,7 +43,7 @@ Most object information is exposed using properties, when the underlying API call is efficient. """ -from __future__ import absolute_import, division, print_function +from __future__ import annotations # TODO # ==== @@ -64,48 +64,80 @@ from ctypes import * -import collections.abc import os +import sys from enum import Enum +from typing import ( + Any, + Callable, + Generic, + Optional, + Type as TType, + TypeVar, + TYPE_CHECKING, + Union as TUnion, +) + +if TYPE_CHECKING: + from ctypes import _Pointer + from typing_extensions import Protocol, TypeAlias + + StrPath: TypeAlias = TUnion[str, os.PathLike[str]] + LibFunc: TypeAlias = TUnion[ + "tuple[str, Optional[list[Any]]]", + "tuple[str, Optional[list[Any]], Any]", + "tuple[str, Optional[list[Any]], Any, Callable[..., Any]]", + ] + + TSeq = TypeVar("TSeq", covariant=True) + + class NoSliceSequence(Protocol[TSeq]): + def __len__(self) -> int: + ... + + def __getitem__(self, key: int) -> TSeq: + ... + # Python 3 strings are unicode, translate them to/from utf8 for C-interop. class c_interop_string(c_char_p): - def __init__(self, p=None): + def __init__(self, p: str | bytes | None = None): if p is None: p = "" if isinstance(p, str): p = p.encode("utf8") super(c_char_p, self).__init__(p) - def __str__(self): - return self.value + def __str__(self) -> str: + return self.value or "" @property - def value(self): - if super(c_char_p, self).value is None: + def value(self) -> str | None: # type: ignore [override] + val = super(c_char_p, self).value + if val is None: return None - return super(c_char_p, self).value.decode("utf8") + return val.decode("utf8") @classmethod - def from_param(cls, param): + def from_param(cls, param: str | bytes | None) -> c_interop_string: if isinstance(param, str): return cls(param) if isinstance(param, bytes): return cls(param) if param is None: # Support passing null to C functions expecting char arrays - return None + return cls(param) raise TypeError( "Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__) ) @staticmethod - def to_python_string(x, *args): + def to_python_string(x: c_interop_string, *args: Any) -> str | None: return x.value -def b(x): +def b(x: str | bytes) -> bytes: if isinstance(x, bytes): return x return x.encode("utf8") @@ -115,9 +147,7 @@ def b(x): # object. This is a problem, because it means that from_parameter will see an # integer and pass the wrong value on platforms where int != void*. Work around # this by marshalling object arguments as void**. -c_object_p = POINTER(c_void_p) - -callbacks = {} +c_object_p: TType[_Pointer[Any]] = POINTER(c_void_p) ### Exception Classes ### @@ -169,8 +199,11 @@ def __init__(self, enumeration, message): ### Structures and Utility Classes ### +TInstance = TypeVar("TInstance") +TResult = TypeVar("TResult") + -class CachedProperty: +class CachedProperty(Generic[TInstance, TResult]): """Decorator that lazy-loads the value of a property. The first time the property is accessed, the original property function is @@ -178,16 +211,20 @@ class CachedProperty: property, replacing the original method. """ - def __init__(self, wrapped): + def __init__(self, wrapped: Callable[[TInstance], TResult]): self.wrapped = wrapped try: self.__doc__ = wrapped.__doc__ except: pass - def __get__(self, instance, instance_type=None): + def __get__(self, instance: TInstance, instance_type: Any = None) -> TResult: if instance is None: - return self + property_name = self.wrapped.__name__ + class_name = instance_type.__name__ + raise TypeError( + f"'{property_name}' is not a static attribute of '{class_name}'" + ) value = self.wrapped(instance) setattr(instance, self.wrapped.__name__, value) @@ -200,13 +237,16 @@ class _CXString(Structure): _fields_ = [("spelling", c_char_p), ("free", c_int)] - def __del__(self): + def __del__(self) -> None: conf.lib.clang_disposeString(self) @staticmethod - def from_result(res, fn=None, args=None): + def from_result(res: _CXString, fn: Any = None, args: Any = None) -> str: assert isinstance(res, _CXString) - return conf.lib.clang_getCString(res) + pystr: str | None = conf.lib.clang_getCString(res) + if pystr is None: + return "" + return pystr class SourceLocation(Structure): @@ -400,15 +440,15 @@ def spelling(self): return conf.lib.clang_getDiagnosticSpelling(self) @property - def ranges(self): + def ranges(self) -> NoSliceSequence[SourceRange]: class RangeIterator: - def __init__(self, diag): + def __init__(self, diag: Diagnostic): self.diag = diag - def __len__(self): + def __len__(self) -> int: return int(conf.lib.clang_getDiagnosticNumRanges(self.diag)) - def __getitem__(self, key): + def __getitem__(self, key: int) -> SourceRange: if key >= len(self): raise IndexError return conf.lib.clang_getDiagnosticRange(self.diag, key) @@ -416,15 +456,15 @@ def __getitem__(self, key): return RangeIterator(self) @property - def fixits(self): + def fixits(self) -> NoSliceSequence[FixIt]: class FixItIterator: - def __init__(self, diag): + def __init__(self, diag: Diagnostic): self.diag = diag - def __len__(self): + def __len__(self) -> int: return int(conf.lib.clang_getDiagnosticNumFixIts(self.diag)) - def __getitem__(self, key): + def __getitem__(self, key: int) -> FixIt: range = SourceRange() value = conf.lib.clang_getDiagnosticFixIt(self.diag, key, byref(range)) if len(value) == 0: @@ -435,15 +475,15 @@ def __getitem__(self, key): return FixItIterator(self) @property - def children(self): + def children(self) -> NoSliceSequence[Diagnostic]: class ChildDiagnosticsIterator: - def __init__(self, diag): + def __init__(self, diag: Diagnostic): self.diag_set = conf.lib.clang_getChildDiagnostics(diag) - def __len__(self): + def __len__(self) -> int: return int(conf.lib.clang_getNumDiagnosticsInSet(self.diag_set)) - def __getitem__(self, key): + def __getitem__(self, key: int) -> Diagnostic: diag = conf.lib.clang_getDiagnosticInSet(self.diag_set, key) if not diag: raise IndexError @@ -2042,8 +2082,8 @@ def visitor(child, parent, children): children.append(child) return 1 # continue - children = [] - conf.lib.clang_visitChildren(self, callbacks["cursor_visit"](visitor), children) + children: list[Cursor] = [] + conf.lib.clang_visitChildren(self, cursor_visit_callback(visitor), children) return iter(children) def walk_preorder(self): @@ -2379,25 +2419,25 @@ def kind(self): """Return the kind of this type.""" return TypeKind.from_id(self._kind_id) - def argument_types(self): + def argument_types(self) -> NoSliceSequence[Type]: """Retrieve a container for the non-variadic arguments for this type. The returned object is iterable and indexable. Each item in the container is a Type instance. """ - class ArgumentsIterator(collections.abc.Sequence): - def __init__(self, parent): + class ArgumentsIterator: + def __init__(self, parent: Type): self.parent = parent - self.length = None + self.length: int | None = None - def __len__(self): + def __len__(self) -> int: if self.length is None: self.length = conf.lib.clang_getNumArgTypes(self.parent) return self.length - def __getitem__(self, key): + def __getitem__(self, key: int) -> Type: # FIXME Support slice objects. if not isinstance(key, int): raise TypeError("Must supply a non-negative int.") @@ -2411,7 +2451,7 @@ def __getitem__(self, key): "%d > %d" % (key, len(self)) ) - result = conf.lib.clang_getArgType(self.parent, key) + result: Type = conf.lib.clang_getArgType(self.parent, key) if result.kind == TypeKind.INVALID: raise IndexError("Argument could not be retrieved.") @@ -2604,10 +2644,8 @@ def visitor(field, children): fields.append(field) return 1 # continue - fields = [] - conf.lib.clang_Type_visitFields( - self, callbacks["fields_visit"](visitor), fields - ) + fields: list[Cursor] = [] + conf.lib.clang_Type_visitFields(self, fields_visit_callback(visitor), fields) return iter(fields) def get_exception_specification_kind(self): @@ -2881,15 +2919,15 @@ def results(self): return self.ptr.contents @property - def diagnostics(self): + def diagnostics(self) -> NoSliceSequence[Diagnostic]: class DiagnosticsItr: - def __init__(self, ccr): + def __init__(self, ccr: CodeCompletionResults): self.ccr = ccr - def __len__(self): + def __len__(self) -> int: return int(conf.lib.clang_codeCompleteGetNumDiagnostics(self.ccr)) - def __getitem__(self, key): + def __getitem__(self, key: int) -> Diagnostic: return conf.lib.clang_codeCompleteGetDiagnostic(self.ccr, key) return DiagnosticsItr(self) @@ -3119,7 +3157,7 @@ def visitor(fobj, lptr, depth, includes): # Automatically adapt CIndex/ctype pointers to python objects includes = [] conf.lib.clang_getInclusions( - self, callbacks["translation_unit_includes"](visitor), includes + self, translation_unit_includes_callback(visitor), includes ) return iter(includes) @@ -3187,19 +3225,19 @@ def get_extent(self, filename, locations): return SourceRange.from_locations(start_location, end_location) @property - def diagnostics(self): + def diagnostics(self) -> NoSliceSequence[Diagnostic]: """ Return an iterable (and indexable) object containing the diagnostics. """ class DiagIterator: - def __init__(self, tu): + def __init__(self, tu: TranslationUnit): self.tu = tu - def __len__(self): + def __len__(self) -> int: return int(conf.lib.clang_getNumDiagnostics(self.tu)) - def __getitem__(self, key): + def __getitem__(self, key: int) -> Diagnostic: diag = conf.lib.clang_getDiagnostic(self.tu, key) if not diag: raise IndexError @@ -3631,15 +3669,15 @@ def write_main_file_to_stdout(self): # Now comes the plumbing to hook up the C library. -# Register callback types in common container. -callbacks["translation_unit_includes"] = CFUNCTYPE( +# Register callback types +translation_unit_includes_callback = CFUNCTYPE( None, c_object_p, POINTER(SourceLocation), c_uint, py_object ) -callbacks["cursor_visit"] = CFUNCTYPE(c_int, Cursor, Cursor, py_object) -callbacks["fields_visit"] = CFUNCTYPE(c_int, Cursor, py_object) +cursor_visit_callback = CFUNCTYPE(c_int, Cursor, Cursor, py_object) +fields_visit_callback = CFUNCTYPE(c_int, Cursor, py_object) # Functions strictly alphabetical order. -functionList = [ +functionList: list[LibFunc] = [ ( "clang_annotateTokens", [TranslationUnit, POINTER(Token), c_uint, POINTER(Cursor)], @@ -3809,7 +3847,7 @@ def write_main_file_to_stdout(self): ("clang_getIncludedFile", [Cursor], c_object_p, File.from_result), ( "clang_getInclusions", - [TranslationUnit, callbacks["translation_unit_includes"], py_object], + [TranslationUnit, translation_unit_includes_callback, py_object], ), ( "clang_getInstantiationLocation", @@ -3894,7 +3932,7 @@ def write_main_file_to_stdout(self): "clang_tokenize", [TranslationUnit, SourceRange, POINTER(POINTER(Token)), POINTER(c_uint)], ), - ("clang_visitChildren", [Cursor, callbacks["cursor_visit"], py_object], c_uint), + ("clang_visitChildren", [Cursor, cursor_visit_callback, py_object], c_uint), ("clang_Cursor_getNumArguments", [Cursor], c_int), ("clang_Cursor_getArgument", [Cursor, c_uint], Cursor, Cursor.from_result), ("clang_Cursor_getNumTemplateArguments", [Cursor], c_int), @@ -3921,19 +3959,19 @@ def write_main_file_to_stdout(self): ("clang_Type_getSizeOf", [Type], c_longlong), ("clang_Type_getCXXRefQualifier", [Type], c_uint), ("clang_Type_getNamedType", [Type], Type, Type.from_result), - ("clang_Type_visitFields", [Type, callbacks["fields_visit"], py_object], c_uint), + ("clang_Type_visitFields", [Type, fields_visit_callback, py_object], c_uint), ] class LibclangError(Exception): - def __init__(self, message): + def __init__(self, message: str): self.m = message - def __str__(self): + def __str__(self) -> str: return self.m -def register_function(lib, item, ignore_errors): +def register_function(lib: CDLL, item: LibFunc, ignore_errors: bool) -> None: # A function may not exist, if these bindings are used with an older or # incompatible version of libclang.so. try: @@ -3957,15 +3995,15 @@ def register_function(lib, item, ignore_errors): func.errcheck = item[3] -def register_functions(lib, ignore_errors): +def register_functions(lib: CDLL, ignore_errors: bool) -> None: """Register function prototypes with a libclang library instance. This must be called as part of library instantiation so Python knows how to call out to the shared library. """ - def register(item): - return register_function(lib, item, ignore_errors) + def register(item: LibFunc) -> None: + register_function(lib, item, ignore_errors) for f in functionList: register(f) @@ -3973,12 +4011,12 @@ def register(item): class Config: library_path = None - library_file = None + library_file: str | None = None compatibility_check = True loaded = False @staticmethod - def set_library_path(path): + def set_library_path(path: StrPath) -> None: """Set the path in which to search for libclang""" if Config.loaded: raise Exception( @@ -3989,7 +4027,7 @@ def set_library_path(path): Config.library_path = os.fspath(path) @staticmethod - def set_library_file(filename): + def set_library_file(filename: StrPath) -> None: """Set the exact location of libclang""" if Config.loaded: raise Exception( @@ -4000,7 +4038,7 @@ def set_library_file(filename): Config.library_file = os.fspath(filename) @staticmethod - def set_compatibility_check(check_status): + def set_compatibility_check(check_status: bool) -> None: """Perform compatibility check when loading libclang The python bindings are only tested and evaluated with the version of @@ -4026,13 +4064,13 @@ def set_compatibility_check(check_status): Config.compatibility_check = check_status @CachedProperty - def lib(self): + def lib(self) -> CDLL: lib = self.get_cindex_library() register_functions(lib, not Config.compatibility_check) Config.loaded = True return lib - def get_filename(self): + def get_filename(self) -> str: if Config.library_file: return Config.library_file @@ -4052,7 +4090,7 @@ def get_filename(self): return file - def get_cindex_library(self): + def get_cindex_library(self) -> CDLL: try: library = cdll.LoadLibrary(self.get_filename()) except OSError as e: @@ -4065,7 +4103,7 @@ def get_cindex_library(self): return library - def function_exists(self, name): + def function_exists(self, name: str) -> bool: try: getattr(self.lib, name) except AttributeError: @@ -4077,6 +4115,7 @@ def function_exists(self, name): conf = Config() __all__ = [ + "AccessSpecifier", "AvailabilityKind", "BinaryOperator", "Config", @@ -4087,12 +4126,16 @@ def function_exists(self, name): "CursorKind", "Cursor", "Diagnostic", + "ExceptionSpecificationKind", "File", "FixIt", "Index", "LinkageKind", + "RefQualifierKind", "SourceLocation", "SourceRange", + "StorageClass", + "TemplateArgumentKind", "TLSKind", "TokenKind", "Token", diff --git a/clang/bindings/python/tests/cindex/test_code_completion.py b/clang/bindings/python/tests/cindex/test_code_completion.py index ca52fc6f73e1d2c..1d513dbca25364a 100644 --- a/clang/bindings/python/tests/cindex/test_code_completion.py +++ b/clang/bindings/python/tests/cindex/test_code_completion.py @@ -53,7 +53,7 @@ def test_code_complete(self): expected = [ "{'int', ResultType} | {'test1', TypedText} || Priority: 50 || Availability: Available || Brief comment: Aaa.", "{'void', ResultType} | {'test2', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 50 || Availability: Available || Brief comment: Bbb.", - "{'return', TypedText} | {';', SemiColon} || Priority: 40 || Availability: Available || Brief comment: None", + "{'return', TypedText} | {';', SemiColon} || Priority: 40 || Availability: Available || Brief comment: ", ] self.check_completion_results(cr, expected) @@ -94,7 +94,7 @@ def test_code_complete_pathlike(self): expected = [ "{'int', ResultType} | {'test1', TypedText} || Priority: 50 || Availability: Available || Brief comment: Aaa.", "{'void', ResultType} | {'test2', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 50 || Availability: Available || Brief comment: Bbb.", - "{'return', TypedText} | {';', SemiColon} || Priority: 40 || Availability: Available || Brief comment: None", + "{'return', TypedText} | {';', SemiColon} || Priority: 40 || Availability: Available || Brief comment: ", ] self.check_completion_results(cr, expected) @@ -128,19 +128,19 @@ class Q : public P { cr = tu.codeComplete("fake.cpp", 12, 5, unsaved_files=files) expected = [ - "{'const', TypedText} || Priority: 50 || Availability: Available || Brief comment: None", - "{'volatile', TypedText} || Priority: 50 || Availability: Available || Brief comment: None", - "{'operator', TypedText} || Priority: 40 || Availability: Available || Brief comment: None", - "{'P', TypedText} || Priority: 50 || Availability: Available || Brief comment: None", - "{'Q', TypedText} || Priority: 50 || Availability: Available || Brief comment: None", + "{'const', TypedText} || Priority: 50 || Availability: Available || Brief comment: ", + "{'volatile', TypedText} || Priority: 50 || Availability: Available || Brief comment: ", + "{'operator', TypedText} || Priority: 40 || Availability: Available || Brief comment: ", + "{'P', TypedText} || Priority: 50 || Availability: Available || Brief comment: ", + "{'Q', TypedText} || Priority: 50 || Availability: Available || Brief comment: ", ] self.check_completion_results(cr, expected) cr = tu.codeComplete("fake.cpp", 13, 5, unsaved_files=files) expected = [ - "{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None", - "{'P &', ResultType} | {'operator=', TypedText} | {'(', LeftParen} | {'const P &', Placeholder} | {')', RightParen} || Priority: 79 || Availability: Available || Brief comment: None", - "{'int', ResultType} | {'member', TypedText} || Priority: 35 || Availability: NotAccessible || Brief comment: None", - "{'void', ResultType} | {'~P', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 79 || Availability: Available || Brief comment: None", + "{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: ", + "{'P &', ResultType} | {'operator=', TypedText} | {'(', LeftParen} | {'const P &', Placeholder} | {')', RightParen} || Priority: 79 || Availability: Available || Brief comment: ", + "{'int', ResultType} | {'member', TypedText} || Priority: 35 || Availability: NotAccessible || Brief comment: ", + "{'void', ResultType} | {'~P', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 79 || Availability: Available || Brief comment: ", ] self.check_completion_results(cr, expected) diff --git a/clang/bindings/python/tests/cindex/test_comment.py b/clang/bindings/python/tests/cindex/test_comment.py index 0727c6fa35d95a0..265c6d3d73de047 100644 --- a/clang/bindings/python/tests/cindex/test_comment.py +++ b/clang/bindings/python/tests/cindex/test_comment.py @@ -53,5 +53,5 @@ def test_comment(self): f = get_cursor(tu, "f") raw = f.raw_comment brief = f.brief_comment - self.assertIsNone(raw) - self.assertIsNone(brief) + self.assertEqual(raw, "") + self.assertEqual(brief, "") diff --git a/clang/cmake/caches/Fuchsia-stage2.cmake b/clang/cmake/caches/Fuchsia-stage2.cmake index 8e0835cb3158f2e..75ceb799352f9e5 100644 --- a/clang/cmake/caches/Fuchsia-stage2.cmake +++ b/clang/cmake/caches/Fuchsia-stage2.cmake @@ -309,7 +309,7 @@ foreach(target armv6m-unknown-eabi;armv7m-unknown-eabi;armv8m.main-unknown-eabi) foreach(lang C;CXX;ASM) set(BUILTINS_${target}_CMAKE_${lang}_local_flags "--target=${target} -mthumb") if(${target} STREQUAL "armv8m.main-unknown-eabi") - set(BUILTINS_${target}_CMAKE_${lang}_local_flags "${BUILTINS_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=hard -march=armv8m.main+fp+dsp -mcpu=cortex-m33" CACHE STRING "") + set(BUILTINS_${target}_CMAKE_${lang}_local_flags "${BUILTINS_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=softfp -march=armv8m.main+fp+dsp -mcpu=cortex-m33" CACHE STRING "") endif() set(BUILTINS_${target}_CMAKE_${lang}_FLAGS "${BUILTINS_${target}_CMAKE_${lang}_local_flags}" CACHE STRING "") endforeach() @@ -327,7 +327,11 @@ foreach(target armv6m-unknown-eabi;armv7m-unknown-eabi;armv8m.main-unknown-eabi) foreach(lang C;CXX;ASM) # TODO: The preprocessor defines workaround various issues in libc and libc++ integration. # These should be addressed and removed over time. - set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "--target=${target} -mthumb -Wno-atomic-alignment \"-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)\" \"-Dfprintf(stream, format, ...)=printf(format)\" \"-Dtimeval=struct timeval{int tv_sec; int tv_usec;}\" \"-Dgettimeofday(tv, tz)\" -D_LIBCPP_PRINT=1" CACHE STRING "") + set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "--target=${target} -mthumb -Wno-atomic-alignment \"-Dvfprintf(stream, format, vlist)=vprintf(format, vlist)\" \"-Dfprintf(stream, format, ...)=printf(format)\" \"-Dtimeval=struct timeval{int tv_sec; int tv_usec;}\" \"-Dgettimeofday(tv, tz)\" -D_LIBCPP_PRINT=1") + if(${target} STREQUAL "armv8m.main-unknown-eabi") + set(RUNTIMES_${target}_CMAKE_${lang}_local_flags "${RUNTIMES_${target}_CMAKE_${lang}_local_flags} -mfloat-abi=softfp -march=armv8m.main+fp+dsp -mcpu=cortex-m33" CACHE STRING "") + endif() + set(RUNTIMES_${target}_CMAKE_${lang}_FLAGS "${RUNTIMES_${target}_CMAKE_${lang}_local_flags}" CACHE STRING "") endforeach() foreach(type SHARED;MODULE;EXE) set(RUNTIMES_${target}_CMAKE_${type}_LINKER_FLAGS "-fuse-ld=lld" CACHE STRING "") diff --git a/clang/cmake/caches/Release.cmake b/clang/cmake/caches/Release.cmake index 9e6feb479d45fc8..e5161dd9a27b965 100644 --- a/clang/cmake/caches/Release.cmake +++ b/clang/cmake/caches/Release.cmake @@ -29,9 +29,13 @@ endfunction() # cache file to CMake via -C. e.g. # # cmake -D LLVM_RELEASE_ENABLE_PGO=ON -C Release.cmake +set (DEFAULT_RUNTIMES "compiler-rt;libcxx") +if (NOT WIN32) + list(APPEND DEFAULT_RUNTIMES "libcxxabi" "libunwind") +endif() set(LLVM_RELEASE_ENABLE_LTO THIN CACHE STRING "") set(LLVM_RELEASE_ENABLE_PGO ON CACHE BOOL "") -set(LLVM_RELEASE_ENABLE_RUNTIMES "compiler-rt;libcxx;libcxxabi;libunwind" CACHE STRING "") +set(LLVM_RELEASE_ENABLE_RUNTIMES ${DEFAULT_RUNTIMES} CACHE STRING "") set(LLVM_RELEASE_ENABLE_PROJECTS "clang;lld;lldb;clang-tools-extra;bolt;polly;mlir;flang" CACHE STRING "") # Note we don't need to add install here, since it is one of the pre-defined # steps. diff --git a/clang/cmake/modules/AddClang.cmake b/clang/cmake/modules/AddClang.cmake index 9d09be19368476e..5327b5d2f089288 100644 --- a/clang/cmake/modules/AddClang.cmake +++ b/clang/cmake/modules/AddClang.cmake @@ -147,6 +147,7 @@ endmacro(add_clang_library) macro(add_clang_executable name) add_llvm_executable( ${name} ${ARGN} ) set_clang_windows_version_resource_properties(${name}) + set_target_properties(${name} PROPERTIES XCODE_GENERATE_SCHEME ON) endmacro(add_clang_executable) macro(add_clang_tool name) @@ -181,6 +182,7 @@ macro(add_clang_tool name) set_property(GLOBAL APPEND PROPERTY CLANG_EXPORTS ${name}) endif() endif() + set_target_properties(${name} PROPERTIES XCODE_GENERATE_SCHEME ON) endmacro() macro(add_clang_symlink name dest) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 81784c75081bae7..a747464582e77d5 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1546,6 +1546,7 @@ The following type trait primitives are supported by Clang. Those traits marked * ``__array_extent(type, dim)`` (Embarcadero): The ``dim``'th array bound in the type ``type``, or ``0`` if ``dim >= __array_rank(type)``. +* ``__builtin_is_virtual_base_of`` (C++, GNU, Microsoft) * ``__can_pass_in_regs`` (C++) Returns whether a class can be passed in registers under the current ABI. This type can only be applied to unqualified class types. diff --git a/clang/docs/MemorySanitizer.rst b/clang/docs/MemorySanitizer.rst index bcc6cc808e8bae1..05e43a32b9b8726 100644 --- a/clang/docs/MemorySanitizer.rst +++ b/clang/docs/MemorySanitizer.rst @@ -8,11 +8,18 @@ MemorySanitizer Introduction ============ -MemorySanitizer is a detector of uninitialized reads. It consists of a +MemorySanitizer is a detector of uninitialized memory use. It consists of a compiler instrumentation module and a run-time library. Typical slowdown introduced by MemorySanitizer is **3x**. +Here is a not comprehensive of list cases when MemorySanitizer will report an error: + +* Uninitialized value was used in a conditional branch. +* Uninitialized pointer was used for memory accesses. +* Uninitialized value was passed or returned from a function call, which is considered an undefined behavior. The check can be disabled with ``-fno-sanitize-memory-param-retval``. +* Uninitialized data was passed into some libc calls. + How to build ============ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 0b79e952b48af2f..3c2e0282d1c72d0 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -54,6 +54,11 @@ Clang Frontend Potentially Breaking Changes Clang Python Bindings Potentially Breaking Changes -------------------------------------------------- +- Parts of the interface returning string results will now return + the empty string `""` when no result is available, instead of `None`. +- Calling a property on the `CompletionChunk` or `CompletionString` class + statically now leads to an error, instead of returning a `CachedProperty` object + that is used internally. Properties are only available on instances. What's New in Clang |release|? ============================== @@ -81,6 +86,9 @@ C++23 Feature Support C++2c Feature Support ^^^^^^^^^^^^^^^^^^^^^ +- Add ``__builtin_is_virtual_base_of`` intrinsic, which supports + `P2985R0 A type trait for detecting virtual base classes `_ + Resolutions to C++ Defect Reports ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -111,6 +119,11 @@ Attribute Changes in Clang - Clang now disallows more than one ``__attribute__((ownership_returns(class, idx)))`` with different class names attached to one function. +- Introduced a new format attribute ``__attribute__((format(syslog, 1, 2)))`` from OpenBSD. + +- The ``hybrid_patchable`` attribute is now supported on ARM64EC targets. It can be used to specify + that a function requires an additional x86-64 thunk, which may be patched at runtime. + Improvements to Clang's diagnostics ----------------------------------- @@ -124,10 +137,14 @@ Improvements to Clang's diagnostics template int i; // error: non-static data member 'i' cannot be declared as a template }; +- Clang now has improved diagnostics for functions with explicit 'this' parameters. Fixes #GH97878 + - Clang now diagnoses dangling references to fields of temporary objects. Fixes #GH81589. - Clang now diagnoses undefined behavior in constant expressions more consistently. This includes invalid shifts, and signed overflow in arithmetic. +- -Wdangling-assignment-gsl is enabled by default. + Improvements to Clang's time-trace ---------------------------------- @@ -150,6 +167,9 @@ Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed a crash when an expression with a dependent ``__typeof__`` type is used as the operand of a unary operator. (#GH97646) +- Fixed a failed assertion when checking invalid delete operator declaration. (#GH96191) +- Fix a crash when checking destructor reference with an invalid initializer. (#GH97230) +- Clang now correctly parses potentially declarative nested-name-specifiers in pointer-to-member declarators. Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -160,6 +180,9 @@ Miscellaneous Bug Fixes Miscellaneous Clang Crashes Fixed ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +- Fixed a crash in C due to incorrect lookup that members in nested anonymous struct/union + can be found as ordinary identifiers in struct/union definition. (#GH31295) + OpenACC Specific Changes ------------------------ @@ -233,6 +256,9 @@ Fixed Point Support in Clang AST Matchers ------------ +- Fixed an issue with the `hasName` and `hasAnyName` matcher when matching + inline namespaces with an enclosing namespace of the same name. + clang-format ------------ @@ -256,6 +282,10 @@ Crash and bug fixes Improvements ^^^^^^^^^^^^ +- Improved the handling of the ``ownership_returns`` attribute. Now, Clang reports an + error if the attribute is attached to a function that returns a non-pointer value. + Fixes (#GH99501) + Moved checkers ^^^^^^^^^^^^^^ diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index 76a9aae17089383..05d3f4d4018f7a8 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -1703,7 +1703,13 @@ are detected: * Invalid 3rd ("``whence``") argument to ``fseek``. The stream operations are by this checker usually split into two cases, a success -and a failure case. However, in the case of write operations (like ``fwrite``, +and a failure case. +On the success case it also assumes that the current value of ``stdout``, +``stderr``, or ``stdin`` can't be equal to the file pointer returned by ``fopen``. +Operations performed on ``stdout``, ``stderr``, or ``stdin`` are not checked by +this checker in contrast to the streams opened by ``fopen``. + +In the case of write operations (like ``fwrite``, ``fprintf`` and even ``fsetpos``) this behavior could produce a large amount of unwanted reports on projects that don't have error checks around the write operations, so by default the checker assumes that write operations always succeed. @@ -1769,9 +1775,7 @@ are assumed to succeed.) **Limitations** The checker does not track the correspondence between integer file descriptors -and ``FILE *`` pointers. Operations on standard streams like ``stdin`` are not -treated specially and are therefore often not recognized (because these streams -are usually not opened explicitly by the program, and are global variables). +and ``FILE *`` pointers. .. _osx-checkers: diff --git a/clang/include/clang/AST/ASTImporter.h b/clang/include/clang/AST/ASTImporter.h index 4ffd9138465757e..f851decd0965ce2 100644 --- a/clang/include/clang/AST/ASTImporter.h +++ b/clang/include/clang/AST/ASTImporter.h @@ -258,7 +258,6 @@ class TypeSourceInfo; FoundDeclsTy findDeclsInToCtx(DeclContext *DC, DeclarationName Name); void AddToLookupTable(Decl *ToD); - llvm::Error ImportAttrs(Decl *ToD, Decl *FromD); protected: /// Can be overwritten by subclasses to implement their own import logic. diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 616f92691ec3237..0546c19ce811952 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -583,7 +583,7 @@ class ASTNodeTraverser void VisitCapturedDecl(const CapturedDecl *D) { Visit(D->getBody()); } void VisitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) { - for (const auto *E : D->varlists()) + for (const auto *E : D->varlist()) Visit(E); } @@ -603,7 +603,7 @@ class ASTNodeTraverser } void VisitOMPAllocateDecl(const OMPAllocateDecl *D) { - for (const auto *E : D->varlists()) + for (const auto *E : D->varlist()) Visit(E); for (const auto *C : D->clauselists()) Visit(C); diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index fb52ac804849d87..3a110454f29eda8 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1188,10 +1188,6 @@ class CXXRecordDecl : public RecordDecl { /// /// \note This does NOT include a check for union-ness. bool isEmpty() const { return data().Empty; } - /// Marks this record as empty. This is used by DWARFASTParserClang - /// when parsing records with empty fields having [[no_unique_address]] - /// attribute - void markEmpty() { data().Empty = true; } void setInitMethod(bool Val) { data().HasInitMethod = Val; } bool hasInitMethod() const { return data().HasInitMethod; } diff --git a/clang/include/clang/AST/DeclOpenMP.h b/clang/include/clang/AST/DeclOpenMP.h index e542c3c8e66b0f2..868662208efa1fe 100644 --- a/clang/include/clang/AST/DeclOpenMP.h +++ b/clang/include/clang/AST/DeclOpenMP.h @@ -143,10 +143,10 @@ class OMPThreadPrivateDecl final : public OMPDeclarativeDirective { unsigned varlist_size() const { return Data->getNumChildren(); } bool varlist_empty() const { return Data->getChildren().empty(); } - varlist_range varlists() { + varlist_range varlist() { return varlist_range(varlist_begin(), varlist_end()); } - varlist_const_range varlists() const { + varlist_const_range varlist() const { return varlist_const_range(varlist_begin(), varlist_end()); } varlist_iterator varlist_begin() { return getVars().begin(); } @@ -513,10 +513,10 @@ class OMPAllocateDecl final : public OMPDeclarativeDirective { unsigned clauselist_size() const { return Data->getNumClauses(); } bool clauselist_empty() const { return Data->getClauses().empty(); } - varlist_range varlists() { + varlist_range varlist() { return varlist_range(varlist_begin(), varlist_end()); } - varlist_const_range varlists() const { + varlist_const_range varlist() const { return varlist_const_range(varlist_begin(), varlist_end()); } varlist_iterator varlist_begin() { return getVars().begin(); } diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 325a1baa4461421..b029c72fa7d8fc6 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -316,10 +316,10 @@ template class OMPVarListClause : public OMPClause { unsigned varlist_size() const { return NumVars; } bool varlist_empty() const { return NumVars == 0; } - varlist_range varlists() { + varlist_range varlist() { return varlist_range(varlist_begin(), varlist_end()); } - varlist_const_range varlists() const { + varlist_const_range varlist() const { return varlist_const_range(varlist_begin(), varlist_end()); } diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index e3c0cb46799f727..dcf5dbf449f8bf3 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1772,10 +1772,10 @@ DEF_TRAVERSE_DECL(UsingShadowDecl, {}) DEF_TRAVERSE_DECL(ConstructorUsingShadowDecl, {}) DEF_TRAVERSE_DECL(OMPThreadPrivateDecl, { - for (auto *I : D->varlists()) { + for (auto *I : D->varlist()) { TRY_TO(TraverseStmt(I)); } - }) +}) DEF_TRAVERSE_DECL(OMPRequiresDecl, { for (auto *C : D->clauselists()) { @@ -1801,7 +1801,7 @@ DEF_TRAVERSE_DECL(OMPDeclareMapperDecl, { DEF_TRAVERSE_DECL(OMPCapturedExprDecl, { TRY_TO(TraverseVarHelper(D)); }) DEF_TRAVERSE_DECL(OMPAllocateDecl, { - for (auto *I : D->varlists()) + for (auto *I : D->varlist()) TRY_TO(TraverseStmt(I)); for (auto *C : D->clauselists()) TRY_TO(TraverseOMPClause(C)); @@ -3552,7 +3552,7 @@ bool RecursiveASTVisitor::VisitOMPNocontextClause( template template bool RecursiveASTVisitor::VisitOMPClauseList(T *Node) { - for (auto *E : Node->varlists()) { + for (auto *E : Node->varlist()) { TRY_TO(TraverseStmt(E)); } return true; @@ -3926,7 +3926,7 @@ template bool RecursiveASTVisitor::VisitOMPAffinityClause( OMPAffinityClause *C) { TRY_TO(TraverseStmt(C->getModifier())); - for (Expr *E : C->varlists()) + for (Expr *E : C->varlist()) TRY_TO(TraverseStmt(E)); return true; } diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 72723c7c56e078f..dec51e032158e55 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2509,6 +2509,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { bool isFunctionNoProtoType() const { return getAs(); } bool isFunctionProtoType() const { return getAs(); } bool isPointerType() const; + bool isPointerOrReferenceType() const; bool isSignableType() const; bool isAnyPointerType() const; // Any C pointer or ObjC object pointer bool isCountAttributedType() const; @@ -4698,26 +4699,25 @@ class FunctionEffect { }; private: - LLVM_PREFERRED_TYPE(Kind) - unsigned FKind : 3; + Kind FKind; // Expansion: for hypothetical TCB+types, there could be one Kind for TCB, // then ~16(?) bits "SubKind" to map to a specific named TCB. SubKind would // be considered for uniqueness. public: - FunctionEffect() : FKind(unsigned(Kind::None)) {} + FunctionEffect() : FKind(Kind::None) {} - explicit FunctionEffect(Kind K) : FKind(unsigned(K)) {} + explicit FunctionEffect(Kind K) : FKind(K) {} /// The kind of the effect. - Kind kind() const { return Kind(FKind); } + Kind kind() const { return FKind; } /// Return the opposite kind, for effects which have opposites. Kind oppositeKind() const; /// For serialization. - uint32_t toOpaqueInt32() const { return FKind; } + uint32_t toOpaqueInt32() const { return uint32_t(FKind); } static FunctionEffect fromOpaqueInt32(uint32_t Value) { return FunctionEffect(Kind(Value)); } @@ -7997,6 +7997,10 @@ inline bool Type::isPointerType() const { return isa(CanonicalType); } +inline bool Type::isPointerOrReferenceType() const { + return isPointerType() || isReferenceType(); +} + inline bool Type::isAnyPointerType() const { return isPointerType() || isObjCObjectPointerType(); } diff --git a/clang/include/clang/Analysis/FlowSensitive/AdornedCFG.h b/clang/include/clang/Analysis/FlowSensitive/AdornedCFG.h index 420f13ce11bfde5..5c64e5b0947498b 100644 --- a/clang/include/clang/Analysis/FlowSensitive/AdornedCFG.h +++ b/clang/include/clang/Analysis/FlowSensitive/AdornedCFG.h @@ -18,6 +18,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Stmt.h" #include "clang/Analysis/CFG.h" +#include "clang/Analysis/FlowSensitive/ASTOps.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/Error.h" @@ -27,6 +28,20 @@ namespace clang { namespace dataflow { +namespace internal { +class StmtToBlockMap { +public: + StmtToBlockMap(const CFG &Cfg); + + const CFGBlock *lookup(const Stmt &S) const { + return StmtToBlock.lookup(&ignoreCFGOmittedNodes(S)); + } + +private: + llvm::DenseMap StmtToBlock; +}; +} // namespace internal + /// Holds CFG with additional information derived from it that is needed to /// perform dataflow analysis. class AdornedCFG { @@ -48,9 +63,10 @@ class AdornedCFG { /// Returns the CFG that is stored in this context. const CFG &getCFG() const { return *Cfg; } - /// Returns a mapping from statements to basic blocks that contain them. - const llvm::DenseMap &getStmtToBlock() const { - return StmtToBlock; + /// Returns the basic block that contains `S`, or null if no basic block + /// containing `S` is found. + const CFGBlock *blockForStmt(const Stmt &S) const { + return StmtToBlock.lookup(S); } /// Returns whether `B` is reachable from the entry block. @@ -73,8 +89,7 @@ class AdornedCFG { private: AdornedCFG( const Decl &D, std::unique_ptr Cfg, - llvm::DenseMap StmtToBlock, - llvm::BitVector BlockReachable, + internal::StmtToBlockMap StmtToBlock, llvm::BitVector BlockReachable, llvm::DenseSet ContainsExprConsumedInDifferentBlock) : ContainingDecl(D), Cfg(std::move(Cfg)), StmtToBlock(std::move(StmtToBlock)), @@ -85,7 +100,7 @@ class AdornedCFG { /// The `Decl` containing the statement used to construct the CFG. const Decl &ContainingDecl; std::unique_ptr Cfg; - llvm::DenseMap StmtToBlock; + internal::StmtToBlockMap StmtToBlock; llvm::BitVector BlockReachable; llvm::DenseSet ContainsExprConsumedInDifferentBlock; }; diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h index 50a70188720613a..e6efde091871fc0 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h @@ -233,7 +233,7 @@ llvm::Expected>>> runDataflowAnalysis(const AdornedCFG &ACFG, AnalysisT &Analysis, const Environment &InitEnv, - CFGEltCallbacks PostAnalysisCallbacks, + CFGEltCallbacks PostAnalysisCallbacks = {}, std::int32_t MaxBlockVisits = kDefaultMaxBlockVisits) { CFGEltCallbacksTypeErased TypeErasedCallbacks; if (PostAnalysisCallbacks.Before) { @@ -286,22 +286,6 @@ runDataflowAnalysis(const AdornedCFG &ACFG, AnalysisT &Analysis, return std::move(BlockStates); } -/// Overload that takes only one post-analysis callback, which is run on the -/// state after visiting the `CFGElement`. This is provided for backwards -/// compatibility; new callers should call the overload taking `CFGEltCallbacks` -/// instead. -template -llvm::Expected>>> -runDataflowAnalysis( - const AdornedCFG &ACFG, AnalysisT &Analysis, const Environment &InitEnv, - CFGEltCallback PostAnalysisCallbackAfterElt = nullptr, - std::int32_t MaxBlockVisits = kDefaultMaxBlockVisits) { - return runDataflowAnalysis(ACFG, Analysis, InitEnv, - {nullptr, PostAnalysisCallbackAfterElt}, - MaxBlockVisits); -} - // Create an analysis class that is derived from `DataflowAnalysis`. This is an // SFINAE adapter that allows us to call two different variants of constructor // (either with or without the optional `Environment` parameter). diff --git a/clang/include/clang/Analysis/FlowSensitive/MapLattice.h b/clang/include/clang/Analysis/FlowSensitive/MapLattice.h index 16b0c978779a79d..b2d147e4ae444bc 100644 --- a/clang/include/clang/Analysis/FlowSensitive/MapLattice.h +++ b/clang/include/clang/Analysis/FlowSensitive/MapLattice.h @@ -49,7 +49,7 @@ template class MapLattice { MapLattice() = default; - explicit MapLattice(Container C) { C = std::move(C); } + explicit MapLattice(Container C) : C{std::move(C)} {}; // The `bottom` element is the empty map. static MapLattice bottom() { return MapLattice(); } diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 4825979a974d22a..46d0a66d59c3753 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -477,6 +477,9 @@ def TargetELF : TargetSpec { def TargetELFOrMachO : TargetSpec { let ObjectFormats = ["ELF", "MachO"]; } +def TargetWindowsArm64EC : TargetSpec { + let CustomCode = [{ Target.getTriple().isWindowsArm64EC() }]; +} def TargetSupportsInitPriority : TargetSpec { let CustomCode = [{ !Target.getTriple().isOSzOS() }]; @@ -4027,6 +4030,12 @@ def SelectAny : InheritableAttr { let SimpleHandler = 1; } +def HybridPatchable : InheritableAttr, TargetSpecificAttr { + let Spellings = [Declspec<"hybrid_patchable">, Clang<"hybrid_patchable">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [HybridPatchableDocs]; +} + def Thread : Attr { let Spellings = [Declspec<"thread">]; let LangOpts = [MicrosoftExt]; diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 99738812c815794..4b8d520d73893d5 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -2453,7 +2453,7 @@ For example: typedef vint8m1_t fixed_vint8m1_t __attribute__((riscv_rvv_vector_bits(__riscv_v_fixed_vlen))); #endif -Creates a type ``fixed_vint8m1_t_t`` that is a fixed-length variant of +Creates a type ``fixed_vint8m1_t`` that is a fixed-length variant of ``vint8m1_t`` that contains exactly 512 bits. Unlike ``vint8m1_t``, this type can be used in globals, structs, unions, and arrays, all of which are unsupported for sizeless types. @@ -5985,6 +5985,16 @@ For more information see or `msvc documentation `_. }]; } +def HybridPatchableDocs : Documentation { + let Category = DocCatFunction; + let Content = [{ +The ``hybrid_patchable`` attribute declares an ARM64EC function with an additional +x86-64 thunk, which may be patched at runtime. + +For more information see +`ARM64EC ABI documentation `_. +}]; } + def WebAssemblyExportNameDocs : Documentation { let Category = DocCatFunction; let Content = [{ diff --git a/clang/include/clang/Basic/AttributeCommonInfo.h b/clang/include/clang/Basic/AttributeCommonInfo.h index 5f024b4b5fd7820..cdf9dcaff75083b 100644 --- a/clang/include/clang/Basic/AttributeCommonInfo.h +++ b/clang/include/clang/Basic/AttributeCommonInfo.h @@ -191,6 +191,12 @@ class AttributeCommonInfo { /// __gnu__::__attr__ will be normalized to gnu::attr). std::string getNormalizedFullName() const; + /// Generate a normalized full name, with syntax, scope and name. + static std::string + normalizeFullNameWithSyntax(const IdentifierInfo *Name, + const IdentifierInfo *Scope, + AttributeCommonInfo::Syntax SyntaxUsed); + bool isDeclspecAttribute() const { return SyntaxUsed == AS_Declspec; } bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; } diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 12a4617c64d87e4..8a1462c670d68f6 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -288,6 +288,9 @@ def err_function_needs_feature : Error< let CategoryName = "Codegen ABI Check" in { def err_function_always_inline_attribute_mismatch : Error< "always_inline function %1 and its caller %0 have mismatching %2 attributes">; +def warn_function_always_inline_attribute_mismatch : Warning< + "always_inline function %1 and its caller %0 have mismatching %2 attributes, " + "inlining may change runtime behaviour">, InGroup; def err_function_always_inline_new_za : Error< "always_inline function %0 has new za state">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 810abe4f23e31ed..581434d33c5c9a6 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3330,6 +3330,8 @@ def err_attribute_invalid_implicit_this_argument : Error< "%0 attribute is invalid for the implicit this argument">; def err_ownership_type : Error< "%0 attribute only applies to %select{pointer|integer}1 arguments">; +def err_ownership_takes_return_type : Error< + "'ownership_returns' attribute only applies to functions that return a pointer">; def err_ownership_returns_index_mismatch : Error< "'ownership_returns' attribute index does not match; here it is %0">; def note_ownership_returns_index_mismatch : Note< @@ -3681,6 +3683,9 @@ def err_attribute_weak_static : Error< "weak declaration cannot have internal linkage">; def err_attribute_selectany_non_extern_data : Error< "'selectany' can only be applied to data items with external linkage">; +def warn_attribute_hybrid_patchable_non_extern : Warning< + "'hybrid_patchable' is ignored on functions without external linkage">, + InGroup; def err_declspec_thread_on_thread_variable : Error< "'__declspec(thread)' applied to variable that already has a " "thread-local storage specifier">; @@ -3812,8 +3817,6 @@ def warn_sme_locally_streaming_has_vl_args_returns : Warning< InGroup, DefaultIgnore; def err_conflicting_attributes_arm_state : Error< "conflicting attributes for state '%0'">; -def err_sme_streaming_cannot_be_multiversioned : Error< - "streaming function cannot be multi-versioned">; def err_unknown_arm_state : Error< "unknown state '%0'">; def err_missing_arm_state : Error< @@ -10133,7 +10136,7 @@ def warn_dangling_lifetime_pointer : Warning< InGroup; def warn_dangling_lifetime_pointer_assignment : Warning<"object backing the " "pointer %0 will be destroyed at the end of the full-expression">, - InGroup, DefaultIgnore; + InGroup; def warn_new_dangling_initializer_list : Warning< "array backing " "%select{initializer list subobject of the allocated object|" diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index 834a6f6cd43e320..0035092ce0d8635 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -224,7 +224,6 @@ COMPATIBLE_LANGOPT(GNUInline , 1, 0, "GNU inline semantics") COMPATIBLE_LANGOPT(NoInlineDefine , 1, 0, "__NO_INLINE__ predefined macro") COMPATIBLE_LANGOPT(Deprecated , 1, 0, "__DEPRECATED predefined macro") COMPATIBLE_LANGOPT(FastMath , 1, 0, "fast FP math optimizations, and __FAST_MATH__ predefined macro") -COMPATIBLE_LANGOPT(FiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined macro") COMPATIBLE_LANGOPT(UnsafeFPMath , 1, 0, "Unsafe Floating Point Math") COMPATIBLE_LANGOPT(ProtectParens , 1, 0, "optimizer honors parentheses " "when floating-point expressions are evaluated") @@ -340,7 +339,6 @@ LANGOPT(SinglePrecisionConstants , 1, 0, "treating double-precision floating poi LANGOPT(FastRelaxedMath , 1, 0, "OpenCL fast relaxed math") BENIGN_LANGOPT(CLNoSignedZero , 1, 0, "Permit Floating Point optimization without regard to signed zeros") COMPATIBLE_LANGOPT(CLUnsafeMath , 1, 0, "Unsafe Floating Point Math") -COMPATIBLE_LANGOPT(CLFiniteMathOnly , 1, 0, "__FINITE_MATH_ONLY__ predefined macro") /// FP_CONTRACT mode (on/off/fast). BENIGN_ENUM_LANGOPT(DefaultFPContractMode, FPModeKind, 2, FPM_Off, "FP contraction type") COMPATIBLE_LANGOPT(ExpStrictFP, 1, false, "Enable experimental strict floating point") diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index f46a92d5ecfd44a..51084913bf1024a 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -107,6 +107,7 @@ OPENMP_DEVICE_MODIFIER(device_num) OPENMP_DEFAULTMAP_KIND(scalar) OPENMP_DEFAULTMAP_KIND(aggregate) OPENMP_DEFAULTMAP_KIND(pointer) +OPENMP_DEFAULTMAP_KIND(all) // Modifiers for 'defaultmap' clause. OPENMP_DEFAULTMAP_MODIFIER(alloc) diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 8c54661e65cf463..7e638dc1ddcdbaf 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -501,6 +501,7 @@ TYPE_TRAIT_1(__has_trivial_move_assign, HasTrivialMoveAssign, KEYCXX) TYPE_TRAIT_1(__has_trivial_move_constructor, HasTrivialMoveConstructor, KEYCXX) // GNU and MS Type Traits +TYPE_TRAIT_2(__builtin_is_virtual_base_of, IsVirtualBaseOf, KEYCXX) TYPE_TRAIT_1(__has_nothrow_assign, HasNothrowAssign, KEYCXX) TYPE_TRAIT_1(__has_nothrow_copy, HasNothrowCopy, KEYCXX) TYPE_TRAIT_1(__has_nothrow_constructor, HasNothrowConstructor, KEYCXX) diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 28a5cb71d2219c5..c8c56dbb51b28a4 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -978,15 +978,15 @@ def Wsystem_headers_in_module_EQ : Joined<["-"], "Wsystem-headers-in-module=">, HelpText<"Enable -Wsystem-headers when building ">, MarshallingInfoStringVector>; def Wdeprecated : Flag<["-"], "Wdeprecated">, Group, - Visibility<[ClangOption, CC1Option]>, + Flags<[HelpHidden]>, Visibility<[ClangOption, CC1Option]>, HelpText<"Enable warnings for deprecated constructs and define __DEPRECATED">; def Wno_deprecated : Flag<["-"], "Wno-deprecated">, Group, Visibility<[ClangOption, CC1Option]>; defm invalid_constexpr : BoolWOption<"invalid-constexpr", LangOpts<"CheckConstexprFunctionBodies">, Default, - NegFlag, - PosFlag, + NegFlag, + PosFlag, BothFlags<[], [ClangOption, CC1Option], " checking of constexpr function bodies for validity within a constant expression context">>; def Wl_COMMA : CommaJoined<["-"], "Wl,">, Visibility<[ClangOption, FlangOption]>, Flags<[LinkerInput, RenderAsInput]>, @@ -1117,8 +1117,7 @@ def cl_single_precision_constant : Flag<["-"], "cl-single-precision-constant">, MarshallingInfoFlag>; def cl_finite_math_only : Flag<["-"], "cl-finite-math-only">, Group, Visibility<[ClangOption, CC1Option]>, - HelpText<"OpenCL only. Allow floating-point optimizations that assume arguments and results are not NaNs or +-Inf.">, - MarshallingInfoFlag>; + HelpText<"OpenCL only. Allow floating-point optimizations that assume arguments and results are not NaNs or +-Inf.">; def cl_kernel_arg_info : Flag<["-"], "cl-kernel-arg-info">, Group, Visibility<[ClangOption, CC1Option]>, HelpText<"OpenCL only. Generate kernel argument metadata.">, @@ -2609,13 +2608,12 @@ defm approx_func : BoolFOption<"approx-func", LangOpts<"ApproxFunc">, DefaultFal "with an approximately equivalent calculation", [funsafe_math_optimizations.KeyPath]>, NegFlag>; -defm finite_math_only : BoolFOption<"finite-math-only", - LangOpts<"FiniteMathOnly">, DefaultFalse, +defm finite_math_only : BoolOptionWithoutMarshalling<"f", "finite-math-only", PosFlag, + [ffast_math.KeyPath]>, NegFlag>; defm signed_zeros : BoolFOption<"signed-zeros", LangOpts<"NoSignedZero">, DefaultFalse, @@ -7534,6 +7532,9 @@ def code_completion_brief_comments : Flag<["-"], "code-completion-brief-comments def code_completion_with_fixits : Flag<["-"], "code-completion-with-fixits">, HelpText<"Include code completion results which require small fix-its.">, MarshallingInfoFlag>; +def skip_function_bodies : Flag<["-"], "skip-function-bodies">, + HelpText<"Skip function bodies when possible">, + MarshallingInfoFlag>; def disable_free : Flag<["-"], "disable-free">, HelpText<"Disable freeing of memory on exit">, MarshallingInfoFlag>; @@ -7812,10 +7813,10 @@ def mreassociate : Flag<["-"], "mreassociate">, MarshallingInfoFlag>, ImpliedByAnyOf<[funsafe_math_optimizations.KeyPath]>; def menable_no_nans : Flag<["-"], "menable-no-nans">, HelpText<"Allow optimization to assume there are no NaNs.">, - MarshallingInfoFlag>, ImpliedByAnyOf<[ffinite_math_only.KeyPath]>; -def menable_no_infinities : Flag<["-"], "menable-no-infs">, + MarshallingInfoFlag>, ImpliedByAnyOf<[ffast_math.KeyPath]>; +def menable_no_infs : Flag<["-"], "menable-no-infs">, HelpText<"Allow optimization to assume there are no infinities.">, - MarshallingInfoFlag>, ImpliedByAnyOf<[ffinite_math_only.KeyPath]>; + MarshallingInfoFlag>, ImpliedByAnyOf<[ffast_math.KeyPath]>; def pic_level : Separate<["-"], "pic-level">, HelpText<"Value for __PIC__">, diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index fc7d0053f2323b6..623f868ca1e648d 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -1160,6 +1160,11 @@ class Preprocessor { /// invoked (at which point the last position is popped). std::vector BacktrackPositions; + /// Stack of cached tokens/initial number of cached tokens pairs, allowing + /// nested unannotated backtracks. + std::vector> + UnannotatedBacktrackTokens; + /// True if \p Preprocessor::SkipExcludedConditionalBlock() is running. /// This is used to guard against calling this function recursively. /// @@ -1722,8 +1727,16 @@ class Preprocessor { /// at some point after EnableBacktrackAtThisPos. If you don't, caching of /// tokens will continue indefinitely. /// - void EnableBacktrackAtThisPos(); + /// \param Unannotated Whether token annotations are reverted upon calling + /// Backtrack(). + void EnableBacktrackAtThisPos(bool Unannotated = false); + +private: + std::pair LastBacktrackPos(); + + CachedTokensTy PopUnannotatedBacktrackTokens(); +public: /// Disable the last EnableBacktrackAtThisPos call. void CommitBacktrackedTokens(); @@ -1735,6 +1748,12 @@ class Preprocessor { /// caching of tokens is on. bool isBacktrackEnabled() const { return !BacktrackPositions.empty(); } + /// True if EnableBacktrackAtThisPos() was called and + /// caching of unannotated tokens is on. + bool isUnannotatedBacktrackEnabled() const { + return !UnannotatedBacktrackTokens.empty(); + } + /// Lex the next token for this preprocessor. void Lex(Token &Result); @@ -1841,8 +1860,9 @@ class Preprocessor { void RevertCachedTokens(unsigned N) { assert(isBacktrackEnabled() && "Should only be called when tokens are cached for backtracking"); - assert(signed(CachedLexPos) - signed(N) >= signed(BacktrackPositions.back()) - && "Should revert tokens up to the last backtrack position, not more"); + assert(signed(CachedLexPos) - signed(N) >= + signed(LastBacktrackPos().first) && + "Should revert tokens up to the last backtrack position, not more"); assert(signed(CachedLexPos) - signed(N) >= 0 && "Corrupted backtrack positions ?"); CachedLexPos -= N; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 35bb1a19d40f0ab..ba7d6866ebacd8e 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1025,6 +1025,8 @@ class Parser : public CodeCompletionHandler { /// .... /// TPA.Revert(); /// + /// If the Unannotated parameter is true, any token annotations created + /// during the tentative parse are reverted. class TentativeParsingAction { Parser &P; PreferredTypeBuilder PrevPreferredType; @@ -1034,7 +1036,7 @@ class Parser : public CodeCompletionHandler { bool isActive; public: - explicit TentativeParsingAction(Parser &p) + explicit TentativeParsingAction(Parser &p, bool Unannotated = false) : P(p), PrevPreferredType(P.PreferredType) { PrevTok = P.Tok; PrevTentativelyDeclaredIdentifierCount = @@ -1042,7 +1044,7 @@ class Parser : public CodeCompletionHandler { PrevParenCount = P.ParenCount; PrevBracketCount = P.BracketCount; PrevBraceCount = P.BraceCount; - P.PP.EnableBacktrackAtThisPos(); + P.PP.EnableBacktrackAtThisPos(Unannotated); isActive = true; } void Commit() { @@ -1073,13 +1075,11 @@ class Parser : public CodeCompletionHandler { class RevertingTentativeParsingAction : private Parser::TentativeParsingAction { public: - RevertingTentativeParsingAction(Parser &P) - : Parser::TentativeParsingAction(P) {} + using TentativeParsingAction::TentativeParsingAction; + ~RevertingTentativeParsingAction() { Revert(); } }; - class UnannotatedTentativeParsingAction; - /// ObjCDeclContextSwitch - An object used to switch context from /// an objective-c decl context to its enclosing decl context and /// back. @@ -1984,7 +1984,8 @@ class Parser : public CodeCompletionHandler { CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHasErrors, bool EnteringContext, bool *MayBePseudoDestructor = nullptr, bool IsTypename = false, const IdentifierInfo **LastII = nullptr, - bool OnlyNamespace = false, bool InUsingDeclaration = false); + bool OnlyNamespace = false, bool InUsingDeclaration = false, + bool Disambiguation = false); //===--------------------------------------------------------------------===// // C++11 5.1.2: Lambda expressions diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index 26ffe057c74a229..d6a6cee62a75284 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -984,7 +984,7 @@ class Sema; unsigned getNumParams() const { if (IsSurrogate) { QualType STy = Surrogate->getConversionType(); - while (STy->isPointerType() || STy->isReferenceType()) + while (STy->isPointerOrReferenceType()) STy = STy->getPointeeType(); return STy->castAs()->getNumParams(); } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 7bfdaaae45a93e2..2ec6367eccea01e 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -2214,6 +2214,7 @@ class Sema final : public SemaBase { FST_FreeBSDKPrintf, FST_OSTrace, FST_OSLog, + FST_Syslog, FST_Unknown }; static FormatStringType GetFormatStringType(const FormatAttr *Format); diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index ec5dbd28a52720c..38b55a0eb0a7b07 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -1045,18 +1045,6 @@ def MallocOverflowSecurityChecker : Checker<"MallocOverflow">, def MmapWriteExecChecker : Checker<"MmapWriteExec">, HelpText<"Warn on mmap() calls that are both writable and executable">, - CheckerOptions<[ - CmdLineOption, - CmdLineOption - ]>, Documentation; def ReturnPointerRangeChecker : Checker<"ReturnPtrRange">, diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index 3a4b08725714940..def2970d448d489 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -326,6 +326,10 @@ class LocAsInteger : public NonLoc { static bool classof(SVal V) { return V.getKind() == LocAsIntegerKind; } }; +/// The simplest example of a concrete compound value is nonloc::CompoundVal, +/// which represents a concrete r-value of an initializer-list or a string. +/// Internally, it contains an llvm::ImmutableList of SVal's stored inside the +/// literal. class CompoundVal : public NonLoc { friend class ento::SValBuilder; @@ -346,6 +350,36 @@ class CompoundVal : public NonLoc { static bool classof(SVal V) { return V.getKind() == CompoundValKind; } }; +/// While nonloc::CompoundVal covers a few simple use cases, +/// nonloc::LazyCompoundVal is a more performant and flexible way to represent +/// an rvalue of record type, so it shows up much more frequently during +/// analysis. This value is an r-value that represents a snapshot of any +/// structure "as a whole" at a given moment during the analysis. Such value is +/// already quite far from being referred to as "concrete", as many fields +/// inside it would be unknown or symbolic. nonloc::LazyCompoundVal operates by +/// storing two things: +/// * a reference to the TypedValueRegion being snapshotted (yes, it is always +/// typed), and also +/// * a reference to the whole Store object, obtained from the ProgramState in +/// which the nonloc::LazyCompoundVal was created. +/// +/// Note that the old ProgramState and its Store is kept alive during the +/// analysis because these are immutable functional data structures and each new +/// Store value is represented as "earlier Store" + "additional binding". +/// +/// Essentially, nonloc::LazyCompoundVal is a performance optimization for the +/// analyzer. Because Store is immutable, creating a nonloc::LazyCompoundVal is +/// a very cheap operation. Note that the Store contains all region bindings in +/// the program state, not only related to the region. Later, if necessary, such +/// value can be unpacked -- eg. when it is assigned to another variable. +/// +/// If you ever need to inspect the contents of the LazyCompoundVal, you can use +/// StoreManager::iterBindings(). It'll iterate through all values in the Store, +/// but you're only interested in the ones that belong to +/// LazyCompoundVal::getRegion(); other bindings are immaterial. +/// +/// NOTE: LazyCompoundVal::getRegion() itself is also immaterial (see the actual +/// method docs for details). class LazyCompoundVal : public NonLoc { friend class ento::SValBuilder; @@ -363,6 +397,18 @@ class LazyCompoundVal : public NonLoc { /// It might return null. const void *getStore() const; + /// This function itself is immaterial. It is only an implementation detail. + /// LazyCompoundVal represents only the rvalue, the data (known or unknown) + /// that *was* stored in that region *at some point in the past*. The region + /// should not be used for any purpose other than figuring out what part of + /// the frozen Store you're interested in. The value does not represent the + /// *current* value of that region. Sometimes it may, but this should not be + /// relied upon. Instead, if you want to figure out what region it represents, + /// you typically need to see where you got it from in the first place. The + /// region is absolutely not analogous to the C++ "this" pointer. It is also + /// not a valid way to "materialize" the prvalue into a glvalue in C++, + /// because the region represents the *old* storage (sometimes very old), not + /// the *future* storage. LLVM_ATTRIBUTE_RETURNS_NONNULL const TypedValueRegion *getRegion() const; diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 08ef09d353afc92..103235547f482ef 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -359,6 +359,54 @@ namespace clang { Params, Importer.getToContext().getTranslationUnitDecl()); } + template + void tryUpdateTemplateParmDeclInheritedFrom(NamedDecl *RecentParm, + NamedDecl *NewParm) { + if (auto *ParmT = dyn_cast(RecentParm)) { + if (ParmT->hasDefaultArgument()) { + auto *P = cast(NewParm); + P->removeDefaultArgument(); + P->setInheritedDefaultArgument(Importer.ToContext, ParmT); + } + } + } + + // Update the parameter list `NewParams` of a template declaration + // by "inheriting" default argument values from `RecentParams`, + // which is the parameter list of an earlier declaration of the + // same template. (Note that "inheriting" default argument values + // is not related to object-oriented inheritance.) + // + // In the clang AST template parameters (NonTypeTemplateParmDec, + // TemplateTypeParmDecl, TemplateTemplateParmDecl) have a reference to the + // default value, if one is specified at the first declaration. The default + // value can be specified only once. The template parameters of the + // following declarations have a reference to the original default value + // through the "inherited" value. This value should be set for all imported + // template parameters that have a previous declaration (also a previous + // template declaration). + // + // In the `Visit*ParmDecl` functions the default value of these template + // arguments is always imported. At that location the previous declaration + // is not easily accessible, it is not possible to call + // `setInheritedDefaultArgument` at that place. + // `updateTemplateParametersInheritedFrom` is called later when the already + // imported default value is erased and changed to "inherited". + // It is important to change the mode to "inherited" otherwise false + // structural in-equivalences could be detected. + void updateTemplateParametersInheritedFrom( + const TemplateParameterList &RecentParams, + TemplateParameterList &NewParams) { + for (auto [Idx, Param] : enumerate(RecentParams)) { + tryUpdateTemplateParmDeclInheritedFrom( + Param, NewParams.getParam(Idx)); + tryUpdateTemplateParmDeclInheritedFrom( + Param, NewParams.getParam(Idx)); + tryUpdateTemplateParmDeclInheritedFrom( + Param, NewParams.getParam(Idx)); + } + } + public: explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) {} @@ -4179,12 +4227,6 @@ ExpectedDecl ASTNodeImporter::VisitFieldDecl(FieldDecl *D) { D->getInClassInitStyle())) return ToField; - // We need [[no_unqiue_address]] attributes to be added to FieldDecl, before - // we add fields in CXXRecordDecl::addedMember, otherwise record will be - // marked as having non-zero size. - Err = Importer.ImportAttrs(ToField, D); - if (Err) - return std::move(Err); ToField->setAccess(D->getAccess()); ToField->setLexicalDeclContext(LexicalDC); ToField->setImplicit(D->isImplicit()); @@ -6138,6 +6180,9 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) { } D2->setPreviousDecl(Recent); + + updateTemplateParametersInheritedFrom(*(Recent->getTemplateParameters()), + **TemplateParamsOrErr); } return D2; @@ -6452,6 +6497,9 @@ ExpectedDecl ASTNodeImporter::VisitVarTemplateDecl(VarTemplateDecl *D) { ToTemplated->setPreviousDecl(PrevTemplated); } ToVarTD->setPreviousDecl(Recent); + + updateTemplateParametersInheritedFrom(*(Recent->getTemplateParameters()), + **TemplateParamsOrErr); } return ToVarTD; @@ -6724,6 +6772,9 @@ ASTNodeImporter::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { TemplatedFD->setPreviousDecl(PrevTemplated); } ToFunc->setPreviousDecl(Recent); + + updateTemplateParametersInheritedFrom(*(Recent->getTemplateParameters()), + *Params); } return ToFunc; @@ -9399,19 +9450,6 @@ TranslationUnitDecl *ASTImporter::GetFromTU(Decl *ToD) { return FromDPos->second->getTranslationUnitDecl(); } -Error ASTImporter::ImportAttrs(Decl *ToD, Decl *FromD) { - if (!FromD->hasAttrs() || ToD->hasAttrs()) - return Error::success(); - for (const Attr *FromAttr : FromD->getAttrs()) { - auto ToAttrOrErr = Import(FromAttr); - if (ToAttrOrErr) - ToD->addAttr(*ToAttrOrErr); - else - return ToAttrOrErr.takeError(); - } - return Error::success(); -} - Expected ASTImporter::Import(Decl *FromD) { if (!FromD) return nullptr; @@ -9545,8 +9583,15 @@ Expected ASTImporter::Import(Decl *FromD) { } // Make sure that ImportImpl registered the imported decl. assert(ImportedDecls.count(FromD) != 0 && "Missing call to MapImported?"); - if (auto Error = ImportAttrs(ToD, FromD)) - return std::move(Error); + + if (FromD->hasAttrs()) + for (const Attr *FromAttr : FromD->getAttrs()) { + auto ToAttrOrErr = Import(FromAttr); + if (ToAttrOrErr) + ToD->addAttr(*ToAttrOrErr); + else + return ToAttrOrErr.takeError(); + } // Notify subclasses. Imported(FromD, ToD); diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index bc5a9206c0db280..a1f70546bde426c 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -879,8 +879,6 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { return IDNS_Ordinary; case Label: return IDNS_Label; - case IndirectField: - return IDNS_Ordinary | IDNS_Member; case Binding: case NonTypeTemplateParm: @@ -918,6 +916,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { return IDNS_ObjCProtocol; case Field: + case IndirectField: case ObjCAtDefsField: case ObjCIvar: return IDNS_Member; diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index e2c96431511262f..6212989e21737fa 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -152,7 +152,7 @@ bool CXXTypeidExpr::isMostDerived(ASTContext &Context) const { const Expr *E = getExprOperand()->IgnoreParenNoopCasts(Context); if (const auto *DRE = dyn_cast(E)) { QualType Ty = DRE->getDecl()->getType(); - if (!Ty->isPointerType() && !Ty->isReferenceType()) + if (!Ty->isPointerOrReferenceType()) return true; } diff --git a/clang/lib/AST/Interp/ByteCodeEmitter.cpp b/clang/lib/AST/Interp/ByteCodeEmitter.cpp index fee4432a8f6614d..a01fa15dc0b7dc9 100644 --- a/clang/lib/AST/Interp/ByteCodeEmitter.cpp +++ b/clang/lib/AST/Interp/ByteCodeEmitter.cpp @@ -28,7 +28,8 @@ using namespace clang::interp; /// but that is not correct for our use cases. static bool isUnevaluatedBuiltin(unsigned BuiltinID) { return BuiltinID == Builtin::BI__builtin_classify_type || - BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size; + BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size || + BuiltinID == Builtin::BI__builtin_constant_p; } Function *ByteCodeEmitter::compileFunc(const FunctionDecl *FuncDecl) { diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp index df55d01b8b9d6ce..258e4ed645254a6 100644 --- a/clang/lib/AST/Interp/Compiler.cpp +++ b/clang/lib/AST/Interp/Compiler.cpp @@ -3256,6 +3256,9 @@ bool Compiler::visitInitializer(const Expr *E) { if (E->containsErrors()) return this->emitError(E); + if (!this->checkLiteralType(E)) + return false; + OptionScope Scope(this, /*NewDiscardResult=*/false, /*NewInitializing=*/true); return this->Visit(E); @@ -4370,6 +4373,7 @@ bool Compiler::visitWhileStmt(const WhileStmt *S) { if (!this->jump(CondLabel)) return false; + this->fallthrough(EndLabel); this->emitLabel(EndLabel); return true; @@ -4698,6 +4702,17 @@ bool Compiler::emitLambdaStaticInvokerBody(const CXXMethodDecl *MD) { return this->emitRetVoid(MD); } +template +bool Compiler::checkLiteralType(const Expr *E) { + if (Ctx.getLangOpts().CPlusPlus23) + return true; + + if (!E->isPRValue() || E->getType()->isLiteralType(Ctx.getASTContext())) + return true; + + return this->emitCheckLiteralType(E->getType().getTypePtr(), E); +} + template bool Compiler::visitFunc(const FunctionDecl *F) { // Classify the return type. @@ -5239,6 +5254,10 @@ bool Compiler::visitDeclRef(const ValueDecl *D, const Expr *E) { return false; }; + // DecompositionDecls are just proxies for us. + if (isa(VD)) + return revisit(VD); + // Visit local const variables like normal. if ((VD->hasGlobalStorage() || VD->isLocalVarDecl() || VD->isStaticDataMember()) && diff --git a/clang/lib/AST/Interp/Compiler.h b/clang/lib/AST/Interp/Compiler.h index d22b29d29a92d07..6bc9985fe723281 100644 --- a/clang/lib/AST/Interp/Compiler.h +++ b/clang/lib/AST/Interp/Compiler.h @@ -359,6 +359,8 @@ class Compiler : public ConstStmtVisitor, bool>, const QualType DerivedType); bool emitLambdaStaticInvokerBody(const CXXMethodDecl *MD); + bool checkLiteralType(const Expr *E); + protected: /// Variable to storage mapping. llvm::DenseMap Locals; diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp index b5e992c5a9ac162..b1e06cd4d8a4c3c 100644 --- a/clang/lib/AST/Interp/Context.cpp +++ b/clang/lib/AST/Interp/Context.cpp @@ -176,8 +176,7 @@ std::optional Context::classify(QualType T) const { T->isFunctionType()) return PT_FnPtr; - if (T->isReferenceType() || T->isPointerType() || - T->isObjCObjectPointerType()) + if (T->isPointerOrReferenceType() || T->isObjCObjectPointerType()) return PT_Ptr; if (const auto *AT = T->getAs()) diff --git a/clang/lib/AST/Interp/Descriptor.cpp b/clang/lib/AST/Interp/Descriptor.cpp index 4f7e9eac76a3235..671f2c03d7e5c7a 100644 --- a/clang/lib/AST/Interp/Descriptor.cpp +++ b/clang/lib/AST/Interp/Descriptor.cpp @@ -33,7 +33,8 @@ static void dtorTy(Block *, std::byte *Ptr, const Descriptor *) { template static void moveTy(Block *, const std::byte *Src, std::byte *Dst, const Descriptor *) { - const auto *SrcPtr = reinterpret_cast(Src); + // FIXME: Get rid of the const_cast. + auto *SrcPtr = reinterpret_cast(const_cast(Src)); auto *DstPtr = reinterpret_cast(Dst); new (DstPtr) T(std::move(*SrcPtr)); } diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp index 867284ecf7f4bd2..5e3a5b9515b5284 100644 --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -278,10 +278,15 @@ LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS, OS << "\n"; OS.indent(Spaces) << "This: " << getThis() << "\n"; OS.indent(Spaces) << "RVO: " << getRVOPtr() << "\n"; - - while (const InterpFrame *F = this->Caller) { + OS.indent(Spaces) << "Depth: " << Depth << "\n"; + OS.indent(Spaces) << "ArgSize: " << ArgSize << "\n"; + OS.indent(Spaces) << "Args: " << (void *)Args << "\n"; + OS.indent(Spaces) << "FrameOffset: " << FrameOffset << "\n"; + OS.indent(Spaces) << "FrameSize: " << (Func ? Func->getFrameSize() : 0) + << "\n"; + + for (const InterpFrame *F = this->Caller; F; F = F->Caller) { F->dump(OS, Indent + 1); - F = F->Caller; } } diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 96c59dd14c04a0a..d128988a480e195 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1571,7 +1571,10 @@ inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) { return false; if (!CheckSubobject(S, OpPC, Ptr, CSK_Base)) return false; - S.Stk.push(Ptr.atField(Off)); + const Pointer &Result = Ptr.atField(Off); + if (Result.isPastEnd()) + return false; + S.Stk.push(Result); return true; } @@ -1581,7 +1584,10 @@ inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) { return false; if (!CheckSubobject(S, OpPC, Ptr, CSK_Base)) return false; - S.Stk.push(Ptr.atField(Off)); + const Pointer &Result = Ptr.atField(Off); + if (Result.isPastEnd()) + return false; + S.Stk.push(Result); return true; } @@ -2582,12 +2588,20 @@ inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0); Pointer &ThisPtr = S.Stk.peek(ThisOffset); - QualType DynamicType = ThisPtr.getDeclDesc()->getType(); - const CXXRecordDecl *DynamicDecl; - if (DynamicType->isPointerType() || DynamicType->isReferenceType()) - DynamicDecl = DynamicType->getPointeeCXXRecordDecl(); - else - DynamicDecl = ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl(); + const CXXRecordDecl *DynamicDecl = nullptr; + { + Pointer TypePtr = ThisPtr; + while (TypePtr.isBaseClass()) + TypePtr = TypePtr.getBase(); + + QualType DynamicType = TypePtr.getType(); + if (DynamicType->isPointerType() || DynamicType->isReferenceType()) + DynamicDecl = DynamicType->getPointeeCXXRecordDecl(); + else + DynamicDecl = DynamicType->getAsCXXRecordDecl(); + } + assert(DynamicDecl); + const auto *StaticDecl = cast(Func->getParentDecl()); const auto *InitialFunction = cast(Func->getDecl()); const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction( @@ -2964,6 +2978,39 @@ static inline bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm) { BlockDesc, Source); } +inline bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T) { + assert(T); + assert(!S.getLangOpts().CPlusPlus23); + + // C++1y: A constant initializer for an object o [...] may also invoke + // constexpr constructors for o and its subobjects even if those objects + // are of non-literal class types. + // + // C++11 missed this detail for aggregates, so classes like this: + // struct foo_t { union { int i; volatile int j; } u; }; + // are not (obviously) initializable like so: + // __attribute__((__require_constant_initialization__)) + // static const foo_t x = {{0}}; + // because "i" is a subobject with non-literal initialization (due to the + // volatile member of the union). See: + // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1677 + // Therefore, we use the C++1y behavior. + + if (S.EvaluatingDecl) + return true; + + if (S.Current->getFunction() && S.Current->getFunction()->isConstructor() && + S.Current->getThis().getDeclDesc()->asDecl() == S.EvaluatingDecl) + return true; + + const Expr *E = S.Current->getExpr(OpPC); + if (S.getLangOpts().CPlusPlus11) + S.FFDiag(E, diag::note_constexpr_nonliteral) << E->getType(); + else + S.FFDiag(E, diag::note_invalid_subexpr_in_const_expr); + return false; +} + //===----------------------------------------------------------------------===// // Read opcode arguments //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index c170042144accaa..d7538c76e91d925 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "../ExprConstShared.h" #include "Boolean.h" +#include "Compiler.h" +#include "EvalEmitter.h" #include "Interp.h" #include "PrimType.h" #include "clang/AST/OSLog.h" @@ -1127,6 +1129,76 @@ static bool interp__builtin_ptrauth_string_discriminator( return true; } +// FIXME: This implementation is not complete. +// The Compiler instance we create cannot access the current stack frame, local +// variables, function parameters, etc. We also need protection from +// side-effects, fatal errors, etc. +static bool interp__builtin_constant_p(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *Func, + const CallExpr *Call) { + const Expr *Arg = Call->getArg(0); + QualType ArgType = Arg->getType(); + + auto returnInt = [&S, Call](bool Value) -> bool { + pushInteger(S, Value, Call->getType()); + return true; + }; + + // __builtin_constant_p always has one operand. The rules which gcc follows + // are not precisely documented, but are as follows: + // + // - If the operand is of integral, floating, complex or enumeration type, + // and can be folded to a known value of that type, it returns 1. + // - If the operand can be folded to a pointer to the first character + // of a string literal (or such a pointer cast to an integral type) + // or to a null pointer or an integer cast to a pointer, it returns 1. + // + // Otherwise, it returns 0. + // + // FIXME: GCC also intends to return 1 for literals of aggregate types, but + // its support for this did not work prior to GCC 9 and is not yet well + // understood. + if (ArgType->isIntegralOrEnumerationType() || ArgType->isFloatingType() || + ArgType->isAnyComplexType() || ArgType->isPointerType() || + ArgType->isNullPtrType()) { + InterpStack Stk; + Compiler C(S.Ctx, S.P, S, Stk); + auto Res = C.interpretExpr(Arg, /*ConvertResultToRValue=*/Arg->isGLValue()); + if (Res.isInvalid()) { + C.cleanup(); + Stk.clear(); + } + + if (!Res.isInvalid() && !Res.empty()) { + const APValue &LV = Res.toAPValue(); + if (LV.isLValue()) { + APValue::LValueBase Base = LV.getLValueBase(); + if (Base.isNull()) { + // A null base is acceptable. + return returnInt(true); + } else if (const auto *E = Base.dyn_cast()) { + if (!isa(E)) + return returnInt(false); + return returnInt(LV.getLValueOffset().isZero()); + } else if (Base.is()) { + // Surprisingly, GCC considers __builtin_constant_p(&typeid(int)) to + // evaluate to true. + return returnInt(true); + } else { + // Any other base is not constant enough for GCC. + return returnInt(false); + } + } + } + + // Otherwise, any constant value is good enough. + return returnInt(true); + } + + return returnInt(false); +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, const CallExpr *Call) { const InterpFrame *Frame = S.Current; @@ -1456,6 +1528,11 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, return false; break; + case Builtin::BI__builtin_constant_p: + if (!interp__builtin_constant_p(S, OpPC, Frame, F, Call)) + return false; + break; + default: S.FFDiag(S.Current->getLocation(OpPC), diag::note_invalid_subexpr_in_const_expr) diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index 9f29fa9272711a9..eeb9cb2e933a6f2 100644 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -67,6 +67,7 @@ def ArgVarDecl : ArgType { let Name = "const VarDecl*"; } def ArgDesc : ArgType { let Name = "const Descriptor *"; } def ArgPrimType : ArgType { let Name = "PrimType"; } def ArgEnumDecl : ArgType { let Name = "const EnumDecl *"; } +def ArgTypePtr : ArgType { let Name = "const Type *"; } //===----------------------------------------------------------------------===// // Classes of types instructions operate on. @@ -396,6 +397,10 @@ def CheckEnumValue : Opcode { let HasGroup = 1; } +def CheckLiteralType : Opcode { + let Args = [ArgTypePtr]; +} + // [] -> [Value] def GetGlobal : AccessOpcode; def GetGlobalUnchecked : AccessOpcode; diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index d46d621d4c7d41e..ead5da4e90f2f03 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -6484,7 +6484,7 @@ void CXXNameMangler::mangleValueInTemplateArg(QualType T, const APValue &V, case APValue::LValue: { // Proposed in https://github.com/itanium-cxx-abi/cxx-abi/issues/47. - assert((T->isPointerType() || T->isReferenceType()) && + assert((T->isPointerOrReferenceType()) && "unexpected type for LValue template arg"); if (V.isNullPointer()) { diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index e0d7c01ca33516d..28f66e71c2f2de0 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -1015,6 +1015,7 @@ void MicrosoftCXXNameMangler::mangleFloat(llvm::APFloat Number) { case APFloat::S_Float8E5M2FNUZ: case APFloat::S_Float8E4M3FNUZ: case APFloat::S_Float8E4M3B11FNUZ: + case APFloat::S_Float8E3M4: case APFloat::S_FloatTF32: case APFloat::S_Float6E3M2FN: case APFloat::S_Float6E2M3FN: diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 89d2a422509d816..f1e723b4242eefb 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -624,7 +624,7 @@ void OMPClauseProfiler::VisitOMPFilterClause(const OMPFilterClause *C) { template void OMPClauseProfiler::VisitOMPClauseList(T *Node) { - for (auto *E : Node->varlists()) { + for (auto *E : Node->varlist()) { if (E) Profiler->VisitStmt(E); } @@ -918,7 +918,7 @@ void OMPClauseProfiler::VisitOMPUsesAllocatorsClause( void OMPClauseProfiler::VisitOMPAffinityClause(const OMPAffinityClause *C) { if (const Expr *Modifier = C->getModifier()) Profiler->VisitStmt(Modifier); - for (const Expr *E : C->varlists()) + for (const Expr *E : C->varlist()) Profiler->VisitStmt(E); } void OMPClauseProfiler::VisitOMPOrderClause(const OMPOrderClause *C) {} diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index fdaab8e4345936c..0456b5f96b21044 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -75,7 +75,7 @@ bool Qualifiers::isStrictSupersetOf(Qualifiers Other) const { const IdentifierInfo* QualType::getBaseTypeIdentifier() const { const Type* ty = getTypePtr(); NamedDecl *ND = nullptr; - if (ty->isPointerType() || ty->isReferenceType()) + if (ty->isPointerOrReferenceType()) return ty->getPointeeType().getBaseTypeIdentifier(); else if (ty->isRecordType()) ND = ty->castAs()->getDecl(); diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index bf87b1aa0992a5e..06309d327896b31 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -537,14 +537,23 @@ class PatternSet { /// that didn't match. /// Return true if there are still any patterns left. bool consumeNameSuffix(StringRef NodeName, bool CanSkip) { - for (size_t I = 0; I < Patterns.size();) { - if (::clang::ast_matchers::internal::consumeNameSuffix(Patterns[I].P, - NodeName) || - CanSkip) { - ++I; - } else { - Patterns.erase(Patterns.begin() + I); + if (CanSkip) { + // If we can skip the node, then we need to handle the case where a + // skipped node has the same name as its parent. + // namespace a { inline namespace a { class A; } } + // cxxRecordDecl(hasName("::a::A")) + // To do this, any patterns that match should be duplicated in our set, + // one of them with the tail removed. + for (size_t I = 0, E = Patterns.size(); I != E; ++I) { + StringRef Pattern = Patterns[I].P; + if (ast_matchers::internal::consumeNameSuffix(Patterns[I].P, NodeName)) + Patterns.push_back({Pattern, Patterns[I].IsFullyQualified}); } + } else { + llvm::erase_if(Patterns, [&NodeName](auto &Pattern) { + return !::clang::ast_matchers::internal::consumeNameSuffix(Pattern.P, + NodeName); + }); } return !Patterns.empty(); } diff --git a/clang/lib/Analysis/Consumed.cpp b/clang/lib/Analysis/Consumed.cpp index d01c7f688e8b5d7..63c594324294470 100644 --- a/clang/lib/Analysis/Consumed.cpp +++ b/clang/lib/Analysis/Consumed.cpp @@ -141,7 +141,7 @@ static bool isCallableInState(const CallableWhenAttr *CWAttr, } static bool isConsumableType(const QualType &QT) { - if (QT->isPointerType() || QT->isReferenceType()) + if (QT->isPointerOrReferenceType()) return false; if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl()) @@ -151,7 +151,7 @@ static bool isConsumableType(const QualType &QT) { } static bool isAutoCastType(const QualType &QT) { - if (QT->isPointerType() || QT->isReferenceType()) + if (QT->isPointerOrReferenceType()) return false; if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl()) @@ -186,10 +186,6 @@ static bool isTestingFunction(const FunctionDecl *FunDecl) { return FunDecl->hasAttr(); } -static bool isPointerOrRef(QualType ParamType) { - return ParamType->isPointerType() || ParamType->isReferenceType(); -} - static ConsumedState mapConsumableAttrState(const QualType QT) { assert(isConsumableType(QT)); @@ -648,7 +644,7 @@ bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg, setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT)); else if (isRValueRef(ParamType) || isConsumableType(ParamType)) setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed); - else if (isPointerOrRef(ParamType) && + else if (ParamType->isPointerOrReferenceType() && (!ParamType->getPointeeType().isConstQualified() || isSetOnReadPtrType(ParamType))) setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown); diff --git a/clang/lib/Analysis/FlowSensitive/AdornedCFG.cpp b/clang/lib/Analysis/FlowSensitive/AdornedCFG.cpp index 255543021a998c9..876b5a3db524987 100644 --- a/clang/lib/Analysis/FlowSensitive/AdornedCFG.cpp +++ b/clang/lib/Analysis/FlowSensitive/AdornedCFG.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/Stmt.h" #include "clang/Analysis/CFG.h" +#include "clang/Analysis/FlowSensitive/ASTOps.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/Error.h" @@ -96,8 +97,7 @@ static llvm::BitVector findReachableBlocks(const CFG &Cfg) { static llvm::DenseSet buildContainsExprConsumedInDifferentBlock( - const CFG &Cfg, - const llvm::DenseMap &StmtToBlock) { + const CFG &Cfg, const internal::StmtToBlockMap &StmtToBlock) { llvm::DenseSet Result; auto CheckChildExprs = [&Result, &StmtToBlock](const Stmt *S, @@ -105,7 +105,7 @@ buildContainsExprConsumedInDifferentBlock( for (const Stmt *Child : S->children()) { if (!isa_and_nonnull(Child)) continue; - const CFGBlock *ChildBlock = StmtToBlock.lookup(Child); + const CFGBlock *ChildBlock = StmtToBlock.lookup(*Child); if (ChildBlock != Block) Result.insert(ChildBlock); } @@ -126,6 +126,13 @@ buildContainsExprConsumedInDifferentBlock( return Result; } +namespace internal { + +StmtToBlockMap::StmtToBlockMap(const CFG &Cfg) + : StmtToBlock(buildStmtToBasicBlockMap(Cfg)) {} + +} // namespace internal + llvm::Expected AdornedCFG::build(const FunctionDecl &Func) { if (!Func.doesThisDeclarationHaveABody()) return llvm::createStringError( @@ -166,8 +173,7 @@ llvm::Expected AdornedCFG::build(const Decl &D, Stmt &S, std::make_error_code(std::errc::invalid_argument), "CFG::buildCFG failed"); - llvm::DenseMap StmtToBlock = - buildStmtToBasicBlockMap(*Cfg); + internal::StmtToBlockMap StmtToBlock(*Cfg); llvm::BitVector BlockReachable = findReachableBlocks(*Cfg); diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 8d7fe1848821714..e1f68e493f3553c 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -416,7 +416,7 @@ class ResultObjectVisitor : public AnalysisASTVisitor { // below them can initialize the same object (or part of it). if (isa(E) || isa(E) || isa(E) || isa(E) || isa(E) || - isa(E) || + isa(E) || isa(E) || // We treat `BuiltinBitCastExpr` as an "original initializer" too as // it may not even be casting from a record type -- and even if it is, // the two objects are in general of unrelated type. diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 3c896d373a211dd..9c54eb16d22246a 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -40,17 +40,16 @@ namespace clang { namespace dataflow { const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const { - auto BlockIt = ACFG.getStmtToBlock().find(&ignoreCFGOmittedNodes(S)); - if (BlockIt == ACFG.getStmtToBlock().end()) { + const CFGBlock *Block = ACFG.blockForStmt(S); + if (Block == nullptr) { assert(false); - // Return null to avoid dereferencing the end iterator in non-assert builds. return nullptr; } - if (!ACFG.isBlockReachable(*BlockIt->getSecond())) + if (!ACFG.isBlockReachable(*Block)) return nullptr; - if (BlockIt->getSecond()->getBlockID() == CurBlockID) + if (Block->getBlockID() == CurBlockID) return &CurState.Env; - const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()]; + const auto &State = BlockToState[Block->getBlockID()]; if (!(State)) return nullptr; return &State->Env; diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 200682faafd6ab5..8afd18b315d286d 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -243,10 +243,11 @@ computeBlockInputState(const CFGBlock &Block, AnalysisContext &AC) { // See `NoreturnDestructorTest` for concrete examples. if (Block.succ_begin()->getReachableBlock() != nullptr && Block.succ_begin()->getReachableBlock()->hasNoReturnElement()) { - auto &StmtToBlock = AC.ACFG.getStmtToBlock(); - auto StmtBlock = StmtToBlock.find(Block.getTerminatorStmt()); - assert(StmtBlock != StmtToBlock.end()); - llvm::erase(Preds, StmtBlock->getSecond()); + const CFGBlock *StmtBlock = nullptr; + if (const Stmt *Terminator = Block.getTerminatorStmt()) + StmtBlock = AC.ACFG.blockForStmt(*Terminator); + assert(StmtBlock != nullptr); + llvm::erase(Preds, StmtBlock); } } diff --git a/clang/lib/Analysis/LiveVariables.cpp b/clang/lib/Analysis/LiveVariables.cpp index 6d03dd05ca3d277..481932ee59c8eeb 100644 --- a/clang/lib/Analysis/LiveVariables.cpp +++ b/clang/lib/Analysis/LiveVariables.cpp @@ -214,6 +214,22 @@ static void AddLiveExpr(llvm::ImmutableSet &Set, Set = F.add(Set, LookThroughExpr(E)); } +/// Add as a live expression all individual conditions in a logical expression. +/// For example, for the expression: +/// "(a < b) || (c && d && ((e || f) != (g && h)))" +/// the following expressions will be added as live: +/// "a < b", "c", "d", "((e || f) != (g && h))" +static void AddAllConditionalTerms(llvm::ImmutableSet &Set, + llvm::ImmutableSet::Factory &F, + const Expr *Cond) { + AddLiveExpr(Set, F, Cond); + if (auto const *BO = dyn_cast(Cond->IgnoreParens()); + BO && BO->isLogicalOp()) { + AddAllConditionalTerms(Set, F, BO->getLHS()); + AddAllConditionalTerms(Set, F, BO->getRHS()); + } +} + void TransferFunctions::Visit(Stmt *S) { if (observer) observer->observeStmt(S, currentBlock, val); @@ -313,7 +329,27 @@ void TransferFunctions::Visit(Stmt *S) { AddLiveExpr(val.liveExprs, LV.ESetFact, cast(S)->getCond()); return; } - + case Stmt::ConditionalOperatorClass: { + // Keep not only direct children alive, but also all the short-circuited + // parts of the condition. Short-circuiting evaluation may cause the + // conditional operator evaluation to skip the evaluation of the entire + // condtion expression, so the value of the entire condition expression is + // never computed. + // + // This makes a difference when we compare exploded nodes coming from true + // and false expressions with no side effects: the only difference in the + // state is the value of (part of) the condition. + // + // BinaryConditionalOperatorClass ('x ?: y') is not affected because it + // explicitly calculates the value of the entire condition expression (to + // possibly use as a value for the "true expr") even if it is + // short-circuited. + auto const *CO = cast(S); + AddAllConditionalTerms(val.liveExprs, LV.ESetFact, CO->getCond()); + AddLiveExpr(val.liveExprs, LV.ESetFact, CO->getTrueExpr()); + AddLiveExpr(val.liveExprs, LV.ESetFact, CO->getFalseExpr()); + return; + } } // HACK + FIXME: What is this? One could only guess that this is an attempt to diff --git a/clang/lib/Analysis/ThreadSafetyCommon.cpp b/clang/lib/Analysis/ThreadSafetyCommon.cpp index 3e8c959ccee4f65..cbcfefdc525490d 100644 --- a/clang/lib/Analysis/ThreadSafetyCommon.cpp +++ b/clang/lib/Analysis/ThreadSafetyCommon.cpp @@ -97,7 +97,7 @@ static StringRef ClassifyDiagnostic(QualType VDT) { if (const auto *TD = TT->getDecl()) if (const auto *CA = TD->getAttr()) return ClassifyDiagnostic(CA); - } else if (VDT->isPointerType() || VDT->isReferenceType()) + } else if (VDT->isPointerOrReferenceType()) return ClassifyDiagnostic(VDT->getPointeeType()); return "mutex"; diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp index 867d241a2cf8479..a39eb85f7e8faab 100644 --- a/clang/lib/Basic/Attributes.cpp +++ b/clang/lib/Basic/Attributes.cpp @@ -153,6 +153,40 @@ std::string AttributeCommonInfo::getNormalizedFullName() const { normalizeName(getAttrName(), getScopeName(), getSyntax())); } +static StringRef getSyntaxName(AttributeCommonInfo::Syntax SyntaxUsed) { + switch (SyntaxUsed) { + case AttributeCommonInfo::AS_GNU: + return "GNU"; + case AttributeCommonInfo::AS_CXX11: + return "CXX11"; + case AttributeCommonInfo::AS_C23: + return "C23"; + case AttributeCommonInfo::AS_Declspec: + return "Declspec"; + case AttributeCommonInfo::AS_Microsoft: + return "Microsoft"; + case AttributeCommonInfo::AS_Keyword: + return "Keyword"; + case AttributeCommonInfo::AS_Pragma: + return "Pragma"; + case AttributeCommonInfo::AS_ContextSensitiveKeyword: + return "ContextSensitiveKeyword"; + case AttributeCommonInfo::AS_HLSLAnnotation: + return "HLSLAnnotation"; + case AttributeCommonInfo::AS_Implicit: + return "Implicit"; + } + llvm_unreachable("Invalid attribute syntax"); +} + +std::string AttributeCommonInfo::normalizeFullNameWithSyntax( + const IdentifierInfo *Name, const IdentifierInfo *ScopeName, + Syntax SyntaxUsed) { + return (Twine(getSyntaxName(SyntaxUsed)) + + "::" + normalizeName(Name, ScopeName, SyntaxUsed)) + .str(); +} + unsigned AttributeCommonInfo::calculateAttributeSpellingListIndex() const { // Both variables will be used in tablegen generated // attribute spell list index matching code. diff --git a/clang/lib/Basic/LangOptions.cpp b/clang/lib/Basic/LangOptions.cpp index e5adc034f60c1f7..9331a63d91b1736 100644 --- a/clang/lib/Basic/LangOptions.cpp +++ b/clang/lib/Basic/LangOptions.cpp @@ -34,8 +34,8 @@ void LangOptions::resetNonModularOptions() { // invocations that cannot be round-tripped to arguments. // FIXME: we should derive this automatically from ImpliedBy in tablegen. AllowFPReassoc = UnsafeFPMath; - NoHonorNaNs = FiniteMathOnly; - NoHonorInfs = FiniteMathOnly; + NoHonorInfs = FastMath; + NoHonorNaNs = FastMath; // These options do not affect AST generation. NoSanitizeFiles.clear(); diff --git a/clang/lib/Basic/Sarif.cpp b/clang/lib/Basic/Sarif.cpp index 8c144df34167363..980b0ae40ae2249 100644 --- a/clang/lib/Basic/Sarif.cpp +++ b/clang/lib/Basic/Sarif.cpp @@ -141,7 +141,7 @@ static unsigned int adjustColumnPos(FullSourceLoc Loc, /// @{ /// \internal -json::Object createMessage(StringRef Text) { +static json::Object createMessage(StringRef Text) { return json::Object{{"text", Text.str()}}; } diff --git a/clang/lib/Basic/Targets/OSTargets.cpp b/clang/lib/Basic/Targets/OSTargets.cpp index 899aefa6173acfe..b56e2c7ca9c494a 100644 --- a/clang/lib/Basic/Targets/OSTargets.cpp +++ b/clang/lib/Basic/Targets/OSTargets.cpp @@ -173,10 +173,10 @@ static void addVisualCDefines(const LangOptions &Opts, MacroBuilder &Builder) { // "Under /fp:precise and /fp:strict, the compiler doesn't do any mathematical // transformation unless the transformation is guaranteed to produce a bitwise // identical result." - const bool any_imprecise_flags = - Opts.FastMath || Opts.FiniteMathOnly || Opts.UnsafeFPMath || - Opts.AllowFPReassoc || Opts.NoHonorNaNs || Opts.NoHonorInfs || - Opts.NoSignedZero || Opts.AllowRecip || Opts.ApproxFunc; + const bool any_imprecise_flags = Opts.FastMath || Opts.UnsafeFPMath || + Opts.AllowFPReassoc || Opts.NoHonorNaNs || + Opts.NoHonorInfs || Opts.NoSignedZero || + Opts.AllowRecip || Opts.ApproxFunc; // "Under both /fp:precise and /fp:fast, the compiler generates code intended // to run in the default floating-point environment." diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp index fbf942d06ca6edb..fbe9569e50ef634 100644 --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -727,7 +727,7 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *E, Address Dest, llvm::Value *LoadVal1 = CGF.Builder.CreateLoad(Val1); llvm::AtomicRMWInst *RMWI = - CGF.Builder.CreateAtomicRMW(Op, Ptr, LoadVal1, Order, Scope); + CGF.emitAtomicRMWInst(Op, Ptr, LoadVal1, Order, Scope); RMWI->setVolatile(E->isVolatile()); // For __atomic_*_fetch operations, perform the operation again to @@ -2034,6 +2034,17 @@ std::pair CodeGenFunction::EmitAtomicCompareExchange( IsWeak); } +llvm::AtomicRMWInst * +CodeGenFunction::emitAtomicRMWInst(llvm::AtomicRMWInst::BinOp Op, Address Addr, + llvm::Value *Val, llvm::AtomicOrdering Order, + llvm::SyncScope::ID SSID) { + + llvm::AtomicRMWInst *RMW = + Builder.CreateAtomicRMW(Op, Addr, Val, Order, SSID); + getTargetHooks().setTargetAtomicMetadata(*this, *RMW); + return RMW; +} + void CodeGenFunction::EmitAtomicUpdate( LValue LVal, llvm::AtomicOrdering AO, const llvm::function_ref &UpdateOp, bool IsVolatile) { diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 0c4d0efb70ea51b..0c2ee446aa303aa 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -692,23 +692,15 @@ static RValue emitLibraryCall(CodeGenFunction &CGF, const FunctionDecl *FD, RValue Call = CGF.EmitCall(E->getCallee()->getType(), callee, E, ReturnValueSlot()); - // Check the supported intrinsic. if (unsigned BuiltinID = FD->getBuiltinID()) { - auto IsErrnoIntrinsic = [&]() -> unsigned { - switch (BuiltinID) { - case Builtin::BIexpf: - case Builtin::BI__builtin_expf: - case Builtin::BI__builtin_expf128: - return true; - } - // TODO: support more FP math libcalls - return false; - }(); - + // Check whether a FP math builtin function, such as BI__builtin_expf + ASTContext &Context = CGF.getContext(); + bool ConstWithoutErrnoAndExceptions = + Context.BuiltinInfo.isConstWithoutErrnoAndExceptions(BuiltinID); // Restrict to target with errno, for example, MacOS doesn't set errno. - if (IsErrnoIntrinsic && CGF.CGM.getLangOpts().MathErrno && - !CGF.Builder.getIsFPConstrained()) { - ASTContext &Context = CGF.getContext(); + // TODO: Support builtin function with complex type returned, eg: cacosh + if (ConstWithoutErrnoAndExceptions && CGF.CGM.getLangOpts().MathErrno && + !CGF.Builder.getIsFPConstrained() && Call.isScalar()) { // Emit "int" TBAA metadata on FP math libcalls. clang::QualType IntTy = Context.IntTy; TBAAAccessInfo TBAAInfo = CGF.CGM.getTBAAAccessInfo(IntTy); @@ -5986,8 +5978,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, getTarget().getTriple().isAMDGCN() || (getTarget().getTriple().isSPIRV() && getTarget().getTriple().getVendor() == Triple::VendorType::AMD)) { - if (getLangOpts().OpenMPIsTargetDevice) - return EmitOpenMPDevicePrintfCallExpr(E); if (getTarget().getTriple().isNVPTX()) return EmitNVPTXDevicePrintfCallExpr(E); if ((getTarget().getTriple().isAMDGCN() || diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 3d8a715b692de82..b49dee24c3c1ac4 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1942,7 +1942,12 @@ CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method, if (Method->isStatic()) return cast_or_null( getOrCreateType(QualType(Func, 0), Unit)); - return getOrCreateInstanceMethodType(Method->getThisType(), Func, Unit); + + QualType ThisType; + if (!Method->hasCXXExplicitFunctionObjectParameter()) + ThisType = Method->getThisType(); + + return getOrCreateInstanceMethodType(ThisType, Func, Unit); } llvm::DISubroutineType *CGDebugInfo::getOrCreateInstanceMethodType( @@ -1974,27 +1979,31 @@ llvm::DISubroutineType *CGDebugInfo::getOrCreateInstanceMethodType( Elts.push_back(Args[0]); // "this" pointer is always first argument. - const CXXRecordDecl *RD = ThisPtr->getPointeeCXXRecordDecl(); - if (isa(RD)) { - // Create pointer type directly in this case. - const PointerType *ThisPtrTy = cast(ThisPtr); - uint64_t Size = CGM.getContext().getTypeSize(ThisPtrTy); - auto Align = getTypeAlignIfRequired(ThisPtrTy, CGM.getContext()); - llvm::DIType *PointeeType = - getOrCreateType(ThisPtrTy->getPointeeType(), Unit); - llvm::DIType *ThisPtrType = - DBuilder.createPointerType(PointeeType, Size, Align); - TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType); - // TODO: This and the artificial type below are misleading, the - // types aren't artificial the argument is, but the current - // metadata doesn't represent that. - ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); - Elts.push_back(ThisPtrType); - } else { - llvm::DIType *ThisPtrType = getOrCreateType(ThisPtr, Unit); - TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType); - ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); - Elts.push_back(ThisPtrType); + // ThisPtr may be null if the member function has an explicit 'this' + // parameter. + if (!ThisPtr.isNull()) { + const CXXRecordDecl *RD = ThisPtr->getPointeeCXXRecordDecl(); + if (isa(RD)) { + // Create pointer type directly in this case. + const PointerType *ThisPtrTy = cast(ThisPtr); + uint64_t Size = CGM.getContext().getTypeSize(ThisPtrTy); + auto Align = getTypeAlignIfRequired(ThisPtrTy, CGM.getContext()); + llvm::DIType *PointeeType = + getOrCreateType(ThisPtrTy->getPointeeType(), Unit); + llvm::DIType *ThisPtrType = + DBuilder.createPointerType(PointeeType, Size, Align); + TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType); + // TODO: This and the artificial type below are misleading, the + // types aren't artificial the argument is, but the current + // metadata doesn't represent that. + ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); + Elts.push_back(ThisPtrType); + } else { + llvm::DIType *ThisPtrType = getOrCreateType(ThisPtr, Unit); + TypeCache[ThisPtr.getAsOpaquePtr()].reset(ThisPtrType); + ThisPtrType = DBuilder.createObjectPointerType(ThisPtrType); + Elts.push_back(ThisPtrType); + } } // Copy rest of the arguments. diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index c3251bb5ab56579..882dbad456379a4 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -2790,7 +2790,7 @@ void CodeGenModule::EmitOMPRequiresDecl(const OMPRequiresDecl *D) { } void CodeGenModule::EmitOMPAllocateDecl(const OMPAllocateDecl *D) { - for (const Expr *E : D->varlists()) { + for (const Expr *E : D->varlist()) { const auto *DE = cast(E); const auto *VD = cast(DE->getDecl()); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index a17d68424bbce5e..84392745ea6144d 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -2841,9 +2841,10 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, isInc ? llvm::Instruction::FAdd : llvm::Instruction::FSub; llvm::Value *amt = llvm::ConstantFP::get( VMContext, llvm::APFloat(static_cast(1.0))); - llvm::Value *old = - Builder.CreateAtomicRMW(aop, LV.getAddress(), amt, - llvm::AtomicOrdering::SequentiallyConsistent); + llvm::AtomicRMWInst *old = + CGF.emitAtomicRMWInst(aop, LV.getAddress(), amt, + llvm::AtomicOrdering::SequentiallyConsistent); + return isPre ? Builder.CreateBinOp(op, old, amt) : old; } value = EmitLoadOfLValue(LV, E->getExprLoc()); @@ -3583,9 +3584,9 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue( EmitScalarConversion(OpInfo.RHS, E->getRHS()->getType(), LHSTy, E->getExprLoc()), LHSTy); - Value *OldVal = Builder.CreateAtomicRMW( - AtomicOp, LHSLV.getAddress(), Amt, - llvm::AtomicOrdering::SequentiallyConsistent); + + llvm::AtomicRMWInst *OldVal = + CGF.emitAtomicRMWInst(AtomicOp, LHSLV.getAddress(), Amt); // Since operation is atomic, the result type is guaranteed to be the // same as the input in LLVM terms. diff --git a/clang/lib/CodeGen/CGGPUBuiltin.cpp b/clang/lib/CodeGen/CGGPUBuiltin.cpp index b2340732afeb5a9..84adf29e8db87eb 100644 --- a/clang/lib/CodeGen/CGGPUBuiltin.cpp +++ b/clang/lib/CodeGen/CGGPUBuiltin.cpp @@ -42,28 +42,6 @@ llvm::Function *GetVprintfDeclaration(llvm::Module &M) { VprintfFuncType, llvm::GlobalVariable::ExternalLinkage, "vprintf", &M); } -llvm::Function *GetOpenMPVprintfDeclaration(CodeGenModule &CGM) { - const char *Name = "__llvm_omp_vprintf"; - llvm::Module &M = CGM.getModule(); - llvm::Type *ArgTypes[] = {llvm::PointerType::getUnqual(M.getContext()), - llvm::PointerType::getUnqual(M.getContext()), - llvm::Type::getInt32Ty(M.getContext())}; - llvm::FunctionType *VprintfFuncType = llvm::FunctionType::get( - llvm::Type::getInt32Ty(M.getContext()), ArgTypes, false); - - if (auto *F = M.getFunction(Name)) { - if (F->getFunctionType() != VprintfFuncType) { - CGM.Error(SourceLocation(), - "Invalid type declaration for __llvm_omp_vprintf"); - return nullptr; - } - return F; - } - - return llvm::Function::Create( - VprintfFuncType, llvm::GlobalVariable::ExternalLinkage, Name, &M); -} - // Transforms a call to printf into a call to the NVPTX vprintf syscall (which // isn't particularly special; it's invoked just like a regular function). // vprintf takes two args: A format string, and a pointer to a buffer containing @@ -213,10 +191,3 @@ RValue CodeGenFunction::EmitAMDGPUDevicePrintfCallExpr(const CallExpr *E) { Builder.SetInsertPoint(IRB.GetInsertBlock(), IRB.GetInsertPoint()); return RValue::get(Printf); } - -RValue CodeGenFunction::EmitOpenMPDevicePrintfCallExpr(const CallExpr *E) { - assert(getTarget().getTriple().isNVPTX() || - getTarget().getTriple().isAMDGCN()); - return EmitDevicePrintfCallExpr(E, this, GetOpenMPVprintfDeclaration(CGM), - true); -} diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 2cef23c733d2563..d869aa3322cce86 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -3861,7 +3861,7 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, HasIterator = true; continue; } - for (const Expr *E : C->varlists()) { + for (const Expr *E : C->varlist()) { llvm::Value *Addr; llvm::Value *Size; std::tie(Addr, Size) = getPointerAndSize(CGF, E); @@ -3894,7 +3894,7 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, continue; OMPIteratorGeneratorScope IteratorScope( CGF, cast_or_null(Modifier->IgnoreParenImpCasts())); - for (const Expr *E : C->varlists()) { + for (const Expr *E : C->varlist()) { llvm::Value *Addr; llvm::Value *Size; std::tie(Addr, Size) = getPointerAndSize(CGF, E); @@ -8187,7 +8187,7 @@ class MappableExprsHandler { : CurDir(&Dir), CGF(CGF) { // Extract firstprivate clause information. for (const auto *C : Dir.getClausesOfKind()) - for (const auto *D : C->varlists()) + for (const auto *D : C->varlist()) FirstPrivateDecls.try_emplace( cast(cast(D)->getDecl()), C->isImplicit()); // Extract implicit firstprivates from uses_allocators clauses. @@ -8867,36 +8867,21 @@ emitMappingInformation(CodeGenFunction &CGF, llvm::OpenMPIRBuilder &OMPBuilder, PLoc.getLine(), PLoc.getColumn(), SrcLocStrSize); } - /// Emit the arrays used to pass the captures and map information to the /// offloading runtime library. If there is no map or capture information, /// return nullptr by reference. -static void emitOffloadingArrays( +static void emitOffloadingArraysAndArgs( CodeGenFunction &CGF, MappableExprsHandler::MapCombinedInfoTy &CombinedInfo, CGOpenMPRuntime::TargetDataInfo &Info, llvm::OpenMPIRBuilder &OMPBuilder, - bool IsNonContiguous = false) { + bool IsNonContiguous = false, bool ForEndCall = false) { CodeGenModule &CGM = CGF.CGM; - // Reset the array information. - Info.clearArrayInfo(); - Info.NumberOfPtrs = CombinedInfo.BasePointers.size(); - using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy; InsertPointTy AllocaIP(CGF.AllocaInsertPt->getParent(), CGF.AllocaInsertPt->getIterator()); InsertPointTy CodeGenIP(CGF.Builder.GetInsertBlock(), CGF.Builder.GetInsertPoint()); - auto FillInfoMap = [&](MappableExprsHandler::MappingExprInfo &MapExpr) { - return emitMappingInformation(CGF, OMPBuilder, MapExpr); - }; - if (CGM.getCodeGenOpts().getDebugInfo() != - llvm::codegenoptions::NoDebugInfo) { - CombinedInfo.Names.resize(CombinedInfo.Exprs.size()); - llvm::transform(CombinedInfo.Exprs, CombinedInfo.Names.begin(), - FillInfoMap); - } - auto DeviceAddrCB = [&](unsigned int I, llvm::Value *NewDecl) { if (const ValueDecl *DevVD = CombinedInfo.DevicePtrDecls[I]) { Info.CaptureDeviceAddrMap.try_emplace(DevVD, NewDecl); @@ -8907,14 +8892,14 @@ static void emitOffloadingArrays( llvm::Value *MFunc = nullptr; if (CombinedInfo.Mappers[I]) { Info.HasMapper = true; - MFunc = CGF.CGM.getOpenMPRuntime().getOrCreateUserDefinedMapperFunc( + MFunc = CGM.getOpenMPRuntime().getOrCreateUserDefinedMapperFunc( cast(CombinedInfo.Mappers[I])); } return MFunc; }; - OMPBuilder.emitOffloadingArrays(AllocaIP, CodeGenIP, CombinedInfo, Info, - /*IsNonContiguous=*/true, DeviceAddrCB, - CustomMapperCB); + OMPBuilder.emitOffloadingArraysAndArgs( + AllocaIP, CodeGenIP, Info, Info.RTArgs, CombinedInfo, IsNonContiguous, + ForEndCall, DeviceAddrCB, CustomMapperCB); } /// Check for inner distribute directive. @@ -9479,29 +9464,14 @@ llvm::Value *emitDynCGGroupMem(const OMPExecutableDirective &D, } return DynCGroupMem; } +static void genMapInfoForCaptures( + MappableExprsHandler &MEHandler, CodeGenFunction &CGF, + const CapturedStmt &CS, llvm::SmallVectorImpl &CapturedVars, + llvm::OpenMPIRBuilder &OMPBuilder, + llvm::DenseSet> &MappedVarSet, + MappableExprsHandler::MapCombinedInfoTy &CombinedInfo) { -static void emitTargetCallKernelLaunch( - CGOpenMPRuntime *OMPRuntime, llvm::Function *OutlinedFn, - const OMPExecutableDirective &D, - llvm::SmallVectorImpl &CapturedVars, bool RequiresOuterTask, - const CapturedStmt &CS, bool OffloadingMandatory, - llvm::PointerIntPair Device, - llvm::Value *OutlinedFnID, CodeGenFunction::OMPTargetDataInfo &InputInfo, - llvm::Value *&MapTypesArray, llvm::Value *&MapNamesArray, - llvm::function_ref - SizeEmitter, - CodeGenFunction &CGF, CodeGenModule &CGM) { - llvm::OpenMPIRBuilder &OMPBuilder = OMPRuntime->getOMPBuilder(); - - // Fill up the arrays with all the captured variables. - MappableExprsHandler::MapCombinedInfoTy CombinedInfo; - - // Get mappable expression information. - MappableExprsHandler MEHandler(D, CGF); llvm::DenseMap LambdaPointers; - llvm::DenseSet> MappedVarSet; - auto RI = CS.getCapturedRecordDecl()->field_begin(); auto *CV = CapturedVars.begin(); for (CapturedStmt::const_capture_iterator CI = CS.capture_begin(), @@ -9568,18 +9538,64 @@ static void emitTargetCallKernelLaunch( MEHandler.adjustMemberOfForLambdaCaptures( OMPBuilder, LambdaPointers, CombinedInfo.BasePointers, CombinedInfo.Pointers, CombinedInfo.Types); +} +static void +genMapInfo(MappableExprsHandler &MEHandler, CodeGenFunction &CGF, + MappableExprsHandler::MapCombinedInfoTy &CombinedInfo, + llvm::OpenMPIRBuilder &OMPBuilder, + const llvm::DenseSet> &SkippedVarSet = + llvm::DenseSet>()) { + + CodeGenModule &CGM = CGF.CGM; // Map any list items in a map clause that were not captures because they // weren't referenced within the construct. - MEHandler.generateAllInfo(CombinedInfo, OMPBuilder, MappedVarSet); + MEHandler.generateAllInfo(CombinedInfo, OMPBuilder, SkippedVarSet); + + auto FillInfoMap = [&](MappableExprsHandler::MappingExprInfo &MapExpr) { + return emitMappingInformation(CGF, OMPBuilder, MapExpr); + }; + if (CGM.getCodeGenOpts().getDebugInfo() != + llvm::codegenoptions::NoDebugInfo) { + CombinedInfo.Names.resize(CombinedInfo.Exprs.size()); + llvm::transform(CombinedInfo.Exprs, CombinedInfo.Names.begin(), + FillInfoMap); + } +} +static void genMapInfo(const OMPExecutableDirective &D, CodeGenFunction &CGF, + const CapturedStmt &CS, + llvm::SmallVectorImpl &CapturedVars, + llvm::OpenMPIRBuilder &OMPBuilder, + MappableExprsHandler::MapCombinedInfoTy &CombinedInfo) { + // Get mappable expression information. + MappableExprsHandler MEHandler(D, CGF); + llvm::DenseSet> MappedVarSet; + + genMapInfoForCaptures(MEHandler, CGF, CS, CapturedVars, OMPBuilder, + MappedVarSet, CombinedInfo); + genMapInfo(MEHandler, CGF, CombinedInfo, OMPBuilder, MappedVarSet); +} +static void emitTargetCallKernelLaunch( + CGOpenMPRuntime *OMPRuntime, llvm::Function *OutlinedFn, + const OMPExecutableDirective &D, + llvm::SmallVectorImpl &CapturedVars, bool RequiresOuterTask, + const CapturedStmt &CS, bool OffloadingMandatory, + llvm::PointerIntPair Device, + llvm::Value *OutlinedFnID, CodeGenFunction::OMPTargetDataInfo &InputInfo, + llvm::Value *&MapTypesArray, llvm::Value *&MapNamesArray, + llvm::function_ref + SizeEmitter, + CodeGenFunction &CGF, CodeGenModule &CGM) { + llvm::OpenMPIRBuilder &OMPBuilder = OMPRuntime->getOMPBuilder(); + + // Fill up the arrays with all the captured variables. + MappableExprsHandler::MapCombinedInfoTy CombinedInfo; CGOpenMPRuntime::TargetDataInfo Info; - // Fill up the arrays and create the arguments. - emitOffloadingArrays(CGF, CombinedInfo, Info, OMPBuilder); - bool EmitDebug = CGF.CGM.getCodeGenOpts().getDebugInfo() != - llvm::codegenoptions::NoDebugInfo; - OMPBuilder.emitOffloadingArraysArgument(CGF.Builder, Info.RTArgs, Info, - EmitDebug, - /*ForEndCall=*/false); + genMapInfo(D, CGF, CS, CapturedVars, OMPBuilder, CombinedInfo); + + emitOffloadingArraysAndArgs(CGF, CombinedInfo, Info, OMPBuilder, + /*IsNonContiguous=*/true, /*ForEndCall=*/false); InputInfo.NumberOfTargetItems = Info.NumberOfPtrs; InputInfo.BasePointersArray = Address(Info.RTArgs.BasePointersArray, @@ -10474,22 +10490,15 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall( PrePostActionTy &) { // Fill up the arrays with all the mapped variables. MappableExprsHandler::MapCombinedInfoTy CombinedInfo; - - // Get map clause information. + CGOpenMPRuntime::TargetDataInfo Info; MappableExprsHandler MEHandler(D, CGF); - MEHandler.generateAllInfo(CombinedInfo, OMPBuilder); + genMapInfo(MEHandler, CGF, CombinedInfo, OMPBuilder); + emitOffloadingArraysAndArgs(CGF, CombinedInfo, Info, OMPBuilder, + /*IsNonContiguous=*/true, /*ForEndCall=*/false); - CGOpenMPRuntime::TargetDataInfo Info; - // Fill up the arrays and create the arguments. - emitOffloadingArrays(CGF, CombinedInfo, Info, OMPBuilder, - /*IsNonContiguous=*/true); bool RequiresOuterTask = D.hasClausesOfKind() || D.hasClausesOfKind(); - bool EmitDebug = CGF.CGM.getCodeGenOpts().getDebugInfo() != - llvm::codegenoptions::NoDebugInfo; - OMPBuilder.emitOffloadingArraysArgument(CGF.Builder, Info.RTArgs, Info, - EmitDebug, - /*ForEndCall=*/false); + InputInfo.NumberOfTargetItems = Info.NumberOfPtrs; InputInfo.BasePointersArray = Address(Info.RTArgs.BasePointersArray, CGF.VoidPtrTy, CGM.getPointerAlign()); @@ -11497,7 +11506,7 @@ void CGOpenMPRuntime::LastprivateConditionalRAII::tryToDisableInnerAnalysis( } // Exclude vars in private clauses. for (const auto *C : S.getClausesOfKind()) { - for (const Expr *Ref : C->varlists()) { + for (const Expr *Ref : C->varlist()) { if (!Ref->getType()->isScalarType()) continue; const auto *DRE = dyn_cast(Ref->IgnoreParenImpCasts()); @@ -11507,7 +11516,7 @@ void CGOpenMPRuntime::LastprivateConditionalRAII::tryToDisableInnerAnalysis( } } for (const auto *C : S.getClausesOfKind()) { - for (const Expr *Ref : C->varlists()) { + for (const Expr *Ref : C->varlist()) { if (!Ref->getType()->isScalarType()) continue; const auto *DRE = dyn_cast(Ref->IgnoreParenImpCasts()); @@ -11517,7 +11526,7 @@ void CGOpenMPRuntime::LastprivateConditionalRAII::tryToDisableInnerAnalysis( } } for (const auto *C : S.getClausesOfKind()) { - for (const Expr *Ref : C->varlists()) { + for (const Expr *Ref : C->varlist()) { if (!Ref->getType()->isScalarType()) continue; const auto *DRE = dyn_cast(Ref->IgnoreParenImpCasts()); @@ -11527,7 +11536,7 @@ void CGOpenMPRuntime::LastprivateConditionalRAII::tryToDisableInnerAnalysis( } } for (const auto *C : S.getClausesOfKind()) { - for (const Expr *Ref : C->varlists()) { + for (const Expr *Ref : C->varlist()) { if (!Ref->getType()->isScalarType()) continue; const auto *DRE = dyn_cast(Ref->IgnoreParenImpCasts()); @@ -11537,7 +11546,7 @@ void CGOpenMPRuntime::LastprivateConditionalRAII::tryToDisableInnerAnalysis( } } for (const auto *C : S.getClausesOfKind()) { - for (const Expr *Ref : C->varlists()) { + for (const Expr *Ref : C->varlist()) { if (!Ref->getType()->isScalarType()) continue; const auto *DRE = dyn_cast(Ref->IgnoreParenImpCasts()); @@ -11580,7 +11589,7 @@ CGOpenMPRuntime::LastprivateConditionalRAII::LastprivateConditionalRAII( if (C->getKind() != OMPC_LASTPRIVATE_conditional) continue; - for (const Expr *Ref : C->varlists()) { + for (const Expr *Ref : C->varlist()) { Data.DeclToUniqueName.insert(std::make_pair( cast(Ref->IgnoreParenImpCasts())->getDecl(), SmallString<16>(generateUniqueName(CGM, "pl_cond", Ref)))); diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index aa97f685ac7a9f0..e16aa3cdd5506ca 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -2751,7 +2751,10 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { if (RequiresCast) { unsigned Size = getContext().getTypeSize(QTy); - Ty = llvm::IntegerType::get(getLLVMContext(), Size); + if (Size) + Ty = llvm::IntegerType::get(getLLVMContext(), Size); + else + CGM.Error(OutExpr->getExprLoc(), "output size should not be zero"); } ResultRegTypes.push_back(Ty); // If this output is tied to an input, and if the input is larger, then diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index 853046bf434952e..b1ac9361957ff92 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -156,7 +156,7 @@ class OMPLoopScope : public CodeGenFunction::RunCleanupsScope { } // Mark private vars as undefs. for (const auto *C : LD->getClausesOfKind()) { - for (const Expr *IRef : C->varlists()) { + for (const Expr *IRef : C->varlist()) { const auto *OrigVD = cast(cast(IRef)->getDecl()); if (EmittedAsPrivate.insert(OrigVD->getCanonicalDecl()).second) { @@ -257,13 +257,13 @@ class OMPSimdLexicalScope : public CodeGenFunction::LexicalScope { } } } else if (const auto *UDP = dyn_cast(C)) { - for (const Expr *E : UDP->varlists()) { + for (const Expr *E : UDP->varlist()) { const Decl *D = cast(E)->getDecl(); if (const auto *OED = dyn_cast(D)) CGF.EmitVarDecl(*OED); } } else if (const auto *UDP = dyn_cast(C)) { - for (const Expr *E : UDP->varlists()) { + for (const Expr *E : UDP->varlist()) { const Decl *D = getBaseDecl(E); if (const auto *OED = dyn_cast(D)) CGF.EmitVarDecl(*OED); @@ -865,7 +865,7 @@ bool CodeGenFunction::EmitOMPFirstprivateClause(const OMPExecutableDirective &D, bool FirstprivateIsLastprivate = false; llvm::DenseMap Lastprivates; for (const auto *C : D.getClausesOfKind()) { - for (const auto *D : C->varlists()) + for (const auto *D : C->varlist()) Lastprivates.try_emplace( cast(cast(D)->getDecl())->getCanonicalDecl(), C->getKind()); @@ -1545,7 +1545,7 @@ checkForLastprivateConditionalUpdate(CodeGenFunction &CGF, return; llvm::DenseSet> PrivateDecls; for (const auto *C : S.getClausesOfKind()) { - for (const Expr *Ref : C->varlists()) { + for (const Expr *Ref : C->varlist()) { if (!Ref->getType()->isScalarType()) continue; const auto *DRE = dyn_cast(Ref->IgnoreParenImpCasts()); @@ -1556,7 +1556,7 @@ checkForLastprivateConditionalUpdate(CodeGenFunction &CGF, } } for (const auto *C : S.getClausesOfKind()) { - for (const Expr *Ref : C->varlists()) { + for (const Expr *Ref : C->varlist()) { if (!Ref->getType()->isScalarType()) continue; const auto *DRE = dyn_cast(Ref->IgnoreParenImpCasts()); @@ -1567,7 +1567,7 @@ checkForLastprivateConditionalUpdate(CodeGenFunction &CGF, } } for (const auto *C : S.getClausesOfKind()) { - for (const Expr *Ref : C->varlists()) { + for (const Expr *Ref : C->varlist()) { if (!Ref->getType()->isScalarType()) continue; const auto *DRE = dyn_cast(Ref->IgnoreParenImpCasts()); @@ -1582,7 +1582,7 @@ checkForLastprivateConditionalUpdate(CodeGenFunction &CGF, // Firstprivates do not return value but may be passed by reference - no need // to check for updated lastprivate conditional. for (const auto *C : S.getClausesOfKind()) { - for (const Expr *Ref : C->varlists()) { + for (const Expr *Ref : C->varlist()) { if (!Ref->getType()->isScalarType()) continue; const auto *DRE = dyn_cast(Ref->IgnoreParenImpCasts()); @@ -2288,7 +2288,7 @@ static void emitAlignedClause(CodeGenFunction &CGF, cast(CGF.EmitScalarExpr(AlignmentExpr)); ClauseAlignment = AlignmentCI->getValue(); } - for (const Expr *E : Clause->varlists()) { + for (const Expr *E : Clause->varlist()) { llvm::APInt Alignment(ClauseAlignment); if (Alignment == 0) { // OpenMP [2.8.1, Description] @@ -2407,7 +2407,7 @@ void CodeGenFunction::EmitOMPLinearClause( } for (const auto *C : D.getClausesOfKind()) { auto CurPrivate = C->privates().begin(); - for (const Expr *E : C->varlists()) { + for (const Expr *E : C->varlist()) { const auto *VD = cast(cast(E)->getDecl()); const auto *PrivateVD = cast(cast(*CurPrivate)->getDecl()); @@ -2711,7 +2711,7 @@ GetAlignedMapping(const OMPLoopDirective &S, CodeGenFunction &CGF) { cast(CGF.EmitScalarExpr(AlignmentExpr)); ClauseAlignment = AlignmentCI->getValue(); } - for (const Expr *E : Clause->varlists()) { + for (const Expr *E : Clause->varlist()) { llvm::APInt Alignment(ClauseAlignment); if (Alignment == 0) { // OpenMP [2.8.1, Description] @@ -4329,7 +4329,7 @@ void CodeGenFunction::EmitOMPSingleDirective(const OMPSingleDirective &S) { // Build a list of copyprivate variables along with helper expressions // (, , = expressions) for (const auto *C : S.getClausesOfKind()) { - CopyprivateVars.append(C->varlists().begin(), C->varlists().end()); + CopyprivateVars.append(C->varlist_begin(), C->varlist_end()); DestExprs.append(C->destination_exprs().begin(), C->destination_exprs().end()); SrcExprs.append(C->source_exprs().begin(), C->source_exprs().end()); @@ -5035,7 +5035,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( auto IPriv = C->privates().begin(); auto IRed = C->reduction_ops().begin(); auto ITD = C->taskgroup_descriptors().begin(); - for (const Expr *Ref : C->varlists()) { + for (const Expr *Ref : C->varlist()) { InRedVars.emplace_back(Ref); InRedPrivs.emplace_back(*IPriv); InRedOps.emplace_back(*IRed); @@ -5318,7 +5318,7 @@ void CodeGenFunction::processInReduction(const OMPExecutableDirective &S, auto IPriv = C->privates().begin(); auto IRed = C->reduction_ops().begin(); auto ITD = C->taskgroup_descriptors().begin(); - for (const Expr *Ref : C->varlists()) { + for (const Expr *Ref : C->varlist()) { InRedVars.emplace_back(Ref); InRedPrivs.emplace_back(*IPriv); InRedOps.emplace_back(*IRed); @@ -6326,8 +6326,8 @@ static std::pair emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X, UpdateVal = CGF.Builder.CreateCast(llvm::Instruction::CastOps::UIToFP, IC, X.getAddress().getElementType()); } - llvm::Value *Res = - CGF.Builder.CreateAtomicRMW(RMWOp, X.getAddress(), UpdateVal, AO); + llvm::AtomicRMWInst *Res = + CGF.emitAtomicRMWInst(RMWOp, X.getAddress(), UpdateVal, AO); return std::make_pair(true, RValue::get(Res)); } @@ -7346,7 +7346,7 @@ void CodeGenFunction::EmitOMPUseDevicePtrClause( const llvm::DenseMap CaptureDeviceAddrMap) { llvm::SmallDenseSet, 4> Processed; - for (const Expr *OrigVarIt : C.varlists()) { + for (const Expr *OrigVarIt : C.varlist()) { const auto *OrigVD = cast(cast(OrigVarIt)->getDecl()); if (!Processed.insert(OrigVD).second) continue; @@ -7397,7 +7397,7 @@ void CodeGenFunction::EmitOMPUseDeviceAddrClause( const llvm::DenseMap CaptureDeviceAddrMap) { llvm::SmallDenseSet, 4> Processed; - for (const Expr *Ref : C.varlists()) { + for (const Expr *Ref : C.varlist()) { const VarDecl *OrigVD = getBaseDecl(Ref); if (!Processed.insert(OrigVD).second) continue; @@ -7494,13 +7494,13 @@ void CodeGenFunction::EmitOMPTargetDataDirective( if (CGM.getLangOpts().OMPTargetTriples.empty()) { // Emit helper decls of the use_device_ptr/use_device_addr clauses. for (const auto *C : S.getClausesOfKind()) - for (const Expr *E : C->varlists()) { + for (const Expr *E : C->varlist()) { const Decl *D = cast(E)->getDecl(); if (const auto *OED = dyn_cast(D)) CGF.EmitVarDecl(*OED); } for (const auto *C : S.getClausesOfKind()) - for (const Expr *E : C->varlists()) { + for (const Expr *E : C->varlist()) { const Decl *D = getBaseDecl(E); if (const auto *OED = dyn_cast(D)) CGF.EmitVarDecl(*OED); @@ -8232,7 +8232,7 @@ void CodeGenFunction::EmitSimpleOMPExecutableDirective( if (isOpenMPTaskingDirective(D.getDirectiveKind())) { // Capture global firstprivates to avoid crash. for (const auto *C : D.getClausesOfKind()) { - for (const Expr *Ref : C->varlists()) { + for (const Expr *Ref : C->varlist()) { const auto *DRE = cast(Ref->IgnoreParenImpCasts()); if (!DRE) continue; diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index d6078696a7d91fa..af201554898f310 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -991,6 +991,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, if (D && D->hasAttr()) Fn->addFnAttr(llvm::Attribute::NoProfile); + if (D && D->hasAttr()) + Fn->addFnAttr(llvm::Attribute::HybridPatchable); + if (D) { // Function attributes take precedence over command line flags. if (auto *A = D->getAttr()) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 67e3019565cd0d1..89cc819c43bb566 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4160,6 +4160,13 @@ class CodeGenFunction : public CodeGenTypeCache { llvm::AtomicOrdering::SequentiallyConsistent, bool IsWeak = false, AggValueSlot Slot = AggValueSlot::ignored()); + /// Emit an atomicrmw instruction, and applying relevant metadata when + /// applicable. + llvm::AtomicRMWInst *emitAtomicRMWInst( + llvm::AtomicRMWInst::BinOp Op, Address Addr, llvm::Value *Val, + llvm::AtomicOrdering Order = llvm::AtomicOrdering::SequentiallyConsistent, + llvm::SyncScope::ID SSID = llvm::SyncScope::System); + void EmitAtomicUpdate(LValue LVal, llvm::AtomicOrdering AO, const llvm::function_ref &UpdateOp, bool IsVolatile); @@ -4529,7 +4536,6 @@ class CodeGenFunction : public CodeGenTypeCache { RValue EmitNVPTXDevicePrintfCallExpr(const CallExpr *E); RValue EmitAMDGPUDevicePrintfCallExpr(const CallExpr *E); - RValue EmitOpenMPDevicePrintfCallExpr(const CallExpr *E); RValue EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, const CallExpr *E, ReturnValueSlot ReturnValue); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 63ed5b4dd0c3103..344a0e538f22a23 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -7484,7 +7484,7 @@ void CodeGenModule::EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D) { // Do not emit threadprivates in simd-only mode. if (LangOpts.OpenMP && LangOpts.OpenMPSimd) return; - for (auto RefExpr : D->varlists()) { + for (auto RefExpr : D->varlist()) { auto *VD = cast(cast(RefExpr)->getDecl()); bool PerformInit = VD->getAnyInitializer() && diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index 2f2138582ba1e38..8f17c053f4783fb 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -334,6 +334,10 @@ class TargetCodeGenInfo { llvm::AtomicOrdering Ordering, llvm::LLVMContext &Ctx) const; + /// Allow the target to apply other metadata to an atomic instruction + virtual void setTargetAtomicMetadata(CodeGenFunction &CGF, + llvm::AtomicRMWInst &RMW) const {} + /// Interface class for filling custom fields of a block literal for OpenCL. class TargetOpenCLBlockHelper { public: diff --git a/clang/lib/CodeGen/Targets/AArch64.cpp b/clang/lib/CodeGen/Targets/AArch64.cpp index b9df54b0c67c40b..1dec3cd40ebd215 100644 --- a/clang/lib/CodeGen/Targets/AArch64.cpp +++ b/clang/lib/CodeGen/Targets/AArch64.cpp @@ -883,8 +883,10 @@ void AArch64TargetCodeGenInfo::checkFunctionCallABIStreaming( if (!CalleeIsStreamingCompatible && (CallerIsStreaming != CalleeIsStreaming || CallerIsStreamingCompatible)) - CGM.getDiags().Report(CallLoc, - diag::err_function_always_inline_attribute_mismatch) + CGM.getDiags().Report( + CallLoc, CalleeIsStreaming + ? diag::err_function_always_inline_attribute_mismatch + : diag::warn_function_always_inline_attribute_mismatch) << Caller->getDeclName() << Callee->getDeclName() << "streaming"; if (auto *NewAttr = Callee->getAttr()) if (NewAttr->isNewZA()) diff --git a/clang/lib/CodeGen/Targets/AMDGPU.cpp b/clang/lib/CodeGen/Targets/AMDGPU.cpp index 4d3275e17c386e7..37e6af3d4196a8c 100644 --- a/clang/lib/CodeGen/Targets/AMDGPU.cpp +++ b/clang/lib/CodeGen/Targets/AMDGPU.cpp @@ -311,6 +311,8 @@ class AMDGPUTargetCodeGenInfo : public TargetCodeGenInfo { SyncScope Scope, llvm::AtomicOrdering Ordering, llvm::LLVMContext &Ctx) const override; + void setTargetAtomicMetadata(CodeGenFunction &CGF, + llvm::AtomicRMWInst &RMW) const override; llvm::Value *createEnqueuedBlockKernel(CodeGenFunction &CGF, llvm::Function *BlockInvokeFunc, llvm::Type *BlockTy) const override; @@ -546,6 +548,23 @@ AMDGPUTargetCodeGenInfo::getLLVMSyncScopeID(const LangOptions &LangOpts, return Ctx.getOrInsertSyncScopeID(Name); } +void AMDGPUTargetCodeGenInfo::setTargetAtomicMetadata( + CodeGenFunction &CGF, llvm::AtomicRMWInst &RMW) const { + if (!CGF.getTarget().allowAMDGPUUnsafeFPAtomics()) + return; + + // TODO: Introduce new, more controlled options that also work for integers, + // and deprecate allowAMDGPUUnsafeFPAtomics. + llvm::AtomicRMWInst::BinOp RMWOp = RMW.getOperation(); + if (llvm::AtomicRMWInst::isFPOperation(RMWOp)) { + llvm::MDNode *Empty = llvm::MDNode::get(CGF.getLLVMContext(), {}); + RMW.setMetadata("amdgpu.no.fine.grained.memory", Empty); + + if (RMWOp == llvm::AtomicRMWInst::FAdd && RMW.getType()->isFloatTy()) + RMW.setMetadata("amdgpu.ignore.denormal.mode", Empty); + } +} + bool AMDGPUTargetCodeGenInfo::shouldEmitStaticExternCAliases() const { return false; } diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index f6c7300162b9e92..aa8f9197cfabc37 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -620,19 +620,33 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { std::string Linker = getToolChain().GetLinkerPath(); ArgStringList CmdArgs; - CmdArgs.push_back("--no-undefined"); - CmdArgs.push_back("-shared"); + if (!Args.hasArg(options::OPT_r)) { + CmdArgs.push_back("--no-undefined"); + CmdArgs.push_back("-shared"); + } addLinkerCompressDebugSectionsOption(getToolChain(), Args, CmdArgs); Args.AddAllArgs(CmdArgs, options::OPT_L); getToolChain().AddFilePathLibArgs(Args, CmdArgs); AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - if (C.getDriver().isUsingLTO()) + if (C.getDriver().isUsingLTO()) { addLTOOptions(getToolChain(), Args, CmdArgs, Output, Inputs[0], C.getDriver().getLTOMode() == LTOK_Thin); - else if (Args.hasArg(options::OPT_mcpu_EQ)) + } else if (Args.hasArg(options::OPT_mcpu_EQ)) { CmdArgs.push_back(Args.MakeArgString( - "-plugin-opt=mcpu=" + Args.getLastArgValue(options::OPT_mcpu_EQ))); + "-plugin-opt=mcpu=" + + getProcessorFromTargetID(getToolChain().getTriple(), + Args.getLastArgValue(options::OPT_mcpu_EQ)))); + } + + // Always pass the target-id features to the LTO job. + std::vector Features; + getAMDGPUTargetFeatures(C.getDriver(), getToolChain().getTriple(), Args, + Features); + if (!Features.empty()) { + CmdArgs.push_back( + Args.MakeArgString("-plugin-opt=-mattr=" + llvm::join(Features, ","))); + } addGPULibraries(getToolChain(), Args, CmdArgs); diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp index 2f63333b732f61e..dc6c8695488bb5f 100644 --- a/clang/lib/Driver/ToolChains/Arch/X86.cpp +++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp @@ -266,19 +266,29 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, } bool IsNegative = Name.starts_with("no-"); + + bool Not64Bit = ArchType != llvm::Triple::x86_64; + if (Not64Bit && Name == "uintr") + D.Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << Triple.getTriple(); + if (A->getOption().matches(options::OPT_mapx_features_EQ) || A->getOption().matches(options::OPT_mno_apx_features_EQ)) { + if (Not64Bit && !IsNegative) + D.Diag(diag::err_drv_unsupported_opt_for_target) + << StringRef(A->getSpelling().str() + "|-mapxf") + << Triple.getTriple(); + for (StringRef Value : A->getValues()) { - if (Value == "egpr" || Value == "push2pop2" || Value == "ppx" || - Value == "ndd" || Value == "ccmp" || Value == "nf" || - Value == "cf" || Value == "zu") { - Features.push_back( - Args.MakeArgString((IsNegative ? "-" : "+") + Value)); - continue; - } - D.Diag(clang::diag::err_drv_unsupported_option_argument) - << A->getSpelling() << Value; + if (Value != "egpr" && Value != "push2pop2" && Value != "ppx" && + Value != "ndd" && Value != "ccmp" && Value != "nf" && + Value != "cf" && Value != "zu") + D.Diag(clang::diag::err_drv_unsupported_option_argument) + << A->getSpelling() << Value; + + Features.push_back( + Args.MakeArgString((IsNegative ? "-" : "+") + Value)); } continue; } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 4a94df7d5f42ee4..843d68c85bc592c 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -3384,9 +3384,28 @@ static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, CmdArgs.push_back("-ffast-math"); // Handle __FINITE_MATH_ONLY__ similarly. - if (!HonorINFs && !HonorNaNs) + // The -ffinite-math-only is added to CmdArgs when !HonorINFs && !HonorNaNs. + // Otherwise process the Xclang arguments to determine if -menable-no-infs and + // -menable-no-nans are set by the user. + bool shouldAddFiniteMathOnly = false; + if (!HonorINFs && !HonorNaNs) { + shouldAddFiniteMathOnly = true; + } else { + bool InfValues = true; + bool NanValues = true; + for (const auto *Arg : Args.filtered(options::OPT_Xclang)) { + StringRef ArgValue = Arg->getValue(); + if (ArgValue == "-menable-no-nans") + NanValues = false; + else if (ArgValue == "-menable-no-infs") + InfValues = false; + } + if (!NanValues && !InfValues) + shouldAddFiniteMathOnly = true; + } + if (shouldAddFiniteMathOnly) { CmdArgs.push_back("-ffinite-math-only"); - + } if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) { CmdArgs.push_back("-mfpmath"); CmdArgs.push_back(A->getValue()); @@ -3755,6 +3774,11 @@ static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs, CmdArgs.push_back(Args.MakeArgString(CLExtStr)); } + if (Args.hasArg(options::OPT_cl_finite_math_only)) { + CmdArgs.push_back("-menable-no-infs"); + CmdArgs.push_back("-menable-no-nans"); + } + for (const auto &Arg : ForwardedArguments) if (const auto *A = Args.getLastArg(Arg)) CmdArgs.push_back(Args.MakeArgString(A->getOption().getPrefixedName())); @@ -9131,7 +9155,7 @@ void LinkerWrapper::ConstructJob(Compilation &C, const JobAction &JA, // If we disable the GPU C library support it needs to be forwarded to the // link job. if (!Args.hasFlag(options::OPT_gpulibc, options::OPT_nogpulibc, true)) - CmdArgs.push_back("--device-linker=-nolibc"); + CmdArgs.push_back("--device-compiler=-nolibc"); // Add the linker arguments to be forwarded by the wrapper. CmdArgs.push_back(Args.MakeArgString(Twine("--linker-path=") + diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index ffe5f4a6f4a2579..e98e574d6cc2b90 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -625,6 +625,13 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, addLTOOptions(getToolChain(), Args, CmdArgs, Output, Inputs[0], C.getDriver().getLTOMode() == LTOK_Thin); + // Forward the PTX features if the nvlink-wrapper needs it. + std::vector Features; + getNVPTXTargetFeatures(C.getDriver(), getToolChain().getTriple(), Args, + Features); + for (StringRef Feature : Features) + CmdArgs.append({"--feature", Args.MakeArgString(Feature)}); + addGPULibraries(getToolChain(), Args, CmdArgs); // Add paths for the default clang library path. diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index c4f2375c64034b5..f5de5eb23e4be7c 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -342,6 +342,9 @@ void Flang::AddAMDGPUTargetArgs(const ArgList &Args, StringRef Val = A->getValue(); CmdArgs.push_back(Args.MakeArgString("-mcode-object-version=" + Val)); } + + const ToolChain &TC = getToolChain(); + TC.addClangTargetOptions(Args, CmdArgs, Action::OffloadKind::OFK_OpenMP); } void Flang::addTargetOptions(const ArgList &Args, diff --git a/clang/lib/Driver/ToolChains/PS4CPU.cpp b/clang/lib/Driver/ToolChains/PS4CPU.cpp index d6af9388e54a64a..a9e612c44da06a0 100644 --- a/clang/lib/Driver/ToolChains/PS4CPU.cpp +++ b/clang/lib/Driver/ToolChains/PS4CPU.cpp @@ -152,48 +152,38 @@ void tools::PS4cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Output.getFilename()); } - const bool UseLTO = D.isUsingLTO(); const bool UseJMC = Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false); const char *LTOArgs = ""; - auto AddCodeGenFlag = [&](Twine Flag) { + auto AddLTOFlag = [&](Twine Flag) { LTOArgs = Args.MakeArgString(Twine(LTOArgs) + " " + Flag); }; - if (UseLTO) { - // This tells LTO to perform JustMyCode instrumentation. - if (UseJMC) - AddCodeGenFlag("-enable-jmc-instrument"); + // If the linker sees bitcode objects it will perform LTO. We can't tell + // whether or not that will be the case at this point. So, unconditionally + // pass LTO options to ensure proper codegen, metadata production, etc if + // LTO indeed occurs. + if (Args.hasFlag(options::OPT_funified_lto, options::OPT_fno_unified_lto, + true)) + CmdArgs.push_back(D.getLTOMode() == LTOK_Thin ? "--lto=thin" + : "--lto=full"); + if (UseJMC) + AddLTOFlag("-enable-jmc-instrument"); - if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir)) - AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue()); + if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir)) + AddLTOFlag(Twine("-crash-diagnostics-dir=") + A->getValue()); - StringRef Parallelism = getLTOParallelism(Args, D); - if (!Parallelism.empty()) - AddCodeGenFlag(Twine("-threads=") + Parallelism); + if (StringRef Threads = getLTOParallelism(Args, D); !Threads.empty()) + AddLTOFlag(Twine("-threads=") + Threads); - const char *Prefix = nullptr; - if (D.getLTOMode() == LTOK_Thin) - Prefix = "-lto-thin-debug-options="; - else if (D.getLTOMode() == LTOK_Full) - Prefix = "-lto-debug-options="; - else - llvm_unreachable("new LTO mode?"); - - CmdArgs.push_back(Args.MakeArgString(Twine(Prefix) + LTOArgs)); - } + if (*LTOArgs) + CmdArgs.push_back( + Args.MakeArgString(Twine("-lto-debug-options=") + LTOArgs)); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) TC.addSanitizerArgs(Args, CmdArgs, "-l", ""); - if (D.isUsingLTO() && Args.hasArg(options::OPT_funified_lto)) { - if (D.getLTOMode() == LTOK_Thin) - CmdArgs.push_back("--lto=thin"); - else if (D.getLTOMode() == LTOK_Full) - CmdArgs.push_back("--lto=full"); - } - Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, options::OPT_s, options::OPT_t}); @@ -259,37 +249,38 @@ void tools::PS5cpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Output.getFilename()); } - const bool UseLTO = D.isUsingLTO(); const bool UseJMC = Args.hasFlag(options::OPT_fjmc, options::OPT_fno_jmc, false); - auto AddCodeGenFlag = [&](Twine Flag) { + auto AddLTOFlag = [&](Twine Flag) { CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=") + Flag)); }; - if (UseLTO) { - // This tells LTO to perform JustMyCode instrumentation. - if (UseJMC) - AddCodeGenFlag("-enable-jmc-instrument"); + // If the linker sees bitcode objects it will perform LTO. We can't tell + // whether or not that will be the case at this point. So, unconditionally + // pass LTO options to ensure proper codegen, metadata production, etc if + // LTO indeed occurs. + if (Args.hasFlag(options::OPT_funified_lto, options::OPT_fno_unified_lto, + true)) + CmdArgs.push_back(D.getLTOMode() == LTOK_Thin ? "--lto=thin" + : "--lto=full"); - if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir)) - AddCodeGenFlag(Twine("-crash-diagnostics-dir=") + A->getValue()); + if (UseJMC) + AddLTOFlag("-enable-jmc-instrument"); - StringRef Parallelism = getLTOParallelism(Args, D); - if (!Parallelism.empty()) - CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + Parallelism)); - } + if (Args.hasFlag(options::OPT_fstack_size_section, + options::OPT_fno_stack_size_section, false)) + AddLTOFlag("-stack-size-section"); + + if (Arg *A = Args.getLastArg(options::OPT_fcrash_diagnostics_dir)) + AddLTOFlag(Twine("-crash-diagnostics-dir=") + A->getValue()); + + if (StringRef Jobs = getLTOParallelism(Args, D); !Jobs.empty()) + AddLTOFlag(Twine("jobs=") + Jobs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) TC.addSanitizerArgs(Args, CmdArgs, "-l", ""); - if (D.isUsingLTO() && Args.hasArg(options::OPT_funified_lto)) { - if (D.getLTOMode() == LTOK_Thin) - CmdArgs.push_back("--lto=thin"); - else if (D.getLTOMode() == LTOK_Full) - CmdArgs.push_back("--lto=full"); - } - Args.addAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, options::OPT_s, options::OPT_t}); diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 16ab18e1af95924..8cd5cf248416024 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -155,8 +155,8 @@ class AnnotatingParser { if (NonTemplateLess.count(CurrentToken->Previous) > 0) return false; - const FormatToken &Previous = *CurrentToken->Previous; // The '<'. - if (Previous.Previous) { + if (const auto &Previous = *CurrentToken->Previous; // The '<'. + Previous.Previous) { if (Previous.Previous->Tok.isLiteral()) return false; if (Previous.Previous->is(tok::r_brace)) @@ -176,11 +176,13 @@ class AnnotatingParser { FormatToken *Left = CurrentToken->Previous; Left->ParentBracket = Contexts.back().ContextKind; ScopedContextCreator ContextCreator(*this, tok::less, 12); - Contexts.back().IsExpression = false; + + const auto *BeforeLess = Left->Previous; + // If there's a template keyword before the opening angle bracket, this is a // template parameter, not an argument. - if (Left->Previous && Left->Previous->isNot(tok::kw_template)) + if (BeforeLess && BeforeLess->isNot(tok::kw_template)) Contexts.back().ContextType = Context::TemplateArgument; if (Style.Language == FormatStyle::LK_Java && @@ -188,19 +190,24 @@ class AnnotatingParser { next(); } - while (CurrentToken) { + for (bool SeenTernaryOperator = false; CurrentToken;) { + const bool InExpr = Contexts[Contexts.size() - 2].IsExpression; if (CurrentToken->is(tok::greater)) { + const auto *Next = CurrentToken->Next; // Try to do a better job at looking for ">>" within the condition of // a statement. Conservatively insert spaces between consecutive ">" // tokens to prevent splitting right bitshift operators and potentially // altering program semantics. This check is overly conservative and // will prevent spaces from being inserted in select nested template // parameter cases, but should not alter program semantics. - if (CurrentToken->Next && CurrentToken->Next->is(tok::greater) && + if (Next && Next->is(tok::greater) && Left->ParentBracket != tok::less && CurrentToken->getStartOfNonWhitespace() == - CurrentToken->Next->getStartOfNonWhitespace().getLocWithOffset( - -1)) { + Next->getStartOfNonWhitespace().getLocWithOffset(-1)) { + return false; + } + if (InExpr && SeenTernaryOperator && + (!Next || !Next->isOneOf(tok::l_paren, tok::l_brace))) { return false; } Left->MatchingParen = CurrentToken; @@ -211,14 +218,14 @@ class AnnotatingParser { // msg: < item: data > // In TT_TextProto, map does not occur. if (Style.Language == FormatStyle::LK_TextProto || - (Style.Language == FormatStyle::LK_Proto && Left->Previous && - Left->Previous->isOneOf(TT_SelectorName, TT_DictLiteral))) { + (Style.Language == FormatStyle::LK_Proto && BeforeLess && + BeforeLess->isOneOf(TT_SelectorName, TT_DictLiteral))) { CurrentToken->setType(TT_DictLiteral); } else { CurrentToken->setType(TT_TemplateCloser); CurrentToken->Tok.setLength(1); } - if (CurrentToken->Next && CurrentToken->Next->Tok.isLiteral()) + if (Next && Next->Tok.isLiteral()) return false; next(); return true; @@ -230,18 +237,21 @@ class AnnotatingParser { } if (CurrentToken->isOneOf(tok::r_paren, tok::r_square, tok::r_brace)) return false; + const auto &Prev = *CurrentToken->Previous; // If a && or || is found and interpreted as a binary operator, this set // of angles is likely part of something like "a < b && c > d". If the // angles are inside an expression, the ||/&& might also be a binary // operator that was misinterpreted because we are parsing template // parameters. // FIXME: This is getting out of hand, write a decent parser. - if (CurrentToken->Previous->isOneOf(tok::pipepipe, tok::ampamp) && - CurrentToken->Previous->is(TT_BinaryOperator) && - Contexts[Contexts.size() - 2].IsExpression && - !Line.startsWith(tok::kw_template)) { - return false; + if (InExpr && !Line.startsWith(tok::kw_template) && + Prev.is(TT_BinaryOperator)) { + const auto Precedence = Prev.getPrecedence(); + if (Precedence > prec::Conditional && Precedence < prec::Relational) + return false; } + if (Prev.is(TT_ConditionalExpr)) + SeenTernaryOperator = true; updateParameterCount(Left, CurrentToken); if (Style.Language == FormatStyle::LK_Proto) { if (FormatToken *Previous = CurrentToken->getPreviousNonComment()) { diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 920ddf7e599138e..17b9ca7cb9910b0 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -1318,7 +1318,7 @@ static void InitializePredefinedMacros(const TargetInfo &TI, if (!LangOpts.MathErrno) Builder.defineMacro("__NO_MATH_ERRNO__"); - if (LangOpts.FastMath || LangOpts.FiniteMathOnly) + if (LangOpts.FastMath || (LangOpts.NoHonorInfs && LangOpts.NoHonorNaNs)) Builder.defineMacro("__FINITE_MATH_ONLY__", "1"); else Builder.defineMacro("__FINITE_MATH_ONLY__", "0"); diff --git a/clang/lib/Frontend/PrintPreprocessedOutput.cpp b/clang/lib/Frontend/PrintPreprocessedOutput.cpp index 0592423c12eca45..135dca0e6a17756 100644 --- a/clang/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/clang/lib/Frontend/PrintPreprocessedOutput.cpp @@ -980,7 +980,6 @@ static void PrintPreprocessedTokens(Preprocessor &PP, Token &Tok, *Callbacks->OS << static_cast(*Iter); PrintComma = true; } - IsStartOfLine = true; } else if (Tok.isAnnotation()) { // Ignore annotation tokens created by pragmas - the pragmas themselves // will be reproduced in the preprocessed output. diff --git a/clang/lib/InstallAPI/DirectoryScanner.cpp b/clang/lib/InstallAPI/DirectoryScanner.cpp index 8984758e7b446c2..03a8208c7364e91 100644 --- a/clang/lib/InstallAPI/DirectoryScanner.cpp +++ b/clang/lib/InstallAPI/DirectoryScanner.cpp @@ -130,7 +130,8 @@ Error DirectoryScanner::scanHeaders(StringRef Path, Library &Lib, if (ParentPath.empty()) ParentPath = Path; for (const StringRef Dir : SubDirectories) - return scanHeaders(Dir, Lib, Type, BasePath, ParentPath); + if (Error Err = scanHeaders(Dir, Lib, Type, BasePath, ParentPath)) + return Err; return Error::success(); } diff --git a/clang/lib/Lex/PPCaching.cpp b/clang/lib/Lex/PPCaching.cpp index f38ff62ebf437ce..cbacda9d31ae2ee 100644 --- a/clang/lib/Lex/PPCaching.cpp +++ b/clang/lib/Lex/PPCaching.cpp @@ -14,6 +14,15 @@ #include "clang/Lex/Preprocessor.h" using namespace clang; +std::pair +Preprocessor::LastBacktrackPos() { + assert(isBacktrackEnabled()); + auto BacktrackPos = BacktrackPositions.back(); + bool Unannotated = + static_cast(BacktrackPos) < 0; + return {Unannotated ? ~BacktrackPos : BacktrackPos, Unannotated}; +} + // EnableBacktrackAtThisPos - From the point that this method is called, and // until CommitBacktrackedTokens() or Backtrack() is called, the Preprocessor // keeps track of the lexed tokens so that a subsequent Backtrack() call will @@ -22,26 +31,45 @@ using namespace clang; // Nested backtracks are allowed, meaning that EnableBacktrackAtThisPos can // be called multiple times and CommitBacktrackedTokens/Backtrack calls will // be combined with the EnableBacktrackAtThisPos calls in reverse order. -void Preprocessor::EnableBacktrackAtThisPos() { +void Preprocessor::EnableBacktrackAtThisPos(bool Unannotated) { assert(LexLevel == 0 && "cannot use lookahead while lexing"); - BacktrackPositions.push_back(CachedLexPos); + BacktrackPositions.push_back(Unannotated ? ~CachedLexPos : CachedLexPos); + if (Unannotated) + UnannotatedBacktrackTokens.emplace_back(CachedTokens, CachedTokens.size()); EnterCachingLexMode(); } +Preprocessor::CachedTokensTy Preprocessor::PopUnannotatedBacktrackTokens() { + assert(isUnannotatedBacktrackEnabled() && "missing unannotated tokens?"); + auto [UnannotatedTokens, NumCachedToks] = + std::move(UnannotatedBacktrackTokens.back()); + UnannotatedBacktrackTokens.pop_back(); + // If another unannotated backtrack is active, propagate any tokens that were + // lexed (not cached) since EnableBacktrackAtThisPos was last called. + if (isUnannotatedBacktrackEnabled()) + UnannotatedBacktrackTokens.back().first.append( + UnannotatedTokens.begin() + NumCachedToks, UnannotatedTokens.end()); + return std::move(UnannotatedTokens); +} + // Disable the last EnableBacktrackAtThisPos call. void Preprocessor::CommitBacktrackedTokens() { - assert(!BacktrackPositions.empty() - && "EnableBacktrackAtThisPos was not called!"); + assert(isBacktrackEnabled() && "EnableBacktrackAtThisPos was not called!"); + auto [BacktrackPos, Unannotated] = LastBacktrackPos(); BacktrackPositions.pop_back(); + if (Unannotated) + PopUnannotatedBacktrackTokens(); } // Make Preprocessor re-lex the tokens that were lexed since // EnableBacktrackAtThisPos() was previously called. void Preprocessor::Backtrack() { - assert(!BacktrackPositions.empty() - && "EnableBacktrackAtThisPos was not called!"); - CachedLexPos = BacktrackPositions.back(); + assert(isBacktrackEnabled() && "EnableBacktrackAtThisPos was not called!"); + auto [BacktrackPos, Unannotated] = LastBacktrackPos(); BacktrackPositions.pop_back(); + CachedLexPos = BacktrackPos; + if (Unannotated) + CachedTokens = PopUnannotatedBacktrackTokens(); recomputeCurLexerKind(); } @@ -67,6 +95,8 @@ void Preprocessor::CachingLex(Token &Result) { EnterCachingLexModeUnchecked(); CachedTokens.push_back(Result); ++CachedLexPos; + if (isUnannotatedBacktrackEnabled()) + UnannotatedBacktrackTokens.back().first.push_back(Result); return; } @@ -108,6 +138,8 @@ const Token &Preprocessor::PeekAhead(unsigned N) { for (size_t C = CachedLexPos + N - CachedTokens.size(); C > 0; --C) { CachedTokens.push_back(Token()); Lex(CachedTokens.back()); + if (isUnannotatedBacktrackEnabled()) + UnannotatedBacktrackTokens.back().first.push_back(CachedTokens.back()); } EnterCachingLexMode(); return CachedTokens.back(); @@ -124,7 +156,7 @@ void Preprocessor::AnnotatePreviousCachedTokens(const Token &Tok) { for (CachedTokensTy::size_type i = CachedLexPos; i != 0; --i) { CachedTokensTy::iterator AnnotBegin = CachedTokens.begin() + i-1; if (AnnotBegin->getLocation() == Tok.getLocation()) { - assert((BacktrackPositions.empty() || BacktrackPositions.back() <= i) && + assert((!isBacktrackEnabled() || LastBacktrackPos().first <= i) && "The backtrack pos points inside the annotated tokens!"); // Replace the cached tokens with the single annotation token. if (i < CachedLexPos) diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 879f01e87806e21..1e31fcc3d731ed9 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -1604,6 +1604,16 @@ static bool isTargetVariantEnvironment(const TargetInfo &TI, return false; } +#if defined(__sun__) && defined(__svr4__) +// GCC mangles std::tm as tm for binary compatibility on Solaris (Issue +// #33114). We need to match this to allow the std::put_time calls to link +// (PR #99075). +asm("_ZNKSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE3putES3_" + "RSt8ios_basecPKSt2tmPKcSB_ = " + "_ZNKSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE3putES3_" + "RSt8ios_basecPK2tmPKcSB_"); +#endif + /// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. void Preprocessor::ExpandBuiltinMacro(Token &Tok) { diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 63e27e62cffc87b..f0b4593e0cc22e1 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -170,7 +170,7 @@ Preprocessor::Preprocessor(std::shared_ptr PPOpts, } Preprocessor::~Preprocessor() { - assert(BacktrackPositions.empty() && "EnableBacktrack/Backtrack imbalance!"); + assert(!isBacktrackEnabled() && "EnableBacktrack/Backtrack imbalance!"); IncludeMacroStack.clear(); diff --git a/clang/lib/Parse/ParseCXXInlineMethods.cpp b/clang/lib/Parse/ParseCXXInlineMethods.cpp index 9ccbbf9a7d5d05c..b461743833c82a8 100644 --- a/clang/lib/Parse/ParseCXXInlineMethods.cpp +++ b/clang/lib/Parse/ParseCXXInlineMethods.cpp @@ -1205,41 +1205,6 @@ bool Parser::ConsumeAndStoreConditional(CachedTokens &Toks) { return true; } -/// A tentative parsing action that can also revert token annotations. -class Parser::UnannotatedTentativeParsingAction : public TentativeParsingAction { -public: - explicit UnannotatedTentativeParsingAction(Parser &Self, - tok::TokenKind EndKind) - : TentativeParsingAction(Self), Self(Self), EndKind(EndKind) { - // Stash away the old token stream, so we can restore it once the - // tentative parse is complete. - TentativeParsingAction Inner(Self); - Self.ConsumeAndStoreUntil(EndKind, Toks, true, /*ConsumeFinalToken*/false); - Inner.Revert(); - } - - void RevertAnnotations() { - Revert(); - - // Put back the original tokens. - Self.SkipUntil(EndKind, StopAtSemi | StopBeforeMatch); - if (Toks.size()) { - auto Buffer = std::make_unique(Toks.size()); - std::copy(Toks.begin() + 1, Toks.end(), Buffer.get()); - Buffer[Toks.size() - 1] = Self.Tok; - Self.PP.EnterTokenStream(std::move(Buffer), Toks.size(), true, - /*IsReinject*/ true); - - Self.Tok = Toks.front(); - } - } - -private: - Parser &Self; - CachedTokens Toks; - tok::TokenKind EndKind; -}; - /// ConsumeAndStoreInitializer - Consume and store the token at the passed token /// container until the end of the current initializer expression (either a /// default argument or an in-class initializer for a non-static data member). @@ -1277,9 +1242,7 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks, // syntactically-valid init-declarator-list, then this comma ends // the default initializer. { - UnannotatedTentativeParsingAction PA(*this, - CIK == CIK_DefaultInitializer - ? tok::semi : tok::r_paren); + TentativeParsingAction TPA(*this, /*Unannotated=*/true); Sema::TentativeAnalysisScope Scope(Actions); TPResult Result = TPResult::Error; @@ -1307,7 +1270,7 @@ bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks, // Put the token stream back and undo any annotations we performed // after the comma. They may reflect a different parse than the one // we will actually perform at the end of the class. - PA.RevertAnnotations(); + TPA.Revert(); // If what follows could be a declaration, it is a declaration. if (Result != TPResult::False && Result != TPResult::Error) diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 7ce9a9cea1c7af8..4a2d9a650e20cc2 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -314,64 +314,92 @@ void Parser::ParseGNUAttributes(ParsedAttributes &Attrs, } /// Determine whether the given attribute has an identifier argument. -static bool attributeHasIdentifierArg(const IdentifierInfo &II) { +static bool attributeHasIdentifierArg(const IdentifierInfo &II, + ParsedAttr::Syntax Syntax, + IdentifierInfo *ScopeName) { + std::string FullName = + AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax); #define CLANG_ATTR_IDENTIFIER_ARG_LIST - return llvm::StringSwitch(normalizeAttrName(II.getName())) + return llvm::StringSwitch(FullName) #include "clang/Parse/AttrParserStringSwitches.inc" - .Default(false); + .Default(false); #undef CLANG_ATTR_IDENTIFIER_ARG_LIST } /// Determine whether the given attribute has an identifier argument. static ParsedAttributeArgumentsProperties -attributeStringLiteralListArg(const llvm::Triple &T, const IdentifierInfo &II) { +attributeStringLiteralListArg(const llvm::Triple &T, const IdentifierInfo &II, + ParsedAttr::Syntax Syntax, + IdentifierInfo *ScopeName) { + std::string FullName = + AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax); #define CLANG_ATTR_STRING_LITERAL_ARG_LIST - return llvm::StringSwitch(normalizeAttrName(II.getName())) + return llvm::StringSwitch(FullName) #include "clang/Parse/AttrParserStringSwitches.inc" .Default(0); #undef CLANG_ATTR_STRING_LITERAL_ARG_LIST } /// Determine whether the given attribute has a variadic identifier argument. -static bool attributeHasVariadicIdentifierArg(const IdentifierInfo &II) { +static bool attributeHasVariadicIdentifierArg(const IdentifierInfo &II, + ParsedAttr::Syntax Syntax, + IdentifierInfo *ScopeName) { + std::string FullName = + AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax); #define CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST - return llvm::StringSwitch(normalizeAttrName(II.getName())) + return llvm::StringSwitch(FullName) #include "clang/Parse/AttrParserStringSwitches.inc" - .Default(false); + .Default(false); #undef CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST } /// Determine whether the given attribute treats kw_this as an identifier. -static bool attributeTreatsKeywordThisAsIdentifier(const IdentifierInfo &II) { +static bool attributeTreatsKeywordThisAsIdentifier(const IdentifierInfo &II, + ParsedAttr::Syntax Syntax, + IdentifierInfo *ScopeName) { + std::string FullName = + AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax); #define CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST - return llvm::StringSwitch(normalizeAttrName(II.getName())) + return llvm::StringSwitch(FullName) #include "clang/Parse/AttrParserStringSwitches.inc" - .Default(false); + .Default(false); #undef CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST } /// Determine if an attribute accepts parameter packs. -static bool attributeAcceptsExprPack(const IdentifierInfo &II) { +static bool attributeAcceptsExprPack(const IdentifierInfo &II, + ParsedAttr::Syntax Syntax, + IdentifierInfo *ScopeName) { + std::string FullName = + AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax); #define CLANG_ATTR_ACCEPTS_EXPR_PACK - return llvm::StringSwitch(normalizeAttrName(II.getName())) + return llvm::StringSwitch(FullName) #include "clang/Parse/AttrParserStringSwitches.inc" .Default(false); #undef CLANG_ATTR_ACCEPTS_EXPR_PACK } /// Determine whether the given attribute parses a type argument. -static bool attributeIsTypeArgAttr(const IdentifierInfo &II) { +static bool attributeIsTypeArgAttr(const IdentifierInfo &II, + ParsedAttr::Syntax Syntax, + IdentifierInfo *ScopeName) { + std::string FullName = + AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax); #define CLANG_ATTR_TYPE_ARG_LIST - return llvm::StringSwitch(normalizeAttrName(II.getName())) + return llvm::StringSwitch(FullName) #include "clang/Parse/AttrParserStringSwitches.inc" - .Default(false); + .Default(false); #undef CLANG_ATTR_TYPE_ARG_LIST } /// Determine whether the given attribute takes identifier arguments. -static bool attributeHasStrictIdentifierArgs(const IdentifierInfo &II) { +static bool attributeHasStrictIdentifierArgs(const IdentifierInfo &II, + ParsedAttr::Syntax Syntax, + IdentifierInfo *ScopeName) { + std::string FullName = + AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax); #define CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST - return (llvm::StringSwitch(normalizeAttrName(II.getName())) + return (llvm::StringSwitch(FullName) #include "clang/Parse/AttrParserStringSwitches.inc" .Default(0)) != 0; #undef CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST @@ -380,9 +408,13 @@ static bool attributeHasStrictIdentifierArgs(const IdentifierInfo &II) { /// Determine whether the given attribute takes an identifier argument at a /// specific index static bool attributeHasStrictIdentifierArgAtIndex(const IdentifierInfo &II, + ParsedAttr::Syntax Syntax, + IdentifierInfo *ScopeName, size_t argIndex) { + std::string FullName = + AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax); #define CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST - return (llvm::StringSwitch(normalizeAttrName(II.getName())) + return (llvm::StringSwitch(FullName) #include "clang/Parse/AttrParserStringSwitches.inc" .Default(0)) & (1ull << argIndex); @@ -391,11 +423,15 @@ static bool attributeHasStrictIdentifierArgAtIndex(const IdentifierInfo &II, /// Determine whether the given attribute requires parsing its arguments /// in an unevaluated context or not. -static bool attributeParsedArgsUnevaluated(const IdentifierInfo &II) { +static bool attributeParsedArgsUnevaluated(const IdentifierInfo &II, + ParsedAttr::Syntax Syntax, + IdentifierInfo *ScopeName) { + std::string FullName = + AttributeCommonInfo::normalizeFullNameWithSyntax(&II, ScopeName, Syntax); #define CLANG_ATTR_ARG_CONTEXT_LIST - return llvm::StringSwitch(normalizeAttrName(II.getName())) + return llvm::StringSwitch(FullName) #include "clang/Parse/AttrParserStringSwitches.inc" - .Default(false); + .Default(false); #undef CLANG_ATTR_ARG_CONTEXT_LIST } @@ -523,10 +559,12 @@ unsigned Parser::ParseAttributeArgsCommon( // Ignore the left paren location for now. ConsumeParen(); - bool ChangeKWThisToIdent = attributeTreatsKeywordThisAsIdentifier(*AttrName); - bool AttributeIsTypeArgAttr = attributeIsTypeArgAttr(*AttrName); + bool ChangeKWThisToIdent = attributeTreatsKeywordThisAsIdentifier( + *AttrName, Form.getSyntax(), ScopeName); + bool AttributeIsTypeArgAttr = + attributeIsTypeArgAttr(*AttrName, Form.getSyntax(), ScopeName); bool AttributeHasVariadicIdentifierArg = - attributeHasVariadicIdentifierArg(*AttrName); + attributeHasVariadicIdentifierArg(*AttrName, Form.getSyntax(), ScopeName); // Interpret "kw_this" as an identifier if the attributed requests it. if (ChangeKWThisToIdent && Tok.is(tok::kw_this)) @@ -535,8 +573,9 @@ unsigned Parser::ParseAttributeArgsCommon( ArgsVector ArgExprs; if (Tok.is(tok::identifier)) { // If this attribute wants an 'identifier' argument, make it so. - bool IsIdentifierArg = AttributeHasVariadicIdentifierArg || - attributeHasIdentifierArg(*AttrName); + bool IsIdentifierArg = + AttributeHasVariadicIdentifierArg || + attributeHasIdentifierArg(*AttrName, Form.getSyntax(), ScopeName); ParsedAttr::Kind AttrKind = ParsedAttr::getParsedKind(AttrName, ScopeName, Form.getSyntax()); @@ -568,7 +607,8 @@ unsigned Parser::ParseAttributeArgsCommon( if (T.isUsable()) TheParsedType = T.get(); } else if (AttributeHasVariadicIdentifierArg || - attributeHasStrictIdentifierArgs(*AttrName)) { + attributeHasStrictIdentifierArgs(*AttrName, Form.getSyntax(), + ScopeName)) { // Parse variadic identifier arg. This can either consume identifiers or // expressions. Variadic identifier args do not support parameter packs // because those are typically used for attributes with enumeration @@ -579,8 +619,9 @@ unsigned Parser::ParseAttributeArgsCommon( if (ChangeKWThisToIdent && Tok.is(tok::kw_this)) Tok.setKind(tok::identifier); - if (Tok.is(tok::identifier) && attributeHasStrictIdentifierArgAtIndex( - *AttrName, ArgExprs.size())) { + if (Tok.is(tok::identifier) && + attributeHasStrictIdentifierArgAtIndex( + *AttrName, Form.getSyntax(), ScopeName, ArgExprs.size())) { ArgExprs.push_back(ParseIdentifierLoc()); continue; } @@ -589,7 +630,8 @@ unsigned Parser::ParseAttributeArgsCommon( if (Tok.is(tok::identifier)) { ArgExprs.push_back(ParseIdentifierLoc()); } else { - bool Uneval = attributeParsedArgsUnevaluated(*AttrName); + bool Uneval = attributeParsedArgsUnevaluated( + *AttrName, Form.getSyntax(), ScopeName); EnterExpressionEvaluationContext Unevaluated( Actions, Uneval ? Sema::ExpressionEvaluationContext::Unevaluated @@ -610,7 +652,8 @@ unsigned Parser::ParseAttributeArgsCommon( } while (TryConsumeToken(tok::comma)); } else { // General case. Parse all available expressions. - bool Uneval = attributeParsedArgsUnevaluated(*AttrName); + bool Uneval = attributeParsedArgsUnevaluated(*AttrName, Form.getSyntax(), + ScopeName); EnterExpressionEvaluationContext Unevaluated( Actions, Uneval ? Sema::ExpressionEvaluationContext::Unevaluated @@ -621,7 +664,8 @@ unsigned Parser::ParseAttributeArgsCommon( ExprVector ParsedExprs; ParsedAttributeArgumentsProperties ArgProperties = - attributeStringLiteralListArg(getTargetInfo().getTriple(), *AttrName); + attributeStringLiteralListArg(getTargetInfo().getTriple(), *AttrName, + Form.getSyntax(), ScopeName); if (ParseAttributeArgumentList(*AttrName, ParsedExprs, ArgProperties)) { SkipUntil(tok::r_paren, StopAtSemi); return 0; @@ -632,7 +676,7 @@ unsigned Parser::ParseAttributeArgsCommon( if (!isa(ParsedExprs[I])) continue; - if (!attributeAcceptsExprPack(*AttrName)) { + if (!attributeAcceptsExprPack(*AttrName, Form.getSyntax(), ScopeName)) { Diag(Tok.getLocation(), diag::err_attribute_argument_parm_pack_not_supported) << AttrName; @@ -696,7 +740,7 @@ void Parser::ParseGNUAttributeArgs( ParseTypeTagForDatatypeAttribute(*AttrName, AttrNameLoc, Attrs, EndLoc, ScopeName, ScopeLoc, Form); return; - } else if (attributeIsTypeArgAttr(*AttrName)) { + } else if (attributeIsTypeArgAttr(*AttrName, Form.getSyntax(), ScopeName)) { ParseAttributeWithTypeArg(*AttrName, AttrNameLoc, Attrs, ScopeName, ScopeLoc, Form); return; @@ -6650,48 +6694,66 @@ void Parser::ParseDeclaratorInternal(Declarator &D, (Tok.is(tok::identifier) && (NextToken().is(tok::coloncolon) || NextToken().is(tok::less))) || Tok.is(tok::annot_cxxscope))) { + TentativeParsingAction TPA(*this, /*Unannotated=*/true); bool EnteringContext = D.getContext() == DeclaratorContext::File || D.getContext() == DeclaratorContext::Member; CXXScopeSpec SS; SS.setTemplateParamLists(D.getTemplateParameterLists()); - ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, - /*ObjectHasErrors=*/false, EnteringContext); - if (SS.isNotEmpty()) { - if (Tok.isNot(tok::star)) { - // The scope spec really belongs to the direct-declarator. - if (D.mayHaveIdentifier()) - D.getCXXScopeSpec() = SS; - else - AnnotateScopeToken(SS, true); + if (ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, + /*ObjectHasErrors=*/false, + /*EnteringContext=*/false, + /*MayBePseudoDestructor=*/nullptr, + /*IsTypename=*/false, /*LastII=*/nullptr, + /*OnlyNamespace=*/false, + /*InUsingDeclaration=*/false, + /*Disambiguation=*/EnteringContext) || + + SS.isEmpty() || SS.isInvalid() || !EnteringContext || + Tok.is(tok::star)) { + TPA.Commit(); + if (SS.isNotEmpty() && Tok.is(tok::star)) { + if (SS.isValid()) { + checkCompoundToken(SS.getEndLoc(), tok::coloncolon, + CompoundToken::MemberPtr); + } - if (DirectDeclParser) - (this->*DirectDeclParser)(D); + SourceLocation StarLoc = ConsumeToken(); + D.SetRangeEnd(StarLoc); + DeclSpec DS(AttrFactory); + ParseTypeQualifierListOpt(DS); + D.ExtendWithDeclSpec(DS); + + // Recurse to parse whatever is left. + Actions.runWithSufficientStackSpace(D.getBeginLoc(), [&] { + ParseDeclaratorInternal(D, DirectDeclParser); + }); + + // Sema will have to catch (syntactically invalid) pointers into global + // scope. It has to catch pointers into namespace scope anyway. + D.AddTypeInfo(DeclaratorChunk::getMemberPointer( + SS, DS.getTypeQualifiers(), StarLoc, DS.getEndLoc()), + std::move(DS.getAttributes()), + /*EndLoc=*/SourceLocation()); return; } + } else { + TPA.Revert(); + SS.clear(); + ParseOptionalCXXScopeSpecifier(SS, /*ObjectType=*/nullptr, + /*ObjectHasErrors=*/false, + /*EnteringContext=*/true); + } - if (SS.isValid()) { - checkCompoundToken(SS.getEndLoc(), tok::coloncolon, - CompoundToken::MemberPtr); - } + if (SS.isNotEmpty()) { + // The scope spec really belongs to the direct-declarator. + if (D.mayHaveIdentifier()) + D.getCXXScopeSpec() = SS; + else + AnnotateScopeToken(SS, true); - SourceLocation StarLoc = ConsumeToken(); - D.SetRangeEnd(StarLoc); - DeclSpec DS(AttrFactory); - ParseTypeQualifierListOpt(DS); - D.ExtendWithDeclSpec(DS); - - // Recurse to parse whatever is left. - Actions.runWithSufficientStackSpace(D.getBeginLoc(), [&] { - ParseDeclaratorInternal(D, DirectDeclParser); - }); - - // Sema will have to catch (syntactically invalid) pointers into global - // scope. It has to catch pointers into namespace scope anyway. - D.AddTypeInfo(DeclaratorChunk::getMemberPointer( - SS, DS.getTypeQualifiers(), StarLoc, DS.getEndLoc()), - std::move(DS.getAttributes()), - /* Don't replace range end. */ SourceLocation()); + if (DirectDeclParser) + (this->*DirectDeclParser)(D); return; } } diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 0a017ae79de7534..e82b5652728317f 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -763,6 +763,9 @@ class CastExpressionIdValidator final : public CorrectionCandidateCallback { bool Parser::isRevertibleTypeTrait(const IdentifierInfo *II, tok::TokenKind *Kind) { if (RevertibleTypeTraits.empty()) { +// Revertible type trait is a feature for backwards compatibility with older +// standard libraries that declare their own structs with the same name as +// the builtins listed below. New builtins should NOT be added to this list. #define RTT_JOIN(X, Y) X##Y #define REVERTIBLE_TYPE_TRAIT(Name) \ RevertibleTypeTraits[PP.getIdentifierInfo(#Name)] = RTT_JOIN(tok::kw_, Name) @@ -790,7 +793,6 @@ bool Parser::isRevertibleTypeTrait(const IdentifierInfo *II, REVERTIBLE_TYPE_TRAIT(__is_fundamental); REVERTIBLE_TYPE_TRAIT(__is_integral); REVERTIBLE_TYPE_TRAIT(__is_interface_class); - REVERTIBLE_TYPE_TRAIT(__is_layout_compatible); REVERTIBLE_TYPE_TRAIT(__is_literal); REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr); REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 1d364f77a81464a..c0eae73927cdd40 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -159,8 +159,8 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, bool Parser::ParseOptionalCXXScopeSpecifier( CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors, bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename, - const IdentifierInfo **LastII, bool OnlyNamespace, - bool InUsingDeclaration) { + const IdentifierInfo **LastII, bool OnlyNamespace, bool InUsingDeclaration, + bool Disambiguation) { assert(getLangOpts().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); @@ -528,13 +528,11 @@ bool Parser::ParseOptionalCXXScopeSpecifier( UnqualifiedId TemplateName; TemplateName.setIdentifier(&II, Tok.getLocation()); bool MemberOfUnknownSpecialization; - if (TemplateNameKind TNK = Actions.isTemplateName(getCurScope(), SS, - /*hasTemplateKeyword=*/false, - TemplateName, - ObjectType, - EnteringContext, - Template, - MemberOfUnknownSpecialization)) { + if (TemplateNameKind TNK = Actions.isTemplateName( + getCurScope(), SS, + /*hasTemplateKeyword=*/false, TemplateName, ObjectType, + EnteringContext, Template, MemberOfUnknownSpecialization, + Disambiguation)) { // If lookup didn't find anything, we treat the name as a template-name // anyway. C++20 requires this, and in prior language modes it improves // error recovery. But before we commit to this, check that we actually @@ -557,7 +555,8 @@ bool Parser::ParseOptionalCXXScopeSpecifier( continue; } - if (MemberOfUnknownSpecialization && (ObjectType || SS.isSet()) && + if (MemberOfUnknownSpecialization && !Disambiguation && + (ObjectType || SS.isSet()) && (IsTypename || isTemplateArgumentList(1) == TPResult::True)) { // If we had errors before, ObjectType can be dependent even without any // templates. Do not report missing template keyword in that case. diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index f5b44d210680cc9..e975e96c5c7e456 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -3837,6 +3837,7 @@ OMPClause *Parser::ParseOpenMPSingleExprWithArgClause(OpenMPDirectiveKind DKind, // Get a defaultmap modifier unsigned Modifier = getOpenMPSimpleClauseType( Kind, Tok.isAnnotation() ? "" : PP.getSpelling(Tok), getLangOpts()); + // Set defaultmap modifier to unknown if it is either scalar, aggregate, or // pointer if (Modifier < OMPC_DEFAULTMAP_MODIFIER_unknown) diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp index 112cf3d08182277..7389046eaddde19 100644 --- a/clang/lib/Sema/CheckExprLifetime.cpp +++ b/clang/lib/Sema/CheckExprLifetime.cpp @@ -825,7 +825,6 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path, if (auto *CCE = dyn_cast(Init)) { if (CCE->getConstructor()->isCopyOrMoveConstructor()) { if (auto *MTE = dyn_cast(CCE->getArg(0))) { - // assert(false && "hit temporary copy path"); Expr *Arg = MTE->getSubExpr(); Path.push_back({IndirectLocalPathEntry::TemporaryCopy, Arg, CCE->getConstructor()}); diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp index be5b7b92dfe6f1e..2c49c1f64b2da86 100644 --- a/clang/lib/Sema/SemaAPINotes.cpp +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -1044,11 +1044,16 @@ void Sema::ProcessAPINotes(Decl *D) { if (auto TagContext = dyn_cast(D->getDeclContext())) { if (auto CXXMethod = dyn_cast(D)) { - for (auto Reader : APINotes.findAPINotes(D->getLocation())) { - if (auto Context = UnwindTagContext(TagContext, APINotes)) { - auto Info = - Reader->lookupCXXMethod(Context->id, CXXMethod->getName()); - ProcessVersionedAPINotes(*this, CXXMethod, Info); + if (!isa(CXXMethod) && + !isa(CXXMethod) && + !isa(CXXMethod) && + !CXXMethod->isOverloadedOperator()) { + for (auto Reader : APINotes.findAPINotes(D->getLocation())) { + if (auto Context = UnwindTagContext(TagContext, APINotes)) { + auto Info = + Reader->lookupCXXMethod(Context->id, CXXMethod->getName()); + ProcessVersionedAPINotes(*this, CXXMethod, Info); + } } } } diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index cf1196ad23c2170..bb30b1e289a1c0b 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -1477,6 +1477,18 @@ static bool BuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, return false; } +// In OpenCL, __builtin_alloca_* should return a pointer to address space +// that corresponds to the stack address space i.e private address space. +static void builtinAllocaAddrSpace(Sema &S, CallExpr *TheCall) { + QualType RT = TheCall->getType(); + assert((RT->isPointerType() && !(RT->getPointeeType().hasAddressSpace())) && + "__builtin_alloca has invalid address space"); + + RT = RT->getPointeeType(); + RT = S.Context.getAddrSpaceQualType(RT, LangAS::opencl_private); + TheCall->setType(S.Context.getPointerType(RT)); +} + namespace { enum PointerAuthOpKind { PAO_Strip, @@ -2214,6 +2226,9 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_alloca_uninitialized: Diag(TheCall->getBeginLoc(), diag::warn_alloca) << TheCall->getDirectCallee(); + if (getLangOpts().OpenCL) { + builtinAllocaAddrSpace(*this, TheCall); + } break; case Builtin::BI__arithmetic_fence: if (BuiltinArithmeticFence(TheCall)) @@ -6030,7 +6045,7 @@ static const Expr *maybeConstEvalStringLiteral(ASTContext &Context, Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) { return llvm::StringSwitch(Format->getType()->getName()) .Case("scanf", FST_Scanf) - .Cases("printf", "printf0", FST_Printf) + .Cases("printf", "printf0", "syslog", FST_Printf) .Cases("NSString", "CFString", FST_NSString) .Case("strftime", FST_Strftime) .Case("strfmon", FST_Strfmon) @@ -6124,6 +6139,7 @@ bool Sema::CheckFormatArguments(ArrayRef Args, case FST_Kprintf: case FST_FreeBSDKPrintf: case FST_Printf: + case FST_Syslog: Diag(FormatLoc, diag::note_format_security_fixit) << FixItHint::CreateInsertion(FormatLoc, "\"%s\", "); break; @@ -7860,7 +7876,7 @@ static void CheckFormatString( if (Type == Sema::FST_Printf || Type == Sema::FST_NSString || Type == Sema::FST_FreeBSDKPrintf || Type == Sema::FST_OSLog || - Type == Sema::FST_OSTrace) { + Type == Sema::FST_OSTrace || Type == Sema::FST_Syslog) { CheckPrintfHandler H( S, FExpr, OrigFormatExpr, Type, firstDataArg, numDataArgs, (Type == Sema::FST_NSString || Type == Sema::FST_OSTrace), Str, APK, @@ -8202,20 +8218,46 @@ static bool IsStdFunction(const FunctionDecl *FDecl, return true; } +enum class MathCheck { NaN, Inf }; +static bool IsInfOrNanFunction(StringRef calleeName, MathCheck Check) { + auto MatchesAny = [&](std::initializer_list names) { + return std::any_of(names.begin(), names.end(), [&](llvm::StringRef name) { + return calleeName == name; + }); + }; + + switch (Check) { + case MathCheck::NaN: + return MatchesAny({"__builtin_nan", "__builtin_nanf", "__builtin_nanl", + "__builtin_nanf16", "__builtin_nanf128"}); + case MathCheck::Inf: + return MatchesAny({"__builtin_inf", "__builtin_inff", "__builtin_infl", + "__builtin_inff16", "__builtin_inff128"}); + } + llvm_unreachable("unknown MathCheck"); +} + void Sema::CheckInfNaNFunction(const CallExpr *Call, const FunctionDecl *FDecl) { FPOptions FPO = Call->getFPFeaturesInEffect(getLangOpts()); - if ((IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered") || - (Call->getBuiltinCallee() == Builtin::BI__builtin_nanf)) && - FPO.getNoHonorNaNs()) + bool HasIdentifier = FDecl->getIdentifier() != nullptr; + bool IsNaNOrIsUnordered = + IsStdFunction(FDecl, "isnan") || IsStdFunction(FDecl, "isunordered"); + bool IsSpecialNaN = + HasIdentifier && IsInfOrNanFunction(FDecl->getName(), MathCheck::NaN); + if ((IsNaNOrIsUnordered || IsSpecialNaN) && FPO.getNoHonorNaNs()) { Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) << 1 << 0 << Call->getSourceRange(); - else if ((IsStdFunction(FDecl, "isinf") || - (IsStdFunction(FDecl, "isfinite") || - (FDecl->getIdentifier() && FDecl->getName() == "infinity"))) && - FPO.getNoHonorInfs()) - Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) - << 0 << 0 << Call->getSourceRange(); + } else { + bool IsInfOrIsFinite = + IsStdFunction(FDecl, "isinf") || IsStdFunction(FDecl, "isfinite"); + bool IsInfinityOrIsSpecialInf = + HasIdentifier && ((FDecl->getName() == "infinity") || + IsInfOrNanFunction(FDecl->getName(), MathCheck::Inf)); + if ((IsInfOrIsFinite || IsInfinityOrIsSpecialInf) && FPO.getNoHonorInfs()) + Diag(Call->getBeginLoc(), diag::warn_fp_nan_inf_when_disabled) + << 0 << 0 << Call->getSourceRange(); + } } void Sema::CheckAbsoluteValueFunction(const CallExpr *Call, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index bb25a0b3a45ae90..a3f8126a9f91527 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5887,7 +5887,7 @@ Sema::GetNameFromUnqualifiedId(const UnqualifiedId &Name) { static QualType getCoreType(QualType Ty) { do { - if (Ty->isPointerType() || Ty->isReferenceType()) + if (Ty->isPointerOrReferenceType()) Ty = Ty->getPointeeType(); else if (Ty->isArrayType()) Ty = Ty->castAsArrayTypeUnsafe()->getElementType(); @@ -6890,6 +6890,11 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { } } + if (HybridPatchableAttr *Attr = ND.getAttr()) { + if (!ND.isExternallyVisible()) + S.Diag(Attr->getLocation(), + diag::warn_attribute_hybrid_patchable_non_extern); + } if (const InheritableAttr *Attr = getDLLAttr(&ND)) { auto *VD = dyn_cast(&ND); bool IsAnonymousNS = false; @@ -9334,7 +9339,7 @@ static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) { if (PT->isDependentType()) return InvalidKernelParam; - if (PT->isPointerType() || PT->isReferenceType()) { + if (PT->isPointerOrReferenceType()) { QualType PointeeType = PT->getPointeeType(); if (PointeeType.getAddressSpace() == LangAS::opencl_generic || PointeeType.getAddressSpace() == LangAS::opencl_private || @@ -10784,10 +10789,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (getLangOpts().getOpenCLCompatibleVersion() >= 200) { if(const PipeType *PipeTy = PT->getAs()) { QualType ElemTy = PipeTy->getElementType(); - if (ElemTy->isReferenceType() || ElemTy->isPointerType()) { - Diag(Param->getTypeSpecStartLoc(), diag::err_reference_pipe_type ); - D.setInvalidType(); - } + if (ElemTy->isPointerOrReferenceType()) { + Diag(Param->getTypeSpecStartLoc(), diag::err_reference_pipe_type); + D.setInvalidType(); + } } } // WebAssembly tables can't be used as function parameters. @@ -11009,6 +11014,9 @@ static bool AttrCompatibleWithMultiVersion(attr::Kind Kind, switch (Kind) { default: return false; + case attr::ArmLocallyStreaming: + return MVKind == MultiVersionKind::TargetVersion || + MVKind == MultiVersionKind::TargetClones; case attr::Used: return MVKind == MultiVersionKind::Target; case attr::NonNull: @@ -11145,7 +11153,21 @@ bool Sema::areMultiversionVariantFunctionsCompatible( FunctionType::ExtInfo OldTypeInfo = OldType->getExtInfo(); FunctionType::ExtInfo NewTypeInfo = NewType->getExtInfo(); - if (OldTypeInfo.getCC() != NewTypeInfo.getCC()) + const auto *OldFPT = OldFD->getType()->getAs(); + const auto *NewFPT = NewFD->getType()->getAs(); + + bool ArmStreamingCCMismatched = false; + if (OldFPT && NewFPT) { + unsigned Diff = + OldFPT->getAArch64SMEAttributes() ^ NewFPT->getAArch64SMEAttributes(); + // Arm-streaming, arm-streaming-compatible and non-streaming versions + // cannot be mixed. + if (Diff & (FunctionType::SME_PStateSMEnabledMask | + FunctionType::SME_PStateSMCompatibleMask)) + ArmStreamingCCMismatched = true; + } + + if (OldTypeInfo.getCC() != NewTypeInfo.getCC() || ArmStreamingCCMismatched) return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << CallingConv; QualType OldReturnType = OldType->getReturnType(); @@ -11165,9 +11187,8 @@ bool Sema::areMultiversionVariantFunctionsCompatible( if (!CLinkageMayDiffer && OldFD->isExternC() != NewFD->isExternC()) return Diag(DiffDiagIDAt.first, DiffDiagIDAt.second) << LanguageLinkage; - if (CheckEquivalentExceptionSpec( - OldFD->getType()->getAs(), OldFD->getLocation(), - NewFD->getType()->getAs(), NewFD->getLocation())) + if (CheckEquivalentExceptionSpec(OldFPT, OldFD->getLocation(), NewFPT, + NewFD->getLocation())) return true; } return false; @@ -20148,8 +20169,10 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(const FunctionDecl *FD, // be emitted, because (say) the definition could include "inline". const FunctionDecl *Def = FD->getDefinition(); - return Def && !isDiscardableGVALinkage( - getASTContext().GetGVALinkageForFunction(Def)); + // We can't compute linkage when we skip function bodies. + return Def && !Def->hasSkippedBody() && + !isDiscardableGVALinkage( + getASTContext().GetGVALinkageForFunction(Def)); }; if (LangOpts.OpenMPIsTargetDevice) { diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 39675422e3f9fd2..9011fa547638e56 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -1481,6 +1481,14 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { break; } + // Allow only pointers to be return type for functions with ownership_returns + // attribute. This matches with current OwnershipAttr::Takes semantics + if (K == OwnershipAttr::Returns && + !getFunctionOrMethodResultType(D)->isPointerType()) { + S.Diag(AL.getLoc(), diag::err_ownership_takes_return_type) << AL; + return; + } + IdentifierInfo *Module = AL.getArgAsIdent(0)->Ident; StringRef ModuleName = Module->getName(); @@ -3034,9 +3042,6 @@ bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D, return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << CurFeature << TargetVersion; } - if (IsArmStreamingFunction(cast(D), - /*IncludeLocallyStreaming=*/false)) - return Diag(LiteralLoc, diag::err_sme_streaming_cannot_be_multiversioned); return false; } @@ -3133,10 +3138,6 @@ bool Sema::checkTargetClonesAttrString( HasNotDefault = true; } } - if (IsArmStreamingFunction(cast(D), - /*IncludeLocallyStreaming=*/false)) - return Diag(LiteralLoc, - diag::err_sme_streaming_cannot_be_multiversioned); } else { // Other targets ( currently X86 ) if (Cur.starts_with("arch=")) { @@ -3407,8 +3408,8 @@ static FormatAttrKind getFormatAttrKind(StringRef Format) { // Otherwise, check for supported formats. .Cases("scanf", "printf", "printf0", "strfmon", SupportedFormat) .Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat) - .Case("kprintf", SupportedFormat) // OpenBSD. - .Case("freebsd_kprintf", SupportedFormat) // FreeBSD. + .Cases("kprintf", "syslog", SupportedFormat) // OpenBSD. + .Case("freebsd_kprintf", SupportedFormat) // FreeBSD. .Case("os_trace", SupportedFormat) .Case("os_log", SupportedFormat) @@ -5991,7 +5992,7 @@ static void handleMSAllocatorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Warn if the return type is not a pointer or reference type. if (auto *FD = dyn_cast(D)) { QualType RetTy = FD->getReturnType(); - if (!RetTy->isPointerType() && !RetTy->isReferenceType()) { + if (!RetTy->isPointerOrReferenceType()) { S.Diag(AL.getLoc(), diag::warn_declspec_allocator_nonpointer) << AL.getRange() << RetTy; return; @@ -6878,6 +6879,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_MSConstexpr: handleMSConstexprAttr(S, D, AL); break; + case ParsedAttr::AT_HybridPatchable: + handleSimpleAttribute(S, D, AL); + break; // HLSL attributes: case ParsedAttr::AT_HLSLNumThreads: diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 04b8d88cae217b6..5782daa041f32d5 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -10385,7 +10385,7 @@ void Sema::checkIncorrectVTablePointerAuthenticationAttribute( while (1) { assert(PrimaryBase); const CXXRecordDecl *Base = nullptr; - for (auto BasePtr : PrimaryBase->bases()) { + for (const CXXBaseSpecifier &BasePtr : PrimaryBase->bases()) { if (!BasePtr.getType()->getAsCXXRecordDecl()->isDynamicClass()) continue; Base = BasePtr.getType()->getAsCXXRecordDecl(); @@ -12248,16 +12248,15 @@ Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS, SourceLocation EnumLoc, SourceRange TyLoc, const IdentifierInfo &II, ParsedType Ty, CXXScopeSpec *SS) { - assert(!SS->isInvalid() && "ScopeSpec is invalid"); + assert(SS && !SS->isInvalid() && "ScopeSpec is invalid"); TypeSourceInfo *TSI = nullptr; SourceLocation IdentLoc = TyLoc.getBegin(); QualType EnumTy = GetTypeFromParser(Ty, &TSI); if (EnumTy.isNull()) { - Diag(IdentLoc, SS && isDependentScopeSpecifier(*SS) + Diag(IdentLoc, isDependentScopeSpecifier(*SS) ? diag::err_using_enum_is_dependent : diag::err_unknown_typename) - << II.getName() - << SourceRange(SS ? SS->getBeginLoc() : IdentLoc, TyLoc.getEnd()); + << II.getName() << SourceRange(SS->getBeginLoc(), TyLoc.getEnd()); return nullptr; } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 14d1f395af90e3a..c5003d9ac02549b 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -711,7 +711,7 @@ getUuidAttrOfType(Sema &SemaRef, QualType QT, llvm::SmallSetVector &UuidAttrs) { // Optionally remove one level of pointer, reference or array indirection. const Type *Ty = QT.getTypePtr(); - if (QT->isPointerType() || QT->isReferenceType()) + if (QT->isPointerOrReferenceType()) Ty = QT->getPointeeType().getTypePtr(); else if (QT->isArrayType()) Ty = Ty->getBaseElementTypeUnsafe(); @@ -3806,6 +3806,9 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, Overaligned, DeleteName); } + if (OperatorDelete->isInvalidDecl()) + return ExprError(); + MarkFunctionReferenced(StartLoc, OperatorDelete); // Check access and ambiguity of destructor if we're going to call it. @@ -6027,6 +6030,32 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI return cast(rhsRecord->getDecl()) ->isDerivedFrom(cast(lhsRecord->getDecl())); } + case BTT_IsVirtualBaseOf: { + const RecordType *BaseRecord = LhsT->getAs(); + const RecordType *DerivedRecord = RhsT->getAs(); + + if (!BaseRecord || !DerivedRecord) { + DiagnoseVLAInCXXTypeTrait(Self, Lhs, + tok::kw___builtin_is_virtual_base_of); + DiagnoseVLAInCXXTypeTrait(Self, Rhs, + tok::kw___builtin_is_virtual_base_of); + return false; + } + + if (BaseRecord->isUnionType() || DerivedRecord->isUnionType()) + return false; + + if (!BaseRecord->isStructureOrClassType() || + !DerivedRecord->isStructureOrClassType()) + return false; + + if (Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT, + diag::err_incomplete_type)) + return false; + + return cast(DerivedRecord->getDecl()) + ->isVirtuallyDerivedFrom(cast(BaseRecord->getDecl())); + } case BTT_IsSame: return Self.Context.hasSameType(LhsT, RhsT); case BTT_TypeCompatible: { diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 9940bc5b4a606a1..11686db117ff4c4 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -650,7 +650,10 @@ class DiagnoseHLSLAvailability bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA); public: - DiagnoseHLSLAvailability(Sema &SemaRef) : SemaRef(SemaRef) {} + DiagnoseHLSLAvailability(Sema &SemaRef) + : SemaRef(SemaRef), + CurrentShaderEnvironment(llvm::Triple::UnknownEnvironment), + CurrentShaderStageBit(0), ReportOnlyShaderStageIssues(false) {} // AST traversal methods void RunOnTranslationUnit(const TranslationUnitDecl *TU); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index dc2ba039afe7f3d..90fd6df782f095f 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -1986,6 +1986,9 @@ static bool checkDestructorReference(QualType ElementType, SourceLocation Loc, return false; CXXDestructorDecl *Destructor = SemaRef.LookupDestructor(CXXRD); + if (!Destructor) + return false; + SemaRef.CheckDestructorAccess(Loc, Destructor, SemaRef.PDiag(diag::err_access_dtor_temp) << ElementType); diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index bb18c558c49a667..4f50efda155fb5e 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -801,7 +801,8 @@ class DSAStackTy { return (M == OMPC_DEFAULTMAP_MODIFIER_alloc) || (M == OMPC_DEFAULTMAP_MODIFIER_to) || (M == OMPC_DEFAULTMAP_MODIFIER_from) || - (M == OMPC_DEFAULTMAP_MODIFIER_tofrom); + (M == OMPC_DEFAULTMAP_MODIFIER_tofrom) || + (M == OMPC_DEFAULTMAP_MODIFIER_present); } return true; } @@ -2830,7 +2831,7 @@ static void checkReductionClauses(Sema &S, DSAStackTy *Stack, S.Diag(InscanLoc, diag::note_omp_previous_inscan_reduction); continue; } - for (Expr *Ref : RC->varlists()) { + for (Expr *Ref : RC->varlist()) { assert(Ref && "NULL expr in OpenMP nontemporal clause."); SourceLocation ELoc; SourceRange ERange; @@ -2870,7 +2871,7 @@ void SemaOpenMP::EndOpenMPDSABlock(Stmt *CurDirective) { for (OMPClause *C : D->clauses()) { if (auto *Clause = dyn_cast(C)) { SmallVector PrivateCopies; - for (Expr *DE : Clause->varlists()) { + for (Expr *DE : Clause->varlist()) { if (DE->isValueDependent() || DE->isTypeDependent()) { PrivateCopies.push_back(nullptr); continue; @@ -2908,7 +2909,7 @@ void SemaOpenMP::EndOpenMPDSABlock(Stmt *CurDirective) { // Finalize nontemporal clause by handling private copies, if any. if (auto *Clause = dyn_cast(C)) { SmallVector PrivateRefs; - for (Expr *RefExpr : Clause->varlists()) { + for (Expr *RefExpr : Clause->varlist()) { assert(RefExpr && "NULL expr in OpenMP nontemporal clause."); SourceLocation ELoc; SourceRange ERange; @@ -3078,11 +3079,11 @@ ExprResult SemaOpenMP::ActOnOpenMPIdExpression(Scope *CurScope, if (TypoCorrection Corrected = SemaRef.CorrectTypo(Id, Sema::LookupOrdinaryName, CurScope, nullptr, CCC, Sema::CTK_ErrorRecovery)) { - SemaRef.diagnoseTypo(Corrected, - PDiag(Lookup.empty() - ? diag::err_undeclared_var_use_suggest - : diag::err_omp_expected_var_arg_suggest) - << Id.getName()); + SemaRef.diagnoseTypo( + Corrected, + SemaRef.PDiag(Lookup.empty() ? diag::err_undeclared_var_use_suggest + : diag::err_omp_expected_var_arg_suggest) + << Id.getName()); VD = Corrected.getCorrectionDeclAs(); } else { Diag(Id.getLoc(), Lookup.empty() ? diag::err_undeclared_var_use @@ -3751,7 +3752,7 @@ class DSAAttrChecker final : public StmtVisitor { !isOpenMPTaskLoopDirective(S->getDirectiveKind())) { for (OMPClause *C : S->clauses()) if (auto *FC = dyn_cast(C)) { - for (Expr *Ref : FC->varlists()) + for (Expr *Ref : FC->varlist()) Visit(Ref); } } @@ -4728,7 +4729,7 @@ StmtResult SemaOpenMP::ActOnOpenMPRegionEnd(StmtResult S, SemaRef.MarkDeclarationsReferencedInExpr(E); } if (auto *AC = dyn_cast(C)) { - for (Expr *E : AC->varlists()) + for (Expr *E : AC->varlist()) SemaRef.MarkDeclarationsReferencedInExpr(E); } } @@ -5310,7 +5311,7 @@ static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, diag::warn_omp_allocate_thread_on_task_target_directive) << getOpenMPDirectiveName(Stack->getCurrentDirective()); } - for (Expr *E : AC->varlists()) { + for (Expr *E : AC->varlist()) { SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = E; @@ -6134,7 +6135,7 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( SmallVector ImplicitExprs; for (OMPClause *C : Clauses) { if (auto *RC = dyn_cast(C)) - for (Expr *E : RC->varlists()) + for (Expr *E : RC->varlist()) if (!isa(E->IgnoreParenImpCasts())) ImplicitExprs.emplace_back(E); } @@ -7500,9 +7501,9 @@ SemaOpenMP::checkOpenMPDeclareVariantFunction(SemaOpenMP::DeclGroupPtrTy DG, PartialDiagnostic::NullDiagnostic()), PartialDiagnosticAt( VariantRef->getExprLoc(), - PDiag(diag::err_omp_declare_variant_doesnt_support)), + SemaRef.PDiag(diag::err_omp_declare_variant_doesnt_support)), PartialDiagnosticAt(VariantRef->getExprLoc(), - PDiag(diag::err_omp_declare_variant_diff) + SemaRef.PDiag(diag::err_omp_declare_variant_diff) << FD->getLocation()), /*TemplatesSupported=*/true, /*ConstexprSupported=*/false, /*CLinkageMayDiffer=*/true)) @@ -10444,7 +10445,7 @@ static bool checkGenericLoopLastprivate(Sema &S, ArrayRef Clauses, bool ErrorFound = false; for (OMPClause *C : Clauses) { if (auto *LPC = dyn_cast(C)) { - for (Expr *RefExpr : LPC->varlists()) { + for (Expr *RefExpr : LPC->varlist()) { SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; @@ -19122,7 +19123,7 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, auto CurInit = Clause.inits().begin(); auto CurPrivate = Clause.privates().begin(); OpenMPLinearClauseKind LinKind = Clause.getModifier(); - for (Expr *RefExpr : Clause.varlists()) { + for (Expr *RefExpr : Clause.varlist()) { SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; @@ -21892,7 +21893,9 @@ OMPClause *SemaOpenMP::ActOnOpenMPDefaultmapClause( bool isDefaultmapKind = (Kind != OMPC_DEFAULTMAP_unknown) || (getLangOpts().OpenMP >= 50 && KindLoc.isInvalid()); if (!isDefaultmapKind || !isDefaultmapModifier) { - StringRef KindValue = "'scalar', 'aggregate', 'pointer'"; + StringRef KindValue = getLangOpts().OpenMP < 52 + ? "'scalar', 'aggregate', 'pointer'" + : "'scalar', 'aggregate', 'pointer', 'all'"; if (getLangOpts().OpenMP == 50) { StringRef ModifierValue = "'alloc', 'from', 'to', 'tofrom', " "'firstprivate', 'none', 'default'"; @@ -21936,7 +21939,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPDefaultmapClause( return nullptr; } } - if (Kind == OMPC_DEFAULTMAP_unknown) { + if (Kind == OMPC_DEFAULTMAP_unknown || Kind == OMPC_DEFAULTMAP_all) { // Variable category is not specified - mark all categories. DSAStack->setDefaultDMAAttr(M, OMPC_DEFAULTMAP_aggregate, StartLoc); DSAStack->setDefaultDMAAttr(M, OMPC_DEFAULTMAP_scalar, StartLoc); @@ -22009,7 +22012,7 @@ NamedDecl *SemaOpenMP::lookupOpenMPDeclareTargetName( SemaRef.CorrectTypo(Id, Sema::LookupOrdinaryName, CurScope, nullptr, CCC, Sema::CTK_ErrorRecovery)) { SemaRef.diagnoseTypo(Corrected, - PDiag(diag::err_undeclared_var_use_suggest) + SemaRef.PDiag(diag::err_undeclared_var_use_suggest) << Id.getName()); checkDeclIsAllowedInOpenMPTarget(nullptr, Corrected.getCorrectionDecl()); return nullptr; @@ -23084,8 +23087,7 @@ OMPClause *SemaOpenMP::ActOnOpenMPDoacrossClause( if (DSAStack->getCurrentDirective() == OMPD_ordered && DepType != OMPC_DOACROSS_source && DepType != OMPC_DOACROSS_sink && DepType != OMPC_DOACROSS_sink_omp_cur_iteration && - DepType != OMPC_DOACROSS_source_omp_cur_iteration && - DepType != OMPC_DOACROSS_source) { + DepType != OMPC_DOACROSS_source_omp_cur_iteration) { Diag(DepLoc, diag::err_omp_unexpected_clause_value) << "'source' or 'sink'" << getOpenMPClauseName(OMPC_doacross); return nullptr; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 86074a4f3a58525..c5f56ac62b458cf 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -11133,7 +11133,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, if (isa(Fn) && !isa(Fn)) { if (I == 0) isObjectArgument = true; - else + else if (!Fn->hasCXXExplicitFunctionObjectParameter()) I--; } diff --git a/clang/lib/Sema/SemaPPC.cpp b/clang/lib/Sema/SemaPPC.cpp index 99f46b12e696830..5b764ed396ebcc8 100644 --- a/clang/lib/Sema/SemaPPC.cpp +++ b/clang/lib/Sema/SemaPPC.cpp @@ -93,7 +93,6 @@ bool SemaPPC::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall) { ASTContext &Context = getASTContext(); - unsigned i = 0, l = 0, u = 0; bool IsTarget64Bit = TI.getTypeWidth(TI.getIntPtrType()) == 64; llvm::APSInt Result; @@ -248,7 +247,7 @@ bool SemaPPC::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, return BuiltinPPCMMACall(TheCall, BuiltinID, Types); #include "clang/Basic/BuiltinsPPC.def" } - return SemaRef.BuiltinConstantArgRange(TheCall, i, l, u); + llvm_unreachable("must return from switch"); } // Check if the given type is a non-pointer PPC MMA type. This function is used diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 7f452d177c16f0b..3cf742b6a672d1b 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -218,7 +218,6 @@ class CallExprFinder : public ConstEvaluatedExprVisitor { static Attr *handleNoMergeAttr(Sema &S, Stmt *St, const ParsedAttr &A, SourceRange Range) { - NoMergeAttr NMA(S.Context, A); CallExprFinder CEF(S, St); if (!CEF.foundCallExpr() && !CEF.foundAsmStmt()) { @@ -594,13 +593,6 @@ static Attr *handleHLSLLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A, unsigned UnrollFactor = 0; if (A.getNumArgs() == 1) { - - if (A.isArgIdent(0)) { - S.Diag(A.getLoc(), diag::err_attribute_argument_type) - << A << AANT_ArgumentIntegerConstant << A.getRange(); - return nullptr; - } - Expr *E = A.getArgAsExpr(0); if (S.CheckLoopHintExpr(E, St->getBeginLoc(), diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 87b1f98bbe5ac98..c22e329bef2b907 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -6719,7 +6719,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, auto *VD = const_cast(Base.dyn_cast()); // For a non-type template-parameter of pointer or reference type, // the value of the constant expression shall not refer to - assert(ParamType->isPointerType() || ParamType->isReferenceType() || + assert(ParamType->isPointerOrReferenceType() || ParamType->isNullPtrType()); // -- a temporary object // -- a string literal diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index b7b857ebf804b36..db7f233dcef7319 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -951,9 +951,11 @@ class PackDeductionScope { // Skip over the pack elements that were expanded into separate arguments. // If we partially expanded, this is the number of partial arguments. + // FIXME: `&& FixedNumExpansions` is a workaround for UB described in + // https://github.com/llvm/llvm-project/issues/100095 if (IsPartiallyExpanded) PackElements += NumPartialPackArgs; - else if (IsExpanded) + else if (IsExpanded && FixedNumExpansions) PackElements += *FixedNumExpansions; for (auto &Pack : Packs) { diff --git a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp index 0602d07c6b9b0d3..545da21183c3c45 100644 --- a/clang/lib/Sema/SemaTemplateDeductionGuide.cpp +++ b/clang/lib/Sema/SemaTemplateDeductionGuide.cpp @@ -39,6 +39,7 @@ #include "clang/Sema/Overload.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "llvm/ADT/ArrayRef.h" @@ -241,11 +242,10 @@ NamedDecl *buildDeductionGuide( } // Transform a given template type parameter `TTP`. -TemplateTypeParmDecl * -transformTemplateTypeParam(Sema &SemaRef, DeclContext *DC, - TemplateTypeParmDecl *TTP, - MultiLevelTemplateArgumentList &Args, - unsigned NewDepth, unsigned NewIndex) { +TemplateTypeParmDecl *transformTemplateTypeParam( + Sema &SemaRef, DeclContext *DC, TemplateTypeParmDecl *TTP, + MultiLevelTemplateArgumentList &Args, unsigned NewDepth, unsigned NewIndex, + bool EvaluateConstraint) { // TemplateTypeParmDecl's index cannot be changed after creation, so // substitute it directly. auto *NewTTP = TemplateTypeParmDecl::Create( @@ -257,7 +257,7 @@ transformTemplateTypeParam(Sema &SemaRef, DeclContext *DC, : std::nullopt); if (const auto *TC = TTP->getTypeConstraint()) SemaRef.SubstTypeConstraint(NewTTP, TC, Args, - /*EvaluateConstraint=*/true); + /*EvaluateConstraint=*/EvaluateConstraint); if (TTP->hasDefaultArgument()) { TemplateArgumentLoc InstantiatedDefaultArg; if (!SemaRef.SubstTemplateArgument( @@ -284,6 +284,22 @@ transformTemplateParam(Sema &SemaRef, DeclContext *DC, return NewParam; } +NamedDecl *transformTemplateParameter(Sema &SemaRef, DeclContext *DC, + NamedDecl *TemplateParam, + MultiLevelTemplateArgumentList &Args, + unsigned NewIndex, unsigned NewDepth, + bool EvaluateConstraint = true) { + if (auto *TTP = dyn_cast(TemplateParam)) + return transformTemplateTypeParam( + SemaRef, DC, TTP, Args, NewDepth, NewIndex, + /*EvaluateConstraint=*/EvaluateConstraint); + if (auto *TTP = dyn_cast(TemplateParam)) + return transformTemplateParam(SemaRef, DC, TTP, Args, NewIndex, NewDepth); + if (auto *NTTP = dyn_cast(TemplateParam)) + return transformTemplateParam(SemaRef, DC, NTTP, Args, NewIndex, NewDepth); + llvm_unreachable("Unhandled template parameter types"); +} + /// Transform to convert portions of a constructor declaration into the /// corresponding deduction guide, per C++1z [over.match.class.deduct]p1. struct ConvertConstructorToDeductionGuideTransform { @@ -358,7 +374,9 @@ struct ConvertConstructorToDeductionGuideTransform { Args.addOuterRetainedLevel(); if (NestedPattern) Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth()); - NamedDecl *NewParam = transformTemplateParameter(Param, Args); + auto [Depth, Index] = getDepthAndIndex(Param); + NamedDecl *NewParam = transformTemplateParameter( + SemaRef, DC, Param, Args, Index + Depth1IndexAdjustment, Depth - 1); if (!NewParam) return nullptr; // Constraints require that we substitute depth-1 arguments @@ -366,12 +384,11 @@ struct ConvertConstructorToDeductionGuideTransform { Depth1Args.push_back(SemaRef.Context.getInjectedTemplateArg(NewParam)); if (NestedPattern) { - TemplateDeclInstantiator Instantiator(SemaRef, DC, - OuterInstantiationArgs); - Instantiator.setEvaluateConstraints(false); - SemaRef.runWithSufficientStackSpace(NewParam->getLocation(), [&] { - NewParam = cast(Instantiator.Visit(NewParam)); - }); + auto [Depth, Index] = getDepthAndIndex(NewParam); + NewParam = transformTemplateParameter( + SemaRef, DC, NewParam, OuterInstantiationArgs, Index, + Depth - OuterInstantiationArgs.getNumSubstitutedLevels(), + /*EvaluateConstraint=*/false); } assert(NewParam->getTemplateDepth() == 0 && @@ -479,25 +496,6 @@ struct ConvertConstructorToDeductionGuideTransform { } private: - /// Transform a constructor template parameter into a deduction guide template - /// parameter, rebuilding any internal references to earlier parameters and - /// renumbering as we go. - NamedDecl *transformTemplateParameter(NamedDecl *TemplateParam, - MultiLevelTemplateArgumentList &Args) { - if (auto *TTP = dyn_cast(TemplateParam)) - return transformTemplateTypeParam( - SemaRef, DC, TTP, Args, TTP->getDepth() - 1, - Depth1IndexAdjustment + TTP->getIndex()); - if (auto *TTP = dyn_cast(TemplateParam)) - return transformTemplateParam(SemaRef, DC, TTP, Args, - Depth1IndexAdjustment + TTP->getIndex(), - TTP->getDepth() - 1); - auto *NTTP = cast(TemplateParam); - return transformTemplateParam(SemaRef, DC, NTTP, Args, - Depth1IndexAdjustment + NTTP->getIndex(), - NTTP->getDepth() - 1); - } - QualType transformFunctionProtoType( TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, SmallVectorImpl &Params, @@ -634,26 +632,6 @@ struct ConvertConstructorToDeductionGuideTransform { } }; -unsigned getTemplateParameterDepth(NamedDecl *TemplateParam) { - if (auto *TTP = dyn_cast(TemplateParam)) - return TTP->getDepth(); - if (auto *TTP = dyn_cast(TemplateParam)) - return TTP->getDepth(); - if (auto *NTTP = dyn_cast(TemplateParam)) - return NTTP->getDepth(); - llvm_unreachable("Unhandled template parameter types"); -} - -unsigned getTemplateParameterIndex(NamedDecl *TemplateParam) { - if (auto *TTP = dyn_cast(TemplateParam)) - return TTP->getIndex(); - if (auto *TTP = dyn_cast(TemplateParam)) - return TTP->getIndex(); - if (auto *NTTP = dyn_cast(TemplateParam)) - return NTTP->getIndex(); - llvm_unreachable("Unhandled template parameter types"); -} - // Find all template parameters that appear in the given DeducedArgs. // Return the indices of the template parameters in the TemplateParams. SmallVector TemplateParamsReferencedInTemplateArgumentList( @@ -689,8 +667,10 @@ SmallVector TemplateParamsReferencedInTemplateArgumentList( void MarkAppeared(NamedDecl *ND) { if (llvm::isa(ND)) - Mark(getTemplateParameterDepth(ND), getTemplateParameterIndex(ND)); + TemplateTemplateParmDecl>(ND)) { + auto [Depth, Index] = getDepthAndIndex(ND); + Mark(Depth, Index); + } } void Mark(unsigned Depth, unsigned Index) { if (Index < TemplateParamList->size() && @@ -722,20 +702,6 @@ bool hasDeclaredDeductionGuides(DeclarationName Name, DeclContext *DC) { return false; } -NamedDecl *transformTemplateParameter(Sema &SemaRef, DeclContext *DC, - NamedDecl *TemplateParam, - MultiLevelTemplateArgumentList &Args, - unsigned NewIndex, unsigned NewDepth) { - if (auto *TTP = dyn_cast(TemplateParam)) - return transformTemplateTypeParam(SemaRef, DC, TTP, Args, NewDepth, - NewIndex); - if (auto *TTP = dyn_cast(TemplateParam)) - return transformTemplateParam(SemaRef, DC, TTP, Args, NewIndex, NewDepth); - if (auto *NTTP = dyn_cast(TemplateParam)) - return transformTemplateParam(SemaRef, DC, NTTP, Args, NewIndex, NewDepth); - llvm_unreachable("Unhandled template parameter types"); -} - // Build the associated constraints for the alias deduction guides. // C++ [over.match.class.deduct]p3.3: // The associated constraints ([temp.constr.decl]) are the conjunction of the @@ -791,7 +757,7 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, NamedDecl *NewParam = transformTemplateParameter( SemaRef, AliasTemplate->getDeclContext(), TP, Args, /*NewIndex=*/AdjustedAliasTemplateArgs.size(), - getTemplateParameterDepth(TP) + AdjustDepth); + getDepthAndIndex(TP).first + AdjustDepth); TemplateArgument NewTemplateArgument = Context.getInjectedTemplateArg(NewParam); @@ -814,10 +780,10 @@ buildAssociatedConstraints(Sema &SemaRef, FunctionTemplateDecl *F, Args.setKind(TemplateSubstitutionKind::Rewrite); Args.addOuterTemplateArguments(TemplateArgsForBuildingRC); // Rebuild the template parameter with updated depth and index. - NamedDecl *NewParam = transformTemplateParameter( - SemaRef, F->getDeclContext(), TP, Args, - /*NewIndex=*/FirstUndeducedParamIdx, - getTemplateParameterDepth(TP) + AdjustDepth); + NamedDecl *NewParam = + transformTemplateParameter(SemaRef, F->getDeclContext(), TP, Args, + /*NewIndex=*/FirstUndeducedParamIdx, + getDepthAndIndex(TP).first + AdjustDepth); FirstUndeducedParamIdx += 1; assert(TemplateArgsForBuildingRC[Index].isNull()); TemplateArgsForBuildingRC[Index] = @@ -919,7 +885,7 @@ Expr *buildIsDeducibleConstraint(Sema &SemaRef, NamedDecl *NewParam = transformTemplateParameter( SemaRef, AliasTemplate->getDeclContext(), TP, Args, /*NewIndex=*/TransformedTemplateArgs.size(), - getTemplateParameterDepth(TP) + AdjustDepth); + getDepthAndIndex(TP).first + AdjustDepth); TemplateArgument NewTemplateArgument = Context.getInjectedTemplateArg(NewParam); @@ -1081,8 +1047,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, Args.addOuterTemplateArguments(TransformedDeducedAliasArgs); NamedDecl *NewParam = transformTemplateParameter( SemaRef, AliasTemplate->getDeclContext(), TP, Args, - /*NewIndex=*/FPrimeTemplateParams.size(), - getTemplateParameterDepth(TP)); + /*NewIndex=*/FPrimeTemplateParams.size(), getDepthAndIndex(TP).first); FPrimeTemplateParams.push_back(NewParam); TemplateArgument NewTemplateArgument = @@ -1101,7 +1066,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef, Args.addOuterTemplateArguments(TemplateArgsForBuildingFPrime); NamedDecl *NewParam = transformTemplateParameter( SemaRef, F->getDeclContext(), TP, Args, FPrimeTemplateParams.size(), - getTemplateParameterDepth(TP)); + getDepthAndIndex(TP).first); FPrimeTemplateParams.push_back(NewParam); assert(TemplateArgsForBuildingFPrime[FTemplateParamIdx].isNull() && diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index a12d2eff1d2c814..f93cd113988ae42 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -330,7 +330,7 @@ instantiateDependentModeAttr(Sema &S, static void instantiateOMPDeclareSimdDeclAttr( Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const OMPDeclareSimdDeclAttr &Attr, Decl *New) { - // Allow 'this' in clauses with varlists. + // Allow 'this' in clauses with varlist. if (auto *FTD = dyn_cast(New)) New = FTD->getTemplatedDecl(); auto *FD = cast(New); @@ -413,7 +413,7 @@ static void instantiateOMPDeclareSimdDeclAttr( static void instantiateOMPDeclareVariantAttr( Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, const OMPDeclareVariantAttr &Attr, Decl *New) { - // Allow 'this' in clauses with varlists. + // Allow 'this' in clauses with varlist. if (auto *FTD = dyn_cast(New)) New = FTD->getTemplatedDecl(); auto *FD = cast(New); @@ -3588,7 +3588,7 @@ Decl *TemplateDeclInstantiator::VisitUsingPackDecl(UsingPackDecl *D) { Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( OMPThreadPrivateDecl *D) { SmallVector Vars; - for (auto *I : D->varlists()) { + for (auto *I : D->varlist()) { Expr *Var = SemaRef.SubstExpr(I, TemplateArgs).get(); assert(isa(Var) && "threadprivate arg is not a DeclRefExpr"); Vars.push_back(Var); @@ -3605,7 +3605,7 @@ Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( Decl *TemplateDeclInstantiator::VisitOMPAllocateDecl(OMPAllocateDecl *D) { SmallVector Vars; - for (auto *I : D->varlists()) { + for (auto *I : D->varlist()) { Expr *Var = SemaRef.SubstExpr(I, TemplateArgs).get(); assert(isa(Var) && "allocate arg is not a DeclRefExpr"); Vars.push_back(Var); @@ -3782,7 +3782,7 @@ TemplateDeclInstantiator::VisitOMPDeclareMapperDecl(OMPDeclareMapperDecl *D) { for (OMPClause *C : D->clauselists()) { auto *OldC = cast(C); SmallVector NewVars; - for (Expr *OE : OldC->varlists()) { + for (Expr *OE : OldC->varlist()) { Expr *NE = SemaRef.SubstExpr(OE, TemplateArgs).get(); if (!NE) { IsCorrect = false; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 4d68ebf0cc45248..8d3e1edf7a45d4b 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -10309,7 +10309,7 @@ OMPClause *TreeTransform::TransformOMPInitClause(OMPInitClause *C) { OMPInteropInfo InteropInfo(C->getIsTarget(), C->getIsTargetSync()); InteropInfo.PreferTypes.reserve(C->varlist_size() - 1); - for (Expr *E : llvm::drop_begin(C->varlists())) { + for (Expr *E : llvm::drop_begin(C->varlist())) { ExprResult ER = getDerived().TransformExpr(cast(E)); if (ER.isInvalid()) return nullptr; @@ -10447,7 +10447,7 @@ OMPClause * TreeTransform::TransformOMPPrivateClause(OMPPrivateClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -10462,7 +10462,7 @@ OMPClause *TreeTransform::TransformOMPFirstprivateClause( OMPFirstprivateClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -10477,7 +10477,7 @@ OMPClause * TreeTransform::TransformOMPLastprivateClause(OMPLastprivateClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -10493,7 +10493,7 @@ OMPClause * TreeTransform::TransformOMPSharedClause(OMPSharedClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -10508,7 +10508,7 @@ OMPClause * TreeTransform::TransformOMPReductionClause(OMPReductionClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -10555,7 +10555,7 @@ OMPClause *TreeTransform::TransformOMPTaskReductionClause( OMPTaskReductionClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -10601,7 +10601,7 @@ OMPClause * TreeTransform::TransformOMPInReductionClause(OMPInReductionClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -10647,7 +10647,7 @@ OMPClause * TreeTransform::TransformOMPLinearClause(OMPLinearClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -10667,7 +10667,7 @@ OMPClause * TreeTransform::TransformOMPAlignedClause(OMPAlignedClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -10686,7 +10686,7 @@ OMPClause * TreeTransform::TransformOMPCopyinClause(OMPCopyinClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -10701,7 +10701,7 @@ OMPClause * TreeTransform::TransformOMPCopyprivateClause(OMPCopyprivateClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -10715,7 +10715,7 @@ template OMPClause *TreeTransform::TransformOMPFlushClause(OMPFlushClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -10747,7 +10747,7 @@ TreeTransform::TransformOMPDependClause(OMPDependClause *C) { DepModifier = DepModRes.get(); } Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -10778,7 +10778,7 @@ bool transformOMPMappableExprListClause( llvm::SmallVectorImpl &UnresolvedMappers) { // Transform expressions in the list. Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = TT.getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return true; @@ -10858,7 +10858,7 @@ TreeTransform::TransformOMPAllocateClause(OMPAllocateClause *C) { } llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -10990,7 +10990,7 @@ OMPClause *TreeTransform::TransformOMPUseDevicePtrClause( OMPUseDevicePtrClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -11005,7 +11005,7 @@ OMPClause *TreeTransform::TransformOMPUseDeviceAddrClause( OMPUseDeviceAddrClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -11020,7 +11020,7 @@ OMPClause * TreeTransform::TransformOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -11035,7 +11035,7 @@ OMPClause *TreeTransform::TransformOMPHasDeviceAddrClause( OMPHasDeviceAddrClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -11050,7 +11050,7 @@ OMPClause * TreeTransform::TransformOMPNontemporalClause(OMPNontemporalClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -11065,7 +11065,7 @@ OMPClause * TreeTransform::TransformOMPInclusiveClause(OMPInclusiveClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -11080,7 +11080,7 @@ OMPClause * TreeTransform::TransformOMPExclusiveClause(OMPExclusiveClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; @@ -11127,7 +11127,7 @@ TreeTransform::TransformOMPAffinityClause(OMPAffinityClause *C) { if (ModifierRes.isInvalid()) return nullptr; } - for (Expr *E : C->varlists()) { + for (Expr *E : C->varlist()) { ExprResult Locator = getDerived().TransformExpr(E); if (Locator.isInvalid()) continue; @@ -11167,7 +11167,7 @@ OMPClause * TreeTransform::TransformOMPDoacrossClause(OMPDoacrossClause *C) { llvm::SmallVector Vars; Vars.reserve(C->varlist_size()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { ExprResult EVar = getDerived().TransformExpr(cast(VE)); if (EVar.isInvalid()) return nullptr; diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index c78d8943d6d92e5..f0f9d397f1717af 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -7220,7 +7220,7 @@ void OMPClauseWriter::VisitOMPNogroupClause(OMPNogroupClause *) {} void OMPClauseWriter::VisitOMPInitClause(OMPInitClause *C) { Record.push_back(C->varlist_size()); - for (Expr *VE : C->varlists()) + for (Expr *VE : C->varlist()) Record.AddStmt(VE); Record.writeBool(C->getIsTarget()); Record.writeBool(C->getIsTargetSync()); @@ -7266,7 +7266,7 @@ void OMPClauseWriter::VisitOMPAlignClause(OMPAlignClause *C) { void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { Record.AddStmt(VE); } for (auto *VE : C->private_copies()) { @@ -7278,7 +7278,7 @@ void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) { Record.push_back(C->varlist_size()); VisitOMPClauseWithPreInit(C); Record.AddSourceLocation(C->getLParenLoc()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { Record.AddStmt(VE); } for (auto *VE : C->private_copies()) { @@ -7296,7 +7296,7 @@ void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) { Record.writeEnum(C->getKind()); Record.AddSourceLocation(C->getKindLoc()); Record.AddSourceLocation(C->getColonLoc()); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlist()) Record.AddStmt(VE); for (auto *E : C->private_copies()) Record.AddStmt(E); @@ -7311,7 +7311,7 @@ void OMPClauseWriter::VisitOMPLastprivateClause(OMPLastprivateClause *C) { void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlist()) Record.AddStmt(VE); } @@ -7324,7 +7324,7 @@ void OMPClauseWriter::VisitOMPReductionClause(OMPReductionClause *C) { Record.AddSourceLocation(C->getColonLoc()); Record.AddNestedNameSpecifierLoc(C->getQualifierLoc()); Record.AddDeclarationNameInfo(C->getNameInfo()); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlist()) Record.AddStmt(VE); for (auto *VE : C->privates()) Record.AddStmt(VE); @@ -7351,7 +7351,7 @@ void OMPClauseWriter::VisitOMPTaskReductionClause(OMPTaskReductionClause *C) { Record.AddSourceLocation(C->getColonLoc()); Record.AddNestedNameSpecifierLoc(C->getQualifierLoc()); Record.AddDeclarationNameInfo(C->getNameInfo()); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlist()) Record.AddStmt(VE); for (auto *VE : C->privates()) Record.AddStmt(VE); @@ -7370,7 +7370,7 @@ void OMPClauseWriter::VisitOMPInReductionClause(OMPInReductionClause *C) { Record.AddSourceLocation(C->getColonLoc()); Record.AddNestedNameSpecifierLoc(C->getQualifierLoc()); Record.AddDeclarationNameInfo(C->getNameInfo()); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlist()) Record.AddStmt(VE); for (auto *VE : C->privates()) Record.AddStmt(VE); @@ -7391,7 +7391,7 @@ void OMPClauseWriter::VisitOMPLinearClause(OMPLinearClause *C) { Record.AddSourceLocation(C->getColonLoc()); Record.push_back(C->getModifier()); Record.AddSourceLocation(C->getModifierLoc()); - for (auto *VE : C->varlists()) { + for (auto *VE : C->varlist()) { Record.AddStmt(VE); } for (auto *VE : C->privates()) { @@ -7416,7 +7416,7 @@ void OMPClauseWriter::VisitOMPAlignedClause(OMPAlignedClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getColonLoc()); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlist()) Record.AddStmt(VE); Record.AddStmt(C->getAlignment()); } @@ -7424,7 +7424,7 @@ void OMPClauseWriter::VisitOMPAlignedClause(OMPAlignedClause *C) { void OMPClauseWriter::VisitOMPCopyinClause(OMPCopyinClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlist()) Record.AddStmt(VE); for (auto *E : C->source_exprs()) Record.AddStmt(E); @@ -7437,7 +7437,7 @@ void OMPClauseWriter::VisitOMPCopyinClause(OMPCopyinClause *C) { void OMPClauseWriter::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlist()) Record.AddStmt(VE); for (auto *E : C->source_exprs()) Record.AddStmt(E); @@ -7450,7 +7450,7 @@ void OMPClauseWriter::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) { void OMPClauseWriter::VisitOMPFlushClause(OMPFlushClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlist()) Record.AddStmt(VE); } @@ -7468,7 +7468,7 @@ void OMPClauseWriter::VisitOMPDependClause(OMPDependClause *C) { Record.AddSourceLocation(C->getDependencyLoc()); Record.AddSourceLocation(C->getColonLoc()); Record.AddSourceLocation(C->getOmpAllMemoryLoc()); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlist()) Record.AddStmt(VE); for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) Record.AddStmt(C->getLoopData(I)); @@ -7500,7 +7500,7 @@ void OMPClauseWriter::VisitOMPMapClause(OMPMapClause *C) { Record.push_back(C->getMapType()); Record.AddSourceLocation(C->getMapLoc()); Record.AddSourceLocation(C->getColonLoc()); - for (auto *E : C->varlists()) + for (auto *E : C->varlist()) Record.AddStmt(E); for (auto *E : C->mapperlists()) Record.AddStmt(E); @@ -7523,7 +7523,7 @@ void OMPClauseWriter::VisitOMPAllocateClause(OMPAllocateClause *C) { Record.AddSourceLocation(C->getLParenLoc()); Record.AddSourceLocation(C->getColonLoc()); Record.AddStmt(C->getAllocator()); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlist()) Record.AddStmt(VE); } @@ -7596,7 +7596,7 @@ void OMPClauseWriter::VisitOMPToClause(OMPToClause *C) { Record.AddNestedNameSpecifierLoc(C->getMapperQualifierLoc()); Record.AddDeclarationNameInfo(C->getMapperIdInfo()); Record.AddSourceLocation(C->getColonLoc()); - for (auto *E : C->varlists()) + for (auto *E : C->varlist()) Record.AddStmt(E); for (auto *E : C->mapperlists()) Record.AddStmt(E); @@ -7626,7 +7626,7 @@ void OMPClauseWriter::VisitOMPFromClause(OMPFromClause *C) { Record.AddNestedNameSpecifierLoc(C->getMapperQualifierLoc()); Record.AddDeclarationNameInfo(C->getMapperIdInfo()); Record.AddSourceLocation(C->getColonLoc()); - for (auto *E : C->varlists()) + for (auto *E : C->varlist()) Record.AddStmt(E); for (auto *E : C->mapperlists()) Record.AddStmt(E); @@ -7649,7 +7649,7 @@ void OMPClauseWriter::VisitOMPUseDevicePtrClause(OMPUseDevicePtrClause *C) { Record.push_back(C->getTotalComponentListNum()); Record.push_back(C->getTotalComponentsNum()); Record.AddSourceLocation(C->getLParenLoc()); - for (auto *E : C->varlists()) + for (auto *E : C->varlist()) Record.AddStmt(E); for (auto *VE : C->private_copies()) Record.AddStmt(VE); @@ -7673,7 +7673,7 @@ void OMPClauseWriter::VisitOMPUseDeviceAddrClause(OMPUseDeviceAddrClause *C) { Record.push_back(C->getTotalComponentListNum()); Record.push_back(C->getTotalComponentsNum()); Record.AddSourceLocation(C->getLParenLoc()); - for (auto *E : C->varlists()) + for (auto *E : C->varlist()) Record.AddStmt(E); for (auto *D : C->all_decls()) Record.AddDeclRef(D); @@ -7693,7 +7693,7 @@ void OMPClauseWriter::VisitOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) { Record.push_back(C->getTotalComponentListNum()); Record.push_back(C->getTotalComponentsNum()); Record.AddSourceLocation(C->getLParenLoc()); - for (auto *E : C->varlists()) + for (auto *E : C->varlist()) Record.AddStmt(E); for (auto *D : C->all_decls()) Record.AddDeclRef(D); @@ -7713,7 +7713,7 @@ void OMPClauseWriter::VisitOMPHasDeviceAddrClause(OMPHasDeviceAddrClause *C) { Record.push_back(C->getTotalComponentListNum()); Record.push_back(C->getTotalComponentsNum()); Record.AddSourceLocation(C->getLParenLoc()); - for (auto *E : C->varlists()) + for (auto *E : C->varlist()) Record.AddStmt(E); for (auto *D : C->all_decls()) Record.AddDeclRef(D); @@ -7765,7 +7765,7 @@ void OMPClauseWriter::VisitOMPMessageClause(OMPMessageClause *C) { void OMPClauseWriter::VisitOMPNontemporalClause(OMPNontemporalClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlist()) Record.AddStmt(VE); for (auto *E : C->private_refs()) Record.AddStmt(E); @@ -7774,14 +7774,14 @@ void OMPClauseWriter::VisitOMPNontemporalClause(OMPNontemporalClause *C) { void OMPClauseWriter::VisitOMPInclusiveClause(OMPInclusiveClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlist()) Record.AddStmt(VE); } void OMPClauseWriter::VisitOMPExclusiveClause(OMPExclusiveClause *C) { Record.push_back(C->varlist_size()); Record.AddSourceLocation(C->getLParenLoc()); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlist()) Record.AddStmt(VE); } @@ -7810,7 +7810,7 @@ void OMPClauseWriter::VisitOMPAffinityClause(OMPAffinityClause *C) { Record.AddSourceLocation(C->getLParenLoc()); Record.AddStmt(C->getModifier()); Record.AddSourceLocation(C->getColonLoc()); - for (Expr *E : C->varlists()) + for (Expr *E : C->varlist()) Record.AddStmt(E); } @@ -7833,7 +7833,7 @@ void OMPClauseWriter::VisitOMPDoacrossClause(OMPDoacrossClause *C) { Record.push_back(C->getDependenceType()); Record.AddSourceLocation(C->getDependenceLoc()); Record.AddSourceLocation(C->getColonLoc()); - for (auto *VE : C->varlists()) + for (auto *VE : C->varlist()) Record.AddStmt(VE); for (unsigned I = 0, E = C->getNumLoops(); I < E; ++I) Record.AddStmt(C->getLoopData(I)); diff --git a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp index cd1dd1b2fc511fd..4b8e5216550d936 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MmapWriteExecChecker.cpp @@ -21,49 +21,56 @@ #include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h" using namespace clang; using namespace ento; namespace { -class MmapWriteExecChecker : public Checker { +class MmapWriteExecChecker + : public Checker, check::PreCall> { CallDescription MmapFn{CDM::CLibrary, {"mmap"}, 6}; CallDescription MprotectFn{CDM::CLibrary, {"mprotect"}, 3}; - static int ProtWrite; - static int ProtExec; - static int ProtRead; const BugType BT{this, "W^X check fails, Write Exec prot flags set", "Security"}; + // Default values are used if definition of the flags is not found. + mutable int ProtRead = 0x01; + mutable int ProtWrite = 0x02; + mutable int ProtExec = 0x04; + public: + void checkASTDecl(const TranslationUnitDecl *TU, AnalysisManager &Mgr, + BugReporter &BR) const; void checkPreCall(const CallEvent &Call, CheckerContext &C) const; - int ProtExecOv; - int ProtReadOv; }; } -int MmapWriteExecChecker::ProtWrite = 0x02; -int MmapWriteExecChecker::ProtExec = 0x04; -int MmapWriteExecChecker::ProtRead = 0x01; +void MmapWriteExecChecker::checkASTDecl(const TranslationUnitDecl *TU, + AnalysisManager &Mgr, + BugReporter &BR) const { + Preprocessor &PP = Mgr.getPreprocessor(); + const std::optional FoundProtRead = tryExpandAsInteger("PROT_READ", PP); + const std::optional FoundProtWrite = + tryExpandAsInteger("PROT_WRITE", PP); + const std::optional FoundProtExec = tryExpandAsInteger("PROT_EXEC", PP); + if (FoundProtRead && FoundProtWrite && FoundProtExec) { + ProtRead = *FoundProtRead; + ProtWrite = *FoundProtWrite; + ProtExec = *FoundProtExec; + } +} void MmapWriteExecChecker::checkPreCall(const CallEvent &Call, - CheckerContext &C) const { + CheckerContext &C) const { if (matchesAny(Call, MmapFn, MprotectFn)) { SVal ProtVal = Call.getArgSVal(2); auto ProtLoc = ProtVal.getAs(); if (!ProtLoc) return; int64_t Prot = ProtLoc->getValue().getSExtValue(); - if (ProtExecOv != ProtExec) - ProtExec = ProtExecOv; - if (ProtReadOv != ProtRead) - ProtRead = ProtReadOv; - - // Wrong settings - if (ProtRead == ProtExec) - return; - if ((Prot & (ProtWrite | ProtExec)) == (ProtWrite | ProtExec)) { + if ((Prot & ProtWrite) && (Prot & ProtExec)) { ExplodedNode *N = C.generateNonFatalErrorNode(); if (!N) return; @@ -80,17 +87,10 @@ void MmapWriteExecChecker::checkPreCall(const CallEvent &Call, } } -void ento::registerMmapWriteExecChecker(CheckerManager &mgr) { - MmapWriteExecChecker *Mwec = - mgr.registerChecker(); - Mwec->ProtExecOv = - mgr.getAnalyzerOptions() - .getCheckerIntegerOption(Mwec, "MmapProtExec"); - Mwec->ProtReadOv = - mgr.getAnalyzerOptions() - .getCheckerIntegerOption(Mwec, "MmapProtRead"); +void ento::registerMmapWriteExecChecker(CheckerManager &Mgr) { + Mgr.registerChecker(); } -bool ento::shouldRegisterMmapWriteExecChecker(const CheckerManager &mgr) { +bool ento::shouldRegisterMmapWriteExecChecker(const CheckerManager &) { return true; } diff --git a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp index 53770532609d5a6..4454f30630e27c8 100644 --- a/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/StreamChecker.cpp @@ -615,30 +615,22 @@ class StreamChecker : public Checker OptInt = - tryExpandAsInteger("EOF", C.getPreprocessor())) + if (const std::optional OptInt = tryExpandAsInteger("EOF", PP)) EofVal = *OptInt; else EofVal = -1; - if (const std::optional OptInt = - tryExpandAsInteger("SEEK_SET", C.getPreprocessor())) + if (const std::optional OptInt = tryExpandAsInteger("SEEK_SET", PP)) SeekSetVal = *OptInt; - if (const std::optional OptInt = - tryExpandAsInteger("SEEK_END", C.getPreprocessor())) + if (const std::optional OptInt = tryExpandAsInteger("SEEK_END", PP)) SeekEndVal = *OptInt; - if (const std::optional OptInt = - tryExpandAsInteger("SEEK_CUR", C.getPreprocessor())) + if (const std::optional OptInt = tryExpandAsInteger("SEEK_CUR", PP)) SeekCurVal = *OptInt; } - void initVaListType(CheckerContext &C) const { - VaListType = C.getASTContext().getBuiltinVaListType().getCanonicalType(); - } - /// Searches for the ExplodedNode where the file descriptor was acquired for /// StreamSym. static const ExplodedNode *getAcquisitionSite(const ExplodedNode *N, @@ -880,9 +872,6 @@ static ProgramStateRef escapeArgs(ProgramStateRef State, CheckerContext &C, void StreamChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { - initMacroValues(C); - initVaListType(C); - const FnDescription *Desc = lookupFn(Call); if (!Desc || !Desc->PreFn) return; @@ -938,7 +927,6 @@ void StreamChecker::evalFopen(const FnDescription *Desc, const CallEvent &Call, assert(RetSym && "RetVal must be a symbol here."); State = State->BindExpr(CE, C.getLocationContext(), RetVal); - State = assumeNoAliasingWithStdStreams(State, RetVal, C); // Bifurcate the state into two: one with a valid FILE* pointer, the other // with a NULL. @@ -951,6 +939,8 @@ void StreamChecker::evalFopen(const FnDescription *Desc, const CallEvent &Call, StateNull = StateNull->set(RetSym, StreamState::getOpenFailed(Desc)); + StateNotNull = assumeNoAliasingWithStdStreams(StateNotNull, RetVal, C); + C.addTransition(StateNotNull, constructLeakNoteTag(C, RetSym, "Stream opened here")); C.addTransition(StateNull); @@ -2081,10 +2071,12 @@ getGlobalStreamPointerByName(const TranslationUnitDecl *TU, StringRef VarName) { } void StreamChecker::checkASTDecl(const TranslationUnitDecl *TU, - AnalysisManager &, BugReporter &) const { + AnalysisManager &Mgr, BugReporter &) const { StdinDecl = getGlobalStreamPointerByName(TU, "stdin"); StdoutDecl = getGlobalStreamPointerByName(TU, "stdout"); StderrDecl = getGlobalStreamPointerByName(TU, "stderr"); + VaListType = TU->getASTContext().getBuiltinVaListType().getCanonicalType(); + initMacroValues(Mgr.getPreprocessor()); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp index 0e317ec765ec09d..eba224b8ec01ce9 100644 --- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -923,12 +923,31 @@ SVal AnyCXXConstructorCall::getCXXThisVal() const { return UnknownVal(); } +static bool isWithinStdNamespace(const Decl *D) { + const DeclContext *DC = D->getDeclContext(); + while (DC) { + if (const auto *NS = dyn_cast(DC); + NS && NS->isStdNamespace()) + return true; + DC = DC->getParent(); + } + return false; +} + void AnyCXXConstructorCall::getExtraInvalidatedValues(ValueList &Values, RegionAndSymbolInvalidationTraits *ETraits) const { SVal V = getCXXThisVal(); if (SymbolRef Sym = V.getAsSymbol(true)) ETraits->setTrait(Sym, RegionAndSymbolInvalidationTraits::TK_SuppressEscape); + + // Standard classes don't reinterpret-cast and modify super regions. + const bool IsStdClassCtor = isWithinStdNamespace(getDecl()); + if (const MemRegion *Obj = V.getAsRegion(); Obj && IsStdClassCtor) { + ETraits->setTrait( + Obj, RegionAndSymbolInvalidationTraits::TK_DoNotInvalidateSuperRegion); + } + Values.push_back(V); } diff --git a/clang/lib/Tooling/ArgumentsAdjusters.cpp b/clang/lib/Tooling/ArgumentsAdjusters.cpp index df4c74205b0874d..d01c57ee69c0092 100644 --- a/clang/lib/Tooling/ArgumentsAdjusters.cpp +++ b/clang/lib/Tooling/ArgumentsAdjusters.cpp @@ -49,10 +49,11 @@ ArgumentsAdjuster getClangSyntaxOnlyAdjuster() { })) continue; - if (!Arg.starts_with("-fcolor-diagnostics") && + if (Arg != "-c" && Arg != "-S" && + !Arg.starts_with("-fcolor-diagnostics") && !Arg.starts_with("-fdiagnostics-color")) AdjustedArgs.push_back(Args[i]); - // If we strip a color option, make sure we strip any preceeding `-Xclang` + // If we strip an option, make sure we strip any preceeding `-Xclang` // option as well. // FIXME: This should be added to most argument adjusters! else if (!AdjustedArgs.empty() && AdjustedArgs.back() == "-Xclang") diff --git a/clang/test/APINotes/Inputs/Headers/Methods.h b/clang/test/APINotes/Inputs/Headers/Methods.h index 6a96b127628711c..cbb57ccd0afbded 100644 --- a/clang/test/APINotes/Inputs/Headers/Methods.h +++ b/clang/test/APINotes/Inputs/Headers/Methods.h @@ -2,6 +2,8 @@ struct IntWrapper { int value; IntWrapper getIncremented() const { return {value + 1}; } + + IntWrapper operator+(const IntWrapper& RHS) const { return {value + RHS.value}; } }; struct Outer { @@ -9,5 +11,9 @@ struct Outer { int value; Inner getDecremented() const { return {value - 1}; } + + bool operator==(const Inner& RHS) const { + return value == RHS.value; + } }; }; diff --git a/clang/test/AST/Interp/builtin-constant-p.cpp b/clang/test/AST/Interp/builtin-constant-p.cpp new file mode 100644 index 000000000000000..0d222d1c9627785 --- /dev/null +++ b/clang/test/AST/Interp/builtin-constant-p.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s +// RUN: %clang_cc1 -verify=ref,both %s + + +static_assert(__builtin_constant_p(12), ""); +static_assert(__builtin_constant_p(1.0), ""); + +constexpr int I = 100; +static_assert(__builtin_constant_p(I), ""); +static_assert(__builtin_constant_p(I + 10), ""); +static_assert(__builtin_constant_p(I + 10.0), ""); +static_assert(__builtin_constant_p(nullptr), ""); +static_assert(__builtin_constant_p(&I), ""); // both-error {{failed due to requirement}} +static_assert(__builtin_constant_p((void)I), ""); // both-error {{failed due to requirement}} diff --git a/clang/test/AST/Interp/builtins.cpp b/clang/test/AST/Interp/builtins.cpp index a74b68bb9d89bb1..9b2b20773be58a5 100644 --- a/clang/test/AST/Interp/builtins.cpp +++ b/clang/test/AST/Interp/builtins.cpp @@ -31,3 +31,8 @@ constexpr bool assume() { return true; } static_assert(assume(), ""); + +void test_builtin_os_log(void *buf, int i, const char *data) { + constexpr int len = __builtin_os_log_format_buffer_size("%d %{public}s %{private}.16P", i, data, data); + static_assert(len > 0, "Expect len > 0"); +} diff --git a/clang/test/AST/Interp/lifetimes.cpp b/clang/test/AST/Interp/lifetimes.cpp index d47533ab547b368..9fca54fe11120aa 100644 --- a/clang/test/AST/Interp/lifetimes.cpp +++ b/clang/test/AST/Interp/lifetimes.cpp @@ -33,3 +33,30 @@ struct S { constexpr int k1 = S().t; // both-error {{must be initialized by a constant expression}} \ // ref-note {{in call to}} \ // expected-note {{in call to}} + + +namespace MoveFnWorks { + template constexpr T &&ref(T &&t) { return (T&&)t; } + + struct Buf {}; + + struct A { + constexpr A(Buf &buf) : buf(buf) { } + Buf &buf; + }; + + constexpr bool dtor_calls_dtor() { + struct B { + A &&d; + constexpr B(Buf &buf) : d(ref(A(buf))) {} + }; + + Buf buf; + { + B b(buf); + } + + return true; + } + static_assert(dtor_calls_dtor(), ""); +} diff --git a/clang/test/AST/Interp/records.cpp b/clang/test/AST/Interp/records.cpp index 9551630caf3d65e..479c0487fecae00 100644 --- a/clang/test/AST/Interp/records.cpp +++ b/clang/test/AST/Interp/records.cpp @@ -1560,3 +1560,19 @@ namespace ArrayInitChain { static_assert(A[1].Width == 12, ""); static_assert(A[1].Mask == 13, ""); } + +#if __cplusplus >= 202002L +namespace ctorOverrider { + // Ensure that we pick the right final overrider during construction. + struct A { + virtual constexpr char f() const { return 'A'; } + char a = f(); + }; + + struct Covariant1 { + A d; + }; + + constexpr Covariant1 cb; +} +#endif diff --git a/clang/test/AST/attr-print-emit.cpp b/clang/test/AST/attr-print-emit.cpp index 8c8a2b20805993d..d8e62ed5f6cd11f 100644 --- a/clang/test/AST/attr-print-emit.cpp +++ b/clang/test/AST/attr-print-emit.cpp @@ -32,8 +32,8 @@ int *aa(int i) __attribute__((alloc_align(1))); void ownt(int *, int *) __attribute__((ownership_takes(foo, 1, 2))); // CHECK: void ownh(int *, int *) __attribute__((ownership_holds(foo, 1, 2))); void ownh(int *, int *) __attribute__((ownership_holds(foo, 1, 2))); -// CHECK: void ownr(int) __attribute__((ownership_returns(foo, 1))); -void ownr(int) __attribute__((ownership_returns(foo, 1))); +// CHECK: void *ownr(int) __attribute__((ownership_returns(foo, 1))); +void *ownr(int) __attribute__((ownership_returns(foo, 1))); // CHECK: void awtt(int, int, ...) __attribute__((argument_with_type_tag(foo, 3, 2))); void awtt(int, int, ...) __attribute__((argument_with_type_tag(foo, 3, 2))); @@ -65,8 +65,8 @@ class C { void ownt(int *, int *) __attribute__((ownership_takes(foo, 2, 3))); // CHECK: void ownh(int *, int *) __attribute__((ownership_holds(foo, 2, 3))); void ownh(int *, int *) __attribute__((ownership_holds(foo, 2, 3))); - // CHECK: void ownr(int) __attribute__((ownership_returns(foo, 2))); - void ownr(int) __attribute__((ownership_returns(foo, 2))); + // CHECK: void *ownr(int) __attribute__((ownership_returns(foo, 2))); + void *ownr(int) __attribute__((ownership_returns(foo, 2))); // CHECK: void awtt(int, int, ...) __attribute__((argument_with_type_tag(foo, 4, 3))); void awtt(int, int, ...) __attribute__((argument_with_type_tag(foo, 4, 3))); diff --git a/clang/test/AST/explicit-base-class-move-cntr.cpp b/clang/test/AST/explicit-base-class-move-cntr.cpp new file mode 100644 index 000000000000000..808af2fc94336f0 --- /dev/null +++ b/clang/test/AST/explicit-base-class-move-cntr.cpp @@ -0,0 +1,171 @@ +// RUN: %clang_cc1 -ast-dump=json %s | FileCheck -strict-whitespace %s + +struct ExplicitBase { + explicit ExplicitBase(const char *) { } + ExplicitBase(const ExplicitBase &) {} + ExplicitBase(ExplicitBase &&) {} + ExplicitBase &operator=(const ExplicitBase &) { return *this; } + ExplicitBase &operator=(ExplicitBase &&) { return *this; } + ~ExplicitBase() { } +}; + +struct Derived1 : ExplicitBase {}; + +Derived1 makeDerived1() { +// CHECK: "kind": "FunctionDecl", +// CHECK: "name": "makeDerived1", + +// CHECK: "kind": "CompoundStmt", + +// CHECK: "kind": "ReturnStmt", +// CHECK: "kind": "ExprWithCleanups", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "Derived1" +// CHECK-NEXT: }, + +// CHECK: "kind": "CXXFunctionalCastExpr", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "Derived1" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "prvalue", +// CHECK-NEXT: "castKind": "NoOp", + +// CHECK: "kind": "CXXBindTemporaryExpr", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "Derived1" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "prvalue", + +// CHECK: "kind": "InitListExpr", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "Derived1" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "prvalue", + +// CHECK: "kind": "CXXConstructExpr", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "ExplicitBase" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "prvalue", +// CHECK-NEXT: "ctorType": { +// CHECK-NEXT: "qualType": "void (ExplicitBase &&)" +// CHECK-NEXT: }, +// CHECK-NEXT: "hadMultipleCandidates": true, +// CHECK-NEXT: "constructionKind": "non-virtual base", + +// CHECK: "kind": "MaterializeTemporaryExpr", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "ExplicitBase" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "xvalue", +// CHECK-NEXT: "storageDuration": "full expression", + +// CHECK: "kind": "CXXBindTemporaryExpr", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "ExplicitBase" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "prvalue", + +// CHECK: "kind": "CXXTemporaryObjectExpr", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "ExplicitBase" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "prvalue", +// CHECK-NEXT: "ctorType": { +// CHECK-NEXT: "qualType": "void (const char *)" +// CHECK-NEXT: }, +// CHECK-NEXT: "list": true, +// CHECK-NEXT: "hadMultipleCandidates": true, +// CHECK-NEXT: "constructionKind": "complete", + +// CHECK: "kind": "ImplicitCastExpr", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "const char *" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "prvalue", +// CHECK-NEXT: "castKind": "ArrayToPointerDecay", + +// CHECK: "kind": "StringLiteral", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "const char[10]" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "lvalue", +// CHECK-NEXT: "value": "\"Move Ctor\"" + return Derived1{ExplicitBase{"Move Ctor"}}; +} + +struct ImplicitBase { + ImplicitBase(const char *) { } + ImplicitBase(const ImplicitBase &) {} + ImplicitBase(ImplicitBase &&) {} + ImplicitBase &operator=(const ImplicitBase &) { return *this; } + ImplicitBase &operator=(ImplicitBase &&) { return *this; } + ~ImplicitBase() { } +}; + +struct Derived2 : ImplicitBase {}; + +Derived2 makeDerived2() { +// CHECK: "kind": "FunctionDecl", +// CHECK: "name": "makeDerived2", + +// CHECK: "kind": "CompoundStmt", + +// CHECK: "kind": "ReturnStmt", + +// CHECK: "kind": "ExprWithCleanups", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "Derived2" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "prvalue", +// CHECK-NEXT: "cleanupsHaveSideEffects": true, + +// CHECK: "kind": "CXXFunctionalCastExpr", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "Derived2" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "prvalue", +// CHECK-NEXT: "castKind": "NoOp", + +// CHECK: "kind": "CXXBindTemporaryExpr", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "Derived2" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "prvalue", + +// CHECK: "kind": "InitListExpr", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "Derived2" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "prvalue", + +// CHECK: "kind": "CXXConstructExpr", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "ImplicitBase" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "prvalue", +// CHECK-NEXT: "ctorType": { +// CHECK-NEXT: "qualType": "void (const char *)" +// CHECK-NEXT: }, +// CHECK-NEXT: "list": true, +// CHECK-NEXT: "hadMultipleCandidates": true, +// CHECK-NEXT: "constructionKind": "non-virtual base", + +// CHECK: "kind": "ImplicitCastExpr", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "const char *" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "prvalue", +// CHECK-NEXT: "castKind": "ArrayToPointerDecay", + +// CHECK: "kind": "StringLiteral", +// CHECK: "type": { +// CHECK-NEXT: "qualType": "const char[8]" +// CHECK-NEXT: }, +// CHECK-NEXT: "valueCategory": "lvalue", +// CHECK-NEXT: "value": "\"No Ctor\"" + return Derived2{{"No Ctor"}}; +} + +// NOTE: CHECK lines have been autogenerated by gen_ast_dump_json_test.py +// using --filters=FunctionDecl,CompoundStmt,ReturnStmt,MaterializeTemporaryExpr,CXXBindTemporaryExpr,CXXTemporaryObjectExpr,ImplicitCastExpr,StringLiteralStringLiteral diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c index 2a4c40005a4dc0c..b8dbcdd7e55afe4 100644 --- a/clang/test/Analysis/analyzer-config.c +++ b/clang/test/Analysis/analyzer-config.c @@ -9,8 +9,6 @@ // CHECK-NEXT: alpha.clone.CloneChecker:ReportNormalClones = true // CHECK-NEXT: alpha.cplusplus.STLAlgorithmModeling:AggressiveStdFindModeling = false // CHECK-NEXT: alpha.osx.cocoa.DirectIvarAssignment:AnnotatedFunctions = false -// CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtExec = 0x04 -// CHECK-NEXT: alpha.security.MmapWriteExec:MmapProtRead = 0x01 // CHECK-NEXT: alpha.security.taint.TaintPropagation:Config = "" // CHECK-NEXT: apply-fixits = false // CHECK-NEXT: assume-controlled-environment = false diff --git a/clang/test/Analysis/call-invalidation.cpp b/clang/test/Analysis/call-invalidation.cpp index 727217f228b0542..fb2b892b31a1f73 100644 --- a/clang/test/Analysis/call-invalidation.cpp +++ b/clang/test/Analysis/call-invalidation.cpp @@ -1,5 +1,6 @@ // RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify -analyzer-config eagerly-assume=false %s +template void clang_analyzer_dump(T); void clang_analyzer_eval(bool); void usePointer(int * const *); @@ -165,3 +166,117 @@ void testMixedConstNonConstCalls() { useFirstNonConstSecondConst(&(s2.x), &(s2.y)); clang_analyzer_eval(s2.y == 1); // expected-warning{{UNKNOWN}} } + +namespace std { +class Opaque { +public: + Opaque(); + int nested_member; +}; +} // namespace std + +struct StdWrappingOpaque { + std::Opaque o; // first member + int uninit; +}; +struct StdWrappingOpaqueSwapped { + int uninit; // first member + std::Opaque o; +}; + +int testStdCtorDoesNotInvalidateParentObject() { + StdWrappingOpaque obj; + int x = obj.o.nested_member; // no-garbage: std::Opaque::ctor might initialized this + int y = obj.uninit; // FIXME: We should have a garbage read here. Read the details. + // As the first member ("obj.o") is invalidated, a conjured default binding is bound + // to the offset 0 within cluster "obj", and this masks every uninitialized fields + // that follows. We need a better store with extents to fix this. + return x + y; +} + +int testStdCtorDoesNotInvalidateParentObjectSwapped() { + StdWrappingOpaqueSwapped obj; + int x = obj.o.nested_member; // no-garbage: std::Opaque::ctor might initialized this + int y = obj.uninit; // expected-warning {{Assigned value is garbage or undefined}} + return x + y; +} + +class UserProvidedOpaque { +public: + UserProvidedOpaque(); // might reinterpret_cast(this) + int nested_member; +}; + +struct WrappingUserProvidedOpaque { + UserProvidedOpaque o; // first member + int uninit; +}; +struct WrappingUserProvidedOpaqueSwapped { + int uninit; // first member + UserProvidedOpaque o; +}; + +int testUserProvidedCtorInvalidatesParentObject() { + WrappingUserProvidedOpaque obj; + int x = obj.o.nested_member; // no-garbage: UserProvidedOpaque::ctor might initialized this + int y = obj.uninit; // no-garbage: UserProvidedOpaque::ctor might reinterpret_cast(this) and write to the "uninit" member. + return x + y; +} + +int testUserProvidedCtorInvalidatesParentObjectSwapped() { + WrappingUserProvidedOpaqueSwapped obj; + int x = obj.o.nested_member; // no-garbage: same as above + int y = obj.uninit; // no-garbage: same as above + return x + y; +} + +struct WrappingStdWrappingOpaqueOuterInits { + int first = 1; + std::Opaque second; + int third = 3; + WrappingStdWrappingOpaqueOuterInits() { + clang_analyzer_dump(first); // expected-warning {{1 S32b}} + clang_analyzer_dump(second.nested_member); // expected-warning {{derived_}} + clang_analyzer_dump(third); // expected-warning {{3 S32b}} + } +}; + +struct WrappingUserProvidedOpaqueOuterInits { + int first = 1; // Potentially overwritten by UserProvidedOpaque::ctor + UserProvidedOpaque second; // Invalidates the object so far. + int third = 3; // Happens after UserProvidedOpaque::ctor, thus preserved! + WrappingUserProvidedOpaqueOuterInits() { + clang_analyzer_dump(first); // expected-warning {{derived_}} + clang_analyzer_dump(second.nested_member); // expected-warning {{derived_}} + clang_analyzer_dump(third); // expected-warning {{3 S32b}} + } +}; + +extern "C++" { +namespace std { +inline namespace v1 { +namespace custom_ranges { +struct Fancy { +struct iterator { +struct Opaque { + Opaque(); + int nested_member; +}; // struct Opaque +}; // struct iterator +}; // struct Fancy +} // namespace custom_ranges +} // namespace v1 +} // namespace std +} // extern "C++" + +struct StdWrappingFancyOpaque { + int uninit; + std::custom_ranges::Fancy::iterator::Opaque o; +}; + +int testNestedStdNamespacesAndRecords() { + StdWrappingFancyOpaque obj; + int x = obj.o.nested_member; // no-garbage: ctor + int y = obj.uninit; // expected-warning {{Assigned value is garbage or undefined}} + return x + y; +} diff --git a/clang/test/Analysis/ctor-array.cpp b/clang/test/Analysis/ctor-array.cpp index 053669cc2aada2e..49412ee5a68c708 100644 --- a/clang/test/Analysis/ctor-array.cpp +++ b/clang/test/Analysis/ctor-array.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-disable-checker=cplusplus -analyzer-config c++-inlining=constructors -verify %s +// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config c++-inlining=constructors -verify %s #include "Inputs/system-header-simulator-cxx.h" @@ -119,16 +119,6 @@ struct s5 { }; void g1(void) { - // FIXME: This test requires -analyzer-disable-checker=cplusplus, - // because of the checker's weird behaviour in case of arrays. - // E.g.: - // s3 *arr = new s3[4]; - // s3 *arr2 = new (arr + 1) s3[1]; - // ^~~~~~~~~~~~~~~~~~~ - // warning: 12 bytes is possibly not enough - // for array allocation which requires - // 4 bytes. - s5::c = 0; s5 *arr = new s5[4]; new (arr + 1) s5[3]; diff --git a/clang/test/Analysis/ctor.mm b/clang/test/Analysis/ctor.mm index fb385833df9c769..6ac9050fc29f70e 100644 --- a/clang/test/Analysis/ctor.mm +++ b/clang/test/Analysis/ctor.mm @@ -56,8 +56,6 @@ void testNonPODCopyConstructor() { namespace ConstructorVirtualCalls { class A { public: - int *out1, *out2, *out3; - virtual int get() { return 1; } A(int *out1) { diff --git a/clang/test/Analysis/live-stmts.cpp b/clang/test/Analysis/live-stmts.cpp index 16954f30129f78f..c60f522588e3929 100644 --- a/clang/test/Analysis/live-stmts.cpp +++ b/clang/test/Analysis/live-stmts.cpp @@ -193,3 +193,112 @@ void test_lambda_refcapture() { // CHECK-NEXT: [ B2 (live expressions at block exit) ] // CHECK-EMPTY: // CHECK-EMPTY: + +int logicalOpInTernary(bool b) { + return (b || b) ? 0 : 1; +} + +// [B6 (ENTRY)] +// | +// V +// [B5 (b || ...)] +// | \ +// | | +// V V +// [B4 (b||b)] ? [B2 (0)] : [B3 (1)] +// \ / +// ---|---- +// V +// [B1] --> [B0 (EXIT)] +// return + +// CHECK: [ B0 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK-EMPTY: +// CHECK: [ B1 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK-EMPTY: +// CHECK: [ B2 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK: ImplicitCastExpr {{.*}} '_Bool' +// CHECK: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK: ImplicitCastExpr {{.*}} '_Bool' +// CHECK: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK: BinaryOperator {{.*}} '_Bool' '||' +// CHECK: |-ImplicitCastExpr {{.*}} '_Bool' +// CHECK: | `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK: `-ImplicitCastExpr {{.*}} '_Bool' +// CHECK: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK: IntegerLiteral {{.*}} 'int' 0 +// CHECK-EMPTY: +// CHECK: IntegerLiteral {{.*}} 'int' 1 +// CHECK-EMPTY: +// CHECK-EMPTY: +// CHECK: [ B3 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK: ImplicitCastExpr {{.*}} '_Bool' +// CHECK: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK: ImplicitCastExpr {{.*}} '_Bool' +// CHECK: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK: BinaryOperator {{.*}} '_Bool' '||' +// CHECK: |-ImplicitCastExpr {{.*}} '_Bool' +// CHECK: | `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK: `-ImplicitCastExpr {{.*}} '_Bool' +// CHECK: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK: IntegerLiteral {{.*}} 'int' 0 +// CHECK-EMPTY: +// CHECK: IntegerLiteral {{.*}} 'int' 1 +// CHECK-EMPTY: +// CHECK-EMPTY: +// CHECK: [ B4 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK: ImplicitCastExpr {{.*}} '_Bool' +// CHECK: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK: ImplicitCastExpr {{.*}} '_Bool' +// CHECK: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK: BinaryOperator {{.*}} '_Bool' '||' +// CHECK: |-ImplicitCastExpr {{.*}} '_Bool' +// CHECK: | `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK: `-ImplicitCastExpr {{.*}} '_Bool' +// CHECK: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK: IntegerLiteral {{.*}} 'int' 0 +// CHECK-EMPTY: +// CHECK: IntegerLiteral {{.*}} 'int' 1 +// CHECK-EMPTY: +// CHECK-EMPTY: +// CHECK: [ B5 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK: ImplicitCastExpr {{.*}} '_Bool' +// CHECK: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK: ImplicitCastExpr {{.*}} '_Bool' +// CHECK: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK: BinaryOperator {{.*}} '_Bool' '||' +// CHECK: |-ImplicitCastExpr {{.*}} '_Bool' +// CHECK: | `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK: `-ImplicitCastExpr {{.*}} '_Bool' +// CHECK: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK: IntegerLiteral {{.*}} 'int' 0 +// CHECK-EMPTY: +// CHECK: IntegerLiteral {{.*}} 'int' 1 +// CHECK-EMPTY: +// CHECK-EMPTY: +// CHECK: [ B6 (live expressions at block exit) ] +// CHECK-EMPTY: +// CHECK: ImplicitCastExpr {{.*}} '_Bool' +// CHECK: `-DeclRefExpr {{.*}} '_Bool' lvalue ParmVar {{.*}} 'b' '_Bool' +// CHECK-EMPTY: +// CHECK: IntegerLiteral {{.*}} 'int' 0 +// CHECK-EMPTY: +// CHECK: IntegerLiteral {{.*}} 'int' 1 diff --git a/clang/test/Analysis/mmap-writeexec.c b/clang/test/Analysis/mmap-writeexec.c index 8fd86ceb9d2a255..579cc75069eec77 100644 --- a/clang/test/Analysis/mmap-writeexec.c +++ b/clang/test/Analysis/mmap-writeexec.c @@ -1,13 +1,14 @@ -// RUN: %clang_analyze_cc1 -triple i686-unknown-linux -analyzer-checker=alpha.security.MmapWriteExec -analyzer-config alpha.security.MmapWriteExec:MmapProtExec=1 -analyzer-config alpha.security.MmapWriteExec:MmapProtRead=4 -DUSE_ALTERNATIVE_PROT_EXEC_DEFINITION -verify %s +// RUN: %clang_analyze_cc1 -triple i686-unknown-linux -analyzer-checker=alpha.security.MmapWriteExec -DUSE_ALTERNATIVE_PROT_EXEC_DEFINITION -verify %s // RUN: %clang_analyze_cc1 -triple x86_64-unknown-apple-darwin10 -analyzer-checker=alpha.security.MmapWriteExec -verify %s -#define PROT_WRITE 0x02 #ifndef USE_ALTERNATIVE_PROT_EXEC_DEFINITION -#define PROT_EXEC 0x04 -#define PROT_READ 0x01 -#else #define PROT_EXEC 0x01 +#define PROT_WRITE 0x02 #define PROT_READ 0x04 +#else +#define PROT_EXEC 0x08 +#define PROT_WRITE 0x04 +#define PROT_READ 0x02 #endif #define MAP_PRIVATE 0x0002 #define MAP_ANON 0x1000 diff --git a/clang/test/Analysis/short-circuiting-eval.cpp b/clang/test/Analysis/short-circuiting-eval.cpp new file mode 100644 index 000000000000000..d0f29a849ab1ca6 --- /dev/null +++ b/clang/test/Analysis/short-circuiting-eval.cpp @@ -0,0 +1,39 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core.DivideZero -verify %s + +int div0LogicalOpInTernary(bool b1) { + int y = (b1 || b1) ? 0 : 1; + return 1 / y; // expected-warning {{Division by zero}} +} + +int div0LogicalAndArith(bool b1, int x) { + int y = (b1 || (x < 3)) ? 0 : 1; + return 1 / y; // expected-warning {{Division by zero}} +} + +int div0NestedLogicalOp(bool b1) { + int y = (b1 && b1 || b1 && b1) ? 0 : 1; + return 1 / y; // expected-warning {{Division by zero}} +} + +int div0TernaryInTernary(bool b) { + int y = ((b || b) ? false : true) ? 0 : 1; + return 1 / y; // expected-warning {{Division by zero}} +} + +int div0LogicalOpParensInTernary(bool b1) { + int y = ((((b1)) || ((b1)))) ? 0 : 1; + return 1 / y; // expected-warning {{Division by zero}} +} + +int div0LogicalOpInsideStExpr(bool b1) { + int y = ({1; (b1 || b1);}) ? 0 : 1; + // expected-warning@-1 {{expression result unused}} + return 1 / y; // expected-warning {{Division by zero}} +} + +int div0StExprInsideLogicalOp(bool b1) { + int y = (({1; b1;}) || ({1; b1;})) ? 0 : 1; + // expected-warning@-1 {{expression result unused}} + // expected-warning@-2 {{expression result unused}} + return 1 / y; // expected-warning {{Division by zero}} +} diff --git a/clang/test/Analysis/stream.c b/clang/test/Analysis/stream.c index b3a47ce4153d364..b9a5b1ba8cd4948 100644 --- a/clang/test/Analysis/stream.c +++ b/clang/test/Analysis/stream.c @@ -1,11 +1,11 @@ // RUN: %clang_analyze_cc1 -triple=x86_64-pc-linux-gnu -analyzer-checker=core,unix.Stream,debug.ExprInspection \ -// RUN: -analyzer-config unix.Stream:Pedantic=true -verify %s +// RUN: -analyzer-config eagerly-assume=false,unix.Stream:Pedantic=true -verify %s // RUN: %clang_analyze_cc1 -triple=armv8-none-linux-eabi -analyzer-checker=core,unix.Stream,debug.ExprInspection \ -// RUN: -analyzer-config unix.Stream:Pedantic=true -verify %s +// RUN: -analyzer-config eagerly-assume=false,unix.Stream:Pedantic=true -verify %s // RUN: %clang_analyze_cc1 -triple=aarch64-linux-gnu -analyzer-checker=core,unix.Stream,debug.ExprInspection \ -// RUN: -analyzer-config unix.Stream:Pedantic=true -verify %s +// RUN: -analyzer-config eagerly-assume=false,unix.Stream:Pedantic=true -verify %s // RUN: %clang_analyze_cc1 -triple=hexagon -analyzer-checker=core,unix.Stream,debug.ExprInspection \ -// RUN: -analyzer-config unix.Stream:Pedantic=true -verify %s +// RUN: -analyzer-config eagerly-assume=false,unix.Stream:Pedantic=true -verify %s #include "Inputs/system-header-simulator.h" #include "Inputs/system-header-simulator-for-malloc.h" @@ -499,14 +499,34 @@ void gh_93408_regression_ZeroSized(struct ZeroSized *buffer) { fclose(f); } -extern FILE *stdout_like_ptr; -void no_aliasing(void) { +extern FILE *non_standard_stream_ptr; +void test_fopen_does_not_alias_with_standard_streams(void) { FILE *f = fopen("file", "r"); - clang_analyzer_eval(f == stdin); // expected-warning {{FALSE}} no-TRUE - clang_analyzer_eval(f == stdout); // expected-warning {{FALSE}} no-TRUE - clang_analyzer_eval(f == stderr); // expected-warning {{FALSE}} no-TRUE - clang_analyzer_eval(f == stdout_like_ptr); // expected-warning {{FALSE}} expected-warning {{TRUE}} - if (f && f != stdout) { + if (!f) return; + clang_analyzer_eval(f == stdin); // expected-warning {{FALSE}} no-TRUE + clang_analyzer_eval(f == stdout); // expected-warning {{FALSE}} no-TRUE + clang_analyzer_eval(f == stderr); // expected-warning {{FALSE}} no-TRUE + clang_analyzer_eval(f == non_standard_stream_ptr); // expected-warning {{UNKNOWN}} + if (f != stdout) { fclose(f); } } // no-leak: 'fclose()' is always called because 'f' cannot be 'stdout'. + +void reopen_std_stream(void) { + FILE *oldStdout = stdout; + fclose(stdout); + FILE *fp = fopen("blah", "w"); + if (!fp) return; + + stdout = fp; // Let's make them alias. + clang_analyzer_eval(fp == oldStdout); // expected-warning {{UNKNOWN}} + clang_analyzer_eval(fp == stdout); // expected-warning {{TRUE}} no-FALSE + clang_analyzer_eval(oldStdout == stdout); // expected-warning {{UNKNOWN}} +} + +void only_success_path_does_not_alias_with_stdout(void) { + if (stdout) return; + FILE *f = fopen("/tmp/foof", "r"); // no-crash + if (!f) return; + fclose(f); +} diff --git a/clang/test/CXX/dcl.decl/dcl.meaning/dcl.mptr/p2.cpp b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.mptr/p2.cpp new file mode 100644 index 000000000000000..a06b10775559682 --- /dev/null +++ b/clang/test/CXX/dcl.decl/dcl.meaning/dcl.mptr/p2.cpp @@ -0,0 +1,64 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s + +template +struct A0 { + struct B0; + + template + struct C0 { + struct D0; + + template + struct E0; + }; +}; + +template +int A0::B0::* f0(); + +template +int A0::B1::* f1(); + +template +int A0::C0::* f2(); // expected-error {{expected unqualified-id}} + +template +int A0::C1::* f3(); // expected-error {{no member named 'C1' in 'A0'}} + // expected-error@-1 {{expected ';' after top level declarator}} + +template +int A0::template C2::* f4(); + +template +int A0::template C0::D0::* f5(); + +template +int A0::template C2::D1::* f6(); + +template +int A0::template C0::E0::* f7(); // expected-error {{use 'template' keyword to treat 'E0' as a dependent template name}} + // expected-error@-1 {{expected unqualified-id}} + +template +int A0::template C2::E1::* f8(); // expected-error {{no member named 'C2' in 'A0'}} + +template +int A0::template C0::template E0::* f9(); + +template +int A0::template C2::template E1::* f10(); + +namespace TypoCorrection { + template + struct A { + template + struct Typo; // expected-note {{'Typo' declared here}} + }; + + template + int A::template typo::* f(); + + template + int A::typo::* g(); // expected-error {{no template named 'typo' in 'A'; did you mean 'Typo'?}} + // expected-error@-1 {{expected unqualified-id}} +} diff --git a/clang/test/CXX/temp/temp.res/p3.cpp b/clang/test/CXX/temp/temp.res/p3.cpp index 37ab93559e36903..1eda967523a59ca 100644 --- a/clang/test/CXX/temp/temp.res/p3.cpp +++ b/clang/test/CXX/temp/temp.res/p3.cpp @@ -2,7 +2,7 @@ template struct A { template struct B; - template using C = U; // expected-note {{here}} + template using C = U; }; struct X { @@ -20,12 +20,10 @@ template A::C f2(); // expected-warning {{missing 'typename'}} template A::C::X(T) {} template A::C::X::Y::Y(T) {} -// FIXME: This is ill-formed -template int A::B::*f3() {} -template int A::C::*f4() {} +template int A::B::*f3() {} // expected-error {{expected unqualified-id}} +template int A::C::*f4() {} // expected-error {{expected unqualified-id}} -// FIXME: This is valid -template int A::template C::*f5() {} // expected-error {{has no members}} +template int A::template C::*f5() {} template template struct A::B { friend A::C f6(); // ok, same as 'friend T f6();' diff --git a/clang/test/CodeGen/AMDGPU/amdgpu-atomic-float.c b/clang/test/CodeGen/AMDGPU/amdgpu-atomic-float.c new file mode 100644 index 000000000000000..6deff1116e1d818 --- /dev/null +++ b/clang/test/CodeGen/AMDGPU/amdgpu-atomic-float.c @@ -0,0 +1,316 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// RUN: %clang_cc1 -fnative-half-arguments-and-returns -triple amdgcn-amd-amdhsa-gnu -target-cpu gfx900 -emit-llvm -o - %s | FileCheck -check-prefixes=CHECK,SAFE %s +// RUN: %clang_cc1 -fnative-half-arguments-and-returns -triple amdgcn-amd-amdhsa-gnu -target-cpu gfx900 -emit-llvm -munsafe-fp-atomics -o - %s | FileCheck -check-prefixes=CHECK,UNSAFE %s + +// SAFE-LABEL: define dso_local float @test_float_post_inc( +// SAFE-SAME: ) #[[ATTR0:[0-9]+]] { +// SAFE-NEXT: [[ENTRY:.*:]] +// SAFE-NEXT: [[RETVAL:%.*]] = alloca float, align 4, addrspace(5) +// SAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// SAFE-NEXT: [[TMP0:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @test_float_post_inc.n to ptr), float 1.000000e+00 seq_cst, align 4 +// SAFE-NEXT: ret float [[TMP0]] +// +// UNSAFE-LABEL: define dso_local float @test_float_post_inc( +// UNSAFE-SAME: ) #[[ATTR0:[0-9]+]] { +// UNSAFE-NEXT: [[ENTRY:.*:]] +// UNSAFE-NEXT: [[RETVAL:%.*]] = alloca float, align 4, addrspace(5) +// UNSAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// UNSAFE-NEXT: [[TMP0:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @test_float_post_inc.n to ptr), float 1.000000e+00 seq_cst, align 4, !amdgpu.no.fine.grained.memory [[META3:![0-9]+]], !amdgpu.ignore.denormal.mode [[META3]] +// UNSAFE-NEXT: ret float [[TMP0]] +// +float test_float_post_inc() +{ + static _Atomic float n; + return n++; +} + +// SAFE-LABEL: define dso_local float @test_float_post_dc( +// SAFE-SAME: ) #[[ATTR0]] { +// SAFE-NEXT: [[ENTRY:.*:]] +// SAFE-NEXT: [[RETVAL:%.*]] = alloca float, align 4, addrspace(5) +// SAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// SAFE-NEXT: [[TMP0:%.*]] = atomicrmw fsub ptr addrspacecast (ptr addrspace(1) @test_float_post_dc.n to ptr), float 1.000000e+00 seq_cst, align 4 +// SAFE-NEXT: ret float [[TMP0]] +// +// UNSAFE-LABEL: define dso_local float @test_float_post_dc( +// UNSAFE-SAME: ) #[[ATTR0]] { +// UNSAFE-NEXT: [[ENTRY:.*:]] +// UNSAFE-NEXT: [[RETVAL:%.*]] = alloca float, align 4, addrspace(5) +// UNSAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// UNSAFE-NEXT: [[TMP0:%.*]] = atomicrmw fsub ptr addrspacecast (ptr addrspace(1) @test_float_post_dc.n to ptr), float 1.000000e+00 seq_cst, align 4, !amdgpu.no.fine.grained.memory [[META3]] +// UNSAFE-NEXT: ret float [[TMP0]] +// +float test_float_post_dc() +{ + static _Atomic float n; + return n--; +} + +// SAFE-LABEL: define dso_local float @test_float_pre_dc( +// SAFE-SAME: ) #[[ATTR0]] { +// SAFE-NEXT: [[ENTRY:.*:]] +// SAFE-NEXT: [[RETVAL:%.*]] = alloca float, align 4, addrspace(5) +// SAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// SAFE-NEXT: [[TMP0:%.*]] = atomicrmw fsub ptr addrspacecast (ptr addrspace(1) @test_float_pre_dc.n to ptr), float 1.000000e+00 seq_cst, align 4 +// SAFE-NEXT: [[TMP1:%.*]] = fsub float [[TMP0]], 1.000000e+00 +// SAFE-NEXT: ret float [[TMP1]] +// +// UNSAFE-LABEL: define dso_local float @test_float_pre_dc( +// UNSAFE-SAME: ) #[[ATTR0]] { +// UNSAFE-NEXT: [[ENTRY:.*:]] +// UNSAFE-NEXT: [[RETVAL:%.*]] = alloca float, align 4, addrspace(5) +// UNSAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// UNSAFE-NEXT: [[TMP0:%.*]] = atomicrmw fsub ptr addrspacecast (ptr addrspace(1) @test_float_pre_dc.n to ptr), float 1.000000e+00 seq_cst, align 4, !amdgpu.no.fine.grained.memory [[META3]] +// UNSAFE-NEXT: [[TMP1:%.*]] = fsub float [[TMP0]], 1.000000e+00 +// UNSAFE-NEXT: ret float [[TMP1]] +// +float test_float_pre_dc() +{ + static _Atomic float n; + return --n; +} + +// SAFE-LABEL: define dso_local float @test_float_pre_inc( +// SAFE-SAME: ) #[[ATTR0]] { +// SAFE-NEXT: [[ENTRY:.*:]] +// SAFE-NEXT: [[RETVAL:%.*]] = alloca float, align 4, addrspace(5) +// SAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// SAFE-NEXT: [[TMP0:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @test_float_pre_inc.n to ptr), float 1.000000e+00 seq_cst, align 4 +// SAFE-NEXT: [[TMP1:%.*]] = fadd float [[TMP0]], 1.000000e+00 +// SAFE-NEXT: ret float [[TMP1]] +// +// UNSAFE-LABEL: define dso_local float @test_float_pre_inc( +// UNSAFE-SAME: ) #[[ATTR0]] { +// UNSAFE-NEXT: [[ENTRY:.*:]] +// UNSAFE-NEXT: [[RETVAL:%.*]] = alloca float, align 4, addrspace(5) +// UNSAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// UNSAFE-NEXT: [[TMP0:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @test_float_pre_inc.n to ptr), float 1.000000e+00 seq_cst, align 4, !amdgpu.no.fine.grained.memory [[META3]], !amdgpu.ignore.denormal.mode [[META3]] +// UNSAFE-NEXT: [[TMP1:%.*]] = fadd float [[TMP0]], 1.000000e+00 +// UNSAFE-NEXT: ret float [[TMP1]] +// +float test_float_pre_inc() +{ + static _Atomic float n; + return ++n; +} + +// SAFE-LABEL: define dso_local double @test_double_post_inc( +// SAFE-SAME: ) #[[ATTR0]] { +// SAFE-NEXT: [[ENTRY:.*:]] +// SAFE-NEXT: [[RETVAL:%.*]] = alloca double, align 8, addrspace(5) +// SAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// SAFE-NEXT: [[TMP0:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @test_double_post_inc.n to ptr), float 1.000000e+00 seq_cst, align 8 +// SAFE-NEXT: store float [[TMP0]], ptr [[RETVAL_ASCAST]], align 8 +// SAFE-NEXT: [[TMP1:%.*]] = load double, ptr [[RETVAL_ASCAST]], align 8 +// SAFE-NEXT: ret double [[TMP1]] +// +// UNSAFE-LABEL: define dso_local double @test_double_post_inc( +// UNSAFE-SAME: ) #[[ATTR0]] { +// UNSAFE-NEXT: [[ENTRY:.*:]] +// UNSAFE-NEXT: [[RETVAL:%.*]] = alloca double, align 8, addrspace(5) +// UNSAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// UNSAFE-NEXT: [[TMP0:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @test_double_post_inc.n to ptr), float 1.000000e+00 seq_cst, align 8, !amdgpu.no.fine.grained.memory [[META3]], !amdgpu.ignore.denormal.mode [[META3]] +// UNSAFE-NEXT: store float [[TMP0]], ptr [[RETVAL_ASCAST]], align 8 +// UNSAFE-NEXT: [[TMP1:%.*]] = load double, ptr [[RETVAL_ASCAST]], align 8 +// UNSAFE-NEXT: ret double [[TMP1]] +// +double test_double_post_inc() +{ + static _Atomic double n; + return n++; +} + +// SAFE-LABEL: define dso_local double @test_double_post_dc( +// SAFE-SAME: ) #[[ATTR0]] { +// SAFE-NEXT: [[ENTRY:.*:]] +// SAFE-NEXT: [[RETVAL:%.*]] = alloca double, align 8, addrspace(5) +// SAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// SAFE-NEXT: [[TMP0:%.*]] = atomicrmw fsub ptr addrspacecast (ptr addrspace(1) @test_double_post_dc.n to ptr), float 1.000000e+00 seq_cst, align 8 +// SAFE-NEXT: store float [[TMP0]], ptr [[RETVAL_ASCAST]], align 8 +// SAFE-NEXT: [[TMP1:%.*]] = load double, ptr [[RETVAL_ASCAST]], align 8 +// SAFE-NEXT: ret double [[TMP1]] +// +// UNSAFE-LABEL: define dso_local double @test_double_post_dc( +// UNSAFE-SAME: ) #[[ATTR0]] { +// UNSAFE-NEXT: [[ENTRY:.*:]] +// UNSAFE-NEXT: [[RETVAL:%.*]] = alloca double, align 8, addrspace(5) +// UNSAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// UNSAFE-NEXT: [[TMP0:%.*]] = atomicrmw fsub ptr addrspacecast (ptr addrspace(1) @test_double_post_dc.n to ptr), float 1.000000e+00 seq_cst, align 8, !amdgpu.no.fine.grained.memory [[META3]] +// UNSAFE-NEXT: store float [[TMP0]], ptr [[RETVAL_ASCAST]], align 8 +// UNSAFE-NEXT: [[TMP1:%.*]] = load double, ptr [[RETVAL_ASCAST]], align 8 +// UNSAFE-NEXT: ret double [[TMP1]] +// +double test_double_post_dc() +{ + static _Atomic double n; + return n--; +} + +// SAFE-LABEL: define dso_local double @test_double_pre_dc( +// SAFE-SAME: ) #[[ATTR0]] { +// SAFE-NEXT: [[ENTRY:.*:]] +// SAFE-NEXT: [[RETVAL:%.*]] = alloca double, align 8, addrspace(5) +// SAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// SAFE-NEXT: [[TMP0:%.*]] = atomicrmw fsub ptr addrspacecast (ptr addrspace(1) @test_double_pre_dc.n to ptr), float 1.000000e+00 seq_cst, align 8 +// SAFE-NEXT: [[TMP1:%.*]] = fsub float [[TMP0]], 1.000000e+00 +// SAFE-NEXT: store float [[TMP1]], ptr [[RETVAL_ASCAST]], align 8 +// SAFE-NEXT: [[TMP2:%.*]] = load double, ptr [[RETVAL_ASCAST]], align 8 +// SAFE-NEXT: ret double [[TMP2]] +// +// UNSAFE-LABEL: define dso_local double @test_double_pre_dc( +// UNSAFE-SAME: ) #[[ATTR0]] { +// UNSAFE-NEXT: [[ENTRY:.*:]] +// UNSAFE-NEXT: [[RETVAL:%.*]] = alloca double, align 8, addrspace(5) +// UNSAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// UNSAFE-NEXT: [[TMP0:%.*]] = atomicrmw fsub ptr addrspacecast (ptr addrspace(1) @test_double_pre_dc.n to ptr), float 1.000000e+00 seq_cst, align 8, !amdgpu.no.fine.grained.memory [[META3]] +// UNSAFE-NEXT: [[TMP1:%.*]] = fsub float [[TMP0]], 1.000000e+00 +// UNSAFE-NEXT: store float [[TMP1]], ptr [[RETVAL_ASCAST]], align 8 +// UNSAFE-NEXT: [[TMP2:%.*]] = load double, ptr [[RETVAL_ASCAST]], align 8 +// UNSAFE-NEXT: ret double [[TMP2]] +// +double test_double_pre_dc() +{ + static _Atomic double n; + return --n; +} + +// SAFE-LABEL: define dso_local double @test_double_pre_inc( +// SAFE-SAME: ) #[[ATTR0]] { +// SAFE-NEXT: [[ENTRY:.*:]] +// SAFE-NEXT: [[RETVAL:%.*]] = alloca double, align 8, addrspace(5) +// SAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// SAFE-NEXT: [[TMP0:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @test_double_pre_inc.n to ptr), float 1.000000e+00 seq_cst, align 8 +// SAFE-NEXT: [[TMP1:%.*]] = fadd float [[TMP0]], 1.000000e+00 +// SAFE-NEXT: store float [[TMP1]], ptr [[RETVAL_ASCAST]], align 8 +// SAFE-NEXT: [[TMP2:%.*]] = load double, ptr [[RETVAL_ASCAST]], align 8 +// SAFE-NEXT: ret double [[TMP2]] +// +// UNSAFE-LABEL: define dso_local double @test_double_pre_inc( +// UNSAFE-SAME: ) #[[ATTR0]] { +// UNSAFE-NEXT: [[ENTRY:.*:]] +// UNSAFE-NEXT: [[RETVAL:%.*]] = alloca double, align 8, addrspace(5) +// UNSAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// UNSAFE-NEXT: [[TMP0:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @test_double_pre_inc.n to ptr), float 1.000000e+00 seq_cst, align 8, !amdgpu.no.fine.grained.memory [[META3]], !amdgpu.ignore.denormal.mode [[META3]] +// UNSAFE-NEXT: [[TMP1:%.*]] = fadd float [[TMP0]], 1.000000e+00 +// UNSAFE-NEXT: store float [[TMP1]], ptr [[RETVAL_ASCAST]], align 8 +// UNSAFE-NEXT: [[TMP2:%.*]] = load double, ptr [[RETVAL_ASCAST]], align 8 +// UNSAFE-NEXT: ret double [[TMP2]] +// +double test_double_pre_inc() +{ + static _Atomic double n; + return ++n; +} + +// SAFE-LABEL: define dso_local half @test__Float16_post_inc( +// SAFE-SAME: ) #[[ATTR0]] { +// SAFE-NEXT: [[ENTRY:.*:]] +// SAFE-NEXT: [[RETVAL:%.*]] = alloca half, align 2, addrspace(5) +// SAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// SAFE-NEXT: [[TMP0:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @test__Float16_post_inc.n to ptr), float 1.000000e+00 seq_cst, align 2 +// SAFE-NEXT: store float [[TMP0]], ptr [[RETVAL_ASCAST]], align 2 +// SAFE-NEXT: [[TMP1:%.*]] = load half, ptr [[RETVAL_ASCAST]], align 2 +// SAFE-NEXT: ret half [[TMP1]] +// +// UNSAFE-LABEL: define dso_local half @test__Float16_post_inc( +// UNSAFE-SAME: ) #[[ATTR0]] { +// UNSAFE-NEXT: [[ENTRY:.*:]] +// UNSAFE-NEXT: [[RETVAL:%.*]] = alloca half, align 2, addrspace(5) +// UNSAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// UNSAFE-NEXT: [[TMP0:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @test__Float16_post_inc.n to ptr), float 1.000000e+00 seq_cst, align 2, !amdgpu.no.fine.grained.memory [[META3]], !amdgpu.ignore.denormal.mode [[META3]] +// UNSAFE-NEXT: store float [[TMP0]], ptr [[RETVAL_ASCAST]], align 2 +// UNSAFE-NEXT: [[TMP1:%.*]] = load half, ptr [[RETVAL_ASCAST]], align 2 +// UNSAFE-NEXT: ret half [[TMP1]] +// +_Float16 test__Float16_post_inc() +{ + static _Atomic _Float16 n; + return n++; +} + +// SAFE-LABEL: define dso_local half @test__Float16_post_dc( +// SAFE-SAME: ) #[[ATTR0]] { +// SAFE-NEXT: [[ENTRY:.*:]] +// SAFE-NEXT: [[RETVAL:%.*]] = alloca half, align 2, addrspace(5) +// SAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// SAFE-NEXT: [[TMP0:%.*]] = atomicrmw fsub ptr addrspacecast (ptr addrspace(1) @test__Float16_post_dc.n to ptr), float 1.000000e+00 seq_cst, align 2 +// SAFE-NEXT: store float [[TMP0]], ptr [[RETVAL_ASCAST]], align 2 +// SAFE-NEXT: [[TMP1:%.*]] = load half, ptr [[RETVAL_ASCAST]], align 2 +// SAFE-NEXT: ret half [[TMP1]] +// +// UNSAFE-LABEL: define dso_local half @test__Float16_post_dc( +// UNSAFE-SAME: ) #[[ATTR0]] { +// UNSAFE-NEXT: [[ENTRY:.*:]] +// UNSAFE-NEXT: [[RETVAL:%.*]] = alloca half, align 2, addrspace(5) +// UNSAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// UNSAFE-NEXT: [[TMP0:%.*]] = atomicrmw fsub ptr addrspacecast (ptr addrspace(1) @test__Float16_post_dc.n to ptr), float 1.000000e+00 seq_cst, align 2, !amdgpu.no.fine.grained.memory [[META3]] +// UNSAFE-NEXT: store float [[TMP0]], ptr [[RETVAL_ASCAST]], align 2 +// UNSAFE-NEXT: [[TMP1:%.*]] = load half, ptr [[RETVAL_ASCAST]], align 2 +// UNSAFE-NEXT: ret half [[TMP1]] +// +_Float16 test__Float16_post_dc() +{ + static _Atomic _Float16 n; + return n--; +} + +// SAFE-LABEL: define dso_local half @test__Float16_pre_dc( +// SAFE-SAME: ) #[[ATTR0]] { +// SAFE-NEXT: [[ENTRY:.*:]] +// SAFE-NEXT: [[RETVAL:%.*]] = alloca half, align 2, addrspace(5) +// SAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// SAFE-NEXT: [[TMP0:%.*]] = atomicrmw fsub ptr addrspacecast (ptr addrspace(1) @test__Float16_pre_dc.n to ptr), float 1.000000e+00 seq_cst, align 2 +// SAFE-NEXT: [[TMP1:%.*]] = fsub float [[TMP0]], 1.000000e+00 +// SAFE-NEXT: store float [[TMP1]], ptr [[RETVAL_ASCAST]], align 2 +// SAFE-NEXT: [[TMP2:%.*]] = load half, ptr [[RETVAL_ASCAST]], align 2 +// SAFE-NEXT: ret half [[TMP2]] +// +// UNSAFE-LABEL: define dso_local half @test__Float16_pre_dc( +// UNSAFE-SAME: ) #[[ATTR0]] { +// UNSAFE-NEXT: [[ENTRY:.*:]] +// UNSAFE-NEXT: [[RETVAL:%.*]] = alloca half, align 2, addrspace(5) +// UNSAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// UNSAFE-NEXT: [[TMP0:%.*]] = atomicrmw fsub ptr addrspacecast (ptr addrspace(1) @test__Float16_pre_dc.n to ptr), float 1.000000e+00 seq_cst, align 2, !amdgpu.no.fine.grained.memory [[META3]] +// UNSAFE-NEXT: [[TMP1:%.*]] = fsub float [[TMP0]], 1.000000e+00 +// UNSAFE-NEXT: store float [[TMP1]], ptr [[RETVAL_ASCAST]], align 2 +// UNSAFE-NEXT: [[TMP2:%.*]] = load half, ptr [[RETVAL_ASCAST]], align 2 +// UNSAFE-NEXT: ret half [[TMP2]] +// +_Float16 test__Float16_pre_dc() +{ + static _Atomic _Float16 n; + return --n; +} + +// SAFE-LABEL: define dso_local half @test__Float16_pre_inc( +// SAFE-SAME: ) #[[ATTR0]] { +// SAFE-NEXT: [[ENTRY:.*:]] +// SAFE-NEXT: [[RETVAL:%.*]] = alloca half, align 2, addrspace(5) +// SAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// SAFE-NEXT: [[TMP0:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @test__Float16_pre_inc.n to ptr), float 1.000000e+00 seq_cst, align 2 +// SAFE-NEXT: [[TMP1:%.*]] = fadd float [[TMP0]], 1.000000e+00 +// SAFE-NEXT: store float [[TMP1]], ptr [[RETVAL_ASCAST]], align 2 +// SAFE-NEXT: [[TMP2:%.*]] = load half, ptr [[RETVAL_ASCAST]], align 2 +// SAFE-NEXT: ret half [[TMP2]] +// +// UNSAFE-LABEL: define dso_local half @test__Float16_pre_inc( +// UNSAFE-SAME: ) #[[ATTR0]] { +// UNSAFE-NEXT: [[ENTRY:.*:]] +// UNSAFE-NEXT: [[RETVAL:%.*]] = alloca half, align 2, addrspace(5) +// UNSAFE-NEXT: [[RETVAL_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[RETVAL]] to ptr +// UNSAFE-NEXT: [[TMP0:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @test__Float16_pre_inc.n to ptr), float 1.000000e+00 seq_cst, align 2, !amdgpu.no.fine.grained.memory [[META3]], !amdgpu.ignore.denormal.mode [[META3]] +// UNSAFE-NEXT: [[TMP1:%.*]] = fadd float [[TMP0]], 1.000000e+00 +// UNSAFE-NEXT: store float [[TMP1]], ptr [[RETVAL_ASCAST]], align 2 +// UNSAFE-NEXT: [[TMP2:%.*]] = load half, ptr [[RETVAL_ASCAST]], align 2 +// UNSAFE-NEXT: ret half [[TMP2]] +// +_Float16 test__Float16_pre_inc() +{ + static _Atomic _Float16 n; + return ++n; +} +//. +// UNSAFE: [[META3]] = !{} +//. +//// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +// CHECK: {{.*}} diff --git a/clang/test/CodeGen/aarch64-fmv-streaming.c b/clang/test/CodeGen/aarch64-fmv-streaming.c new file mode 100644 index 000000000000000..e549ccda59ad888 --- /dev/null +++ b/clang/test/CodeGen/aarch64-fmv-streaming.c @@ -0,0 +1,107 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -emit-llvm -o - %s | FileCheck %s + + +// CHECK-LABEL: define {{[^@]+}}@n_callee._Msve +// CHECK-SAME: () #[[ATTR0:[0-9]+]] { +// +// CHECK-LABEL: define {{[^@]+}}@n_callee._Msimd +// CHECK-SAME: () #[[ATTR1:[0-9]+]] { +// +__arm_locally_streaming __attribute__((target_clones("sve", "simd"))) void n_callee(void) {} +// CHECK-LABEL: define {{[^@]+}}@n_callee._Msme2 +// CHECK-SAME: () #[[ATTR2:[0-9]+]] { +// +__attribute__((target_version("sme2"))) void n_callee(void) {} +// CHECK-LABEL: define {{[^@]+}}@n_callee.default +// CHECK-SAME: () #[[ATTR3:[0-9]+]] { +// +__attribute__((target_version("default"))) void n_callee(void) {} + + +// CHECK-LABEL: define {{[^@]+}}@s_callee._Msve +// CHECK-SAME: () #[[ATTR4:[0-9]+]] { +// +// CHECK-LABEL: define {{[^@]+}}@s_callee._Msimd +// CHECK-SAME: () #[[ATTR5:[0-9]+]] { +// +__attribute__((target_clones("sve", "simd"))) void s_callee(void) __arm_streaming {} +// CHECK-LABEL: define {{[^@]+}}@s_callee._Msme2 +// CHECK-SAME: () #[[ATTR6:[0-9]+]] { +// +__arm_locally_streaming __attribute__((target_version("sme2"))) void s_callee(void) __arm_streaming {} +// CHECK-LABEL: define {{[^@]+}}@s_callee.default +// CHECK-SAME: () #[[ATTR7:[0-9]+]] { +// +__attribute__((target_version("default"))) void s_callee(void) __arm_streaming {} + + +// CHECK-LABEL: define {{[^@]+}}@sc_callee._Msve +// CHECK-SAME: () #[[ATTR8:[0-9]+]] { +// +// CHECK-LABEL: define {{[^@]+}}@sc_callee._Msimd +// CHECK-SAME: () #[[ATTR9:[0-9]+]] { +// +__attribute__((target_clones("sve", "simd"))) void sc_callee(void) __arm_streaming_compatible {} +// CHECK-LABEL: define {{[^@]+}}@sc_callee._Msme2 +// CHECK-SAME: () #[[ATTR10:[0-9]+]] { +// +__arm_locally_streaming __attribute__((target_version("sme2"))) void sc_callee(void) __arm_streaming_compatible {} +// CHECK-LABEL: define {{[^@]+}}@sc_callee.default +// CHECK-SAME: () #[[ATTR11:[0-9]+]] { +// +__attribute__((target_version("default"))) void sc_callee(void) __arm_streaming_compatible {} + + +// CHECK-LABEL: define {{[^@]+}}@n_caller +// CHECK-SAME: () #[[ATTR3:[0-9]+]] { +// CHECK: call void @n_callee() +// CHECK: call void @s_callee() #[[ATTR12:[0-9]+]] +// CHECK: call void @sc_callee() #[[ATTR13:[0-9]+]] +// +void n_caller(void) { + n_callee(); + s_callee(); + sc_callee(); +} + + +// CHECK-LABEL: define {{[^@]+}}@s_caller +// CHECK-SAME: () #[[ATTR7:[0-9]+]] { +// CHECK: call void @n_callee() +// CHECK: call void @s_callee() #[[ATTR12]] +// CHECK: call void @sc_callee() #[[ATTR13]] +// +void s_caller(void) __arm_streaming { + n_callee(); + s_callee(); + sc_callee(); +} + + +// CHECK-LABEL: define {{[^@]+}}@sc_caller +// CHECK-SAME: () #[[ATTR11:[0-9]+]] { +// CHECK: call void @n_callee() +// CHECK: call void @s_callee() #[[ATTR12]] +// CHECK: call void @sc_callee() #[[ATTR13]] +// +void sc_caller(void) __arm_streaming_compatible { + n_callee(); + s_callee(); + sc_callee(); +} + + +// CHECK: attributes #[[ATTR0:[0-9]+]] = {{.*}} "aarch64_pstate_sm_body" +// CHECK: attributes #[[ATTR1:[0-9]+]] = {{.*}} "aarch64_pstate_sm_body" +// CHECK: attributes #[[ATTR2:[0-9]+]] = {{.*}} +// CHECK: attributes #[[ATTR3]] = {{.*}} +// CHECK: attributes #[[ATTR4:[0-9]+]] = {{.*}} "aarch64_pstate_sm_enabled" +// CHECK: attributes #[[ATTR5:[0-9]+]] = {{.*}} "aarch64_pstate_sm_enabled" +// CHECK: attributes #[[ATTR6:[0-9]+]] = {{.*}} "aarch64_pstate_sm_body" "aarch64_pstate_sm_enabled" +// CHECK: attributes #[[ATTR7]] = {{.*}} "aarch64_pstate_sm_enabled" +// CHECK: attributes #[[ATTR8:[0-9]+]] = {{.*}} "aarch64_pstate_sm_compatible" +// CHECK: attributes #[[ATTR9:[0-9]+]] = {{.*}} "aarch64_pstate_sm_compatible" +// CHECK: attributes #[[ATTR10]] = {{.*}} "aarch64_pstate_sm_body" "aarch64_pstate_sm_compatible" +// CHECK: attributes #[[ATTR11]] = {{.*}} "aarch64_pstate_sm_compatible" +// CHECK: attributes #[[ATTR12]] = {{.*}} "aarch64_pstate_sm_enabled" +// CHECK: attributes #[[ATTR13]] = {{.*}} "aarch64_pstate_sm_compatible" diff --git a/clang/test/CodeGen/aarch64-sme-inline-streaming-attrs.c b/clang/test/CodeGen/aarch64-sme-inline-streaming-attrs.c index 25aebeced9379c7..9c3d08a25945a32 100644 --- a/clang/test/CodeGen/aarch64-sme-inline-streaming-attrs.c +++ b/clang/test/CodeGen/aarch64-sme-inline-streaming-attrs.c @@ -3,6 +3,8 @@ // RUN: %clang_cc1 -triple aarch64-none-linux-gnu -S -o /dev/null -target-feature +sme -verify -DTEST_STREAMING %s // RUN: %clang_cc1 -triple aarch64-none-linux-gnu -S -o /dev/null -target-feature +sme -verify -DTEST_LOCALLY %s +// REQUIRES: aarch64-registered-target + #define __ai __attribute__((always_inline)) __ai void inlined_fn(void) {} __ai void inlined_fn_streaming_compatible(void) __arm_streaming_compatible {} @@ -20,7 +22,7 @@ void caller(void) { #ifdef TEST_COMPATIBLE void caller_compatible(void) __arm_streaming_compatible { - inlined_fn(); // expected-error {{always_inline function 'inlined_fn' and its caller 'caller_compatible' have mismatching streaming attributes}} + inlined_fn(); // expected-warning {{always_inline function 'inlined_fn' and its caller 'caller_compatible' have mismatching streaming attributes, inlining may change runtime behaviour}} inlined_fn_streaming_compatible(); inlined_fn_streaming(); // expected-error {{always_inline function 'inlined_fn_streaming' and its caller 'caller_compatible' have mismatching streaming attributes}} inlined_fn_local(); // expected-error {{always_inline function 'inlined_fn_local' and its caller 'caller_compatible' have mismatching streaming attributes}} @@ -29,7 +31,7 @@ void caller_compatible(void) __arm_streaming_compatible { #ifdef TEST_STREAMING void caller_streaming(void) __arm_streaming { - inlined_fn(); // expected-error {{always_inline function 'inlined_fn' and its caller 'caller_streaming' have mismatching streaming attributes}} + inlined_fn(); // expected-warning {{always_inline function 'inlined_fn' and its caller 'caller_streaming' have mismatching streaming attributes, inlining may change runtime behaviour}} inlined_fn_streaming_compatible(); inlined_fn_streaming(); inlined_fn_local(); @@ -39,7 +41,7 @@ void caller_streaming(void) __arm_streaming { #ifdef TEST_LOCALLY __arm_locally_streaming void caller_local(void) { - inlined_fn(); // expected-error {{always_inline function 'inlined_fn' and its caller 'caller_local' have mismatching streaming attributes}} + inlined_fn(); // expected-warning {{always_inline function 'inlined_fn' and its caller 'caller_local' have mismatching streaming attributes, inlining may change runtime behaviour}} inlined_fn_streaming_compatible(); inlined_fn_streaming(); inlined_fn_local(); diff --git a/clang/test/CodeGen/arm64ec-hybrid-patchable.c b/clang/test/CodeGen/arm64ec-hybrid-patchable.c new file mode 100644 index 000000000000000..4d1fa12afd2aae5 --- /dev/null +++ b/clang/test/CodeGen/arm64ec-hybrid-patchable.c @@ -0,0 +1,34 @@ +// REQUIRES: aarch64-registered-target +// RUN: %clang_cc1 -triple arm64ec-pc-windows -fms-extensions -emit-llvm -o - %s -verify | FileCheck %s + +// CHECK: ; Function Attrs: hybrid_patchable noinline nounwind optnone +// CHECK-NEXT: define dso_local i32 @func() #0 { +int __attribute__((hybrid_patchable)) func(void) { return 1; } + +// CHECK: ; Function Attrs: hybrid_patchable noinline nounwind optnone +// CHECK-NEXT: define dso_local i32 @func2() #0 { +int __declspec(hybrid_patchable) func2(void) { return 2; } + +// CHECK: ; Function Attrs: hybrid_patchable noinline nounwind optnone +// CHECK-NEXT: define dso_local i32 @func3() #0 { +int __declspec(hybrid_patchable) func3(void); +int func3(void) { return 3; } + +// CHECK: ; Function Attrs: hybrid_patchable noinline nounwind optnone +// CHECK-NEXT: define dso_local i32 @func4() #0 { +[[clang::hybrid_patchable]] int func4(void); +int func4(void) { return 3; } + +// CHECK: ; Function Attrs: hybrid_patchable noinline nounwind optnone +// CHECK-NEXT: define internal void @static_func() #0 { +// expected-warning@+1 {{'hybrid_patchable' is ignored on functions without external linkage}} +static void __declspec(hybrid_patchable) static_func(void) {} + +// CHECK: ; Function Attrs: hybrid_patchable noinline nounwind optnone +// CHECK-NEXT: define linkonce_odr dso_local i32 @func5() #0 comdat { +int inline __declspec(hybrid_patchable) func5(void) { return 4; } + +void caller(void) { + static_func(); + func5(); +} diff --git a/clang/test/CodeGen/finite-math.c b/clang/test/CodeGen/finite-math.c index d1a2956b69feb2d..9cddba99ddf63f3 100644 --- a/clang/test/CodeGen/finite-math.c +++ b/clang/test/CodeGen/finite-math.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -ffinite-math-only -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=FINITE +// RUN: %clang_cc1 -menable-no-infs -menable-no-nans -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=FINITE // RUN: %clang_cc1 -fno-signed-zeros -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=NSZ // RUN: %clang_cc1 -freciprocal-math -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=RECIP // RUN: %clang_cc1 -mreassociate -emit-llvm -o - %s | FileCheck %s -check-prefix=CHECK -check-prefix=REASSOC diff --git a/clang/test/CodeGen/fp-floatcontrol-stack.cpp b/clang/test/CodeGen/fp-floatcontrol-stack.cpp index 090da25d21207d8..237c9d4f9a37e28 100644 --- a/clang/test/CodeGen/fp-floatcontrol-stack.cpp +++ b/clang/test/CodeGen/fp-floatcontrol-stack.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DDEFAULT=1 -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DDEFAULT %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DEBSTRICT=1 -ffp-exception-behavior=strict -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-DEBSTRICT %s // RUN: %clang_cc1 -triple x86_64-linux-gnu -DFAST=1 -ffast-math -ffp-contract=fast -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-FAST %s -// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DNOHONOR=1 -menable-no-infs -menable-no-nans -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-NOHONOR %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -ffp-contract=on -DNOHONOR=1 -ffinite-math-only -menable-no-infs -menable-no-nans -emit-llvm -o - %s | FileCheck --check-prefix=CHECK-NOHONOR %s #define FUN(n) \ (float z) { return n * z + n; } diff --git a/clang/test/CodeGen/fp-options-to-fast-math-flags.c b/clang/test/CodeGen/fp-options-to-fast-math-flags.c index abdcf8541f225e3..6aa62266d9898cb 100644 --- a/clang/test/CodeGen/fp-options-to-fast-math-flags.c +++ b/clang/test/CodeGen/fp-options-to-fast-math-flags.c @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple x86_64-unknown-unknown -emit-llvm -o - %s | FileCheck -check-prefix CHECK-PRECISE %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown -menable-no-nans -emit-llvm -o - %s | FileCheck -check-prefix CHECK-NO-NANS %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown -menable-no-infs -emit-llvm -o - %s | FileCheck -check-prefix CHECK-NO-INFS %s -// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ffinite-math-only -emit-llvm -o - %s | FileCheck -check-prefix CHECK-FINITE %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -menable-no-infs -menable-no-nans -emit-llvm -o - %s | FileCheck -check-prefix CHECK-FINITE %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown -fno-signed-zeros -emit-llvm -o - %s | FileCheck -check-prefix CHECK-NO-SIGNED-ZEROS %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown -mreassociate -emit-llvm -o - %s | FileCheck -check-prefix CHECK-REASSOC %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown -freciprocal-math -emit-llvm -o - %s | FileCheck -check-prefix CHECK-RECIP %s diff --git a/clang/test/CodeGen/inline-asm-size-zero.c b/clang/test/CodeGen/inline-asm-size-zero.c new file mode 100644 index 000000000000000..564f5207d1e7115 --- /dev/null +++ b/clang/test/CodeGen/inline-asm-size-zero.c @@ -0,0 +1,6 @@ +// RUN: not %clang_cc1 -S %s -verify -o - + +void foo(void) { + extern long bar[]; + asm ("" : "=r"(bar)); // expected-error{{output size should not be zero}} +} diff --git a/clang/test/CodeGen/math-libcalls-tbaa.c b/clang/test/CodeGen/math-libcalls-tbaa.c new file mode 100644 index 000000000000000..9c86eea67d14d87 --- /dev/null +++ b/clang/test/CodeGen/math-libcalls-tbaa.c @@ -0,0 +1,170 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 + +// RUN: %clang_cc1 -triple=aarch64-unknown-linux-gnu -fmath-errno -O3 -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,NONEWSTRUCTPATHTBAA +// RUN: %clang_cc1 -triple=aarch64-unknown-linux-gnu -fmath-errno -O3 -new-struct-path-tbaa -emit-llvm -o - %s | FileCheck %s -check-prefixes=CHECK,NEWSTRUCTPATHTBAA + +float expf(float); +double remainder(double, double); +double fabs(double); +double frexp(double, int *exp); +void sincos(float a, float *s, float *c); +float _Complex cacoshf(float _Complex); +float crealf(float _Complex); + +// Emit int TBAA metadata on FP math libcalls, which is useful for alias analysis + +// CHECK-LABEL: define dso_local float @test_expf( +// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 40 +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2:![0-9]+]] +// CHECK-NEXT: [[CALL:%.*]] = tail call float @expf(float noundef [[TMP0]]) #[[ATTR9:[0-9]+]], !tbaa [[TBAA6:![0-9]+]] +// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP0]], [[CALL]] +// CHECK-NEXT: ret float [[MUL]] +// +float test_expf (float num[]) { + const float expm2 = expf(num[10]); // Emit TBAA metadata on @expf + float tmp = expm2 * num[10]; + return tmp; +} + +// CHECK-LABEL: define dso_local float @test_builtin_expf( +// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 40 +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: [[CALL:%.*]] = tail call float @expf(float noundef [[TMP0]]) #[[ATTR9]], !tbaa [[TBAA6]] +// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP0]], [[CALL]] +// CHECK-NEXT: ret float [[MUL]] +// +float test_builtin_expf (float num[]) { + const float expm2 = __builtin_expf(num[10]); // Emit TBAA metadata on @expf + float tmp = expm2 * num[10]; + return tmp; +} + +// +// Negative test: fabs cannot set errno +// CHECK-LABEL: define dso_local double @test_fabs( +// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR3:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 80 +// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8:![0-9]+]] +// CHECK-NEXT: [[TMP1:%.*]] = tail call double @llvm.fabs.f64(double [[TMP0]]) +// CHECK-NEXT: [[MUL:%.*]] = fmul double [[TMP0]], [[TMP1]] +// CHECK-NEXT: ret double [[MUL]] +// +double test_fabs (double num[]) { + const double expm2 = fabs(num[10]); // Don't emit TBAA metadata + double tmp = expm2 * num[10]; + return tmp; +} + +// CHECK-LABEL: define dso_local double @test_remainder( +// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]], double noundef [[A:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 80 +// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8]] +// CHECK-NEXT: [[CALL:%.*]] = tail call double @remainder(double noundef [[TMP0]], double noundef [[A]]) #[[ATTR9]], !tbaa [[TBAA6]] +// CHECK-NEXT: [[MUL:%.*]] = fmul double [[TMP0]], [[CALL]] +// CHECK-NEXT: ret double [[MUL]] +// +double test_remainder (double num[], double a) { + const double expm2 = remainder(num[10], a); // Emit TBAA metadata + double tmp = expm2 * num[10]; + return tmp; +} + +// +// TODO: frexp is not subject to any errors, but also writes to +// its int pointer out argument, so it could emit int TBAA metadata. +// CHECK-LABEL: define dso_local double @test_frexp( +// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[E:%.*]] = alloca i32, align 4 +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[E]]) #[[ATTR9]] +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 16 +// CHECK-NEXT: [[TMP0:%.*]] = load double, ptr [[ARRAYIDX]], align 8, !tbaa [[TBAA8]] +// CHECK-NEXT: [[CALL:%.*]] = call double @frexp(double noundef [[TMP0]], ptr noundef nonnull [[E]]) #[[ATTR9]] +// CHECK-NEXT: [[MUL:%.*]] = fmul double [[TMP0]], [[CALL]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[E]]) #[[ATTR9]] +// CHECK-NEXT: ret double [[MUL]] +// +double test_frexp (double num[]) { + int e; + double expm2 = frexp(num[2], &e); // Don't emit TBAA metadata + double tmp = expm2 * num[2]; + return tmp; +} + +// +// Negative test: sincos is a library function, but is not a builtin function +// checked in CodeGenFunction::EmitCallExpr. +// CHECK-LABEL: define dso_local float @test_sincos( +// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR7:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[SIN:%.*]] = alloca float, align 4 +// CHECK-NEXT: [[COS:%.*]] = alloca float, align 4 +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[SIN]]) #[[ATTR9]] +// CHECK-NEXT: call void @llvm.lifetime.start.p0(i64 4, ptr nonnull [[COS]]) #[[ATTR9]] +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 8 +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: call void @sincos(float noundef [[TMP0]], ptr noundef nonnull [[SIN]], ptr noundef nonnull [[COS]]) #[[ATTR9]] +// CHECK-NEXT: [[TMP1:%.*]] = load float, ptr [[SIN]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: [[TMP2:%.*]] = load float, ptr [[COS]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP1]], [[TMP2]] +// CHECK-NEXT: [[TMP3:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: [[ADD:%.*]] = fadd float [[MUL]], [[TMP3]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[COS]]) #[[ATTR9]] +// CHECK-NEXT: call void @llvm.lifetime.end.p0(i64 4, ptr nonnull [[SIN]]) #[[ATTR9]] +// CHECK-NEXT: ret float [[ADD]] +// +float test_sincos (float num[]) { + float sin, cos; + sincos(num[2], &sin, &cos); // Don't emit TBAA metadata + float tmp = sin * cos + num[2]; + return tmp; +} + +// TODO: The builtin return a complex type +// CHECK-LABEL: define dso_local float @test_cacoshf( +// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]]) local_unnamed_addr #[[ATTR7]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 8 +// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: [[DOTFCA_0_INSERT:%.*]] = insertvalue [2 x float] poison, float [[TMP0]], 0 +// CHECK-NEXT: [[DOTFCA_1_INSERT:%.*]] = insertvalue [2 x float] [[DOTFCA_0_INSERT]], float 0.000000e+00, 1 +// CHECK-NEXT: [[CALL:%.*]] = tail call { float, float } @cacoshf([2 x float] noundef alignstack(8) [[DOTFCA_1_INSERT]]) #[[ATTR9]] +// CHECK-NEXT: [[TMP1:%.*]] = extractvalue { float, float } [[CALL]], 0 +// CHECK-NEXT: [[TMP2:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2]] +// CHECK-NEXT: [[ADD:%.*]] = fadd float [[TMP1]], [[TMP2]] +// CHECK-NEXT: ret float [[ADD]] +// +float test_cacoshf (float num[]) { + float _Complex z = cacoshf(num[2]); // Don't emit TBAA metadata + float tmp = crealf(z) + num[2]; + return tmp; +} + +//. +// NONEWSTRUCTPATHTBAA: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0} +// NONEWSTRUCTPATHTBAA: [[META3]] = !{!"float", [[META4:![0-9]+]], i64 0} +// NONEWSTRUCTPATHTBAA: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0} +// NONEWSTRUCTPATHTBAA: [[META5]] = !{!"Simple C/C++ TBAA"} +// NONEWSTRUCTPATHTBAA: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0} +// NONEWSTRUCTPATHTBAA: [[META7]] = !{!"int", [[META4]], i64 0} +// NONEWSTRUCTPATHTBAA: [[TBAA8]] = !{[[META9:![0-9]+]], [[META9]], i64 0} +// NONEWSTRUCTPATHTBAA: [[META9]] = !{!"double", [[META4]], i64 0} +//. +// NEWSTRUCTPATHTBAA: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0, i64 4} +// NEWSTRUCTPATHTBAA: [[META3]] = !{[[META4:![0-9]+]], i64 4, !"float"} +// NEWSTRUCTPATHTBAA: [[META4]] = !{[[META5:![0-9]+]], i64 1, !"omnipotent char"} +// NEWSTRUCTPATHTBAA: [[META5]] = !{!"Simple C/C++ TBAA"} +// NEWSTRUCTPATHTBAA: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0, i64 4} +// NEWSTRUCTPATHTBAA: [[META7]] = !{[[META4]], i64 4, !"int"} +// NEWSTRUCTPATHTBAA: [[TBAA8]] = !{[[META9:![0-9]+]], [[META9]], i64 0, i64 8} +// NEWSTRUCTPATHTBAA: [[META9]] = !{[[META4]], i64 8, !"double"} +//. +//// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: +// NEWSTRUCTPATHTBAA: {{.*}} +// NONEWSTRUCTPATHTBAA: {{.*}} diff --git a/clang/test/CodeGen/math-libcalls-tbaa.cpp b/clang/test/CodeGen/math-libcalls-tbaa.cpp deleted file mode 100644 index f15938dee02724e..000000000000000 --- a/clang/test/CodeGen/math-libcalls-tbaa.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 - -// RUN: %clang_cc1 -triple=aarch64-unknown-linux-gnu -fmath-errno -O3 -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,NoNewStructPathTBAA -// RUN: %clang_cc1 -triple=aarch64-unknown-linux-gnu -fmath-errno -O3 -new-struct-path-tbaa -emit-llvm -o - -x c++ %s | FileCheck %s -check-prefixes=CHECK,NewStructPathTBAA - -extern "C" float expf(float); - -// Emit int TBAA metadata on FP math libcalls, which is useful for alias analysis - -// CHECK-LABEL: define dso_local float @foo( -// CHECK-SAME: ptr nocapture noundef readonly [[NUM:%.*]], float noundef [[R2INV:%.*]], i32 noundef [[N:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { -// CHECK-NEXT: [[ENTRY:.*:]] -// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i8, ptr [[NUM]], i64 40 -// CHECK-NEXT: [[TMP0:%.*]] = load float, ptr [[ARRAYIDX]], align 4, !tbaa [[TBAA2:![0-9]+]] -// CHECK-NEXT: [[CALL:%.*]] = tail call float @expf(float noundef [[TMP0]]) #[[ATTR2:[0-9]+]], !tbaa [[TBAA6:![0-9]+]] -// CHECK-NEXT: [[MUL:%.*]] = fmul float [[TMP0]], [[CALL]] -// CHECK-NEXT: ret float [[MUL]] -// -extern "C" float foo (float num[], float r2inv, int n) { - const float expm2 = expf(num[10]); // Emit TBAA metadata on @expf - float tmp = expm2 * num[10]; - return tmp; -} -//. -// NoNewStructPathTBAA: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0} -// NoNewStructPathTBAA: [[META3]] = !{!"float", [[META4:![0-9]+]], i64 0} -// NoNewStructPathTBAA: [[META4]] = !{!"omnipotent char", [[META5:![0-9]+]], i64 0} -// NoNewStructPathTBAA: [[META5]] = !{!"Simple C++ TBAA"} -// NoNewStructPathTBAA: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0} -// NoNewStructPathTBAA: [[META7]] = !{!"int", [[META4]], i64 0} -//. -// NewStructPathTBAA: [[TBAA2]] = !{[[META3:![0-9]+]], [[META3]], i64 0, i64 4} -// NewStructPathTBAA: [[META3]] = !{[[META4:![0-9]+]], i64 4, !"float"} -// NewStructPathTBAA: [[META4]] = !{[[META5:![0-9]+]], i64 1, !"omnipotent char"} -// NewStructPathTBAA: [[META5]] = !{!"Simple C++ TBAA"} -// NewStructPathTBAA: [[TBAA6]] = !{[[META7:![0-9]+]], [[META7]], i64 0, i64 4} -// NewStructPathTBAA: [[META7]] = !{[[META4]], i64 4, !"int"} -//. -//// NOTE: These prefixes are unused and the list is autogenerated. Do not add tests below this line: -// NewStructPathTBAA: {{.*}} -// NoNewStructPathTBAA: {{.*}} diff --git a/clang/test/CodeGen/nofpclass.c b/clang/test/CodeGen/nofpclass.c index fc4c64f9b921bae..23470914d0ab41b 100644 --- a/clang/test/CodeGen/nofpclass.c +++ b/clang/test/CodeGen/nofpclass.c @@ -1,7 +1,7 @@ // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --check-attributes --version 2 // REQUIRES: x86-registered-target -// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-feature +avx -fenable-matrix -ffinite-math-only -emit-llvm -o - %s | FileCheck -check-prefixes=CFINITEONLY %s -// RUN: %clang_cc1 -x cl -triple x86_64-unknown-unknown -target-feature +avx -fenable-matrix -cl-finite-math-only -emit-llvm -o - %s | FileCheck -check-prefixes=CLFINITEONLY %s +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-feature +avx -fenable-matrix -menable-no-infs -menable-no-nans -emit-llvm -o - %s | FileCheck -check-prefixes=CFINITEONLY %s +// RUN: %clang_cc1 -x cl -triple x86_64-unknown-unknown -target-feature +avx -fenable-matrix -menable-no-nans -menable-no-infs -emit-llvm -o - %s | FileCheck -check-prefixes=CLFINITEONLY %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-feature +avx -fenable-matrix -menable-no-nans -emit-llvm -o - %s | FileCheck -check-prefixes=NONANS %s // RUN: %clang_cc1 -triple x86_64-unknown-unknown -target-feature +avx -fenable-matrix -menable-no-infs -emit-llvm -o - %s | FileCheck -check-prefixes=NOINFS %s diff --git a/clang/test/CodeGenCUDA/amdgpu-atomic-ops.cu b/clang/test/CodeGenCUDA/amdgpu-atomic-ops.cu index eeb23bc7e1c01e4..55ddb52da311e3e 100644 --- a/clang/test/CodeGenCUDA/amdgpu-atomic-ops.cu +++ b/clang/test/CodeGenCUDA/amdgpu-atomic-ops.cu @@ -1,6 +1,10 @@ // RUN: %clang_cc1 -x hip %s -emit-llvm -o - -triple=amdgcn-amd-amdhsa \ // RUN: -fcuda-is-device -target-cpu gfx906 -fnative-half-type \ -// RUN: -fnative-half-arguments-and-returns | FileCheck %s +// RUN: -fnative-half-arguments-and-returns | FileCheck -check-prefixes=CHECK,SAFEIR %s + +// RUN: %clang_cc1 -x hip %s -emit-llvm -o - -triple=amdgcn-amd-amdhsa \ +// RUN: -fcuda-is-device -target-cpu gfx906 -fnative-half-type \ +// RUN: -fnative-half-arguments-and-returns -munsafe-fp-atomics | FileCheck -check-prefixes=CHECK,UNSAFEIR %s // RUN: %clang_cc1 -x hip %s -O3 -S -o - -triple=amdgcn-amd-amdhsa \ // RUN: -fcuda-is-device -target-cpu gfx1100 -fnative-half-type \ @@ -18,24 +22,38 @@ __global__ void ffp1(float *p) { // CHECK-LABEL: @_Z4ffp1Pf - // CHECK: atomicrmw fadd ptr {{.*}} monotonic - // CHECK: atomicrmw fmax ptr {{.*}} monotonic - // CHECK: atomicrmw fmin ptr {{.*}} monotonic - // CHECK: atomicrmw fmax ptr {{.*}} syncscope("agent-one-as") monotonic - // CHECK: atomicrmw fmin ptr {{.*}} syncscope("workgroup-one-as") monotonic + // SAFEIR: atomicrmw fadd ptr {{.*}} monotonic, align 4{{$}} + // SAFEIR: atomicrmw fsub ptr {{.*}} monotonic, align 4{{$}} + // SAFEIR: atomicrmw fmax ptr {{.*}} monotonic, align 4{{$}} + // SAFEIR: atomicrmw fmin ptr {{.*}} monotonic, align 4{{$}} + // SAFEIR: atomicrmw fmax ptr {{.*}} syncscope("agent-one-as") monotonic, align 4{{$}} + // SAFEIR: atomicrmw fmin ptr {{.*}} syncscope("workgroup-one-as") monotonic, align 4{{$}} + + // UNSAFEIR: atomicrmw fadd ptr {{.*}} monotonic, align 4, !amdgpu.no.fine.grained.memory !{{[0-9]+}}, !amdgpu.ignore.denormal.mode !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fsub ptr {{.*}} monotonic, align 4, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmax ptr {{.*}} monotonic, align 4, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmin ptr {{.*}} monotonic, align 4, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmax ptr {{.*}} syncscope("agent-one-as") monotonic, align 4, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmin ptr {{.*}} syncscope("workgroup-one-as") monotonic, align 4, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // SAFE: _Z4ffp1Pf // SAFE: global_atomic_cmpswap // SAFE: global_atomic_cmpswap // SAFE: global_atomic_cmpswap // SAFE: global_atomic_cmpswap // SAFE: global_atomic_cmpswap + // SAFE: global_atomic_cmpswap + // UNSAFE: _Z4ffp1Pf // UNSAFE: global_atomic_add_f32 // UNSAFE: global_atomic_cmpswap // UNSAFE: global_atomic_cmpswap // UNSAFE: global_atomic_cmpswap // UNSAFE: global_atomic_cmpswap + // UNSAFE: global_atomic_cmpswap + __atomic_fetch_add(p, 1.0f, memory_order_relaxed); + __atomic_fetch_sub(p, 1.0f, memory_order_relaxed); __atomic_fetch_max(p, 1.0f, memory_order_relaxed); __atomic_fetch_min(p, 1.0f, memory_order_relaxed); __hip_atomic_fetch_max(p, 1.0f, memory_order_relaxed, __HIP_MEMORY_SCOPE_AGENT); @@ -44,23 +62,36 @@ __global__ void ffp1(float *p) { __global__ void ffp2(double *p) { // CHECK-LABEL: @_Z4ffp2Pd - // CHECK: atomicrmw fsub ptr {{.*}} monotonic - // CHECK: atomicrmw fmax ptr {{.*}} monotonic - // CHECK: atomicrmw fmin ptr {{.*}} monotonic - // CHECK: atomicrmw fmax ptr {{.*}} syncscope("agent-one-as") monotonic - // CHECK: atomicrmw fmin ptr {{.*}} syncscope("workgroup-one-as") monotonic + // SAFEIR: atomicrmw fadd ptr {{.*}} monotonic, align 8{{$}} + // SAFEIR: atomicrmw fsub ptr {{.*}} monotonic, align 8{{$}} + // SAFEIR: atomicrmw fmax ptr {{.*}} monotonic, align 8{{$}} + // SAFEIR: atomicrmw fmin ptr {{.*}} monotonic, align 8{{$}} + // SAFEIR: atomicrmw fmax ptr {{.*}} syncscope("agent-one-as") monotonic, align 8{{$}} + // SAFEIR: atomicrmw fmin ptr {{.*}} syncscope("workgroup-one-as") monotonic, align 8{{$}} + + // UNSAFEIR: atomicrmw fadd ptr {{.*}} monotonic, align 8, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fsub ptr {{.*}} monotonic, align 8, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmax ptr {{.*}} monotonic, align 8, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmin ptr {{.*}} monotonic, align 8, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmax ptr {{.*}} syncscope("agent-one-as") monotonic, align 8, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmin ptr {{.*}} syncscope("workgroup-one-as") monotonic, align 8, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // SAFE-LABEL: @_Z4ffp2Pd // SAFE: global_atomic_cmpswap_b64 // SAFE: global_atomic_cmpswap_b64 // SAFE: global_atomic_cmpswap_b64 // SAFE: global_atomic_cmpswap_b64 // SAFE: global_atomic_cmpswap_b64 + // SAFE: global_atomic_cmpswap_b64 + // UNSAFE-LABEL: @_Z4ffp2Pd + // UNSAFE: global_atomic_add_f64 // UNSAFE: global_atomic_cmpswap_x2 // UNSAFE: global_atomic_cmpswap_x2 // UNSAFE: global_atomic_cmpswap_x2 // UNSAFE: global_atomic_max_f64 // UNSAFE: global_atomic_min_f64 + __atomic_fetch_add(p, 1.0, memory_order_relaxed); __atomic_fetch_sub(p, 1.0, memory_order_relaxed); __atomic_fetch_max(p, 1.0, memory_order_relaxed); __atomic_fetch_min(p, 1.0, memory_order_relaxed); @@ -71,11 +102,20 @@ __global__ void ffp2(double *p) { // long double is the same as double for amdgcn. __global__ void ffp3(long double *p) { // CHECK-LABEL: @_Z4ffp3Pe - // CHECK: atomicrmw fsub ptr {{.*}} monotonic - // CHECK: atomicrmw fmax ptr {{.*}} monotonic - // CHECK: atomicrmw fmin ptr {{.*}} monotonic - // CHECK: atomicrmw fmax ptr {{.*}} syncscope("agent-one-as") monotonic - // CHECK: atomicrmw fmin ptr {{.*}} syncscope("workgroup-one-as") monotonic + // SAFEIR: atomicrmw fadd ptr {{.*}} monotonic, align 8{{$}} + // SAFEIR: atomicrmw fsub ptr {{.*}} monotonic, align 8{{$}} + // SAFEIR: atomicrmw fmax ptr {{.*}} monotonic, align 8{{$}} + // SAFEIR: atomicrmw fmin ptr {{.*}} monotonic, align 8{{$}} + // SAFEIR: atomicrmw fmax ptr {{.*}} syncscope("agent-one-as") monotonic, align 8{{$}} + // SAFEIR: atomicrmw fmin ptr {{.*}} syncscope("workgroup-one-as") monotonic, align 8{{$}} + + // UNSAFEIR: atomicrmw fadd ptr {{.*}} monotonic, align 8, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fsub ptr {{.*}} monotonic, align 8, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmax ptr {{.*}} monotonic, align 8, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmin ptr {{.*}} monotonic, align 8, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmax ptr {{.*}} syncscope("agent-one-as") monotonic, align 8, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmin ptr {{.*}} syncscope("workgroup-one-as") monotonic, align 8, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // SAFE-LABEL: @_Z4ffp3Pe // SAFE: global_atomic_cmpswap_b64 // SAFE: global_atomic_cmpswap_b64 @@ -88,6 +128,7 @@ __global__ void ffp3(long double *p) { // UNSAFE: global_atomic_cmpswap_x2 // UNSAFE: global_atomic_max_f64 // UNSAFE: global_atomic_min_f64 + __atomic_fetch_add(p, 1.0L, memory_order_relaxed); __atomic_fetch_sub(p, 1.0L, memory_order_relaxed); __atomic_fetch_max(p, 1.0L, memory_order_relaxed); __atomic_fetch_min(p, 1.0L, memory_order_relaxed); @@ -98,37 +139,52 @@ __global__ void ffp3(long double *p) { __device__ double ffp4(double *p, float f) { // CHECK-LABEL: @_Z4ffp4Pdf // CHECK: fpext float {{.*}} to double - // CHECK: atomicrmw fsub ptr {{.*}} monotonic + // SAFEIR: atomicrmw fsub ptr {{.*}} monotonic, align 8{{$}} + // UNSAFEIR: atomicrmw fsub ptr {{.*}} monotonic, align 8, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} return __atomic_fetch_sub(p, f, memory_order_relaxed); } __device__ double ffp5(double *p, int i) { // CHECK-LABEL: @_Z4ffp5Pdi // CHECK: sitofp i32 {{.*}} to double - // CHECK: atomicrmw fsub ptr {{.*}} monotonic + // SAFEIR: atomicrmw fsub ptr {{.*}} monotonic, align 8{{$}} + // UNSAFEIR: atomicrmw fsub ptr {{.*}} monotonic, align 8, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} return __atomic_fetch_sub(p, i, memory_order_relaxed); } __global__ void ffp6(_Float16 *p) { // CHECK-LABEL: @_Z4ffp6PDF16 - // CHECK: atomicrmw fadd ptr {{.*}} monotonic - // CHECK: atomicrmw fmax ptr {{.*}} monotonic - // CHECK: atomicrmw fmin ptr {{.*}} monotonic - // CHECK: atomicrmw fmax ptr {{.*}} syncscope("agent-one-as") monotonic - // CHECK: atomicrmw fmin ptr {{.*}} syncscope("workgroup-one-as") monotonic + // SAFEIR: atomicrmw fadd ptr {{.*}} monotonic, align 2{{$}} + // SAFEIR: atomicrmw fsub ptr {{.*}} monotonic, align 2{{$}} + // SAFEIR: atomicrmw fmax ptr {{.*}} monotonic, align 2{{$}} + // SAFEIR: atomicrmw fmin ptr {{.*}} monotonic, align 2{{$}} + // SAFEIR: atomicrmw fmax ptr {{.*}} syncscope("agent-one-as") monotonic, align 2{{$}} + // SAFEIR: atomicrmw fmin ptr {{.*}} syncscope("workgroup-one-as") monotonic, align 2{{$}} + + // UNSAFEIR: atomicrmw fadd ptr {{.*}} monotonic, align 2, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fsub ptr {{.*}} monotonic, align 2, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmax ptr {{.*}} monotonic, align 2, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmin ptr {{.*}} monotonic, align 2, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmax ptr {{.*}} syncscope("agent-one-as") monotonic, align 2, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // UNSAFEIR: atomicrmw fmin ptr {{.*}} syncscope("workgroup-one-as") monotonic, align 2, !amdgpu.no.fine.grained.memory !{{[0-9]+$}} + // SAFE: _Z4ffp6PDF16 // SAFE: global_atomic_cmpswap // SAFE: global_atomic_cmpswap // SAFE: global_atomic_cmpswap // SAFE: global_atomic_cmpswap // SAFE: global_atomic_cmpswap + // SAFE: global_atomic_cmpswap + // UNSAFE: _Z4ffp6PDF16 // UNSAFE: global_atomic_cmpswap // UNSAFE: global_atomic_cmpswap // UNSAFE: global_atomic_cmpswap // UNSAFE: global_atomic_cmpswap // UNSAFE: global_atomic_cmpswap + // UNSAFE: global_atomic_cmpswap __atomic_fetch_add(p, 1.0, memory_order_relaxed); + __atomic_fetch_sub(p, 1.0, memory_order_relaxed); __atomic_fetch_max(p, 1.0, memory_order_relaxed); __atomic_fetch_min(p, 1.0, memory_order_relaxed); __hip_atomic_fetch_max(p, 1.0f, memory_order_relaxed, __HIP_MEMORY_SCOPE_AGENT); diff --git a/clang/test/CodeGenCXX/debug-info-explicit-this.cpp b/clang/test/CodeGenCXX/debug-info-explicit-this.cpp new file mode 100644 index 000000000000000..45ab2a0216ca7a7 --- /dev/null +++ b/clang/test/CodeGenCXX/debug-info-explicit-this.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -emit-llvm -debug-info-kind=limited -std=c++2b %s -o - | FileCheck %s + +struct Foo { + void Bar(this Foo&& self) {} +}; + +void fn() { + Foo{}.Bar(); +} + +// CHECK: distinct !DISubprogram(name: "Bar", {{.*}}, type: ![[BAR_TYPE:[0-9]+]], {{.*}}, declaration: ![[BAR_DECL:[0-9]+]], {{.*}} +// CHECK: ![[FOO:[0-9]+]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Foo" +// CHECK: ![[BAR_DECL]] = !DISubprogram(name: "Bar", {{.*}}, type: ![[BAR_TYPE]], {{.*}}, +// CHECK: ![[BAR_TYPE]] = !DISubroutineType(types: ![[PARAMS:[0-9]+]]) +// CHECK: ![[PARAMS]] = !{null, ![[SELF:[0-9]+]]} +// CHECK: ![[SELF]] = !DIDerivedType(tag: DW_TAG_rvalue_reference_type, baseType: ![[FOO]] diff --git a/clang/test/CodeGenCoroutines/coro-elide-thinlto.cpp b/clang/test/CodeGenCoroutines/coro-elide-thinlto.cpp new file mode 100644 index 000000000000000..54063cf0704aad3 --- /dev/null +++ b/clang/test/CodeGenCoroutines/coro-elide-thinlto.cpp @@ -0,0 +1,78 @@ +// REQUIRES: x86_64-linux +// This tests that the coroutine elide optimization could happen succesfully with ThinLTO. +// This test is adapted from coro-elide.cpp and splits functions into two files. +// +// RUN: split-file %s %t +// RUN: %clang --target=x86_64-linux -std=c++20 -O2 -flto=thin -I %S -c %t/coro-elide-callee.cpp -o %t/coro-elide-callee.bc +// RUN: %clang --target=x86_64-linux -std=c++20 -O2 -flto=thin -I %S -c %t/coro-elide-caller.cpp -o %t/coro-elide-caller.bc +// RUN: llvm-lto --thinlto %t/coro-elide-callee.bc %t/coro-elide-caller.bc -o %t/summary +// RUN: %clang_cc1 -O2 -x ir %t/coro-elide-caller.bc -fthinlto-index=%t/summary.thinlto.bc -emit-llvm -o - | FileCheck %s + +//--- coro-elide-task.h +#pragma once +#include "Inputs/coroutine.h" + +struct Task { + struct promise_type { + struct FinalAwaiter { + bool await_ready() const noexcept { return false; } + template + std::coroutine_handle<> await_suspend(std::coroutine_handle h) noexcept { + if (!h) + return std::noop_coroutine(); + return h.promise().continuation; + } + void await_resume() noexcept {} + }; + Task get_return_object() noexcept { + return std::coroutine_handle::from_promise(*this); + } + std::suspend_always initial_suspend() noexcept { return {}; } + FinalAwaiter final_suspend() noexcept { return {}; } + void unhandled_exception() noexcept {} + void return_value(int x) noexcept { + _value = x; + } + std::coroutine_handle<> continuation; + int _value; + }; + + Task(std::coroutine_handle handle) : handle(handle) {} + ~Task() { + if (handle) + handle.destroy(); + } + + struct Awaiter { + bool await_ready() const noexcept { return false; } + void await_suspend(std::coroutine_handle continuation) noexcept {} + int await_resume() noexcept { + return 43; + } + }; + + auto operator co_await() { + return Awaiter{}; + } + +private: + std::coroutine_handle handle; +}; + +//--- coro-elide-callee.cpp +#include "coro-elide-task.h" +Task task0() { + co_return 43; +} + +//--- coro-elide-caller.cpp +#include "coro-elide-task.h" + +Task task0(); + +Task task1() { + co_return co_await task0(); +} + +// CHECK-LABEL: define{{.*}} void @_Z5task1v.resume +// CHECK-NOT: {{.*}}_Znwm diff --git a/clang/test/CodeGenOpenCL/builtins-alloca.cl b/clang/test/CodeGenOpenCL/builtins-alloca.cl new file mode 100644 index 000000000000000..474e95e74e006b1 --- /dev/null +++ b/clang/test/CodeGenOpenCL/builtins-alloca.cl @@ -0,0 +1,141 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa -cl-std=CL1.2 \ +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=OPENCL %s +// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa -cl-std=CL2.0 \ +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=OPENCL %s +// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa -cl-std=CL3.0 \ +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=OPENCL %s +// RUN: %clang_cc1 %s -O0 -triple amdgcn-amd-amdhsa -cl-std=CL3.0 -cl-ext=+__opencl_c_generic_address_space \ +// RUN: -emit-llvm -o - | FileCheck --check-prefixes=OPENCL %s + +// OPENCL-LABEL: define dso_local void @test1_builtin_alloca( +// OPENCL-SAME: i32 noundef [[N:%.*]]) #[[ATTR0:[0-9]+]] { +// OPENCL-NEXT: [[ENTRY:.*:]] +// OPENCL-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4, addrspace(5) +// OPENCL-NEXT: [[ALLOC_PTR:%.*]] = alloca ptr addrspace(5), align 4, addrspace(5) +// OPENCL-NEXT: store i32 [[N]], ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[CONV:%.*]] = zext i32 [[TMP0]] to i64 +// OPENCL-NEXT: [[MUL:%.*]] = mul i64 [[CONV]], 4 +// OPENCL-NEXT: [[TMP1:%.*]] = alloca i8, i64 [[MUL]], align 8, addrspace(5) +// OPENCL-NEXT: store ptr addrspace(5) [[TMP1]], ptr addrspace(5) [[ALLOC_PTR]], align 4 +// OPENCL-NEXT: ret void +// +void test1_builtin_alloca(unsigned n) { + __private float* alloc_ptr = (__private float*)__builtin_alloca(n*sizeof(int)); +} + +// OPENCL-LABEL: define dso_local void @test1_builtin_alloca_uninitialized( +// OPENCL-SAME: i32 noundef [[N:%.*]]) #[[ATTR0]] { +// OPENCL-NEXT: [[ENTRY:.*:]] +// OPENCL-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4, addrspace(5) +// OPENCL-NEXT: [[ALLOC_PTR_UNINITIALIZED:%.*]] = alloca ptr addrspace(5), align 4, addrspace(5) +// OPENCL-NEXT: store i32 [[N]], ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[CONV:%.*]] = zext i32 [[TMP0]] to i64 +// OPENCL-NEXT: [[MUL:%.*]] = mul i64 [[CONV]], 4 +// OPENCL-NEXT: [[TMP1:%.*]] = alloca i8, i64 [[MUL]], align 8, addrspace(5) +// OPENCL-NEXT: store ptr addrspace(5) [[TMP1]], ptr addrspace(5) [[ALLOC_PTR_UNINITIALIZED]], align 4 +// OPENCL-NEXT: ret void +// +void test1_builtin_alloca_uninitialized(unsigned n) { + __private float* alloc_ptr_uninitialized = (__private float*)__builtin_alloca_uninitialized(n*sizeof(int)); +} + +// OPENCL-LABEL: define dso_local void @test1_builtin_alloca_with_align( +// OPENCL-SAME: i32 noundef [[N:%.*]]) #[[ATTR0]] { +// OPENCL-NEXT: [[ENTRY:.*:]] +// OPENCL-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4, addrspace(5) +// OPENCL-NEXT: [[ALLOC_PTR_ALIGN:%.*]] = alloca ptr addrspace(5), align 4, addrspace(5) +// OPENCL-NEXT: store i32 [[N]], ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[CONV:%.*]] = zext i32 [[TMP0]] to i64 +// OPENCL-NEXT: [[MUL:%.*]] = mul i64 [[CONV]], 4 +// OPENCL-NEXT: [[TMP1:%.*]] = alloca i8, i64 [[MUL]], align 1, addrspace(5) +// OPENCL-NEXT: store ptr addrspace(5) [[TMP1]], ptr addrspace(5) [[ALLOC_PTR_ALIGN]], align 4 +// OPENCL-NEXT: ret void +// +void test1_builtin_alloca_with_align(unsigned n) { + __private float* alloc_ptr_align = (__private float*)__builtin_alloca_with_align((n*sizeof(int)), 8); +} + +// OPENCL-LABEL: define dso_local void @test1_builtin_alloca_with_align_uninitialized( +// OPENCL-SAME: i32 noundef [[N:%.*]]) #[[ATTR0]] { +// OPENCL-NEXT: [[ENTRY:.*:]] +// OPENCL-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4, addrspace(5) +// OPENCL-NEXT: [[ALLOC_PTR_ALIGN_UNINITIALIZED:%.*]] = alloca ptr addrspace(5), align 4, addrspace(5) +// OPENCL-NEXT: store i32 [[N]], ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[CONV:%.*]] = zext i32 [[TMP0]] to i64 +// OPENCL-NEXT: [[MUL:%.*]] = mul i64 [[CONV]], 4 +// OPENCL-NEXT: [[TMP1:%.*]] = alloca i8, i64 [[MUL]], align 1, addrspace(5) +// OPENCL-NEXT: store ptr addrspace(5) [[TMP1]], ptr addrspace(5) [[ALLOC_PTR_ALIGN_UNINITIALIZED]], align 4 +// OPENCL-NEXT: ret void +// +void test1_builtin_alloca_with_align_uninitialized(unsigned n) { + __private float* alloc_ptr_align_uninitialized = (__private float*)__builtin_alloca_with_align_uninitialized((n*sizeof(int)), 8); +} + +// OPENCL-LABEL: define dso_local void @test2_builtin_alloca( +// OPENCL-SAME: i32 noundef [[N:%.*]]) #[[ATTR0]] { +// OPENCL-NEXT: [[ENTRY:.*:]] +// OPENCL-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4, addrspace(5) +// OPENCL-NEXT: [[ALLOC_PTR:%.*]] = alloca ptr addrspace(5), align 4, addrspace(5) +// OPENCL-NEXT: store i32 [[N]], ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[CONV:%.*]] = zext i32 [[TMP0]] to i64 +// OPENCL-NEXT: [[TMP1:%.*]] = alloca i8, i64 [[CONV]], align 8, addrspace(5) +// OPENCL-NEXT: store ptr addrspace(5) [[TMP1]], ptr addrspace(5) [[ALLOC_PTR]], align 4 +// OPENCL-NEXT: ret void +// +void test2_builtin_alloca(unsigned n) { + __private void *alloc_ptr = __builtin_alloca(n); +} + +// OPENCL-LABEL: define dso_local void @test2_builtin_alloca_uninitialized( +// OPENCL-SAME: i32 noundef [[N:%.*]]) #[[ATTR0]] { +// OPENCL-NEXT: [[ENTRY:.*:]] +// OPENCL-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4, addrspace(5) +// OPENCL-NEXT: [[ALLOC_PTR_UNINITIALIZED:%.*]] = alloca ptr addrspace(5), align 4, addrspace(5) +// OPENCL-NEXT: store i32 [[N]], ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[CONV:%.*]] = zext i32 [[TMP0]] to i64 +// OPENCL-NEXT: [[TMP1:%.*]] = alloca i8, i64 [[CONV]], align 8, addrspace(5) +// OPENCL-NEXT: store ptr addrspace(5) [[TMP1]], ptr addrspace(5) [[ALLOC_PTR_UNINITIALIZED]], align 4 +// OPENCL-NEXT: ret void +// +void test2_builtin_alloca_uninitialized(unsigned n) { + __private void *alloc_ptr_uninitialized = __builtin_alloca_uninitialized(n); +} + +// OPENCL-LABEL: define dso_local void @test2_builtin_alloca_with_align( +// OPENCL-SAME: i32 noundef [[N:%.*]]) #[[ATTR0]] { +// OPENCL-NEXT: [[ENTRY:.*:]] +// OPENCL-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4, addrspace(5) +// OPENCL-NEXT: [[ALLOC_PTR_ALIGN:%.*]] = alloca ptr addrspace(5), align 4, addrspace(5) +// OPENCL-NEXT: store i32 [[N]], ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[CONV:%.*]] = zext i32 [[TMP0]] to i64 +// OPENCL-NEXT: [[TMP1:%.*]] = alloca i8, i64 [[CONV]], align 1, addrspace(5) +// OPENCL-NEXT: store ptr addrspace(5) [[TMP1]], ptr addrspace(5) [[ALLOC_PTR_ALIGN]], align 4 +// OPENCL-NEXT: ret void +// +void test2_builtin_alloca_with_align(unsigned n) { + __private void *alloc_ptr_align = __builtin_alloca_with_align(n, 8); +} + +// OPENCL-LABEL: define dso_local void @test2_builtin_alloca_with_align_uninitialized( +// OPENCL-SAME: i32 noundef [[N:%.*]]) #[[ATTR0]] { +// OPENCL-NEXT: [[ENTRY:.*:]] +// OPENCL-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4, addrspace(5) +// OPENCL-NEXT: [[ALLOC_PTR_ALIGN_UNINITIALIZED:%.*]] = alloca ptr addrspace(5), align 4, addrspace(5) +// OPENCL-NEXT: store i32 [[N]], ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[TMP0:%.*]] = load i32, ptr addrspace(5) [[N_ADDR]], align 4 +// OPENCL-NEXT: [[CONV:%.*]] = zext i32 [[TMP0]] to i64 +// OPENCL-NEXT: [[TMP1:%.*]] = alloca i8, i64 [[CONV]], align 1, addrspace(5) +// OPENCL-NEXT: store ptr addrspace(5) [[TMP1]], ptr addrspace(5) [[ALLOC_PTR_ALIGN_UNINITIALIZED]], align 4 +// OPENCL-NEXT: ret void +// +void test2_builtin_alloca_with_align_uninitialized(unsigned n) { + __private void *alloc_ptr_align_uninitialized = __builtin_alloca_with_align_uninitialized(n, 8); +} diff --git a/clang/test/CodeGenOpenCL/relaxed-fpmath.cl b/clang/test/CodeGenOpenCL/relaxed-fpmath.cl index 2751caa97307289..a5f0019dbc1e54e 100644 --- a/clang/test/CodeGenOpenCL/relaxed-fpmath.cl +++ b/clang/test/CodeGenOpenCL/relaxed-fpmath.cl @@ -1,6 +1,6 @@ // RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s -check-prefix=NORMAL // RUN: %clang_cc1 %s -emit-llvm -cl-fast-relaxed-math -o - | FileCheck %s -check-prefix=FAST -// RUN: %clang_cc1 %s -emit-llvm -cl-finite-math-only -o - | FileCheck %s -check-prefix=FINITE +// RUN: %clang_cc1 %s -emit-llvm -menable-no-infs -menable-no-nans -cl-finite-math-only -o - | FileCheck %s -check-prefix=FINITE // RUN: %clang_cc1 %s -emit-llvm -cl-unsafe-math-optimizations -o - | FileCheck %s -check-prefix=UNSAFE // RUN: %clang_cc1 %s -emit-llvm -cl-mad-enable -o - | FileCheck %s -check-prefix=MAD // RUN: %clang_cc1 %s -emit-llvm -cl-no-signed-zeros -o - | FileCheck %s -check-prefix=NOSIGNED @@ -9,7 +9,7 @@ // RUN: %clang_cc1 %s -DGEN_PCH=1 -finclude-default-header -triple spir-unknown-unknown -emit-pch -o %t.pch // RUN: %clang_cc1 %s -include-pch %t.pch -fno-validate-pch -emit-llvm -o - | FileCheck %s -check-prefix=NORMAL // RUN: %clang_cc1 %s -include-pch %t.pch -fno-validate-pch -emit-llvm -cl-fast-relaxed-math -o - | FileCheck %s -check-prefix=FAST -// RUN: %clang_cc1 %s -include-pch %t.pch -fno-validate-pch -emit-llvm -cl-finite-math-only -o - | FileCheck %s -check-prefix=FINITE +// RUN: %clang_cc1 %s -include-pch %t.pch -fno-validate-pch -emit-llvm -menable-no-infs -menable-no-nans -cl-finite-math-only -o - | FileCheck %s -check-prefix=FINITE // RUN: %clang_cc1 %s -include-pch %t.pch -fno-validate-pch -emit-llvm -cl-unsafe-math-optimizations -o - | FileCheck %s -check-prefix=UNSAFE // RUN: %clang_cc1 %s -include-pch %t.pch -fno-validate-pch -emit-llvm -cl-mad-enable -o - | FileCheck %s -check-prefix=MAD // RUN: %clang_cc1 %s -include-pch %t.pch -fno-validate-pch -emit-llvm -cl-no-signed-zeros -o - | FileCheck %s -check-prefix=NOSIGNED diff --git a/clang/test/Driver/aarch64-ptrauth.c b/clang/test/Driver/aarch64-ptrauth.c index c8e3aeef1640a1b..75190c438082674 100644 --- a/clang/test/Driver/aarch64-ptrauth.c +++ b/clang/test/Driver/aarch64-ptrauth.c @@ -49,14 +49,14 @@ // ERR1-NEXT: error: unsupported option '-fptrauth-init-fini' for target '{{.*}}' //// Only support PAuth ABI for Linux as for now. -// RUN: not %clang -c --target=aarch64-unknown -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefix=ERR2 -// RUN: not %clang -c --target=aarch64-unknown-pauthtest %s 2>&1 | FileCheck %s --check-prefix=ERR2 +// RUN: not %clang -o /dev/null -c --target=aarch64-unknown -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefix=ERR2 +// RUN: not %clang -o /dev/null -c --target=aarch64-unknown-pauthtest %s 2>&1 | FileCheck %s --check-prefix=ERR2 // ERR2: error: ABI 'pauthtest' is not supported for 'aarch64-unknown-unknown-pauthtest' //// PAuth ABI is encoded as environment part of the triple, so don't allow to explicitly set other environments. -// RUN: not %clang -c --target=aarch64-linux-gnu -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefix=ERR3 +// RUN: not %clang -### -c --target=aarch64-linux-gnu -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefix=ERR3 // ERR3: error: unsupported option '-mabi=pauthtest' for target 'aarch64-unknown-linux-gnu' -// RUN: %clang -c --target=aarch64-linux-pauthtest -mabi=pauthtest %s +// RUN: %clang -### -c --target=aarch64-linux-pauthtest -mabi=pauthtest %s //// The only branch protection option compatible with PAuthABI is BTI. // RUN: not %clang -### -c --target=aarch64-linux -mabi=pauthtest -mbranch-protection=pac-ret %s 2>&1 | \ diff --git a/clang/test/Driver/amdgpu-toolchain.c b/clang/test/Driver/amdgpu-toolchain.c index 8ab6a071314745b..b60d31bae627009 100644 --- a/clang/test/Driver/amdgpu-toolchain.c +++ b/clang/test/Driver/amdgpu-toolchain.c @@ -18,13 +18,17 @@ // AS_LINK_UR: "-cc1as" // AS_LINK_UR: ld.lld{{.*}} "--no-undefined"{{.*}} "--unresolved-symbols=ignore-all" -// RUN: %clang -### --target=amdgcn-amd-amdhsa -mcpu=gfx906 -nogpulib \ +// RUN: %clang -### --target=amdgcn-amd-amdhsa -mcpu=gfx90a:xnack+:sramecc- -nogpulib \ // RUN: -L. -flto -fconvergent-functions %s 2>&1 | FileCheck -check-prefixes=LTO,MCPU %s -// RUN: %clang -### --target=amdgcn-amd-amdhsa -mcpu=gfx906 -nogpulib \ +// RUN: %clang -### --target=amdgcn-amd-amdhsa -mcpu=gfx90a:xnack+:sramecc- -nogpulib \ // RUN: -L. -fconvergent-functions %s 2>&1 | FileCheck -check-prefix=MCPU %s // LTO: clang{{.*}} "-flto=full"{{.*}}"-fconvergent-functions" -// MCPU: ld.lld{{.*}}"-L."{{.*}}"-plugin-opt=mcpu=gfx906" +// MCPU: ld.lld{{.*}}"-L."{{.*}}"-plugin-opt=mcpu=gfx90a"{{.*}}"-plugin-opt=-mattr=-sramecc,+xnack" // RUN: %clang -### --target=amdgcn-amd-amdhsa -mcpu=gfx906 -nogpulib \ // RUN: -fuse-ld=ld %s 2>&1 | FileCheck -check-prefixes=LD %s // LD: ld.lld + +// RUN: %clang -### --target=amdgcn-amd-amdhsa -mcpu=gfx906 -nogpulib \ +// RUN: -r %s 2>&1 | FileCheck -check-prefixes=RELO %s +// RELO-NOT: -shared diff --git a/clang/test/Driver/cuda-cross-compiling.c b/clang/test/Driver/cuda-cross-compiling.c index 42d56cbfcc321de..c2e538c25329e1c 100644 --- a/clang/test/Driver/cuda-cross-compiling.c +++ b/clang/test/Driver/cuda-cross-compiling.c @@ -90,3 +90,11 @@ // RUN: | FileCheck -check-prefix=GENERIC %s // GENERIC-NOT: -cc1" "-triple" "nvptx64-nvidia-cuda" {{.*}} "-target-cpu" + +// +// Test forwarding the necessary +ptx feature. +// +// RUN: %clang -target nvptx64-nvidia-cuda --cuda-feature=+ptx63 -march=sm_52 -### %s 2>&1 \ +// RUN: | FileCheck -check-prefix=FEATURE %s + +// FEATURE: clang-nvlink-wrapper{{.*}}"--feature" "+ptx63" diff --git a/clang/test/Driver/immediate-options.c b/clang/test/Driver/immediate-options.c index 77878fe2e9c58e2..b74f6b41f22a0d3 100644 --- a/clang/test/Driver/immediate-options.c +++ b/clang/test/Driver/immediate-options.c @@ -2,6 +2,8 @@ // HELP: isystem // HELP-NOT: ast-dump // HELP-NOT: driver-mode +// HELP: -Wa, +// HELP-NOT: -W{{[a-z][a-z]}} // Make sure that Flang-only options are not available in Clang // HELP-NOT: test-io diff --git a/clang/test/Driver/linker-wrapper.c b/clang/test/Driver/linker-wrapper.c index 342907c1a3390ad..99cfdb9ebfc7cd5 100644 --- a/clang/test/Driver/linker-wrapper.c +++ b/clang/test/Driver/linker-wrapper.c @@ -129,14 +129,14 @@ __attribute__((visibility("protected"), used)) int x; // RUN: -fembed-offload-object=%t.out // RUN: clang-linker-wrapper --dry-run --host-triple=x86_64-unknown-linux-gnu \ // RUN: --linker-path=/usr/bin/ld --device-linker=foo=bar --device-linker=a \ -// RUN: --device-linker=nvptx64-nvidia-cuda=b \ +// RUN: --device-linker=nvptx64-nvidia-cuda=b --device-compiler=foo\ // RUN: %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=LINKER-ARGS -// LINKER-ARGS: clang{{.*}}--target=amdgcn-amd-amdhsa{{.*}}foo=bar{{.*}}a -// LINKER-ARGS: clang{{.*}}--target=nvptx64-nvidia-cuda{{.*}}foo=bar{{.*}}a b +// LINKER-ARGS: clang{{.*}}--target=amdgcn-amd-amdhsa{{.*}}-Xlinker foo=bar{{.*}}-Xlinker a{{.*}}foo +// LINKER-ARGS: clang{{.*}}--target=nvptx64-nvidia-cuda{{.*}}-Xlinker foo=bar{{.*}}-Xlinker a -Xlinker b{{.*}}foo -// RUN: not clang-linker-wrapper --dry-run --host-triple=x86_64-unknown-linux-gnu -ldummy \ -// RUN: --linker-path=/usr/bin/ld --device-linker=a --device-linker=nvptx64-nvidia-cuda=b \ +// RUN: not clang-linker-wrapper --dry-run --host-triple=x86_64-unknown-linux-gnu \ +// RUN: -ldummy --linker-path=/usr/bin/ld \ // RUN: -o a.out 2>&1 | FileCheck %s --check-prefix=MISSING-LIBRARY // MISSING-LIBRARY: error: unable to find library -ldummy @@ -234,3 +234,13 @@ __attribute__((visibility("protected"), used)) int x; // RUN: | FileCheck %s --check-prefix=OVERRIDE // OVERRIDE-NOT: clang // OVERRIDE: /usr/bin/ld + +// RUN: clang-offload-packager -o %t.out \ +// RUN: --image=file=%t.elf.o,kind=openmp,triple=amdgcn-amd-amdhsa,arch=gfx908 +// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.out +// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run --offload-opt=-pass-remarks=foo \ +// RUN: --linker-path=/usr/bin/ld %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=OFFLOAD-OPT +// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run -mllvm -pass-remarks=foo \ +// RUN: --linker-path=/usr/bin/ld %t.o -o a.out 2>&1 | FileCheck %s --check-prefix=OFFLOAD-OPT + +// OFFLOAD-OPT: clang{{.*}}-Wl,--plugin-opt=-pass-remarks=foo diff --git a/clang/test/Driver/lto-jobs.c b/clang/test/Driver/lto-jobs.c index b4f109e4c502c1d..2c7ca02ea47797d 100644 --- a/clang/test/Driver/lto-jobs.c +++ b/clang/test/Driver/lto-jobs.c @@ -6,12 +6,15 @@ // RUN: %clang --target=x86_64-sie-ps5 -### %s -flto=thin -flto-jobs=5 2> %t // RUN: FileCheck -check-prefix=CHECK-LINK-THIN-JOBS-ACTION < %t %s // +// RUN: %clang --target=x86_64-sie-ps5 -### %s -flto-jobs=5 2> %t +// RUN: FileCheck -check-prefix=CHECK-LINK-THIN-JOBS-ACTION < %t %s +// // CHECK-LINK-THIN-JOBS-ACTION: "-plugin-opt=jobs=5" // // RUN: %clang --target=x86_64-scei-ps4 -### %s -flto=thin -flto-jobs=5 2> %t // RUN: FileCheck -check-prefix=CHECK-PS4-LINK-THIN-JOBS-ACTION < %t %s // -// CHECK-PS4-LINK-THIN-JOBS-ACTION: "-lto-thin-debug-options= -threads=5" +// CHECK-PS4-LINK-THIN-JOBS-ACTION: "-lto-debug-options= -threads=5" // RUN: %clang --target=x86_64-apple-darwin13.3.0 -### %s -flto=thin -flto-jobs=5 2> %t // RUN: FileCheck -check-prefix=CHECK-LINK-THIN-JOBS2-ACTION < %t %s diff --git a/clang/test/Driver/opencl.cl b/clang/test/Driver/opencl.cl index aba37fc328fbbb7..3b0b191827b4cd8 100644 --- a/clang/test/Driver/opencl.cl +++ b/clang/test/Driver/opencl.cl @@ -35,7 +35,7 @@ // CHECK-OPT-DISABLE: "-cc1" {{.*}} "-cl-opt-disable" // CHECK-STRICT-ALIASING: "-cc1" {{.*}} "-cl-strict-aliasing" // CHECK-SINGLE-PRECISION-CONST: "-cc1" {{.*}} "-cl-single-precision-constant" -// CHECK-FINITE-MATH-ONLY: "-cc1" {{.*}} "-cl-finite-math-only" +// CHECK-FINITE-MATH-ONLY: "-cc1" {{.*}} "-menable-no-infs" "-menable-no-nans" "-cl-finite-math-only" // CHECK-KERNEL-ARG-INFO: "-cc1" {{.*}} "-cl-kernel-arg-info" // CHECK-UNSAFE-MATH-OPT: "-cc1" {{.*}} "-cl-unsafe-math-optimizations" // CHECK-FAST-RELAXED-MATH: "-cc1" {{.*}} "-cl-fast-relaxed-math" diff --git a/clang/test/Driver/openmp-offload-gpu.c b/clang/test/Driver/openmp-offload-gpu.c index 0314f28f38a4343..ef6cbdded6a6f21 100644 --- a/clang/test/Driver/openmp-offload-gpu.c +++ b/clang/test/Driver/openmp-offload-gpu.c @@ -377,4 +377,4 @@ // RUN: --cuda-path=%S/Inputs/CUDA_102/usr/local/cuda \ // RUN: --offload-arch=sm_52 -nogpulibc -nogpuinc %s 2>&1 \ // RUN: | FileCheck --check-prefix=LIBC-GPU %s -// LIBC-GPU: clang-linker-wrapper{{.*}}"--device-linker=-nolibc" +// LIBC-GPU: clang-linker-wrapper{{.*}}"--device-compiler=-nolibc" diff --git a/clang/test/Driver/ps4-linker.c b/clang/test/Driver/ps4-linker.c index be989cdd7d5b17e..2a095d660bf3651 100644 --- a/clang/test/Driver/ps4-linker.c +++ b/clang/test/Driver/ps4-linker.c @@ -1,20 +1,23 @@ // Test the driver's control over the JustMyCode behavior with linker flags. -// RUN: %clang --target=x86_64-scei-ps4 -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-LIB %s -// RUN: %clang --target=x86_64-scei-ps4 -flto=thin -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-THIN-LTO,CHECK-LIB %s -// RUN: %clang --target=x86_64-scei-ps4 -flto=full -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-FULL-LTO,CHECK-LIB %s +// RUN: %clang --target=x86_64-scei-ps4 -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-LTO,CHECK-LIB %s +// RUN: %clang --target=x86_64-scei-ps4 -flto=thin -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-LTO,CHECK-LIB %s +// RUN: %clang --target=x86_64-scei-ps4 -flto=full -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-LTO,CHECK-LIB %s -// CHECK-NOT: -enable-jmc-instrument -// CHECK-THIN-LTO: "-lto-thin-debug-options= -enable-jmc-instrument" -// CHECK-FULL-LTO: "-lto-debug-options= -enable-jmc-instrument" +// CHECK-LTO: "-lto-debug-options= -enable-jmc-instrument" // Check the default library name. // CHECK-LIB: "--whole-archive" "-lSceDbgJmc" "--no-whole-archive" // Test the driver's control over the -fcrash-diagnostics-dir behavior with linker flags. -// RUN: %clang --target=x86_64-scei-ps4 -flto=thin -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG-THIN-LTO %s -// RUN: %clang --target=x86_64-scei-ps4 -flto=full -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG-FULL-LTO %s +// RUN: %clang --target=x86_64-scei-ps4 -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG-LTO %s +// RUN: %clang --target=x86_64-scei-ps4 -flto=thin -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG-LTO %s +// RUN: %clang --target=x86_64-scei-ps4 -flto=full -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG-LTO %s -// CHECK-DIAG-THIN-LTO: "-lto-thin-debug-options= -crash-diagnostics-dir=mydumps" -// CHECK-DIAG-FULL-LTO: "-lto-debug-options= -crash-diagnostics-dir=mydumps" +// CHECK-DIAG-LTO: "-lto-debug-options= -crash-diagnostics-dir=mydumps" + +// Test that -lto-debug-options is only supplied to the linker when necessary + +// RUN: %clang --target=x86_64-scei-ps4 %s -### 2>&1 | FileCheck --check-prefixes=CHECK-NO-LTO %s +// CHECK-NO-LTO-NOT: -lto-debug-options diff --git a/clang/test/Driver/ps5-linker.c b/clang/test/Driver/ps5-linker.c index 9f1e3a273b2db2e..cf39d5bae97acd7 100644 --- a/clang/test/Driver/ps5-linker.c +++ b/clang/test/Driver/ps5-linker.c @@ -1,10 +1,9 @@ // Test the driver's control over the JustMyCode behavior with linker flags. // RUN: %clang --target=x86_64-scei-ps5 -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-LIB %s -// RUN: %clang --target=x86_64-scei-ps5 -flto -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK-LTO,CHECK-LIB %s +// RUN: %clang --target=x86_64-scei-ps5 -flto -fjmc %s -### 2>&1 | FileCheck --check-prefixes=CHECK,CHECK-LIB %s -// CHECK-NOT: -plugin-opt=-enable-jmc-instrument -// CHECK-LTO: -plugin-opt=-enable-jmc-instrument +// CHECK: -plugin-opt=-enable-jmc-instrument // Check the default library name. // CHECK-LIB: "--whole-archive" "-lSceJmc_nosubmission" "--no-whole-archive" @@ -12,7 +11,6 @@ // Test the driver's control over the -fcrash-diagnostics-dir behavior with linker flags. // RUN: %clang --target=x86_64-scei-ps5 -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG %s -// RUN: %clang --target=x86_64-scei-ps5 -flto -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG-LTO %s +// RUN: %clang --target=x86_64-scei-ps5 -flto -fcrash-diagnostics-dir=mydumps %s -### 2>&1 | FileCheck --check-prefixes=CHECK-DIAG %s -// CHECK-DIAG-NOT: -plugin-opt=-crash-diagnostics-dir=mydumps -// CHECK-DIAG-LTO: -plugin-opt=-crash-diagnostics-dir=mydumps +// CHECK-DIAG: -plugin-opt=-crash-diagnostics-dir=mydumps diff --git a/clang/test/Driver/stack-size-section.c b/clang/test/Driver/stack-size-section.c index 71b9f85692b99de..7cd41e491a8174b 100644 --- a/clang/test/Driver/stack-size-section.c +++ b/clang/test/Driver/stack-size-section.c @@ -14,6 +14,7 @@ // RUN: %clang -### --target=x86_64-linux-gnu -flto -fstack-size-section %s 2>&1 | FileCheck %s --check-prefix=LTO // RUN: %clang -### --target=x86_64-linux-gnu -flto -fstack-size-section -fno-stack-size-section %s 2>&1 | FileCheck %s --check-prefix=LTO-NO +// RUN: %clang -### --target=x86_64-sie-ps5 -fstack-size-section %s 2>&1 | FileCheck %s --check-prefix=LTO // LTO: "-plugin-opt=-stack-size-section" // LTO-NO-NOT: "-plugin-opt=-stack-size-section" diff --git a/clang/test/Driver/unified-lto.c b/clang/test/Driver/unified-lto.c index 3a6fe44f5b32dfd..445ca0bbf14f1b8 100644 --- a/clang/test/Driver/unified-lto.c +++ b/clang/test/Driver/unified-lto.c @@ -7,6 +7,27 @@ // NOUNIT-NOT: "-flto-unit" // RUN: %clang --target=x86_64-sie-ps5 -### %s -funified-lto 2>&1 | FileCheck --check-prefix=NOUNILTO %s -// NOUNILTO: clang: warning: argument unused during compilation: '-funified-lto' // NOUNILTO: "-cc1" // NOUNILTO-NOT: "-funified-lto + +// On PlayStation -funified-lto is the default. `-flto(=...)` influences the +// `--lto=...` option passed to linker, unless `-fno-unified-lto` is supplied. +// PS4: +// RUN: %clang --target=x86_64-sie-ps4 -### %s 2>&1 | FileCheck --check-prefixes=LD,LTOFULL %s +// RUN: %clang --target=x86_64-sie-ps4 -### %s -flto 2>&1 | FileCheck --check-prefixes=LD,LTOFULL %s +// RUN: %clang --target=x86_64-sie-ps4 -### %s -flto=full 2>&1 | FileCheck --check-prefixes=LD,LTOFULL %s +// RUN: %clang --target=x86_64-sie-ps4 -### %s -flto=thin 2>&1 | FileCheck --check-prefixes=LD,LTOTHIN %s +// RUN: %clang --target=x86_64-sie-ps4 -### %s -fno-unified-lto -flto=full 2>&1 | FileCheck --check-prefixes=LD,NOLTO %s +// RUN: %clang --target=x86_64-sie-ps4 -### %s -fno-unified-lto -flto=thin 2>&1 | FileCheck --check-prefixes=LD,NOLTO %s +// PS5: +// RUN: %clang --target=x86_64-sie-ps5 -### %s 2>&1 | FileCheck --check-prefixes=LD,LTOFULL %s +// RUN: %clang --target=x86_64-sie-ps5 -### %s -flto 2>&1 | FileCheck --check-prefixes=LD,LTOFULL %s +// RUN: %clang --target=x86_64-sie-ps5 -### %s -flto=full 2>&1 | FileCheck --check-prefixes=LD,LTOFULL %s +// RUN: %clang --target=x86_64-sie-ps5 -### %s -flto=thin 2>&1 | FileCheck --check-prefixes=LD,LTOTHIN %s +// RUN: %clang --target=x86_64-sie-ps5 -### %s -fno-unified-lto -flto=full 2>&1 | FileCheck --check-prefixes=LD,NOLTO %s +// RUN: %clang --target=x86_64-sie-ps5 -### %s -fno-unified-lto -flto=thin 2>&1 | FileCheck --check-prefixes=LD,NOLTO %s + +// LD: {{.*ld(\.exe)?}}" +// LTOFULL-SAME: "--lto=full" +// LTOTHIN-SAME: "--lto=thin" +// NOLTO-NOT: "--lto diff --git a/clang/test/Driver/x86-target-features.c b/clang/test/Driver/x86-target-features.c index 63237cbc3e7efad..7d77ae75f8c4701 100644 --- a/clang/test/Driver/x86-target-features.c +++ b/clang/test/Driver/x86-target-features.c @@ -309,8 +309,8 @@ // HRESET: "-target-feature" "+hreset" // NO-HRESET: "-target-feature" "-hreset" -// RUN: %clang --target=i386 -march=i386 -muintr %s -### 2>&1 | FileCheck -check-prefix=UINTR %s -// RUN: %clang --target=i386 -march=i386 -mno-uintr %s -### 2>&1 | FileCheck -check-prefix=NO-UINTR %s +// RUN: %clang --target=x86_64 -muintr %s -### 2>&1 | FileCheck -check-prefix=UINTR %s +// RUN: %clang --target=x86_64 -mno-uintr %s -### 2>&1 | FileCheck -check-prefix=NO-UINTR %s // UINTR: "-target-feature" "+uintr" // NO-UINTR: "-target-feature" "-uintr" @@ -409,6 +409,15 @@ // NONX86-NEXT: warning: argument unused during compilation: '-msse4.2' [-Wunused-command-line-argument] // NONX86-NEXT: error: unsupported option '-mno-sgx' for target 'aarch64' +// RUN: not %clang -### --target=i386 -muintr %s 2>&1 | FileCheck --check-prefix=NON-UINTR %s +// RUN: %clang -### --target=i386 -mno-uintr %s 2>&1 > /dev/null +// RUN: not %clang -### --target=i386 -mapx-features=ndd %s 2>&1 | FileCheck --check-prefix=NON-APX %s +// RUN: not %clang -### --target=i386 -mapxf %s 2>&1 | FileCheck --check-prefix=NON-APX %s +// RUN: %clang -### --target=i386 -mno-apxf %s 2>&1 > /dev/null +// NON-UINTR: error: unsupported option '-muintr' for target 'i386' +// NON-APX: error: unsupported option '-mapx-features=|-mapxf' for target 'i386' +// NON-APX-NOT: error: {{.*}} -mapx-features= + // RUN: %clang --target=i386 -march=i386 -mharden-sls=return %s -### -o %t.o 2>&1 | FileCheck -check-prefixes=SLS-RET,NO-SLS %s // RUN: %clang --target=i386 -march=i386 -mharden-sls=indirect-jmp %s -### -o %t.o 2>&1 | FileCheck -check-prefixes=SLS-IJMP,NO-SLS %s // RUN: %clang --target=i386 -march=i386 -mharden-sls=none -mharden-sls=all %s -### -o %t.o 2>&1 | FileCheck -check-prefixes=SLS-IJMP,SLS-RET %s diff --git a/clang/test/Frontend/skip-function-bodies.cpp b/clang/test/Frontend/skip-function-bodies.cpp new file mode 100644 index 000000000000000..d0593b474bda212 --- /dev/null +++ b/clang/test/Frontend/skip-function-bodies.cpp @@ -0,0 +1,13 @@ +// Trivial check to ensure skip-function-bodies flag is propagated. +// +// RUN: %clang_cc1 -verify -skip-function-bodies -pedantic-errors %s +// expected-no-diagnostics + +int f() { + // normally this should emit some diags, but we're skipping it! + this is garbage; +} + +// Make sure we only accept it as a cc1 arg. +// RUN: not %clang -skip-function-bodies %s 2>&1 | FileCheck %s +// CHECK: clang: error: unknown argument '-skip-function-bodies'; did you mean '-Xclang -skip-function-bodies'? diff --git a/clang/test/Headers/__clang_hip_cmath.hip b/clang/test/Headers/__clang_hip_cmath.hip index cd085fdb5039a61..ed1030b820627b6 100644 --- a/clang/test/Headers/__clang_hip_cmath.hip +++ b/clang/test/Headers/__clang_hip_cmath.hip @@ -13,7 +13,8 @@ // RUN: -internal-isystem %S/../../lib/Headers/cuda_wrappers \ // RUN: -internal-isystem %S/Inputs/include \ // RUN: -triple amdgcn-amd-amdhsa -aux-triple x86_64-unknown-unknown \ -// RUN: -target-cpu gfx906 -emit-llvm %s -fcuda-is-device -O1 -ffinite-math-only -o - \ +// RUN: -target-cpu gfx906 -emit-llvm %s -fcuda-is-device -O1 -menable-no-infs \ +// RUN: -menable-no-nans -o - \ // RUN: -D__HIPCC_RTC__ | FileCheck -check-prefix=FINITEONLY %s // DEFAULT-LABEL: @test_fma_f16( diff --git a/clang/test/Headers/__clang_hip_math.hip b/clang/test/Headers/__clang_hip_math.hip index 26da82843c5124d..6ee10976f120797 100644 --- a/clang/test/Headers/__clang_hip_math.hip +++ b/clang/test/Headers/__clang_hip_math.hip @@ -14,7 +14,8 @@ // RUN: -internal-isystem %S/../../lib/Headers/cuda_wrappers \ // RUN: -internal-isystem %S/Inputs/include \ // RUN: -triple amdgcn-amd-amdhsa -aux-triple x86_64-unknown-unknown \ -// RUN: -target-cpu gfx906 -emit-llvm %s -fcuda-is-device -O1 -ffinite-math-only -o - \ +// RUN: -target-cpu gfx906 -emit-llvm %s -fcuda-is-device -O1 -menable-no-infs \ +// RUN: -menable-no-nans -o - \ // RUN: -D__HIPCC_RTC__ | FileCheck -check-prefixes=CHECK,FINITEONLY %s // Check that we end up with -fapprox-func set on intrinsic calls diff --git a/clang/test/Headers/float.c b/clang/test/Headers/float.c index d524d0e53f3fd4f..a3dd9c90f785c83 100644 --- a/clang/test/Headers/float.c +++ b/clang/test/Headers/float.c @@ -2,7 +2,7 @@ // RUN: %clang_cc1 -fsyntax-only -verify -std=c99 -ffreestanding %s // RUN: %clang_cc1 -fsyntax-only -verify -std=c11 -ffreestanding %s // RUN: %clang_cc1 -fsyntax-only -verify -std=c23 -ffreestanding %s -// RUN: %clang_cc1 -fsyntax-only -verify=finite -std=c23 -ffreestanding -ffinite-math-only %s +// RUN: %clang_cc1 -fsyntax-only -verify=finite -std=c23 -ffreestanding -menable-no-nans -menable-no-infs %s // RUN: %clang_cc1 -fsyntax-only -verify -xc++ -std=c++11 -ffreestanding %s // RUN: %clang_cc1 -fsyntax-only -verify -xc++ -std=c++14 -ffreestanding %s // RUN: %clang_cc1 -fsyntax-only -verify -xc++ -std=c++17 -ffreestanding %s @@ -223,8 +223,9 @@ #ifndef NAN #error "Mandatory macro NAN is missing." #endif - // FIXME: the NAN diagnostic should only be issued once, not twice. - _Static_assert(_Generic(INFINITY, float : 1, default : 0), ""); // finite-warning {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// FIXME: the NAN and INF diagnostics should only be issued once, not twice. + _Static_assert(_Generic(INFINITY, float : 1, default : 0), ""); // finite-warning {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} \ + finite-warning {{use of infinity is undefined behavior due to the currently enabled floating-point options}} _Static_assert(_Generic(NAN, float : 1, default : 0), ""); // finite-warning {{use of NaN is undefined behavior due to the currently enabled floating-point options}} \ finite-warning {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} diff --git a/clang/test/InstallAPI/directory-scanning-subdirectories.test b/clang/test/InstallAPI/directory-scanning-subdirectories.test new file mode 100644 index 000000000000000..3eac90440fa1e71 --- /dev/null +++ b/clang/test/InstallAPI/directory-scanning-subdirectories.test @@ -0,0 +1,61 @@ +; RUN: rm -rf %t +; RUN: split-file %s %t +; RUN: mkdir -p %t/DstRoot/ +; RUN: cp -r %S/Inputs/LibFoo/* %t/DstRoot/ + +; RUN: clang-installapi \ +; RUN: -target arm64-apple-macos12 -install_name @rpath/libfoo.dylib \ +; RUN: -current_version 1 -compatibility_version 1 \ +; RUN: -I%t/DstRoot/usr/include -dynamiclib \ +; RUN: -exclude-public-header %t/DstRoot/usr/include/public.h \ +; RUN: %t/DstRoot -o %t/output.tbd 2>&1 | FileCheck %s --allow-empty \ +; RUN: --implicit-check-not=error --implicit-check-not=warning +; RUN: llvm-readtapi --compare %t/output.tbd %t/expected.tbd + + +;--- DstRoot/usr/include/extra/extra.h +int extra(void); + +;--- DstRoot/usr/include/extra/additional/additional.h +int additional(void); + +;--- DstRoot/usr/include/more/more.h +int more(void); + +;--- DstRoot/usr/include/another/another.h +int another(void); + +;--- expected.tbd +{ + "main_library": { + "exported_symbols": [ + { + "text": { + "global": [ + "_foo", "_additional", "_more", + "_another", "_extra" + ] + } + } + ], + "flags": [ + { + "attributes": [ + "not_app_extension_safe" + ] + } + ], + "install_names": [ + { + "name": "@rpath/libfoo.dylib" + } + ], + "target_info": [ + { + "min_deployment": "12", + "target": "arm64-macos" + } + ] + }, + "tapi_tbd_version": 5 +} diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test index 33f9c2f51363c64..e082db698ef0ced 100644 --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -83,6 +83,7 @@ // CHECK-NEXT: HIPManaged (SubjectMatchRule_variable) // CHECK-NEXT: HLSLResourceClass (SubjectMatchRule_record_not_is_union) // CHECK-NEXT: Hot (SubjectMatchRule_function) +// CHECK-NEXT: HybridPatchable (SubjectMatchRule_function) // CHECK-NEXT: IBAction (SubjectMatchRule_objc_method_is_instance) // CHECK-NEXT: IFunc (SubjectMatchRule_function) // CHECK-NEXT: InitPriority (SubjectMatchRule_variable) diff --git a/clang/test/OpenMP/amdgpu-unsafe-fp-atomics.cpp b/clang/test/OpenMP/amdgpu-unsafe-fp-atomics.cpp new file mode 100644 index 000000000000000..7a34113cec8fa17 --- /dev/null +++ b/clang/test/OpenMP/amdgpu-unsafe-fp-atomics.cpp @@ -0,0 +1,59 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5 +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple amdgcn-amd-amdhsa -fopenmp-targets=amdgcn-amd-amdhsa -emit-llvm %s -fopenmp-is-target-device -o - | FileCheck -check-prefix=DEFAULT %s +// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple amdgcn-amd-amdhsa -fopenmp-targets=amdgcn-amd-amdhsa -munsafe-fp-atomics -emit-llvm %s -fopenmp-is-target-device -o - | FileCheck -check-prefix=UNSAFE-FP-ATOMICS %s + +#pragma omp declare target + +float fv, fx; +double dv, dx; + +// DEFAULT-LABEL: define hidden void @_Z15atomic_fadd_f32v( +// DEFAULT-SAME: ) #[[ATTR0:[0-9]+]] { +// DEFAULT-NEXT: [[ENTRY:.*:]] +// DEFAULT-NEXT: [[TMP0:%.*]] = load float, ptr addrspacecast (ptr addrspace(1) @fv to ptr), align 4 +// DEFAULT-NEXT: [[TMP1:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @fx to ptr), float [[TMP0]] monotonic, align 4 +// DEFAULT-NEXT: [[ADD:%.*]] = fadd float [[TMP1]], [[TMP0]] +// DEFAULT-NEXT: store float [[ADD]], ptr addrspacecast (ptr addrspace(1) @fv to ptr), align 4 +// DEFAULT-NEXT: ret void +// +// UNSAFE-FP-ATOMICS-LABEL: define hidden void @_Z15atomic_fadd_f32v( +// UNSAFE-FP-ATOMICS-SAME: ) #[[ATTR0:[0-9]+]] { +// UNSAFE-FP-ATOMICS-NEXT: [[ENTRY:.*:]] +// UNSAFE-FP-ATOMICS-NEXT: [[TMP0:%.*]] = load float, ptr addrspacecast (ptr addrspace(1) @fv to ptr), align 4 +// UNSAFE-FP-ATOMICS-NEXT: [[TMP1:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @fx to ptr), float [[TMP0]] monotonic, align 4, !amdgpu.no.fine.grained.memory [[META5:![0-9]+]], !amdgpu.ignore.denormal.mode [[META5]] +// UNSAFE-FP-ATOMICS-NEXT: [[ADD:%.*]] = fadd float [[TMP1]], [[TMP0]] +// UNSAFE-FP-ATOMICS-NEXT: store float [[ADD]], ptr addrspacecast (ptr addrspace(1) @fv to ptr), align 4 +// UNSAFE-FP-ATOMICS-NEXT: ret void +// +void atomic_fadd_f32() { +#pragma omp atomic capture + fv = fx = fx + fv; +} + +// DEFAULT-LABEL: define hidden void @_Z15atomic_fadd_f64v( +// DEFAULT-SAME: ) #[[ATTR0]] { +// DEFAULT-NEXT: [[ENTRY:.*:]] +// DEFAULT-NEXT: [[TMP0:%.*]] = load double, ptr addrspacecast (ptr addrspace(1) @dv to ptr), align 8 +// DEFAULT-NEXT: [[TMP1:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @dx to ptr), double [[TMP0]] monotonic, align 8 +// DEFAULT-NEXT: [[ADD:%.*]] = fadd double [[TMP1]], [[TMP0]] +// DEFAULT-NEXT: store double [[ADD]], ptr addrspacecast (ptr addrspace(1) @dv to ptr), align 8 +// DEFAULT-NEXT: ret void +// +// UNSAFE-FP-ATOMICS-LABEL: define hidden void @_Z15atomic_fadd_f64v( +// UNSAFE-FP-ATOMICS-SAME: ) #[[ATTR0]] { +// UNSAFE-FP-ATOMICS-NEXT: [[ENTRY:.*:]] +// UNSAFE-FP-ATOMICS-NEXT: [[TMP0:%.*]] = load double, ptr addrspacecast (ptr addrspace(1) @dv to ptr), align 8 +// UNSAFE-FP-ATOMICS-NEXT: [[TMP1:%.*]] = atomicrmw fadd ptr addrspacecast (ptr addrspace(1) @dx to ptr), double [[TMP0]] monotonic, align 8, !amdgpu.no.fine.grained.memory [[META5]] +// UNSAFE-FP-ATOMICS-NEXT: [[ADD:%.*]] = fadd double [[TMP1]], [[TMP0]] +// UNSAFE-FP-ATOMICS-NEXT: store double [[ADD]], ptr addrspacecast (ptr addrspace(1) @dv to ptr), align 8 +// UNSAFE-FP-ATOMICS-NEXT: ret void +// +void atomic_fadd_f64() { +#pragma omp atomic capture + dv = dx = dx + dv; +} + +#pragma omp end declare target +//. +// UNSAFE-FP-ATOMICS: [[META5]] = !{} +//. diff --git a/clang/test/OpenMP/nvptx_target_printf_codegen.c b/clang/test/OpenMP/nvptx_target_printf_codegen.c deleted file mode 100644 index f53daf65205c91c..000000000000000 --- a/clang/test/OpenMP/nvptx_target_printf_codegen.c +++ /dev/null @@ -1,179 +0,0 @@ -// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs --replace-value-regex "__omp_offloading_[0-9a-z]+_[0-9a-z]+" "reduction_size[.].+[.]" "pl_cond[.].+[.|,]" --prefix-filecheck-ir-name _ -// Test target codegen - host bc file has to be created first. -// RUN: %clang_cc1 -verify -fopenmp -x c -triple powerpc64le-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-ppc-host.bc -// RUN: %clang_cc1 -verify -fopenmp -x c -triple nvptx64-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm %s -fopenmp-is-target-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix=CHECK-64 -// RUN: %clang_cc1 -verify -fopenmp -x c -triple i386-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm-bc %s -o %t-x86-host.bc -// RUN: %clang_cc1 -verify -fopenmp -x c -triple nvptx-unknown-unknown -fopenmp-targets=nvptx-nvidia-cuda -emit-llvm %s -fopenmp-is-target-device -fopenmp-host-ir-file-path %t-x86-host.bc -o - | FileCheck %s --check-prefix=CHECK-32 -// expected-no-diagnostics -extern int printf(const char *, ...); - - -// Check a simple call to printf end-to-end. -int CheckSimple(void) { -#pragma omp target - { - // printf in master-only basic block. - const char* fmt = "%d %lld %f"; - - printf(fmt, 1, 2ll, 3.0); - } - - return 0; -} - -void CheckNoArgs(void) { -#pragma omp target - { - // printf in master-only basic block. - printf("hello, world!"); - } -} - -// Check that printf's alloca happens in the entry block, not inside the if -// statement. -int foo; -void CheckAllocaIsInEntryBlock(void) { -#pragma omp target - { - if (foo) { - printf("%d", 42); - } - } -} -// CHECK-64-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_CheckSimple_l13 -// CHECK-64-SAME: (ptr noalias noundef [[DYN_PTR:%.*]]) #[[ATTR0:[0-9]+]] { -// CHECK-64-NEXT: entry: -// CHECK-64-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8 -// CHECK-64-NEXT: [[FMT:%.*]] = alloca ptr, align 8 -// CHECK-64-NEXT: [[TMP:%.*]] = alloca [[PRINTF_ARGS:%.*]], align 8 -// CHECK-64-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 8 -// CHECK-64-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_target_init(ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_CheckSimple_l13_kernel_environment, ptr [[DYN_PTR]]) -// CHECK-64-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP0]], -1 -// CHECK-64-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]] -// CHECK-64: user_code.entry: -// CHECK-64-NEXT: store ptr @.str, ptr [[FMT]], align 8 -// CHECK-64-NEXT: [[TMP1:%.*]] = load ptr, ptr [[FMT]], align 8 -// CHECK-64-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[PRINTF_ARGS]], ptr [[TMP]], i32 0, i32 0 -// CHECK-64-NEXT: store i32 1, ptr [[TMP2]], align 4 -// CHECK-64-NEXT: [[TMP3:%.*]] = getelementptr inbounds [[PRINTF_ARGS]], ptr [[TMP]], i32 0, i32 1 -// CHECK-64-NEXT: store i64 2, ptr [[TMP3]], align 8 -// CHECK-64-NEXT: [[TMP4:%.*]] = getelementptr inbounds [[PRINTF_ARGS]], ptr [[TMP]], i32 0, i32 2 -// CHECK-64-NEXT: store double 3.000000e+00, ptr [[TMP4]], align 8 -// CHECK-64-NEXT: [[TMP5:%.*]] = call i32 @__llvm_omp_vprintf(ptr [[TMP1]], ptr [[TMP]], i32 24) -// CHECK-64-NEXT: call void @__kmpc_target_deinit() -// CHECK-64-NEXT: ret void -// CHECK-64: worker.exit: -// CHECK-64-NEXT: ret void -// -// -// CHECK-64-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_CheckNoArgs_l25 -// CHECK-64-SAME: (ptr noalias noundef [[DYN_PTR:%.*]]) #[[ATTR0]] { -// CHECK-64-NEXT: entry: -// CHECK-64-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8 -// CHECK-64-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 8 -// CHECK-64-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_target_init(ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_CheckNoArgs_l25_kernel_environment, ptr [[DYN_PTR]]) -// CHECK-64-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP0]], -1 -// CHECK-64-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]] -// CHECK-64: user_code.entry: -// CHECK-64-NEXT: [[TMP1:%.*]] = call i32 @__llvm_omp_vprintf(ptr @.str1, ptr null, i32 0) -// CHECK-64-NEXT: call void @__kmpc_target_deinit() -// CHECK-64-NEXT: ret void -// CHECK-64: worker.exit: -// CHECK-64-NEXT: ret void -// -// -// CHECK-64-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_CheckAllocaIsInEntryBlock_l36 -// CHECK-64-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], i64 noundef [[FOO:%.*]]) #[[ATTR0]] { -// CHECK-64-NEXT: entry: -// CHECK-64-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8 -// CHECK-64-NEXT: [[FOO_ADDR:%.*]] = alloca i64, align 8 -// CHECK-64-NEXT: [[TMP:%.*]] = alloca [[PRINTF_ARGS_0:%.*]], align 8 -// CHECK-64-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 8 -// CHECK-64-NEXT: store i64 [[FOO]], ptr [[FOO_ADDR]], align 8 -// CHECK-64-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_target_init(ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_CheckAllocaIsInEntryBlock_l36_kernel_environment, ptr [[DYN_PTR]]) -// CHECK-64-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP0]], -1 -// CHECK-64-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]] -// CHECK-64: user_code.entry: -// CHECK-64-NEXT: [[TMP1:%.*]] = load i32, ptr [[FOO_ADDR]], align 4 -// CHECK-64-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP1]], 0 -// CHECK-64-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] -// CHECK-64: if.then: -// CHECK-64-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[PRINTF_ARGS_0]], ptr [[TMP]], i32 0, i32 0 -// CHECK-64-NEXT: store i32 42, ptr [[TMP2]], align 4 -// CHECK-64-NEXT: [[TMP3:%.*]] = call i32 @__llvm_omp_vprintf(ptr @.str2, ptr [[TMP]], i32 4) -// CHECK-64-NEXT: br label [[IF_END]] -// CHECK-64: worker.exit: -// CHECK-64-NEXT: ret void -// CHECK-64: if.end: -// CHECK-64-NEXT: call void @__kmpc_target_deinit() -// CHECK-64-NEXT: ret void -// -// -// CHECK-32-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_CheckSimple_l13 -// CHECK-32-SAME: (ptr noalias noundef [[DYN_PTR:%.*]]) #[[ATTR0:[0-9]+]] { -// CHECK-32-NEXT: entry: -// CHECK-32-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 4 -// CHECK-32-NEXT: [[FMT:%.*]] = alloca ptr, align 4 -// CHECK-32-NEXT: [[TMP:%.*]] = alloca [[PRINTF_ARGS:%.*]], align 8 -// CHECK-32-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 4 -// CHECK-32-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_target_init(ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_CheckSimple_l13_kernel_environment, ptr [[DYN_PTR]]) -// CHECK-32-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP0]], -1 -// CHECK-32-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]] -// CHECK-32: user_code.entry: -// CHECK-32-NEXT: store ptr @.str, ptr [[FMT]], align 4 -// CHECK-32-NEXT: [[TMP1:%.*]] = load ptr, ptr [[FMT]], align 4 -// CHECK-32-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[PRINTF_ARGS]], ptr [[TMP]], i32 0, i32 0 -// CHECK-32-NEXT: store i32 1, ptr [[TMP2]], align 4 -// CHECK-32-NEXT: [[TMP3:%.*]] = getelementptr inbounds [[PRINTF_ARGS]], ptr [[TMP]], i32 0, i32 1 -// CHECK-32-NEXT: store i64 2, ptr [[TMP3]], align 8 -// CHECK-32-NEXT: [[TMP4:%.*]] = getelementptr inbounds [[PRINTF_ARGS]], ptr [[TMP]], i32 0, i32 2 -// CHECK-32-NEXT: store double 3.000000e+00, ptr [[TMP4]], align 8 -// CHECK-32-NEXT: [[TMP5:%.*]] = call i32 @__llvm_omp_vprintf(ptr [[TMP1]], ptr [[TMP]], i32 24) -// CHECK-32-NEXT: call void @__kmpc_target_deinit() -// CHECK-32-NEXT: ret void -// CHECK-32: worker.exit: -// CHECK-32-NEXT: ret void -// -// -// CHECK-32-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_CheckNoArgs_l25 -// CHECK-32-SAME: (ptr noalias noundef [[DYN_PTR:%.*]]) #[[ATTR0]] { -// CHECK-32-NEXT: entry: -// CHECK-32-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 4 -// CHECK-32-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 4 -// CHECK-32-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_target_init(ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_CheckNoArgs_l25_kernel_environment, ptr [[DYN_PTR]]) -// CHECK-32-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP0]], -1 -// CHECK-32-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]] -// CHECK-32: user_code.entry: -// CHECK-32-NEXT: [[TMP1:%.*]] = call i32 @__llvm_omp_vprintf(ptr @.str1, ptr null, i32 0) -// CHECK-32-NEXT: call void @__kmpc_target_deinit() -// CHECK-32-NEXT: ret void -// CHECK-32: worker.exit: -// CHECK-32-NEXT: ret void -// -// -// CHECK-32-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_CheckAllocaIsInEntryBlock_l36 -// CHECK-32-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], i32 noundef [[FOO:%.*]]) #[[ATTR0]] { -// CHECK-32-NEXT: entry: -// CHECK-32-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 4 -// CHECK-32-NEXT: [[FOO_ADDR:%.*]] = alloca i32, align 4 -// CHECK-32-NEXT: [[TMP:%.*]] = alloca [[PRINTF_ARGS_0:%.*]], align 8 -// CHECK-32-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 4 -// CHECK-32-NEXT: store i32 [[FOO]], ptr [[FOO_ADDR]], align 4 -// CHECK-32-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_target_init(ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_CheckAllocaIsInEntryBlock_l36_kernel_environment, ptr [[DYN_PTR]]) -// CHECK-32-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP0]], -1 -// CHECK-32-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]] -// CHECK-32: user_code.entry: -// CHECK-32-NEXT: [[TMP1:%.*]] = load i32, ptr [[FOO_ADDR]], align 4 -// CHECK-32-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP1]], 0 -// CHECK-32-NEXT: br i1 [[TOBOOL]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] -// CHECK-32: if.then: -// CHECK-32-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[PRINTF_ARGS_0]], ptr [[TMP]], i32 0, i32 0 -// CHECK-32-NEXT: store i32 42, ptr [[TMP2]], align 4 -// CHECK-32-NEXT: [[TMP3:%.*]] = call i32 @__llvm_omp_vprintf(ptr @.str2, ptr [[TMP]], i32 4) -// CHECK-32-NEXT: br label [[IF_END]] -// CHECK-32: worker.exit: -// CHECK-32-NEXT: ret void -// CHECK-32: if.end: -// CHECK-32-NEXT: call void @__kmpc_target_deinit() -// CHECK-32-NEXT: ret void -// diff --git a/clang/test/OpenMP/target_defaultmap_messages.cpp b/clang/test/OpenMP/target_defaultmap_messages.cpp index 8052e34d5c9336b..88ae3b7962d55f7 100644 --- a/clang/test/OpenMP/target_defaultmap_messages.cpp +++ b/clang/test/OpenMP/target_defaultmap_messages.cpp @@ -1,5 +1,8 @@ -// RUN: %clang_cc1 -verify -Wno-vla -fopenmp %s -verify=expected,omp51 -Wuninitialized -DOMP51 -// RUN: %clang_cc1 -verify -Wno-vla -fopenmp-simd %s -verify=expected,omp51 -Wuninitialized -DOMP51 +// RUN: %clang_cc1 -verify -Wno-vla -fopenmp %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized +// RUN: %clang_cc1 -verify -Wno-vla -fopenmp-simd %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized + +// RUN: %clang_cc1 -verify -Wno-vla -fopenmp %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized -DOMP51 +// RUN: %clang_cc1 -verify -Wno-vla -fopenmp-simd %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized -DOMP51 // RUN: %clang_cc1 -verify -Wno-vla -fopenmp -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 // RUN: %clang_cc1 -verify -Wno-vla -fopenmp-simd -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 @@ -30,23 +33,23 @@ template T tmain(T argc, S **argv) { #pragma omp target defaultmap // expected-error {{expected '(' after 'defaultmap'}} foo(); -#pragma omp target defaultmap( // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target defaultmap( // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); -#pragma omp target defaultmap() // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target defaultmap() // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); - #pragma omp target defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} + #pragma omp target defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); - #pragma omp target defaultmap (scalar: // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} + #pragma omp target defaultmap (scalar: // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); - #pragma omp target defaultmap(tofrom:scalar) defaultmap(tofrom:scalar) // omp45-error {{directive '#pragma omp target' cannot contain more than one 'defaultmap' clause}} omp5-error {{at most one defaultmap clause for each variable-category can appear on the directive}} omp51-error {{at most one defaultmap clause for each variable-category can appear on the directive}} + #pragma omp target defaultmap(tofrom:scalar) defaultmap(tofrom:scalar) // omp45-error {{directive '#pragma omp target' cannot contain more than one 'defaultmap' clause}} omp5-error {{at most one defaultmap clause for each variable-category can appear on the directive}} omp5x-error {{at most one defaultmap clause for each variable-category can appear on the directive}} foo(); @@ -93,23 +96,23 @@ T tmain(T argc, S **argv) { int main(int argc, char **argv) { #pragma omp target defaultmap // expected-error {{expected '(' after 'defaultmap'}} foo(); -#pragma omp target defaultmap( // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target defaultmap( // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); -#pragma omp target defaultmap() // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target defaultmap() // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); -#pragma omp target defaultmap(tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} +#pragma omp target defaultmap(tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); -#pragma omp target defaultmap(scalar: // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target defaultmap(scalar: // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); -#pragma omp target defaultmap(tofrom: scalar) defaultmap(tofrom: scalar) // omp45-error {{directive '#pragma omp target' cannot contain more than one 'defaultmap' clause}} omp5-error {{at most one defaultmap clause for each variable-category can appear on the directive}} omp51-error {{at most one defaultmap clause for each variable-category can appear on the directive}} +#pragma omp target defaultmap(tofrom: scalar) defaultmap(tofrom: scalar) // omp45-error {{directive '#pragma omp target' cannot contain more than one 'defaultmap' clause}} omp5-error {{at most one defaultmap clause for each variable-category can appear on the directive}} omp5x-error {{at most one defaultmap clause for each variable-category can appear on the directive}} foo(); #ifdef OMP5 diff --git a/clang/test/OpenMP/target_parallel_defaultmap_messages.cpp b/clang/test/OpenMP/target_parallel_defaultmap_messages.cpp index 4c226e9ca2aef8b..3c628c4f3e1720c 100644 --- a/clang/test/OpenMP/target_parallel_defaultmap_messages.cpp +++ b/clang/test/OpenMP/target_parallel_defaultmap_messages.cpp @@ -1,5 +1,8 @@ -// RUN: %clang_cc1 -verify -fopenmp %s -verify=expected,omp51 -Wuninitialized -Wno-vla -DOMP51 -// RUN: %clang_cc1 -verify -fopenmp-simd %s -verify=expected,omp51 -Wuninitialized -Wno-vla -DOMP51 +// RUN: %clang_cc1 -verify -Wno-vla -fopenmp %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized +// RUN: %clang_cc1 -verify -Wno-vla -fopenmp-simd %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized + +// RUN: %clang_cc1 -verify -Wno-vla -fopenmp %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized -DOMP51 +// RUN: %clang_cc1 -verify -Wno-vla -fopenmp-simd %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized -DOMP51 // RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -Wno-vla -DOMP5 // RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -Wno-vla -DOMP5 @@ -28,19 +31,19 @@ void foo() { template T tmain(T argc, S **argv) { -#pragma omp target parallel defaultmap( // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target parallel defaultmap( // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); -#pragma omp target parallel defaultmap() // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target parallel defaultmap() // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target parallel defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); - #pragma omp target parallel defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} + #pragma omp target parallel defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target parallel defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target parallel defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); - #pragma omp target parallel defaultmap (scalar: // expected-error {{expected ')'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} + #pragma omp target parallel defaultmap (scalar: // expected-error {{expected ')'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target parallel defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); @@ -90,19 +93,19 @@ T tmain(T argc, S **argv) { } int main(int argc, char **argv) { -#pragma omp target parallel defaultmap( // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target parallel defaultmap( // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); -#pragma omp target parallel defaultmap() // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target parallel defaultmap() // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target parallel defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); - #pragma omp target parallel defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} + #pragma omp target parallel defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target parallel defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target parallel defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); - #pragma omp target parallel defaultmap (scalar: // expected-error {{expected ')'}} omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} + #pragma omp target parallel defaultmap (scalar: // expected-error {{expected ')'}} omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target parallel defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); diff --git a/clang/test/OpenMP/target_parallel_for_defaultmap_messages.cpp b/clang/test/OpenMP/target_parallel_for_defaultmap_messages.cpp index 8b58bb9111c8119..b142ae1733a3c53 100644 --- a/clang/test/OpenMP/target_parallel_for_defaultmap_messages.cpp +++ b/clang/test/OpenMP/target_parallel_for_defaultmap_messages.cpp @@ -1,5 +1,8 @@ -// RUN: %clang_cc1 -verify -fopenmp %s -verify=expected,omp51 -Wuninitialized -// RUN: %clang_cc1 -verify -fopenmp-simd %s -verify=expected,omp51 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized + +// RUN: %clang_cc1 -verify -fopenmp %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized // RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 // RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 @@ -15,21 +18,21 @@ T tmain(T argc, S **argv) { int i; #pragma omp target parallel for defaultmap // expected-error {{expected '(' after 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target parallel for defaultmap( // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target parallel for defaultmap( // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target parallel for defaultmap() // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target parallel for defaultmap() // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); - #pragma omp target parallel for defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} + #pragma omp target parallel for defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target parallel for defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp51-error {{expected ')'}} omp5-note {{to match this '('}} omp51-note {{to match this '('}} +#pragma omp target parallel for defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5x-error {{expected ')'}} omp5-note {{to match this '('}} omp5x-note {{to match this '('}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); - #pragma omp target parallel for defaultmap (scalar: // expected-error {{expected ')'}} omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} + #pragma omp target parallel for defaultmap (scalar: // expected-error {{expected ')'}} omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); @@ -41,21 +44,21 @@ int main(int argc, char **argv) { int i; #pragma omp target parallel for defaultmap // expected-error {{expected '(' after 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target parallel for defaultmap( // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target parallel for defaultmap( // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target parallel for defaultmap() // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target parallel for defaultmap() // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); - #pragma omp target parallel for defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} + #pragma omp target parallel for defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target parallel for defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp51-error {{expected ')'}} omp5-note {{to match this '('}} omp51-note {{to match this '('}} +#pragma omp target parallel for defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5x-error {{expected ')'}} omp5-note {{to match this '('}} omp5x-note {{to match this '('}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); - #pragma omp target parallel for defaultmap (scalar: // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} + #pragma omp target parallel for defaultmap (scalar: // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); diff --git a/clang/test/OpenMP/target_parallel_for_simd_defaultmap_messages.cpp b/clang/test/OpenMP/target_parallel_for_simd_defaultmap_messages.cpp index 7d72547d24e1ee0..46f78290cba4bf9 100644 --- a/clang/test/OpenMP/target_parallel_for_simd_defaultmap_messages.cpp +++ b/clang/test/OpenMP/target_parallel_for_simd_defaultmap_messages.cpp @@ -1,5 +1,8 @@ -// RUN: %clang_cc1 -verify -fopenmp %s -verify=expected,omp51 -Wuninitialized -// RUN: %clang_cc1 -verify -fopenmp-simd %s -verify=expected,omp51 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized + +// RUN: %clang_cc1 -verify -fopenmp %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized // RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 // RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 @@ -15,21 +18,21 @@ T tmain(T argc, S **argv) { int i; #pragma omp target parallel for simd defaultmap // expected-error {{expected '(' after 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target parallel for simd defaultmap( // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target parallel for simd defaultmap( // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target parallel for simd defaultmap() // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target parallel for simd defaultmap() // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for simd defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); - #pragma omp target parallel for simd defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} + #pragma omp target parallel for simd defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for simd defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target parallel for simd defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp51-error {{expected ')'}} omp51-note {{to match this '('}} +#pragma omp target parallel for simd defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp5x-error {{expected ')'}} omp5x-note {{to match this '('}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for simd defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); - #pragma omp target parallel for simd defaultmap (scalar: // expected-error {{expected ')'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} + #pragma omp target parallel for simd defaultmap (scalar: // expected-error {{expected ')'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for simd defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); @@ -41,21 +44,21 @@ int main(int argc, char **argv) { int i; #pragma omp target parallel for simd defaultmap // expected-error {{expected '(' after 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target parallel for simd defaultmap( // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target parallel for simd defaultmap( // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target parallel for simd defaultmap() // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target parallel for simd defaultmap() // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for simd defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); - #pragma omp target parallel for simd defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} + #pragma omp target parallel for simd defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for simd defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target parallel for simd defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp51-error {{expected ')'}} omp51-note {{to match this '('}} +#pragma omp target parallel for simd defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp5x-error {{expected ')'}} omp5x-note {{to match this '('}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for simd defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); - #pragma omp target parallel for simd defaultmap (scalar: // expected-error {{expected ')'}} omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} + #pragma omp target parallel for simd defaultmap (scalar: // expected-error {{expected ')'}} omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target parallel for simd defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); diff --git a/clang/test/OpenMP/target_simd_defaultmap_messages.cpp b/clang/test/OpenMP/target_simd_defaultmap_messages.cpp index 0fa86cc7279ad67..2169681e05749f9 100644 --- a/clang/test/OpenMP/target_simd_defaultmap_messages.cpp +++ b/clang/test/OpenMP/target_simd_defaultmap_messages.cpp @@ -1,5 +1,8 @@ -// RUN: %clang_cc1 -verify -fopenmp %s -verify=expected,omp51 -Wuninitialized -// RUN: %clang_cc1 -verify -fopenmp-simd %s -verify=expected,omp51 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized + +// RUN: %clang_cc1 -verify -fopenmp %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized // RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 // RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 @@ -15,24 +18,24 @@ T tmain(T argc, S **argv) { int i; #pragma omp target simd defaultmap // expected-error {{expected '(' after 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target simd defaultmap( // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target simd defaultmap( // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target simd defaultmap() // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target simd defaultmap() // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target simd defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target simd defaultmap(tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} +#pragma omp target simd defaultmap(tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target simd defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target simd defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp51-error {{expected ')'}} omp51-note {{to match this '('}} +#pragma omp target simd defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp5x-error {{expected ')'}} omp5x-note {{to match this '('}} for (i = 0; i < argc; ++i) foo(); #pragma omp target simd defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); - #pragma omp target simd defaultmap (scalar: // expected-error {{expected ')'}} omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} + #pragma omp target simd defaultmap (scalar: // expected-error {{expected ')'}} omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target simd defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} @@ -46,28 +49,28 @@ int main(int argc, char **argv) { #pragma omp target simd defaultmap // expected-error {{expected '(' after 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target simd defaultmap( // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target simd defaultmap( // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target simd defaultmap() // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target simd defaultmap() // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target simd defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target simd defaultmap(tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} +#pragma omp target simd defaultmap(tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target simd defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target simd defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp51-error {{expected ')'}} omp51-note {{to match this '('}} +#pragma omp target simd defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp5x-error {{expected ')'}} omp5x-note {{to match this '('}} for (i = 0; i < argc; ++i) foo(); #pragma omp target simd defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target simd defaultmap(scalar: // expected-error {{expected ')'}} omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} +#pragma omp target simd defaultmap(scalar: // expected-error {{expected ')'}} omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target simd defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} diff --git a/clang/test/OpenMP/target_teams_defaultmap_messages.cpp b/clang/test/OpenMP/target_teams_defaultmap_messages.cpp index 206a1e4f18af26a..97ed5315c4c8ed0 100644 --- a/clang/test/OpenMP/target_teams_defaultmap_messages.cpp +++ b/clang/test/OpenMP/target_teams_defaultmap_messages.cpp @@ -1,5 +1,8 @@ -// RUN: %clang_cc1 -verify -fopenmp %s -verify=expected,omp51 -Wuninitialized -// RUN: %clang_cc1 -verify -fopenmp-simd %s -verify=expected,omp51 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized + +// RUN: %clang_cc1 -verify -fopenmp %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized // RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 // RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 @@ -14,21 +17,21 @@ template T tmain(T argc, S **argv) { #pragma omp target teams defaultmap // expected-error {{expected '(' after 'defaultmap'}} foo(); -#pragma omp target teams defaultmap( // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams defaultmap( // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); -#pragma omp target teams defaultmap() // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams defaultmap() // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target teams defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); - #pragma omp target teams defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} + #pragma omp target teams defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target teams defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); -#pragma omp target teams defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp51-error {{expected ')'}} omp51-note {{to match this '('}} +#pragma omp target teams defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp5x-error {{expected ')'}} omp5x-note {{to match this '('}} foo(); #pragma omp target teams defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); - #pragma omp target teams defaultmap (scalar: // expected-error {{expected ')'}} omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} + #pragma omp target teams defaultmap (scalar: // expected-error {{expected ')'}} omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target teams defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); @@ -39,21 +42,21 @@ T tmain(T argc, S **argv) { int main(int argc, char **argv) { #pragma omp target teams defaultmap // expected-error {{expected '(' after 'defaultmap'}} foo(); -#pragma omp target teams defaultmap( // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams defaultmap( // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); -#pragma omp target teams defaultmap() // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams defaultmap() // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target teams defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); - #pragma omp target teams defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} + #pragma omp target teams defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target teams defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); -#pragma omp target teams defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp51-error {{expected ')'}} omp51-note {{to match this '('}} +#pragma omp target teams defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp5x-error {{expected ')'}} omp5x-note {{to match this '('}} foo(); #pragma omp target teams defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); - #pragma omp target teams defaultmap (scalar: // expected-error {{expected ')'}} omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} + #pragma omp target teams defaultmap (scalar: // expected-error {{expected ')'}} omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} foo(); #pragma omp target teams defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} foo(); diff --git a/clang/test/OpenMP/target_teams_distribute_defaultmap_messages.cpp b/clang/test/OpenMP/target_teams_distribute_defaultmap_messages.cpp index 84d5b198c287855..3e3392d94af980d 100644 --- a/clang/test/OpenMP/target_teams_distribute_defaultmap_messages.cpp +++ b/clang/test/OpenMP/target_teams_distribute_defaultmap_messages.cpp @@ -1,5 +1,8 @@ -// RUN: %clang_cc1 -verify -fopenmp %s -verify=expected,omp51 -Wuninitialized -// RUN: %clang_cc1 -verify -fopenmp-simd %s -verify=expected,omp51 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized + +// RUN: %clang_cc1 -verify -fopenmp %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized // RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 // RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 @@ -15,21 +18,21 @@ T tmain(T argc, S **argv) { int i; #pragma omp target teams distribute defaultmap // expected-error {{expected '(' after 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute defaultmap( // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute defaultmap( // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute defaultmap() // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute defaultmap() // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp51-error {{expected ')'}} omp51-note {{to match this '('}} +#pragma omp target teams distribute defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp5x-error {{expected ')'}} omp5x-note {{to match this '('}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute defaultmap (scalar: // expected-error {{expected ')'}} omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute defaultmap (scalar: // expected-error {{expected ')'}} omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); @@ -41,21 +44,21 @@ int main(int argc, char **argv) { int i; #pragma omp target teams distribute defaultmap // expected-error {{expected '(' after 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute defaultmap( // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute defaultmap( // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute defaultmap() // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute defaultmap() // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp51-error {{expected ')'}} omp51-note {{to match this '('}} +#pragma omp target teams distribute defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp5x-error {{expected ')'}} omp5x-note {{to match this '('}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute defaultmap (scalar: // expected-error {{expected ')'}} omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute defaultmap (scalar: // expected-error {{expected ')'}} omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); diff --git a/clang/test/OpenMP/target_teams_distribute_parallel_for_defaultmap_messages.cpp b/clang/test/OpenMP/target_teams_distribute_parallel_for_defaultmap_messages.cpp index 0bb519be217401f..b789c39dfad6b58 100644 --- a/clang/test/OpenMP/target_teams_distribute_parallel_for_defaultmap_messages.cpp +++ b/clang/test/OpenMP/target_teams_distribute_parallel_for_defaultmap_messages.cpp @@ -1,5 +1,8 @@ -// RUN: %clang_cc1 -verify -fopenmp %s -verify=expected,omp51 -Wuninitialized -// RUN: %clang_cc1 -verify -fopenmp-simd %s -verify=expected,omp51 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized + +// RUN: %clang_cc1 -verify -fopenmp %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized // RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 // RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 @@ -15,21 +18,21 @@ T tmain(T argc, S **argv) { int i; #pragma omp target teams distribute parallel for defaultmap // expected-error {{expected '(' after 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for defaultmap( // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for defaultmap( // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for defaultmap() // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for defaultmap() // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp51-error {{expected ')'}} omp51-note {{to match this '('}} +#pragma omp target teams distribute parallel for defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp5x-error {{expected ')'}} omp5x-note {{to match this '('}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for defaultmap (scalar: // expected-error {{expected ')'}} omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for defaultmap (scalar: // expected-error {{expected ')'}} omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); @@ -41,21 +44,21 @@ int main(int argc, char **argv) { int i; #pragma omp target teams distribute parallel for defaultmap // expected-error {{expected '(' after 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for defaultmap( // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for defaultmap( // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for defaultmap() // omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for defaultmap() // omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp51-error {{expected ')'}} omp51-note {{to match this '('}} +#pragma omp target teams distribute parallel for defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp5x-error {{expected ')'}} omp5x-note {{to match this '('}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for defaultmap (scalar: // expected-error {{expected ')'}} omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for defaultmap (scalar: // expected-error {{expected ')'}} omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); diff --git a/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_defaultmap_messages.cpp b/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_defaultmap_messages.cpp index 0eeca55a9dcd278..ab3ea1b283d3b8e 100644 --- a/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_defaultmap_messages.cpp +++ b/clang/test/OpenMP/target_teams_distribute_parallel_for_simd_defaultmap_messages.cpp @@ -1,5 +1,8 @@ -// RUN: %clang_cc1 -verify -fopenmp %s -verify=expected,omp51 -Wuninitialized -// RUN: %clang_cc1 -verify -fopenmp-simd %s -verify=expected,omp51 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd %s -fopenmp-version=52 -verify=expected,omp5x,omp52 -Wuninitialized + +// RUN: %clang_cc1 -verify -fopenmp %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized +// RUN: %clang_cc1 -verify -fopenmp-simd %s -fopenmp-version=51 -verify=expected,omp5x,omp51 -Wuninitialized // RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 // RUN: %clang_cc1 -verify -fopenmp-simd -fopenmp-version=50 %s -verify=expected,omp5 -Wuninitialized -DOMP5 @@ -15,22 +18,22 @@ T tmain(T argc, S **argv) { int i; #pragma omp target teams distribute parallel for simd defaultmap // expected-error {{expected '(' after 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for simd defaultmap( // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for simd defaultmap( // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for simd defaultmap() // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for simd defaultmap() // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for simd defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for simd defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for simd defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for simd defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for simd defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp51-error {{expected ')'}} omp51-note {{to match this '('}} +#pragma omp target teams distribute parallel for simd defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp5x-error {{expected ')'}} omp5x-note {{to match this '('}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for simd defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for simd defaultmap (scalar: // expected-error {{expected ')'}} omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for simd defaultmap (scalar: // expected-error {{expected ')'}} omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for simd defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} @@ -44,27 +47,27 @@ int main(int argc, char **argv) { #pragma omp target teams distribute parallel for simd defaultmap // expected-error {{expected '(' after 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for simd defaultmap( // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for simd defaultmap( // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for simd defaultmap() // omp51-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for simd defaultmap() // omp5x-error {{'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for simd defaultmap(tofrom // expected-error {{expected ')'}} expected-note {{to match this '('}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for simd defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for simd defaultmap (tofrom: // expected-error {{expected ')'}} expected-note {{to match this '('}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for simd defaultmap(tofrom) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for simd defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp51-error {{expected ')'}} omp51-note {{to match this '('}} +#pragma omp target teams distribute parallel for simd defaultmap(tofrom scalar) // omp45-warning {{missing ':' after defaultmap modifier - ignoring}} omp5-error {{expected ')'}} omp5-note {{to match this '('}} omp5x-error {{expected ')'}} omp5x-note {{to match this '('}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for simd defaultmap(tofrom, // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); -#pragma omp target teams distribute parallel for simd defaultmap (scalar: // expected-error {{expected ')'}} omp51-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} +#pragma omp target teams distribute parallel for simd defaultmap (scalar: // expected-error {{expected ')'}} omp5x-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default', 'present' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'alloc', 'from', 'to', 'tofrom', 'firstprivate', 'none', 'default' in OpenMP clause 'defaultmap'}} omp52-error {{expected 'scalar', 'aggregate', 'pointer', 'all' in OpenMP clause 'defaultmap'}} omp51-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} omp5-error {{expected 'scalar', 'aggregate', 'pointer' in OpenMP clause 'defaultmap'}} expected-note {{to match this '('}} omp45-error {{expected 'tofrom' in OpenMP clause 'defaultmap'}} for (i = 0; i < argc; ++i) foo(); #pragma omp target teams distribute parallel for simd defaultmap(tofrom, scalar // expected-error {{expected ')'}} omp45-warning {{missing ':' after defaultmap modifier - ignoring}} expected-note {{to match this '('}} omp45-error {{expected 'scalar' in OpenMP clause 'defaultmap'}} diff --git a/clang/test/Parser/namelookup-anonymous-struct.c b/clang/test/Parser/namelookup-anonymous-struct.c new file mode 100644 index 000000000000000..cb691c22f97ffd6 --- /dev/null +++ b/clang/test/Parser/namelookup-anonymous-struct.c @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -std=c11 -verify %s + +struct GH31295 { + struct { int x; }; + int arr[sizeof(x)]; // expected-error{{use of undeclared identifier 'x'}} +}; diff --git a/clang/test/Preprocessor/predefined-macros.c b/clang/test/Preprocessor/predefined-macros.c index 7f036bff401ca09..633ba4681ac52b0 100644 --- a/clang/test/Preprocessor/predefined-macros.c +++ b/clang/test/Preprocessor/predefined-macros.c @@ -70,7 +70,7 @@ // RUN: | FileCheck -match-full-lines %s --check-prefix=CHECK-NO-MATH-ERRNO // CHECK-NO-MATH-ERRNO: #define __NO_MATH_ERRNO__ 1 // -// RUN: %clang_cc1 %s -E -dM -ffinite-math-only -o - \ +// RUN: %clang_cc1 %s -E -dM -menable-no-nans -menable-no-infs -o - \ // RUN: | FileCheck -match-full-lines %s --check-prefix=CHECK-FINITE-MATH-ONLY // CHECK-FINITE-MATH-ONLY: #define __FINITE_MATH_ONLY__ 1 // @@ -316,4 +316,4 @@ // RUN: -triple amdgcn-amd-amdhsa -fcuda-is-device | FileCheck -match-full-lines \ // RUN: %s --check-prefix=CHECK-HIPSTDPAR-INTERPOSE-DEV-NEG // CHECK-HIPSTDPAR-INTERPOSE-DEV-NEG: #define __HIPSTDPAR__ 1 -// CHECK-HIPSTDPAR-INTERPOSE-DEV-NEG-NOT: #define __HIPSTDPAR_INTERPOSE_ALLOC__ 1 \ No newline at end of file +// CHECK-HIPSTDPAR-INTERPOSE-DEV-NEG-NOT: #define __HIPSTDPAR_INTERPOSE_ALLOC__ 1 diff --git a/clang/test/Preprocessor/x86_target_features.c b/clang/test/Preprocessor/x86_target_features.c index 1babf4747ba1538..5d510cb4667f4b6 100644 --- a/clang/test/Preprocessor/x86_target_features.c +++ b/clang/test/Preprocessor/x86_target_features.c @@ -512,11 +512,11 @@ // NOHRESET-NOT: #define __HRESET__ 1 -// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -muintr -x c -E -dM -o - %s | FileCheck -check-prefix=UINTR %s +// RUN: %clang -target x86_64-unknown-linux-gnu -march=x86-64 -muintr -x c -E -dM -o - %s | FileCheck -check-prefix=UINTR %s // UINTR: #define __UINTR__ 1 -// RUN: %clang -target i386-unknown-linux-gnu -march=i386 -mno-uintr -x c -E -dM -o - %s | FileCheck -check-prefix=NOUINTR %s +// RUN: %clang -target x86_64-unknown-linux-gnu -march=x86-64 -mno-uintr -x c -E -dM -o - %s | FileCheck -check-prefix=NOUINTR %s // NOUINTR-NOT: #define __UINTR__ 1 diff --git a/clang/test/Sema/aarch64-fmv-streaming.c b/clang/test/Sema/aarch64-fmv-streaming.c new file mode 100644 index 000000000000000..93b7656216c0c99 --- /dev/null +++ b/clang/test/Sema/aarch64-fmv-streaming.c @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -Waarch64-sme-attributes -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme -Waarch64-sme-attributes -fsyntax-only -verify=expected-cpp -x c++ %s + +__attribute__((target_clones("sve", "simd"))) void ok_arm_streaming(void) __arm_streaming {} +__arm_locally_streaming __attribute__((target_version("sme2"))) void ok_arm_streaming(void) __arm_streaming {} +__attribute__((target_version("default"))) void ok_arm_streaming(void) __arm_streaming {} + +__attribute__((target_clones("sve", "simd"))) void ok_arm_streaming_compatible(void) __arm_streaming_compatible {} +__arm_locally_streaming __attribute__((target_version("sme2"))) void ok_arm_streaming_compatible(void) __arm_streaming_compatible {} +__attribute__((target_version("default"))) void ok_arm_streaming_compatible(void) __arm_streaming_compatible {} + +__arm_locally_streaming __attribute__((target_clones("sve", "simd"))) void ok_no_streaming(void) {} +__attribute__((target_version("sme2"))) void ok_no_streaming(void) {} +__attribute__((target_version("default"))) void ok_no_streaming(void) {} + +__attribute__((target_clones("sve", "simd"))) void bad_mixed_streaming(void) {} +// expected-cpp-error@+2 {{multiversioned function declaration has a different calling convention}} +// expected-error@+1 {{multiversioned function declaration has a different calling convention}} +__attribute__((target_version("sme2"))) void bad_mixed_streaming(void) __arm_streaming {} +// expected-cpp-error@+2 {{multiversioned function declaration has a different calling convention}} +// expected-error@+1 {{multiversioned function declaration has a different calling convention}} +__attribute__((target_version("default"))) void bad_mixed_streaming(void) __arm_streaming_compatible {} +// expected-cpp-error@+2 {{multiversioned function declaration has a different calling convention}} +// expected-error@+1 {{multiversioned function declaration has a different calling convention}} +__arm_locally_streaming __attribute__((target_version("dotprod"))) void bad_mixed_streaming(void) __arm_streaming {} + +void n_caller(void) { + ok_arm_streaming(); + ok_arm_streaming_compatible(); + ok_no_streaming(); + bad_mixed_streaming(); +} + +void s_caller(void) __arm_streaming { + ok_arm_streaming(); + ok_arm_streaming_compatible(); + ok_no_streaming(); + bad_mixed_streaming(); +} + +void sc_caller(void) __arm_streaming_compatible { + ok_arm_streaming(); + ok_arm_streaming_compatible(); + ok_no_streaming(); + bad_mixed_streaming(); +} diff --git a/clang/test/Sema/aarch64-sme-func-attrs.c b/clang/test/Sema/aarch64-sme-func-attrs.c index 6db39d6a71e366d..0c263eb2610cfbc 100644 --- a/clang/test/Sema/aarch64-sme-func-attrs.c +++ b/clang/test/Sema/aarch64-sme-func-attrs.c @@ -455,48 +455,6 @@ void unimplemented_spill_fill_za(void (*share_zt0_only)(void) __arm_inout("zt0") share_zt0_only(); } -// expected-cpp-error@+2 {{streaming function cannot be multi-versioned}} -// expected-error@+1 {{streaming function cannot be multi-versioned}} -__attribute__((target_version("sme2"))) -void cannot_work_version(void) __arm_streaming {} -// expected-cpp-error@+5 {{function declared 'void ()' was previously declared 'void () __arm_streaming', which has different SME function attributes}} -// expected-cpp-note@-2 {{previous declaration is here}} -// expected-error@+3 {{function declared 'void (void)' was previously declared 'void (void) __arm_streaming', which has different SME function attributes}} -// expected-note@-4 {{previous declaration is here}} -__attribute__((target_version("default"))) -void cannot_work_version(void) {} - - -// expected-cpp-error@+2 {{streaming function cannot be multi-versioned}} -// expected-error@+1 {{streaming function cannot be multi-versioned}} -__attribute__((target_clones("sme2"))) -void cannot_work_clones(void) __arm_streaming {} - - -__attribute__((target("sme2"))) -void just_fine_streaming(void) __arm_streaming {} -__attribute__((target_version("sme2"))) -void just_fine(void) { just_fine_streaming(); } -__attribute__((target_version("default"))) -void just_fine(void) {} - - -__arm_locally_streaming -__attribute__((target_version("sme2"))) -void incompatible_locally_streaming(void) {} -// expected-error@-1 {{attribute 'target_version' multiversioning cannot be combined with attribute '__arm_locally_streaming'}} -// expected-cpp-error@-2 {{attribute 'target_version' multiversioning cannot be combined with attribute '__arm_locally_streaming'}} -__attribute__((target_version("default"))) -void incompatible_locally_streaming(void) {} - - -void fmv_caller() { - cannot_work_version(); - cannot_work_clones(); - just_fine(); - incompatible_locally_streaming(); -} - void sme_streaming_with_vl_arg(__SVInt8_t a) __arm_streaming { } __SVInt8_t sme_streaming_returns_vl(void) __arm_streaming { __SVInt8_t r; return r; } diff --git a/clang/test/Sema/attr-format.c b/clang/test/Sema/attr-format.c index 1f4c864d4f78bd2..5a8b1ac9eca5c42 100644 --- a/clang/test/Sema/attr-format.c +++ b/clang/test/Sema/attr-format.c @@ -99,3 +99,10 @@ void forward_fixed(const char *fmt, _Bool b, char i, short j, int k, float l, do a(fmt, b, i, j, k, l, m); } +// OpenBSD +// same as format(printf(...))... +void a2(const char *a, ...) __attribute__((format(syslog, 1, 2))); // no-error +void b2(const char *a, ...) __attribute__((format(syslog, 1, 1))); // expected-error {{'format' attribute parameter 3 is out of bounds}} +void c2(const char *a, ...) __attribute__((format(syslog, 0, 2))); // expected-error {{'format' attribute parameter 2 is out of bounds}} +void d2(const char *a, int c) __attribute__((format(syslog, 1, 2))); // expected-warning {{GCC requires a function with the 'format' attribute to be variadic}} +void e2(char *str, int c, ...) __attribute__((format(syslog, 2, 3))); // expected-error {{format argument not a string type}} diff --git a/clang/test/Sema/attr-ownership.c b/clang/test/Sema/attr-ownership.c index 084624353315ca8..d2e40538a40f028 100644 --- a/clang/test/Sema/attr-ownership.c +++ b/clang/test/Sema/attr-ownership.c @@ -18,7 +18,7 @@ void *f12(float i, int k, int f, int *j) __attribute__((ownership_returns(foo, 4 void f13(int *i, int *j) __attribute__((ownership_holds(foo, 1))) __attribute__((ownership_takes(foo, 2))); void f14(int i, int j, int *k) __attribute__((ownership_holds(foo, 3))) __attribute__((ownership_takes(foo, 3))); // expected-error {{'ownership_takes' and 'ownership_holds' attributes are not compatible}} -void f15(int, int) +void *f15(int, int) __attribute__((ownership_returns(foo, 1))) // expected-error {{'ownership_returns' attribute index does not match; here it is 1}} __attribute__((ownership_returns(foo, 2))); // expected-note {{declared with index 2 here}} void f16(int *i, int *j) __attribute__((ownership_holds(foo, 1))) __attribute__((ownership_holds(foo, 1))); // OK, same index @@ -28,3 +28,6 @@ void f18() __attribute__((ownership_takes(foo, 1))); // expected-warning {{'own int f19(void *) __attribute__((ownership_takes(foo, 1))) // expected-error {{'ownership_takes' attribute class does not match; here it is 'foo'}} __attribute__((ownership_takes(foo1, 1))); // expected-note {{declared with class 'foo1' here}} + +void f20(void) __attribute__((ownership_returns(foo))); // expected-error {{'ownership_returns' attribute only applies to functions that return a pointer}} +int f21(void) __attribute__((ownership_returns(foo))); // expected-error {{'ownership_returns' attribute only applies to functions that return a pointer}} diff --git a/clang/test/Sema/attr-ownership.cpp b/clang/test/Sema/attr-ownership.cpp index 7381285e2da4887..0626efa5aaf9a2d 100644 --- a/clang/test/Sema/attr-ownership.cpp +++ b/clang/test/Sema/attr-ownership.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 %s -verify -fsyntax-only class C { - void f(int, int) - __attribute__((ownership_returns(foo, 2))) // expected-error {{'ownership_returns' attribute index does not match; here it is 2}} - __attribute__((ownership_returns(foo, 3))); // expected-note {{declared with index 3 here}} + void *f(int, int) + __attribute__((ownership_returns(foo, 2))) // expected-error {{'ownership_returns' attribute index does not match; here it is 2}} + __attribute__((ownership_returns(foo, 3))); // expected-note {{declared with index 3 here}} }; diff --git a/clang/test/Sema/builtin-cpu-supports.c b/clang/test/Sema/builtin-cpu-supports.c index 133410abaa711dd..4dace25b42a9708 100644 --- a/clang/test/Sema/builtin-cpu-supports.c +++ b/clang/test/Sema/builtin-cpu-supports.c @@ -2,6 +2,9 @@ // RUN: %clang_cc1 -fsyntax-only -triple aarch64-linux-gnu -verify %s // RUN: %clang_cc1 -fsyntax-only -triple riscv32-linux-gnu -verify %s // RUN: %clang_cc1 -fsyntax-only -triple riscv64-linux-gnu -verify %s +// RUN: %clang_cc1 -fsyntax-only -triple powerpc64le-unknown-linux -verify %s +// RUN: %clang_cc1 -fsyntax-only -triple powerpc64-unknown-aix7.2.0.0 -verify %s +// RUN: %clang_cc1 -fsyntax-only -triple powerpc-unknown-aix7.2.0.0 -verify %s extern void a(const char *); @@ -45,5 +48,16 @@ int main(void) { a("vsx"); #endif +#ifdef __powerpc__ + if (__builtin_cpu_is("garbage")) // expected-error {{invalid cpu name for builtin}} + a("vsx"); + + if (__builtin_cpu_is("power3")) // expected-error {{invalid cpu name for builtin}} + a("vsx"); + + if (__builtin_cpu_supports("garbage")) // expected-warning {{invalid cpu feature string for builtin}} + a("vsx"); +#endif + return 0; } diff --git a/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp b/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp index 03a432e05851d1f..357c9e5b6410737 100644 --- a/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp +++ b/clang/test/Sema/warn-infinity-nan-disabled-lnx.cpp @@ -1,10 +1,11 @@ // RUN: %clang_cc1 -x c++ -verify=no-inf-no-nan \ -// RUN: -triple powerpc64le-unknown-unknown %s -menable-no-infs \ -// RUN: -menable-no-nans -std=c++23 +// RUN: -triple powerpc64le-unknown-unknown %s \ +// RUN: -menable-no-infs -menable-no-nans -std=c++23 // RUN: %clang_cc1 -x c++ -verify=no-inf-no-nan \ -// RUN: -triple powerpc64le-unknown-unknown %s -menable-no-infs \ -// RUN: -menable-no-nans -funsafe-math-optimizations -std=c++23 +// RUN: -triple powerpc64le-unknown-unknown %s \ +// RUN: -menable-no-infs -menable-no-nans -funsafe-math-optimizations \ +// RUN: -std=c++23 // RUN: %clang_cc1 -x c++ -verify=no-fast -triple powerpc64le-unknown-unknown \ // RUN: %s -std=c++23 @@ -87,11 +88,15 @@ class numeric_limits { int compareit(float a, float b) { volatile int i, j, k, l, m, n, o, p; -// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+4 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} // no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} i = a == INFINITY; -// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+4 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} // no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} j = INFINITY == a; @@ -107,11 +112,15 @@ int compareit(float a, float b) { // no-nan-warning@+1 {{use of NaN via a macro is undefined behavior due to the currently enabled floating-point options}} j = NAN == a; -// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+4 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} // no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} j = INFINITY <= a; -// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+4 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} // no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} j = INFINITY < a; @@ -192,7 +201,9 @@ int compareit(float a, float b) { // no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} j = isunorderedf(a, NAN); -// no-inf-no-nan-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+4 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+3 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} // no-inf-warning@+1 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} j = isunorderedf(a, INFINITY); @@ -204,9 +215,11 @@ int compareit(float a, float b) { // no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} i = std::isunordered(a, NAN); -// no-inf-no-nan-warning@+4 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} -// no-inf-no-nan-warning@+3 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} -// no-inf-warning@+2 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+6 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+5 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-no-nan-warning@+4 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+3 {{use of infinity via a macro is undefined behavior due to the currently enabled floating-point options}} +// no-inf-warning@+2 {{use of infinity is undefined behavior due to the currently enabled floating-point options}} // no-nan-warning@+1 {{use of NaN is undefined behavior due to the currently enabled floating-point options}} i = std::isunordered(a, INFINITY); diff --git a/clang/test/Sema/warn-infinity-nan-disabled-win.cpp b/clang/test/Sema/warn-infinity-nan-disabled-win.cpp index 51f9d325619ba04..ee4eb33a16e449b 100644 --- a/clang/test/Sema/warn-infinity-nan-disabled-win.cpp +++ b/clang/test/Sema/warn-infinity-nan-disabled-win.cpp @@ -6,8 +6,9 @@ // RUN: -menable-no-nans -std=c++23 // RUN: %clang_cc1 -x c++ -verify=no-inf-no-nan \ -// RUN: -triple powerpc64le-unknown-unknown %s -menable-no-infs \ -// RUN: -menable-no-nans -funsafe-math-optimizations -std=c++23 +// RUN: -triple powerpc64le-unknown-unknown %s \ +// RUN: -menable-no-infs -menable-no-nans -funsafe-math-optimizations \ +// RUN: -std=c++23 // RUN: %clang_cc1 -x c++ -verify=no-fast -triple powerpc64le-unknown-unknown \ // RUN: %s -std=c++23 diff --git a/clang/test/SemaCXX/cxx1z-decomposition.cpp b/clang/test/SemaCXX/cxx1z-decomposition.cpp index 305a9ac2ebc2467..19c730303625ee2 100644 --- a/clang/test/SemaCXX/cxx1z-decomposition.cpp +++ b/clang/test/SemaCXX/cxx1z-decomposition.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -std=c++17 -Wc++20-extensions -verify=expected %s // RUN: %clang_cc1 -std=c++20 -Wpre-c++20-compat -verify=expected %s +// RUN: %clang_cc1 -std=c++20 -Wpre-c++20-compat -fexperimental-new-constant-interpreter -verify=expected %s void use_from_own_init() { auto [a] = a; // expected-error {{binding 'a' cannot appear in the initializer of its own decomposition declaration}} diff --git a/clang/test/SemaCXX/cxx2a-destroying-delete.cpp b/clang/test/SemaCXX/cxx2a-destroying-delete.cpp index 349e6e9538a4cfe..25b985ef11d1573 100644 --- a/clang/test/SemaCXX/cxx2a-destroying-delete.cpp +++ b/clang/test/SemaCXX/cxx2a-destroying-delete.cpp @@ -187,3 +187,12 @@ namespace delete_from_new { #endif } } + +namespace GH96191 { + struct S {}; + struct T { + void operator delete(S) { } // expected-error {{first parameter of 'operator delete' must have type 'void *'}} + }; + + void foo(T *t) { delete t; } +} diff --git a/clang/test/SemaCXX/cxx2b-deducing-this.cpp b/clang/test/SemaCXX/cxx2b-deducing-this.cpp index 4811b6052254c9a..45fee6514c12bc6 100644 --- a/clang/test/SemaCXX/cxx2b-deducing-this.cpp +++ b/clang/test/SemaCXX/cxx2b-deducing-this.cpp @@ -965,3 +965,10 @@ void f(); }; void a::f(this auto) {} // expected-error {{an explicit object parameter cannot appear in a non-member function}} } + +struct R { + void f(this auto &&self, int &&r_value_ref) {} // expected-note {{candidate function template not viable: expects an rvalue for 2nd argument}} + void g(int &&r_value_ref) { + f(r_value_ref); // expected-error {{no matching member function for call to 'f'}} + } +}; diff --git a/clang/test/SemaCXX/destructor.cpp b/clang/test/SemaCXX/destructor.cpp index 028bc7cc196989c..dfcd1b033af5a23 100644 --- a/clang/test/SemaCXX/destructor.cpp +++ b/clang/test/SemaCXX/destructor.cpp @@ -577,4 +577,13 @@ static_assert(!__is_trivially_constructible(Foo, const Foo &), ""); static_assert(!__is_trivially_constructible(Foo, Foo &&), ""); } // namespace GH89544 +namespace GH97230 { +struct X { + ~X() = defaul; // expected-error {{initializer on function does not look like a pure-specifier}} \ + // expected-error {{use of undeclared identifier 'defaul'}} +}; +struct Y : X {} y1{ }; // expected-error {{call to implicitly-deleted default constructor of 'struct Y'}} \ + // expected-note {{default constructor of 'Y' is implicitly deleted because base class 'X' has no destructor}} +} + #endif // BE_THE_HEADER diff --git a/clang/test/SemaCXX/new-delete-0x.cpp b/clang/test/SemaCXX/new-delete-0x.cpp index a4b43308d010fe6..aa9ce37c8e3e435 100644 --- a/clang/test/SemaCXX/new-delete-0x.cpp +++ b/clang/test/SemaCXX/new-delete-0x.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu -std=c++11 +// RUN: %clang_cc1 -fsyntax-only -verify %s -triple=i686-pc-linux-gnu -std=c++11 -fexperimental-new-constant-interpreter using size_t = decltype(sizeof(0)); struct noreturn_t {} constexpr noreturn = {}; diff --git a/clang/test/SemaCXX/pr100095.cpp b/clang/test/SemaCXX/pr100095.cpp new file mode 100644 index 000000000000000..15913fec9d5ae0a --- /dev/null +++ b/clang/test/SemaCXX/pr100095.cpp @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s +// XFAIL: asserts + +template struct Pair; +template struct Tuple { + template Tuple(_Up); +}; +template struct StatusOr; +template using ElementType = int; +template +using Key = Tuple...>; +template +StatusOr>> Parser(); +struct Helper { Helper(Tuple<>, Tuple<>, int, int); }; +struct D : Helper { + D(Key<> f, int n, int e) : Helper(f, Parser<>, n, e) {} +}; diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp index 23b07cac13eaf62..e131212bb1071d2 100644 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -2402,11 +2402,11 @@ template struct DerivedB : BaseA { }; template struct CrazyDerived : T { }; -class class_forward; // expected-note 2 {{forward declaration of 'class_forward'}} +class class_forward; // expected-note 4 {{forward declaration of 'class_forward'}} template class DerivedTemp : Base {}; template class NonderivedTemp {}; -template class UndefinedTemp; // expected-note {{declared here}} +template class UndefinedTemp; // expected-note 2 {{declared here}} void is_base_of() { static_assert(__is_base_of(Base, Derived)); @@ -2457,6 +2457,76 @@ void is_base_of() { static_assert(!__is_base_of(DerivedB, BaseA)); } +struct DerivedTransitiveViaNonVirtual : Derived3 {}; +struct DerivedTransitiveViaVirtual : virtual Derived3 {}; + +template +struct CrazyDerivedVirtual : virtual T {}; + +struct DerivedPrivate : private virtual Base {}; +struct DerivedProtected : protected virtual Base {}; +struct DerivedPrivatePrivate : private DerivedPrivate {}; +struct DerivedPrivateProtected : private DerivedProtected {}; +struct DerivedProtectedPrivate : protected DerivedProtected {}; +struct DerivedProtectedProtected : protected DerivedProtected {}; + +void is_virtual_base_of(int n) { + static_assert(!__builtin_is_virtual_base_of(Base, Derived)); + static_assert(!__builtin_is_virtual_base_of(const Base, Derived)); + static_assert(!__builtin_is_virtual_base_of(Derived, Base)); + static_assert(!__builtin_is_virtual_base_of(Derived, int)); + static_assert(!__builtin_is_virtual_base_of(Base, Base)); + static_assert(!__builtin_is_virtual_base_of(Base, Derived3)); + static_assert(!__builtin_is_virtual_base_of(Derived, Derived3)); + static_assert(__builtin_is_virtual_base_of(Derived2b, Derived3)); + static_assert(__builtin_is_virtual_base_of(Derived2a, Derived3)); + static_assert(!__builtin_is_virtual_base_of(BaseA, DerivedB)); + static_assert(!__builtin_is_virtual_base_of(DerivedB, BaseA)); + static_assert(!__builtin_is_virtual_base_of(Union, Union)); + static_assert(!__builtin_is_virtual_base_of(Empty, Empty)); + static_assert(!__builtin_is_virtual_base_of(class_forward, class_forward)); // expected-error {{incomplete type 'class_forward' where a complete type is required}} + static_assert(!__builtin_is_virtual_base_of(Empty, class_forward)); // expected-error {{incomplete type 'class_forward' where a complete type is required}} + static_assert(!__builtin_is_virtual_base_of(class_forward, Empty)); + static_assert(!__builtin_is_virtual_base_of(Base&, Derived&)); + static_assert(!__builtin_is_virtual_base_of(Base[10], Derived[10])); + static_assert(!__builtin_is_virtual_base_of(Base[n], Derived[n])); // expected-error 2 {{variable length arrays are not supported in '__builtin_is_virtual_base_of'}} + static_assert(!__builtin_is_virtual_base_of(int, int)); + static_assert(!__builtin_is_virtual_base_of(int[], int[])); + static_assert(!__builtin_is_virtual_base_of(long, int)); + static_assert(!__builtin_is_virtual_base_of(Base, DerivedTemp)); + static_assert(!__builtin_is_virtual_base_of(Base, NonderivedTemp)); + static_assert(!__builtin_is_virtual_base_of(Base, UndefinedTemp)); // expected-error {{implicit instantiation of undefined template 'UndefinedTemp'}} + static_assert(__builtin_is_virtual_base_of(Base, DerivedPrivate)); + static_assert(__builtin_is_virtual_base_of(Base, DerivedProtected)); + static_assert(__builtin_is_virtual_base_of(Base, DerivedPrivatePrivate)); + static_assert(__builtin_is_virtual_base_of(Base, DerivedPrivateProtected)); + static_assert(__builtin_is_virtual_base_of(Base, DerivedProtectedPrivate)); + static_assert(__builtin_is_virtual_base_of(Base, DerivedProtectedProtected)); + static_assert(__builtin_is_virtual_base_of(Derived2a, DerivedTransitiveViaNonVirtual)); + static_assert(__builtin_is_virtual_base_of(Derived2b, DerivedTransitiveViaNonVirtual)); + static_assert(__builtin_is_virtual_base_of(Derived2a, DerivedTransitiveViaVirtual)); + static_assert(__builtin_is_virtual_base_of(Derived2b, DerivedTransitiveViaVirtual)); + static_assert(!__builtin_is_virtual_base_of(Base, CrazyDerived)); + static_assert(!__builtin_is_virtual_base_of(CrazyDerived, Base)); + static_assert(__builtin_is_virtual_base_of(Base, CrazyDerivedVirtual)); + static_assert(!__builtin_is_virtual_base_of(CrazyDerivedVirtual, Base)); + + static_assert(!__builtin_is_virtual_base_of(IncompleteUnion, IncompleteUnion)); + static_assert(!__builtin_is_virtual_base_of(Union, IncompleteUnion)); + static_assert(!__builtin_is_virtual_base_of(IncompleteUnion, Union)); + static_assert(!__builtin_is_virtual_base_of(IncompleteStruct, IncompleteUnion)); + static_assert(!__builtin_is_virtual_base_of(IncompleteUnion, IncompleteStruct)); + static_assert(!__builtin_is_virtual_base_of(Empty, IncompleteUnion)); + static_assert(!__builtin_is_virtual_base_of(IncompleteUnion, Empty)); + static_assert(!__builtin_is_virtual_base_of(int, IncompleteUnion)); + static_assert(!__builtin_is_virtual_base_of(IncompleteUnion, int)); + static_assert(!__builtin_is_virtual_base_of(Empty, Union)); + static_assert(!__builtin_is_virtual_base_of(Union, Empty)); + static_assert(!__builtin_is_virtual_base_of(int, Empty)); + static_assert(!__builtin_is_virtual_base_of(Union, int)); + static_assert(!__builtin_is_virtual_base_of(IncompleteStruct, IncompleteStruct[n])); // expected-error {{variable length arrays are not supported in '__builtin_is_virtual_base_of'}} +} + template class TemplateClass {}; diff --git a/clang/test/SemaHLSL/Loops/unroll.hlsl b/clang/test/SemaHLSL/Loops/unroll.hlsl index 2e2be319e466692..c94dc5857c2e84f 100644 --- a/clang/test/SemaHLSL/Loops/unroll.hlsl +++ b/clang/test/SemaHLSL/Loops/unroll.hlsl @@ -1,7 +1,10 @@ // RUN: %clang_cc1 -O0 -finclude-default-header -fsyntax-only -triple dxil-pc-shadermodel6.6-library %s -verify void unroll_no_vars() { + // expected-note@+1 {{declared here}} int I = 3; - [unroll(I)] // expected-error {{'unroll' attribute requires an integer constant}} + // expected-error@+2 {{expression is not an integral constant expression}} + // expected-note@+1 {{read of non-const variable 'I' is not allowed in a constant expression}} + [unroll(I)] while (I--); } diff --git a/clang/test/TableGen/attrs-parser-string-switches.td b/clang/test/TableGen/attrs-parser-string-switches.td new file mode 100644 index 000000000000000..c15ab104e0ccd57 --- /dev/null +++ b/clang/test/TableGen/attrs-parser-string-switches.td @@ -0,0 +1,232 @@ +// RUN: clang-tblgen -gen-clang-attr-parser-string-switches -I%p/../../include %s -o - 2>&1 | FileCheck %s + +// Tests that the tablegen can support attributes with the same spellings but +// different argument types. + +include "clang/Basic/Attr.td" + +// Test attributeParsedArgsUnevaluated : different ParseArgumentsAsUnevaluated +def TestUnEvalOne : InheritableAttr { + let Spellings = [Clang<"test_uneval">]; + let Args = [ExprArgument<"Count">]; + let Subjects = SubjectList<[Function]>; + let ParseArgumentsAsUnevaluated = 1; + let Documentation = [Undocumented]; +} + +def TestUnEvalTwo : InheritableAttr { + let Spellings = [Pragma<"", "test_uneval">]; + let Args = [ExprArgument<"Count">]; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +// CHECK: #if defined(CLANG_ATTR_ARG_CONTEXT_LIST) +// CHECK-NOT: .Case("Pragma::test_uneval", true) +// CHECK: .Case("GNU::test_uneval", true) +// CHECK-NOT: .Case("Pragma::test_uneval", true) +// CHECK: .Case("CXX11::clang::test_uneval", true) +// CHECK-NOT: .Case("Pragma::test_uneval", true) +// CHECK: .Case("C23::clang::test_uneval", true) +// CHECK-NOT: .Case("Pragma::test_uneval", true) +// CHECK: #endif // CLANG_ATTR_ARG_CONTEXT_LIST + +// Test attributeHasIdentifierArg: Same spelling, one with and one without +// an IdentifierArg. +def TestIdentOne : Attr { + let Spellings = [Clang<"test_ident">]; + let Args = [EnumArgument<"Option", "OptionType", /*is_string=*/false, + ["optA", "optB"], ["OPTA", "OPTB"]>]; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +def TestIdentTwo : StmtAttr { + let Spellings = [Pragma<"", "test_ident">]; + let Args = [UnsignedArgument<"val", /*opt*/1>]; + let Subjects = SubjectList<[Function]>; + let Documentation = [Undocumented]; +} + +// CHECK: #if defined(CLANG_ATTR_IDENTIFIER_ARG_LIST) +// CHECK-NOT: .Case("Pragma::test_ident", true) +// CHECK: .Case("GNU::test_ident", true) +// CHECK-NOT: .Case("Pragma::test_ident", true) +// CHECK: .Case("CXX11::clang::test_ident", true) +// CHECK-NOT: .Case("Pragma::test_ident", true) +// CHECK: .Case("C23::clang::test_ident", true) +// CHECK-NOT: .Case("Pragma::test_ident", true) +// CHECK: #endif // CLANG_ATTR_IDENTIFIER_ARG_LIST + +// Test attributeStringLiteralListArg : Same spelling, some with a +// StringArgument, some without, some in different locations. +def TestStringOne : DeclOrTypeAttr { + let Spellings = [Clang<"test_string">]; + let Args = [StringArgument<"strarg">]; + let Subjects = SubjectList<[Function, TypedefName, ParmVar]>; + let Documentation = [AcquireHandleDocs]; +} + +def TestStringTwo : InheritableAttr { + let Spellings = [Pragma<"", "test_string">]; + let Args = [UnsignedArgument<"unsarg">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +// In a different position +def TestStringThree : Attr { + let Spellings = [Declspec<"test_string">]; + let Args = [UnsignedArgument<"uarg">, StringArgument<"strarg">]; + let Subjects = SubjectList<[Function, TypedefName, ParmVar]>; + let Documentation = [AcquireHandleDocs]; +} + +// CHECK: #if defined(CLANG_ATTR_STRING_LITERAL_ARG_LIST) +// CHECK-NOT: .Case("Pragma::test_string" +// CHECK: .Case("GNU::test_string", 1) +// CHECK: .Case("CXX11::clang::test_string", 1) +// CHECK: .Case("C23::clang::test_string", 1) +// CHECK-NOT: .Case("Pragma::test_string" +// CHECK: .Case("Declspec::test_string", 2) +// CHECK-NOT: .Case("Pragma::test_string" +// CHECK: #endif // CLANG_ATTR_STRING_LITERAL_ARG_LIST + +// Test attributeHasVariadicIdentifierArg : One with VariadicIdentifierArgument +// and one without. +def TestVariadicIdentOne : InheritableAttr { + let Spellings = [Clang<"test_var_ident">]; + let Args = [VariadicIdentifierArgument<"iargs">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def TestVariadicIdentTwo : InheritableAttr { + let Spellings = [Pragma<"", "test_var_ident">]; + let Args = [UnsignedArgument<"Hint">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +// CHECK: #if defined(CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST) +// CHECK-NOT: .Case("Pragma::"test_var_ident", true) +// CHECK: .Case("GNU::test_var_ident", true) +// CHECK-NOT: .Case("Pragma::test_var_ident", true) +// CHECK: .Case("CXX11::clang::test_var_ident", true) +// CHECK-NOT: .Case("Pragma::test_var_ident", true) +// CHECK: .Case("C23::clang::test_var_ident", true) +// CHECK-NOT: .Case("Pragma::test_var_ident", true) +// CHECK: #endif // CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST + +// Test attributeTreatsKeywordThisAsIdentifier : Same spelling, one with and +// one without VariadicParamOrParamIdxArgument. +def TestVarOrIdxOne : InheritableAttr { + let Spellings = [Clang<"test_var_idx">]; + let Args = [VariadicParamOrParamIdxArgument<"arg">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def TestVarOrIdxTwo : InheritableAttr { + let Spellings = [Pragma<"", "test_var_idx">]; + let Args = [UnsignedArgument<"Hint">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +// CHECK: #if defined(CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST) +// CHECK-NOT: .Case("Pragma::test_var_idx", true) +// CHECK: .Case("GNU::test_var_idx", true) +// CHECK-NOT: .Case("Pragma::test_var_idx", true) +// CHECK: .Case("CXX11::clang::test_var_idx", true) +// CHECK-NOT: .Case("Pragma::test_var_idx", true) +// CHECK: .Case("C23::clang::test_var_idx", true) +// CHECK-NOT: .Case("Pragma::test_var_idx", true) +// CHECK: #endif // CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST + +// Test attributeAcceptsExprPack : One with, one without. +def TestExprPackOne : InheritableAttr { + let Spellings = [Clang<"test_expr_pack">]; + let Args = [StringArgument<"str">, VariadicExprArgument<"args">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let AcceptsExprPack = 1; + let Documentation = [Undocumented]; +} + +def TestExprPackTwo : InheritableAttr { + let Spellings = [Pragma<"", "test_expr_pack">]; + let Args = [StringArgument<"str">, VariadicExprArgument<"args">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +// CHECK: #if defined(CLANG_ATTR_ACCEPTS_EXPR_PACK) +// CHECK-NOT: .Case("Pragma::test_expr_pack", true) +// CHECK: .Case("GNU::test_expr_pack", true) +// CHECK-NOT: .Case("Pragma::test_expr_pack", true) +// CHECK: .Case("CXX11::clang::test_expr_pack", true) +// CHECK-NOT: .Case("Pragma::test_expr_pack", true) +// CHECK: .Case("C23::clang::test_expr_pack", true) +// CHECK-NOT: .Case("Pragma::test_expr_pack", true) +// CHECK: #endif // CLANG_ATTR_ACCEPTS_EXPR_PACK + + +// Test attributeIsTypeArgAttr : Same spelling, one with TypeArgument and one +// without. +def TestTypeOne : InheritableAttr { + let Spellings = [Clang<"test_type">]; + let Args = [TypeArgument<"Hint">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def TestTypeTwo : InheritableAttr { + let Spellings = [Pragma<"", "test_type">]; + let Args = [UnsignedArgument<"Hint">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +// CHECK: #if defined(CLANG_ATTR_TYPE_ARG_LIST) +// CHECK-NOT: .Case("Pragma::test_type", true) +// CHECK: .Case("GNU::test_type", true) +// CHECK-NOT: .Case("Pragma::test_type", true) +// CHECK: .Case("CXX11::clang::test_type", true) +// CHECK-NOT: .Case("Pragma::test_type", true) +// CHECK: .Case("C23::clang::test_type", true) +// CHECK-NOT: .Case("Pragma::test_type", true) +// CHECK: #endif // CLANG_ATTR_TYPE_ARG_LIST + +// Test attributeHasStrictIdentifierArgs and +// attributeHasStrictIdentifierArgAtIndex, one used StrictEnumParameters, the +// other does not. +def TestStrictEnumOne : InheritableAttr { + let Spellings = [Clang<"strict_enum">]; + let StrictEnumParameters = 1; + let Args = [EnumArgument<"One", "OneType", /*is_string=*/true, + ["a", "b", "c", "d"], + ["A", "B", "C", "D"]>, + IntArgument<"Other", 1>, + EnumArgument<"Two", "TwoType", /*is_string=*/true, + ["e", "f", "g", "h"], + ["E", "F", "G", "H"]>]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +def TestStrictEnumTwo : InheritableAttr { + let Spellings = [Pragma<"", "strict_enum">]; + let Args = [VariadicExprArgument<"Args">]; + let Subjects = SubjectList<[Function], ErrorDiag>; + let Documentation = [Undocumented]; +} + +// CHECK: #if defined(CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST) +// CHECK-NOT: .Case("Pragma::strict_enum", 5ull) +// CHECK: .Case("GNU::strict_enum", 5ull) +// CHECK-NOT: .Case("Pragma::strict_enum", 5ull) +// CHECK: .Case("CXX11::clang::strict_enum", 5ull) +// CHECK-NOT: .Case("Pragma::strict_enum", 5ull) +// CHECK: .Case("C23::clang::strict_enum", 5ull) +// CHECK-NOT: .Case("Pragma::strict_enum", 5ull) +// CHECK: #endif // CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST diff --git a/clang/test/Tooling/clang-check-extra-arg.cpp b/clang/test/Tooling/clang-check-extra-arg.cpp index df5fb930eedcd0d..488497edd4e8102 100644 --- a/clang/test/Tooling/clang-check-extra-arg.cpp +++ b/clang/test/Tooling/clang-check-extra-arg.cpp @@ -1,4 +1,6 @@ -// RUN: clang-check "%s" -extra-arg=-Wunimplemented-warning -extra-arg-before=-Wunimplemented-warning-before -- -c 2>&1 | FileCheck %s +/// Check we do not report "argument unused during compilation: '-c'" +// RUN: clang-check "%s" -extra-arg=-Wunimplemented-warning -extra-arg-before=-Wunimplemented-warning-before -- -c 2>&1 | FileCheck %s --implicit-check-not='argument unused' +// RUN: clang-check "%s" -extra-arg=-Wunimplemented-warning -extra-arg-before=-Wunimplemented-warning-before -- -S -Xclang -S 2>&1 | FileCheck %s --implicit-check-not='argument unused' // CHECK: unknown warning option '-Wunimplemented-warning-before' // CHECK: unknown warning option '-Wunimplemented-warning' diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp index 4bb021eae25a8ab..24cc4f0eeadf914 100644 --- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp +++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp @@ -297,7 +297,8 @@ Expected findProgram(StringRef Name, ArrayRef Paths) { /// supported by the toolchain. bool linkerSupportsLTO(const ArgList &Args) { llvm::Triple Triple(Args.getLastArgValue(OPT_triple_EQ)); - return Triple.isNVPTX() || Triple.isAMDGPU(); + return Triple.isNVPTX() || Triple.isAMDGPU() || + Args.getLastArgValue(OPT_linker_path_EQ).ends_with("ld.lld"); } /// Returns the hashed value for a constant string. @@ -524,6 +525,13 @@ Expected clang(ArrayRef InputFiles, const ArgList &Args) { Args.MakeArgString("-" + OptLevel), }; + // Forward all of the `--offload-opt` and similar options to the device. + if (linkerSupportsLTO(Args)) { + for (auto &Arg : Args.filtered(OPT_offload_opt_eq_minus, OPT_mllvm)) + CmdArgs.push_back( + Args.MakeArgString("-Wl,--plugin-opt=" + StringRef(Arg->getValue()))); + } + if (!Triple.isNVPTX()) CmdArgs.push_back("-Wl,--no-undefined"); @@ -591,6 +599,8 @@ Expected clang(ArrayRef InputFiles, const ArgList &Args) { std::back_inserter(CmdArgs)); for (StringRef Arg : Args.getAllArgValues(OPT_linker_arg_EQ)) + CmdArgs.append({"-Xlinker", Args.MakeArgString(Arg)}); + for (StringRef Arg : Args.getAllArgValues(OPT_compiler_arg_EQ)) CmdArgs.push_back(Args.MakeArgString(Arg)); for (StringRef Arg : Args.getAllArgValues(OPT_builtin_bitcode_EQ)) { @@ -1216,8 +1226,7 @@ DerivedArgList getLinkerArgs(ArrayRef Input, auto [Triple, Value] = Arg.split('='); llvm::Triple TT(Triple); // If this isn't a recognized triple then it's an `arg=value` option. - if (TT.getArch() <= Triple::ArchType::UnknownArch || - TT.getArch() > Triple::ArchType::LastArchType) + if (TT.getArch() == Triple::ArchType::UnknownArch) DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_linker_arg_EQ), Args.MakeArgString(Arg)); else if (Value.empty()) @@ -1228,6 +1237,22 @@ DerivedArgList getLinkerArgs(ArrayRef Input, Args.MakeArgString(Value)); } + // Forward '-Xoffload-compiler' options to the appropriate backend. + for (StringRef Arg : Args.getAllArgValues(OPT_device_compiler_args_EQ)) { + auto [Triple, Value] = Arg.split('='); + llvm::Triple TT(Triple); + // If this isn't a recognized triple then it's an `arg=value` option. + if (TT.getArch() == Triple::ArchType::UnknownArch) + DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_compiler_arg_EQ), + Args.MakeArgString(Arg)); + else if (Value.empty()) + DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_compiler_arg_EQ), + Args.MakeArgString(Triple)); + else if (Triple == DAL.getLastArgValue(OPT_triple_EQ)) + DAL.AddJoinedArg(nullptr, Tbl.getOption(OPT_compiler_arg_EQ), + Args.MakeArgString(Value)); + } + return DAL; } @@ -1756,7 +1781,7 @@ int main(int Argc, char **Argv) { for (const opt::Arg *Arg : Args.filtered(OPT_mllvm)) NewArgv.push_back(Arg->getValue()); for (const opt::Arg *Arg : Args.filtered(OPT_offload_opt_eq_minus)) - NewArgv.push_back(Args.MakeArgString(StringRef("-") + Arg->getValue())); + NewArgv.push_back(Arg->getValue()); SmallVector PluginList; PassPlugins.setCallback([&](const std::string &PluginPath) { auto Plugin = PassPlugin::Load(PluginPath); diff --git a/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td b/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td index 9c27e588fc4f573..a3e8199380046fc 100644 --- a/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td +++ b/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td @@ -32,6 +32,9 @@ def builtin_bitcode_EQ : Joined<["--"], "builtin-bitcode=">, def device_linker_args_EQ : Joined<["--"], "device-linker=">, Flags<[WrapperOnlyOption]>, MetaVarName<" or =">, HelpText<"Arguments to pass to the device linker invocation">; +def device_compiler_args_EQ : Joined<["--"], "device-compiler=">, + Flags<[WrapperOnlyOption]>, MetaVarName<" or =">, + HelpText<"Arguments to pass to the device compiler invocation">; def clang_backend : Flag<["--"], "clang-backend">, Flags<[WrapperOnlyOption]>, HelpText<"Run the backend using clang rather than the LTO backend">; @@ -91,6 +94,9 @@ def whole_program : Flag<["--"], "whole-program">, def linker_arg_EQ : Joined<["--"], "linker-arg=">, Flags<[DeviceOnlyOption, HelpHidden]>, HelpText<"An extra argument to be passed to the linker">; +def compiler_arg_EQ : Joined<["--"], "compiler-arg=">, + Flags<[DeviceOnlyOption, HelpHidden]>, + HelpText<"An extra argument to be passed to the compiler">; // Arguments for the LLVM backend. def mllvm : Separate<["-"], "mllvm">, Flags<[WrapperOnlyOption]>, @@ -98,7 +104,7 @@ def mllvm : Separate<["-"], "mllvm">, Flags<[WrapperOnlyOption]>, HelpText<"Arguments passed to LLVM, including Clang invocations, for which " "the '-mllvm' prefix is preserved. Use '-mllvm --help' for a list " "of options.">; -def offload_opt_eq_minus : Joined<["--", "-"], "offload-opt=-">, Flags<[HelpHidden, WrapperOnlyOption]>, +def offload_opt_eq_minus : Joined<["--", "-"], "offload-opt=">, Flags<[HelpHidden, WrapperOnlyOption]>, HelpText<"Options passed to LLVM, not including the Clang invocation. Use " "'--offload-opt=--help' for a list of options.">; diff --git a/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp b/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp index 3885166e76ca7c5..30c45eda66288f2 100644 --- a/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp +++ b/clang/tools/clang-nvlink-wrapper/ClangNVLinkWrapper.cpp @@ -598,10 +598,11 @@ Expected> getInput(const ArgList &Args) { Res.Prevailing = !Sym.isUndefined() && ObjSym.File == *BitcodeFile; // We need LTO to preseve the following global symbols: - // 1) Symbols used in regular objects. - // 2) Prevailing symbols that are needed visible to the gpu runtime. + // 1) All symbols during a relocatable link. + // 2) Symbols used in regular objects. + // 3) Prevailing symbols that are needed visible to the gpu runtime. Res.VisibleToRegularObj = - ObjSym.UsedInRegularObj || + Args.hasArg(OPT_relocatable) || ObjSym.UsedInRegularObj || (Res.Prevailing && (Sym.getVisibility() != GlobalValue::HiddenVisibility && !Sym.canBeOmittedFromSymbolTable())); diff --git a/clang/tools/clang-nvlink-wrapper/NVLinkOpts.td b/clang/tools/clang-nvlink-wrapper/NVLinkOpts.td index 8c80a51b12a44ed..01bd0f85b1a33e9 100644 --- a/clang/tools/clang-nvlink-wrapper/NVLinkOpts.td +++ b/clang/tools/clang-nvlink-wrapper/NVLinkOpts.td @@ -73,6 +73,10 @@ def plugin_opt : Joined<["--", "-"], "plugin-opt=">, Flags<[WrapperOnlyOption]>, def save_temps : Flag<["--", "-"], "save-temps">, Flags<[WrapperOnlyOption]>, HelpText<"Save intermediate results">; +def relocatable : Flag<["--", "-"], "relocatable">, + Flags<[WrapperOnlyOption]>, HelpText<"Perform a relocatable link (LTO only)">; +def r : Flag<["-"], "r">, Flags<[WrapperOnlyOption]>, Alias; + def whole_archive : Flag<["--", "-"], "whole-archive">, Flags<[WrapperOnlyOption, HelpHidden]>; def no_whole_archive : Flag<["--", "-"], "no-whole-archive">, @@ -83,8 +87,7 @@ def mllvm : Separate<["-"], "mllvm">, Flags<[WrapperOnlyOption]>, HelpText<"Arguments passed to LLVM, including Clang invocations, for which " "the '-mllvm' prefix is preserved. Use '-mllvm --help' for a list " "of options.">; -def mllvm_EQ : Joined<["-"], "mllvm=">, Flags<[HelpHidden]>, - Alias; +def mllvm_EQ : Joined<["-"], "mllvm=">, Flags<[HelpHidden]>, Alias; def dry_run : Flag<["--", "-"], "dry-run">, Flags<[WrapperOnlyOption]>, HelpText<"Print generated commands without running.">; diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index d8af5abce7ceed6..937d7ff09e4eefb 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -2526,7 +2526,7 @@ void OMPClauseEnqueue::VisitOMPHintClause(const OMPHintClause *C) { } template void OMPClauseEnqueue::VisitOMPClauseList(T *Node) { - for (const auto *I : Node->varlists()) { + for (const auto *I : Node->varlist()) { Visitor->AddStmt(I); } } @@ -2746,7 +2746,7 @@ void OMPClauseEnqueue::VisitOMPUsesAllocatorsClause( } void OMPClauseEnqueue::VisitOMPAffinityClause(const OMPAffinityClause *C) { Visitor->AddStmt(C->getModifier()); - for (const Expr *E : C->varlists()) + for (const Expr *E : C->varlist()) Visitor->AddStmt(E); } void OMPClauseEnqueue::VisitOMPBindClause(const OMPBindClause *C) {} diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp index 6d987cc7e9ec69f..57242ff49fe3b82 100644 --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -9376,29 +9376,6 @@ TEST_P(ASTImporterOptionSpecificTestBase, VaListCpp) { ToVaList->getUnderlyingType(), ToBuiltinVaList->getUnderlyingType())); } -TEST_P(ASTImporterOptionSpecificTestBase, - ImportDefinitionOfEmptyClassWithNoUniqueAddressField) { - Decl *FromTU = getTuDecl( - R"( - struct B {}; - struct A { B b; }; - )", - Lang_CXX20); - - CXXRecordDecl *FromD = FirstDeclMatcher().match( - FromTU, cxxRecordDecl(hasName("A"))); - - for (auto *FD : FromD->fields()) - FD->addAttr(clang::NoUniqueAddressAttr::Create(FromD->getASTContext(), - clang::SourceRange())); - FromD->markEmpty(); - - CXXRecordDecl *ToD = Import(FromD, Lang_CXX20); - EXPECT_TRUE(ToD->isEmpty()); - for (auto *FD : ToD->fields()) - EXPECT_EQ(true, FD->hasAttr()); -} - TEST_P(ASTImporterOptionSpecificTestBase, ImportExistingTypedefToRecord) { const char *Code = R"( @@ -9783,6 +9760,165 @@ TEST_P(ASTImporterOptionSpecificTestBase, ImportExistingEmptyAnonymousEnums) { EXPECT_EQ(ImportedE2, ToE1); } +TEST_P(ASTImporterOptionSpecificTestBase, ImportMultipleAnonymousEnumDecls) { + Decl *ToTU = getToTuDecl("", Lang_CXX03); + Decl *FromTU = getTuDecl( + R"( + struct foo { + enum { A }; + enum { B }; + }; + )", + Lang_CXX03); + + auto EnumConstA = enumConstantDecl(hasName("A")); + auto EnumConstB = enumConstantDecl(hasName("B")); + + auto *FromA = FirstDeclMatcher().match(FromTU, EnumConstA); + auto *FromB = FirstDeclMatcher().match(FromTU, EnumConstB); + + auto *ToA = Import(FromA, Lang_CXX03); + auto *ToB = Import(FromB, Lang_CXX03); + + ASSERT_TRUE(ToA); + ASSERT_TRUE(ToB); + + auto *ToFooA = FirstDeclMatcher().match( + ToTU, tagDecl(has(enumDecl(has(EnumConstA))))); + auto *ToFooB = FirstDeclMatcher().match( + ToTU, tagDecl(has(enumDecl(has(EnumConstB))))); + ASSERT_EQ(ToFooA, ToFooB); + + // different EnumDecl + auto *ToEnumDeclA = + FirstDeclMatcher().match(ToTU, enumDecl(has(EnumConstA))); + auto *ToEnumDeclB = + FirstDeclMatcher().match(ToTU, enumDecl(has(EnumConstB))); + ASSERT_NE(ToEnumDeclA, ToEnumDeclB); +} + +struct ImportTemplateParmDeclDefaultValue + : public ASTImporterOptionSpecificTestBase { +protected: + void checkTemplateParams(RedeclarableTemplateDecl *D) { + auto *CanD = cast(D->getCanonicalDecl()); + auto *CanNonTypeP = cast( + CanD->getTemplateParameters()->getParam(0)); + auto *CanTypeP = + cast(CanD->getTemplateParameters()->getParam(1)); + auto *CanTemplateP = cast( + CanD->getTemplateParameters()->getParam(2)); + EXPECT_FALSE(CanNonTypeP->getDefaultArgStorage().isInherited()); + EXPECT_FALSE(CanTypeP->getDefaultArgStorage().isInherited()); + EXPECT_FALSE(CanTemplateP->getDefaultArgStorage().isInherited()); + for (Decl *Redecl : D->redecls()) { + auto *ReD = cast(Redecl); + if (ReD != CanD) { + auto *NonTypeP = cast( + ReD->getTemplateParameters()->getParam(0)); + auto *TypeP = cast( + ReD->getTemplateParameters()->getParam(1)); + auto *TemplateP = cast( + ReD->getTemplateParameters()->getParam(2)); + EXPECT_TRUE(NonTypeP->getDefaultArgStorage().isInherited()); + EXPECT_TRUE(TypeP->getDefaultArgStorage().isInherited()); + EXPECT_TRUE(TemplateP->getDefaultArgStorage().isInherited()); + EXPECT_EQ(NonTypeP->getDefaultArgStorage().getInheritedFrom(), + CanNonTypeP); + EXPECT_EQ(TypeP->getDefaultArgStorage().getInheritedFrom(), CanTypeP); + EXPECT_EQ(TemplateP->getDefaultArgStorage().getInheritedFrom(), + CanTemplateP); + } + } + } + + void testImport(RedeclarableTemplateDecl *FromD) { + RedeclarableTemplateDecl *ToD = Import(FromD, Lang_CXX14); + checkTemplateParams(ToD); + } + + const char *CodeFunction = + R"( + template struct X; + + template class C = X> + void f(); + template class C> + void f(); + template class C> + void f() {} + )"; + + const char *CodeClass = + R"( + template struct X; + + template class C = X> + struct S; + template class C> + struct S; + template class C> + struct S {}; + )"; + + const char *CodeVar = + R"( + template struct X; + + template class C = X> + extern int V; + template class C> + extern int V; + template class C> + int V = A; + )"; +}; + +TEST_P(ImportTemplateParmDeclDefaultValue, ImportFunctionTemplate) { + Decl *FromTU = getTuDecl(CodeFunction, Lang_CXX14); + auto *FromLastD = LastDeclMatcher().match( + FromTU, functionTemplateDecl(hasName("f"))); + testImport(FromLastD); +} + +TEST_P(ImportTemplateParmDeclDefaultValue, ImportExistingFunctionTemplate) { + getToTuDecl(CodeFunction, Lang_CXX14); + Decl *FromTU = getTuDecl(CodeFunction, Lang_CXX14); + auto *FromLastD = LastDeclMatcher().match( + FromTU, functionTemplateDecl(hasName("f"))); + testImport(FromLastD); +} + +TEST_P(ImportTemplateParmDeclDefaultValue, ImportClassTemplate) { + Decl *FromTU = getTuDecl(CodeClass, Lang_CXX14); + auto *FromLastD = LastDeclMatcher().match( + FromTU, classTemplateDecl(hasName("S"))); + testImport(FromLastD); +} + +TEST_P(ImportTemplateParmDeclDefaultValue, ImportExistingClassTemplate) { + getToTuDecl(CodeClass, Lang_CXX14); + Decl *FromTU = getTuDecl(CodeClass, Lang_CXX14); + auto *FromLastD = LastDeclMatcher().match( + FromTU, classTemplateDecl(hasName("S"))); + testImport(FromLastD); +} + +TEST_P(ImportTemplateParmDeclDefaultValue, ImportVarTemplate) { + Decl *FromTU = getTuDecl(CodeVar, Lang_CXX14); + auto *FromLastD = LastDeclMatcher().match( + FromTU, varTemplateDecl(hasName("V"))); + testImport(FromLastD); +} + +TEST_P(ImportTemplateParmDeclDefaultValue, ImportExistingVarTemplate) { + getToTuDecl(CodeVar, Lang_CXX14); + Decl *FromTU = getTuDecl(CodeVar, Lang_CXX14); + auto *FromLastD = LastDeclMatcher().match( + FromTU, varTemplateDecl(hasName("V"))); + testImport(FromLastD); +} + INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ASTImporterLookupTableTest, DefaultTestValuesForRunOptions); @@ -9866,6 +10002,9 @@ INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportInjectedClassNameType, INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportMatrixType, DefaultTestValuesForRunOptions); +INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportTemplateParmDeclDefaultValue, + DefaultTestValuesForRunOptions); + // FIXME: Make ImportOpenCLPipe test work. // INSTANTIATE_TEST_SUITE_P(ParameterizedTests, ImportOpenCLPipe, // DefaultTestValuesForRunOptions); diff --git a/clang/unittests/AST/StructuralEquivalenceTest.cpp b/clang/unittests/AST/StructuralEquivalenceTest.cpp index 952c83be0cb6496..e994086c99d0419 100644 --- a/clang/unittests/AST/StructuralEquivalenceTest.cpp +++ b/clang/unittests/AST/StructuralEquivalenceTest.cpp @@ -1109,6 +1109,20 @@ TEST_F(StructuralEquivalenceEnumTest, EnumsWithDifferentBody) { EXPECT_FALSE(testStructuralMatch(t)); } +TEST_F(StructuralEquivalenceEnumTest, AnonymousEnumsWithSameConsts) { + // field x is required to trigger comparison of the anonymous enum + auto t = makeNamedDecls("struct foo { enum { A } x; };", + "struct foo { enum { A } x;};", Lang_CXX11); + EXPECT_TRUE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceEnumTest, AnonymousEnumsWithDiffConsts) { + // field x is required to trigger comparison of the anonymous enum + auto t = makeNamedDecls("struct foo { enum { A } x; };", + "struct foo { enum { B } x;};", Lang_CXX11); + EXPECT_FALSE(testStructuralMatch(t)); +} + struct StructuralEquivalenceEnumConstantTest : StructuralEquivalenceTest {}; TEST_F(StructuralEquivalenceEnumConstantTest, EnumConstantsWithSameValues) { diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp index f26140675fd4629..611e1f9ba5327c6 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -2552,6 +2552,10 @@ TEST_P(ASTMatchersTest, HasName_MatchesNamespaces) { recordDecl(hasName("a+b::C")))); EXPECT_TRUE(notMatches("namespace a { namespace b { class AC; } }", recordDecl(hasName("C")))); + EXPECT_TRUE(matches("namespace a { inline namespace a { class C; } }", + recordDecl(hasName("::a::C")))); + EXPECT_TRUE(matches("namespace a { inline namespace a { class C; } }", + recordDecl(hasName("::a::a::C")))); } TEST_P(ASTMatchersTest, HasName_MatchesOuterClasses) { diff --git a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp index 41fca6bf6eba22d..737277e167edd10 100644 --- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp @@ -442,6 +442,55 @@ TEST_F(EnvironmentTest, CXXDefaultInitExprResultObjIsWrappedExprResultObj) { &Env.getResultObjectLocation(*DefaultInit->getExpr())); } +// This test verifies the behavior of `getResultObjectLocation()` in +// scenarios involving inherited constructors. +// Since the specific AST node of interest `CXXConstructorDecl` is implicitly +// generated, we cannot annotate any statements inside of it as we do in tests +// within TransferTest. Thus, the only way to get the right `Environment` is by +// explicitly initializing it as we do in tests within EnvironmentTest. +// This is why this test is not inside TransferTest, where most of the tests for +// `getResultObjectLocation()` are located. +TEST_F(EnvironmentTest, ResultObjectLocationForInheritedCtorInitExpr) { + using namespace ast_matchers; + + std::string Code = R"( + struct Base { + Base(int b) {} + }; + struct Derived : Base { + using Base::Base; + }; + + Derived d = Derived(0); + )"; + + auto Unit = + tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++20"}); + auto &Context = Unit->getASTContext(); + + ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U); + + auto Results = + match(cxxConstructorDecl( + hasAnyConstructorInitializer(cxxCtorInitializer( + withInitializer(expr().bind("inherited_ctor_init_expr"))))) + .bind("ctor"), + Context); + const auto *Constructor = selectFirst("ctor", Results); + const auto *InheritedCtorInit = selectFirst( + "inherited_ctor_init_expr", Results); + + EXPECT_EQ(InheritedCtorInit->child_begin(), InheritedCtorInit->child_end()); + + Environment Env(DAContext, *Constructor); + Env.initialize(); + + RecordStorageLocation &Loc = Env.getResultObjectLocation(*InheritedCtorInit); + EXPECT_NE(&Loc, nullptr); + + EXPECT_EQ(&Loc, Env.getThisPointeeStorageLocation()); +} + TEST_F(EnvironmentTest, Stmt) { using namespace ast_matchers; diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index 1a52b82d656656e..8717d9753d161b1 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -9,6 +9,7 @@ #include "TestingSupport.h" #include "clang/AST/Decl.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/OperationKinds.h" #include "clang/AST/Type.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/ASTMatchers/ASTMatchers.h" @@ -79,7 +80,7 @@ class DataflowAnalysisTest : public Test { /// Returns the `CFGBlock` containing `S` (and asserts that it exists). const CFGBlock *blockForStmt(const Stmt &S) { - const CFGBlock *Block = ACFG->getStmtToBlock().lookup(&S); + const CFGBlock *Block = ACFG->blockForStmt(S); assert(Block != nullptr); return Block; } @@ -370,6 +371,42 @@ TEST_F(DiscardExprStateTest, ConditionalOperator) { EXPECT_EQ(CallGState.Env.get(AddrOfI), nullptr); } +TEST_F(DiscardExprStateTest, CallWithParenExprTreatedCorrectly) { + // This is a regression test. + // In the CFG for `target()` below, the expression that evaluates the function + // pointer for `expect` and the actual call are separated into different + // baseic blocks (because of the control flow introduced by the `||` + // operator). + // The value for the `expect` function pointer was erroneously discarded + // from the environment between these two blocks because the code that + // determines whether the expression values for a block need to be preserved + // did not ignore the `ParenExpr` around `(i == 1)` (which is not represented + // in the CFG). + std::string Code = R"( + bool expect(bool, bool); + void target(int i) { + expect(false || (i == 1), false); + } + )"; + auto BlockStates = llvm::cantFail(runAnalysis( + Code, [](ASTContext &C) { return NoopAnalysis(C); })); + + const auto &FnToPtrDecay = matchNode( + implicitCastExpr(hasCastKind(CK_FunctionToPointerDecay))); + const auto &CallExpect = + matchNode(callExpr(callee(functionDecl(hasName("expect"))))); + + // In the block that evaluates the implicit cast of `expect` to a pointer, + // this expression is associated with a value. + const auto &FnToPtrDecayState = blockStateForStmt(BlockStates, FnToPtrDecay); + EXPECT_NE(FnToPtrDecayState.Env.getValue(FnToPtrDecay), nullptr); + + // In the block that calls `expect()`, the implicit cast of `expect` to a + // pointer is still associated with a value. + const auto &CallExpectState = blockStateForStmt(BlockStates, CallExpect); + EXPECT_NE(CallExpectState.Env.getValue(FnToPtrDecay), nullptr); +} + struct NonConvergingLattice { int State; diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 1f820d83c261a35..f432b95cc1e2bec 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -577,12 +577,20 @@ TEST_F(TokenAnnotatorTest, UnderstandsTernaryInTemplate) { EXPECT_TOKEN(Tokens[7], tok::greater, TT_TemplateCloser); // IsExpression = true + Tokens = annotate("return foo();"); ASSERT_EQ(Tokens.size(), 13u) << Tokens; EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); EXPECT_TOKEN(Tokens[4], tok::question, TT_ConditionalExpr); EXPECT_TOKEN(Tokens[6], tok::colon, TT_ConditionalExpr); EXPECT_TOKEN(Tokens[8], tok::greater, TT_TemplateCloser); + + Tokens = annotate("return foo{};"); + ASSERT_EQ(Tokens.size(), 13u) << Tokens; + EXPECT_TOKEN(Tokens[2], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[4], tok::question, TT_ConditionalExpr); + EXPECT_TOKEN(Tokens[6], tok::colon, TT_ConditionalExpr); + EXPECT_TOKEN(Tokens[8], tok::greater, TT_TemplateCloser); } TEST_F(TokenAnnotatorTest, UnderstandsNonTemplateAngleBrackets) { @@ -596,6 +604,21 @@ TEST_F(TokenAnnotatorTest, UnderstandsNonTemplateAngleBrackets) { EXPECT_TOKEN(Tokens[1], tok::less, TT_BinaryOperator); EXPECT_TOKEN(Tokens[7], tok::greater, TT_BinaryOperator); + Tokens = annotate("return A < B ? true : A > B;"); + ASSERT_EQ(Tokens.size(), 12u) << Tokens; + EXPECT_TOKEN(Tokens[2], tok::less, TT_BinaryOperator); + EXPECT_TOKEN(Tokens[8], tok::greater, TT_BinaryOperator); + + Tokens = annotate("return A < B ? true : A > B ? false : false;"); + ASSERT_EQ(Tokens.size(), 16u) << Tokens; + EXPECT_TOKEN(Tokens[2], tok::less, TT_BinaryOperator); + EXPECT_TOKEN(Tokens[8], tok::greater, TT_BinaryOperator); + + Tokens = annotate("return A < B ^ A > B;"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[2], tok::less, TT_BinaryOperator); + EXPECT_TOKEN(Tokens[6], tok::greater, TT_BinaryOperator); + Tokens = annotate("ratio{-1, 2} < ratio{-1, 3} == -1 / 3 > -1 / 2;"); ASSERT_EQ(Tokens.size(), 27u) << Tokens; EXPECT_TOKEN(Tokens[7], tok::less, TT_BinaryOperator); diff --git a/clang/unittests/Tooling/ToolingTest.cpp b/clang/unittests/Tooling/ToolingTest.cpp index 2e3da2cd2a70135..f41a44fa0922a1d 100644 --- a/clang/unittests/Tooling/ToolingTest.cpp +++ b/clang/unittests/Tooling/ToolingTest.cpp @@ -586,6 +586,11 @@ TEST(runToolOnCode, TestSkipFunctionBody) { EXPECT_FALSE(runToolOnCodeWithArgs( std::make_unique(), "template int skipMeNot() { an_error_here }", Args2)); + + EXPECT_TRUE(runToolOnCodeWithArgs( + std::make_unique(), + "__inline __attribute__((__gnu_inline__)) void skipMe() {}", + {"--cuda-host-only", "-nocudainc", "-xcuda"})); } TEST(runToolOnCodeWithArgs, TestNoDepFile) { diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 1f8344068033066..f504b1de144b721 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -2372,13 +2372,10 @@ void PragmaClangAttributeSupport::generateParsingHelpers(raw_ostream &OS) { OS << "}\n\n"; } -template -static void forEachUniqueSpelling(const Record &Attr, Fn &&F) { +template static void forEachSpelling(const Record &Attr, Fn &&F) { std::vector Spellings = GetFlattenedSpellings(Attr); - SmallDenseSet Seen; for (const FlattenedSpelling &S : Spellings) { - if (Seen.insert(S.name()).second) - F(S); + F(S); } } @@ -2402,8 +2399,11 @@ static void emitClangAttrTypeArgList(RecordKeeper &Records, raw_ostream &OS) { continue; // All these spellings take a single type argument. - forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) { - OS << ".Case(\"" << S.name() << "\", " << "true" << ")\n"; + forEachSpelling(*Attr, [&](const FlattenedSpelling &S) { + OS << ".Case(\"" << S.variety(); + if (S.nameSpace().length()) + OS << "::" << S.nameSpace(); + OS << "::" << S.name() << "\", true)\n"; }); } OS << "#endif // CLANG_ATTR_TYPE_ARG_LIST\n\n"; @@ -2421,8 +2421,11 @@ static void emitClangAttrArgContextList(RecordKeeper &Records, raw_ostream &OS) continue; // All these spellings take are parsed unevaluated. - forEachUniqueSpelling(Attr, [&](const FlattenedSpelling &S) { - OS << ".Case(\"" << S.name() << "\", " << "true" << ")\n"; + forEachSpelling(Attr, [&](const FlattenedSpelling &S) { + OS << ".Case(\"" << S.variety(); + if (S.nameSpace().length()) + OS << "::" << S.nameSpace(); + OS << "::" << S.name() << "\", true)\n"; }); } OS << "#endif // CLANG_ATTR_ARG_CONTEXT_LIST\n\n"; @@ -2483,10 +2486,11 @@ static void emitClangAttrVariadicIdentifierArgList(RecordKeeper &Records, continue; // All these spellings take an identifier argument. - forEachUniqueSpelling(*A, [&](const FlattenedSpelling &S) { - OS << ".Case(\"" << S.name() << "\", " - << "true" - << ")\n"; + forEachSpelling(*A, [&](const FlattenedSpelling &S) { + OS << ".Case(\"" << S.variety(); + if (S.nameSpace().length()) + OS << "::" << S.nameSpace(); + OS << "::" << S.name() << "\", true)\n"; }); } OS << "#endif // CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST\n\n"; @@ -2552,8 +2556,11 @@ static void emitClangAttrUnevaluatedStringLiteralList(RecordKeeper &Records, continue; // All these spellings have at least one string literal has argument. - forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) { - OS << ".Case(\"" << S.name() << "\", " << MaskStr << ")\n"; + forEachSpelling(*Attr, [&](const FlattenedSpelling &S) { + OS << ".Case(\"" << S.variety(); + if (S.nameSpace().length()) + OS << "::" << S.nameSpace(); + OS << "::" << S.name() << "\", " << MaskStr << ")\n"; }); } OS << "#endif // CLANG_ATTR_STRING_LITERAL_ARG_LIST\n\n"; @@ -2571,8 +2578,11 @@ static void emitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &O continue; // All these spellings take an identifier argument. - forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) { - OS << ".Case(\"" << S.name() << "\", " << "true" << ")\n"; + forEachSpelling(*Attr, [&](const FlattenedSpelling &S) { + OS << ".Case(\"" << S.variety(); + if (S.nameSpace().length()) + OS << "::" << S.nameSpace(); + OS << "::" << S.name() << "\", true)\n"; }); } OS << "#endif // CLANG_ATTR_IDENTIFIER_ARG_LIST\n\n"; @@ -2587,18 +2597,20 @@ static void emitClangAttrStrictIdentifierArgAtIndexList(RecordKeeper &Records, for (const auto *Attr : Attrs) { if (!Attr->getValueAsBit("StrictEnumParameters")) continue; - // Determine whether the first argument is an identifier. + // Determine whether each argument is an identifier. std::vector Args = Attr->getValueAsListOfDefs("Args"); uint64_t enumAtIndex = 0; - for (size_t i = 0; i < Args.size(); i++) { - enumAtIndex |= ((uint64_t)isIdentifierArgument(Args[0])) << i; - } + for (size_t I = 0; I < Args.size(); I++) + enumAtIndex |= ((uint64_t)isIdentifierArgument(Args[I])) << I; if (!enumAtIndex) continue; // All these spellings take an identifier argument. - forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) { - OS << ".Case(\"" << S.name() << "\", " << enumAtIndex << "ull)\n"; + forEachSpelling(*Attr, [&](const FlattenedSpelling &S) { + OS << ".Case(\"" << S.variety(); + if (S.nameSpace().length()) + OS << "::" << S.nameSpace(); + OS << "::" << S.name() << "\", " << enumAtIndex << "ull)\n"; }); } OS << "#endif // CLANG_ATTR_STRICT_IDENTIFIER_ARG_AT_INDEX_LIST\n\n"; @@ -2623,10 +2635,11 @@ static void emitClangAttrThisIsaIdentifierArgList(RecordKeeper &Records, continue; // All these spellings take an identifier argument. - forEachUniqueSpelling(*A, [&](const FlattenedSpelling &S) { - OS << ".Case(\"" << S.name() << "\", " - << "true" - << ")\n"; + forEachSpelling(*A, [&](const FlattenedSpelling &S) { + OS << ".Case(\"" << S.variety(); + if (S.nameSpace().length()) + OS << "::" << S.nameSpace(); + OS << "::" << S.name() << "\", true)\n"; }); } OS << "#endif // CLANG_ATTR_THIS_ISA_IDENTIFIER_ARG_LIST\n\n"; @@ -2642,8 +2655,11 @@ static void emitClangAttrAcceptsExprPack(RecordKeeper &Records, if (!Attr.getValueAsBit("AcceptsExprPack")) continue; - forEachUniqueSpelling(Attr, [&](const FlattenedSpelling &S) { - OS << ".Case(\"" << S.name() << "\", true)\n"; + forEachSpelling(Attr, [&](const FlattenedSpelling &S) { + OS << ".Case(\"" << S.variety(); + if (S.nameSpace().length()) + OS << "::" << S.nameSpace(); + OS << "::" << S.name() << "\", true)\n"; }); } OS << "#endif // CLANG_ATTR_ACCEPTS_EXPR_PACK\n\n"; diff --git a/compiler-rt/CMakeLists.txt b/compiler-rt/CMakeLists.txt index 96e432e2c97a791..2207555b03a03f5 100644 --- a/compiler-rt/CMakeLists.txt +++ b/compiler-rt/CMakeLists.txt @@ -797,6 +797,10 @@ if(ANDROID) append_list_if(COMPILER_RT_HAS_FUSE_LD_LLD_FLAG -fuse-ld=lld SANITIZER_COMMON_LINK_FLAGS) append_list_if(COMPILER_RT_HAS_LLD -fuse-ld=lld COMPILER_RT_UNITTEST_LINK_FLAGS) endif() +if(${COMPILER_RT_DEFAULT_TARGET_ARCH} MATCHES sparc) + # lld has several bugs/limitations on SPARC, so disable (Issue #100320). + set(COMPILER_RT_HAS_LLD FALSE) +endif() pythonize_bool(COMPILER_RT_HAS_LLD) pythonize_bool(COMPILER_RT_TEST_USE_LLD) diff --git a/compiler-rt/include/profile/InstrProfData.inc b/compiler-rt/include/profile/InstrProfData.inc index 847e53cfa74328d..b9df3266fbcf8fa 100644 --- a/compiler-rt/include/profile/InstrProfData.inc +++ b/compiler-rt/include/profile/InstrProfData.inc @@ -738,6 +738,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure, #define INSTR_PROF_RAW_VERSION_VAR __llvm_profile_raw_version #define INSTR_PROF_PROFILE_RUNTIME_VAR __llvm_profile_runtime #define INSTR_PROF_PROFILE_COUNTER_BIAS_VAR __llvm_profile_counter_bias +#define INSTR_PROF_PROFILE_BITMAP_BIAS_VAR __llvm_profile_bitmap_bias #define INSTR_PROF_PROFILE_SET_TIMESTAMP __llvm_profile_set_timestamp #define INSTR_PROF_PROFILE_SAMPLING_VAR __llvm_profile_sampling diff --git a/compiler-rt/lib/builtins/aarch64/sme-abi-vg.c b/compiler-rt/lib/builtins/aarch64/sme-abi-vg.c index 20061012e16c60a..4b9ee8c1d382d9e 100644 --- a/compiler-rt/lib/builtins/aarch64/sme-abi-vg.c +++ b/compiler-rt/lib/builtins/aarch64/sme-abi-vg.c @@ -10,10 +10,7 @@ struct FEATURES { extern struct FEATURES __aarch64_cpu_features; -#if __GNUC__ >= 9 -#pragma GCC diagnostic ignored "-Wprio-ctor-dtor" -#endif -__attribute__((constructor(90))) static void get_aarch64_cpu_features(void) { +CONSTRUCTOR_ATTRIBUTE static void get_aarch64_cpu_features(void) { if (__atomic_load_n(&__aarch64_cpu_features.features, __ATOMIC_RELAXED)) return; diff --git a/compiler-rt/lib/builtins/cpu_model/riscv.c b/compiler-rt/lib/builtins/cpu_model/riscv.c index 145954e704433a1..92931fae64fbf3e 100644 --- a/compiler-rt/lib/builtins/cpu_model/riscv.c +++ b/compiler-rt/lib/builtins/cpu_model/riscv.c @@ -108,6 +108,9 @@ struct { #if defined(__linux__) +// The RISC-V hwprobe interface is documented here: +// . + static long syscall_impl_5_args(long number, long arg1, long arg2, long arg3, long arg4, long arg5) { register long a7 __asm__("a7") = number; diff --git a/compiler-rt/lib/builtins/os_version_check.c b/compiler-rt/lib/builtins/os_version_check.c index 01fae834ab2191b..b10f23a81a9c6fa 100644 --- a/compiler-rt/lib/builtins/os_version_check.c +++ b/compiler-rt/lib/builtins/os_version_check.c @@ -14,6 +14,7 @@ #ifdef __APPLE__ #include +#include #include #include #include @@ -270,6 +271,8 @@ static inline uint32_t ConstructVersion(uint32_t Major, uint32_t Minor, return ((Major & 0xffff) << 16) | ((Minor & 0xff) << 8) | (Subminor & 0xff); } +#define PLATFORM_MACOS 1 + int32_t __isPlatformVersionAtLeast(uint32_t Platform, uint32_t Major, uint32_t Minor, uint32_t Subminor) { dispatch_once_f(&DispatchOnceCounter, NULL, initializeAvailabilityCheck); @@ -282,6 +285,29 @@ int32_t __isPlatformVersionAtLeast(uint32_t Platform, uint32_t Major, return AvailabilityVersionCheck(1, Versions); } +#if TARGET_OS_OSX + +int32_t __isPlatformOrVariantPlatformVersionAtLeast( + uint32_t Platform, uint32_t Major, uint32_t Minor, uint32_t Subminor, + uint32_t Platform2, uint32_t Major2, uint32_t Minor2, uint32_t Subminor2) { + dispatch_once_f(&DispatchOnceCounter, NULL, initializeAvailabilityCheck); + + if (!AvailabilityVersionCheck) { + // Handle case of back-deployment for older macOS. + if (Platform == PLATFORM_MACOS) { + return __isOSVersionAtLeast(Major, Minor, Subminor); + } + assert(Platform2 == PLATFORM_MACOS && "unexpected platform"); + return __isOSVersionAtLeast(Major2, Minor2, Subminor2); + } + dyld_build_version_t Versions[] = { + {Platform, ConstructVersion(Major, Minor, Subminor)}, + {Platform2, ConstructVersion(Major2, Minor2, Subminor2)}}; + return AvailabilityVersionCheck(2, Versions); +} + +#endif + #elif __ANDROID__ #include diff --git a/compiler-rt/lib/gwp_asan/definitions.h b/compiler-rt/lib/gwp_asan/definitions.h index bec02903893462f..c6785d4aba69521 100644 --- a/compiler-rt/lib/gwp_asan/definitions.h +++ b/compiler-rt/lib/gwp_asan/definitions.h @@ -12,7 +12,8 @@ #define GWP_ASAN_TLS_INITIAL_EXEC \ __thread __attribute__((tls_model("initial-exec"))) -#define GWP_ASAN_UNLIKELY(X) __builtin_expect(!!(X), 0) +#define GWP_ASAN_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true) +#define GWP_ASAN_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false) #define GWP_ASAN_ALWAYS_INLINE inline __attribute__((always_inline)) #define GWP_ASAN_WEAK __attribute__((weak)) diff --git a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_fuchsia.cpp b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_fuchsia.cpp index 3f39402652a998d..5d5c729cdc8b701 100644 --- a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_fuchsia.cpp +++ b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_fuchsia.cpp @@ -24,13 +24,13 @@ void *GuardedPoolAllocator::map(size_t Size, const char *Name) const { assert((Size % State.PageSize) == 0); zx_handle_t Vmo; zx_status_t Status = _zx_vmo_create(Size, 0, &Vmo); - check(Status == ZX_OK, "Failed to create Vmo"); + checkWithErrorCode(Status == ZX_OK, "Failed to create Vmo", Status); _zx_object_set_property(Vmo, ZX_PROP_NAME, Name, strlen(Name)); zx_vaddr_t Addr; Status = _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_ALLOW_FAULTS, 0, Vmo, 0, Size, &Addr); - check(Status == ZX_OK, "Vmo mapping failed"); + checkWithErrorCode(Status == ZX_OK, "Vmo mapping failed", Status); _zx_handle_close(Vmo); return reinterpret_cast(Addr); } @@ -40,7 +40,7 @@ void GuardedPoolAllocator::unmap(void *Ptr, size_t Size) const { assert((Size % State.PageSize) == 0); zx_status_t Status = _zx_vmar_unmap(_zx_vmar_root_self(), reinterpret_cast(Ptr), Size); - check(Status == ZX_OK, "Vmo unmapping failed"); + checkWithErrorCode(Status == ZX_OK, "Vmo unmapping failed", Status); } void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) { @@ -50,7 +50,8 @@ void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) { _zx_vmar_root_self(), ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0, Size, &GuardedPagePoolPlatformData.Vmar, &Addr); - check(Status == ZX_OK, "Failed to reserve guarded pool allocator memory"); + checkWithErrorCode(Status == ZX_OK, + "Failed to reserve guarded pool allocator memory", Status); _zx_object_set_property(GuardedPagePoolPlatformData.Vmar, ZX_PROP_NAME, kGwpAsanGuardPageName, strlen(kGwpAsanGuardPageName)); return reinterpret_cast(Addr); @@ -59,8 +60,10 @@ void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) { void GuardedPoolAllocator::unreserveGuardedPool() { const zx_handle_t Vmar = GuardedPagePoolPlatformData.Vmar; assert(Vmar != ZX_HANDLE_INVALID && Vmar != _zx_vmar_root_self()); - check(_zx_vmar_destroy(Vmar) == ZX_OK, "Failed to destroy a vmar"); - check(_zx_handle_close(Vmar) == ZX_OK, "Failed to close a vmar"); + zx_status_t Status = _zx_vmar_destroy(Vmar); + checkWithErrorCode(Status == ZX_OK, "Failed to destroy a vmar", Status); + Status = _zx_handle_close(Vmar); + checkWithErrorCode(Status == ZX_OK, "Failed to close a vmar", Status); GuardedPagePoolPlatformData.Vmar = ZX_HANDLE_INVALID; } @@ -69,7 +72,7 @@ void GuardedPoolAllocator::allocateInGuardedPool(void *Ptr, size_t Size) const { assert((Size % State.PageSize) == 0); zx_handle_t Vmo; zx_status_t Status = _zx_vmo_create(Size, 0, &Vmo); - check(Status == ZX_OK, "Failed to create vmo"); + checkWithErrorCode(Status == ZX_OK, "Failed to create vmo", Status); _zx_object_set_property(Vmo, ZX_PROP_NAME, kGwpAsanAliveSlotName, strlen(kGwpAsanAliveSlotName)); const zx_handle_t Vmar = GuardedPagePoolPlatformData.Vmar; @@ -81,7 +84,7 @@ void GuardedPoolAllocator::allocateInGuardedPool(void *Ptr, size_t Size) const { ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_ALLOW_FAULTS | ZX_VM_SPECIFIC, Offset, Vmo, 0, Size, &P); - check(Status == ZX_OK, "Vmo mapping failed"); + checkWithErrorCode(Status == ZX_OK, "Vmo mapping failed", Status); _zx_handle_close(Vmo); } @@ -93,7 +96,7 @@ void GuardedPoolAllocator::deallocateInGuardedPool(void *Ptr, assert(Vmar != ZX_HANDLE_INVALID && Vmar != _zx_vmar_root_self()); const zx_status_t Status = _zx_vmar_unmap(Vmar, reinterpret_cast(Ptr), Size); - check(Status == ZX_OK, "Vmar unmapping failed"); + checkWithErrorCode(Status == ZX_OK, "Vmar unmapping failed", Status); } size_t GuardedPoolAllocator::getPlatformPageSize() { diff --git a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp index 549e31acb176d36..7b2e19956c7962d 100644 --- a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp +++ b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp @@ -12,6 +12,7 @@ #include "gwp_asan/utilities.h" #include +#include #include #include #include @@ -46,7 +47,8 @@ void *GuardedPoolAllocator::map(size_t Size, const char *Name) const { assert((Size % State.PageSize) == 0); void *Ptr = mmap(nullptr, Size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - check(Ptr != MAP_FAILED, "Failed to map guarded pool allocator memory"); + checkWithErrorCode(Ptr != MAP_FAILED, + "Failed to map guarded pool allocator memory", errno); MaybeSetMappingName(Ptr, Size, Name); return Ptr; } @@ -54,15 +56,16 @@ void *GuardedPoolAllocator::map(size_t Size, const char *Name) const { void GuardedPoolAllocator::unmap(void *Ptr, size_t Size) const { assert((reinterpret_cast(Ptr) % State.PageSize) == 0); assert((Size % State.PageSize) == 0); - check(munmap(Ptr, Size) == 0, - "Failed to unmap guarded pool allocator memory."); + checkWithErrorCode(munmap(Ptr, Size) == 0, + "Failed to unmap guarded pool allocator memory.", errno); } void *GuardedPoolAllocator::reserveGuardedPool(size_t Size) { assert((Size % State.PageSize) == 0); void *Ptr = mmap(nullptr, Size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - check(Ptr != MAP_FAILED, "Failed to reserve guarded pool allocator memory"); + checkWithErrorCode(Ptr != MAP_FAILED, + "Failed to reserve guarded pool allocator memory", errno); MaybeSetMappingName(Ptr, Size, kGwpAsanGuardPageName); return Ptr; } @@ -75,8 +78,9 @@ void GuardedPoolAllocator::unreserveGuardedPool() { void GuardedPoolAllocator::allocateInGuardedPool(void *Ptr, size_t Size) const { assert((reinterpret_cast(Ptr) % State.PageSize) == 0); assert((Size % State.PageSize) == 0); - check(mprotect(Ptr, Size, PROT_READ | PROT_WRITE) == 0, - "Failed to allocate in guarded pool allocator memory"); + checkWithErrorCode(mprotect(Ptr, Size, PROT_READ | PROT_WRITE) == 0, + "Failed to allocate in guarded pool allocator memory", + errno); MaybeSetMappingName(Ptr, Size, kGwpAsanAliveSlotName); } @@ -87,9 +91,10 @@ void GuardedPoolAllocator::deallocateInGuardedPool(void *Ptr, // mmap() a PROT_NONE page over the address to release it to the system, if // we used mprotect() here the system would count pages in the quarantine // against the RSS. - check(mmap(Ptr, Size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, - 0) != MAP_FAILED, - "Failed to deallocate in guarded pool allocator memory"); + checkWithErrorCode( + mmap(Ptr, Size, PROT_NONE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, + 0) != MAP_FAILED, + "Failed to deallocate in guarded pool allocator memory", errno); MaybeSetMappingName(Ptr, Size, kGwpAsanGuardPageName); } diff --git a/compiler-rt/lib/gwp_asan/platform_specific/utilities_fuchsia.cpp b/compiler-rt/lib/gwp_asan/platform_specific/utilities_fuchsia.cpp index bc9d3a4462a2f72..fecf94b0d1a1962 100644 --- a/compiler-rt/lib/gwp_asan/platform_specific/utilities_fuchsia.cpp +++ b/compiler-rt/lib/gwp_asan/platform_specific/utilities_fuchsia.cpp @@ -8,12 +8,25 @@ #include "gwp_asan/utilities.h" +#include +#include #include #include +#include namespace gwp_asan { void die(const char *Message) { __sanitizer_log_write(Message, strlen(Message)); __builtin_trap(); } + +void dieWithErrorCode(const char *Message, int64_t ErrorCode) { + const char *error_str = + _zx_status_get_string(static_cast(ErrorCode)); + size_t buffer_size = strlen(Message) + 32 + strlen(error_str); + char *buffer = static_cast(alloca(buffer_size)); + snprintf(buffer, buffer_size, "%s (Error Code: %s)", Message, error_str); + __sanitizer_log_write(buffer, strlen(buffer)); + __builtin_trap(); +} } // namespace gwp_asan diff --git a/compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp b/compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp index 735796305509562..750198062ce4f54 100644 --- a/compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp +++ b/compiler-rt/lib/gwp_asan/platform_specific/utilities_posix.cpp @@ -6,7 +6,11 @@ // //===----------------------------------------------------------------------===// +#include #include // IWYU pragma: keep (for __BIONIC__ macro) +#include +#include +#include #ifdef __BIONIC__ #include "gwp_asan/definitions.h" @@ -27,4 +31,21 @@ void die(const char *Message) { __builtin_trap(); #endif // __BIONIC__ } + +void dieWithErrorCode(const char *Message, int64_t ErrorCode) { +#ifdef __BIONIC__ + if (&android_set_abort_message == nullptr) + abort(); + + size_t buffer_size = strlen(Message) + 48; + char *buffer = static_cast(alloca(buffer_size)); + snprintf(buffer, buffer_size, "%s (Error Code: %" PRId64 ")", Message, + ErrorCode); + android_set_abort_message(buffer); + abort(); +#else // __BIONIC__ + fprintf(stderr, "%s (Error Code: %" PRId64 ")", Message, ErrorCode); + __builtin_trap(); +#endif // __BIONIC__ +} } // namespace gwp_asan diff --git a/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt b/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt index ca43ec2a94ac4d8..5de1af10eec3667 100644 --- a/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt +++ b/compiler-rt/lib/gwp_asan/tests/CMakeLists.txt @@ -28,7 +28,9 @@ set(GWP_ASAN_UNITTESTS late_init.cpp options.cpp recoverable.cpp - never_allocated.cpp) + never_allocated.cpp + utilities.cpp +) set(GWP_ASAN_UNIT_TEST_HEADERS ${GWP_ASAN_HEADERS} diff --git a/compiler-rt/lib/gwp_asan/tests/utilities.cpp b/compiler-rt/lib/gwp_asan/tests/utilities.cpp new file mode 100644 index 000000000000000..09a54e526f5dbc4 --- /dev/null +++ b/compiler-rt/lib/gwp_asan/tests/utilities.cpp @@ -0,0 +1,24 @@ +//===-- utilities.cpp -------------------------------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "gwp_asan/utilities.h" +#include "gwp_asan/tests/harness.h" + +using gwp_asan::check; +using gwp_asan::checkWithErrorCode; + +TEST(UtilitiesDeathTest, CheckPrintsAsExpected) { + EXPECT_DEATH({ check(false, "Hello world"); }, "Hello world"); + check(true, "Should not crash"); + EXPECT_DEATH( + { checkWithErrorCode(false, "Hello world", 1337); }, + "Hello world \\(Error Code: 1337\\)"); + EXPECT_DEATH( + { checkWithErrorCode(false, "Hello world", -1337); }, + "Hello world \\(Error Code: -1337\\)"); +} diff --git a/compiler-rt/lib/gwp_asan/utilities.h b/compiler-rt/lib/gwp_asan/utilities.h index 76e5df2e3eb8f87..02f450a9eeec3da 100644 --- a/compiler-rt/lib/gwp_asan/utilities.h +++ b/compiler-rt/lib/gwp_asan/utilities.h @@ -12,17 +12,28 @@ #include "gwp_asan/definitions.h" #include +#include namespace gwp_asan { // Terminates in a platform-specific way with `Message`. void die(const char *Message); +void dieWithErrorCode(const char *Message, int64_t ErrorCode); // Checks that `Condition` is true, otherwise dies with `Message`. GWP_ASAN_ALWAYS_INLINE void check(bool Condition, const char *Message) { - if (Condition) + if (GWP_ASAN_LIKELY(Condition)) return; die(Message); } + +// Checks that `Condition` is true, otherwise dies with `Message` (including +// errno at the end). +GWP_ASAN_ALWAYS_INLINE void +checkWithErrorCode(bool Condition, const char *Message, int64_t ErrorCode) { + if (GWP_ASAN_LIKELY(Condition)) + return; + dieWithErrorCode(Message, ErrorCode); +} } // namespace gwp_asan #endif // GWP_ASAN_UTILITIES_H_ diff --git a/compiler-rt/lib/interception/interception_linux.h b/compiler-rt/lib/interception/interception_linux.h index 433a3d9bd7fa722..2e01ff44578c3ce 100644 --- a/compiler-rt/lib/interception/interception_linux.h +++ b/compiler-rt/lib/interception/interception_linux.h @@ -28,12 +28,14 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real, uptr func, uptr trampoline); } // namespace __interception -#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) \ - ::__interception::InterceptFunction( \ - #func, \ - (::__interception::uptr *)&REAL(func), \ - (::__interception::uptr)&(func), \ - (::__interception::uptr)&TRAMPOLINE(func)) +// Cast func to type of REAL(func) before casting to uptr in case it is an +// overloaded function, which is the case for some glibc functions when +// _FORTIFY_SOURCE is used. This disambiguates which overload to use. +#define INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) \ + ::__interception::InterceptFunction( \ + #func, (::__interception::uptr *)&REAL(func), \ + (::__interception::uptr)(decltype(REAL(func)))&(func), \ + (::__interception::uptr) &TRAMPOLINE(func)) // dlvsym is a GNU extension supported by some other platforms. #if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD @@ -41,7 +43,7 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real, ::__interception::InterceptFunction( \ #func, symver, \ (::__interception::uptr *)&REAL(func), \ - (::__interception::uptr)&(func), \ + (::__interception::uptr)(decltype(REAL(func)))&(func), \ (::__interception::uptr)&TRAMPOLINE(func)) #else #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \ diff --git a/compiler-rt/lib/memprof/memprof_mapping.h b/compiler-rt/lib/memprof/memprof_mapping.h index fef8acfcfc92191..6da385ab3d6e2df 100644 --- a/compiler-rt/lib/memprof/memprof_mapping.h +++ b/compiler-rt/lib/memprof/memprof_mapping.h @@ -55,7 +55,7 @@ extern uptr kHighMemEnd; // Initialized in __memprof_init. // computed by summing up all individual 1 byte counters. This can incur an // accuracy penalty. -#define HISTOGRAM_GRANULARITY 8U +#define HISTOGRAM_GRANULARITY 8ULL #define HISTOGRAM_MAX_COUNTER 255U diff --git a/compiler-rt/lib/nsan/nsan_interceptors.cpp b/compiler-rt/lib/nsan/nsan_interceptors.cpp index 544b44f53cc42e7..852524bd3733285 100644 --- a/compiler-rt/lib/nsan/nsan_interceptors.cpp +++ b/compiler-rt/lib/nsan/nsan_interceptors.cpp @@ -21,10 +21,6 @@ #include -#if SANITIZER_LINUX -extern "C" int mallopt(int param, int value); -#endif - using namespace __sanitizer; using __nsan::nsan_init_is_running; using __nsan::nsan_initialized; @@ -209,12 +205,6 @@ void __nsan::InitializeInterceptors() { static bool initialized = false; CHECK(!initialized); - // Instruct libc malloc to consume less memory. -#if SANITIZER_LINUX - mallopt(1, 0); // M_MXFAST - mallopt(-3, 32 * 1024); // M_MMAP_THRESHOLD -#endif - InitializeMallocInterceptors(); INTERCEPT_FUNCTION(memset); diff --git a/compiler-rt/lib/profile/InstrProfiling.h b/compiler-rt/lib/profile/InstrProfiling.h index d424a22c212c30e..6906d52eacaf1b4 100644 --- a/compiler-rt/lib/profile/InstrProfiling.h +++ b/compiler-rt/lib/profile/InstrProfiling.h @@ -49,7 +49,6 @@ typedef struct ValueProfNode { #include "profile/InstrProfData.inc" } ValueProfNode; -typedef void *IntPtrT; typedef struct COMPILER_RT_ALIGNAS(INSTR_PROF_DATA_ALIGNMENT) VTableProfData { #define INSTR_PROF_VTABLE_DATA(Type, LLVMType, Name, Initializer) Type Name; #include "profile/InstrProfData.inc" diff --git a/compiler-rt/lib/profile/InstrProfilingFile.c b/compiler-rt/lib/profile/InstrProfilingFile.c index 1c58584d2d4f73c..db3918d84103195 100644 --- a/compiler-rt/lib/profile/InstrProfilingFile.c +++ b/compiler-rt/lib/profile/InstrProfilingFile.c @@ -101,6 +101,8 @@ static const int UseBiasVar = 0; static const char *FileOpenMode = "a+b"; static void *BiasAddr = NULL; static void *BiasDefaultAddr = NULL; +static void *BitmapBiasAddr = NULL; +static void *BitmapBiasDefaultAddr = NULL; static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) { /* Get the sizes of various profile data sections. Taken from * __llvm_profile_get_size_for_buffer(). */ @@ -199,11 +201,15 @@ static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) { #define INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR \ INSTR_PROF_CONCAT(INSTR_PROF_PROFILE_COUNTER_BIAS_VAR, _default) COMPILER_RT_VISIBILITY intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR = 0; +#define INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR \ + INSTR_PROF_CONCAT(INSTR_PROF_PROFILE_BITMAP_BIAS_VAR, _default) +COMPILER_RT_VISIBILITY intptr_t INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR = 0; /* This variable is a weak external reference which could be used to detect * whether or not the compiler defined this symbol. */ #if defined(_MSC_VER) COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR; +COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_BITMAP_BIAS_VAR; #if defined(_M_IX86) || defined(__i386__) #define WIN_SYM_PREFIX "_" #else @@ -213,10 +219,17 @@ COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR; linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE( \ INSTR_PROF_PROFILE_COUNTER_BIAS_VAR) "=" WIN_SYM_PREFIX \ INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR)) +#pragma comment( \ + linker, "/alternatename:" WIN_SYM_PREFIX INSTR_PROF_QUOTE( \ + INSTR_PROF_PROFILE_BITMAP_BIAS_VAR) "=" WIN_SYM_PREFIX \ + INSTR_PROF_QUOTE(INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR)) #else COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_COUNTER_BIAS_VAR __attribute__((weak, alias(INSTR_PROF_QUOTE( INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR)))); +COMPILER_RT_VISIBILITY extern intptr_t INSTR_PROF_PROFILE_BITMAP_BIAS_VAR + __attribute__((weak, alias(INSTR_PROF_QUOTE( + INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR)))); #endif static const int ContinuousModeSupported = 1; static const int UseBiasVar = 1; @@ -227,6 +240,9 @@ static const char *FileOpenMode = "w+b"; * used and runtime provides a weak alias so we can check if it's defined. */ static void *BiasAddr = &INSTR_PROF_PROFILE_COUNTER_BIAS_VAR; static void *BiasDefaultAddr = &INSTR_PROF_PROFILE_COUNTER_BIAS_DEFAULT_VAR; +static void *BitmapBiasAddr = &INSTR_PROF_PROFILE_BITMAP_BIAS_VAR; +static void *BitmapBiasDefaultAddr = + &INSTR_PROF_PROFILE_BITMAP_BIAS_DEFAULT_VAR; static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) { /* Get the sizes of various profile data sections. Taken from * __llvm_profile_get_size_for_buffer(). */ @@ -237,12 +253,18 @@ static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) { const char *BitmapBegin = __llvm_profile_begin_bitmap(); const char *BitmapEnd = __llvm_profile_end_bitmap(); uint64_t DataSize = __llvm_profile_get_data_size(DataBegin, DataEnd); + uint64_t CountersSize = + __llvm_profile_get_counters_size(CountersBegin, CountersEnd); + uint64_t NumBitmapBytes = + __llvm_profile_get_num_bitmap_bytes(BitmapBegin, BitmapEnd); /* Get the file size. */ uint64_t FileSize = 0; if (getProfileFileSizeForMerging(File, &FileSize)) return 1; int Fileno = fileno(File); + uint64_t PaddingBytesAfterCounters = + __llvm_profile_get_num_padding_bytes(CountersSize); uint64_t FileOffsetToCounters = sizeof(__llvm_profile_header) + __llvm_write_binary_ids(NULL) + DataSize; @@ -260,7 +282,17 @@ static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) { /* Return the memory allocated for counters to OS. */ lprofReleaseMemoryPagesToOS((uintptr_t)CountersBegin, (uintptr_t)CountersEnd); - /* BIAS MODE not supported yet for Bitmap (MCDC). */ + /* Also mmap MCDC bitmap bytes. If there aren't any bitmap bytes, mmap() + * will fail with EINVAL. */ + if (NumBitmapBytes == 0) + return 0; + + /* Update profbm_bias. */ + uint64_t FileOffsetToBitmap = + FileOffsetToCounters + CountersSize + PaddingBytesAfterCounters; + /* Update the profile fields based on the current mapping. */ + INSTR_PROF_PROFILE_BITMAP_BIAS_VAR = + (uintptr_t)Profile - (uintptr_t)BitmapBegin + FileOffsetToBitmap; /* Return the memory allocated for counters to OS. */ lprofReleaseMemoryPagesToOS((uintptr_t)BitmapBegin, (uintptr_t)BitmapEnd); @@ -272,6 +304,8 @@ static const int UseBiasVar = 0; static const char *FileOpenMode = "a+b"; static void *BiasAddr = NULL; static void *BiasDefaultAddr = NULL; +static void *BitmapBiasAddr = NULL; +static void *BitmapBiasDefaultAddr = NULL; static int mmapForContinuousMode(uint64_t CurrentFileOffset, FILE *File) { return 0; } @@ -619,8 +653,10 @@ static void initializeProfileForContinuousMode(void) { PROF_ERR("%s\n", "continuous mode is unsupported on this platform"); return; } - if (UseBiasVar && BiasAddr == BiasDefaultAddr) { - PROF_ERR("%s\n", "__llvm_profile_counter_bias is undefined"); + if (UseBiasVar && BiasAddr == BiasDefaultAddr && + BitmapBiasAddr == BitmapBiasDefaultAddr) { + PROF_ERR("%s\n", "Neither __llvm_profile_counter_bias nor " + "__llvm_profile_bitmap_bias is defined"); return; } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp index 2ea61b1cb424ce2..fd5ff1b40054575 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -33,11 +33,15 @@ // For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat' // format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To // access stat from asm/stat.h, without conflicting with definition in -// sys/stat.h, we use this trick. -# if SANITIZER_MIPS64 +// sys/stat.h, we use this trick. sparc64 is similar, using +// syscall(__NR_stat64) and struct kernel_stat64. +# if SANITIZER_LINUX && (SANITIZER_MIPS64 || SANITIZER_SPARC64) # include # include # define stat kernel_stat +# if SANITIZER_SPARC64 +# define stat64 kernel_stat64 +# endif # if SANITIZER_GO # undef st_atime # undef st_mtime @@ -48,6 +52,7 @@ # endif # include # undef stat +# undef stat64 # endif # include @@ -220,7 +225,7 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, // mmap2 specifies file offset in 4096-byte units. CHECK(IsAligned(offset, 4096)); return internal_syscall(SYSCALL(mmap2), addr, length, prot, flags, fd, - offset / 4096); + (OFF_T)(offset / 4096)); # endif } # endif // !SANITIZER_S390 @@ -285,8 +290,7 @@ uptr internal_ftruncate(fd_t fd, uptr size) { return res; } -# if (!SANITIZER_LINUX_USES_64BIT_SYSCALLS || SANITIZER_SPARC) && \ - SANITIZER_LINUX +# if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX static void stat64_to_stat(struct stat64 *in, struct stat *out) { internal_memset(out, 0, sizeof(*out)); out->st_dev = in->st_dev; @@ -327,7 +331,12 @@ static void statx_to_stat(struct statx *in, struct stat *out) { } # endif -# if SANITIZER_MIPS64 +# if SANITIZER_MIPS64 || SANITIZER_SPARC64 +# if SANITIZER_MIPS64 +typedef struct kernel_stat kstat_t; +# else +typedef struct kernel_stat64 kstat_t; +# endif // Undefine compatibility macros from // so that they would not clash with the kernel_stat // st_[a|m|c]time fields @@ -345,7 +354,7 @@ static void statx_to_stat(struct statx *in, struct stat *out) { # undef st_mtime_nsec # undef st_ctime_nsec # endif -static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) { +static void kernel_stat_to_stat(kstat_t *in, struct stat *out) { internal_memset(out, 0, sizeof(*out)); out->st_dev = in->st_dev; out->st_ino = in->st_ino; @@ -391,6 +400,12 @@ uptr internal_stat(const char *path, void *buf) { !SANITIZER_SPARC return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, 0); +# elif SANITIZER_SPARC64 + kstat_t buf64; + int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path, + (uptr)&buf64, 0); + kernel_stat_to_stat(&buf64, (struct stat *)buf); + return res; # else struct stat64 buf64; int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path, @@ -423,6 +438,12 @@ uptr internal_lstat(const char *path, void *buf) { !SANITIZER_SPARC return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path, (uptr)buf, AT_SYMLINK_NOFOLLOW); +# elif SANITIZER_SPARC64 + kstat_t buf64; + int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path, + (uptr)&buf64, AT_SYMLINK_NOFOLLOW); + kernel_stat_to_stat(&buf64, (struct stat *)buf); + return res; # else struct stat64 buf64; int res = internal_syscall(SYSCALL(fstatat64), AT_FDCWD, (uptr)path, @@ -442,10 +463,16 @@ uptr internal_fstat(fd_t fd, void *buf) { # if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS # if SANITIZER_MIPS64 // For mips64, fstat syscall fills buffer in the format of kernel_stat - struct kernel_stat kbuf; + kstat_t kbuf; int res = internal_syscall(SYSCALL(fstat), fd, &kbuf); kernel_stat_to_stat(&kbuf, (struct stat *)buf); return res; +# elif SANITIZER_LINUX && SANITIZER_SPARC64 + // For sparc64, fstat64 syscall fills buffer in the format of kernel_stat64 + kstat_t kbuf; + int res = internal_syscall(SYSCALL(fstat64), fd, &kbuf); + kernel_stat_to_stat(&kbuf, (struct stat *)buf); + return res; # elif SANITIZER_LINUX && defined(__loongarch__) struct statx bufx; int res = internal_syscall(SYSCALL(statx), fd, "", AT_EMPTY_PATH, @@ -826,10 +853,16 @@ uptr internal_sigaltstack(const void *ss, void *oss) { return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss); } +extern "C" pid_t __fork(void); + int internal_fork() { # if SANITIZER_LINUX # if SANITIZER_S390 return internal_syscall(SYSCALL(clone), 0, SIGCHLD); +# elif SANITIZER_SPARC + // The clone syscall interface on SPARC differs massively from the rest, + // so fall back to __fork. + return __fork(); # else return internal_syscall(SYSCALL(clone), SIGCHLD, 0); # endif @@ -2121,8 +2154,26 @@ bool SignalContext::IsTrueFaultingAddress() const { UNUSED static const char *RegNumToRegName(int reg) { switch (reg) { -# if SANITIZER_LINUX +# if SANITIZER_LINUX && SANITIZER_GLIBC || SANITIZER_NETBSD # if defined(__x86_64__) +# if SANITIZER_NETBSD +# define REG_RAX _REG_RAX +# define REG_RBX _REG_RBX +# define REG_RCX _REG_RCX +# define REG_RDX _REG_RDX +# define REG_RDI _REG_RDI +# define REG_RSI _REG_RSI +# define REG_RBP _REG_RBP +# define REG_RSP _REG_RSP +# define REG_R8 _REG_R8 +# define REG_R9 _REG_R9 +# define REG_R10 _REG_R10 +# define REG_R11 _REG_R11 +# define REG_R12 _REG_R12 +# define REG_R13 _REG_R13 +# define REG_R14 _REG_R14 +# define REG_R15 _REG_R15 +# endif case REG_RAX: return "rax"; case REG_RBX: @@ -2156,6 +2207,16 @@ static const char *RegNumToRegName(int reg) { case REG_R15: return "r15"; # elif defined(__i386__) +# if SANITIZER_NETBSD +# define REG_EAX _REG_EAX +# define REG_EBX _REG_EBX +# define REG_ECX _REG_ECX +# define REG_EDX _REG_EDX +# define REG_EDI _REG_EDI +# define REG_ESI _REG_ESI +# define REG_EBP _REG_EBP +# define REG_ESP _REG_ESP +# endif case REG_EAX: return "eax"; case REG_EBX: @@ -2240,14 +2301,15 @@ static const char *RegNumToRegName(int reg) { case 31: return "sp"; # endif -# endif // SANITIZER_LINUX +# endif // SANITIZER_LINUX && SANITIZER_GLIBC default: return NULL; } return NULL; } -# if SANITIZER_LINUX && (defined(__arm__) || defined(__aarch64__)) +# if SANITIZER_LINUX && SANITIZER_GLIBC && \ + (defined(__arm__) || defined(__aarch64__)) static uptr GetArmRegister(ucontext_t *ctx, int RegNum) { switch (RegNum) { # if defined(__arm__) @@ -2289,22 +2351,39 @@ static uptr GetArmRegister(ucontext_t *ctx, int RegNum) { } return 0; } -# endif // SANITIZER_LINUX && (defined(__arm__) || defined(__aarch64__)) +# endif // SANITIZER_LINUX && SANITIZER_GLIBC && (defined(__arm__) || + // defined(__aarch64__)) UNUSED static void DumpSingleReg(ucontext_t *ctx, int RegNum) { const char *RegName = RegNumToRegName(RegNum); +# if SANITIZER_LINUX && SANITIZER_GLIBC || SANITIZER_NETBSD # if defined(__x86_64__) Printf("%s%s = 0x%016llx ", internal_strlen(RegName) == 2 ? " " : "", - RegName, ctx->uc_mcontext.gregs[RegNum]); + RegName, +# if SANITIZER_LINUX + ctx->uc_mcontext.gregs[RegNum] +# elif SANITIZER_NETBSD + ctx->uc_mcontext.__gregs[RegNum] +# endif + ); # elif defined(__i386__) - Printf("%s = 0x%08x ", RegName, ctx->uc_mcontext.gregs[RegNum]); -# elif defined(__arm__) + Printf("%s = 0x%08x ", RegName, +# if SANITIZER_LINUX + ctx->uc_mcontext.gregs[RegNum] +# elif SANITIZER_NETBSD + ctx->uc_mcontext.__gregs[RegNum] +# endif + ); +# elif defined(__arm__) Printf("%s%s = 0x%08zx ", internal_strlen(RegName) == 2 ? " " : "", RegName, GetArmRegister(ctx, RegNum)); -# elif defined(__aarch64__) +# elif defined(__aarch64__) Printf("%s%s = 0x%016zx ", internal_strlen(RegName) == 2 ? " " : "", RegName, GetArmRegister(ctx, RegNum)); +# else + (void)RegName; +# endif # else (void)RegName; # endif @@ -2312,7 +2391,7 @@ static void DumpSingleReg(ucontext_t *ctx, int RegNum) { void SignalContext::DumpAllRegisters(void *context) { ucontext_t *ucontext = (ucontext_t *)context; -# if SANITIZER_LINUX +# if SANITIZER_LINUX && SANITIZER_GLIBC || SANITIZER_NETBSD # if defined(__x86_64__) Report("Register values:\n"); DumpSingleReg(ucontext, REG_RAX); @@ -2351,7 +2430,7 @@ void SignalContext::DumpAllRegisters(void *context) { DumpSingleReg(ucontext, REG_EBP); DumpSingleReg(ucontext, REG_ESP); Printf("\n"); -# elif defined(__arm__) +# elif defined(__arm__) && !SANITIZER_NETBSD Report("Register values:\n"); DumpSingleReg(ucontext, REG_R0); DumpSingleReg(ucontext, REG_R1); @@ -2373,7 +2452,7 @@ void SignalContext::DumpAllRegisters(void *context) { DumpSingleReg(ucontext, REG_R14); DumpSingleReg(ucontext, REG_R15); Printf("\n"); -# elif defined(__aarch64__) +# elif defined(__aarch64__) && !SANITIZER_NETBSD Report("Register values:\n"); for (int i = 0; i <= 31; ++i) { DumpSingleReg(ucontext, i); @@ -2386,25 +2465,25 @@ void SignalContext::DumpAllRegisters(void *context) { # elif SANITIZER_FREEBSD # if defined(__x86_64__) Report("Register values:\n"); - Printf("rax = 0x%016llx ", ucontext->uc_mcontext.mc_rax); - Printf("rbx = 0x%016llx ", ucontext->uc_mcontext.mc_rbx); - Printf("rcx = 0x%016llx ", ucontext->uc_mcontext.mc_rcx); - Printf("rdx = 0x%016llx ", ucontext->uc_mcontext.mc_rdx); + Printf("rax = 0x%016lx ", ucontext->uc_mcontext.mc_rax); + Printf("rbx = 0x%016lx ", ucontext->uc_mcontext.mc_rbx); + Printf("rcx = 0x%016lx ", ucontext->uc_mcontext.mc_rcx); + Printf("rdx = 0x%016lx ", ucontext->uc_mcontext.mc_rdx); Printf("\n"); - Printf("rdi = 0x%016llx ", ucontext->uc_mcontext.mc_rdi); - Printf("rsi = 0x%016llx ", ucontext->uc_mcontext.mc_rsi); - Printf("rbp = 0x%016llx ", ucontext->uc_mcontext.mc_rbp); - Printf("rsp = 0x%016llx ", ucontext->uc_mcontext.mc_rsp); + Printf("rdi = 0x%016lx ", ucontext->uc_mcontext.mc_rdi); + Printf("rsi = 0x%016lx ", ucontext->uc_mcontext.mc_rsi); + Printf("rbp = 0x%016lx ", ucontext->uc_mcontext.mc_rbp); + Printf("rsp = 0x%016lx ", ucontext->uc_mcontext.mc_rsp); Printf("\n"); - Printf(" r8 = 0x%016llx ", ucontext->uc_mcontext.mc_r8); - Printf(" r9 = 0x%016llx ", ucontext->uc_mcontext.mc_r9); - Printf("r10 = 0x%016llx ", ucontext->uc_mcontext.mc_r10); - Printf("r11 = 0x%016llx ", ucontext->uc_mcontext.mc_r11); + Printf(" r8 = 0x%016lx ", ucontext->uc_mcontext.mc_r8); + Printf(" r9 = 0x%016lx ", ucontext->uc_mcontext.mc_r9); + Printf("r10 = 0x%016lx ", ucontext->uc_mcontext.mc_r10); + Printf("r11 = 0x%016lx ", ucontext->uc_mcontext.mc_r11); Printf("\n"); - Printf("r12 = 0x%016llx ", ucontext->uc_mcontext.mc_r12); - Printf("r13 = 0x%016llx ", ucontext->uc_mcontext.mc_r13); - Printf("r14 = 0x%016llx ", ucontext->uc_mcontext.mc_r14); - Printf("r15 = 0x%016llx ", ucontext->uc_mcontext.mc_r15); + Printf("r12 = 0x%016lx ", ucontext->uc_mcontext.mc_r12); + Printf("r13 = 0x%016lx ", ucontext->uc_mcontext.mc_r13); + Printf("r14 = 0x%016lx ", ucontext->uc_mcontext.mc_r14); + Printf("r15 = 0x%016lx ", ucontext->uc_mcontext.mc_r15); Printf("\n"); # elif defined(__i386__) Report("Register values:\n"); @@ -2421,6 +2500,8 @@ void SignalContext::DumpAllRegisters(void *context) { # else (void)ucontext; # endif +# else + (void)ucontext; # endif // FIXME: Implement this for other OSes and architectures. } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h b/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h index 5200354694851eb..265a9925a15a037 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_ptrauth.h @@ -9,31 +9,33 @@ #ifndef SANITIZER_PTRAUTH_H #define SANITIZER_PTRAUTH_H -#if __has_feature(ptrauth_calls) -#include +#if __has_feature(ptrauth_intrinsics) +# include #elif defined(__ARM_FEATURE_PAC_DEFAULT) && !defined(__APPLE__) -inline unsigned long ptrauth_strip(void* __value, unsigned int __key) { - // On the stack the link register is protected with Pointer - // Authentication Code when compiled with -mbranch-protection. - // Let's stripping the PAC unconditionally because xpaclri is in - // the NOP space so will do nothing when it is not enabled or not available. - unsigned long ret; - asm volatile( - "mov x30, %1\n\t" - "hint #7\n\t" // xpaclri - "mov %0, x30\n\t" - : "=r"(ret) - : "r"(__value) - : "x30"); - return ret; -} -#define ptrauth_auth_data(__value, __old_key, __old_data) __value -#define ptrauth_string_discriminator(__string) ((int)0) +// On the stack the link register is protected with Pointer +// Authentication Code when compiled with -mbranch-protection. +// Let's stripping the PAC unconditionally because xpaclri is in +// the NOP space so will do nothing when it is not enabled or not available. +# define ptrauth_strip(__value, __key) \ + ({ \ + __typeof(__value) ret; \ + asm volatile( \ + "mov x30, %1\n\t" \ + "hint #7\n\t" \ + "mov %0, x30\n\t" \ + "mov x30, xzr\n\t" \ + : "=r"(ret) \ + : "r"(__value) \ + : "x30"); \ + ret; \ + }) +# define ptrauth_auth_data(__value, __old_key, __old_data) __value +# define ptrauth_string_discriminator(__string) ((int)0) #else // Copied from -#define ptrauth_strip(__value, __key) __value -#define ptrauth_auth_data(__value, __old_key, __old_data) __value -#define ptrauth_string_discriminator(__string) ((int)0) +# define ptrauth_strip(__value, __key) __value +# define ptrauth_auth_data(__value, __old_key, __old_data) __value +# define ptrauth_string_discriminator(__string) ((int)0) #endif #define STRIP_PAC_PC(pc) ((uptr)ptrauth_strip(pc, 0)) diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cpp index 1a1ccce82d259b8..601897a64f05142 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_test.cpp @@ -28,12 +28,13 @@ using namespace __sanitizer; -#if SANITIZER_SOLARIS && defined(__sparcv9) +#if defined(__sparcv9) // FIXME: These tests probably fail because Solaris/sparcv9 uses the full -// 64-bit address space. Needs more investigation -#define SKIP_ON_SOLARIS_SPARCV9(x) DISABLED_##x +// 64-bit address space. Same on Linux/sparc64, so probably a general SPARC +// issue. Needs more investigation +# define SKIP_ON_SPARCV9(x) DISABLED_##x #else -#define SKIP_ON_SOLARIS_SPARCV9(x) x +# define SKIP_ON_SPARCV9(x) x #endif // On 64-bit systems with small virtual address spaces (e.g. 39-bit) we can't @@ -781,7 +782,7 @@ TEST(SanitizerCommon, CombinedAllocator64VeryCompact) { } #endif -TEST(SanitizerCommon, SKIP_ON_SOLARIS_SPARCV9(CombinedAllocator32Compact)) { +TEST(SanitizerCommon, SKIP_ON_SPARCV9(CombinedAllocator32Compact)) { TestCombinedAllocator(); } @@ -1028,7 +1029,7 @@ TEST(SanitizerCommon, SizeClassAllocator64DynamicPremappedIteration) { #endif #endif -TEST(SanitizerCommon, SKIP_ON_SOLARIS_SPARCV9(SizeClassAllocator32Iteration)) { +TEST(SanitizerCommon, SKIP_ON_SPARCV9(SizeClassAllocator32Iteration)) { TestSizeClassAllocatorIteration(); } diff --git a/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cpp b/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cpp index 8da09f693c2b83e..8500d3aa91fec75 100644 --- a/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cpp +++ b/compiler-rt/lib/sanitizer_common/tests/sanitizer_ioctl_test.cpp @@ -77,7 +77,8 @@ TEST(SanitizerIoctl, Fixup) { // Test decoding KVM ioctl numbers. TEST(SanitizerIoctl, KVM_GET_MP_STATE) { ioctl_desc desc; - unsigned int desc_value = SANITIZER_MIPS ? 0x4004ae98U : 0x8004ae98U; + unsigned int desc_value = + SANITIZER_MIPS || SANITIZER_SPARC ? 0x4004ae98U : 0x8004ae98U; bool res = ioctl_decode(desc_value, &desc); EXPECT_TRUE(res); EXPECT_EQ(ioctl_desc::WRITE, desc.type); @@ -86,7 +87,8 @@ TEST(SanitizerIoctl, KVM_GET_MP_STATE) { TEST(SanitizerIoctl, KVM_GET_LAPIC) { ioctl_desc desc; - unsigned int desc_value = SANITIZER_MIPS ? 0x4400ae8eU : 0x8400ae8eU; + unsigned int desc_value = + SANITIZER_MIPS || SANITIZER_SPARC ? 0x4400ae8eU : 0x8400ae8eU; bool res = ioctl_decode(desc_value, &desc); EXPECT_TRUE(res); EXPECT_EQ(ioctl_desc::WRITE, desc.type); diff --git a/compiler-rt/test/builtins/TestCases/Darwin/platform_version_check_test.c b/compiler-rt/test/builtins/TestCases/Darwin/platform_version_check_test.c index da0e366430a73c8..ebbeba1cd0014fa 100644 --- a/compiler-rt/test/builtins/TestCases/Darwin/platform_version_check_test.c +++ b/compiler-rt/test/builtins/TestCases/Darwin/platform_version_check_test.c @@ -7,11 +7,22 @@ typedef unsigned int uint32_t; int32_t __isPlatformVersionAtLeast(uint32_t Platform, uint32_t Major, uint32_t Minor, uint32_t Subminor); +int32_t __isPlatformOrVariantPlatformVersionAtLeast( + uint32_t Platform, uint32_t Major, uint32_t Minor, uint32_t Subminor, + uint32_t Platform2, uint32_t Major2, uint32_t Minor2, uint32_t Subminor2); + +void exit(int status); + #define PLATFORM_MACOS 1 +#define PLATFORM_IOS 2 int32_t check(uint32_t Major, uint32_t Minor, uint32_t Subminor) { int32_t Result = __isPlatformVersionAtLeast(PLATFORM_MACOS, Major, Minor, Subminor); + int32_t ResultVariant = __isPlatformOrVariantPlatformVersionAtLeast( + PLATFORM_MACOS, Major, Minor, Subminor, PLATFORM_IOS, 13, 0, 0); + if (Result != ResultVariant) + exit(-1); return Result; } diff --git a/compiler-rt/test/builtins/Unit/ppc/test b/compiler-rt/test/builtins/Unit/ppc/test deleted file mode 100755 index 96e06320dbe2a86..000000000000000 --- a/compiler-rt/test/builtins/Unit/ppc/test +++ /dev/null @@ -1,18 +0,0 @@ -for FILE in $(ls *.c); do - if gcc -arch ppc -O0 $FILE ../../../Release/ppc/libcompiler_rt.Optimized.a -mlong-double-128 - then - echo "Testing $FILE" - if ./a.out - then - rm ./a.out - else - echo "fail" -# exit 1 - fi - else - echo "$FILE failed to compile" -# exit 1 - fi -done -echo "pass" -exit diff --git a/compiler-rt/test/builtins/Unit/test b/compiler-rt/test/builtins/Unit/test deleted file mode 100755 index e0683790c225cd0..000000000000000 --- a/compiler-rt/test/builtins/Unit/test +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env bash - -ARCHS='' -REMOTE=0 -if test `uname` = "Darwin"; then - if test "$1" = "armv6"; then - ARCHS="armv6" - LIBS="-lSystem" - REMOTE=1 - mkdir -p remote - else - ARCHS="i386 x86_64 ppc" - LIBS="-lSystem" - fi -else - LIBS="-lc -lm" -fi - -for ARCH in $ARCHS; do - CFLAGS="-Os -nodefaultlibs -I../../lib" - if test "$ARCH" != ''; then - CFLAGS="-arch $ARCH $CFLAGS" - fi - for FILE in $(ls *.c); do - # Use -nodefaultlibs to avoid using libgcc.a - # Use -lSystem to link with libSystem.dylb. - # Note -lSystem is *after* libcompiler_rt.Optimized.a so that linker will - # prefer our implementation over the ones in libSystem.dylib - EXTRA= - if test $FILE = gcc_personality_test.c - then - # the gcc_personality_test.c requires a helper C++ program - EXTRA="-fexceptions gcc_personality_test_helper.cxx -lstdc++ /usr/lib/libgcc_s.1.dylib" - # the libgcc_s.1.dylib use at the end is a hack until libSystem contains _Unwind_Resume - fi - if test "$REMOTE" = "1" - then - if gcc $CFLAGS $FILE ../../darwin_fat/Release/libcompiler_rt.a $LIBS $EXTRA -o ./remote/$FILE.exe - then - echo "Built $FILE.exe for $ARCH" - else - echo "$FILE failed to compile" - fi - else - if gcc $CFLAGS $FILE ../../darwin_fat/Release/libcompiler_rt.a $LIBS $EXTRA - then - echo "Testing $FILE for $ARCH" - if ./a.out - then - rm ./a.out - else - echo "fail" - exit 1 - fi - else - echo "$FILE failed to compile" - exit 1 - fi - fi - done -done -echo "pass" -exit diff --git a/compiler-rt/test/profile/ContinuousSyncMode/darwin-proof-of-concept.c b/compiler-rt/test/profile/ContinuousSyncMode/darwin-proof-of-concept.c index 85caca9a56b4028..3ed7c1894b6d106 100644 --- a/compiler-rt/test/profile/ContinuousSyncMode/darwin-proof-of-concept.c +++ b/compiler-rt/test/profile/ContinuousSyncMode/darwin-proof-of-concept.c @@ -8,8 +8,8 @@ // Align counters and data to the maximum expected page size (16K). // RUN: %clang -g -o %t %s \ -// RUN: -Wl,-sectalign,__DATA,__pcnts,0x4000 \ -// RUN: -Wl,-sectalign,__DATA,__pdata,0x4000 +// RUN: -Wl,-sectalign,__DATA,__pcnts,0x1000 \ +// RUN: -Wl,-sectalign,__DATA,__pdata,0x1000 // Create a 'profile' using mmap() and validate it. // RUN: %run %t create %t.tmpfile @@ -24,7 +24,7 @@ __attribute__((section("__DATA,__pcnts"))) int counters[] = {0xbad}; extern int cnts_start __asm("section$start$__DATA$__pcnts"); -const size_t cnts_len = 0x4000; +const size_t cnts_len = 0x1000; __attribute__((section("__DATA,__pdata"))) int data[] = {1, 2, 3}; extern int data_start __asm("section$start$__DATA$__pdata"); @@ -44,8 +44,8 @@ int create_tmpfile(char *path) { return EXIT_FAILURE; } - // Write the data first (at offset 0x4000, after the counters). - if (data_len != pwrite(fd, &data, data_len, 0x4000)) { + // Write the data first (at offset 0x1000, after the counters). + if (data_len != pwrite(fd, &data, data_len, cnts_len)) { perror("write"); return EXIT_FAILURE; } @@ -55,8 +55,8 @@ int create_tmpfile(char *path) { // Requirements (on Darwin): // - &cnts_start must be page-aligned. // - The length and offset-into-fd must be page-aligned. - int *counter_map = (int *)mmap(&cnts_start, 0x4000, PROT_READ | PROT_WRITE, - MAP_FIXED | MAP_SHARED, fd, 0); + int *counter_map = (int *)mmap(&cnts_start, cnts_len, PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_SHARED, fd, 0); if (counter_map != &cnts_start) { perror("mmap"); return EXIT_FAILURE; @@ -97,7 +97,7 @@ int validate_tmpfile(char *path) { } // Verify that the rest of the counters (after counter 9) are 0. - const int num_cnts = 0x4000 / sizeof(int); + const int num_cnts = cnts_len / sizeof(int); for (int i = 10; i < num_cnts; ++i) { if (buf[i] != 0) { fprintf(stderr, @@ -131,11 +131,12 @@ int main(int argc, char **argv) { fprintf(stderr, "__pcnts is not page-aligned: 0x%lx.\n", cnts_start_int); return EXIT_FAILURE; } - if (data_start_int % pagesz != 0) { - fprintf(stderr, "__pdata is not page-aligned: 0x%lx.\n", data_start_int); + if (data_start_int % 0x1000 != 0) { + fprintf(stderr, "__pdata is not correctly aligned: 0x%lx.\n", + data_start_int); return EXIT_FAILURE; } - if (cnts_start_int + 0x4000 != data_start_int) { + if (cnts_start_int + 0x1000 != data_start_int) { fprintf(stderr, "__pdata not ordered after __pcnts.\n"); return EXIT_FAILURE; } diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_aarch64.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_aarch64.cpp index e01b826c86b8ac0..d1015a4e369561d 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_aarch64.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_aarch64.cpp @@ -3,7 +3,7 @@ // RUN: %env_tool_opts=dump_registers=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NODUMP // RUN: not %run %t 2>&1 | FileCheck %s --strict-whitespace --check-prefix=CHECK-DUMP // -// REQUIRES: aarch64-target-arch +// REQUIRES: aarch64-target-arch && glibc #include diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_arm.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_arm.cpp index e17dbf196227b67..e747f78188d32a3 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_arm.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_arm.cpp @@ -3,7 +3,7 @@ // RUN: %env_tool_opts=dump_registers=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NODUMP // RUN: not %run %t 2>&1 | FileCheck %s --strict-whitespace --check-prefix=CHECK-DUMP // -// REQUIRES: arm-target-arch +// REQUIRES: arm-target-arch && glibc #include diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_i386.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_i386.cpp index 74aea4d8b360a38..5a62ef88ccd897d 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_i386.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_i386.cpp @@ -3,7 +3,7 @@ // RUN: %env_tool_opts=dump_registers=0 not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK-NODUMP --strict-whitespace // RUN: not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK-DUMP --strict-whitespace // -// REQUIRES: i386-target-arch +// REQUIRES: i386-target-arch && glibc #include diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_x86_64.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_x86_64.cpp index 3d11ef0e098f1d2..aac3c3fbd105217 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_x86_64.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/dump_registers_x86_64.cpp @@ -3,7 +3,7 @@ // RUN: %env_tool_opts=dump_registers=0 not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK-NODUMP --strict-whitespace // RUN: not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK-DUMP --strict-whitespace // -// REQUIRES: x86_64-target-arch +// REQUIRES: x86_64-target-arch && glibc #include diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/signal_line.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/signal_line.cpp index 208ece3e05af400..f1afd859c207a12 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/signal_line.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/signal_line.cpp @@ -20,7 +20,8 @@ int main(int argc, char **argv) { // CHECK1: SUMMARY: [[SAN]]: SEGV {{.*}}signal_line.cpp:[[@LINE-2]]:[[TAB]] in main if (n == 2) - *((volatile int *)0x1) = __LINE__; + // Allow for strict-alignment targets that require natural alignment. + *((volatile int *)0x8) = __LINE__; // CHECK2: #{{[0-9]+ .*}}main {{.*}}signal_line.cpp:[[@LINE-1]]:[[TAB:[0-9]+]] // CHECK2: SUMMARY: [[SAN]]: SEGV {{.*}}signal_line.cpp:[[@LINE-2]]:[[TAB]] in main } diff --git a/compiler-rt/test/sanitizer_common/TestCases/Linux/signal_send.cpp b/compiler-rt/test/sanitizer_common/TestCases/Linux/signal_send.cpp index 035a5a8df77ae58..638be63397dc613 100644 --- a/compiler-rt/test/sanitizer_common/TestCases/Linux/signal_send.cpp +++ b/compiler-rt/test/sanitizer_common/TestCases/Linux/signal_send.cpp @@ -62,14 +62,14 @@ void test_sigwait() { int res; res = fork_and_signal(s); fprintf(stderr, "fork_and_signal with SIGUSR1,2: %d\n", res); - // CHECK: died with sig 10 + // CHECK: died with sig {{10|30}} // CHECK: fork_and_signal with SIGUSR1,2: 0 // test sigandset... s should only have SIGUSR2 now s = sigset_and(s, mkset(1, SIGUSR2)); res = fork_and_signal(s); fprintf(stderr, "fork_and_signal with SIGUSR2: %d\n", res); - // CHECK: died with sig 12 + // CHECK: died with sig {{12|31}} // CHECK: fork_and_signal with SIGUSR2: 0 } diff --git a/compiler-rt/test/sanitizer_common/TestCases/NetBSD/dump_registers_i386.cpp b/compiler-rt/test/sanitizer_common/TestCases/NetBSD/dump_registers_i386.cpp new file mode 100644 index 000000000000000..74aea4d8b360a38 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/NetBSD/dump_registers_i386.cpp @@ -0,0 +1,17 @@ +// Check that sanitizer prints registers dump_registers on dump_registers=1 +// RUN: %clangxx %s -o %t +// RUN: %env_tool_opts=dump_registers=0 not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK-NODUMP --strict-whitespace +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK-DUMP --strict-whitespace +// +// REQUIRES: i386-target-arch + +#include + +int main() { + raise(SIGSEGV); + // CHECK-DUMP: Register values + // CHECK-DUMP-NEXT: eax = {{0x[0-9a-f]+}} ebx = {{0x[0-9a-f]+}} ecx = {{0x[0-9a-f]+}} edx = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT: edi = {{0x[0-9a-f]+}} esi = {{0x[0-9a-f]+}} ebp = {{0x[0-9a-f]+}} esp = {{0x[0-9a-f]+}} + // CHECK-NODUMP-NOT: Register values + return 0; +} diff --git a/compiler-rt/test/sanitizer_common/TestCases/NetBSD/dump_registers_x86_64.cpp b/compiler-rt/test/sanitizer_common/TestCases/NetBSD/dump_registers_x86_64.cpp new file mode 100644 index 000000000000000..3d11ef0e098f1d2 --- /dev/null +++ b/compiler-rt/test/sanitizer_common/TestCases/NetBSD/dump_registers_x86_64.cpp @@ -0,0 +1,19 @@ +// Check that sanitizer prints registers dump_registers on dump_registers=1 +// RUN: %clangxx %s -o %t +// RUN: %env_tool_opts=dump_registers=0 not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK-NODUMP --strict-whitespace +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefixes=CHECK-DUMP --strict-whitespace +// +// REQUIRES: x86_64-target-arch + +#include + +int main() { + raise(SIGSEGV); + // CHECK-DUMP: Register values + // CHECK-DUMP-NEXT: rax = {{0x[0-9a-f]+}} rbx = {{0x[0-9a-f]+}} rcx = {{0x[0-9a-f]+}} rdx = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT: rdi = {{0x[0-9a-f]+}} rsi = {{0x[0-9a-f]+}} rbp = {{0x[0-9a-f]+}} rsp = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT: r8 = {{0x[0-9a-f]+}} r9 = {{0x[0-9a-f]+}} r10 = {{0x[0-9a-f]+}} r11 = {{0x[0-9a-f]+}} + // CHECK-DUMP-NEXT: r12 = {{0x[0-9a-f]+}} r13 = {{0x[0-9a-f]+}} r14 = {{0x[0-9a-f]+}} r15 = {{0x[0-9a-f]+}} + // CHECK-NODUMP-NOT: Register values + return 0; +} diff --git a/flang/include/flang/Common/Fortran-features.h b/flang/include/flang/Common/Fortran-features.h index 7346d702b073d89..938da08e19d6b17 100644 --- a/flang/include/flang/Common/Fortran-features.h +++ b/flang/include/flang/Common/Fortran-features.h @@ -70,7 +70,7 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable, IgnoredIntrinsicFunctionType, PreviousScalarUse, RedeclaredInaccessibleComponent, ImplicitShared, IndexVarRedefinition, IncompatibleImplicitInterfaces, BadTypeForTarget, - VectorSubscriptFinalization) + VectorSubscriptFinalization, UndefinedFunctionResult) using LanguageFeatures = EnumSet; using UsageWarnings = EnumSet; @@ -144,6 +144,7 @@ class LanguageFeatureControl { warnUsage_.set(UsageWarning::IncompatibleImplicitInterfaces); warnUsage_.set(UsageWarning::BadTypeForTarget); warnUsage_.set(UsageWarning::VectorSubscriptFinalization); + warnUsage_.set(UsageWarning::UndefinedFunctionResult); } LanguageFeatureControl(const LanguageFeatureControl &) = default; diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h index 8555073a2d0d45a..8c6d3b37166a92a 100644 --- a/flang/include/flang/Evaluate/tools.h +++ b/flang/include/flang/Evaluate/tools.h @@ -1243,22 +1243,30 @@ bool CheckForCoindexedObject(parser::ContextualMessages &, const std::optional &, const std::string &procName, const std::string &argName); -// Get the number of distinct symbols with CUDA attribute in the expression. +inline bool IsCUDADeviceSymbol(const Symbol &sym) { + if (const auto *details = + sym.GetUltimate().detailsIf()) { + if (details->cudaDataAttr() && + *details->cudaDataAttr() != common::CUDADataAttr::Pinned) { + return true; + } + } + return false; +} + +// Get the number of distinct symbols with CUDA device +// attribute in the expression. template inline int GetNbOfCUDADeviceSymbols(const A &expr) { semantics::UnorderedSymbolSet symbols; for (const Symbol &sym : CollectCudaSymbols(expr)) { - if (const auto *details = - sym.GetUltimate().detailsIf()) { - if (details->cudaDataAttr() && - *details->cudaDataAttr() != common::CUDADataAttr::Pinned) { - symbols.insert(sym); - } + if (IsCUDADeviceSymbol(sym)) { + symbols.insert(sym); } } return symbols.size(); } -// Check if any of the symbols part of the expression has a CUDA data +// Check if any of the symbols part of the expression has a CUDA device // attribute. template inline bool HasCUDADeviceAttrs(const A &expr) { return GetNbOfCUDADeviceSymbols(expr) > 0; @@ -1270,26 +1278,15 @@ inline bool HasCUDAImplicitTransfer(const Expr &expr) { unsigned hostSymbols{0}; unsigned deviceSymbols{0}; for (const Symbol &sym : CollectCudaSymbols(expr)) { - if (const auto *details = - sym.GetUltimate().detailsIf()) { - if (details->cudaDataAttr() && - *details->cudaDataAttr() != common::CUDADataAttr::Pinned) { - ++deviceSymbols; - } else { - if (sym.owner().IsDerivedType()) { - if (const auto *details = - sym.owner() - .GetSymbol() - ->GetUltimate() - .detailsIf()) { - if (details->cudaDataAttr() && - *details->cudaDataAttr() != common::CUDADataAttr::Pinned) { - ++deviceSymbols; - } - } + if (IsCUDADeviceSymbol(sym)) { + ++deviceSymbols; + } else { + if (sym.owner().IsDerivedType()) { + if (IsCUDADeviceSymbol(sym.owner().GetSymbol()->GetUltimate())) { + ++deviceSymbols; } - ++hostSymbols; } + ++hostSymbols; } } return hostSymbols > 0 && deviceSymbols > 0; diff --git a/flang/include/flang/Lower/ConvertVariable.h b/flang/include/flang/Lower/ConvertVariable.h index 515f4695951b43c..de394a39e112ed4 100644 --- a/flang/include/flang/Lower/ConvertVariable.h +++ b/flang/include/flang/Lower/ConvertVariable.h @@ -62,6 +62,14 @@ using AggregateStoreMap = llvm::DenseMap; void instantiateVariable(AbstractConverter &, const pft::Variable &var, SymMap &symMap, AggregateStoreMap &storeMap); +/// Does this variable have a default initialization? +bool hasDefaultInitialization(const Fortran::semantics::Symbol &sym); + +/// Call default initialization runtime routine to initialize \p var. +void defaultInitializeAtRuntime(Fortran::lower::AbstractConverter &converter, + const Fortran::semantics::Symbol &sym, + Fortran::lower::SymMap &symMap); + /// Create a fir::GlobalOp given a module variable definition. This is intended /// to be used when lowering a module definition, not when lowering variables /// used from a module. For used variables instantiateVariable must directly be diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h index 80f077ad133f38a..78bb82b17d40501 100644 --- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h +++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h @@ -330,6 +330,8 @@ struct IntrinsicLibrary { mlir::Value genModulo(mlir::Type, llvm::ArrayRef); void genMoveAlloc(llvm::ArrayRef); void genMvbits(llvm::ArrayRef); + enum class NearestProc { Nearest, NextAfter, NextDown, NextUp }; + template mlir::Value genNearest(mlir::Type, llvm::ArrayRef); mlir::Value genNint(mlir::Type, llvm::ArrayRef); fir::ExtendedValue genNorm2(mlir::Type, llvm::ArrayRef); @@ -422,9 +424,12 @@ struct IntrinsicLibrary { mlir::Type resultType, llvm::ArrayRef args); - /// Generate code to raise \p except if \p cond is absent, + /// Generate code to raise \p excepts if \p cond is absent, /// or present and true. - void genRaiseExcept(int except, mlir::Value cond = {}); + void genRaiseExcept(int excepts, mlir::Value cond = {}); + + /// Generate a quiet NaN of a given floating point type. + mlir::Value genQNan(mlir::Type resultType); /// Define the different FIR generators that can be mapped to intrinsic to /// generate the related code. diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h b/flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h index 29745b8c231db39..aa6e33c7440adc3 100644 --- a/flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h +++ b/flang/include/flang/Optimizer/Builder/Runtime/Exceptions.h @@ -21,10 +21,10 @@ class FirOpBuilder; namespace fir::runtime { -/// Generate a runtime call to map an ieee_flag_type exception value to a -/// libm fenv.h value. -mlir::Value genMapException(fir::FirOpBuilder &builder, mlir::Location loc, - mlir::Value except); +/// Generate a runtime call to map a set of ieee_flag_type exceptions to a +/// libm fenv.h excepts value. +mlir::Value genMapExcept(fir::FirOpBuilder &builder, mlir::Location loc, + mlir::Value excepts); } // namespace fir::runtime #endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_EXCEPTIONS_H diff --git a/flang/include/flang/Optimizer/CodeGen/CGOps.td b/flang/include/flang/Optimizer/CodeGen/CGOps.td index c375edee1fa77f0..f4740a263ffd2b8 100644 --- a/flang/include/flang/Optimizer/CodeGen/CGOps.td +++ b/flang/include/flang/Optimizer/CodeGen/CGOps.td @@ -78,16 +78,24 @@ def fircg_XEmboxOp : fircg_Op<"ext_embox", [AttrSizedOperandSegments]> { unsigned getOutRank(); // The shape operands are mandatory and always start at 1. - unsigned shapeOffset() { return 1; } - unsigned shiftOffset() { return shapeOffset() + getShape().size(); } - unsigned sliceOffset() { return shiftOffset() + getShift().size(); } - unsigned subcomponentOffset() { return sliceOffset() + getSlice().size(); } - unsigned substrOffset() { - return subcomponentOffset() + getSubcomponent().size(); + unsigned getShapeOperandIndex() { return 1; } + unsigned getShiftOperandIndex() { + return getShapeOperandIndex() + getShape().size(); } - unsigned lenParamOffset() { return substrOffset() + getSubstr().size(); } - unsigned getSourceBoxOffset() { - return lenParamOffset() + getLenParams().size(); + unsigned getSliceOperandIndex() { + return getShiftOperandIndex() + getShift().size(); + } + unsigned getSubcomponentOperandIndex() { + return getSliceOperandIndex() + getSlice().size(); + } + unsigned getSubstrOperandIndex() { + return getSubcomponentOperandIndex() + getSubcomponent().size(); + } + unsigned getLenParamOperandIndex() { + return getSubstrOperandIndex() + getSubstr().size(); + } + unsigned getSourceBoxOperandIndex() { + return getLenParamOperandIndex() + getLenParams().size(); } }]; } @@ -135,12 +143,18 @@ def fircg_XReboxOp : fircg_Op<"ext_rebox", [AttrSizedOperandSegments]> { // The rank of the result box unsigned getOutRank(); - unsigned shapeOffset() { return 1; } - unsigned shiftOffset() { return shapeOffset() + getShape().size(); } - unsigned sliceOffset() { return shiftOffset() + getShift().size(); } - unsigned subcomponentOffset() { return sliceOffset() + getSlice().size(); } - unsigned substrOffset() { - return subcomponentOffset() + getSubcomponent().size(); + unsigned getShapeOperandIndex() { return 1; } + unsigned getShiftOperandIndex() { + return getShapeOperandIndex() + getShape().size(); + } + unsigned getSliceOperandIndex() { + return getShiftOperandIndex() + getShift().size(); + } + unsigned getSubcomponentOperandIndex() { + return getSliceOperandIndex() + getSlice().size(); + } + unsigned getSubstrOperandIndex() { + return getSubcomponentOperandIndex() + getSubcomponent().size(); } }]; } @@ -193,14 +207,22 @@ def fircg_XArrayCoorOp : fircg_Op<"ext_array_coor", [AttrSizedOperandSegments]> unsigned getRank(); // Shape is optional, but if it exists, it will be at offset 1. - unsigned shapeOffset() { return 1; } - unsigned shiftOffset() { return shapeOffset() + getShape().size(); } - unsigned sliceOffset() { return shiftOffset() + getShift().size(); } - unsigned subcomponentOffset() { return sliceOffset() + getSlice().size(); } - unsigned indicesOffset() { - return subcomponentOffset() + getSubcomponent().size(); - } - unsigned lenParamsOffset() { return indicesOffset() + getIndices().size(); } + unsigned getShapeOperandIndex() { return 1; } + unsigned getShiftOperandIndex() { + return getShapeOperandIndex() + getShape().size(); + } + unsigned getSliceOperandIndex() { + return getShiftOperandIndex() + getShift().size(); + } + unsigned getSubcomponentOperandIndex() { + return getSliceOperandIndex() + getSlice().size(); + } + unsigned getIndicesOperandIndex() { + return getSubcomponentOperandIndex() + getSubcomponent().size(); + } + unsigned getLenParamsOperandIndex() { + return getIndicesOperandIndex() + getIndices().size(); + } }]; } @@ -231,8 +253,10 @@ def fircg_XDeclareOp : fircg_Op<"ext_declare", [AttrSizedOperandSegments]> { let extraClassDeclaration = [{ // Shape is optional, but if it exists, it will be at offset 1. - unsigned shapeOffset() { return 1; } - unsigned shiftOffset() { return shapeOffset() + getShape().size(); } + unsigned getShapeOperandIndex() { return 1; } + unsigned getShiftOperandIndex() { + return getShapeOperandIndex() + getShape().size(); + } }]; } diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td index 89c13fa7cebe6ee..bee8e8f603ce308 100644 --- a/flang/include/flang/Optimizer/Dialect/FIROps.td +++ b/flang/include/flang/Optimizer/Dialect/FIROps.td @@ -817,7 +817,7 @@ def fir_EmboxOp : fir_Op<"embox", [NoMemoryEffect, AttrSizedOperandSegments]> { let extraClassDeclaration = [{ bool hasLenParams() { return !getTypeparams().empty(); } unsigned numLenParams() { return getTypeparams().size(); } - unsigned getSourceBoxOffset() { + unsigned getSourceBoxOperandIndex() { return 1 + (getShape() ? 1 : 0) + (getSlice() ? 1 : 0) + numLenParams(); } diff --git a/flang/include/flang/Runtime/exceptions.h b/flang/include/flang/Runtime/exceptions.h index 8f806ab9ad98ace..1ab22da103a50fc 100644 --- a/flang/include/flang/Runtime/exceptions.h +++ b/flang/include/flang/Runtime/exceptions.h @@ -12,7 +12,6 @@ #define FORTRAN_RUNTIME_EXCEPTIONS_H_ #include "flang/Runtime/entry-names.h" -#include "flang/Runtime/magic-numbers.h" #include namespace Fortran::runtime { @@ -21,11 +20,9 @@ class Descriptor; extern "C" { -// Map a (single) IEEE_FLAG_TYPE exception value to a libm fenv.h value. -// This could be extended to handle sets of exceptions, but there is no -// current use case for that. This mapping is done at runtime to support -// cross compilation. -std::int32_t RTNAME(MapException)(std::int32_t except); +// Map a set of IEEE_FLAG_TYPE exception values to a libm fenv.h excepts value. +// This mapping is done at runtime to support cross compilation. +std::uint32_t RTNAME(MapException)(std::uint32_t excepts); } // extern "C" } // namespace Fortran::runtime diff --git a/flang/include/flang/Runtime/magic-numbers.h b/flang/include/flang/Runtime/magic-numbers.h index 1cded1fd63238f3..bab0e9ae05299ad 100644 --- a/flang/include/flang/Runtime/magic-numbers.h +++ b/flang/include/flang/Runtime/magic-numbers.h @@ -100,6 +100,10 @@ The denorm value is a nonstandard extension. #define _FORTRAN_RUNTIME_IEEE_OVERFLOW 8 #define _FORTRAN_RUNTIME_IEEE_UNDERFLOW 16 #define _FORTRAN_RUNTIME_IEEE_INEXACT 32 +#define _FORTRAN_RUNTIME_IEEE_ALL \ + _FORTRAN_RUNTIME_IEEE_INVALID | _FORTRAN_RUNTIME_IEEE_DENORM | \ + _FORTRAN_RUNTIME_IEEE_DIVIDE_BY_ZERO | _FORTRAN_RUNTIME_IEEE_OVERFLOW | \ + _FORTRAN_RUNTIME_IEEE_UNDERFLOW | _FORTRAN_RUNTIME_IEEE_INEXACT #if 0 ieee_round_type values diff --git a/flang/include/flang/Semantics/semantics.h b/flang/include/flang/Semantics/semantics.h index 3ee71fe48552408..ec8d12b0f986535 100644 --- a/flang/include/flang/Semantics/semantics.h +++ b/flang/include/flang/Semantics/semantics.h @@ -254,6 +254,9 @@ class SemanticsContext { // behavior. CommonBlockList GetCommonBlocks() const; + void NoteDefinedSymbol(const Symbol &); + bool IsSymbolDefined(const Symbol &) const; + private: struct ScopeIndexComparator { bool operator()(parser::CharBlock, parser::CharBlock) const; @@ -303,6 +306,7 @@ class SemanticsContext { std::unique_ptr commonBlockMap_; ModuleDependences moduleDependences_; std::map moduleFileOutputRenamings_; + UnorderedSymbolSet isDefined_; }; class Semantics { diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h index cdbe3e39386bb5d..cf0350735b5b94c 100644 --- a/flang/include/flang/Semantics/symbol.h +++ b/flang/include/flang/Semantics/symbol.h @@ -460,15 +460,19 @@ class ProcEntityDetails : public EntityDetails, public WithPassArg { // and specialized for each distinct set of type parameter values. class DerivedTypeDetails { public: - const std::list ¶mNames() const { return paramNames_; } - const SymbolVector ¶mDecls() const { return paramDecls_; } + const SymbolVector ¶mNameOrder() const { return paramNameOrder_; } + const SymbolVector ¶mDeclOrder() const { return paramDeclOrder_; } bool sequence() const { return sequence_; } bool isDECStructure() const { return isDECStructure_; } std::map &finals() { return finals_; } const std::map &finals() const { return finals_; } bool isForwardReferenced() const { return isForwardReferenced_; } - void add_paramName(const SourceName &name) { paramNames_.push_back(name); } - void add_paramDecl(const Symbol &symbol) { paramDecls_.push_back(symbol); } + void add_paramNameOrder(const Symbol &symbol) { + paramNameOrder_.push_back(symbol); + } + void add_paramDeclOrder(const Symbol &symbol) { + paramDeclOrder_.push_back(symbol); + } void add_component(const Symbol &); void set_sequence(bool x = true) { sequence_ = x; } void set_isDECStructure(bool x = true) { isDECStructure_ = x; } @@ -491,12 +495,12 @@ class DerivedTypeDetails { const Symbol *GetFinalForRank(int) const; private: - // These are (1) the names of the derived type parameters in the order + // These are (1) the symbols of the derived type parameters in the order // in which they appear on the type definition statement(s), and (2) the // symbols that correspond to those names in the order in which their // declarations appear in the derived type definition(s). - std::list paramNames_; - SymbolVector paramDecls_; + SymbolVector paramNameOrder_; + SymbolVector paramDeclOrder_; // These are the names of the derived type's components in component // order. A parent component, if any, appears first in this list. std::list componentNames_; @@ -565,18 +569,19 @@ class MiscDetails { class TypeParamDetails { public: - explicit TypeParamDetails(common::TypeParamAttr attr) : attr_{attr} {} + TypeParamDetails() = default; TypeParamDetails(const TypeParamDetails &) = default; - common::TypeParamAttr attr() const { return attr_; } + std::optional attr() const { return attr_; } + TypeParamDetails &set_attr(common::TypeParamAttr); MaybeIntExpr &init() { return init_; } const MaybeIntExpr &init() const { return init_; } void set_init(MaybeIntExpr &&expr) { init_ = std::move(expr); } const DeclTypeSpec *type() const { return type_; } - void set_type(const DeclTypeSpec &); + TypeParamDetails &set_type(const DeclTypeSpec &); void ReplaceType(const DeclTypeSpec &); private: - common::TypeParamAttr attr_; + std::optional attr_; MaybeIntExpr init_; const DeclTypeSpec *type_{nullptr}; }; diff --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h index 0fcba3131fad125..0aee1ef299bc8b6 100644 --- a/flang/include/flang/Semantics/tools.h +++ b/flang/include/flang/Semantics/tools.h @@ -52,7 +52,6 @@ const Symbol *FindPointerComponent(const DeclTypeSpec &); const Symbol *FindPointerComponent(const Symbol &); const Symbol *FindInterface(const Symbol &); const Symbol *FindSubprogram(const Symbol &); -const Symbol *FindFunctionResult(const Symbol &); const Symbol *FindOverriddenBinding( const Symbol &, bool &isInaccessibleDeferred); const Symbol *FindGlobal(const Symbol &); @@ -261,7 +260,7 @@ std::optional GetImageControlStmtCoarrayMsg( SymbolVector OrderParameterDeclarations(const Symbol &); // Returns the complete list of derived type parameter names in the // order defined by 7.5.3.2. -std::list OrderParameterNames(const Symbol &); +SymbolVector OrderParameterNames(const Symbol &); // Return an existing or new derived type instance const DeclTypeSpec &FindOrInstantiateDerivedType(Scope &, DerivedTypeSpec &&, diff --git a/flang/lib/Evaluate/fold-character.cpp b/flang/lib/Evaluate/fold-character.cpp index 877bc2eac1fc279..5bdfa539eb0e025 100644 --- a/flang/lib/Evaluate/fold-character.cpp +++ b/flang/lib/Evaluate/fold-character.cpp @@ -97,7 +97,7 @@ Expr> FoldIntrinsicFunction( return Expr{Constant{CharacterUtils::NEW_LINE()}}; } else if (name == "repeat") { // not elemental if (auto scalars{GetScalarConstantArguments( - context, funcRef.arguments())}) { + context, funcRef.arguments(), /*hasOptionalArgument=*/false)}) { auto str{std::get>(*scalars)}; auto n{std::get>(*scalars).ToInt64()}; if (n < 0) { @@ -117,8 +117,8 @@ Expr> FoldIntrinsicFunction( } } } else if (name == "trim") { // not elemental - if (auto scalar{ - GetScalarConstantArguments(context, funcRef.arguments())}) { + if (auto scalar{GetScalarConstantArguments( + context, funcRef.arguments(), /*hasOptionalArgument=*/false)}) { return Expr{Constant{ CharacterUtils::TRIM(std::get>(*scalar))}}; } diff --git a/flang/lib/Evaluate/fold-implementation.h b/flang/lib/Evaluate/fold-implementation.h index d5c393140c57458..9ce0edbdcb77960 100644 --- a/flang/lib/Evaluate/fold-implementation.h +++ b/flang/lib/Evaluate/fold-implementation.h @@ -54,7 +54,8 @@ static constexpr bool useKahanSummation{false}; // Utilities template class Folder { public: - explicit Folder(FoldingContext &c) : context_{c} {} + explicit Folder(FoldingContext &c, bool forOptionalArgument = false) + : context_{c}, forOptionalArgument_{forOptionalArgument} {} std::optional> GetNamedConstant(const Symbol &); std::optional> ApplySubscripts(const Constant &array, const std::vector> &subscripts); @@ -81,6 +82,7 @@ template class Folder { private: FoldingContext &context_; + bool forOptionalArgument_{false}; }; std::optional> GetConstantSubscript( @@ -407,7 +409,14 @@ Constant *Folder::Folding(std::optional &arg) { if (auto *expr{UnwrapExpr>(arg)}) { if constexpr (T::category != TypeCategory::Derived) { if (!UnwrapExpr>(*expr)) { - if (auto converted{ConvertToType(T::GetType(), std::move(*expr))}) { + if (const Symbol * + var{forOptionalArgument_ + ? UnwrapWholeSymbolOrComponentDataRef(*expr) + : nullptr}; + var && (IsOptional(*var) || IsAllocatableOrObjectPointer(var))) { + // can't safely convert item that may not be present + } else if (auto converted{ + ConvertToType(T::GetType(), std::move(*expr))}) { *expr = Fold(context_, std::move(*converted)); } } @@ -420,10 +429,10 @@ Constant *Folder::Folding(std::optional &arg) { template std::optional *...>> GetConstantArgumentsHelper( FoldingContext &context, ActualArguments &arguments, - std::index_sequence) { + bool hasOptionalArgument, std::index_sequence) { static_assert(sizeof...(A) > 0); std::tuple *...> args{ - Folder{context}.Folding(arguments.at(I))...}; + Folder{context, hasOptionalArgument}.Folding(arguments.at(I))...}; if ((... && (std::get(args)))) { return args; } else { @@ -433,15 +442,17 @@ std::optional *...>> GetConstantArgumentsHelper( template std::optional *...>> GetConstantArguments( - FoldingContext &context, ActualArguments &args) { + FoldingContext &context, ActualArguments &args, bool hasOptionalArgument) { return GetConstantArgumentsHelper( - context, args, std::index_sequence_for{}); + context, args, hasOptionalArgument, std::index_sequence_for{}); } template std::optional...>> GetScalarConstantArgumentsHelper( - FoldingContext &context, ActualArguments &args, std::index_sequence) { - if (auto constArgs{GetConstantArguments(context, args)}) { + FoldingContext &context, ActualArguments &args, bool hasOptionalArgument, + std::index_sequence) { + if (auto constArgs{ + GetConstantArguments(context, args, hasOptionalArgument)}) { return std::tuple...>{ std::get(*constArgs)->GetScalarValue().value()...}; } else { @@ -451,9 +462,9 @@ std::optional...>> GetScalarConstantArgumentsHelper( template std::optional...>> GetScalarConstantArguments( - FoldingContext &context, ActualArguments &args) { + FoldingContext &context, ActualArguments &args, bool hasOptionalArgument) { return GetScalarConstantArgumentsHelper( - context, args, std::index_sequence_for{}); + context, args, hasOptionalArgument, std::index_sequence_for{}); } // helpers to fold intrinsic function references @@ -470,9 +481,10 @@ template