diff --git a/.ci/monolithic-linux.sh b/.ci/monolithic-linux.sh index 9e670c447fbaddc82106905b60927fc2c5c883db..b347c443da677fd530afb91936a9605ec1218b2b 100755 --- a/.ci/monolithic-linux.sh +++ b/.ci/monolithic-linux.sh @@ -18,7 +18,7 @@ set -o pipefail MONOREPO_ROOT="${MONOREPO_ROOT:="$(git rev-parse --show-toplevel)"}" BUILD_DIR="${BUILD_DIR:=${MONOREPO_ROOT}/build}" -rm -rf ${BUILD_DIR} +rm -rf "${BUILD_DIR}" ccache --zero-stats @@ -37,8 +37,8 @@ projects="${1}" targets="${2}" echo "--- cmake" -pip install -q -r ${MONOREPO_ROOT}/mlir/python/requirements.txt -cmake -S ${MONOREPO_ROOT}/llvm -B ${BUILD_DIR} \ +pip install -q -r "${MONOREPO_ROOT}"/mlir/python/requirements.txt +cmake -S "${MONOREPO_ROOT}"/llvm -B "${BUILD_DIR}" \ -D LLVM_ENABLE_PROJECTS="${projects}" \ -G Ninja \ -D CMAKE_BUILD_TYPE=Release \ diff --git a/.ci/monolithic-windows.sh b/.ci/monolithic-windows.sh index 52ba13036f915983e97ad1149ffc40ee51a4c24e..4fd88ea81c84a8e2c2e1201b5593e4305ed28b09 100755 --- a/.ci/monolithic-windows.sh +++ b/.ci/monolithic-windows.sh @@ -19,7 +19,7 @@ set -o pipefail MONOREPO_ROOT="${MONOREPO_ROOT:="$(git rev-parse --show-toplevel)"}" BUILD_DIR="${BUILD_DIR:=${MONOREPO_ROOT}/build}" -rm -rf ${BUILD_DIR} +rm -rf "${BUILD_DIR}" if [[ -n "${CLEAR_CACHE:-}" ]]; then echo "clearing sccache" @@ -37,14 +37,14 @@ projects="${1}" targets="${2}" echo "--- cmake" -pip install -q -r ${MONOREPO_ROOT}/mlir/python/requirements.txt +pip install -q -r "${MONOREPO_ROOT}"/mlir/python/requirements.txt # The CMAKE_*_LINKER_FLAGS to disable the manifest come from research # on fixing a build reliability issue on the build server, please # see https://github.com/llvm/llvm-project/pull/82393 and # https://discourse.llvm.org/t/rfc-future-of-windows-pre-commit-ci/76840/40 # for further information. -cmake -S ${MONOREPO_ROOT}/llvm -B ${BUILD_DIR} \ +cmake -S "${MONOREPO_ROOT}"/llvm -B "${BUILD_DIR}" \ -D LLVM_ENABLE_PROJECTS="${projects}" \ -G Ninja \ -D CMAKE_BUILD_TYPE=Release \ diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c246c42b0904d2fd84687e8362ef67ad0eb2400d..76b8266cae87c4b0b3fbf90e4bf72626aad7c9f3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -59,8 +59,8 @@ clang/test/AST/Interp/ @tbaederr /mlir/Dialect/*/Transforms/Bufferize.cpp @matthias-springer # Linalg Dialect in MLIR. -/mlir/include/mlir/Dialect/Linalg @dcaballe @nicolasvasilache -/mlir/lib/Dialect/Linalg @dcaballe @nicolasvasilache +/mlir/include/mlir/Dialect/Linalg/* @dcaballe @nicolasvasilache +/mlir/lib/Dialect/Linalg/* @dcaballe @nicolasvasilache /mlir/lib/Dialect/Linalg/Transforms/DecomposeLinalgOps.cpp @MaheshRavishankar @nicolasvasilache /mlir/lib/Dialect/Linalg/Transforms/DropUnitDims.cpp @MaheshRavishankar @nicolasvasilache /mlir/lib/Dialect/Linalg/Transforms/ElementwiseOpFusion.cpp @MaheshRavishankar @nicolasvasilache @@ -77,14 +77,14 @@ clang/test/AST/Interp/ @tbaederr /mlir/**/*SME* @banach-space @dcaballe @nicolasvasilache /mlir/**/*SVE* @banach-space @dcaballe @nicolasvasilache /mlir/**/*VectorInterfaces* @dcaballe @nicolasvasilache -/mlir/**/*VectorToSCF* @banach-space @dcaballe @nicolasvasilache @matthias-springer +/mlir/**/*VectorToSCF* @banach-space @dcaballe @matthias-springer @nicolasvasilache /mlir/**/*VectorToLLVM* @banach-space @dcaballe @nicolasvasilache /mlir/**/*X86Vector* @aartbik @dcaballe @nicolasvasilache -/mlir/include/mlir/Dialect/Vector @dcaballe @nicolasvasilache -/mlir/lib/Dialect/Vector @dcaballe @nicolasvasilache -/mlir/lib/Dialect/Vector/Transforms/VectorEmulateNarrowType.cpp @MaheshRavishankar @nicolasvasilache -/mlir/**/*EmulateNarrowType* @hanhanW +/mlir/include/mlir/Dialect/Vector/* @dcaballe @nicolasvasilache +/mlir/lib/Dialect/Vector/* @dcaballe @nicolasvasilache /mlir/lib/Dialect/Vector/Transforms/* @hanhanW @nicolasvasilache +/mlir/lib/Dialect/Vector/Transforms/VectorEmulateNarrowType.cpp @MaheshRavishankar @nicolasvasilache +/mlir/**/*EmulateNarrowType* @dcaballe @hanhanW # Presburger library in MLIR /mlir/**/*Presburger* @Groverkss @Superty @@ -96,6 +96,7 @@ clang/test/AST/Interp/ @tbaederr # Transform Dialect in MLIR. /mlir/include/mlir/Dialect/Transform/* @ftynse @nicolasvasilache /mlir/lib/Dialect/Transform/* @ftynse @nicolasvasilache +/mlir/**/*TransformOps* @ftynse @nicolasvasilache # SPIR-V Dialect in MLIR. /mlir/**/SPIRV/ @antiagainst @kuhar @@ -119,3 +120,11 @@ clang/test/AST/Interp/ @tbaederr # Bazel build system. /utils/bazel/ @rupprecht + +# InstallAPI and TextAPI +/llvm/**/TextAPI/ @cyndyishida +/clang/**/InstallAPI/ @cyndyishida +/clang/tools/clang-installapi/ @cyndyishida + +# ExtractAPI +/clang/**/ExtractAPI @daniel-grumberg diff --git a/.github/workflows/email-check.yaml b/.github/workflows/email-check.yaml index ac53b5e527b0949020e0e73d90def5d2b6295cd0..8f32d020975f5d70e7eead9c34a0ea86fb836e81 100644 --- a/.github/workflows/email-check.yaml +++ b/.github/workflows/email-check.yaml @@ -1,7 +1,7 @@ name: "Check for private emails used in PRs" on: - pull_request_target: + pull_request: types: - opened @@ -10,8 +10,6 @@ permissions: jobs: validate_email: - permissions: - pull-requests: write runs-on: ubuntu-latest if: github.repository == 'llvm/llvm-project' steps: @@ -25,20 +23,24 @@ jobs: run: | git log -1 echo "EMAIL=$(git show -s --format='%ae' HEAD~0)" >> $GITHUB_OUTPUT + # Create empty comment file + echo "[]" > comments - name: Validate author email if: ${{ endsWith(steps.author.outputs.EMAIL, 'noreply.github.com') }} - uses: actions/github-script@v6 env: - EMAIL: ${{ steps.author.outputs.EMAIL }} + COMMENT: >- + ⚠️ We detected that you are using a GitHub private e-mail address to contribute to the repo.
+ Please turn off [Keep my email addresses private](https://github.com/settings/emails) setting in your account.
+ See [LLVM Discourse](https://discourse.llvm.org/t/hidden-emails-on-github-should-we-do-something-about-it) for more information. + run: | + cat << EOF > comments + [{"body" : "$COMMENT"}] + EOF + + - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0 + if: always() with: - script: | - const { EMAIL } = process.env - await github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: `⚠️ We detected that you are using a GitHub private e-mail address to contribute to the repo. - Please turn off [Keep my email addresses private](https://github.com/settings/emails) setting in your account. - See [LLVM Discourse](https://discourse.llvm.org/t/hidden-emails-on-github-should-we-do-something-about-it) for more information. - `}) + name: workflow-args + path: | + comments diff --git a/.github/workflows/issue-write.yml b/.github/workflows/issue-write.yml new file mode 100644 index 0000000000000000000000000000000000000000..e003be006c4e15405bd977e277b0f9a64e69d2af --- /dev/null +++ b/.github/workflows/issue-write.yml @@ -0,0 +1,139 @@ +name: Comment on an issue + +on: + workflow_run: + workflows: + - "Check code formatting" + - "Check for private emails used in PRs" + types: + - completed + +permissions: + contents: read + +jobs: + pr-comment: + runs-on: ubuntu-latest + permissions: + pull-requests: write + if: > + github.event.workflow_run.event == 'pull_request' + steps: + - name: 'Download artifact' + uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 + with: + github-token: ${{ secrets.ISSUE_WRITE_DOWNLOAD_ARTIFACT }} + run-id: ${{ github.event.workflow_run.id }} + name: workflow-args + + - name: 'Comment on PR' + uses: actions/github-script@v3 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + var fs = require('fs'); + const comments = JSON.parse(fs.readFileSync('./comments')); + if (!comments || comments.length == 0) { + return; + } + + let runInfo = await github.actions.getWorkflowRun({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: context.payload.workflow_run.id + }); + + console.log(runInfo); + + + // Query to find the number of the pull request that triggered this job. + // The associated pull requests are based off of the branch name, so if + // you create a pull request for a branch, close it, and then create + // another pull request with the same branch, then this query will return + // two associated pull requests. This is why we have to fetch all the + // associated pull requests and then iterate through them to find the + // one that is open. + const gql_query = ` + query($repo_owner : String!, $repo_name : String!, $branch: String!) { + repository(owner: $repo_owner, name: $repo_name) { + ref (qualifiedName: $branch) { + associatedPullRequests(first: 100) { + nodes { + baseRepository { + owner { + login + } + } + number + state + } + } + } + } + } + ` + const gql_variables = { + repo_owner: runInfo.data.head_repository.owner.login, + repo_name: runInfo.data.head_repository.name, + branch: runInfo.data.head_branch + } + const gql_result = await github.graphql(gql_query, gql_variables); + console.log(gql_result); + // If the branch for the PR was deleted before this job has a chance + // to run, then the ref will be null. This can happen if someone: + // 1. Rebase the PR, which triggers some workflow. + // 2. Immediately merges the PR and deletes the branch. + // 3. The workflow finishes and triggers this job. + if (!gql_result.repository.ref) { + console.log("Ref has been deleted"); + return; + } + console.log(gql_result.repository.ref.associatedPullRequests.nodes); + + var pr_number = 0; + gql_result.repository.ref.associatedPullRequests.nodes.forEach((pr) => { + if (pr.baseRepository.owner.login = context.repo.owner && pr.state == 'OPEN') { + pr_number = pr.number; + } + }); + if (pr_number == 0) { + console.log("Error retrieving pull request number"); + return; + } + + await comments.forEach(function (comment) { + if (comment.id) { + // Security check: Ensure that this comment was created by + // the github-actions bot, so a malicious input won't overwrite + // a user's comment. + github.issues.getComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: comment.id + }).then((old_comment) => { + console.log(old_comment); + if (old_comment.data.user.login != "github-actions[bot]") { + console.log("Invalid comment id: " + comment.id); + return; + } + github.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr_number, + comment_id: comment.id, + body: comment.body + }); + }); + } else { + github.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr_number, + body: comment.body + }); + } + }); + + - name: Dump comments file + if: always() + run: cat comments diff --git a/.github/workflows/libcxx-build-and-test.yaml b/.github/workflows/libcxx-build-and-test.yaml index 4a881ef5ff56af432500413950890ee8d6563dbc..1e9367732e591118445fef2c69acf3339c2cbf5d 100644 --- a/.github/workflows/libcxx-build-and-test.yaml +++ b/.github/workflows/libcxx-build-and-test.yaml @@ -38,11 +38,11 @@ env: # LLVM POST-BRANCH bump version # LLVM POST-BRANCH add compiler test for ToT - 1, e.g. "Clang 17" # LLVM RELEASE bump remove compiler ToT - 3, e.g. "Clang 15" - LLVM_HEAD_VERSION: "18" # Used compiler, update POST-BRANCH. - LLVM_PREVIOUS_VERSION: "17" - LLVM_OLDEST_VERSION: "16" + LLVM_HEAD_VERSION: "19" # Used compiler, update POST-BRANCH. + LLVM_PREVIOUS_VERSION: "18" + LLVM_OLDEST_VERSION: "17" GCC_STABLE_VERSION: "13" - LLVM_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer-18" + LLVM_SYMBOLIZER_PATH: "/usr/bin/llvm-symbolizer-19" CLANG_CRASH_DIAGNOSTICS_DIR: "crash_diagnostics" @@ -59,8 +59,8 @@ jobs: 'generic-cxx26', 'generic-modules' ] - cc: [ 'clang-18' ] - cxx: [ 'clang++-18' ] + cc: [ 'clang-19' ] + cxx: [ 'clang++-19' ] clang_tidy: [ 'ON' ] include: - config: 'generic-gcc' @@ -100,22 +100,22 @@ jobs: 'generic-cxx20', 'generic-cxx23' ] - cc: [ 'clang-18' ] - cxx: [ 'clang++-18' ] + cc: [ 'clang-19' ] + cxx: [ 'clang++-19' ] clang_tidy: [ 'ON' ] include: - config: 'generic-gcc-cxx11' cc: 'gcc-13' cxx: 'g++-13' clang_tidy: 'OFF' - - config: 'generic-cxx23' - cc: 'clang-16' - cxx: 'clang++-16' - clang_tidy: 'OFF' - config: 'generic-cxx23' cc: 'clang-17' cxx: 'clang++-17' clang_tidy: 'OFF' + - config: 'generic-cxx26' + cc: 'clang-18' + cxx: 'clang++-18' + clang_tidy: 'ON' steps: - uses: actions/checkout@v4 - name: ${{ matrix.config }} @@ -186,8 +186,8 @@ jobs: - name: ${{ matrix.config }} run: libcxx/utils/ci/run-buildbot ${{ matrix.config }} env: - CC: clang-18 - CXX: clang++-18 + CC: clang-19 + CXX: clang++-19 ENABLE_CLANG_TIDY: "OFF" - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0 if: always() diff --git a/.github/workflows/pr-code-format.yml b/.github/workflows/pr-code-format.yml index 1d1fa2483b658f762b5d4a3a65ec4c99842d65ba..983838858ba43ed90cca953b6b00668d6746f5df 100644 --- a/.github/workflows/pr-code-format.yml +++ b/.github/workflows/pr-code-format.yml @@ -1,12 +1,13 @@ name: "Check code formatting" + +permissions: + contents: read + on: - pull_request_target: + pull_request: branches: - main -permissions: - pull-requests: write - jobs: code_formatter: runs-on: ubuntu-latest @@ -31,12 +32,13 @@ jobs: separator: "," skip_initial_fetch: true - # We need to make sure that we aren't executing/using any code from the - # PR for security reasons as we're using pull_request_target. Checkout - # the target branch with the necessary files. + # We need to pull the script from the main branch, so that we ensure + # we get the latest version of this script. - name: Fetch code formatting utils uses: actions/checkout@v4 with: + repository: ${{ github.repository }} + ref: ${{ github.base_ref }} sparse-checkout: | llvm/utils/git/requirements_formatting.txt llvm/utils/git/code-format-helper.py @@ -75,10 +77,20 @@ jobs: # to take advantage of the new --diff_from_common_commit option # explicitly in code-format-helper.py and not have to diff starting at # the merge base. + # Create an empty comments file so the pr-write job doesn't fail. run: | + echo "[]" > comments && python ./code-format-tools/llvm/utils/git/code-format-helper.py \ + --write-comment-to-file \ --token ${{ secrets.GITHUB_TOKEN }} \ --issue-number $GITHUB_PR_NUMBER \ --start-rev $(git merge-base $START_REV $END_REV) \ --end-rev $END_REV \ --changed-files "$CHANGED_FILES" + + - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 #v4.3.0 + if: always() + with: + name: workflow-args + path: | + comments diff --git a/.github/workflows/release-lit.yml b/.github/workflows/release-lit.yml index 36b0b6edd518fc74fecf397c8947ff706066a52e..0316ba406041d6fc63c812da994ea662276bee6e 100644 --- a/.github/workflows/release-lit.yml +++ b/.github/workflows/release-lit.yml @@ -58,7 +58,7 @@ jobs: cd llvm/utils/lit # Remove 'dev' suffix from lit version. sed -i 's/ + "dev"//g' lit/__init__.py - python3 setup.py sdist + python3 setup.py sdist bdist_wheel - name: Upload lit to test.pypi.org uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index b8e8ab26c3ffa61a1f3a76883034564086d1d237..ff61cf83a6af3c816e7fa4b0a55fa26f3d1471e4 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -36,7 +36,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@e38b1902ae4f44df626f11ba0734b14fb91f8f86 # v2.1.2 + uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 with: results_file: results.sarif results_format: sarif diff --git a/bolt/docs/BAT.md b/bolt/docs/BAT.md index 186b0e5ea89d38bcabe617e0c68d2b0c010b5c36..f23ef1abf8761cc58fc2249ef0da43ae0034e114 100644 --- a/bolt/docs/BAT.md +++ b/bolt/docs/BAT.md @@ -42,21 +42,21 @@ and [BoltAddressTranslation.cpp](/bolt/lib/Profile/BoltAddressTranslation.cpp). ### Layout The general layout is as follows: ``` -Hot functions table header -|------------------| -| Function entry | -| |--------------| | -| | OutOff InOff | | -| |--------------| | -~~~~~~~~~~~~~~~~~~~~ +Hot functions table +Cold functions table -Cold functions table header +Functions table: |------------------| | Function entry | -| |--------------| | -| | OutOff InOff | | -| |--------------| | -~~~~~~~~~~~~~~~~~~~~ +| | +| Address | +| translation | +| table | +| | +| Secondary entry | +| points | +|------------------| + ``` ### Functions table @@ -74,30 +74,43 @@ internal offsets, and between hot and cold fragments, to better spread deltas and save space. Hot indices are delta encoded, implicitly starting at zero. -| Entry | Encoding | Description | -| ------ | ------| ----------- | -| `Address` | Continuous, Delta, ULEB128 | Function address in the output binary | -| `HotIndex` | Delta, ULEB128 | Cold functions only: index of corresponding hot function in hot functions table | -| `FuncHash` | 8b | Hot functions only: function hash for input function | -| `NumEntries` | ULEB128 | Number of address translation entries for a function | -| `EqualElems` | ULEB128 | Hot functions only: number of equal offsets in the beginning of a function | -| `BranchEntries` | Bitmask, `alignTo(EqualElems, 8)` bits | Hot functions only: if `EqualElems` is non-zero, bitmask denoting entries with `BRANCHENTRY` bit | - -Function header is followed by `EqualElems` offsets (hot functions only) and -`NumEntries-EqualElems` (`NumEntries` for cold functions) pairs of offsets for -current function. +| Entry | Encoding | Description | Hot/Cold | +| ------ | ------| ----------- | ------ | +| `Address` | Continuous, Delta, ULEB128 | Function address in the output binary | Both | +| `HotIndex` | Delta, ULEB128 | Index of corresponding hot function in hot functions table | Cold | +| `FuncHash` | 8b | Function hash for input function | Hot | +| `NumBlocks` | ULEB128 | Number of basic blocks in the original function | Hot | +| `NumSecEntryPoints` | ULEB128 | Number of secondary entry points in the original function | Hot | +| `NumEntries` | ULEB128 | Number of address translation entries for a function | Both | +| `EqualElems` | ULEB128 | Number of equal offsets in the beginning of a function | Hot | +| `BranchEntries` | Bitmask, `alignTo(EqualElems, 8)` bits | If `EqualElems` is non-zero, bitmask denoting entries with `BRANCHENTRY` bit | Hot | + +Function header is followed by *Address Translation Table* with `NumEntries` +total entries, and *Secondary Entry Points* table with `NumSecEntryPoints` +entries (hot functions only). ### Address translation table Delta encoding means that only the difference with the previous corresponding entry is encoded. Input offsets implicitly start at zero. -| Entry | Encoding | Description | -| ------ | ------| ----------- | -| `OutputOffset` | Continuous, Delta, ULEB128 | Function offset in output binary | -| `InputOffset` | Optional, Delta, SLEB128 | Function offset in input binary with `BRANCHENTRY` LSB bit | -| `BBHash` | Optional, 8b | Basic block entries only: basic block hash in input binary | +| Entry | Encoding | Description | Branch/BB | +| ------ | ------| ----------- | ------ | +| `OutputOffset` | Continuous, Delta, ULEB128 | Function offset in output binary | Both | +| `InputOffset` | Optional, Delta, SLEB128 | Function offset in input binary with `BRANCHENTRY` LSB bit | Both | +| `BBHash` | Optional, 8b | Basic block hash in input binary | BB | +| `BBIdx` | Optional, Delta, ULEB128 | Basic block index in input binary | BB | + +For hot fragments, the table omits the first `EqualElems` input offsets +where the input offset equals output offset. `BRANCHENTRY` bit denotes whether a given offset pair is a control flow source (branch or call instruction). If not set, it signifies a control flow target (basic block offset). `InputAddr` is omitted for equal offsets in input and output function. In this case, `BRANCHENTRY` bits are encoded separately in a `BranchEntries` bitvector. + +### Secondary Entry Points table +The table is emitted for hot fragments only. It contains `NumSecEntryPoints` +offsets denoting secondary entry points, delta encoded, implicitly starting at zero. +| Entry | Encoding | Description | +| ----- | -------- | ----------- | +| `SecEntryPoint` | Delta, ULEB128 | Secondary entry point offset | diff --git a/bolt/include/bolt/Core/AddressMap.h b/bolt/include/bolt/Core/AddressMap.h index 85a9ab4473aafedd192145acaa334208e22ac6e6..31ed7d40ee7f215586e53a6b285f492c898ab765 100644 --- a/bolt/include/bolt/Core/AddressMap.h +++ b/bolt/include/bolt/Core/AddressMap.h @@ -14,7 +14,6 @@ #ifndef BOLT_CORE_ADDRESS_MAP_H #define BOLT_CORE_ADDRESS_MAP_H -#include "llvm/ADT/StringRef.h" #include "llvm/MC/MCSymbol.h" #include diff --git a/bolt/include/bolt/Core/BinaryContext.h b/bolt/include/bolt/Core/BinaryContext.h index 741b1a36af86f871bb51430686ff229ce2e1d1b8..8b1af9e8153925760985efcb954e87a046b2c1f2 100644 --- a/bolt/include/bolt/Core/BinaryContext.h +++ b/bolt/include/bolt/Core/BinaryContext.h @@ -265,7 +265,8 @@ class BinaryContext { public: static Expected> - createBinaryContext(const ObjectFile *File, bool IsPIC, + createBinaryContext(Triple TheTriple, StringRef InputFileName, + SubtargetFeatures *Features, bool IsPIC, std::unique_ptr DwCtx, JournalingStreams Logger); diff --git a/bolt/include/bolt/Core/BinaryData.h b/bolt/include/bolt/Core/BinaryData.h index 5f1efda781905db66ec18e16a3263a88c5f0816f..495163f1b61aafd2360b9699fcda4f95844f1dd3 100644 --- a/bolt/include/bolt/Core/BinaryData.h +++ b/bolt/include/bolt/Core/BinaryData.h @@ -18,7 +18,6 @@ #include "llvm/ADT/Twine.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/raw_ostream.h" -#include #include #include diff --git a/bolt/include/bolt/Core/BinaryDomTree.h b/bolt/include/bolt/Core/BinaryDomTree.h index a9565795f94631b25c6674eb699b78e9f9d5bffd..de27aa78769d23398eaf97177ad316abf3e09798 100644 --- a/bolt/include/bolt/Core/BinaryDomTree.h +++ b/bolt/include/bolt/Core/BinaryDomTree.h @@ -16,7 +16,6 @@ #include "bolt/Core/BinaryBasicBlock.h" #include "llvm/IR/Dominators.h" -#include "llvm/Support/GenericDomTreeConstruction.h" namespace llvm { namespace bolt { diff --git a/bolt/include/bolt/Core/BinaryFunction.h b/bolt/include/bolt/Core/BinaryFunction.h index c170fa6397cc927293f539391ea5a29b7389a7be..26d2d01f86267127f4c4bea9daa5862b4b412738 100644 --- a/bolt/include/bolt/Core/BinaryFunction.h +++ b/bolt/include/bolt/Core/BinaryFunction.h @@ -27,6 +27,7 @@ #include "bolt/Core/BinaryBasicBlock.h" #include "bolt/Core/BinaryContext.h" +#include "bolt/Core/BinaryDomTree.h" #include "bolt/Core/BinaryLoop.h" #include "bolt/Core/BinarySection.h" #include "bolt/Core/DebugData.h" @@ -51,7 +52,6 @@ #include #include #include -#include #include #include @@ -266,6 +266,7 @@ private: BinaryContext &BC; std::unique_ptr BLI; + std::unique_ptr BDT; /// All labels in the function that are referenced via relocations from /// data objects. Typically these are jump table destinations and computed @@ -838,6 +839,14 @@ public: /// stats. void calculateMacroOpFusionStats(); + /// Returns if BinaryDominatorTree has been constructed for this function. + bool hasDomTree() const { return BDT != nullptr; } + + BinaryDominatorTree &getDomTree() { return *BDT.get(); } + + /// Constructs DomTree for this function. + void constructDomTree(); + /// Returns if loop detection has been run for this function. bool hasLoopInfo() const { return BLI != nullptr; } @@ -1159,7 +1168,7 @@ public: /// Pass an offset of the entry point in the input binary and a corresponding /// global symbol to the callback function. /// - /// Return true of all callbacks returned true, false otherwise. + /// Return true if all callbacks returned true, false otherwise. bool forEachEntryPoint(EntryPointCallbackTy Callback) const; /// Return MC symbol associated with the end of the function. @@ -1393,7 +1402,8 @@ public: /// Return true if the function has CFI instructions bool hasCFI() const { - return !FrameInstructions.empty() || !CIEFrameInstructions.empty(); + return !FrameInstructions.empty() || !CIEFrameInstructions.empty() || + IsInjected; } /// Return unique number associated with the function. diff --git a/bolt/include/bolt/Core/BinaryLoop.h b/bolt/include/bolt/Core/BinaryLoop.h index 72dce77df8c14b970023a59b82180f6bc2bb1633..b425c75715d8b1d02e66655d8ff7e4d9115fffdd 100644 --- a/bolt/include/bolt/Core/BinaryLoop.h +++ b/bolt/include/bolt/Core/BinaryLoop.h @@ -15,7 +15,7 @@ #ifndef BOLT_CORE_BINARY_LOOP_H #define BOLT_CORE_BINARY_LOOP_H -#include "llvm/Support/GenericLoopInfoImpl.h" +#include "llvm/Support/GenericLoopInfo.h" namespace llvm { namespace bolt { diff --git a/bolt/include/bolt/Core/BinarySection.h b/bolt/include/bolt/Core/BinarySection.h index 0f179877bd3df3b4bf7e736d1fc00e4806c9f7d2..5b7a5b08820e6e5190559ce2ad59992c7a998e2a 100644 --- a/bolt/include/bolt/Core/BinarySection.h +++ b/bolt/include/bolt/Core/BinarySection.h @@ -18,7 +18,6 @@ #include "bolt/Core/DebugData.h" #include "bolt/Core/Relocation.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachO.h" diff --git a/bolt/include/bolt/Core/DebugData.h b/bolt/include/bolt/Core/DebugData.h index 7d10b208dc83a22c9eee5d0f5acd538258401e42..166bb3617e57f68448eb662348e2e414ed885b32 100644 --- a/bolt/include/bolt/Core/DebugData.h +++ b/bolt/include/bolt/Core/DebugData.h @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff --git a/bolt/include/bolt/Core/DebugNames.h b/bolt/include/bolt/Core/DebugNames.h index 1f17f1ae4d139badf57defc981f0557d78c35593..a4fdde7c396ad886e3d8c96bb92d25a657a4a0e1 100644 --- a/bolt/include/bolt/Core/DebugNames.h +++ b/bolt/include/bolt/Core/DebugNames.h @@ -14,7 +14,7 @@ #ifndef BOLT_CORE_DEBUG_NAMES_H #define BOLT_CORE_DEBUG_NAMES_H -#include "DebugData.h" +#include "bolt/Core/DebugData.h" #include "llvm/CodeGen/AccelTable.h" namespace llvm { @@ -68,6 +68,16 @@ public: std::unique_ptr releaseBuffer() { return std::move(FullTableBuffer); } + /// Adds a DIE that is referenced across CUs. + void addCrossCUDie(const DIE *Die) { + CrossCUDies.insert({Die->getOffset(), Die}); + } + /// Returns true if the DIE can generate an entry for a cross cu reference. + /// This only checks TAGs of a DIE because when this is invoked DIE might not + /// be fully constructed. + bool canGenerateEntryWithCrossCUReference( + const DWARFUnit &Unit, const DIE &Die, + const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec); private: BinaryContext &BC; @@ -128,6 +138,7 @@ private: llvm::DenseMap CUOffsetsToPatch; // Contains a map of Entry ID to Entry relative offset. llvm::DenseMap EntryRelativeOffsets; + llvm::DenseMap CrossCUDies; /// Adds Unit to either CUList, LocalTUList or ForeignTUList. /// Input Unit being processed, and DWO ID if Unit is being processed comes /// from a DWO section. diff --git a/bolt/include/bolt/Core/FunctionLayout.h b/bolt/include/bolt/Core/FunctionLayout.h index 2e4c184ba4511ca6836ca9d031014c1f784385f0..b685a99c79c14cccd0e7661ed8a48991c9a53b98 100644 --- a/bolt/include/bolt/Core/FunctionLayout.h +++ b/bolt/include/bolt/Core/FunctionLayout.h @@ -25,7 +25,6 @@ #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include -#include namespace llvm { namespace bolt { diff --git a/bolt/include/bolt/Core/MCPlus.h b/bolt/include/bolt/Core/MCPlus.h index 1d2360c180335f9f2b1d243153dc1c6f5f92b6fd..601d709712864ebefce1a4156378b023f564be96 100644 --- a/bolt/include/bolt/Core/MCPlus.h +++ b/bolt/include/bolt/Core/MCPlus.h @@ -14,10 +14,8 @@ #ifndef BOLT_CORE_MCPLUS_H #define BOLT_CORE_MCPLUS_H -#include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" -#include "llvm/Support/Casting.h" #include namespace llvm { diff --git a/bolt/include/bolt/Core/MCPlusBuilder.h b/bolt/include/bolt/Core/MCPlusBuilder.h index 198a8d8bf48f8222cf4863d7d6d928f5ff160c6e..f7614cf9ac9777be6812e228190cc20c810b4c3d 100644 --- a/bolt/include/bolt/Core/MCPlusBuilder.h +++ b/bolt/include/bolt/Core/MCPlusBuilder.h @@ -19,6 +19,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/StringMap.h" +#include "llvm/CodeGen/TargetOpcodes.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCDisassembler/MCSymbolizer.h" #include "llvm/MC/MCExpr.h" @@ -27,6 +28,7 @@ #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/RWMutex.h" @@ -533,9 +535,7 @@ public: return Analysis->isReturn(Inst); } - virtual bool isTerminator(const MCInst &Inst) const { - return Analysis->isTerminator(Inst); - } + virtual bool isTerminator(const MCInst &Inst) const; virtual bool isNoop(const MCInst &Inst) const { llvm_unreachable("not implemented"); diff --git a/bolt/include/bolt/Passes/BinaryPasses.h b/bolt/include/bolt/Passes/BinaryPasses.h index 046765b16f19d21b8562440f51c1b0c3c666995e..8d89ef8b5484f8e18d7ea034c3d38df57746760a 100644 --- a/bolt/include/bolt/Passes/BinaryPasses.h +++ b/bolt/include/bolt/Passes/BinaryPasses.h @@ -18,7 +18,6 @@ #include "bolt/Core/DynoStats.h" #include "llvm/Support/CommandLine.h" #include -#include #include #include #include diff --git a/bolt/include/bolt/Passes/CacheMetrics.h b/bolt/include/bolt/Passes/CacheMetrics.h index 5c88d98c76c1d5aa20b386a5398e3ee010867243..ea56d330446b9932bd021ee71be5fc0ad7107829 100644 --- a/bolt/include/bolt/Passes/CacheMetrics.h +++ b/bolt/include/bolt/Passes/CacheMetrics.h @@ -13,7 +13,6 @@ #ifndef BOLT_PASSES_CACHEMETRICS_H #define BOLT_PASSES_CACHEMETRICS_H -#include #include namespace llvm { diff --git a/bolt/include/bolt/Passes/DominatorAnalysis.h b/bolt/include/bolt/Passes/DominatorAnalysis.h index c2b5c3af01472213ef56b994b04866c2a2b7ec1e..3f3afa943c06cefe853113de6e9b29703742f7f7 100644 --- a/bolt/include/bolt/Passes/DominatorAnalysis.h +++ b/bolt/include/bolt/Passes/DominatorAnalysis.h @@ -11,7 +11,6 @@ #include "bolt/Passes/DataflowAnalysis.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Timer.h" namespace opts { extern llvm::cl::opt TimeOpts; diff --git a/bolt/include/bolt/Passes/ReachingDefOrUse.h b/bolt/include/bolt/Passes/ReachingDefOrUse.h index f38d1a373e18b8de4618bdb2d95362b05d4bea00..585d673e3b84e58431ff074a01b2283315abb7a4 100644 --- a/bolt/include/bolt/Passes/ReachingDefOrUse.h +++ b/bolt/include/bolt/Passes/ReachingDefOrUse.h @@ -11,9 +11,7 @@ #include "bolt/Passes/DataflowAnalysis.h" #include "bolt/Passes/RegAnalysis.h" -#include "llvm/MC/MCRegisterInfo.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Timer.h" #include namespace opts { diff --git a/bolt/include/bolt/Passes/ReachingInsns.h b/bolt/include/bolt/Passes/ReachingInsns.h index 65782b12064b85848d59b1d7e7d2a06cf03cdba4..ef878f5e452db30f6b4f8e3d5617e4fc285dcf19 100644 --- a/bolt/include/bolt/Passes/ReachingInsns.h +++ b/bolt/include/bolt/Passes/ReachingInsns.h @@ -11,7 +11,6 @@ #include "bolt/Passes/DataflowAnalysis.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Support/Timer.h" namespace opts { extern llvm::cl::opt TimeOpts; diff --git a/bolt/include/bolt/Passes/ReorderUtils.h b/bolt/include/bolt/Passes/ReorderUtils.h index bc82b4f436fa7553f9ae7762ad2098147080250e..8ceb8ba62690a55b87fe0933633c7ebe0239b318 100644 --- a/bolt/include/bolt/Passes/ReorderUtils.h +++ b/bolt/include/bolt/Passes/ReorderUtils.h @@ -14,7 +14,6 @@ #ifndef BOLT_PASSES_REORDER_UTILS_H #define BOLT_PASSES_REORDER_UTILS_H -#include #include #include "llvm/ADT/BitVector.h" diff --git a/bolt/include/bolt/Profile/BoltAddressTranslation.h b/bolt/include/bolt/Profile/BoltAddressTranslation.h index 1f53f6d344ad7402a6145b335f85dfe0a0a61f75..eef05e8a0e681406cd1a48784ece7edf5f85ff4a 100644 --- a/bolt/include/bolt/Profile/BoltAddressTranslation.h +++ b/bolt/include/bolt/Profile/BoltAddressTranslation.h @@ -19,6 +19,7 @@ #include namespace llvm { +class MCSymbol; class raw_ostream; namespace object { @@ -115,23 +116,23 @@ public: /// Save function and basic block hashes used for metadata dump. void saveMetadata(BinaryContext &BC); - /// Returns BB hash by function output address (after BOLT) and basic block - /// input offset. - size_t getBBHash(uint64_t FuncOutputAddress, uint32_t BBInputOffset) const; - - /// Returns BF hash by function output address (after BOLT). - size_t getBFHash(uint64_t OutputAddress) const; - /// True if a given \p Address is a function with translation table entry. bool isBATFunction(uint64_t Address) const { return Maps.count(Address); } + /// For a given \p Symbol in the output binary and known \p InputOffset + /// return a corresponding pair of parent BinaryFunction and secondary entry + /// point in it. + std::pair + translateSymbol(const BinaryContext &BC, const MCSymbol &Symbol, + uint32_t InputOffset) const; + private: /// Helper to update \p Map by inserting one or more BAT entries reflecting /// \p BB for function located at \p FuncAddress. At least one entry will be /// emitted for the start of the BB. More entries may be emitted to cover /// the location of calls or any instruction that may change control flow. void writeEntriesForBB(MapTy &Map, const BinaryBasicBlock &BB, - uint64_t FuncAddress); + uint64_t FuncInputAddress, uint64_t FuncOutputAddress); /// Write the serialized address translation table for a function. template @@ -154,8 +155,15 @@ private: std::map Maps; - using BBHashMap = std::unordered_map; - std::unordered_map> FuncHashes; + /// Map a function to its basic blocks count + std::unordered_map NumBasicBlocksMap; + + /// Map a function to its secondary entry points vector + std::unordered_map> SecondaryEntryPointsMap; + + /// Return a secondary entry point ID for a function located at \p Address and + /// \p Offset within that function. + unsigned getSecondaryEntryPointId(uint64_t Address, uint32_t Offset) const; /// Links outlined cold bocks to their original function std::map ColdPartSource; @@ -166,6 +174,115 @@ private: /// Identifies the address of a control-flow changing instructions in a /// translation map entry const static uint32_t BRANCHENTRY = 0x1; + +public: + /// Map basic block input offset to a basic block index and hash pair. + class BBHashMapTy { + class EntryTy { + unsigned Index; + size_t Hash; + + public: + unsigned getBBIndex() const { return Index; } + size_t getBBHash() const { return Hash; } + EntryTy(unsigned Index, size_t Hash) : Index(Index), Hash(Hash) {} + }; + + std::map Map; + const EntryTy &getEntry(uint32_t BBInputOffset) const { + auto It = Map.find(BBInputOffset); + assert(It != Map.end()); + return It->second; + } + + public: + bool isInputBlock(uint32_t InputOffset) const { + return Map.count(InputOffset); + } + + unsigned getBBIndex(uint32_t BBInputOffset) const { + return getEntry(BBInputOffset).getBBIndex(); + } + + size_t getBBHash(uint32_t BBInputOffset) const { + return getEntry(BBInputOffset).getBBHash(); + } + + void addEntry(uint32_t BBInputOffset, unsigned BBIndex, size_t BBHash) { + Map.emplace(BBInputOffset, EntryTy(BBIndex, BBHash)); + } + + size_t getNumBasicBlocks() const { return Map.size(); } + + auto begin() const { return Map.begin(); } + auto end() const { return Map.end(); } + auto upper_bound(uint32_t Offset) const { return Map.upper_bound(Offset); } + }; + + /// Map function output address to its hash and basic blocks hash map. + class FuncHashesTy { + class EntryTy { + size_t Hash; + BBHashMapTy BBHashMap; + + public: + size_t getBFHash() const { return Hash; } + const BBHashMapTy &getBBHashMap() const { return BBHashMap; } + EntryTy(size_t Hash) : Hash(Hash) {} + }; + + std::unordered_map Map; + const EntryTy &getEntry(uint64_t FuncOutputAddress) const { + auto It = Map.find(FuncOutputAddress); + assert(It != Map.end()); + return It->second; + } + + public: + size_t getBFHash(uint64_t FuncOutputAddress) const { + return getEntry(FuncOutputAddress).getBFHash(); + } + + const BBHashMapTy &getBBHashMap(uint64_t FuncOutputAddress) const { + return getEntry(FuncOutputAddress).getBBHashMap(); + } + + void addEntry(uint64_t FuncOutputAddress, size_t BFHash) { + Map.emplace(FuncOutputAddress, EntryTy(BFHash)); + } + + size_t getNumFunctions() const { return Map.size(); }; + + size_t getNumBasicBlocks() const { + size_t NumBasicBlocks{0}; + for (auto &I : Map) + NumBasicBlocks += I.second.getBBHashMap().getNumBasicBlocks(); + return NumBasicBlocks; + } + }; + + /// Returns BF hash by function output address (after BOLT). + size_t getBFHash(uint64_t FuncOutputAddress) const { + return FuncHashes.getBFHash(FuncOutputAddress); + } + + /// Returns BBHashMap by function output address (after BOLT). + const BBHashMapTy &getBBHashMap(uint64_t FuncOutputAddress) const { + return FuncHashes.getBBHashMap(FuncOutputAddress); + } + + BBHashMapTy &getBBHashMap(uint64_t FuncOutputAddress) { + return const_cast( + std::as_const(*this).getBBHashMap(FuncOutputAddress)); + } + + /// Returns the number of basic blocks in a function. + size_t getNumBasicBlocks(uint64_t OutputAddress) const { + return NumBasicBlocksMap.at(OutputAddress); + } + +private: + FuncHashesTy FuncHashes; }; } // namespace bolt diff --git a/bolt/include/bolt/Profile/DataAggregator.h b/bolt/include/bolt/Profile/DataAggregator.h index f7840b49199f90ab0bf33b4f9478d34490affb90..84f76caae9dbb01ea38e59f5eb629e0492ddb800 100644 --- a/bolt/include/bolt/Profile/DataAggregator.h +++ b/bolt/include/bolt/Profile/DataAggregator.h @@ -225,6 +225,10 @@ private: /// Aggregation statistics uint64_t NumInvalidTraces{0}; uint64_t NumLongRangeTraces{0}; + /// Specifies how many samples were recorded in cold areas if we are dealing + /// with profiling data collected in a bolted binary. For LBRs, incremented + /// for the source of the branch to avoid counting cold activity twice (one + /// for source and another for destination). uint64_t NumColdSamples{0}; /// Looks into system PATH for Linux Perf and set up the aggregator to use it @@ -245,14 +249,12 @@ private: /// disassembled BinaryFunctions BinaryFunction *getBinaryFunctionContainingAddress(uint64_t Address) const; + /// Perform BAT translation for a given \p Func and return the parent + /// BinaryFunction or nullptr. + BinaryFunction *getBATParentFunction(const BinaryFunction &Func) const; + /// Retrieve the location name to be used for samples recorded in \p Func. - /// If doing BAT translation, link cold parts to the hot part names (used by - /// the original binary). \p Count specifies how many samples were recorded - /// at that location, so we can tally total activity in cold areas if we are - /// dealing with profiling data collected in a bolted binary. For LBRs, - /// \p Count should only be used for the source of the branch to avoid - /// counting cold activity twice (one for source and another for destination). - StringRef getLocationName(BinaryFunction &Func, uint64_t Count); + StringRef getLocationName(const BinaryFunction &Func) const; /// Semantic actions - parser hooks to interpret parsed perf samples /// Register a sample (non-LBR mode), i.e. a new hit at \p Address diff --git a/bolt/include/bolt/Profile/ProfileReaderBase.h b/bolt/include/bolt/Profile/ProfileReaderBase.h index 511718f3c0ec7431310d5c722e90bbb061c9057f..3e5cf2612893907677014e01dbe08922fe8cae24 100644 --- a/bolt/include/bolt/Profile/ProfileReaderBase.h +++ b/bolt/include/bolt/Profile/ProfileReaderBase.h @@ -65,7 +65,7 @@ public: /// Return true if the function \p BF may have a profile available. /// The result is based on the name(s) of the function alone and the profile /// match is not guaranteed. - virtual bool mayHaveProfileData(const BinaryFunction &BF); + virtual bool mayHaveProfileData(const BinaryFunction &BF) { return true; } /// Return true if the profile contains an entry for a local object /// that has an associated file name. diff --git a/bolt/include/bolt/Profile/ProfileYAMLMapping.h b/bolt/include/bolt/Profile/ProfileYAMLMapping.h index 548b528ae2d6534d96cbcea298f9b283c79385f6..9dd3920dbf0943fbb1f6aac2721b170a01d34900 100644 --- a/bolt/include/bolt/Profile/ProfileYAMLMapping.h +++ b/bolt/include/bolt/Profile/ProfileYAMLMapping.h @@ -14,7 +14,6 @@ #define BOLT_PROFILE_PROFILEYAMLMAPPING_H #include "bolt/Core/BinaryFunction.h" -#include "llvm/ADT/StringRef.h" #include "llvm/Support/YAMLTraits.h" #include diff --git a/bolt/include/bolt/Profile/YAMLProfileWriter.h b/bolt/include/bolt/Profile/YAMLProfileWriter.h index 882748627e7f54aec2a5d0b85d738ce93cf292ee..4a9355dfceac9ec174729553d7b80006a8429d80 100644 --- a/bolt/include/bolt/Profile/YAMLProfileWriter.h +++ b/bolt/include/bolt/Profile/YAMLProfileWriter.h @@ -15,6 +15,7 @@ namespace llvm { namespace bolt { +class BoltAddressTranslation; class RewriteInstance; class YAMLProfileWriter { @@ -31,8 +32,16 @@ public: /// Save execution profile for that instance. std::error_code writeProfile(const RewriteInstance &RI); - static yaml::bolt::BinaryFunctionProfile convert(const BinaryFunction &BF, - bool UseDFS); + static yaml::bolt::BinaryFunctionProfile + convert(const BinaryFunction &BF, bool UseDFS, + const BoltAddressTranslation *BAT = nullptr); + + /// Set CallSiteInfo destination fields from \p Symbol and return a target + /// BinaryFunction for that symbol. + static const BinaryFunction * + setCSIDestination(const BinaryContext &BC, yaml::bolt::CallSiteInfo &CSI, + const MCSymbol *Symbol, const BoltAddressTranslation *BAT, + uint32_t Offset = 0); }; } // namespace bolt diff --git a/bolt/include/bolt/Rewrite/DWARFRewriter.h b/bolt/include/bolt/Rewrite/DWARFRewriter.h index 20972f3d0b85ae2ac553d1a8ddf85746a6bfaf24..2c482bd2b9ea965ff1bc289ead744bfe3f19737d 100644 --- a/bolt/include/bolt/Rewrite/DWARFRewriter.h +++ b/bolt/include/bolt/Rewrite/DWARFRewriter.h @@ -22,9 +22,7 @@ #include #include #include -#include #include -#include #include namespace llvm { diff --git a/bolt/include/bolt/Rewrite/MetadataManager.h b/bolt/include/bolt/Rewrite/MetadataManager.h index efbc74b4daba9de588581719534d0a4e02f787f7..2ff70dbaab3de74d6af6ec14cf89cc84d29c69b4 100644 --- a/bolt/include/bolt/Rewrite/MetadataManager.h +++ b/bolt/include/bolt/Rewrite/MetadataManager.h @@ -11,7 +11,6 @@ #include "bolt/Rewrite/MetadataRewriter.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Support/Error.h" namespace llvm { namespace bolt { diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h index 97ab65cd5a4a1ffd26df3e575b8ce2853437405d..826677cd63b22b1a0abef55837f4c254a7b7ee84 100644 --- a/bolt/include/bolt/Rewrite/RewriteInstance.h +++ b/bolt/include/bolt/Rewrite/RewriteInstance.h @@ -17,7 +17,6 @@ #include "bolt/Core/Linker.h" #include "bolt/Rewrite/MetadataManager.h" #include "bolt/Utils/NameResolver.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ObjectFile.h" diff --git a/bolt/include/bolt/RuntimeLibs/RuntimeLibrary.h b/bolt/include/bolt/RuntimeLibs/RuntimeLibrary.h index c845cb7f7b214d825929d7019ba1c3e7652e612a..e392029156bcea81c2fbfda93f8584a6109dd480 100644 --- a/bolt/include/bolt/RuntimeLibs/RuntimeLibrary.h +++ b/bolt/include/bolt/RuntimeLibs/RuntimeLibrary.h @@ -17,7 +17,6 @@ #include "bolt/Core/Linker.h" #include "llvm/ADT/StringRef.h" -#include #include namespace llvm { diff --git a/bolt/include/bolt/Utils/NameShortener.h b/bolt/include/bolt/Utils/NameShortener.h index 9c7b7ec9ba655c452e9dffa7d17e1177d1628228..fd61235f93c86bcfedd7df514658e588fd142d36 100644 --- a/bolt/include/bolt/Utils/NameShortener.h +++ b/bolt/include/bolt/Utils/NameShortener.h @@ -14,7 +14,6 @@ #define BOLT_UTILS_NAME_SHORTENER_H #include "llvm/ADT/StringMap.h" -#include "llvm/ADT/Twine.h" namespace llvm { namespace bolt { diff --git a/bolt/lib/Core/BinaryContext.cpp b/bolt/lib/Core/BinaryContext.cpp index 267f43f65e206e65d6f65d9579f66ae2772d61a2..47eae964e816c5565697bdc2ef974bdfecdff4dc 100644 --- a/bolt/lib/Core/BinaryContext.cpp +++ b/bolt/lib/Core/BinaryContext.cpp @@ -14,7 +14,6 @@ #include "bolt/Core/BinaryEmitter.h" #include "bolt/Core/BinaryFunction.h" #include "bolt/Utils/CommandLineOpts.h" -#include "bolt/Utils/NameResolver.h" #include "bolt/Utils/Utils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" @@ -39,7 +38,6 @@ #include #include #include -#include #include using namespace llvm; @@ -162,28 +160,30 @@ BinaryContext::~BinaryContext() { /// Create BinaryContext for a given architecture \p ArchName and /// triple \p TripleName. -Expected> -BinaryContext::createBinaryContext(const ObjectFile *File, bool IsPIC, - std::unique_ptr DwCtx, - JournalingStreams Logger) { +Expected> BinaryContext::createBinaryContext( + Triple TheTriple, StringRef InputFileName, SubtargetFeatures *Features, + bool IsPIC, std::unique_ptr DwCtx, JournalingStreams Logger) { StringRef ArchName = ""; std::string FeaturesStr = ""; - switch (File->getArch()) { + switch (TheTriple.getArch()) { case llvm::Triple::x86_64: + if (Features) + return createFatalBOLTError( + "x86_64 target does not use SubtargetFeatures"); ArchName = "x86-64"; FeaturesStr = "+nopl"; break; case llvm::Triple::aarch64: + if (Features) + return createFatalBOLTError( + "AArch64 target does not use SubtargetFeatures"); ArchName = "aarch64"; FeaturesStr = "+all"; break; case llvm::Triple::riscv64: { ArchName = "riscv64"; - Expected Features = File->getFeatures(); - - if (auto E = Features.takeError()) - return std::move(E); - + if (!Features) + return createFatalBOLTError("RISCV target needs SubtargetFeatures"); // We rely on relaxation for some transformations (e.g., promoting all calls // to PseudoCALL and then making JITLink relax them). Since the relax // feature is not stored in the object file, we manually enable it. @@ -196,12 +196,11 @@ BinaryContext::createBinaryContext(const ObjectFile *File, bool IsPIC, "BOLT-ERROR: Unrecognized machine in ELF file"); } - auto TheTriple = std::make_unique(File->makeTriple()); - const std::string TripleName = TheTriple->str(); + const std::string TripleName = TheTriple.str(); std::string Error; const Target *TheTarget = - TargetRegistry::lookupTarget(std::string(ArchName), *TheTriple, Error); + TargetRegistry::lookupTarget(std::string(ArchName), TheTriple, Error); if (!TheTarget) return createStringError(make_error_code(std::errc::not_supported), Twine("BOLT-ERROR: ", Error)); @@ -240,13 +239,13 @@ BinaryContext::createBinaryContext(const ObjectFile *File, bool IsPIC, Twine("BOLT-ERROR: no instruction info for target ", TripleName)); std::unique_ptr Ctx( - new MCContext(*TheTriple, AsmInfo.get(), MRI.get(), STI.get())); + new MCContext(TheTriple, AsmInfo.get(), MRI.get(), STI.get())); std::unique_ptr MOFI( TheTarget->createMCObjectFileInfo(*Ctx, IsPIC)); Ctx->setObjectFileInfo(MOFI.get()); // We do not support X86 Large code model. Change this in the future. bool Large = false; - if (TheTriple->getArch() == llvm::Triple::aarch64) + if (TheTriple.getArch() == llvm::Triple::aarch64) Large = true; unsigned LSDAEncoding = Large ? dwarf::DW_EH_PE_absptr : dwarf::DW_EH_PE_udata4; @@ -273,7 +272,7 @@ BinaryContext::createBinaryContext(const ObjectFile *File, bool IsPIC, int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); std::unique_ptr InstructionPrinter( - TheTarget->createMCInstPrinter(*TheTriple, AsmPrinterVariant, *AsmInfo, + TheTarget->createMCInstPrinter(TheTriple, AsmPrinterVariant, *AsmInfo, *MII, *MRI)); if (!InstructionPrinter) return createStringError( @@ -285,8 +284,8 @@ BinaryContext::createBinaryContext(const ObjectFile *File, bool IsPIC, TheTarget->createMCCodeEmitter(*MII, *Ctx)); auto BC = std::make_unique( - std::move(Ctx), std::move(DwCtx), std::move(TheTriple), TheTarget, - std::string(TripleName), std::move(MCE), std::move(MOFI), + std::move(Ctx), std::move(DwCtx), std::make_unique(TheTriple), + TheTarget, std::string(TripleName), std::move(MCE), std::move(MOFI), std::move(AsmInfo), std::move(MII), std::move(STI), std::move(InstructionPrinter), std::move(MIA), nullptr, std::move(MRI), std::move(DisAsm), Logger); @@ -296,7 +295,7 @@ BinaryContext::createBinaryContext(const ObjectFile *File, bool IsPIC, BC->MAB = std::unique_ptr( BC->TheTarget->createMCAsmBackend(*BC->STI, *BC->MRI, MCTargetOptions())); - BC->setFilename(File->getFileName()); + BC->setFilename(InputFileName); BC->HasFixedLoadAddress = !IsPIC; diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index fdadef9dcd384828db57559b8be5dc76b9d9b29d..1fa96dfaabde819eeb3ff70e5340cc46af5ed49a 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -12,7 +12,6 @@ #include "bolt/Core/BinaryFunction.h" #include "bolt/Core/BinaryBasicBlock.h" -#include "bolt/Core/BinaryDomTree.h" #include "bolt/Core/DynoStats.h" #include "bolt/Core/HashUtilities.h" #include "bolt/Core/MCPlusBuilder.h" @@ -35,6 +34,8 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/GenericDomTreeConstruction.h" +#include "llvm/Support/GenericLoopInfoImpl.h" #include "llvm/Support/GraphWriter.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/Regex.h" @@ -3547,7 +3548,7 @@ MCSymbol *BinaryFunction::getSymbolForEntryID(uint64_t EntryID) { if (!isMultiEntry()) return nullptr; - uint64_t NumEntries = 0; + uint64_t NumEntries = 1; if (hasCFG()) { for (BinaryBasicBlock *BB : BasicBlocks) { MCSymbol *EntrySymbol = getSecondaryEntryPointSymbol(*BB); @@ -3580,7 +3581,7 @@ uint64_t BinaryFunction::getEntryIDForSymbol(const MCSymbol *Symbol) const { return 0; // Check all secondary entries available as either basic blocks or lables. - uint64_t NumEntries = 0; + uint64_t NumEntries = 1; for (const BinaryBasicBlock *BB : BasicBlocks) { MCSymbol *EntrySymbol = getSecondaryEntryPointSymbol(*BB); if (!EntrySymbol) @@ -3589,7 +3590,7 @@ uint64_t BinaryFunction::getEntryIDForSymbol(const MCSymbol *Symbol) const { return NumEntries; ++NumEntries; } - NumEntries = 0; + NumEntries = 1; for (const std::pair &KV : Labels) { MCSymbol *EntrySymbol = getSecondaryEntryPointSymbol(KV.second); if (!EntrySymbol) @@ -4076,12 +4077,17 @@ BinaryFunction::~BinaryFunction() { delete BB; } +void BinaryFunction::constructDomTree() { + BDT.reset(new BinaryDominatorTree); + BDT->recalculate(*this); +} + void BinaryFunction::calculateLoopInfo() { + if (!hasDomTree()) + constructDomTree(); // Discover loops. - BinaryDominatorTree DomTree; - DomTree.recalculate(*this); BLI.reset(new BinaryLoopInfo()); - BLI->analyze(DomTree); + BLI->analyze(getDomTree()); // Traverse discovered loops and add depth and profile information. std::stack St; diff --git a/bolt/lib/Core/DIEBuilder.cpp b/bolt/lib/Core/DIEBuilder.cpp index 0cf8a5e8c2c3db8a4892a62b78ee1f326887bb89..c4b0b251c1201fcf9f27454b3b26fc861d5235bb 100644 --- a/bolt/lib/Core/DIEBuilder.cpp +++ b/bolt/lib/Core/DIEBuilder.cpp @@ -22,7 +22,6 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Format.h" #include "llvm/Support/LEB128.h" #include @@ -545,6 +544,10 @@ void DIEBuilder::cloneDieReferenceAttribute( NewRefDie = DieInfo.Die; if (AttrSpec.Form == dwarf::DW_FORM_ref_addr) { + // Adding referenced DIE to DebugNames to be used when entries are created + // that contain cross cu references. + if (DebugNamesTable.canGenerateEntryWithCrossCUReference(U, Die, AttrSpec)) + DebugNamesTable.addCrossCUDie(DieInfo.Die); // no matter forward reference or backward reference, we are supposed // to calculate them in `finish` due to the possible modification of // the DIE. @@ -554,7 +557,7 @@ void DIEBuilder::cloneDieReferenceAttribute( std::make_pair(CurDieInfo, AddrReferenceInfo(&DieInfo, AttrSpec))); Die.addValue(getState().DIEAlloc, AttrSpec.Attr, dwarf::DW_FORM_ref_addr, - DIEInteger(0xDEADBEEF)); + DIEInteger(DieInfo.Die->getOffset())); return; } diff --git a/bolt/lib/Core/DebugData.cpp b/bolt/lib/Core/DebugData.cpp index a75016ede3090d5b6f77897bab9120d38e8c6057..a987a103a08b93ad7311fc81efb752ca15bac303 100644 --- a/bolt/lib/Core/DebugData.cpp +++ b/bolt/lib/Core/DebugData.cpp @@ -13,7 +13,6 @@ #include "bolt/Core/DebugData.h" #include "bolt/Core/BinaryContext.h" #include "bolt/Core/DIEBuilder.h" -#include "bolt/Rewrite/RewriteInstance.h" #include "bolt/Utils/Utils.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/CodeGen/DIE.h" @@ -23,7 +22,6 @@ #include "llvm/MC/MCAssembler.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCObjectStreamer.h" -#include "llvm/Support/Allocator.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/LEB128.h" @@ -32,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/bolt/lib/Core/DebugNames.cpp b/bolt/lib/Core/DebugNames.cpp index 23a29f52513c04bb751e9932df923fa052419a95..049244c4b51518a88cd9d8af1b5d64c24010d705 100644 --- a/bolt/lib/Core/DebugNames.cpp +++ b/bolt/lib/Core/DebugNames.cpp @@ -146,6 +146,55 @@ static bool shouldIncludeVariable(const DWARFUnit &Unit, const DIE &Die) { return false; } +bool static canProcess(const DWARFUnit &Unit, const DIE &Die, + std::string &NameToUse, const bool TagsOnly) { + switch (Die.getTag()) { + case dwarf::DW_TAG_base_type: + case dwarf::DW_TAG_class_type: + case dwarf::DW_TAG_enumeration_type: + case dwarf::DW_TAG_imported_declaration: + case dwarf::DW_TAG_pointer_type: + case dwarf::DW_TAG_structure_type: + case dwarf::DW_TAG_typedef: + case dwarf::DW_TAG_unspecified_type: + if (TagsOnly || Die.findAttribute(dwarf::Attribute::DW_AT_name)) + return true; + return false; + case dwarf::DW_TAG_namespace: + // According to DWARF5 spec namespaces without DW_AT_name needs to have + // "(anonymous namespace)" + if (!Die.findAttribute(dwarf::Attribute::DW_AT_name)) + NameToUse = "(anonymous namespace)"; + return true; + case dwarf::DW_TAG_inlined_subroutine: + case dwarf::DW_TAG_label: + case dwarf::DW_TAG_subprogram: + if (TagsOnly || Die.findAttribute(dwarf::Attribute::DW_AT_low_pc) || + Die.findAttribute(dwarf::Attribute::DW_AT_high_pc) || + Die.findAttribute(dwarf::Attribute::DW_AT_ranges) || + Die.findAttribute(dwarf::Attribute::DW_AT_entry_pc)) + return true; + return false; + case dwarf::DW_TAG_variable: + return TagsOnly || shouldIncludeVariable(Unit, Die); + default: + break; + } + return false; +} + +bool DWARF5AcceleratorTable::canGenerateEntryWithCrossCUReference( + const DWARFUnit &Unit, const DIE &Die, + const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec) { + if (!isCreated()) + return false; + std::string NameToUse = ""; + if (!canProcess(Unit, Die, NameToUse, true)) + return false; + return (AttrSpec.Attr == dwarf::Attribute::DW_AT_abstract_origin || + AttrSpec.Attr == dwarf::Attribute::DW_AT_specification) && + AttrSpec.Form == dwarf::DW_FORM_ref_addr; +} /// Returns name offset in String Offset section. static uint64_t getNameOffset(BinaryContext &BC, DWARFUnit &Unit, const uint64_t Index) { @@ -175,41 +224,6 @@ DWARF5AcceleratorTable::addAccelTableEntry( if (Unit.getVersion() < 5 || !NeedToCreate) return std::nullopt; std::string NameToUse = ""; - auto canProcess = [&](const DIE &Die) -> bool { - switch (Die.getTag()) { - case dwarf::DW_TAG_base_type: - case dwarf::DW_TAG_class_type: - case dwarf::DW_TAG_enumeration_type: - case dwarf::DW_TAG_imported_declaration: - case dwarf::DW_TAG_pointer_type: - case dwarf::DW_TAG_structure_type: - case dwarf::DW_TAG_typedef: - case dwarf::DW_TAG_unspecified_type: - if (Die.findAttribute(dwarf::Attribute::DW_AT_name)) - return true; - return false; - case dwarf::DW_TAG_namespace: - // According to DWARF5 spec namespaces without DW_AT_name needs to have - // "(anonymous namespace)" - if (!Die.findAttribute(dwarf::Attribute::DW_AT_name)) - NameToUse = "(anonymous namespace)"; - return true; - case dwarf::DW_TAG_inlined_subroutine: - case dwarf::DW_TAG_label: - case dwarf::DW_TAG_subprogram: - if (Die.findAttribute(dwarf::Attribute::DW_AT_low_pc) || - Die.findAttribute(dwarf::Attribute::DW_AT_high_pc) || - Die.findAttribute(dwarf::Attribute::DW_AT_ranges) || - Die.findAttribute(dwarf::Attribute::DW_AT_entry_pc)) - return true; - return false; - case dwarf::DW_TAG_variable: - return shouldIncludeVariable(Unit, Die); - default: - break; - } - return false; - }; auto getUnitID = [&](const DWARFUnit &Unit, bool &IsTU, uint32_t &DieTag) -> uint32_t { @@ -223,7 +237,7 @@ DWARF5AcceleratorTable::addAccelTableEntry( return CUList.size() - 1; }; - if (!canProcess(Die)) + if (!canProcess(Unit, Die, NameToUse, false)) return std::nullopt; // Addes a Unit to either CU, LocalTU or ForeignTU list the first time we @@ -318,10 +332,24 @@ DWARF5AcceleratorTable::addAccelTableEntry( const DIEValue Value = Die.findAttribute(Attr); if (!Value) return std::nullopt; - const DIEEntry &DIEENtry = Value.getDIEEntry(); - DIE &EntryDie = DIEENtry.getEntry(); - addEntry(EntryDie.findAttribute(dwarf::Attribute::DW_AT_linkage_name)); - return addEntry(EntryDie.findAttribute(dwarf::Attribute::DW_AT_name)); + const DIE *EntryDie = nullptr; + if (Value.getForm() == dwarf::DW_FORM_ref_addr) { + auto Iter = CrossCUDies.find(Value.getDIEInteger().getValue()); + if (Iter == CrossCUDies.end()) { + BC.errs() << "BOLT-WARNING: [internal-dwarf-warning]: Could not find " + "referenced DIE in CrossCUDies for " + << Twine::utohexstr(Value.getDIEInteger().getValue()) + << ".\n"; + return std::nullopt; + } + EntryDie = Iter->second; + } else { + const DIEEntry &DIEENtry = Value.getDIEEntry(); + EntryDie = &DIEENtry.getEntry(); + } + + addEntry(EntryDie->findAttribute(dwarf::Attribute::DW_AT_linkage_name)); + return addEntry(EntryDie->findAttribute(dwarf::Attribute::DW_AT_name)); }; if (std::optional Entry = @@ -332,7 +360,6 @@ DWARF5AcceleratorTable::addAccelTableEntry( return *Entry; return addEntry(Die.findAttribute(dwarf::Attribute::DW_AT_name)); - ; } /// Algorithm from llvm implementation. diff --git a/bolt/lib/Core/FunctionLayout.cpp b/bolt/lib/Core/FunctionLayout.cpp index 27e40de94be660f0ffbe9b5f6ddacb5b0393b0ac..73f4d5247d9ac06092601f1e931055223b83c00d 100644 --- a/bolt/lib/Core/FunctionLayout.cpp +++ b/bolt/lib/Core/FunctionLayout.cpp @@ -1,12 +1,17 @@ +//===- bolt/Core/FunctionLayout.cpp - Fragmented Function Layout -*- 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 "bolt/Core/FunctionLayout.h" -#include "bolt/Core/BinaryFunction.h" +#include "bolt/Core/BinaryBasicBlock.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/edit_distance.h" #include -#include -#include #include -#include using namespace llvm; using namespace bolt; diff --git a/bolt/lib/Core/HashUtilities.cpp b/bolt/lib/Core/HashUtilities.cpp index d40159b2e216d90f97b510886b7d79e468f895be..c4c67bd68198b6681b4dc95b7d3f0cb43caae5df 100644 --- a/bolt/lib/Core/HashUtilities.cpp +++ b/bolt/lib/Core/HashUtilities.cpp @@ -12,7 +12,6 @@ #include "bolt/Core/HashUtilities.h" #include "bolt/Core/BinaryContext.h" -#include "bolt/Core/BinaryFunction.h" #include "llvm/MC/MCInstPrinter.h" namespace llvm { diff --git a/bolt/lib/Core/MCPlusBuilder.cpp b/bolt/lib/Core/MCPlusBuilder.cpp index 5b14ad5cdb880f307c12d4e72d959a9a9b432a55..7ff7a2288451c844f360f9b24878d6d335be85ee 100644 --- a/bolt/lib/Core/MCPlusBuilder.cpp +++ b/bolt/lib/Core/MCPlusBuilder.cpp @@ -12,15 +12,16 @@ #include "bolt/Core/MCPlusBuilder.h" #include "bolt/Core/MCPlus.h" +#include "bolt/Utils/CommandLineOpts.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCInstrAnalysis.h" #include "llvm/MC/MCInstrDesc.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include -#include #define DEBUG_TYPE "mcplus" @@ -28,6 +29,13 @@ using namespace llvm; using namespace bolt; using namespace MCPlus; +namespace opts { +cl::opt + TerminalTrap("terminal-trap", + cl::desc("Assume that execution stops at trap instruction"), + cl::init(true), cl::Hidden, cl::cat(BoltCategory)); +} + bool MCPlusBuilder::equals(const MCInst &A, const MCInst &B, CompFuncTy Comp) const { if (A.getOpcode() != B.getOpcode()) @@ -121,6 +129,11 @@ bool MCPlusBuilder::equals(const MCTargetExpr &A, const MCTargetExpr &B, llvm_unreachable("target-specific expressions are unsupported"); } +bool MCPlusBuilder::isTerminator(const MCInst &Inst) const { + return Analysis->isTerminator(Inst) || + (opts::TerminalTrap && Info->get(Inst.getOpcode()).isTrap()); +} + void MCPlusBuilder::setTailCall(MCInst &Inst) const { assert(!hasAnnotation(Inst, MCAnnotation::kTailCall)); setAnnotationOpValue(Inst, MCAnnotation::kTailCall, true); diff --git a/bolt/lib/Core/Relocation.cpp b/bolt/lib/Core/Relocation.cpp index cbf95a7db08b52bc95856a90fd5266560fef7c2a..d16b7a94787c65d1e9b25324f3b1961b6b109102 100644 --- a/bolt/lib/Core/Relocation.cpp +++ b/bolt/lib/Core/Relocation.cpp @@ -774,60 +774,95 @@ static bool isPCRelativeRISCV(uint64_t Type) { } bool Relocation::isSupported(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + return false; + case Triple::aarch64: return isSupportedAArch64(Type); - if (Arch == Triple::riscv64) + case Triple::riscv64: return isSupportedRISCV(Type); - return isSupportedX86(Type); + case Triple::x86_64: + return isSupportedX86(Type); + } } size_t Relocation::getSizeForType(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return getSizeForTypeAArch64(Type); - if (Arch == Triple::riscv64) + case Triple::riscv64: return getSizeForTypeRISCV(Type); - return getSizeForTypeX86(Type); + case Triple::x86_64: + return getSizeForTypeX86(Type); + } } bool Relocation::skipRelocationType(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return skipRelocationTypeAArch64(Type); - if (Arch == Triple::riscv64) + case Triple::riscv64: return skipRelocationTypeRISCV(Type); - return skipRelocationTypeX86(Type); + case Triple::x86_64: + return skipRelocationTypeX86(Type); + } } bool Relocation::skipRelocationProcess(uint64_t &Type, uint64_t Contents) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return skipRelocationProcessAArch64(Type, Contents); - if (Arch == Triple::riscv64) - skipRelocationProcessRISCV(Type, Contents); - return skipRelocationProcessX86(Type, Contents); + case Triple::riscv64: + return skipRelocationProcessRISCV(Type, Contents); + case Triple::x86_64: + return skipRelocationProcessX86(Type, Contents); + } } uint64_t Relocation::encodeValue(uint64_t Type, uint64_t Value, uint64_t PC) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return encodeValueAArch64(Type, Value, PC); - if (Arch == Triple::riscv64) + case Triple::riscv64: return encodeValueRISCV(Type, Value, PC); - return encodeValueX86(Type, Value, PC); + case Triple::x86_64: + return encodeValueX86(Type, Value, PC); + } } uint64_t Relocation::extractValue(uint64_t Type, uint64_t Contents, uint64_t PC) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return extractValueAArch64(Type, Contents, PC); - if (Arch == Triple::riscv64) + case Triple::riscv64: return extractValueRISCV(Type, Contents, PC); - return extractValueX86(Type, Contents, PC); + case Triple::x86_64: + return extractValueX86(Type, Contents, PC); + } } bool Relocation::isGOT(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return isGOTAArch64(Type); - if (Arch == Triple::riscv64) + case Triple::riscv64: return isGOTRISCV(Type); - return isGOTX86(Type); + case Triple::x86_64: + return isGOTX86(Type); + } } bool Relocation::isX86GOTPCRELX(uint64_t Type) { @@ -845,27 +880,42 @@ bool Relocation::isX86GOTPC64(uint64_t Type) { bool Relocation::isNone(uint64_t Type) { return Type == getNone(); } bool Relocation::isRelative(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return Type == ELF::R_AARCH64_RELATIVE; - if (Arch == Triple::riscv64) + case Triple::riscv64: return Type == ELF::R_RISCV_RELATIVE; - return Type == ELF::R_X86_64_RELATIVE; + case Triple::x86_64: + return Type == ELF::R_X86_64_RELATIVE; + } } bool Relocation::isIRelative(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return Type == ELF::R_AARCH64_IRELATIVE; - if (Arch == Triple::riscv64) + case Triple::riscv64: llvm_unreachable("not implemented"); - return Type == ELF::R_X86_64_IRELATIVE; + case Triple::x86_64: + return Type == ELF::R_X86_64_IRELATIVE; + } } bool Relocation::isTLS(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return isTLSAArch64(Type); - if (Arch == Triple::riscv64) + case Triple::riscv64: return isTLSRISCV(Type); - return isTLSX86(Type); + case Triple::x86_64: + return isTLSX86(Type); + } } bool Relocation::isInstructionReference(uint64_t Type) { @@ -882,49 +932,81 @@ bool Relocation::isInstructionReference(uint64_t Type) { } uint64_t Relocation::getNone() { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return ELF::R_AARCH64_NONE; - if (Arch == Triple::riscv64) + case Triple::riscv64: return ELF::R_RISCV_NONE; - return ELF::R_X86_64_NONE; + case Triple::x86_64: + return ELF::R_X86_64_NONE; + } } uint64_t Relocation::getPC32() { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return ELF::R_AARCH64_PREL32; - if (Arch == Triple::riscv64) + case Triple::riscv64: return ELF::R_RISCV_32_PCREL; - return ELF::R_X86_64_PC32; + case Triple::x86_64: + return ELF::R_X86_64_PC32; + } } uint64_t Relocation::getPC64() { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return ELF::R_AARCH64_PREL64; - if (Arch == Triple::riscv64) + case Triple::riscv64: llvm_unreachable("not implemented"); - return ELF::R_X86_64_PC64; + case Triple::x86_64: + return ELF::R_X86_64_PC64; + } } bool Relocation::isPCRelative(uint64_t Type) { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return isPCRelativeAArch64(Type); - if (Arch == Triple::riscv64) + case Triple::riscv64: return isPCRelativeRISCV(Type); - return isPCRelativeX86(Type); + case Triple::x86_64: + return isPCRelativeX86(Type); + } } uint64_t Relocation::getAbs64() { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return ELF::R_AARCH64_ABS64; - if (Arch == Triple::riscv64) + case Triple::riscv64: return ELF::R_RISCV_64; - return ELF::R_X86_64_64; + case Triple::x86_64: + return ELF::R_X86_64_64; + } } uint64_t Relocation::getRelative() { - if (Arch == Triple::aarch64) + switch (Arch) { + default: + llvm_unreachable("Unsupported architecture"); + case Triple::aarch64: return ELF::R_AARCH64_RELATIVE; - return ELF::R_X86_64_RELATIVE; + case Triple::riscv64: + llvm_unreachable("not implemented"); + case Triple::x86_64: + return ELF::R_X86_64_RELATIVE; + } } size_t Relocation::emit(MCStreamer *Streamer) const { @@ -991,9 +1073,16 @@ void Relocation::print(raw_ostream &OS) const { static const char *AArch64RelocNames[] = { #include "llvm/BinaryFormat/ELFRelocs/AArch64.def" }; - if (Arch == Triple::aarch64) + switch (Arch) { + default: + OS << "RType:" << Twine::utohexstr(Type); + break; + + case Triple::aarch64: OS << AArch64RelocNames[Type]; - else if (Arch == Triple::riscv64) { + break; + + case Triple::riscv64: // RISC-V relocations are not sequentially numbered so we cannot use an // array switch (Type) { @@ -1006,8 +1095,12 @@ void Relocation::print(raw_ostream &OS) const { break; #include "llvm/BinaryFormat/ELFRelocs/RISCV.def" } - } else + break; + + case Triple::x86_64: OS << X86RelocNames[Type]; + break; + } OS << ", 0x" << Twine::utohexstr(Offset); if (Symbol) { OS << ", " << Symbol->getName(); diff --git a/bolt/lib/Passes/CMOVConversion.cpp b/bolt/lib/Passes/CMOVConversion.cpp index 2492ff21794634bd35bc4f7f03c9970bccf69739..cdd99b55207e0b6e92a1f0eab59f5082f57bd614 100644 --- a/bolt/lib/Passes/CMOVConversion.cpp +++ b/bolt/lib/Passes/CMOVConversion.cpp @@ -17,7 +17,6 @@ #include "llvm/ADT/PostOrderIterator.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" -#include #define DEBUG_TYPE "cmov" diff --git a/bolt/lib/Passes/FixRISCVCallsPass.cpp b/bolt/lib/Passes/FixRISCVCallsPass.cpp index 83c745facb290b70209a3243fdf4a553ca49f3e4..9011ef303a80ef1922f4f772d5e43f6a4f9f1b05 100644 --- a/bolt/lib/Passes/FixRISCVCallsPass.cpp +++ b/bolt/lib/Passes/FixRISCVCallsPass.cpp @@ -1,3 +1,11 @@ +//===- bolt/Passes/FixRISCVCallsPass.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 "bolt/Passes/FixRISCVCallsPass.h" #include "bolt/Core/ParallelUtilities.h" diff --git a/bolt/lib/Passes/FixRelaxationPass.cpp b/bolt/lib/Passes/FixRelaxationPass.cpp index a49fb9894e808cccdf0f222a51e6f354db2c0f8d..7c970e464a94e361626dac979546e0564f25a012 100644 --- a/bolt/lib/Passes/FixRelaxationPass.cpp +++ b/bolt/lib/Passes/FixRelaxationPass.cpp @@ -1,3 +1,11 @@ +//===- bolt/Passes/FixRelaxationPass.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 "bolt/Passes/FixRelaxationPass.h" #include "bolt/Core/ParallelUtilities.h" diff --git a/bolt/lib/Passes/FrameOptimizer.cpp b/bolt/lib/Passes/FrameOptimizer.cpp index fb5f8eafa5cf846e576bbfff6b4f7b1ddbec5b06..8461225e1819c169023ab1f31fb34e6ab619d08e 100644 --- a/bolt/lib/Passes/FrameOptimizer.cpp +++ b/bolt/lib/Passes/FrameOptimizer.cpp @@ -20,7 +20,6 @@ #include "bolt/Utils/CommandLineOpts.h" #include "llvm/Support/Timer.h" #include -#include #define DEBUG_TYPE "fop" diff --git a/bolt/lib/Passes/Hugify.cpp b/bolt/lib/Passes/Hugify.cpp index b77356153bfd8caf5f1e01b27c29547c3b45a704..1ac1b08573b86954f01ef3de3a5c4db2f732b984 100644 --- a/bolt/lib/Passes/Hugify.cpp +++ b/bolt/lib/Passes/Hugify.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "bolt/Passes/Hugify.h" -#include "llvm/Support/CommandLine.h" #define DEBUG_TYPE "bolt-hugify" diff --git a/bolt/lib/Passes/Inliner.cpp b/bolt/lib/Passes/Inliner.cpp index a3b2017aa32aa82dfc3dec7043bf2f9385d892d5..84e7d97067b0cf7bde944c7a139e4c5246a0ddf7 100644 --- a/bolt/lib/Passes/Inliner.cpp +++ b/bolt/lib/Passes/Inliner.cpp @@ -27,7 +27,6 @@ #include "bolt/Passes/Inliner.h" #include "bolt/Core/MCPlus.h" #include "llvm/Support/CommandLine.h" -#include #define DEBUG_TYPE "bolt-inliner" diff --git a/bolt/lib/Passes/ShrinkWrapping.cpp b/bolt/lib/Passes/ShrinkWrapping.cpp index c9706500758d1f223f5d71de45e310755f021f78..176321c58dc903fdb62e76a237f31a15c7ffba12 100644 --- a/bolt/lib/Passes/ShrinkWrapping.cpp +++ b/bolt/lib/Passes/ShrinkWrapping.cpp @@ -11,7 +11,6 @@ //===----------------------------------------------------------------------===// #include "bolt/Passes/ShrinkWrapping.h" -#include "bolt/Core/MCPlus.h" #include "bolt/Passes/DataflowInfoManager.h" #include "bolt/Passes/MCF.h" #include "bolt/Utils/CommandLineOpts.h" diff --git a/bolt/lib/Passes/SplitFunctions.cpp b/bolt/lib/Passes/SplitFunctions.cpp index cdbb2a15f667c6b7dc2a06674028e583bbb27aaf..f9e634d15a97244c58adf185c0ea4ec80017079c 100644 --- a/bolt/lib/Passes/SplitFunctions.cpp +++ b/bolt/lib/Passes/SplitFunctions.cpp @@ -17,7 +17,6 @@ #include "bolt/Core/ParallelUtilities.h" #include "bolt/Utils/CommandLineOpts.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/Sequence.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Support/CommandLine.h" diff --git a/bolt/lib/Passes/TailDuplication.cpp b/bolt/lib/Passes/TailDuplication.cpp index 2163e3a6a008362586fc484efb97cfad71a43b52..463ea49527fa6cd5696ea1fde973f6e5e8c7e10e 100644 --- a/bolt/lib/Passes/TailDuplication.cpp +++ b/bolt/lib/Passes/TailDuplication.cpp @@ -13,9 +13,9 @@ #include "bolt/Passes/TailDuplication.h" #include "llvm/ADT/DenseMap.h" #include "llvm/MC/MCRegisterInfo.h" -#include #include +#include #define DEBUG_TYPE "taildup" diff --git a/bolt/lib/Passes/ValidateInternalCalls.cpp b/bolt/lib/Passes/ValidateInternalCalls.cpp index 54ae621159cfa3bcd1587d4a4a680eb53089c006..88df2e5b59f3895497312e1f8536ed8358694f1c 100644 --- a/bolt/lib/Passes/ValidateInternalCalls.cpp +++ b/bolt/lib/Passes/ValidateInternalCalls.cpp @@ -14,7 +14,6 @@ #include "bolt/Core/BinaryBasicBlock.h" #include "bolt/Passes/DataflowInfoManager.h" #include "bolt/Passes/FrameAnalysis.h" -#include "llvm/ADT/SmallVector.h" #include "llvm/MC/MCInstPrinter.h" #include #include diff --git a/bolt/lib/Profile/BoltAddressTranslation.cpp b/bolt/lib/Profile/BoltAddressTranslation.cpp index 1d61a1b735b403ee58f93abcba52688ec4005c4c..0141ce189acda584e98cf73168a70c32e661cd43 100644 --- a/bolt/lib/Profile/BoltAddressTranslation.cpp +++ b/bolt/lib/Profile/BoltAddressTranslation.cpp @@ -22,12 +22,10 @@ const char *BoltAddressTranslation::SECTION_NAME = ".note.bolt_bat"; void BoltAddressTranslation::writeEntriesForBB(MapTy &Map, const BinaryBasicBlock &BB, - uint64_t FuncAddress) { - uint64_t HotFuncAddress = ColdPartSource.count(FuncAddress) - ? ColdPartSource[FuncAddress] - : FuncAddress; + uint64_t FuncInputAddress, + uint64_t FuncOutputAddress) { const uint64_t BBOutputOffset = - BB.getOutputAddressRange().first - FuncAddress; + BB.getOutputAddressRange().first - FuncOutputAddress; const uint32_t BBInputOffset = BB.getInputOffset(); // Every output BB must track back to an input BB for profile collection @@ -42,9 +40,14 @@ void BoltAddressTranslation::writeEntriesForBB(MapTy &Map, LLVM_DEBUG(dbgs() << "BB " << BB.getName() << "\n"); LLVM_DEBUG(dbgs() << " Key: " << Twine::utohexstr(BBOutputOffset) << " Val: " << Twine::utohexstr(BBInputOffset) << "\n"); - LLVM_DEBUG(dbgs() << formatv(" Hash: {0:x}\n", - getBBHash(HotFuncAddress, BBInputOffset))); - (void)HotFuncAddress; + // NB: in `writeEntriesForBB` we use the input address because hashes are + // saved early in `saveMetadata` before output addresses are assigned. + const BBHashMapTy &BBHashMap = getBBHashMap(FuncInputAddress); + (void)BBHashMap; + LLVM_DEBUG( + dbgs() << formatv(" Hash: {0:x}\n", BBHashMap.getBBHash(BBInputOffset))); + LLVM_DEBUG( + dbgs() << formatv(" Index: {0}\n", BBHashMap.getBBIndex(BBInputOffset))); // In case of conflicts (same Key mapping to different Vals), the last // update takes precedence. Of course it is not ideal to have conflicts and // those happen when we have an empty BB that either contained only @@ -61,7 +64,7 @@ void BoltAddressTranslation::writeEntriesForBB(MapTy &Map, const auto InputAddress = BB.getFunction()->getAddress() + InputOffset; const auto OutputAddress = IOAddressMap.lookup(InputAddress); assert(OutputAddress && "Unknown instruction address"); - const auto OutputOffset = *OutputAddress - FuncAddress; + const auto OutputOffset = *OutputAddress - FuncOutputAddress; // Is this the first instruction in the BB? No need to duplicate the entry. if (OutputOffset == BBOutputOffset) @@ -85,19 +88,26 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) { if (Function.isIgnored() || (!BC.HasRelocations && !Function.isSimple())) continue; - // TBD: handle BAT functions w/multiple entry points. - if (Function.isMultiEntry()) - continue; + uint32_t NumSecondaryEntryPoints = 0; + Function.forEachEntryPoint([&](uint64_t Offset, const MCSymbol *) { + if (!Offset) + return true; + ++NumSecondaryEntryPoints; + SecondaryEntryPointsMap[OutputAddress].push_back(Offset); + return true; + }); LLVM_DEBUG(dbgs() << "Function name: " << Function.getPrintName() << "\n"); LLVM_DEBUG(dbgs() << " Address reference: 0x" << Twine::utohexstr(Function.getOutputAddress()) << "\n"); - LLVM_DEBUG(dbgs() << formatv(" Hash: {0:x}\n", getBFHash(OutputAddress))); + LLVM_DEBUG(dbgs() << formatv(" Hash: {0:x}\n", getBFHash(InputAddress))); + LLVM_DEBUG(dbgs() << " Secondary Entry Points: " << NumSecondaryEntryPoints + << '\n'); MapTy Map; for (const BinaryBasicBlock *const BB : Function.getLayout().getMainFragment()) - writeEntriesForBB(Map, *BB, Function.getOutputAddress()); + writeEntriesForBB(Map, *BB, InputAddress, OutputAddress); Maps.emplace(Function.getOutputAddress(), std::move(Map)); ReverseMap.emplace(OutputAddress, InputAddress); @@ -111,7 +121,7 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) { ColdPartSource.emplace(FF.getAddress(), Function.getOutputAddress()); Map.clear(); for (const BinaryBasicBlock *const BB : FF) - writeEntriesForBB(Map, *BB, FF.getAddress()); + writeEntriesForBB(Map, *BB, InputAddress, FF.getAddress()); Maps.emplace(FF.getAddress(), std::move(Map)); } @@ -123,11 +133,9 @@ void BoltAddressTranslation::write(const BinaryContext &BC, raw_ostream &OS) { writeMaps(Maps, PrevAddress, OS); BC.outs() << "BOLT-INFO: Wrote " << Maps.size() << " BAT maps\n"; - const uint64_t NumBBHashes = std::accumulate( - FuncHashes.begin(), FuncHashes.end(), 0ull, - [](size_t Acc, const auto &B) { return Acc + B.second.second.size(); }); - BC.outs() << "BOLT-INFO: Wrote " << FuncHashes.size() << " function and " - << NumBBHashes << " basic block hashes\n"; + BC.outs() << "BOLT-INFO: Wrote " << FuncHashes.getNumFunctions() + << " function and " << FuncHashes.getNumBasicBlocks() + << " basic block hashes\n"; } APInt BoltAddressTranslation::calculateBranchEntriesBitMask(MapTy &Map, @@ -174,26 +182,39 @@ void BoltAddressTranslation::writeMaps(std::map &Maps, // Only process cold fragments in cold mode, and vice versa. if (Cold != ColdPartSource.count(Address)) continue; - // NB: here we use the input address because hashes are saved early (in - // `saveMetadata`) before output addresses are assigned. + // NB: in `writeMaps` we use the input address because hashes are saved + // early in `saveMetadata` before output addresses are assigned. const uint64_t HotInputAddress = ReverseMap[Cold ? ColdPartSource[Address] : Address]; - std::pair &FuncHashPair = FuncHashes[HotInputAddress]; MapTy &Map = MapEntry.second; const uint32_t NumEntries = Map.size(); LLVM_DEBUG(dbgs() << "Writing " << NumEntries << " entries for 0x" << Twine::utohexstr(Address) << ".\n"); encodeULEB128(Address - PrevAddress, OS); PrevAddress = Address; + const uint32_t NumSecondaryEntryPoints = + SecondaryEntryPointsMap.count(Address) + ? SecondaryEntryPointsMap[Address].size() + : 0; if (Cold) { - size_t HotIndex = - std::distance(ColdPartSource.begin(), ColdPartSource.find(Address)); + auto HotEntryIt = Maps.find(ColdPartSource[Address]); + assert(HotEntryIt != Maps.end()); + size_t HotIndex = std::distance(Maps.begin(), HotEntryIt); encodeULEB128(HotIndex - PrevIndex, OS); PrevIndex = HotIndex; } else { // Function hash - LLVM_DEBUG(dbgs() << "Hash: " << formatv("{0:x}\n", FuncHashPair.first)); - OS.write(reinterpret_cast(&FuncHashPair.first), 8); + size_t BFHash = getBFHash(HotInputAddress); + LLVM_DEBUG(dbgs() << "Hash: " << formatv("{0:x}\n", BFHash)); + OS.write(reinterpret_cast(&BFHash), 8); + // Number of basic blocks + size_t NumBasicBlocks = NumBasicBlocksMap[HotInputAddress]; + LLVM_DEBUG(dbgs() << "Basic blocks: " << NumBasicBlocks << '\n'); + encodeULEB128(NumBasicBlocks, OS); + // Secondary entry points + encodeULEB128(NumSecondaryEntryPoints, OS); + LLVM_DEBUG(dbgs() << "Secondary Entry Points: " << NumSecondaryEntryPoints + << '\n'); } encodeULEB128(NumEntries, OS); // For hot fragments only: encode the number of equal offsets @@ -215,8 +236,10 @@ void BoltAddressTranslation::writeMaps(std::map &Maps, }); } } + const BBHashMapTy &BBHashMap = getBBHashMap(HotInputAddress); size_t Index = 0; uint64_t InOffset = 0; + size_t PrevBBIndex = 0; // Output and Input addresses and delta-encoded for (std::pair &KeyVal : Map) { const uint64_t OutputAddress = KeyVal.first + Address; @@ -226,12 +249,27 @@ void BoltAddressTranslation::writeMaps(std::map &Maps, encodeSLEB128(KeyVal.second - InOffset, OS); InOffset = KeyVal.second; // Keeping InOffset as if BRANCHENTRY is encoded if ((InOffset & BRANCHENTRY) == 0) { - // Basic block hash - size_t BBHash = FuncHashPair.second[InOffset >> 1]; + const bool IsBlock = BBHashMap.isInputBlock(InOffset >> 1); + unsigned BBIndex = IsBlock ? BBHashMap.getBBIndex(InOffset >> 1) : 0; + size_t BBHash = IsBlock ? BBHashMap.getBBHash(InOffset >> 1) : 0; OS.write(reinterpret_cast(&BBHash), 8); - LLVM_DEBUG(dbgs() << formatv("{0:x} -> {1:x} {2:x}\n", KeyVal.first, - InOffset >> 1, BBHash)); + // Basic block index in the input binary + encodeULEB128(BBIndex - PrevBBIndex, OS); + PrevBBIndex = BBIndex; + LLVM_DEBUG(dbgs() << formatv("{0:x} -> {1:x} {2:x} {3}\n", KeyVal.first, + InOffset >> 1, BBHash, BBIndex)); + } + } + uint32_t PrevOffset = 0; + if (!Cold && NumSecondaryEntryPoints) { + LLVM_DEBUG(dbgs() << "Secondary entry points: "); + // Secondary entry point offsets, delta-encoded + for (uint32_t Offset : SecondaryEntryPointsMap[Address]) { + encodeULEB128(Offset - PrevOffset, OS); + LLVM_DEBUG(dbgs() << formatv("{0:x} ", Offset)); + PrevOffset = Offset; } + LLVM_DEBUG(dbgs() << '\n'); } } } @@ -276,6 +314,7 @@ void BoltAddressTranslation::parseMaps(std::vector &HotFuncs, const uint64_t Address = PrevAddress + DE.getULEB128(&Offset, &Err); uint64_t HotAddress = Cold ? 0 : Address; PrevAddress = Address; + uint32_t SecondaryEntryPoints = 0; if (Cold) { HotIndex += DE.getULEB128(&Offset, &Err); HotAddress = HotFuncs[HotIndex]; @@ -284,8 +323,20 @@ void BoltAddressTranslation::parseMaps(std::vector &HotFuncs, HotFuncs.push_back(Address); // Function hash const size_t FuncHash = DE.getU64(&Offset, &Err); - FuncHashes[Address].first = FuncHash; + FuncHashes.addEntry(Address, FuncHash); LLVM_DEBUG(dbgs() << formatv("{0:x}: hash {1:x}\n", Address, FuncHash)); + // Number of basic blocks + const size_t NumBasicBlocks = DE.getULEB128(&Offset, &Err); + NumBasicBlocksMap.emplace(Address, NumBasicBlocks); + LLVM_DEBUG(dbgs() << formatv("{0:x}: #bbs {1}, {2} bytes\n", Address, + NumBasicBlocks, + getULEB128Size(NumBasicBlocks))); + // Secondary entry points + SecondaryEntryPoints = DE.getULEB128(&Offset, &Err); + LLVM_DEBUG( + dbgs() << formatv("{0:x}: secondary entry points {1}, {2} bytes\n", + Address, SecondaryEntryPoints, + getULEB128Size(SecondaryEntryPoints))); } const uint32_t NumEntries = DE.getULEB128(&Offset, &Err); // Equal offsets, hot fragments only. @@ -316,6 +367,7 @@ void BoltAddressTranslation::parseMaps(std::vector &HotFuncs, LLVM_DEBUG(dbgs() << "Parsing " << NumEntries << " entries for 0x" << Twine::utohexstr(Address) << "\n"); uint64_t InputOffset = 0; + size_t BBIndex = 0; for (uint32_t J = 0; J < NumEntries; ++J) { const uint64_t OutputDelta = DE.getULEB128(&Offset, &Err); const uint64_t OutputAddress = PrevAddress + OutputDelta; @@ -330,23 +382,41 @@ void BoltAddressTranslation::parseMaps(std::vector &HotFuncs, } Map.insert(std::pair(OutputOffset, InputOffset)); size_t BBHash = 0; + size_t BBIndexDelta = 0; const bool IsBranchEntry = InputOffset & BRANCHENTRY; if (!IsBranchEntry) { BBHash = DE.getU64(&Offset, &Err); + BBIndexDelta = DE.getULEB128(&Offset, &Err); + BBIndex += BBIndexDelta; // Map basic block hash to hot fragment by input offset - FuncHashes[HotAddress].second.emplace(InputOffset >> 1, BBHash); + getBBHashMap(HotAddress).addEntry(InputOffset >> 1, BBIndex, BBHash); } LLVM_DEBUG({ dbgs() << formatv( "{0:x} -> {1:x} ({2}/{3}b -> {4}/{5}b), {6:x}", OutputOffset, InputOffset, OutputDelta, getULEB128Size(OutputDelta), InputDelta, (J < EqualElems) ? 0 : getSLEB128Size(InputDelta), OutputAddress); - if (BBHash) - dbgs() << formatv(" {0:x}", BBHash); + if (!IsBranchEntry) { + dbgs() << formatv(" {0:x} {1}/{2}b", BBHash, BBIndex, + getULEB128Size(BBIndexDelta)); + } dbgs() << '\n'; }); } Maps.insert(std::pair(Address, Map)); + if (!Cold && SecondaryEntryPoints) { + uint32_t EntryPointOffset = 0; + LLVM_DEBUG(dbgs() << "Secondary entry points: "); + for (uint32_t EntryPointId = 0; EntryPointId != SecondaryEntryPoints; + ++EntryPointId) { + uint32_t OffsetDelta = DE.getULEB128(&Offset, &Err); + EntryPointOffset += OffsetDelta; + SecondaryEntryPointsMap[Address].push_back(EntryPointOffset); + LLVM_DEBUG(dbgs() << formatv("{0:x}/{1}b ", EntryPointOffset, + getULEB128Size(OffsetDelta))); + } + LLVM_DEBUG(dbgs() << '\n'); + } } } @@ -356,11 +426,14 @@ void BoltAddressTranslation::dump(raw_ostream &OS) { for (const auto &MapEntry : Maps) { const uint64_t Address = MapEntry.first; const uint64_t HotAddress = fetchParentAddress(Address); + const bool IsHotFunction = HotAddress == 0; OS << "Function Address: 0x" << Twine::utohexstr(Address); - if (HotAddress == 0) + if (IsHotFunction) OS << formatv(", hash: {0:x}", getBFHash(Address)); OS << "\n"; OS << "BB mappings:\n"; + const BBHashMapTy &BBHashMap = + getBBHashMap(HotAddress ? HotAddress : Address); for (const auto &Entry : MapEntry.second) { const bool IsBranch = Entry.second & BRANCHENTRY; const uint32_t Val = Entry.second >> 1; // dropping BRANCHENTRY bit @@ -369,10 +442,18 @@ void BoltAddressTranslation::dump(raw_ostream &OS) { if (IsBranch) OS << " (branch)"; else - OS << formatv(" hash: {0:x}", - getBBHash(HotAddress ? HotAddress : Address, Val)); + OS << formatv(" hash: {0:x}", BBHashMap.getBBHash(Val)); OS << "\n"; } + if (IsHotFunction) + OS << "NumBlocks: " << NumBasicBlocksMap[Address] << '\n'; + if (SecondaryEntryPointsMap.count(Address)) { + const std::vector &SecondaryEntryPoints = + SecondaryEntryPointsMap[Address]; + OS << SecondaryEntryPoints.size() << " secondary entry points:\n"; + for (uint32_t EntryPointOffset : SecondaryEntryPoints) + OS << formatv("{0:x}\n", EntryPointOffset); + } OS << "\n"; } const size_t NumColdParts = ColdPartSource.size(); @@ -491,21 +572,58 @@ void BoltAddressTranslation::saveMetadata(BinaryContext &BC) { if (BF.isIgnored() || (!BC.HasRelocations && !BF.isSimple())) continue; // Prepare function and block hashes - FuncHashes[BF.getAddress()].first = BF.computeHash(); + FuncHashes.addEntry(BF.getAddress(), BF.computeHash()); BF.computeBlockHashes(); + BBHashMapTy &BBHashMap = getBBHashMap(BF.getAddress()); + // Set BF/BB metadata for (const BinaryBasicBlock &BB : BF) - FuncHashes[BF.getAddress()].second.emplace(BB.getInputOffset(), - BB.getHash()); + BBHashMap.addEntry(BB.getInputOffset(), BB.getIndex(), BB.getHash()); + NumBasicBlocksMap.emplace(BF.getAddress(), BF.size()); } } -size_t BoltAddressTranslation::getBBHash(uint64_t FuncOutputAddress, - uint32_t BBInputOffset) const { - return FuncHashes.at(FuncOutputAddress).second.at(BBInputOffset); +unsigned +BoltAddressTranslation::getSecondaryEntryPointId(uint64_t Address, + uint32_t Offset) const { + auto FunctionIt = SecondaryEntryPointsMap.find(Address); + if (FunctionIt == SecondaryEntryPointsMap.end()) + return 0; + const std::vector &Offsets = FunctionIt->second; + auto OffsetIt = std::find(Offsets.begin(), Offsets.end(), Offset); + if (OffsetIt == Offsets.end()) + return 0; + // Adding one here because main entry point is not stored in BAT, and + // enumeration for secondary entry points starts with 1. + return OffsetIt - Offsets.begin() + 1; } -size_t BoltAddressTranslation::getBFHash(uint64_t OutputAddress) const { - return FuncHashes.at(OutputAddress).first; +std::pair +BoltAddressTranslation::translateSymbol(const BinaryContext &BC, + const MCSymbol &Symbol, + uint32_t Offset) const { + // The symbol could be a secondary entry in a cold fragment. + uint64_t SymbolValue = cantFail(errorOrToExpected(BC.getSymbolValue(Symbol))); + + const BinaryFunction *Callee = BC.getFunctionForSymbol(&Symbol); + assert(Callee); + + // Containing function, not necessarily the same as symbol value. + const uint64_t CalleeAddress = Callee->getAddress(); + const uint32_t OutputOffset = SymbolValue - CalleeAddress; + + const uint64_t ParentAddress = fetchParentAddress(CalleeAddress); + const uint64_t HotAddress = ParentAddress ? ParentAddress : CalleeAddress; + + const BinaryFunction *ParentBF = BC.getBinaryFunctionAtAddress(HotAddress); + + const uint32_t InputOffset = + translate(CalleeAddress, OutputOffset, /*IsBranchSrc*/ false) + Offset; + + unsigned SecondaryEntryId{0}; + if (InputOffset) + SecondaryEntryId = getSecondaryEntryPointId(HotAddress, InputOffset); + + return std::pair(ParentBF, SecondaryEntryId); } } // namespace bolt diff --git a/bolt/lib/Profile/CMakeLists.txt b/bolt/lib/Profile/CMakeLists.txt index 3a31a9cc191971dc487e1d54ade64c5b08f7565e..045ac47edb950bb1ebc99fd4dc56fb38cc652667 100644 --- a/bolt/lib/Profile/CMakeLists.txt +++ b/bolt/lib/Profile/CMakeLists.txt @@ -3,7 +3,6 @@ add_llvm_library(LLVMBOLTProfile DataAggregator.cpp DataReader.cpp Heatmap.cpp - ProfileReaderBase.cpp StaleProfileMatching.cpp YAMLProfileReader.cpp YAMLProfileWriter.cpp diff --git a/bolt/lib/Profile/DataAggregator.cpp b/bolt/lib/Profile/DataAggregator.cpp index 37c637a44a0e56d74a1a94ab954c6e19f2425783..0b2a4e86561f3aaa56a7385bf4fd8e5439f2d56a 100644 --- a/bolt/lib/Profile/DataAggregator.cpp +++ b/bolt/lib/Profile/DataAggregator.cpp @@ -662,18 +662,19 @@ DataAggregator::getBinaryFunctionContainingAddress(uint64_t Address) const { /*UseMaxSize=*/true); } -StringRef DataAggregator::getLocationName(BinaryFunction &Func, - uint64_t Count) { +BinaryFunction * +DataAggregator::getBATParentFunction(const BinaryFunction &Func) const { + if (BAT) + if (const uint64_t HotAddr = BAT->fetchParentAddress(Func.getAddress())) + return getBinaryFunctionContainingAddress(HotAddr); + return nullptr; +} + +StringRef DataAggregator::getLocationName(const BinaryFunction &Func) const { if (!BAT) return Func.getOneName(); const BinaryFunction *OrigFunc = &Func; - if (const uint64_t HotAddr = BAT->fetchParentAddress(Func.getAddress())) { - NumColdSamples += Count; - BinaryFunction *HotFunc = getBinaryFunctionContainingAddress(HotAddr); - if (HotFunc) - OrigFunc = HotFunc; - } // If it is a local function, prefer the name containing the file name where // the local function was declared for (StringRef AlternativeName : OrigFunc->getNames()) { @@ -688,12 +689,17 @@ StringRef DataAggregator::getLocationName(BinaryFunction &Func, return OrigFunc->getOneName(); } -bool DataAggregator::doSample(BinaryFunction &Func, uint64_t Address, +bool DataAggregator::doSample(BinaryFunction &OrigFunc, uint64_t Address, uint64_t Count) { + BinaryFunction *ParentFunc = getBATParentFunction(OrigFunc); + BinaryFunction &Func = ParentFunc ? *ParentFunc : OrigFunc; + if (ParentFunc) + NumColdSamples += Count; + auto I = NamesToSamples.find(Func.getOneName()); if (I == NamesToSamples.end()) { bool Success; - StringRef LocName = getLocationName(Func, Count); + StringRef LocName = getLocationName(Func); std::tie(I, Success) = NamesToSamples.insert( std::make_pair(Func.getOneName(), FuncSampleData(LocName, FuncSampleData::ContainerTy()))); @@ -713,22 +719,12 @@ bool DataAggregator::doIntraBranch(BinaryFunction &Func, uint64_t From, FuncBranchData *AggrData = getBranchData(Func); if (!AggrData) { AggrData = &NamesToBranches[Func.getOneName()]; - AggrData->Name = getLocationName(Func, Count); + AggrData->Name = getLocationName(Func); setBranchData(Func, AggrData); } - From -= Func.getAddress(); - To -= Func.getAddress(); LLVM_DEBUG(dbgs() << "BOLT-DEBUG: bumpBranchCount: " << formatv("{0} @ {1:x} -> {0} @ {2:x}\n", Func, From, To)); - if (BAT) { - From = BAT->translate(Func.getAddress(), From, /*IsBranchSrc=*/true); - To = BAT->translate(Func.getAddress(), To, /*IsBranchSrc=*/false); - LLVM_DEBUG( - dbgs() << "BOLT-DEBUG: BAT translation on bumpBranchCount: " - << formatv("{0} @ {1:x} -> {0} @ {2:x}\n", Func, From, To)); - } - AggrData->bumpBranchCount(From, To, Count, Mispreds); return true; } @@ -742,30 +738,24 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc, StringRef SrcFunc; StringRef DstFunc; if (FromFunc) { - SrcFunc = getLocationName(*FromFunc, Count); + SrcFunc = getLocationName(*FromFunc); FromAggrData = getBranchData(*FromFunc); if (!FromAggrData) { FromAggrData = &NamesToBranches[FromFunc->getOneName()]; FromAggrData->Name = SrcFunc; setBranchData(*FromFunc, FromAggrData); } - From -= FromFunc->getAddress(); - if (BAT) - From = BAT->translate(FromFunc->getAddress(), From, /*IsBranchSrc=*/true); recordExit(*FromFunc, From, Mispreds, Count); } if (ToFunc) { - DstFunc = getLocationName(*ToFunc, 0); + DstFunc = getLocationName(*ToFunc); ToAggrData = getBranchData(*ToFunc); if (!ToAggrData) { ToAggrData = &NamesToBranches[ToFunc->getOneName()]; ToAggrData->Name = DstFunc; setBranchData(*ToFunc, ToAggrData); } - To -= ToFunc->getAddress(); - if (BAT) - To = BAT->translate(ToFunc->getAddress(), To, /*IsBranchSrc=*/false); recordEntry(*ToFunc, To, Mispreds, Count); } @@ -781,15 +771,32 @@ bool DataAggregator::doInterBranch(BinaryFunction *FromFunc, bool DataAggregator::doBranch(uint64_t From, uint64_t To, uint64_t Count, uint64_t Mispreds) { - BinaryFunction *FromFunc = getBinaryFunctionContainingAddress(From); - BinaryFunction *ToFunc = getBinaryFunctionContainingAddress(To); + auto handleAddress = [&](uint64_t &Addr, bool IsFrom) -> BinaryFunction * { + if (BinaryFunction *Func = getBinaryFunctionContainingAddress(Addr)) { + Addr -= Func->getAddress(); + + if (BAT) + Addr = BAT->translate(Func->getAddress(), Addr, IsFrom); + + if (BinaryFunction *ParentFunc = getBATParentFunction(*Func)) { + Func = ParentFunc; + if (IsFrom) + NumColdSamples += Count; + } + + return Func; + } + return nullptr; + }; + + BinaryFunction *FromFunc = handleAddress(From, /*IsFrom=*/true); + BinaryFunction *ToFunc = handleAddress(To, /*IsFrom=*/false); if (!FromFunc && !ToFunc) return false; // Treat recursive control transfers as inter-branches. - if (FromFunc == ToFunc && (To != ToFunc->getAddress())) { - recordBranch(*FromFunc, From - FromFunc->getAddress(), - To - FromFunc->getAddress(), Count, Mispreds); + if (FromFunc == ToFunc && To != 0) { + recordBranch(*FromFunc, From, To, Count, Mispreds); return doIntraBranch(*FromFunc, From, To, Count, Mispreds); } @@ -840,9 +847,14 @@ bool DataAggregator::doTrace(const LBREntry &First, const LBREntry &Second, << FromFunc->getPrintName() << ":" << Twine::utohexstr(First.To) << " to " << Twine::utohexstr(Second.From) << ".\n"); - for (const std::pair &Pair : *FTs) - doIntraBranch(*FromFunc, Pair.first + FromFunc->getAddress(), - Pair.second + FromFunc->getAddress(), Count, false); + BinaryFunction *ParentFunc = getBATParentFunction(*FromFunc); + for (auto [From, To] : *FTs) { + if (BAT) { + From = BAT->translate(FromFunc->getAddress(), From, /*IsBranchSrc=*/true); + To = BAT->translate(FromFunc->getAddress(), To, /*IsBranchSrc=*/false); + } + doIntraBranch(ParentFunc ? *ParentFunc : *FromFunc, From, To, Count, false); + } return true; } @@ -2308,7 +2320,90 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC, if (BAT->isBATFunction(Function.getAddress())) continue; BP.Functions.emplace_back( - YAMLProfileWriter::convert(Function, /*UseDFS=*/false)); + YAMLProfileWriter::convert(Function, /*UseDFS=*/false, BAT)); + } + + for (const auto &KV : NamesToBranches) { + const StringRef FuncName = KV.first; + const FuncBranchData &Branches = KV.second; + yaml::bolt::BinaryFunctionProfile YamlBF; + BinaryData *BD = BC.getBinaryDataByName(FuncName); + assert(BD); + uint64_t FuncAddress = BD->getAddress(); + if (!BAT->isBATFunction(FuncAddress)) + continue; + BinaryFunction *BF = BC.getBinaryFunctionAtAddress(FuncAddress); + assert(BF); + YamlBF.Name = FuncName.str(); + YamlBF.Id = BF->getFunctionNumber(); + YamlBF.Hash = BAT->getBFHash(FuncAddress); + YamlBF.ExecCount = BF->getKnownExecutionCount(); + YamlBF.NumBasicBlocks = BAT->getNumBasicBlocks(FuncAddress); + const BoltAddressTranslation::BBHashMapTy &BlockMap = + BAT->getBBHashMap(FuncAddress); + YamlBF.Blocks.resize(YamlBF.NumBasicBlocks); + + for (auto &&[Idx, YamlBB] : llvm::enumerate(YamlBF.Blocks)) + YamlBB.Index = Idx; + + for (auto BI = BlockMap.begin(), BE = BlockMap.end(); BI != BE; ++BI) + YamlBF.Blocks[BI->second.getBBIndex()].Hash = BI->second.getBBHash(); + + auto getSuccessorInfo = [&](uint32_t SuccOffset, unsigned SuccDataIdx) { + const llvm::bolt::BranchInfo &BI = Branches.Data.at(SuccDataIdx); + yaml::bolt::SuccessorInfo SI; + SI.Index = BlockMap.getBBIndex(SuccOffset); + SI.Count = BI.Branches; + SI.Mispreds = BI.Mispreds; + return SI; + }; + + auto getCallSiteInfo = [&](Location CallToLoc, unsigned CallToIdx, + uint32_t Offset) { + const llvm::bolt::BranchInfo &BI = Branches.Data.at(CallToIdx); + yaml::bolt::CallSiteInfo CSI; + CSI.DestId = 0; // designated for unknown functions + CSI.EntryDiscriminator = 0; + CSI.Count = BI.Branches; + CSI.Mispreds = BI.Mispreds; + CSI.Offset = Offset; + if (BinaryData *BD = BC.getBinaryDataByName(CallToLoc.Name)) + YAMLProfileWriter::setCSIDestination(BC, CSI, BD->getSymbol(), BAT, + CallToLoc.Offset); + return CSI; + }; + + for (const auto &[FromOffset, SuccKV] : Branches.IntraIndex) { + if (!BlockMap.isInputBlock(FromOffset)) + continue; + const unsigned Index = BlockMap.getBBIndex(FromOffset); + yaml::bolt::BinaryBasicBlockProfile &YamlBB = YamlBF.Blocks[Index]; + for (const auto &[SuccOffset, SuccDataIdx] : SuccKV) + if (BlockMap.isInputBlock(SuccOffset)) + YamlBB.Successors.emplace_back( + getSuccessorInfo(SuccOffset, SuccDataIdx)); + } + for (const auto &[FromOffset, CallTo] : Branches.InterIndex) { + auto BlockIt = BlockMap.upper_bound(FromOffset); + --BlockIt; + const unsigned BlockOffset = BlockIt->first; + const unsigned BlockIndex = BlockIt->second.getBBIndex(); + yaml::bolt::BinaryBasicBlockProfile &YamlBB = YamlBF.Blocks[BlockIndex]; + const uint32_t Offset = FromOffset - BlockOffset; + for (const auto &[CallToLoc, CallToIdx] : CallTo) + YamlBB.CallSites.emplace_back( + getCallSiteInfo(CallToLoc, CallToIdx, Offset)); + llvm::sort(YamlBB.CallSites, [](yaml::bolt::CallSiteInfo &A, + yaml::bolt::CallSiteInfo &B) { + return A.Offset < B.Offset; + }); + } + // Drop blocks without a hash, won't be useful for stale matching. + llvm::erase_if(YamlBF.Blocks, + [](const yaml::bolt::BinaryBasicBlockProfile &YamlBB) { + return YamlBB.Hash == (yaml::Hex64)0; + }); + BP.Functions.emplace_back(YamlBF); } } diff --git a/bolt/lib/Profile/DataReader.cpp b/bolt/lib/Profile/DataReader.cpp index aa21eb121ad65256695dfff0318058879c0b203c..67f357fe4d3f0c42f704a52ca163e328652e7136 100644 --- a/bolt/lib/Profile/DataReader.cpp +++ b/bolt/lib/Profile/DataReader.cpp @@ -18,7 +18,6 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/Errc.h" -#include #undef DEBUG_TYPE #define DEBUG_TYPE "bolt-prof" diff --git a/bolt/lib/Profile/Heatmap.cpp b/bolt/lib/Profile/Heatmap.cpp index 13541f6f6a4b64200429bf02ce2885d1e373835a..210a5cc98c1041035e7eb470d6a62fa1b2739873 100644 --- a/bolt/lib/Profile/Heatmap.cpp +++ b/bolt/lib/Profile/Heatmap.cpp @@ -10,7 +10,6 @@ #include "bolt/Utils/CommandLineOpts.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" diff --git a/bolt/lib/Profile/YAMLProfileWriter.cpp b/bolt/lib/Profile/YAMLProfileWriter.cpp index 6fcc4a956fa1a19400f9159c38d22686816102c7..ef04ba0d21ad75cf29421c24922738e9f0cba1d9 100644 --- a/bolt/lib/Profile/YAMLProfileWriter.cpp +++ b/bolt/lib/Profile/YAMLProfileWriter.cpp @@ -9,6 +9,7 @@ #include "bolt/Profile/YAMLProfileWriter.h" #include "bolt/Core/BinaryBasicBlock.h" #include "bolt/Core/BinaryFunction.h" +#include "bolt/Profile/BoltAddressTranslation.h" #include "bolt/Profile/ProfileReaderBase.h" #include "bolt/Rewrite/RewriteInstance.h" #include "llvm/Support/CommandLine.h" @@ -25,8 +26,30 @@ extern llvm::cl::opt ProfileUseDFS; namespace llvm { namespace bolt { +const BinaryFunction *YAMLProfileWriter::setCSIDestination( + const BinaryContext &BC, yaml::bolt::CallSiteInfo &CSI, + const MCSymbol *Symbol, const BoltAddressTranslation *BAT, + uint32_t Offset) { + CSI.DestId = 0; // designated for unknown functions + CSI.EntryDiscriminator = 0; + + if (Symbol) { + uint64_t EntryID = 0; + if (const BinaryFunction *Callee = + BC.getFunctionForSymbol(Symbol, &EntryID)) { + if (BAT && BAT->isBATFunction(Callee->getAddress())) + std::tie(Callee, EntryID) = BAT->translateSymbol(BC, *Symbol, Offset); + CSI.DestId = Callee->getFunctionNumber(); + CSI.EntryDiscriminator = EntryID; + return Callee; + } + } + return nullptr; +} + yaml::bolt::BinaryFunctionProfile -YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS) { +YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS, + const BoltAddressTranslation *BAT) { yaml::bolt::BinaryFunctionProfile YamlBF; const BinaryContext &BC = BF.getBinaryContext(); @@ -79,31 +102,21 @@ YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS) { continue; for (const IndirectCallProfile &CSP : ICSP.get()) { StringRef TargetName = ""; - CSI.DestId = 0; // designated for unknown functions - CSI.EntryDiscriminator = 0; - if (CSP.Symbol) { - const BinaryFunction *Callee = BC.getFunctionForSymbol(CSP.Symbol); - if (Callee) { - CSI.DestId = Callee->getFunctionNumber(); - TargetName = Callee->getOneName(); - } - } + const BinaryFunction *Callee = + setCSIDestination(BC, CSI, CSP.Symbol, BAT); + if (Callee) + TargetName = Callee->getOneName(); CSI.Count = CSP.Count; CSI.Mispreds = CSP.Mispreds; CSTargets.emplace_back(TargetName, CSI); } } else { // direct call or a tail call - uint64_t EntryID = 0; - CSI.DestId = 0; StringRef TargetName = ""; const MCSymbol *CalleeSymbol = BC.MIB->getTargetSymbol(Instr); const BinaryFunction *const Callee = - BC.getFunctionForSymbol(CalleeSymbol, &EntryID); - if (Callee) { - CSI.DestId = Callee->getFunctionNumber(); - CSI.EntryDiscriminator = EntryID; + setCSIDestination(BC, CSI, CalleeSymbol, BAT); + if (Callee) TargetName = Callee->getOneName(); - } auto getAnnotationWithDefault = [&](const MCInst &Inst, StringRef Ann) { return BC.MIB->getAnnotationWithDefault(Instr, Ann, 0ull); diff --git a/bolt/lib/Rewrite/BinaryPassManager.cpp b/bolt/lib/Rewrite/BinaryPassManager.cpp index 489b33fe1c7c201aa11b07f76d5d369170b9ef02..be4888ccfa56457fe2f59dcee91abdd05b947021 100644 --- a/bolt/lib/Rewrite/BinaryPassManager.cpp +++ b/bolt/lib/Rewrite/BinaryPassManager.cpp @@ -72,7 +72,7 @@ static cl::opt JTFootprintReductionFlag( "instructions at jump sites"), cl::cat(BoltOptCategory)); -static cl::opt +cl::opt KeepNops("keep-nops", cl::desc("keep no-op instructions. By default they are removed."), cl::Hidden, cl::cat(BoltOptCategory)); @@ -377,8 +377,9 @@ Error BinaryFunctionPassManager::runAllPasses(BinaryContext &BC) { Manager.registerPass(std::make_unique(PrintNormalized)); - Manager.registerPass(std::make_unique(NeverPrint), - opts::StripRepRet); + if (BC.isX86()) + Manager.registerPass(std::make_unique(NeverPrint), + opts::StripRepRet); Manager.registerPass(std::make_unique(PrintICF), opts::ICF); diff --git a/bolt/lib/Rewrite/DWARFRewriter.cpp b/bolt/lib/Rewrite/DWARFRewriter.cpp index 8dc7b90a6e307e72f22b3c8053859cadeaa823d1..feeba89a40dc4d03c48b3836c0e27fa5f68903d7 100644 --- a/bolt/lib/Rewrite/DWARFRewriter.cpp +++ b/bolt/lib/Rewrite/DWARFRewriter.cpp @@ -14,7 +14,6 @@ #include "bolt/Core/DynoStats.h" #include "bolt/Core/ParallelUtilities.h" #include "bolt/Rewrite/RewriteInstance.h" -#include "bolt/Utils/Utils.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -375,12 +374,11 @@ static cl::opt AlwaysConvertToRanges( extern cl::opt CompDirOverride; } // namespace opts -static bool getLowAndHighPC(const DIE &Die, const DWARFUnit &DU, - uint64_t &LowPC, uint64_t &HighPC, - uint64_t &SectionIndex) { +/// If DW_AT_low_pc exists sets LowPC and returns true. +static bool getLowPC(const DIE &Die, const DWARFUnit &DU, uint64_t &LowPC, + uint64_t &SectionIndex) { DIEValue DvalLowPc = Die.findAttribute(dwarf::DW_AT_low_pc); - DIEValue DvalHighPc = Die.findAttribute(dwarf::DW_AT_high_pc); - if (!DvalLowPc || !DvalHighPc) + if (!DvalLowPc) return false; dwarf::Form Form = DvalLowPc.getForm(); @@ -403,14 +401,39 @@ static bool getLowAndHighPC(const DIE &Die, const DWARFUnit &DU, LowPC = LowPcValue; SectionIndex = 0; } + return true; +} + +/// If DW_AT_high_pc exists sets HighPC and returns true. +static bool getHighPC(const DIE &Die, const uint64_t LowPC, uint64_t &HighPC) { + DIEValue DvalHighPc = Die.findAttribute(dwarf::DW_AT_high_pc); + if (!DvalHighPc) + return false; if (DvalHighPc.getForm() == dwarf::DW_FORM_addr) HighPC = DvalHighPc.getDIEInteger().getValue(); else HighPC = LowPC + DvalHighPc.getDIEInteger().getValue(); - return true; } +/// If DW_AT_low_pc and DW_AT_high_pc exist sets LowPC and HighPC and returns +/// true. +static bool getLowAndHighPC(const DIE &Die, const DWARFUnit &DU, + uint64_t &LowPC, uint64_t &HighPC, + uint64_t &SectionIndex) { + uint64_t TempLowPC = LowPC; + uint64_t TempHighPC = HighPC; + uint64_t TempSectionIndex = SectionIndex; + if (getLowPC(Die, DU, TempLowPC, TempSectionIndex) && + getHighPC(Die, TempLowPC, TempHighPC)) { + LowPC = TempLowPC; + HighPC = TempHighPC; + SectionIndex = TempSectionIndex; + return true; + } + return false; +} + static Expected getDIEAddressRanges(const DIE &Die, DWARFUnit &DU) { uint64_t LowPC, HighPC, Index; @@ -1248,10 +1271,9 @@ void DWARFRewriter::updateUnitDebugInfo( } } } else if (LowPCAttrInfo) { - const std::optional Result = - LowPCAttrInfo.getDIEInteger().getValue(); - if (Result.has_value()) { - const uint64_t Address = Result.value(); + uint64_t Address = 0; + uint64_t SectionIndex = 0; + if (getLowPC(*Die, Unit, Address, SectionIndex)) { uint64_t NewAddress = 0; if (const BinaryFunction *Function = BC.getBinaryFunctionContainingAddress(Address)) { @@ -1662,7 +1684,7 @@ namespace { std::unique_ptr createDwarfOnlyBC(const object::ObjectFile &File) { return cantFail(BinaryContext::createBinaryContext( - &File, false, + File.makeTriple(), File.getFileName(), nullptr, false, DWARFContext::create(File, DWARFContext::ProcessDebugRelocations::Ignore, nullptr, "", WithColor::defaultErrorHandler, WithColor::defaultWarningHandler), diff --git a/bolt/lib/Rewrite/JITLinkLinker.cpp b/bolt/lib/Rewrite/JITLinkLinker.cpp index 66e129bf1d05db7a8136a6c1ae819e4d69315ae5..be8f9dd03467e17d297b26e94bafbbabcde68c1c 100644 --- a/bolt/lib/Rewrite/JITLinkLinker.cpp +++ b/bolt/lib/Rewrite/JITLinkLinker.cpp @@ -5,9 +5,11 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// + #include "bolt/Rewrite/JITLinkLinker.h" +#include "bolt/Core/BinaryContext.h" #include "bolt/Core/BinaryData.h" -#include "bolt/Rewrite/RewriteInstance.h" +#include "bolt/Core/BinarySection.h" #include "llvm/ExecutionEngine/JITLink/ELF_riscv.h" #include "llvm/ExecutionEngine/JITLink/JITLink.h" #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" diff --git a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp index b028a455a6db526b81d56cc6d73b2fed737ca91f..d96199e020d31a159c9505d846a3985d9df2223c 100644 --- a/bolt/lib/Rewrite/LinuxKernelRewriter.cpp +++ b/bolt/lib/Rewrite/LinuxKernelRewriter.cpp @@ -212,6 +212,11 @@ class LinuxKernelRewriter final : public MetadataRewriter { /// Size of bug_entry struct. static constexpr size_t BUG_TABLE_ENTRY_SIZE = 12; + /// List of bug entries per function. + using FunctionBugListType = + DenseMap>; + FunctionBugListType FunctionBugList; + /// .pci_fixup section. ErrorOr PCIFixupSection = std::errc::bad_address; static constexpr size_t PCI_FIXUP_ENTRY_SIZE = 16; @@ -252,11 +257,19 @@ class LinuxKernelRewriter final : public MetadataRewriter { /// Paravirtual instruction patch sites. Error readParaInstructions(); + Error rewriteParaInstructions(); + /// __bug_table section handling. Error readBugTable(); + Error rewriteBugTable(); + + /// Do no process functions containing instruction annotated with + /// \p Annotation. + void skipFunctionsWithAnnotation(StringRef Annotation) const; - /// Read alternative instruction info from .altinstructions. + /// Handle alternative instruction info from .altinstructions. Error readAltInstructions(); + Error rewriteAltInstructions(); /// Read .pci_fixup Error readPCIFixupTable(); @@ -318,6 +331,12 @@ public: if (Error E = rewriteExceptionTable()) return E; + if (Error E = rewriteAltInstructions()) + return E; + + if (Error E = rewriteParaInstructions()) + return E; + if (Error E = rewriteORCTables()) return E; @@ -327,6 +346,9 @@ public: if (Error E = rewriteStaticKeysJumpTable()) return E; + if (Error E = rewriteBugTable()) + return E; + return Error::success(); } @@ -1126,16 +1148,43 @@ Error LinuxKernelRewriter::readParaInstructions() { return Error::success(); } +void LinuxKernelRewriter::skipFunctionsWithAnnotation( + StringRef Annotation) const { + for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) { + if (!BC.shouldEmit(BF)) + continue; + for (const BinaryBasicBlock &BB : BF) { + const bool HasAnnotation = llvm::any_of(BB, [&](const MCInst &Inst) { + return BC.MIB->hasAnnotation(Inst, Annotation); + }); + if (HasAnnotation) { + BF.setSimple(false); + break; + } + } + } +} + +Error LinuxKernelRewriter::rewriteParaInstructions() { + // Disable output of functions with paravirtual instructions before the + // rewrite support is complete. + skipFunctionsWithAnnotation("ParaSite"); + + return Error::success(); +} + /// Process __bug_table section. -/// This section contains information useful for kernel debugging. +/// This section contains information useful for kernel debugging, mostly +/// utilized by WARN()/WARN_ON() macros and deprecated BUG()/BUG_ON(). +/// /// Each entry in the section is a struct bug_entry that contains a pointer to /// the ud2 instruction corresponding to the bug, corresponding file name (both /// pointers use PC relative offset addressing), line number, and flags. /// The definition of the struct bug_entry can be found in -/// `include/asm-generic/bug.h` -/// -/// NB: find_bug() uses linear search to match an address to an entry in the bug -/// table. Hence there is no need to sort entries when rewriting the table. +/// `include/asm-generic/bug.h`. The first entry in the struct is an instruction +/// address encoded as a PC-relative offset. In theory, it could be an absolute +/// address if CONFIG_GENERIC_BUG_RELATIVE_POINTERS is not set, but in practice +/// the kernel code relies on it being a relative offset on x86-64. Error LinuxKernelRewriter::readBugTable() { BugTableSection = BC.getUniqueSectionByName("__bug_table"); if (!BugTableSection) @@ -1178,6 +1227,8 @@ Error LinuxKernelRewriter::readBugTable() { " referenced by bug table entry %d", InstAddress, EntryID); BC.MIB->addAnnotation(*Inst, "BugEntry", EntryID); + + FunctionBugList[BF].push_back(EntryID); } } @@ -1186,6 +1237,52 @@ Error LinuxKernelRewriter::readBugTable() { return Error::success(); } +/// find_bug() uses linear search to match an address to an entry in the bug +/// table. Hence, there is no need to sort entries when rewriting the table. +/// When we need to erase an entry, we set its instruction address to zero. +Error LinuxKernelRewriter::rewriteBugTable() { + if (!BugTableSection) + return Error::success(); + + for (BinaryFunction &BF : llvm::make_second_range(BC.getBinaryFunctions())) { + if (!BC.shouldEmit(BF)) + continue; + + if (!FunctionBugList.count(&BF)) + continue; + + // Bugs that will be emitted for this function. + DenseSet EmittedIDs; + for (BinaryBasicBlock &BB : BF) { + for (MCInst &Inst : BB) { + if (!BC.MIB->hasAnnotation(Inst, "BugEntry")) + continue; + const uint32_t ID = BC.MIB->getAnnotationAs(Inst, "BugEntry"); + EmittedIDs.insert(ID); + + // Create a relocation entry for this bug entry. + MCSymbol *Label = + BC.MIB->getOrCreateInstLabel(Inst, "__BUG_", BC.Ctx.get()); + const uint64_t EntryOffset = (ID - 1) * BUG_TABLE_ENTRY_SIZE; + BugTableSection->addRelocation(EntryOffset, Label, ELF::R_X86_64_PC32, + /*Addend*/ 0); + } + } + + // Clear bug entries that were not emitted for this function, e.g. as a + // result of DCE, but setting their instruction address to zero. + for (const uint32_t ID : FunctionBugList[&BF]) { + if (!EmittedIDs.count(ID)) { + const uint64_t EntryOffset = (ID - 1) * BUG_TABLE_ENTRY_SIZE; + BugTableSection->addRelocation(EntryOffset, nullptr, ELF::R_X86_64_PC32, + /*Addend*/ 0); + } + } + } + + return Error::success(); +} + /// The kernel can replace certain instruction sequences depending on hardware /// it is running on and features specified during boot time. The information /// about alternative instruction sequences is stored in .altinstructions @@ -1305,6 +1402,14 @@ Error LinuxKernelRewriter::readAltInstructions() { return Error::success(); } +Error LinuxKernelRewriter::rewriteAltInstructions() { + // Disable output of functions with alt instructions before the rewrite + // support is complete. + skipFunctionsWithAnnotation("AltInst"); + + return Error::success(); +} + /// When the Linux kernel needs to handle an error associated with a given PCI /// device, it uses a table stored in .pci_fixup section to locate a fixup code /// specific to the vendor and the problematic device. The section contains a @@ -1679,6 +1784,8 @@ Error LinuxKernelRewriter::updateStaticKeysJumpTablePostEmit() { << "\n\tTargetAddress: 0x" << Twine::utohexstr(TargetAddress) << "\n\tKeyAddress: 0x" << Twine::utohexstr(KeyAddress) << '\n'; }); + (void)TargetAddress; + (void)KeyAddress; BinaryFunction *BF = BC.getBinaryFunctionContainingAddress(JumpAddress, diff --git a/bolt/lib/Rewrite/MachORewriteInstance.cpp b/bolt/lib/Rewrite/MachORewriteInstance.cpp index 0970a0507ebe8803e6ae85789b8ec10618465211..172cb640bf911a96e11c3112b007cd1636479867 100644 --- a/bolt/lib/Rewrite/MachORewriteInstance.cpp +++ b/bolt/lib/Rewrite/MachORewriteInstance.cpp @@ -18,6 +18,7 @@ #include "bolt/Rewrite/BinaryPassManager.h" #include "bolt/Rewrite/ExecutableFileMemoryManager.h" #include "bolt/Rewrite/JITLinkLinker.h" +#include "bolt/Rewrite/RewriteInstance.h" #include "bolt/RuntimeLibs/InstrumentationRuntimeLibrary.h" #include "bolt/Utils/Utils.h" #include "llvm/MC/MCObjectStreamer.h" @@ -54,37 +55,6 @@ extern cl::opt Verbosity; namespace llvm { namespace bolt { -extern MCPlusBuilder *createX86MCPlusBuilder(const MCInstrAnalysis *, - const MCInstrInfo *, - const MCRegisterInfo *, - const MCSubtargetInfo *); -extern MCPlusBuilder *createAArch64MCPlusBuilder(const MCInstrAnalysis *, - const MCInstrInfo *, - const MCRegisterInfo *, - const MCSubtargetInfo *); - -namespace { - -MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch, - const MCInstrAnalysis *Analysis, - const MCInstrInfo *Info, - const MCRegisterInfo *RegInfo, - const MCSubtargetInfo *STI) { -#ifdef X86_AVAILABLE - if (Arch == Triple::x86_64) - return createX86MCPlusBuilder(Analysis, Info, RegInfo, STI); -#endif - -#ifdef AARCH64_AVAILABLE - if (Arch == Triple::aarch64) - return createAArch64MCPlusBuilder(Analysis, Info, RegInfo, STI); -#endif - - llvm_unreachable("architecture unsupported by MCPlusBuilder"); -} - -} // anonymous namespace - #define DEBUG_TYPE "bolt" Expected> @@ -103,7 +73,8 @@ MachORewriteInstance::MachORewriteInstance(object::MachOObjectFile *InputFile, : InputFile(InputFile), ToolPath(ToolPath) { ErrorAsOutParameter EAO(&Err); auto BCOrErr = BinaryContext::createBinaryContext( - InputFile, /* IsPIC */ true, DWARFContext::create(*InputFile), + InputFile->makeTriple(), InputFile->getFileName(), nullptr, + /* IsPIC */ true, DWARFContext::create(*InputFile), {llvm::outs(), llvm::errs()}); if (Error E = BCOrErr.takeError()) { Err = std::move(E); diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp index 03f4298e817d179a80e6b1de268630ec1227ad73..eea66454b289c284de8ba3da6f4ffb4c9a6d2132 100644 --- a/bolt/lib/Rewrite/RewriteInstance.cpp +++ b/bolt/lib/Rewrite/RewriteInstance.cpp @@ -81,8 +81,10 @@ extern cl::list HotTextMoveSections; extern cl::opt Hugify; extern cl::opt Instrument; extern cl::opt JumpTables; +extern cl::opt KeepNops; extern cl::list ReorderData; extern cl::opt ReorderFunctions; +extern cl::opt TerminalTrap; extern cl::opt TimeBuild; cl::opt AllowStripped("allow-stripped", @@ -266,6 +268,10 @@ namespace bolt { extern const char *BoltRevision; +// Weird location for createMCPlusBuilder, but this is here to avoid a +// cyclic dependency of libCore (its natural place) and libTarget. libRewrite +// can depend on libTarget, but not libCore. Since libRewrite is the only +// user of this function, we define it here. MCPlusBuilder *createMCPlusBuilder(const Triple::ArchType Arch, const MCInstrAnalysis *Analysis, const MCInstrInfo *Info, @@ -343,8 +349,21 @@ RewriteInstance::RewriteInstance(ELFObjectFileBase *File, const int Argc, Stderr.SetUnbuffered(); LLVM_DEBUG(dbgs().SetUnbuffered()); + // Read RISCV subtarget features from input file + std::unique_ptr Features; + Triple TheTriple = File->makeTriple(); + if (TheTriple.getArch() == llvm::Triple::riscv64) { + Expected FeaturesOrErr = File->getFeatures(); + if (auto E = FeaturesOrErr.takeError()) { + Err = std::move(E); + return; + } else { + Features.reset(new SubtargetFeatures(*FeaturesOrErr)); + } + } + auto BCOrErr = BinaryContext::createBinaryContext( - File, IsPIC, + TheTriple, File->getFileName(), Features.get(), IsPIC, DWARFContext::create(*File, DWARFContext::ProcessDebugRelocations::Ignore, nullptr, opts::DWPPathName, WithColor::defaultErrorHandler, @@ -537,7 +556,7 @@ Error RewriteInstance::discoverStorage() { if (Error E = SectionNameOrErr.takeError()) return E; StringRef SectionName = SectionNameOrErr.get(); - if (SectionName == ".text") { + if (SectionName == BC->getMainCodeSectionName()) { BC->OldTextSectionAddress = Section.getAddress(); BC->OldTextSectionSize = Section.getSize(); @@ -1845,7 +1864,8 @@ Error RewriteInstance::readSpecialSections() { "Use -update-debug-sections to keep it.\n"; } - HasTextRelocations = (bool)BC->getUniqueSectionByName(".rela.text"); + HasTextRelocations = (bool)BC->getUniqueSectionByName( + ".rela" + std::string(BC->getMainCodeSectionName())); HasSymbolTable = (bool)BC->getUniqueSectionByName(".symtab"); EHFrameSection = BC->getUniqueSectionByName(".eh_frame"); BuildIDSection = BC->getUniqueSectionByName(".note.gnu.build-id"); @@ -2031,6 +2051,15 @@ void RewriteInstance::adjustCommandLineOptions() { if (opts::Lite) BC->outs() << "BOLT-INFO: enabling lite mode\n"; + + if (BC->IsLinuxKernel) { + if (!opts::KeepNops.getNumOccurrences()) + opts::KeepNops = true; + + // Linux kernel may resume execution after a trap instruction in some cases. + if (!opts::TerminalTrap.getNumOccurrences()) + opts::TerminalTrap = false; + } } namespace { @@ -3413,7 +3442,8 @@ void RewriteInstance::emitAndLink() { ErrorOr TextSection = BC->getUniqueSectionByName(BC->getMainCodeSectionName()); if (BC->HasRelocations && TextSection) - BC->renameSection(*TextSection, getOrgSecPrefix() + ".text"); + BC->renameSection(*TextSection, + getOrgSecPrefix() + BC->getMainCodeSectionName()); ////////////////////////////////////////////////////////////////////////////// // Assign addresses to new sections. @@ -4389,6 +4419,7 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile *File) { raw_fd_ostream &OS = Out->os(); const ELFFile &Obj = File->getELFFile(); + // Mapping from old section indices to new ones std::vector NewSectionIndex; std::vector OutputSections = getOutputSections(File, NewSectionIndex); @@ -4406,10 +4437,8 @@ void RewriteInstance::patchELFSectionHeaderTable(ELFObjectFile *File) { // Write all section header entries while patching section references. for (ELFShdrTy &Section : OutputSections) { Section.sh_link = NewSectionIndex[Section.sh_link]; - if (Section.sh_type == ELF::SHT_REL || Section.sh_type == ELF::SHT_RELA) { - if (Section.sh_info) - Section.sh_info = NewSectionIndex[Section.sh_info]; - } + if (Section.sh_type == ELF::SHT_REL || Section.sh_type == ELF::SHT_RELA) + Section.sh_info = NewSectionIndex[Section.sh_info]; OS.write(reinterpret_cast(&Section), sizeof(Section)); } diff --git a/bolt/lib/RuntimeLibs/HugifyRuntimeLibrary.cpp b/bolt/lib/RuntimeLibs/HugifyRuntimeLibrary.cpp index b6fc49d3f5d671b8a0205961f2aace7e39253418..d114d70f2d37668df5c39cf31a154126e537a109 100644 --- a/bolt/lib/RuntimeLibs/HugifyRuntimeLibrary.cpp +++ b/bolt/lib/RuntimeLibs/HugifyRuntimeLibrary.cpp @@ -11,10 +11,9 @@ //===----------------------------------------------------------------------===// #include "bolt/RuntimeLibs/HugifyRuntimeLibrary.h" -#include "bolt/Core/BinaryFunction.h" +#include "bolt/Core/BinaryContext.h" #include "bolt/Core/Linker.h" #include "llvm/MC/MCStreamer.h" -#include "llvm/Support/Alignment.h" #include "llvm/Support/CommandLine.h" using namespace llvm; diff --git a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp index ab9623d5c51b287f4a1e6e58e1ff0784eb6508a7..74f2f0aae91e667d12d6edff81f371c1e1044bfe 100644 --- a/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp +++ b/bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp @@ -16,10 +16,7 @@ #include "llvm/BinaryFormat/ELF.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCSubtargetInfo.h" -#include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/raw_ostream.h" #define DEBUG_TYPE "mcplus" diff --git a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp index 15f95f8217776514ffc7253f0da7b840607a6668..8b1894953f3757f036aa2d7e58f2f033861b0efd 100644 --- a/bolt/lib/Target/X86/X86MCPlusBuilder.cpp +++ b/bolt/lib/Target/X86/X86MCPlusBuilder.cpp @@ -211,13 +211,6 @@ public: return false; } - // FIXME: For compatibility with old LLVM only! - bool isTerminator(const MCInst &Inst) const override { - unsigned Opcode = Inst.getOpcode(); - return Info->get(Opcode).isTerminator() || X86::isUD1(Opcode) || - X86::isUD2(Opcode); - } - bool isIndirectCall(const MCInst &Inst) const override { return isCall(Inst) && ((getMemoryOperandNo(Inst) != -1) || Inst.getOperand(0).isReg()); diff --git a/bolt/test/X86/bolt-address-translation-yaml.test b/bolt/test/X86/bolt-address-translation-yaml.test index 25ff4e7fbfcc5738705756caea3efc3d7aeb2ef5..af24c3d84a0f15f9f8d68eabf7b42daac3e39e69 100644 --- a/bolt/test/X86/bolt-address-translation-yaml.test +++ b/bolt/test/X86/bolt-address-translation-yaml.test @@ -18,13 +18,14 @@ RUN: | FileCheck --check-prefix CHECK-BOLT-YAML %s WRITE-BAT-CHECK: BOLT-INFO: Wrote 5 BAT maps WRITE-BAT-CHECK: BOLT-INFO: Wrote 4 function and 22 basic block hashes -WRITE-BAT-CHECK: BOLT-INFO: BAT section size (bytes): 344 +WRITE-BAT-CHECK: BOLT-INFO: BAT section size (bytes): 384 READ-BAT-CHECK-NOT: BOLT-ERROR: unable to save profile in YAML format for input file processed by BOLT READ-BAT-CHECK: BOLT-INFO: Parsed 5 BAT entries READ-BAT-CHECK: PERF2BOLT: read 79 aggregated LBR entries YAML-BAT-CHECK: functions: +# Function not covered by BAT - has insns in basic block YAML-BAT-CHECK: - name: main YAML-BAT-CHECK-NEXT: fid: 2 YAML-BAT-CHECK-NEXT: hash: 0x9895746D48B2C876 @@ -35,6 +36,34 @@ YAML-BAT-CHECK-NEXT: - bid: 0 YAML-BAT-CHECK-NEXT: insns: 26 YAML-BAT-CHECK-NEXT: hash: 0xA900AE79CFD40000 YAML-BAT-CHECK-NEXT: succ: [ { bid: 3, cnt: 0 }, { bid: 1, cnt: 0 } ] +# Calls from no-BAT to BAT function +YAML-BAT-CHECK: - bid: 28 +YAML-BAT-CHECK-NEXT: insns: 13 +YAML-BAT-CHECK-NEXT: hash: 0xB2F04C1F25F00400 +YAML-BAT-CHECK-NEXT: calls: [ { off: 0x21, fid: [[#SOLVECUBIC:]], cnt: 25 }, { off: 0x2D, fid: [[#]], cnt: 9 } ] +# Function covered by BAT with calls +YAML-BAT-CHECK: - name: SolveCubic +YAML-BAT-CHECK-NEXT: fid: [[#SOLVECUBIC]] +YAML-BAT-CHECK-NEXT: hash: 0x6AF7E61EA3966722 +YAML-BAT-CHECK-NEXT: exec: 25 +YAML-BAT-CHECK-NEXT: nblocks: 15 +YAML-BAT-CHECK-NEXT: blocks: +YAML-BAT-CHECK: - bid: 3 +YAML-BAT-CHECK-NEXT: insns: [[#]] +YAML-BAT-CHECK-NEXT: hash: 0xDDA1DC5F69F900AC +YAML-BAT-CHECK-NEXT: calls: [ { off: 0x26, fid: [[#]], cnt: [[#]] } ] +YAML-BAT-CHECK-NEXT: succ: [ { bid: 5, cnt: [[#]] } +# Function covered by BAT - doesn't have insns in basic block +YAML-BAT-CHECK: - name: usqrt +YAML-BAT-CHECK-NEXT: fid: [[#]] +YAML-BAT-CHECK-NEXT: hash: 0x99E67ED32A203023 +YAML-BAT-CHECK-NEXT: exec: 21 +YAML-BAT-CHECK-NEXT: nblocks: 5 +YAML-BAT-CHECK-NEXT: blocks: +YAML-BAT-CHECK: - bid: 1 +YAML-BAT-CHECK-NEXT: insns: [[#]] +YAML-BAT-CHECK-NEXT: hash: 0xD70DC695320E0010 +YAML-BAT-CHECK-NEXT: succ: {{.*}} { bid: 2, cnt: [[#]] } CHECK-BOLT-YAML: pre-processing profile using YAML profile reader -CHECK-BOLT-YAML-NEXT: 1 out of 16 functions in the binary (6.2%) have non-empty execution profile +CHECK-BOLT-YAML-NEXT: 5 out of 16 functions in the binary (31.2%) have non-empty execution profile diff --git a/bolt/test/X86/bolt-address-translation.test b/bolt/test/X86/bolt-address-translation.test index 4277b4e0d0fef0ca4fb6cee51124544d70c2e4de..63234b4c1d21851f447fa804669e780774a6e9c8 100644 --- a/bolt/test/X86/bolt-address-translation.test +++ b/bolt/test/X86/bolt-address-translation.test @@ -37,7 +37,7 @@ # CHECK: BOLT: 3 out of 7 functions were overwritten. # CHECK: BOLT-INFO: Wrote 6 BAT maps # CHECK: BOLT-INFO: Wrote 3 function and 58 basic block hashes -# CHECK: BOLT-INFO: BAT section size (bytes): 816 +# CHECK: BOLT-INFO: BAT section size (bytes): 924 # # usqrt mappings (hot part). We match against any key (left side containing # the bolted binary offsets) because BOLT may change where it puts instructions diff --git a/bolt/test/X86/dwarf4-label-low-pc.s b/bolt/test/X86/dwarf4-label-low-pc.s new file mode 100644 index 0000000000000000000000000000000000000000..dfd5af18c09b75934fb6cac317d4d6807bcea5d4 --- /dev/null +++ b/bolt/test/X86/dwarf4-label-low-pc.s @@ -0,0 +1,263 @@ + +# REQUIRES: system-linux + +# RUN: llvm-mc -dwarf-version=4 -filetype=obj -triple x86_64-unknown-linux %s -o %tmain.o +# RUN: %clang %cflags -dwarf-4 %tmain.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections +# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.exe | FileCheck --check-prefix=PRECHECK %s +# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt > %t.txt +# RUN: llvm-objdump -d %t.bolt >> %t.txt +# RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s + +## This test checks that we correctly handle DW_AT_low_pc [DW_FORM_addr] that is part of DW_TAG_label. + +# PRECHECK: version = 0x0004 +# PRECHECK: DW_TAG_label +# PRECHECK-NEXT: DW_AT_name +# PRECHECK-NEXT: DW_AT_decl_file +# PRECHECK-NEXT: DW_AT_decl_line +# PRECHECK-NEXT:DW_AT_low_pc [DW_FORM_addr] +# PRECHECK: DW_TAG_label +# PRECHECK-NEXT: DW_AT_name +# PRECHECK-NEXT: DW_AT_decl_file +# PRECHECK-NEXT: DW_AT_decl_line +# PRECHECK-NEXT:DW_AT_low_pc [DW_FORM_addr] + +# POSTCHECK: version = 0x0004 +# POSTCHECK: DW_TAG_label +# POSTCHECK-NEXT: DW_AT_name +# POSTCHECK-NEXT: DW_AT_decl_file +# POSTCHECK-NEXT: DW_AT_decl_line +# POSTCHECK-NEXT:DW_AT_low_pc [DW_FORM_addr] (0x[[ADDR:[1-9a-f]*]] +# POSTCHECK: DW_TAG_label +# POSTCHECK-NEXT: DW_AT_name +# POSTCHECK-NEXT: DW_AT_decl_file +# POSTCHECK-NEXT: DW_AT_decl_line +# POSTCHECK-NEXT:DW_AT_low_pc [DW_FORM_addr] (0x[[ADDR2:[1-9a-f]*]] + +# POSTCHECK: [[ADDR]]: 8b 45 f8 +# POSTCHECK: [[ADDR2]]: 8b 45 f8 + +## clang++ main.cpp -g2 -gdwarf-4 -S +## int main() { +## int a = 4; +## if (a == 5) +## goto LABEL1; +## else +## goto LABEL2; +## LABEL1:a++; +## LABEL2:a--; +## return 0; +## } + + .text + .file "main.cpp" + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main +.Lfunc_begin0: + .file 1 "/home" "main.cpp" + .loc 1 1 0 # main.cpp:1:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl $0, -4(%rbp) +.Ltmp0: + .loc 1 2 7 prologue_end # main.cpp:2:7 + movl $4, -8(%rbp) +.Ltmp1: + .loc 1 3 9 # main.cpp:3:9 + cmpl $5, -8(%rbp) +.Ltmp2: + .loc 1 3 7 is_stmt 0 # main.cpp:3:7 + jne .LBB0_2 +# %bb.1: # %if.then +.Ltmp3: + .loc 1 4 5 is_stmt 1 # main.cpp:4:5 + jmp .LBB0_3 +.LBB0_2: # %if.else + .loc 1 6 5 # main.cpp:6:5 + jmp .LBB0_4 +.Ltmp4: +.LBB0_3: # %LABEL1 + #DEBUG_LABEL: main:LABEL1 + .loc 1 7 11 # main.cpp:7:11 + movl -8(%rbp), %eax + addl $1, %eax + movl %eax, -8(%rbp) +.LBB0_4: # %LABEL2 +.Ltmp5: + #DEBUG_LABEL: main:LABEL2 + .loc 1 8 11 # main.cpp:8:11 + movl -8(%rbp), %eax + addl $-1, %eax + movl %eax, -8(%rbp) + .loc 1 9 3 # main.cpp:9:3 + xorl %eax, %eax + .loc 1 9 3 epilogue_begin is_stmt 0 # main.cpp:9:3 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.Ltmp6: +.Lfunc_end0: + .size main, .Lfunc_end0-main + .cfi_endproc + # -- End function + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 14 # DW_FORM_strp + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 14 # DW_FORM_strp + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 10 # DW_TAG_label + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 17 # DW_AT_low_pc + .byte 1 # DW_FORM_addr + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 14 # DW_FORM_strp + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 4 # DWARF version number + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 8 # Address Size (in bytes) + .byte 1 # Abbrev [1] 0xb:0x6d DW_TAG_compile_unit + .long .Linfo_string0 # DW_AT_producer + .short 33 # DW_AT_language + .long .Linfo_string1 # DW_AT_name + .long .Lline_table_start0 # DW_AT_stmt_list + .long .Linfo_string2 # DW_AT_comp_dir + .quad .Lfunc_begin0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 2 # Abbrev [2] 0x2a:0x46 DW_TAG_subprogram + .quad .Lfunc_begin0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .long .Linfo_string3 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .long 112 # DW_AT_type + # DW_AT_external + .byte 3 # Abbrev [3] 0x43:0xe DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .long .Linfo_string5 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long 112 # DW_AT_type + .byte 4 # Abbrev [4] 0x51:0xf DW_TAG_label + .long .Linfo_string6 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 7 # DW_AT_decl_line + .quad .Ltmp4 # DW_AT_low_pc + .byte 4 # Abbrev [4] 0x60:0xf DW_TAG_label + .long .Linfo_string7 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 8 # DW_AT_decl_line + .quad .Ltmp5 # DW_AT_low_pc + .byte 0 # End Of Children Mark + .byte 5 # Abbrev [5] 0x70:0x7 DW_TAG_base_type + .long .Linfo_string4 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_end0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 19.0.0git" # string offset=0 +.Linfo_string1: + .asciz "main.cpp" # string offset=24 +.Linfo_string2: + .asciz "/home" # string offset=33 +.Linfo_string3: + .asciz "main" # string offset=71 +.Linfo_string4: + .asciz "int" # string offset=76 +.Linfo_string5: + .asciz "a" # string offset=80 +.Linfo_string6: + .asciz "LABEL1" # string offset=82 +.Linfo_string7: + .asciz "LABEL2" # string offset=89 + .ident "clang version 19.0.0git" + .section ".note.GNU-stack","",@progbits + .addrsig + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/dwarf5-debug-names-cross-cu.s b/bolt/test/X86/dwarf5-debug-names-cross-cu.s new file mode 100644 index 0000000000000000000000000000000000000000..73c50d6d41db09cf2976d91c71da4ed8dcaea3cd --- /dev/null +++ b/bolt/test/X86/dwarf5-debug-names-cross-cu.s @@ -0,0 +1,712 @@ + +# REQUIRES: system-linux + +# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %s -o %tmain.o +# RUN: %clang %cflags -dwarf-5 %tmain.o -o %t.exe -Wl,-q +# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections +# RUN: llvm-dwarfdump --debug-info -r 0 --debug-names %t.bolt > %t.txt +# RUN: cat %t.txt | FileCheck --check-prefix=CHECK %s + +## This test checks that BOLT generates Entries for DW_AT_abstract_origin when it has cross cu reference. + +# CHECK: [[OFFSET1:0x[0-9a-f]*]]: Compile Unit +# CHECK: [[OFFSET2:0x[0-9a-f]*]]: Compile Unit +# CHECK: Name Index @ 0x0 { +# CHECK-NEXT: Header { +# CHECK-NEXT: Length: 0xD2 +# CHECK-NEXT: Format: DWARF32 +# CHECK-NEXT: Version: 5 +# CHECK-NEXT: CU count: 2 +# CHECK-NEXT: Local TU count: 0 +# CHECK-NEXT: Foreign TU count: 0 +# CHECK-NEXT: Bucket count: 5 +# CHECK-NEXT: Name count: 5 +# CHECK-NEXT: Abbreviations table size: 0x1F +# CHECK-NEXT: Augmentation: 'BOLT' +# CHECK-NEXT: } +# CHECK-NEXT: Compilation Unit offsets [ +# CHECK-NEXT: CU[0]: [[OFFSET1]] +# CHECK-NEXT: CU[1]: [[OFFSET2]] +# CHECK-NEXT: ] +# CHECK-NEXT: Abbreviations [ +# CHECK-NEXT: Abbreviation [[ABBREV1:0x[0-9a-f]*]] { +# CHECK-NEXT: Tag: DW_TAG_subprogram +# CHECK-NEXT: DW_IDX_compile_unit: DW_FORM_data1 +# CHECK-NEXT: DW_IDX_die_offset: DW_FORM_ref4 +# CHECK-NEXT: DW_IDX_parent: DW_FORM_flag_present +# CHECK-NEXT: } +# CHECK-NEXT: Abbreviation [[ABBREV2:0x[0-9a-f]*]] { +# CHECK-NEXT: Tag: DW_TAG_inlined_subroutine +# CHECK-NEXT: DW_IDX_compile_unit: DW_FORM_data1 +# CHECK-NEXT: DW_IDX_die_offset: DW_FORM_ref4 +# CHECK-NEXT: DW_IDX_parent: DW_FORM_ref4 +# CHECK-NEXT: } +# CHECK-NEXT: Abbreviation [[ABBREV3:0x[0-9a-f]*]] { +# CHECK-NEXT: Tag: DW_TAG_base_type +# CHECK-NEXT: DW_IDX_compile_unit: DW_FORM_data1 +# CHECK-NEXT: DW_IDX_die_offset: DW_FORM_ref4 +# CHECK-NEXT: DW_IDX_parent: DW_FORM_flag_present +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: Bucket 0 [ +# CHECK-NEXT: EMPTY +# CHECK-NEXT: ] +# CHECK-NEXT: Bucket 1 [ +# CHECK-NEXT: Name 1 { +# CHECK-NEXT: Hash: 0x7C9A7F6A +# CHECK-NEXT: String: {{.+}} "main" +# CHECK-NEXT: Entry @ [[ENTRY:0x[0-9a-f]*]] { +# CHECK-NEXT: Abbrev: [[ABBREV1]] +# CHECK-NEXT: Tag: DW_TAG_subprogram +# CHECK-NEXT: DW_IDX_compile_unit: 0x00 +# CHECK-NEXT: DW_IDX_die_offset: 0x00000024 +# CHECK-NEXT: DW_IDX_parent: +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: Name 2 { +# CHECK-NEXT: Hash: 0xB5063CFE +# CHECK-NEXT: String: {{.+}} "_Z3fooi" +# CHECK-NEXT: Entry @ {{.+}} { +# CHECK-NEXT: Abbrev: [[ABBREV1]] +# CHECK-NEXT: Tag: DW_TAG_subprogram +# CHECK-NEXT: DW_IDX_compile_unit: 0x01 +# CHECK-NEXT: DW_IDX_die_offset: 0x0000003a +# CHECK-NEXT: DW_IDX_parent: +# CHECK-NEXT: } +# CHECK-NEXT: Entry @ {{.+}} { +# CHECK-NEXT: Abbrev: [[ABBREV2]] +# CHECK-NEXT: Tag: DW_TAG_inlined_subroutine +# CHECK-NEXT: DW_IDX_compile_unit: 0x00 +# CHECK-NEXT: DW_IDX_die_offset: 0x00000054 +# CHECK-NEXT: DW_IDX_parent: Entry @ [[ENTRY]] +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: Bucket 2 [ +# CHECK-NEXT: EMPTY +# CHECK-NEXT: ] +# CHECK-NEXT: Bucket 3 [ +# CHECK-NEXT: Name 3 { +# CHECK-NEXT: Hash: 0xB888030 +# CHECK-NEXT: String: {{.+}} "int" +# CHECK-NEXT: Entry @ {{.+}} { +# CHECK-NEXT: Abbrev: [[ABBREV3]] +# CHECK-NEXT: Tag: DW_TAG_base_type +# CHECK-NEXT: DW_IDX_compile_unit: 0x01 +# CHECK-NEXT: DW_IDX_die_offset: 0x00000036 +# CHECK-NEXT: DW_IDX_parent: +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: Bucket 4 [ +# CHECK-NEXT: Name 4 { +# CHECK-NEXT: Hash: 0xB887389 +# CHECK-NEXT: String: {{.+}} "foo" +# CHECK-NEXT: Entry @ {{.+}} { +# CHECK-NEXT: Abbrev: [[ABBREV1]] +# CHECK-NEXT: Tag: DW_TAG_subprogram +# CHECK-NEXT: DW_IDX_compile_unit: 0x01 +# CHECK-NEXT: DW_IDX_die_offset: 0x0000003a +# CHECK-NEXT: DW_IDX_parent: +# CHECK-NEXT: } +# CHECK-NEXT: Entry @ 0xc4 { +# CHECK-NEXT: Abbrev: [[ABBREV2]] +# CHECK-NEXT: Tag: DW_TAG_inlined_subroutine +# CHECK-NEXT: DW_IDX_compile_unit: 0x00 +# CHECK-NEXT: DW_IDX_die_offset: 0x00000054 +# CHECK-NEXT: DW_IDX_parent: Entry @ [[ENTRY]] +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: Name 5 { +# CHECK-NEXT: Hash: 0x7C952063 +# CHECK-NEXT: String: {{.+}} "char" +# CHECK-NEXT: Entry @ {{.+}} { +# CHECK-NEXT: Abbrev: [[ABBREV3]] +# CHECK-NEXT: Tag: DW_TAG_base_type +# CHECK-NEXT: DW_IDX_compile_unit: 0x00 +# CHECK-NEXT: DW_IDX_die_offset: 0x00000075 +# CHECK-NEXT: DW_IDX_parent: +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: } + +## clang++ -g2 -gpubnames -S -emit-llvm main.cpp -o main.ll +## clang++ -g2 -gpubnames -S -emit-llvm helper.cpp -o helper.ll +## llvm-link main.ll helper.ll -o combined.ll +## clang++ -g2 -gpubnames combined.ll -emit-llvm -S -o combined.opt.ll +## llc -dwarf-version=5 -filetype=asm -mtriple x86_64-unknown-linux combined.opt.ll -o combined.s +## main.cpp +## extern int foo(int); +## int main(int argc, char* argv[]) { +## int i = 0; +## [[clang::always_inline]] i = foo(argc); +## return i; +## } +## helper.cpp +## int foo(int i) { +## return i ++; +## } + + .text + .file "llvm-link" + .globl main # -- Begin function main + .p2align 4, 0x90 + .type main,@function +main: # @main +.Lfunc_begin0: + .file 1 "/home" "main.cpp" md5 0x24fb0b4c3900e91fece1ac87ed73ff3b + .loc 1 2 0 # main.cpp:2:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl $0, -16(%rbp) + movl %edi, -12(%rbp) + movq %rsi, -24(%rbp) +.Ltmp0: + .loc 1 3 7 prologue_end # main.cpp:3:7 + movl $0, -4(%rbp) + .loc 1 4 36 # main.cpp:4:36 + movl -12(%rbp), %eax + movl %eax, -8(%rbp) +.Ltmp1: + .file 2 "/home" "helper.cpp" md5 0x7d4429e24d8c74d7ee22c1889ad46d6b + .loc 2 2 12 # helper.cpp:2:12 + movl -8(%rbp), %eax + movl %eax, %ecx + addl $1, %ecx + movl %ecx, -8(%rbp) +.Ltmp2: + .loc 1 4 30 # main.cpp:4:30 + movl %eax, -4(%rbp) + .loc 1 5 10 # main.cpp:5:10 + movl -4(%rbp), %eax + .loc 1 5 3 epilogue_begin is_stmt 0 # main.cpp:5:3 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.Ltmp3: +.Lfunc_end0: + .size main, .Lfunc_end0-main + .cfi_endproc + # -- End function + .globl _Z3fooi # -- Begin function _Z3fooi + .p2align 4, 0x90 + .type _Z3fooi,@function +_Z3fooi: # @_Z3fooi +.Lfunc_begin1: + .loc 2 1 0 is_stmt 1 # helper.cpp:1:0 + .cfi_startproc +# %bb.0: # %entry + pushq %rbp + .cfi_def_cfa_offset 16 + .cfi_offset %rbp, -16 + movq %rsp, %rbp + .cfi_def_cfa_register %rbp + movl %edi, -4(%rbp) +.Ltmp4: + .loc 2 2 12 prologue_end # helper.cpp:2:12 + movl -4(%rbp), %eax + movl %eax, %ecx + addl $1, %ecx + movl %ecx, -4(%rbp) + .loc 2 2 3 epilogue_begin is_stmt 0 # helper.cpp:2:3 + popq %rbp + .cfi_def_cfa %rsp, 8 + retq +.Ltmp5: +.Lfunc_end1: + .size _Z3fooi, .Lfunc_end1-_Z3fooi + .cfi_endproc + # -- End function + .section .debug_abbrev,"",@progbits + .byte 1 # Abbreviation Code + .byte 17 # DW_TAG_compile_unit + .byte 1 # DW_CHILDREN_yes + .byte 37 # DW_AT_producer + .byte 37 # DW_FORM_strx1 + .byte 19 # DW_AT_language + .byte 5 # DW_FORM_data2 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 114 # DW_AT_str_offsets_base + .byte 23 # DW_FORM_sec_offset + .byte 16 # DW_AT_stmt_list + .byte 23 # DW_FORM_sec_offset + .byte 27 # DW_AT_comp_dir + .byte 37 # DW_FORM_strx1 + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 115 # DW_AT_addr_base + .byte 23 # DW_FORM_sec_offset + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 2 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 16 # DW_FORM_ref_addr + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 3 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 16 # DW_FORM_ref_addr + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 4 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 5 # Abbreviation Code + .byte 52 # DW_TAG_variable + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 16 # DW_FORM_ref_addr + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 6 # Abbreviation Code + .byte 29 # DW_TAG_inlined_subroutine + .byte 1 # DW_CHILDREN_yes + .byte 49 # DW_AT_abstract_origin + .byte 16 # DW_FORM_ref_addr + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 88 # DW_AT_call_file + .byte 11 # DW_FORM_data1 + .byte 89 # DW_AT_call_line + .byte 11 # DW_FORM_data1 + .byte 87 # DW_AT_call_column + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 7 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 16 # DW_FORM_ref_addr + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 8 # Abbreviation Code + .byte 15 # DW_TAG_pointer_type + .byte 0 # DW_CHILDREN_no + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 9 # Abbreviation Code + .byte 36 # DW_TAG_base_type + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 62 # DW_AT_encoding + .byte 11 # DW_FORM_data1 + .byte 11 # DW_AT_byte_size + .byte 11 # DW_FORM_data1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 10 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 110 # DW_AT_linkage_name + .byte 37 # DW_FORM_strx1 + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 63 # DW_AT_external + .byte 25 # DW_FORM_flag_present + .byte 32 # DW_AT_inline + .byte 33 # DW_FORM_implicit_const + .byte 1 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 11 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 3 # DW_AT_name + .byte 37 # DW_FORM_strx1 + .byte 58 # DW_AT_decl_file + .byte 11 # DW_FORM_data1 + .byte 59 # DW_AT_decl_line + .byte 11 # DW_FORM_data1 + .byte 73 # DW_AT_type + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 12 # Abbreviation Code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_CHILDREN_yes + .byte 17 # DW_AT_low_pc + .byte 27 # DW_FORM_addrx + .byte 18 # DW_AT_high_pc + .byte 6 # DW_FORM_data4 + .byte 64 # DW_AT_frame_base + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 13 # Abbreviation Code + .byte 5 # DW_TAG_formal_parameter + .byte 0 # DW_CHILDREN_no + .byte 2 # DW_AT_location + .byte 24 # DW_FORM_exprloc + .byte 49 # DW_AT_abstract_origin + .byte 19 # DW_FORM_ref4 + .byte 0 # EOM(1) + .byte 0 # EOM(2) + .byte 0 # EOM(3) + .section .debug_info,"",@progbits +.Lcu_begin0: + .long .Ldebug_info_end0-.Ldebug_info_start0 # Length of Unit +.Ldebug_info_start0: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 1 # Abbrev [1] 0xc:0x6d DW_TAG_compile_unit + .byte 0 # DW_AT_producer + .short 33 # DW_AT_language + .byte 1 # DW_AT_name + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .long .Lline_table_start0 # DW_AT_stmt_list + .byte 2 # DW_AT_comp_dir + .byte 0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .long .Laddr_table_base0 # DW_AT_addr_base + .byte 2 # Abbrev [2] 0x23:0x47 DW_TAG_subprogram + .byte 0 # DW_AT_low_pc + .long .Lfunc_end0-.Lfunc_begin0 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .byte 8 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long .debug_info+174 # DW_AT_type + # DW_AT_external + .byte 3 # Abbrev [3] 0x32:0xb DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 116 + .byte 9 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long .debug_info+174 # DW_AT_type + .byte 4 # Abbrev [4] 0x3d:0xb DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 104 + .byte 10 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 2 # DW_AT_decl_line + .long 106 # DW_AT_type + .byte 5 # Abbrev [5] 0x48:0xb DW_TAG_variable + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .byte 7 # DW_AT_name + .byte 1 # DW_AT_decl_file + .byte 3 # DW_AT_decl_line + .long .debug_info+174 # DW_AT_type + .byte 6 # Abbrev [6] 0x53:0x16 DW_TAG_inlined_subroutine + .long .debug_info+156 # DW_AT_abstract_origin + .byte 1 # DW_AT_low_pc + .long .Ltmp2-.Ltmp1 # DW_AT_high_pc + .byte 1 # DW_AT_call_file + .byte 4 # DW_AT_call_line + .byte 32 # DW_AT_call_column + .byte 7 # Abbrev [7] 0x60:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 120 + .long .debug_info+165 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark + .byte 8 # Abbrev [8] 0x6a:0x5 DW_TAG_pointer_type + .long 111 # DW_AT_type + .byte 8 # Abbrev [8] 0x6f:0x5 DW_TAG_pointer_type + .long 116 # DW_AT_type + .byte 9 # Abbrev [9] 0x74:0x4 DW_TAG_base_type + .byte 11 # DW_AT_name + .byte 6 # DW_AT_encoding + .byte 1 # DW_AT_byte_size + .byte 0 # End Of Children Mark +.Ldebug_info_end0: +.Lcu_begin1: + .long .Ldebug_info_end1-.Ldebug_info_start1 # Length of Unit +.Ldebug_info_start1: + .short 5 # DWARF version number + .byte 1 # DWARF Unit Type + .byte 8 # Address Size (in bytes) + .long .debug_abbrev # Offset Into Abbrev. Section + .byte 1 # Abbrev [1] 0xc:0x43 DW_TAG_compile_unit + .byte 0 # DW_AT_producer + .short 33 # DW_AT_language + .byte 3 # DW_AT_name + .long .Lstr_offsets_base0 # DW_AT_str_offsets_base + .long .Lline_table_start0 # DW_AT_stmt_list + .byte 2 # DW_AT_comp_dir + .byte 2 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .long .Laddr_table_base0 # DW_AT_addr_base + .byte 10 # Abbrev [10] 0x23:0x12 DW_TAG_subprogram + .byte 4 # DW_AT_linkage_name + .byte 5 # DW_AT_name + .byte 2 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .long 53 # DW_AT_type + # DW_AT_external + # DW_AT_inline + .byte 11 # Abbrev [11] 0x2c:0x8 DW_TAG_formal_parameter + .byte 7 # DW_AT_name + .byte 2 # DW_AT_decl_file + .byte 1 # DW_AT_decl_line + .long 53 # DW_AT_type + .byte 0 # End Of Children Mark + .byte 9 # Abbrev [9] 0x35:0x4 DW_TAG_base_type + .byte 6 # DW_AT_name + .byte 5 # DW_AT_encoding + .byte 4 # DW_AT_byte_size + .byte 12 # Abbrev [12] 0x39:0x15 DW_TAG_subprogram + .byte 2 # DW_AT_low_pc + .long .Lfunc_end1-.Lfunc_begin1 # DW_AT_high_pc + .byte 1 # DW_AT_frame_base + .byte 86 + .long 35 # DW_AT_abstract_origin + .byte 13 # Abbrev [13] 0x45:0x8 DW_TAG_formal_parameter + .byte 2 # DW_AT_location + .byte 145 + .byte 124 + .long 44 # DW_AT_abstract_origin + .byte 0 # End Of Children Mark + .byte 0 # End Of Children Mark +.Ldebug_info_end1: + .section .debug_str_offsets,"",@progbits + .long 52 # Length of String Offsets Set + .short 5 + .short 0 +.Lstr_offsets_base0: + .section .debug_str,"MS",@progbits,1 +.Linfo_string0: + .asciz "clang version 19.0.0git" # string offset=0 +.Linfo_string1: + .asciz "main.cpp" # string offset=24 +.Linfo_string2: + .asciz "/home/ayermolo/local/tasks/T182867349" # string offset=33 +.Linfo_string3: + .asciz "helper.cpp" # string offset=71 +.Linfo_string4: + .asciz "_Z3fooi" # string offset=82 +.Linfo_string5: + .asciz "foo" # string offset=90 +.Linfo_string6: + .asciz "int" # string offset=94 +.Linfo_string7: + .asciz "i" # string offset=98 +.Linfo_string8: + .asciz "main" # string offset=100 +.Linfo_string9: + .asciz "argc" # string offset=105 +.Linfo_string10: + .asciz "argv" # string offset=110 +.Linfo_string11: + .asciz "char" # string offset=115 + .section .debug_str_offsets,"",@progbits + .long .Linfo_string0 + .long .Linfo_string1 + .long .Linfo_string2 + .long .Linfo_string3 + .long .Linfo_string4 + .long .Linfo_string5 + .long .Linfo_string6 + .long .Linfo_string7 + .long .Linfo_string8 + .long .Linfo_string9 + .long .Linfo_string10 + .long .Linfo_string11 + .section .debug_addr,"",@progbits + .long .Ldebug_addr_end0-.Ldebug_addr_start0 # Length of contribution +.Ldebug_addr_start0: + .short 5 # DWARF version number + .byte 8 # Address size + .byte 0 # Segment selector size +.Laddr_table_base0: + .quad .Lfunc_begin0 + .quad .Ltmp1 + .quad .Lfunc_begin1 +.Ldebug_addr_end0: + .section .debug_names,"",@progbits + .long .Lnames_end0-.Lnames_start0 # Header: unit length +.Lnames_start0: + .short 5 # Header: version + .short 0 # Header: padding + .long 2 # Header: compilation unit count + .long 0 # Header: local type unit count + .long 0 # Header: foreign type unit count + .long 5 # Header: bucket count + .long 5 # Header: name count + .long .Lnames_abbrev_end0-.Lnames_abbrev_start0 # Header: abbreviation table size + .long 8 # Header: augmentation string size + .ascii "LLVM0700" # Header: augmentation string + .long .Lcu_begin0 # Compilation unit 0 + .long .Lcu_begin1 # Compilation unit 1 + .long 0 # Bucket 0 + .long 1 # Bucket 1 + .long 0 # Bucket 2 + .long 3 # Bucket 3 + .long 4 # Bucket 4 + .long 2090499946 # Hash in Bucket 1 + .long -1257882370 # Hash in Bucket 1 + .long 193495088 # Hash in Bucket 3 + .long 193491849 # Hash in Bucket 4 + .long 2090147939 # Hash in Bucket 4 + .long .Linfo_string8 # String in Bucket 1: main + .long .Linfo_string4 # String in Bucket 1: _Z3fooi + .long .Linfo_string6 # String in Bucket 3: int + .long .Linfo_string5 # String in Bucket 4: foo + .long .Linfo_string11 # String in Bucket 4: char + .long .Lnames1-.Lnames_entries0 # Offset in Bucket 1 + .long .Lnames3-.Lnames_entries0 # Offset in Bucket 1 + .long .Lnames0-.Lnames_entries0 # Offset in Bucket 3 + .long .Lnames2-.Lnames_entries0 # Offset in Bucket 4 + .long .Lnames4-.Lnames_entries0 # Offset in Bucket 4 +.Lnames_abbrev_start0: + .byte 1 # Abbrev code + .byte 46 # DW_TAG_subprogram + .byte 1 # DW_IDX_compile_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 2 # Abbrev code + .byte 29 # DW_TAG_inlined_subroutine + .byte 1 # DW_IDX_compile_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 19 # DW_FORM_ref4 + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 3 # Abbrev code + .byte 36 # DW_TAG_base_type + .byte 1 # DW_IDX_compile_unit + .byte 11 # DW_FORM_data1 + .byte 3 # DW_IDX_die_offset + .byte 19 # DW_FORM_ref4 + .byte 4 # DW_IDX_parent + .byte 25 # DW_FORM_flag_present + .byte 0 # End of abbrev + .byte 0 # End of abbrev + .byte 0 # End of abbrev list +.Lnames_abbrev_end0: +.Lnames_entries0: +.Lnames1: +.L3: + .byte 1 # Abbreviation code + .byte 0 # DW_IDX_compile_unit + .long 35 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: main +.Lnames3: +.L0: + .byte 1 # Abbreviation code + .byte 1 # DW_IDX_compile_unit + .long 57 # DW_IDX_die_offset +.L2: # DW_IDX_parent + .byte 2 # Abbreviation code + .byte 0 # DW_IDX_compile_unit + .long 83 # DW_IDX_die_offset + .long .L3-.Lnames_entries0 # DW_IDX_parent + .byte 0 # End of list: _Z3fooi +.Lnames0: +.L4: + .byte 3 # Abbreviation code + .byte 1 # DW_IDX_compile_unit + .long 53 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: int +.Lnames2: + .byte 1 # Abbreviation code + .byte 1 # DW_IDX_compile_unit + .long 57 # DW_IDX_die_offset + .byte 2 # DW_IDX_parent + # Abbreviation code + .byte 0 # DW_IDX_compile_unit + .long 83 # DW_IDX_die_offset + .long .L3-.Lnames_entries0 # DW_IDX_parent + .byte 0 # End of list: foo +.Lnames4: +.L1: + .byte 3 # Abbreviation code + .byte 0 # DW_IDX_compile_unit + .long 116 # DW_IDX_die_offset + .byte 0 # DW_IDX_parent + # End of list: char + .p2align 2, 0x0 +.Lnames_end0: + .ident "clang version 19.0.0git" + .ident "clang version 19.0.0git" + .section ".note.GNU-stack","",@progbits + .section .debug_line,"",@progbits +.Lline_table_start0: diff --git a/bolt/test/X86/dwarf5-label-low-pc.s b/bolt/test/X86/dwarf5-label-low-pc.s index 890d9e024d1a0c1f1609d7cd33ea85076a10a2bf..1e3fc17ad516acb70410e60e4b860c0702f379ea 100644 --- a/bolt/test/X86/dwarf5-label-low-pc.s +++ b/bolt/test/X86/dwarf5-label-low-pc.s @@ -8,9 +8,10 @@ # RUN: llvm-dwarfdump --show-form --verbose --debug-addr %t.bolt > %t.txt # RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t.txt +# RUN: llvm-objdump -d %t.bolt >> %t.txt # RUN: cat %t.txt | FileCheck --check-prefix=POSTCHECK %s -# This test checks that we correctly handle DW_AT_low_pc [DW_FORM_addrx] that is part of DW_TAG_label. +## This test checks that we correctly handle DW_AT_low_pc [DW_FORM_addrx] that is part of DW_TAG_label. # PRECHECK: version = 0x0005 # PRECHECK: DW_TAG_label @@ -28,8 +29,8 @@ # POSTCHECK: Addrs: [ # POSTCHECK-NEXT: 0x # POSTCHECK-NEXT: 0x -# POSTCHECK-NEXT: 0x[[#%.16x,ADDR:]] -# POSTCHECK-NEXT: 0x[[#%.16x,ADDR2:]] +# POSTCHECK-NEXT: 0x[[ADDR:[1-9a-f]*]] +# POSTCHECK-NEXT: 0x[[ADDR2:[1-9a-f]*]] # POSTCHECK: version = 0x0005 # POSTCHECK: DW_TAG_label @@ -37,25 +38,28 @@ # POSTCHECK-NEXT: DW_AT_decl_file # POSTCHECK-NEXT: DW_AT_decl_line # POSTCHECK-NEXT:DW_AT_low_pc [DW_FORM_addrx] (indexed (00000002) -# POSTCHECK-SAME: 0x[[#ADDR]] +# POSTCHECK-SAME: 0x[[ADDR]] # POSTCHECK: DW_TAG_label # POSTCHECK-NEXT: DW_AT_name # POSTCHECK-NEXT: DW_AT_decl_file # POSTCHECK-NEXT: DW_AT_decl_line # POSTCHECK-NEXT:DW_AT_low_pc [DW_FORM_addrx] (indexed (00000003) -# POSTCHECK-SAME: 0x[[#ADDR2]] +# POSTCHECK-SAME: 0x[[ADDR2]] -# clang++ main.cpp -g -S -# int main() { -# int a = 4; -# if (a == 5) -# goto LABEL1; -# else -# goto LABEL2; -# LABEL1:a++; -# LABEL2:a--; -# return 0; -# } +# POSTCHECK: [[ADDR]]: 8b 45 f8 +# POSTCHECK: [[ADDR2]]: 8b 45 f8 + +## clang++ main.cpp -g -S +## int main() { +## int a = 4; +## if (a == 5) +## goto LABEL1; +## else +## goto LABEL2; +## LABEL1:a++; +## LABEL2:a--; +## return 0; +## } .text .file "main.cpp" diff --git a/bolt/test/X86/linux-alt-instruction.s b/bolt/test/X86/linux-alt-instruction.s index 5dcc6fe3ab0c81f178bd447be064529d79f11593..2cdf31519682a8e300a05efe46ccd4a867ddd133 100644 --- a/bolt/test/X86/linux-alt-instruction.s +++ b/bolt/test/X86/linux-alt-instruction.s @@ -6,8 +6,8 @@ # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o # RUN: %clang %cflags -nostdlib %t.o -o %t.exe \ # RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie -# RUN: llvm-bolt %t.exe --print-normalized --keep-nops -o %t.out \ -# RUN: --alt-inst-feature-size=2 | FileCheck %s +# RUN: llvm-bolt %t.exe --print-normalized --alt-inst-feature-size=2 -o %t.out \ +# RUN: | FileCheck %s ## Older kernels used to have padlen field in alt_instr. Check compatibility. @@ -15,8 +15,8 @@ # RUN: %s -o %t.o # RUN: %clang %cflags -nostdlib %t.o -o %t.exe \ # RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie -# RUN: llvm-bolt %t.exe --print-normalized --keep-nops --alt-inst-has-padlen \ -# RUN: -o %t.out | FileCheck %s +# RUN: llvm-bolt %t.exe --print-normalized --alt-inst-has-padlen -o %t.out \ +# RUN: | FileCheck %s ## Check with a larger size of "feature" field in alt_instr. @@ -24,13 +24,12 @@ # RUN: --defsym FEATURE_SIZE_4=1 %s -o %t.o # RUN: %clang %cflags -nostdlib %t.o -o %t.exe \ # RUN: -Wl,--image-base=0xffffffff80000000,--no-dynamic-linker,--no-eh-frame-hdr,--no-pie -# RUN: llvm-bolt %t.exe --print-normalized --keep-nops \ -# RUN: --alt-inst-feature-size=4 -o %t.out | FileCheck %s +# RUN: llvm-bolt %t.exe --print-normalized --alt-inst-feature-size=4 -o %t.out \ +# RUN: | FileCheck %s ## Check that out-of-bounds read is handled properly. -# RUN: not llvm-bolt %t.exe --print-normalized --keep-nops \ -# RUN: --alt-inst-feature-size=2 -o %t.out +# RUN: not llvm-bolt %t.exe --print-normalized --alt-inst-feature-size=2 -o %t.out # CHECK: BOLT-INFO: Linux kernel binary detected # CHECK: BOLT-INFO: parsed 2 alternative instruction entries diff --git a/bolt/test/X86/linux-bug-table.s b/bolt/test/X86/linux-bug-table.s index e8de2fb6cba79ddab8061705700f263200c0701e..63f70a0b35d9fe59c85a68998a019a2175a74c46 100644 --- a/bolt/test/X86/linux-bug-table.s +++ b/bolt/test/X86/linux-bug-table.s @@ -1,6 +1,7 @@ # REQUIRES: system-linux -## Check that BOLT correctly parses the Linux kernel __bug_table section. +## Check that BOLT correctly parses and updates the Linux kernel __bug_table +## section. # RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o # RUN: %clang %cflags -nostdlib %t.o -o %t.exe \ @@ -8,7 +9,13 @@ ## Verify bug entry bindings to instructions. -# RUN: llvm-bolt %t.exe --print-normalized -o %t.out | FileCheck %s +# RUN: llvm-bolt %t.exe --print-normalized --print-only=_start -o %t.out \ +# RUN: --eliminate-unreachable=1 --bolt-info=0 | FileCheck %s + +## Verify bug entry bindings again after unreachable code elimination. + +# RUN: llvm-bolt %t.out -o %t.out.1 --print-only=_start --print-normalized \ +# RUN: |& FileCheck --check-prefix=CHECK-REOPT %s # CHECK: BOLT-INFO: Linux kernel binary detected # CHECK: BOLT-INFO: parsed 2 bug table entries @@ -17,18 +24,26 @@ .globl _start .type _start, %function _start: -# CHECK: Binary Function "_start" - nop + jmp .L1 .L0: ud2 # CHECK: ud2 # CHECK-SAME: BugEntry: 1 - nop .L1: ud2 # CHECK: ud2 # CHECK-SAME: BugEntry: 2 + +## Only the second entry should remain after the first pass. + +# CHECK-REOPT: ud2 +# CHECK-REOPT-SAME: BugEntry: 2 + ret +## The return instruction is reachable only via preceding ud2. Test that it is +## treated as a reachable instruction in the Linux kernel mode. + +# CHECK-REOPT-NEXT: ret .size _start, .-_start diff --git a/bolt/test/X86/linux-orc.s b/bolt/test/X86/linux-orc.s index 4da19989408e2458c156c6cc97e95147d1419326..5f2096278e92d6a10c04bb387b74d52833d2a540 100644 --- a/bolt/test/X86/linux-orc.s +++ b/bolt/test/X86/linux-orc.s @@ -27,7 +27,7 @@ ## Verify ORC bindings to instructions. # RUN: llvm-bolt %t.exe --print-normalized --dump-orc --print-orc -o %t.out \ -# RUN: --bolt-info=0 |& FileCheck %s +# RUN: --keep-nops=0 --bolt-info=0 |& FileCheck %s ## Verify ORC bindings after rewrite. @@ -37,7 +37,7 @@ ## Verify ORC binding after rewrite when some of the functions are skipped. -# RUN: llvm-bolt %t.exe -o %t.out --skip-funcs=bar --bolt-info=0 +# RUN: llvm-bolt %t.exe -o %t.out --skip-funcs=bar --bolt-info=0 --keep-nops=0 # RUN: llvm-bolt %t.out -o %t.out.1 --print-normalized --print-orc \ # RUN: |& FileCheck %s diff --git a/bolt/test/X86/linux-parainstructions.s b/bolt/test/X86/linux-parainstructions.s index 4bdfde5fb7f24bf505ae4537b988fa8321d6db20..07fca6bbedafaba54b44106519634d93712dad7e 100644 --- a/bolt/test/X86/linux-parainstructions.s +++ b/bolt/test/X86/linux-parainstructions.s @@ -8,7 +8,7 @@ ## Verify paravirtual bindings to instructions. -# RUN: llvm-bolt %t.exe --print-normalized -o %t.out | FileCheck %s +# RUN: llvm-bolt %t.exe --print-normalized -o %t.out --keep-nops=0 | FileCheck %s # CHECK: BOLT-INFO: Linux kernel binary detected # CHECK: BOLT-INFO: parsed 2 paravirtual patch sites diff --git a/bolt/test/X86/patch-entries.test b/bolt/test/X86/patch-entries.test index 54f358f273e793c30da84fe3a6134e77d4cb4759..4a725412dd616adeb760df155837c17b003213e0 100644 --- a/bolt/test/X86/patch-entries.test +++ b/bolt/test/X86/patch-entries.test @@ -7,4 +7,25 @@ REQUIRES: system-linux RUN: %clang %cflags -no-pie -g %p/Inputs/patch-entries.c -fuse-ld=lld -o %t.exe \ RUN: -Wl,-q -I%p/../Inputs -RUN: llvm-bolt -relocs %t.exe -o %t.out --update-debug-sections --force-patch +RUN: llvm-bolt -relocs %t.exe -o %t.out --update-debug-sections --force-patch \ +RUN: --enable-bat + +# Check that patched functions can be disassembled (override FDE from the +# original function) +# PREAGG: B X:0 #foo.org.0# 1 0 +RUN: link_fdata %s %t.out %t.preagg PREAGG +RUN: perf2bolt %t.out -p %t.preagg --pa -o %t.yaml --profile-format=yaml \ +RUN: -print-disasm -print-only=foo.org.0/1 2>&1 | FileCheck %s +CHECK-NOT: BOLT-WARNING: sizes differ for function foo.org.0/1 +CHECK: Binary Function "foo.org.0/1(*2)" after disassembly { + +# Check the expected eh_frame contents +RUN: llvm-nm --print-size %t.out > %t.foo +RUN: llvm-objdump %t.out --dwarf=frames >> %t.foo +RUN: FileCheck %s --input-file %t.foo --check-prefix=CHECK-FOO +CHECK-FOO: 0000000000[[#%x,FOO:]] [[#%x,OPTSIZE:]] t foo +CHECK-FOO: 0000000000[[#%x,ORG:]] [[#%x,ORGSIZE:]] t foo.org.0 +# patched FDE comes first +CHECK-FOO: FDE {{.*}} pc=00[[#%x,ORG]]...00[[#%x,ORG+ORGSIZE]] +# original FDE comes second +CHECK-FOO: FDE {{.*}} pc=00[[#%x,ORG]]...00[[#%x,ORG+OPTSIZE]] diff --git a/bolt/test/X86/yaml-secondary-entry-discriminator.s b/bolt/test/X86/yaml-secondary-entry-discriminator.s new file mode 100644 index 0000000000000000000000000000000000000000..5d6e291fd7c22a79594afa6b5daa7d828bacc082 --- /dev/null +++ b/bolt/test/X86/yaml-secondary-entry-discriminator.s @@ -0,0 +1,145 @@ +## This reproduces a bug with BOLT setting incorrect discriminator for +## secondary entry points in YAML profile. + +# REQUIRES: system-linux +# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o +# RUN: link_fdata %s %t.o %t.fdata +# RUN: llvm-strip --strip-unneeded %t.o +# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q -nostdlib +# RUN: llvm-bolt %t.exe -o %t.out --data %t.fdata -w %t.yaml --print-profile \ +# RUN: --print-only=main | FileCheck %s --check-prefix=CHECK-CFG +# RUN: FileCheck %s -input-file %t.yaml +# CHECK: - name: main +# CHECK-NEXT: fid: 2 +# CHECK-NEXT: hash: {{.*}} +# CHECK-NEXT: exec: 0 +# CHECK-NEXT: nblocks: 4 +# CHECK-NEXT: blocks: +# CHECK: - bid: 1 +# CHECK-NEXT: insns: 1 +# CHECK-NEXT: hash: {{.*}} +# CHECK-NEXT: calls: [ { off: 0x0, fid: 1, disc: 1, cnt: 1 } ] +# CHECK: - bid: 2 +# CHECK-NEXT: insns: 5 +# CHECK-NEXT: hash: {{.*}} +# CHECK-NEXT: calls: [ { off: 0x0, fid: 1, disc: 1, cnt: 1, mis: 1 } ] + +## Make sure that the profile is attached correctly +# RUN: llvm-bolt %t.exe -o %t.out --data %t.yaml --print-profile \ +# RUN: --print-only=main | FileCheck %s --check-prefix=CHECK-CFG + +# CHECK-CFG: Binary Function "main" after attaching profile { +# CHECK-CFG: callq secondary_entry # Offset: [[#]] # Count: 1 +# CHECK-CFG: callq *%rax # Offset: [[#]] # CallProfile: 1 (1 misses) : +# CHECK-CFG-NEXT: { secondary_entry: 1 (1 misses) } + +## YAML BAT test of calling BAT secondary entry from non-BAT function +## Now force-split func and skip main (making it call secondary entries) +# RUN: llvm-bolt %t.exe -o %t.bat --data %t.fdata --funcs=func \ +# RUN: --split-functions --split-strategy=all --split-all-cold --enable-bat + +## Prepare pre-aggregated profile using %t.bat +# RUN: link_fdata %s %t.bat %t.preagg PREAGG +## Strip labels used for pre-aggregated profile +# RUN: llvm-strip -NLcall -NLindcall %t.bat + +## Convert pre-aggregated profile using BAT +# RUN: perf2bolt %t.bat -p %t.preagg --pa -o %t.bat.fdata -w %t.bat.yaml + +## Convert BAT fdata into YAML +# RUN: llvm-bolt %t.exe -data %t.bat.fdata -w %t.bat.fdata-yaml -o /dev/null + +## Check fdata YAML - make sure that a direct call has discriminator field +# RUN: FileCheck %s --input-file %t.bat.fdata-yaml -check-prefix CHECK-BAT-YAML + +## Check BAT YAML - make sure that a direct call has discriminator field +# RUN: FileCheck %s --input-file %t.bat.yaml --check-prefix CHECK-BAT-YAML + +## YAML BAT test of calling BAT secondary entry from BAT function +# RUN: llvm-bolt %t.exe -o %t.bat2 --data %t.fdata --funcs=main,func \ +# RUN: --split-functions --split-strategy=all --split-all-cold --enable-bat + +## Prepare pre-aggregated profile using %t.bat +# RUN: link_fdata %s %t.bat2 %t.preagg2 PREAGG2 + +## Strip labels used for pre-aggregated profile +# RUN: llvm-strip -NLcall -NLindcall %t.bat2 + +## Convert pre-aggregated profile using BAT +# RUN: perf2bolt %t.bat2 -p %t.preagg2 --pa -o %t.bat2.fdata -w %t.bat2.yaml + +## Convert BAT fdata into YAML +# RUN: llvm-bolt %t.exe -data %t.bat2.fdata -w %t.bat2.fdata-yaml -o /dev/null + +## Check fdata YAML - make sure that a direct call has discriminator field +# RUN: FileCheck %s --input-file %t.bat2.fdata-yaml -check-prefix CHECK-BAT-YAML + +## Check BAT YAML - make sure that a direct call has discriminator field +# RUN: FileCheck %s --input-file %t.bat2.yaml --check-prefix CHECK-BAT-YAML + +# CHECK-BAT-YAML: - name: main +# CHECK-BAT-YAML-NEXT: fid: [[#]] +# CHECK-BAT-YAML-NEXT: hash: 0xADF270D550151185 +# CHECK-BAT-YAML-NEXT: exec: 0 +# CHECK-BAT-YAML-NEXT: nblocks: 4 +# CHECK-BAT-YAML-NEXT: blocks: +# CHECK-BAT-YAML: - bid: 1 +# CHECK-BAT-YAML-NEXT: insns: [[#]] +# CHECK-BAT-YAML-NEXT: hash: 0x36A303CBA4360018 +# CHECK-BAT-YAML-NEXT: calls: [ { off: 0x0, fid: [[#]], disc: 1, cnt: 1 + +.globl func +.type func, @function +func: +# FDATA: 0 [unknown] 0 1 func 0 1 0 +# PREAGG: B X:0 #func# 1 1 +# PREAGG2: B X:0 #func# 1 1 + .cfi_startproc + pushq %rbp + movq %rsp, %rbp +## Placeholder code to make splitting profitable +.rept 5 + testq %rax, %rax +.endr +.globl secondary_entry +secondary_entry: +## Placeholder code to make splitting profitable +.rept 5 + testq %rax, %rax +.endr + popq %rbp + retq + nopl (%rax) + .cfi_endproc + .size func, .-func + +.globl main +.type main, @function +main: + .cfi_startproc + pushq %rbp + movq %rsp, %rbp + subq $16, %rsp + movl $0, -4(%rbp) + testq %rax, %rax + jne Lindcall +.globl Lcall +Lcall: + call secondary_entry +# FDATA: 1 main #Lcall# 1 secondary_entry 0 1 1 +# PREAGG: B #Lcall# #secondary_entry# 1 1 +# PREAGG2: B #main.cold.0# #func.cold.0# 1 1 +.globl Lindcall +Lindcall: + callq *%rax +# FDATA: 1 main #Lindcall# 1 secondary_entry 0 1 1 +# PREAGG: B #Lindcall# #secondary_entry# 1 1 +# PREAGG2: B #main.cold.1# #func.cold.0# 1 1 + xorl %eax, %eax + addq $16, %rsp + popq %rbp + retq +## For relocations against .text + call exit + .cfi_endproc + .size main, .-main diff --git a/bolt/tools/bat-dump/bat-dump.cpp b/bolt/tools/bat-dump/bat-dump.cpp index 2e9b26cc137a8621eb2faeebdfca47dbfb031976..709eb076bca2da7976a0e9c6199f1c9c7b9398a6 100644 --- a/bolt/tools/bat-dump/bat-dump.cpp +++ b/bolt/tools/bat-dump/bat-dump.cpp @@ -1,9 +1,16 @@ +//===- bolt/tools/bat-dump/bat-dump.cpp - BAT dumper utility --------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + #include "bolt/Profile/BoltAddressTranslation.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" -#include "llvm/ADT/iterator_range.h" #include "llvm/Object/Binary.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/Error.h" @@ -18,7 +25,6 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Program.h" #include "llvm/Support/raw_ostream.h" -#include #include #include #include @@ -27,7 +33,6 @@ #include #include #include -#include using namespace llvm; using namespace bolt; diff --git a/bolt/tools/heatmap/heatmap.cpp b/bolt/tools/heatmap/heatmap.cpp index 9b190dd288b279deb411b63500ef909e4cc667a9..3bb9f2ce7491db6f1dbf08cbb2dec6cdb92b3ea9 100644 --- a/bolt/tools/heatmap/heatmap.cpp +++ b/bolt/tools/heatmap/heatmap.cpp @@ -1,4 +1,11 @@ -#include "bolt/Profile/DataAggregator.h" +//===- bolt/tools/heatmap/heatmap.cpp - Profile heatmap visualization tool ===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + #include "bolt/Rewrite/RewriteInstance.h" #include "bolt/Utils/CommandLineOpts.h" #include "llvm/MC/TargetRegistry.h" @@ -6,7 +13,8 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Errc.h" #include "llvm/Support/Error.h" -#include "llvm/Support/Path.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Program.h" #include "llvm/Support/TargetSelect.h" using namespace llvm; diff --git a/bolt/unittests/Core/BinaryContext.cpp b/bolt/unittests/Core/BinaryContext.cpp index 08619eccdd75ab765db3951a565466218313b64d..cfec72a34a59f24eebaf3e09b8de13e3794c8e20 100644 --- a/bolt/unittests/Core/BinaryContext.cpp +++ b/bolt/unittests/Core/BinaryContext.cpp @@ -1,7 +1,14 @@ +//===- bolt/unittest/Core/BinaryContext.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + #include "bolt/Core/BinaryContext.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/TargetSelect.h" #include "gtest/gtest.h" @@ -40,8 +47,8 @@ protected: void initializeBOLT() { BC = cantFail(BinaryContext::createBinaryContext( - ObjFile.get(), true, DWARFContext::create(*ObjFile.get()), - {llvm::outs(), llvm::errs()})); + ObjFile->makeTriple(), ObjFile->getFileName(), nullptr, true, + DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()})); ASSERT_FALSE(!BC); } diff --git a/bolt/unittests/Core/MCPlusBuilder.cpp b/bolt/unittests/Core/MCPlusBuilder.cpp index daf9f392b8228198fcf77807ef1e5a9a557288a5..62f3aaab4a725cbcfcfb445bc44ffc001152fc70 100644 --- a/bolt/unittests/Core/MCPlusBuilder.cpp +++ b/bolt/unittests/Core/MCPlusBuilder.cpp @@ -1,3 +1,11 @@ +//===- bolt/unittest/Core/MCPlusBuilder.cpp -------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + #ifdef AARCH64_AVAILABLE #include "AArch64Subtarget.h" #endif // AARCH64_AVAILABLE @@ -11,7 +19,6 @@ #include "bolt/Rewrite/RewriteInstance.h" #include "llvm/BinaryFormat/ELF.h" #include "llvm/DebugInfo/DWARF/DWARFContext.h" -#include "llvm/Object/ELFObjectFile.h" #include "llvm/Support/TargetSelect.h" #include "gtest/gtest.h" @@ -50,8 +57,8 @@ protected: void initializeBolt() { BC = cantFail(BinaryContext::createBinaryContext( - ObjFile.get(), true, DWARFContext::create(*ObjFile.get()), - {llvm::outs(), llvm::errs()})); + ObjFile->makeTriple(), ObjFile->getFileName(), nullptr, true, + DWARFContext::create(*ObjFile.get()), {llvm::outs(), llvm::errs()})); ASSERT_FALSE(!BC); BC->initializeTarget(std::unique_ptr( createMCPlusBuilder(GetParam(), BC->MIA.get(), BC->MII.get(), diff --git a/clang-tools-extra/clang-tidy/ClangTidy.cpp b/clang-tools-extra/clang-tidy/ClangTidy.cpp index 40ac6918faf40786b1add8fb16e1c5933d76ca2e..b877ea06dc05cd78b5536155efb25afa4ae32906 100644 --- a/clang-tools-extra/clang-tidy/ClangTidy.cpp +++ b/clang-tools-extra/clang-tidy/ClangTidy.cpp @@ -233,7 +233,7 @@ public: if (!tooling::applyAllReplacements(Replacements.get(), Rewrite)) { llvm::errs() << "Can't apply replacements for file " << File << "\n"; } - AnyNotWritten &= Rewrite.overwriteChangedFiles(); + AnyNotWritten |= Rewrite.overwriteChangedFiles(); } if (AnyNotWritten) { diff --git a/clang-tools-extra/clang-tidy/bugprone/IncDecInConditionsCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/IncDecInConditionsCheck.cpp index 16f43128d55e87ed43a0f16a227bc16a07297959..9b3b01eb02683324d16ee91050116332c9281a1f 100644 --- a/clang-tools-extra/clang-tidy/bugprone/IncDecInConditionsCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/IncDecInConditionsCheck.cpp @@ -31,6 +31,10 @@ void IncDecInConditionsCheck::registerMatchers(MatchFinder *Finder) { anyOf(binaryOperator(anyOf(isComparisonOperator(), isLogicalOperator())), cxxOperatorCallExpr(isComparisonOperator()))); + auto IsInUnevaluatedContext = + expr(anyOf(hasAncestor(expr(matchers::hasUnevaluatedContext())), + hasAncestor(typeLoc()))); + Finder->addMatcher( expr( OperatorMatcher, unless(isExpansionInSystemHeader()), @@ -42,12 +46,14 @@ void IncDecInConditionsCheck::registerMatchers(MatchFinder *Finder) { cxxOperatorCallExpr( isPrePostOperator(), hasUnaryOperand(expr().bind("operand")))), + unless(IsInUnevaluatedContext), hasAncestor( expr(equalsBoundNode("parent"), hasDescendant( expr(unless(equalsBoundNode("operand")), matchers::isStatementIdenticalToBoundNode( - "operand")) + "operand"), + unless(IsInUnevaluatedContext)) .bind("second"))))) .bind("operator"))), this); diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp index 87fd8adf997082593a28d680478c06f06fcfd9fc..bbb35228ce47fbb168a5a0c779177d0ae1510058 100644 --- a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp +++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp @@ -9,8 +9,8 @@ #include "MissingStdForwardCheck.h" #include "../utils/Matchers.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/ExprConcepts.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Basic/IdentifierTable.h" using namespace clang::ast_matchers; @@ -79,6 +79,11 @@ AST_MATCHER_P(LambdaExpr, hasCaptureDefaultKind, LambdaCaptureDefault, Kind) { return Node.getCaptureDefault() == Kind; } +AST_MATCHER(VarDecl, hasIdentifier) { + const IdentifierInfo *ID = Node.getIdentifier(); + return ID != NULL && !ID->isPlaceholder(); +} + } // namespace void MissingStdForwardCheck::registerMatchers(MatchFinder *Finder) { @@ -125,12 +130,14 @@ void MissingStdForwardCheck::registerMatchers(MatchFinder *Finder) { hasAncestor(expr(hasUnevaluatedContext()))))); Finder->addMatcher( - parmVarDecl(parmVarDecl().bind("param"), isTemplateTypeParameter(), - hasAncestor(functionDecl().bind("func")), - hasAncestor(functionDecl( - isDefinition(), equalsBoundNode("func"), ToParam, - unless(anyOf(isDeleted(), hasDescendant(std::move( - ForwardCallMatcher))))))), + parmVarDecl( + parmVarDecl().bind("param"), hasIdentifier(), + unless(hasAttr(attr::Kind::Unused)), isTemplateTypeParameter(), + hasAncestor(functionDecl().bind("func")), + hasAncestor(functionDecl( + isDefinition(), equalsBoundNode("func"), ToParam, + unless(anyOf(isDeleted(), + hasDescendant(std::move(ForwardCallMatcher))))))), this); } diff --git a/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.cpp b/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.cpp index ef511e9108f2ee957c9ff466fc8aa069b137312b..359d8efd100bad9bdbfe369afec099a20f87834d 100644 --- a/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.cpp +++ b/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.cpp @@ -40,6 +40,34 @@ namespace { AST_MATCHER(FunctionDecl, isUserDefineLiteral) { return Node.getLiteralIdentifier() != nullptr; } + +AST_MATCHER(TypeLoc, isValidAndNotInMacro) { + const SourceLocation Loc = Node.getBeginLoc(); + return Loc.isValid() && !Loc.isMacroID(); +} + +AST_MATCHER(TypeLoc, isBuiltinType) { + TypeLoc TL = Node; + if (auto QualLoc = Node.getAs()) + TL = QualLoc.getUnqualifiedLoc(); + + const auto BuiltinLoc = TL.getAs(); + if (!BuiltinLoc) + return false; + + switch (BuiltinLoc.getTypePtr()->getKind()) { + case BuiltinType::Short: + case BuiltinType::Long: + case BuiltinType::LongLong: + case BuiltinType::UShort: + case BuiltinType::ULong: + case BuiltinType::ULongLong: + return true; + default: + return false; + } +} + } // namespace namespace tidy::google::runtime { @@ -63,11 +91,11 @@ void IntegerTypesCheck::registerMatchers(MatchFinder *Finder) { // "Where possible, avoid passing arguments of types specified by // bitwidth typedefs to printf-based APIs." Finder->addMatcher( - typeLoc(loc(isInteger()), - unless(anyOf(hasAncestor(callExpr( - callee(functionDecl(hasAttr(attr::Format))))), - hasParent(parmVarDecl(hasAncestor( - functionDecl(isUserDefineLiteral()))))))) + typeLoc(loc(isInteger()), isValidAndNotInMacro(), isBuiltinType(), + unless(hasAncestor( + callExpr(callee(functionDecl(hasAttr(attr::Format)))))), + unless(hasParent(parmVarDecl( + hasAncestor(functionDecl(isUserDefineLiteral())))))) .bind("tl"), this); IdentTable = std::make_unique(getLangOpts()); @@ -77,9 +105,6 @@ void IntegerTypesCheck::check(const MatchFinder::MatchResult &Result) { auto TL = *Result.Nodes.getNodeAs("tl"); SourceLocation Loc = TL.getBeginLoc(); - if (Loc.isInvalid() || Loc.isMacroID()) - return; - // Look through qualification. if (auto QualLoc = TL.getAs()) TL = QualLoc.getUnqualifiedLoc(); diff --git a/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.h b/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.h index 3be7d24021b9ffcbc25f35321d3af2a6d9f05a76..c62bda67ae2d987d68dc7cb1dc78b506e0ac6f63 100644 --- a/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.h +++ b/clang-tools-extra/clang-tidy/google/IntegerTypesCheck.h @@ -35,6 +35,9 @@ public: void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + std::optional getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } private: const StringRef UnsignedTypePrefix; diff --git a/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.cpp b/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.cpp index 8020f8cd062510b5ac677cf1d73de8d8c38800f1..b1a18485ce168d2bf94528d1c5a6f453537c6e79 100644 --- a/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.cpp +++ b/clang-tools-extra/clang-tidy/hicpp/IgnoredRemoveResultCheck.cpp @@ -14,9 +14,9 @@ IgnoredRemoveResultCheck::IgnoredRemoveResultCheck(llvm::StringRef Name, ClangTidyContext *Context) : UnusedReturnValueCheck(Name, Context, { - "::std::remove", - "::std::remove_if", - "::std::unique", + "::std::remove$", + "::std::remove_if$", + "::std::unique$", }) { // The constructor for ClangTidyCheck needs to have been called // before we can access options via Options.get(). diff --git a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp index bb05f206c717cea3a4c2067e7473d4a30dccdc12..24eefdb082eb32ad2c0195030d1e1d3f10f2af67 100644 --- a/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp +++ b/clang-tools-extra/clang-tidy/modernize/UseUsingCheck.cpp @@ -8,6 +8,7 @@ #include "UseUsingCheck.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclGroup.h" #include "clang/Lex/Lexer.h" using namespace clang::ast_matchers; @@ -24,6 +25,7 @@ static constexpr llvm::StringLiteral ExternCDeclName = "extern-c-decl"; static constexpr llvm::StringLiteral ParentDeclName = "parent-decl"; static constexpr llvm::StringLiteral TagDeclName = "tag-decl"; static constexpr llvm::StringLiteral TypedefName = "typedef"; +static constexpr llvm::StringLiteral DeclStmtName = "decl-stmt"; UseUsingCheck::UseUsingCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), @@ -41,7 +43,8 @@ void UseUsingCheck::registerMatchers(MatchFinder *Finder) { unless(isInstantiated()), optionally(hasAncestor( linkageSpecDecl(isExternCLinkage()).bind(ExternCDeclName))), - hasParent(decl().bind(ParentDeclName))) + anyOf(hasParent(decl().bind(ParentDeclName)), + hasParent(declStmt().bind(DeclStmtName)))) .bind(TypedefName), this); @@ -51,17 +54,32 @@ void UseUsingCheck::registerMatchers(MatchFinder *Finder) { tagDecl( anyOf(allOf(unless(anyOf(isImplicit(), classTemplateSpecializationDecl())), - hasParent(decl().bind(ParentDeclName))), + anyOf(hasParent(decl().bind(ParentDeclName)), + hasParent(declStmt().bind(DeclStmtName)))), // We want the parent of the ClassTemplateDecl, not the parent // of the specialization. classTemplateSpecializationDecl(hasAncestor(classTemplateDecl( - hasParent(decl().bind(ParentDeclName))))))) + anyOf(hasParent(decl().bind(ParentDeclName)), + hasParent(declStmt().bind(DeclStmtName)))))))) .bind(TagDeclName), this); } void UseUsingCheck::check(const MatchFinder::MatchResult &Result) { const auto *ParentDecl = Result.Nodes.getNodeAs(ParentDeclName); + + if (!ParentDecl) { + const auto *ParentDeclStmt = Result.Nodes.getNodeAs(DeclStmtName); + if (ParentDeclStmt) { + if (ParentDeclStmt->isSingleDecl()) + ParentDecl = ParentDeclStmt->getSingleDecl(); + else + ParentDecl = + ParentDeclStmt->getDeclGroup().getDeclGroup() + [ParentDeclStmt->getDeclGroup().getDeclGroup().size() - 1]; + } + } + if (!ParentDecl) return; diff --git a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp index e3400f614fa5640784b1d6dee31caade6a5a2c8b..48bca41f4a3b1e87dbd7488617702f17e5f6e15a 100644 --- a/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/AvoidReturnWithVoidValueCheck.cpp @@ -7,19 +7,18 @@ //===----------------------------------------------------------------------===// #include "AvoidReturnWithVoidValueCheck.h" -#include "clang/AST/Stmt.h" -#include "clang/ASTMatchers/ASTMatchFinder.h" -#include "clang/ASTMatchers/ASTMatchers.h" +#include "../utils/BracesAroundStatement.h" +#include "../utils/LexerUtils.h" using namespace clang::ast_matchers; namespace clang::tidy::readability { -static constexpr auto IgnoreMacrosName = "IgnoreMacros"; -static constexpr auto IgnoreMacrosDefault = true; +static constexpr char IgnoreMacrosName[] = "IgnoreMacros"; +static const bool IgnoreMacrosDefault = true; -static constexpr auto StrictModeName = "StrictMode"; -static constexpr auto StrictModeDefault = true; +static constexpr char StrictModeName[] = "StrictMode"; +static const bool StrictModeDefault = true; AvoidReturnWithVoidValueCheck::AvoidReturnWithVoidValueCheck( StringRef Name, ClangTidyContext *Context) @@ -32,7 +31,10 @@ void AvoidReturnWithVoidValueCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( returnStmt( hasReturnValue(allOf(hasType(voidType()), unless(initListExpr()))), - optionally(hasParent(compoundStmt().bind("compound_parent")))) + optionally(hasParent( + compoundStmt( + optionally(hasParent(functionDecl().bind("function_parent")))) + .bind("compound_parent")))) .bind("void_return"), this); } @@ -42,10 +44,30 @@ void AvoidReturnWithVoidValueCheck::check( const auto *VoidReturn = Result.Nodes.getNodeAs("void_return"); if (IgnoreMacros && VoidReturn->getBeginLoc().isMacroID()) return; - if (!StrictMode && !Result.Nodes.getNodeAs("compound_parent")) + const auto *SurroundingBlock = + Result.Nodes.getNodeAs("compound_parent"); + if (!StrictMode && !SurroundingBlock) return; - diag(VoidReturn->getBeginLoc(), "return statement within a void function " - "should not have a specified return value"); + DiagnosticBuilder Diag = diag(VoidReturn->getBeginLoc(), + "return statement within a void function " + "should not have a specified return value"); + const SourceLocation SemicolonPos = utils::lexer::findNextTerminator( + VoidReturn->getEndLoc(), *Result.SourceManager, getLangOpts()); + if (SemicolonPos.isInvalid()) + return; + if (!SurroundingBlock) { + const auto BraceInsertionHints = utils::getBraceInsertionsHints( + VoidReturn, getLangOpts(), *Result.SourceManager, + VoidReturn->getBeginLoc()); + if (BraceInsertionHints) + Diag << BraceInsertionHints.openingBraceFixIt() + << BraceInsertionHints.closingBraceFixIt(); + } + Diag << FixItHint::CreateRemoval(VoidReturn->getReturnLoc()); + if (!Result.Nodes.getNodeAs("function_parent") || + SurroundingBlock->body_back() != VoidReturn) + Diag << FixItHint::CreateInsertion(SemicolonPos.getLocWithOffset(1), + " return;", true); } void AvoidReturnWithVoidValueCheck::storeOptions( diff --git a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp index 81ca33cbbdfb4b5461b54b8a0b5903c0d1186942..85bd9c1e4f9a043074963487e72077c55bc089b3 100644 --- a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "BracesAroundStatementsCheck.h" +#include "../utils/BracesAroundStatement.h" #include "../utils/LexerUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchers.h" @@ -17,12 +18,10 @@ using namespace clang::ast_matchers; namespace clang::tidy::readability { static tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM, - const ASTContext *Context) { + const LangOptions &LangOpts) { Token Tok; - SourceLocation Beginning = - Lexer::GetBeginningOfToken(Loc, SM, Context->getLangOpts()); - const bool Invalid = - Lexer::getRawToken(Beginning, Tok, SM, Context->getLangOpts()); + SourceLocation Beginning = Lexer::GetBeginningOfToken(Loc, SM, LangOpts); + const bool Invalid = Lexer::getRawToken(Beginning, Tok, SM, LangOpts); assert(!Invalid && "Expected a valid token."); if (Invalid) @@ -33,64 +32,21 @@ static tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM, static SourceLocation forwardSkipWhitespaceAndComments(SourceLocation Loc, const SourceManager &SM, - const ASTContext *Context) { + const LangOptions &LangOpts) { assert(Loc.isValid()); for (;;) { while (isWhitespace(*SM.getCharacterData(Loc))) Loc = Loc.getLocWithOffset(1); - tok::TokenKind TokKind = getTokenKind(Loc, SM, Context); + tok::TokenKind TokKind = getTokenKind(Loc, SM, LangOpts); if (TokKind != tok::comment) return Loc; // Fast-forward current token. - Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts()); + Loc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts); } } -static SourceLocation findEndLocation(const Stmt &S, const SourceManager &SM, - const ASTContext *Context) { - SourceLocation Loc = - utils::lexer::getUnifiedEndLoc(S, SM, Context->getLangOpts()); - if (!Loc.isValid()) - return Loc; - - // Start searching right after S. - Loc = Loc.getLocWithOffset(1); - - for (;;) { - assert(Loc.isValid()); - while (isHorizontalWhitespace(*SM.getCharacterData(Loc))) { - Loc = Loc.getLocWithOffset(1); - } - - if (isVerticalWhitespace(*SM.getCharacterData(Loc))) { - // EOL, insert brace before. - break; - } - tok::TokenKind TokKind = getTokenKind(Loc, SM, Context); - if (TokKind != tok::comment) { - // Non-comment token, insert brace before. - break; - } - - SourceLocation TokEndLoc = - Lexer::getLocForEndOfToken(Loc, 0, SM, Context->getLangOpts()); - SourceRange TokRange(Loc, TokEndLoc); - StringRef Comment = Lexer::getSourceText( - CharSourceRange::getTokenRange(TokRange), SM, Context->getLangOpts()); - if (Comment.starts_with("/*") && Comment.contains('\n')) { - // Multi-line block comment, insert brace before. - break; - } - // else: Trailing comment, insert brace after the newline. - - // Fast-forward current token. - Loc = TokEndLoc; - } - return Loc; -} - BracesAroundStatementsCheck::BracesAroundStatementsCheck( StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context), @@ -124,7 +80,7 @@ void BracesAroundStatementsCheck::check( } else if (const auto *S = Result.Nodes.getNodeAs("do")) { checkStmt(Result, S->getBody(), S->getDoLoc(), S->getWhileLoc()); } else if (const auto *S = Result.Nodes.getNodeAs("while")) { - SourceLocation StartLoc = findRParenLoc(S, SM, Context); + SourceLocation StartLoc = findRParenLoc(S, SM, Context->getLangOpts()); if (StartLoc.isInvalid()) return; checkStmt(Result, S->getBody(), StartLoc); @@ -133,7 +89,7 @@ void BracesAroundStatementsCheck::check( if (S->isConsteval()) return; - SourceLocation StartLoc = findRParenLoc(S, SM, Context); + SourceLocation StartLoc = findRParenLoc(S, SM, Context->getLangOpts()); if (StartLoc.isInvalid()) return; if (ForceBracesStmts.erase(S)) @@ -156,7 +112,7 @@ template SourceLocation BracesAroundStatementsCheck::findRParenLoc(const IfOrWhileStmt *S, const SourceManager &SM, - const ASTContext *Context) { + const LangOptions &LangOpts) { // Skip macros. if (S->getBeginLoc().isMacroID()) return {}; @@ -170,14 +126,14 @@ BracesAroundStatementsCheck::findRParenLoc(const IfOrWhileStmt *S, } SourceLocation PastCondEndLoc = - Lexer::getLocForEndOfToken(CondEndLoc, 0, SM, Context->getLangOpts()); + Lexer::getLocForEndOfToken(CondEndLoc, 0, SM, LangOpts); if (PastCondEndLoc.isInvalid()) return {}; SourceLocation RParenLoc = - forwardSkipWhitespaceAndComments(PastCondEndLoc, SM, Context); + forwardSkipWhitespaceAndComments(PastCondEndLoc, SM, LangOpts); if (RParenLoc.isInvalid()) return {}; - tok::TokenKind TokKind = getTokenKind(RParenLoc, SM, Context); + tok::TokenKind TokKind = getTokenKind(RParenLoc, SM, LangOpts); if (TokKind != tok::r_paren) return {}; return RParenLoc; @@ -188,86 +144,23 @@ BracesAroundStatementsCheck::findRParenLoc(const IfOrWhileStmt *S, bool BracesAroundStatementsCheck::checkStmt( const MatchFinder::MatchResult &Result, const Stmt *S, SourceLocation StartLoc, SourceLocation EndLocHint) { - while (const auto *AS = dyn_cast(S)) S = AS->getSubStmt(); - const SourceManager &SM = *Result.SourceManager; - const ASTContext *Context = Result.Context; - - // 1) If there's a corresponding "else" or "while", the check inserts "} " - // right before that token. - // 2) If there's a multi-line block comment starting on the same line after - // the location we're inserting the closing brace at, or there's a non-comment - // token, the check inserts "\n}" right before that token. - // 3) Otherwise the check finds the end of line (possibly after some block or - // line comments) and inserts "\n}" right before that EOL. - if (!S || isa(S)) { - // Already inside braces. - return false; - } - - // When TreeTransform, Stmt in constexpr IfStmt will be transform to NullStmt. - // This NullStmt can be detected according to beginning token. - const SourceLocation StmtBeginLoc = S->getBeginLoc(); - if (isa(S) && StmtBeginLoc.isValid() && - getTokenKind(StmtBeginLoc, SM, Context) == tok::l_brace) - return false; - - if (StartLoc.isInvalid()) - return false; - - // Convert StartLoc to file location, if it's on the same macro expansion - // level as the start of the statement. We also need file locations for - // Lexer::getLocForEndOfToken working properly. - StartLoc = Lexer::makeFileCharRange( - CharSourceRange::getCharRange(StartLoc, S->getBeginLoc()), SM, - Context->getLangOpts()) - .getBegin(); - if (StartLoc.isInvalid()) - return false; - StartLoc = - Lexer::getLocForEndOfToken(StartLoc, 0, SM, Context->getLangOpts()); - - // StartLoc points at the location of the opening brace to be inserted. - SourceLocation EndLoc; - std::string ClosingInsertion; - if (EndLocHint.isValid()) { - EndLoc = EndLocHint; - ClosingInsertion = "} "; - } else { - EndLoc = findEndLocation(*S, SM, Context); - ClosingInsertion = "\n}"; - } - - assert(StartLoc.isValid()); - - // Don't require braces for statements spanning less than certain number of - // lines. - if (ShortStatementLines && !ForceBracesStmts.erase(S)) { - unsigned StartLine = SM.getSpellingLineNumber(StartLoc); - unsigned EndLine = SM.getSpellingLineNumber(EndLoc); - if (EndLine - StartLine < ShortStatementLines) + const auto BraceInsertionHints = utils::getBraceInsertionsHints( + S, Result.Context->getLangOpts(), *Result.SourceManager, StartLoc, + EndLocHint); + if (BraceInsertionHints) { + if (ShortStatementLines && !ForceBracesStmts.erase(S) && + BraceInsertionHints.resultingCompoundLineExtent(*Result.SourceManager) < + ShortStatementLines) return false; + auto Diag = diag(BraceInsertionHints.DiagnosticPos, + "statement should be inside braces"); + if (BraceInsertionHints.offersFixIts()) + Diag << BraceInsertionHints.openingBraceFixIt() + << BraceInsertionHints.closingBraceFixIt(); } - - auto Diag = diag(StartLoc, "statement should be inside braces"); - - // Change only if StartLoc and EndLoc are on the same macro expansion level. - // This will also catch invalid EndLoc. - // Example: LLVM_DEBUG( for(...) do_something() ); - // In this case fix-it cannot be provided as the semicolon which is not - // visible here is part of the macro. Adding braces here would require adding - // another semicolon. - if (Lexer::makeFileCharRange( - CharSourceRange::getTokenRange(SourceRange( - SM.getSpellingLoc(StartLoc), SM.getSpellingLoc(EndLoc))), - SM, Context->getLangOpts()) - .isInvalid()) - return false; - - Diag << FixItHint::CreateInsertion(StartLoc, " {") - << FixItHint::CreateInsertion(EndLoc, ClosingInsertion); return true; } diff --git a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h index 249aa1aaaa91545549c847912feb3415a381e8cf..4cd37a7b2dd6cc169f9301d6a21b1613748399db 100644 --- a/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h +++ b/clang-tools-extra/clang-tidy/readability/BracesAroundStatementsCheck.h @@ -52,7 +52,7 @@ private: SourceLocation EndLocHint = SourceLocation()); template SourceLocation findRParenLoc(const IfOrWhileStmt *S, const SourceManager &SM, - const ASTContext *Context); + const LangOptions &LangOpts); std::optional getCheckTraversalKind() const override { return TK_IgnoreUnlessSpelledInSource; } diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt index 5728c9970fb65d5334225cce3d3db69e013bdf62..dd772d692025481a9eae7475168f96ec29baf6fe 100644 --- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt @@ -17,6 +17,7 @@ add_clang_library(clangTidyReadabilityModule DeleteNullPointerCheck.cpp DuplicateIncludeCheck.cpp ElseAfterReturnCheck.cpp + EnumInitialValueCheck.cpp FunctionCognitiveComplexityCheck.cpp FunctionSizeCheck.cpp IdentifierLengthCheck.cpp diff --git a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp index 67147164946ab405138aeafbb361f490f4382ad6..229e5583846b96c0a4ddc537bc78d7a4467fa355 100644 --- a/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/DuplicateIncludeCheck.cpp @@ -79,6 +79,10 @@ void DuplicateIncludeCallbacks::InclusionDirective( bool IsAngled, CharSourceRange FilenameRange, OptionalFileEntryRef File, StringRef SearchPath, StringRef RelativePath, const Module *SuggestedModule, bool ModuleImported, SrcMgr::CharacteristicKind FileType) { + // Skip includes behind macros + if (FilenameRange.getBegin().isMacroID() || + FilenameRange.getEnd().isMacroID()) + return; if (llvm::is_contained(Files.back(), FileName)) { // We want to delete the entire line, so make sure that [Start,End] covers // everything. diff --git a/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp b/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f2841c32259a254a9b2821e6382e6b51714e177 --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.cpp @@ -0,0 +1,200 @@ +//===--- EnumInitialValueCheck.cpp - clang-tidy ---------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "EnumInitialValueCheck.h" +#include "../utils/LexerUtils.h" +#include "clang/AST/Decl.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::readability { + +static bool isNoneEnumeratorsInitialized(const EnumDecl &Node) { + return llvm::all_of(Node.enumerators(), [](const EnumConstantDecl *ECD) { + return ECD->getInitExpr() == nullptr; + }); +} + +static bool isOnlyFirstEnumeratorInitialized(const EnumDecl &Node) { + bool IsFirst = true; + for (const EnumConstantDecl *ECD : Node.enumerators()) { + if ((IsFirst && ECD->getInitExpr() == nullptr) || + (!IsFirst && ECD->getInitExpr() != nullptr)) + return false; + IsFirst = false; + } + return !IsFirst; +} + +static bool areAllEnumeratorsInitialized(const EnumDecl &Node) { + return llvm::all_of(Node.enumerators(), [](const EnumConstantDecl *ECD) { + return ECD->getInitExpr() != nullptr; + }); +} + +/// Check if \p Enumerator is initialized with a (potentially negated) \c +/// IntegerLiteral. +static bool isInitializedByLiteral(const EnumConstantDecl *Enumerator) { + const Expr *const Init = Enumerator->getInitExpr(); + if (!Init) + return false; + return Init->isIntegerConstantExpr(Enumerator->getASTContext()); +} + +static void cleanInitialValue(DiagnosticBuilder &Diag, + const EnumConstantDecl *ECD, + const SourceManager &SM, + const LangOptions &LangOpts) { + const SourceRange InitExprRange = ECD->getInitExpr()->getSourceRange(); + if (InitExprRange.isInvalid() || InitExprRange.getBegin().isMacroID() || + InitExprRange.getEnd().isMacroID()) + return; + std::optional EqualToken = utils::lexer::findNextTokenSkippingComments( + ECD->getLocation(), SM, LangOpts); + if (!EqualToken.has_value() || + EqualToken.value().getKind() != tok::TokenKind::equal) + return; + const SourceLocation EqualLoc{EqualToken->getLocation()}; + if (EqualLoc.isInvalid() || EqualLoc.isMacroID()) + return; + Diag << FixItHint::CreateRemoval(EqualLoc) + << FixItHint::CreateRemoval(InitExprRange); + return; +} + +namespace { + +AST_MATCHER(EnumDecl, isMacro) { + SourceLocation Loc = Node.getBeginLoc(); + return Loc.isMacroID(); +} + +AST_MATCHER(EnumDecl, hasConsistentInitialValues) { + return isNoneEnumeratorsInitialized(Node) || + isOnlyFirstEnumeratorInitialized(Node) || + areAllEnumeratorsInitialized(Node); +} + +AST_MATCHER(EnumDecl, hasZeroInitialValueForFirstEnumerator) { + const EnumDecl::enumerator_range Enumerators = Node.enumerators(); + if (Enumerators.empty()) + return false; + const EnumConstantDecl *ECD = *Enumerators.begin(); + return isOnlyFirstEnumeratorInitialized(Node) && + isInitializedByLiteral(ECD) && ECD->getInitVal().isZero(); +} + +/// Excludes bitfields because enumerators initialized with the result of a +/// bitwise operator on enumeration values or any other expr that is not a +/// potentially negative integer literal. +/// Enumerations where it is not directly clear if they are used with +/// bitmask, evident when enumerators are only initialized with (potentially +/// negative) integer literals, are ignored. This is also the case when all +/// enumerators are powers of two (e.g., 0, 1, 2). +AST_MATCHER(EnumDecl, hasSequentialInitialValues) { + const EnumDecl::enumerator_range Enumerators = Node.enumerators(); + if (Enumerators.empty()) + return false; + const EnumConstantDecl *const FirstEnumerator = *Node.enumerator_begin(); + llvm::APSInt PrevValue = FirstEnumerator->getInitVal(); + if (!isInitializedByLiteral(FirstEnumerator)) + return false; + bool AllEnumeratorsArePowersOfTwo = true; + for (const EnumConstantDecl *Enumerator : llvm::drop_begin(Enumerators)) { + const llvm::APSInt NewValue = Enumerator->getInitVal(); + if (NewValue != ++PrevValue) + return false; + if (!isInitializedByLiteral(Enumerator)) + return false; + PrevValue = NewValue; + AllEnumeratorsArePowersOfTwo &= NewValue.isPowerOf2(); + } + return !AllEnumeratorsArePowersOfTwo; +} + +} // namespace + +EnumInitialValueCheck::EnumInitialValueCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + AllowExplicitZeroFirstInitialValue( + Options.get("AllowExplicitZeroFirstInitialValue", true)), + AllowExplicitSequentialInitialValues( + Options.get("AllowExplicitSequentialInitialValues", true)) {} + +void EnumInitialValueCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "AllowExplicitZeroFirstInitialValue", + AllowExplicitZeroFirstInitialValue); + Options.store(Opts, "AllowExplicitSequentialInitialValues", + AllowExplicitSequentialInitialValues); +} + +void EnumInitialValueCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + enumDecl(unless(isMacro()), unless(hasConsistentInitialValues())) + .bind("inconsistent"), + this); + if (!AllowExplicitZeroFirstInitialValue) + Finder->addMatcher( + enumDecl(hasZeroInitialValueForFirstEnumerator()).bind("zero_first"), + this); + if (!AllowExplicitSequentialInitialValues) + Finder->addMatcher(enumDecl(unless(isMacro()), hasSequentialInitialValues()) + .bind("sequential"), + this); +} + +void EnumInitialValueCheck::check(const MatchFinder::MatchResult &Result) { + if (const auto *Enum = Result.Nodes.getNodeAs("inconsistent")) { + DiagnosticBuilder Diag = + diag(Enum->getBeginLoc(), + "inital values in enum %0 are not consistent, consider explicit " + "initialization of all, none or only the first enumerator") + << Enum; + for (const EnumConstantDecl *ECD : Enum->enumerators()) + if (ECD->getInitExpr() == nullptr) { + const SourceLocation EndLoc = Lexer::getLocForEndOfToken( + ECD->getLocation(), 0, *Result.SourceManager, getLangOpts()); + if (EndLoc.isMacroID()) + continue; + llvm::SmallString<8> Str{" = "}; + ECD->getInitVal().toString(Str); + Diag << FixItHint::CreateInsertion(EndLoc, Str); + } + return; + } + + if (const auto *Enum = Result.Nodes.getNodeAs("zero_first")) { + const EnumConstantDecl *ECD = *Enum->enumerator_begin(); + const SourceLocation Loc = ECD->getLocation(); + if (Loc.isInvalid() || Loc.isMacroID()) + return; + DiagnosticBuilder Diag = diag(Loc, "zero initial value for the first " + "enumerator in %0 can be disregarded") + << Enum; + cleanInitialValue(Diag, ECD, *Result.SourceManager, getLangOpts()); + return; + } + if (const auto *Enum = Result.Nodes.getNodeAs("sequential")) { + DiagnosticBuilder Diag = + diag(Enum->getBeginLoc(), + "sequential initial value in %0 can be ignored") + << Enum; + for (const EnumConstantDecl *ECD : llvm::drop_begin(Enum->enumerators())) + cleanInitialValue(Diag, ECD, *Result.SourceManager, getLangOpts()); + return; + } +} + +} // namespace clang::tidy::readability diff --git a/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.h b/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.h new file mode 100644 index 0000000000000000000000000000000000000000..66087e4ee170da955c43bfa6cb553a092442705b --- /dev/null +++ b/clang-tools-extra/clang-tidy/readability/EnumInitialValueCheck.h @@ -0,0 +1,38 @@ +//===--- EnumInitialValueCheck.h - clang-tidy -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ENUMINITIALVALUECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ENUMINITIALVALUECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::readability { + +/// Enforces consistent style for enumerators' initialization, covering three +/// styles: none, first only, or all initialized explicitly. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/readability/enum-initial-value.html +class EnumInitialValueCheck : public ClangTidyCheck { +public: + EnumInitialValueCheck(StringRef Name, ClangTidyContext *Context); + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + std::optional getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } + +private: + const bool AllowExplicitZeroFirstInitialValue; + const bool AllowExplicitSequentialInitialValues; +}; + +} // namespace clang::tidy::readability + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_ENUMINITIALVALUECHECK_H diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp index bca2c425111f6cd1594316ca05971d290dbf1062..376b84683df74e4e8880431b58a70220b600e486 100644 --- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp @@ -22,6 +22,7 @@ #include "DeleteNullPointerCheck.h" #include "DuplicateIncludeCheck.h" #include "ElseAfterReturnCheck.h" +#include "EnumInitialValueCheck.h" #include "FunctionCognitiveComplexityCheck.h" #include "FunctionSizeCheck.h" #include "IdentifierLengthCheck.h" @@ -92,6 +93,8 @@ public: "readability-duplicate-include"); CheckFactories.registerCheck( "readability-else-after-return"); + CheckFactories.registerCheck( + "readability-enum-initial-value"); CheckFactories.registerCheck( "readability-function-cognitive-complexity"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.h b/clang-tools-extra/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.h index c28087e07e9b61f55a048c4b533c9045b44c9fe6..620cd6e3f2f8779792ddec763a7d636234217698 100644 --- a/clang-tools-extra/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.h +++ b/clang-tools-extra/clang-tidy/readability/StaticDefinitionInAnonymousNamespaceCheck.h @@ -24,6 +24,12 @@ public: : ClangTidyCheck(Name, Context) {} void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + std::optional getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } }; } // namespace clang::tidy::readability diff --git a/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.cpp b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2a3b7bed08c1e00363d9ad2c899528d8e150f61e --- /dev/null +++ b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.cpp @@ -0,0 +1,168 @@ +//===--- BracesAroundStatement.cpp - clang-tidy -------- ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file provides utilities to put braces around a statement. +/// +//===----------------------------------------------------------------------===// + +#include "BracesAroundStatement.h" +#include "../utils/LexerUtils.h" +#include "LexerUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Lex/Lexer.h" + +namespace clang::tidy::utils { + +BraceInsertionHints::operator bool() const { return DiagnosticPos.isValid(); } + +bool BraceInsertionHints::offersFixIts() const { + return OpeningBracePos.isValid() && ClosingBracePos.isValid(); +} + +unsigned BraceInsertionHints::resultingCompoundLineExtent( + const SourceManager &SourceMgr) const { + return SourceMgr.getSpellingLineNumber(ClosingBracePos) - + SourceMgr.getSpellingLineNumber(OpeningBracePos); +} + +FixItHint BraceInsertionHints::openingBraceFixIt() const { + return OpeningBracePos.isValid() + ? FixItHint::CreateInsertion(OpeningBracePos, " {") + : FixItHint(); +} + +FixItHint BraceInsertionHints::closingBraceFixIt() const { + return ClosingBracePos.isValid() + ? FixItHint::CreateInsertion(ClosingBracePos, ClosingBrace) + : FixItHint(); +} + +static tok::TokenKind getTokenKind(SourceLocation Loc, const SourceManager &SM, + const LangOptions &LangOpts) { + Token Tok; + SourceLocation Beginning = Lexer::GetBeginningOfToken(Loc, SM, LangOpts); + const bool Invalid = Lexer::getRawToken(Beginning, Tok, SM, LangOpts); + assert(!Invalid && "Expected a valid token."); + + if (Invalid) + return tok::NUM_TOKENS; + + return Tok.getKind(); +} + +static SourceLocation findEndLocation(const Stmt &S, const SourceManager &SM, + const LangOptions &LangOpts) { + SourceLocation Loc = lexer::getUnifiedEndLoc(S, SM, LangOpts); + if (!Loc.isValid()) + return Loc; + + // Start searching right after S. + Loc = Loc.getLocWithOffset(1); + + for (;;) { + assert(Loc.isValid()); + while (isHorizontalWhitespace(*SM.getCharacterData(Loc))) { + Loc = Loc.getLocWithOffset(1); + } + + if (isVerticalWhitespace(*SM.getCharacterData(Loc))) { + // EOL, insert brace before. + break; + } + tok::TokenKind TokKind = getTokenKind(Loc, SM, LangOpts); + if (TokKind != tok::comment) { + // Non-comment token, insert brace before. + break; + } + + SourceLocation TokEndLoc = Lexer::getLocForEndOfToken(Loc, 0, SM, LangOpts); + SourceRange TokRange(Loc, TokEndLoc); + StringRef Comment = Lexer::getSourceText( + CharSourceRange::getTokenRange(TokRange), SM, LangOpts); + if (Comment.starts_with("/*") && Comment.contains('\n')) { + // Multi-line block comment, insert brace before. + break; + } + // else: Trailing comment, insert brace after the newline. + + // Fast-forward current token. + Loc = TokEndLoc; + } + return Loc; +} + +BraceInsertionHints getBraceInsertionsHints(const Stmt *const S, + const LangOptions &LangOpts, + const SourceManager &SM, + SourceLocation StartLoc, + SourceLocation EndLocHint) { + // 1) If there's a corresponding "else" or "while", the check inserts "} " + // right before that token. + // 2) If there's a multi-line block comment starting on the same line after + // the location we're inserting the closing brace at, or there's a non-comment + // token, the check inserts "\n}" right before that token. + // 3) Otherwise the check finds the end of line (possibly after some block or + // line comments) and inserts "\n}" right before that EOL. + if (!S || isa(S)) { + // Already inside braces. + return {}; + } + + // When TreeTransform, Stmt in constexpr IfStmt will be transform to NullStmt. + // This NullStmt can be detected according to beginning token. + const SourceLocation StmtBeginLoc = S->getBeginLoc(); + if (isa(S) && StmtBeginLoc.isValid() && + getTokenKind(StmtBeginLoc, SM, LangOpts) == tok::l_brace) + return {}; + + if (StartLoc.isInvalid()) + return {}; + + // Convert StartLoc to file location, if it's on the same macro expansion + // level as the start of the statement. We also need file locations for + // Lexer::getLocForEndOfToken working properly. + StartLoc = Lexer::makeFileCharRange( + CharSourceRange::getCharRange(StartLoc, S->getBeginLoc()), SM, + LangOpts) + .getBegin(); + if (StartLoc.isInvalid()) + return {}; + StartLoc = Lexer::getLocForEndOfToken(StartLoc, 0, SM, LangOpts); + + // StartLoc points at the location of the opening brace to be inserted. + SourceLocation EndLoc; + std::string ClosingInsertion; + if (EndLocHint.isValid()) { + EndLoc = EndLocHint; + ClosingInsertion = "} "; + } else { + EndLoc = findEndLocation(*S, SM, LangOpts); + ClosingInsertion = "\n}"; + } + + assert(StartLoc.isValid()); + + // Change only if StartLoc and EndLoc are on the same macro expansion level. + // This will also catch invalid EndLoc. + // Example: LLVM_DEBUG( for(...) do_something() ); + // In this case fix-it cannot be provided as the semicolon which is not + // visible here is part of the macro. Adding braces here would require adding + // another semicolon. + if (Lexer::makeFileCharRange( + CharSourceRange::getTokenRange(SourceRange( + SM.getSpellingLoc(StartLoc), SM.getSpellingLoc(EndLoc))), + SM, LangOpts) + .isInvalid()) + return {StartLoc}; + return {StartLoc, EndLoc, ClosingInsertion}; +} + +} // namespace clang::tidy::utils diff --git a/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.h b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.h new file mode 100644 index 0000000000000000000000000000000000000000..cb1c06c7aa1a1a9d5bdd56cd805aa26f19e56c8d --- /dev/null +++ b/clang-tools-extra/clang-tidy/utils/BracesAroundStatement.h @@ -0,0 +1,75 @@ +//===--- BracesAroundStatement.h - clang-tidy ------- -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file provides utilities to put braces around a statement. +/// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Stmt.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" + +namespace clang::tidy::utils { + +/// A provider of fix-it hints to insert opening and closing braces. An instance +/// of this type is the result of calling `getBraceInsertionsHints` below. +struct BraceInsertionHints { + /// The position of a potential diagnostic. It coincides with the position of + /// the opening brace to insert, but can also just be the place to show a + /// diagnostic in case braces cannot be inserted automatically. + SourceLocation DiagnosticPos; + + /// Constructor for a no-hint. + BraceInsertionHints() = default; + + /// Constructor for a valid hint that cannot insert braces automatically. + BraceInsertionHints(SourceLocation DiagnosticPos) + : DiagnosticPos(DiagnosticPos) {} + + /// Constructor for a hint offering fix-its for brace insertion. Both + /// positions must be valid. + BraceInsertionHints(SourceLocation OpeningBracePos, + SourceLocation ClosingBracePos, std::string ClosingBrace) + : DiagnosticPos(OpeningBracePos), OpeningBracePos(OpeningBracePos), + ClosingBracePos(ClosingBracePos), ClosingBrace(ClosingBrace) { + assert(offersFixIts()); + } + + /// Indicates whether the hint provides at least the position of a diagnostic. + operator bool() const; + + /// Indicates whether the hint provides fix-its to insert braces. + bool offersFixIts() const; + + /// The number of lines between the inserted opening brace and its closing + /// counterpart. + unsigned resultingCompoundLineExtent(const SourceManager &SourceMgr) const; + + /// Fix-it to insert an opening brace. + FixItHint openingBraceFixIt() const; + + /// Fix-it to insert a closing brace. + FixItHint closingBraceFixIt() const; + +private: + SourceLocation OpeningBracePos; + SourceLocation ClosingBracePos; + std::string ClosingBrace; +}; + +/// Create fix-it hints for braces that wrap the given statement when applied. +/// The algorithm computing them respects comment before and after the statement +/// and adds line breaks before the braces accordingly. +BraceInsertionHints +getBraceInsertionsHints(const Stmt *const S, const LangOptions &LangOpts, + const SourceManager &SM, SourceLocation StartLoc, + SourceLocation EndLocHint = SourceLocation()); + +} // namespace clang::tidy::utils diff --git a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt index f0160fa9df74879429e6f6be554d43bf633af0d6..9cff7d475425d792c2c2f373a3e88d34f7216513 100644 --- a/clang-tools-extra/clang-tidy/utils/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/utils/CMakeLists.txt @@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS add_clang_library(clangTidyUtils Aliasing.cpp ASTUtils.cpp + BracesAroundStatement.cpp DeclRefExprUtils.cpp DesignatedInitializers.cpp ExceptionAnalyzer.cpp diff --git a/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp b/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp index b6d9c50d0b109c1c24323e304500165a607287d3..a44720c47eca2d7eb9ef815d7cea3dc18a44c616 100644 --- a/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp +++ b/clang-tools-extra/clang-tidy/utils/IncludeSorter.cpp @@ -108,7 +108,7 @@ int compareHeaders(StringRef LHS, StringRef RHS, IncludeSorter::IncludeStyle Style) { if (Style == IncludeSorter::IncludeStyle::IS_Google_ObjC) { const std::pair &Mismatch = - std::mismatch(LHS.begin(), LHS.end(), RHS.begin()); + std::mismatch(LHS.begin(), LHS.end(), RHS.begin(), RHS.end()); if ((Mismatch.first != LHS.end()) && (Mismatch.second != RHS.end())) { if ((*Mismatch.first == '.') && (*Mismatch.second == '+')) { return -1; diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp index da1433aa2d05d472f5f581973fead7993d468794..ad8048e2a92b7e37241c37836e59da568a264a86 100644 --- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp +++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp @@ -31,13 +31,12 @@ struct DenseMapInfo { using NamingCheckId = clang::tidy::RenamerClangTidyCheck::NamingCheckId; static inline NamingCheckId getEmptyKey() { - return {DenseMapInfo::getEmptyKey(), - "EMPTY"}; + return {DenseMapInfo::getEmptyKey(), "EMPTY"}; } static inline NamingCheckId getTombstoneKey() { return {DenseMapInfo::getTombstoneKey(), - "TOMBSTONE"}; + "TOMBSTONE"}; } static unsigned getHashValue(NamingCheckId Val) { @@ -367,6 +366,23 @@ public: return true; } + bool VisitDesignatedInitExpr(DesignatedInitExpr *Expr) { + for (const DesignatedInitExpr::Designator &D : Expr->designators()) { + if (!D.isFieldDesignator()) + continue; + const FieldDecl *FD = D.getFieldDecl(); + if (!FD) + continue; + const IdentifierInfo *II = FD->getIdentifier(); + if (!II) + continue; + SourceRange FixLocation{D.getFieldLoc(), D.getFieldLoc()}; + Check->addUsage(FD, FixLocation, SM); + } + + return true; + } + private: RenamerClangTidyCheck *Check; const SourceManager *SM; @@ -473,7 +489,7 @@ void RenamerClangTidyCheck::checkNamedDecl(const NamedDecl *Decl, } Failure.Info = std::move(Info); - addUsage(Decl, Range); + addUsage(Decl, Range, &SourceMgr); } void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) { diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp index f29dadde2b86d5a20d542e0c6812d42ba2be1910..7fd599d4e1a0b0e393ee6a36291955496073f12e 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -1390,7 +1390,7 @@ void ClangdLSPServer::onClangdInlayHints(const InlayHintsParams &Params, // Extension doesn't have paddingLeft/Right so adjust the label // accordingly. {"label", - ((Hint.paddingLeft ? " " : "") + llvm::StringRef(Hint.label) + + ((Hint.paddingLeft ? " " : "") + llvm::StringRef(Hint.joinLabels()) + (Hint.paddingRight ? " " : "")) .str()}, }); diff --git a/clang-tools-extra/clangd/CompileCommands.cpp b/clang-tools-extra/clangd/CompileCommands.cpp index 5b8128fca62668ca555f049b7652369cd11be39e..fddfffe7523d9516037e310bd0d20b0c9520d100 100644 --- a/clang-tools-extra/clangd/CompileCommands.cpp +++ b/clang-tools-extra/clangd/CompileCommands.cpp @@ -466,7 +466,8 @@ llvm::ArrayRef ArgStripper::rulesFor(llvm::StringRef Arg) { static constexpr llvm::ArrayRef NAME( \ NAME##_init, std::size(NAME##_init) - 1); #define OPTION(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \ - FLAGS, VISIBILITY, PARAM, HELP, METAVAR, VALUES) \ + FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, \ + METAVAR, VALUES) \ Prefixes[DriverID::OPT_##ID] = PREFIX; #include "clang/Driver/Options.inc" #undef OPTION @@ -478,7 +479,8 @@ llvm::ArrayRef ArgStripper::rulesFor(llvm::StringRef Arg) { const void *AliasArgs; } AliasTable[] = { #define OPTION(PREFIX, PREFIXED_NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, \ - FLAGS, VISIBILITY, PARAM, HELP, METAVAR, VALUES) \ + FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, \ + METAVAR, VALUES) \ {DriverID::OPT_##ID, DriverID::OPT_##ALIAS, ALIASARGS}, #include "clang/Driver/Options.inc" #undef OPTION diff --git a/clang-tools-extra/clangd/IncludeCleaner.h b/clang-tools-extra/clangd/IncludeCleaner.h index 387763de340767be7e3cf8598db2b1a6c7076fd5..624e2116be7da3015816dfec628d8de6ac7f363c 100644 --- a/clang-tools-extra/clangd/IncludeCleaner.h +++ b/clang-tools-extra/clangd/IncludeCleaner.h @@ -62,15 +62,6 @@ issueIncludeCleanerDiagnostics(ParsedAST &AST, llvm::StringRef Code, const ThreadsafeFS &TFS, HeaderFilter IgnoreHeader = {}); -/// Affects whether standard library includes should be considered for -/// removal. This is off by default for now due to implementation limitations: -/// - macros are not tracked -/// - symbol names without a unique associated header are not tracked -/// - references to std-namespaced C types are not properly tracked: -/// instead of std::size_t -> we see ::size_t -> -/// FIXME: remove this hack once the implementation is good enough. -void setIncludeCleanerAnalyzesStdlib(bool B); - /// Converts the clangd include representation to include-cleaner /// include representation. include_cleaner::Includes convertIncludes(const ParsedAST &); diff --git a/clang-tools-extra/clangd/InlayHints.cpp b/clang-tools-extra/clangd/InlayHints.cpp index a0ebc631ef8285ad37ac5da70df63bb3152494f7..cd4f1931b3ce1dabd27195366c66349f0ff01cf0 100644 --- a/clang-tools-extra/clangd/InlayHints.cpp +++ b/clang-tools-extra/clangd/InlayHints.cpp @@ -977,8 +977,9 @@ private: return; bool PadLeft = Prefix.consume_front(" "); bool PadRight = Suffix.consume_back(" "); - Results.push_back(InlayHint{LSPPos, (Prefix + Label + Suffix).str(), Kind, - PadLeft, PadRight, LSPRange}); + Results.push_back(InlayHint{LSPPos, + /*label=*/{(Prefix + Label + Suffix).str()}, + Kind, PadLeft, PadRight, LSPRange}); } // Get the range of the main file that *exactly* corresponds to R. diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp index c6553e00dcae28209da96ff0eb6a7dd2288d008f..c08f80442eaa0605c1a7513ace13cb57032518c3 100644 --- a/clang-tools-extra/clangd/Protocol.cpp +++ b/clang-tools-extra/clangd/Protocol.cpp @@ -1501,6 +1501,10 @@ bool operator<(const InlayHint &A, const InlayHint &B) { return std::tie(A.position, A.range, A.kind, A.label) < std::tie(B.position, B.range, B.kind, B.label); } +std::string InlayHint::joinLabels() const { + return llvm::join(llvm::map_range(label, [](auto &L) { return L.value; }), + ""); +} llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, InlayHintKind Kind) { auto ToString = [](InlayHintKind K) { @@ -1519,6 +1523,33 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, InlayHintKind Kind) { return OS << ToString(Kind); } +llvm::json::Value toJSON(const InlayHintLabelPart &L) { + llvm::json::Object Result{{"value", L.value}}; + if (L.tooltip) + Result["tooltip"] = *L.tooltip; + if (L.location) + Result["location"] = *L.location; + if (L.command) + Result["command"] = *L.command; + return Result; +} + +bool operator==(const InlayHintLabelPart &LHS, const InlayHintLabelPart &RHS) { + return std::tie(LHS.value, LHS.location) == std::tie(RHS.value, RHS.location); +} + +bool operator<(const InlayHintLabelPart &LHS, const InlayHintLabelPart &RHS) { + return std::tie(LHS.value, LHS.location) < std::tie(RHS.value, RHS.location); +} + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const InlayHintLabelPart &L) { + OS << L.value; + if (L.location) + OS << " (" << L.location << ")"; + return OS; +} + static const char *toString(OffsetEncoding OE) { switch (OE) { case OffsetEncoding::UTF8: diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h index 358d4c6feaf87d45c5f0a3fc4f3f0635af168a8d..a0f8b04bc4ffdb043212d13861d78e7dbc8ecdd2 100644 --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -1689,6 +1689,48 @@ enum class InlayHintKind { }; llvm::json::Value toJSON(const InlayHintKind &); +/// An inlay hint label part allows for interactive and composite labels +/// of inlay hints. +struct InlayHintLabelPart { + + InlayHintLabelPart() = default; + + InlayHintLabelPart(std::string value, + std::optional location = std::nullopt) + : value(std::move(value)), location(std::move(location)) {} + + /// The value of this label part. + std::string value; + + /// The tooltip text when you hover over this label part. Depending on + /// the client capability `inlayHint.resolveSupport`, clients might resolve + /// this property late using the resolve request. + std::optional tooltip; + + /// An optional source code location that represents this + /// label part. + /// + /// The editor will use this location for the hover and for code navigation + /// features: This part will become a clickable link that resolves to the + /// definition of the symbol at the given location (not necessarily the + /// location itself), it shows the hover that shows at the given location, + /// and it shows a context menu with further code navigation commands. + /// + /// Depending on the client capability `inlayHint.resolveSupport` clients + /// might resolve this property late using the resolve request. + std::optional location; + + /// An optional command for this label part. + /// + /// Depending on the client capability `inlayHint.resolveSupport` clients + /// might resolve this property late using the resolve request. + std::optional command; +}; +llvm::json::Value toJSON(const InlayHintLabelPart &); +bool operator==(const InlayHintLabelPart &, const InlayHintLabelPart &); +bool operator<(const InlayHintLabelPart &, const InlayHintLabelPart &); +llvm::raw_ostream &operator<<(llvm::raw_ostream &, const InlayHintLabelPart &); + /// Inlay hint information. struct InlayHint { /// The position of this hint. @@ -1698,7 +1740,7 @@ struct InlayHint { /// InlayHintLabelPart label parts. /// /// *Note* that neither the string nor the label part can be empty. - std::string label; + std::vector label; /// The kind of this hint. Can be omitted in which case the client should fall /// back to a reasonable default. @@ -1724,6 +1766,9 @@ struct InlayHint { /// The range allows clients more flexibility of when/how to display the hint. /// This is an (unserialized) clangd extension. Range range; + + /// Join the label[].value together. + std::string joinLabels() const; }; llvm::json::Value toJSON(const InlayHint &); bool operator==(const InlayHint &, const InlayHint &); diff --git a/clang-tools-extra/clangd/support/Trace.h b/clang-tools-extra/clangd/support/Trace.h index 1bfc75b874d8a9b1bee0de26990e9fff3f0cacdb..36c3745a41e969f03866931aa9bcefddffda4ce3 100644 --- a/clang-tools-extra/clangd/support/Trace.h +++ b/clang-tools-extra/clangd/support/Trace.h @@ -143,8 +143,8 @@ bool enabled(); class Span { public: Span(llvm::Twine Name); - /// Records span's duration in seconds to \p LatencyMetric with \p Name as the - /// label. + /// Records span's duration in milliseconds to \p LatencyMetric with \p Name + /// as the label. Span(llvm::Twine Name, const Metric &LatencyMetric); ~Span(); diff --git a/clang-tools-extra/clangd/test/inlayHints.test b/clang-tools-extra/clangd/test/inlayHints.test index 8f302dd17a5494f246d15b9a2468c04664d1d105..e5b3c0fb0b960aa13a1acefb184e9795ff4854c8 100644 --- a/clang-tools-extra/clangd/test/inlayHints.test +++ b/clang-tools-extra/clangd/test/inlayHints.test @@ -51,7 +51,11 @@ # CHECK-NEXT: "result": [ # CHECK-NEXT: { # CHECK-NEXT: "kind": 2, -# CHECK-NEXT: "label": "bar:", +# CHECK-NEXT: "label": [ +# CHECK-NEXT: { +# CHECK-NEXT: "value": "bar:" +# CHECK-NEXT: } +# CHECK-NEXT: ], # CHECK-NEXT: "paddingLeft": false, # CHECK-NEXT: "paddingRight": true, # CHECK-NEXT: "position": { diff --git a/clang-tools-extra/clangd/tool/Check.cpp b/clang-tools-extra/clangd/tool/Check.cpp index 45e2e1e278deafa4843d8f7945472b961f7519a4..25005ec1bd04532093d24334ece75f7661f5c0e7 100644 --- a/clang-tools-extra/clangd/tool/Check.cpp +++ b/clang-tools-extra/clangd/tool/Check.cpp @@ -367,7 +367,13 @@ public: auto Hints = inlayHints(*AST, LineRange); for (const auto &Hint : Hints) { - vlog(" {0} {1} {2}", Hint.kind, Hint.position, Hint.label); + vlog(" {0} {1} [{2}]", Hint.kind, Hint.position, [&] { + return llvm::join(llvm::map_range(Hint.label, + [&](auto &L) { + return llvm::formatv("{{{0}}", L); + }), + ", "); + }()); } } diff --git a/clang-tools-extra/clangd/unittests/HoverTests.cpp b/clang-tools-extra/clangd/unittests/HoverTests.cpp index 35db757b9c15b5d3258552783cbbe5351c8d1a3c..5ead74748f550cb4536c7edf9cc246a4d41b5a42 100644 --- a/clang-tools-extra/clangd/unittests/HoverTests.cpp +++ b/clang-tools-extra/clangd/unittests/HoverTests.cpp @@ -1983,10 +1983,14 @@ TEST(Hover, All) { HI.Kind = index::SymbolKind::Macro; HI.Definition = R"cpp(#define MACRO \ - { return 0; } + { \ + return 0; \ + } // Expands to -{ return 0; })cpp"; +{ + return 0; +})cpp"; }}, { R"cpp(// Forward class declaration diff --git a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp index 0fff0dfca6c9b8f21a459a4ec63b4821555c21a0..5b1531eb2fa60bcd0ae81137fcc3cf5b26fd79ee 100644 --- a/clang-tools-extra/clangd/unittests/InlayHintTests.cpp +++ b/clang-tools-extra/clangd/unittests/InlayHintTests.cpp @@ -25,7 +25,7 @@ namespace clangd { llvm::raw_ostream &operator<<(llvm::raw_ostream &Stream, const InlayHint &Hint) { - return Stream << Hint.label << "@" << Hint.range; + return Stream << Hint.joinLabels() << "@" << Hint.range; } namespace { @@ -57,10 +57,11 @@ struct ExpectedHint { MATCHER_P2(HintMatcher, Expected, Code, llvm::to_string(Expected)) { llvm::StringRef ExpectedView(Expected.Label); - if (arg.label != ExpectedView.trim(" ") || + std::string ResultLabel = arg.joinLabels(); + if (ResultLabel != ExpectedView.trim(" ") || arg.paddingLeft != ExpectedView.starts_with(" ") || arg.paddingRight != ExpectedView.ends_with(" ")) { - *result_listener << "label is '" << arg.label << "'"; + *result_listener << "label is '" << ResultLabel << "'"; return false; } if (arg.range != Code.range(Expected.RangeName)) { @@ -72,7 +73,7 @@ MATCHER_P2(HintMatcher, Expected, Code, llvm::to_string(Expected)) { return true; } -MATCHER_P(labelIs, Label, "") { return arg.label == Label; } +MATCHER_P(labelIs, Label, "") { return arg.joinLabels() == Label; } Config noHintsConfig() { Config C; diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index a604e9276668aecfab23cd583b83fcb71682a958..b66be44e9f8a6f924768759faf27dc34410ecbf4 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -123,6 +123,12 @@ New checks Finds initializer lists for aggregate types that could be written as designated initializers instead. +- New :doc:`readability-enum-initial-value + ` check. + + Enforces consistent style for enumerators' initialization, covering three + styles: none, first only, or all initialized explicitly. + - New :doc:`readability-use-std-min-max ` check. @@ -139,6 +145,10 @@ Changes in existing checks ` check by detecting side effect from calling a method with non-const reference parameters. +- Improved :doc:`bugprone-inc-dec-in-conditions + ` check to ignore code + within unevaluated contexts, such as ``decltype``. + - Improved :doc:`bugprone-non-zero-enum-to-bool-conversion ` check by eliminating false positives resulting from direct usage of bitwise operators @@ -169,20 +179,21 @@ Changes in existing checks - Improved :doc:`cppcoreguidelines-missing-std-forward ` check by no longer - giving false positives for deleted functions and fix false negative when some - parameters are forwarded, but other aren't. + giving false positives for deleted functions, by fixing false negatives when only + a few parameters are forwarded and by ignoring parameters without a name (unused + arguments). - Improved :doc:`cppcoreguidelines-owning-memory ` check to properly handle return type in lambdas and in nested functions. -- Cleaned up :doc:`cppcoreguidelines-prefer-member-initializer - ` +- Improved :doc:`cppcoreguidelines-prefer-member-initializer + ` check by removing enforcement of rule `C.48 `_, which was deprecated since :program:`clang-tidy` 17. This rule is now covered by :doc:`cppcoreguidelines-use-default-member-init - ` and fixes + `. Fixed incorrect hints when using list-initialization. - Improved :doc:`google-build-namespaces @@ -197,6 +208,13 @@ Changes in existing checks ` check by replacing the local option `HeaderFileExtensions` by the global option of the same name. +- Improved :doc:`google-runtime-int ` + check performance through optimizations. + +- Improved :doc:`hicpp-ignored-remove-result ` + check by ignoring other functions with same prefixes as the target specific + functions. + - Improved :doc:`llvm-header-guard ` check by replacing the local option `HeaderFileExtensions` by the global option of the same name. @@ -229,12 +247,29 @@ Changes in existing checks ` check to also remove any trailing whitespace when deleting the ``virtual`` keyword. +- Improved :doc:`modernize-use-using ` + check by adding support for detection of typedefs declared on function level. + - Improved :doc:`performance-unnecessary-copy-initialization ` check by detecting more cases of constant access. In particular, pointers can be analyzed, se the check now handles the common patterns `const auto e = (*vector_ptr)[i]` and `const auto e = vector_ptr->at(i);`. +- Improved :doc:`readability-avoid-return-with-void-value + ` check by adding + fix-its. + +- Improved :doc:`readability-duplicate-include + ` check by excluding include + directives that form the filename using macro. + +- Improved :doc:`readability-identifier-naming + ` check in `GetConfigPerFile` + mode by resolving symbolic links to header files. Fixed handling of Hungarian + Prefix when configured to `LowerCase`. Added support for renaming designated + initializers. Added support for renaming macro arguments. + - Improved :doc:`readability-implicit-bool-conversion ` check to provide valid fix suggestions for ``static_cast`` without a preceding space and @@ -244,10 +279,10 @@ Changes in existing checks ` check to properly emit warnings for static data member with an in-class initializer. -- Improved :doc:`readability-identifier-naming - ` check in `GetConfigPerFile` - mode by resolving symbolic links to header files. Fixed handling of Hungarian - Prefix when configured to `LowerCase`. +- Improved :doc:`readability-static-definition-in-anonymous-namespace + ` + check by resolving fix-it overlaps in template code by disregarding implicit + instances. Removed checks ^^^^^^^^^^^^^^ @@ -258,9 +293,9 @@ Removed checks Miscellaneous ^^^^^^^^^^^^^ -- Fixed incorrect formatting in ``clang-apply-replacements`` when no ``--format`` - option is specified. Now ``clang-apply-replacements`` applies formatting only with - the option. +- Fixed incorrect formatting in :program:`clang-apply-replacements` when no + ``--format`` option is specified. Now :program:`clang-apply-replacements` + applies formatting only with the option. Improvements to include-fixer ----------------------------- diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 79e81dd174e4f3d4eace4161f9023142d3648210..188a42bfddd383619ed1e143543bf5a5201c7881 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -352,6 +352,7 @@ Clang-Tidy Checks :doc:`readability-delete-null-pointer `, "Yes" :doc:`readability-duplicate-include `, "Yes" :doc:`readability-else-after-return `, "Yes" + :doc:`readability-enum-initial-value `, "Yes" :doc:`readability-function-cognitive-complexity `, :doc:`readability-function-size `, :doc:`readability-identifier-length `, diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/enum-initial-value.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/enum-initial-value.rst new file mode 100644 index 0000000000000000000000000000000000000000..660efc1eaff3e53527aad41a19151be0fe13062d --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/readability/enum-initial-value.rst @@ -0,0 +1,75 @@ +.. title:: clang-tidy - readability-enum-initial-value + +readability-enum-initial-value +============================== + +Enforces consistent style for enumerators' initialization, covering three +styles: none, first only, or all initialized explicitly. + +When adding new enumerations, inconsistent initial value will cause potential +enumeration value conflicts. + +In an enumeration, the following three cases are accepted. +1. none of enumerators are explicit initialized. +2. the first enumerator is explicit initialized. +3. all of enumerators are explicit initialized. + +.. code-block:: c++ + + // valid, none of enumerators are initialized. + enum A { + e0, + e1, + e2, + }; + + // valid, the first enumerator is initialized. + enum A { + e0 = 0, + e1, + e2, + }; + + // valid, all of enumerators are initialized. + enum A { + e0 = 0, + e1 = 1, + e2 = 2, + }; + + // invalid, e1 is not explicit initialized. + enum A { + e0 = 0, + e1, + e2 = 2, + }; + +Options +------- + +.. option:: AllowExplicitZeroFirstInitialValue + + If set to `false`, the first enumerator must not be explicitly initialized. + See examples below. Default is `true`. + + .. code-block:: c++ + + enum A { + e0 = 0, // not allowed if AllowExplicitZeroFirstInitialValue is false + e1, + e2, + }; + + +.. option:: AllowExplicitSequentialInitialValues + + If set to `false`, sequential initializations are not allowed. + See examples below. Default is `true`. + + .. code-block:: c++ + + enum A { + e0 = 1, // not allowed if AllowExplicitSequentialInitialValues is false + e1 = 2, + e2 = 3, + }; diff --git a/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp b/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp index fd2de6a17ad4a53c009c9c5d1337cce4da9f0d52..7b28d1c252d715e1eb8501a25ead5f1abc41b2ef 100644 --- a/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp +++ b/clang-tools-extra/include-cleaner/lib/FindHeaders.cpp @@ -275,6 +275,12 @@ llvm::SmallVector
headersForSymbol(const Symbol &S, // are already ranked in the stdlib mapping. if (H.kind() == Header::Standard) continue; + // Don't apply name match hints to exporting headers. As they usually have + // names similar to the original header, e.g. foo_wrapper/foo.h vs + // foo/foo.h, but shouldn't be preferred (unless marked as the public + // interface). + if ((H.Hint & Hints::OriginHeader) == Hints::None) + continue; if (nameMatch(SymbolName, H)) H.Hint |= Hints::PreferredHeader; } diff --git a/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp b/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp index 5a2a41b2d99bdd78b52b63fda3ce5db38394d404..07302142a13e363730f6a3713b9e8df806e2efdf 100644 --- a/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp +++ b/clang-tools-extra/include-cleaner/unittests/FindHeadersTest.cpp @@ -628,5 +628,24 @@ TEST_F(HeadersForSymbolTest, StandardHeaders) { tooling::stdlib::Header::named(""))); } +TEST_F(HeadersForSymbolTest, ExporterNoNameMatch) { + Inputs.Code = R"cpp( + #include "exporter/foo.h" + #include "foo_public.h" + )cpp"; + Inputs.ExtraArgs.emplace_back("-I."); + // Deliberately named as foo_public to make sure it doesn't get name-match + // boost and also gets lexicographically bigger order than "exporter/foo.h". + Inputs.ExtraFiles["foo_public.h"] = guard(R"cpp( + struct foo {}; + )cpp"); + Inputs.ExtraFiles["exporter/foo.h"] = guard(R"cpp( + #include "foo_public.h" // IWYU pragma: export + )cpp"); + buildAST(); + EXPECT_THAT(headersForFoo(), ElementsAre(physicalHeader("foo_public.h"), + physicalHeader("exporter/foo.h"))); +} + } // namespace } // namespace clang::include_cleaner diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/inc-dec-in-conditions.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/inc-dec-in-conditions.cpp index 82af039973c3bb76dab22c57bb0e0f7c2e703d6a..91de013138f0deea472742be633bec41e34417aa 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/inc-dec-in-conditions.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/inc-dec-in-conditions.cpp @@ -68,3 +68,13 @@ bool doubleCheck(Container x) { // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: decrementing and referencing a variable in a complex condition can cause unintended side-effects due to C++'s order of evaluation, consider moving the modification outside of the condition to avoid misunderstandings [bugprone-inc-dec-in-conditions] // CHECK-MESSAGES: :[[@LINE-2]]:31: warning: incrementing and referencing a variable in a complex condition can cause unintended side-effects due to C++'s order of evaluation, consider moving the modification outside of the condition to avoid misunderstandings [bugprone-inc-dec-in-conditions] } + +namespace PR85838 { + void test() + { + auto foo = 0; + auto bar = 0; + if (++foo < static_cast(bar)) {} + if (static_cast(bar) < foo) {} + } +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp index 9a50eabf619bd57a8f18091b48796e2ef7a479f1..8116db58c937d44524b6f6e3b7dd26273bc2a288 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp @@ -198,3 +198,16 @@ struct S { }; } // namespace deleted_functions + +namespace unused_arguments { + +template +void unused_argument1(F&&) {} + +template +void unused_argument2([[maybe_unused]] F&& f) {} + +template +void unused_argument3(F&& _) {} + +} // namespace unused_arguments diff --git a/clang-tools-extra/test/clang-tidy/checkers/hicpp/ignored-remove-result.cpp b/clang-tools-extra/test/clang-tidy/checkers/hicpp/ignored-remove-result.cpp index b068f08590989394dc5702f310515d9c4b7f8793..fc431024303ab2d39f1b2d50fbba01503b3b1ead 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/hicpp/ignored-remove-result.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/hicpp/ignored-remove-result.cpp @@ -15,6 +15,10 @@ ForwardIt unique(ForwardIt, ForwardIt); template InputIt find(InputIt, InputIt, const T&); +struct unique_disposable { + void* release(); +}; + class error_code { }; @@ -63,4 +67,6 @@ void noWarning() { // bugprone-unused-return-value's checked return types. errorFunc(); (void) errorFunc(); + + std::unique_disposable{}.release(); } diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp index 462bc984fd3ad5609fabde7a313d9c03e4de8abd..925e5f9c1ca54e8b274139ee114b1556dcfeb327 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-using.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s modernize-use-using %t -- -- -I %S/Inputs/use-using/ +// RUN: %check_clang_tidy %s modernize-use-using %t -- -- -fno-delayed-template-parsing -I %S/Inputs/use-using/ typedef int Type; // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: use 'using' instead of 'typedef' [modernize-use-using] @@ -342,3 +342,44 @@ typedef int InExternCPP; // CHECK-FIXES: using InExternCPP = int; } + +namespace ISSUE_72179 +{ + void foo() + { + typedef int a; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'using' instead of 'typedef' [modernize-use-using] + // CHECK-FIXES: using a = int; + + } + + void foo2() + { + typedef struct { int a; union { int b; }; } c; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'using' instead of 'typedef' [modernize-use-using] + // CHECK-FIXES: using c = struct { int a; union { int b; }; }; + } + + template + void foo3() + { + typedef T b; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: use 'using' instead of 'typedef' [modernize-use-using] + // CHECK-FIXES: using b = T; + } + + template + class MyClass + { + void foo() + { + typedef MyClass c; + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use 'using' instead of 'typedef' [modernize-use-using] + // CHECK-FIXES: using c = MyClass; + } + }; + + const auto foo4 = [](int a){typedef int d;}; + // CHECK-MESSAGES: :[[@LINE-1]]:31: warning: use 'using' instead of 'typedef' [modernize-use-using] + // CHECK-FIXES: const auto foo4 = [](int a){using d = int;}; +} diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp index f00407c99ce57021a4be3fcad13feaa9bbd24140..7c948dba3e8f7c0d4991270f3647761ec3de3dbb 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-return-with-void-value.cpp @@ -12,23 +12,30 @@ void f2() { return f1(); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: f1(); } void f3(bool b) { if (b) return f1(); // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: if (b) { f1(); return; + // CHECK-NEXT: } return f2(); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: f2(); + // CHECK-FIXES-LENIENT: f2(); } template T f4() {} void f5() { - return f4(); - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] - // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + { return f4(); } + // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:7: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: { f4(); return; } + // CHECK-FIXES-LENIENT: { f4(); return; } } void f6() { return; } @@ -41,6 +48,8 @@ void f9() { return (void)f7(); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: (void)f7(); + // CHECK-FIXES-LENIENT: (void)f7(); } #define RETURN_VOID return (void)1 @@ -50,12 +59,12 @@ void f10() { // CHECK-MESSAGES-INCLUDE-MACROS: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] } -template +template struct C { C(A) {} }; -template +template C f11() { return {}; } using VOID = void; @@ -66,4 +75,36 @@ VOID f13() { return f12(); // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: f12(); return; + // CHECK-FIXES-LENIENT: f12(); return; + (void)1; +} + +void f14() { + return /* comment */ f1() /* comment */ ; + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: /* comment */ f1() /* comment */ ; return; + // CHECK-FIXES-LENIENT: /* comment */ f1() /* comment */ ; return; + (void)1; +} + +void f15() { + return/*comment*/f1()/*comment*/;//comment + // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-MESSAGES-LENIENT: :[[@LINE-2]]:5: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: /*comment*/f1()/*comment*/; return;//comment + // CHECK-FIXES-LENIENT: /*comment*/f1()/*comment*/; return;//comment + (void)1; +} + +void f16(bool b) { + if (b) return f1(); + // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: if (b) { f1(); return; + // CHECK-NEXT: } + else return f2(); + // CHECK-MESSAGES: :[[@LINE-1]]:10: warning: return statement within a void function should not have a specified return value [readability-avoid-return-with-void-value] + // CHECK-FIXES: else { f2(); return; + // CHECK-NEXT: } } diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp index dd954c705514fb777bb5e0570623f076fb5a7070..2119602ba454b49d111524fd42730f41e76b8ede 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/duplicate-include.cpp @@ -70,3 +70,18 @@ int r; // CHECK-FIXES: {{^int q;$}} // CHECK-FIXES-NEXT: {{^#include $}} // CHECK-FIXES-NEXT: {{^int r;$}} + +namespace Issue_87303 { +#define RESET_INCLUDE_CACHE +// Expect no warnings + +#define MACRO_FILENAME "duplicate-include.h" +#include MACRO_FILENAME +#include "duplicate-include.h" + +#define MACRO_FILENAME_2 +#include +#include MACRO_FILENAME_2 + +#undef RESET_INCLUDE_CACHE +} // Issue_87303 diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.c b/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.c new file mode 100644 index 0000000000000000000000000000000000000000..c66288cbe3e9575da8f963d59874cf5ab76bddd0 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.c @@ -0,0 +1,80 @@ +// RUN: %check_clang_tidy %s readability-enum-initial-value %t +// RUN: %check_clang_tidy -check-suffix=ENABLE %s readability-enum-initial-value %t -- \ +// RUN: -config='{CheckOptions: { \ +// RUN: readability-enum-initial-value.AllowExplicitZeroFirstInitialValue: false, \ +// RUN: readability-enum-initial-value.AllowExplicitSequentialInitialValues: false, \ +// RUN: }}' + +enum EError { + // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: inital values in enum 'EError' are not consistent + // CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: inital values in enum 'EError' are not consistent + EError_a = 1, + EError_b, + // CHECK-FIXES: EError_b = 2, + EError_c = 3, +}; + +enum ENone { + ENone_a, + ENone_b, + EENone_c, +}; + +enum EFirst { + EFirst_a = 1, + EFirst_b, + EFirst_c, +}; + +enum EAll { + EAll_a = 1, + EAll_b = 2, + EAll_c = 4, +}; + +#define ENUMERATOR_1 EMacro1_b +enum EMacro1 { + // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: inital values in enum 'EMacro1' are not consistent + // CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: inital values in enum 'EMacro1' are not consistent + EMacro1_a = 1, + ENUMERATOR_1, + // CHECK-FIXES: ENUMERATOR_1 = 2, + EMacro1_c = 3, +}; + + +#define ENUMERATOR_2 EMacro2_b = 2 +enum EMacro2 { + // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: inital values in enum 'EMacro2' are not consistent + // CHECK-MESSAGES-ENABLE: :[[@LINE-2]]:1: warning: inital values in enum 'EMacro2' are not consistent + EMacro2_a = 1, + ENUMERATOR_2, + EMacro2_c, + // CHECK-FIXES: EMacro2_c = 3, +}; + +enum EnumZeroFirstInitialValue { + EnumZeroFirstInitialValue_0 = 0, + // CHECK-MESSAGES-ENABLE: :[[@LINE-1]]:3: warning: zero initial value for the first enumerator in 'EnumZeroFirstInitialValue' can be disregarded + // CHECK-FIXES-ENABLE: EnumZeroFirstInitialValue_0 , + EnumZeroFirstInitialValue_1, + EnumZeroFirstInitialValue_2, +}; + +enum EnumZeroFirstInitialValueWithComment { + EnumZeroFirstInitialValueWithComment_0 = /* == */ 0, + // CHECK-MESSAGES-ENABLE: :[[@LINE-1]]:3: warning: zero initial value for the first enumerator in 'EnumZeroFirstInitialValueWithComment' can be disregarded + // CHECK-FIXES-ENABLE: EnumZeroFirstInitialValueWithComment_0 /* == */ , + EnumZeroFirstInitialValueWithComment_1, + EnumZeroFirstInitialValueWithComment_2, +}; + +enum EnumSequentialInitialValue { + // CHECK-MESSAGES-ENABLE: :[[@LINE-1]]:1: warning: sequential initial value in 'EnumSequentialInitialValue' can be ignored + EnumSequentialInitialValue_0 = 2, + // CHECK-FIXES-ENABLE: EnumSequentialInitialValue_0 = 2, + EnumSequentialInitialValue_1 = 3, + // CHECK-FIXES-ENABLE: EnumSequentialInitialValue_1 , + EnumSequentialInitialValue_2 = 4, + // CHECK-FIXES-ENABLE: EnumSequentialInitialValue_2 , +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c4ba970372a077bf12ad7bb84dc7ce1836ed8ac --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/enum-initial-value.cpp @@ -0,0 +1,27 @@ +// RUN: %check_clang_tidy %s readability-enum-initial-value %t + +enum class EError { + // CHECK-MESSAGES: :[[@LINE-1]]:1: warning: inital values in enum 'EError' are not consistent + EError_a = 1, + EError_b, + // CHECK-FIXES: EError_b = 2, + EError_c = 3, +}; + +enum class ENone { + ENone_a, + ENone_b, + EENone_c, +}; + +enum class EFirst { + EFirst_a = 1, + EFirst_b, + EFirst_c, +}; + +enum class EAll { + EAll_a = 1, + EAll_b = 2, + EAll_c = 3, +}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp index d2e89a7c9855c9a8b9407406cbc7227b9c24ef44..99149fe86aceecf662ead7f674103230bb263630 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp @@ -108,10 +108,12 @@ USER_NS::object g_s2; // NO warnings or fixes expected as USER_NS and object are declared in a header file SYSTEM_MACRO(var1); -// NO warnings or fixes expected as var1 is from macro expansion +// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: invalid case style for global variable 'var1' [readability-identifier-naming] +// CHECK-FIXES: {{^}}SYSTEM_MACRO(g_var1); USER_MACRO(var2); -// NO warnings or fixes expected as var2 is declared in a macro expansion +// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: invalid case style for global variable 'var2' [readability-identifier-naming] +// CHECK-FIXES: {{^}}USER_MACRO(g_var2); #define BLA int FOO_bar BLA; @@ -602,9 +604,20 @@ static void static_Function() { // CHECK-FIXES: {{^}}#define MY_TEST_MACRO(X) X() void MY_TEST_Macro(function) {} -// CHECK-FIXES: {{^}}void MY_TEST_MACRO(function) {} -} -} +// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: invalid case style for global function 'function' [readability-identifier-naming] +// CHECK-FIXES: {{^}}void MY_TEST_MACRO(Function) {} + +#define MY_CAT_IMPL(l, r) l ## r +#define MY_CAT(l, r) MY_CAT_IMPL(l, r) +#define MY_MACRO2(foo) int MY_CAT(awesome_, MY_CAT(foo, __COUNTER__)) = 0 +#define MY_MACRO3(foo) int MY_CAT(awesome_, foo) = 0 +MY_MACRO2(myglob); +MY_MACRO3(myglob); +// No suggestions should occur even though the resulting decl of awesome_myglob# +// or awesome_myglob are not entirely within a macro argument. + +} // namespace InlineNamespace +} // namespace FOO_NS template struct a { // CHECK-MESSAGES: :[[@LINE-1]]:32: warning: invalid case style for struct 'a' @@ -766,3 +779,13 @@ STATIC_MACRO void someFunc(MyFunPtr, const MyFunPtr****) {} // CHECK-FIXES: {{^}}STATIC_MACRO void someFunc(my_fun_ptr_t, const my_fun_ptr_t****) {} #undef STATIC_MACRO } + +struct Some_struct { + int SomeMember; +// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: invalid case style for public member 'SomeMember' [readability-identifier-naming] +// CHECK-FIXES: {{^}} int some_member; +}; +Some_struct g_s1{ .SomeMember = 1 }; +// CHECK-FIXES: {{^}}Some_struct g_s1{ .some_member = 1 }; +Some_struct g_s2{.SomeMember=1}; +// CHECK-FIXES: {{^}}Some_struct g_s2{.some_member=1}; diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/static-definition-in-anonymous-namespace.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/static-definition-in-anonymous-namespace.cpp index e9938db4f5b83f216570aefe9001010b3f05e2ec..e204199393db4221feb89a4366673b92deb96ece 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/readability/static-definition-in-anonymous-namespace.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/readability/static-definition-in-anonymous-namespace.cpp @@ -51,6 +51,17 @@ static int c = 1; } // namespace deep_inner } // namespace inner +template +static void printTemplate(T&&) {} +// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: 'printTemplate' is a static definition in anonymous namespace; static is redundant here [readability-static-definition-in-anonymous-namespace] +// CHECK-FIXES: {{^}}void printTemplate(T&&) {} + +void testTemplate() { + printTemplate(5); + printTemplate(5U); + printTemplate("some string"); +} + } // namespace namespace N { diff --git a/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp b/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp index d0efc5ca7637538859ab4865eaa3e28e44a60bf1..57d930b26e64c0f1920ff932e18e48e279a0ec0e 100644 --- a/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp +++ b/clang-tools-extra/test/clang-tidy/infrastructure/diagnostic.cpp @@ -25,7 +25,7 @@ // RUN: not clang-tidy -checks='-*,modernize-use-override' %T/diagnostics/input.cpp -- -DCOMPILATION_ERROR 2>&1 | FileCheck -check-prefix=CHECK6 -implicit-check-not='{{warning:|error:}}' %s // RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-macro-redefined' %s -- -DMACRO_FROM_COMMAND_LINE -std=c++20 | FileCheck -check-prefix=CHECK4 -implicit-check-not='{{warning:|error:}}' %s // RUN: clang-tidy -checks='-*,modernize-use-override,clang-diagnostic-macro-redefined,clang-diagnostic-literal-conversion' %s -- -DMACRO_FROM_COMMAND_LINE -std=c++20 -Wno-macro-redefined | FileCheck --check-prefix=CHECK7 -implicit-check-not='{{warning:|error:}}' %s -// RUN: not clang-tidy -checks='-*,modernize-use-override' %s -- -std=c++20 -DPR64602 | FileCheck -check-prefix=CHECK8 -implicit-check-not='{{warning:|error:}}' %s +// RUN: clang-tidy -checks='-*,modernize-use-override' %s -- -std=c++20 -DPR64602 // CHECK1: error: no input files [clang-diagnostic-error] // CHECK1: error: no such file or directory: '{{.*}}nonexistent.cpp' [clang-diagnostic-error] @@ -68,6 +68,4 @@ auto S<>::foo(auto) { return 1; } -// CHECK8: error: conflicting types for 'foo' [clang-diagnostic-error] -// CHECK8: note: previous declaration is here #endif diff --git a/clang/CMakeLists.txt b/clang/CMakeLists.txt index 50a57a51797675a54c7bb788d1cbf1c17ce5189c..f092766fa19f07f754960ec9524078d6b65070d4 100644 --- a/clang/CMakeLists.txt +++ b/clang/CMakeLists.txt @@ -13,8 +13,16 @@ if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR) set(CLANG_BUILT_STANDALONE TRUE) endif() +# Make sure that our source directory is on the current cmake module path so that +# we can include cmake files from this directory. +list(INSERT CMAKE_MODULE_PATH 0 + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" + "${LLVM_COMMON_CMAKE_UTILS}/Modules" + ) + # Must go below project(..) include(GNUInstallDirs) +include(GetDarwinLinkerVersion) if(CLANG_BUILT_STANDALONE) set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ standard to conform to") @@ -140,13 +148,6 @@ if(CLANG_BUILT_STANDALONE) endif() # LLVM_INCLUDE_TESTS endif() # standalone -# Make sure that our source directory is on the current cmake module path so that -# we can include cmake files from this directory. -list(INSERT CMAKE_MODULE_PATH 0 - "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" - "${LLVM_COMMON_CMAKE_UTILS}/Modules" - ) - # This allows disabling clang's XML dependency even if LLVM finds libxml2. # By default, clang depends on libxml2 if LLVM does. option(CLANG_ENABLE_LIBXML2 "Whether libclang may depend on libxml2" @@ -353,20 +354,7 @@ endif () # Determine HOST_LINK_VERSION on Darwin. set(HOST_LINK_VERSION) if (APPLE AND NOT CMAKE_LINKER MATCHES ".*lld.*") - set(LD_V_OUTPUT) - execute_process( - COMMAND sh -c "${CMAKE_LINKER} -v 2>&1 | head -1" - RESULT_VARIABLE HAD_ERROR - OUTPUT_VARIABLE LD_V_OUTPUT - ) - if (HAD_ERROR) - message(FATAL_ERROR "${CMAKE_LINKER} failed with status ${HAD_ERROR}") - endif() - if ("${LD_V_OUTPUT}" MATCHES ".*ld64-([0-9.]+).*") - string(REGEX REPLACE ".*ld64-([0-9.]+).*" "\\1" HOST_LINK_VERSION ${LD_V_OUTPUT}) - elseif ("${LD_V_OUTPUT}" MATCHES "[^0-9]*([0-9.]+).*") - string(REGEX REPLACE "[^0-9]*([0-9.]+).*" "\\1" HOST_LINK_VERSION ${LD_V_OUTPUT}) - endif() + get_darwin_linker_version(HOST_LINK_VERSION) message(STATUS "Host linker version: ${HOST_LINK_VERSION}") endif() diff --git a/clang/cmake/caches/Apple-stage2.cmake b/clang/cmake/caches/Apple-stage2.cmake index 72cdedd611bc9600c0aecbef59060bee7d22b6be..ede256a2da6b8fd6864bd8584aeddf5126dd5bb9 100644 --- a/clang/cmake/caches/Apple-stage2.cmake +++ b/clang/cmake/caches/Apple-stage2.cmake @@ -15,6 +15,7 @@ set(LLVM_ENABLE_ZLIB ON CACHE BOOL "") set(LLVM_ENABLE_BACKTRACES OFF CACHE BOOL "") set(LLVM_ENABLE_MODULES ON CACHE BOOL "") set(LLVM_EXTERNALIZE_DEBUGINFO ON CACHE BOOL "") +set(LLVM_ENABLE_EXPORTED_SYMBOLS_IN_EXECUTABLES OFF CACHE BOOL "") set(CLANG_PLUGIN_SUPPORT OFF CACHE BOOL "") set(CLANG_SPAWN_CC1 ON CACHE BOOL "") set(BUG_REPORT_URL "http://developer.apple.com/bugreporter/" CACHE STRING "") diff --git a/clang/cmake/caches/CrossWinToARMLinux.cmake b/clang/cmake/caches/CrossWinToARMLinux.cmake index 2a0953af53faddfdc7885cdd1021bb715165dc50..736a54ece550c62a589e0a48b97e7a61eccd01af 100644 --- a/clang/cmake/caches/CrossWinToARMLinux.cmake +++ b/clang/cmake/caches/CrossWinToARMLinux.cmake @@ -29,6 +29,11 @@ # cmake --build . --target check-cxxabi- # cmake --build . --target check-unwind- # cmake --build . --target check-cxx- +# (another way to execute the tests) +# python bin/llvm-lit.py -v --threads=32 runtimes/runtimes-bins/libunwind/test 2>&1 | tee libunwind-tests.log +# python bin/llvm-lit.py -v --threads=32 runtimes/runtimes--bins/libcxxabi/test 2>&1 | tee libcxxabi-tests.log +# python bin/llvm-lit.py -v --threads=32 runtimes/runtimes--bins/libcxx/test 2>&1 | tee libcxx-tests.log + # LLVM_PROJECT_DIR is the path to the llvm-project directory. # The right way to compute it would probably be to use "${CMAKE_SOURCE_DIR}/../", @@ -42,9 +47,6 @@ if (NOT DEFINED DEFAULT_SYSROOT) message(WARNING "DEFAULT_SYSROOT must be specified for the cross toolchain build.") endif() -if (NOT DEFINED LLVM_TARGETS_TO_BUILD) - set(LLVM_TARGETS_TO_BUILD "ARM" CACHE STRING "") -endif() if (NOT DEFINED LLVM_ENABLE_ASSERTIONS) set(LLVM_ENABLE_ASSERTIONS ON CACHE BOOL "") endif() @@ -56,7 +58,7 @@ if (NOT DEFINED LLVM_ENABLE_RUNTIMES) endif() if (NOT DEFINED TOOLCHAIN_TARGET_TRIPLE) - set(TOOLCHAIN_TARGET_TRIPLE "armv7-unknown-linux-gnueabihf") + set(TOOLCHAIN_TARGET_TRIPLE "aarch64-unknown-linux-gnu") else() #NOTE: we must normalize specified target triple to a fully specified triple, # including the vendor part. It is necessary to synchronize the runtime library @@ -74,24 +76,38 @@ else() string(REPLACE ";" "-" TOOLCHAIN_TARGET_TRIPLE "${TOOLCHAIN_TARGET_TRIPLE}") endif() +message(STATUS "Toolchain target triple: ${TOOLCHAIN_TARGET_TRIPLE}") + +if (NOT DEFINED LLVM_TARGETS_TO_BUILD) + if ("${TOOLCHAIN_TARGET_TRIPLE}" MATCHES "^(armv|arm32)+") + set(LLVM_TARGETS_TO_BUILD "ARM" CACHE STRING "") + endif() + if ("${TOOLCHAIN_TARGET_TRIPLE}" MATCHES "^(aarch64|arm64)+") + set(LLVM_TARGETS_TO_BUILD "AArch64" CACHE STRING "") + endif() +endif() + +message(STATUS "Toolchain target to build: ${LLVM_TARGETS_TO_BUILD}") + if (NOT DEFINED CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release" CACHE STRING "") endif() -message(STATUS "Toolchain target triple: ${TOOLCHAIN_TARGET_TRIPLE}") - set(CMAKE_CROSSCOMPILING ON CACHE BOOL "") set(CMAKE_CL_SHOWINCLUDES_PREFIX "Note: including file: " CACHE STRING "") # Required if COMPILER_RT_DEFAULT_TARGET_ONLY is ON set(CMAKE_C_COMPILER_TARGET "${TOOLCHAIN_TARGET_TRIPLE}" CACHE STRING "") set(CMAKE_CXX_COMPILER_TARGET "${TOOLCHAIN_TARGET_TRIPLE}" CACHE STRING "") -set(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR ON CACHE BOOL "") set(LLVM_DEFAULT_TARGET_TRIPLE "${TOOLCHAIN_TARGET_TRIPLE}" CACHE STRING "") set(LLVM_TARGET_ARCH "${TOOLCHAIN_TARGET_TRIPLE}" CACHE STRING "") set(LLVM_LIT_ARGS "-vv ${LLVM_LIT_ARGS}" CACHE STRING "" FORCE) +set(CLANG_DEFAULT_CXX_STDLIB "libc++" CACHE STRING "") set(CLANG_DEFAULT_LINKER "lld" CACHE STRING "") +set(CLANG_DEFAULT_OBJCOPY "llvm-objcopy" CACHE STRING "") +set(CLANG_DEFAULT_RTLIB "compiler-rt" CACHE STRING "") +set(CLANG_DEFAULT_UNWINDLIB "libunwind" CACHE STRING "") if(WIN32) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded" CACHE STRING "") @@ -109,9 +125,10 @@ set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_SYSTEM_NAME set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_SYSROOT "${DEFAULT_SYSROOT}" CACHE STRING "") set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_INSTALL_RPATH "${RUNTIMES_INSTALL_RPATH}" CACHE STRING "") set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_CMAKE_BUILD_WITH_INSTALL_RPATH ON CACHE BOOL "") - +set(BUILTINS_${TOOLCHAIN_TARGET_TRIPLE}_LLVM_CMAKE_DIR "${LLVM_PROJECT_DIR}/llvm/cmake/modules" CACHE PATH "") set(LLVM_RUNTIME_TARGETS "${TOOLCHAIN_TARGET_TRIPLE}" CACHE STRING "") +set(LLVM_ENABLE_PER_TARGET_RUNTIME_DIR ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LLVM_ENABLE_RUNTIMES "${LLVM_ENABLE_RUNTIMES}" CACHE STRING "") @@ -125,13 +142,16 @@ set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_SANITIZERS set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_XRAY OFF CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_LIBFUZZER OFF CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_PROFILE OFF CACHE BOOL "") -set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_CRT OFF CACHE BOOL "") +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_CRT ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_BUILD_ORC OFF CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_DEFAULT_TARGET_ONLY ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_INCLUDE_TESTS ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_CAN_EXECUTE_TESTS ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_USE_BUILTINS_LIBRARY ON CACHE BOOL "") +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_CXX_LIBRARY libcxx CACHE STRING "") +# Tell Clang to seach C++ headers alongside with the just-built binaries for the C++ compiler-rt tests. +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_COMPILER_RT_TEST_COMPILER_CFLAGS "--stdlib=libc++" CACHE STRING "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_USE_COMPILER_RT ON CACHE BOOL "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_ENABLE_SHARED OFF CACHE BOOL "") @@ -148,8 +168,10 @@ set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ABI_VERSION set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_CXX_ABI "libcxxabi" CACHE STRING "") #!!! set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXX_ENABLE_NEW_DELETE_DEFINITIONS ON CACHE BOOL "") - +# Avoid searching for the python3 interpreter during the runtimes configuration for the cross builds. +# It starts searching the python3 package using the target's sysroot path, that usually is not compatible with the build host. find_package(Python3 COMPONENTS Interpreter) +set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_Python3_EXECUTABLE ${Python3_EXECUTABLE} CACHE PATH "") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBUNWIND_TEST_PARAMS_default "${RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_TEST_PARAMS}") set(RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_LIBCXXABI_TEST_PARAMS_default "${RUNTIMES_${TOOLCHAIN_TARGET_TRIPLE}_TEST_PARAMS}") diff --git a/clang/cmake/caches/Fuchsia.cmake b/clang/cmake/caches/Fuchsia.cmake index df69d7d0dd414beb8be6752acae171cf6fd5272e..393d97a4cf1a3302db9be62d1982d0f485d52a3b 100644 --- a/clang/cmake/caches/Fuchsia.cmake +++ b/clang/cmake/caches/Fuchsia.cmake @@ -71,6 +71,8 @@ set(_FUCHSIA_BOOTSTRAP_PASSTHROUGH Python3_LIBRARIES Python3_INCLUDE_DIRS Python3_RPATH + SWIG_DIR + SWIG_EXECUTABLE CMAKE_FIND_PACKAGE_PREFER_CONFIG CMAKE_SYSROOT CMAKE_MODULE_LINKER_FLAGS diff --git a/clang/cmake/caches/HLSL.cmake b/clang/cmake/caches/HLSL.cmake index 71f81e53f6bd351f18e8d23cbc1ec24ced9622ac..84850c86f12cd7ab92237452ce8b2bd8fdfb0dce 100644 --- a/clang/cmake/caches/HLSL.cmake +++ b/clang/cmake/caches/HLSL.cmake @@ -4,7 +4,7 @@ set(LLVM_TARGETS_TO_BUILD Native CACHE STRING "") # Include the DirectX target for DXIL code generation, eventually we'll include # SPIR-V here too. -set(LLVM_EXPERIMENTAL_TARGETS_TO_BUILD DirectX CACHE STRING "") +set(LLVM_EXPERIMENTAL_TARGETS_TO_BUILD "DirectX;SPIRV" CACHE STRING "") # HLSL support is currently limted to clang, eventually it will expand to # clang-tools-extra too. diff --git a/clang/docs/ClangFormatStyleOptions.rst b/clang/docs/ClangFormatStyleOptions.rst index be021dfc5c084cde660d1d6b4628dedbe8cf57f2..39f7cded36edbff5846925aa56319682a04ed476 100644 --- a/clang/docs/ClangFormatStyleOptions.rst +++ b/clang/docs/ClangFormatStyleOptions.rst @@ -955,6 +955,151 @@ the configuration (without a prefix: ``Auto``). } +.. _AlignConsecutiveTableGenBreakingDAGArgColons: + +**AlignConsecutiveTableGenBreakingDAGArgColons** (``AlignConsecutiveStyle``) :versionbadge:`clang-format 19` :ref:`¶ ` + Style of aligning consecutive TableGen DAGArg operator colons. + If enabled, align the colon inside DAGArg which have line break inside. + This works only when TableGenBreakInsideDAGArg is BreakElements or + BreakAll and the DAGArg is not excepted by + TableGenBreakingDAGArgOperators's effect. + + .. code-block:: c++ + + let dagarg = (ins + a :$src1, + aa :$src2, + aaa:$src3 + ) + + Nested configuration flags: + + Alignment options. + + They can also be read as a whole for compatibility. The choices are: + - None + - Consecutive + - AcrossEmptyLines + - AcrossComments + - AcrossEmptyLinesAndComments + + For example, to align across empty lines and not across comments, either + of these work. + + .. code-block:: c++ + + AlignConsecutiveTableGenBreakingDAGArgColons: AcrossEmptyLines + + AlignConsecutiveTableGenBreakingDAGArgColons: + Enabled: true + AcrossEmptyLines: true + AcrossComments: false + + * ``bool Enabled`` Whether aligning is enabled. + + .. code-block:: c++ + + #define SHORT_NAME 42 + #define LONGER_NAME 0x007f + #define EVEN_LONGER_NAME (2) + #define foo(x) (x * x) + #define bar(y, z) (y + z) + + int a = 1; + int somelongname = 2; + double c = 3; + + int aaaa : 1; + int b : 12; + int ccc : 8; + + int aaaa = 12; + float b = 23; + std::string ccc; + + * ``bool AcrossEmptyLines`` Whether to align across empty lines. + + .. code-block:: c++ + + true: + int a = 1; + int somelongname = 2; + double c = 3; + + int d = 3; + + false: + int a = 1; + int somelongname = 2; + double c = 3; + + int d = 3; + + * ``bool AcrossComments`` Whether to align across comments. + + .. code-block:: c++ + + true: + int d = 3; + /* A comment. */ + double e = 4; + + false: + int d = 3; + /* A comment. */ + double e = 4; + + * ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments + like ``+=`` are aligned along with ``=``. + + .. code-block:: c++ + + true: + a &= 2; + bbb = 2; + + false: + a &= 2; + bbb = 2; + + * ``bool AlignFunctionPointers`` Only for ``AlignConsecutiveDeclarations``. Whether function pointers are + aligned. + + .. code-block:: c++ + + true: + unsigned i; + int &r; + int *p; + int (*f)(); + + false: + unsigned i; + int &r; + int *p; + int (*f)(); + + * ``bool PadOperators`` Only for ``AlignConsecutiveAssignments``. Whether short assignment + operators are left-padded to the same length as long ones in order to + put all assignment operators to the right of the left hand side. + + .. code-block:: c++ + + true: + a >>= 2; + bbb = 2; + + a = 2; + bbb >>= 2; + + false: + a >>= 2; + bbb = 2; + + a = 2; + bbb >>= 2; + + .. _AlignConsecutiveTableGenCondOperatorColons: **AlignConsecutiveTableGenCondOperatorColons** (``AlignConsecutiveStyle``) :versionbadge:`clang-format 19` :ref:`¶ ` @@ -3150,6 +3295,21 @@ the configuration (without a prefix: ``Auto``). +.. _BreakFunctionDefinitionParameters: + +**BreakFunctionDefinitionParameters** (``Boolean``) :versionbadge:`clang-format 19` :ref:`¶ ` + If ``true``, clang-format will always break before function definition + parameters. + + .. code-block:: c++ + + true: + void functionDefinition( + int A, int B) {} + + false: + void functionDefinition(int A, int B) {} + .. _BreakInheritanceList: **BreakInheritanceList** (``BreakInheritanceListStyle``) :versionbadge:`clang-format 7` :ref:`¶ ` diff --git a/clang/docs/HIPSupport.rst b/clang/docs/HIPSupport.rst index 543c82cf90244945a7cf08b89009a6a37e5c34bf..5ba84c2f670556491b51f3d716be759d8f653fec 100644 --- a/clang/docs/HIPSupport.rst +++ b/clang/docs/HIPSupport.rst @@ -208,6 +208,20 @@ Host Code Compilation - These relocatable objects are then linked together. - Host code within a TU can call host functions and launch kernels from another TU. +Syntax Difference with CUDA +=========================== + +Clang's front end, used for both CUDA and HIP programming models, shares the same parsing and semantic analysis mechanisms. This includes the resolution of overloads concerning device and host functions. While there exists a comprehensive documentation on the syntax differences between Clang and NVCC for CUDA at `Dialect Differences Between Clang and NVCC `_, it is important to note that these differences also apply to HIP code compilation. + +Predefined Macros for Differentiation +------------------------------------- + +To facilitate differentiation between HIP and CUDA code, as well as between device and host compilations within HIP, Clang defines specific macros: + +- ``__HIP__`` : This macro is defined only when compiling HIP code. It can be used to conditionally compile code specific to HIP, enabling developers to write portable code that can be compiled for both CUDA and HIP. + +- ``__HIP_DEVICE_COMPILE__`` : Defined exclusively during HIP device compilation, this macro allows for conditional compilation of device-specific code. It provides a mechanism to segregate device and host code, ensuring that each can be optimized for their respective execution environments. + Function Pointers Support ========================= diff --git a/clang/docs/HLSL/FunctionCalls.rst b/clang/docs/HLSL/FunctionCalls.rst index 7317de2163f8975b3d9d283a55aa8d4d9ba2ac55..6d65fe6e3fb20b90a3a755a13123042de2226958 100644 --- a/clang/docs/HLSL/FunctionCalls.rst +++ b/clang/docs/HLSL/FunctionCalls.rst @@ -157,22 +157,23 @@ Clang Implementation of the changes in the prototype implementation are restoring Clang-3.7 code that was previously modified to its original state. -The implementation in clang depends on two new AST nodes and minor extensions to -Clang's existing support for Objective-C write-back arguments. The goal of this -design is to capture the semantic details of HLSL function calls in the AST, and -minimize the amount of magic that needs to occur during IR generation. - -The two new AST nodes are ``HLSLArrayTemporaryExpr`` and ``HLSLOutParamExpr``, -which respectively represent the temporaries used for passing arrays by value -and the temporaries created for function outputs. +The implementation in clang adds a new non-decaying array type, a new AST node +to represent output parameters, and minor extensions to Clang's existing support +for Objective-C write-back arguments. The goal of this design is to capture the +semantic details of HLSL function calls in the AST, and minimize the amount of +magic that needs to occur during IR generation. Array Temporaries ----------------- -The ``HLSLArrayTemporaryExpr`` represents temporary values for input -constant-sized array arguments. This applies for all constant-sized array -arguments regardless of whether or not the parameter is constant-sized or -unsized. +The new ``ArrayParameterType`` is a sub-class of ``ConstantArrayType`` +inheriting all the behaviors and methods of the parent except that it does not +decay to a pointer during overload resolution or template type deduction. + +An argument of ``ConstantArrayType`` can be implicitly converted to an +equivalent non-decayed ``ArrayParameterType`` if the underlying canonical +``ConstantArrayType`` is the same. This occurs during overload resolution +instead of array to pointer decay. .. code-block:: c++ @@ -193,7 +194,7 @@ In the example above, the following AST is generated for the call to CallExpr 'void' |-ImplicitCastExpr 'void (*)(float [4])' | `-DeclRefExpr 'void (float [4])' lvalue Function 'SizedArray' 'void (float [4])' - `-HLSLArrayTemporaryExpr 'float [4]' + `-ImplicitCastExpr 'float [4]' `-DeclRefExpr 'float [4]' lvalue Var 'arr' 'float [4]' In the example above, the following AST is generated for the call to @@ -204,7 +205,7 @@ In the example above, the following AST is generated for the call to CallExpr 'void' |-ImplicitCastExpr 'void (*)(float [])' | `-DeclRefExpr 'void (float [])' lvalue Function 'UnsizedArray' 'void (float [])' - `-HLSLArrayTemporaryExpr 'float [4]' + `-ImplicitCastExpr 'float [4]' `-DeclRefExpr 'float [4]' lvalue Var 'arr' 'float [4]' In both of these cases the argument expression is of known array size so we can @@ -236,7 +237,7 @@ An expected AST should be something like: CallExpr 'void' |-ImplicitCastExpr 'void (*)(float [])' | `-DeclRefExpr 'void (float [])' lvalue Function 'UnsizedArray' 'void (float [])' - `-HLSLArrayTemporaryExpr 'float [4]' + `-ImplicitCastExpr 'float [4]' `-DeclRefExpr 'float [4]' lvalue Var 'arr' 'float [4]' Out Parameter Temporaries diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index 5711972b55e6c03de349a7bc39157b34acb1e27e..7b23e4d1c2f30c1544b2eba17b2a53849a6bc6a9 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -5420,10 +5420,12 @@ The following builtin intrinsics can be used in constant expressions: * ``__builtin_clzl`` * ``__builtin_clzll`` * ``__builtin_clzs`` +* ``__builtin_clzg`` * ``__builtin_ctz`` * ``__builtin_ctzl`` * ``__builtin_ctzll`` * ``__builtin_ctzs`` +* ``__builtin_ctzg`` * ``__builtin_ffs`` * ``__builtin_ffsl`` * ``__builtin_ffsll`` diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index fd12bb41be47a3e16f28e477b425b6b367e49173..45a9a79739a4eb3bf2930852243d890aac0228be 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -57,6 +57,12 @@ ABI Changes in This Version inline member function that contains a static local variable with a dynamic initializer is declared with ``__declspec(dllimport)``. (#GH83616). +- Fixed Microsoft name mangling of lifetime extended temporary objects. This + change corrects missing back reference registrations that could result in + incorrect back reference indexes and suprising demangled name results. Since + MSVC uses a different mangling for these objects, compatibility is not affected. + (#GH85423). + AST Dumping Potentially Breaking Changes ---------------------------------------- @@ -104,6 +110,10 @@ C++20 Feature Support templates (`P1814R0 `_). (#GH54051). +- We have sufficient confidence and experience with the concepts implementation + to update the ``__cpp_concepts`` macro to `202002L`. This enables + ```` from libstdc++ to work correctly with Clang. + C++23 Feature Support ^^^^^^^^^^^^^^^^^^^^^ @@ -137,6 +147,9 @@ Resolutions to C++ Defect Reports compatibility of two types. (`CWG2759: [[no_unique_address] and common initial sequence `_). +- Clang now diagnoses declarative nested-name-specifiers with pack-index-specifiers. + (`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers `_). + C Language Changes ------------------ @@ -182,8 +195,20 @@ Non-comprehensive list of changes in this release - Lambda expressions are now accepted in C++03 mode as an extension. +- Added ``__builtin_clzg`` and ``__builtin_ctzg`` as type-generic alternatives + to ``__builtin_clz{,s,l,ll}`` and ``__builtin_ctz{,s,l,ll}`` respectively, + with support for any unsigned integer type. Like the previous builtins, these + new builtins are constexpr and may be used in constant expressions. + +- ``__typeof_unqual__`` is available in all C modes as an extension, which behaves + like ``typeof_unqual`` from C23, similar to ``__typeof__`` and ``typeof``. + New Compiler Flags ------------------ +- ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and + sign change. +- ``-fsanitize=implicit-integer-conversion`` a group that replaces the previous + group ``-fsanitize=implicit-conversion``. - ``-Wmissing-designated-field-initializers``, grouped under ``-Wmissing-field-initializers``. This diagnostic can be disabled to make ``-Wmissing-field-initializers`` behave @@ -197,6 +222,9 @@ Modified Compiler Flags - Added a new diagnostic flag ``-Wreturn-mismatch`` which is grouped under ``-Wreturn-type``, and moved some of the diagnostics previously controlled by ``-Wreturn-type`` under this new flag. Fixes #GH72116. +- ``-fsanitize=implicit-conversion`` is now a group for both + ``-fsanitize=implicit-integer-conversion`` and + ``-fsanitize=implicit-bitfield-conversion``. - Added ``-Wcast-function-type-mismatch`` under the ``-Wcast-function-type`` warning group. Moved the diagnostic previously controlled by @@ -242,6 +270,21 @@ Attribute Changes in Clang added a new extension query ``__has_extension(swiftcc)`` corresponding to the ``__attribute__((swiftcc))`` attribute. +- The ``_Nullable`` and ``_Nonnull`` family of type attributes can now apply + to certain C++ class types, such as smart pointers: + ``void useObject(std::unique_ptr _Nonnull obj);``. + + This works for standard library types including ``unique_ptr``, ``shared_ptr``, + and ``function``. See + `the attribute reference documentation `_ + for the full list. + +- The ``_Nullable`` attribute can be applied to C++ class declarations: + ``template class _Nullable MySmartPointer {};``. + + This allows the ``_Nullable`` and ``_Nonnull`` family of type attributes to + apply to this class. + Improvements to Clang's diagnostics ----------------------------------- - Clang now applies syntax highlighting to the code snippets it @@ -289,11 +332,46 @@ Improvements to Clang's diagnostics - Clang now correctly diagnoses no arguments to a variadic macro parameter as a C23/C++20 extension. Fixes #GH84495. +- Clang no longer emits a ``-Wexit-time destructors`` warning on static variables explicitly + annotated with the ``clang::always_destroy`` attribute. + Fixes #GH68686, #GH86486 + +- ``-Wmicrosoft``, ``-Wgnu``, or ``-pedantic`` is now required to diagnose C99 + flexible array members in a union or alone in a struct. Fixes GH#84565. + +- Clang now no longer diagnoses type definitions in ``offsetof`` in C23 mode. + Fixes #GH83658. + +- New ``-Wformat-signedness`` diagnostic that warn if the format string requires an + unsigned argument and the argument is signed and vice versa. + +- Clang now emits ``unused argument`` warning when the -fmodule-output flag is used + with an input that is not of type c++-module. + +- Clang emits a ``-Wreturn-stack-address`` warning if a function returns a pointer or + reference to a struct literal. Fixes #GH8678 + +- Clang emits a ``-Wunused-but-set-variable`` warning on C++ variables whose declaration + (with initializer) entirely consist the condition expression of a if/while/for construct + but are not actually used in the body of the if/while/for construct. Fixes #GH41447 + +- Clang emits a diagnostic when a tentative array definition is assumed to have + a single element, but that diagnostic was never given a diagnostic group. + Added the ``-Wtentative-definition-array`` warning group to cover this. + Fixes #GH87766 + +- Clang now uses the correct type-parameter-key (``class`` or ``typename``) when printing + template template parameter declarations. + Improvements to Clang's time-trace ---------------------------------- Bug Fixes in This Version ------------------------- +- Clang's ``-Wundefined-func-template`` no longer warns on pure virtual + functions. + (`#74016 `_) + - Fixed missing warnings when comparing mismatched enumeration constants in C (`#29217 `). @@ -339,6 +417,9 @@ Bug Fixes in This Version - Fixes an assertion failure on invalid code when trying to define member functions in lambdas. +- Fixed a regression in CTAD that a friend declaration that befriends itself may cause + incorrect constraint substitution. (#GH86769). + Bug Fixes to Compiler Builtins ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -425,6 +506,8 @@ Bug Fixes to C++ Support when one of the function had more specialized templates. Fixes (`#82509 `_) and (`#74494 `_) +- Clang now supports direct lambda calls inside of a type alias template declarations. + This addresses (#GH70601), (#GH76674), (#GH79555), (#GH81145) and (#GH82104). - Allow access to a public template alias declaration that refers to friend's private nested type. (#GH25708). - Fixed a crash in constant evaluation when trying to access a @@ -437,10 +520,27 @@ Bug Fixes to C++ Support - Clang's __builtin_bit_cast will now produce a constant value for records with empty bases. See: (#GH82383) - Fix a crash when instantiating a lambda that captures ``this`` outside of its context. Fixes (#GH85343). +- Fix an issue where a namespace alias could be defined using a qualified name (all name components + following the first `::` were ignored). +- Fix an out-of-bounds crash when checking the validity of template partial specializations. (part of #GH86757). +- Fix an issue caused by not handling invalid cases when substituting into the parameter mapping of a constraint. Fixes (#GH86757). +- Fixed a bug that prevented member function templates of class templates declared with a deduced return type + from being explicitly specialized for a given implicit instantiation of the class template. +- Fixed a crash when ``this`` is used in a dependent class scope function template specialization + that instantiates to a static member function. + +- Fix crash when inheriting from a cv-qualified type. Fixes: + (`#35603 `_) +- Fix a crash when the using enum declaration uses an anonymous enumeration. Fixes (#GH86790). +- Handled an edge case in ``getFullyPackExpandedSize`` so that we now avoid a false-positive diagnostic. (#GH84220) +- Clang now correctly tracks type dependence of by-value captures in lambdas with an explicit + object parameter. + Fixes (#GH70604), (#GH79754), (#GH84163), (#GH84425), (#GH86054), (#GH86398), and (#GH86399). Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ - Clang now properly preserves ``FoundDecls`` within a ``ConceptReference``. (#GH82628) +- The presence of the ``typename`` keyword is now stored in ``TemplateTemplateParmDecl``. Miscellaneous Bug Fixes ^^^^^^^^^^^^^^^^^^^^^^^ @@ -520,6 +620,7 @@ RISC-V Support ^^^^^^^^^^^^^^ - ``__attribute__((rvv_vector_bits(N)))`` is now supported for RVV vbool*_t types. +- Profile names in ``-march`` option are now supported. CUDA/HIP Language Changes ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -554,10 +655,14 @@ Fixed Point Support in Clang AST Matchers ------------ +- Fixes a long-standing performance issue in parent map generation for + ancestry-based matchers such as ``hasParent`` and ``hasAncestor``, making + them significantly faster. - ``isInStdNamespace`` now supports Decl declared with ``extern "C++"``. - Add ``isExplicitObjectMemberFunction``. - Fixed ``forEachArgumentWithParam`` and ``forEachArgumentWithParamType`` to not skip the explicit object parameter for operator calls. +- Fixed captureVars assertion failure if not capturesVariables. (#GH76425) clang-format ------------ @@ -576,6 +681,7 @@ Static Analyzer - Fixed crashing on loops if the loop variable was declared in switch blocks but not under any case blocks if ``unroll-loops=true`` analyzer config is set. (#GH68819) +- Support C++23 static operator calls. (#GH84972) New features ^^^^^^^^^^^^ @@ -607,6 +713,10 @@ Sanitizers manually disable potentially noisy signed integer overflow checks with ``-fno-sanitize=signed-integer-overflow`` +- ``-fsanitize=cfi -fsanitize-cfi-cross-dso`` (cross-DSO CFI instrumentation) + now generates the ``__cfi_check`` function with proper target-specific + attributes, for example allowing unwind table generation. + Python Binding Changes ---------------------- diff --git a/clang/docs/UndefinedBehaviorSanitizer.rst b/clang/docs/UndefinedBehaviorSanitizer.rst index 8f58c92bd2a1634f50e357905ba7b4738e36b64a..531d56e313826c766e0d8b7c5a41c4792dca1c2f 100644 --- a/clang/docs/UndefinedBehaviorSanitizer.rst +++ b/clang/docs/UndefinedBehaviorSanitizer.rst @@ -148,6 +148,11 @@ Available checks are: Issues caught by this sanitizer are not undefined behavior, but are often unintentional. - ``-fsanitize=integer-divide-by-zero``: Integer division by zero. + - ``-fsanitize=implicit-bitfield-conversion``: Implicit conversion from + integer of larger bit width to smaller bitfield, if that results in data + loss. This includes unsigned/signed truncations and sign changes, similarly + to how the ``-fsanitize=implicit-integer-conversion`` group works, but + explicitly for bitfields. - ``-fsanitize=nonnull-attribute``: Passing null pointer as a function parameter which is declared to never be null. - ``-fsanitize=null``: Use of a null pointer or creation of a null @@ -193,8 +198,8 @@ Available checks are: signed division overflow (``INT_MIN/-1``). Note that checks are still added even when ``-fwrapv`` is enabled. This sanitizer does not check for lossy implicit conversions performed before the computation (see - ``-fsanitize=implicit-conversion``). Both of these two issues are handled - by ``-fsanitize=implicit-conversion`` group of checks. + ``-fsanitize=implicit-integer-conversion``). Both of these two issues are handled + by ``-fsanitize=implicit-integer-conversion`` group of checks. - ``-fsanitize=unreachable``: If control flow reaches an unreachable program point. - ``-fsanitize=unsigned-integer-overflow``: Unsigned integer overflow, where @@ -202,7 +207,7 @@ Available checks are: type. Unlike signed integer overflow, this is not undefined behavior, but it is often unintentional. This sanitizer does not check for lossy implicit conversions performed before such a computation - (see ``-fsanitize=implicit-conversion``). + (see ``-fsanitize=implicit-integer-conversion``). - ``-fsanitize=vla-bound``: A variable-length array whose bound does not evaluate to a positive value. - ``-fsanitize=vptr``: Use of an object whose vptr indicates that it is of @@ -224,11 +229,15 @@ You can also use the following check groups: - ``-fsanitize=implicit-integer-arithmetic-value-change``: Catches implicit conversions that change the arithmetic value of the integer. Enables ``implicit-signed-integer-truncation`` and ``implicit-integer-sign-change``. - - ``-fsanitize=implicit-conversion``: Checks for suspicious - behavior of implicit conversions. Enables + - ``-fsanitize=implicit-integer-conversion``: Checks for suspicious + behavior of implicit integer conversions. Enables ``implicit-unsigned-integer-truncation``, ``implicit-signed-integer-truncation``, and ``implicit-integer-sign-change``. + - ``-fsanitize=implicit-conversion``: Checks for suspicious + behavior of implicit conversions. Enables + ``implicit-integer-conversion``, and + ``implicit-bitfield-conversion``. - ``-fsanitize=integer``: Checks for undefined or suspicious integer behavior (e.g. unsigned integer overflow). Enables ``signed-integer-overflow``, ``unsigned-integer-overflow``, diff --git a/clang/docs/UsersManual.rst b/clang/docs/UsersManual.rst index 129e75fc9a785a65a3a3028eeb439f7f8075858b..c464bc3a69adc51c1f59db5245f1fc077aed4a11 100644 --- a/clang/docs/UsersManual.rst +++ b/clang/docs/UsersManual.rst @@ -2441,20 +2441,39 @@ usual build cycle when using sample profilers for optimization: 1. Build the code with source line table information. You can use all the usual build flags that you always build your application with. The only - requirement is that you add ``-gline-tables-only`` or ``-g`` to the - command line. This is important for the profiler to be able to map - instructions back to source line locations. + requirement is that DWARF debug info including source line information is + generated. This DWARF information is important for the profiler to be able + to map instructions back to source line locations. + + On Linux, ``-g`` or just ``-gline-tables-only`` is sufficient: .. code-block:: console $ clang++ -O2 -gline-tables-only code.cc -o code + While MSVC-style targets default to CodeView debug information, DWARF debug + information is required to generate source-level LLVM profiles. Use + ``-gdwarf`` to include DWARF debug information: + + .. code-block:: console + + $ clang-cl -O2 -gdwarf -gline-tables-only coff-profile.cpp -fuse-ld=lld -link -debug:dwarf + 2. Run the executable under a sampling profiler. The specific profiler you use does not really matter, as long as its output can be converted - into the format that the LLVM optimizer understands. Currently, there - exists a conversion tool for the Linux Perf profiler - (https://perf.wiki.kernel.org/), so these examples assume that you - are using Linux Perf to profile your code. + into the format that the LLVM optimizer understands. + + Two such profilers are the the Linux Perf profiler + (https://perf.wiki.kernel.org/) and Intel's Sampling Enabling Product (SEP), + available as part of `Intel VTune + `_. + While Perf is Linux-specific, SEP can be used on Linux, Windows, and FreeBSD. + + The LLVM tool ``llvm-profgen`` can convert output of either Perf or SEP. An + external project, `AutoFDO `_, also + provides a ``create_llvm_prof`` tool which supports Linux Perf output. + + When using Perf: .. code-block:: console @@ -2465,11 +2484,19 @@ usual build cycle when using sample profilers for optimization: it provides better call information, which improves the accuracy of the profile data. -3. Convert the collected profile data to LLVM's sample profile format. - This is currently supported via the AutoFDO converter ``create_llvm_prof``. - It is available at https://github.com/google/autofdo. Once built and - installed, you can convert the ``perf.data`` file to LLVM using - the command: + When using SEP: + + .. code-block:: console + + $ sep -start -out code.tb7 -ec BR_INST_RETIRED.NEAR_TAKEN:precise=yes:pdir -lbr no_filter:usr -perf-script brstack -app ./code + + This produces a ``code.perf.data.script`` output which can be used with + ``llvm-profgen``'s ``--perfscript`` input option. + +3. Convert the collected profile data to LLVM's sample profile format. This is + currently supported via the `AutoFDO `_ + converter ``create_llvm_prof``. Once built and installed, you can convert + the ``perf.data`` file to LLVM using the command: .. code-block:: console @@ -2485,7 +2512,14 @@ usual build cycle when using sample profilers for optimization: .. code-block:: console - $ llvm-profgen --binary=./code --output=code.prof--perfdata=perf.data + $ llvm-profgen --binary=./code --output=code.prof --perfdata=perf.data + + When using SEP the output is in the textual format corresponding to + ``llvm-profgen --perfscript``. For example: + + .. code-block:: console + + $ llvm-profgen --binary=./code --output=code.prof --perfscript=code.perf.data.script 4. Build the code again using the collected profile. This step feeds diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index fe2115149142723724feea43e0af6d285d9dd604..fb748d23a53d01ce04c607f38d605c3ac7b26de8 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -340,6 +340,51 @@ cplusplus C++ Checkers. +.. _cplusplus-ArrayDelete: + +cplusplus.ArrayDelete (C++) +""""""""""""""""""""""""""" + +Reports destructions of arrays of polymorphic objects that are destructed as +their base class. If the dynamic type of the array is different from its static +type, calling `delete[]` is undefined. + +This checker corresponds to the SEI CERT rule `EXP51-CPP: Do not delete an array through a pointer of the incorrect type `_. + +.. code-block:: cpp + + class Base { + public: + virtual ~Base() {} + }; + class Derived : public Base {}; + + Base *create() { + Base *x = new Derived[10]; // note: Casting from 'Derived' to 'Base' here + return x; + } + + void foo() { + Base *x = create(); + delete[] x; // warn: Deleting an array of 'Derived' objects as their base class 'Base' is undefined + } + +**Limitations** + +The checker does not emit note tags when casting to and from reference types, +even though the pointer values are tracked across references. + +.. code-block:: cpp + + void foo() { + Derived *d = new Derived[10]; + Derived &dref = *d; + + Base &bref = static_cast(dref); // no note + Base *b = &bref; + delete[] b; // warn: Deleting an array of 'Derived' objects as their base class 'Base' is undefined + } + .. _cplusplus-InnerPointer: cplusplus.InnerPointer (C++) @@ -804,10 +849,89 @@ Check for performance anti-patterns when using Grand Central Dispatch. .. _optin-performance-Padding: -optin.performance.Padding -""""""""""""""""""""""""" +optin.performance.Padding (C, C++, ObjC) +"""""""""""""""""""""""""""""""""""""""" Check for excessively padded structs. +This checker detects structs with excessive padding, which can lead to wasted +memory thus decreased performance by reducing the effectiveness of the +processor cache. Padding bytes are added by compilers to align data accesses +as some processors require data to be aligned to certain boundaries. On others, +unaligned data access are possible, but impose significantly larger latencies. + +To avoid padding bytes, the fields of a struct should be ordered by decreasing +by alignment. Usually, its easier to think of the ``sizeof`` of the fields, and +ordering the fields by ``sizeof`` would usually also lead to the same optimal +layout. + +In rare cases, one can use the ``#pragma pack(1)`` directive to enforce a packed +layout too, but it can significantly increase the access times, so reordering the +fields is usually a better solution. + + +.. code-block:: cpp + + // warn: Excessive padding in 'struct NonOptimal' (35 padding bytes, where 3 is optimal) + struct NonOptimal { + char c1; + // 7 bytes of padding + std::int64_t big1; // 8 bytes + char c2; + // 7 bytes of padding + std::int64_t big2; // 8 bytes + char c3; + // 7 bytes of padding + std::int64_t big3; // 8 bytes + char c4; + // 7 bytes of padding + std::int64_t big4; // 8 bytes + char c5; + // 7 bytes of padding + }; + static_assert(sizeof(NonOptimal) == 4*8+5+5*7); + + // no-warning: The fields are nicely aligned to have the minimal amount of padding bytes. + struct Optimal { + std::int64_t big1; // 8 bytes + std::int64_t big2; // 8 bytes + std::int64_t big3; // 8 bytes + std::int64_t big4; // 8 bytes + char c1; + char c2; + char c3; + char c4; + char c5; + // 3 bytes of padding + }; + static_assert(sizeof(Optimal) == 4*8+5+3); + + // no-warning: Bit packing representation is also accepted by this checker, but + // it can significantly increase access times, so prefer reordering the fields. + #pragma pack(1) + struct BitPacked { + char c1; + std::int64_t big1; // 8 bytes + char c2; + std::int64_t big2; // 8 bytes + char c3; + std::int64_t big3; // 8 bytes + char c4; + std::int64_t big4; // 8 bytes + char c5; + }; + static_assert(sizeof(BitPacked) == 4*8+5); + +The ``AllowedPad`` option can be used to specify a threshold for the number +padding bytes raising the warning. If the number of padding bytes of the struct +and the optimal number of padding bytes differ by more than the threshold value, +a warning will be raised. + +By default, the ``AllowedPad`` threshold is 24 bytes. + +To override this threshold to e.g. 4 bytes, use the +``-analyzer-config optin.performance.Padding:AllowedPad=4`` option. + + .. _optin-portability-UnixAPI: optin.portability.UnixAPI @@ -2139,30 +2263,6 @@ Either the comparison is useless or there is division by zero. alpha.cplusplus ^^^^^^^^^^^^^^^ -.. _alpha-cplusplus-ArrayDelete: - -alpha.cplusplus.ArrayDelete (C++) -""""""""""""""""""""""""""""""""" -Reports destructions of arrays of polymorphic objects that are destructed as their base class. -This checker corresponds to the CERT rule `EXP51-CPP: Do not delete an array through a pointer of the incorrect type `_. - -.. code-block:: cpp - - class Base { - virtual ~Base() {} - }; - class Derived : public Base {} - - Base *create() { - Base *x = new Derived[10]; // note: Casting from 'Derived' to 'Base' here - return x; - } - - void foo() { - Base *x = create(); - delete[] x; // warn: Deleting an array of 'Derived' objects as their base class 'Base' is undefined - } - .. _alpha-cplusplus-DeleteWithNonVirtualDtor: alpha.cplusplus.DeleteWithNonVirtualDtor (C++) @@ -3020,43 +3120,94 @@ Check for misuses of stream APIs. Check for misuses of stream APIs: ``fopen, fcl alpha.unix.Stream (C) """"""""""""""""""""" -Check stream handling functions: ``fopen, tmpfile, fclose, fread, fwrite, fseek, ftell, rewind, fgetpos,`` -``fsetpos, clearerr, feof, ferror, fileno``. +Check C stream handling functions: +``fopen, fdopen, freopen, tmpfile, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, fprintf, fscanf, ungetc, getdelim, getline, fseek, fseeko, ftell, ftello, fflush, rewind, fgetpos, fsetpos, clearerr, feof, ferror, fileno``. + +The checker maintains information about the C stream objects (``FILE *``) and +can detect error conditions related to use of streams. The following conditions +are detected: + +* The ``FILE *`` pointer passed to the function is NULL (the single exception is + ``fflush`` where NULL is allowed). +* Use of stream after close. +* Opened stream is not closed. +* Read from a stream after end-of-file. (This is not a fatal error but reported + by the checker. Stream remains in EOF state and the read operation fails.) +* Use of stream when the file position is indeterminate after a previous failed + operation. Some functions (like ``ferror``, ``clearerr``, ``fseek``) are + allowed in this state. +* Invalid 3rd ("``whence``") argument to ``fseek``. + +The stream operations are by this checker usually split into two cases, a success +and a failure case. However, in the case of write operations (like ``fwrite``, +``fprintf`` and even ``fsetpos``) this behavior could produce a large amount of +unwanted reports on projects that don't have error checks around the write +operations, so by default the checker assumes that write operations always succeed. +This behavior can be controlled by the ``Pedantic`` flag: With +``-analyzer-config alpha.unix.Stream:Pedantic=true`` the checker will model the +cases where a write operation fails and report situations where this leads to +erroneous behavior. (The default is ``Pedantic=false``, where write operations +are assumed to succeed.) .. code-block:: c - void test() { + void test1() { FILE *p = fopen("foo", "r"); } // warn: opened file is never closed - void test() { + void test2() { FILE *p = fopen("foo", "r"); fseek(p, 1, SEEK_SET); // warn: stream pointer might be NULL fclose(p); } - void test() { + void test3() { FILE *p = fopen("foo", "r"); + if (p) { + fseek(p, 1, 3); // warn: third arg should be SEEK_SET, SEEK_END, or SEEK_CUR + fclose(p); + } + } - if (p) - fseek(p, 1, 3); - // warn: third arg should be SEEK_SET, SEEK_END, or SEEK_CUR + void test4() { + FILE *p = fopen("foo", "r"); + if (!p) + return; fclose(p); + fclose(p); // warn: stream already closed } - void test() { + void test5() { FILE *p = fopen("foo", "r"); + if (!p) + return; + + fgetc(p); + if (!ferror(p)) + fgetc(p); // warn: possible read after end-of-file + fclose(p); - fclose(p); // warn: already closed } - void test() { - FILE *p = tmpfile(); - ftell(p); // warn: stream pointer might be NULL + void test6() { + FILE *p = fopen("foo", "r"); + if (!p) + return; + + fgetc(p); + if (!feof(p)) + fgetc(p); // warn: file position may be indeterminate after I/O error + fclose(p); } +**Limitations** + +The checker does not track the correspondence between integer file descriptors +and ``FILE *`` pointers. Operations on standard streams like ``stdin`` are not +treated specially and are therefore often not recognized (because these streams +are usually not opened explicitly by the program, and are global variables). .. _alpha-unix-cstring-BufferOverlap: diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt index 70687c23b15e61e3417ff09cf32b78781b7e9c18..3089438c23d94e73b580ffb6442e7735a259e41e 100644 --- a/clang/docs/tools/clang-formatted-files.txt +++ b/clang/docs/tools/clang-formatted-files.txt @@ -123,7 +123,6 @@ clang/include/clang/Analysis/Analyses/CalledOnceCheck.h clang/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h clang/include/clang/Analysis/FlowSensitive/AdornedCFG.h -clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -2147,8 +2146,10 @@ flang/include/flang/Parser/message.h flang/include/flang/Parser/parse-state.h flang/include/flang/Parser/parse-tree-visitor.h flang/include/flang/Parser/parsing.h +flang/include/flang/Parser/preprocessor.h flang/include/flang/Parser/provenance.h flang/include/flang/Parser/source.h +flang/include/flang/Parser/token-sequence.h flang/include/flang/Parser/tools.h flang/include/flang/Parser/unparse.h flang/include/flang/Parser/user-state.h @@ -2319,7 +2320,6 @@ flang/lib/Parser/openmp-parsers.cpp flang/lib/Parser/parse-tree.cpp flang/lib/Parser/parsing.cpp flang/lib/Parser/preprocessor.cpp -flang/lib/Parser/preprocessor.h flang/lib/Parser/prescan.cpp flang/lib/Parser/prescan.h flang/lib/Parser/program-parsers.cpp @@ -2328,7 +2328,6 @@ flang/lib/Parser/source.cpp flang/lib/Parser/stmt-parser.h flang/lib/Parser/token-parsers.h flang/lib/Parser/token-sequence.cpp -flang/lib/Parser/token-sequence.h flang/lib/Parser/tools.cpp flang/lib/Parser/type-parser-implementation.h flang/lib/Parser/type-parsers.h diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 60db3cf0966c0263083b82e1dec923ffe42bcff2..7a8bd985a91fc00b2c3a6c488aca5030fc211c8d 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2991,6 +2991,7 @@ enum CXCallingConv { CXCallingConv_AArch64SVEPCS = 18, CXCallingConv_M68kRTD = 19, CXCallingConv_PreserveNone = 20, + CXCallingConv_RISCVVectorCall = 21, CXCallingConv_Invalid = 100, CXCallingConv_Unexposed = 200 diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index 002f36ecbbaa3f3a1dca7e02b6f3e913f6eaa07c..28f8d67811f0a2517fba976008f0849b4793f25a 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -260,6 +260,9 @@ class ASTContext : public RefCountedBase { ASTContext&> SubstTemplateTemplateParmPacks; + mutable llvm::ContextualFoldingSet + ArrayParameterTypes; + /// The set of nested name specifiers. /// /// This set is managed by the NestedNameSpecifier class. @@ -1367,6 +1370,10 @@ public: /// type to the decayed type. QualType getDecayedType(QualType Orig, QualType Decayed) const; + /// Return the uniqued reference to a specified array parameter type from the + /// original array type. + QualType getArrayParameterType(QualType Ty) const; + /// Return the uniqued reference to the atomic type for the specified /// type. QualType getAtomicType(QualType T) const; @@ -3404,13 +3411,13 @@ const StreamingDiagnostic &operator<<(const StreamingDiagnostic &DB, /// Utility function for constructing a nullary selector. inline Selector GetNullarySelector(StringRef name, ASTContext &Ctx) { - IdentifierInfo* II = &Ctx.Idents.get(name); + const IdentifierInfo *II = &Ctx.Idents.get(name); return Ctx.Selectors.getSelector(0, &II); } /// Utility function for constructing an unary selector. inline Selector GetUnarySelector(StringRef name, ASTContext &Ctx) { - IdentifierInfo* II = &Ctx.Idents.get(name); + const IdentifierInfo *II = &Ctx.Idents.get(name); return Ctx.Selectors.getSelector(1, &II); } diff --git a/clang/include/clang/AST/ASTNodeTraverser.h b/clang/include/clang/AST/ASTNodeTraverser.h index 06d67e9cba95363a72c1c28ed8fb53f052fc630f..94e7dd817809dd2e09c34ed71f819ddccc13db63 100644 --- a/clang/include/clang/AST/ASTNodeTraverser.h +++ b/clang/include/clang/AST/ASTNodeTraverser.h @@ -53,6 +53,7 @@ struct { void Visit(TypeLoc); void Visit(const Decl *D); void Visit(const CXXCtorInitializer *Init); + void Visit(const OpenACCClause *C); void Visit(const OMPClause *C); void Visit(const BlockDecl::Capture &C); void Visit(const GenericSelectionExpr::ConstAssociation &A); @@ -239,6 +240,13 @@ public: }); } + void Visit(const OpenACCClause *C) { + getNodeDelegate().AddChild([=] { + getNodeDelegate().Visit(C); + // TODO OpenACC: Switch on clauses that have children, and add them. + }); + } + void Visit(const OMPClause *C) { getNodeDelegate().AddChild([=] { getNodeDelegate().Visit(C); @@ -799,6 +807,11 @@ public: Visit(C); } + void VisitOpenACCConstructStmt(const OpenACCConstructStmt *Node) { + for (const auto *C : Node->clauses()) + Visit(C); + } + void VisitInitListExpr(const InitListExpr *ILE) { if (auto *Filler = ILE->getArrayFiller()) { Visit(Filler, "array_filler"); diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index a5879591f4c65965b4ebd4b391c26f8e7fd6224c..ed6790acdfc7cca7598f8a1473f68d1ec1748e1a 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -1100,6 +1100,9 @@ protected: LLVM_PREFERRED_TYPE(bool) unsigned EscapingByref : 1; + + LLVM_PREFERRED_TYPE(bool) + unsigned IsCXXCondDecl : 1; }; union { @@ -1589,6 +1592,15 @@ public: NonParmVarDeclBits.EscapingByref = true; } + bool isCXXCondDecl() const { + return isa(this) ? false : NonParmVarDeclBits.IsCXXCondDecl; + } + + void setCXXCondDecl() { + assert(!isa(this)); + NonParmVarDeclBits.IsCXXCondDecl = true; + } + /// Determines if this variable's alignment is dependent. bool hasDependentAlignment() const; @@ -1719,7 +1731,7 @@ public: static ImplicitParamDecl *CreateDeserialized(ASTContext &C, unsigned ID); ImplicitParamDecl(ASTContext &C, DeclContext *DC, SourceLocation IdLoc, - IdentifierInfo *Id, QualType Type, + const IdentifierInfo *Id, QualType Type, ImplicitParamKind ParamKind) : VarDecl(ImplicitParam, C, DC, IdLoc, IdLoc, Id, Type, /*TInfo=*/nullptr, SC_None) { @@ -1753,7 +1765,7 @@ public: protected: ParmVarDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, QualType T, + SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S, Expr *DefArg) : VarDecl(DK, C, DC, StartLoc, IdLoc, Id, T, TInfo, S) { assert(ParmVarDeclBits.HasInheritedDefaultArg == false); @@ -1765,10 +1777,10 @@ protected: public: static ParmVarDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, - StorageClass S, Expr *DefArg); + SourceLocation StartLoc, SourceLocation IdLoc, + const IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, StorageClass S, + Expr *DefArg); static ParmVarDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -3083,7 +3095,7 @@ class FieldDecl : public DeclaratorDecl, public Mergeable { protected: FieldDecl(Kind DK, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, QualType T, + SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle) : DeclaratorDecl(DK, DC, IdLoc, Id, T, TInfo, StartLoc), BitField(false), @@ -3099,7 +3111,7 @@ public: static FieldDecl *Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, QualType T, + const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle); @@ -3320,8 +3332,9 @@ public: friend class ASTDeclReader; static IndirectFieldDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation L, IdentifierInfo *Id, - QualType T, llvm::MutableArrayRef CH); + SourceLocation L, const IdentifierInfo *Id, + QualType T, + llvm::MutableArrayRef CH); static IndirectFieldDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -3369,9 +3382,9 @@ class TypeDecl : public NamedDecl { void anchor() override; protected: - TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, const IdentifierInfo *Id, SourceLocation StartL = SourceLocation()) - : NamedDecl(DK, DC, L, Id), LocStart(StartL) {} + : NamedDecl(DK, DC, L, Id), LocStart(StartL) {} public: // Low-level accessor. If you just want the type defined by this node, @@ -3413,7 +3426,7 @@ class TypedefNameDecl : public TypeDecl, public Redeclarable { protected: TypedefNameDecl(Kind DK, ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, TypeSourceInfo *TInfo) + const IdentifierInfo *Id, TypeSourceInfo *TInfo) : TypeDecl(DK, DC, IdLoc, Id, StartLoc), redeclarable_base(C), MaybeModedTInfo(TInfo, 0) {} @@ -3500,13 +3513,14 @@ private: /// type specifier. class TypedefDecl : public TypedefNameDecl { TypedefDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) + SourceLocation IdLoc, const IdentifierInfo *Id, + TypeSourceInfo *TInfo) : TypedefNameDecl(Typedef, C, DC, StartLoc, IdLoc, Id, TInfo) {} public: static TypedefDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, TypeSourceInfo *TInfo); + const IdentifierInfo *Id, TypeSourceInfo *TInfo); static TypedefDecl *CreateDeserialized(ASTContext &C, unsigned ID); SourceRange getSourceRange() const override LLVM_READONLY; @@ -3523,14 +3537,15 @@ class TypeAliasDecl : public TypedefNameDecl { TypeAliasTemplateDecl *Template; TypeAliasDecl(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, TypeSourceInfo *TInfo) + SourceLocation IdLoc, const IdentifierInfo *Id, + TypeSourceInfo *TInfo) : TypedefNameDecl(TypeAlias, C, DC, StartLoc, IdLoc, Id, TInfo), Template(nullptr) {} public: static TypeAliasDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, TypeSourceInfo *TInfo); + const IdentifierInfo *Id, TypeSourceInfo *TInfo); static TypeAliasDecl *CreateDeserialized(ASTContext &C, unsigned ID); SourceRange getSourceRange() const override LLVM_READONLY; diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h index 47ed6d0d1db0df804f55cdfca4c5c0ddd4868bb9..858450926455c602030671323257a4470bc096f7 100644 --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -669,9 +669,8 @@ public: /// Whether this declaration comes from another module unit. bool isInAnotherModuleUnit() const; - /// FIXME: Implement discarding declarations actually in global module - /// fragment. See [module.global.frag]p3,4 for details. - bool isDiscardedInGlobalModuleFragment() const { return false; } + /// Whether this declaration comes from explicit global module. + bool isFromExplicitGlobalModule() const; /// Check if we should skip checking ODRHash for declaration \param D. /// diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 9cebaff63bb0dbe77dfbaa4d441a4e26526db167..7aed4d5cbc002e2c60d743922f16d507bfb2a2dd 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1869,6 +1869,10 @@ public: DL.MethodTyInfo = TS; } + void setLambdaDependencyKind(unsigned Kind) { + getLambdaData().DependencyKind = Kind; + } + void setLambdaIsGeneric(bool IsGeneric) { assert(DefinitionData && DefinitionData->IsLambda && "setting lambda property of non-lambda class"); diff --git a/clang/include/clang/AST/DeclContextInternals.h b/clang/include/clang/AST/DeclContextInternals.h index 903cdb7bfcc822a2a066fe0e96d96f44f1e6e217..c4734ab578953835ee9719264ae2e9279d7d979f 100644 --- a/clang/include/clang/AST/DeclContextInternals.h +++ b/clang/include/clang/AST/DeclContextInternals.h @@ -205,7 +205,7 @@ public: Data.setPointer(Head); } - /// Return an array of all the decls that this list represents. + /// Return the list of all the decls. DeclContext::lookup_result getLookupResult() const { return DeclContext::lookup_result(Data.getPointer()); } diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index f8f894b4b10d1919a484eae6b14adf45517166ea..b8d17dd06d1550082446496c9d02ef5fa9c759a5 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -772,7 +772,7 @@ private: // Synthesize ivar for this property ObjCIvarDecl *PropertyIvarDecl = nullptr; - ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, + ObjCPropertyDecl(DeclContext *DC, SourceLocation L, const IdentifierInfo *Id, SourceLocation AtLocation, SourceLocation LParenLocation, QualType T, TypeSourceInfo *TSI, PropertyControl propControl) : NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation), @@ -782,10 +782,12 @@ private: PropertyImplementation(propControl) {} public: - static ObjCPropertyDecl * - Create(ASTContext &C, DeclContext *DC, SourceLocation L, IdentifierInfo *Id, - SourceLocation AtLocation, SourceLocation LParenLocation, QualType T, - TypeSourceInfo *TSI, PropertyControl propControl = None); + static ObjCPropertyDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, const IdentifierInfo *Id, + SourceLocation AtLocation, + SourceLocation LParenLocation, QualType T, + TypeSourceInfo *TSI, + PropertyControl propControl = None); static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -952,7 +954,7 @@ class ObjCContainerDecl : public NamedDecl, public DeclContext { void anchor() override; public: - ObjCContainerDecl(Kind DK, DeclContext *DC, IdentifierInfo *Id, + ObjCContainerDecl(Kind DK, DeclContext *DC, const IdentifierInfo *Id, SourceLocation nameLoc, SourceLocation atStartLoc); // Iterator access to instance/class properties. @@ -1240,7 +1242,7 @@ class ObjCInterfaceDecl : public ObjCContainerDecl llvm::PointerIntPair Data; ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, SourceLocation AtLoc, - IdentifierInfo *Id, ObjCTypeParamList *typeParamList, + const IdentifierInfo *Id, ObjCTypeParamList *typeParamList, SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl, bool IsInternal); @@ -1271,13 +1273,11 @@ class ObjCInterfaceDecl : public ObjCContainerDecl } public: - static ObjCInterfaceDecl *Create(const ASTContext &C, DeclContext *DC, - SourceLocation atLoc, - IdentifierInfo *Id, - ObjCTypeParamList *typeParamList, - ObjCInterfaceDecl *PrevDecl, - SourceLocation ClassLoc = SourceLocation(), - bool isInternal = false); + static ObjCInterfaceDecl * + Create(const ASTContext &C, DeclContext *DC, SourceLocation atLoc, + const IdentifierInfo *Id, ObjCTypeParamList *typeParamList, + ObjCInterfaceDecl *PrevDecl, + SourceLocation ClassLoc = SourceLocation(), bool isInternal = false); static ObjCInterfaceDecl *CreateDeserialized(const ASTContext &C, unsigned ID); @@ -1338,7 +1338,8 @@ public: ObjCImplementationDecl *getImplementation() const; void setImplementation(ObjCImplementationDecl *ImplD); - ObjCCategoryDecl *FindCategoryDeclaration(IdentifierInfo *CategoryId) const; + ObjCCategoryDecl * + FindCategoryDeclaration(const IdentifierInfo *CategoryId) const; // Get the local instance/class method declared in a category. ObjCMethodDecl *getCategoryInstanceMethod(Selector Sel) const; @@ -1794,9 +1795,9 @@ public: data().CategoryList = category; } - ObjCPropertyDecl - *FindPropertyVisibleInPrimaryClass(IdentifierInfo *PropertyId, - ObjCPropertyQueryKind QueryKind) const; + ObjCPropertyDecl * + FindPropertyVisibleInPrimaryClass(const IdentifierInfo *PropertyId, + ObjCPropertyQueryKind QueryKind) const; void collectPropertiesToImplement(PropertyMap &PM) const override; @@ -1954,8 +1955,8 @@ public: private: ObjCIvarDecl(ObjCContainerDecl *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, + SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, AccessControl ac, Expr *BW, bool synthesized) : FieldDecl(ObjCIvar, DC, StartLoc, IdLoc, Id, T, TInfo, BW, /*Mutable=*/false, /*HasInit=*/ICIS_NoInit), @@ -1964,10 +1965,9 @@ private: public: static ObjCIvarDecl *Create(ASTContext &C, ObjCContainerDecl *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, QualType T, - TypeSourceInfo *TInfo, - AccessControl ac, Expr *BW = nullptr, - bool synthesized=false); + const IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, AccessControl ac, + Expr *BW = nullptr, bool synthesized = false); static ObjCIvarDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -2343,7 +2343,7 @@ class ObjCCategoryDecl : public ObjCContainerDecl { ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc, SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, - IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, + const IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, ObjCTypeParamList *typeParamList, SourceLocation IvarLBraceLoc = SourceLocation(), SourceLocation IvarRBraceLoc = SourceLocation()); @@ -2354,15 +2354,13 @@ public: friend class ASTDeclReader; friend class ASTDeclWriter; - static ObjCCategoryDecl *Create(ASTContext &C, DeclContext *DC, - SourceLocation AtLoc, - SourceLocation ClassNameLoc, - SourceLocation CategoryNameLoc, - IdentifierInfo *Id, - ObjCInterfaceDecl *IDecl, - ObjCTypeParamList *typeParamList, - SourceLocation IvarLBraceLoc=SourceLocation(), - SourceLocation IvarRBraceLoc=SourceLocation()); + static ObjCCategoryDecl * + Create(ASTContext &C, DeclContext *DC, SourceLocation AtLoc, + SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, + const IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, + ObjCTypeParamList *typeParamList, + SourceLocation IvarLBraceLoc = SourceLocation(), + SourceLocation IvarRBraceLoc = SourceLocation()); static ObjCCategoryDecl *CreateDeserialized(ASTContext &C, unsigned ID); ObjCInterfaceDecl *getClassInterface() { return ClassInterface; } @@ -2472,10 +2470,9 @@ class ObjCImplDecl : public ObjCContainerDecl { void anchor() override; protected: - ObjCImplDecl(Kind DK, DeclContext *DC, - ObjCInterfaceDecl *classInterface, - IdentifierInfo *Id, - SourceLocation nameLoc, SourceLocation atStartLoc) + ObjCImplDecl(Kind DK, DeclContext *DC, ObjCInterfaceDecl *classInterface, + const IdentifierInfo *Id, SourceLocation nameLoc, + SourceLocation atStartLoc) : ObjCContainerDecl(DK, DC, Id, nameLoc, atStartLoc), ClassInterface(classInterface) {} @@ -2543,12 +2540,12 @@ class ObjCCategoryImplDecl : public ObjCImplDecl { // Category name location SourceLocation CategoryNameLoc; - ObjCCategoryImplDecl(DeclContext *DC, IdentifierInfo *Id, + ObjCCategoryImplDecl(DeclContext *DC, const IdentifierInfo *Id, ObjCInterfaceDecl *classInterface, SourceLocation nameLoc, SourceLocation atStartLoc, SourceLocation CategoryNameLoc) - : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id, - nameLoc, atStartLoc), + : ObjCImplDecl(ObjCCategoryImpl, DC, classInterface, Id, nameLoc, + atStartLoc), CategoryNameLoc(CategoryNameLoc) {} void anchor() override; @@ -2557,12 +2554,10 @@ public: friend class ASTDeclReader; friend class ASTDeclWriter; - static ObjCCategoryImplDecl *Create(ASTContext &C, DeclContext *DC, - IdentifierInfo *Id, - ObjCInterfaceDecl *classInterface, - SourceLocation nameLoc, - SourceLocation atStartLoc, - SourceLocation CategoryNameLoc); + static ObjCCategoryImplDecl * + Create(ASTContext &C, DeclContext *DC, const IdentifierInfo *Id, + ObjCInterfaceDecl *classInterface, SourceLocation nameLoc, + SourceLocation atStartLoc, SourceLocation CategoryNameLoc); static ObjCCategoryImplDecl *CreateDeserialized(ASTContext &C, unsigned ID); ObjCCategoryDecl *getCategoryDecl() const; diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index e3b6a7efb1127af56d594d8299f49a21ed38a43f..f24e71ff229648d80336e76faef5abbe850a0fe9 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -1389,14 +1389,14 @@ class NonTypeTemplateParmDecl final NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, unsigned D, unsigned P, - IdentifierInfo *Id, QualType T, + const IdentifierInfo *Id, QualType T, bool ParameterPack, TypeSourceInfo *TInfo) : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc), TemplateParmPosition(D, P), ParameterPack(ParameterPack) {} NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, unsigned D, unsigned P, - IdentifierInfo *Id, QualType T, + const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, ArrayRef ExpandedTypes, ArrayRef ExpandedTInfos); @@ -1404,12 +1404,12 @@ class NonTypeTemplateParmDecl final public: static NonTypeTemplateParmDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, + SourceLocation IdLoc, unsigned D, unsigned P, const IdentifierInfo *Id, QualType T, bool ParameterPack, TypeSourceInfo *TInfo); static NonTypeTemplateParmDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, + SourceLocation IdLoc, unsigned D, unsigned P, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, ArrayRef ExpandedTypes, ArrayRef ExpandedTInfos); @@ -1581,26 +1581,36 @@ class TemplateTemplateParmDecl final DefaultArgStorage; DefArgStorage DefaultArgument; + /// Whether this template template parameter was declaration with + /// the 'typename' keyword. + /// + /// If false, it was declared with the 'class' keyword. + LLVM_PREFERRED_TYPE(bool) + unsigned Typename : 1; + /// Whether this parameter is a parameter pack. - bool ParameterPack; + LLVM_PREFERRED_TYPE(bool) + unsigned ParameterPack : 1; /// Whether this template template parameter is an "expanded" /// parameter pack, meaning that it is a pack expansion and we /// already know the set of template parameters that expansion expands to. - bool ExpandedParameterPack = false; + LLVM_PREFERRED_TYPE(bool) + unsigned ExpandedParameterPack : 1; /// The number of parameters in an expanded parameter pack. unsigned NumExpandedParams = 0; - TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, - unsigned D, unsigned P, bool ParameterPack, - IdentifierInfo *Id, TemplateParameterList *Params) + TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, + unsigned P, bool ParameterPack, IdentifierInfo *Id, + bool Typename, TemplateParameterList *Params) : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), - TemplateParmPosition(D, P), ParameterPack(ParameterPack) {} + TemplateParmPosition(D, P), Typename(Typename), + ParameterPack(ParameterPack), ExpandedParameterPack(false) {} - TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, - unsigned D, unsigned P, - IdentifierInfo *Id, TemplateParameterList *Params, + TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, + unsigned P, IdentifierInfo *Id, bool Typename, + TemplateParameterList *Params, ArrayRef Expansions); void anchor() override; @@ -1613,14 +1623,13 @@ public: static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, bool ParameterPack, - IdentifierInfo *Id, + IdentifierInfo *Id, bool Typename, TemplateParameterList *Params); - static TemplateTemplateParmDecl *Create(const ASTContext &C, DeclContext *DC, - SourceLocation L, unsigned D, - unsigned P, - IdentifierInfo *Id, - TemplateParameterList *Params, - ArrayRef Expansions); + static TemplateTemplateParmDecl * + Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, + unsigned P, IdentifierInfo *Id, bool Typename, + TemplateParameterList *Params, + ArrayRef Expansions); static TemplateTemplateParmDecl *CreateDeserialized(ASTContext &C, unsigned ID); @@ -1634,6 +1643,14 @@ public: using TemplateParmPosition::setPosition; using TemplateParmPosition::getIndex; + /// Whether this template template parameter was declared with + /// the 'typename' keyword. + bool wasDeclaredWithTypename() const { return Typename; } + + /// Set whether this template template parameter was declared with + /// the 'typename' or 'class' keyword. + void setDeclaredWithTypename(bool withTypename) { Typename = withTypename; } + /// Whether this template template parameter is a template /// parameter pack. /// diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h index 6e153ebe024b42eeb19bdfe178889ce272c25d56..2bfefeabc348bee1cc399a43bfd8aa057a18ec3d 100644 --- a/clang/include/clang/AST/Expr.h +++ b/clang/include/clang/AST/Expr.h @@ -3163,23 +3163,12 @@ public: } }; -/// Extra data stored in some MemberExpr objects. -struct MemberExprNameQualifier { - /// The nested-name-specifier that qualifies the name, including - /// source-location information. - NestedNameSpecifierLoc QualifierLoc; - - /// The DeclAccessPair through which the MemberDecl was found due to - /// name qualifiers. - DeclAccessPair FoundDecl; -}; - /// MemberExpr - [C99 6.5.2.3] Structure and Union Members. X->F and X.F. /// class MemberExpr final : public Expr, - private llvm::TrailingObjects { friend class ASTReader; friend class ASTStmtReader; @@ -3201,26 +3190,30 @@ class MemberExpr final /// MemberLoc - This is the location of the member name. SourceLocation MemberLoc; - size_t numTrailingObjects(OverloadToken) const { - return hasQualifierOrFoundDecl(); + size_t numTrailingObjects(OverloadToken) const { + return hasQualifier(); + } + + size_t numTrailingObjects(OverloadToken) const { + return hasFoundDecl(); } size_t numTrailingObjects(OverloadToken) const { return hasTemplateKWAndArgsInfo(); } - bool hasQualifierOrFoundDecl() const { - return MemberExprBits.HasQualifierOrFoundDecl; - } + bool hasFoundDecl() const { return MemberExprBits.HasFoundDecl; } bool hasTemplateKWAndArgsInfo() const { return MemberExprBits.HasTemplateKWAndArgsInfo; } MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc, - ValueDecl *MemberDecl, const DeclarationNameInfo &NameInfo, - QualType T, ExprValueKind VK, ExprObjectKind OK, - NonOdrUseReason NOUR); + NestedNameSpecifierLoc QualifierLoc, SourceLocation TemplateKWLoc, + ValueDecl *MemberDecl, DeclAccessPair FoundDecl, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs, QualType T, + ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR); MemberExpr(EmptyShell Empty) : Expr(MemberExprClass, Empty), Base(), MemberDecl() {} @@ -3264,24 +3257,24 @@ public: /// Retrieves the declaration found by lookup. DeclAccessPair getFoundDecl() const { - if (!hasQualifierOrFoundDecl()) + if (!hasFoundDecl()) return DeclAccessPair::make(getMemberDecl(), getMemberDecl()->getAccess()); - return getTrailingObjects()->FoundDecl; + return *getTrailingObjects(); } /// Determines whether this member expression actually had /// a C++ nested-name-specifier prior to the name of the member, e.g., /// x->Base::foo. - bool hasQualifier() const { return getQualifier() != nullptr; } + bool hasQualifier() const { return MemberExprBits.HasQualifier; } /// If the member name was qualified, retrieves the /// nested-name-specifier that precedes the member name, with source-location /// information. NestedNameSpecifierLoc getQualifierLoc() const { - if (!hasQualifierOrFoundDecl()) + if (!hasQualifier()) return NestedNameSpecifierLoc(); - return getTrailingObjects()->QualifierLoc; + return *getTrailingObjects(); } /// If the member name was qualified, retrieves the diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index 6003b866c9f564519006077b3618fc324bd09bef..d28e5c3a78ee4bbb9c76ddb2d229a9d99372ab19 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -1149,6 +1149,7 @@ class CXXThisExpr : public Expr { CXXThisExpr(SourceLocation L, QualType Ty, bool IsImplicit, ExprValueKind VK) : Expr(CXXThisExprClass, Ty, VK, OK_Ordinary) { CXXThisExprBits.IsImplicit = IsImplicit; + CXXThisExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter = false; CXXThisExprBits.Loc = L; setDependence(computeDependence(this)); } @@ -1170,6 +1171,15 @@ public: bool isImplicit() const { return CXXThisExprBits.IsImplicit; } void setImplicit(bool I) { CXXThisExprBits.IsImplicit = I; } + bool isCapturedByCopyInLambdaWithExplicitObjectParameter() const { + return CXXThisExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter; + } + + void setCapturedByCopyInLambdaWithExplicitObjectParameter(bool Set) { + CXXThisExprBits.CapturedByCopyInLambdaWithExplicitObjectParameter = Set; + setDependence(computeDependence(this)); + } + static bool classof(const Stmt *T) { return T->getStmtClass() == CXXThisExprClass; } @@ -2549,7 +2559,7 @@ public: class PseudoDestructorTypeStorage { /// Either the type source information or the name of the type, if /// it couldn't be resolved due to type-dependence. - llvm::PointerUnion Type; + llvm::PointerUnion Type; /// The starting source location of the pseudo-destructor type. SourceLocation Location; @@ -2557,7 +2567,7 @@ class PseudoDestructorTypeStorage { public: PseudoDestructorTypeStorage() = default; - PseudoDestructorTypeStorage(IdentifierInfo *II, SourceLocation Loc) + PseudoDestructorTypeStorage(const IdentifierInfo *II, SourceLocation Loc) : Type(II), Location(Loc) {} PseudoDestructorTypeStorage(TypeSourceInfo *Info); @@ -2566,8 +2576,8 @@ public: return Type.dyn_cast(); } - IdentifierInfo *getIdentifier() const { - return Type.dyn_cast(); + const IdentifierInfo *getIdentifier() const { + return Type.dyn_cast(); } SourceLocation getLocation() const { return Location; } @@ -2698,7 +2708,7 @@ public: /// In a dependent pseudo-destructor expression for which we do not /// have full type information on the destroyed type, provides the name /// of the destroyed type. - IdentifierInfo *getDestroyedTypeIdentifier() const { + const IdentifierInfo *getDestroyedTypeIdentifier() const { return DestroyedType.getIdentifier(); } diff --git a/clang/include/clang/AST/ExternalASTSource.h b/clang/include/clang/AST/ExternalASTSource.h index 8e573965b0a3360c2f70ea4cd95ec85fa718f925..230c83943c2224469f59e40d5eb264a262e453d3 100644 --- a/clang/include/clang/AST/ExternalASTSource.h +++ b/clang/include/clang/AST/ExternalASTSource.h @@ -138,7 +138,7 @@ public: virtual CXXBaseSpecifier *GetExternalCXXBaseSpecifiers(uint64_t Offset); /// Update an out-of-date identifier. - virtual void updateOutOfDateIdentifier(IdentifierInfo &II) {} + virtual void updateOutOfDateIdentifier(const IdentifierInfo &II) {} /// Find all declarations with the given name in the given context, /// and add them to the context by calling SetExternalVisibleDeclsForName diff --git a/clang/include/clang/AST/FormatString.h b/clang/include/clang/AST/FormatString.h index e2232fb4a47153f77882427d83046108525c691b..a074dd23e2ad4c7600b4206e3f36ec10f85b3d73 100644 --- a/clang/include/clang/AST/FormatString.h +++ b/clang/include/clang/AST/FormatString.h @@ -284,6 +284,8 @@ public: /// The conversion specifier and the argument type are disallowed by the C /// standard, but are in practice harmless. For instance, "%p" and int*. NoMatchPedantic, + /// The conversion specifier and the argument type have different sign. + NoMatchSignedness, /// The conversion specifier and the argument type are compatible, but still /// seems likely to be an error. For instance, "%hd" and _Bool. NoMatchTypeConfusion, diff --git a/clang/include/clang/AST/JSONNodeDumper.h b/clang/include/clang/AST/JSONNodeDumper.h index dde70dde2fa2be1aa8e17565cd6cfe7384ed03f2..7a60f362650ca0a939a03acb390bef7ae887eb57 100644 --- a/clang/include/clang/AST/JSONNodeDumper.h +++ b/clang/include/clang/AST/JSONNodeDumper.h @@ -203,6 +203,7 @@ public: void Visit(const TemplateArgument &TA, SourceRange R = {}, const Decl *From = nullptr, StringRef Label = {}); void Visit(const CXXCtorInitializer *Init); + void Visit(const OpenACCClause *C); void Visit(const OMPClause *C); void Visit(const BlockDecl::Capture &C); void Visit(const GenericSelectionExpr::ConstAssociation &A); diff --git a/clang/include/clang/AST/NestedNameSpecifier.h b/clang/include/clang/AST/NestedNameSpecifier.h index 3b6cf97211850925e4b2392b56a1d88a16612161..7b0c21b9e7cfb1515789809bee50566bedbad480 100644 --- a/clang/include/clang/AST/NestedNameSpecifier.h +++ b/clang/include/clang/AST/NestedNameSpecifier.h @@ -124,7 +124,7 @@ public: /// cannot be resolved. static NestedNameSpecifier *Create(const ASTContext &Context, NestedNameSpecifier *Prefix, - IdentifierInfo *II); + const IdentifierInfo *II); /// Builds a nested name specifier that names a namespace. static NestedNameSpecifier *Create(const ASTContext &Context, @@ -134,7 +134,7 @@ public: /// Builds a nested name specifier that names a namespace alias. static NestedNameSpecifier *Create(const ASTContext &Context, NestedNameSpecifier *Prefix, - NamespaceAliasDecl *Alias); + const NamespaceAliasDecl *Alias); /// Builds a nested name specifier that names a type. static NestedNameSpecifier *Create(const ASTContext &Context, @@ -148,7 +148,7 @@ public: /// nested name specifier, e.g., in "x->Base::f", the "x" has a dependent /// type. static NestedNameSpecifier *Create(const ASTContext &Context, - IdentifierInfo *II); + const IdentifierInfo *II); /// Returns the nested name specifier representing the global /// scope. diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h new file mode 100644 index 0000000000000000000000000000000000000000..27e4e1a12c98371e550bcf0a8cd73901bde9d471 --- /dev/null +++ b/clang/include/clang/AST/OpenACCClause.h @@ -0,0 +1,173 @@ +//===- OpenACCClause.h - Classes for OpenACC clauses ------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// \file +// This file defines OpenACC AST classes for clauses. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_OPENACCCLAUSE_H +#define LLVM_CLANG_AST_OPENACCCLAUSE_H +#include "clang/AST/ASTContext.h" +#include "clang/Basic/OpenACCKinds.h" + +namespace clang { +/// This is the base type for all OpenACC Clauses. +class OpenACCClause { + OpenACCClauseKind Kind; + SourceRange Location; + +protected: + OpenACCClause(OpenACCClauseKind K, SourceLocation BeginLoc, + SourceLocation EndLoc) + : Kind(K), Location(BeginLoc, EndLoc) {} + +public: + OpenACCClauseKind getClauseKind() const { return Kind; } + SourceLocation getBeginLoc() const { return Location.getBegin(); } + SourceLocation getEndLoc() const { return Location.getEnd(); } + + static bool classof(const OpenACCClause *) { return true; } + + virtual ~OpenACCClause() = default; +}; + +/// Represents a clause that has a list of parameters. +class OpenACCClauseWithParams : public OpenACCClause { + /// Location of the '('. + SourceLocation LParenLoc; + +protected: + OpenACCClauseWithParams(OpenACCClauseKind K, SourceLocation BeginLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OpenACCClause(K, BeginLoc, EndLoc), LParenLoc(LParenLoc) {} + +public: + SourceLocation getLParenLoc() const { return LParenLoc; } +}; + +/// A 'default' clause, has the optional 'none' or 'present' argument. +class OpenACCDefaultClause : public OpenACCClauseWithParams { + friend class ASTReaderStmt; + friend class ASTWriterStmt; + + OpenACCDefaultClauseKind DefaultClauseKind; + +protected: + OpenACCDefaultClause(OpenACCDefaultClauseKind K, SourceLocation BeginLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) + : OpenACCClauseWithParams(OpenACCClauseKind::Default, BeginLoc, LParenLoc, + EndLoc), + DefaultClauseKind(K) { + assert((DefaultClauseKind == OpenACCDefaultClauseKind::None || + DefaultClauseKind == OpenACCDefaultClauseKind::Present) && + "Invalid Clause Kind"); + } + +public: + OpenACCDefaultClauseKind getDefaultClauseKind() const { + return DefaultClauseKind; + } + + static OpenACCDefaultClause *Create(const ASTContext &C, + OpenACCDefaultClauseKind K, + SourceLocation BeginLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); +}; + +template class OpenACCClauseVisitor { + Impl &getDerived() { return static_cast(*this); } + +public: + void VisitClauseList(ArrayRef List) { + for (const OpenACCClause *Clause : List) + Visit(Clause); + } + + void Visit(const OpenACCClause *C) { + if (!C) + return; + + switch (C->getClauseKind()) { + case OpenACCClauseKind::Default: + VisitOpenACCDefaultClause(*cast(C)); + return; + case OpenACCClauseKind::Finalize: + case OpenACCClauseKind::IfPresent: + case OpenACCClauseKind::Seq: + case OpenACCClauseKind::Independent: + case OpenACCClauseKind::Auto: + case OpenACCClauseKind::Worker: + case OpenACCClauseKind::Vector: + case OpenACCClauseKind::NoHost: + case OpenACCClauseKind::If: + case OpenACCClauseKind::Self: + case OpenACCClauseKind::Copy: + case OpenACCClauseKind::UseDevice: + case OpenACCClauseKind::Attach: + case OpenACCClauseKind::Delete: + case OpenACCClauseKind::Detach: + case OpenACCClauseKind::Device: + case OpenACCClauseKind::DevicePtr: + case OpenACCClauseKind::DeviceResident: + case OpenACCClauseKind::FirstPrivate: + case OpenACCClauseKind::Host: + case OpenACCClauseKind::Link: + case OpenACCClauseKind::NoCreate: + case OpenACCClauseKind::Present: + case OpenACCClauseKind::Private: + case OpenACCClauseKind::CopyOut: + case OpenACCClauseKind::CopyIn: + case OpenACCClauseKind::Create: + case OpenACCClauseKind::Reduction: + case OpenACCClauseKind::Collapse: + case OpenACCClauseKind::Bind: + case OpenACCClauseKind::VectorLength: + case OpenACCClauseKind::NumGangs: + case OpenACCClauseKind::NumWorkers: + case OpenACCClauseKind::DeviceNum: + case OpenACCClauseKind::DefaultAsync: + case OpenACCClauseKind::DeviceType: + case OpenACCClauseKind::DType: + case OpenACCClauseKind::Async: + case OpenACCClauseKind::Tile: + case OpenACCClauseKind::Gang: + case OpenACCClauseKind::Wait: + case OpenACCClauseKind::Invalid: + llvm_unreachable("Clause visitor not yet implemented"); + } + llvm_unreachable("Invalid Clause kind"); + } + + void VisitOpenACCDefaultClause(const OpenACCDefaultClause &Clause) { + return getDerived().VisitOpenACCDefaultClause(Clause); + } +}; + +class OpenACCClausePrinter final + : public OpenACCClauseVisitor { + raw_ostream &OS; + +public: + void VisitClauseList(ArrayRef List) { + for (const OpenACCClause *Clause : List) { + Visit(Clause); + + if (Clause != List.back()) + OS << ' '; + } + } + OpenACCClausePrinter(raw_ostream &OS) : OS(OS) {} + + void VisitOpenACCDefaultClause(const OpenACCDefaultClause &Clause); +}; + +} // namespace clang + +#endif // LLVM_CLANG_AST_OPENACCCLAUSE_H diff --git a/clang/include/clang/AST/OperationKinds.def b/clang/include/clang/AST/OperationKinds.def index ef05072800f11a1bcd6a7ee48824150ea92104b6..8788b8ff0ef0a4538ff8bed81b05f1993d3a6c24 100644 --- a/clang/include/clang/AST/OperationKinds.def +++ b/clang/include/clang/AST/OperationKinds.def @@ -364,6 +364,9 @@ CAST_OPERATION(IntToOCLSampler) // Truncate a vector type by dropping elements from the end (HLSL only). CAST_OPERATION(HLSLVectorTruncation) +// Non-decaying array RValue cast (HLSL only). +CAST_OPERATION(HLSLArrayRValue) + //===- Binary Operations -------------------------------------------------===// // Operators listed in order of precedence. // Note that additions to this should also update the StmtVisitor class, diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 4a1ff222ecadcda0b37c231c3a243c8d40d922b7..7eb92e304a3856bcdbc70bb9733e108389df3778 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -509,6 +509,7 @@ private: bool TraverseOpenACCConstructStmt(OpenACCConstructStmt *S); bool TraverseOpenACCAssociatedStmtConstruct(OpenACCAssociatedStmtConstruct *S); + bool VisitOpenACCClauseList(ArrayRef); }; template @@ -993,6 +994,12 @@ DEF_TRAVERSE_TYPE(ConstantArrayType, { TRY_TO(TraverseStmt(const_cast(T->getSizeExpr()))); }) +DEF_TRAVERSE_TYPE(ArrayParameterType, { + TRY_TO(TraverseType(T->getElementType())); + if (T->getSizeExpr()) + TRY_TO(TraverseStmt(const_cast(T->getSizeExpr()))); +}) + DEF_TRAVERSE_TYPE(IncompleteArrayType, { TRY_TO(TraverseType(T->getElementType())); }) @@ -1260,6 +1267,11 @@ DEF_TRAVERSE_TYPELOC(ConstantArrayType, { TRY_TO(TraverseArrayTypeLocHelper(TL)); }) +DEF_TRAVERSE_TYPELOC(ArrayParameterType, { + TRY_TO(TraverseTypeLoc(TL.getElementLoc())); + TRY_TO(TraverseArrayTypeLocHelper(TL)); +}) + DEF_TRAVERSE_TYPELOC(IncompleteArrayType, { TRY_TO(TraverseTypeLoc(TL.getElementLoc())); TRY_TO(TraverseArrayTypeLocHelper(TL)); @@ -3925,8 +3937,8 @@ bool RecursiveASTVisitor::VisitOMPXBareClause(OMPXBareClause *C) { template bool RecursiveASTVisitor::TraverseOpenACCConstructStmt( - OpenACCConstructStmt *) { - // TODO OpenACC: When we implement clauses, ensure we traverse them here. + OpenACCConstructStmt *C) { + TRY_TO(VisitOpenACCClauseList(C->clauses())); return true; } @@ -3938,6 +3950,14 @@ bool RecursiveASTVisitor::TraverseOpenACCAssociatedStmtConstruct( return true; } +template +bool RecursiveASTVisitor::VisitOpenACCClauseList( + ArrayRef) { + // TODO OpenACC: When we have Clauses with expressions, we should visit them + // here. + return true; +} + DEF_TRAVERSE_STMT(OpenACCComputeConstruct, { TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); }) diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h index 55eca4007d17ea25c9244cf94fe34b849461149b..1b9c9231047717bd32f2c19d77f18264eed512bf 100644 --- a/clang/include/clang/AST/Stmt.h +++ b/clang/include/clang/AST/Stmt.h @@ -583,11 +583,13 @@ protected: unsigned IsArrow : 1; /// True if this member expression used a nested-name-specifier to - /// refer to the member, e.g., "x->Base::f", or found its member via - /// a using declaration. When true, a MemberExprNameQualifier - /// structure is allocated immediately after the MemberExpr. + /// refer to the member, e.g., "x->Base::f". LLVM_PREFERRED_TYPE(bool) - unsigned HasQualifierOrFoundDecl : 1; + unsigned HasQualifier : 1; + + // True if this member expression found its member via a using declaration. + LLVM_PREFERRED_TYPE(bool) + unsigned HasFoundDecl : 1; /// True if this member expression specified a template keyword /// and/or a template argument list explicitly, e.g., x->f, @@ -782,6 +784,11 @@ protected: LLVM_PREFERRED_TYPE(bool) unsigned IsImplicit : 1; + /// Whether there is a lambda with an explicit object parameter that + /// captures this "this" by copy. + LLVM_PREFERRED_TYPE(bool) + unsigned CapturedByCopyInLambdaWithExplicitObjectParameter : 1; + /// The location of the "this". SourceLocation Loc; }; diff --git a/clang/include/clang/AST/StmtOpenACC.h b/clang/include/clang/AST/StmtOpenACC.h index 19da66832c7374ca38048fb5b630cc6aee786281..419cb6cada0bc7d483c18872816bdfb78569965d 100644 --- a/clang/include/clang/AST/StmtOpenACC.h +++ b/clang/include/clang/AST/StmtOpenACC.h @@ -13,9 +13,11 @@ #ifndef LLVM_CLANG_AST_STMTOPENACC_H #define LLVM_CLANG_AST_STMTOPENACC_H +#include "clang/AST/OpenACCClause.h" #include "clang/AST/Stmt.h" #include "clang/Basic/OpenACCKinds.h" #include "clang/Basic/SourceLocation.h" +#include namespace clang { /// This is the base class for an OpenACC statement-level construct, other @@ -30,13 +32,23 @@ class OpenACCConstructStmt : public Stmt { /// the directive. SourceRange Range; - // TODO OPENACC: Clauses should probably be collected in this class. + /// The list of clauses. This is stored here as an ArrayRef, as this is the + /// most convienient place to access the list, however the list itself should + /// be stored in leaf nodes, likely in trailing-storage. + MutableArrayRef Clauses; protected: OpenACCConstructStmt(StmtClass SC, OpenACCDirectiveKind K, SourceLocation Start, SourceLocation End) : Stmt(SC), Kind(K), Range(Start, End) {} + // Used only for initialization, the leaf class can initialize this to + // trailing storage. + void setClauseList(MutableArrayRef NewClauses) { + assert(Clauses.empty() && "Cannot change clause list"); + Clauses = NewClauses; + } + public: OpenACCDirectiveKind getDirectiveKind() const { return Kind; } @@ -47,6 +59,7 @@ public: SourceLocation getBeginLoc() const { return Range.getBegin(); } SourceLocation getEndLoc() const { return Range.getEnd(); } + ArrayRef clauses() const { return Clauses; } child_range children() { return child_range(child_iterator(), child_iterator()); @@ -101,17 +114,32 @@ public: /// those three, as they are semantically identical, and have only minor /// differences in the permitted list of clauses, which can be differentiated by /// the 'Kind'. -class OpenACCComputeConstruct : public OpenACCAssociatedStmtConstruct { +class OpenACCComputeConstruct final + : public OpenACCAssociatedStmtConstruct, + public llvm::TrailingObjects { friend class ASTStmtWriter; friend class ASTStmtReader; friend class ASTContext; - OpenACCComputeConstruct() - : OpenACCAssociatedStmtConstruct( - OpenACCComputeConstructClass, OpenACCDirectiveKind::Invalid, - SourceLocation{}, SourceLocation{}, /*AssociatedStmt=*/nullptr) {} + OpenACCComputeConstruct(unsigned NumClauses) + : OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass, + OpenACCDirectiveKind::Invalid, + SourceLocation{}, SourceLocation{}, + /*AssociatedStmt=*/nullptr) { + // We cannot send the TrailingObjects storage to the base class (which holds + // a reference to the data) until it is constructed, so we have to set it + // separately here. + std::uninitialized_value_construct( + getTrailingObjects(), + getTrailingObjects() + NumClauses); + setClauseList(MutableArrayRef(getTrailingObjects(), + NumClauses)); + } OpenACCComputeConstruct(OpenACCDirectiveKind K, SourceLocation Start, - SourceLocation End, Stmt *StructuredBlock) + SourceLocation End, + ArrayRef Clauses, + Stmt *StructuredBlock) : OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass, K, Start, End, StructuredBlock) { assert((K == OpenACCDirectiveKind::Parallel || @@ -119,6 +147,13 @@ class OpenACCComputeConstruct : public OpenACCAssociatedStmtConstruct { K == OpenACCDirectiveKind::Kernels) && "Only parallel, serial, and kernels constructs should be " "represented by this type"); + + // Initialize the trailing storage. + std::uninitialized_copy(Clauses.begin(), Clauses.end(), + getTrailingObjects()); + + setClauseList(MutableArrayRef(getTrailingObjects(), + Clauses.size())); } void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); } @@ -128,10 +163,12 @@ public: return T->getStmtClass() == OpenACCComputeConstructClass; } - static OpenACCComputeConstruct *CreateEmpty(const ASTContext &C, EmptyShell); + static OpenACCComputeConstruct *CreateEmpty(const ASTContext &C, + unsigned NumClauses); static OpenACCComputeConstruct * Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc, - SourceLocation EndLoc, Stmt *StructuredBlock); + SourceLocation EndLoc, ArrayRef Clauses, + Stmt *StructuredBlock); Stmt *getStructuredBlock() { return getAssociatedStmt(); } const Stmt *getStructuredBlock() const { diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h index 3cb3c1014d73b7526dcfe326f78482ff36e28829..f735fa5643aecf9631d1f5efc26a43c7cafe0866 100644 --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -6109,6 +6109,8 @@ public: class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective { friend class ASTStmtReader; friend class OMPExecutableDirective; + /// true if loop directive's associated loop can be a parallel for. + bool CanBeParallelFor = false; /// Build directive with the given start and end location. /// /// \param StartLoc Starting location of the directive kind. @@ -6131,6 +6133,9 @@ class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective { llvm::omp::OMPD_target_teams_loop, SourceLocation(), SourceLocation(), CollapsedNum) {} + /// Set whether associated loop can be a parallel for. + void setCanBeParallelFor(bool ParFor) { CanBeParallelFor = ParFor; } + public: /// Creates directive with a list of \p Clauses. /// @@ -6145,7 +6150,7 @@ public: static OMPTargetTeamsGenericLoopDirective * Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, ArrayRef Clauses, - Stmt *AssociatedStmt, const HelperExprs &Exprs); + Stmt *AssociatedStmt, const HelperExprs &Exprs, bool CanBeParallelFor); /// Creates an empty directive with the place /// for \a NumClauses clauses. @@ -6159,6 +6164,10 @@ public: unsigned CollapsedNum, EmptyShell); + /// Return true if current loop directive's associated loop can be a + /// parallel for. + bool canBeParallelFor() const { return CanBeParallelFor; } + static bool classof(const Stmt *T) { return T->getStmtClass() == OMPTargetTeamsGenericLoopDirectiveClass; } diff --git a/clang/include/clang/AST/TextNodeDumper.h b/clang/include/clang/AST/TextNodeDumper.h index de67f0b5714846f11ff2c5c2f76e8b1d972158f0..1fede6e462e9253c253cc7cc302900084c2d48d6 100644 --- a/clang/include/clang/AST/TextNodeDumper.h +++ b/clang/include/clang/AST/TextNodeDumper.h @@ -189,6 +189,8 @@ public: void Visit(const OMPClause *C); + void Visit(const OpenACCClause *C); + void Visit(const BlockDecl::Capture &C); void Visit(const GenericSelectionExpr::ConstAssociation &A); @@ -352,6 +354,7 @@ public: void VisitEnumConstantDecl(const EnumConstantDecl *D); void VisitIndirectFieldDecl(const IndirectFieldDecl *D); void VisitFunctionDecl(const FunctionDecl *D); + void VisitCXXDeductionGuideDecl(const CXXDeductionGuideDecl *D); void VisitFieldDecl(const FieldDecl *D); void VisitVarDecl(const VarDecl *D); void VisitBindingDecl(const BindingDecl *D); diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index b3bf23227a47f2c1d8ed876bc3c722b04987cdf4..99f45d518c7960fab956a317719a6870a2c8fdf4 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -1690,7 +1690,10 @@ protected: /// Whether we have a stored size expression. LLVM_PREFERRED_TYPE(bool) - unsigned HasStoredSizeExpr : 1; + unsigned HasExternalSize : 1; + + LLVM_PREFERRED_TYPE(unsigned) + unsigned SizeWidth : 5; }; class BuiltinTypeBitfields { @@ -2297,6 +2300,7 @@ public: bool isConstantArrayType() const; bool isIncompleteArrayType() const; bool isVariableArrayType() const; + bool isArrayParameterType() const; bool isDependentSizedArrayType() const; bool isRecordType() const; bool isClassType() const; @@ -3331,42 +3335,114 @@ public: return T->getTypeClass() == ConstantArray || T->getTypeClass() == VariableArray || T->getTypeClass() == IncompleteArray || - T->getTypeClass() == DependentSizedArray; + T->getTypeClass() == DependentSizedArray || + T->getTypeClass() == ArrayParameter; } }; /// Represents the canonical version of C arrays with a specified constant size. /// For example, the canonical type for 'int A[4 + 4*100]' is a /// ConstantArrayType where the element type is 'int' and the size is 404. -class ConstantArrayType final - : public ArrayType, - private llvm::TrailingObjects { +class ConstantArrayType : public ArrayType { friend class ASTContext; // ASTContext creates these. - friend TrailingObjects; - llvm::APInt Size; // Allows us to unique the type. + struct ExternalSize { + ExternalSize(const llvm::APInt &Sz, const Expr *SE) + : Size(Sz), SizeExpr(SE) {} + llvm::APInt Size; // Allows us to unique the type. + const Expr *SizeExpr; + }; - ConstantArrayType(QualType et, QualType can, const llvm::APInt &size, - const Expr *sz, ArraySizeModifier sm, unsigned tq) - : ArrayType(ConstantArray, et, can, sm, tq, sz), Size(size) { - ConstantArrayTypeBits.HasStoredSizeExpr = sz != nullptr; - if (ConstantArrayTypeBits.HasStoredSizeExpr) { - assert(!can.isNull() && "canonical constant array should not have size"); - *getTrailingObjects() = sz; - } + union { + uint64_t Size; + ExternalSize *SizePtr; + }; + + ConstantArrayType(QualType Et, QualType Can, uint64_t Width, uint64_t Sz, + ArraySizeModifier SM, unsigned TQ) + : ArrayType(ConstantArray, Et, Can, SM, TQ, nullptr), Size(Sz) { + ConstantArrayTypeBits.HasExternalSize = false; + ConstantArrayTypeBits.SizeWidth = Width / 8; + // The in-structure size stores the size in bytes rather than bits so we + // drop the three least significant bits since they're always zero anyways. + assert(Width < 0xFF && "Type width in bits must be less than 8 bits"); + } + + ConstantArrayType(QualType Et, QualType Can, ExternalSize *SzPtr, + ArraySizeModifier SM, unsigned TQ) + : ArrayType(ConstantArray, Et, Can, SM, TQ, SzPtr->SizeExpr), + SizePtr(SzPtr) { + ConstantArrayTypeBits.HasExternalSize = true; + ConstantArrayTypeBits.SizeWidth = 0; + + assert((SzPtr->SizeExpr == nullptr || !Can.isNull()) && + "canonical constant array should not have size expression"); } - unsigned numTrailingObjects(OverloadToken) const { - return ConstantArrayTypeBits.HasStoredSizeExpr; + static ConstantArrayType *Create(const ASTContext &Ctx, QualType ET, + QualType Can, const llvm::APInt &Sz, + const Expr *SzExpr, ArraySizeModifier SzMod, + unsigned Qual); + +protected: + ConstantArrayType(TypeClass Tc, const ConstantArrayType *ATy, QualType Can) + : ArrayType(Tc, ATy->getElementType(), Can, ATy->getSizeModifier(), + ATy->getIndexTypeQualifiers().getAsOpaqueValue(), nullptr) { + ConstantArrayTypeBits.HasExternalSize = + ATy->ConstantArrayTypeBits.HasExternalSize; + if (!ConstantArrayTypeBits.HasExternalSize) { + ConstantArrayTypeBits.SizeWidth = ATy->ConstantArrayTypeBits.SizeWidth; + Size = ATy->Size; + } else + SizePtr = ATy->SizePtr; } public: - const llvm::APInt &getSize() const { return Size; } + /// Return the constant array size as an APInt. + llvm::APInt getSize() const { + return ConstantArrayTypeBits.HasExternalSize + ? SizePtr->Size + : llvm::APInt(ConstantArrayTypeBits.SizeWidth * 8, Size); + } + + /// Return the bit width of the size type. + unsigned getSizeBitWidth() const { + return ConstantArrayTypeBits.HasExternalSize + ? SizePtr->Size.getBitWidth() + : static_cast(ConstantArrayTypeBits.SizeWidth * 8); + } + + /// Return true if the size is zero. + bool isZeroSize() const { + return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.isZero() + : 0 == Size; + } + + /// Return the size zero-extended as a uint64_t. + uint64_t getZExtSize() const { + return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.getZExtValue() + : Size; + } + + /// Return the size sign-extended as a uint64_t. + int64_t getSExtSize() const { + return ConstantArrayTypeBits.HasExternalSize ? SizePtr->Size.getSExtValue() + : static_cast(Size); + } + + /// Return the size zero-extended to uint64_t or UINT64_MAX if the value is + /// larger than UINT64_MAX. + uint64_t getLimitedSize() const { + return ConstantArrayTypeBits.HasExternalSize + ? SizePtr->Size.getLimitedValue() + : Size; + } + + /// Return a pointer to the size expression. const Expr *getSizeExpr() const { - return ConstantArrayTypeBits.HasStoredSizeExpr - ? *getTrailingObjects() - : nullptr; + return ConstantArrayTypeBits.HasExternalSize ? SizePtr->SizeExpr : nullptr; } + bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } @@ -3383,17 +3459,31 @@ public: static unsigned getMaxSizeBits(const ASTContext &Context); void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { - Profile(ID, Ctx, getElementType(), getSize(), getSizeExpr(), + Profile(ID, Ctx, getElementType(), getZExtSize(), getSizeExpr(), getSizeModifier(), getIndexTypeCVRQualifiers()); } static void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx, - QualType ET, const llvm::APInt &ArraySize, - const Expr *SizeExpr, ArraySizeModifier SizeMod, - unsigned TypeQuals); + QualType ET, uint64_t ArraySize, const Expr *SizeExpr, + ArraySizeModifier SizeMod, unsigned TypeQuals); + + static bool classof(const Type *T) { + return T->getTypeClass() == ConstantArray || + T->getTypeClass() == ArrayParameter; + } +}; + +/// Represents a constant array type that does not decay to a pointer when used +/// as a function parameter. +class ArrayParameterType : public ConstantArrayType { + friend class ASTContext; // ASTContext creates these. + ArrayParameterType(const ConstantArrayType *ATy, QualType CanTy) + : ConstantArrayType(ArrayParameter, ATy, CanTy) {} + +public: static bool classof(const Type *T) { - return T->getTypeClass() == ConstantArray; + return T->getTypeClass() == ArrayParameter; } }; @@ -7125,7 +7215,8 @@ inline bool QualType::isCanonicalAsParam() const { if (T->isVariablyModifiedType() && T->hasSizedVLAType()) return false; - return !isa(T) && !isa(T); + return !isa(T) && + (!isa(T) || isa(T)); } inline bool QualType::isConstQualified() const { @@ -7390,6 +7481,10 @@ inline bool Type::isVariableArrayType() const { return isa(CanonicalType); } +inline bool Type::isArrayParameterType() const { + return isa(CanonicalType); +} + inline bool Type::isDependentSizedArrayType() const { return isa(CanonicalType); } @@ -7753,7 +7848,7 @@ inline bool Type::isTypedefNameType() const { /// Determines whether this type can decay to a pointer type. inline bool Type::canDecayToPointerType() const { - return isFunctionType() || isArrayType(); + return isFunctionType() || (isArrayType() && !isArrayParameterType()); } inline bool Type::hasPointerRepresentation() const { diff --git a/clang/include/clang/AST/TypeLoc.h b/clang/include/clang/AST/TypeLoc.h index b09eb3539a4badb306ec2e3abe6c82164028eacc..9f2dff7a782cb328289f3be17e6ab42f144689da 100644 --- a/clang/include/clang/AST/TypeLoc.h +++ b/clang/include/clang/AST/TypeLoc.h @@ -1611,6 +1611,11 @@ class ConstantArrayTypeLoc : ConstantArrayType> { }; +/// Wrapper for source info for array parameter types. +class ArrayParameterTypeLoc + : public InheritingConcreteTypeLoc< + ConstantArrayTypeLoc, ArrayParameterTypeLoc, ArrayParameterType> {}; + class IncompleteArrayTypeLoc : public InheritingConcreteTypeLoc; } +let Class = ArrayParameterType in { + def : Creator<[{ return ctx.getAdjustedParameterType( + ctx.getConstantArrayType(elementType,sizeValue, + size,sizeModifier, + indexQualifiers.getCVRQualifiers())); }]>; +} + let Class = IncompleteArrayType in { def : Creator<[{ return ctx.getIncompleteArrayType(elementType, sizeModifier, diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 2f71053d030f688f6921d15e265072a8b0cbf759..8a2bbfff9e9e6b0025c5af3cb7d94c0017038efa 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -4961,6 +4961,8 @@ AST_MATCHER_P(LambdaExpr, hasAnyCapture, internal::Matcher, /// capturesVar(hasName("x")) matches `x` and `x = 1`. AST_MATCHER_P(LambdaCapture, capturesVar, internal::Matcher, InnerMatcher) { + if (!Node.capturesVariable()) + return false; auto *capturedVar = Node.getCapturedVar(); return capturedVar && InnerMatcher.matches(*capturedVar, Finder, Builder); } diff --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h deleted file mode 100644 index 3972962d0b2daa681b0cdc99b3e951507e2d61ee..0000000000000000000000000000000000000000 --- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h +++ /dev/null @@ -1,27 +0,0 @@ -//===-- ControlFlowContext.h ------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file defines a deprecated alias for AdornedCFG. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CONTROLFLOWCONTEXT_H -#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CONTROLFLOWCONTEXT_H - -#include "clang/Analysis/FlowSensitive/AdornedCFG.h" - -namespace clang { -namespace dataflow { - -// This is a deprecated alias. Use `AdornedCFG` instead. -using ControlFlowContext = AdornedCFG; - -} // namespace dataflow -} // namespace clang - -#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CONTROLFLOWCONTEXT_H diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h index 2330697299fdd7aaffe728dae049c33cb5efdf9f..706664d7db1c25b9829a255aa7869c3a5254869c 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowEnvironment.h @@ -30,6 +30,7 @@ #include "llvm/ADT/MapVector.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/ErrorHandling.h" +#include #include #include @@ -43,6 +44,15 @@ enum class ComparisonResult { Unknown, }; +/// The result of a `widen` operation. +struct WidenResult { + /// Non-null pointer to a potentially widened version of the input value. + Value *V; + /// Whether `V` represents a "change" (that is, a different value) with + /// respect to the previous value in the sequence. + LatticeEffect Effect; +}; + /// Holds the state of the program (store and heap) at a given program point. /// /// WARNING: Symbolic values that are created by the environment for static @@ -104,14 +114,17 @@ public: /// serve as a comparison operation, by indicating whether the widened value /// is equivalent to the previous value. /// - /// Returns either: - /// - /// `nullptr`, if this value is not of interest to the model, or - /// - /// `&Prev`, if the widened value is equivalent to `Prev`, or - /// - /// A non-null value that approximates `Current`. `Prev` is available to - /// inform the chosen approximation. + /// Returns one of the folowing: + /// * `std::nullopt`, if this value is not of interest to the + /// model. + /// * A `WidenResult` with: + /// * A non-null `Value *` that points either to `Current` or a widened + /// version of `Current`. This value must be consistent with + /// the flow condition of `CurrentEnv`. We particularly caution + /// against using `Prev`, which is rarely consistent. + /// * A `LatticeEffect` indicating whether the value should be + /// considered a new value (`Changed`) or one *equivalent* (if not + /// necessarily equal) to `Prev` (`Unchanged`). /// /// `PrevEnv` and `CurrentEnv` can be used to query child values and path /// condition implications of `Prev` and `Current`, respectively. @@ -122,17 +135,19 @@ public: /// /// `Prev` and `Current` must be assigned to the same storage location in /// `PrevEnv` and `CurrentEnv`, respectively. - virtual Value *widen(QualType Type, Value &Prev, const Environment &PrevEnv, - Value &Current, Environment &CurrentEnv) { + virtual std::optional widen(QualType Type, Value &Prev, + const Environment &PrevEnv, + Value &Current, + Environment &CurrentEnv) { // The default implementation reduces to just comparison, since comparison // is required by the API, even if no widening is performed. switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) { - case ComparisonResult::Same: - return &Prev; - case ComparisonResult::Different: - return &Current; - case ComparisonResult::Unknown: - return nullptr; + case ComparisonResult::Unknown: + return std::nullopt; + case ComparisonResult::Same: + return WidenResult{&Current, LatticeEffect::Unchanged}; + case ComparisonResult::Different: + return WidenResult{&Current, LatticeEffect::Changed}; } llvm_unreachable("all cases in switch covered"); } @@ -236,8 +251,8 @@ public: /// /// `PrevEnv` must be the immediate previous version of the environment. /// `PrevEnv` and `this` must use the same `DataflowAnalysisContext`. - LatticeJoinEffect widen(const Environment &PrevEnv, - Environment::ValueModel &Model); + LatticeEffect widen(const Environment &PrevEnv, + Environment::ValueModel &Model); // FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`, // `getStableStorageLocation`, or something more appropriate. @@ -330,17 +345,6 @@ public: /// location of the result object to pass in `this`, even though prvalues are /// otherwise not associated with storage locations. /// - /// FIXME: Currently, this simply returns a stable storage location for `E`, - /// but this doesn't do the right thing in scenarios like the following: - /// ``` - /// MyClass c = some_condition()? MyClass(foo) : MyClass(bar); - /// ``` - /// Here, `MyClass(foo)` and `MyClass(bar)` will have two different storage - /// locations, when in fact their storage locations should be the same. - /// Eventually, we want to propagate storage locations from result objects - /// down to the prvalues that initialize them, similar to the way that this is - /// done in Clang's CodeGen. - /// /// Requirements: /// `E` must be a prvalue of record type. RecordStorageLocation & @@ -448,7 +452,13 @@ public: /// Initializes the fields (including synthetic fields) of `Loc` with values, /// unless values of the field type are not supported or we hit one of the /// limits at which we stop producing values. - void initializeFieldsWithValues(RecordStorageLocation &Loc); + /// If `Type` is provided, initializes only those fields that are modeled for + /// `Type`; this is intended for use in cases where `Loc` is a derived type + /// and we only want to initialize the fields of a base type. + void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type); + void initializeFieldsWithValues(RecordStorageLocation &Loc) { + initializeFieldsWithValues(Loc, Loc.getType()); + } /// Assigns `Val` as the value of `Loc` in the environment. void setValue(const StorageLocation &Loc, Value &Val); @@ -639,6 +649,9 @@ public: LLVM_DUMP_METHOD void dump(raw_ostream &OS) const; private: + using PrValueToResultObject = + llvm::DenseMap; + // The copy-constructor is for use in fork() only. Environment(const Environment &) = default; @@ -668,8 +681,10 @@ private: /// Initializes the fields (including synthetic fields) of `Loc` with values, /// unless values of the field type are not supported or we hit one of the /// limits at which we stop producing values (controlled by `Visited`, - /// `Depth`, and `CreatedValuesCount`). - void initializeFieldsWithValues(RecordStorageLocation &Loc, + /// `Depth`, and `CreatedValuesCount`). If `Type` is different from + /// `Loc.getType()`, initializes only those fields that are modeled for + /// `Type`. + void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type, llvm::DenseSet &Visited, int Depth, int &CreatedValuesCount); @@ -688,22 +703,45 @@ private: /// and functions referenced in `FuncDecl`. `FuncDecl` must have a body. void initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl); + static PrValueToResultObject + buildResultObjectMap(DataflowAnalysisContext *DACtx, + const FunctionDecl *FuncDecl, + RecordStorageLocation *ThisPointeeLoc, + RecordStorageLocation *LocForRecordReturnVal); + // `DACtx` is not null and not owned by this object. DataflowAnalysisContext *DACtx; - // FIXME: move the fields `CallStack`, `ReturnVal`, `ReturnLoc` and - // `ThisPointeeLoc` into a separate call-context object, shared between - // environments in the same call. + // FIXME: move the fields `CallStack`, `ResultObjectMap`, `ReturnVal`, + // `ReturnLoc` and `ThisPointeeLoc` into a separate call-context object, + // shared between environments in the same call. // https://github.com/llvm/llvm-project/issues/59005 // `DeclContext` of the block being analysed if provided. std::vector CallStack; - // Value returned by the function (if it has non-reference return type). + // Maps from prvalues of record type to their result objects. Shared between + // all environments for the same function. + // FIXME: It's somewhat unsatisfactory that we have to use a `shared_ptr` + // here, though the cost is acceptable: The overhead of a `shared_ptr` is + // incurred when it is copied, and this happens only relatively rarely (when + // we fork the environment). The need for a `shared_ptr` will go away once we + // introduce a shared call-context object (see above). + std::shared_ptr ResultObjectMap; + + // The following three member variables handle various different types of + // return values. + // - If the return type is not a reference and not a record: Value returned + // by the function. Value *ReturnVal = nullptr; - // Storage location of the reference returned by the function (if it has - // reference return type). + // - If the return type is a reference: Storage location of the reference + // returned by the function. StorageLocation *ReturnLoc = nullptr; + // - If the return type is a record or the function being analyzed is a + // constructor: Storage location into which the return value should be + // constructed. + RecordStorageLocation *LocForRecordReturnVal = nullptr; + // The storage location of the `this` pointee. Should only be null if the // function being analyzed is only a function and not a method. RecordStorageLocation *ThisPointeeLoc = nullptr; @@ -744,6 +782,35 @@ RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME, std::vector getFieldsForInitListExpr(const InitListExpr *InitList); +/// Helper class for initialization of a record with an `InitListExpr`. +/// `InitListExpr::inits()` contains the initializers for both the base classes +/// and the fields of the record; this helper class separates these out into two +/// different lists. In addition, it deals with special cases associated with +/// unions. +class RecordInitListHelper { +public: + // `InitList` must have record type. + RecordInitListHelper(const InitListExpr *InitList); + + // Base classes with their associated initializer expressions. + ArrayRef> base_inits() const { + return BaseInits; + } + + // Fields with their associated initializer expressions. + ArrayRef> field_inits() const { + return FieldInits; + } + +private: + SmallVector> BaseInits; + SmallVector> FieldInits; + + // We potentially synthesize an `ImplicitValueInitExpr` for unions. It's a + // member variable because we store a pointer to it in `FieldInits`. + std::optional ImplicitValueInitForUnion; +}; + /// Associates a new `RecordValue` with `Loc` and returns the new value. RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env); diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowLattice.h b/clang/include/clang/Analysis/FlowSensitive/DataflowLattice.h index 0c81e2f078c2412a9333e0432953db6093e0cdf1..b262732804ed692436da71317c34adcc103e3485 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowLattice.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowLattice.h @@ -17,13 +17,13 @@ namespace clang { namespace dataflow { -/// Effect indicating whether a lattice join operation resulted in a new value. -// FIXME: Rename to `LatticeEffect` since `widen` uses it as well, and we are -// likely removing it from `join`. -enum class LatticeJoinEffect { +/// Effect indicating whether a lattice operation resulted in a new value. +enum class LatticeEffect { Unchanged, Changed, }; +// DEPRECATED. Use `LatticeEffect`. +using LatticeJoinEffect = LatticeEffect; } // namespace dataflow } // namespace clang diff --git a/clang/include/clang/Analysis/PathDiagnostic.h b/clang/include/clang/Analysis/PathDiagnostic.h index 90559e7efb06f05f341cc1f79798de561155f765..5907df022e449d5be5c74230e3f189c63ecbc481 100644 --- a/clang/include/clang/Analysis/PathDiagnostic.h +++ b/clang/include/clang/Analysis/PathDiagnostic.h @@ -780,6 +780,9 @@ class PathDiagnostic : public llvm::FoldingSetNode { PathDiagnosticLocation UniqueingLoc; const Decl *UniqueingDecl; + /// The top-level entry point from which this issue was discovered. + const Decl *AnalysisEntryPoint = nullptr; + /// Lines executed in the path. std::unique_ptr ExecutedLines; @@ -788,7 +791,7 @@ public: PathDiagnostic(StringRef CheckerName, const Decl *DeclWithIssue, StringRef bugtype, StringRef verboseDesc, StringRef shortDesc, StringRef category, PathDiagnosticLocation LocationToUnique, - const Decl *DeclToUnique, + const Decl *DeclToUnique, const Decl *AnalysisEntryPoint, std::unique_ptr ExecutedLines); ~PathDiagnostic(); @@ -852,6 +855,9 @@ public: return *ExecutedLines; } + /// Get the top-level entry point from which this issue was discovered. + const Decl *getAnalysisEntryPoint() const { return AnalysisEntryPoint; } + /// Return the semantic context where an issue occurred. If the /// issue occurs along a path, this represents the "central" area /// where the bug manifests. diff --git a/clang/include/clang/Analysis/SelectorExtras.h b/clang/include/clang/Analysis/SelectorExtras.h index 1e1daf5706bbf5a53dbe91a661fd393d03f293c5..ac2c2519beae35e54479e622b281827954a140ae 100644 --- a/clang/include/clang/Analysis/SelectorExtras.h +++ b/clang/include/clang/Analysis/SelectorExtras.h @@ -15,10 +15,10 @@ namespace clang { template static inline Selector getKeywordSelector(ASTContext &Ctx, - IdentifierInfos *... IIs) { + const IdentifierInfos *...IIs) { static_assert(sizeof...(IdentifierInfos) > 0, "keyword selectors must have at least one argument"); - SmallVector II({&Ctx.Idents.get(IIs)...}); + SmallVector II({&Ctx.Idents.get(IIs)...}); return Ctx.Selectors.getSelector(II.size(), &II[0]); } diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 3e03e55612645bd8c521524bfc29e70756d1e317..dc87a8c6f022dc5f451f51f13c0dfdb068104ae6 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -324,13 +324,10 @@ class Spelling { } class GNU : Spelling; -class Declspec : Spelling { - bit PrintOnLeft = 1; -} +class Declspec : Spelling; class Microsoft : Spelling; class CXX11 : Spelling { - bit CanPrintOnLeft = 0; string Namespace = namespace; } class C23 @@ -596,12 +593,6 @@ class AttrSubjectMatcherAggregateRule { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; class Attr { - // Specifies that when printed, this attribute is meaningful on the - // 'left side' of the declaration. - bit CanPrintOnLeft = 1; - // Specifies that when printed, this attribute is required to be printed on - // the 'left side' of the declaration. - bit PrintOnLeft = 0; // The various ways in which an attribute can be spelled in source list Spellings; // The things to which an attribute can appertain @@ -937,7 +928,6 @@ def AVRSignal : InheritableAttr, TargetSpecificAttr { } def AsmLabel : InheritableAttr { - let CanPrintOnLeft = 0; let Spellings = [CustomKeyword<"asm">, CustomKeyword<"__asm__">]; let Args = [ // Label specifies the mangled name for the decl. @@ -1534,7 +1524,6 @@ def AllocSize : InheritableAttr { } def EnableIf : InheritableAttr { - let CanPrintOnLeft = 0; // Does not have a [[]] spelling because this attribute requires the ability // to parse function arguments but the attribute is not written in the type // position. @@ -2178,9 +2167,10 @@ def TypeNonNull : TypeAttr { let Documentation = [TypeNonNullDocs]; } -def TypeNullable : TypeAttr { +def TypeNullable : DeclOrTypeAttr { let Spellings = [CustomKeyword<"_Nullable">]; let Documentation = [TypeNullableDocs]; +// let Subjects = SubjectList<[CXXRecord], ErrorDiag>; } def TypeNullableResult : TypeAttr { @@ -3011,6 +3001,13 @@ def PreserveNone : DeclOrTypeAttr, TargetSpecificAttr { let Documentation = [PreserveNoneDocs]; } +def RISCVVectorCC: DeclOrTypeAttr, TargetSpecificAttr { + let Spellings = [CXX11<"riscv", "vector_cc">, + C23<"riscv", "vector_cc">, + Clang<"riscv_vector_cc">]; + let Documentation = [RISCVVectorCCDocs]; +} + def Target : InheritableAttr { let Spellings = [GCC<"target">]; let Args = [StringArgument<"featuresStr">]; @@ -3088,6 +3085,20 @@ def TargetClones : InheritableAttr { StringRef getFeatureStr(unsigned Index) const { return *(featuresStrs_begin() + Index); } + bool isDefaultVersion(unsigned Index) const { + return getFeatureStr(Index) == "default"; + } + void getFeatures(llvm::SmallVectorImpl &Out, + unsigned Index) const { + if (isDefaultVersion(Index)) return; + StringRef Features = getFeatureStr(Index); + SmallVector AttrFeatures; + Features.split(AttrFeatures, "+"); + for (auto &Feature : AttrFeatures) { + Feature = Feature.trim(); + Out.push_back(Feature); + } + } // Given an index into the 'featuresStrs' sequence, compute a unique // ID to be used with function name mangling for the associated variant. // This mapping is necessary due to a requirement that the mangling ID @@ -3149,7 +3160,6 @@ def Unavailable : InheritableAttr { } def DiagnoseIf : InheritableAttr { - let CanPrintOnLeft = 0; // Does not have a [[]] spelling because this attribute requires the ability // to parse function arguments but the attribute is not written in the type // position. diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 9de14f608fd114792d10bffc04f3fa64be3a3a41..0ca4ea377fc36aca742d155d53edb072474ab255 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -4151,6 +4151,20 @@ non-underscored keywords. For example: @property (assign, nullable) NSView *superview; @property (readonly, nonnull) NSArray *subviews; @end + +As well as built-in pointer types, the nullability attributes can be attached +to C++ classes marked with the ``_Nullable`` attribute. + +The following C++ standard library types are considered nullable: +``unique_ptr``, ``shared_ptr``, ``auto_ptr``, ``exception_ptr``, ``function``, +``move_only_function`` and ``coroutine_handle``. + +Types should be marked nullable only where the type itself leaves nullability +ambiguous. For example, ``std::optional`` is not marked ``_Nullable``, because +``optional _Nullable`` is redundant and ``optional _Nonnull`` is +not a useful type. ``std::weak_ptr`` is not nullable, because its nullability +can change with no visible modification, so static annotation is unlikely to be +unhelpful. }]; } @@ -4185,6 +4199,17 @@ The ``_Nullable`` nullability qualifier indicates that a value of the int fetch_or_zero(int * _Nullable ptr); a caller of ``fetch_or_zero`` can provide null. + +The ``_Nullable`` attribute on classes indicates that the given class can +represent null values, and so the ``_Nullable``, ``_Nonnull`` etc qualifiers +make sense for this type. For example: + + .. code-block:: c + + class _Nullable ArenaPointer { ... }; + + ArenaPointer _Nonnull x = ...; + ArenaPointer _Nullable y = nullptr; }]; } @@ -5494,6 +5519,17 @@ for clang builtin functions. }]; } +def RISCVVectorCCDocs : Documentation { + let Category = DocCatCallingConvs; + let Heading = "riscv::vector_cc, riscv_vector_cc, clang::riscv_vector_cc"; + let Content = [{ +The ``riscv_vector_cc`` attribute can be applied to a function. It preserves 15 +registers namely, v1-v7 and v24-v31 as callee-saved. Callers thus don't need +to save these registers before function calls, and callees only need to save +them if they use them. + }]; +} + def PreferredNameDocs : Documentation { let Category = DocCatDecl; let Content = [{ @@ -6069,6 +6105,9 @@ def AlwaysDestroyDocs : Documentation { The ``always_destroy`` attribute specifies that a variable with static or thread storage duration should have its exit-time destructor run. This attribute is the default unless clang was invoked with -fno-c++-static-destructors. + +If a variable is explicitly declared with this attribute, Clang will silence +otherwise applicable ``-Wexit-time-destructors`` warnings. }]; } diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 21ab9bb86d1b8ca080e23e6155cc172aa9a34546..d6ceb450bd106b60754b8a3888b4e5b337b221cb 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -678,7 +678,7 @@ def Clz : Builtin, BitShort_Int_Long_LongLongTemplate { def Clzg : Builtin { let Spellings = ["__builtin_clzg"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking]; let Prototype = "int(...)"; } @@ -690,7 +690,7 @@ def Ctz : Builtin, BitShort_Int_Long_LongLongTemplate { def Ctzg : Builtin { let Spellings = ["__builtin_ctzg"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Attributes = [NoThrow, Const, Constexpr, CustomTypeChecking]; let Prototype = "int(...)"; } @@ -4587,6 +4587,12 @@ def GetDeviceSideMangledName : LangBuiltin<"CUDA_LANG"> { } // HLSL +def HLSLAll : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_elementwise_all"]; + let Attributes = [NoThrow, Const]; + let Prototype = "bool(...)"; +} + def HLSLAny : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_elementwise_any"]; let Attributes = [NoThrow, Const]; @@ -4599,6 +4605,12 @@ def HLSLWaveActiveCountBits : LangBuiltin<"HLSL_LANG"> { let Prototype = "unsigned int(bool)"; } +def HLSLWaveGetLaneIndex : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_wave_get_lane_index"]; + let Attributes = [NoThrow, Const]; + let Prototype = "unsigned int()"; +} + def HLSLClamp : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_elementwise_clamp"]; let Attributes = [NoThrow, Const]; diff --git a/clang/include/clang/Basic/BuiltinsAMDGPU.def b/clang/include/clang/Basic/BuiltinsAMDGPU.def index 61ec8b79bf054daa03e02fddca3c4edb2da75088..c660582cc98e666031ae1dfbecf9d9b4612c9eae 100644 --- a/clang/include/clang/Basic/BuiltinsAMDGPU.def +++ b/clang/include/clang/Basic/BuiltinsAMDGPU.def @@ -432,13 +432,10 @@ TARGET_BUILTIN(__builtin_amdgcn_s_wakeup_barrier, "vi", "n", "gfx12-insts") TARGET_BUILTIN(__builtin_amdgcn_s_barrier_leave, "b", "n", "gfx12-insts") TARGET_BUILTIN(__builtin_amdgcn_s_get_barrier_state, "Uii", "n", "gfx12-insts") -TARGET_BUILTIN(__builtin_amdgcn_global_load_tr_v2i32, "V2iV2i*1", "nc", "gfx12-insts,wavefrontsize32") -TARGET_BUILTIN(__builtin_amdgcn_global_load_tr_v8i16, "V8sV8s*1", "nc", "gfx12-insts,wavefrontsize32") -TARGET_BUILTIN(__builtin_amdgcn_global_load_tr_v8f16, "V8hV8h*1", "nc", "gfx12-insts,wavefrontsize32") - -TARGET_BUILTIN(__builtin_amdgcn_global_load_tr_i32, "ii*1", "nc", "gfx12-insts,wavefrontsize64") -TARGET_BUILTIN(__builtin_amdgcn_global_load_tr_v4i16, "V4sV4s*1", "nc", "gfx12-insts,wavefrontsize64") -TARGET_BUILTIN(__builtin_amdgcn_global_load_tr_v4f16, "V4hV4h*1", "nc", "gfx12-insts,wavefrontsize64") +TARGET_BUILTIN(__builtin_amdgcn_global_load_tr_b64_v2i32, "V2iV2i*1", "nc", "gfx12-insts,wavefrontsize32") +TARGET_BUILTIN(__builtin_amdgcn_global_load_tr_b128_v8i16, "V8sV8s*1", "nc", "gfx12-insts,wavefrontsize32") +TARGET_BUILTIN(__builtin_amdgcn_global_load_tr_b64_i32, "ii*1", "nc", "gfx12-insts,wavefrontsize64") +TARGET_BUILTIN(__builtin_amdgcn_global_load_tr_b128_v4i16, "V4sV4s*1", "nc", "gfx12-insts,wavefrontsize64") //===----------------------------------------------------------------------===// // WMMA builtins. diff --git a/clang/include/clang/Basic/CMakeLists.txt b/clang/include/clang/Basic/CMakeLists.txt index 7d53c751c13ac405d8293d912f97dd2a683e1659..2ef6ddc68f4bf364b676975de566fbcd6d07f924 100644 --- a/clang/include/clang/Basic/CMakeLists.txt +++ b/clang/include/clang/Basic/CMakeLists.txt @@ -31,16 +31,6 @@ clang_tablegen(AttrList.inc -gen-clang-attr-list SOURCE Attr.td TARGET ClangAttrList) -clang_tablegen(AttrLeftSideCanPrintList.inc -gen-clang-attr-can-print-left-list - -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ - SOURCE Attr.td - TARGET ClangAttrCanPrintLeftList) - -clang_tablegen(AttrLeftSideMustPrintList.inc -gen-clang-attr-must-print-left-list - -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ - SOURCE Attr.td - TARGET ClangAttrMustPrintLeftList) - clang_tablegen(AttrSubMatchRulesList.inc -gen-clang-attr-subject-match-rule-list -I ${CMAKE_CURRENT_SOURCE_DIR}/../../ SOURCE Attr.td diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index e33a1f4c45b949733798ab5fb648260bcaddd7f3..ed3fd9b1c4a55b6a9a3694ecd54575bd1056de36 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -142,6 +142,9 @@ def warn_drv_unsupported_diag_option_for_flang : Warning< def warn_drv_unsupported_option_for_processor : Warning< "ignoring '%0' option as it is not currently supported for processor '%1'">, InGroup; +def warn_drv_unsupported_openmp_library : Warning< + "The library '%0=%1' is not supported, openmp is not be enabled">, + InGroup; def err_drv_invalid_thread_model_for_target : Error< "invalid thread model '%0' in '%1' for this target">; @@ -548,6 +551,12 @@ def err_drv_extract_api_wrong_kind : Error< "header file '%0' input '%1' does not match the type of prior input " "in api extraction; use '-x %2' to override">; +def err_drv_missing_symbol_graph_dir: Error< + "Must provide a symbol graph output directory using --symbol-graph-dir=">; + +def err_drv_unexpected_symbol_graph_output : Error< + "Unexpected output symbol graph '%1'; please provide --symbol-graph-dir= instead">; + def warn_slash_u_filename : Warning<"'/U%0' treated as the '/U' option">, InGroup>; def note_use_dashdash : Note< @@ -657,6 +666,7 @@ def warn_drv_darwin_sdk_invalid_settings : Warning< "SDK settings were ignored as 'SDKSettings.json' could not be parsed">, InGroup>; +def err_missing_sysroot : Error<"no such sysroot directory: '%0'">; def err_drv_darwin_sdk_missing_arclite : Error< "SDK does not contain 'libarclite' at the path '%0'; try increasing the minimum deployment target">; @@ -753,7 +763,8 @@ def err_drv_hlsl_unsupported_target : Error< "HLSL code generation is unsupported for target '%0'">; def err_drv_hlsl_bad_shader_required_in_target : Error< "%select{shader model|Vulkan environment|shader stage}0 is required as %select{OS|environment}1 in target '%2' for HLSL code generation">; - +def err_drv_hlsl_16bit_types_unsupported: Error< + "'%0' option requires target HLSL Version >= 2018%select{| and shader model >= 6.2}1, but HLSL Version is '%2'%select{| and shader model is '%3'}1">; def err_drv_hlsl_bad_shader_unsupported : Error< "%select{shader model|Vulkan environment|shader stage}0 '%1' in target '%2' is invalid for HLSL code generation">; def warn_drv_dxc_missing_dxv : Warning<"dxv not found. " diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index ba23cf84c5e3438d860c0f65e5bbf472f3b63946..14b08d4927ec5e264ac9bb73cf8f07ebc4eb1cc2 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -366,4 +366,8 @@ def warn_profile_data_misexpect : Warning< def err_extract_api_ignores_file_not_found : Error<"file '%0' specified by '--extract-api-ignores=' not found">, DefaultFatal; +def warn_missing_symbol_graph_dir : Warning< + "Missing symbol graph output directory, defaulting to working directory">, + InGroup; + } diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 44035e2fd16f2e8277f3f5dab0ea9395e86fb6bc..47747d8704b6c85413312beb703c6800f6173893 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -985,6 +985,7 @@ def FormatSecurity : DiagGroup<"format-security">; def FormatNonStandard : DiagGroup<"format-non-iso">; def FormatY2K : DiagGroup<"format-y2k">; def FormatPedantic : DiagGroup<"format-pedantic">; +def FormatSignedness : DiagGroup<"format-signedness">; def FormatTypeConfusion : DiagGroup<"format-type-confusion">; def FormatOverflowNonKprintf: DiagGroup<"format-overflow-non-kprintf">; @@ -1411,6 +1412,9 @@ def MultiGPU: DiagGroup<"multi-gpu">; // libc and the CRT to be skipped. def AVRRtlibLinkingQuirks : DiagGroup<"avr-rtlib-linking-quirks">; +// A warning group related to AArch64 SME function attribues. +def AArch64SMEAttributes : DiagGroup<"aarch64-sme-attributes">; + // A warning group for things that will change semantics in the future. def FutureCompat : DiagGroup<"future-compat">; @@ -1516,3 +1520,5 @@ def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInCon // Warnings and notes InstallAPI verification. def InstallAPIViolation : DiagGroup<"installapi-violation">; +// Warnings about misuse of ExtractAPI options. +def ExtractAPIMisuse : DiagGroup<"extractapi-misuse">; diff --git a/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h index 5ff782c7f8c7e812203a77fbc91beb751e8f78d9..bce7605b95ba43f298d34b9d67c9e681424e7a74 100644 --- a/clang/include/clang/Basic/DiagnosticIDs.h +++ b/clang/include/clang/Basic/DiagnosticIDs.h @@ -32,7 +32,7 @@ namespace clang { enum { DIAG_SIZE_COMMON = 300, DIAG_SIZE_DRIVER = 400, - DIAG_SIZE_FRONTEND = 150, + DIAG_SIZE_FRONTEND = 200, DIAG_SIZE_SERIALIZATION = 120, DIAG_SIZE_LEX = 400, DIAG_SIZE_PARSE = 700, diff --git a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td index a4c6e630ac5fd82617e8f34889561e8124093070..0a477da7186b09b0f95ba850fb111d970c2eb155 100644 --- a/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td +++ b/clang/include/clang/Basic/DiagnosticInstallAPIKinds.td @@ -15,9 +15,15 @@ let CategoryName = "Command line" in { def err_cannot_write_file : Error<"cannot write file '%0': %1">; def err_no_install_name : Error<"no install name specified: add -install_name ">; def err_no_output_file: Error<"no output file specified">; +def err_no_such_header_file : Error<"no such %select{public|private|project}1 header file: '%0'">; +def warn_no_such_excluded_header_file : Warning<"no such excluded %select{public|private}0 header file: '%1'">, InGroup; +def warn_glob_did_not_match: Warning<"glob '%0' did not match any header file">, InGroup; +def err_no_such_umbrella_header_file : Error<"%select{public|private|project}1 umbrella header file not found in input: '%0'">; +def err_cannot_find_reexport : Error<"cannot find re-exported %select{framework|library}0: '%1'">; } // end of command line category. let CategoryName = "Verification" in { +// Diagnostics about symbols. def warn_target: Warning<"violations found for %0">, InGroup; def err_library_missing_symbol : Error<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">; def warn_library_missing_symbol : Warning<"declaration has external linkage, but dynamic library doesn't have symbol '%0'">, InGroup; @@ -39,6 +45,25 @@ def err_dylib_symbol_flags_mismatch : Error<"dynamic library symbol '%0' is " "%select{weak defined|thread local}1, but its declaration is not">; def err_header_symbol_flags_mismatch : Error<"declaration '%0' is " "%select{weak defined|thread local}1, but symbol is not in dynamic library">; + +// Diagnostics about load commands. +def err_architecture_mismatch : Error<"architectures do not match: '%0' (provided) vs '%1' (found)">; +def warn_platform_mismatch : Warning<"platform does not match: '%0' (provided) vs '%1' (found)">, InGroup; +def err_platform_mismatch : Error<"platform does not match: '%0' (provided) vs '%1' (found)">; +def err_install_name_mismatch : Error<"install_name does not match: '%0' (provided) vs '%1' (found)">; +def err_current_version_mismatch : Error<"current_version does not match: '%0' (provided) vs '%1' (found)">; +def err_compatibility_version_mismatch : Error<"compatibility_version does not match: '%0' (provided) vs '%1' (found)">; +def err_appextension_safe_mismatch : Error<"ApplicationExtensionSafe flag does not match: '%0' (provided) vs '%1' (found)">; +def err_shared_cache_eligiblity_mismatch : Error<"NotForDyldSharedCache flag does not match: '%0' (provided) vs '%1' (found)">; +def err_no_twolevel_namespace : Error<"flat namespace libraries are not supported">; +def err_parent_umbrella_missing: Error<"parent umbrella missing from %0: '%1'">; +def err_parent_umbrella_mismatch : Error<"parent umbrella does not match: '%0' (provided) vs '%1' (found)">; +def err_reexported_libraries_missing : Error<"re-exported library missing from %0: '%1'">; +def err_reexported_libraries_mismatch : Error<"re-exported libraries do not match: '%0' (provided) vs '%1' (found)">; +def err_allowable_clients_missing : Error<"allowable client missing from %0: '%1'">; +def err_allowable_clients_mismatch : Error<"allowable clients do not match: '%0' (provided) vs '%1' (found)">; +def warn_rpaths_missing : Warning<"runpath search paths missing from %0: '%1'">, InGroup; +def warn_rpaths_mismatch : Warning<"runpath search paths do not match: '%0' (provided) vs '%1' (found)">, InGroup; } // end of Verification category. } // end of InstallAPI component diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 48de5e2ef5f4af2c121e1a3bbfda1aac0cc28227..46a44418a3153bc75df0ac7327bab65ac1528bc3 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -268,6 +268,8 @@ def err_expected_semi_after_namespace_name : Error< "expected ';' after namespace name">; def err_unexpected_namespace_attributes_alias : Error< "attributes cannot be specified on namespace alias">; +def err_unexpected_qualified_namespace_alias : Error< + "namespace alias must be a single identifier">; def err_unexpected_nested_namespace_attribute : Error< "attributes cannot be specified on a nested namespace definition">; def err_inline_namespace_alias : Error<"namespace alias cannot be inline">; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index fc727cef9cd835805ad1641f7045aa3a447c912f..180e913155d67c6ca037992b13cd092f02994c46 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -165,7 +165,7 @@ def ext_vla_folded_to_constant : ExtWarn< "variable length array folded to constant array as an extension">, InGroup; def err_vla_unsupported : Error< - "variable length arrays are not supported for %select{the current target|'%1'}0">; + "variable length arrays are not supported %select{for the current target|in '%1'}0">; def err_vla_in_coroutine_unsupported : Error< "variable length arrays in a coroutine are not supported">; def note_vla_unsupported : Note< @@ -1748,8 +1748,8 @@ def err_type_defined_in_condition : Error< def err_type_defined_in_enum : Error< "%0 cannot be defined in an enumeration">; def ext_type_defined_in_offsetof : Extension< - "defining a type within '%select{__builtin_offsetof|offsetof}0' is a Clang " - "extension">, InGroup; + "defining a type within '%select{__builtin_offsetof|offsetof}0' is a C23 " + "extension">, InGroup; def note_pure_virtual_function : Note< "unimplemented pure virtual method %0 in %1">; @@ -2402,10 +2402,6 @@ def err_selected_explicit_constructor : Error< def note_explicit_ctor_deduction_guide_here : Note< "explicit %select{constructor|deduction guide}0 declared here">; -// C++11 decltype -def err_decltype_in_declarator : Error< - "'decltype' cannot be used to name a declaration">; - // C++11 auto def warn_cxx98_compat_auto_type_specifier : Warning< "'auto' type specifier is incompatible with C++98">, @@ -3755,6 +3751,16 @@ def err_sme_definition_using_za_in_non_sme_target : Error< "function using ZA state requires 'sme'">; def err_sme_definition_using_zt0_in_non_sme2_target : Error< "function using ZT0 state requires 'sme2'">; +def warn_sme_streaming_pass_return_vl_to_non_streaming : Warning< + "passing a VL-dependent argument to/from a function that has a different" + " streaming-mode. The streaming and non-streaming vector lengths may be" + " different">, + InGroup, DefaultIgnore; +def warn_sme_locally_streaming_has_vl_args_returns : Warning< + "passing/returning a VL-dependent argument to/from a __arm_locally_streaming" + " function. The streaming and non-streaming vector" + " lengths may be different">, + InGroup, DefaultIgnore; def err_conflicting_attributes_arm_state : Error< "conflicting attributes for state '%0'">; def err_sme_streaming_cannot_be_multiversioned : Error< @@ -6464,9 +6470,6 @@ def ext_c99_flexible_array_member : Extension< def err_flexible_array_virtual_base : Error< "flexible array member %0 not allowed in " "%select{struct|interface|union|class|enum}1 which has a virtual base class">; -def err_flexible_array_empty_aggregate : Error< - "flexible array member %0 not allowed in otherwise empty " - "%select{struct|interface|union|class|enum}1">; def err_flexible_array_has_nontrivial_dtor : Error< "flexible array member %0 of type %1 with non-trivial destruction">; def ext_flexible_array_in_struct : Extension< @@ -6481,8 +6484,6 @@ def ext_flexible_array_empty_aggregate_ms : Extension< "flexible array member %0 in otherwise empty " "%select{struct|interface|union|class|enum}1 is a Microsoft extension">, InGroup; -def err_flexible_array_union : Error< - "flexible array member %0 in a union is not allowed">; def ext_flexible_array_union_ms : Extension< "flexible array member %0 in a union is a Microsoft extension">, InGroup; @@ -7147,7 +7148,8 @@ def ext_typecheck_decl_incomplete_type : ExtWarn< def err_tentative_def_incomplete_type : Error< "tentative definition has type %0 that is never completed">; def warn_tentative_incomplete_array : Warning< - "tentative array definition assumed to have one element">; + "tentative array definition assumed to have one element">, + InGroup>; def err_typecheck_incomplete_array_needs_initializer : Error< "definition of variable with array type needs an explicit size " "or an initializer">; @@ -8307,6 +8309,9 @@ def ext_template_after_declarative_nns : ExtWarn< def ext_alias_template_in_declarative_nns : ExtWarn< "a declarative nested name specifier cannot name an alias template">, InGroup>; +def err_computed_type_in_declarative_nns : Error< + "a %select{pack indexing|'decltype'}0 specifier cannot be used in " + "a declarative nested name specifier">; def err_no_typeid_with_fno_rtti : Error< "use of typeid requires -frtti">; @@ -9826,6 +9831,9 @@ def warn_format_conversion_argument_type_mismatch : Warning< def warn_format_conversion_argument_type_mismatch_pedantic : Extension< warn_format_conversion_argument_type_mismatch.Summary>, InGroup; +def warn_format_conversion_argument_type_mismatch_signedness : Warning< + warn_format_conversion_argument_type_mismatch.Summary>, + InGroup, DefaultIgnore; def warn_format_conversion_argument_type_mismatch_confusion : Warning< warn_format_conversion_argument_type_mismatch.Summary>, InGroup, DefaultIgnore; @@ -12254,6 +12262,12 @@ def warn_acc_clause_unimplemented def err_acc_construct_appertainment : Error<"OpenACC construct '%0' cannot be used here; it can only " "be used in a statement context">; +def err_acc_clause_appertainment + : Error<"OpenACC '%1' clause is not valid on '%0' directive">; +def err_acc_duplicate_clause_disallowed + : Error<"OpenACC '%1' clause cannot appear more than once on a '%0' " + "directive">; +def note_acc_previous_clause_here : Note<"previous clause is here">; def err_acc_branch_in_out_compute_construct : Error<"invalid %select{branch|return|throw}0 %select{out of|into}1 " "OpenACC Compute Construct">; diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index b41aadc73f205d5db241bdbdd5638f76e3272cb9..fe4d1c4afcca6538ecec88e77fc08970dc9d8d5c 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -94,6 +94,7 @@ EXTENSION(define_target_os_macros, FEATURE(enumerator_attributes, true) FEATURE(nullability, true) FEATURE(nullability_on_arrays, true) +FEATURE(nullability_on_classes, true) FEATURE(nullability_nullable_result, true) FEATURE(memory_sanitizer, LangOpts.Sanitize.hasOneOf(SanitizerKind::Memory | diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index a091639bfa2542cad34c50db6df289b8302f7d95..a893e6f4d3d39de843b673f60600c6747ce98985 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -913,12 +913,13 @@ class alignas(IdentifierInfoAlignment) MultiKeywordSelector public: // Constructor for keyword selectors. - MultiKeywordSelector(unsigned nKeys, IdentifierInfo **IIV) + MultiKeywordSelector(unsigned nKeys, const IdentifierInfo **IIV) : DeclarationNameExtra(nKeys) { assert((nKeys > 1) && "not a multi-keyword selector"); // Fill in the trailing keyword array. - IdentifierInfo **KeyInfo = reinterpret_cast(this + 1); + const IdentifierInfo **KeyInfo = + reinterpret_cast(this + 1); for (unsigned i = 0; i != nKeys; ++i) KeyInfo[i] = IIV[i]; } @@ -928,7 +929,7 @@ public: using DeclarationNameExtra::getNumArgs; - using keyword_iterator = IdentifierInfo *const *; + using keyword_iterator = const IdentifierInfo *const *; keyword_iterator keyword_begin() const { return reinterpret_cast(this + 1); @@ -938,7 +939,7 @@ public: return keyword_begin() + getNumArgs(); } - IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const { + const IdentifierInfo *getIdentifierInfoForSlot(unsigned i) const { assert(i < getNumArgs() && "getIdentifierInfoForSlot(): illegal index"); return keyword_begin()[i]; } @@ -991,10 +992,10 @@ class Selector { /// Do not reorder or add any arguments to this template /// without thoroughly understanding how tightly coupled these classes are. llvm::PointerIntPair< - llvm::PointerUnion, 2> + llvm::PointerUnion, 2> InfoPtr; - Selector(IdentifierInfo *II, unsigned nArgs) { + Selector(const IdentifierInfo *II, unsigned nArgs) { assert(nArgs < 2 && "nArgs not equal to 0/1"); InfoPtr.setPointerAndInt(II, nArgs + 1); } @@ -1006,8 +1007,8 @@ class Selector { InfoPtr.setPointerAndInt(SI, MultiArg & 0b11); } - IdentifierInfo *getAsIdentifierInfo() const { - return InfoPtr.getPointer().dyn_cast(); + const IdentifierInfo *getAsIdentifierInfo() const { + return InfoPtr.getPointer().dyn_cast(); } MultiKeywordSelector *getMultiKeywordSelector() const { @@ -1075,7 +1076,7 @@ public: /// /// \returns the uniqued identifier for this slot, or NULL if this slot has /// no corresponding identifier. - IdentifierInfo *getIdentifierInfoForSlot(unsigned argIndex) const; + const IdentifierInfo *getIdentifierInfoForSlot(unsigned argIndex) const; /// Retrieve the name at a given position in the selector. /// @@ -1132,13 +1133,13 @@ public: /// /// \p NumArgs indicates whether this is a no argument selector "foo", a /// single argument selector "foo:" or multi-argument "foo:bar:". - Selector getSelector(unsigned NumArgs, IdentifierInfo **IIV); + Selector getSelector(unsigned NumArgs, const IdentifierInfo **IIV); - Selector getUnarySelector(IdentifierInfo *ID) { + Selector getUnarySelector(const IdentifierInfo *ID) { return Selector(ID, 1); } - Selector getNullarySelector(IdentifierInfo *ID) { + Selector getNullarySelector(const IdentifierInfo *ID) { return Selector(ID, 0); } diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h index 4456f4afd142df0c74023d74ff1640bb79fe1435..3414df9999170192492dd1fb8283e8a866b0008d 100644 --- a/clang/include/clang/Basic/OpenACCKinds.h +++ b/clang/include/clang/Basic/OpenACCKinds.h @@ -67,7 +67,7 @@ enum class OpenACCDirectiveKind { }; template -inline StreamTy &PrintOpenACCDirectiveKind(StreamTy &Out, +inline StreamTy &printOpenACCDirectiveKind(StreamTy &Out, OpenACCDirectiveKind K) { switch (K) { case OpenACCDirectiveKind::Parallel: @@ -138,12 +138,12 @@ inline StreamTy &PrintOpenACCDirectiveKind(StreamTy &Out, inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out, OpenACCDirectiveKind K) { - return PrintOpenACCDirectiveKind(Out, K); + return printOpenACCDirectiveKind(Out, K); } inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out, OpenACCDirectiveKind K) { - return PrintOpenACCDirectiveKind(Out, K); + return printOpenACCDirectiveKind(Out, K); } enum class OpenACCAtomicKind { @@ -266,7 +266,7 @@ enum class OpenACCClauseKind { }; template -inline StreamTy &PrintOpenACCClauseKind(StreamTy &Out, OpenACCClauseKind K) { +inline StreamTy &printOpenACCClauseKind(StreamTy &Out, OpenACCClauseKind K) { switch (K) { case OpenACCClauseKind::Finalize: return Out << "finalize"; @@ -402,12 +402,12 @@ inline StreamTy &PrintOpenACCClauseKind(StreamTy &Out, OpenACCClauseKind K) { inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out, OpenACCClauseKind K) { - return PrintOpenACCClauseKind(Out, K); + return printOpenACCClauseKind(Out, K); } inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out, OpenACCClauseKind K) { - return PrintOpenACCClauseKind(Out, K); + return printOpenACCClauseKind(Out, K); } enum class OpenACCDefaultClauseKind { @@ -419,6 +419,30 @@ enum class OpenACCDefaultClauseKind { Invalid, }; +template +inline StreamTy &printOpenACCDefaultClauseKind(StreamTy &Out, + OpenACCDefaultClauseKind K) { + switch (K) { + case OpenACCDefaultClauseKind::None: + return Out << "none"; + case OpenACCDefaultClauseKind::Present: + return Out << "present"; + case OpenACCDefaultClauseKind::Invalid: + return Out << ""; + } + llvm_unreachable("Unknown OpenACCDefaultClauseKind enum"); +} + +inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out, + OpenACCDefaultClauseKind K) { + return printOpenACCDefaultClauseKind(Out, K); +} + +inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out, + OpenACCDefaultClauseKind K) { + return printOpenACCDefaultClauseKind(Out, K); +} + enum class OpenACCReductionOperator { /// '+'. Addition, diff --git a/clang/include/clang/Basic/Sanitizers.def b/clang/include/clang/Basic/Sanitizers.def index c2137e3f61f64508606a6d2ec84e40b9f9a97c59..b228ffd07ee7454dafab9255bbda0d3e3f43484f 100644 --- a/clang/include/clang/Basic/Sanitizers.def +++ b/clang/include/clang/Basic/Sanitizers.def @@ -163,24 +163,24 @@ SANITIZER_GROUP("implicit-integer-arithmetic-value-change", ImplicitIntegerArithmeticValueChange, ImplicitIntegerSignChange | ImplicitSignedIntegerTruncation) -SANITIZER("objc-cast", ObjCCast) +SANITIZER_GROUP("implicit-integer-conversion", ImplicitIntegerConversion, + ImplicitIntegerArithmeticValueChange | + ImplicitUnsignedIntegerTruncation) -// FIXME: -//SANITIZER_GROUP("implicit-integer-conversion", ImplicitIntegerConversion, -// ImplicitIntegerArithmeticValueChange | -// ImplicitUnsignedIntegerTruncation) -//SANITIZER_GROUP("implicit-conversion", ImplicitConversion, -// ImplicitIntegerConversion) +// Implicit bitfield sanitizers +SANITIZER("implicit-bitfield-conversion", ImplicitBitfieldConversion) SANITIZER_GROUP("implicit-conversion", ImplicitConversion, - ImplicitIntegerArithmeticValueChange | - ImplicitUnsignedIntegerTruncation) + ImplicitIntegerConversion | + ImplicitBitfieldConversion) SANITIZER_GROUP("integer", Integer, - ImplicitConversion | IntegerDivideByZero | Shift | + ImplicitIntegerConversion | IntegerDivideByZero | Shift | SignedIntegerOverflow | UnsignedIntegerOverflow | UnsignedShiftBase) +SANITIZER("objc-cast", ObjCCast) + SANITIZER("local-bounds", LocalBounds) SANITIZER_GROUP("bounds", Bounds, ArrayBounds | LocalBounds) diff --git a/clang/include/clang/Basic/Specifiers.h b/clang/include/clang/Basic/Specifiers.h index 8586405825cfe01514754591f0855be2f5667c62..fb11e8212f8b68f235faa690aab875b56096c8f6 100644 --- a/clang/include/clang/Basic/Specifiers.h +++ b/clang/include/clang/Basic/Specifiers.h @@ -273,29 +273,30 @@ namespace clang { /// CallingConv - Specifies the calling convention that a function uses. enum CallingConv { - CC_C, // __attribute__((cdecl)) - CC_X86StdCall, // __attribute__((stdcall)) - CC_X86FastCall, // __attribute__((fastcall)) - CC_X86ThisCall, // __attribute__((thiscall)) - CC_X86VectorCall, // __attribute__((vectorcall)) - CC_X86Pascal, // __attribute__((pascal)) - CC_Win64, // __attribute__((ms_abi)) - CC_X86_64SysV, // __attribute__((sysv_abi)) - CC_X86RegCall, // __attribute__((regcall)) - CC_AAPCS, // __attribute__((pcs("aapcs"))) - CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp"))) - CC_IntelOclBicc, // __attribute__((intel_ocl_bicc)) - CC_SpirFunction, // default for OpenCL functions on SPIR target - CC_OpenCLKernel, // inferred for OpenCL kernels - CC_Swift, // __attribute__((swiftcall)) + CC_C, // __attribute__((cdecl)) + CC_X86StdCall, // __attribute__((stdcall)) + CC_X86FastCall, // __attribute__((fastcall)) + CC_X86ThisCall, // __attribute__((thiscall)) + CC_X86VectorCall, // __attribute__((vectorcall)) + CC_X86Pascal, // __attribute__((pascal)) + CC_Win64, // __attribute__((ms_abi)) + CC_X86_64SysV, // __attribute__((sysv_abi)) + CC_X86RegCall, // __attribute__((regcall)) + CC_AAPCS, // __attribute__((pcs("aapcs"))) + CC_AAPCS_VFP, // __attribute__((pcs("aapcs-vfp"))) + CC_IntelOclBicc, // __attribute__((intel_ocl_bicc)) + CC_SpirFunction, // default for OpenCL functions on SPIR target + CC_OpenCLKernel, // inferred for OpenCL kernels + CC_Swift, // __attribute__((swiftcall)) CC_SwiftAsync, // __attribute__((swiftasynccall)) - CC_PreserveMost, // __attribute__((preserve_most)) - CC_PreserveAll, // __attribute__((preserve_all)) + CC_PreserveMost, // __attribute__((preserve_most)) + CC_PreserveAll, // __attribute__((preserve_all)) CC_AArch64VectorCall, // __attribute__((aarch64_vector_pcs)) - CC_AArch64SVEPCS, // __attribute__((aarch64_sve_pcs)) - CC_AMDGPUKernelCall, // __attribute__((amdgpu_kernel)) - CC_M68kRTD, // __attribute__((m68k_rtd)) - CC_PreserveNone, // __attribute__((preserve_none)) + CC_AArch64SVEPCS, // __attribute__((aarch64_sve_pcs)) + CC_AMDGPUKernelCall, // __attribute__((amdgpu_kernel)) + CC_M68kRTD, // __attribute__((m68k_rtd)) + CC_PreserveNone, // __attribute__((preserve_none)) + CC_RISCVVectorCall, // __attribute__((riscv_vector_cc)) }; /// Checks whether the given calling convention supports variadic diff --git a/clang/include/clang/Basic/SyncScope.h b/clang/include/clang/Basic/SyncScope.h index bc7ec7b5cf777ef4556678445dc44fed078dcfb5..45beff41afa11d3286afad7b2336567b4aa72c8a 100644 --- a/clang/include/clang/Basic/SyncScope.h +++ b/clang/include/clang/Basic/SyncScope.h @@ -252,8 +252,7 @@ public: } bool isValid(unsigned S) const override { - return S >= static_cast(System) && - S <= static_cast(Last); + return S <= static_cast(Last); } ArrayRef getRuntimeValues() const override { diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 374595edd2ce4a2e8f92842ccce97b066291e0b8..e1ef7454f01669c4ecff7f1998275a0b2512ed71 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -267,6 +267,9 @@ protected: LLVM_PREFERRED_TYPE(bool) unsigned AllowAMDGPUUnsafeFPAtomics : 1; + LLVM_PREFERRED_TYPE(bool) + unsigned HasUnalignedAccess : 1; + unsigned ARMCDECoprocMask : 8; unsigned MaxOpenCLWorkGroupSize; @@ -859,6 +862,18 @@ public: return PointerWidth; } + /// Return true iff unaligned accesses are a single instruction (rather than + /// a synthesized sequence). + bool hasUnalignedAccess() const { return HasUnalignedAccess; } + + /// Return true iff unaligned accesses are cheap. This affects placement and + /// size of bitfield loads/stores. (Not the ABI-mandated placement of + /// the bitfields themselves.) + bool hasCheapUnalignedBitFieldAccess() const { + // Simply forward to the unaligned access getter. + return hasUnalignedAccess(); + } + /// \brief Returns the default value of the __USER_LABEL_PREFIX__ macro, /// which is the prefix given to user symbols by default. /// diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def index 3a96f8a4d22bd14b843a9fb3a3750676255726c1..800af0e6d0448058d901d396e4f41025610d3b02 100644 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -665,28 +665,30 @@ KEYWORD(__kindof , KEYOBJC) // Alternate spelling for various tokens. There are GCC extensions in all // languages, but should not be disabled in strict conformance mode. -ALIAS("__alignof__" , __alignof , KEYALL) -ALIAS("__asm" , asm , KEYALL) -ALIAS("__asm__" , asm , KEYALL) -ALIAS("__attribute__", __attribute, KEYALL) -ALIAS("__complex" , _Complex , KEYALL) -ALIAS("__complex__" , _Complex , KEYALL) -ALIAS("__const" , const , KEYALL) -ALIAS("__const__" , const , KEYALL) -ALIAS("__decltype" , decltype , KEYCXX) -ALIAS("__imag__" , __imag , KEYALL) -ALIAS("__inline" , inline , KEYALL) -ALIAS("__inline__" , inline , KEYALL) -ALIAS("__nullptr" , nullptr , KEYCXX) -ALIAS("__real__" , __real , KEYALL) -ALIAS("__restrict" , restrict , KEYALL) -ALIAS("__restrict__" , restrict , KEYALL) -ALIAS("__signed" , signed , KEYALL) -ALIAS("__signed__" , signed , KEYALL) -ALIAS("__typeof" , typeof , KEYALL) -ALIAS("__typeof__" , typeof , KEYALL) -ALIAS("__volatile" , volatile , KEYALL) -ALIAS("__volatile__" , volatile , KEYALL) +ALIAS("__alignof__" , __alignof , KEYALL) +ALIAS("__asm" , asm , KEYALL) +ALIAS("__asm__" , asm , KEYALL) +ALIAS("__attribute__" , __attribute , KEYALL) +ALIAS("__complex" , _Complex , KEYALL) +ALIAS("__complex__" , _Complex , KEYALL) +ALIAS("__const" , const , KEYALL) +ALIAS("__const__" , const , KEYALL) +ALIAS("__decltype" , decltype , KEYCXX) +ALIAS("__imag__" , __imag , KEYALL) +ALIAS("__inline" , inline , KEYALL) +ALIAS("__inline__" , inline , KEYALL) +ALIAS("__nullptr" , nullptr , KEYCXX) +ALIAS("__real__" , __real , KEYALL) +ALIAS("__restrict" , restrict , KEYALL) +ALIAS("__restrict__" , restrict , KEYALL) +ALIAS("__signed" , signed , KEYALL) +ALIAS("__signed__" , signed , KEYALL) +ALIAS("__typeof" , typeof , KEYALL) +ALIAS("__typeof__" , typeof , KEYALL) +ALIAS("__typeof_unqual" , typeof_unqual, KEYALL) +ALIAS("__typeof_unqual__", typeof_unqual, KEYALL) +ALIAS("__volatile" , volatile , KEYALL) +ALIAS("__volatile__" , volatile , KEYALL) // Type nullability. KEYWORD(_Nonnull , KEYALL) diff --git a/clang/include/clang/Basic/TypeNodes.td b/clang/include/clang/Basic/TypeNodes.td index 3625f063758915f285f96d93871d55c0ebb11b2c..fee49cf4326dfca96d040f0a369d72b5a1f0a506 100644 --- a/clang/include/clang/Basic/TypeNodes.td +++ b/clang/include/clang/Basic/TypeNodes.td @@ -64,6 +64,7 @@ def ConstantArrayType : TypeNode; def IncompleteArrayType : TypeNode; def VariableArrayType : TypeNode; def DependentSizedArrayType : TypeNode, AlwaysDependent; +def ArrayParameterType : TypeNode; def DependentSizedExtVectorType : TypeNode, AlwaysDependent; def DependentAddressSpaceType : TypeNode, AlwaysDependent; def VectorType : TypeNode; diff --git a/clang/include/clang/Basic/arm_neon.td b/clang/include/clang/Basic/arm_neon.td index f16de97f4e6bdafd7b5ec43b0719f1207c0558c7..7edac5afafaa996704c89911beeb5d52c061621e 100644 --- a/clang/include/clang/Basic/arm_neon.td +++ b/clang/include/clang/Basic/arm_neon.td @@ -1758,24 +1758,21 @@ let TargetGuard = "fullfp16" in { // Mul lane def VMUL_LANEH : IOpInst<"vmul_lane", "..qI", "hQh", OP_MUL_LN>; def VMUL_NH : IOpInst<"vmul_n", "..1", "hQh", OP_MUL_N>; +} - // Data processing intrinsics - section 5 - - // Logical operations - let isHiddenLInst = 1 in - def VBSLH : SInst<"vbsl", ".U..", "hQh">; - - // Transposition operations - def VZIPH : WInst<"vzip", "2..", "hQh">; - def VUZPH : WInst<"vuzp", "2..", "hQh">; - def VTRNH : WInst<"vtrn", "2..", "hQh">; - - // Vector Extract - def VEXTH : WInst<"vext", "...I", "hQh">; +// Data processing intrinsics - section 5. Do not require fullfp16. - // Reverse vector elements - def VREV64H : WOpInst<"vrev64", "..", "hQh", OP_REV64>; -} +// Logical operations +let isHiddenLInst = 1 in +def VBSLH : SInst<"vbsl", ".U..", "hQh">; +// Transposition operations +def VZIPH : WInst<"vzip", "2..", "hQh">; +def VUZPH : WInst<"vuzp", "2..", "hQh">; +def VTRNH : WInst<"vtrn", "2..", "hQh">; +// Vector Extract +def VEXTH : WInst<"vext", "...I", "hQh">; +// Reverse vector elements +def VREV64H : WOpInst<"vrev64", "..", "hQh", OP_REV64>; // ARMv8.2-A FP16 vector intrinsics for A64 only. let ArchGuard = "defined(__aarch64__)", TargetGuard = "fullfp16" in { @@ -1857,7 +1854,9 @@ let ArchGuard = "defined(__aarch64__)", TargetGuard = "fullfp16" in { def VMINVH : SInst<"vminv", "1.", "hQh">; def FMAXNMVH : SInst<"vmaxnmv", "1.", "hQh">; def FMINNMVH : SInst<"vminnmv", "1.", "hQh">; +} +let ArchGuard = "defined(__aarch64__)" in { // Permutation def VTRN1H : SOpInst<"vtrn1", "...", "hQh", OP_TRN1>; def VZIP1H : SOpInst<"vzip1", "...", "hQh", OP_ZIP1>; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 4a954258ce40b6a7050c66a478f7bcc9d866b9cf..7ac36222644aac78e6c90cd8a3826bdce52ddceb 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -802,9 +802,11 @@ def B : JoinedOrSeparate<["-"], "B">, MetaVarName<"">, HelpText<"Search $prefix$file for executables, libraries, and data files. " "If $prefix is a directory, search $prefix/$file">; def gcc_install_dir_EQ : Joined<["--"], "gcc-install-dir=">, + Visibility<[ClangOption, FlangOption]>, HelpText<"Use GCC installation in the specified directory. The directory ends with path components like 'lib{,32,64}/gcc{,-cross}/$triple/$version'. " "Note: executables (e.g. ld) used by the compiler are not overridden by the selected GCC installation">; def gcc_toolchain : Joined<["--"], "gcc-toolchain=">, Flags<[NoXarchOption]>, + Visibility<[ClangOption, FlangOption]>, HelpText<"Specify a directory where Clang can find 'include' and 'lib{,32,64}/gcc{,-cross}/$triple/$version'. " "Clang will use the GCC installation with the largest version">; def gcc_triple_EQ : Joined<["--"], "gcc-triple=">, @@ -1001,7 +1003,8 @@ def : Joined<["-"], "Xclang=">, Group, def Xcuda_fatbinary : Separate<["-"], "Xcuda-fatbinary">, HelpText<"Pass to fatbinary invocation">, MetaVarName<"">; def Xcuda_ptxas : Separate<["-"], "Xcuda-ptxas">, - HelpText<"Pass to the ptxas assembler">, MetaVarName<"">; + HelpText<"Pass to the ptxas assembler">, MetaVarName<"">, + Visibility<[ClangOption, CLOption]>; def Xopenmp_target : Separate<["-"], "Xopenmp-target">, Group, HelpText<"Pass to the target offloading toolchain.">, MetaVarName<"">; def Xopenmp_target_EQ : JoinedAndSeparate<["-"], "Xopenmp-target=">, Group, @@ -1446,7 +1449,7 @@ def dD : Flag<["-"], "dD">, Group, Visibility<[ClangOption, CC1Option]> def dI : Flag<["-"], "dI">, Group, Visibility<[ClangOption, CC1Option]>, HelpText<"Print include directives in -E mode in addition to normal output">, MarshallingInfoFlag>; -def dM : Flag<["-"], "dM">, Group, Visibility<[ClangOption, CC1Option]>, +def dM : Flag<["-"], "dM">, Group, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, HelpText<"Print macro definitions in -E mode instead of normal output">; def dead__strip : Flag<["-"], "dead_strip">; def dependency_file : Separate<["-"], "dependency-file">, @@ -1507,14 +1510,29 @@ def extract_api : Flag<["-"], "extract-api">, def product_name_EQ: Joined<["--"], "product-name=">, Visibility<[ClangOption, CC1Option]>, MarshallingInfoString>; -def emit_symbol_graph_EQ: JoinedOrSeparate<["--"], "emit-symbol-graph=">, +def emit_symbol_graph: Flag<["-"], "emit-symbol-graph">, Visibility<[ClangOption, CC1Option]>, - HelpText<"Generate Extract API information as a side effect of compilation.">, - MarshallingInfoString>; + HelpText<"Generate Extract API information as a side effect of compilation.">, + MarshallingInfoFlag>; +def emit_extension_symbol_graphs: Flag<["--"], "emit-extension-symbol-graphs">, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Generate additional symbol graphs for extended modules.">, + MarshallingInfoFlag>; def extract_api_ignores_EQ: CommaJoined<["--"], "extract-api-ignores=">, Visibility<[ClangOption, CC1Option]>, HelpText<"Comma separated list of files containing a new line separated list of API symbols to ignore when extracting API information.">, MarshallingInfoStringVector>; +def symbol_graph_dir_EQ: Joined<["--"], "symbol-graph-dir=">, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Directory in which to emit symbol graphs.">, + MarshallingInfoString>; +def emit_pretty_sgf: Flag<["--"], "pretty-sgf">, + Visibility<[ClangOption, CC1Option]>, + HelpText<"Emit pretty printed symbol graphs">, + MarshallingInfoFlag>; +def emit_sgf_symbol_labels_for_testing: Flag<["--"], "emit-sgf-symbol-labels-for-testing">, + Visibility<[CC1Option]>, + MarshallingInfoFlag>; def e : Separate<["-"], "e">, Flags<[LinkerInput]>, Group; def fmax_tokens_EQ : Joined<["-"], "fmax-tokens=">, Group, Visibility<[ClangOption, CC1Option]>, @@ -3392,17 +3410,24 @@ def fopenmp : Flag<["-"], "fopenmp">, Group, HelpText<"Parse OpenMP pragmas and generate parallel code.">; def fno_openmp : Flag<["-"], "fno-openmp">, Group, Flags<[NoArgumentUnused]>; +class OpenMPVersionHelp { + string str = !strconcat( + "Set OpenMP version (e.g. 45 for OpenMP 4.5, 51 for OpenMP 5.1). Default value is ", + default, " for ", program); +} def fopenmp_version_EQ : Joined<["-"], "fopenmp-version=">, Group, Flags<[NoArgumentUnused]>, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>, - HelpText<"Set OpenMP version (e.g. 45 for OpenMP 4.5, 51 for OpenMP 5.1). Default value is 51 for Clang">; + HelpText.str>, + HelpTextForVariants<[FlangOption, FC1Option], OpenMPVersionHelp<"Flang", "11">.str>; defm openmp_extensions: BoolFOption<"openmp-extensions", LangOpts<"OpenMPExtensions">, DefaultTrue, PosFlag, NegFlag>; -def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group; +def fopenmp_EQ : Joined<["-"], "fopenmp=">, Group, + Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>; def fopenmp_use_tls : Flag<["-"], "fopenmp-use-tls">, Group, Flags<[NoArgumentUnused, HelpHidden]>; def fnoopenmp_use_tls : Flag<["-"], "fnoopenmp-use-tls">, Group, @@ -3635,6 +3660,9 @@ defm preserve_as_comments : BoolFOption<"preserve-as-comments", "Do not preserve comments in inline assembly">, PosFlag>; def framework : Separate<["-"], "framework">, Flags<[LinkerInput]>; +def reexport_framework : Separate<["-"], "reexport_framework">, Flags<[LinkerInput]>; +def reexport_l : Joined<["-"], "reexport-l">, Flags<[LinkerInput]>; +def reexport_library : JoinedOrSeparate<["-"], "reexport_library">, Flags<[LinkerInput]>; def frandom_seed_EQ : Joined<["-"], "frandom-seed=">, Group; def freg_struct_return : Flag<["-"], "freg-struct-return">, Group, Visibility<[ClangOption, CC1Option]>, @@ -4105,12 +4133,8 @@ defm strict_return : BoolFOption<"strict-return", " of a non-void function as unreachable">, PosFlag>; -let Group = f_Group in { - let Visibility = [ClangOption,CC1Option] in { - def fptrauth_intrinsics : Flag<["-"], "fptrauth-intrinsics">, - HelpText<"Enable pointer authentication intrinsics">; - } - def fno_ptrauth_intrinsics : Flag<["-"], "fno-ptrauth-intrinsics">; +let Flags = [TargetSpecific] in { +defm ptrauth_intrinsics : OptInCC1FFlag<"ptrauth-intrinsics", "Enable pointer authentication intrinsics">; } def fenable_matrix : Flag<["-"], "fenable-matrix">, Group, @@ -4511,6 +4535,9 @@ def mwindows : Joined<["-"], "mwindows">, Group; def mdll : Joined<["-"], "mdll">, Group; def municode : Joined<["-"], "municode">, Group; def mthreads : Joined<["-"], "mthreads">, Group; +def marm64x : Joined<["-"], "marm64x">, Group, + Visibility<[ClangOption, CLOption]>, + HelpText<"Link as a hybrid ARM64X image">; def mguard_EQ : Joined<["-"], "mguard=">, Group, HelpText<"Enable or disable Control Flow Guard checks and guard tables emission">, Values<"none,cf,cf-nochecks">; @@ -4885,6 +4912,9 @@ defm tgsplit : SimpleMFlag<"tgsplit", "Enable", "Disable", defm wavefrontsize64 : SimpleMFlag<"wavefrontsize64", "Specify wavefront size 64", "Specify wavefront size 32", " mode (AMDGPU only)">; +defm amdgpu_precise_memory_op + : SimpleMFlag<"amdgpu-precise-memory-op", "Enable", "Disable", + " precise memory mode (AMDGPU only)">; defm unsafe_fp_atomics : BoolMOption<"unsafe-fp-atomics", TargetOpts<"AllowAMDGPUUnsafeFPAtomics">, DefaultFalse, @@ -6688,6 +6718,9 @@ def analyzer_opt_analyze_headers : Flag<["-"], "analyzer-opt-analyze-headers">, def analyzer_display_progress : Flag<["-"], "analyzer-display-progress">, HelpText<"Emit verbose output about the analyzer's progress">, MarshallingInfoFlag>; +def analyzer_note_analysis_entry_points : Flag<["-"], "analyzer-note-analysis-entry-points">, + HelpText<"Add a note for each bug report to denote their analysis entry points">, + MarshallingInfoFlag>; def analyze_function : Separate<["-"], "analyze-function">, HelpText<"Run analysis on specific function (for C++ include parameters in name)">, MarshallingInfoString>; @@ -8308,6 +8341,7 @@ def _SLASH_Fi : CLCompileJoined<"Fi">, def _SLASH_Fo : CLCompileJoined<"Fo">, HelpText<"Set output object file (with /c)">, MetaVarName<"">; +def _SLASH_Fo_COLON : CLCompileJoined<"Fo:">, Alias<_SLASH_Fo>; def _SLASH_guard : CLJoined<"guard:">, HelpText<"Enable Control Flow Guard with /guard:cf, or only the table with /guard:cf,nochecks. " "Enable EH Continuation Guard with /guard:ehcont">; diff --git a/clang/include/clang/ExtractAPI/API.h b/clang/include/clang/ExtractAPI/API.h index b220db294101d896ae78c02be072071c9a350b02..92cacf65c7d64e585d00687d0121d071e3c6ca0d 100644 --- a/clang/include/clang/ExtractAPI/API.h +++ b/clang/include/clang/ExtractAPI/API.h @@ -20,17 +20,25 @@ #include "clang/AST/Availability.h" #include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/RawCommentList.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "clang/ExtractAPI/DeclarationFragments.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" #include "llvm/Support/Casting.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/Triple.h" +#include +#include #include +#include #include namespace clang { @@ -149,15 +157,58 @@ public: /// \endcode using DocComment = std::vector; -// Classes deriving from APIRecord need to have USR be the first constructor -// argument. This is so that they are compatible with `addTopLevelRecord` -// defined in API.cpp +struct APIRecord; + +// This represents a reference to another symbol that might come from external +/// sources. +struct SymbolReference { + StringRef Name; + StringRef USR; + + /// The source project/module/product of the referred symbol. + StringRef Source; + + // A Pointer to the APIRecord for this reference if known + const APIRecord *Record = nullptr; + + SymbolReference() = default; + SymbolReference(StringRef Name, StringRef USR, StringRef Source = "") + : Name(Name), USR(USR), Source(Source) {} + SymbolReference(const APIRecord *R); + + /// Determine if this SymbolReference is empty. + /// + /// \returns true if and only if all \c Name, \c USR, and \c Source is empty. + bool empty() const { return Name.empty() && USR.empty() && Source.empty(); } +}; + +class RecordContext; + +// Concrete classes deriving from APIRecord need to have a construct with first +// arguments USR, and Name, in that order. This is so that they +// are compatible with `APISet::createRecord`. +// When adding a new kind of record don't forget to update APIRecords.inc! /// The base representation of an API record. Holds common symbol information. struct APIRecord { /// Discriminator for LLVM-style RTTI (dyn_cast<> et al.) enum RecordKind { RK_Unknown, + // If adding a record context record kind here make sure to update + // RecordContext::classof if needed and add a RECORD_CONTEXT entry to + // APIRecords.inc + RK_FirstRecordContext, RK_Namespace, + RK_Enum, + RK_Struct, + RK_Union, + RK_ObjCInterface, + RK_ObjCCategory, + RK_ObjCProtocol, + RK_CXXClass, + RK_ClassTemplate, + RK_ClassTemplateSpecialization, + RK_ClassTemplatePartialSpecialization, + RK_LastRecordContext, RK_GlobalFunction, RK_GlobalFunctionTemplate, RK_GlobalFunctionTemplateSpecialization, @@ -166,18 +217,11 @@ struct APIRecord { RK_GlobalVariableTemplateSpecialization, RK_GlobalVariableTemplatePartialSpecialization, RK_EnumConstant, - RK_Enum, RK_StructField, - RK_Struct, RK_UnionField, - RK_Union, RK_StaticField, RK_CXXField, RK_CXXFieldTemplate, - RK_CXXClass, - RK_ClassTemplate, - RK_ClassTemplateSpecialization, - RK_ClassTemplatePartialSpecialization, RK_Concept, RK_CXXStaticMethod, RK_CXXInstanceMethod, @@ -190,40 +234,15 @@ struct APIRecord { RK_ObjCIvar, RK_ObjCClassMethod, RK_ObjCInstanceMethod, - RK_ObjCInterface, - RK_ObjCCategory, - RK_ObjCCategoryModule, - RK_ObjCProtocol, RK_MacroDefinition, RK_Typedef, }; - /// Stores information about the context of the declaration of this API. - /// This is roughly analogous to the DeclContext hierarchy for an AST Node. - struct HierarchyInformation { - /// The USR of the parent API. - StringRef ParentUSR; - /// The name of the parent API. - StringRef ParentName; - /// The record kind of the parent API. - RecordKind ParentKind = RK_Unknown; - /// A pointer to the parent APIRecord if known. - APIRecord *ParentRecord = nullptr; - - HierarchyInformation() = default; - HierarchyInformation(StringRef ParentUSR, StringRef ParentName, - RecordKind Kind, APIRecord *ParentRecord = nullptr) - : ParentUSR(ParentUSR), ParentName(ParentName), ParentKind(Kind), - ParentRecord(ParentRecord) {} - - bool empty() const { - return ParentUSR.empty() && ParentName.empty() && - ParentKind == RK_Unknown && ParentRecord == nullptr; - } - }; - StringRef USR; StringRef Name; + + SymbolReference Parent; + PresumedLoc Location; AvailabilityInfo Availability; LinkageInfo Linkage; @@ -242,79 +261,169 @@ struct APIRecord { /// Objective-C class/instance methods). DeclarationFragments SubHeading; - /// Information about the parent record of this record. - HierarchyInformation ParentInformation; - /// Whether the symbol was defined in a system header. bool IsFromSystemHeader; + AccessControl Access; + private: const RecordKind Kind; + friend class RecordContext; + // Used to store the next child record in RecordContext. This works because + // APIRecords semantically only have one parent. + mutable APIRecord *NextInContext = nullptr; public: + APIRecord *getNextInContext() const { return NextInContext; } + RecordKind getKind() const { return Kind; } + static APIRecord *castFromRecordContext(const RecordContext *Ctx); + static RecordContext *castToRecordContext(const APIRecord *Record); + APIRecord() = delete; APIRecord(RecordKind Kind, StringRef USR, StringRef Name, - PresumedLoc Location, AvailabilityInfo Availability, - LinkageInfo Linkage, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - bool IsFromSystemHeader) - : USR(USR), Name(Name), Location(Location), + SymbolReference Parent, PresumedLoc Location, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader, + AccessControl Access = AccessControl()) + : USR(USR), Name(Name), Parent(std::move(Parent)), Location(Location), Availability(std::move(Availability)), Linkage(Linkage), Comment(Comment), Declaration(Declaration), SubHeading(SubHeading), - IsFromSystemHeader(IsFromSystemHeader), Kind(Kind) {} + IsFromSystemHeader(IsFromSystemHeader), Access(std::move(Access)), + Kind(Kind) {} APIRecord(RecordKind Kind, StringRef USR, StringRef Name) : USR(USR), Name(Name), Kind(Kind) {} // Pure virtual destructor to make APIRecord abstract virtual ~APIRecord() = 0; + static bool classof(const APIRecord *Record) { return true; } + static bool classofKind(RecordKind K) { return true; } + static bool classof(const RecordContext *Ctx) { return true; } +}; + +/// Base class used for specific record types that have children records this is +/// analogous to the DeclContext for the AST +class RecordContext { +public: + static bool classof(const APIRecord *Record) { + return classofKind(Record->getKind()); + } + static bool classofKind(APIRecord::RecordKind K) { + return K > APIRecord::RK_FirstRecordContext && + K < APIRecord::RK_LastRecordContext; + } + + static bool classof(const RecordContext *Context) { return true; } + + RecordContext(APIRecord::RecordKind Kind) : Kind(Kind) {} + + APIRecord::RecordKind getKind() const { return Kind; } + + struct record_iterator { + private: + APIRecord *Current = nullptr; + + public: + using value_type = APIRecord *; + using reference = const value_type &; + using pointer = const value_type *; + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + + record_iterator() = default; + explicit record_iterator(value_type R) : Current(R) {} + reference operator*() const { return Current; } + // This doesn't strictly meet the iterator requirements, but it's the + // behavior we want here. + value_type operator->() const { return Current; } + record_iterator &operator++() { + Current = Current->getNextInContext(); + return *this; + } + record_iterator operator++(int) { + record_iterator tmp(*this); + ++(*this); + return tmp; + } + + friend bool operator==(record_iterator x, record_iterator y) { + return x.Current == y.Current; + } + friend bool operator!=(record_iterator x, record_iterator y) { + return x.Current != y.Current; + } + }; + + using record_range = llvm::iterator_range; + record_range records() const { + return record_range(records_begin(), records_end()); + } + record_iterator records_begin() const { return record_iterator(First); }; + record_iterator records_end() const { return record_iterator(); } + bool records_empty() const { return First == nullptr; }; + +private: + APIRecord::RecordKind Kind; + mutable APIRecord *First = nullptr; + mutable APIRecord *Last = nullptr; + +protected: + friend class APISet; + void addToRecordChain(APIRecord *) const; }; -struct NamespaceRecord : APIRecord { - NamespaceRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, +struct NamespaceRecord : APIRecord, RecordContext { + NamespaceRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + LinkageInfo Linkage, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) - : APIRecord(RK_Namespace, USR, Name, Loc, std::move(Availability), + : APIRecord(RK_Namespace, USR, Name, Parent, Loc, std::move(Availability), Linkage, Comment, Declaration, SubHeading, - IsFromSystemHeader) {} + IsFromSystemHeader), + RecordContext(RK_Namespace) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_Namespace; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_Namespace; } }; /// This holds information associated with global functions. struct GlobalFunctionRecord : APIRecord { FunctionSignature Signature; - GlobalFunctionRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, + GlobalFunctionRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, bool IsFromSystemHeader) - : APIRecord(RK_GlobalFunction, USR, Name, Loc, std::move(Availability), - Linkage, Comment, Declaration, SubHeading, - IsFromSystemHeader), + : APIRecord(RK_GlobalFunction, USR, Name, Parent, Loc, + std::move(Availability), Linkage, Comment, Declaration, + SubHeading, IsFromSystemHeader), Signature(Signature) {} GlobalFunctionRecord(RecordKind Kind, StringRef USR, StringRef Name, - PresumedLoc Loc, AvailabilityInfo Availability, - LinkageInfo Linkage, const DocComment &Comment, + SymbolReference Parent, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Loc, std::move(Availability), Linkage, - Comment, Declaration, SubHeading, IsFromSystemHeader), + : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), + Linkage, Comment, Declaration, SubHeading, + IsFromSystemHeader), Signature(Signature) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_GlobalFunction; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_GlobalFunction; } private: virtual void anchor(); @@ -323,63 +432,74 @@ private: struct GlobalFunctionTemplateRecord : GlobalFunctionRecord { Template Templ; - GlobalFunctionTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + GlobalFunctionTemplateRecord(StringRef USR, StringRef Name, + SymbolReference Parent, PresumedLoc Loc, AvailabilityInfo Availability, LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, Template Template, bool IsFromSystemHeader) - : GlobalFunctionRecord(RK_GlobalFunctionTemplate, USR, Name, Loc, + : GlobalFunctionRecord(RK_GlobalFunctionTemplate, USR, Name, Parent, Loc, std::move(Availability), Linkage, Comment, Declaration, SubHeading, Signature, IsFromSystemHeader), Templ(Template) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_GlobalFunctionTemplate; + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { + return K == RK_GlobalFunctionTemplate; } }; struct GlobalFunctionTemplateSpecializationRecord : GlobalFunctionRecord { GlobalFunctionTemplateSpecializationRecord( - StringRef USR, StringRef Name, PresumedLoc Loc, + StringRef USR, StringRef Name, SymbolReference Parent, PresumedLoc Loc, AvailabilityInfo Availability, LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, bool IsFromSystemHeader) : GlobalFunctionRecord(RK_GlobalFunctionTemplateSpecialization, USR, Name, - Loc, std::move(Availability), Linkage, Comment, - Declaration, SubHeading, Signature, + Parent, Loc, std::move(Availability), Linkage, + Comment, Declaration, SubHeading, Signature, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_GlobalFunctionTemplateSpecialization; + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { + return K == RK_GlobalFunctionTemplateSpecialization; } }; /// This holds information associated with global functions. struct GlobalVariableRecord : APIRecord { - GlobalVariableRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, + GlobalVariableRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) - : APIRecord(RK_GlobalVariable, USR, Name, Loc, std::move(Availability), - Linkage, Comment, Declaration, SubHeading, - IsFromSystemHeader) {} + : APIRecord(RK_GlobalVariable, USR, Name, Parent, Loc, + std::move(Availability), Linkage, Comment, Declaration, + SubHeading, IsFromSystemHeader) {} GlobalVariableRecord(RecordKind Kind, StringRef USR, StringRef Name, + SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Loc, std::move(Availability), Linkage, - Comment, Declaration, SubHeading, IsFromSystemHeader) {} + : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), + Linkage, Comment, Declaration, SubHeading, + IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_GlobalVariable; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_GlobalVariable; } private: virtual void anchor(); @@ -388,34 +508,42 @@ private: struct GlobalVariableTemplateRecord : GlobalVariableRecord { Template Templ; - GlobalVariableTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + GlobalVariableTemplateRecord(StringRef USR, StringRef Name, + SymbolReference Parent, PresumedLoc Loc, AvailabilityInfo Availability, LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, class Template Template, bool IsFromSystemHeader) - : GlobalVariableRecord(RK_GlobalVariableTemplate, USR, Name, Loc, + : GlobalVariableRecord(RK_GlobalVariableTemplate, USR, Name, Parent, Loc, std::move(Availability), Linkage, Comment, Declaration, SubHeading, IsFromSystemHeader), Templ(Template) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_GlobalVariableTemplate; + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { + return K == RK_GlobalVariableTemplate; } }; struct GlobalVariableTemplateSpecializationRecord : GlobalVariableRecord { GlobalVariableTemplateSpecializationRecord( - StringRef USR, StringRef Name, PresumedLoc Loc, + StringRef USR, StringRef Name, SymbolReference Parent, PresumedLoc Loc, AvailabilityInfo Availability, LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) : GlobalVariableRecord(RK_GlobalVariableTemplateSpecialization, USR, Name, - Loc, std::move(Availability), Linkage, Comment, - Declaration, SubHeading, IsFromSystemHeader) {} + Parent, Loc, std::move(Availability), Linkage, + Comment, Declaration, SubHeading, + IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_GlobalVariableTemplateSpecialization; + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { + return K == RK_GlobalVariableTemplateSpecialization; } }; @@ -424,126 +552,203 @@ struct GlobalVariableTemplatePartialSpecializationRecord Template Templ; GlobalVariableTemplatePartialSpecializationRecord( - StringRef USR, StringRef Name, PresumedLoc Loc, + StringRef USR, StringRef Name, SymbolReference Parent, PresumedLoc Loc, AvailabilityInfo Availability, LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, class Template Template, bool IsFromSystemHeader) : GlobalVariableRecord(RK_GlobalVariableTemplatePartialSpecialization, - USR, Name, Loc, std::move(Availability), Linkage, - Comment, Declaration, SubHeading, + USR, Name, Parent, Loc, std::move(Availability), + Linkage, Comment, Declaration, SubHeading, IsFromSystemHeader), Templ(Template) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_GlobalVariableTemplatePartialSpecialization; + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { + return K == RK_GlobalVariableTemplatePartialSpecialization; } }; /// This holds information associated with enum constants. struct EnumConstantRecord : APIRecord { - EnumConstantRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, + EnumConstantRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) - : APIRecord(RK_EnumConstant, USR, Name, Loc, std::move(Availability), - LinkageInfo::none(), Comment, Declaration, SubHeading, - IsFromSystemHeader) {} + : APIRecord(RK_EnumConstant, USR, Name, Parent, Loc, + std::move(Availability), LinkageInfo::none(), Comment, + Declaration, SubHeading, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_EnumConstant; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_EnumConstant; } private: virtual void anchor(); }; /// This holds information associated with enums. -struct EnumRecord : APIRecord { - SmallVector> Constants; - - EnumRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - bool IsFromSystemHeader) - : APIRecord(RK_Enum, USR, Name, Loc, std::move(Availability), +struct EnumRecord : APIRecord, RecordContext { + EnumRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader) + : APIRecord(RK_Enum, USR, Name, Parent, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, - IsFromSystemHeader) {} + IsFromSystemHeader), + RecordContext(RK_Enum) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_Enum; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_Enum; } private: virtual void anchor(); }; -/// This holds information associated with struct fields. +/// This holds information associated with struct or union fields fields. struct RecordFieldRecord : APIRecord { - RecordFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + RecordFieldRecord(RecordKind Kind, StringRef USR, StringRef Name, + SymbolReference Parent, PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, RecordKind Kind, - bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Loc, std::move(Availability), + DeclarationFragments SubHeading, bool IsFromSystemHeader) + : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_StructField || - Record->getKind() == RK_UnionField; + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { + return K == RK_StructField || K == RK_UnionField; } -private: - virtual void anchor(); + virtual ~RecordFieldRecord() = 0; }; -/// This holds information associated with structs. -struct RecordRecord : APIRecord { - SmallVector> Fields; - - RecordRecord(StringRef USR, StringRef Name, PresumedLoc Loc, +/// This holds information associated with structs and unions. +struct RecordRecord : APIRecord, RecordContext { + RecordRecord(RecordKind Kind, StringRef USR, StringRef Name, + SymbolReference Parent, PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, RecordKind Kind, - bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Loc, std::move(Availability), + DeclarationFragments SubHeading, bool IsFromSystemHeader) + : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, - IsFromSystemHeader) {} + IsFromSystemHeader), + RecordContext(Kind) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_Struct || Record->getKind() == RK_Union; + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { + return K == RK_Struct || K == RK_Union; } + virtual ~RecordRecord() = 0; +}; + +struct StructFieldRecord : RecordFieldRecord { + StructFieldRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader) + : RecordFieldRecord(RK_StructField, USR, Name, Parent, Loc, + std::move(Availability), Comment, Declaration, + SubHeading, IsFromSystemHeader) {} + + static bool classof(const APIRecord *Record) { + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { return K == RK_StructField; } + private: virtual void anchor(); }; -struct CXXFieldRecord : APIRecord { - AccessControl Access; +struct StructRecord : RecordRecord { + StructRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader) + : RecordRecord(RK_Struct, USR, Name, Parent, Loc, std::move(Availability), + Comment, Declaration, SubHeading, IsFromSystemHeader) {} - CXXFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, + static bool classof(const APIRecord *Record) { + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { return K == RK_Struct; } + +private: + virtual void anchor(); +}; + +struct UnionFieldRecord : RecordFieldRecord { + UnionFieldRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader) + : RecordFieldRecord(RK_UnionField, USR, Name, Parent, Loc, + std::move(Availability), Comment, Declaration, + SubHeading, IsFromSystemHeader) {} + + static bool classof(const APIRecord *Record) { + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { return K == RK_UnionField; } + +private: + virtual void anchor(); +}; + +struct UnionRecord : RecordRecord { + UnionRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, + DeclarationFragments SubHeading, bool IsFromSystemHeader) + : RecordRecord(RK_Union, USR, Name, Parent, Loc, std::move(Availability), + Comment, Declaration, SubHeading, IsFromSystemHeader) {} + + static bool classof(const APIRecord *Record) { + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { return K == RK_Union; } + +private: + virtual void anchor(); +}; + +struct CXXFieldRecord : APIRecord { + CXXFieldRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, AccessControl Access, bool IsFromSystemHeader) - : APIRecord(RK_CXXField, USR, Name, Loc, std::move(Availability), + : APIRecord(RK_CXXField, USR, Name, Parent, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, - IsFromSystemHeader), - Access(Access) {} + IsFromSystemHeader, std::move(Access)) {} CXXFieldRecord(RecordKind Kind, StringRef USR, StringRef Name, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, + SymbolReference Parent, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, AccessControl Access, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Loc, std::move(Availability), + : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, - IsFromSystemHeader), - Access(Access) {} + IsFromSystemHeader, std::move(Access)) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_CXXField; + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { + return K == RK_CXXField || K == RK_CXXFieldTemplate || K == RK_StaticField; } private: @@ -553,111 +758,122 @@ private: struct CXXFieldTemplateRecord : CXXFieldRecord { Template Templ; - CXXFieldTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, + CXXFieldTemplateRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, AccessControl Access, Template Template, bool IsFromSystemHeader) - : CXXFieldRecord(RK_CXXFieldTemplate, USR, Name, Loc, + : CXXFieldRecord(RK_CXXFieldTemplate, USR, Name, Parent, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Access, IsFromSystemHeader), + SubHeading, std::move(Access), IsFromSystemHeader), Templ(Template) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_CXXFieldTemplate; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_CXXFieldTemplate; } }; struct CXXMethodRecord : APIRecord { FunctionSignature Signature; - AccessControl Access; CXXMethodRecord() = delete; CXXMethodRecord(RecordKind Kind, StringRef USR, StringRef Name, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, + SymbolReference Parent, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, AccessControl Access, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Loc, std::move(Availability), + : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, - IsFromSystemHeader), - Signature(Signature), Access(Access) {} + IsFromSystemHeader, std::move(Access)), + Signature(Signature) {} virtual ~CXXMethodRecord() = 0; }; struct CXXConstructorRecord : CXXMethodRecord { - CXXConstructorRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, + CXXConstructorRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, AccessControl Access, bool IsFromSystemHeader) - : CXXMethodRecord(RK_CXXConstructorMethod, USR, Name, Loc, + : CXXMethodRecord(RK_CXXConstructorMethod, USR, Name, Parent, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, Access, IsFromSystemHeader) {} + SubHeading, Signature, std::move(Access), + IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_CXXConstructorMethod; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_CXXConstructorMethod; } private: virtual void anchor(); }; struct CXXDestructorRecord : CXXMethodRecord { - CXXDestructorRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, + CXXDestructorRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, AccessControl Access, bool IsFromSystemHeader) - : CXXMethodRecord(RK_CXXDestructorMethod, USR, Name, Loc, + : CXXMethodRecord(RK_CXXDestructorMethod, USR, Name, Parent, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, Access, IsFromSystemHeader) {} + SubHeading, Signature, std::move(Access), + IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_CXXDestructorMethod; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_CXXDestructorMethod; } private: virtual void anchor(); }; struct CXXStaticMethodRecord : CXXMethodRecord { - CXXStaticMethodRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, + CXXStaticMethodRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, AccessControl Access, bool IsFromSystemHeader) - : CXXMethodRecord(RK_CXXStaticMethod, USR, Name, Loc, + : CXXMethodRecord(RK_CXXStaticMethod, USR, Name, Parent, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, Access, IsFromSystemHeader) {} + SubHeading, Signature, std::move(Access), + IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_CXXStaticMethod; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_CXXStaticMethod; } private: virtual void anchor(); }; struct CXXInstanceMethodRecord : CXXMethodRecord { - CXXInstanceMethodRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, + CXXInstanceMethodRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, AccessControl Access, bool IsFromSystemHeader) - : CXXMethodRecord(RK_CXXInstanceMethod, USR, Name, Loc, + : CXXMethodRecord(RK_CXXInstanceMethod, USR, Name, Parent, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, Access, IsFromSystemHeader) {} + SubHeading, Signature, std::move(Access), + IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_CXXInstanceMethod; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_CXXInstanceMethod; } private: virtual void anchor(); @@ -666,36 +882,42 @@ private: struct CXXMethodTemplateRecord : CXXMethodRecord { Template Templ; - CXXMethodTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, + CXXMethodTemplateRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, AccessControl Access, Template Template, bool IsFromSystemHeader) - : CXXMethodRecord(RK_CXXMethodTemplate, USR, Name, Loc, + : CXXMethodRecord(RK_CXXMethodTemplate, USR, Name, Parent, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, Access, IsFromSystemHeader), + SubHeading, Signature, std::move(Access), + IsFromSystemHeader), Templ(Template) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_CXXMethodTemplate; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_CXXMethodTemplate; } }; struct CXXMethodTemplateSpecializationRecord : CXXMethodRecord { CXXMethodTemplateSpecializationRecord( - StringRef USR, StringRef Name, PresumedLoc Loc, + StringRef USR, StringRef Name, SymbolReference Parent, PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, AccessControl Access, bool IsFromSystemHeader) - : CXXMethodRecord(RK_CXXMethodTemplateSpecialization, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Signature, Access, IsFromSystemHeader) {} + : CXXMethodRecord(RK_CXXMethodTemplateSpecialization, USR, Name, Parent, + Loc, std::move(Availability), Comment, Declaration, + SubHeading, Signature, std::move(Access), + IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_CXXMethodTemplateSpecialization; + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { + return K == RK_CXXMethodTemplateSpecialization; } }; @@ -714,13 +936,13 @@ struct ObjCPropertyRecord : APIRecord { bool IsOptional; ObjCPropertyRecord(RecordKind Kind, StringRef USR, StringRef Name, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, + SymbolReference Parent, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, AttributeKind Attributes, StringRef GetterName, StringRef SetterName, bool IsOptional, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Loc, std::move(Availability), + : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, IsFromSystemHeader), Attributes(Attributes), GetterName(GetterName), SetterName(SetterName), @@ -733,44 +955,44 @@ struct ObjCPropertyRecord : APIRecord { }; struct ObjCInstancePropertyRecord : ObjCPropertyRecord { - ObjCInstancePropertyRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - AttributeKind Attributes, StringRef GetterName, - StringRef SetterName, bool IsOptional, - bool IsFromSystemHeader) - : ObjCPropertyRecord(RK_ObjCInstanceProperty, USR, Name, Loc, + ObjCInstancePropertyRecord( + StringRef USR, StringRef Name, SymbolReference Parent, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, + AttributeKind Attributes, StringRef GetterName, StringRef SetterName, + bool IsOptional, bool IsFromSystemHeader) + : ObjCPropertyRecord(RK_ObjCInstanceProperty, USR, Name, Parent, Loc, std::move(Availability), Comment, Declaration, SubHeading, Attributes, GetterName, SetterName, IsOptional, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_ObjCInstanceProperty; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_ObjCInstanceProperty; } private: virtual void anchor(); }; struct ObjCClassPropertyRecord : ObjCPropertyRecord { - ObjCClassPropertyRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, + ObjCClassPropertyRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, AttributeKind Attributes, StringRef GetterName, StringRef SetterName, bool IsOptional, bool IsFromSystemHeader) - : ObjCPropertyRecord(RK_ObjCClassProperty, USR, Name, Loc, + : ObjCPropertyRecord(RK_ObjCClassProperty, USR, Name, Parent, Loc, std::move(Availability), Comment, Declaration, SubHeading, Attributes, GetterName, SetterName, IsOptional, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_ObjCClassProperty; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_ObjCClassProperty; } private: virtual void anchor(); @@ -778,23 +1000,21 @@ private: /// This holds information associated with Objective-C instance variables. struct ObjCInstanceVariableRecord : APIRecord { - using AccessControl = ObjCIvarDecl::AccessControl; - AccessControl Access; - - ObjCInstanceVariableRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + ObjCInstanceVariableRecord(StringRef USR, StringRef Name, + SymbolReference Parent, PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, - AccessControl Access, bool IsFromSystemHeader) - : APIRecord(RK_ObjCIvar, USR, Name, Loc, std::move(Availability), + bool IsFromSystemHeader) + : APIRecord(RK_ObjCIvar, USR, Name, Parent, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, - IsFromSystemHeader), - Access(Access) {} + IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_ObjCIvar; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_ObjCIvar; } private: virtual void anchor(); @@ -807,11 +1027,12 @@ struct ObjCMethodRecord : APIRecord { ObjCMethodRecord() = delete; ObjCMethodRecord(RecordKind Kind, StringRef USR, StringRef Name, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, + SymbolReference Parent, PresumedLoc Loc, + AvailabilityInfo Availability, const DocComment &Comment, + DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Loc, std::move(Availability), + : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, IsFromSystemHeader), Signature(Signature) {} @@ -820,122 +1041,103 @@ struct ObjCMethodRecord : APIRecord { }; struct ObjCInstanceMethodRecord : ObjCMethodRecord { - ObjCInstanceMethodRecord(StringRef USR, StringRef Name, PresumedLoc Loc, + ObjCInstanceMethodRecord(StringRef USR, StringRef Name, + SymbolReference Parent, PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, bool IsFromSystemHeader) - : ObjCMethodRecord(RK_ObjCInstanceMethod, USR, Name, Loc, + : ObjCMethodRecord(RK_ObjCInstanceMethod, USR, Name, Parent, Loc, std::move(Availability), Comment, Declaration, SubHeading, Signature, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_ObjCInstanceMethod; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_ObjCInstanceMethod; } private: virtual void anchor(); }; struct ObjCClassMethodRecord : ObjCMethodRecord { - ObjCClassMethodRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, + ObjCClassMethodRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, FunctionSignature Signature, bool IsFromSystemHeader) - : ObjCMethodRecord(RK_ObjCClassMethod, USR, Name, Loc, + : ObjCMethodRecord(RK_ObjCClassMethod, USR, Name, Parent, Loc, std::move(Availability), Comment, Declaration, SubHeading, Signature, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_ObjCClassMethod; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_ObjCClassMethod; } private: virtual void anchor(); }; -/// This represents a reference to another symbol that might come from external -/// sources. -struct SymbolReference { - StringRef Name; - StringRef USR; - - /// The source project/module/product of the referred symbol. - StringRef Source; - - SymbolReference() = default; - SymbolReference(StringRef Name, StringRef USR = "", StringRef Source = "") - : Name(Name), USR(USR), Source(Source) {} - SymbolReference(const APIRecord &Record) - : Name(Record.Name), USR(Record.USR) {} - SymbolReference(const APIRecord *Record) - : Name(Record->Name), USR(Record->USR) {} - - /// Determine if this SymbolReference is empty. - /// - /// \returns true if and only if all \c Name, \c USR, and \c Source is empty. - bool empty() const { return Name.empty() && USR.empty() && Source.empty(); } -}; - struct StaticFieldRecord : CXXFieldRecord { - SymbolReference Context; - - StaticFieldRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, SymbolReference Context, - AccessControl Access, bool IsFromSystemHeader) - : CXXFieldRecord(RK_StaticField, USR, Name, Loc, std::move(Availability), - Comment, Declaration, SubHeading, Access, - IsFromSystemHeader), - Context(Context) {} + StaticFieldRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + LinkageInfo Linkage, const DocComment &Comment, + DeclarationFragments Declaration, + DeclarationFragments SubHeading, AccessControl Access, + bool IsFromSystemHeader) + : CXXFieldRecord(RK_StaticField, USR, Name, Parent, Loc, + std::move(Availability), Comment, Declaration, + SubHeading, std::move(Access), IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_StaticField; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_StaticField; } }; /// The base representation of an Objective-C container record. Holds common /// information associated with Objective-C containers. -struct ObjCContainerRecord : APIRecord { - SmallVector> Methods; - SmallVector> Properties; - SmallVector> Ivars; +struct ObjCContainerRecord : APIRecord, RecordContext { SmallVector Protocols; ObjCContainerRecord() = delete; ObjCContainerRecord(RecordKind Kind, StringRef USR, StringRef Name, - PresumedLoc Loc, AvailabilityInfo Availability, - LinkageInfo Linkage, const DocComment &Comment, + SymbolReference Parent, PresumedLoc Loc, + AvailabilityInfo Availability, LinkageInfo Linkage, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Loc, std::move(Availability), Linkage, - Comment, Declaration, SubHeading, IsFromSystemHeader) {} + : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), + Linkage, Comment, Declaration, SubHeading, + IsFromSystemHeader), + RecordContext(Kind) {} virtual ~ObjCContainerRecord() = 0; }; -struct CXXClassRecord : APIRecord { - SmallVector> Fields; - SmallVector> Methods; +struct CXXClassRecord : APIRecord, RecordContext { SmallVector Bases; - AccessControl Access; - CXXClassRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, + CXXClassRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, RecordKind Kind, AccessControl Access, bool IsFromSystemHeader) - : APIRecord(Kind, USR, Name, Loc, std::move(Availability), + : APIRecord(Kind, USR, Name, Parent, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, - IsFromSystemHeader), - Access(Access) {} + IsFromSystemHeader, std::move(Access)), + RecordContext(Kind) {} static bool classof(const APIRecord *Record) { - return (Record->getKind() == RK_CXXClass); + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { + return K == RK_CXXClass || K == RK_ClassTemplate || + K == RK_ClassTemplateSpecialization || + K == RK_ClassTemplatePartialSpecialization; } private: @@ -945,86 +1147,108 @@ private: struct ClassTemplateRecord : CXXClassRecord { Template Templ; - ClassTemplateRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, + ClassTemplateRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, Template Template, AccessControl Access, bool IsFromSystemHeader) - : CXXClassRecord(USR, Name, Loc, std::move(Availability), Comment, - Declaration, SubHeading, RK_ClassTemplate, Access, - IsFromSystemHeader), + : CXXClassRecord(USR, Name, Parent, Loc, std::move(Availability), Comment, + Declaration, SubHeading, RK_ClassTemplate, + std::move(Access), IsFromSystemHeader), Templ(Template) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_ClassTemplate; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_ClassTemplate; } }; struct ClassTemplateSpecializationRecord : CXXClassRecord { ClassTemplateSpecializationRecord( - StringRef USR, StringRef Name, PresumedLoc Loc, + StringRef USR, StringRef Name, SymbolReference Parent, PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, AccessControl Access, bool IsFromSystemHeader) - : CXXClassRecord(USR, Name, Loc, std::move(Availability), Comment, + : CXXClassRecord(USR, Name, Parent, Loc, std::move(Availability), Comment, Declaration, SubHeading, RK_ClassTemplateSpecialization, Access, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_ClassTemplateSpecialization; + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { + return K == RK_ClassTemplateSpecialization; } }; struct ClassTemplatePartialSpecializationRecord : CXXClassRecord { Template Templ; ClassTemplatePartialSpecializationRecord( - StringRef USR, StringRef Name, PresumedLoc Loc, + StringRef USR, StringRef Name, SymbolReference Parent, PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, Template Template, AccessControl Access, bool IsFromSystemHeader) - : CXXClassRecord(USR, Name, Loc, std::move(Availability), Comment, - Declaration, SubHeading, RK_ClassTemplateSpecialization, - Access, IsFromSystemHeader), + : CXXClassRecord(USR, Name, Parent, Loc, std::move(Availability), Comment, + Declaration, SubHeading, + RK_ClassTemplatePartialSpecialization, Access, + IsFromSystemHeader), Templ(Template) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_ClassTemplatePartialSpecialization; + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { + return K == RK_ClassTemplatePartialSpecialization; } }; struct ConceptRecord : APIRecord { Template Templ; - ConceptRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, + ConceptRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, Template Template, bool IsFromSystemHeader) - : APIRecord(RK_Concept, USR, Name, Loc, std::move(Availability), + : APIRecord(RK_Concept, USR, Name, Parent, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, IsFromSystemHeader), Templ(Template) {} + + static bool classof(const APIRecord *Record) { + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { return K == RK_Concept; } }; /// This holds information associated with Objective-C categories. struct ObjCCategoryRecord : ObjCContainerRecord { SymbolReference Interface; - /// Determine whether the Category is derived from external class interface. - bool IsFromExternalModule = false; - ObjCCategoryRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, + ObjCCategoryRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, SymbolReference Interface, bool IsFromSystemHeader) - : ObjCContainerRecord(RK_ObjCCategory, USR, Name, Loc, + : ObjCContainerRecord(RK_ObjCCategory, USR, Name, Parent, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, IsFromSystemHeader), Interface(Interface) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_ObjCCategory; + return classofKind(Record->getKind()); + } + static bool classofKind(RecordKind K) { return K == RK_ObjCCategory; } + + bool isExtendingExternalModule() const { return !Interface.Source.empty(); } + + std::optional getExtendedExternalModule() const { + if (!isExtendingExternalModule()) + return {}; + return Interface.Source; } private: @@ -1034,23 +1258,22 @@ private: /// This holds information associated with Objective-C interfaces/classes. struct ObjCInterfaceRecord : ObjCContainerRecord { SymbolReference SuperClass; - // ObjCCategoryRecord%s are stored in and owned by APISet. - SmallVector Categories; - ObjCInterfaceRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, + ObjCInterfaceRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + LinkageInfo Linkage, const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, SymbolReference SuperClass, bool IsFromSystemHeader) - : ObjCContainerRecord(RK_ObjCInterface, USR, Name, Loc, + : ObjCContainerRecord(RK_ObjCInterface, USR, Name, Parent, Loc, std::move(Availability), Linkage, Comment, Declaration, SubHeading, IsFromSystemHeader), SuperClass(SuperClass) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_ObjCInterface; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_ObjCInterface; } private: virtual void anchor(); @@ -1058,18 +1281,20 @@ private: /// This holds information associated with Objective-C protocols. struct ObjCProtocolRecord : ObjCContainerRecord { - ObjCProtocolRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, + ObjCProtocolRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) - : ObjCContainerRecord(RK_ObjCProtocol, USR, Name, Loc, + : ObjCContainerRecord(RK_ObjCProtocol, USR, Name, Parent, Loc, std::move(Availability), LinkageInfo::none(), Comment, Declaration, SubHeading, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_ObjCProtocol; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_ObjCProtocol; } private: virtual void anchor(); @@ -1077,17 +1302,18 @@ private: /// This holds information associated with macro definitions. struct MacroDefinitionRecord : APIRecord { - MacroDefinitionRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - DeclarationFragments Declaration, + MacroDefinitionRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, DeclarationFragments Declaration, DeclarationFragments SubHeading, bool IsFromSystemHeader) - : APIRecord(RK_MacroDefinition, USR, Name, Loc, AvailabilityInfo(), - LinkageInfo(), {}, Declaration, SubHeading, - IsFromSystemHeader) {} + : APIRecord(RK_MacroDefinition, USR, Name, Parent, Loc, + AvailabilityInfo(), LinkageInfo(), {}, Declaration, + SubHeading, IsFromSystemHeader) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_MacroDefinition; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_MacroDefinition; } private: virtual void anchor(); @@ -1101,575 +1327,228 @@ private: struct TypedefRecord : APIRecord { SymbolReference UnderlyingType; - TypedefRecord(StringRef USR, StringRef Name, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, + TypedefRecord(StringRef USR, StringRef Name, SymbolReference Parent, + PresumedLoc Loc, AvailabilityInfo Availability, + const DocComment &Comment, DeclarationFragments Declaration, DeclarationFragments SubHeading, SymbolReference UnderlyingType, bool IsFromSystemHeader) - : APIRecord(RK_Typedef, USR, Name, Loc, std::move(Availability), + : APIRecord(RK_Typedef, USR, Name, Parent, Loc, std::move(Availability), LinkageInfo(), Comment, Declaration, SubHeading, IsFromSystemHeader), UnderlyingType(UnderlyingType) {} static bool classof(const APIRecord *Record) { - return Record->getKind() == RK_Typedef; + return classofKind(Record->getKind()); } + static bool classofKind(RecordKind K) { return K == RK_Typedef; } private: virtual void anchor(); }; -/// Check if a record type has a function signature mixin. -/// -/// This is denoted by the record type having a ``Signature`` field of type -/// FunctionSignature. -template -struct has_function_signature : public std::false_type {}; -template <> -struct has_function_signature : public std::true_type {}; -template <> -struct has_function_signature : public std::true_type {}; -template <> -struct has_function_signature - : public std::true_type {}; -template <> -struct has_function_signature : public std::true_type {}; -template <> -struct has_function_signature : public std::true_type {}; -template <> -struct has_function_signature : public std::true_type {}; -template <> -struct has_function_signature : public std::true_type { -}; -template <> -struct has_function_signature - : public std::true_type {}; - -template struct has_access : public std::false_type {}; -template <> struct has_access : public std::true_type {}; -template <> struct has_access : public std::true_type {}; -template <> struct has_access : public std::true_type {}; -template <> -struct has_access : public std::true_type {}; -template <> -struct has_access - : public std::true_type {}; -template <> -struct has_access : public std::true_type {}; -template <> struct has_access : public std::true_type {}; -template <> struct has_access : public std::true_type {}; -template <> -struct has_access : public std::true_type {}; -template <> -struct has_access - : public std::true_type {}; - -template struct has_template : public std::false_type {}; -template <> struct has_template : public std::true_type {}; -template <> -struct has_template - : public std::true_type {}; -template <> struct has_template : public std::true_type {}; -template <> -struct has_template : public std::true_type {}; -template <> -struct has_template - : public std::true_type {}; -template <> -struct has_template : public std::true_type {}; -template <> -struct has_template : public std::true_type {}; - -template <> -struct has_template : public std::true_type {}; -template <> -struct has_function_signature - : public std::true_type {}; -template <> -struct has_function_signature - : public std::true_type {}; - /// APISet holds the set of API records collected from given inputs. class APISet { public: - NamespaceRecord *addNamespace(APIRecord *Parent, StringRef Name, - StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, - LinkageInfo Linkage, const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - bool IsFromSystemHeaderg); - /// Create and add a global variable record into the API set. - /// - /// Note: the caller is responsible for keeping the StringRef \p Name and - /// \p USR alive. APISet::copyString provides a way to copy strings into - /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method - /// to generate the USR for \c D and keep it alive in APISet. - GlobalVariableRecord * - addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeadin, bool IsFromSystemHeaderg); + /// Get the target triple for the ExtractAPI invocation. + const llvm::Triple &getTarget() const { return Target; } - GlobalVariableTemplateRecord * - addGlobalVariableTemplate(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, Template Template, - bool IsFromSystemHeader); + /// Get the language used by the APIs. + Language getLanguage() const { return Lang; } - /// Create and add a function record into the API set. + /// Finds the APIRecord for a given USR. /// - /// Note: the caller is responsible for keeping the StringRef \p Name and - /// \p USR alive. APISet::copyString provides a way to copy strings into - /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method - /// to generate the USR for \c D and keep it alive in APISet. - GlobalFunctionRecord * - addGlobalFunction(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, - FunctionSignature Signature, bool IsFromSystemHeader); - - GlobalFunctionTemplateRecord *addGlobalFunctionTemplate( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, FunctionSignature Signature, - Template Template, bool IsFromSystemHeader); - - GlobalFunctionTemplateSpecializationRecord * - addGlobalFunctionTemplateSpecialization( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, FunctionSignature Signature, - bool IsFromSystemHeader); + /// \returns a pointer to the APIRecord associated with that USR or nullptr. + APIRecord *findRecordForUSR(StringRef USR) const; - /// Create and add an enum constant record into the API set. + /// Copy \p String into the Allocator in this APISet. /// - /// Note: the caller is responsible for keeping the StringRef \p Name and - /// \p USR alive. APISet::copyString provides a way to copy strings into - /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method - /// to generate the USR for \c D and keep it alive in APISet. - EnumConstantRecord * - addEnumConstant(EnumRecord *Enum, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader); + /// \returns a StringRef of the copied string in APISet::Allocator. + StringRef copyString(StringRef String); - /// Create and add an enum record into the API set. - /// - /// Note: the caller is responsible for keeping the StringRef \p Name and - /// \p USR alive. APISet::copyString provides a way to copy strings into - /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method - /// to generate the USR for \c D and keep it alive in APISet. - EnumRecord *addEnum(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader); + SymbolReference createSymbolReference(StringRef Name, StringRef USR, + StringRef Source = ""); - /// Create and add a record field record into the API set. + /// Create a subclass of \p APIRecord and store it in the APISet. /// - /// Note: the caller is responsible for keeping the StringRef \p Name and - /// \p USR alive. APISet::copyString provides a way to copy strings into - /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method - /// to generate the USR for \c D and keep it alive in APISet. - RecordFieldRecord * - addRecordField(RecordRecord *Record, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, APIRecord::RecordKind Kind, - bool IsFromSystemHeader); - - /// Create and add a record record into the API set. - /// - /// Note: the caller is responsible for keeping the StringRef \p Name and - /// \p USR alive. APISet::copyString provides a way to copy strings into - /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method - /// to generate the USR for \c D and keep it alive in APISet. - RecordRecord *addRecord(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - APIRecord::RecordKind Kind, bool IsFromSystemHeader); - - StaticFieldRecord * - addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, SymbolReference Context, - AccessControl Access, bool IsFromSystemHeaderg); - - CXXFieldRecord *addCXXField(APIRecord *CXXClass, StringRef Name, - StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - AccessControl Access, bool IsFromSystemHeader); - - CXXFieldTemplateRecord *addCXXFieldTemplate( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - AccessControl Access, Template Template, bool IsFromSystemHeader); - - CXXClassRecord *addCXXClass(APIRecord *Parent, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - APIRecord::RecordKind Kind, AccessControl Access, - bool IsFromSystemHeader); - - ClassTemplateRecord * - addClassTemplate(APIRecord *Parent, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, Template Template, - AccessControl Access, bool IsFromSystemHeader); - - ClassTemplateSpecializationRecord *addClassTemplateSpecialization( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - AccessControl Access, bool IsFromSystemHeader); - - ClassTemplatePartialSpecializationRecord * - addClassTemplatePartialSpecialization( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - Template Template, AccessControl Access, bool IsFromSystemHeader); - - GlobalVariableTemplateSpecializationRecord * - addGlobalVariableTemplateSpecialization( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader); - - GlobalVariableTemplatePartialSpecializationRecord * - addGlobalVariableTemplatePartialSpecialization( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, Template Template, - bool IsFromSystemHeader); - - CXXMethodRecord *addCXXInstanceMethod( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, - bool IsFromSystemHeader); - - CXXMethodRecord *addCXXStaticMethod( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, - bool IsFromSystemHeader); - - CXXMethodRecord *addCXXSpecialMethod( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, - bool IsFromSystemHeader); - - CXXMethodTemplateRecord *addCXXMethodTemplate( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, Template Template, - bool IsFromSystemHeader); + /// \returns A pointer to the created record or the already existing record + /// matching this USR. + template + typename std::enable_if_t, RecordTy> * + createRecord(StringRef USR, StringRef Name, CtorArgsContTy &&...CtorArgs); + + ArrayRef getTopLevelRecords() const { + return TopLevelRecords; + } - CXXMethodTemplateSpecializationRecord *addCXXMethodTemplateSpec( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, - bool IsFromSystemHeader); + APISet(const llvm::Triple &Target, Language Lang, + const std::string &ProductName) + : Target(Target), Lang(Lang), ProductName(ProductName) {} - ConceptRecord *addConcept(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, Template Template, - bool IsFromSystemHeader); + // Prevent moves and copies + APISet(const APISet &Other) = delete; + APISet &operator=(const APISet &Other) = delete; + APISet(APISet &&Other) = delete; + APISet &operator=(APISet &&Other) = delete; - /// Create and add an Objective-C category record into the API set. - /// - /// Note: the caller is responsible for keeping the StringRef \p Name and - /// \p USR alive. APISet::copyString provides a way to copy strings into - /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method - /// to generate the USR for \c D and keep it alive in APISet. - ObjCCategoryRecord * - addObjCCategory(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, SymbolReference Interface, - bool IsFromSystemHeader, bool IsFromExternalModule); +private: + /// BumpPtrAllocator that serves as the memory arena for the allocated objects + llvm::BumpPtrAllocator Allocator; - /// Create and add an Objective-C interface record into the API set. - /// - /// Note: the caller is responsible for keeping the StringRef \p Name and - /// \p USR alive. APISet::copyString provides a way to copy strings into - /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method - /// to generate the USR for \c D and keep it alive in APISet. - ObjCInterfaceRecord * - addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, SymbolReference SuperClass, - bool IsFromSystemHeader); + const llvm::Triple Target; + const Language Lang; - /// Create and add an Objective-C method record into the API set. - /// - /// Note: the caller is responsible for keeping the StringRef \p Name and - /// \p USR alive. APISet::copyString provides a way to copy strings into - /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method - /// to generate the USR for \c D and keep it alive in APISet. - ObjCMethodRecord * - addObjCMethod(ObjCContainerRecord *Container, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, FunctionSignature Signature, - bool IsInstanceMethod, bool IsFromSystemHeader); + struct APIRecordDeleter { + void operator()(APIRecord *Record) { Record->~APIRecord(); } + }; - /// Create and add an Objective-C property record into the API set. - /// - /// Note: the caller is responsible for keeping the StringRef \p Name and - /// \p USR alive. APISet::copyString provides a way to copy strings into - /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method - /// to generate the USR for \c D and keep it alive in APISet. - ObjCPropertyRecord * - addObjCProperty(ObjCContainerRecord *Container, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, - ObjCPropertyRecord::AttributeKind Attributes, - StringRef GetterName, StringRef SetterName, bool IsOptional, - bool IsInstanceProperty, bool IsFromSystemHeader); + // Ensure that the destructor of each record is called when the LookupTable is + // destroyed without calling delete operator as the memory for the record + // lives in the BumpPtrAllocator. + using APIRecordStoredPtr = std::unique_ptr; + llvm::DenseMap USRBasedLookupTable; + std::vector TopLevelRecords; - /// Create and add an Objective-C instance variable record into the API set. - /// - /// Note: the caller is responsible for keeping the StringRef \p Name and - /// \p USR alive. APISet::copyString provides a way to copy strings into - /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method - /// to generate the USR for \c D and keep it alive in APISet. - ObjCInstanceVariableRecord *addObjCInstanceVariable( - ObjCContainerRecord *Container, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - ObjCInstanceVariableRecord::AccessControl Access, - bool IsFromSystemHeader); +public: + const std::string ProductName; +}; - /// Create and add an Objective-C protocol record into the API set. - /// - /// Note: the caller is responsible for keeping the StringRef \p Name and - /// \p USR alive. APISet::copyString provides a way to copy strings into - /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method - /// to generate the USR for \c D and keep it alive in APISet. - ObjCProtocolRecord * - addObjCProtocol(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader); +template +typename std::enable_if_t, RecordTy> * +APISet::createRecord(StringRef USR, StringRef Name, + CtorArgsContTy &&...CtorArgs) { + // Ensure USR refers to a String stored in the allocator. + auto USRString = copyString(USR); + auto Result = USRBasedLookupTable.insert({USRString, nullptr}); + RecordTy *Record; + + // Create the record if it does not already exist + if (Result.second) { + Record = new (Allocator) RecordTy( + USRString, copyString(Name), std::forward(CtorArgs)...); + // Store the record in the record lookup map + Result.first->second = APIRecordStoredPtr(Record); + + if (auto *ParentContext = + dyn_cast_if_present(Record->Parent.Record)) + ParentContext->addToRecordChain(Record); + else + TopLevelRecords.push_back(Record); + } else { + Record = dyn_cast(Result.first->second.get()); + } - /// Create a macro definition record into the API set. - /// - /// Note: the caller is responsible for keeping the StringRef \p Name and - /// \p USR alive. APISet::copyString provides a way to copy strings into - /// APISet itself, and APISet::recordUSRForMacro(StringRef Name, - /// SourceLocation SL, const SourceManager &SM) is a helper method to generate - /// the USR for the macro and keep it alive in APISet. - MacroDefinitionRecord *addMacroDefinition(StringRef Name, StringRef USR, - PresumedLoc Loc, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - bool IsFromSystemHeader); - - /// Create a typedef record into the API set. - /// - /// Note: the caller is responsible for keeping the StringRef \p Name and - /// \p USR alive. APISet::copyString provides a way to copy strings into - /// APISet itself, and APISet::recordUSR(const Decl *D) is a helper method - /// to generate the USR for \c D and keep it alive in APISet. - TypedefRecord * - addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - SymbolReference UnderlyingType, bool IsFromSystemHeader); - - /// A mapping type to store a set of APIRecord%s with the USR as the key. - template ::value>> - using RecordMap = llvm::MapVector>; + return Record; +} - /// Get the target triple for the ExtractAPI invocation. - const llvm::Triple &getTarget() const { return Target; } +// Helper type for implementing casting to RecordContext pointers. +// Selected when FromTy not a known subclass of RecordContext. +template > +struct ToRecordContextCastInfoWrapper { + static_assert(std::is_base_of_v, + "Can only cast APIRecord and derived classes to RecordContext"); - /// Get the language used by the APIs. - Language getLanguage() const { return Lang; } + static bool isPossible(FromTy *From) { return RecordContext::classof(From); } - const RecordMap &getNamespaces() const { return Namespaces; } - const RecordMap &getGlobalFunctions() const { - return GlobalFunctions; - } - const RecordMap & - getGlobalFunctionTemplates() const { - return GlobalFunctionTemplates; - } - const RecordMap & - getGlobalFunctionTemplateSpecializations() const { - return GlobalFunctionTemplateSpecializations; - } - const RecordMap &getGlobalVariables() const { - return GlobalVariables; - } - const RecordMap & - getGlobalVariableTemplates() const { - return GlobalVariableTemplates; + static RecordContext *doCast(FromTy *From) { + return APIRecord::castToRecordContext(From); } - const RecordMap &getStaticFields() const { - return StaticFields; - } - const RecordMap & - getGlobalVariableTemplateSpecializations() const { - return GlobalVariableTemplateSpecializations; - } - const RecordMap & - getGlobalVariableTemplatePartialSpecializations() const { - return GlobalVariableTemplatePartialSpecializations; - } - const RecordMap &getEnums() const { return Enums; } - const RecordMap &getRecords() const { return Records; } - const RecordMap &getCXXClasses() const { return CXXClasses; } - const RecordMap &getCXXMethodTemplates() const { - return CXXMethodTemplates; - } - const RecordMap &getCXXInstanceMethods() const { - return CXXInstanceMethods; - } - const RecordMap &getCXXStaticMethods() const { - return CXXStaticMethods; - } - const RecordMap &getCXXFields() const { return CXXFields; } - const RecordMap & - getCXXMethodTemplateSpecializations() const { - return CXXMethodTemplateSpecializations; - } - const RecordMap &getCXXFieldTemplates() const { - return CXXFieldTemplates; - } - const RecordMap &getClassTemplates() const { - return ClassTemplates; - } - const RecordMap & - getClassTemplateSpecializations() const { - return ClassTemplateSpecializations; +}; + +// Selected when FromTy is a known subclass of RecordContext. +template struct ToRecordContextCastInfoWrapper { + static_assert(std::is_base_of_v, + "Can only cast APIRecord and derived classes to RecordContext"); + static bool isPossible(const FromTy *From) { return true; } + static RecordContext *doCast(FromTy *From) { + return static_cast(From); } - const RecordMap & - getClassTemplatePartialSpecializations() const { - return ClassTemplatePartialSpecializations; +}; + +// Helper type for implementing casting to RecordContext pointers. +// Selected when ToTy isn't a known subclass of RecordContext +template > +struct FromRecordContextCastInfoWrapper { + static_assert( + std::is_base_of_v, + "Can only class RecordContext to APIRecord and derived classes"); + + static bool isPossible(RecordContext *Ctx) { + return ToTy::classofKind(Ctx->getKind()); } - const RecordMap &getConcepts() const { return Concepts; } - const RecordMap &getObjCCategories() const { - return ObjCCategories; + + static ToTy *doCast(RecordContext *Ctx) { + return APIRecord::castFromRecordContext(Ctx); } - const RecordMap &getObjCInterfaces() const { - return ObjCInterfaces; +}; + +// Selected when ToTy is a known subclass of RecordContext. +template struct FromRecordContextCastInfoWrapper { + static_assert( + std::is_base_of_v, + "Can only class RecordContext to APIRecord and derived classes"); + static bool isPossible(RecordContext *Ctx) { + return ToTy::classof(Ctx->getKind()); } - const RecordMap &getObjCProtocols() const { - return ObjCProtocols; + static RecordContext *doCast(RecordContext *Ctx) { + return static_cast(Ctx); } - const RecordMap &getMacros() const { return Macros; } - const RecordMap &getTypedefs() const { return Typedefs; } - - /// Finds the APIRecord for a given USR. - /// - /// \returns a pointer to the APIRecord associated with that USR or nullptr. - APIRecord *findRecordForUSR(StringRef USR) const; - - /// Generate and store the USR of declaration \p D. - /// - /// Note: The USR string is stored in and owned by Allocator. - /// - /// \returns a StringRef of the generated USR string. - StringRef recordUSR(const Decl *D); - - /// Generate and store the USR for a macro \p Name. - /// - /// Note: The USR string is stored in and owned by Allocator. - /// - /// \returns a StringRef to the generate USR string. - StringRef recordUSRForMacro(StringRef Name, SourceLocation SL, - const SourceManager &SM); - - /// Copy \p String into the Allocator in this APISet. - /// - /// \returns a StringRef of the copied string in APISet::Allocator. - StringRef copyString(StringRef String); +}; - APISet(const llvm::Triple &Target, Language Lang, - const std::string &ProductName) - : Target(Target), Lang(Lang), ProductName(ProductName) {} +} // namespace extractapi +} // namespace clang -private: - /// BumpPtrAllocator to store generated/copied strings. - /// - /// Note: The main use for this is being able to deduplicate strings. - llvm::BumpPtrAllocator StringAllocator; +// Implement APIRecord (and derived classes) to and from RecordContext +// conversions +namespace llvm { + +template +struct CastInfo<::clang::extractapi::RecordContext, FromTy *> + : public NullableValueCastFailed<::clang::extractapi::RecordContext *>, + public DefaultDoCastIfPossible< + ::clang::extractapi::RecordContext *, FromTy *, + CastInfo<::clang::extractapi::RecordContext, FromTy *>> { + static inline bool isPossible(FromTy *From) { + return ::clang::extractapi::ToRecordContextCastInfoWrapper< + FromTy>::isPossible(From); + } - const llvm::Triple Target; - const Language Lang; + static inline ::clang::extractapi::RecordContext *doCast(FromTy *From) { + return ::clang::extractapi::ToRecordContextCastInfoWrapper::doCast( + From); + } +}; - llvm::DenseMap USRBasedLookupTable; - RecordMap Namespaces; - RecordMap GlobalFunctions; - RecordMap GlobalFunctionTemplates; - RecordMap - GlobalFunctionTemplateSpecializations; - RecordMap GlobalVariables; - RecordMap GlobalVariableTemplates; - RecordMap - GlobalVariableTemplateSpecializations; - RecordMap - GlobalVariableTemplatePartialSpecializations; - RecordMap Concepts; - RecordMap StaticFields; - RecordMap Enums; - RecordMap Records; - RecordMap CXXClasses; - RecordMap CXXFields; - RecordMap CXXMethods; - RecordMap CXXInstanceMethods; - RecordMap CXXStaticMethods; - RecordMap CXXMethodTemplates; - RecordMap - CXXMethodTemplateSpecializations; - RecordMap CXXFieldTemplates; - RecordMap ClassTemplates; - RecordMap ClassTemplateSpecializations; - RecordMap - ClassTemplatePartialSpecializations; - RecordMap ObjCCategories; - RecordMap ObjCInterfaces; - RecordMap ObjCProtocols; - RecordMap Macros; - RecordMap Typedefs; +template +struct CastInfo<::clang::extractapi::RecordContext, const FromTy *> + : public ConstStrippingForwardingCast< + ::clang::extractapi::RecordContext, const FromTy *, + CastInfo<::clang::extractapi::RecordContext, FromTy *>> {}; + +template +struct CastInfo + : public NullableValueCastFailed, + public DefaultDoCastIfPossible< + ToTy *, ::clang::extractapi::RecordContext *, + CastInfo> { + static inline bool isPossible(::clang::extractapi::RecordContext *Ctx) { + return ::clang::extractapi::FromRecordContextCastInfoWrapper< + ToTy>::isPossible(Ctx); + } -public: - const std::string ProductName; + static inline ToTy *doCast(::clang::extractapi::RecordContext *Ctx) { + return ::clang::extractapi::FromRecordContextCastInfoWrapper::doCast( + Ctx); + } }; -} // namespace extractapi -} // namespace clang +template +struct CastInfo + : public ConstStrippingForwardingCast< + ToTy, const ::clang::extractapi::RecordContext *, + CastInfo> {}; + +} // namespace llvm #endif // LLVM_CLANG_EXTRACTAPI_API_H diff --git a/clang/include/clang/ExtractAPI/APIRecords.inc b/clang/include/clang/ExtractAPI/APIRecords.inc new file mode 100644 index 0000000000000000000000000000000000000000..15fee809656d9a4b5e50ba7b1f8c2ff88978128e --- /dev/null +++ b/clang/include/clang/ExtractAPI/APIRecords.inc @@ -0,0 +1,103 @@ +//===- ExtractAPI/APIRecords.inc --------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file defines the classes defined from ExtractAPI's APIRecord +/// +//===----------------------------------------------------------------------===// + +#ifndef ABSTRACT_RECORD +#define ABSTRACT_RECORD(CLASS, BASE) RECORD(CLASS, BASE) +#endif +#ifndef CONCRETE_RECORD +#define CONCRETE_RECORD(CLASS, BASE, KIND) RECORD(CLASS, BASE) +#endif +#ifndef RECORD +#define RECORD(CLASS, BASE) +#endif + +CONCRETE_RECORD(NamespaceRecord, APIRecord, RK_Namespace) +CONCRETE_RECORD(GlobalFunctionRecord, APIRecord, RK_GlobalFunction) +CONCRETE_RECORD(GlobalFunctionTemplateRecord, GlobalFunctionRecord, + RK_GlobalFunctionTemplate) +CONCRETE_RECORD(GlobalFunctionTemplateSpecializationRecord, + GlobalFunctionRecord, RK_GlobalFunctionTemplateSpecialization) +CONCRETE_RECORD(GlobalVariableRecord, APIRecord, RK_GlobalVariable) +CONCRETE_RECORD(GlobalVariableTemplateRecord, GlobalVariableRecord, + RK_GlobalVariableTemplate) +CONCRETE_RECORD(GlobalVariableTemplateSpecializationRecord, + GlobalVariableRecord, RK_GlobalVariableTemplateSpecialization) +CONCRETE_RECORD(GlobalVariableTemplatePartialSpecializationRecord, + GlobalVariableRecord, + RK_GlobalVariableTemplatePartialSpecialization) +CONCRETE_RECORD(EnumConstantRecord, APIRecord, RK_EnumConstant) +CONCRETE_RECORD(EnumRecord, APIRecord, RK_Enum) +ABSTRACT_RECORD(RecordFieldRecord, APIRecord) +ABSTRACT_RECORD(RecordRecord, APIRecord) +CONCRETE_RECORD(StructFieldRecord, RecordFieldRecord, RK_StructField) +CONCRETE_RECORD(StructRecord, APIRecord, RK_Struct) +CONCRETE_RECORD(UnionFieldRecord, RecordFieldRecord, RK_UnionField) +CONCRETE_RECORD(UnionRecord, APIRecord, RK_Union) +CONCRETE_RECORD(CXXFieldRecord, APIRecord, RK_CXXField) +CONCRETE_RECORD(CXXFieldTemplateRecord, CXXFieldRecord, RK_CXXFieldTemplate) +ABSTRACT_RECORD(CXXMethodRecord, APIRecord) +CONCRETE_RECORD(CXXConstructorRecord, CXXMethodRecord, RK_CXXConstructorMethod) +CONCRETE_RECORD(CXXDestructorRecord, CXXMethodRecord, RK_CXXDestructorMethod) +CONCRETE_RECORD(CXXStaticMethodRecord, CXXMethodRecord, RK_CXXStaticMethod) +CONCRETE_RECORD(CXXInstanceMethodRecord, CXXMethodRecord, RK_CXXInstanceMethod) +CONCRETE_RECORD(CXXMethodTemplateRecord, CXXMethodRecord, RK_CXXMethodTemplate) +CONCRETE_RECORD(CXXMethodTemplateSpecializationRecord, CXXMethodRecord, + RK_CXXMethodTemplateSpecialization) +ABSTRACT_RECORD(ObjCPropertyRecord, APIRecord) +CONCRETE_RECORD(ObjCInstancePropertyRecord, ObjCPropertyRecord, + RK_ObjCInstanceProperty) +CONCRETE_RECORD(ObjCClassPropertyRecord, ObjCPropertyRecord, + RK_ObjCClassProperty) +CONCRETE_RECORD(ObjCInstanceVariableRecord, APIRecord, RK_ObjCIvar) +ABSTRACT_RECORD(ObjCMethodRecord, APIRecord) +CONCRETE_RECORD(ObjCInstanceMethodRecord, ObjCMethodRecord, + RK_ObjCInstanceMethod) +CONCRETE_RECORD(ObjCClassMethodRecord, ObjCMethodRecord, RK_ObjCClassMethod) +CONCRETE_RECORD(StaticFieldRecord, CXXFieldRecord, RK_StaticField) +ABSTRACT_RECORD(ObjCContainerRecord, APIRecord) +CONCRETE_RECORD(CXXClassRecord, APIRecord, RK_CXXClass) +CONCRETE_RECORD(ClassTemplateRecord, CXXClassRecord, RK_ClassTemplate) +CONCRETE_RECORD(ClassTemplateSpecializationRecord, CXXClassRecord, + RK_ClassTemplateSpecialization) +CONCRETE_RECORD(ClassTemplatePartialSpecializationRecord, CXXClassRecord, + RK_ClassTemplatePartialSpecialization) +CONCRETE_RECORD(ConceptRecord, APIRecord, RK_Concept) +CONCRETE_RECORD(ObjCCategoryRecord, ObjCContainerRecord, RK_ObjCCategory) +CONCRETE_RECORD(ObjCInterfaceRecord, ObjCContainerRecord, RK_ObjCInterface) +CONCRETE_RECORD(ObjCProtocolRecord, ObjCContainerRecord, RK_ObjCProtocol) +CONCRETE_RECORD(MacroDefinitionRecord, APIRecord, RK_MacroDefinition) +CONCRETE_RECORD(TypedefRecord, APIRecord, RK_Typedef) + +#undef CONCRETE_RECORD +#undef ABSTRACT_RECORD +#undef RECORD + +#ifndef RECORD_CONTEXT +#define RECORD_CONTEXT(CLASS, KIND) +#endif + +RECORD_CONTEXT(NamespaceRecord, RK_Namespace) +RECORD_CONTEXT(EnumRecord, RK_Enum) +RECORD_CONTEXT(StructRecord, RK_Struct) +RECORD_CONTEXT(UnionRecord, RK_Union) +RECORD_CONTEXT(ObjCCategoryRecord, RK_ObjCCategory) +RECORD_CONTEXT(ObjCInterfaceRecord, RK_ObjCInterface) +RECORD_CONTEXT(ObjCProtocolRecord, RK_ObjCProtocol) +RECORD_CONTEXT(CXXClassRecord, RK_CXXClass) +RECORD_CONTEXT(ClassTemplateRecord, RK_ClassTemplate) +RECORD_CONTEXT(ClassTemplateSpecializationRecord, + RK_ClassTemplateSpecialization) +RECORD_CONTEXT(ClassTemplatePartialSpecializationRecord, + RK_ClassTemplatePartialSpecialization) + +#undef RECORD_CONTEXT diff --git a/clang/include/clang/ExtractAPI/DeclarationFragments.h b/clang/include/clang/ExtractAPI/DeclarationFragments.h index b85a5d21d61217e2404c7c54bde6ed5f5d2f34e2..94392c185165951c39adad41cd402f83cd30119c 100644 --- a/clang/include/clang/ExtractAPI/DeclarationFragments.h +++ b/clang/include/clang/ExtractAPI/DeclarationFragments.h @@ -27,8 +27,6 @@ #include "clang/AST/TypeLoc.h" #include "clang/Basic/Specifiers.h" #include "clang/Lex/MacroInfo.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" #include namespace clang { @@ -182,6 +180,18 @@ public: /// appending to chain up consecutive appends. DeclarationFragments &appendSpace(); + /// Append a text Fragment of a semicolon character. + /// + /// \returns a reference to the DeclarationFragments object itself after + /// appending to chain up consecutive appends. + DeclarationFragments &appendSemicolon(); + + /// Removes a trailing semicolon character if present. + /// + /// \returns a reference to the DeclarationFragments object itself after + /// removing to chain up consecutive operations. + DeclarationFragments &removeTrailingSemicolon(); + /// Get the string description of a FragmentKind \p Kind. static StringRef getFragmentKindString(FragmentKind Kind); @@ -194,12 +204,14 @@ public: static DeclarationFragments getStructureTypeFragment(const RecordDecl *Decl); private: + DeclarationFragments &appendUnduplicatedTextCharacter(char Character); std::vector Fragments; }; class AccessControl { public: AccessControl(std::string Access) : Access(Access) {} + AccessControl() : Access("public") {} const std::string &getAccess() const { return Access; } @@ -315,13 +327,9 @@ public: static DeclarationFragments getFragmentsForTemplateParameters(ArrayRef); - static std::string - getNameForTemplateArgument(const ArrayRef, std::string); - - static DeclarationFragments - getFragmentsForTemplateArguments(const ArrayRef, - ASTContext &, - const std::optional>); + static DeclarationFragments getFragmentsForTemplateArguments( + const ArrayRef, ASTContext &, + const std::optional>); static DeclarationFragments getFragmentsForConcept(const ConceptDecl *); @@ -430,12 +438,7 @@ DeclarationFragmentsBuilder::getFunctionSignature(const FunctionT *Function) { if (isa(Function) && dyn_cast(Function)->getDescribedFunctionTemplate() && StringRef(ReturnType.begin()->Spelling).starts_with("type-parameter")) { - std::string ProperArgName = - getNameForTemplateArgument(dyn_cast(Function) - ->getDescribedFunctionTemplate() - ->getTemplateParameters() - ->asArray(), - ReturnType.begin()->Spelling); + std::string ProperArgName = Function->getReturnType().getAsString(); ReturnType.begin()->Spelling.swap(ProperArgName); } ReturnType.append(std::move(After)); diff --git a/clang/include/clang/ExtractAPI/ExtractAPIActionBase.h b/clang/include/clang/ExtractAPI/ExtractAPIActionBase.h index ac4f391db5f14a2e0a406008c05d96ab85de0b3b..08210a7ee05954f2efbc308c4899d950855b7614 100644 --- a/clang/include/clang/ExtractAPI/ExtractAPIActionBase.h +++ b/clang/include/clang/ExtractAPI/ExtractAPIActionBase.h @@ -17,6 +17,8 @@ #include "clang/ExtractAPI/API.h" #include "clang/ExtractAPI/APIIgnoresList.h" +#include "clang/Frontend/CompilerInstance.h" +#include "llvm/Support/raw_ostream.h" namespace clang { @@ -29,8 +31,8 @@ protected: /// A representation of the APIs this action extracts. std::unique_ptr API; - /// A stream to the output file of this action. - std::unique_ptr OS; + /// A stream to the main output file of this action. + std::unique_ptr OS; /// The product this action is extracting API information for. std::string ProductName; @@ -46,7 +48,7 @@ protected: /// /// Use the serializer to generate output symbol graph files from /// the information gathered during the execution of Action. - void ImplEndSourceFileAction(); + void ImplEndSourceFileAction(CompilerInstance &CI); }; } // namespace clang diff --git a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h index e1c3e41c750d40d341c0a024196a4aa3ec20a601..4cb866892b5d00d10c7a3f70c2174b35f103563b 100644 --- a/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h +++ b/clang/include/clang/ExtractAPI/ExtractAPIVisitor.h @@ -14,23 +14,23 @@ #ifndef LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H #define LLVM_CLANG_EXTRACTAPI_EXTRACT_API_VISITOR_H -#include "clang/AST/Availability.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" -#include "clang/Basic/OperatorKinds.h" -#include "clang/Basic/Specifiers.h" -#include "clang/ExtractAPI/DeclarationFragments.h" -#include "llvm/ADT/FunctionExtras.h" - -#include "clang/AST/ASTContext.h" #include "clang/AST/ParentMapContext.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/Module.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/Specifiers.h" #include "clang/ExtractAPI/API.h" +#include "clang/ExtractAPI/DeclarationFragments.h" #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" #include "clang/Index/USRGeneration.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Casting.h" #include namespace clang { @@ -130,12 +130,6 @@ protected: void recordEnumConstants(EnumRecord *EnumRecord, const EnumDecl::enumerator_range Constants); - /// Collect API information for the record fields and associate with the - /// parent struct. - void recordRecordFields(RecordRecord *RecordRecord, - APIRecord::RecordKind FieldKind, - const RecordDecl::field_range Fields); - /// Collect API information for the Objective-C methods and associate with the /// parent container. void recordObjCMethods(ObjCContainerRecord *Container, @@ -172,6 +166,7 @@ private: return *static_cast(this); } +protected: SmallVector getBases(const CXXRecordDecl *Decl) { // FIXME: store AccessSpecifier given by inheritance SmallVector Bases; @@ -182,49 +177,54 @@ private: SymbolReference BaseClass; if (BaseSpecifier.getType().getTypePtr()->isTemplateTypeParmType()) { BaseClass.Name = API.copyString(BaseSpecifier.getType().getAsString()); - BaseClass.USR = API.recordUSR( - BaseSpecifier.getType()->getAs()->getDecl()); + if (auto *TTPTD = BaseSpecifier.getType() + ->getAs() + ->getDecl()) { + SmallString<128> USR; + index::generateUSRForDecl(TTPTD, USR); + BaseClass.USR = API.copyString(USR); + BaseClass.Source = API.copyString(getOwningModuleName(*TTPTD)); + } } else { - CXXRecordDecl *BaseClassDecl = - BaseSpecifier.getType().getTypePtr()->getAsCXXRecordDecl(); - BaseClass.Name = BaseClassDecl->getName(); - BaseClass.USR = API.recordUSR(BaseClassDecl); + BaseClass = createSymbolReferenceForDecl( + *BaseSpecifier.getType().getTypePtr()->getAsCXXRecordDecl()); } Bases.emplace_back(BaseClass); } return Bases; } - APIRecord *determineParentRecord(const DeclContext *Context) { - SmallString<128> ParentUSR; - if (Context->getDeclKind() == Decl::TranslationUnit) - return nullptr; + StringRef getOwningModuleName(const Decl &D) { + if (auto *OwningModule = D.getImportedOwningModule()) + return OwningModule->Name; - index::generateUSRForDecl(dyn_cast(Context), ParentUSR); + return {}; + } - APIRecord *Parent = API.findRecordForUSR(ParentUSR); - return Parent; + SymbolReference createHierarchyInformationForDecl(const Decl &D) { + const auto *Context = cast_if_present(D.getDeclContext()); + + if (!Context || isa(Context)) + return {}; + + return createSymbolReferenceForDecl(*Context); } -}; -template -static void modifyRecords(const T &Records, const StringRef &Name) { - for (const auto &Record : Records) { - if (Name == Record.second.get()->Name) { - auto &DeclFragment = Record.second->Declaration; - DeclFragment.insert(DeclFragment.begin(), " ", - DeclarationFragments::FragmentKind::Text); - DeclFragment.insert(DeclFragment.begin(), "typedef", - DeclarationFragments::FragmentKind::Keyword, "", - nullptr); - DeclFragment.insert(--DeclFragment.end(), " { ... } ", - DeclarationFragments::FragmentKind::Text); - DeclFragment.insert(--DeclFragment.end(), Name, - DeclarationFragments::FragmentKind::Identifier); - break; - } + SymbolReference createSymbolReferenceForDecl(const Decl &D) { + SmallString<128> USR; + index::generateUSRForDecl(&D, USR); + + APIRecord *Record = API.findRecordForUSR(USR); + if (Record) + return SymbolReference(Record); + + StringRef Name; + if (auto *ND = dyn_cast(&D)) + Name = ND->getName(); + + return API.createSymbolReference(Name, USR, getOwningModuleName(D)); } -} +}; template bool ExtractAPIVisitorBase::VisitVarDecl(const VarDecl *Decl) { @@ -251,7 +251,8 @@ bool ExtractAPIVisitorBase::VisitVarDecl(const VarDecl *Decl) { // Collect symbol information. StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); @@ -267,21 +268,17 @@ bool ExtractAPIVisitorBase::VisitVarDecl(const VarDecl *Decl) { DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); if (Decl->isStaticDataMember()) { - SymbolReference Context; - // getDeclContext() should return a RecordDecl since we - // are currently handling a static data member. - auto *Record = cast(Decl->getDeclContext()); - Context.Name = Record->getName(); - Context.USR = API.recordUSR(Record); auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl); - API.addStaticField(Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), - Linkage, Comment, Declaration, SubHeading, Context, - Access, isInSystemHeader(Decl)); + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, + SubHeading, Access, isInSystemHeader(Decl)); } else // Add the global variable record to the API set. - API.addGlobalVar(Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), - Linkage, Comment, Declaration, SubHeading, - isInSystemHeader(Decl)); + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, + SubHeading, isInSystemHeader(Decl)); return true; } @@ -304,7 +301,7 @@ bool ExtractAPIVisitorBase::VisitFunctionDecl( return true; } - // Skip templated functions. + // Skip templated functions that aren't processed here. switch (Decl->getTemplatedKind()) { case FunctionDecl::TK_NonTemplate: case FunctionDecl::TK_DependentNonTemplate: @@ -321,7 +318,8 @@ bool ExtractAPIVisitorBase::VisitFunctionDecl( // Collect symbol information. StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); @@ -337,18 +335,19 @@ bool ExtractAPIVisitorBase::VisitFunctionDecl( FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl); if (Decl->getTemplateSpecializationInfo()) - API.addGlobalFunctionTemplateSpecialization( - Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, - Comment, + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, DeclarationFragmentsBuilder:: getFragmentsForFunctionTemplateSpecialization(Decl), SubHeading, Signature, isInSystemHeader(Decl)); else // Add the function record to the API set. - API.addGlobalFunction( - Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, - Comment, DeclarationFragmentsBuilder::getFragmentsForFunction(Decl), - SubHeading, Signature, isInSystemHeader(Decl)); + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, + DeclarationFragmentsBuilder::getFragmentsForFunction(Decl), SubHeading, + Signature, isInSystemHeader(Decl)); return true; } @@ -368,7 +367,8 @@ bool ExtractAPIVisitorBase::VisitEnumDecl(const EnumDecl *Decl) { Name = QualifiedNameBuffer.str(); } - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -382,13 +382,13 @@ bool ExtractAPIVisitorBase::VisitEnumDecl(const EnumDecl *Decl) { DeclarationFragmentsBuilder::getFragmentsForEnum(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - EnumRecord *EnumRecord = API.addEnum( - API.copyString(Name), USR, Loc, AvailabilityInfo::createFromDecl(Decl), - Comment, Declaration, SubHeading, isInSystemHeader(Decl)); + auto *ER = API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, + isInSystemHeader(Decl)); // Now collect information about the enumerators in this enum. - getDerivedExtractAPIVisitor().recordEnumConstants(EnumRecord, - Decl->enumerators()); + getDerivedExtractAPIVisitor().recordEnumConstants(ER, Decl->enumerators()); return true; } @@ -476,13 +476,13 @@ bool ExtractAPIVisitorBase::WalkUpFromNamespaceDecl( template bool ExtractAPIVisitorBase::VisitNamespaceDecl( const NamespaceDecl *Decl) { - if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; if (Decl->isAnonymousNamespace()) return true; StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); @@ -497,10 +497,10 @@ bool ExtractAPIVisitorBase::VisitNamespaceDecl( DeclarationFragmentsBuilder::getFragmentsForNamespace(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - APIRecord *Parent = determineParentRecord(Decl->getDeclContext()); - API.addNamespace(Parent, Name, USR, Loc, - AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, - Declaration, SubHeading, isInSystemHeader(Decl)); + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, + SubHeading, isInSystemHeader(Decl)); return true; } @@ -509,14 +509,20 @@ template bool ExtractAPIVisitorBase::VisitRecordDecl(const RecordDecl *Decl) { if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; + + SmallString<128> QualifiedNameBuffer; // Collect symbol information. StringRef Name = Decl->getName(); if (Name.empty()) Name = getTypedefName(Decl); - if (Name.empty()) - return true; + if (Name.empty()) { + llvm::raw_svector_ostream OS(QualifiedNameBuffer); + Decl->printQualifiedName(OS); + Name = QualifiedNameBuffer.str(); + } - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -531,21 +537,16 @@ bool ExtractAPIVisitorBase::VisitRecordDecl(const RecordDecl *Decl) { DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - auto RecordKind = APIRecord::RK_Struct; - auto FieldRecordKind = APIRecord::RK_StructField; - - if (Decl->isUnion()) { - RecordKind = APIRecord::RK_Union; - FieldRecordKind = APIRecord::RK_UnionField; - } - - RecordRecord *RecordRecord = API.addRecord( - Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, - Declaration, SubHeading, RecordKind, isInSystemHeader(Decl)); - - // Now collect information about the fields in this struct. - getDerivedExtractAPIVisitor().recordRecordFields( - RecordRecord, FieldRecordKind, Decl->fields()); + if (Decl->isUnion()) + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, + SubHeading, isInSystemHeader(Decl)); + else + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, + SubHeading, isInSystemHeader(Decl)); return true; } @@ -558,7 +559,8 @@ bool ExtractAPIVisitorBase::VisitCXXRecordDecl( return true; StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -580,24 +582,25 @@ bool ExtractAPIVisitorBase::VisitCXXRecordDecl( Kind = APIRecord::RecordKind::RK_CXXClass; auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl); - APIRecord *Parent = determineParentRecord(Decl->getDeclContext()); - CXXClassRecord *CXXClassRecord; + CXXClassRecord *Record; if (Decl->getDescribedClassTemplate()) { // Inject template fragments before class fragments. Declaration.insert( Declaration.begin(), DeclarationFragmentsBuilder::getFragmentsForRedeclarableTemplate( Decl->getDescribedClassTemplate())); - CXXClassRecord = API.addClassTemplate( - Parent, Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, - Declaration, SubHeading, Template(Decl->getDescribedClassTemplate()), - Access, isInSystemHeader(Decl)); + Record = API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, + SubHeading, Template(Decl->getDescribedClassTemplate()), Access, + isInSystemHeader(Decl)); } else - CXXClassRecord = API.addCXXClass( - Parent, Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, - Declaration, SubHeading, Kind, Access, isInSystemHeader(Decl)); + Record = API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, + SubHeading, Kind, Access, isInSystemHeader(Decl)); - CXXClassRecord->Bases = getBases(Decl); + Record->Bases = getBases(Decl); return true; } @@ -614,7 +617,8 @@ bool ExtractAPIVisitorBase::VisitCXXMethodDecl( if (isa(Decl) || isa(Decl)) return true; - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -627,14 +631,10 @@ bool ExtractAPIVisitorBase::VisitCXXMethodDecl( auto Access = DeclarationFragmentsBuilder::getAccessControl(Decl); auto Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl); - SmallString<128> ParentUSR; - index::generateUSRForDecl(dyn_cast(Decl->getDeclContext()), - ParentUSR); - auto *Parent = API.findRecordForUSR(ParentUSR); - if (Decl->isTemplated()) { - FunctionTemplateDecl *TemplateDecl = Decl->getDescribedFunctionTemplate(); - API.addCXXMethodTemplate( - API.findRecordForUSR(ParentUSR), Decl->getName(), USR, Loc, + if (FunctionTemplateDecl *TemplateDecl = + Decl->getDescribedFunctionTemplate()) { + API.createRecord( + USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate( TemplateDecl), @@ -642,27 +642,27 @@ bool ExtractAPIVisitorBase::VisitCXXMethodDecl( DeclarationFragmentsBuilder::getAccessControl(TemplateDecl), Template(TemplateDecl), isInSystemHeader(Decl)); } else if (Decl->getTemplateSpecializationInfo()) - API.addCXXMethodTemplateSpec( - Parent, Decl->getName(), USR, Loc, + API.createRecord( + USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder:: getFragmentsForFunctionTemplateSpecialization(Decl), SubHeading, Signature, Access, isInSystemHeader(Decl)); else if (Decl->isOverloadedOperator()) - API.addCXXInstanceMethod( - Parent, API.copyString(Decl->getNameAsString()), USR, Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, + API.createRecord( + USR, Decl->getNameAsString(), createHierarchyInformationForDecl(*Decl), + Loc, AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder::getFragmentsForOverloadedOperator(Decl), SubHeading, Signature, Access, isInSystemHeader(Decl)); else if (Decl->isStatic()) - API.addCXXStaticMethod( - Parent, Decl->getName(), USR, Loc, + API.createRecord( + USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading, Signature, Access, isInSystemHeader(Decl)); else - API.addCXXInstanceMethod( - Parent, Decl->getName(), USR, Loc, + API.createRecord( + USR, Decl->getName(), createHierarchyInformationForDecl(*Decl), Loc, AvailabilityInfo::createFromDecl(Decl), Comment, DeclarationFragmentsBuilder::getFragmentsForCXXMethod(Decl), SubHeading, Signature, Access, isInSystemHeader(Decl)); @@ -673,9 +673,13 @@ bool ExtractAPIVisitorBase::VisitCXXMethodDecl( template bool ExtractAPIVisitorBase::VisitCXXConstructorDecl( const CXXConstructorDecl *Decl) { + if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) || + Decl->isImplicit()) + return true; - StringRef Name = API.copyString(Decl->getNameAsString()); - StringRef USR = API.recordUSR(Decl); + auto Name = Decl->getNameAsString(); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -692,22 +696,24 @@ bool ExtractAPIVisitorBase::VisitCXXConstructorDecl( FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl); AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl); - SmallString<128> ParentUSR; - index::generateUSRForDecl(dyn_cast(Decl->getDeclContext()), - ParentUSR); - API.addCXXInstanceMethod(API.findRecordForUSR(ParentUSR), Name, USR, Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, - Declaration, SubHeading, Signature, Access, - isInSystemHeader(Decl)); + + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, + Signature, Access, isInSystemHeader(Decl)); return true; } template bool ExtractAPIVisitorBase::VisitCXXDestructorDecl( const CXXDestructorDecl *Decl) { + if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) || + Decl->isImplicit()) + return true; - StringRef Name = API.copyString(Decl->getNameAsString()); - StringRef USR = API.recordUSR(Decl); + auto Name = Decl->getNameAsString(); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -724,13 +730,10 @@ bool ExtractAPIVisitorBase::VisitCXXDestructorDecl( FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature(Decl); AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl); - SmallString<128> ParentUSR; - index::generateUSRForDecl(dyn_cast(Decl->getDeclContext()), - ParentUSR); - API.addCXXInstanceMethod(API.findRecordForUSR(ParentUSR), Name, USR, Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, - Declaration, SubHeading, Signature, Access, - isInSystemHeader(Decl)); + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, + Signature, Access, isInSystemHeader(Decl)); return true; } @@ -740,7 +743,8 @@ bool ExtractAPIVisitorBase::VisitConceptDecl(const ConceptDecl *Decl) { return true; StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -752,9 +756,10 @@ bool ExtractAPIVisitorBase::VisitConceptDecl(const ConceptDecl *Decl) { DeclarationFragmentsBuilder::getFragmentsForConcept(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - API.addConcept(Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), - Comment, Declaration, SubHeading, Template(Decl), - isInSystemHeader(Decl)); + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, + Template(Decl), isInSystemHeader(Decl)); return true; } @@ -765,7 +770,8 @@ bool ExtractAPIVisitorBase::VisitClassTemplateSpecializationDecl( return true; StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -779,14 +785,13 @@ bool ExtractAPIVisitorBase::VisitClassTemplateSpecializationDecl( DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - APIRecord *Parent = determineParentRecord(Decl->getDeclContext()); - auto *ClassTemplateSpecializationRecord = API.addClassTemplateSpecialization( - Parent, Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, - Declaration, SubHeading, + auto *CTSR = API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, DeclarationFragmentsBuilder::getAccessControl(Decl), isInSystemHeader(Decl)); - ClassTemplateSpecializationRecord->Bases = getBases(Decl); + CTSR->Bases = getBases(Decl); return true; } @@ -799,7 +804,8 @@ bool ExtractAPIVisitorBase:: return true; StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -811,15 +817,13 @@ bool ExtractAPIVisitorBase:: getFragmentsForClassTemplatePartialSpecialization(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - APIRecord *Parent = determineParentRecord(Decl->getDeclContext()); - auto *ClassTemplatePartialSpecRecord = - API.addClassTemplatePartialSpecialization( - Parent, Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), - Comment, Declaration, SubHeading, Template(Decl), - DeclarationFragmentsBuilder::getAccessControl(Decl), - isInSystemHeader(Decl)); + auto *CTPSR = API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, + Template(Decl), DeclarationFragmentsBuilder::getAccessControl(Decl), + isInSystemHeader(Decl)); - ClassTemplatePartialSpecRecord->Bases = getBases(Decl); + CTPSR->Bases = getBases(Decl); return true; } @@ -832,7 +836,8 @@ bool ExtractAPIVisitorBase::VisitVarTemplateDecl( // Collect symbol information. StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); @@ -853,20 +858,17 @@ bool ExtractAPIVisitorBase::VisitVarTemplateDecl( DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - SmallString<128> ParentUSR; - index::generateUSRForDecl(dyn_cast(Decl->getDeclContext()), - ParentUSR); if (Decl->getDeclContext()->getDeclKind() == Decl::CXXRecord) - API.addCXXFieldTemplate(API.findRecordForUSR(ParentUSR), Name, USR, Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, - Declaration, SubHeading, - DeclarationFragmentsBuilder::getAccessControl(Decl), - Template(Decl), isInSystemHeader(Decl)); + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, + SubHeading, DeclarationFragmentsBuilder::getAccessControl(Decl), + Template(Decl), isInSystemHeader(Decl)); else - API.addGlobalVariableTemplate(Name, USR, Loc, - AvailabilityInfo::createFromDecl(Decl), - Linkage, Comment, Declaration, SubHeading, - Template(Decl), isInSystemHeader(Decl)); + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, + SubHeading, Template(Decl), isInSystemHeader(Decl)); return true; } @@ -878,7 +880,8 @@ bool ExtractAPIVisitorBase::VisitVarTemplateSpecializationDecl( // Collect symbol information. StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); @@ -894,9 +897,10 @@ bool ExtractAPIVisitorBase::VisitVarTemplateSpecializationDecl( Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - API.addGlobalVariableTemplateSpecialization( - Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, - Declaration, SubHeading, isInSystemHeader(Decl)); + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, + SubHeading, isInSystemHeader(Decl)); return true; } @@ -908,7 +912,8 @@ bool ExtractAPIVisitorBase::VisitVarTemplatePartialSpecializationDecl( // Collect symbol information. StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); @@ -923,9 +928,10 @@ bool ExtractAPIVisitorBase::VisitVarTemplatePartialSpecializationDecl( getFragmentsForVarTemplatePartialSpecialization(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - API.addGlobalVariableTemplatePartialSpecialization( - Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, - Declaration, SubHeading, Template(Decl), isInSystemHeader(Decl)); + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, + SubHeading, Template(Decl), isInSystemHeader(Decl)); return true; } @@ -939,7 +945,8 @@ bool ExtractAPIVisitorBase::VisitFunctionTemplateDecl( // Collect symbol information. StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); @@ -954,8 +961,9 @@ bool ExtractAPIVisitorBase::VisitFunctionTemplateDecl( FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature( Decl->getTemplatedDecl()); - API.addGlobalFunctionTemplate( - Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, DeclarationFragmentsBuilder::getFragmentsForFunctionTemplate(Decl), SubHeading, Signature, Template(Decl), isInSystemHeader(Decl)); @@ -970,7 +978,8 @@ bool ExtractAPIVisitorBase::VisitObjCInterfaceDecl( // Collect symbol information. StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); LinkageInfo Linkage = Decl->getLinkageAndVisibility(); @@ -988,24 +997,23 @@ bool ExtractAPIVisitorBase::VisitObjCInterfaceDecl( // Collect super class information. SymbolReference SuperClass; - if (const auto *SuperClassDecl = Decl->getSuperClass()) { - SuperClass.Name = SuperClassDecl->getObjCRuntimeNameAsString(); - SuperClass.USR = API.recordUSR(SuperClassDecl); - } + if (const auto *SuperClassDecl = Decl->getSuperClass()) + SuperClass = createSymbolReferenceForDecl(*SuperClassDecl); - ObjCInterfaceRecord *ObjCInterfaceRecord = API.addObjCInterface( - Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, - Declaration, SubHeading, SuperClass, isInSystemHeader(Decl)); + auto *InterfaceRecord = API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Linkage, Comment, Declaration, + SubHeading, SuperClass, isInSystemHeader(Decl)); // Record all methods (selectors). This doesn't include automatically // synthesized property methods. - getDerivedExtractAPIVisitor().recordObjCMethods(ObjCInterfaceRecord, + getDerivedExtractAPIVisitor().recordObjCMethods(InterfaceRecord, Decl->methods()); - getDerivedExtractAPIVisitor().recordObjCProperties(ObjCInterfaceRecord, + getDerivedExtractAPIVisitor().recordObjCProperties(InterfaceRecord, Decl->properties()); - getDerivedExtractAPIVisitor().recordObjCInstanceVariables(ObjCInterfaceRecord, + getDerivedExtractAPIVisitor().recordObjCInstanceVariables(InterfaceRecord, Decl->ivars()); - getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCInterfaceRecord, + getDerivedExtractAPIVisitor().recordObjCProtocols(InterfaceRecord, Decl->protocols()); return true; @@ -1019,7 +1027,8 @@ bool ExtractAPIVisitorBase::VisitObjCProtocolDecl( // Collect symbol information. StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -1034,15 +1043,15 @@ bool ExtractAPIVisitorBase::VisitObjCProtocolDecl( DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - ObjCProtocolRecord *ObjCProtocolRecord = API.addObjCProtocol( - Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, - Declaration, SubHeading, isInSystemHeader(Decl)); + auto *ProtoRecord = API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, + isInSystemHeader(Decl)); - getDerivedExtractAPIVisitor().recordObjCMethods(ObjCProtocolRecord, - Decl->methods()); - getDerivedExtractAPIVisitor().recordObjCProperties(ObjCProtocolRecord, + getDerivedExtractAPIVisitor().recordObjCMethods(ProtoRecord, Decl->methods()); + getDerivedExtractAPIVisitor().recordObjCProperties(ProtoRecord, Decl->properties()); - getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCProtocolRecord, + getDerivedExtractAPIVisitor().recordObjCProtocols(ProtoRecord, Decl->protocols()); return true; @@ -1061,25 +1070,36 @@ bool ExtractAPIVisitorBase::VisitTypedefNameDecl( if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; - // Add the notion of typedef for tag type (struct or enum) of the same name. - if (const ElaboratedType *ET = - dyn_cast(Decl->getUnderlyingType())) { - if (const TagType *TagTy = dyn_cast(ET->desugar())) { - if (Decl->getName() == TagTy->getDecl()->getName()) { - if (isa(TagTy->getDecl())) { - modifyRecords(API.getRecords(), Decl->getName()); - } - if (TagTy->getDecl()->isEnum()) { - modifyRecords(API.getEnums(), Decl->getName()); - } + StringRef Name = Decl->getName(); + + // If the underlying type was defined as part of the typedef modify it's + // fragments directly and pretend the typedef doesn't exist. + if (auto *TagDecl = Decl->getUnderlyingType()->getAsTagDecl()) { + if (TagDecl->getName() == Decl->getName() && + TagDecl->isEmbeddedInDeclarator() && TagDecl->isCompleteDefinition()) { + SmallString<128> TagUSR; + index::generateUSRForDecl(TagDecl, TagUSR); + if (auto *Record = API.findRecordForUSR(TagUSR)) { + DeclarationFragments LeadingFragments; + LeadingFragments.append("typedef", + DeclarationFragments::FragmentKind::Keyword, "", + nullptr); + LeadingFragments.appendSpace(); + Record->Declaration.removeTrailingSemicolon() + .insert(Record->Declaration.begin(), std::move(LeadingFragments)) + .append(" { ... } ", DeclarationFragments::FragmentKind::Text) + .append(Name, DeclarationFragments::FragmentKind::Identifier) + .appendSemicolon(); + + return true; } } } PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); - StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); DocComment Comment; if (auto *RawComment = getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Decl)) @@ -1091,11 +1111,12 @@ bool ExtractAPIVisitorBase::VisitTypedefNameDecl( TypedefUnderlyingTypeResolver(Context).getSymbolReferenceForType(Type, API); - API.addTypedef(Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), - Comment, - DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl), - DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef, - isInSystemHeader(Decl)); + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, + DeclarationFragmentsBuilder::getFragmentsForTypedef(Decl), + DeclarationFragmentsBuilder::getSubHeading(Decl), SymRef, + isInSystemHeader(Decl)); return true; } @@ -1107,7 +1128,8 @@ bool ExtractAPIVisitorBase::VisitObjCCategoryDecl( return true; StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -1122,29 +1144,20 @@ bool ExtractAPIVisitorBase::VisitObjCCategoryDecl( DeclarationFragmentsBuilder::getSubHeading(Decl); const ObjCInterfaceDecl *InterfaceDecl = Decl->getClassInterface(); - SymbolReference Interface(InterfaceDecl->getName(), - API.recordUSR(InterfaceDecl)); - - bool IsFromExternalModule = true; - for (const auto &Interface : API.getObjCInterfaces()) { - if (InterfaceDecl->getName() == Interface.second.get()->Name) { - IsFromExternalModule = false; - break; - } - } + SymbolReference Interface = createSymbolReferenceForDecl(*InterfaceDecl); - ObjCCategoryRecord *ObjCCategoryRecord = API.addObjCCategory( - Name, USR, Loc, AvailabilityInfo::createFromDecl(Decl), Comment, - Declaration, SubHeading, Interface, isInSystemHeader(Decl), - IsFromExternalModule); + auto *CategoryRecord = API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, SubHeading, + Interface, isInSystemHeader(Decl)); - getDerivedExtractAPIVisitor().recordObjCMethods(ObjCCategoryRecord, + getDerivedExtractAPIVisitor().recordObjCMethods(CategoryRecord, Decl->methods()); - getDerivedExtractAPIVisitor().recordObjCProperties(ObjCCategoryRecord, + getDerivedExtractAPIVisitor().recordObjCProperties(CategoryRecord, Decl->properties()); - getDerivedExtractAPIVisitor().recordObjCInstanceVariables(ObjCCategoryRecord, + getDerivedExtractAPIVisitor().recordObjCInstanceVariables(CategoryRecord, Decl->ivars()); - getDerivedExtractAPIVisitor().recordObjCProtocols(ObjCCategoryRecord, + getDerivedExtractAPIVisitor().recordObjCProtocols(CategoryRecord, Decl->protocols()); return true; @@ -1158,7 +1171,8 @@ void ExtractAPIVisitorBase::recordEnumConstants( for (const auto *Constant : Constants) { // Collect symbol information. StringRef Name = Constant->getName(); - StringRef USR = API.recordUSR(Constant); + SmallString<128> USR; + index::generateUSRForDecl(Constant, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Constant->getLocation()); DocComment Comment; @@ -1173,51 +1187,26 @@ void ExtractAPIVisitorBase::recordEnumConstants( DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Constant); - API.addEnumConstant(EnumRecord, Name, USR, Loc, - AvailabilityInfo::createFromDecl(Constant), Comment, - Declaration, SubHeading, isInSystemHeader(Constant)); - } -} - -/// Collect API information for the struct fields and associate with the -/// parent struct. -template -void ExtractAPIVisitorBase::recordRecordFields( - RecordRecord *RecordRecord, APIRecord::RecordKind FieldKind, - const RecordDecl::field_range Fields) { - for (const auto *Field : Fields) { - // Collect symbol information. - StringRef Name = Field->getName(); - StringRef USR = API.recordUSR(Field); - PresumedLoc Loc = - Context.getSourceManager().getPresumedLoc(Field->getLocation()); - DocComment Comment; - if (auto *RawComment = - getDerivedExtractAPIVisitor().fetchRawCommentForDecl(Field)) - Comment = RawComment->getFormattedLines(Context.getSourceManager(), - Context.getDiagnostics()); - - // Build declaration fragments and sub-heading for the struct field. - DeclarationFragments Declaration = - DeclarationFragmentsBuilder::getFragmentsForField(Field); - DeclarationFragments SubHeading = - DeclarationFragmentsBuilder::getSubHeading(Field); - - API.addRecordField( - RecordRecord, Name, USR, Loc, AvailabilityInfo::createFromDecl(Field), - Comment, Declaration, SubHeading, FieldKind, isInSystemHeader(Field)); + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Constant), Loc, + AvailabilityInfo::createFromDecl(Constant), Comment, Declaration, + SubHeading, isInSystemHeader(Constant)); } } template bool ExtractAPIVisitorBase::VisitFieldDecl(const FieldDecl *Decl) { - if (Decl->getDeclContext()->getDeclKind() == Decl::Record) + // ObjCIvars are handled separately + if (isa(Decl) || isa(Decl)) return true; - if (isa(Decl)) + + if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl)) return true; + // Collect symbol information. StringRef Name = Decl->getName(); - StringRef USR = API.recordUSR(Decl); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -1231,22 +1220,40 @@ bool ExtractAPIVisitorBase::VisitFieldDecl(const FieldDecl *Decl) { DeclarationFragmentsBuilder::getFragmentsForField(Decl); DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Decl); - AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl); - SmallString<128> ParentUSR; - index::generateUSRForDecl(dyn_cast(Decl->getDeclContext()), - ParentUSR); - API.addCXXField(API.findRecordForUSR(ParentUSR), Name, USR, Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, - SubHeading, Access, isInSystemHeader(Decl)); + if (isa(Decl->getDeclContext())) { + AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl); + + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, + SubHeading, Access, isInSystemHeader(Decl)); + } else if (auto *RD = dyn_cast(Decl->getDeclContext())) { + if (RD->isUnion()) + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, + SubHeading, isInSystemHeader(Decl)); + else + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, + SubHeading, isInSystemHeader(Decl)); + } + return true; } template bool ExtractAPIVisitorBase::VisitCXXConversionDecl( const CXXConversionDecl *Decl) { - StringRef Name = API.copyString(Decl->getNameAsString()); - StringRef USR = API.recordUSR(Decl); + if (!getDerivedExtractAPIVisitor().shouldDeclBeIncluded(Decl) || + Decl->isImplicit()) + return true; + + auto Name = Decl->getNameAsString(); + SmallString<128> USR; + index::generateUSRForDecl(Decl, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Decl->getLocation()); DocComment Comment; @@ -1264,19 +1271,17 @@ bool ExtractAPIVisitorBase::VisitCXXConversionDecl( DeclarationFragmentsBuilder::getFunctionSignature(Decl); AccessControl Access = DeclarationFragmentsBuilder::getAccessControl(Decl); - SmallString<128> ParentUSR; - index::generateUSRForDecl(dyn_cast(Decl->getDeclContext()), - ParentUSR); if (Decl->isStatic()) - API.addCXXStaticMethod(API.findRecordForUSR(ParentUSR), Name, USR, Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, - Declaration, SubHeading, Signature, Access, - isInSystemHeader(Decl)); + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, + SubHeading, Signature, Access, isInSystemHeader(Decl)); else - API.addCXXInstanceMethod(API.findRecordForUSR(ParentUSR), Name, USR, Loc, - AvailabilityInfo::createFromDecl(Decl), Comment, - Declaration, SubHeading, Signature, Access, - isInSystemHeader(Decl)); + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Decl), Loc, + AvailabilityInfo::createFromDecl(Decl), Comment, Declaration, + SubHeading, Signature, Access, isInSystemHeader(Decl)); + return true; } @@ -1291,8 +1296,9 @@ void ExtractAPIVisitorBase::recordObjCMethods( if (Method->isPropertyAccessor()) continue; - StringRef Name = API.copyString(Method->getSelector().getAsString()); - StringRef USR = API.recordUSR(Method); + auto Name = Method->getSelector().getAsString(); + SmallString<128> USR; + index::generateUSRForDecl(Method, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Method->getLocation()); DocComment Comment; @@ -1309,10 +1315,16 @@ void ExtractAPIVisitorBase::recordObjCMethods( FunctionSignature Signature = DeclarationFragmentsBuilder::getFunctionSignature(Method); - API.addObjCMethod(Container, Name, USR, Loc, - AvailabilityInfo::createFromDecl(Method), Comment, - Declaration, SubHeading, Signature, - Method->isInstanceMethod(), isInSystemHeader(Method)); + if (Method->isInstanceMethod()) + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Method), Loc, + AvailabilityInfo::createFromDecl(Method), Comment, Declaration, + SubHeading, Signature, isInSystemHeader(Method)); + else + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Method), Loc, + AvailabilityInfo::createFromDecl(Method), Comment, Declaration, + SubHeading, Signature, isInSystemHeader(Method)); } } @@ -1322,7 +1334,8 @@ void ExtractAPIVisitorBase::recordObjCProperties( const ObjCContainerDecl::prop_range Properties) { for (const auto *Property : Properties) { StringRef Name = Property->getName(); - StringRef USR = API.recordUSR(Property); + SmallString<128> USR; + index::generateUSRForDecl(Property, USR); PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Property->getLocation()); DocComment Comment; @@ -1337,10 +1350,8 @@ void ExtractAPIVisitorBase::recordObjCProperties( DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Property); - StringRef GetterName = - API.copyString(Property->getGetterName().getAsString()); - StringRef SetterName = - API.copyString(Property->getSetterName().getAsString()); + auto GetterName = Property->getGetterName().getAsString(); + auto SetterName = Property->getSetterName().getAsString(); // Get the attributes for property. unsigned Attributes = ObjCPropertyRecord::NoAttr; @@ -1348,14 +1359,22 @@ void ExtractAPIVisitorBase::recordObjCProperties( ObjCPropertyAttribute::kind_readonly) Attributes |= ObjCPropertyRecord::ReadOnly; - API.addObjCProperty( - Container, Name, USR, Loc, AvailabilityInfo::createFromDecl(Property), - Comment, Declaration, SubHeading, - static_cast(Attributes), GetterName, - SetterName, Property->isOptional(), - !(Property->getPropertyAttributes() & - ObjCPropertyAttribute::kind_class), - isInSystemHeader(Property)); + if (Property->getPropertyAttributes() & ObjCPropertyAttribute::kind_class) + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Property), Loc, + AvailabilityInfo::createFromDecl(Property), Comment, Declaration, + SubHeading, + static_cast(Attributes), + GetterName, SetterName, Property->isOptional(), + isInSystemHeader(Property)); + else + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Property), Loc, + AvailabilityInfo::createFromDecl(Property), Comment, Declaration, + SubHeading, + static_cast(Attributes), + GetterName, SetterName, Property->isOptional(), + isInSystemHeader(Property)); } } @@ -1367,7 +1386,9 @@ void ExtractAPIVisitorBase::recordObjCInstanceVariables( Ivars) { for (const auto *Ivar : Ivars) { StringRef Name = Ivar->getName(); - StringRef USR = API.recordUSR(Ivar); + SmallString<128> USR; + index::generateUSRForDecl(Ivar, USR); + PresumedLoc Loc = Context.getSourceManager().getPresumedLoc(Ivar->getLocation()); DocComment Comment; @@ -1382,12 +1403,10 @@ void ExtractAPIVisitorBase::recordObjCInstanceVariables( DeclarationFragments SubHeading = DeclarationFragmentsBuilder::getSubHeading(Ivar); - ObjCInstanceVariableRecord::AccessControl Access = - Ivar->getCanonicalAccessControl(); - - API.addObjCInstanceVariable( - Container, Name, USR, Loc, AvailabilityInfo::createFromDecl(Ivar), - Comment, Declaration, SubHeading, Access, isInSystemHeader(Ivar)); + API.createRecord( + USR, Name, createHierarchyInformationForDecl(*Ivar), Loc, + AvailabilityInfo::createFromDecl(Ivar), Comment, Declaration, + SubHeading, isInSystemHeader(Ivar)); } } @@ -1396,8 +1415,7 @@ void ExtractAPIVisitorBase::recordObjCProtocols( ObjCContainerRecord *Container, ObjCInterfaceDecl::protocol_range Protocols) { for (const auto *Protocol : Protocols) - Container->Protocols.emplace_back(Protocol->getName(), - API.recordUSR(Protocol)); + Container->Protocols.emplace_back(createSymbolReferenceForDecl(*Protocol)); } } // namespace impl diff --git a/clang/include/clang/ExtractAPI/FrontendActions.h b/clang/include/clang/ExtractAPI/FrontendActions.h index c67864aac9af9cc2255da641a732a6eba013246d..08045a30823db8c7a78ecc8fde07b4b5e9bf792d 100644 --- a/clang/include/clang/ExtractAPI/FrontendActions.h +++ b/clang/include/clang/ExtractAPI/FrontendActions.h @@ -49,9 +49,6 @@ private: void EndSourceFileAction() override; static StringRef getInputBufferName() { return ""; } - - static std::unique_ptr - CreateOutputFile(CompilerInstance &CI, StringRef InFile); }; /// Wrap ExtractAPIAction on top of a pre-existing action @@ -85,9 +82,6 @@ private: /// actions. This is the place where all the gathered symbol graph /// information is emited. void EndSourceFileAction() override; - - static std::unique_ptr - CreateOutputFile(CompilerInstance &CI, StringRef InFile); }; } // namespace clang diff --git a/clang/include/clang/ExtractAPI/Serialization/APISetVisitor.h b/clang/include/clang/ExtractAPI/Serialization/APISetVisitor.h new file mode 100644 index 0000000000000000000000000000000000000000..07f14f349f3dd762e1700441e5c6378b50b1e603 --- /dev/null +++ b/clang/include/clang/ExtractAPI/Serialization/APISetVisitor.h @@ -0,0 +1,172 @@ +//===- ExtractAPI/Serialization/APISetVisitor.h ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file defines the ExtractAPI APISetVisitor interface. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H +#define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H + +#include "clang/ExtractAPI/API.h" + +namespace clang { +namespace extractapi { + +// A helper macro to implement short-circuiting when recursing. It +// invokes CALL_EXPR, which must be a method call, on the derived +// object (s.t. a user of RecursiveASTVisitor can override the method +// in CALL_EXPR). +#define TRY_TO(CALL_EXPR) \ + do { \ + if (!getDerived()->CALL_EXPR) \ + return false; \ + } while (false) + +/// The base interface of visitors for API information, the interface and usage +/// is almost identical to RecurisveASTVistor. This class performs three +/// distinct tasks: +/// 1. traverse the APISet (i.e. go to every record); +/// 2. at a given record, walk up the class hierarchy starting from the record's +/// dynamic type until APIRecord is reached. +/// 3. given a (record, class) combination where 'class' is some base class of +/// the dynamic type of 'record', call a user-overridable function to actually +/// visit the record. +/// +/// These tasks are done by three groups of methods, respectively: +/// 1. traverseRecord(APIRecord *x) does task #1, it is the entry point for +/// traversing the records starting from x. This method simply forwards to +/// traverseFoo(Foo *x) where Foo is the dynamic type of *x, which calls +/// walkUpFromFoo(x) and then recursively visits the child records of x. +/// 2. walkUpFromFoo(Foo *x) does task #2. It doesn't visit children records of +/// x, instead it first calls walkUpFromBar(x) where Bar is the direct parent +/// class of Foo (unless Foo has no parent) and then calls visitFoo(x). +/// 3. visitFoo(Foo *x) does task #3. +/// +/// These three method groups are tiered (traverse* > walkUpFrom* > +/// visit*). A method (e.g. traverse*) may call methods from the same +/// tier (e.g. other traverse*) or one tier lower (e.g. walkUpFrom*). +/// It may not call methods from a higher tier. +/// +/// Note that since walkUpFromFoo() calls walkUpFromBar() (where Bar +/// is Foo's super class) before calling visitFoo(), the result is +/// that the visit*() methods for a given record are called in the +/// top-down order (e.g. for a record of type ObjCInstancePropertyRecord, the +/// order will be visitRecord(), visitObjCPropertyRecord(), and then +/// visitObjCInstancePropertyRecord()). +/// +/// This scheme guarantees that all visit*() calls for the same record +/// are grouped together. In other words, visit*() methods for different +/// records are never interleaved. +/// +/// Clients of this visitor should subclass the visitor (providing +/// themselves as the template argument, using the curiously recurring +/// template pattern) and override any of the traverse*, walkUpFrom*, +/// and visit* methods for records where the visitor should customize +/// behavior. Most users only need to override visit*. Advanced +/// users may override traverse* and walkUpFrom* to implement custom +/// traversal strategies. Returning false from one of these overridden +/// functions will abort the entire traversal. +template class APISetVisitor { +public: + bool traverseAPISet() { + for (const APIRecord *TLR : API.getTopLevelRecords()) { + TRY_TO(traverseAPIRecord(TLR)); + } + return true; + } + + bool traverseAPIRecord(const APIRecord *Record); + bool walkUpFromAPIRecord(const APIRecord *Record) { + TRY_TO(visitAPIRecord(Record)); + return true; + } + bool visitAPIRecord(const APIRecord *Record) { return true; } + +#define GENERATE_TRAVERSE_METHOD(CLASS, BASE) \ + bool traverse##CLASS(const CLASS *Record) { \ + TRY_TO(walkUpFrom##CLASS(Record)); \ + TRY_TO(traverseRecordContext(dyn_cast(Record))); \ + return true; \ + } + +#define GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE) \ + bool walkUpFrom##CLASS(const CLASS *Record) { \ + TRY_TO(walkUpFrom##BASE(Record)); \ + TRY_TO(visit##CLASS(Record)); \ + return true; \ + } \ + bool visit##CLASS(const CLASS *Record) { return true; } + +#define CONCRETE_RECORD(CLASS, BASE, KIND) \ + GENERATE_TRAVERSE_METHOD(CLASS, BASE) \ + GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE) + +#define ABSTRACT_RECORD(CLASS, BASE) \ + GENERATE_WALKUP_AND_VISIT_METHODS(CLASS, BASE) + +#include "../APIRecords.inc" + +#undef GENERATE_WALKUP_AND_VISIT_METHODS +#undef GENERATE_TRAVERSE_METHOD + + bool traverseRecordContext(const RecordContext *); + +protected: + const APISet &API; + +public: + APISetVisitor() = delete; + APISetVisitor(const APISetVisitor &) = delete; + APISetVisitor(APISetVisitor &&) = delete; + APISetVisitor &operator=(const APISetVisitor &) = delete; + APISetVisitor &operator=(APISetVisitor &&) = delete; + +protected: + APISetVisitor(const APISet &API) : API(API) {} + ~APISetVisitor() = default; + + Derived *getDerived() { return static_cast(this); }; +}; + +template +bool APISetVisitor::traverseRecordContext( + const RecordContext *Context) { + if (!Context) + return true; + + for (auto *Child : Context->records()) + TRY_TO(traverseAPIRecord(Child)); + + return true; +} + +template +bool APISetVisitor::traverseAPIRecord(const APIRecord *Record) { + switch (Record->getKind()) { +#define CONCRETE_RECORD(CLASS, BASE, KIND) \ + case APIRecord::KIND: { \ + TRY_TO(traverse##CLASS(static_cast(Record))); \ + break; \ + } +#include "../APIRecords.inc" + case APIRecord::RK_Unknown: { + TRY_TO(walkUpFromAPIRecord(static_cast(Record))); + break; + } + default: + llvm_unreachable("API Record with uninstantiable kind"); + } + return true; +} + +} // namespace extractapi +} // namespace clang + +#endif // LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H diff --git a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h deleted file mode 100644 index f0629a9ad56b033eb29cdee40f2e5e8241e39eae..0000000000000000000000000000000000000000 --- a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h +++ /dev/null @@ -1,314 +0,0 @@ -//===- ExtractAPI/Serialization/SerializerBase.h ----------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// This file defines the ExtractAPI APISetVisitor interface. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H -#define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H - -#include "clang/ExtractAPI/API.h" - -namespace clang { -namespace extractapi { - -/// The base interface of visitors for API information. -template class APISetVisitor { -public: - void traverseAPISet() { - getDerived()->traverseNamespaces(); - - getDerived()->traverseGlobalVariableRecords(); - - getDerived()->traverseGlobalFunctionRecords(); - - getDerived()->traverseEnumRecords(); - - getDerived()->traverseStaticFieldRecords(); - - getDerived()->traverseCXXClassRecords(); - - getDerived()->traverseClassTemplateRecords(); - - getDerived()->traverseClassTemplateSpecializationRecords(); - - getDerived()->traverseClassTemplatePartialSpecializationRecords(); - - getDerived()->traverseCXXInstanceMethods(); - - getDerived()->traverseCXXStaticMethods(); - - getDerived()->traverseCXXMethodTemplates(); - - getDerived()->traverseCXXMethodTemplateSpecializations(); - - getDerived()->traverseCXXFields(); - - getDerived()->traverseCXXFieldTemplates(); - - getDerived()->traverseConcepts(); - - getDerived()->traverseGlobalVariableTemplateRecords(); - - getDerived()->traverseGlobalVariableTemplateSpecializationRecords(); - - getDerived()->traverseGlobalVariableTemplatePartialSpecializationRecords(); - - getDerived()->traverseGlobalFunctionTemplateRecords(); - - getDerived()->traverseGlobalFunctionTemplateSpecializationRecords(); - - getDerived()->traverseRecordRecords(); - - getDerived()->traverseObjCInterfaces(); - - getDerived()->traverseObjCProtocols(); - - getDerived()->traverseObjCCategories(); - - getDerived()->traverseMacroDefinitionRecords(); - - getDerived()->traverseTypedefRecords(); - } - - void traverseNamespaces() { - for (const auto &Namespace : API.getNamespaces()) - getDerived()->visitNamespaceRecord(*Namespace.second); - } - - void traverseGlobalFunctionRecords() { - for (const auto &GlobalFunction : API.getGlobalFunctions()) - getDerived()->visitGlobalFunctionRecord(*GlobalFunction.second); - } - - void traverseGlobalVariableRecords() { - for (const auto &GlobalVariable : API.getGlobalVariables()) - getDerived()->visitGlobalVariableRecord(*GlobalVariable.second); - } - - void traverseEnumRecords() { - for (const auto &Enum : API.getEnums()) - getDerived()->visitEnumRecord(*Enum.second); - } - - void traverseRecordRecords() { - for (const auto &Record : API.getRecords()) - getDerived()->visitRecordRecord(*Record.second); - } - - void traverseStaticFieldRecords() { - for (const auto &StaticField : API.getStaticFields()) - getDerived()->visitStaticFieldRecord(*StaticField.second); - } - - void traverseCXXClassRecords() { - for (const auto &Class : API.getCXXClasses()) - getDerived()->visitCXXClassRecord(*Class.second); - } - - void traverseCXXMethodTemplates() { - for (const auto &MethodTemplate : API.getCXXMethodTemplates()) - getDerived()->visitMethodTemplateRecord(*MethodTemplate.second); - } - - void traverseCXXMethodTemplateSpecializations() { - for (const auto &MethodTemplateSpecialization : - API.getCXXMethodTemplateSpecializations()) - getDerived()->visitMethodTemplateSpecializationRecord( - *MethodTemplateSpecialization.second); - } - - void traverseClassTemplateRecords() { - for (const auto &ClassTemplate : API.getClassTemplates()) - getDerived()->visitClassTemplateRecord(*ClassTemplate.second); - } - - void traverseClassTemplateSpecializationRecords() { - for (const auto &ClassTemplateSpecialization : - API.getClassTemplateSpecializations()) - getDerived()->visitClassTemplateSpecializationRecord( - *ClassTemplateSpecialization.second); - } - - void traverseClassTemplatePartialSpecializationRecords() { - for (const auto &ClassTemplatePartialSpecialization : - API.getClassTemplatePartialSpecializations()) - getDerived()->visitClassTemplatePartialSpecializationRecord( - *ClassTemplatePartialSpecialization.second); - } - - void traverseCXXInstanceMethods() { - for (const auto &InstanceMethod : API.getCXXInstanceMethods()) - getDerived()->visitCXXInstanceMethodRecord(*InstanceMethod.second); - } - - void traverseCXXStaticMethods() { - for (const auto &InstanceMethod : API.getCXXStaticMethods()) - getDerived()->visitCXXStaticMethodRecord(*InstanceMethod.second); - } - - void traverseCXXFields() { - for (const auto &CXXField : API.getCXXFields()) - getDerived()->visitCXXFieldRecord(*CXXField.second); - } - - void traverseCXXFieldTemplates() { - for (const auto &CXXFieldTemplate : API.getCXXFieldTemplates()) - getDerived()->visitCXXFieldTemplateRecord(*CXXFieldTemplate.second); - } - - void traverseGlobalVariableTemplateRecords() { - for (const auto &GlobalVariableTemplate : API.getGlobalVariableTemplates()) - getDerived()->visitGlobalVariableTemplateRecord( - *GlobalVariableTemplate.second); - } - - void traverseGlobalVariableTemplateSpecializationRecords() { - for (const auto &GlobalVariableTemplateSpecialization : - API.getGlobalVariableTemplateSpecializations()) - getDerived()->visitGlobalVariableTemplateSpecializationRecord( - *GlobalVariableTemplateSpecialization.second); - } - - void traverseGlobalVariableTemplatePartialSpecializationRecords() { - for (const auto &GlobalVariableTemplatePartialSpecialization : - API.getGlobalVariableTemplatePartialSpecializations()) - getDerived()->visitGlobalVariableTemplatePartialSpecializationRecord( - *GlobalVariableTemplatePartialSpecialization.second); - } - - void traverseGlobalFunctionTemplateRecords() { - for (const auto &GlobalFunctionTemplate : API.getGlobalFunctionTemplates()) - getDerived()->visitGlobalFunctionTemplateRecord( - *GlobalFunctionTemplate.second); - } - - void traverseGlobalFunctionTemplateSpecializationRecords() { - for (const auto &GlobalFunctionTemplateSpecialization : - API.getGlobalFunctionTemplateSpecializations()) - getDerived()->visitGlobalFunctionTemplateSpecializationRecord( - *GlobalFunctionTemplateSpecialization.second); - } - - void traverseConcepts() { - for (const auto &Concept : API.getConcepts()) - getDerived()->visitConceptRecord(*Concept.second); - } - - void traverseObjCInterfaces() { - for (const auto &Interface : API.getObjCInterfaces()) - getDerived()->visitObjCContainerRecord(*Interface.second); - } - - void traverseObjCProtocols() { - for (const auto &Protocol : API.getObjCProtocols()) - getDerived()->visitObjCContainerRecord(*Protocol.second); - } - - void traverseObjCCategories() { - for (const auto &Category : API.getObjCCategories()) - getDerived()->visitObjCCategoryRecord(*Category.second); - } - - void traverseMacroDefinitionRecords() { - for (const auto &Macro : API.getMacros()) - getDerived()->visitMacroDefinitionRecord(*Macro.second); - } - - void traverseTypedefRecords() { - for (const auto &Typedef : API.getTypedefs()) - getDerived()->visitTypedefRecord(*Typedef.second); - } - - void visitNamespaceRecord(const NamespaceRecord &Record){}; - - /// Visit a global function record. - void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record){}; - - /// Visit a global variable record. - void visitGlobalVariableRecord(const GlobalVariableRecord &Record){}; - - /// Visit an enum record. - void visitEnumRecord(const EnumRecord &Record){}; - - /// Visit a record record. - void visitRecordRecord(const RecordRecord &Record){}; - - void visitStaticFieldRecord(const StaticFieldRecord &Record){}; - - void visitCXXClassRecord(const CXXClassRecord &Record){}; - - void visitClassTemplateRecord(const ClassTemplateRecord &Record){}; - - void visitClassTemplateSpecializationRecord( - const ClassTemplateSpecializationRecord &Record){}; - - void visitClassTemplatePartialSpecializationRecord( - const ClassTemplatePartialSpecializationRecord &Record){}; - - void visitCXXInstanceRecord(const CXXInstanceMethodRecord &Record){}; - - void visitCXXStaticRecord(const CXXStaticMethodRecord &Record){}; - - void visitMethodTemplateRecord(const CXXMethodTemplateRecord &Record){}; - - void visitMethodTemplateSpecializationRecord( - const CXXMethodTemplateSpecializationRecord &Record){}; - - void visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord &Record){}; - - void visitGlobalVariableTemplateRecord( - const GlobalVariableTemplateRecord &Record) {} - - void visitGlobalVariableTemplateSpecializationRecord( - const GlobalVariableTemplateSpecializationRecord &Record){}; - - void visitGlobalVariableTemplatePartialSpecializationRecord( - const GlobalVariableTemplatePartialSpecializationRecord &Record){}; - - void visitGlobalFunctionTemplateRecord( - const GlobalFunctionTemplateRecord &Record){}; - - void visitGlobalFunctionTemplateSpecializationRecord( - const GlobalFunctionTemplateSpecializationRecord &Record){}; - - /// Visit an Objective-C container record. - void visitObjCContainerRecord(const ObjCContainerRecord &Record){}; - - /// Visit an Objective-C category record. - void visitObjCCategoryRecord(const ObjCCategoryRecord &Record){}; - - /// Visit a macro definition record. - void visitMacroDefinitionRecord(const MacroDefinitionRecord &Record){}; - - /// Visit a typedef record. - void visitTypedefRecord(const TypedefRecord &Record){}; - -protected: - const APISet &API; - -public: - APISetVisitor() = delete; - APISetVisitor(const APISetVisitor &) = delete; - APISetVisitor(APISetVisitor &&) = delete; - APISetVisitor &operator=(const APISetVisitor &) = delete; - APISetVisitor &operator=(APISetVisitor &&) = delete; - -protected: - APISetVisitor(const APISet &API) : API(API) {} - ~APISetVisitor() = default; - - Derived *getDerived() { return static_cast(this); }; -}; - -} // namespace extractapi -} // namespace clang - -#endif // LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SERIALIZERBASE_H diff --git a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h index 4249ac405fd2622854f6deb8d7319aa827af4933..724b087f7aea98f577591b6a1e96a965b0de15d2 100644 --- a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h +++ b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h @@ -17,11 +17,17 @@ #ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H #define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H +#include "clang/Basic/Module.h" #include "clang/ExtractAPI/API.h" #include "clang/ExtractAPI/APIIgnoresList.h" -#include "clang/ExtractAPI/Serialization/SerializerBase.h" +#include "clang/ExtractAPI/Serialization/APISetVisitor.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" +#include "llvm/ADT/Twine.h" #include "llvm/Support/JSON.h" #include "llvm/Support/VersionTuple.h" #include "llvm/Support/raw_ostream.h" @@ -35,7 +41,30 @@ using namespace llvm::json; /// Common options to customize the visitor output. struct SymbolGraphSerializerOption { /// Do not include unnecessary whitespaces to save space. - bool Compact; + bool Compact = true; + bool EmitSymbolLabelsForTesting = false; +}; + +/// A representation of the contents of a given module symbol graph +struct ExtendedModule { + ExtendedModule() = default; + ExtendedModule(ExtendedModule &&EM) = default; + ExtendedModule &operator=(ExtendedModule &&EM) = default; + // Copies are expensive so disable them. + ExtendedModule(const ExtendedModule &EM) = delete; + ExtendedModule &operator=(const ExtendedModule &EM) = delete; + + /// Add a symbol to the module, do not store the resulting pointer or use it + /// across insertions. + Object *addSymbol(Object &&Symbol); + + void addRelationship(Object &&Relationship); + + /// A JSON array of formatted symbols from an \c APISet. + Array Symbols; + + /// A JSON array of formatted symbol relationships from an \c APISet. + Array Relationships; }; /// The visitor that organizes API information in the Symbol Graph format. @@ -44,28 +73,54 @@ struct SymbolGraphSerializerOption { /// models an API set as a directed graph, where nodes are symbol declarations, /// and edges are relationships between the connected symbols. class SymbolGraphSerializer : public APISetVisitor { - /// A JSON array of formatted symbols in \c APISet. - Array Symbols; +private: + using Base = APISetVisitor; + /// The main symbol graph that contains symbols that are either top-level or a + /// are related to symbols defined in this product/module. + ExtendedModule MainModule; - /// A JSON array of formatted symbol relationships in \c APISet. - Array Relationships; + /// Additional symbol graphs that contain symbols that are related to symbols + /// defined in another product/module. The key of this map is the module name + /// of the extended module. + llvm::StringMap ExtendedModules; /// The Symbol Graph format version used by this serializer. static const VersionTuple FormatVersion; - /// Indicates whether child symbols should be visited. This is mainly + /// Indicates whether to take into account the extended module. This is only /// useful for \c serializeSingleSymbolSGF. - bool ShouldRecurse; + bool ForceEmitToMainModule; -public: - /// Serialize the APIs in \c APISet in the Symbol Graph format. + // Stores the references required to construct path components for the + // currently visited APIRecord. + llvm::SmallVector Hierarchy; + + /// The list of symbols to ignore. /// - /// \returns a JSON object that contains the root of the formatted - /// Symbol Graph. - Object serialize(); + /// Note: This should be consulted before emitting a symbol. + const APIIgnoresList &IgnoresList; - /// Wrap serialize(void) and write out the serialized JSON object to \p os. - void serialize(raw_ostream &os); + const bool EmitSymbolLabelsForTesting = false; + + /// The object instantiated by the last call to serializeAPIRecord. + Object *CurrentSymbol = nullptr; + + /// The module to which \p CurrentSymbol belongs too. + ExtendedModule *ModuleForCurrentSymbol = nullptr; + +public: + static void + serializeMainSymbolGraph(raw_ostream &OS, const APISet &API, + const APIIgnoresList &IgnoresList, + SymbolGraphSerializerOption Options = {}); + + static void serializeWithExtensionGraphs( + raw_ostream &MainOutput, const APISet &API, + const APIIgnoresList &IgnoresList, + llvm::function_ref< + std::unique_ptr(llvm::Twine BaseFileName)> + CreateOutputStream, + SymbolGraphSerializerOption Options = {}); /// Serialize a single symbol SGF. This is primarily used for libclang. /// @@ -75,6 +130,7 @@ public: static std::optional serializeSingleSymbolSGF(StringRef USR, const APISet &API); +private: /// The kind of a relationship between two symbols. enum RelationshipKind { /// The source symbol is a member of the target symbol. @@ -94,16 +150,32 @@ public: ExtensionTo, }; + /// Serialize a single record. + void serializeSingleRecord(const APIRecord *Record); + /// Get the string representation of the relationship kind. static StringRef getRelationshipString(RelationshipKind Kind); + void serializeRelationship(RelationshipKind Kind, + const SymbolReference &Source, + const SymbolReference &Target, + ExtendedModule &Into); + enum ConstraintKind { Conformance, ConditionalConformance }; static StringRef getConstraintString(ConstraintKind Kind); -private: - /// Just serialize the currently recorded objects in Symbol Graph format. - Object serializeCurrentGraph(); + /// Serialize the APIs in \c ExtendedModule. + /// + /// \returns a JSON object that contains the root of the formatted + /// Symbol Graph. + Object serializeGraph(StringRef ModuleName, ExtendedModule &&EM); + + /// Serialize the APIs in \c ExtendedModule in the Symbol Graph format and + /// write them to the provide stream. + void serializeGraphToStream(raw_ostream &OS, + SymbolGraphSerializerOption Options, + StringRef ModuleName, ExtendedModule &&EM); /// Synthesize the metadata section of the Symbol Graph format. /// @@ -117,124 +189,92 @@ private: /// by the given API set. /// Note that "module" here is not to be confused with the Clang/C++ module /// concept. - Object serializeModule() const; + Object serializeModuleObject(StringRef ModuleName) const; + + Array serializePathComponents(const APIRecord *Record) const; /// Determine if the given \p Record should be skipped during serialization. - bool shouldSkip(const APIRecord &Record) const; + bool shouldSkip(const APIRecord *Record) const; + + ExtendedModule &getModuleForCurrentSymbol(); /// Format the common API information for \p Record. /// /// This handles the shared information of all kinds of API records, - /// for example identifier and source location. The resulting object is then - /// augmented with kind-specific symbol information by the caller. - /// This method also checks if the given \p Record should be skipped during - /// serialization. + /// for example identifier, source location and path components. The resulting + /// object is then augmented with kind-specific symbol information in + /// subsequent visit* methods by accessing the \p State member variable. This + /// method also checks if the given \p Record should be skipped during + /// serialization. This should be called only once per concrete APIRecord + /// instance and the first visit* method to be called is responsible for + /// calling this. This is normally visitAPIRecord unless a walkUpFromFoo + /// method is implemented along the inheritance hierarchy in which case the + /// visitFoo method needs to call this. /// - /// \returns \c std::nullopt if this \p Record should be skipped, or a JSON - /// object containing common symbol information of \p Record. - template - std::optional serializeAPIRecord(const RecordTy &Record) const; - - /// Helper method to serialize second-level member records of \p Record and - /// the member-of relationships. - template - void serializeMembers(const APIRecord &Record, - const SmallVector> &Members); - - /// Serialize the \p Kind relationship between \p Source and \p Target. - /// - /// Record the relationship between the two symbols in - /// SymbolGraphSerializer::Relationships. - void serializeRelationship(RelationshipKind Kind, SymbolReference Source, - SymbolReference Target); - -protected: - /// The list of symbols to ignore. - /// - /// Note: This should be consulted before emitting a symbol. - const APIIgnoresList &IgnoresList; - - SymbolGraphSerializerOption Options; - - llvm::StringSet<> visitedCategories; + /// \returns \c nullptr if this \p Record should be skipped, or a pointer to + /// JSON object containing common symbol information of \p Record. Do not + /// store the returned pointer only use it to augment the object with record + /// specific information as it directly points to the object in the + /// \p ExtendedModule, the pointer won't be valid as soon as another object is + /// inserted into the module. + void serializeAPIRecord(const APIRecord *Record); public: - void visitNamespaceRecord(const NamespaceRecord &Record); - - /// Visit a global function record. - void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record); - - /// Visit a global variable record. - void visitGlobalVariableRecord(const GlobalVariableRecord &Record); - - /// Visit an enum record. - void visitEnumRecord(const EnumRecord &Record); - - /// Visit a record record. - void visitRecordRecord(const RecordRecord &Record); - - void visitStaticFieldRecord(const StaticFieldRecord &Record); + // Handle if records should be skipped at this level of the traversal to + // ensure that children of skipped records aren't serialized. + bool traverseAPIRecord(const APIRecord *Record); - void visitCXXClassRecord(const CXXClassRecord &Record); + bool visitAPIRecord(const APIRecord *Record); - void visitClassTemplateRecord(const ClassTemplateRecord &Record); - - void visitClassTemplateSpecializationRecord( - const ClassTemplateSpecializationRecord &Record); - - void visitClassTemplatePartialSpecializationRecord( - const ClassTemplatePartialSpecializationRecord &Record); - - void visitCXXInstanceMethodRecord(const CXXInstanceMethodRecord &Record); + /// Visit a global function record. + bool visitGlobalFunctionRecord(const GlobalFunctionRecord *Record); - void visitCXXStaticMethodRecord(const CXXStaticMethodRecord &Record); + bool visitCXXClassRecord(const CXXClassRecord *Record); - void visitMethodTemplateRecord(const CXXMethodTemplateRecord &Record); + bool visitClassTemplateRecord(const ClassTemplateRecord *Record); - void visitMethodTemplateSpecializationRecord( - const CXXMethodTemplateSpecializationRecord &Record); + bool visitClassTemplatePartialSpecializationRecord( + const ClassTemplatePartialSpecializationRecord *Record); - void visitCXXFieldRecord(const CXXFieldRecord &Record); + bool visitCXXMethodRecord(const CXXMethodRecord *Record); - void visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord &Record); + bool visitCXXMethodTemplateRecord(const CXXMethodTemplateRecord *Record); - void visitConceptRecord(const ConceptRecord &Record); + bool visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord *Record); - void - visitGlobalVariableTemplateRecord(const GlobalVariableTemplateRecord &Record); + bool visitConceptRecord(const ConceptRecord *Record); - void visitGlobalVariableTemplateSpecializationRecord( - const GlobalVariableTemplateSpecializationRecord &Record); + bool + visitGlobalVariableTemplateRecord(const GlobalVariableTemplateRecord *Record); - void visitGlobalVariableTemplatePartialSpecializationRecord( - const GlobalVariableTemplatePartialSpecializationRecord &Record); + bool visitGlobalVariableTemplatePartialSpecializationRecord( + const GlobalVariableTemplatePartialSpecializationRecord *Record); - void - visitGlobalFunctionTemplateRecord(const GlobalFunctionTemplateRecord &Record); + bool + visitGlobalFunctionTemplateRecord(const GlobalFunctionTemplateRecord *Record); - void visitGlobalFunctionTemplateSpecializationRecord( - const GlobalFunctionTemplateSpecializationRecord &Record); + bool visitObjCContainerRecord(const ObjCContainerRecord *Record); - /// Visit an Objective-C container record. - void visitObjCContainerRecord(const ObjCContainerRecord &Record); + bool visitObjCInterfaceRecord(const ObjCInterfaceRecord *Record); - /// Visit an Objective-C category record. - void visitObjCCategoryRecord(const ObjCCategoryRecord &Record); + bool traverseObjCCategoryRecord(const ObjCCategoryRecord *Record); + bool walkUpFromObjCCategoryRecord(const ObjCCategoryRecord *Record); + bool visitObjCCategoryRecord(const ObjCCategoryRecord *Record); - /// Visit a macro definition record. - void visitMacroDefinitionRecord(const MacroDefinitionRecord &Record); + bool visitObjCMethodRecord(const ObjCMethodRecord *Record); - /// Visit a typedef record. - void visitTypedefRecord(const TypedefRecord &Record); + bool + visitObjCInstanceVariableRecord(const ObjCInstanceVariableRecord *Record); - /// Serialize a single record. - void serializeSingleRecord(const APIRecord *Record); + bool walkUpFromTypedefRecord(const TypedefRecord *Record); + bool visitTypedefRecord(const TypedefRecord *Record); SymbolGraphSerializer(const APISet &API, const APIIgnoresList &IgnoresList, - SymbolGraphSerializerOption Options = {}, - bool ShouldRecurse = true) - : APISetVisitor(API), ShouldRecurse(ShouldRecurse), - IgnoresList(IgnoresList), Options(Options) {} + bool EmitSymbolLabelsForTesting = false, + bool ForceEmitToMainModule = false) + : Base(API), ForceEmitToMainModule(ForceEmitToMainModule), + IgnoresList(IgnoresList), + EmitSymbolLabelsForTesting(EmitSymbolLabelsForTesting) {} }; } // namespace extractapi diff --git a/clang/include/clang/Format/Format.h b/clang/include/clang/Format/Format.h index 7ad2579bf7773b76643efef6b960dba66184c9fc..48f5fb441575704ece96966e57fb988649e4ff72 100644 --- a/clang/include/clang/Format/Format.h +++ b/clang/include/clang/Format/Format.h @@ -414,6 +414,21 @@ struct FormatStyle { /// \version 17 ShortCaseStatementsAlignmentStyle AlignConsecutiveShortCaseStatements; + /// Style of aligning consecutive TableGen DAGArg operator colons. + /// If enabled, align the colon inside DAGArg which have line break inside. + /// This works only when TableGenBreakInsideDAGArg is BreakElements or + /// BreakAll and the DAGArg is not excepted by + /// TableGenBreakingDAGArgOperators's effect. + /// \code + /// let dagarg = (ins + /// a :$src1, + /// aa :$src2, + /// aaa:$src3 + /// ) + /// \endcode + /// \version 19 + AlignConsecutiveStyle AlignConsecutiveTableGenBreakingDAGArgColons; + /// Style of aligning consecutive TableGen cond operator colons. /// Align the colons of cases inside !cond operators. /// \code @@ -2208,6 +2223,20 @@ struct FormatStyle { /// \version 5 BreakConstructorInitializersStyle BreakConstructorInitializers; + /// If ``true``, clang-format will always break before function definition + /// parameters. + /// \code + /// true: + /// void functionDefinition( + /// int A, int B) {} + /// + /// false: + /// void functionDefinition(int A, int B) {} + /// + /// \endcode + /// \version 19 + bool BreakFunctionDefinitionParameters; + /// Break after each annotation on a field in Java files. /// \code{.java} /// true: false: @@ -4879,6 +4908,8 @@ struct FormatStyle { AlignConsecutiveMacros == R.AlignConsecutiveMacros && AlignConsecutiveShortCaseStatements == R.AlignConsecutiveShortCaseStatements && + AlignConsecutiveTableGenBreakingDAGArgColons == + R.AlignConsecutiveTableGenBreakingDAGArgColons && AlignConsecutiveTableGenCondOperatorColons == R.AlignConsecutiveTableGenCondOperatorColons && AlignConsecutiveTableGenDefinitionColons == @@ -4921,6 +4952,8 @@ struct FormatStyle { BreakBeforeInlineASMColon == R.BreakBeforeInlineASMColon && BreakBeforeTernaryOperators == R.BreakBeforeTernaryOperators && BreakConstructorInitializers == R.BreakConstructorInitializers && + BreakFunctionDefinitionParameters == + R.BreakFunctionDefinitionParameters && BreakInheritanceList == R.BreakInheritanceList && BreakStringLiterals == R.BreakStringLiterals && BreakTemplateDeclarations == R.BreakTemplateDeclarations && diff --git a/clang/include/clang/Frontend/CompilerInstance.h b/clang/include/clang/Frontend/CompilerInstance.h index cce91862ae3d03b210d5939ab17f29bb1f231f80..3464654284f199c73beeef8ea9d7858882e1173f 100644 --- a/clang/include/clang/Frontend/CompilerInstance.h +++ b/clang/include/clang/Frontend/CompilerInstance.h @@ -133,6 +133,24 @@ class CompilerInstance : public ModuleLoader { std::vector> DependencyCollectors; + /// Records the set of modules + class FailedModulesSet { + llvm::StringSet<> Failed; + + public: + bool hasAlreadyFailed(StringRef module) { return Failed.count(module) > 0; } + + void addFailed(StringRef module) { Failed.insert(module); } + }; + + /// The set of modules that failed to build. + /// + /// This pointer will be shared among all of the compiler instances created + /// to (re)build modules, so that once a module fails to build anywhere, + /// other instances will see that the module has failed and won't try to + /// build it again. + std::shared_ptr FailedModules; + /// The set of top-level modules that has already been built on the /// fly as part of this overall compilation action. std::map> BuiltModules; @@ -619,6 +637,24 @@ public: } /// @} + /// @name Failed modules set + /// @{ + + bool hasFailedModulesSet() const { return (bool)FailedModules; } + + void createFailedModulesSet() { + FailedModules = std::make_shared(); + } + + std::shared_ptr getFailedModulesSetPtr() const { + return FailedModules; + } + + void setFailedModulesSet(std::shared_ptr FMS) { + FailedModules = FMS; + } + + /// } /// @name Output Files /// @{ diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index 8085dbcbf671a6e858df6870fc121055f51f60df..5ee4d471670f48bae893ad9da4432923ae305660 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -15,6 +15,7 @@ #include "clang/Sema/CodeCompleteOptions.h" #include "clang/Serialization/ModuleFileExtension.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/Compiler.h" #include "llvm/Support/MemoryBuffer.h" #include #include @@ -387,6 +388,22 @@ public: LLVM_PREFERRED_TYPE(bool) unsigned ModulesShareFileManager : 1; + /// Whether to emit symbol graph files as a side effect of compilation. + LLVM_PREFERRED_TYPE(bool) + unsigned EmitSymbolGraph : 1; + + /// Whether to emit additional symbol graphs for extended modules. + LLVM_PREFERRED_TYPE(bool) + unsigned EmitExtensionSymbolGraphs : 1; + + /// Whether to emit symbol labels for testing in generated symbol graphs + LLVM_PREFERRED_TYPE(bool) + unsigned EmitSymbolGraphSymbolLabelsForTesting : 1; + + /// Whether to emit symbol labels for testing in generated symbol graphs + LLVM_PREFERRED_TYPE(bool) + unsigned EmitPrettySymbolGraphs : 1; + CodeCompleteOptions CodeCompleteOpts; /// Specifies the output format of the AST. @@ -496,10 +513,8 @@ public: // ignore when extracting documentation. std::vector ExtractAPIIgnoresFileList; - // Currently this is only used as part of the `-emit-symbol-graph` - // action. // Location of output directory where symbol graph information would - // be dumped + // be dumped. This overrides regular -o output file specification std::string SymbolGraphOutputDir; /// Args to pass to the plugins @@ -565,7 +580,9 @@ public: BuildingImplicitModuleUsesLock(true), ModulesEmbedAllFiles(false), IncludeTimestamps(true), UseTemporary(true), AllowPCMWithCompilerErrors(false), ModulesShareFileManager(true), - TimeTraceGranularity(500) {} + EmitSymbolGraph(false), EmitExtensionSymbolGraphs(false), + EmitSymbolGraphSymbolLabelsForTesting(false), + EmitPrettySymbolGraphs(false), TimeTraceGranularity(500) {} /// getInputKindForExtension - Return the appropriate input kind for a file /// extension. For example, "c" would return Language::C. diff --git a/clang/include/clang/InstallAPI/Context.h b/clang/include/clang/InstallAPI/Context.h index 54e517544b8edf526097afd66347b9e55998c0f3..8f88331a2803fc4a6505010ac1d238c3fa1928ba 100644 --- a/clang/include/clang/InstallAPI/Context.h +++ b/clang/include/clang/InstallAPI/Context.h @@ -28,6 +28,9 @@ struct InstallAPIContext { /// Library attributes that are typically passed as linker inputs. BinaryAttrs BA; + /// Install names of reexported libraries of a library. + LibAttrs Reexports; + /// All headers that represent a library. HeaderSeq InputHeaders; @@ -80,6 +83,20 @@ private: llvm::DenseMap KnownIncludes; }; +/// Lookup the dylib or TextAPI file location for a system library or framework. +/// The search paths provided are searched in order. +/// @rpath based libraries are not supported. +/// +/// \param InstallName The install name for the library. +/// \param FrameworkSearchPaths Search paths to look up frameworks with. +/// \param LibrarySearchPaths Search paths to look up dylibs with. +/// \param SearchPaths Fallback search paths if library was not found in earlier +/// paths. +/// \return The full path of the library. +std::string findLibrary(StringRef InstallName, FileManager &FM, + ArrayRef FrameworkSearchPaths, + ArrayRef LibrarySearchPaths, + ArrayRef SearchPaths); } // namespace installapi } // namespace clang diff --git a/clang/include/clang/InstallAPI/DylibVerifier.h b/clang/include/clang/InstallAPI/DylibVerifier.h index 49de24763f1f938d88ba6e2f2ab41d593fc34a38..a3df25f10de4b13f311c0b790c3503bd83e8f53a 100644 --- a/clang/include/clang/InstallAPI/DylibVerifier.h +++ b/clang/include/clang/InstallAPI/DylibVerifier.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_INSTALLAPI_DYLIBVERIFIER_H #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceManager.h" #include "clang/InstallAPI/MachO.h" namespace clang { @@ -24,6 +25,9 @@ enum class VerificationMode { Pedantic, }; +using LibAttrs = llvm::StringMap; +using ReexportedInterfaces = llvm::SmallVector; + /// Service responsible to tracking state of verification across the /// lifetime of InstallAPI. /// As declarations are collected during AST traversal, they are @@ -31,6 +35,7 @@ enum class VerificationMode { class DylibVerifier : llvm::MachO::RecordVisitor { private: struct SymbolContext; + struct DWARFContext; public: enum class Result { NoVerify, Ignore, Valid, Invalid }; @@ -54,7 +59,7 @@ public: DiagnosticsEngine *Diag = nullptr; // Handle diagnostics reporting for target level violations. - void emitDiag(llvm::function_ref Report); + void emitDiag(llvm::function_ref Report, RecordLoc *Loc = nullptr); VerifierContext() = default; VerifierContext(DiagnosticsEngine *Diag) : Diag(Diag) {} @@ -62,9 +67,11 @@ public: DylibVerifier() = default; - DylibVerifier(llvm::MachO::Records &&Dylib, DiagnosticsEngine *Diag, - VerificationMode Mode, bool Demangle) - : Dylib(std::move(Dylib)), Mode(Mode), Demangle(Demangle), + DylibVerifier(llvm::MachO::Records &&Dylib, ReexportedInterfaces &&Reexports, + DiagnosticsEngine *Diag, VerificationMode Mode, bool Demangle, + StringRef DSYMPath) + : Dylib(std::move(Dylib)), Reexports(std::move(Reexports)), Mode(Mode), + Demangle(Demangle), DSYMPath(DSYMPath), Exports(std::make_unique()), Ctx(VerifierContext{Diag}) {} Result verify(GlobalRecord *R, const FrontendAttrs *FA); @@ -75,6 +82,14 @@ public: // Scan through dylib slices and report any remaining missing exports. Result verifyRemainingSymbols(); + /// Compare and report the attributes represented as + /// load commands in the dylib to the attributes provided via options. + bool verifyBinaryAttrs(const ArrayRef ProvidedTargets, + const BinaryAttrs &ProvidedBA, + const LibAttrs &ProvidedReexports, + const LibAttrs &ProvidedClients, + const LibAttrs &ProvidedRPaths, const FileType &FT); + /// Initialize target for verification. void setTarget(const Target &T); @@ -85,11 +100,7 @@ public: Result getState() const { return Ctx.FrontendState; } /// Set different source managers to the same diagnostics engine. - void setSourceManager(SourceManager &SourceMgr) const { - if (!Ctx.Diag) - return; - Ctx.Diag->setSourceManager(&SourceMgr); - } + void setSourceManager(IntrusiveRefCntPtr SourceMgr); private: /// Determine whether to compare declaration to symbol in binary. @@ -103,6 +114,10 @@ private: bool shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx, const Record *DR); + /// Check if declaration is exported from a reexported library. These + /// symbols should be omitted from the text-api file. + bool shouldIgnoreReexport(const Record *R, SymbolContext &SymCtx) const; + /// Compare the visibility declarations to the linkage of symbol found in /// dylib. Result compareVisibility(const Record *R, SymbolContext &SymCtx, @@ -143,20 +158,38 @@ private: std::string getAnnotatedName(const Record *R, SymbolContext &SymCtx, bool ValidSourceLoc = true); + /// Extract source location for symbol implementations. + /// As this is a relatively expensive operation, it is only used + /// when there is a violation to report and there is not a known declaration + /// in the interface. + void accumulateSrcLocForDylibSymbols(); + // Symbols in dylib. llvm::MachO::Records Dylib; + // Reexported interfaces apart of the library. + ReexportedInterfaces Reexports; + // Controls what class of violations to report. VerificationMode Mode = VerificationMode::Invalid; // Attempt to demangle when reporting violations. bool Demangle = false; + // File path to DSYM file. + StringRef DSYMPath; + // Valid symbols in final text file. std::unique_ptr Exports = std::make_unique(); // Track current state of verification while traversing AST. VerifierContext Ctx; + + // Track DWARF provided source location for dylibs. + DWARFContext *DWARFCtx = nullptr; + + // Source manager for each unique compiler instance. + llvm::SmallVector, 12> SourceManagers; }; } // namespace installapi diff --git a/clang/include/clang/InstallAPI/Frontend.h b/clang/include/clang/InstallAPI/Frontend.h index 5cccd891c58093ac540b5ac8af103b493f54871d..bc4e77de2b72569b1ad6f603b6609892a69ed4cd 100644 --- a/clang/include/clang/InstallAPI/Frontend.h +++ b/clang/include/clang/InstallAPI/Frontend.h @@ -36,7 +36,7 @@ public: std::unique_ptr CreateASTConsumer(CompilerInstance &CI, StringRef InFile) override { Ctx.Diags->getClient()->BeginSourceFile(CI.getLangOpts()); - Ctx.Verifier->setSourceManager(CI.getSourceManager()); + Ctx.Verifier->setSourceManager(CI.getSourceManagerPtr()); return std::make_unique( CI.getASTContext(), Ctx, CI.getSourceManager(), CI.getPreprocessor()); } diff --git a/clang/include/clang/InstallAPI/FrontendRecords.h b/clang/include/clang/InstallAPI/FrontendRecords.h index 59271e81e230c2f022e1bec0894e0529e3f3a0e2..ef82398addd7ac85add76d2aea3534e94e154d86 100644 --- a/clang/include/clang/InstallAPI/FrontendRecords.h +++ b/clang/include/clang/InstallAPI/FrontendRecords.h @@ -21,6 +21,7 @@ namespace installapi { struct FrontendAttrs { const AvailabilityInfo Avail; const Decl *D; + const SourceLocation Loc; const HeaderType Access; }; diff --git a/clang/include/clang/InstallAPI/HeaderFile.h b/clang/include/clang/InstallAPI/HeaderFile.h index 70e83bbb3e76f6bb91030fb6edca023aa5450e36..c67503d4ad49e934a6e4ac6927e9bd95fabd4567 100644 --- a/clang/include/clang/InstallAPI/HeaderFile.h +++ b/clang/include/clang/InstallAPI/HeaderFile.h @@ -13,7 +13,9 @@ #ifndef LLVM_CLANG_INSTALLAPI_HEADERFILE_H #define LLVM_CLANG_INSTALLAPI_HEADERFILE_H +#include "clang/Basic/FileManager.h" #include "clang/Basic/LangStandard.h" +#include "clang/InstallAPI/MachO.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Regex.h" @@ -22,8 +24,6 @@ namespace clang::installapi { enum class HeaderType { - /// Unset or unknown type. - Unknown, /// Represents declarations accessible to all clients. Public, /// Represents declarations accessible to a disclosed set of clients. @@ -31,6 +31,8 @@ enum class HeaderType { /// Represents declarations only accessible as implementation details to the /// input library. Project, + /// Unset or unknown type. + Unknown, }; inline StringRef getName(const HeaderType T) { @@ -56,6 +58,12 @@ class HeaderFile { std::string IncludeName; /// Supported language mode for header. std::optional Language; + /// Exclude header file from processing. + bool Excluded{false}; + /// Add header file to processing. + bool Extra{false}; + /// Specify that header file is the umbrella header for library. + bool Umbrella{false}; public: HeaderFile() = delete; @@ -71,17 +79,52 @@ public: StringRef getIncludeName() const { return IncludeName; } StringRef getPath() const { return FullPath; } + void setExtra(bool V = true) { Extra = V; } + void setExcluded(bool V = true) { Excluded = V; } + void setUmbrellaHeader(bool V = true) { Umbrella = V; } + bool isExtra() const { return Extra; } + bool isExcluded() const { return Excluded; } + bool isUmbrellaHeader() const { return Umbrella; } + bool useIncludeName() const { return Type != HeaderType::Project && !IncludeName.empty(); } bool operator==(const HeaderFile &Other) const { - return std::tie(Type, FullPath, IncludeName, Language) == - std::tie(Other.Type, Other.FullPath, Other.IncludeName, - Other.Language); + return std::tie(Type, FullPath, IncludeName, Language, Excluded, Extra, + Umbrella) == std::tie(Other.Type, Other.FullPath, + Other.IncludeName, Other.Language, + Other.Excluded, Other.Extra, + Other.Umbrella); } }; +/// Glob that represents a pattern of header files to retreive. +class HeaderGlob { +private: + std::string GlobString; + llvm::Regex Rule; + HeaderType Type; + bool FoundMatch{false}; + +public: + HeaderGlob(StringRef GlobString, llvm::Regex &&, HeaderType Type); + + /// Create a header glob from string for the header access level. + static llvm::Expected> + create(StringRef GlobString, HeaderType Type); + + /// Query if provided header matches glob. + bool match(const HeaderFile &Header); + + /// Query if a header was matched in the glob, used primarily for error + /// reporting. + bool didMatch() { return FoundMatch; } + + /// Provide back input glob string. + StringRef str() { return GlobString; } +}; + /// Assemble expected way header will be included by clients. /// As in what maps inside the brackets of `#include ` /// For example, @@ -93,6 +136,19 @@ public: std::optional createIncludeHeaderName(const StringRef FullPath); using HeaderSeq = std::vector; +/// Determine if Path is a header file. +/// It does not touch the file system. +/// +/// \param Path File path to file. +bool isHeaderFile(StringRef Path); + +/// Given input directory, collect all header files. +/// +/// \param FM FileManager for finding input files. +/// \param Directory Path to directory file. +llvm::Expected enumerateFiles(clang::FileManager &FM, + StringRef Directory); + } // namespace clang::installapi #endif // LLVM_CLANG_INSTALLAPI_HEADERFILE_H diff --git a/clang/include/clang/InstallAPI/MachO.h b/clang/include/clang/InstallAPI/MachO.h index f0dea8bbd24ccd6ac34cc7b43fa128c696838e1c..854399f54ba6c84cea32fac9c66f78f67a46b6d1 100644 --- a/clang/include/clang/InstallAPI/MachO.h +++ b/clang/include/clang/InstallAPI/MachO.h @@ -23,6 +23,8 @@ #include "llvm/TextAPI/TextAPIWriter.h" #include "llvm/TextAPI/Utils.h" +using Architecture = llvm::MachO::Architecture; +using ArchitectureSet = llvm::MachO::ArchitectureSet; using SymbolFlags = llvm::MachO::SymbolFlags; using RecordLinkage = llvm::MachO::RecordLinkage; using Record = llvm::MachO::Record; @@ -34,12 +36,14 @@ using ObjCCategoryRecord = llvm::MachO::ObjCCategoryRecord; using ObjCIVarRecord = llvm::MachO::ObjCIVarRecord; using ObjCIFSymbolKind = llvm::MachO::ObjCIFSymbolKind; using Records = llvm::MachO::Records; +using RecordLoc = llvm::MachO::RecordLoc; using RecordsSlice = llvm::MachO::RecordsSlice; using BinaryAttrs = llvm::MachO::RecordsSlice::BinaryAttrs; using SymbolSet = llvm::MachO::SymbolSet; using SimpleSymbol = llvm::MachO::SimpleSymbol; using FileType = llvm::MachO::FileType; using PackedVersion = llvm::MachO::PackedVersion; +using PathSeq = llvm::MachO::PathSeq; using Target = llvm::MachO::Target; using TargetList = llvm::MachO::TargetList; diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h index 1dcba1ef967980b7aa6297316b78912b3dbdb21d..970e0245417b5198b03b32f5ba4ee20ffe218128 100644 --- a/clang/include/clang/Interpreter/Interpreter.h +++ b/clang/include/clang/Interpreter/Interpreter.h @@ -30,6 +30,7 @@ namespace llvm { namespace orc { class LLJIT; +class LLJITBuilder; class ThreadSafeContext; } // namespace orc } // namespace llvm @@ -127,6 +128,13 @@ protected: // custom runtime. virtual std::unique_ptr FindRuntimeInterface(); + // Lazily construct thev ORCv2 JITBuilder. This called when the internal + // IncrementalExecutor is created. The default implementation populates an + // in-process JIT with debugging support. Override this to configure the JIT + // engine used for execution. + virtual llvm::Expected> + CreateJITBuilder(CompilerInstance &CI); + public: virtual ~Interpreter(); diff --git a/clang/include/clang/Interpreter/Value.h b/clang/include/clang/Interpreter/Value.h index c380cd91550defa524d87e5b074d9e0a130760eb..d70e8f8719026b9dfc17c573451a3c8fc9c9545d 100644 --- a/clang/include/clang/Interpreter/Value.h +++ b/clang/include/clang/Interpreter/Value.h @@ -76,6 +76,7 @@ class QualType; X(bool, Bool) \ X(char, Char_S) \ X(signed char, SChar) \ + X(unsigned char, Char_U) \ X(unsigned char, UChar) \ X(short, Short) \ X(unsigned short, UShort) \ diff --git a/clang/include/clang/Lex/ExternalPreprocessorSource.h b/clang/include/clang/Lex/ExternalPreprocessorSource.h index 685941b66bd8bf4eab40fd2c1d069aaba4d66668..6775841860373cb35d690a3647f7ccf861d679ee 100644 --- a/clang/include/clang/Lex/ExternalPreprocessorSource.h +++ b/clang/include/clang/Lex/ExternalPreprocessorSource.h @@ -31,7 +31,7 @@ public: virtual void ReadDefinedMacros() = 0; /// Update an out-of-date identifier. - virtual void updateOutOfDateIdentifier(IdentifierInfo &II) = 0; + virtual void updateOutOfDateIdentifier(const IdentifierInfo &II) = 0; /// Return the identifier associated with the given ID number. /// diff --git a/clang/include/clang/Lex/HeaderSearch.h b/clang/include/clang/Lex/HeaderSearch.h index 705dcfa8aacc3f88e279d00cf086d2867536bc6e..855f81f775f8a83bedb0fcdb490ec18ba404cdd5 100644 --- a/clang/include/clang/Lex/HeaderSearch.h +++ b/clang/include/clang/Lex/HeaderSearch.h @@ -78,11 +78,19 @@ struct HeaderFileInfo { LLVM_PREFERRED_TYPE(bool) unsigned External : 1; - /// Whether this header is part of a module. + /// Whether this header is part of and built with a module. i.e. it is listed + /// in a module map, and is not `excluded` or `textual`. (same meaning as + /// `ModuleMap::isModular()`). LLVM_PREFERRED_TYPE(bool) unsigned isModuleHeader : 1; - /// Whether this header is part of the module that we are building. + /// Whether this header is a `textual header` in a module. + LLVM_PREFERRED_TYPE(bool) + unsigned isTextualModuleHeader : 1; + + /// Whether this header is part of the module that we are building, even if it + /// doesn't build with the module. i.e. this will include `excluded` and + /// `textual` headers as well as normal headers. LLVM_PREFERRED_TYPE(bool) unsigned isCompilingModuleHeader : 1; @@ -128,13 +136,20 @@ struct HeaderFileInfo { HeaderFileInfo() : isImport(false), isPragmaOnce(false), DirInfo(SrcMgr::C_User), - External(false), isModuleHeader(false), isCompilingModuleHeader(false), - Resolved(false), IndexHeaderMapHeader(false), IsValid(false) {} + External(false), isModuleHeader(false), isTextualModuleHeader(false), + isCompilingModuleHeader(false), Resolved(false), + IndexHeaderMapHeader(false), IsValid(false) {} /// Retrieve the controlling macro for this header file, if /// any. const IdentifierInfo * getControllingMacro(ExternalPreprocessorSource *External); + + /// Update the module membership bits based on the header role. + /// + /// isModuleHeader will potentially be set, but not cleared. + /// isTextualModuleHeader will be set or cleared based on the role update. + void mergeModuleMembership(ModuleMap::ModuleHeaderRole Role); }; /// An external source of header file information, which may supply @@ -522,6 +537,9 @@ public: /// /// \return false if \#including the file will have no effect or true /// if we should include it. + /// + /// \param M The module to which `File` belongs (this should usually be the + /// SuggestedModule returned by LookupFile/LookupSubframeworkHeader) bool ShouldEnterIncludeFile(Preprocessor &PP, FileEntryRef File, bool isImport, bool ModulesEnabled, Module *M, bool &IsFirstIncludeOfFile); diff --git a/clang/include/clang/Lex/MacroInfo.h b/clang/include/clang/Lex/MacroInfo.h index 1237fc62eb6cf392e2c5831e0f9bdebd831c9b87..19a706216d5093c07d85a86b4ce3888f551e3cc8 100644 --- a/clang/include/clang/Lex/MacroInfo.h +++ b/clang/include/clang/Lex/MacroInfo.h @@ -515,7 +515,7 @@ class ModuleMacro : public llvm::FoldingSetNode { friend class Preprocessor; /// The name defined by the macro. - IdentifierInfo *II; + const IdentifierInfo *II; /// The body of the #define, or nullptr if this is a #undef. MacroInfo *Macro; @@ -529,7 +529,7 @@ class ModuleMacro : public llvm::FoldingSetNode { /// The number of modules whose macros are directly overridden by this one. unsigned NumOverrides; - ModuleMacro(Module *OwningModule, IdentifierInfo *II, MacroInfo *Macro, + ModuleMacro(Module *OwningModule, const IdentifierInfo *II, MacroInfo *Macro, ArrayRef Overrides) : II(II), Macro(Macro), OwningModule(OwningModule), NumOverrides(Overrides.size()) { @@ -539,7 +539,7 @@ class ModuleMacro : public llvm::FoldingSetNode { public: static ModuleMacro *create(Preprocessor &PP, Module *OwningModule, - IdentifierInfo *II, MacroInfo *Macro, + const IdentifierInfo *II, MacroInfo *Macro, ArrayRef Overrides); void Profile(llvm::FoldingSetNodeID &ID) const { @@ -553,7 +553,7 @@ public: } /// Get the name of the macro. - IdentifierInfo *getName() const { return II; } + const IdentifierInfo *getName() const { return II; } /// Get the ID of the module that exports this macro. Module *getOwningModule() const { return OwningModule; } diff --git a/clang/include/clang/Lex/ModuleMap.h b/clang/include/clang/Lex/ModuleMap.h index 867cb6eab42f2d7bf04bfa8e32c5e073170f7816..2e28ff6823cb2a73cd577bd96e483c71bd513011 100644 --- a/clang/include/clang/Lex/ModuleMap.h +++ b/clang/include/clang/Lex/ModuleMap.h @@ -263,8 +263,8 @@ private: Attributes Attrs; /// If \c InferModules is non-zero, the module map file that allowed - /// inferred modules. Otherwise, nullopt. - OptionalFileEntryRef ModuleMapFile; + /// inferred modules. Otherwise, invalid. + FileID ModuleMapFID; /// The names of modules that cannot be inferred within this /// directory. @@ -279,8 +279,7 @@ private: /// A mapping from an inferred module to the module map that allowed the /// inference. - // FIXME: Consider making the values non-optional. - llvm::DenseMap InferredModuleAllowedBy; + llvm::DenseMap InferredModuleAllowedBy; llvm::DenseMap AdditionalModMaps; @@ -618,8 +617,9 @@ public: /// /// \param Module The module whose module map file will be returned, if known. /// - /// \returns The file entry for the module map file containing the given - /// module, or nullptr if the module definition was inferred. + /// \returns The FileID for the module map file containing the given module, + /// invalid if the module definition was inferred. + FileID getContainingModuleMapFileID(const Module *Module) const; OptionalFileEntryRef getContainingModuleMapFile(const Module *Module) const; /// Get the module map file that (along with the module name) uniquely @@ -631,9 +631,10 @@ public: /// of inferred modules, returns the module map that allowed the inference /// (e.g. contained 'module *'). Otherwise, returns /// getContainingModuleMapFile(). + FileID getModuleMapFileIDForUniquing(const Module *M) const; OptionalFileEntryRef getModuleMapFileForUniquing(const Module *M) const; - void setInferredModuleAllowedBy(Module *M, OptionalFileEntryRef ModMap); + void setInferredModuleAllowedBy(Module *M, FileID ModMapFID); /// Canonicalize \p Path in a manner suitable for a module map file. In /// particular, this canonicalizes the parent directory separately from the diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h index 0836b7d439bb049054074c4cfa845d4e56bd085e..e89b4a2c5230e7612e07ca5fea84b67537a2a001 100644 --- a/clang/include/clang/Lex/Preprocessor.h +++ b/clang/include/clang/Lex/Preprocessor.h @@ -836,7 +836,7 @@ private: ModuleMacroInfo *getModuleInfo(Preprocessor &PP, const IdentifierInfo *II) const { if (II->isOutOfDate()) - PP.updateOutOfDateIdentifier(const_cast(*II)); + PP.updateOutOfDateIdentifier(*II); // FIXME: Find a spare bit on IdentifierInfo and store a // HasModuleMacros flag. if (!II->hasMacroDefinition() || @@ -1162,7 +1162,7 @@ private: /// skipped. llvm::DenseMap RecordedSkippedRanges; - void updateOutOfDateIdentifier(IdentifierInfo &II) const; + void updateOutOfDateIdentifier(const IdentifierInfo &II) const; public: Preprocessor(std::shared_ptr PPOpts, @@ -1432,14 +1432,15 @@ public: MacroDirective *MD); /// Register an exported macro for a module and identifier. - ModuleMacro *addModuleMacro(Module *Mod, IdentifierInfo *II, MacroInfo *Macro, + ModuleMacro *addModuleMacro(Module *Mod, const IdentifierInfo *II, + MacroInfo *Macro, ArrayRef Overrides, bool &IsNew); ModuleMacro *getModuleMacro(Module *Mod, const IdentifierInfo *II); /// Get the list of leaf (non-overridden) module macros for a name. ArrayRef getLeafModuleMacros(const IdentifierInfo *II) const { if (II->isOutOfDate()) - updateOutOfDateIdentifier(const_cast(*II)); + updateOutOfDateIdentifier(*II); auto I = LeafModuleMacros.find(II); if (I != LeafModuleMacros.end()) return I->second; diff --git a/clang/include/clang/Lex/PreprocessorOptions.h b/clang/include/clang/Lex/PreprocessorOptions.h index f841e4a028df50d3030a21145fa8d9af8bb047a3..635971d0ce5ee8c410ef488628bda2519ab62714 100644 --- a/clang/include/clang/Lex/PreprocessorOptions.h +++ b/clang/include/clang/Lex/PreprocessorOptions.h @@ -186,28 +186,6 @@ public: /// with support for lifetime-qualified pointers. ObjCXXARCStandardLibraryKind ObjCXXARCStandardLibrary = ARCXX_nolib; - /// Records the set of modules - class FailedModulesSet { - llvm::StringSet<> Failed; - - public: - bool hasAlreadyFailed(StringRef module) { - return Failed.count(module) > 0; - } - - void addFailed(StringRef module) { - Failed.insert(module); - } - }; - - /// The set of modules that failed to build. - /// - /// This pointer will be shared among all of the compiler instances created - /// to (re)build modules, so that once a module fails to build anywhere, - /// other instances will see that the module has failed and won't try to - /// build it again. - std::shared_ptr FailedModules; - /// Function for getting the dependency preprocessor directives of a file. /// /// These are directives derived from a special form of lexing where the diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h index 36ec5ddaa29adb3174b363dda3e0c74ec15f0c38..4f29fb7d11415963fc62cc1bf6d424466d0fe56a 100644 --- a/clang/include/clang/Lex/Token.h +++ b/clang/include/clang/Lex/Token.h @@ -58,7 +58,7 @@ class Token { /// Annotations (resolved type names, C++ scopes, etc): isAnnotation(). /// This is a pointer to sema-specific data for the annotation token. /// Eof: - // This is a pointer to a Decl. + /// This is a pointer to a Decl. /// Other: /// This is null. void *PtrData; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index bba8ef4ff017391f7aa912ec89653658a5591866..3a055c10ffb3877717a2e97b020523178bfb6c41 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -41,6 +41,7 @@ namespace clang { class InMessageExpressionRAIIObject; class PoisonSEHIdentifiersRAIIObject; class OMPClause; + class OpenACCClause; class ObjCTypeParamList; struct OMPTraitProperty; struct OMPTraitSelector; @@ -328,7 +329,7 @@ class Parser : public CodeCompletionHandler { }; /// Identifiers which have been declared within a tentative parse. - SmallVector TentativelyDeclaredIdentifiers; + SmallVector TentativelyDeclaredIdentifiers; /// Tracker for '<' tokens that might have been intended to be treated as an /// angle bracket instead of a less-than comparison. @@ -1926,15 +1927,11 @@ private: bool EnteringContext, IdentifierInfo &II, CXXScopeSpec &SS); - bool ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS, - ParsedType ObjectType, - bool ObjectHasErrors, - bool EnteringContext, - bool *MayBePseudoDestructor = nullptr, - bool IsTypename = false, - IdentifierInfo **LastII = nullptr, - bool OnlyNamespace = false, - bool InUsingDeclaration = false); + bool ParseOptionalCXXScopeSpecifier( + CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHasErrors, + bool EnteringContext, bool *MayBePseudoDestructor = nullptr, + bool IsTypename = false, const IdentifierInfo **LastII = nullptr, + bool OnlyNamespace = false, bool InUsingDeclaration = false); //===--------------------------------------------------------------------===// // C++11 5.1.2: Lambda expressions @@ -3014,6 +3011,7 @@ private: void DiagnoseAndSkipExtendedMicrosoftTypeAttributes(); SourceLocation SkipExtendedMicrosoftTypeAttributes(); void ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs); + void ParseNullabilityClassAttributes(ParsedAttributes &attrs); void ParseBorlandTypeAttributes(ParsedAttributes &attrs); void ParseOpenCLKernelAttributes(ParsedAttributes &attrs); void ParseOpenCLQualifiers(ParsedAttributes &Attrs); @@ -3593,11 +3591,26 @@ private: OpenACCDirectiveKind DirKind; SourceLocation StartLoc; SourceLocation EndLoc; - // TODO OpenACC: Add Clause list here once we have a type for that. + SmallVector Clauses; // TODO OpenACC: As we implement support for the Atomic, Routine, Cache, and // Wait constructs, we likely want to put that information in here as well. }; + /// Represents the 'error' state of parsing an OpenACC Clause, and stores + /// whether we can continue parsing, or should give up on the directive. + enum class OpenACCParseCanContinue { Cannot = 0, Can = 1 }; + + /// A type to represent the state of parsing an OpenACC Clause. Situations + /// that result in an OpenACCClause pointer are a success and can continue + /// parsing, however some other situations can also continue. + /// FIXME: This is better represented as a std::expected when we get C++23. + using OpenACCClauseParseResult = + llvm::PointerIntPair; + + OpenACCClauseParseResult OpenACCCanContinue(); + OpenACCClauseParseResult OpenACCCannotContinue(); + OpenACCClauseParseResult OpenACCSuccess(OpenACCClause *Clause); + /// Parses the OpenACC directive (the entire pragma) including the clause /// list, but does not produce the main AST node. OpenACCDirectiveParseInfo ParseOpenACCDirective(); @@ -3612,12 +3625,18 @@ private: bool ParseOpenACCClauseVarList(OpenACCClauseKind Kind); /// Parses any parameters for an OpenACC Clause, including required/optional /// parens. - bool ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, - OpenACCClauseKind Kind); - /// Parses a single clause in a clause-list for OpenACC. - bool ParseOpenACCClause(OpenACCDirectiveKind DirKind); + OpenACCClauseParseResult + ParseOpenACCClauseParams(ArrayRef ExistingClauses, + OpenACCDirectiveKind DirKind, OpenACCClauseKind Kind, + SourceLocation ClauseLoc); + /// Parses a single clause in a clause-list for OpenACC. Returns nullptr on + /// error. + OpenACCClauseParseResult + ParseOpenACCClause(ArrayRef ExistingClauses, + OpenACCDirectiveKind DirKind); /// Parses the clause-list for an OpenACC directive. - void ParseOpenACCClauseList(OpenACCDirectiveKind DirKind); + SmallVector + ParseOpenACCClauseList(OpenACCDirectiveKind DirKind); bool ParseOpenACCWaitArgument(); /// Parses the clause of the 'bind' argument, which can be a string literal or /// an ID expression. diff --git a/clang/include/clang/Sema/CodeCompleteConsumer.h b/clang/include/clang/Sema/CodeCompleteConsumer.h index a2028e40f83d54c1008d78568ad67cfe47479449..0924dc27af82b512331dd3049f41319880c5cd48 100644 --- a/clang/include/clang/Sema/CodeCompleteConsumer.h +++ b/clang/include/clang/Sema/CodeCompleteConsumer.h @@ -362,7 +362,7 @@ private: QualType BaseType; /// The identifiers for Objective-C selector parts. - ArrayRef SelIdents; + ArrayRef SelIdents; /// The scope specifier that comes before the completion token e.g. /// "a::b::" @@ -378,8 +378,9 @@ public: : CCKind(CCKind), IsUsingDeclaration(false), SelIdents(std::nullopt) {} /// Construct a new code-completion context of the given kind. - CodeCompletionContext(Kind CCKind, QualType T, - ArrayRef SelIdents = std::nullopt) + CodeCompletionContext( + Kind CCKind, QualType T, + ArrayRef SelIdents = std::nullopt) : CCKind(CCKind), IsUsingDeclaration(false), SelIdents(SelIdents) { if (CCKind == CCC_DotMemberAccess || CCKind == CCC_ArrowMemberAccess || CCKind == CCC_ObjCPropertyAccess || CCKind == CCC_ObjCClassMessage || @@ -406,7 +407,7 @@ public: QualType getBaseType() const { return BaseType; } /// Retrieve the Objective-C selector identifiers. - ArrayRef getSelIdents() const { return SelIdents; } + ArrayRef getSelIdents() const { return SelIdents; } /// Determines whether we want C++ constructors as results within this /// context. diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index a176159707486c61f618ec55e78d100b1a4a9d0a..c9eecdafe62c7ce148f69dfbfca8f791e129112d 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -1049,7 +1049,7 @@ public: union { /// When Kind == IK_Identifier, the parsed identifier, or when /// Kind == IK_UserLiteralId, the identifier suffix. - IdentifierInfo *Identifier; + const IdentifierInfo *Identifier; /// When Kind == IK_OperatorFunctionId, the overloaded operator /// that we parsed. @@ -1111,7 +1111,7 @@ public: /// \param IdLoc the location of the parsed identifier. void setIdentifier(const IdentifierInfo *Id, SourceLocation IdLoc) { Kind = UnqualifiedIdKind::IK_Identifier; - Identifier = const_cast(Id); + Identifier = Id; StartLocation = EndLocation = IdLoc; } @@ -1154,9 +1154,9 @@ public: /// /// \param IdLoc the location of the identifier. void setLiteralOperatorId(const IdentifierInfo *Id, SourceLocation OpLoc, - SourceLocation IdLoc) { + SourceLocation IdLoc) { Kind = UnqualifiedIdKind::IK_LiteralOperatorId; - Identifier = const_cast(Id); + Identifier = Id; StartLocation = OpLoc; EndLocation = IdLoc; } @@ -1225,7 +1225,7 @@ public: /// \param Id the identifier. void setImplicitSelfParam(const IdentifierInfo *Id) { Kind = UnqualifiedIdKind::IK_ImplicitSelfParam; - Identifier = const_cast(Id); + Identifier = Id; StartLocation = EndLocation = SourceLocation(); } @@ -1327,7 +1327,7 @@ struct DeclaratorChunk { /// Parameter type lists will have type info (if the actions module provides /// it), but may have null identifier info: e.g. for 'void foo(int X, int)'. struct ParamInfo { - IdentifierInfo *Ident; + const IdentifierInfo *Ident; SourceLocation IdentLoc; Decl *Param; @@ -1339,11 +1339,10 @@ struct DeclaratorChunk { std::unique_ptr DefaultArgTokens; ParamInfo() = default; - ParamInfo(IdentifierInfo *ident, SourceLocation iloc, - Decl *param, + ParamInfo(const IdentifierInfo *ident, SourceLocation iloc, Decl *param, std::unique_ptr DefArgTokens = nullptr) - : Ident(ident), IdentLoc(iloc), Param(param), - DefaultArgTokens(std::move(DefArgTokens)) {} + : Ident(ident), IdentLoc(iloc), Param(param), + DefaultArgTokens(std::move(DefArgTokens)) {} }; struct TypeAndRange { @@ -2326,7 +2325,7 @@ public: return BindingGroup.isSet(); } - IdentifierInfo *getIdentifier() const { + const IdentifierInfo *getIdentifier() const { if (Name.getKind() == UnqualifiedIdKind::IK_Identifier) return Name.Identifier; @@ -2335,7 +2334,7 @@ public: SourceLocation getIdentifierLoc() const { return Name.StartLocation; } /// Set the name of this declarator to be the given identifier. - void SetIdentifier(IdentifierInfo *Id, SourceLocation IdLoc) { + void SetIdentifier(const IdentifierInfo *Id, SourceLocation IdLoc) { Name.setIdentifier(Id, IdLoc); } diff --git a/clang/include/clang/Sema/Overload.h b/clang/include/clang/Sema/Overload.h index e4717dd5baf1e8d2fd91f47291803ff81a72971c..76311b00d2fc586fc249b1a3e0456412ddc4b05e 100644 --- a/clang/include/clang/Sema/Overload.h +++ b/clang/include/clang/Sema/Overload.h @@ -198,6 +198,9 @@ class Sema; /// HLSL vector truncation. ICK_HLSL_Vector_Truncation, + /// HLSL non-decaying array rvalue cast. + ICK_HLSL_Array_RValue, + /// The number of conversion kinds ICK_Num_Conversion_Kinds, }; diff --git a/clang/include/clang/Sema/ParsedTemplate.h b/clang/include/clang/Sema/ParsedTemplate.h index 65182d57246ae7209ac06f03449c87f1c4808380..ac4dbbf294caf2f61ff785f992d18d5713cd30d3 100644 --- a/clang/include/clang/Sema/ParsedTemplate.h +++ b/clang/include/clang/Sema/ParsedTemplate.h @@ -159,7 +159,7 @@ namespace clang { SourceLocation TemplateNameLoc; /// FIXME: Temporarily stores the name of a specialization - IdentifierInfo *Name; + const IdentifierInfo *Name; /// FIXME: Temporarily stores the overloaded operator kind. OverloadedOperatorKind Operator; @@ -197,7 +197,7 @@ namespace clang { /// appends it to List. static TemplateIdAnnotation * Create(SourceLocation TemplateKWLoc, SourceLocation TemplateNameLoc, - IdentifierInfo *Name, OverloadedOperatorKind OperatorKind, + const IdentifierInfo *Name, OverloadedOperatorKind OperatorKind, ParsedTemplateTy OpaqueTemplateName, TemplateNameKind TemplateKind, SourceLocation LAngleLoc, SourceLocation RAngleLoc, ArrayRef TemplateArgs, bool ArgsInvalid, @@ -236,7 +236,8 @@ namespace clang { TemplateIdAnnotation(const TemplateIdAnnotation &) = delete; TemplateIdAnnotation(SourceLocation TemplateKWLoc, - SourceLocation TemplateNameLoc, IdentifierInfo *Name, + SourceLocation TemplateNameLoc, + const IdentifierInfo *Name, OverloadedOperatorKind OperatorKind, ParsedTemplateTy OpaqueTemplateName, TemplateNameKind TemplateKind, diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 5ecd2f9eb2881f3d6e5e19a0409b8b8f5d533117..351b8e1f31134fe87920acfd9e651f789e7080af 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -33,7 +33,6 @@ #include "clang/AST/NSAPI.h" #include "clang/AST/PrettyPrinter.h" #include "clang/AST/StmtCXX.h" -#include "clang/AST/StmtOpenACC.h" #include "clang/AST/StmtOpenMP.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeOrdering.h" @@ -42,7 +41,6 @@ #include "clang/Basic/DarwinSDKInfo.h" #include "clang/Basic/ExpressionTraits.h" #include "clang/Basic/Module.h" -#include "clang/Basic/OpenACCKinds.h" #include "clang/Basic/OpenCLOptions.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/PragmaKinds.h" @@ -57,6 +55,7 @@ #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/Ownership.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/SemaBase.h" #include "clang/Sema/SemaConcept.h" #include "clang/Sema/TypoCorrection.h" #include "clang/Sema/Weak.h" @@ -183,6 +182,9 @@ class Preprocessor; class PseudoDestructorTypeStorage; class PseudoObjectExpr; class QualType; +class SemaHLSL; +class SemaOpenACC; +class SemaSYCL; class StandardConversionSequence; class Stmt; class StringLiteral; @@ -423,7 +425,7 @@ enum class TemplateDeductionResult { /// Sema - This implements semantic analysis and AST building for C. /// \nosubgrouping -class Sema final { +class Sema final : public SemaBase { // Table of Contents // ----------------- // 1. Semantic Analysis (Sema.cpp) @@ -465,10 +467,7 @@ class Sema final { // 36. FixIt Helpers (SemaFixItUtils.cpp) // 37. Name Lookup for RISC-V Vector Intrinsic (SemaRISCVVectorLookup.cpp) // 38. CUDA (SemaCUDA.cpp) - // 39. HLSL Constructs (SemaHLSL.cpp) - // 40. OpenACC Constructs (SemaOpenACC.cpp) - // 41. OpenMP Directives and Clauses (SemaOpenMP.cpp) - // 42. SYCL Constructs (SemaSYCL.cpp) + // 39. OpenMP Directives and Clauses (SemaOpenMP.cpp) /// \name Semantic Analysis /// Implementations are in Sema.cpp @@ -514,195 +513,6 @@ public: /// void addExternalSource(ExternalSemaSource *E); - /// Helper class that creates diagnostics with optional - /// template instantiation stacks. - /// - /// This class provides a wrapper around the basic DiagnosticBuilder - /// class that emits diagnostics. ImmediateDiagBuilder is - /// responsible for emitting the diagnostic (as DiagnosticBuilder - /// does) and, if the diagnostic comes from inside a template - /// instantiation, printing the template instantiation stack as - /// well. - class ImmediateDiagBuilder : public DiagnosticBuilder { - Sema &SemaRef; - unsigned DiagID; - - public: - ImmediateDiagBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) - : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} - ImmediateDiagBuilder(DiagnosticBuilder &&DB, Sema &SemaRef, unsigned DiagID) - : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} - - // This is a cunning lie. DiagnosticBuilder actually performs move - // construction in its copy constructor (but due to varied uses, it's not - // possible to conveniently express this as actual move construction). So - // the default copy ctor here is fine, because the base class disables the - // source anyway, so the user-defined ~ImmediateDiagBuilder is a safe no-op - // in that case anwyay. - ImmediateDiagBuilder(const ImmediateDiagBuilder &) = default; - - ~ImmediateDiagBuilder() { - // If we aren't active, there is nothing to do. - if (!isActive()) - return; - - // Otherwise, we need to emit the diagnostic. First clear the diagnostic - // builder itself so it won't emit the diagnostic in its own destructor. - // - // This seems wasteful, in that as written the DiagnosticBuilder dtor will - // do its own needless checks to see if the diagnostic needs to be - // emitted. However, because we take care to ensure that the builder - // objects never escape, a sufficiently smart compiler will be able to - // eliminate that code. - Clear(); - - // Dispatch to Sema to emit the diagnostic. - SemaRef.EmitCurrentDiagnostic(DiagID); - } - - /// Teach operator<< to produce an object of the correct type. - template - friend const ImmediateDiagBuilder & - operator<<(const ImmediateDiagBuilder &Diag, const T &Value) { - const DiagnosticBuilder &BaseDiag = Diag; - BaseDiag << Value; - return Diag; - } - - // It is necessary to limit this to rvalue reference to avoid calling this - // function with a bitfield lvalue argument since non-const reference to - // bitfield is not allowed. - template ::value>> - const ImmediateDiagBuilder &operator<<(T &&V) const { - const DiagnosticBuilder &BaseDiag = *this; - BaseDiag << std::move(V); - return *this; - } - }; - - /// A generic diagnostic builder for errors which may or may not be deferred. - /// - /// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch) - /// which are not allowed to appear inside __device__ functions and are - /// allowed to appear in __host__ __device__ functions only if the host+device - /// function is never codegen'ed. - /// - /// To handle this, we use the notion of "deferred diagnostics", where we - /// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed. - /// - /// This class lets you emit either a regular diagnostic, a deferred - /// diagnostic, or no diagnostic at all, according to an argument you pass to - /// its constructor, thus simplifying the process of creating these "maybe - /// deferred" diagnostics. - class SemaDiagnosticBuilder { - public: - enum Kind { - /// Emit no diagnostics. - K_Nop, - /// Emit the diagnostic immediately (i.e., behave like Sema::Diag()). - K_Immediate, - /// Emit the diagnostic immediately, and, if it's a warning or error, also - /// emit a call stack showing how this function can be reached by an a - /// priori known-emitted function. - K_ImmediateWithCallStack, - /// Create a deferred diagnostic, which is emitted only if the function - /// it's attached to is codegen'ed. Also emit a call stack as with - /// K_ImmediateWithCallStack. - K_Deferred - }; - - SemaDiagnosticBuilder(Kind K, SourceLocation Loc, unsigned DiagID, - const FunctionDecl *Fn, Sema &S); - SemaDiagnosticBuilder(SemaDiagnosticBuilder &&D); - SemaDiagnosticBuilder(const SemaDiagnosticBuilder &) = default; - - // The copy and move assignment operator is defined as deleted pending - // further motivation. - SemaDiagnosticBuilder &operator=(const SemaDiagnosticBuilder &) = delete; - SemaDiagnosticBuilder &operator=(SemaDiagnosticBuilder &&) = delete; - - ~SemaDiagnosticBuilder(); - - bool isImmediate() const { return ImmediateDiag.has_value(); } - - /// Convertible to bool: True if we immediately emitted an error, false if - /// we didn't emit an error or we created a deferred error. - /// - /// Example usage: - /// - /// if (SemaDiagnosticBuilder(...) << foo << bar) - /// return ExprError(); - /// - /// But see CUDADiagIfDeviceCode() and CUDADiagIfHostCode() -- you probably - /// want to use these instead of creating a SemaDiagnosticBuilder yourself. - operator bool() const { return isImmediate(); } - - template - friend const SemaDiagnosticBuilder & - operator<<(const SemaDiagnosticBuilder &Diag, const T &Value) { - if (Diag.ImmediateDiag) - *Diag.ImmediateDiag << Value; - else if (Diag.PartialDiagId) - Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second - << Value; - return Diag; - } - - // It is necessary to limit this to rvalue reference to avoid calling this - // function with a bitfield lvalue argument since non-const reference to - // bitfield is not allowed. - template ::value>> - const SemaDiagnosticBuilder &operator<<(T &&V) const { - if (ImmediateDiag) - *ImmediateDiag << std::move(V); - else if (PartialDiagId) - S.DeviceDeferredDiags[Fn][*PartialDiagId].second << std::move(V); - return *this; - } - - friend const SemaDiagnosticBuilder & - operator<<(const SemaDiagnosticBuilder &Diag, const PartialDiagnostic &PD) { - if (Diag.ImmediateDiag) - PD.Emit(*Diag.ImmediateDiag); - else if (Diag.PartialDiagId) - Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second = PD; - return Diag; - } - - void AddFixItHint(const FixItHint &Hint) const { - if (ImmediateDiag) - ImmediateDiag->AddFixItHint(Hint); - else if (PartialDiagId) - S.DeviceDeferredDiags[Fn][*PartialDiagId].second.AddFixItHint(Hint); - } - - friend ExprResult ExprError(const SemaDiagnosticBuilder &) { - return ExprError(); - } - friend StmtResult StmtError(const SemaDiagnosticBuilder &) { - return StmtError(); - } - operator ExprResult() const { return ExprError(); } - operator StmtResult() const { return StmtError(); } - operator TypeResult() const { return TypeError(); } - operator DeclResult() const { return DeclResult(true); } - operator MemInitResult() const { return MemInitResult(true); } - - private: - Sema &S; - SourceLocation Loc; - unsigned DiagID; - const FunctionDecl *Fn; - bool ShowCallStack; - - // Invariant: At most one of these Optionals has a value. - // FIXME: Switch these to a Variant once that exists. - std::optional ImmediateDiag; - std::optional PartialDiagId; - }; - void PrintStats() const; /// Warn that the stack is nearly exhausted. @@ -744,14 +554,6 @@ public: void addImplicitTypedef(StringRef Name, QualType T); - /// Emit a diagnostic. - SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, - bool DeferHint = false); - - /// Emit a partial diagnostic. - SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD, - bool DeferHint = false); - /// Whether uncompilable error has occurred. This includes error happens /// in deferred diagnostics. bool hasUncompilableErrorOccurred() const; @@ -766,7 +568,7 @@ public: /// Invent a new identifier for parameters of abbreviated templates. IdentifierInfo * - InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName, + InventAbbreviatedTemplateParameterTypeName(const IdentifierInfo *ParamName, unsigned Index); void emitAndClearUnusedLocalTypedefWarnings(); @@ -1162,6 +964,21 @@ public: /// CurContext - This is the current declaration context of parsing. DeclContext *CurContext; + SemaHLSL &HLSL() { + assert(HLSLPtr); + return *HLSLPtr; + } + + SemaOpenACC &OpenACC() { + assert(OpenACCPtr); + return *OpenACCPtr; + } + + SemaSYCL &SYCL() { + assert(SYCLPtr); + return *SYCLPtr; + } + protected: friend class Parser; friend class InitializationSequence; @@ -1192,6 +1009,10 @@ private: mutable IdentifierInfo *Ident_super; + std::unique_ptr HLSLPtr; + std::unique_ptr OpenACCPtr; + std::unique_ptr SYCLPtr; + ///@} // @@ -1655,6 +1476,9 @@ public: /// Add [[gsl::Pointer]] attributes for std:: types. void inferGslPointerAttribute(TypedefNameDecl *TD); + /// Add _Nullable attributes for std:: types. + void inferNullableClassAttribute(CXXRecordDecl *CRD); + enum PragmaOptionsAlignKind { POAK_Native, // #pragma options align=native POAK_Natural, // #pragma options align=natural @@ -2019,10 +1843,10 @@ public: bool IsVariadic, FormatStringInfo *FSI); // Used by C++ template instantiation. - ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall); - ExprResult SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, - SourceLocation BuiltinLoc, - SourceLocation RParenLoc); + ExprResult BuiltinShuffleVector(CallExpr *TheCall); + ExprResult ConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc); enum FormatStringType { FST_Scanf, @@ -2155,6 +1979,11 @@ public: bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, const FunctionProtoType *Proto); + bool BuiltinVectorMath(CallExpr *TheCall, QualType &Res); + bool BuiltinVectorToScalarMath(CallExpr *TheCall); + + bool CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); + private: void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, const ArraySubscriptExpr *ASE = nullptr, @@ -2234,7 +2063,8 @@ private: bool CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum); bool CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); - void checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D); + void checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D, + const llvm::StringMap &FeatureMap); bool CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); bool CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, @@ -2243,62 +2073,59 @@ private: bool CheckNVPTXBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall); - bool SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall); - bool SemaBuiltinVAStartARMMicrosoft(CallExpr *Call); - bool SemaBuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID); - bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, - unsigned BuiltinID); - bool SemaBuiltinComplex(CallExpr *TheCall); - bool SemaBuiltinVSX(CallExpr *TheCall); - bool SemaBuiltinOSLogFormat(CallExpr *TheCall); - bool SemaValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum); - - bool SemaBuiltinPrefetch(CallExpr *TheCall); - bool SemaBuiltinAllocaWithAlign(CallExpr *TheCall); - bool SemaBuiltinArithmeticFence(CallExpr *TheCall); - bool SemaBuiltinAssume(CallExpr *TheCall); - bool SemaBuiltinAssumeAligned(CallExpr *TheCall); - bool SemaBuiltinLongjmp(CallExpr *TheCall); - bool SemaBuiltinSetjmp(CallExpr *TheCall); - ExprResult SemaBuiltinAtomicOverloaded(ExprResult TheCallResult); - ExprResult SemaBuiltinNontemporalOverloaded(ExprResult TheCallResult); - ExprResult SemaAtomicOpsOverloaded(ExprResult TheCallResult, - AtomicExpr::AtomicOp Op); - bool SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, - llvm::APSInt &Result); - bool SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, - int High, bool RangeIsError = true); - bool SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, - unsigned Multiple); - bool SemaBuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum); - bool SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, - unsigned ArgBits); - bool SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, int ArgNum, - unsigned ArgBits); - bool SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, - int ArgNum, unsigned ExpectedFieldNum, - bool AllowName); - bool SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall); - bool SemaBuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, - const char *TypeDesc); + bool BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall); + bool BuiltinVAStartARMMicrosoft(CallExpr *Call); + bool BuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID); + bool BuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, + unsigned BuiltinID); + bool BuiltinComplex(CallExpr *TheCall); + bool BuiltinVSX(CallExpr *TheCall); + bool BuiltinOSLogFormat(CallExpr *TheCall); + bool ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum); + + bool BuiltinPrefetch(CallExpr *TheCall); + bool BuiltinAllocaWithAlign(CallExpr *TheCall); + bool BuiltinArithmeticFence(CallExpr *TheCall); + bool BuiltinAssume(CallExpr *TheCall); + bool BuiltinAssumeAligned(CallExpr *TheCall); + bool BuiltinLongjmp(CallExpr *TheCall); + bool BuiltinSetjmp(CallExpr *TheCall); + ExprResult BuiltinAtomicOverloaded(ExprResult TheCallResult); + ExprResult BuiltinNontemporalOverloaded(ExprResult TheCallResult); + ExprResult AtomicOpsOverloaded(ExprResult TheCallResult, + AtomicExpr::AtomicOp Op); + bool BuiltinConstantArg(CallExpr *TheCall, int ArgNum, llvm::APSInt &Result); + bool BuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, int High, + bool RangeIsError = true); + bool BuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, + unsigned Multiple); + bool BuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum); + bool BuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, + unsigned ArgBits); + bool BuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, int ArgNum, + unsigned ArgBits); + bool BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, int ArgNum, + unsigned ExpectedFieldNum, bool AllowName); + bool BuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall); + bool BuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, + const char *TypeDesc); bool CheckPPCMMAType(QualType Type, SourceLocation TypeLoc); - bool SemaBuiltinElementwiseMath(CallExpr *TheCall); - bool SemaBuiltinElementwiseTernaryMath(CallExpr *TheCall, - bool CheckForFloatArgs = true); + bool BuiltinElementwiseMath(CallExpr *TheCall); + bool BuiltinElementwiseTernaryMath(CallExpr *TheCall, + bool CheckForFloatArgs = true); bool PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall); bool PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall); - bool SemaBuiltinNonDeterministicValue(CallExpr *TheCall); + bool BuiltinNonDeterministicValue(CallExpr *TheCall); // Matrix builtin handling. - ExprResult SemaBuiltinMatrixTranspose(CallExpr *TheCall, - ExprResult CallResult); - ExprResult SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall, - ExprResult CallResult); - ExprResult SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall, - ExprResult CallResult); + ExprResult BuiltinMatrixTranspose(CallExpr *TheCall, ExprResult CallResult); + ExprResult BuiltinMatrixColumnMajorLoad(CallExpr *TheCall, + ExprResult CallResult); + ExprResult BuiltinMatrixColumnMajorStore(CallExpr *TheCall, + ExprResult CallResult); // WebAssembly builtin handling. bool BuiltinWasmRefNullExtern(CallExpr *TheCall); @@ -3131,9 +2958,9 @@ public: SourceLocation NameLoc, TypeSourceInfo *TSInfo); ParmVarDecl *CheckParameter(DeclContext *DC, SourceLocation StartLoc, - SourceLocation NameLoc, IdentifierInfo *Name, - QualType T, TypeSourceInfo *TSInfo, - StorageClass SC); + SourceLocation NameLoc, + const IdentifierInfo *Name, QualType T, + TypeSourceInfo *TSInfo, StorageClass SC); // Contexts where using non-trivial C union types can be disallowed. This is // passed to err_non_trivial_c_union_in_invalid_context. @@ -3538,7 +3365,7 @@ public: /// variable. void DiagnoseUnusedButSetDecl(const VarDecl *VD, DiagReceiverTy DiagReceiver); - ObjCInterfaceDecl *getObjCInterfaceDecl(IdentifierInfo *&Id, + ObjCInterfaceDecl *getObjCInterfaceDecl(const IdentifierInfo *&Id, SourceLocation IdLoc, bool TypoCorrection = false); @@ -3615,8 +3442,9 @@ public: /// VerifyBitField - verifies that a bit field expression is an ICE and has /// the correct width, and that the field type is valid. /// Returns false on success. - ExprResult VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, - QualType FieldTy, bool IsMsStruct, Expr *BitWidth); + ExprResult VerifyBitField(SourceLocation FieldLoc, + const IdentifierInfo *FieldName, QualType FieldTy, + bool IsMsStruct, Expr *BitWidth); /// IsValueInFlagEnum - Determine if a value is allowed as part of a flag /// enum. If AllowMask is true, then we also allow the complement of a valid @@ -4811,7 +4639,8 @@ public: VarDecl *BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id); + SourceLocation IdLoc, + const IdentifierInfo *Id); Decl *ActOnExceptionDeclarator(Scope *S, Declarator &D); @@ -5618,7 +5447,8 @@ public: ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool NeedsADL, - bool AcceptInvalidDecl = false); + bool AcceptInvalidDecl = false, + bool NeedUnresolved = false); ExprResult BuildDeclarationNameExpr( const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D, NamedDecl *FoundD = nullptr, @@ -5634,15 +5464,6 @@ public: ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind); ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val); - ExprResult BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc, - SourceLocation LParen, - SourceLocation RParen, - TypeSourceInfo *TSI); - ExprResult ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc, - SourceLocation LParen, - SourceLocation RParen, - ParsedType ParsedTy); - bool CheckLoopHintExpr(Expr *E, SourceLocation Loc); ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr); @@ -6737,12 +6558,12 @@ public: ParsedType getInheritingConstructorName(CXXScopeSpec &SS, SourceLocation NameLoc, - IdentifierInfo &Name); + const IdentifierInfo &Name); - ParsedType getConstructorName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, CXXScopeSpec &SS, - bool EnteringContext); - ParsedType getDestructorName(IdentifierInfo &II, SourceLocation NameLoc, + ParsedType getConstructorName(const IdentifierInfo &II, + SourceLocation NameLoc, Scope *S, + CXXScopeSpec &SS, bool EnteringContext); + ParsedType getDestructorName(const IdentifierInfo &II, SourceLocation NameLoc, Scope *S, CXXScopeSpec &SS, ParsedType ObjectType, bool EnteringContext); @@ -6770,7 +6591,10 @@ public: SourceLocation RParenLoc); //// ActOnCXXThis - Parse 'this' pointer. - ExprResult ActOnCXXThis(SourceLocation loc); + ExprResult ActOnCXXThis(SourceLocation Loc); + + /// Check whether the type of 'this' is valid in the current context. + bool CheckCXXThisType(SourceLocation Loc, QualType Type); /// Build a CXXThisExpr and mark it referenced in the current context. Expr *BuildCXXThisExpr(SourceLocation Loc, QualType Type, bool IsImplicit); @@ -7142,7 +6966,7 @@ public: concepts::Requirement *ActOnTypeRequirement(SourceLocation TypenameKWLoc, CXXScopeSpec &SS, SourceLocation NameLoc, - IdentifierInfo *TypeName, + const IdentifierInfo *TypeName, TemplateIdAnnotation *TemplateId); concepts::Requirement *ActOnCompoundRequirement(Expr *E, SourceLocation NoexceptLoc); @@ -7173,8 +6997,8 @@ public: SourceLocation ClosingBraceLoc); private: - ExprResult SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, - bool IsDelete); + ExprResult BuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, + bool IsDelete); void AnalyzeDeleteExprMismatch(const CXXDeleteExpr *DE); void AnalyzeDeleteExprMismatch(FieldDecl *Field, SourceLocation DeleteLoc, @@ -7193,10 +7017,14 @@ private: ///@{ public: + /// Check whether an expression might be an implicit class member access. + bool isPotentialImplicitMemberAccess(const CXXScopeSpec &SS, LookupResult &R, + bool IsAddressOfOperand); + ExprResult BuildPossibleImplicitMemberExpr( const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs, const Scope *S, - UnresolvedLookupExpr *AsULE = nullptr); + const TemplateArgumentListInfo *TemplateArgs, const Scope *S); + ExprResult BuildImplicitMemberExpr(const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, @@ -9244,7 +9072,7 @@ public: Expr *DefaultArg); NamedDecl *ActOnTemplateTemplateParameter( Scope *S, SourceLocation TmpLoc, TemplateParameterList *Params, - SourceLocation EllipsisLoc, IdentifierInfo *ParamName, + bool Typename, SourceLocation EllipsisLoc, IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position, SourceLocation EqualLoc, ParsedTemplateArgument DefaultArg); @@ -9298,7 +9126,7 @@ public: TypeResult ActOnTemplateIdType(Scope *S, CXXScopeSpec &SS, SourceLocation TemplateKWLoc, - TemplateTy Template, IdentifierInfo *TemplateII, + TemplateTy Template, const IdentifierInfo *TemplateII, SourceLocation TemplateIILoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc, bool IsCtorOrDtorName = false, bool IsClassName = false, @@ -9639,7 +9467,7 @@ public: TypeResult ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, const CXXScopeSpec &SS, SourceLocation TemplateLoc, - TemplateTy TemplateName, IdentifierInfo *TemplateII, + TemplateTy TemplateName, const IdentifierInfo *TemplateII, SourceLocation TemplateIILoc, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgs, SourceLocation RAngleLoc); @@ -9704,7 +9532,8 @@ public: /// not already done so. void DeclareImplicitDeductionGuides(TemplateDecl *Template, SourceLocation Loc); - FunctionTemplateDecl *DeclareImplicitDeductionGuideFromInitList( + + FunctionTemplateDecl *DeclareAggregateDeductionGuideFromInitList( TemplateDecl *Template, MutableArrayRef ParamTypes, SourceLocation Loc); @@ -9716,14 +9545,15 @@ public: Decl *ActOnConceptDefinition(Scope *S, MultiTemplateParamsArg TemplateParameterLists, - IdentifierInfo *Name, SourceLocation NameLoc, - Expr *ConstraintExpr); + const IdentifierInfo *Name, + SourceLocation NameLoc, Expr *ConstraintExpr); void CheckConceptRedefinition(ConceptDecl *NewDecl, LookupResult &Previous, bool &AddToScope); TypeResult ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, - const CXXScopeSpec &SS, IdentifierInfo *Name, + const CXXScopeSpec &SS, + const IdentifierInfo *Name, SourceLocation TagLoc, SourceLocation NameLoc); void MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD, @@ -10161,6 +9991,9 @@ public: /// We are building deduction guides for a class. BuildingDeductionGuides, + + /// We are instantiating a type alias template declaration. + TypeAliasTemplateInstantiation, } Kind; /// Was the enclosing context a non-instantiation SFINAE context? @@ -10250,6 +10083,12 @@ public: FunctionDecl *Entity, ExceptionSpecification, SourceRange InstantiationRange = SourceRange()); + /// Note that we are instantiating a type alias template declaration. + InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, + TypeAliasTemplateDecl *Entity, + ArrayRef TemplateArgs, + SourceRange InstantiationRange = SourceRange()); + /// Note that we are instantiating a default argument in a /// template-id. InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -12160,22 +11999,22 @@ public: SkipBodyInfo *SkipBody); ObjCCategoryDecl *ActOnStartCategoryInterface( - SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, + SourceLocation AtInterfaceLoc, const IdentifierInfo *ClassName, SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, - IdentifierInfo *CategoryName, SourceLocation CategoryLoc, + const IdentifierInfo *CategoryName, SourceLocation CategoryLoc, Decl *const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, const ParsedAttributesView &AttrList); ObjCImplementationDecl *ActOnStartClassImplementation( - SourceLocation AtClassImplLoc, IdentifierInfo *ClassName, - SourceLocation ClassLoc, IdentifierInfo *SuperClassname, + SourceLocation AtClassImplLoc, const IdentifierInfo *ClassName, + SourceLocation ClassLoc, const IdentifierInfo *SuperClassname, SourceLocation SuperClassLoc, const ParsedAttributesView &AttrList); ObjCCategoryImplDecl *ActOnStartCategoryImplementation( - SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, - SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc, - const ParsedAttributesView &AttrList); + SourceLocation AtCatImplLoc, const IdentifierInfo *ClassName, + SourceLocation ClassLoc, const IdentifierInfo *CatName, + SourceLocation CatLoc, const ParsedAttributesView &AttrList); DeclGroupPtrTy ActOnFinishObjCImplementation(Decl *ObjCImpDecl, ArrayRef Decls); @@ -12358,11 +12197,13 @@ public: bool CheckObjCDeclScope(Decl *D); void ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, - IdentifierInfo *ClassName, SmallVectorImpl &Decls); + const IdentifierInfo *ClassName, + SmallVectorImpl &Decls); VarDecl *BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType ExceptionType, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, bool Invalid = false); + const IdentifierInfo *Id, + bool Invalid = false); Decl *ActOnObjCExceptionDecl(Scope *S, Declarator &D); @@ -12479,8 +12320,8 @@ public: SourceLocation SuperLoc, QualType SuperType, bool Super); - ExprResult ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, - IdentifierInfo &propertyName, + ExprResult ActOnClassPropertyRefExpr(const IdentifierInfo &receiverName, + const IdentifierInfo &propertyName, SourceLocation receiverNameLoc, SourceLocation propertyNameLoc); @@ -12955,18 +12796,18 @@ public: bool IsParameter); void CodeCompleteObjCMessageReceiver(Scope *S); void CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, - ArrayRef SelIdents, + ArrayRef SelIdents, bool AtArgumentExpression); void CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, - ArrayRef SelIdents, + ArrayRef SelIdents, bool AtArgumentExpression, bool IsSuper = false); - void CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, - ArrayRef SelIdents, - bool AtArgumentExpression, - ObjCInterfaceDecl *Super = nullptr); + void CodeCompleteObjCInstanceMessage( + Scope *S, Expr *Receiver, ArrayRef SelIdents, + bool AtArgumentExpression, ObjCInterfaceDecl *Super = nullptr); void CodeCompleteObjCForCollection(Scope *S, DeclGroupPtrTy IterationVar); - void CodeCompleteObjCSelector(Scope *S, ArrayRef SelIdents); + void CodeCompleteObjCSelector(Scope *S, + ArrayRef SelIdents); void CodeCompleteObjCProtocolReferences(ArrayRef Protocols); void CodeCompleteObjCProtocolDecl(Scope *S); @@ -12986,11 +12827,11 @@ public: void CodeCompleteObjCMethodDecl(Scope *S, std::optional IsInstanceMethod, ParsedType ReturnType); - void CodeCompleteObjCMethodDeclSelector(Scope *S, bool IsInstanceMethod, - bool AtParameterName, - ParsedType ReturnType, - ArrayRef SelIdents); - void CodeCompleteObjCClassPropertyRefExpr(Scope *S, IdentifierInfo &ClassName, + void CodeCompleteObjCMethodDeclSelector( + Scope *S, bool IsInstanceMethod, bool AtParameterName, + ParsedType ReturnType, ArrayRef SelIdents); + void CodeCompleteObjCClassPropertyRefExpr(Scope *S, + const IdentifierInfo &ClassName, SourceLocation ClassNameLoc, bool IsBaseExprStatement); void CodeCompletePreprocessorDirective(bool InConditional); @@ -13096,9 +12937,7 @@ public: /// Diagnostics that are emitted only if we discover that the given function /// must be codegen'ed. Because handling these correctly adds overhead to /// compilation, this is currently only enabled for CUDA compilations. - llvm::DenseMap, - std::vector> - DeviceDeferredDiags; + SemaDiagnosticBuilder::DeferredDiagnosticsType DeviceDeferredDiags; /// A pair of a canonical FunctionDecl and a SourceLocation. When used as the /// key in a hashtable, both the FD and location are hashed. @@ -13327,79 +13166,6 @@ private: // // - /// \name HLSL Constructs - /// Implementations are in SemaHLSL.cpp - ///@{ - -public: - Decl *ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer, - SourceLocation KwLoc, IdentifierInfo *Ident, - SourceLocation IdentLoc, SourceLocation LBrace); - void ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace); - - bool CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall); - - bool SemaBuiltinVectorMath(CallExpr *TheCall, QualType &Res); - bool SemaBuiltinVectorToScalarMath(CallExpr *TheCall); - - ///@} - - // - // - // ------------------------------------------------------------------------- - // - // - - /// \name OpenACC Constructs - /// Implementations are in SemaOpenACC.cpp - ///@{ - -public: - /// Called after parsing an OpenACC Clause so that it can be checked. - bool ActOnOpenACCClause(OpenACCClauseKind ClauseKind, - SourceLocation StartLoc); - - /// Called after the construct has been parsed, but clauses haven't been - /// parsed. This allows us to diagnose not-implemented, as well as set up any - /// state required for parsing the clauses. - void ActOnOpenACCConstruct(OpenACCDirectiveKind K, SourceLocation StartLoc); - - /// Called after the directive, including its clauses, have been parsed and - /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES - /// happen before any associated declarations or statements have been parsed. - /// This function is only called when we are parsing a 'statement' context. - bool ActOnStartOpenACCStmtDirective(OpenACCDirectiveKind K, - SourceLocation StartLoc); - - /// Called after the directive, including its clauses, have been parsed and - /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES - /// happen before any associated declarations or statements have been parsed. - /// This function is only called when we are parsing a 'Decl' context. - bool ActOnStartOpenACCDeclDirective(OpenACCDirectiveKind K, - SourceLocation StartLoc); - /// Called when we encounter an associated statement for our construct, this - /// should check legality of the statement as it appertains to this Construct. - StmtResult ActOnOpenACCAssociatedStmt(OpenACCDirectiveKind K, - StmtResult AssocStmt); - - /// Called after the directive has been completely parsed, including the - /// declaration group or associated statement. - StmtResult ActOnEndOpenACCStmtDirective(OpenACCDirectiveKind K, - SourceLocation StartLoc, - SourceLocation EndLoc, - StmtResult AssocStmt); - /// Called after the directive has been completely parsed, including the - /// declaration group or associated statement. - DeclGroupRef ActOnEndOpenACCDeclDirective(); - - ///@} - - // - // - // ------------------------------------------------------------------------- - // - // - /// \name OpenMP Directives and Clauses /// Implementations are in SemaOpenMP.cpp ///@{ @@ -14760,44 +14526,6 @@ private: OpenMPDirectiveKind CancelRegion); ///@} - - // - // - // ------------------------------------------------------------------------- - // - // - - /// \name SYCL Constructs - /// Implementations are in SemaSYCL.cpp - ///@{ - -public: - /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current - /// context is "used as device code". - /// - /// - If CurLexicalContext is a kernel function or it is known that the - /// function will be emitted for the device, emits the diagnostics - /// immediately. - /// - If CurLexicalContext is a function and we are compiling - /// for the device, but we don't know that this function will be codegen'ed - /// for devive yet, creates a diagnostic which is emitted if and when we - /// realize that the function will be codegen'ed. - /// - /// Example usage: - /// - /// Diagnose __float128 type usage only from SYCL device code if the current - /// target doesn't support it - /// if (!S.Context.getTargetInfo().hasFloat128Type() && - /// S.getLangOpts().SYCLIsDevice) - /// SYCLDiagIfDeviceCode(Loc, diag::err_type_unsupported) << "__float128"; - SemaDiagnosticBuilder SYCLDiagIfDeviceCode(SourceLocation Loc, - unsigned DiagID); - - void deepTypeCheckForSYCLDevice(SourceLocation UsedAt, - llvm::DenseSet Visited, - ValueDecl *DeclToCheck); - - ///@} }; DeductionFailureInfo diff --git a/clang/include/clang/Sema/SemaBase.h b/clang/include/clang/Sema/SemaBase.h new file mode 100644 index 0000000000000000000000000000000000000000..ff718022fca03cbc91c2efb79b02c21aceafd626 --- /dev/null +++ b/clang/include/clang/Sema/SemaBase.h @@ -0,0 +1,224 @@ +//===--- SemaBase.h - Common utilities for semantic analysis-----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the SemaBase class, which provides utilities for Sema +// and its parts like SemaOpenACC. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMABASE_H +#define LLVM_CLANG_SEMA_SEMABASE_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Redeclarable.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/Ownership.h" +#include "llvm/ADT/DenseMap.h" +#include +#include +#include +#include + +namespace clang { + +class ASTContext; +class DiagnosticsEngine; +class LangOptions; +class Sema; + +class SemaBase { +public: + SemaBase(Sema &S); + + Sema &SemaRef; + + ASTContext &getASTContext() const; + DiagnosticsEngine &getDiagnostics() const; + const LangOptions &getLangOpts() const; + + /// Helper class that creates diagnostics with optional + /// template instantiation stacks. + /// + /// This class provides a wrapper around the basic DiagnosticBuilder + /// class that emits diagnostics. ImmediateDiagBuilder is + /// responsible for emitting the diagnostic (as DiagnosticBuilder + /// does) and, if the diagnostic comes from inside a template + /// instantiation, printing the template instantiation stack as + /// well. + class ImmediateDiagBuilder : public DiagnosticBuilder { + Sema &SemaRef; + unsigned DiagID; + + public: + ImmediateDiagBuilder(DiagnosticBuilder &DB, Sema &SemaRef, unsigned DiagID) + : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} + ImmediateDiagBuilder(DiagnosticBuilder &&DB, Sema &SemaRef, unsigned DiagID) + : DiagnosticBuilder(DB), SemaRef(SemaRef), DiagID(DiagID) {} + + // This is a cunning lie. DiagnosticBuilder actually performs move + // construction in its copy constructor (but due to varied uses, it's not + // possible to conveniently express this as actual move construction). So + // the default copy ctor here is fine, because the base class disables the + // source anyway, so the user-defined ~ImmediateDiagBuilder is a safe no-op + // in that case anwyay. + ImmediateDiagBuilder(const ImmediateDiagBuilder &) = default; + + ~ImmediateDiagBuilder(); + + /// Teach operator<< to produce an object of the correct type. + template + friend const ImmediateDiagBuilder & + operator<<(const ImmediateDiagBuilder &Diag, const T &Value) { + const DiagnosticBuilder &BaseDiag = Diag; + BaseDiag << Value; + return Diag; + } + + // It is necessary to limit this to rvalue reference to avoid calling this + // function with a bitfield lvalue argument since non-const reference to + // bitfield is not allowed. + template ::value>> + const ImmediateDiagBuilder &operator<<(T &&V) const { + const DiagnosticBuilder &BaseDiag = *this; + BaseDiag << std::move(V); + return *this; + } + }; + + /// A generic diagnostic builder for errors which may or may not be deferred. + /// + /// In CUDA, there exist constructs (e.g. variable-length arrays, try/catch) + /// which are not allowed to appear inside __device__ functions and are + /// allowed to appear in __host__ __device__ functions only if the host+device + /// function is never codegen'ed. + /// + /// To handle this, we use the notion of "deferred diagnostics", where we + /// attach a diagnostic to a FunctionDecl that's emitted iff it's codegen'ed. + /// + /// This class lets you emit either a regular diagnostic, a deferred + /// diagnostic, or no diagnostic at all, according to an argument you pass to + /// its constructor, thus simplifying the process of creating these "maybe + /// deferred" diagnostics. + class SemaDiagnosticBuilder { + public: + enum Kind { + /// Emit no diagnostics. + K_Nop, + /// Emit the diagnostic immediately (i.e., behave like Sema::Diag()). + K_Immediate, + /// Emit the diagnostic immediately, and, if it's a warning or error, also + /// emit a call stack showing how this function can be reached by an a + /// priori known-emitted function. + K_ImmediateWithCallStack, + /// Create a deferred diagnostic, which is emitted only if the function + /// it's attached to is codegen'ed. Also emit a call stack as with + /// K_ImmediateWithCallStack. + K_Deferred + }; + + SemaDiagnosticBuilder(Kind K, SourceLocation Loc, unsigned DiagID, + const FunctionDecl *Fn, Sema &S); + SemaDiagnosticBuilder(SemaDiagnosticBuilder &&D); + SemaDiagnosticBuilder(const SemaDiagnosticBuilder &) = default; + + // The copy and move assignment operator is defined as deleted pending + // further motivation. + SemaDiagnosticBuilder &operator=(const SemaDiagnosticBuilder &) = delete; + SemaDiagnosticBuilder &operator=(SemaDiagnosticBuilder &&) = delete; + + ~SemaDiagnosticBuilder(); + + bool isImmediate() const { return ImmediateDiag.has_value(); } + + /// Convertible to bool: True if we immediately emitted an error, false if + /// we didn't emit an error or we created a deferred error. + /// + /// Example usage: + /// + /// if (SemaDiagnosticBuilder(...) << foo << bar) + /// return ExprError(); + /// + /// But see CUDADiagIfDeviceCode() and CUDADiagIfHostCode() -- you probably + /// want to use these instead of creating a SemaDiagnosticBuilder yourself. + operator bool() const { return isImmediate(); } + + template + friend const SemaDiagnosticBuilder & + operator<<(const SemaDiagnosticBuilder &Diag, const T &Value) { + if (Diag.ImmediateDiag) + *Diag.ImmediateDiag << Value; + else if (Diag.PartialDiagId) + Diag.getDeviceDeferredDiags()[Diag.Fn][*Diag.PartialDiagId].second + << Value; + return Diag; + } + + // It is necessary to limit this to rvalue reference to avoid calling this + // function with a bitfield lvalue argument since non-const reference to + // bitfield is not allowed. + template ::value>> + const SemaDiagnosticBuilder &operator<<(T &&V) const { + if (ImmediateDiag) + *ImmediateDiag << std::move(V); + else if (PartialDiagId) + getDeviceDeferredDiags()[Fn][*PartialDiagId].second << std::move(V); + return *this; + } + + friend const SemaDiagnosticBuilder & + operator<<(const SemaDiagnosticBuilder &Diag, const PartialDiagnostic &PD); + + void AddFixItHint(const FixItHint &Hint) const; + + friend ExprResult ExprError(const SemaDiagnosticBuilder &) { + return ExprError(); + } + friend StmtResult StmtError(const SemaDiagnosticBuilder &) { + return StmtError(); + } + operator ExprResult() const { return ExprError(); } + operator StmtResult() const { return StmtError(); } + operator TypeResult() const { return TypeError(); } + operator DeclResult() const { return DeclResult(true); } + operator MemInitResult() const { return MemInitResult(true); } + + using DeferredDiagnosticsType = + llvm::DenseMap, + std::vector>; + + private: + Sema &S; + SourceLocation Loc; + unsigned DiagID; + const FunctionDecl *Fn; + bool ShowCallStack; + + // Invariant: At most one of these Optionals has a value. + // FIXME: Switch these to a Variant once that exists. + std::optional ImmediateDiag; + std::optional PartialDiagId; + + DeferredDiagnosticsType &getDeviceDeferredDiags() const; + }; + + /// Emit a diagnostic. + SemaDiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID, + bool DeferHint = false); + + /// Emit a partial diagnostic. + SemaDiagnosticBuilder Diag(SourceLocation Loc, const PartialDiagnostic &PD, + bool DeferHint = false); +}; + +} // namespace clang + +#endif diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h new file mode 100644 index 0000000000000000000000000000000000000000..acc675963c23a580c93ce0e09e3f53c6145e9234 --- /dev/null +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -0,0 +1,37 @@ +//===----- SemaHLSL.h ----- Semantic Analysis for HLSL constructs ---------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis for HLSL constructs. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAHLSL_H +#define LLVM_CLANG_SEMA_SEMAHLSL_H + +#include "clang/AST/DeclBase.h" +#include "clang/AST/Expr.h" +#include "clang/Basic/IdentifierTable.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/Scope.h" +#include "clang/Sema/SemaBase.h" + +namespace clang { + +class SemaHLSL : public SemaBase { +public: + SemaHLSL(Sema &S); + + Decl *ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer, + SourceLocation KwLoc, IdentifierInfo *Ident, + SourceLocation IdentLoc, SourceLocation LBrace); + void ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace); +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAHLSL_H diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h new file mode 100644 index 0000000000000000000000000000000000000000..27aaee164a28809d585152b5c47c89c3a919d052 --- /dev/null +++ b/clang/include/clang/Sema/SemaOpenACC.h @@ -0,0 +1,117 @@ +//===----- SemaOpenACC.h - Semantic Analysis for OpenACC constructs -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis for OpenACC constructs and +/// clauses. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMAOPENACC_H +#define LLVM_CLANG_SEMA_SEMAOPENACC_H + +#include "clang/AST/DeclGroup.h" +#include "clang/Basic/OpenACCKinds.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/Ownership.h" +#include "clang/Sema/SemaBase.h" +#include + +namespace clang { +class OpenACCClause; + +class SemaOpenACC : public SemaBase { +public: + /// A type to represent all the data for an OpenACC Clause that has been + /// parsed, but not yet created/semantically analyzed. This is effectively a + /// discriminated union on the 'Clause Kind', with all of the individual + /// clause details stored in a std::variant. + class OpenACCParsedClause { + OpenACCDirectiveKind DirKind; + OpenACCClauseKind ClauseKind; + SourceRange ClauseRange; + SourceLocation LParenLoc; + + struct DefaultDetails { + OpenACCDefaultClauseKind DefaultClauseKind; + }; + + std::variant Details; + + public: + OpenACCParsedClause(OpenACCDirectiveKind DirKind, + OpenACCClauseKind ClauseKind, SourceLocation BeginLoc) + : DirKind(DirKind), ClauseKind(ClauseKind), ClauseRange(BeginLoc, {}) {} + + OpenACCDirectiveKind getDirectiveKind() const { return DirKind; } + + OpenACCClauseKind getClauseKind() const { return ClauseKind; } + + SourceLocation getBeginLoc() const { return ClauseRange.getBegin(); } + + SourceLocation getLParenLoc() const { return LParenLoc; } + + SourceLocation getEndLoc() const { return ClauseRange.getEnd(); } + + OpenACCDefaultClauseKind getDefaultClauseKind() const { + assert(ClauseKind == OpenACCClauseKind::Default && + "Parsed clause is not a default clause"); + return std::get(Details).DefaultClauseKind; + } + + void setLParenLoc(SourceLocation EndLoc) { LParenLoc = EndLoc; } + void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); } + + void setDefaultDetails(OpenACCDefaultClauseKind DefKind) { + assert(ClauseKind == OpenACCClauseKind::Default && + "Parsed clause is not a default clause"); + Details = DefaultDetails{DefKind}; + } + }; + + SemaOpenACC(Sema &S); + + /// Called after parsing an OpenACC Clause so that it can be checked. + OpenACCClause *ActOnClause(ArrayRef ExistingClauses, + OpenACCParsedClause &Clause); + + /// Called after the construct has been parsed, but clauses haven't been + /// parsed. This allows us to diagnose not-implemented, as well as set up any + /// state required for parsing the clauses. + void ActOnConstruct(OpenACCDirectiveKind K, SourceLocation StartLoc); + + /// Called after the directive, including its clauses, have been parsed and + /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES + /// happen before any associated declarations or statements have been parsed. + /// This function is only called when we are parsing a 'statement' context. + bool ActOnStartStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc); + + /// Called after the directive, including its clauses, have been parsed and + /// parsing has consumed the 'annot_pragma_openacc_end' token. This DOES + /// happen before any associated declarations or statements have been parsed. + /// This function is only called when we are parsing a 'Decl' context. + bool ActOnStartDeclDirective(OpenACCDirectiveKind K, SourceLocation StartLoc); + /// Called when we encounter an associated statement for our construct, this + /// should check legality of the statement as it appertains to this Construct. + StmtResult ActOnAssociatedStmt(OpenACCDirectiveKind K, StmtResult AssocStmt); + + /// Called after the directive has been completely parsed, including the + /// declaration group or associated statement. + StmtResult ActOnEndStmtDirective(OpenACCDirectiveKind K, + SourceLocation StartLoc, + SourceLocation EndLoc, + ArrayRef Clauses, + StmtResult AssocStmt); + + /// Called after the directive has been completely parsed, including the + /// declaration group or associated statement. + DeclGroupRef ActOnEndDeclDirective(); +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMAOPENACC_H diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h new file mode 100644 index 0000000000000000000000000000000000000000..f0dcb92ee9ab3e74a41a2d12c3287eb89e21666b --- /dev/null +++ b/clang/include/clang/Sema/SemaSYCL.h @@ -0,0 +1,65 @@ +//===----- SemaSYCL.h ------- Semantic Analysis for SYCL constructs -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// \file +/// This file declares semantic analysis for SYCL constructs. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_SEMA_SEMASYCL_H +#define LLVM_CLANG_SEMA_SEMASYCL_H + +#include "clang/AST/Decl.h" +#include "clang/AST/Type.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Sema/Ownership.h" +#include "clang/Sema/SemaBase.h" +#include "llvm/ADT/DenseSet.h" + +namespace clang { + +class SemaSYCL : public SemaBase { +public: + SemaSYCL(Sema &S); + + /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current + /// context is "used as device code". + /// + /// - If CurLexicalContext is a kernel function or it is known that the + /// function will be emitted for the device, emits the diagnostics + /// immediately. + /// - If CurLexicalContext is a function and we are compiling + /// for the device, but we don't know yet that this function will be + /// codegen'ed for the devive, creates a diagnostic which is emitted if and + /// when we realize that the function will be codegen'ed. + /// + /// Example usage: + /// + /// Diagnose __float128 type usage only from SYCL device code if the current + /// target doesn't support it + /// if (!S.Context.getTargetInfo().hasFloat128Type() && + /// S.getLangOpts().SYCLIsDevice) + /// DiagIfDeviceCode(Loc, diag::err_type_unsupported) << "__float128"; + SemaDiagnosticBuilder DiagIfDeviceCode(SourceLocation Loc, unsigned DiagID); + + void deepTypeCheckForDevice(SourceLocation UsedAt, + llvm::DenseSet Visited, + ValueDecl *DeclToCheck); + + ExprResult BuildUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + TypeSourceInfo *TSI); + ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + ParsedType ParsedTy); +}; + +} // namespace clang + +#endif // LLVM_CLANG_SEMA_SEMASYCL_H diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index f31efa5117f0d1e7d414fb23ec24bf3c98739b6e..f762116fea956c3fbee92038538e0f3e81f06c7e 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -41,7 +41,7 @@ namespace serialization { /// Version 4 of AST files also requires that the version control branch and /// revision match exactly, since there is no backward compatibility of /// AST files at this time. -const unsigned VERSION_MAJOR = 29; +const unsigned VERSION_MAJOR = 30; /// AST file minor version number supported by this version of /// Clang. diff --git a/clang/include/clang/Serialization/ASTReader.h b/clang/include/clang/Serialization/ASTReader.h index 370d8037a4da17933e80256f651ddfa104d78203..e8b9f28690d9fa06ab536f45c6be52b50fbcdca4 100644 --- a/clang/include/clang/Serialization/ASTReader.h +++ b/clang/include/clang/Serialization/ASTReader.h @@ -1082,26 +1082,12 @@ private: /// The set of lookup results that we have faked in order to support /// merging of partially deserialized decls but that we have not yet removed. - llvm::SmallMapVector, 16> - PendingFakeLookupResults; + llvm::SmallMapVector, 16> + PendingFakeLookupResults; /// The generation number of each identifier, which keeps track of /// the last time we loaded information about this identifier. - llvm::DenseMap IdentifierGeneration; - - class InterestingDecl { - Decl *D; - bool DeclHasPendingBody; - - public: - InterestingDecl(Decl *D, bool HasBody) - : D(D), DeclHasPendingBody(HasBody) {} - - Decl *getDecl() { return D; } - - /// Whether the declaration has a pending body. - bool hasPendingBody() { return DeclHasPendingBody; } - }; + llvm::DenseMap IdentifierGeneration; /// Contains declarations and definitions that could be /// "interesting" to the ASTConsumer, when we get that AST consumer. @@ -1109,7 +1095,7 @@ private: /// "Interesting" declarations are those that have data that may /// need to be emitted, such as inline function definitions or /// Objective-C protocols. - std::deque PotentiallyInterestingDecls; + std::deque PotentiallyInterestingDecls; /// The list of deduced function types that we have not yet read, because /// they might contain a deduced return type that refers to a local type @@ -1506,6 +1492,7 @@ public: getModuleFileLevelDecls(ModuleFile &Mod); private: + bool isConsumerInterestedIn(Decl *D); void PassInterestingDeclsToConsumer(); void PassInterestingDeclToConsumer(Decl *D); @@ -2344,10 +2331,10 @@ public: void ReadDefinedMacros() override; /// Update an out-of-date identifier. - void updateOutOfDateIdentifier(IdentifierInfo &II) override; + void updateOutOfDateIdentifier(const IdentifierInfo &II) override; /// Note that this identifier is up-to-date. - void markIdentifierUpToDate(IdentifierInfo *II); + void markIdentifierUpToDate(const IdentifierInfo *II); /// Load all external visible decls in the given DeclContext. void completeVisibleDeclsMap(const DeclContext *DC) override; diff --git a/clang/include/clang/Serialization/ASTRecordReader.h b/clang/include/clang/Serialization/ASTRecordReader.h index 5d3e95cb5d630f855cde1e00cbab9a3c1834eacd..7dd1140106e47c6199e60a7e0186864e571b0627 100644 --- a/clang/include/clang/Serialization/ASTRecordReader.h +++ b/clang/include/clang/Serialization/ASTRecordReader.h @@ -24,6 +24,7 @@ #include "llvm/ADT/APSInt.h" namespace clang { +class OpenACCClause; class OMPTraitInfo; class OMPChildren; @@ -278,6 +279,12 @@ public: /// Read an OpenMP children, advancing Idx. void readOMPChildren(OMPChildren *Data); + /// Read an OpenACC clause, advancing Idx. + OpenACCClause *readOpenACCClause(); + + /// Read a list of OpenACC clauses into the passed SmallVector. + void readOpenACCClauseList(MutableArrayRef Clauses); + /// Read a source location, advancing Idx. SourceLocation readSourceLocation(LocSeq *Seq = nullptr) { return Reader->ReadSourceLocation(*F, Record, Idx, Seq); diff --git a/clang/include/clang/Serialization/ASTRecordWriter.h b/clang/include/clang/Serialization/ASTRecordWriter.h index e007d4a70843a151f0958bcefc3e758503efbda9..1feb8fcbacf772cec2d88a50ee98fcd37241ad36 100644 --- a/clang/include/clang/Serialization/ASTRecordWriter.h +++ b/clang/include/clang/Serialization/ASTRecordWriter.h @@ -21,6 +21,7 @@ namespace clang { +class OpenACCClause; class TypeLoc; /// An object for streaming information to a record. @@ -292,6 +293,12 @@ public: /// Writes data related to the OpenMP directives. void writeOMPChildren(OMPChildren *Data); + /// Writes out a single OpenACC Clause. + void writeOpenACCClause(const OpenACCClause *C); + + /// Writes out a list of OpenACC clauses. + void writeOpenACCClauseList(ArrayRef Clauses); + /// Emit a string. void AddString(StringRef Str) { return Writer->AddString(Str, *Record); diff --git a/clang/include/clang/Serialization/ASTWriter.h b/clang/include/clang/Serialization/ASTWriter.h index 3ed9803fa3745b237b0bcb77cbd7489666722021..214eb3601148b0d18d6392d535e23e7d5d3baffd 100644 --- a/clang/include/clang/Serialization/ASTWriter.h +++ b/clang/include/clang/Serialization/ASTWriter.h @@ -542,6 +542,7 @@ private: void WriteReferencedSelectorsPool(Sema &SemaRef); void WriteIdentifierTable(Preprocessor &PP, IdentifierResolver &IdResolver, bool IsModule); + void WriteDeclAndTypes(ASTContext &Context); void WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord); void WriteDeclContextVisibleUpdate(const DeclContext *DC); void WriteFPPragmaOptions(const FPOptionsOverride &Opts); @@ -846,7 +847,7 @@ private: /// AST and semantic-analysis consumer that generates a /// precompiled header from the parsed source code. class PCHGenerator : public SemaConsumer { - const Preprocessor &PP; + Preprocessor &PP; std::string OutputFile; std::string isysroot; Sema *SemaPtr; @@ -867,11 +868,12 @@ protected: DiagnosticsEngine &getDiagnostics() const { return SemaPtr->getDiagnostics(); } + Preprocessor &getPreprocessor() { return PP; } virtual Module *getEmittingModule(ASTContext &Ctx); public: - PCHGenerator(const Preprocessor &PP, InMemoryModuleCache &ModuleCache, + PCHGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache, StringRef OutputFile, StringRef isysroot, std::shared_ptr Buffer, ArrayRef> Extensions, @@ -893,7 +895,7 @@ protected: virtual Module *getEmittingModule(ASTContext &Ctx) override; public: - ReducedBMIGenerator(const Preprocessor &PP, InMemoryModuleCache &ModuleCache, + ReducedBMIGenerator(Preprocessor &PP, InMemoryModuleCache &ModuleCache, StringRef OutputFile); void HandleTranslationUnit(ASTContext &Ctx) override; diff --git a/clang/include/clang/Serialization/TypeBitCodes.def b/clang/include/clang/Serialization/TypeBitCodes.def index 3c82dfed9497d587a6eaf985b809e9263d2a78c5..82b053d4caca63514d3179b5f358cd650312cbec 100644 --- a/clang/include/clang/Serialization/TypeBitCodes.def +++ b/clang/include/clang/Serialization/TypeBitCodes.def @@ -66,5 +66,6 @@ TYPE_BIT_CODE(Using, USING, 54) TYPE_BIT_CODE(BTFTagAttributed, BTFTAG_ATTRIBUTED, 55) TYPE_BIT_CODE(PackIndexing, PACK_INDEXING, 56) TYPE_BIT_CODE(CountAttributed, COUNT_ATTRIBUTED, 57) +TYPE_BIT_CODE(ArrayParameter, ARRAY_PARAMETER, 58) #undef TYPE_BIT_CODE diff --git a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td index 686e5e99f4a62c4a2649ea40849998968aa3e92b..9aa1c6ddfe4492c38f1a07851be9c15587479ccf 100644 --- a/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ b/clang/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -604,6 +604,15 @@ def PthreadLockChecker : Checker<"PthreadLock">, def StreamChecker : Checker<"Stream">, HelpText<"Check stream handling functions">, WeakDependencies<[NonNullParamChecker]>, + CheckerOptions<[ + CmdLineOption + ]>, Documentation; def SimpleStreamChecker : Checker<"SimpleStream">, @@ -622,6 +631,11 @@ def BlockInCriticalSectionChecker : Checker<"BlockInCriticalSection">, let ParentPackage = Cplusplus in { +def ArrayDeleteChecker : Checker<"ArrayDelete">, + HelpText<"Reports destructions of arrays of polymorphic objects that are " + "destructed as their base class.">, + Documentation; + def InnerPointerChecker : Checker<"InnerPointer">, HelpText<"Check for inner pointers of C++ containers used after " "re/deallocation">, @@ -777,11 +791,6 @@ def ContainerModeling : Checker<"ContainerModeling">, Documentation, Hidden; -def CXXArrayDeleteChecker : Checker<"ArrayDelete">, - HelpText<"Reports destructions of arrays of polymorphic objects that are " - "destructed as their base class.">, - Documentation; - def DeleteWithNonVirtualDtorChecker : Checker<"DeleteWithNonVirtualDtor">, HelpText<"Reports destructions of polymorphic objects with a non-virtual " "destructor in their base class">, @@ -908,7 +917,7 @@ def PaddingChecker : Checker<"Padding">, "24", Released> ]>, - Documentation; + Documentation; } // end: "padding" diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h index 276d11e80a5b21c78acd293650fadeddcf4bd1c3..3a3c1a13d67dd554bc39684ceeb8b6898073c5c5 100644 --- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h +++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h @@ -227,6 +227,7 @@ public: unsigned ShouldEmitErrorsOnInvalidConfigValue : 1; unsigned AnalyzeAll : 1; unsigned AnalyzerDisplayProgress : 1; + unsigned AnalyzerNoteAnalysisEntryPoints : 1; unsigned eagerlyAssumeBinOpBifurcation : 1; @@ -291,10 +292,10 @@ public: ShowCheckerOptionDeveloperList(false), ShowEnabledCheckerList(false), ShowConfigOptionsList(false), ShouldEmitErrorsOnInvalidConfigValue(false), AnalyzeAll(false), - AnalyzerDisplayProgress(false), eagerlyAssumeBinOpBifurcation(false), - TrimGraph(false), visualizeExplodedGraphWithGraphViz(false), - UnoptimizedCFG(false), PrintStats(false), NoRetryExhausted(false), - AnalyzerWerror(false) {} + AnalyzerDisplayProgress(false), AnalyzerNoteAnalysisEntryPoints(false), + eagerlyAssumeBinOpBifurcation(false), TrimGraph(false), + visualizeExplodedGraphWithGraphViz(false), UnoptimizedCFG(false), + PrintStats(false), NoRetryExhausted(false), AnalyzerWerror(false) {} /// Interprets an option's string value as a boolean. The "true" string is /// interpreted as true and the "false" string is interpreted as false. diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h index e762f7548e0b54186883f140bcc793378913a67b..ead96ce6891c39a261fc47fe73b0753611d5eaaa 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h @@ -586,6 +586,9 @@ class BugReporter { private: BugReporterData& D; + /// The top-level entry point for the issue to be reported. + const Decl *AnalysisEntryPoint = nullptr; + /// Generate and flush the diagnostics for the given bug report. void FlushReport(BugReportEquivClass& EQ); @@ -623,6 +626,14 @@ public: Preprocessor &getPreprocessor() { return D.getPreprocessor(); } + /// Get the top-level entry point for the issue to be reported. + const Decl *getAnalysisEntryPoint() const { return AnalysisEntryPoint; } + + void setAnalysisEntryPoint(const Decl *EntryPoint) { + assert(EntryPoint); + AnalysisEntryPoint = EntryPoint; + } + /// Add the given report to the set of reports tracked by BugReporter. /// /// The reports are usually generated by the checkers. Further, they are @@ -713,6 +724,7 @@ public: virtual ~BugReporterContext() = default; PathSensitiveBugReporter& getBugReporter() { return BR; } + const PathSensitiveBugReporter &getBugReporter() const { return BR; } ProgramStateManager& getStateManager() const { return BR.getStateManager(); diff --git a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h index d9b3d9352d32243557ec8d7b5be5a60d8834a12b..cc3d93aabafda4d29d51070a4a1aa0dda3e328fb 100644 --- a/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h +++ b/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h @@ -374,6 +374,7 @@ bool trackExpressionValue(const ExplodedNode *N, const Expr *E, /// from. /// /// \param V We're searching for the store where \c R received this value. +/// It may be either defined or undefined, but should not be unknown. /// \param R The region we're tracking. /// \param Opts Tracking options specifying how we want to track the value. /// \param Origin Only adds notes when the last store happened in a @@ -383,7 +384,7 @@ bool trackExpressionValue(const ExplodedNode *N, const Expr *E, /// changes to its value in a nested stackframe could be pruned, and /// this visitor can prevent that without polluting the bugpath too /// much. -void trackStoredValue(KnownSVal V, const MemRegion *R, +void trackStoredValue(SVal V, const MemRegion *R, PathSensitiveBugReport &Report, TrackingOptions Opts = {}, const StackFrameContext *Origin = nullptr); diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h index 3432d2648633c25a575e93087c766688bcd6ede6..ccfe8d47c290bcaa294ecf797a3e52c01b45afbd 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h @@ -32,23 +32,22 @@ namespace ento { class CallDescription { public: enum class Mode { - /// Match calls to functions from the C standard library. On some platforms - /// some functions may be implemented as macros that expand to calls to - /// built-in variants of the given functions, so in this mode we use some - /// heuristics to recognize these implementation-defined variants: - /// - We also accept calls where the name is derived from the specified - /// name by adding "__builtin" or similar prefixes/suffixes. - /// - We also accept calls where the number of arguments or parameters is - /// greater than the specified value. + /// Match calls to functions from the C standard library. This also + /// recognizes builtin variants whose name is derived by adding + /// "__builtin", "__inline" or similar prefixes or suffixes; but only + /// matches functions than are externally visible and are declared either + /// directly within a TU or in the namespace 'std'. /// For the exact heuristics, see CheckerContext::isCLibraryFunction(). - /// Note that functions whose declaration context is not a TU (e.g. - /// methods, functions in namespaces) are not accepted as C library - /// functions. - /// FIXME: If I understand it correctly, this discards calls where C++ code - /// refers a C library function through the namespace `std::` via headers - /// like . CLibrary, + /// An extended version of the `CLibrary` mode that also matches the + /// hardened variants like __FOO_chk() and __builtin__FOO_chk() that take + /// additional arguments compared to the "regular" function FOO(). + /// This is not the default behavior of `CLibrary` because in this case the + /// checker code must be prepared to handle the different parametrization. + /// For the exact heuristics, see CheckerContext::isHardenedVariantOf(). + CLibraryMaybeHardened, + /// Matches "simple" functions that are not methods. (Static methods are /// methods.) SimpleFunc, @@ -191,6 +190,9 @@ public: private: bool matchesImpl(const FunctionDecl *Callee, size_t ArgCount, size_t ParamCount) const; + + bool matchNameOnly(const NamedDecl *ND) const; + bool matchQualifiedNameParts(const Decl *D) const; }; /// An immutable map from CallDescriptions to arbitrary data. Provides a unified diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index 0d36587484bf9c30c567ba242ab0df647ebc020d..549c864dc91ef2f74984122155f62c27152afe86 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -59,6 +59,7 @@ namespace ento { enum CallEventKind { CE_Function, + CE_CXXStaticOperator, CE_CXXMember, CE_CXXMemberOperator, CE_CXXDestructor, @@ -709,6 +710,77 @@ public: } }; +/// Represents a static C++ operator call. +/// +/// "A" in this example. +/// However, "B" and "C" are represented by SimpleFunctionCall. +/// \code +/// struct S { +/// int pad; +/// static void operator()(int x, int y); +/// }; +/// S s{10}; +/// void (*fptr)(int, int) = &S::operator(); +/// +/// s(1, 2); // A +/// S::operator()(1, 2); // B +/// fptr(1, 2); // C +/// \endcode +class CXXStaticOperatorCall : public SimpleFunctionCall { + friend class CallEventManager; + +protected: + CXXStaticOperatorCall(const CXXOperatorCallExpr *CE, ProgramStateRef St, + const LocationContext *LCtx, + CFGBlock::ConstCFGElementRef ElemRef) + : SimpleFunctionCall(CE, St, LCtx, ElemRef) {} + CXXStaticOperatorCall(const CXXStaticOperatorCall &Other) = default; + + void cloneTo(void *Dest) const override { + new (Dest) CXXStaticOperatorCall(*this); + } + +public: + const CXXOperatorCallExpr *getOriginExpr() const override { + return cast(SimpleFunctionCall::getOriginExpr()); + } + + unsigned getNumArgs() const override { + // Ignore the object parameter that is not used for static member functions. + assert(getOriginExpr()->getNumArgs() > 0); + return getOriginExpr()->getNumArgs() - 1; + } + + const Expr *getArgExpr(unsigned Index) const override { + // Ignore the object parameter that is not used for static member functions. + return getOriginExpr()->getArg(Index + 1); + } + + std::optional + getAdjustedParameterIndex(unsigned ASTArgumentIndex) const override { + // Ignore the object parameter that is not used for static member functions. + if (ASTArgumentIndex == 0) + return std::nullopt; + return ASTArgumentIndex - 1; + } + + unsigned getASTArgumentIndex(unsigned CallArgumentIndex) const override { + // Account for the object parameter for the static member function. + return CallArgumentIndex + 1; + } + + OverloadedOperatorKind getOverloadedOperator() const { + return getOriginExpr()->getOperator(); + } + + Kind getKind() const override { return CE_CXXStaticOperator; } + StringRef getKindAsString() const override { return "CXXStaticOperatorCall"; } + + static bool classof(const CallEvent *CA) { + return CA->getKind() == CE_CXXStaticOperator; + } +}; + /// Represents a non-static C++ member function call. /// /// Example: \c obj.fun() diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h index 9923c41e6ad2d1f327ef1fdea2d0ce9d788f7cfd..0365f9e41312dff0ee29d0171b6c9139c98fa610 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h @@ -366,19 +366,31 @@ public: return getCalleeName(FunDecl); } - /// Returns true if the callee is an externally-visible function in the - /// top-level namespace, such as \c malloc. + /// Returns true if the given function is an externally-visible function in + /// the top-level namespace, such as \c malloc. /// /// If a name is provided, the function must additionally match the given /// name. /// - /// Note that this deliberately excludes C++ library functions in the \c std - /// namespace, but will include C library functions accessed through the - /// \c std namespace. This also does not check if the function is declared - /// as 'extern "C"', or if it uses C++ name mangling. + /// Note that this also accepts functions from the \c std namespace (because + /// headers like declare them there) and does not check if the + /// function is declared as 'extern "C"' or if it uses C++ name mangling. static bool isCLibraryFunction(const FunctionDecl *FD, StringRef Name = StringRef()); + /// In builds that use source hardening (-D_FORTIFY_SOURCE), many standard + /// functions are implemented as macros that expand to calls of hardened + /// functions that take additional arguments compared to the "usual" + /// variant and perform additional input validation. For example, a `memcpy` + /// call may expand to `__memcpy_chk()` or `__builtin___memcpy_chk()`. + /// + /// This method returns true if `FD` declares a fortified variant of the + /// standard library function `Name`. + /// + /// NOTE: This method relies on heuristics; extend it if you need to handle a + /// hardened variant that's not yet covered by it. + static bool isHardenedVariantOf(const FunctionDecl *FD, StringRef Name); + /// Depending on wither the location corresponds to a macro, return /// either the macro name or the token spelling. /// diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h index 60421e5437d82f7d35e2b3da4473098735d2c7dc..d053a97189123afbbb9da502e1397b83f19f9763 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerHelpers.h @@ -15,7 +15,6 @@ #include "ProgramState_Fwd.h" #include "SVals.h" - #include "clang/AST/OperationKinds.h" #include "clang/AST/Stmt.h" #include "clang/Basic/OperatorKinds.h" @@ -113,8 +112,7 @@ public: OperatorKind operationKindFromOverloadedOperator(OverloadedOperatorKind OOK, bool IsBinary); -std::optional getPointeeDefVal(SVal PtrSVal, - ProgramStateRef State); +std::optional getPointeeVal(SVal PtrSVal, ProgramStateRef State); } // namespace ento diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 859c1497d7e6db8f0f6bd6cfda62025ecc69cc36..e38a3bb56ece26f6b0ea326dcc364b5c79415f97 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -187,6 +187,8 @@ public: /// Returns true if there is still simulation state on the worklist. bool ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) { + assert(L->inTopFrame()); + BR.setAnalysisEntryPoint(L->getDecl()); return Engine.ExecuteWorkList(L, Steps, nullptr); } diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h index c60528b7685fe8297ff331aeef0f2a28f940b810..3a4b08725714940de5894be0ce5c55d6bf6fb4c6 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SVals.h @@ -232,14 +232,6 @@ protected: : DefinedOrUnknownSVal(Kind, Data) {} }; -/// Represents an SVal that is guaranteed to not be UnknownVal. -class KnownSVal : public SVal { -public: - /*implicit*/ KnownSVal(DefinedSVal V) : SVal(V) {} - /*implicit*/ KnownSVal(UndefinedVal V) : SVal(V) {} - static bool classof(SVal V) { return !V.isUnknown(); } -}; - class NonLoc : public DefinedSVal { protected: NonLoc(SValKind Kind, const void *Data) : DefinedSVal(Kind, Data) {} diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h index 846fdc7253977f99f03d0359b909d1f6a99b0938..9a522a3e2fe252082e1b2ee5b839c3d1d519cb63 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningFilesystem.h @@ -242,6 +242,8 @@ class EntryRef { /// The underlying cached entry. const CachedFileSystemEntry &Entry; + friend class DependencyScanningWorkerFilesystem; + public: EntryRef(StringRef Name, const CachedFileSystemEntry &Entry) : Filename(Name), Entry(Entry) {} @@ -300,14 +302,15 @@ public: /// /// Attempts to use the local and shared caches first, then falls back to /// using the underlying filesystem. - llvm::ErrorOr - getOrCreateFileSystemEntry(StringRef Filename, - bool DisableDirectivesScanning = false); + llvm::ErrorOr getOrCreateFileSystemEntry(StringRef Filename); -private: - /// Check whether the file should be scanned for preprocessor directives. - bool shouldScanForDirectives(StringRef Filename); + /// Ensure the directive tokens are populated for this file entry. + /// + /// Returns true if the directive tokens are populated for this file entry, + /// false if not (i.e. this entry is not a file or its scan fails). + bool ensureDirectiveTokensArePopulated(EntryRef Entry); +private: /// For a filename that's not yet associated with any entry in the caches, /// uses the underlying filesystem to either look up the entry based in the /// shared cache indexed by unique ID, or creates new entry from scratch. @@ -317,11 +320,6 @@ private: computeAndStoreResult(StringRef OriginalFilename, StringRef FilenameForLookup); - /// Scan for preprocessor directives for the given entry if necessary and - /// returns a wrapper object with reference semantics. - EntryRef scanForDirectivesIfNecessary(const CachedFileSystemEntry &Entry, - StringRef Filename, bool Disable); - /// Represents a filesystem entry that has been stat-ed (and potentially read) /// and that's about to be inserted into the cache as `CachedFileSystemEntry`. struct TentativeEntry { diff --git a/clang/lib/APINotes/APINotesManager.cpp b/clang/lib/APINotes/APINotesManager.cpp index f60f09e2b3c23198b2cb58eea29beba8312efdb0..789bb97d81de004724f759f16f0dc7a496909f9d 100644 --- a/clang/lib/APINotes/APINotesManager.cpp +++ b/clang/lib/APINotes/APINotesManager.cpp @@ -221,6 +221,7 @@ APINotesManager::getCurrentModuleAPINotes(Module *M, bool LookInModule, ArrayRef SearchPaths) { FileManager &FM = SM.getFileManager(); auto ModuleName = M->getTopLevelModuleName(); + auto ExportedModuleName = M->getTopLevelModule()->ExportAsModule; llvm::SmallVector APINotes; // First, look relative to the module itself. @@ -233,6 +234,10 @@ APINotesManager::getCurrentModuleAPINotes(Module *M, bool LookInModule, APINotes.push_back(*File); } + // If module FooCore is re-exported through module Foo, try Foo.apinotes. + if (!ExportedModuleName.empty()) + if (auto File = findAPINotesFile(Dir, ExportedModuleName, WantPublic)) + APINotes.push_back(*File); }; if (M->IsFramework) { diff --git a/clang/lib/APINotes/APINotesWriter.cpp b/clang/lib/APINotes/APINotesWriter.cpp index 76fd24ccfae98469d96b41e4729f51983775ab83..e3f5d102fcd07fe5b398bfd95c0edc7df0cc5b2d 100644 --- a/clang/lib/APINotes/APINotesWriter.cpp +++ b/clang/lib/APINotes/APINotesWriter.cpp @@ -441,7 +441,7 @@ void emitVersionedInfo( std::sort(VI.begin(), VI.end(), [](const std::pair &LHS, const std::pair &RHS) -> bool { - assert(LHS.first != RHS.first && + assert((&LHS == &RHS || LHS.first != RHS.first) && "two entries for the same version"); return LHS.first < RHS.first; }); diff --git a/clang/lib/ARCMigrate/ObjCMT.cpp b/clang/lib/ARCMigrate/ObjCMT.cpp index 0786c81516b2d14e7c3b7f79fbdf557c96d26016..b9dcfb8951b3e17858a9d6d641bdd0293b9777bf 100644 --- a/clang/lib/ARCMigrate/ObjCMT.cpp +++ b/clang/lib/ARCMigrate/ObjCMT.cpp @@ -1144,7 +1144,7 @@ static bool IsValidIdentifier(ASTContext &Ctx, return false; std::string NameString = Name; NameString[0] = toLowercase(NameString[0]); - IdentifierInfo *II = &Ctx.Idents.get(NameString); + const IdentifierInfo *II = &Ctx.Idents.get(NameString); return II->getTokenID() == tok::identifier; } @@ -1166,7 +1166,7 @@ bool ObjCMigrateASTConsumer::migrateProperty(ASTContext &Ctx, if (OIT_Family != OIT_None) return false; - IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0); + const IdentifierInfo *getterName = GetterSelector.getIdentifierInfoForSlot(0); Selector SetterSelector = SelectorTable::constructSetterSelector(PP.getIdentifierTable(), PP.getSelectorTable(), @@ -1311,7 +1311,8 @@ void ObjCMigrateASTConsumer::migrateFactoryMethod(ASTContext &Ctx, std::string StringLoweredClassName = LoweredClassName.lower(); LoweredClassName = StringLoweredClassName; - IdentifierInfo *MethodIdName = OM->getSelector().getIdentifierInfoForSlot(0); + const IdentifierInfo *MethodIdName = + OM->getSelector().getIdentifierInfoForSlot(0); // Handle method with no name at its first selector slot; e.g. + (id):(int)x. if (!MethodIdName) return; diff --git a/clang/lib/ARCMigrate/TransAPIUses.cpp b/clang/lib/ARCMigrate/TransAPIUses.cpp index 638850dcf9ecc72a524a78f30ae101c53ad78b17..8f5d4f4bde06ca313a3f9075a797fb3a45d0fba7 100644 --- a/clang/lib/ARCMigrate/TransAPIUses.cpp +++ b/clang/lib/ARCMigrate/TransAPIUses.cpp @@ -41,7 +41,7 @@ public: getReturnValueSel = sels.getUnarySelector(&ids.get("getReturnValue")); setReturnValueSel = sels.getUnarySelector(&ids.get("setReturnValue")); - IdentifierInfo *selIds[2]; + const IdentifierInfo *selIds[2]; selIds[0] = &ids.get("getArgument"); selIds[1] = &ids.get("atIndex"); getArgumentSel = sels.getSelector(2, selIds); diff --git a/clang/lib/AST/APValue.cpp b/clang/lib/AST/APValue.cpp index 4eae308ef5b34c608df0783c187130ae5bcf792b..d8042321319a67b253b034d8a0d4572a97f14d2f 100644 --- a/clang/lib/AST/APValue.cpp +++ b/clang/lib/AST/APValue.cpp @@ -704,6 +704,9 @@ void APValue::printPretty(raw_ostream &Out, const PrintingPolicy &Policy, return; } + if (const auto *AT = Ty->getAs()) + Ty = AT->getValueType(); + switch (getKind()) { case APValue::None: Out << ""; diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index fcf801adeaf5ef55e05393f6426eabae18e4cfcd..6ce233704a5885ab27094b8db7614bd98ef95b9e 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -799,7 +799,7 @@ ASTContext::getCanonicalTemplateTemplateParmDecl( TemplateTemplateParmDecl *CanonTTP = TemplateTemplateParmDecl::Create( *this, getTranslationUnitDecl(), SourceLocation(), TTP->getDepth(), - TTP->getPosition(), TTP->isParameterPack(), nullptr, + TTP->getPosition(), TTP->isParameterPack(), nullptr, /*Typename=*/false, TemplateParameterList::Create(*this, SourceLocation(), SourceLocation(), CanonParams, SourceLocation(), /*RequiresClause=*/nullptr)); @@ -879,7 +879,8 @@ ASTContext::ASTContext(LangOptions &LOpts, SourceManager &SM, TemplateSpecializationTypes(this_()), DependentTemplateSpecializationTypes(this_()), AutoTypes(this_()), DependentBitIntTypes(this_()), SubstTemplateTemplateParmPacks(this_()), - CanonTemplateTemplateParms(this_()), SourceMgr(SM), LangOpts(LOpts), + ArrayParameterTypes(this_()), CanonTemplateTemplateParms(this_()), + SourceMgr(SM), LangOpts(LOpts), NoSanitizeL(new NoSanitizeList(LangOpts.NoSanitizeFiles, SM)), XRayFilter(new XRayFunctionFilter(LangOpts.XRayAlwaysInstrumentFiles, LangOpts.XRayNeverInstrumentFiles, @@ -1766,7 +1767,7 @@ TypeInfoChars static getConstantArrayInfoInChars(const ASTContext &Context, const ConstantArrayType *CAT) { TypeInfoChars EltInfo = Context.getTypeInfoInChars(CAT->getElementType()); - uint64_t Size = CAT->getSize().getZExtValue(); + uint64_t Size = CAT->getZExtSize(); assert((Size == 0 || static_cast(EltInfo.Width.getQuantity()) <= (uint64_t)(-1)/Size) && "Overflow in array type char size evaluation"); @@ -1906,11 +1907,12 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { case Type::IncompleteArray: case Type::VariableArray: - case Type::ConstantArray: { + case Type::ConstantArray: + case Type::ArrayParameter: { // Model non-constant sized arrays as size zero, but track the alignment. uint64_t Size = 0; if (const auto *CAT = dyn_cast(T)) - Size = CAT->getSize().getZExtValue(); + Size = CAT->getZExtSize(); TypeInfo EltInfo = getTypeInfo(cast(T)->getElementType()); assert((Size == 0 || EltInfo.Width <= (uint64_t)(-1) / Size) && @@ -3396,6 +3398,37 @@ QualType ASTContext::getDecayedType(QualType T) const { return getDecayedType(T, Decayed); } +QualType ASTContext::getArrayParameterType(QualType Ty) const { + if (Ty->isArrayParameterType()) + return Ty; + assert(Ty->isConstantArrayType() && "Ty must be an array type."); + const auto *ATy = cast(Ty); + llvm::FoldingSetNodeID ID; + ATy->Profile(ID, *this, ATy->getElementType(), ATy->getZExtSize(), + ATy->getSizeExpr(), ATy->getSizeModifier(), + ATy->getIndexTypeQualifiers().getAsOpaqueValue()); + void *InsertPos = nullptr; + ArrayParameterType *AT = + ArrayParameterTypes.FindNodeOrInsertPos(ID, InsertPos); + if (AT) + return QualType(AT, 0); + + QualType Canonical; + if (!Ty.isCanonical()) { + Canonical = getArrayParameterType(getCanonicalType(Ty)); + + // Get the new insert position for the node we care about. + AT = ArrayParameterTypes.FindNodeOrInsertPos(ID, InsertPos); + assert(!AT && "Shouldn't be in the map!"); + } + + AT = new (*this, alignof(ArrayParameterType)) + ArrayParameterType(ATy, Canonical); + Types.push_back(AT); + ArrayParameterTypes.InsertNode(AT, InsertPos); + return QualType(AT, 0); +} + /// getBlockPointerType - Return the uniqued reference to the type for /// a pointer to the specified block. QualType ASTContext::getBlockPointerType(QualType T) const { @@ -3560,8 +3593,8 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, ArySize = ArySize.zextOrTrunc(Target->getMaxPointerWidth()); llvm::FoldingSetNodeID ID; - ConstantArrayType::Profile(ID, *this, EltTy, ArySize, SizeExpr, ASM, - IndexTypeQuals); + ConstantArrayType::Profile(ID, *this, EltTy, ArySize.getZExtValue(), SizeExpr, + ASM, IndexTypeQuals); void *InsertPos = nullptr; if (ConstantArrayType *ATP = @@ -3585,11 +3618,8 @@ QualType ASTContext::getConstantArrayType(QualType EltTy, assert(!NewIP && "Shouldn't be in the map!"); (void)NewIP; } - void *Mem = Allocate( - ConstantArrayType::totalSizeToAlloc(SizeExpr ? 1 : 0), - alignof(ConstantArrayType)); - auto *New = new (Mem) - ConstantArrayType(EltTy, Canon, ArySize, SizeExpr, ASM, IndexTypeQuals); + auto *New = ConstantArrayType::Create(*this, EltTy, Canon, ArySize, SizeExpr, + ASM, IndexTypeQuals); ConstantArrayTypes.InsertNode(New, InsertPos); Types.push_back(New); return QualType(New, 0); @@ -3645,6 +3675,7 @@ QualType ASTContext::getVariableArrayDecayedType(QualType type) const { case Type::PackIndexing: case Type::BitInt: case Type::DependentBitInt: + case Type::ArrayParameter: llvm_unreachable("type should never be variably-modified"); // These types can be variably-modified but should never need to @@ -6054,7 +6085,9 @@ CanQualType ASTContext::getCanonicalParamType(QualType T) const { T = getVariableArrayDecayedType(T); const Type *Ty = T.getTypePtr(); QualType Result; - if (isa(Ty)) { + if (getLangOpts().HLSL && isa(Ty)) { + Result = getArrayParameterType(QualType(Ty, 0)); + } else if (isa(Ty)) { Result = getArrayDecayedType(QualType(Ty,0)); } else if (isa(Ty)) { Result = getPointerType(QualType(Ty, 0)); @@ -6896,16 +6929,13 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) const { // typedef typename T::type T1; // typedef typename T1::type T2; if (const auto *DNT = T->getAs()) - return NestedNameSpecifier::Create( - *this, DNT->getQualifier(), - const_cast(DNT->getIdentifier())); + return NestedNameSpecifier::Create(*this, DNT->getQualifier(), + DNT->getIdentifier()); if (const auto *DTST = T->getAs()) - return NestedNameSpecifier::Create(*this, DTST->getQualifier(), true, - const_cast(T)); + return NestedNameSpecifier::Create(*this, DTST->getQualifier(), true, T); // TODO: Set 'Template' parameter to true for other template types. - return NestedNameSpecifier::Create(*this, nullptr, false, - const_cast(T)); + return NestedNameSpecifier::Create(*this, nullptr, false, T); } case NestedNameSpecifier::Global: @@ -6976,6 +7006,8 @@ const ArrayType *ASTContext::getAsArrayType(QualType T) const { } QualType ASTContext::getAdjustedParameterType(QualType T) const { + if (getLangOpts().HLSL && T->isConstantArrayType()) + return getArrayParameterType(T); if (T->isArrayType() || T->isFunctionType()) return getDecayedType(T); return T; @@ -7051,7 +7083,7 @@ uint64_t ASTContext::getConstantArrayElementCount(const ConstantArrayType *CA) const { uint64_t ElementCount = 1; do { - ElementCount *= CA->getSize().getZExtValue(); + ElementCount *= CA->getZExtSize(); CA = dyn_cast_or_null( CA->getElementType()->getAsArrayTypeUnsafe()); } while (CA); @@ -8374,7 +8406,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, S += '['; if (const auto *CAT = dyn_cast(AT)) - S += llvm::utostr(CAT->getSize().getZExtValue()); + S += llvm::utostr(CAT->getZExtSize()); else { //Variable length arrays are encoded as a regular array with 0 elements. assert((isa(AT) || isa(AT)) && @@ -8586,6 +8618,7 @@ void ASTContext::getObjCEncodingForTypeImpl(QualType T, std::string &S, case Type::DeducedTemplateSpecialization: return; + case Type::ArrayParameter: case Type::Pipe: #define ABSTRACT_TYPE(KIND, BASE) #define TYPE(KIND, BASE) @@ -9603,11 +9636,11 @@ static uint64_t getRVVTypeSize(ASTContext &Context, const BuiltinType *Ty) { ASTContext::BuiltinVectorTypeInfo Info = Context.getBuiltinVectorTypeInfo(Ty); - unsigned EltSize = Context.getTypeSize(Info.ElementType); + uint64_t EltSize = Context.getTypeSize(Info.ElementType); if (Info.ElementType == Context.BoolTy) EltSize = 1; - unsigned MinElts = Info.EC.getKnownMinValue(); + uint64_t MinElts = Info.EC.getKnownMinValue(); return VScale->first * MinElts * EltSize; } @@ -10808,7 +10841,7 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer, { const ConstantArrayType* LCAT = getAsConstantArrayType(LHS); const ConstantArrayType* RCAT = getAsConstantArrayType(RHS); - if (LCAT && RCAT && RCAT->getSize() != LCAT->getSize()) + if (LCAT && RCAT && RCAT->getZExtSize() != LCAT->getZExtSize()) return {}; QualType LHSElem = getAsArrayType(LHS)->getElementType(); @@ -10929,6 +10962,10 @@ QualType ASTContext::mergeTypes(QualType LHS, QualType RHS, bool OfBlockPointer, assert(LHS != RHS && "Equivalent pipe types should have already been handled!"); return {}; + case Type::ArrayParameter: + assert(LHS != RHS && + "Equivalent ArrayParameter types should have already been handled!"); + return {}; case Type::BitInt: { // Merge two bit-precise int types, while trying to preserve typedef info. bool LHSUnsigned = LHS->castAs()->isUnsigned(); @@ -12820,6 +12857,18 @@ static QualType getCommonNonSugarTypeNode(ASTContext &Ctx, const Type *X, getCommonArrayElementType(Ctx, AX, QX, AY, QY), AX->getSize(), SizeExpr, getCommonSizeModifier(AX, AY), getCommonIndexTypeCVRQualifiers(AX, AY)); } + case Type::ArrayParameter: { + const auto *AX = cast(X), + *AY = cast(Y); + assert(AX->getSize() == AY->getSize()); + const Expr *SizeExpr = Ctx.hasSameExpr(AX->getSizeExpr(), AY->getSizeExpr()) + ? AX->getSizeExpr() + : nullptr; + auto ArrayTy = Ctx.getConstantArrayType( + getCommonArrayElementType(Ctx, AX, QX, AY, QY), AX->getSize(), SizeExpr, + getCommonSizeModifier(AX, AY), getCommonIndexTypeCVRQualifiers(AX, AY)); + return Ctx.getArrayParameterType(ArrayTy); + } case Type::Atomic: { const auto *AX = cast(X), *AY = cast(Y); return Ctx.getAtomicType( @@ -13081,6 +13130,7 @@ static QualType getCommonSugarTypeNode(ASTContext &Ctx, const Type *X, CANONICAL_TYPE(Builtin) CANONICAL_TYPE(Complex) CANONICAL_TYPE(ConstantArray) + CANONICAL_TYPE(ArrayParameter) CANONICAL_TYPE(ConstantMatrix) CANONICAL_TYPE(Enum) CANONICAL_TYPE(ExtVector) @@ -13676,22 +13726,19 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap &FeatureMap, Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features); } else if (const auto *TC = FD->getAttr()) { std::vector Features; - StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex()); if (Target->getTriple().isAArch64()) { // TargetClones for AArch64 - if (VersionStr != "default") { - SmallVector VersionFeatures; - VersionStr.split(VersionFeatures, "+"); - for (auto &VFeature : VersionFeatures) { - VFeature = VFeature.trim(); + llvm::SmallVector Feats; + TC->getFeatures(Feats, GD.getMultiVersionIndex()); + for (StringRef Feat : Feats) + if (Target->validateCpuSupports(Feat.str())) // Use '?' to mark features that came from AArch64 TargetClones. - Features.push_back((StringRef{"?"} + VFeature).str()); - } - } + Features.push_back("?" + Feat.str()); Features.insert(Features.begin(), Target->getTargetOpts().FeaturesAsWritten.begin(), Target->getTargetOpts().FeaturesAsWritten.end()); } else { + StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex()); if (VersionStr.starts_with("arch=")) TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1); else if (VersionStr != "default") diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 786695f00fadccc37cc67fcb83dc03ff45cf25c9..a5e43fc63166759bb60dd84ab5d8196ac8521193 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1218,6 +1218,15 @@ ASTNodeImporter::VisitConstantArrayType(const ConstantArrayType *T) { T->getIndexTypeCVRQualifiers()); } +ExpectedType +ASTNodeImporter::VisitArrayParameterType(const ArrayParameterType *T) { + ExpectedType ToArrayTypeOrErr = VisitConstantArrayType(T); + if (!ToArrayTypeOrErr) + return ToArrayTypeOrErr.takeError(); + + return Importer.getToContext().getArrayParameterType(*ToArrayTypeOrErr); +} + ExpectedType ASTNodeImporter::VisitIncompleteArrayType(const IncompleteArrayType *T) { ExpectedType ToElementTypeOrErr = import(T->getElementType()); @@ -4532,6 +4541,10 @@ ExpectedDecl ASTNodeImporter::VisitVarDecl(VarDecl *D) { ToVar->setQualifierInfo(ToQualifierLoc); ToVar->setAccess(D->getAccess()); ToVar->setLexicalDeclContext(LexicalDC); + if (D->isInlineSpecified()) + ToVar->setInlineSpecified(); + if (D->isInline()) + ToVar->setImplicitlyInline(); if (FoundByLookup) { auto *Recent = const_cast(FoundByLookup->getMostRecentDecl()); @@ -5939,7 +5952,8 @@ ASTNodeImporter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { ToD, D, Importer.getToContext(), Importer.getToContext().getTranslationUnitDecl(), *LocationOrErr, D->getDepth(), D->getPosition(), D->isParameterPack(), - (*NameOrErr).getAsIdentifierInfo(), *TemplateParamsOrErr)) + (*NameOrErr).getAsIdentifierInfo(), D->wasDeclaredWithTypename(), + *TemplateParamsOrErr)) return ToD; if (D->hasDefaultArgument()) { @@ -8370,8 +8384,8 @@ ASTNodeImporter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { return std::move(Err); PseudoDestructorTypeStorage Storage; - if (IdentifierInfo *FromII = E->getDestroyedTypeIdentifier()) { - IdentifierInfo *ToII = Importer.Import(FromII); + if (const IdentifierInfo *FromII = E->getDestroyedTypeIdentifier()) { + const IdentifierInfo *ToII = Importer.Import(FromII); ExpectedSLoc ToDestroyedTypeLocOrErr = import(E->getDestroyedTypeLoc()); if (!ToDestroyedTypeLocOrErr) return ToDestroyedTypeLocOrErr.takeError(); @@ -10181,7 +10195,7 @@ Expected ASTImporter::Import(Selector FromSel) { if (FromSel.isNull()) return Selector{}; - SmallVector Idents; + SmallVector Idents; Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(0))); for (unsigned I = 1, N = FromSel.getNumArgs(); I < N; ++I) Idents.push_back(Import(FromSel.getIdentifierInfoForSlot(I))); diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp index 226e0aa38ece70bb990dee34bcf2de8eda6b2957..d56bf21b459e035cea410a56828dd78fec082686 100644 --- a/clang/lib/AST/ASTStructuralEquivalence.cpp +++ b/clang/lib/AST/ASTStructuralEquivalence.cpp @@ -840,6 +840,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, case Type::Adjusted: case Type::Decayed: + case Type::ArrayParameter: if (!IsStructurallyEquivalent(Context, cast(T1)->getOriginalType(), cast(T2)->getOriginalType())) diff --git a/clang/lib/AST/CMakeLists.txt b/clang/lib/AST/CMakeLists.txt index 3fba052d916c9ea031659c0bba312d75e6d3312f..3faefb54f599fb6b311607983810dc448cd5c4a9 100644 --- a/clang/lib/AST/CMakeLists.txt +++ b/clang/lib/AST/CMakeLists.txt @@ -98,6 +98,7 @@ add_clang_library(clangAST NSAPI.cpp ODRDiagsEmitter.cpp ODRHash.cpp + OpenACCClause.cpp OpenMPClause.cpp OSLog.cpp ParentMap.cpp diff --git a/clang/lib/AST/ComputeDependence.cpp b/clang/lib/AST/ComputeDependence.cpp index 9d3856b8f7e08a8ccbcc636ff16c6ba28d57791a..5ec3013fabba9ae4868d8faef7989a1ae0c648f0 100644 --- a/clang/lib/AST/ComputeDependence.cpp +++ b/clang/lib/AST/ComputeDependence.cpp @@ -310,6 +310,16 @@ ExprDependence clang::computeDependence(CXXThisExpr *E) { // 'this' is type-dependent if the class type of the enclosing // member function is dependent (C++ [temp.dep.expr]p2) auto D = toExprDependenceForImpliedType(E->getType()->getDependence()); + + // If a lambda with an explicit object parameter captures '*this', then + // 'this' now refers to the captured copy of lambda, and if the lambda + // is type-dependent, so is the object and thus 'this'. + // + // Note: The standard does not mention this case explicitly, but we need + // to do this so we can mark NSDM accesses as dependent. + if (E->isCapturedByCopyInLambdaWithExplicitObjectParameter()) + D |= ExprDependence::Type; + assert(!(D & ExprDependence::UnexpandedPack)); return D; } @@ -654,6 +664,9 @@ ExprDependence clang::computeDependence(MemberExpr *E) { D |= toExprDependence(NNS->getDependence() & ~NestedNameSpecifierDependence::Dependent); + for (const auto &A : E->template_arguments()) + D |= toExprDependence(A.getArgument().getDependence()); + auto *MemberDecl = E->getMemberDecl(); if (FieldDecl *FD = dyn_cast(MemberDecl)) { DeclContext *DC = MemberDecl->getDeclContext(); @@ -670,7 +683,6 @@ ExprDependence clang::computeDependence(MemberExpr *E) { D |= ExprDependence::Type; } } - // FIXME: move remaining dependence computation from MemberExpr::Create() return D; } diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 95900afdd2c5d8e17e68a0fe38f9fd38a751c4da..60e0a3aecf6c8e67c3cd1de634dbc92fbce4e31c 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -2840,7 +2840,7 @@ bool VarDecl::hasFlexibleArrayInit(const ASTContext &Ctx) const { auto InitTy = Ctx.getAsConstantArrayType(FlexibleInit->getType()); if (!InitTy) return false; - return InitTy->getSize() != 0; + return !InitTy->isZeroSize(); } CharUnits VarDecl::getFlexibleArrayInitChars(const ASTContext &Ctx) const { @@ -2913,10 +2913,10 @@ VarDecl::setInstantiationOfStaticDataMember(VarDecl *VD, //===----------------------------------------------------------------------===// ParmVarDecl *ParmVarDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, - StorageClass S, Expr *DefArg) { + SourceLocation StartLoc, SourceLocation IdLoc, + const IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, StorageClass S, + Expr *DefArg) { return new (C, DC) ParmVarDecl(ParmVar, C, DC, StartLoc, IdLoc, Id, T, TInfo, S, DefArg); } @@ -4511,7 +4511,7 @@ unsigned FunctionDecl::getODRHash() { FieldDecl *FieldDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, QualType T, + const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, Expr *BW, bool Mutable, InClassInitStyle InitStyle) { return new (C, DC) FieldDecl(Decl::Field, DC, StartLoc, IdLoc, Id, T, TInfo, @@ -5438,7 +5438,7 @@ IndirectFieldDecl::IndirectFieldDecl(ASTContext &C, DeclContext *DC, IndirectFieldDecl * IndirectFieldDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, - IdentifierInfo *Id, QualType T, + const IdentifierInfo *Id, QualType T, llvm::MutableArrayRef CH) { return new (C, DC) IndirectFieldDecl(C, DC, L, Id, T, CH); } @@ -5461,7 +5461,8 @@ void TypeDecl::anchor() {} TypedefDecl *TypedefDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, TypeSourceInfo *TInfo) { + const IdentifierInfo *Id, + TypeSourceInfo *TInfo) { return new (C, DC) TypedefDecl(C, DC, StartLoc, IdLoc, Id, TInfo); } @@ -5511,7 +5512,8 @@ TypedefDecl *TypedefDecl::CreateDeserialized(ASTContext &C, unsigned ID) { TypeAliasDecl *TypeAliasDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, + SourceLocation IdLoc, + const IdentifierInfo *Id, TypeSourceInfo *TInfo) { return new (C, DC) TypeAliasDecl(C, DC, StartLoc, IdLoc, Id, TInfo); } diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 04bbc49ab2f3192aea29e9dd2d198c3d3fa6908c..66a727d9dd0c39a8e1d1f993c6ab2a98950015c6 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -1102,9 +1102,13 @@ bool Decl::isInAnotherModuleUnit() const { return M != getASTContext().getCurrentNamedModule(); } +bool Decl::isFromExplicitGlobalModule() const { + return getOwningModule() && getOwningModule()->isExplicitGlobalModule(); +} + bool Decl::shouldSkipCheckingODR() const { - return getASTContext().getLangOpts().SkipODRCheckInGMF && getOwningModule() && - getOwningModule()->isExplicitGlobalModule(); + return getASTContext().getLangOpts().SkipODRCheckInGMF && + isFromExplicitGlobalModule(); } static Decl::Kind getKind(const Decl *D) { return D->getKind(); } @@ -1848,9 +1852,9 @@ DeclContext::lookup(DeclarationName Name) const { DeclContext::lookup_result DeclContext::noload_lookup(DeclarationName Name) { - assert(getDeclKind() != Decl::LinkageSpec && - getDeclKind() != Decl::Export && - "should not perform lookups into transparent contexts"); + // For transparent DeclContext, we should lookup in their enclosing context. + if (getDeclKind() == Decl::LinkageSpec || getDeclKind() == Decl::Export) + return getParent()->noload_lookup(Name); DeclContext *PrimaryContext = getPrimaryContext(); if (PrimaryContext != this) diff --git a/clang/lib/AST/DeclObjC.cpp b/clang/lib/AST/DeclObjC.cpp index 962f503306a0f0df585e4116c240dff26a5fd822..32c14938cd5888cd65a8dda612f5b996bf4a7f30 100644 --- a/clang/lib/AST/DeclObjC.cpp +++ b/clang/lib/AST/DeclObjC.cpp @@ -66,7 +66,8 @@ void ObjCProtocolList::set(ObjCProtocolDecl* const* InList, unsigned Elts, //===----------------------------------------------------------------------===// ObjCContainerDecl::ObjCContainerDecl(Kind DK, DeclContext *DC, - IdentifierInfo *Id, SourceLocation nameLoc, + const IdentifierInfo *Id, + SourceLocation nameLoc, SourceLocation atStartLoc) : NamedDecl(DK, DC, nameLoc, Id), DeclContext(DK) { setAtStartLoc(atStartLoc); @@ -378,10 +379,8 @@ SourceLocation ObjCInterfaceDecl::getSuperClassLoc() const { /// FindPropertyVisibleInPrimaryClass - Finds declaration of the property /// with name 'PropertyId' in the primary class; including those in protocols /// (direct or indirect) used by the primary class. -ObjCPropertyDecl * -ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass( - IdentifierInfo *PropertyId, - ObjCPropertyQueryKind QueryKind) const { +ObjCPropertyDecl *ObjCInterfaceDecl::FindPropertyVisibleInPrimaryClass( + const IdentifierInfo *PropertyId, ObjCPropertyQueryKind QueryKind) const { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) return nullptr; @@ -1539,14 +1538,10 @@ void ObjCTypeParamList::gatherDefaultTypeArgs( // ObjCInterfaceDecl //===----------------------------------------------------------------------===// -ObjCInterfaceDecl *ObjCInterfaceDecl::Create(const ASTContext &C, - DeclContext *DC, - SourceLocation atLoc, - IdentifierInfo *Id, - ObjCTypeParamList *typeParamList, - ObjCInterfaceDecl *PrevDecl, - SourceLocation ClassLoc, - bool isInternal){ +ObjCInterfaceDecl *ObjCInterfaceDecl::Create( + const ASTContext &C, DeclContext *DC, SourceLocation atLoc, + const IdentifierInfo *Id, ObjCTypeParamList *typeParamList, + ObjCInterfaceDecl *PrevDecl, SourceLocation ClassLoc, bool isInternal) { auto *Result = new (C, DC) ObjCInterfaceDecl(C, DC, atLoc, Id, typeParamList, ClassLoc, PrevDecl, isInternal); @@ -1564,12 +1559,10 @@ ObjCInterfaceDecl *ObjCInterfaceDecl::CreateDeserialized(const ASTContext &C, return Result; } -ObjCInterfaceDecl::ObjCInterfaceDecl(const ASTContext &C, DeclContext *DC, - SourceLocation AtLoc, IdentifierInfo *Id, - ObjCTypeParamList *typeParamList, - SourceLocation CLoc, - ObjCInterfaceDecl *PrevDecl, - bool IsInternal) +ObjCInterfaceDecl::ObjCInterfaceDecl( + const ASTContext &C, DeclContext *DC, SourceLocation AtLoc, + const IdentifierInfo *Id, ObjCTypeParamList *typeParamList, + SourceLocation CLoc, ObjCInterfaceDecl *PrevDecl, bool IsInternal) : ObjCContainerDecl(ObjCInterface, DC, Id, CLoc, AtLoc), redeclarable_base(C) { setPreviousDecl(PrevDecl); @@ -1751,8 +1744,8 @@ ObjCIvarDecl *ObjCInterfaceDecl::all_declared_ivar_begin() { /// categories for this class and returns it. Name of the category is passed /// in 'CategoryId'. If category not found, return 0; /// -ObjCCategoryDecl * -ObjCInterfaceDecl::FindCategoryDeclaration(IdentifierInfo *CategoryId) const { +ObjCCategoryDecl *ObjCInterfaceDecl::FindCategoryDeclaration( + const IdentifierInfo *CategoryId) const { // FIXME: Should make sure no callers ever do this. if (!hasDefinition()) return nullptr; @@ -1838,10 +1831,10 @@ void ObjCIvarDecl::anchor() {} ObjCIvarDecl *ObjCIvarDecl::Create(ASTContext &C, ObjCContainerDecl *DC, SourceLocation StartLoc, - SourceLocation IdLoc, IdentifierInfo *Id, - QualType T, TypeSourceInfo *TInfo, - AccessControl ac, Expr *BW, - bool synthesized) { + SourceLocation IdLoc, + const IdentifierInfo *Id, QualType T, + TypeSourceInfo *TInfo, AccessControl ac, + Expr *BW, bool synthesized) { if (DC) { // Ivar's can only appear in interfaces, implementations (via synthesized // properties), and class extensions (via direct declaration, or synthesized @@ -2120,28 +2113,23 @@ void ObjCProtocolDecl::setHasODRHash(bool HasHash) { void ObjCCategoryDecl::anchor() {} -ObjCCategoryDecl::ObjCCategoryDecl(DeclContext *DC, SourceLocation AtLoc, - SourceLocation ClassNameLoc, - SourceLocation CategoryNameLoc, - IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, - ObjCTypeParamList *typeParamList, - SourceLocation IvarLBraceLoc, - SourceLocation IvarRBraceLoc) +ObjCCategoryDecl::ObjCCategoryDecl( + DeclContext *DC, SourceLocation AtLoc, SourceLocation ClassNameLoc, + SourceLocation CategoryNameLoc, const IdentifierInfo *Id, + ObjCInterfaceDecl *IDecl, ObjCTypeParamList *typeParamList, + SourceLocation IvarLBraceLoc, SourceLocation IvarRBraceLoc) : ObjCContainerDecl(ObjCCategory, DC, Id, ClassNameLoc, AtLoc), ClassInterface(IDecl), CategoryNameLoc(CategoryNameLoc), IvarLBraceLoc(IvarLBraceLoc), IvarRBraceLoc(IvarRBraceLoc) { setTypeParamList(typeParamList); } -ObjCCategoryDecl *ObjCCategoryDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation AtLoc, - SourceLocation ClassNameLoc, - SourceLocation CategoryNameLoc, - IdentifierInfo *Id, - ObjCInterfaceDecl *IDecl, - ObjCTypeParamList *typeParamList, - SourceLocation IvarLBraceLoc, - SourceLocation IvarRBraceLoc) { +ObjCCategoryDecl *ObjCCategoryDecl::Create( + ASTContext &C, DeclContext *DC, SourceLocation AtLoc, + SourceLocation ClassNameLoc, SourceLocation CategoryNameLoc, + const IdentifierInfo *Id, ObjCInterfaceDecl *IDecl, + ObjCTypeParamList *typeParamList, SourceLocation IvarLBraceLoc, + SourceLocation IvarRBraceLoc) { auto *CatDecl = new (C, DC) ObjCCategoryDecl(DC, AtLoc, ClassNameLoc, CategoryNameLoc, Id, IDecl, typeParamList, IvarLBraceLoc, @@ -2190,13 +2178,10 @@ void ObjCCategoryDecl::setTypeParamList(ObjCTypeParamList *TPL) { void ObjCCategoryImplDecl::anchor() {} -ObjCCategoryImplDecl * -ObjCCategoryImplDecl::Create(ASTContext &C, DeclContext *DC, - IdentifierInfo *Id, - ObjCInterfaceDecl *ClassInterface, - SourceLocation nameLoc, - SourceLocation atStartLoc, - SourceLocation CategoryNameLoc) { +ObjCCategoryImplDecl *ObjCCategoryImplDecl::Create( + ASTContext &C, DeclContext *DC, const IdentifierInfo *Id, + ObjCInterfaceDecl *ClassInterface, SourceLocation nameLoc, + SourceLocation atStartLoc, SourceLocation CategoryNameLoc) { if (ClassInterface && ClassInterface->hasDefinition()) ClassInterface = ClassInterface->getDefinition(); return new (C, DC) ObjCCategoryImplDecl(DC, Id, ClassInterface, nameLoc, @@ -2365,14 +2350,11 @@ ObjCCompatibleAliasDecl::CreateDeserialized(ASTContext &C, unsigned ID) { void ObjCPropertyDecl::anchor() {} -ObjCPropertyDecl *ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC, - SourceLocation L, - IdentifierInfo *Id, - SourceLocation AtLoc, - SourceLocation LParenLoc, - QualType T, - TypeSourceInfo *TSI, - PropertyControl propControl) { +ObjCPropertyDecl * +ObjCPropertyDecl::Create(ASTContext &C, DeclContext *DC, SourceLocation L, + const IdentifierInfo *Id, SourceLocation AtLoc, + SourceLocation LParenLoc, QualType T, + TypeSourceInfo *TSI, PropertyControl propControl) { return new (C, DC) ObjCPropertyDecl(DC, L, Id, AtLoc, LParenLoc, T, TSI, propControl); } diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index edbcdfe4d55bc94beb16169f374c4ab386237573..c66774dd1df1516a495b5244b63ff9b7c239a8c2 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -21,6 +21,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyPrinter.h" #include "clang/Basic/Module.h" +#include "clang/Basic/SourceManager.h" #include "llvm/Support/raw_ostream.h" using namespace clang; @@ -49,18 +50,6 @@ namespace { void PrintObjCTypeParams(ObjCTypeParamList *Params); - enum class AttrPrintLoc { - None = 0, - Left = 1, - Right = 2, - Any = Left | Right, - - LLVM_MARK_AS_BITMASK_ENUM(/*DefaultValue=*/Any) - }; - - void prettyPrintAttributes(Decl *D, raw_ostream &out, - AttrPrintLoc loc = AttrPrintLoc::Any); - public: DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy, const ASTContext &Context, unsigned Indentation = 0, @@ -129,11 +118,10 @@ namespace { const TemplateParameterList *Params); void printTemplateArguments(llvm::ArrayRef Args, const TemplateParameterList *Params); - - inline void prettyPrintAttributes(Decl *D) { - prettyPrintAttributes(D, Out); - } - + enum class AttrPosAsWritten { Default = 0, Left, Right }; + void + prettyPrintAttributes(const Decl *D, + AttrPosAsWritten Pos = AttrPosAsWritten::Default); void prettyPrintPragmas(Decl *D); void printDeclType(QualType T, StringRef DeclName, bool Pack = false); }; @@ -250,87 +238,48 @@ raw_ostream& DeclPrinter::Indent(unsigned Indentation) { return Out; } -// For CLANG_ATTR_LIST_CanPrintOnLeft macro. -#include "clang/Basic/AttrLeftSideCanPrintList.inc" - -// For CLANG_ATTR_LIST_PrintOnLeft macro. -#include "clang/Basic/AttrLeftSideMustPrintList.inc" - -static bool canPrintOnLeftSide(attr::Kind kind) { -#ifdef CLANG_ATTR_LIST_CanPrintOnLeft - switch (kind) { - CLANG_ATTR_LIST_CanPrintOnLeft - return true; - default: - return false; - } -#else - return false; -#endif -} - -static bool canPrintOnLeftSide(const Attr *A) { - if (A->isStandardAttributeSyntax()) - return false; - - return canPrintOnLeftSide(A->getKind()); -} - -static bool mustPrintOnLeftSide(attr::Kind kind) { -#ifdef CLANG_ATTR_LIST_PrintOnLeft - switch (kind) { - CLANG_ATTR_LIST_PrintOnLeft - return true; - default: - return false; - } -#else - return false; -#endif -} +static DeclPrinter::AttrPosAsWritten getPosAsWritten(const Attr *A, + const Decl *D) { + SourceLocation ALoc = A->getLoc(); + SourceLocation DLoc = D->getLocation(); + const ASTContext &C = D->getASTContext(); + if (ALoc.isInvalid() || DLoc.isInvalid()) + return DeclPrinter::AttrPosAsWritten::Left; -static bool mustPrintOnLeftSide(const Attr *A) { - if (A->isDeclspecAttribute()) - return true; + if (C.getSourceManager().isBeforeInTranslationUnit(ALoc, DLoc)) + return DeclPrinter::AttrPosAsWritten::Left; - return mustPrintOnLeftSide(A->getKind()); + return DeclPrinter::AttrPosAsWritten::Right; } -void DeclPrinter::prettyPrintAttributes(Decl *D, llvm::raw_ostream &Out, - AttrPrintLoc Loc) { +void DeclPrinter::prettyPrintAttributes(const Decl *D, + AttrPosAsWritten Pos /*=Default*/) { if (Policy.PolishForDeclaration) return; if (D->hasAttrs()) { - AttrVec &Attrs = D->getAttrs(); + const AttrVec &Attrs = D->getAttrs(); for (auto *A : Attrs) { if (A->isInherited() || A->isImplicit()) continue; - - AttrPrintLoc AttrLoc = AttrPrintLoc::Right; - if (mustPrintOnLeftSide(A)) { - // If we must always print on left side (e.g. declspec), then mark as - // so. - AttrLoc = AttrPrintLoc::Left; - } else if (canPrintOnLeftSide(A)) { - // For functions with body defined we print the attributes on the left - // side so that GCC accept our dumps as well. - if (const FunctionDecl *FD = dyn_cast(D); - FD && FD->isThisDeclarationADefinition()) - // In case Decl is a function with a body, then attrs should be print - // on the left side. - AttrLoc = AttrPrintLoc::Left; - - // In case it is a variable declaration with a ctor, then allow - // printing on the left side for readbility. - else if (const VarDecl *VD = dyn_cast(D); - VD && VD->getInit() && - VD->getInitStyle() == VarDecl::CallInit) - AttrLoc = AttrPrintLoc::Left; + switch (A->getKind()) { +#define ATTR(X) +#define PRAGMA_SPELLING_ATTR(X) case attr::X: +#include "clang/Basic/AttrList.inc" + break; + default: + AttrPosAsWritten APos = getPosAsWritten(A, D); + assert(APos != AttrPosAsWritten::Default && + "Default not a valid for an attribute location"); + if (Pos == AttrPosAsWritten::Default || Pos == APos) { + if (Pos != AttrPosAsWritten::Left) + Out << ' '; + A->printPretty(Out, Policy); + if (Pos == AttrPosAsWritten::Left) + Out << ' '; + } + break; } - // Only print the side matches the user requested. - if ((Loc & AttrLoc) != AttrPrintLoc::None) - A->printPretty(Out, Policy); } } } @@ -691,8 +640,10 @@ static void MaybePrintTagKeywordIfSupressingScopes(PrintingPolicy &Policy, void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { if (!D->getDescribedFunctionTemplate() && - !D->isFunctionTemplateSpecialization()) + !D->isFunctionTemplateSpecialization()) { prettyPrintPragmas(D); + prettyPrintAttributes(D, AttrPosAsWritten::Left); + } if (D->isFunctionTemplateSpecialization()) Out << "template<> "; @@ -702,22 +653,6 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { printTemplateParameters(D->getTemplateParameterList(I)); } - std::string LeftsideAttrs; - llvm::raw_string_ostream LSAS(LeftsideAttrs); - - prettyPrintAttributes(D, LSAS, AttrPrintLoc::Left); - - // prettyPrintAttributes print a space on left side of the attribute. - if (LeftsideAttrs[0] == ' ') { - // Skip the space prettyPrintAttributes generated. - LeftsideAttrs.erase(0, LeftsideAttrs.find_first_not_of(' ')); - - // Add a single space between the attribute and the Decl name. - LSAS << ' '; - } - - Out << LeftsideAttrs; - CXXConstructorDecl *CDecl = dyn_cast(D); CXXConversionDecl *ConversionDecl = dyn_cast(D); CXXDeductionGuideDecl *GuideDecl = dyn_cast(D); @@ -883,7 +818,7 @@ void DeclPrinter::VisitFunctionDecl(FunctionDecl *D) { Ty.print(Out, Policy, Proto); } - prettyPrintAttributes(D, Out, AttrPrintLoc::Right); + prettyPrintAttributes(D, AttrPosAsWritten::Right); if (D->isPureVirtual()) Out << " = 0"; @@ -976,27 +911,12 @@ void DeclPrinter::VisitLabelDecl(LabelDecl *D) { void DeclPrinter::VisitVarDecl(VarDecl *D) { prettyPrintPragmas(D); + prettyPrintAttributes(D, AttrPosAsWritten::Left); + if (const auto *Param = dyn_cast(D); Param && Param->isExplicitObjectParameter()) Out << "this "; - std::string LeftSide; - llvm::raw_string_ostream LeftSideStream(LeftSide); - - // Print attributes that should be placed on the left, such as __declspec. - prettyPrintAttributes(D, LeftSideStream, AttrPrintLoc::Left); - - // prettyPrintAttributes print a space on left side of the attribute. - if (LeftSide[0] == ' ') { - // Skip the space prettyPrintAttributes generated. - LeftSide.erase(0, LeftSide.find_first_not_of(' ')); - - // Add a single space between the attribute and the Decl name. - LeftSideStream << ' '; - } - - Out << LeftSide; - QualType T = D->getTypeSourceInfo() ? D->getTypeSourceInfo()->getType() : D->getASTContext().getUnqualifiedObjCPointerType(D->getType()); @@ -1029,21 +949,16 @@ void DeclPrinter::VisitVarDecl(VarDecl *D) { } } - StringRef Name; - - Name = (isa(D) && Policy.CleanUglifiedParameters && - D->getIdentifier()) - ? D->getIdentifier()->deuglifiedName() - : D->getName(); - if (!Policy.SuppressTagKeyword && Policy.SuppressScope && !Policy.SuppressUnwrittenScope) MaybePrintTagKeywordIfSupressingScopes(Policy, T, Out); - printDeclType(T, Name); - // Print the attributes that should be placed right before the end of the - // decl. - prettyPrintAttributes(D, Out, AttrPrintLoc::Right); + printDeclType(T, (isa(D) && Policy.CleanUglifiedParameters && + D->getIdentifier()) + ? D->getIdentifier()->deuglifiedName() + : D->getName()); + + prettyPrintAttributes(D, AttrPosAsWritten::Right); Expr *Init = D->getInit(); if (!Policy.SuppressInitializers && Init) { @@ -1303,7 +1218,10 @@ void DeclPrinter::VisitTemplateDecl(const TemplateDecl *D) { if (const TemplateTemplateParmDecl *TTP = dyn_cast(D)) { - Out << "class"; + if (TTP->wasDeclaredWithTypename()) + Out << "typename"; + else + Out << "class"; if (TTP->isParameterPack()) Out << " ..."; diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 3c217d6a6a5ae31933e3f88d249c0d5d116fc119..5aa2484197372bae11343ba22335c1734023ca1d 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -715,7 +715,7 @@ void TemplateTypeParmDecl::setTypeConstraint( NonTypeTemplateParmDecl::NonTypeTemplateParmDecl( DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, unsigned D, - unsigned P, IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, + unsigned P, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, ArrayRef ExpandedTypes, ArrayRef ExpandedTInfos) : DeclaratorDecl(NonTypeTemplateParm, DC, IdLoc, Id, T, TInfo, StartLoc), TemplateParmPosition(D, P), ParameterPack(true), @@ -730,12 +730,10 @@ NonTypeTemplateParmDecl::NonTypeTemplateParmDecl( } } -NonTypeTemplateParmDecl * -NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, - SourceLocation StartLoc, SourceLocation IdLoc, - unsigned D, unsigned P, IdentifierInfo *Id, - QualType T, bool ParameterPack, - TypeSourceInfo *TInfo) { +NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create( + const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, + SourceLocation IdLoc, unsigned D, unsigned P, const IdentifierInfo *Id, + QualType T, bool ParameterPack, TypeSourceInfo *TInfo) { AutoType *AT = C.getLangOpts().CPlusPlus20 ? T->getContainedAutoType() : nullptr; return new (C, DC, @@ -748,7 +746,7 @@ NonTypeTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, NonTypeTemplateParmDecl *NonTypeTemplateParmDecl::Create( const ASTContext &C, DeclContext *DC, SourceLocation StartLoc, - SourceLocation IdLoc, unsigned D, unsigned P, IdentifierInfo *Id, + SourceLocation IdLoc, unsigned D, unsigned P, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, ArrayRef ExpandedTypes, ArrayRef ExpandedTInfos) { AutoType *AT = TInfo->getType()->getContainedAutoType(); @@ -807,10 +805,10 @@ void TemplateTemplateParmDecl::anchor() {} TemplateTemplateParmDecl::TemplateTemplateParmDecl( DeclContext *DC, SourceLocation L, unsigned D, unsigned P, - IdentifierInfo *Id, TemplateParameterList *Params, + IdentifierInfo *Id, bool Typename, TemplateParameterList *Params, ArrayRef Expansions) : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), - TemplateParmPosition(D, P), ParameterPack(true), + TemplateParmPosition(D, P), Typename(Typename), ParameterPack(true), ExpandedParameterPack(true), NumExpandedParams(Expansions.size()) { if (!Expansions.empty()) std::uninitialized_copy(Expansions.begin(), Expansions.end(), @@ -821,26 +819,26 @@ TemplateTemplateParmDecl * TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, bool ParameterPack, IdentifierInfo *Id, - TemplateParameterList *Params) { + bool Typename, TemplateParameterList *Params) { return new (C, DC) TemplateTemplateParmDecl(DC, L, D, P, ParameterPack, Id, - Params); + Typename, Params); } TemplateTemplateParmDecl * TemplateTemplateParmDecl::Create(const ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, unsigned P, - IdentifierInfo *Id, + IdentifierInfo *Id, bool Typename, TemplateParameterList *Params, ArrayRef Expansions) { return new (C, DC, additionalSizeToAlloc(Expansions.size())) - TemplateTemplateParmDecl(DC, L, D, P, Id, Params, Expansions); + TemplateTemplateParmDecl(DC, L, D, P, Id, Typename, Params, Expansions); } TemplateTemplateParmDecl * TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (C, ID) TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0, - false, nullptr, nullptr); + false, nullptr, false, nullptr); } TemplateTemplateParmDecl * @@ -849,7 +847,7 @@ TemplateTemplateParmDecl::CreateDeserialized(ASTContext &C, unsigned ID, auto *TTP = new (C, ID, additionalSizeToAlloc(NumExpansions)) TemplateTemplateParmDecl(nullptr, SourceLocation(), 0, 0, nullptr, - nullptr, std::nullopt); + false, nullptr, std::nullopt); TTP->NumExpandedParams = NumExpansions; return TTP; } @@ -1471,7 +1469,7 @@ createMakeIntegerSeqParameterList(const ASTContext &C, DeclContext *DC) { // template class IntSeq auto *TemplateTemplateParm = TemplateTemplateParmDecl::Create( C, DC, SourceLocation(), /*Depth=*/0, /*Position=*/0, - /*ParameterPack=*/false, /*Id=*/nullptr, TPL); + /*ParameterPack=*/false, /*Id=*/nullptr, /*Typename=*/false, TPL); TemplateTemplateParm->setImplicit(true); // typename T diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 6221ebd5c9b4e99371d4998f7381e5673de10a67..07c9f287dd0767208d783ad14d88169f7ba1efa0 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -1712,8 +1712,11 @@ UnaryExprOrTypeTraitExpr::UnaryExprOrTypeTraitExpr( } MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc, - ValueDecl *MemberDecl, - const DeclarationNameInfo &NameInfo, QualType T, + NestedNameSpecifierLoc QualifierLoc, + SourceLocation TemplateKWLoc, ValueDecl *MemberDecl, + DeclAccessPair FoundDecl, + const DeclarationNameInfo &NameInfo, + const TemplateArgumentListInfo *TemplateArgs, QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR) : Expr(MemberExprClass, T, VK, OK), Base(Base), MemberDecl(MemberDecl), @@ -1721,11 +1724,30 @@ MemberExpr::MemberExpr(Expr *Base, bool IsArrow, SourceLocation OperatorLoc, assert(!NameInfo.getName() || MemberDecl->getDeclName() == NameInfo.getName()); MemberExprBits.IsArrow = IsArrow; - MemberExprBits.HasQualifierOrFoundDecl = false; - MemberExprBits.HasTemplateKWAndArgsInfo = false; + MemberExprBits.HasQualifier = QualifierLoc.hasQualifier(); + MemberExprBits.HasFoundDecl = + FoundDecl.getDecl() != MemberDecl || + FoundDecl.getAccess() != MemberDecl->getAccess(); + MemberExprBits.HasTemplateKWAndArgsInfo = + TemplateArgs || TemplateKWLoc.isValid(); MemberExprBits.HadMultipleCandidates = false; MemberExprBits.NonOdrUseReason = NOUR; MemberExprBits.OperatorLoc = OperatorLoc; + + if (hasQualifier()) + new (getTrailingObjects()) + NestedNameSpecifierLoc(QualifierLoc); + if (hasFoundDecl()) + *getTrailingObjects() = FoundDecl; + if (TemplateArgs) { + auto Deps = TemplateArgumentDependence::None; + getTrailingObjects()->initializeFrom( + TemplateKWLoc, *TemplateArgs, getTrailingObjects(), + Deps); + } else if (TemplateKWLoc.isValid()) { + getTrailingObjects()->initializeFrom( + TemplateKWLoc); + } setDependence(computeDependence(this)); } @@ -1735,48 +1757,20 @@ MemberExpr *MemberExpr::Create( ValueDecl *MemberDecl, DeclAccessPair FoundDecl, DeclarationNameInfo NameInfo, const TemplateArgumentListInfo *TemplateArgs, QualType T, ExprValueKind VK, ExprObjectKind OK, NonOdrUseReason NOUR) { - bool HasQualOrFound = QualifierLoc || FoundDecl.getDecl() != MemberDecl || - FoundDecl.getAccess() != MemberDecl->getAccess(); + bool HasQualifier = QualifierLoc.hasQualifier(); + bool HasFoundDecl = FoundDecl.getDecl() != MemberDecl || + FoundDecl.getAccess() != MemberDecl->getAccess(); bool HasTemplateKWAndArgsInfo = TemplateArgs || TemplateKWLoc.isValid(); std::size_t Size = - totalSizeToAlloc( - HasQualOrFound ? 1 : 0, HasTemplateKWAndArgsInfo ? 1 : 0, + totalSizeToAlloc( + HasQualifier, HasFoundDecl, HasTemplateKWAndArgsInfo, TemplateArgs ? TemplateArgs->size() : 0); void *Mem = C.Allocate(Size, alignof(MemberExpr)); - MemberExpr *E = new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, MemberDecl, - NameInfo, T, VK, OK, NOUR); - - if (HasQualOrFound) { - E->MemberExprBits.HasQualifierOrFoundDecl = true; - - MemberExprNameQualifier *NQ = - E->getTrailingObjects(); - NQ->QualifierLoc = QualifierLoc; - NQ->FoundDecl = FoundDecl; - } - - E->MemberExprBits.HasTemplateKWAndArgsInfo = - TemplateArgs || TemplateKWLoc.isValid(); - - // FIXME: remove remaining dependence computation to computeDependence(). - auto Deps = E->getDependence(); - if (TemplateArgs) { - auto TemplateArgDeps = TemplateArgumentDependence::None; - E->getTrailingObjects()->initializeFrom( - TemplateKWLoc, *TemplateArgs, - E->getTrailingObjects(), TemplateArgDeps); - for (const TemplateArgumentLoc &ArgLoc : TemplateArgs->arguments()) { - Deps |= toExprDependence(ArgLoc.getArgument().getDependence()); - } - } else if (TemplateKWLoc.isValid()) { - E->getTrailingObjects()->initializeFrom( - TemplateKWLoc); - } - E->setDependence(Deps); - - return E; + return new (Mem) MemberExpr(Base, IsArrow, OperatorLoc, QualifierLoc, + TemplateKWLoc, MemberDecl, FoundDecl, NameInfo, + TemplateArgs, T, VK, OK, NOUR); } MemberExpr *MemberExpr::CreateEmpty(const ASTContext &Context, @@ -1785,12 +1779,11 @@ MemberExpr *MemberExpr::CreateEmpty(const ASTContext &Context, unsigned NumTemplateArgs) { assert((!NumTemplateArgs || HasTemplateKWAndArgsInfo) && "template args but no template arg info?"); - bool HasQualOrFound = HasQualifier || HasFoundDecl; std::size_t Size = - totalSizeToAlloc(HasQualOrFound ? 1 : 0, - HasTemplateKWAndArgsInfo ? 1 : 0, - NumTemplateArgs); + totalSizeToAlloc( + HasQualifier, HasFoundDecl, HasTemplateKWAndArgsInfo, + NumTemplateArgs); void *Mem = Context.Allocate(Size, alignof(MemberExpr)); return new (Mem) MemberExpr(EmptyShell()); } @@ -1948,6 +1941,7 @@ bool CastExpr::CastConsistency() const { case CK_UserDefinedConversion: // operator bool() case CK_BuiltinFnToFnPtr: case CK_FixedPointToBoolean: + case CK_HLSLArrayRValue: CheckNoBasePath: assert(path_empty() && "Cast kind should not have a base path!"); break; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 592d43597dc1b45a4f325602f80bb39da5758c78..88c8eaf6ef9b6eb86b288828cd5066ae911cb365 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -209,7 +209,7 @@ namespace { IsArray = true; if (auto *CAT = dyn_cast(AT)) { - ArraySize = CAT->getSize().getZExtValue(); + ArraySize = CAT->getZExtSize(); } else { assert(I == 0 && "unexpected unsized array designator"); FirstEntryIsUnsizedArray = true; @@ -401,7 +401,7 @@ namespace { // This is a most-derived object. MostDerivedType = CAT->getElementType(); MostDerivedIsArrayElement = true; - MostDerivedArraySize = CAT->getSize().getZExtValue(); + MostDerivedArraySize = CAT->getZExtSize(); MostDerivedPathLength = Entries.size(); } /// Update this designator to refer to the first element within the array of @@ -3476,7 +3476,7 @@ static void expandStringLiteral(EvalInfo &Info, const StringLiteral *S, QualType CharType = CAT->getElementType(); assert(CharType->isIntegerType() && "unexpected character type"); - unsigned Elts = CAT->getSize().getZExtValue(); + unsigned Elts = CAT->getZExtSize(); Result = APValue(APValue::UninitArray(), std::min(S->getLength(), Elts), Elts); APSInt Value(Info.Ctx.getTypeSize(CharType), @@ -3619,7 +3619,7 @@ static bool CheckArraySize(EvalInfo &Info, const ConstantArrayType *CAT, SourceLocation CallLoc = {}) { return Info.CheckArraySize( CAT->getSizeExpr() ? CAT->getSizeExpr()->getBeginLoc() : CallLoc, - CAT->getNumAddressingBits(Info.Ctx), CAT->getSize().getZExtValue(), + CAT->getNumAddressingBits(Info.Ctx), CAT->getZExtSize(), /*Diag=*/true); } @@ -4908,7 +4908,7 @@ static bool handleDefaultInitValue(QualType T, APValue &Result) { if (auto *AT = dyn_cast_or_null(T->getAsArrayTypeUnsafe())) { - Result = APValue(APValue::UninitArray(), 0, AT->getSize().getZExtValue()); + Result = APValue(APValue::UninitArray(), 0, AT->getZExtSize()); if (Result.hasArrayFiller()) Success &= handleDefaultInitValue(AT->getElementType(), Result.getArrayFiller()); @@ -6456,7 +6456,7 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This, // Non-virtual base classes are initialized in the order in the class // definition. We have already checked for virtual base classes. assert(!BaseIt->isVirtual() && "virtual base for literal type"); - assert(Info.Ctx.hasSameType(BaseIt->getType(), BaseType) && + assert(Info.Ctx.hasSameUnqualifiedType(BaseIt->getType(), BaseType) && "base class initializers not in expected order"); ++BaseIt; #endif @@ -6595,7 +6595,7 @@ static bool HandleDestructionImpl(EvalInfo &Info, SourceRange CallRange, // For arrays, destroy elements right-to-left. if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(T)) { - uint64_t Size = CAT->getSize().getZExtValue(); + uint64_t Size = CAT->getZExtSize(); QualType ElemT = CAT->getElementType(); if (!CheckArraySize(Info, CAT, CallRange.getBegin())) @@ -7396,7 +7396,7 @@ class BufferToAPValueConverter { } std::optional visit(const ConstantArrayType *Ty, CharUnits Offset) { - size_t Size = Ty->getSize().getLimitedValue(); + size_t Size = Ty->getLimitedSize(); CharUnits ElementWidth = Info.Ctx.getTypeSizeInChars(Ty->getElementType()); APValue ArrayValue(APValue::UninitArray(), Size, Size); @@ -9951,7 +9951,7 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const CXXNewExpr *E) { assert(CAT && "unexpected type for array initializer"); unsigned Bits = - std::max(CAT->getSize().getBitWidth(), ArrayBound.getBitWidth()); + std::max(CAT->getSizeBitWidth(), ArrayBound.getBitWidth()); llvm::APInt InitBound = CAT->getSize().zext(Bits); llvm::APInt AllocBound = ArrayBound.zext(Bits); if (InitBound.ugt(AllocBound)) { @@ -10410,7 +10410,7 @@ bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr( if (Field->getType()->isIncompleteArrayType()) { if (auto *CAT = Info.Ctx.getAsConstantArrayType(Init->getType())) { - if (!CAT->getSize().isZero()) { + if (!CAT->isZeroSize()) { // Bail out for now. This might sort of "work", but the rest of the // code isn't really prepared to handle it. Info.FFDiag(Init, diag::note_constexpr_unsupported_flexible_array); @@ -10554,7 +10554,7 @@ bool RecordExprEvaluator::VisitCXXStdInitializerListExpr( // End pointer. if (!HandleLValueArrayAdjustment(Info, E, Array, ArrayType->getElementType(), - ArrayType->getSize().getZExtValue())) + ArrayType->getZExtSize())) return false; Array.moveInto(Result.getStructField(1)); } else if (Info.Ctx.hasSameType(Field->getType(), Info.Ctx.getSizeType())) @@ -10996,8 +10996,7 @@ namespace { return Error(E); } - Result = APValue(APValue::UninitArray(), 0, - CAT->getSize().getZExtValue()); + Result = APValue(APValue::UninitArray(), 0, CAT->getZExtSize()); if (!Result.hasArrayFiller()) return true; @@ -11122,7 +11121,7 @@ bool ArrayExprEvaluator::VisitCXXParenListOrInitListExpr( Filler = Result.getArrayFiller(); unsigned NumEltsToInit = Args.size(); - unsigned NumElts = CAT->getSize().getZExtValue(); + unsigned NumElts = CAT->getZExtSize(); // If the initializer might depend on the array index, run it for each // array element. @@ -11180,7 +11179,7 @@ bool ArrayExprEvaluator::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E) { auto *CAT = cast(E->getType()->castAsArrayTypeUnsafe()); - uint64_t Elements = CAT->getSize().getZExtValue(); + uint64_t Elements = CAT->getZExtSize(); Result = APValue(APValue::UninitArray(), Elements, Elements); LValue Subobject = This; @@ -11225,7 +11224,7 @@ bool ArrayExprEvaluator::VisitCXXConstructExpr(const CXXConstructExpr *E, bool HadZeroInit = Value->hasValue(); if (const ConstantArrayType *CAT = Info.Ctx.getAsConstantArrayType(Type)) { - unsigned FinalSize = CAT->getSize().getZExtValue(); + unsigned FinalSize = CAT->getZExtSize(); // Preserve the array filler if we had prior zero-initialization. APValue Filler = @@ -11700,6 +11699,7 @@ GCCTypeClass EvaluateBuiltinClassifyType(QualType T, case Type::IncompleteArray: case Type::FunctionNoProto: case Type::FunctionProto: + case Type::ArrayParameter: return GCCTypeClass::Pointer; case Type::MemberPointer: @@ -11940,7 +11940,7 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) { return true; const auto *CAT = cast(Ctx.getAsArrayType(BaseType)); uint64_t Index = Entry.getAsArrayIndex(); - if (Index + 1 != CAT->getSize()) + if (Index + 1 != CAT->getZExtSize()) return false; BaseType = CAT->getElementType(); } else if (BaseType->isAnyComplexType()) { @@ -12354,6 +12354,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__builtin_clzl: case Builtin::BI__builtin_clzll: case Builtin::BI__builtin_clzs: + case Builtin::BI__builtin_clzg: case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes case Builtin::BI__lzcnt: case Builtin::BI__lzcnt64: { @@ -12361,14 +12362,28 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, if (!EvaluateInteger(E->getArg(0), Val, Info)) return false; - // When the argument is 0, the result of GCC builtins is undefined, whereas - // for Microsoft intrinsics, the result is the bit-width of the argument. - bool ZeroIsUndefined = BuiltinOp != Builtin::BI__lzcnt16 && - BuiltinOp != Builtin::BI__lzcnt && - BuiltinOp != Builtin::BI__lzcnt64; + std::optional Fallback; + if (BuiltinOp == Builtin::BI__builtin_clzg && E->getNumArgs() > 1) { + APSInt FallbackTemp; + if (!EvaluateInteger(E->getArg(1), FallbackTemp, Info)) + return false; + Fallback = FallbackTemp; + } - if (ZeroIsUndefined && !Val) - return Error(E); + if (!Val) { + if (Fallback) + return Success(*Fallback, E); + + // When the argument is 0, the result of GCC builtins is undefined, + // whereas for Microsoft intrinsics, the result is the bit-width of the + // argument. + bool ZeroIsUndefined = BuiltinOp != Builtin::BI__lzcnt16 && + BuiltinOp != Builtin::BI__lzcnt && + BuiltinOp != Builtin::BI__lzcnt64; + + if (ZeroIsUndefined) + return Error(E); + } return Success(Val.countl_zero(), E); } @@ -12410,12 +12425,26 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, case Builtin::BI__builtin_ctz: case Builtin::BI__builtin_ctzl: case Builtin::BI__builtin_ctzll: - case Builtin::BI__builtin_ctzs: { + case Builtin::BI__builtin_ctzs: + case Builtin::BI__builtin_ctzg: { APSInt Val; if (!EvaluateInteger(E->getArg(0), Val, Info)) return false; - if (!Val) + + std::optional Fallback; + if (BuiltinOp == Builtin::BI__builtin_ctzg && E->getNumArgs() > 1) { + APSInt FallbackTemp; + if (!EvaluateInteger(E->getArg(1), FallbackTemp, Info)) + return false; + Fallback = FallbackTemp; + } + + if (!Val) { + if (Fallback) + return Success(*Fallback, E); + return Error(E); + } return Success(Val.countr_zero(), E); } @@ -14057,6 +14086,7 @@ bool IntExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_AtomicToNonAtomic: case CK_NoOp: case CK_LValueToRValueBitCast: + case CK_HLSLArrayRValue: return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_MemberPointerToBoolean: @@ -14885,6 +14915,7 @@ bool ComplexExprEvaluator::VisitCastExpr(const CastExpr *E) { case CK_AtomicToNonAtomic: case CK_NoOp: case CK_LValueToRValueBitCast: + case CK_HLSLArrayRValue: return ExprEvaluatorBaseTy::VisitCastExpr(E); case CK_Dependent: diff --git a/clang/lib/AST/FormatString.cpp b/clang/lib/AST/FormatString.cpp index 0c80ad109ccbb272236706fefb6cbc70b2c66d7b..da8164bad518ec7d646030cabbcbb0bb0d26cb8f 100644 --- a/clang/lib/AST/FormatString.cpp +++ b/clang/lib/AST/FormatString.cpp @@ -413,7 +413,7 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { return Match; if (const auto *BT = argTy->getAs()) { // Check if the only difference between them is signed vs unsigned - // if true, we consider they are compatible. + // if true, return match signedness. switch (BT->getKind()) { default: break; @@ -423,44 +423,53 @@ ArgType::matchesType(ASTContext &C, QualType argTy) const { [[fallthrough]]; case BuiltinType::Char_S: case BuiltinType::SChar: + if (T == C.UnsignedShortTy || T == C.ShortTy) + return NoMatchTypeConfusion; + if (T == C.UnsignedCharTy) + return NoMatchSignedness; + if (T == C.SignedCharTy) + return Match; + break; case BuiltinType::Char_U: case BuiltinType::UChar: if (T == C.UnsignedShortTy || T == C.ShortTy) return NoMatchTypeConfusion; - if (T == C.UnsignedCharTy || T == C.SignedCharTy) + if (T == C.UnsignedCharTy) return Match; + if (T == C.SignedCharTy) + return NoMatchSignedness; break; case BuiltinType::Short: if (T == C.UnsignedShortTy) - return Match; + return NoMatchSignedness; break; case BuiltinType::UShort: if (T == C.ShortTy) - return Match; + return NoMatchSignedness; break; case BuiltinType::Int: if (T == C.UnsignedIntTy) - return Match; + return NoMatchSignedness; break; case BuiltinType::UInt: if (T == C.IntTy) - return Match; + return NoMatchSignedness; break; case BuiltinType::Long: if (T == C.UnsignedLongTy) - return Match; + return NoMatchSignedness; break; case BuiltinType::ULong: if (T == C.LongTy) - return Match; + return NoMatchSignedness; break; case BuiltinType::LongLong: if (T == C.UnsignedLongLongTy) - return Match; + return NoMatchSignedness; break; case BuiltinType::ULongLong: if (T == C.LongLongTy) - return Match; + return NoMatchSignedness; break; } // "Partially matched" because of promotions? diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 73831eefba45687a9a469cd722f3aedf312c8fd7..01ec31e4077f707c8fa540b6ec5d13564e2f920c 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -173,10 +173,18 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return this->emitCastFloatingIntegral(*ToT, CE); } - case CK_NullToPointer: + case CK_NullToPointer: { if (DiscardResult) return true; - return this->emitNull(classifyPrim(CE->getType()), CE); + + const Descriptor *Desc = nullptr; + const QualType PointeeType = CE->getType()->getPointeeType(); + if (!PointeeType.isNull()) { + if (std::optional T = classify(PointeeType)) + Desc = P.createDescriptor(SubExpr, *T); + } + return this->emitNull(classifyPrim(CE->getType()), Desc, CE); + } case CK_PointerToIntegral: { if (DiscardResult) @@ -199,6 +207,41 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { return true; } + case CK_IntegralToPointer: { + QualType IntType = SubExpr->getType(); + assert(IntType->isIntegralOrEnumerationType()); + if (!this->visit(SubExpr)) + return false; + // FIXME: I think the discard is wrong since the int->ptr cast might cause a + // diagnostic. + PrimType T = classifyPrim(IntType); + if (DiscardResult) + return this->emitPop(T, CE); + + QualType PtrType = CE->getType(); + assert(PtrType->isPointerType()); + + const Descriptor *Desc; + if (std::optional T = classify(PtrType->getPointeeType())) + Desc = P.createDescriptor(SubExpr, *T); + else if (PtrType->getPointeeType()->isVoidType()) + Desc = nullptr; + else + Desc = P.createDescriptor(CE, PtrType->getPointeeType().getTypePtr(), + Descriptor::InlineDescMD, true, false, + /*IsMutable=*/false, nullptr); + + if (!this->emitGetIntPtr(T, Desc, CE)) + return false; + + PrimType DestPtrT = classifyPrim(PtrType); + if (DestPtrT == PT_Ptr) + return true; + + // In case we're converting the integer to a non-Pointer. + return this->emitDecayPtr(PT_Ptr, DestPtrT, CE); + } + case CK_AtomicToNonAtomic: case CK_ConstructorConversion: case CK_FunctionToPointerDecay: @@ -207,13 +250,31 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { case CK_UserDefinedConversion: return this->delegate(SubExpr); - case CK_BitCast: + case CK_BitCast: { + // Reject bitcasts to atomic types. if (CE->getType()->isAtomicType()) { if (!this->discard(SubExpr)) return false; return this->emitInvalidCast(CastKind::Reinterpret, CE); } - return this->delegate(SubExpr); + + if (DiscardResult) + return this->discard(SubExpr); + + std::optional FromT = classify(SubExpr->getType()); + std::optional ToT = classifyPrim(CE->getType()); + if (!FromT || !ToT) + return false; + + assert(isPtrType(*FromT)); + assert(isPtrType(*ToT)); + if (FromT == ToT) + return this->delegate(SubExpr); + + if (!this->visit(SubExpr)) + return false; + return this->emitDecayPtr(*FromT, *ToT, CE); + } case CK_IntegralToBoolean: case CK_IntegralCast: { @@ -245,7 +306,7 @@ bool ByteCodeExprGen::VisitCastExpr(const CastExpr *CE) { if (!this->visit(SubExpr)) return false; - if (!this->emitNull(PtrT, CE)) + if (!this->emitNull(PtrT, nullptr, CE)) return false; return this->emitNE(PtrT, CE); @@ -455,7 +516,7 @@ bool ByteCodeExprGen::VisitBinaryOperator(const BinaryOperator *BO) { // Pointer arithmetic special case. if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) { - if (T == PT_Ptr || (LT == PT_Ptr && RT == PT_Ptr)) + if (isPtrType(*T) || (isPtrType(*LT) && isPtrType(*RT))) return this->VisitPointerArithBinOp(BO); } @@ -819,7 +880,7 @@ bool ByteCodeExprGen::VisitImplicitValueInitExpr(const ImplicitValueIni const ArrayType *AT = QT->getAsArrayTypeUnsafe(); assert(AT); const auto *CAT = cast(AT); - size_t NumElems = CAT->getSize().getZExtValue(); + size_t NumElems = CAT->getZExtSize(); PrimType ElemT = classifyPrim(CAT->getElementType()); for (size_t I = 0; I != NumElems; ++I) { @@ -992,7 +1053,7 @@ bool ByteCodeExprGen::VisitInitListExpr(const InitListExpr *E) { if (const Expr *Filler = E->getArrayFiller()) { const ConstantArrayType *CAT = Ctx.getASTContext().getAsConstantArrayType(E->getType()); - uint64_t NumElems = CAT->getSize().getZExtValue(); + uint64_t NumElems = CAT->getZExtSize(); for (; ElementIndex != NumElems; ++ElementIndex) { if (!this->visitArrayElemInit(ElementIndex, Filler)) @@ -1033,6 +1094,34 @@ bool ByteCodeExprGen::VisitInitListExpr(const InitListExpr *E) { return true; } + if (const auto *VecT = E->getType()->getAs()) { + unsigned NumVecElements = VecT->getNumElements(); + assert(NumVecElements >= E->getNumInits()); + + QualType ElemQT = VecT->getElementType(); + PrimType ElemT = classifyPrim(ElemQT); + + // All initializer elements. + unsigned InitIndex = 0; + for (const Expr *Init : E->inits()) { + if (!this->visit(Init)) + return false; + + if (!this->emitInitElem(ElemT, InitIndex, E)) + return false; + ++InitIndex; + } + + // Fill the rest with zeroes. + for (; InitIndex != NumVecElements; ++InitIndex) { + if (!this->visitZeroInitializer(ElemT, ElemQT, E)) + return false; + if (!this->emitInitElem(ElemT, InitIndex, E)) + return false; + } + return true; + } + return false; } @@ -1084,6 +1173,9 @@ static CharUnits AlignOfType(QualType T, const ASTContext &ASTCtx, if (const auto *Ref = T->getAs()) T = Ref->getPointeeType(); + if (T.getQualifiers().hasUnaligned()) + return CharUnits::One(); + // __alignof is defined to return the preferred alignment. // Before 8, clang returned the preferred alignment for alignof and // _Alignof as well. @@ -1318,7 +1410,7 @@ bool ByteCodeExprGen::VisitStringLiteral(const StringLiteral *E) { // If the initializer string is too long, a diagnostic has already been // emitted. Read only the array length from the string literal. - unsigned ArraySize = CAT->getSize().getZExtValue(); + unsigned ArraySize = CAT->getZExtSize(); unsigned N = std::min(ArraySize, E->getLength()); size_t CharWidth = E->getCharByteWidth(); @@ -1919,7 +2011,7 @@ bool ByteCodeExprGen::VisitCXXConstructExpr( const ConstantArrayType *CAT = Ctx.getASTContext().getAsConstantArrayType(E->getType()); assert(CAT); - size_t NumElems = CAT->getSize().getZExtValue(); + size_t NumElems = CAT->getZExtSize(); const Function *Func = getFunction(E->getConstructor()); if (!Func || !Func->isConstexpr()) return false; @@ -2323,7 +2415,7 @@ bool ByteCodeExprGen::visitBool(const Expr *E) { // Convert pointers to bool. if (T == PT_Ptr || T == PT_FnPtr) { - if (!this->emitNull(*T, E)) + if (!this->emitNull(*T, nullptr, E)) return false; return this->emitNE(*T, E); } @@ -2363,9 +2455,9 @@ bool ByteCodeExprGen::visitZeroInitializer(PrimType T, QualType QT, case PT_IntAPS: return this->emitZeroIntAPS(Ctx.getBitWidth(QT), E); case PT_Ptr: - return this->emitNullPtr(E); + return this->emitNullPtr(nullptr, E); case PT_FnPtr: - return this->emitNullFnPtr(E); + return this->emitNullFnPtr(nullptr, E); case PT_Float: { return this->emitConstFloat(APFloat::getZero(Ctx.getFloatSemantics(QT)), E); } @@ -2511,6 +2603,7 @@ unsigned ByteCodeExprGen::allocateLocalPrimitive(DeclTy &&Src, dyn_cast_if_present(Src.dyn_cast())) { assert(!P.getGlobal(VD)); assert(!Locals.contains(VD)); + (void)VD; } // FIXME: There are cases where Src.is() is wrong, e.g. @@ -2685,26 +2778,34 @@ bool ByteCodeExprGen::visitVarDecl(const VarDecl *VD) { std::optional VarT = classify(VD->getType()); if (Context::shouldBeGloballyIndexed(VD)) { - // We've already seen and initialized this global. - if (P.getGlobal(VD)) - return true; - - std::optional GlobalIndex = P.createGlobal(VD, Init); - - if (!GlobalIndex) - return false; - - if (Init) { + auto initGlobal = [&](unsigned GlobalIndex) -> bool { + assert(Init); DeclScope LocalScope(this, VD); if (VarT) { if (!this->visit(Init)) return false; - return this->emitInitGlobal(*VarT, *GlobalIndex, VD); + return this->emitInitGlobal(*VarT, GlobalIndex, VD); } - return this->visitGlobalInitializer(Init, *GlobalIndex); + return this->visitGlobalInitializer(Init, GlobalIndex); + }; + + // We've already seen and initialized this global. + if (std::optional GlobalIndex = P.getGlobal(VD)) { + if (P.getPtrGlobal(*GlobalIndex).isInitialized()) + return true; + + // The previous attempt at initialization might've been unsuccessful, + // so let's try this one. + return Init && initGlobal(*GlobalIndex); } - return true; + + std::optional GlobalIndex = P.createGlobal(VD, Init); + + if (!GlobalIndex) + return false; + + return !Init || initGlobal(*GlobalIndex); } else { VariableScope LocalScope(this); if (VarT) { @@ -2948,7 +3049,7 @@ bool ByteCodeExprGen::VisitCXXNullPtrLiteralExpr( if (DiscardResult) return true; - return this->emitNullPtr(E); + return this->emitNullPtr(nullptr, E); } template diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp index 675063e74898867e0edc7875a252c8510a701a87..55a06f37a0c3dec8296174593d35c07579e53f80 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -110,7 +110,7 @@ bool ByteCodeStmtGen::emitLambdaStaticInvokerBody( // one here, and we don't need one either because the lambda cannot have // any captures, as verified above. Emit a null pointer. This is then // special-cased when interpreting to not emit any misleading diagnostics. - if (!this->emitNullPtr(MD)) + if (!this->emitNullPtr(nullptr, MD)) return false; // Forward all arguments from the static invoker to the lambda call operator. diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.h b/clang/lib/AST/Interp/ByteCodeStmtGen.h index ab7a591fb798ee6fb8e1d97c12d7a491fe84c536..d7e6e5042c2740b72c38a219fcaf1a89ba9d3c7c 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.h +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.h @@ -82,6 +82,7 @@ private: OptLabelTy DefaultLabel; }; +extern template class ByteCodeStmtGen; extern template class ByteCodeExprGen; } // namespace interp diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp index 15a9d46880e954acf13d2a7fc4d7ac33d3e62ede..274178837bf047d346ba7be09a6ac6ba159dbc92 100644 --- a/clang/lib/AST/Interp/Context.cpp +++ b/clang/lib/AST/Interp/Context.cpp @@ -120,7 +120,8 @@ std::optional Context::classify(QualType T) const { if (T->isBooleanType()) return PT_Bool; - if (T->isAnyComplexType()) + // We map these to primitive arrays. + if (T->isAnyComplexType() || T->isVectorType()) return std::nullopt; if (T->isSignedIntegerOrEnumerationType()) { diff --git a/clang/lib/AST/Interp/Descriptor.h b/clang/lib/AST/Interp/Descriptor.h index 4e257361ad146bfaa14c78873cb1f08bf1bbf162..c386fc8ac7b09d5030d1332e2d8dc227bba19a4c 100644 --- a/clang/lib/AST/Interp/Descriptor.h +++ b/clang/lib/AST/Interp/Descriptor.h @@ -168,6 +168,7 @@ public: const Decl *asDecl() const { return Source.dyn_cast(); } const Expr *asExpr() const { return Source.dyn_cast(); } + const DeclTy &getSource() const { return Source; } const ValueDecl *asValueDecl() const { return dyn_cast_if_present(asDecl()); diff --git a/clang/lib/AST/Interp/Disasm.cpp b/clang/lib/AST/Interp/Disasm.cpp index 01ef1c24744a582f4df50980ec4ddd81ac86bc10..022b394e58e6438cbaa27039a5d6e773aa67d7de 100644 --- a/clang/lib/AST/Interp/Disasm.cpp +++ b/clang/lib/AST/Interp/Disasm.cpp @@ -233,3 +233,34 @@ LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS, F = F->Caller; } } + +LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation, + unsigned Offset) const { + unsigned Indent = Indentation * 2; + OS.indent(Indent); + { + ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true}); + OS << getName() << "\n"; + } + + unsigned I = 0; + for (const Record::Base &B : bases()) { + OS.indent(Indent) << "- Base " << I << ". Offset " << (Offset + B.Offset) + << "\n"; + B.R->dump(OS, Indentation + 1, Offset + B.Offset); + ++I; + } + + // FIXME: Virtual bases. + + I = 0; + for (const Record::Field &F : fields()) { + OS.indent(Indent) << "- Field " << I << ": "; + { + ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true}); + OS << F.Decl->getName(); + } + OS << ". Offset " << (Offset + F.Offset) << "\n"; + ++I; + } +} diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp index caffb69d83e379a8d62225359889a0f1d22d1f9b..d764b4b6f6d17b1fde40c37c1e0ef85a77573db3 100644 --- a/clang/lib/AST/Interp/EvalEmitter.cpp +++ b/clang/lib/AST/Interp/EvalEmitter.cpp @@ -51,7 +51,8 @@ EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD, this->CheckFullyInitialized = CheckFullyInitialized; this->ConvertResultToRValue = VD->getAnyInitializer() && - (VD->getAnyInitializer()->getType()->isAnyComplexType()); + (VD->getAnyInitializer()->getType()->isAnyComplexType() || + VD->getAnyInitializer()->getType()->isVectorType()); EvalResult.setSource(VD); if (!this->visitDecl(VD) && EvalResult.empty()) diff --git a/clang/lib/AST/Interp/EvaluationResult.cpp b/clang/lib/AST/Interp/EvaluationResult.cpp index 07b28d07326f9017bfd0a0a6311f7fe0b75024fe..d567b551f7f6fcffbab18b4c067572f8f4960f15 100644 --- a/clang/lib/AST/Interp/EvaluationResult.cpp +++ b/clang/lib/AST/Interp/EvaluationResult.cpp @@ -66,7 +66,7 @@ static bool CheckArrayInitialized(InterpState &S, SourceLocation Loc, const Pointer &BasePtr, const ConstantArrayType *CAT) { bool Result = true; - size_t NumElems = CAT->getSize().getZExtValue(); + size_t NumElems = CAT->getZExtSize(); QualType ElemType = CAT->getElementType(); if (ElemType->isRecordType()) { diff --git a/clang/lib/AST/Interp/FunctionPointer.h b/clang/lib/AST/Interp/FunctionPointer.h index 2ff691b1cd3e186323e4907d4e7ca78dfa0a7327..840c1101f396b9516a6508a334bfa9985e18a8da 100644 --- a/clang/lib/AST/Interp/FunctionPointer.h +++ b/clang/lib/AST/Interp/FunctionPointer.h @@ -20,10 +20,15 @@ namespace interp { class FunctionPointer final { private: const Function *Func; + bool Valid; public: - FunctionPointer() : Func(nullptr) {} - FunctionPointer(const Function *Func) : Func(Func) { assert(Func); } + FunctionPointer(const Function *Func) : Func(Func), Valid(true) { + assert(Func); + } + + FunctionPointer(uintptr_t IntVal = 0, const Descriptor *Desc = nullptr) + : Func(reinterpret_cast(IntVal)), Valid(false) {} const Function *getFunction() const { return Func; } bool isZero() const { return !Func; } @@ -33,14 +38,21 @@ public: return APValue(static_cast(nullptr), CharUnits::Zero(), {}, /*OnePastTheEnd=*/false, /*IsNull=*/true); + if (!Valid) + return APValue(static_cast(nullptr), + CharUnits::fromQuantity(getIntegerRepresentation()), {}, + /*OnePastTheEnd=*/false, /*IsNull=*/false); + return APValue(Func->getDecl(), CharUnits::Zero(), {}, /*OnePastTheEnd=*/false, /*IsNull=*/false); } void print(llvm::raw_ostream &OS) const { OS << "FnPtr("; - if (Func) + if (Func && Valid) OS << Func->getName(); + else if (Func) + OS << reinterpret_cast(Func); else OS << "nullptr"; OS << ")"; @@ -53,6 +65,10 @@ public: return toAPValue().getAsString(Ctx, Func->getDecl()->getType()); } + uint64_t getIntegerRepresentation() const { + return static_cast(reinterpret_cast(Func)); + } + ComparisonCategoryResult compare(const FunctionPointer &RHS) const { if (Func == RHS.Func) return ComparisonCategoryResult::Equal; diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp index 0ce64a572c263f3daa07d3de4385037e24fa6496..2607e0743251673aaba35b958795723ec22b5002 100644 --- a/clang/lib/AST/Interp/Interp.cpp +++ b/clang/lib/AST/Interp/Interp.cpp @@ -56,22 +56,65 @@ static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) { return true; } +static void diagnoseMissingInitializer(InterpState &S, CodePtr OpPC, + const ValueDecl *VD) { + const SourceInfo &E = S.Current->getSource(OpPC); + S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD; + S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange(); +} + +static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, + const ValueDecl *VD); +static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC, + const ValueDecl *D) { + const SourceInfo &E = S.Current->getSource(OpPC); + + if (isa(D)) { + if (S.getLangOpts().CPlusPlus11) { + S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D; + S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange(); + } else { + S.FFDiag(E); + } + } else if (const auto *VD = dyn_cast(D)) { + if (!VD->getType().isConstQualified()) { + diagnoseNonConstVariable(S, OpPC, VD); + return false; + } + + // const, but no initializer. + if (!VD->getAnyInitializer()) { + diagnoseMissingInitializer(S, OpPC, VD); + return false; + } + } + return false; +} + static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC, const ValueDecl *VD) { if (!S.getLangOpts().CPlusPlus) return; const SourceInfo &Loc = S.Current->getSource(OpPC); + if (const auto *VarD = dyn_cast(VD); + VarD && VarD->getType().isConstQualified() && + !VarD->getAnyInitializer()) { + diagnoseMissingInitializer(S, OpPC, VD); + return; + } - if (VD->getType()->isIntegralOrEnumerationType()) + if (VD->getType()->isIntegralOrEnumerationType()) { S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD; - else - S.FFDiag(Loc, - S.getLangOpts().CPlusPlus11 - ? diag::note_constexpr_ltor_non_constexpr - : diag::note_constexpr_ltor_non_integral, - 1) - << VD << VD->getType(); + S.Note(VD->getLocation(), diag::note_declared_at); + return; + } + + S.FFDiag(Loc, + S.getLangOpts().CPlusPlus11 ? diag::note_constexpr_ltor_non_constexpr + : diag::note_constexpr_ltor_non_integral, + 1) + << VD << VD->getType(); S.Note(VD->getLocation(), diag::note_declared_at); } @@ -202,6 +245,9 @@ bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { if (!Ptr.isExtern()) return true; + if (Ptr.isInitialized()) + return true; + if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) { const auto *VD = Ptr.getDeclDesc()->asValueDecl(); diagnoseNonConstVariable(S, OpPC, VD); @@ -282,6 +328,8 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { } static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { + if (Ptr.isIntegralPointer()) + return true; return CheckConstant(S, OpPC, Ptr.getDeclDesc()); } @@ -335,6 +383,9 @@ bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { return true; } + if (!Ptr.isBlockPointer()) + return false; + const QualType Ty = Ptr.getType(); const SourceInfo &Loc = S.Current->getSource(OpPC); S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty; @@ -364,9 +415,15 @@ bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, if (const auto *VD = Ptr.getDeclDesc()->asVarDecl(); VD && VD->hasGlobalStorage()) { const SourceInfo &Loc = S.Current->getSource(OpPC); - S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD; - S.Note(VD->getLocation(), diag::note_declared_at); + if (VD->getAnyInitializer()) { + S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD; + S.Note(VD->getLocation(), diag::note_declared_at); + } else { + diagnoseMissingInitializer(S, OpPC, VD); + } + return false; } + if (!S.checkingPotentialConstantExpression()) { S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit) << AK << /*uninitialized=*/true << S.Current->getRange(OpPC); @@ -593,33 +650,6 @@ bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, return true; } -static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC, - const ValueDecl *D) { - const SourceInfo &E = S.Current->getSource(OpPC); - - if (isa(D)) { - if (S.getLangOpts().CPlusPlus11) { - S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D; - S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange(); - } else { - S.FFDiag(E); - } - } else if (const auto *VD = dyn_cast(D)) { - if (!VD->getType().isConstQualified()) { - diagnoseNonConstVariable(S, OpPC, VD); - return false; - } - - // const, but no initializer. - if (!VD->getAnyInitializer()) { - S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD; - S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange(); - return false; - } - } - return false; -} - /// We aleady know the given DeclRefExpr is invalid for some reason, /// now figure out why and print appropriate diagnostics. bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) { diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 405993eb827036f620ec62e119ddb33667697682..c7012aa4ec680bed8d2b5b3bdf0d90996c84c401 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -801,6 +801,17 @@ inline bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) { return true; } + for (const auto &P : {LHS, RHS}) { + if (P.isZero()) + continue; + if (P.isWeak()) { + const SourceInfo &Loc = S.Current->getSource(OpPC); + S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison) + << P.toDiagnosticString(S.getCtx()); + return false; + } + } + if (!Pointer::hasSameBase(LHS, RHS)) { S.Stk.push(BoolT::from(Fn(ComparisonCategoryResult::Unordered))); return true; @@ -812,9 +823,9 @@ inline bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) { // element in the same array are NOT equal. They have the same Base value, // but a different Offset. This is a pretty rare case, so we fix this here // by comparing pointers to the first elements. - if (!LHS.isDummy() && LHS.isArrayRoot()) + if (!LHS.isZero() && !LHS.isDummy() && LHS.isArrayRoot()) VL = LHS.atIndex(0).getByteOffset(); - if (!RHS.isDummy() && RHS.isArrayRoot()) + if (!RHS.isZero() && !RHS.isDummy() && RHS.isArrayRoot()) VR = RHS.atIndex(0).getByteOffset(); S.Stk.push(BoolT::from(Fn(Compare(VL, VR)))); @@ -1333,6 +1344,11 @@ inline bool FinishInit(InterpState &S, CodePtr OpPC) { return true; } +inline bool Dump(InterpState &S, CodePtr OpPC) { + S.Stk.dump(); + return true; +} + inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, const Pointer &Ptr) { Pointer Base = Ptr; @@ -1370,6 +1386,8 @@ bool Load(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.peek(); if (!CheckLoad(S, OpPC, Ptr)) return false; + if (!Ptr.isBlockPointer()) + return false; S.Stk.push(Ptr.deref()); return true; } @@ -1379,6 +1397,8 @@ bool LoadPop(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop(); if (!CheckLoad(S, OpPC, Ptr)) return false; + if (!Ptr.isBlockPointer()) + return false; S.Stk.push(Ptr.deref()); return true; } @@ -1517,8 +1537,12 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, return true; } - if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) - return false; + if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) { + // The CheckNull will have emitted a note already, but we only + // abort in C++, since this is fine in C. + if (S.getLangOpts().CPlusPlus) + return false; + } // Arrays of unknown bounds cannot have pointers into them. if (!CheckArray(S, OpPC, Ptr)) @@ -1544,23 +1568,25 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, Invalid = true; }; - T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth()); - if constexpr (Op == ArithOp::Add) { - // If the new offset would be negative, bail out. - if (Offset.isNegative() && (Offset.isMin() || -Offset > Index)) - DiagInvalidOffset(); - - // If the new offset would be out of bounds, bail out. - if (Offset.isPositive() && Offset > MaxOffset) - DiagInvalidOffset(); - } else { - // If the new offset would be negative, bail out. - if (Offset.isPositive() && Index < Offset) - DiagInvalidOffset(); - - // If the new offset would be out of bounds, bail out. - if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset)) - DiagInvalidOffset(); + if (Ptr.isBlockPointer()) { + T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth()); + if constexpr (Op == ArithOp::Add) { + // If the new offset would be negative, bail out. + if (Offset.isNegative() && (Offset.isMin() || -Offset > Index)) + DiagInvalidOffset(); + + // If the new offset would be out of bounds, bail out. + if (Offset.isPositive() && Offset > MaxOffset) + DiagInvalidOffset(); + } else { + // If the new offset would be negative, bail out. + if (Offset.isPositive() && Index < Offset) + DiagInvalidOffset(); + + // If the new offset would be out of bounds, bail out. + if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset)) + DiagInvalidOffset(); + } } if (Invalid && !Ptr.isDummy() && S.getLangOpts().CPlusPlus) @@ -1644,6 +1670,11 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC) { const Pointer &LHS = S.Stk.pop(); const Pointer &RHS = S.Stk.pop(); + if (RHS.isZero()) { + S.Stk.push(T::from(LHS.getIndex())); + return true; + } + if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) { // TODO: Diagnose. return false; @@ -1822,8 +1853,9 @@ static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { } template ::T> -inline bool Null(InterpState &S, CodePtr OpPC) { - S.Stk.push(); +inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { + // Note: Desc can be null. + S.Stk.push(0, Desc); return true; } @@ -1841,6 +1873,15 @@ inline bool This(InterpState &S, CodePtr OpPC) { if (!CheckThis(S, OpPC, This)) return false; + // Ensure the This pointer has been cast to the correct base. + if (!This.isDummy()) { + assert(isa(S.Current->getFunction()->getDecl())); + assert(This.getRecord()); + assert( + This.getRecord()->getDecl() == + cast(S.Current->getFunction()->getDecl())->getParent()); + } + S.Stk.push(This); return true; } @@ -2218,6 +2259,14 @@ inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) { return true; } +template ::T> +inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { + const T &IntVal = S.Stk.pop(); + + S.Stk.push(static_cast(IntVal), Desc); + return true; +} + /// Just emit a diagnostic. The expression that caused emission of this /// op is not valid in a constant context. inline bool Invalid(InterpState &S, CodePtr OpPC) { @@ -2274,6 +2323,18 @@ inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) { return false; } +/// OldPtr -> Integer -> NewPtr. +template +inline bool DecayPtr(InterpState &S, CodePtr OpPC) { + static_assert(isPtrType(TIn) && isPtrType(TOut)); + using FromT = typename PrimConv::T; + using ToT = typename PrimConv::T; + + const FromT &OldPtr = S.Stk.pop(); + S.Stk.push(ToT(OldPtr.getIntegerRepresentation(), nullptr)); + return true; +} + //===----------------------------------------------------------------------===// // Read opcode arguments //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/Interp/InterpBlock.cpp b/clang/lib/AST/Interp/InterpBlock.cpp index a62128d9cfaedd292b38238715b7d0bf33754751..9b33d1b778fb2c0aadf77cc10d8c1dbb42a2fcb9 100644 --- a/clang/lib/AST/Interp/InterpBlock.cpp +++ b/clang/lib/AST/Interp/InterpBlock.cpp @@ -73,7 +73,7 @@ void Block::replacePointer(Pointer *Old, Pointer *New) { removePointer(Old); addPointer(New); - Old->Pointee = nullptr; + Old->PointeeStorage.BS.Pointee = nullptr; #ifndef NDEBUG assert(!hasPointer(Old)); @@ -104,7 +104,7 @@ DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk) // Transfer pointers. B.Pointers = Blk->Pointers; for (Pointer *P = Blk->Pointers; P; P = P->Next) - P->Pointee = &B; + P->PointeeStorage.BS.Pointee = &B; } void DeadBlock::free() { diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index 1bf5d55314f1f2ac2a059defc40903cb2dec3e85..984ba4f7f2689c0e61b944e31882ae8533c1b760 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -16,6 +16,16 @@ namespace clang { namespace interp { +static unsigned callArgSize(const InterpState &S, const CallExpr *C) { + unsigned O = 0; + + for (const Expr *E : C->arguments()) { + O += align(primSize(*S.getContext().classify(E))); + } + + return O; +} + template static T getParam(const InterpFrame *Frame, unsigned Index) { assert(Frame->getFunction()->getNumParams() > Index); @@ -816,9 +826,10 @@ static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC, static bool interp__builtin_clz(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, const CallExpr *Call) { + unsigned CallSize = callArgSize(S, Call); unsigned BuiltinOp = Func->getBuiltinID(); PrimType ValT = *S.getContext().classify(Call->getArg(0)); - const APSInt &Val = peekToAPSInt(S.Stk, ValT); + const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize); // When the argument is 0, the result of GCC builtins is undefined, whereas // for Microsoft intrinsics, the result is the bit-width of the argument. @@ -826,8 +837,19 @@ static bool interp__builtin_clz(InterpState &S, CodePtr OpPC, BuiltinOp != Builtin::BI__lzcnt && BuiltinOp != Builtin::BI__lzcnt64; - if (ZeroIsUndefined && Val == 0) - return false; + if (Val == 0) { + if (Func->getBuiltinID() == Builtin::BI__builtin_clzg && + Call->getNumArgs() == 2) { + // We have a fallback parameter. + PrimType FallbackT = *S.getContext().classify(Call->getArg(1)); + const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT); + pushInteger(S, Fallback, Call->getType()); + return true; + } + + if (ZeroIsUndefined) + return false; + } pushInteger(S, Val.countl_zero(), Call->getType()); return true; @@ -836,11 +858,21 @@ static bool interp__builtin_clz(InterpState &S, CodePtr OpPC, static bool interp__builtin_ctz(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const Function *Func, const CallExpr *Call) { + unsigned CallSize = callArgSize(S, Call); PrimType ValT = *S.getContext().classify(Call->getArg(0)); - const APSInt &Val = peekToAPSInt(S.Stk, ValT); - - if (Val == 0) + const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize); + + if (Val == 0) { + if (Func->getBuiltinID() == Builtin::BI__builtin_ctzg && + Call->getNumArgs() == 2) { + // We have a fallback parameter. + PrimType FallbackT = *S.getContext().classify(Call->getArg(1)); + const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT); + pushInteger(S, Fallback, Call->getType()); + return true; + } return false; + } pushInteger(S, Val.countr_zero(), Call->getType()); return true; @@ -1223,6 +1255,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, case Builtin::BI__builtin_clzl: case Builtin::BI__builtin_clzll: case Builtin::BI__builtin_clzs: + case Builtin::BI__builtin_clzg: case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes case Builtin::BI__lzcnt: case Builtin::BI__lzcnt64: @@ -1234,6 +1267,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, case Builtin::BI__builtin_ctzl: case Builtin::BI__builtin_ctzll: case Builtin::BI__builtin_ctzs: + case Builtin::BI__builtin_ctzg: if (!interp__builtin_ctz(S, OpPC, Frame, F, Call)) return false; break; diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td index cc1310f4c0d52aeb0b00ac8fd39acafdcce43fac..e17be3afd25729a7f3a1b78fcb425af3d16ae1fa 100644 --- a/clang/lib/AST/Interp/Opcodes.td +++ b/clang/lib/AST/Interp/Opcodes.td @@ -59,6 +59,7 @@ def ArgCastKind : ArgType { let Name = "CastKind"; } def ArgCallExpr : ArgType { let Name = "const CallExpr *"; } def ArgOffsetOfExpr : ArgType { let Name = "const OffsetOfExpr *"; } def ArgDeclRef : ArgType { let Name = "const DeclRefExpr *"; } +def ArgDesc : ArgType { let Name = "const Descriptor *"; } def ArgCCI : ArgType { let Name = "const ComparisonCategoryInfo *"; } //===----------------------------------------------------------------------===// @@ -272,6 +273,7 @@ def ZeroIntAPS : Opcode { // [] -> [Pointer] def Null : Opcode { let Types = [PtrTypeClass]; + let Args = [ArgDesc]; let HasGroup = 1; } @@ -530,6 +532,11 @@ def GetFnPtr : Opcode { let Args = [ArgFunction]; } +def GetIntPtr : Opcode { + let Types = [AluTypeClass]; + let Args = [ArgDesc]; + let HasGroup = 1; +} //===----------------------------------------------------------------------===// // Binary operators. @@ -662,6 +669,11 @@ def CastPointerIntegral : Opcode { let HasGroup = 1; } +def DecayPtr : Opcode { + let Types = [PtrTypeClass, PtrTypeClass]; + let HasGroup = 1; +} + //===----------------------------------------------------------------------===// // Comparison opcodes. //===----------------------------------------------------------------------===// @@ -723,3 +735,8 @@ def CheckNonNullArg : Opcode { } def Memcpy : Opcode; + +//===----------------------------------------------------------------------===// +// Debugging. +//===----------------------------------------------------------------------===// +def Dump : Opcode; diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index af60ced0e10e9ea2a6e4231a6bf34a3c841976d6..e163e658d462b2d2020900e95d27798461c41f4c 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -26,60 +26,95 @@ Pointer::Pointer(Block *Pointee) Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset) : Pointer(Pointee, BaseAndOffset, BaseAndOffset) {} -Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {} +Pointer::Pointer(const Pointer &P) + : Offset(P.Offset), PointeeStorage(P.PointeeStorage), + StorageKind(P.StorageKind) { -Pointer::Pointer(Pointer &&P) - : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) { - if (Pointee) - Pointee->replacePointer(&P, this); + if (isBlockPointer() && PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->addPointer(this); } Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset) - : Pointee(Pointee), Base(Base), Offset(Offset) { + : Offset(Offset), StorageKind(Storage::Block) { assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base"); + + PointeeStorage.BS = {Pointee, Base}; + if (Pointee) Pointee->addPointer(this); } +Pointer::Pointer(Pointer &&P) + : Offset(P.Offset), PointeeStorage(P.PointeeStorage), + StorageKind(P.StorageKind) { + + if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->replacePointer(&P, this); +} + Pointer::~Pointer() { - if (Pointee) { - Pointee->removePointer(this); - Pointee->cleanup(); + if (isIntegralPointer()) + return; + + if (PointeeStorage.BS.Pointee) { + PointeeStorage.BS.Pointee->removePointer(this); + PointeeStorage.BS.Pointee->cleanup(); } } void Pointer::operator=(const Pointer &P) { - Block *Old = Pointee; - if (Pointee) - Pointee->removePointer(this); + if (!this->isIntegralPointer() || !P.isBlockPointer()) + assert(P.StorageKind == StorageKind); - Offset = P.Offset; - Base = P.Base; + bool WasBlockPointer = isBlockPointer(); + StorageKind = P.StorageKind; + if (StorageKind == Storage::Block) { + Block *Old = PointeeStorage.BS.Pointee; + if (WasBlockPointer && PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->removePointer(this); - Pointee = P.Pointee; - if (Pointee) - Pointee->addPointer(this); + Offset = P.Offset; + PointeeStorage.BS = P.PointeeStorage.BS; + + if (PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->addPointer(this); + + if (WasBlockPointer && Old) + Old->cleanup(); - if (Old) - Old->cleanup(); + } else if (StorageKind == Storage::Int) { + PointeeStorage.Int = P.PointeeStorage.Int; + } else { + assert(false && "Unhandled storage kind"); + } } void Pointer::operator=(Pointer &&P) { - Block *Old = Pointee; + if (!this->isIntegralPointer() || !P.isBlockPointer()) + assert(P.StorageKind == StorageKind); - if (Pointee) - Pointee->removePointer(this); + bool WasBlockPointer = isBlockPointer(); + StorageKind = P.StorageKind; + if (StorageKind == Storage::Block) { + Block *Old = PointeeStorage.BS.Pointee; + if (WasBlockPointer && PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->removePointer(this); - Offset = P.Offset; - Base = P.Base; + Offset = P.Offset; + PointeeStorage.BS = P.PointeeStorage.BS; - Pointee = P.Pointee; - if (Pointee) - Pointee->replacePointer(&P, this); + if (PointeeStorage.BS.Pointee) + PointeeStorage.BS.Pointee->addPointer(this); - if (Old) - Old->cleanup(); + if (WasBlockPointer && Old) + Old->cleanup(); + + } else if (StorageKind == Storage::Int) { + PointeeStorage.Int = P.PointeeStorage.Int; + } else { + assert(false && "Unhandled storage kind"); + } } APValue Pointer::toAPValue() const { @@ -88,6 +123,11 @@ APValue Pointer::toAPValue() const { if (isZero()) return APValue(static_cast(nullptr), CharUnits::Zero(), Path, /*IsOnePastEnd=*/false, /*IsNullPtr=*/true); + if (isIntegralPointer()) + return APValue(static_cast(nullptr), + CharUnits::fromQuantity(asIntPointer().Value + this->Offset), + Path, + /*IsOnePastEnd=*/false, /*IsNullPtr=*/false); // Build the lvalue base from the block. const Descriptor *Desc = getDeclDesc(); @@ -137,19 +177,52 @@ APValue Pointer::toAPValue() const { return APValue(Base, Offset, Path, IsOnePastEnd, /*IsNullPtr=*/false); } +void Pointer::print(llvm::raw_ostream &OS) const { + OS << PointeeStorage.BS.Pointee << " ("; + if (isBlockPointer()) { + OS << "Block) {"; + + if (PointeeStorage.BS.Base == RootPtrMark) + OS << "rootptr, "; + else + OS << PointeeStorage.BS.Base << ", "; + + if (Offset == PastEndMark) + OS << "pastend, "; + else + OS << Offset << ", "; + + if (isBlockPointer() && PointeeStorage.BS.Pointee) + OS << PointeeStorage.BS.Pointee->getSize(); + else + OS << "nullptr"; + } else { + OS << "Int) {"; + OS << PointeeStorage.Int.Value << ", " << PointeeStorage.Int.Desc; + } + OS << "}"; +} + std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const { - if (!Pointee) + if (isZero()) return "nullptr"; + if (isIntegralPointer()) + return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str(); + return toAPValue().getAsString(Ctx, getType()); } bool Pointer::isInitialized() const { - assert(Pointee && "Cannot check if null pointer was initialized"); + if (isIntegralPointer()) + return true; + + assert(PointeeStorage.BS.Pointee && + "Cannot check if null pointer was initialized"); const Descriptor *Desc = getFieldDesc(); assert(Desc); if (Desc->isPrimitiveArray()) { - if (isStatic() && Base == 0) + if (isStatic() && PointeeStorage.BS.Base == 0) return true; InitMapPtr &IM = getInitMap(); @@ -164,17 +237,24 @@ bool Pointer::isInitialized() const { } // Field has its bit in an inline descriptor. - return Base == 0 || getInlineDesc()->IsInitialized; + return PointeeStorage.BS.Base == 0 || getInlineDesc()->IsInitialized; } void Pointer::initialize() const { - assert(Pointee && "Cannot initialize null pointer"); + if (isIntegralPointer()) + return; + + assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer"); const Descriptor *Desc = getFieldDesc(); assert(Desc); if (Desc->isPrimitiveArray()) { // Primitive global arrays don't have an initmap. - if (isStatic() && Base == 0) + if (isStatic() && PointeeStorage.BS.Base == 0) + return; + + // Nothing to do for these. + if (Desc->getNumElems() == 0) return; InitMapPtr &IM = getInitMap(); @@ -196,13 +276,15 @@ void Pointer::initialize() const { } // Field has its bit in an inline descriptor. - assert(Base != 0 && "Only composite fields can be initialised"); + assert(PointeeStorage.BS.Base != 0 && + "Only composite fields can be initialised"); getInlineDesc()->IsInitialized = true; } void Pointer::activate() const { // Field has its bit in an inline descriptor. - assert(Base != 0 && "Only composite fields can be initialised"); + assert(PointeeStorage.BS.Base != 0 && + "Only composite fields can be initialised"); getInlineDesc()->IsActive = true; } @@ -211,11 +293,23 @@ void Pointer::deactivate() const { } bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) { - return A.Pointee == B.Pointee; + // Two null pointers always have the same base. + if (A.isZero() && B.isZero()) + return true; + + if (A.isIntegralPointer() && B.isIntegralPointer()) + return true; + + if (A.isIntegralPointer() || B.isIntegralPointer()) + return A.getSource() == B.getSource(); + + return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee; } bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) { - return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray; + return hasSameBase(A, B) && + A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base && + A.getFieldDesc()->IsArray; } std::optional Pointer::toRValue(const Context &Ctx) const { @@ -338,6 +432,25 @@ std::optional Pointer::toRValue(const Context &Ctx) const { return false; } + // Vector types. + if (const auto *VT = Ty->getAs()) { + assert(Ptr.getFieldDesc()->isPrimitiveArray()); + QualType ElemTy = VT->getElementType(); + PrimType ElemT = *Ctx.classify(ElemTy); + + SmallVector Values; + Values.reserve(VT->getNumElements()); + for (unsigned I = 0; I != VT->getNumElements(); ++I) { + TYPE_SWITCH(ElemT, { + Values.push_back(Ptr.atIndex(I).deref().toAPValue()); + }); + } + + assert(Values.size() == VT->getNumElements()); + R = APValue(Values.data(), Values.size()); + return true; + } + llvm_unreachable("invalid value to return"); }; diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h index fffb4aba492fc83c8a3082342e324959bd10c151..fcd00aac62f93e6d0af089ae8c61c089976d84b7 100644 --- a/clang/lib/AST/Interp/Pointer.h +++ b/clang/lib/AST/Interp/Pointer.h @@ -28,11 +28,26 @@ class Block; class DeadBlock; class Pointer; class Context; +template class Integral; enum PrimType : unsigned; class Pointer; inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P); +struct BlockPointer { + /// The block the pointer is pointing to. + Block *Pointee; + /// Start of the current subfield. + unsigned Base; +}; + +struct IntPointer { + const Descriptor *Desc; + uint64_t Value; +}; + +enum class Storage { Block, Int }; + /// A pointer to a memory block, live or dead. /// /// This object can be allocated into interpreter stack frames. If pointing to @@ -68,11 +83,20 @@ private: static constexpr unsigned RootPtrMark = ~0u; public: - Pointer() {} + Pointer() { + StorageKind = Storage::Int; + PointeeStorage.Int.Value = 0; + PointeeStorage.Int.Desc = nullptr; + } Pointer(Block *B); Pointer(Block *B, unsigned BaseAndOffset); Pointer(const Pointer &P); Pointer(Pointer &&P); + Pointer(uint64_t Address, const Descriptor *Desc, unsigned Offset = 0) + : Offset(Offset), StorageKind(Storage::Int) { + PointeeStorage.Int.Value = Address; + PointeeStorage.Int.Desc = Desc; + } ~Pointer(); void operator=(const Pointer &P); @@ -80,21 +104,30 @@ public: /// Equality operators are just for tests. bool operator==(const Pointer &P) const { - return Pointee == P.Pointee && Base == P.Base && Offset == P.Offset; - } + if (P.StorageKind != StorageKind) + return false; + if (isIntegralPointer()) + return P.asIntPointer().Value == asIntPointer().Value && + Offset == P.Offset; - bool operator!=(const Pointer &P) const { - return Pointee != P.Pointee || Base != P.Base || Offset != P.Offset; + assert(isBlockPointer()); + return P.asBlockPointer().Pointee == asBlockPointer().Pointee && + P.asBlockPointer().Base == asBlockPointer().Base && + Offset == P.Offset; } + bool operator!=(const Pointer &P) const { return !(P == *this); } + /// Converts the pointer to an APValue. APValue toAPValue() const; /// Converts the pointer to a string usable in diagnostics. std::string toDiagnosticString(const ASTContext &Ctx) const; - unsigned getIntegerRepresentation() const { - return reinterpret_cast(Pointee) + Offset; + uint64_t getIntegerRepresentation() const { + if (isIntegralPointer()) + return asIntPointer().Value + (Offset * elemSize()); + return reinterpret_cast(asBlockPointer().Pointee) + Offset; } /// Converts the pointer to an APValue that is an rvalue. @@ -102,20 +135,27 @@ public: /// Offsets a pointer inside an array. [[nodiscard]] Pointer atIndex(unsigned Idx) const { - if (Base == RootPtrMark) - return Pointer(Pointee, RootPtrMark, getDeclDesc()->getSize()); + if (isIntegralPointer()) + return Pointer(asIntPointer().Value, asIntPointer().Desc, Idx); + + if (asBlockPointer().Base == RootPtrMark) + return Pointer(asBlockPointer().Pointee, RootPtrMark, + getDeclDesc()->getSize()); unsigned Off = Idx * elemSize(); if (getFieldDesc()->ElemDesc) Off += sizeof(InlineDescriptor); else Off += sizeof(InitMapPtr); - return Pointer(Pointee, Base, Base + Off); + return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, + asBlockPointer().Base + Off); } /// Creates a pointer to a field. [[nodiscard]] Pointer atField(unsigned Off) const { unsigned Field = Offset + Off; - return Pointer(Pointee, Field, Field); + if (isIntegralPointer()) + return Pointer(asIntPointer().Value + Field, asIntPointer().Desc); + return Pointer(asBlockPointer().Pointee, Field, Field); } /// Subtract the given offset from the current Base and Offset @@ -123,44 +163,49 @@ public: [[nodiscard]] Pointer atFieldSub(unsigned Off) const { assert(Offset >= Off); unsigned O = Offset - Off; - return Pointer(Pointee, O, O); + return Pointer(asBlockPointer().Pointee, O, O); } /// Restricts the scope of an array element pointer. [[nodiscard]] Pointer narrow() const { + if (!isBlockPointer()) + return *this; + assert(isBlockPointer()); // Null pointers cannot be narrowed. if (isZero() || isUnknownSizeArray()) return *this; // Pointer to an array of base types - enter block. - if (Base == RootPtrMark) - return Pointer(Pointee, sizeof(InlineDescriptor), + if (asBlockPointer().Base == RootPtrMark) + return Pointer(asBlockPointer().Pointee, sizeof(InlineDescriptor), Offset == 0 ? Offset : PastEndMark); // Pointer is one past end - magic offset marks that. if (isOnePastEnd()) - return Pointer(Pointee, Base, PastEndMark); + return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, + PastEndMark); // Primitive arrays are a bit special since they do not have inline // descriptors. If Offset != Base, then the pointer already points to // an element and there is nothing to do. Otherwise, the pointer is // adjusted to the first element of the array. if (inPrimitiveArray()) { - if (Offset != Base) + if (Offset != asBlockPointer().Base) return *this; - return Pointer(Pointee, Base, Offset + sizeof(InitMapPtr)); + return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, + Offset + sizeof(InitMapPtr)); } // Pointer is to a field or array element - enter it. - if (Offset != Base) - return Pointer(Pointee, Offset, Offset); + if (Offset != asBlockPointer().Base) + return Pointer(asBlockPointer().Pointee, Offset, Offset); // Enter the first element of an array. if (!getFieldDesc()->isArray()) return *this; - const unsigned NewBase = Base + sizeof(InlineDescriptor); - return Pointer(Pointee, NewBase, NewBase); + const unsigned NewBase = asBlockPointer().Base + sizeof(InlineDescriptor); + return Pointer(asBlockPointer().Pointee, NewBase, NewBase); } /// Expands a pointer to the containing array, undoing narrowing. @@ -172,72 +217,109 @@ public: Adjust = sizeof(InitMapPtr); else Adjust = sizeof(InlineDescriptor); - return Pointer(Pointee, Base, Base + getSize() + Adjust); + return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, + asBlockPointer().Base + getSize() + Adjust); } // Do not step out of array elements. - if (Base != Offset) + if (asBlockPointer().Base != Offset) return *this; // If at base, point to an array of base types. - if (Base == 0 || Base == sizeof(InlineDescriptor)) - return Pointer(Pointee, RootPtrMark, 0); + if (asBlockPointer().Base == 0 || + asBlockPointer().Base == sizeof(InlineDescriptor)) + return Pointer(asBlockPointer().Pointee, RootPtrMark, 0); // Step into the containing array, if inside one. - unsigned Next = Base - getInlineDesc()->Offset; + unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset; const Descriptor *Desc = Next == 0 ? getDeclDesc() : getDescriptor(Next)->Desc; if (!Desc->IsArray) return *this; - return Pointer(Pointee, Next, Offset); + return Pointer(asBlockPointer().Pointee, Next, Offset); } /// Checks if the pointer is null. - bool isZero() const { return Pointee == nullptr; } + bool isZero() const { + if (Offset != 0) + return false; + + if (isBlockPointer()) + return asBlockPointer().Pointee == nullptr; + assert(isIntegralPointer()); + return asIntPointer().Value == 0; + } /// Checks if the pointer is live. - bool isLive() const { return Pointee && !Pointee->IsDead; } + bool isLive() const { + if (isIntegralPointer()) + return true; + return asBlockPointer().Pointee && !asBlockPointer().Pointee->IsDead; + } /// Checks if the item is a field in an object. bool isField() const { + if (isIntegralPointer()) + return false; + + unsigned Base = asBlockPointer().Base; return Base != 0 && Base != sizeof(InlineDescriptor) && Base != RootPtrMark && getFieldDesc()->asDecl(); } /// Accessor for information about the declaration site. const Descriptor *getDeclDesc() const { - assert(Pointee); - return Pointee->Desc; + if (isIntegralPointer()) + return asIntPointer().Desc; + + assert(isBlockPointer()); + assert(asBlockPointer().Pointee); + return asBlockPointer().Pointee->Desc; } SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); } + /// Returns the expression or declaration the pointer has been created for. + DeclTy getSource() const { + if (isBlockPointer()) + return getDeclDesc()->getSource(); + + assert(isIntegralPointer()); + return asIntPointer().Desc ? asIntPointer().Desc->getSource() : DeclTy(); + } + /// Returns a pointer to the object of which this pointer is a field. [[nodiscard]] Pointer getBase() const { - if (Base == RootPtrMark) { + if (asBlockPointer().Base == RootPtrMark) { assert(Offset == PastEndMark && "cannot get base of a block"); - return Pointer(Pointee, Base, 0); + return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0); } - unsigned NewBase = Base - getInlineDesc()->Offset; - return Pointer(Pointee, NewBase, NewBase); + unsigned NewBase = asBlockPointer().Base - getInlineDesc()->Offset; + return Pointer(asBlockPointer().Pointee, NewBase, NewBase); } /// Returns the parent array. [[nodiscard]] Pointer getArray() const { - if (Base == RootPtrMark) { + if (asBlockPointer().Base == RootPtrMark) { assert(Offset != 0 && Offset != PastEndMark && "not an array element"); - return Pointer(Pointee, Base, 0); + return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0); } - assert(Offset != Base && "not an array element"); - return Pointer(Pointee, Base, Base); + assert(Offset != asBlockPointer().Base && "not an array element"); + return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, + asBlockPointer().Base); } /// Accessors for information about the innermost field. const Descriptor *getFieldDesc() const { - if (Base == 0 || Base == sizeof(InlineDescriptor) || Base == RootPtrMark) + if (isIntegralPointer()) + return asIntPointer().Desc; + if (isBlockPointer() && + (asBlockPointer().Base == 0 || + asBlockPointer().Base == sizeof(InlineDescriptor) || + asBlockPointer().Base == RootPtrMark)) return getDeclDesc(); return getInlineDesc()->Desc; } /// Returns the type of the innermost field. QualType getType() const { - if (inPrimitiveArray() && Offset != Base) { + if (inPrimitiveArray() && Offset != asBlockPointer().Base) { // Unfortunately, complex types are not array types in clang, but they are // for us. if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe()) @@ -248,58 +330,104 @@ public: return getFieldDesc()->getType(); } - [[nodiscard]] Pointer getDeclPtr() const { return Pointer(Pointee); } + [[nodiscard]] Pointer getDeclPtr() const { + return Pointer(asBlockPointer().Pointee); + } /// Returns the element size of the innermost field. size_t elemSize() const { - if (Base == RootPtrMark) + if (isIntegralPointer()) { + if (!asIntPointer().Desc) + return 1; + return asIntPointer().Desc->getElemSize(); + } + + if (asBlockPointer().Base == RootPtrMark) return getDeclDesc()->getSize(); return getFieldDesc()->getElemSize(); } /// Returns the total size of the innermost field. - size_t getSize() const { return getFieldDesc()->getSize(); } + size_t getSize() const { + assert(isBlockPointer()); + return getFieldDesc()->getSize(); + } /// Returns the offset into an array. unsigned getOffset() const { assert(Offset != PastEndMark && "invalid offset"); - if (Base == RootPtrMark) + if (asBlockPointer().Base == RootPtrMark) return Offset; unsigned Adjust = 0; - if (Offset != Base) { + if (Offset != asBlockPointer().Base) { if (getFieldDesc()->ElemDesc) Adjust = sizeof(InlineDescriptor); else Adjust = sizeof(InitMapPtr); } - return Offset - Base - Adjust; + return Offset - asBlockPointer().Base - Adjust; } /// Whether this array refers to an array, but not /// to the first element. - bool isArrayRoot() const { return inArray() && Offset == Base; } + bool isArrayRoot() const { + return inArray() && Offset == asBlockPointer().Base; + } /// Checks if the innermost field is an array. - bool inArray() const { return getFieldDesc()->IsArray; } + bool inArray() const { + if (isBlockPointer()) + return getFieldDesc()->IsArray; + return false; + } /// Checks if the structure is a primitive array. - bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); } + bool inPrimitiveArray() const { + if (isBlockPointer()) + return getFieldDesc()->isPrimitiveArray(); + return false; + } /// Checks if the structure is an array of unknown size. bool isUnknownSizeArray() const { + if (!isBlockPointer()) + return false; // If this points inside a dummy block, return true. // FIXME: This might change in the future. If it does, we need // to set the proper Ctor/Dtor functions for dummy Descriptors. - if (Base != 0 && Base != sizeof(InlineDescriptor) && isDummy()) + if (asBlockPointer().Base != 0 && + asBlockPointer().Base != sizeof(InlineDescriptor) && isDummy()) return true; return getFieldDesc()->isUnknownSizeArray(); } /// Checks if the pointer points to an array. - bool isArrayElement() const { return inArray() && Base != Offset; } + bool isArrayElement() const { + if (isBlockPointer()) + return inArray() && asBlockPointer().Base != Offset; + return false; + } /// Pointer points directly to a block. bool isRoot() const { - return (Base == 0 || Base == RootPtrMark) && Offset == 0; + return (asBlockPointer().Base == 0 || + asBlockPointer().Base == RootPtrMark) && + Offset == 0; } /// If this pointer has an InlineDescriptor we can use to initialize. - bool canBeInitialized() const { return Pointee && Base > 0; } + bool canBeInitialized() const { + if (!isBlockPointer()) + return false; + + return asBlockPointer().Pointee && asBlockPointer().Base > 0; + } + + [[nodiscard]] const BlockPointer &asBlockPointer() const { + assert(isBlockPointer()); + return PointeeStorage.BS; + } + [[nodiscard]] const IntPointer &asIntPointer() const { + assert(isIntegralPointer()); + return PointeeStorage.Int; + } + bool isBlockPointer() const { return StorageKind == Storage::Block; } + bool isIntegralPointer() const { return StorageKind == Storage::Int; } /// Returns the record descriptor of a class. const Record *getRecord() const { return getFieldDesc()->ElemRecord; } @@ -315,71 +443,119 @@ public: bool isUnion() const; /// Checks if the storage is extern. - bool isExtern() const { return Pointee && Pointee->isExtern(); } + bool isExtern() const { + if (isBlockPointer()) + return asBlockPointer().Pointee && asBlockPointer().Pointee->isExtern(); + return false; + } /// Checks if the storage is static. bool isStatic() const { - assert(Pointee); - return Pointee->isStatic(); + if (isIntegralPointer()) + return true; + assert(asBlockPointer().Pointee); + return asBlockPointer().Pointee->isStatic(); } /// Checks if the storage is temporary. bool isTemporary() const { - assert(Pointee); - return Pointee->isTemporary(); + if (isBlockPointer()) { + assert(asBlockPointer().Pointee); + return asBlockPointer().Pointee->isTemporary(); + } + return false; } /// Checks if the storage is a static temporary. bool isStaticTemporary() const { return isStatic() && isTemporary(); } /// Checks if the field is mutable. bool isMutable() const { - return Base != 0 && Base != sizeof(InlineDescriptor) && + if (!isBlockPointer()) + return false; + return asBlockPointer().Base != 0 && + asBlockPointer().Base != sizeof(InlineDescriptor) && getInlineDesc()->IsFieldMutable; } + + bool isWeak() const { + if (isIntegralPointer()) + return false; + + assert(isBlockPointer()); + if (const ValueDecl *VD = getDeclDesc()->asValueDecl()) + return VD->isWeak(); + return false; + } /// Checks if an object was initialized. bool isInitialized() const; /// Checks if the object is active. bool isActive() const { - return Base == 0 || Base == sizeof(InlineDescriptor) || + if (!isBlockPointer()) + return true; + return asBlockPointer().Base == 0 || + asBlockPointer().Base == sizeof(InlineDescriptor) || getInlineDesc()->IsActive; } /// Checks if a structure is a base class. bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; } /// Checks if the pointer points to a dummy value. bool isDummy() const { - if (!Pointee) + if (!isBlockPointer()) return false; + + if (!asBlockPointer().Pointee) + return false; + return getDeclDesc()->isDummy(); } /// Checks if an object or a subfield is mutable. bool isConst() const { - return (Base == 0 || Base == sizeof(InlineDescriptor)) + if (isIntegralPointer()) + return true; + return (asBlockPointer().Base == 0 || + asBlockPointer().Base == sizeof(InlineDescriptor)) ? getDeclDesc()->IsConst : getInlineDesc()->IsConst; } /// Returns the declaration ID. std::optional getDeclID() const { - assert(Pointee); - return Pointee->getDeclID(); + if (isBlockPointer()) { + assert(asBlockPointer().Pointee); + return asBlockPointer().Pointee->getDeclID(); + } + return std::nullopt; } /// Returns the byte offset from the start. unsigned getByteOffset() const { + if (isIntegralPointer()) + return asIntPointer().Value + Offset; return Offset; } /// Returns the number of elements. - unsigned getNumElems() const { return getSize() / elemSize(); } + unsigned getNumElems() const { + if (isIntegralPointer()) + return ~unsigned(0); + return getSize() / elemSize(); + } - const Block *block() const { return Pointee; } + const Block *block() const { return asBlockPointer().Pointee; } /// Returns the index into an array. int64_t getIndex() const { + if (!isBlockPointer()) + return 0; + + if (isZero()) + return 0; + if (isElementPastEnd()) return 1; // narrow()ed element in a composite array. - if (Base > sizeof(InlineDescriptor) && Base == Offset) + if (asBlockPointer().Base > sizeof(InlineDescriptor) && + asBlockPointer().Base == Offset) return 0; if (auto ElemSize = elemSize()) @@ -389,7 +565,10 @@ public: /// Checks if the index is one past end. bool isOnePastEnd() const { - if (!Pointee) + if (isIntegralPointer()) + return false; + + if (!asBlockPointer().Pointee) return false; return isElementPastEnd() || getSize() == getOffset(); } @@ -400,20 +579,25 @@ public: /// Dereferences the pointer, if it's live. template T &deref() const { assert(isLive() && "Invalid pointer"); - assert(Pointee); + assert(isBlockPointer()); + assert(asBlockPointer().Pointee); + assert(Offset + sizeof(T) <= + asBlockPointer().Pointee->getDescriptor()->getAllocSize()); + if (isArrayRoot()) - return *reinterpret_cast(Pointee->rawData() + Base + - sizeof(InitMapPtr)); + return *reinterpret_cast(asBlockPointer().Pointee->rawData() + + asBlockPointer().Base + sizeof(InitMapPtr)); - assert(Offset + sizeof(T) <= Pointee->getDescriptor()->getAllocSize()); - return *reinterpret_cast(Pointee->rawData() + Offset); + return *reinterpret_cast(asBlockPointer().Pointee->rawData() + Offset); } /// Dereferences a primitive element. template T &elem(unsigned I) const { assert(I < getNumElems()); - assert(Pointee); - return reinterpret_cast(Pointee->data() + sizeof(InitMapPtr))[I]; + assert(isBlockPointer()); + assert(asBlockPointer().Pointee); + return reinterpret_cast(asBlockPointer().Pointee->data() + + sizeof(InitMapPtr))[I]; } /// Initializes a field. @@ -442,24 +626,7 @@ public: static bool hasSameArray(const Pointer &A, const Pointer &B); /// Prints the pointer. - void print(llvm::raw_ostream &OS) const { - OS << Pointee << " {"; - if (Base == RootPtrMark) - OS << "rootptr, "; - else - OS << Base << ", "; - - if (Offset == PastEndMark) - OS << "pastend, "; - else - OS << Offset << ", "; - - if (Pointee) - OS << Pointee->getSize(); - else - OS << "nullptr"; - OS << "}"; - } + void print(llvm::raw_ostream &OS) const; private: friend class Block; @@ -469,33 +636,41 @@ private: Pointer(Block *Pointee, unsigned Base, unsigned Offset); /// Returns the embedded descriptor preceding a field. - InlineDescriptor *getInlineDesc() const { return getDescriptor(Base); } + InlineDescriptor *getInlineDesc() const { + return getDescriptor(asBlockPointer().Base); + } /// Returns a descriptor at a given offset. InlineDescriptor *getDescriptor(unsigned Offset) const { assert(Offset != 0 && "Not a nested pointer"); - assert(Pointee); - return reinterpret_cast(Pointee->rawData() + Offset) - + assert(isBlockPointer()); + assert(!isZero()); + return reinterpret_cast( + asBlockPointer().Pointee->rawData() + Offset) - 1; } /// Returns a reference to the InitMapPtr which stores the initialization map. InitMapPtr &getInitMap() const { - assert(Pointee); - return *reinterpret_cast(Pointee->rawData() + Base); + assert(isBlockPointer()); + assert(!isZero()); + return *reinterpret_cast(asBlockPointer().Pointee->rawData() + + asBlockPointer().Base); } - /// The block the pointer is pointing to. - Block *Pointee = nullptr; - /// Start of the current subfield. - unsigned Base = 0; - /// Offset into the block. + /// Offset into the storage. unsigned Offset = 0; /// Previous link in the pointer chain. Pointer *Prev = nullptr; /// Next link in the pointer chain. Pointer *Next = nullptr; + + union { + BlockPointer BS; + IntPointer Int; + } PointeeStorage; + Storage StorageKind = Storage::Int; }; inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) { diff --git a/clang/lib/AST/Interp/PrimType.h b/clang/lib/AST/Interp/PrimType.h index 2bc83b334643e352d2e9e2594b0f571d58b3b424..05a094d0c5b1ff122160b900448d89373d0668f9 100644 --- a/clang/lib/AST/Interp/PrimType.h +++ b/clang/lib/AST/Interp/PrimType.h @@ -46,6 +46,10 @@ enum PrimType : unsigned { PT_FnPtr, }; +inline constexpr bool isPtrType(PrimType T) { + return T == PT_Ptr || T == PT_FnPtr; +} + enum class CastKind : uint8_t { Reinterpret, Atomic, diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp index da6f72c62115dd94a3c216ce9cbbc2351aaadf3e..e6f22e79451e970e06d5ab47744be4489d3b7715 100644 --- a/clang/lib/AST/Interp/Program.cpp +++ b/clang/lib/AST/Interp/Program.cpp @@ -177,7 +177,7 @@ std::optional Program::createGlobal(const ValueDecl *VD, bool IsStatic, IsExtern; if (const auto *Var = dyn_cast(VD)) { IsStatic = Context::shouldBeGloballyIndexed(VD); - IsExtern = !Var->getAnyInitializer(); + IsExtern = Var->hasExternalStorage(); } else if (isa(VD)) { IsStatic = true; IsExtern = false; @@ -355,7 +355,7 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, QualType ElemTy = ArrayType->getElementType(); // Array of well-known bounds. if (auto CAT = dyn_cast(ArrayType)) { - size_t NumElems = CAT->getSize().getZExtValue(); + size_t NumElems = CAT->getZExtSize(); if (std::optional T = Ctx.classify(ElemTy)) { // Arrays of primitives. unsigned ElemSize = primSize(*T); @@ -411,5 +411,12 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty, IsMutable); } + // Same with vector types. + if (const auto *VT = Ty->getAs()) { + PrimType ElemTy = *Ctx.classify(VT->getElementType()); + return allocateDescriptor(D, ElemTy, MDSize, VT->getNumElements(), IsConst, + IsTemporary, IsMutable); + } + return nullptr; } diff --git a/clang/lib/AST/Interp/Record.cpp b/clang/lib/AST/Interp/Record.cpp index 909416e6e1a1a53936061d4ff5ce2d6add7b8578..6a0a28bc9124bcc15e7a7dc00a3cb7ac132a2aa1 100644 --- a/clang/lib/AST/Interp/Record.cpp +++ b/clang/lib/AST/Interp/Record.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "Record.h" +#include "clang/AST/ASTContext.h" using namespace clang; using namespace clang::interp; @@ -27,6 +28,14 @@ Record::Record(const RecordDecl *Decl, BaseList &&SrcBases, VirtualBaseMap[V.Decl] = &V; } +const std::string Record::getName() const { + std::string Ret; + llvm::raw_string_ostream OS(Ret); + Decl->getNameForDiagnostic(OS, Decl->getASTContext().getPrintingPolicy(), + /*Qualified=*/true); + return Ret; +} + const Record::Field *Record::getField(const FieldDecl *FD) const { auto It = FieldMap.find(FD); assert(It != FieldMap.end() && "Missing field"); diff --git a/clang/lib/AST/Interp/Record.h b/clang/lib/AST/Interp/Record.h index a6bde01062531b8982771dcca6692b7c538e73ce..cf0480b3f62fa668ceff6a442c728b5ff653c3ed 100644 --- a/clang/lib/AST/Interp/Record.h +++ b/clang/lib/AST/Interp/Record.h @@ -51,7 +51,7 @@ public: /// Returns the underlying declaration. const RecordDecl *getDecl() const { return Decl; } /// Returns the name of the underlying declaration. - const std::string getName() const { return Decl->getNameAsString(); } + const std::string getName() const; /// Checks if the record is a union. bool isUnion() const { return getDecl()->isUnion(); } /// Returns the size of the record. @@ -100,6 +100,10 @@ public: unsigned getNumVirtualBases() const { return VirtualBases.size(); } const Base *getVirtualBase(unsigned I) const { return &VirtualBases[I]; } + void dump(llvm::raw_ostream &OS, unsigned Indentation = 0, + unsigned Offset = 0) const; + void dump() const { dump(llvm::errs()); } + private: /// Constructor used by Program to create record descriptors. Record(const RecordDecl *, BaseList &&Bases, FieldList &&Fields, diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index f619d657ae9f50c4491532d497eaf7d54522acdd..d632c697fa20dbc4e88e15a6715f923020680b19 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -2398,6 +2398,7 @@ bool CXXNameMangler::mangleUnresolvedTypeOrSimpleId(QualType Ty, case Type::Complex: case Type::Adjusted: case Type::Decayed: + case Type::ArrayParameter: case Type::Pointer: case Type::BlockPointer: case Type::LValueReference: @@ -3445,6 +3446,7 @@ StringRef CXXNameMangler::getCallingConvQualifierName(CallingConv CC) { case CC_PreserveAll: case CC_M68kRTD: case CC_PreserveNone: + case CC_RISCVVectorCall: // FIXME: we should be mangling all of the above. return ""; @@ -4445,6 +4447,10 @@ void CXXNameMangler::mangleType(const DependentBitIntType *T) { Out << "_"; } +void CXXNameMangler::mangleType(const ArrayParameterType *T) { + mangleType(cast(T)); +} + void CXXNameMangler::mangleIntegerLiteral(QualType T, const llvm::APSInt &Value) { // ::= L E # integer literal diff --git a/clang/lib/AST/JSONNodeDumper.cpp b/clang/lib/AST/JSONNodeDumper.cpp index e27d44fc2ffe67316d2f4175c4c04856e8ae222e..fb3494393f7559af8765b5c29a0634f6bdb6dfb5 100644 --- a/clang/lib/AST/JSONNodeDumper.cpp +++ b/clang/lib/AST/JSONNodeDumper.cpp @@ -187,6 +187,8 @@ void JSONNodeDumper::Visit(const CXXCtorInitializer *Init) { llvm_unreachable("Unknown initializer type"); } +void JSONNodeDumper::Visit(const OpenACCClause *C) {} + void JSONNodeDumper::Visit(const OMPClause *C) {} void JSONNodeDumper::Visit(const BlockDecl::Capture &C) { @@ -695,7 +697,7 @@ void JSONNodeDumper::VisitArrayType(const ArrayType *AT) { void JSONNodeDumper::VisitConstantArrayType(const ConstantArrayType *CAT) { // FIXME: this should use ZExt instead of SExt, but JSON doesn't allow a // narrowing conversion to int64_t so it cannot be expressed. - JOS.attribute("size", CAT->getSize().getSExtValue()); + JOS.attribute("size", CAT->getSExtSize()); VisitArrayType(CAT); } diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index aa26bb7ed46f482cfa4b7e02dee65c0f69a303b0..a0bb04e69c9be8ad244618fb51277344309811a6 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -3079,6 +3079,11 @@ void MicrosoftCXXNameMangler::mangleArrayType(const ArrayType *T) { mangleType(ElementTy, SourceRange(), QMM_Escape); } +void MicrosoftCXXNameMangler::mangleType(const ArrayParameterType *T, + Qualifiers, SourceRange) { + mangleArrayType(cast(T)); +} + // ::= // ::= // @@ -3911,7 +3916,8 @@ void MicrosoftMangleContextImpl::mangleReferenceTemporary( msvc_hashing_ostream MHO(Out); MicrosoftCXXNameMangler Mangler(*this, MHO); - Mangler.getStream() << "?$RT" << ManglingNumber << '@'; + Mangler.getStream() << "?"; + Mangler.mangleSourceName("$RT" + llvm::utostr(ManglingNumber)); Mangler.mangle(VD, ""); } @@ -4022,10 +4028,8 @@ void MicrosoftMangleContextImpl::mangleStringLiteral(const StringLiteral *SL, // char bar[42] = "foobar"; // Where it is truncated or zero-padded to fit the array. This is the length // used for mangling, and any trailing null-bytes also need to be mangled. - unsigned StringLength = getASTContext() - .getAsConstantArrayType(SL->getType()) - ->getSize() - .getZExtValue(); + unsigned StringLength = + getASTContext().getAsConstantArrayType(SL->getType())->getZExtSize(); unsigned StringByteLength = StringLength * SL->getCharByteWidth(); // : The "kind" of string literal is encoded into the mangled name. diff --git a/clang/lib/AST/NSAPI.cpp b/clang/lib/AST/NSAPI.cpp index 86dee540e9e299546a3b1a90840f6eebf6a27dba..ecc56c13fb757338751e5b7e60ae64d078924cb9 100644 --- a/clang/lib/AST/NSAPI.cpp +++ b/clang/lib/AST/NSAPI.cpp @@ -56,10 +56,8 @@ Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const { &Ctx.Idents.get("initWithUTF8String")); break; case NSStr_stringWithCStringEncoding: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("stringWithCString"), - &Ctx.Idents.get("encoding") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("stringWithCString"), + &Ctx.Idents.get("encoding")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } @@ -93,10 +91,8 @@ Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const { Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObjects")); break; case NSArr_arrayWithObjectsCount: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("arrayWithObjects"), - &Ctx.Idents.get("count") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("arrayWithObjects"), + &Ctx.Idents.get("count")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } @@ -110,10 +106,9 @@ Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const { Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectAtIndex")); break; case NSMutableArr_replaceObjectAtIndex: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("replaceObjectAtIndex"), - &Ctx.Idents.get("withObject") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("replaceObjectAtIndex"), + &Ctx.Idents.get("withObject")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } @@ -121,18 +116,14 @@ Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const { Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject")); break; case NSMutableArr_insertObjectAtIndex: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("insertObject"), - &Ctx.Idents.get("atIndex") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("insertObject"), + &Ctx.Idents.get("atIndex")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSMutableArr_setObjectAtIndexedSubscript: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("setObject"), - &Ctx.Idents.get("atIndexedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("setObject"), &Ctx.Idents.get("atIndexedSubscript")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } @@ -167,27 +158,21 @@ Selector NSAPI::getNSDictionarySelector( &Ctx.Idents.get("dictionaryWithDictionary")); break; case NSDict_dictionaryWithObjectForKey: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("dictionaryWithObject"), - &Ctx.Idents.get("forKey") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("dictionaryWithObject"), &Ctx.Idents.get("forKey")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSDict_dictionaryWithObjectsForKeys: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("dictionaryWithObjects"), - &Ctx.Idents.get("forKeys") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("dictionaryWithObjects"), &Ctx.Idents.get("forKeys")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSDict_dictionaryWithObjectsForKeysCount: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("dictionaryWithObjects"), - &Ctx.Idents.get("forKeys"), - &Ctx.Idents.get("count") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("dictionaryWithObjects"), &Ctx.Idents.get("forKeys"), + &Ctx.Idents.get("count")}; Sel = Ctx.Selectors.getSelector(3, KeyIdents); break; } @@ -204,10 +189,8 @@ Selector NSAPI::getNSDictionarySelector( &Ctx.Idents.get("initWithObjectsAndKeys")); break; case NSDict_initWithObjectsForKeys: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("initWithObjects"), - &Ctx.Idents.get("forKeys") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("initWithObjects"), + &Ctx.Idents.get("forKeys")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } @@ -215,26 +198,20 @@ Selector NSAPI::getNSDictionarySelector( Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey")); break; case NSMutableDict_setObjectForKey: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("setObject"), - &Ctx.Idents.get("forKey") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setObject"), + &Ctx.Idents.get("forKey")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSMutableDict_setObjectForKeyedSubscript: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("setObject"), - &Ctx.Idents.get("forKeyedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("setObject"), &Ctx.Idents.get("forKeyedSubscript")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSMutableDict_setValueForKey: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("setValue"), - &Ctx.Idents.get("forKey") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setValue"), + &Ctx.Idents.get("forKey")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } @@ -264,34 +241,27 @@ Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const { Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject")); break; case NSOrderedSet_insertObjectAtIndex: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("insertObject"), - &Ctx.Idents.get("atIndex") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("insertObject"), + &Ctx.Idents.get("atIndex")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSOrderedSet_setObjectAtIndex: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("setObject"), - &Ctx.Idents.get("atIndex") - }; + const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setObject"), + &Ctx.Idents.get("atIndex")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSOrderedSet_setObjectAtIndexedSubscript: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("setObject"), - &Ctx.Idents.get("atIndexedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("setObject"), &Ctx.Idents.get("atIndexedSubscript")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } case NSOrderedSet_replaceObjectAtIndexWithObject: { - IdentifierInfo *KeyIdents[] = { - &Ctx.Idents.get("replaceObjectAtIndex"), - &Ctx.Idents.get("withObject") - }; + const IdentifierInfo *KeyIdents[] = { + &Ctx.Idents.get("replaceObjectAtIndex"), + &Ctx.Idents.get("withObject")}; Sel = Ctx.Selectors.getSelector(2, KeyIdents); break; } @@ -606,7 +576,7 @@ bool NSAPI::isObjCEnumerator(const Expr *E, Selector NSAPI::getOrInitSelector(ArrayRef Ids, Selector &Sel) const { if (Sel.isNull()) { - SmallVector Idents; + SmallVector Idents; for (ArrayRef::const_iterator I = Ids.begin(), E = Ids.end(); I != E; ++I) Idents.push_back(&Ctx.Idents.get(*I)); @@ -617,7 +587,7 @@ Selector NSAPI::getOrInitSelector(ArrayRef Ids, Selector NSAPI::getOrInitNullarySelector(StringRef Id, Selector &Sel) const { if (Sel.isNull()) { - IdentifierInfo *Ident = &Ctx.Idents.get(Id); + const IdentifierInfo *Ident = &Ctx.Idents.get(Id); Sel = Ctx.Selectors.getSelector(0, &Ident); } return Sel; diff --git a/clang/lib/AST/NestedNameSpecifier.cpp b/clang/lib/AST/NestedNameSpecifier.cpp index 36f2c47b30005d9123fc276dadfe3d2fe96d6dd6..785c46e86a77c57de82240343a39205d64079593 100644 --- a/clang/lib/AST/NestedNameSpecifier.cpp +++ b/clang/lib/AST/NestedNameSpecifier.cpp @@ -55,16 +55,16 @@ NestedNameSpecifier::FindOrInsert(const ASTContext &Context, return NNS; } -NestedNameSpecifier * -NestedNameSpecifier::Create(const ASTContext &Context, - NestedNameSpecifier *Prefix, IdentifierInfo *II) { +NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, + NestedNameSpecifier *Prefix, + const IdentifierInfo *II) { assert(II && "Identifier cannot be NULL"); assert((!Prefix || Prefix->isDependent()) && "Prefix must be dependent"); NestedNameSpecifier Mockup; Mockup.Prefix.setPointer(Prefix); Mockup.Prefix.setInt(StoredIdentifier); - Mockup.Specifier = II; + Mockup.Specifier = const_cast(II); return FindOrInsert(Context, Mockup); } @@ -87,7 +87,7 @@ NestedNameSpecifier::Create(const ASTContext &Context, NestedNameSpecifier * NestedNameSpecifier::Create(const ASTContext &Context, NestedNameSpecifier *Prefix, - NamespaceAliasDecl *Alias) { + const NamespaceAliasDecl *Alias) { assert(Alias && "Namespace alias cannot be NULL"); assert((!Prefix || (Prefix->getAsType() == nullptr && @@ -96,7 +96,7 @@ NestedNameSpecifier::Create(const ASTContext &Context, NestedNameSpecifier Mockup; Mockup.Prefix.setPointer(Prefix); Mockup.Prefix.setInt(StoredDecl); - Mockup.Specifier = Alias; + Mockup.Specifier = const_cast(Alias); return FindOrInsert(Context, Mockup); } @@ -112,13 +112,13 @@ NestedNameSpecifier::Create(const ASTContext &Context, return FindOrInsert(Context, Mockup); } -NestedNameSpecifier * -NestedNameSpecifier::Create(const ASTContext &Context, IdentifierInfo *II) { +NestedNameSpecifier *NestedNameSpecifier::Create(const ASTContext &Context, + const IdentifierInfo *II) { assert(II && "Identifier cannot be NULL"); NestedNameSpecifier Mockup; Mockup.Prefix.setPointer(nullptr); Mockup.Prefix.setInt(StoredIdentifier); - Mockup.Specifier = II; + Mockup.Specifier = const_cast(II); return FindOrInsert(Context, Mockup); } diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 2dbc259138a897d46db6e76df532df62a4dda2e0..e159a1b00be552bab566c07313ff64264f9951ff 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -944,6 +944,10 @@ public: VisitArrayType(T); } + void VisitArrayParameterType(const ArrayParameterType *T) { + VisitConstantArrayType(T); + } + void VisitDependentSizedArrayType(const DependentSizedArrayType *T) { AddStmt(T->getSizeExpr()); VisitArrayType(T); diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c83128b60e3acc44de9386f00e591ea1d799f224 --- /dev/null +++ b/clang/lib/AST/OpenACCClause.cpp @@ -0,0 +1,36 @@ +//===---- OpenACCClause.cpp - Classes for OpenACC Clauses ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the subclasses of the OpenACCClause class declared in +// OpenACCClause.h +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/OpenACCClause.h" +#include "clang/AST/ASTContext.h" + +using namespace clang; + +OpenACCDefaultClause *OpenACCDefaultClause::Create(const ASTContext &C, + OpenACCDefaultClauseKind K, + SourceLocation BeginLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + void *Mem = + C.Allocate(sizeof(OpenACCDefaultClause), alignof(OpenACCDefaultClause)); + + return new (Mem) OpenACCDefaultClause(K, BeginLoc, LParenLoc, EndLoc); +} + +//===----------------------------------------------------------------------===// +// OpenACC clauses printing methods +//===----------------------------------------------------------------------===// +void OpenACCClausePrinter::VisitOpenACCDefaultClause( + const OpenACCDefaultClause &C) { + OS << "default(" << C.getDefaultClauseKind() << ")"; +} diff --git a/clang/lib/AST/ParentMapContext.cpp b/clang/lib/AST/ParentMapContext.cpp index 21cfd5b1de6e9dd38f7884d6cf2b24b14094633b..9723c0cfa83bbeaf5938616f5ec560bda0430661 100644 --- a/clang/lib/AST/ParentMapContext.cpp +++ b/clang/lib/AST/ParentMapContext.cpp @@ -61,7 +61,26 @@ class ParentMapContext::ParentMap { template friend struct ::MatchParents; /// Contains parents of a node. - using ParentVector = llvm::SmallVector; + class ParentVector { + public: + ParentVector() = default; + explicit ParentVector(size_t N, const DynTypedNode &Value) { + Items.reserve(N); + for (; N > 0; --N) + push_back(Value); + } + bool contains(const DynTypedNode &Value) { + return Seen.contains(Value); + } + void push_back(const DynTypedNode &Value) { + if (!Value.getMemoizationData() || Seen.insert(Value).second) + Items.push_back(Value); + } + llvm::ArrayRef view() const { return Items; } + private: + llvm::SmallVector Items; + llvm::SmallDenseSet Seen; + }; /// Maps from a node to its parents. This is used for nodes that have /// pointer identity only, which are more common and we can save space by @@ -99,7 +118,7 @@ class ParentMapContext::ParentMap { return llvm::ArrayRef(); } if (const auto *V = I->second.template dyn_cast()) { - return llvm::ArrayRef(*V); + return V->view(); } return getSingleDynTypedNodeFromParentMap(I->second); } @@ -252,7 +271,7 @@ public: const auto *S = It->second.dyn_cast(); if (!S) { if (auto *Vec = It->second.dyn_cast()) - return llvm::ArrayRef(*Vec); + return Vec->view(); return getSingleDynTypedNodeFromParentMap(It->second); } const auto *P = dyn_cast(S); diff --git a/clang/lib/AST/ScanfFormatString.cpp b/clang/lib/AST/ScanfFormatString.cpp index 64c430e623b577e1101f5807bea2d57b95b8ec56..7ee21c8c619544009c454cae8940832b2a40a967 100644 --- a/clang/lib/AST/ScanfFormatString.cpp +++ b/clang/lib/AST/ScanfFormatString.cpp @@ -448,9 +448,7 @@ bool ScanfSpecifier::fixType(QualType QT, QualType RawQT, if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(RawQT)) { if (CAT->getSizeModifier() == ArraySizeModifier::Normal) FieldWidth = OptionalAmount(OptionalAmount::Constant, - CAT->getSize().getZExtValue() - 1, - "", 0, false); - + CAT->getZExtSize() - 1, "", 0, false); } return true; } diff --git a/clang/lib/AST/SelectorLocationsKind.cpp b/clang/lib/AST/SelectorLocationsKind.cpp index 2c34c9c60c2b20b79e8fd96607bf4b73a4c2b781..ebe6324f904c7819eb9d319bccd668ee0fc14c90 100644 --- a/clang/lib/AST/SelectorLocationsKind.cpp +++ b/clang/lib/AST/SelectorLocationsKind.cpp @@ -26,7 +26,7 @@ static SourceLocation getStandardSelLoc(unsigned Index, assert(Index == 0); if (EndLoc.isInvalid()) return SourceLocation(); - IdentifierInfo *II = Sel.getIdentifierInfoForSlot(0); + const IdentifierInfo *II = Sel.getIdentifierInfoForSlot(0); unsigned Len = II ? II->getLength() : 0; return EndLoc.getLocWithOffset(-Len); } @@ -34,7 +34,7 @@ static SourceLocation getStandardSelLoc(unsigned Index, assert(Index < NumSelArgs); if (ArgLoc.isInvalid()) return SourceLocation(); - IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Index); + const IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Index); unsigned Len = /* selector id */ (II ? II->getLength() : 0) + /* ':' */ 1; if (WithArgSpace) ++Len; diff --git a/clang/lib/AST/StmtOpenACC.cpp b/clang/lib/AST/StmtOpenACC.cpp index e6191bc6db7080a5c71a710838d7f1bd1bcd2bef..a381a8dd7b62c30a1fb0fdf7ddd5e3b24f0eb9b0 100644 --- a/clang/lib/AST/StmtOpenACC.cpp +++ b/clang/lib/AST/StmtOpenACC.cpp @@ -15,20 +15,23 @@ using namespace clang; OpenACCComputeConstruct * -OpenACCComputeConstruct::CreateEmpty(const ASTContext &C, EmptyShell) { - void *Mem = C.Allocate(sizeof(OpenACCComputeConstruct), - alignof(OpenACCComputeConstruct)); - auto *Inst = new (Mem) OpenACCComputeConstruct; +OpenACCComputeConstruct::CreateEmpty(const ASTContext &C, unsigned NumClauses) { + void *Mem = C.Allocate( + OpenACCComputeConstruct::totalSizeToAlloc( + NumClauses)); + auto *Inst = new (Mem) OpenACCComputeConstruct(NumClauses); return Inst; } OpenACCComputeConstruct * OpenACCComputeConstruct::Create(const ASTContext &C, OpenACCDirectiveKind K, SourceLocation BeginLoc, SourceLocation EndLoc, + ArrayRef Clauses, Stmt *StructuredBlock) { - void *Mem = C.Allocate(sizeof(OpenACCComputeConstruct), - alignof(OpenACCComputeConstruct)); - auto *Inst = - new (Mem) OpenACCComputeConstruct(K, BeginLoc, EndLoc, StructuredBlock); + void *Mem = C.Allocate( + OpenACCComputeConstruct::totalSizeToAlloc( + Clauses.size())); + auto *Inst = new (Mem) + OpenACCComputeConstruct(K, BeginLoc, EndLoc, Clauses, StructuredBlock); return Inst; } diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp index 426b35848cb5c894540beb11db9f93bced621243..d8519b2071e6da9d65c9c7409b45212b3239de74 100644 --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -2431,7 +2431,7 @@ OMPTeamsGenericLoopDirective::CreateEmpty(const ASTContext &C, OMPTargetTeamsGenericLoopDirective *OMPTargetTeamsGenericLoopDirective::Create( const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, ArrayRef Clauses, Stmt *AssociatedStmt, - const HelperExprs &Exprs) { + const HelperExprs &Exprs, bool CanBeParallelFor) { auto *Dir = createDirective( C, Clauses, AssociatedStmt, numLoopChildren(CollapsedNum, OMPD_target_teams_loop), StartLoc, EndLoc, @@ -2473,6 +2473,7 @@ OMPTargetTeamsGenericLoopDirective *OMPTargetTeamsGenericLoopDirective::Create( Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB); Dir->setCombinedDistCond(Exprs.DistCombinedFields.DistCond); Dir->setCombinedParForInDistCond(Exprs.DistCombinedFields.ParForInDistCond); + Dir->setCanBeParallelFor(CanBeParallelFor); return Dir; } diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index d66c3ccce2094c47affed4e534640fe571dfdc0e..5855ab3141edcc7d89a27ca956a4e670e1f8c604 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -292,8 +292,11 @@ void StmtPrinter::VisitLabelStmt(LabelStmt *Node) { } void StmtPrinter::VisitAttributedStmt(AttributedStmt *Node) { - for (const auto *Attr : Node->getAttrs()) { + llvm::ArrayRef Attrs = Node->getAttrs(); + for (const auto *Attr : Attrs) { Attr->printPretty(OS, Policy); + if (Attr != Attrs.back()) + OS << ' '; } PrintStmt(Node->getSubStmt(), 0); @@ -1142,7 +1145,13 @@ void StmtPrinter::VisitOMPTargetParallelGenericLoopDirective( //===----------------------------------------------------------------------===// void StmtPrinter::VisitOpenACCComputeConstruct(OpenACCComputeConstruct *S) { Indent() << "#pragma acc " << S->getDirectiveKind(); - // TODO OpenACC: Print Clauses. + + if (!S->clauses().empty()) { + OS << ' '; + OpenACCClausePrinter Printer(OS); + Printer.VisitClauseList(S->clauses()); + } + PrintStmt(S->getStructuredBlock()); } @@ -1438,7 +1447,7 @@ void StmtPrinter::VisitOffsetOfExpr(OffsetOfExpr *Node) { continue; // Field or identifier node. - IdentifierInfo *Id = ON.getFieldName(); + const IdentifierInfo *Id = ON.getFieldName(); if (!Id) continue; @@ -2339,7 +2348,7 @@ void StmtPrinter::VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E) { E->getQualifier()->print(OS, Policy); OS << "~"; - if (IdentifierInfo *II = E->getDestroyedTypeIdentifier()) + if (const IdentifierInfo *II = E->getDestroyedTypeIdentifier()) OS << II->getName(); else E->getDestroyedType().print(OS, Policy); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index b545ff472e5a2b81ebc30e7fdc63c549b3975e62..01e1d1cc8289bfdbca3b4e15e3c09a16cd926f2d 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -61,7 +61,7 @@ namespace { virtual void VisitName(DeclarationName Name, bool TreatAsDecl = false) = 0; /// Visit identifiers that are not in Decl's or Type's. - virtual void VisitIdentifierInfo(IdentifierInfo *II) = 0; + virtual void VisitIdentifierInfo(const IdentifierInfo *II) = 0; /// Visit a nested-name-specifier that occurs within an expression /// or statement. @@ -163,7 +163,7 @@ namespace { ID.AddPointer(Name.getAsOpaquePtr()); } - void VisitIdentifierInfo(IdentifierInfo *II) override { + void VisitIdentifierInfo(const IdentifierInfo *II) override { ID.AddPointer(II); } @@ -211,7 +211,7 @@ namespace { } Hash.AddDeclarationName(Name, TreatAsDecl); } - void VisitIdentifierInfo(IdentifierInfo *II) override { + void VisitIdentifierInfo(const IdentifierInfo *II) override { ID.AddBoolean(II); if (II) { Hash.AddIdentifierInfo(II); @@ -2011,6 +2011,7 @@ void StmtProfiler::VisitMSPropertySubscriptExpr( void StmtProfiler::VisitCXXThisExpr(const CXXThisExpr *S) { VisitExpr(S); ID.AddBoolean(S->isImplicit()); + ID.AddBoolean(S->isCapturedByCopyInLambdaWithExplicitObjectParameter()); } void StmtProfiler::VisitCXXThrowExpr(const CXXThrowExpr *S) { @@ -2441,11 +2442,35 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) { } } +namespace { +class OpenACCClauseProfiler + : public OpenACCClauseVisitor { + +public: + OpenACCClauseProfiler() = default; + + void VisitOpenACCClauseList(ArrayRef Clauses) { + for (const OpenACCClause *Clause : Clauses) { + // TODO OpenACC: When we have clauses with expressions, we should + // profile them too. + Visit(Clause); + } + } + void VisitOpenACCDefaultClause(const OpenACCDefaultClause &Clause); +}; + +/// Nothing to do here, there are no sub-statements. +void OpenACCClauseProfiler::VisitOpenACCDefaultClause( + const OpenACCDefaultClause &Clause) {} +} // namespace + void StmtProfiler::VisitOpenACCComputeConstruct( const OpenACCComputeConstruct *S) { // VisitStmt handles children, so the AssociatedStmt is handled. VisitStmt(S); - // TODO OpenACC: Visit Clauses. + + OpenACCClauseProfiler P; + P.VisitOpenACCClauseList(S->clauses()); } void Stmt::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp index b683eb1edd8f136eb9c878ce995a635f1685a721..085a7f51ce99ade39402cd4869b6487558bebe1c 100644 --- a/clang/lib/AST/TextNodeDumper.cpp +++ b/clang/lib/AST/TextNodeDumper.cpp @@ -381,6 +381,31 @@ void TextNodeDumper::Visit(const OMPClause *C) { OS << " "; } +void TextNodeDumper::Visit(const OpenACCClause *C) { + if (!C) { + ColorScope Color(OS, ShowColors, NullColor); + OS << "<<>> OpenACCClause"; + return; + } + { + ColorScope Color(OS, ShowColors, AttrColor); + OS << C->getClauseKind(); + + // Handle clauses with parens for types that have no children, likely + // because there is no sub expression. + switch (C->getClauseKind()) { + case OpenACCClauseKind::Default: + OS << '(' << cast(C)->getDefaultClauseKind() << ')'; + break; + default: + // Nothing to do here. + break; + } + } + dumpPointer(C); + dumpSourceRange(SourceRange(C->getBeginLoc(), C->getEndLoc())); +} + void TextNodeDumper::Visit(const GenericSelectionExpr::ConstAssociation &A) { const TypeSourceInfo *TSI = A.getTypeSourceInfo(); if (TSI) { @@ -1180,8 +1205,11 @@ void TextNodeDumper::VisitDeclRefExpr(const DeclRefExpr *Node) { case NOUR_Constant: OS << " non_odr_use_constant"; break; case NOUR_Discarded: OS << " non_odr_use_discarded"; break; } - if (Node->refersToEnclosingVariableOrCapture()) + if (Node->isCapturedByCopyInLambdaWithExplicitObjectParameter()) + OS << " dependent_capture"; + else if (Node->refersToEnclosingVariableOrCapture()) OS << " refers_to_enclosing_variable_or_capture"; + if (Node->isImmediateEscalating()) OS << " immediate-escalating"; } @@ -1337,6 +1365,8 @@ void TextNodeDumper::VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *Node) { void TextNodeDumper::VisitCXXThisExpr(const CXXThisExpr *Node) { if (Node->isImplicit()) OS << " implicit"; + if (Node->isCapturedByCopyInLambdaWithExplicitObjectParameter()) + OS << " dependent_capture"; OS << " this"; } @@ -1990,6 +2020,19 @@ void TextNodeDumper::VisitFunctionDecl(const FunctionDecl *D) { } } +void TextNodeDumper::VisitCXXDeductionGuideDecl( + const CXXDeductionGuideDecl *D) { + VisitFunctionDecl(D); + switch (D->getDeductionCandidateKind()) { + case DeductionCandidate::Normal: + case DeductionCandidate::Copy: + return; + case DeductionCandidate::Aggregate: + OS << " aggregate "; + break; + } +} + void TextNodeDumper::VisitLifetimeExtendedTemporaryDecl( const LifetimeExtendedTemporaryDecl *D) { OS << " extended by "; @@ -2671,5 +2714,4 @@ void TextNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) { void TextNodeDumper::VisitOpenACCConstructStmt(const OpenACCConstructStmt *S) { OS << " " << S->getDirectiveKind(); - // TODO OpenACC: Dump clauses as well. } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index c6fe90ba5e292736976286bffcdc5caa30b1f508..cb22c91a12aa8911b9c487e7044f3032ef5c9654 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -159,6 +159,22 @@ ArrayType::ArrayType(TypeClass tc, QualType et, QualType can, ArrayTypeBits.SizeModifier = llvm::to_underlying(sm); } +ConstantArrayType * +ConstantArrayType::Create(const ASTContext &Ctx, QualType ET, QualType Can, + const llvm::APInt &Sz, const Expr *SzExpr, + ArraySizeModifier SzMod, unsigned Qual) { + bool NeedsExternalSize = SzExpr != nullptr || Sz.ugt(0x0FFFFFFFFFFFFFFF) || + Sz.getBitWidth() > 0xFF; + if (!NeedsExternalSize) + return new (Ctx, alignof(ConstantArrayType)) ConstantArrayType( + ET, Can, Sz.getBitWidth(), Sz.getZExtValue(), SzMod, Qual); + + auto *SzPtr = new (Ctx, alignof(ConstantArrayType::ExternalSize)) + ConstantArrayType::ExternalSize(Sz, SzExpr); + return new (Ctx, alignof(ConstantArrayType)) + ConstantArrayType(ET, Can, SzPtr, SzMod, Qual); +} + unsigned ConstantArrayType::getNumAddressingBits(const ASTContext &Context, QualType ElementType, const llvm::APInt &NumElements) { @@ -213,11 +229,10 @@ unsigned ConstantArrayType::getMaxSizeBits(const ASTContext &Context) { void ConstantArrayType::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context, QualType ET, - const llvm::APInt &ArraySize, - const Expr *SizeExpr, ArraySizeModifier SizeMod, - unsigned TypeQuals) { + uint64_t ArraySize, const Expr *SizeExpr, + ArraySizeModifier SizeMod, unsigned TypeQuals) { ID.AddPointer(ET.getAsOpaquePtr()); - ID.AddInteger(ArraySize.getZExtValue()); + ID.AddInteger(ArraySize); ID.AddInteger(llvm::to_underlying(SizeMod)); ID.AddInteger(TypeQuals); ID.AddBoolean(SizeExpr != nullptr); @@ -452,12 +467,8 @@ QualType QualType::getSingleStepDesugaredTypeImpl(QualType type, // Check that no type class has a non-trival destructor. Types are // allocated with the BumpPtrAllocator from ASTContext and therefore // their destructor is not executed. -// -// FIXME: ConstantArrayType is not trivially destructible because of its -// APInt member. It should be replaced in favor of ASTContext allocation. #define TYPE(CLASS, BASE) \ - static_assert(std::is_trivially_destructible::value || \ - std::is_same::value, \ + static_assert(std::is_trivially_destructible::value, \ #CLASS "Type should be trivially destructible!"); #include "clang/AST/TypeNodes.inc" @@ -1186,6 +1197,14 @@ public: return Ctx.getDecayedType(originalType); } + QualType VisitArrayParameterType(const ArrayParameterType *T) { + QualType ArrTy = VisitConstantArrayType(T); + if (ArrTy.isNull()) + return {}; + + return Ctx.getArrayParameterType(ArrTy); + } + SUGARED_TYPE_CLASS(TypeOfExpr) SUGARED_TYPE_CLASS(TypeOf) SUGARED_TYPE_CLASS(Decltype) @@ -3473,6 +3492,9 @@ StringRef FunctionType::getNameForCallConv(CallingConv CC) { case CC_PreserveAll: return "preserve_all"; case CC_M68kRTD: return "m68k_rtd"; case CC_PreserveNone: return "preserve_none"; + // clang-format off + case CC_RISCVVectorCall: return "riscv_vector_cc"; + // clang-format on } llvm_unreachable("Invalid calling convention."); @@ -4063,6 +4085,7 @@ bool AttributedType::isCallingConv() const { case attr::PreserveAll: case attr::M68kRTD: case attr::PreserveNone: + case attr::RISCVVectorCC: return true; } llvm_unreachable("invalid attr kind"); @@ -4439,6 +4462,7 @@ static CachedProperties computeCachedProperties(const Type *T) { case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: + case Type::ArrayParameter: return Cache::get(cast(T)->getElementType()); case Type::Vector: case Type::ExtVector: @@ -4527,6 +4551,7 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) { case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: + case Type::ArrayParameter: return computeTypeLinkageInfo(cast(T)->getElementType()); case Type::Vector: case Type::ExtVector: @@ -4627,16 +4652,15 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { case Type::Auto: return ResultIfUnknown; - // Dependent template specializations can instantiate to pointer - // types unless they're known to be specializations of a class - // template. + // Dependent template specializations could instantiate to pointer types. case Type::TemplateSpecialization: - if (TemplateDecl *templateDecl - = cast(type.getTypePtr()) - ->getTemplateName().getAsTemplateDecl()) { - if (isa(templateDecl)) - return false; - } + // If it's a known class template, we can already check if it's nullable. + if (TemplateDecl *templateDecl = + cast(type.getTypePtr()) + ->getTemplateName() + .getAsTemplateDecl()) + if (auto *CTD = dyn_cast(templateDecl)) + return CTD->getTemplatedDecl()->hasAttr(); return ResultIfUnknown; case Type::Builtin: @@ -4693,6 +4717,17 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { } llvm_unreachable("unknown builtin type"); + case Type::Record: { + const RecordDecl *RD = cast(type)->getDecl(); + // For template specializations, look only at primary template attributes. + // This is a consistent regardless of whether the instantiation is known. + if (const auto *CTSD = dyn_cast(RD)) + return CTSD->getSpecializedTemplate() + ->getTemplatedDecl() + ->hasAttr(); + return RD->hasAttr(); + } + // Non-pointer types. case Type::Complex: case Type::LValueReference: @@ -4710,7 +4745,6 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { case Type::DependentAddressSpace: case Type::FunctionProto: case Type::FunctionNoProto: - case Type::Record: case Type::DeducedTemplateSpecialization: case Type::Enum: case Type::InjectedClassName: @@ -4721,6 +4755,7 @@ bool Type::canHaveNullability(bool ResultIfUnknown) const { case Type::Pipe: case Type::BitInt: case Type::DependentBitInt: + case Type::ArrayParameter: return false; } llvm_unreachable("bad type kind!"); diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 7032ff2f18468c2a23c6a2dd4fa9041cc0b0bf2b..9602f448e942796f8c2dccf927635c3d5ef81cef 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -268,6 +268,7 @@ bool TypePrinter::canPrefixQualifiers(const Type *T, case Type::Adjusted: case Type::Decayed: + case Type::ArrayParameter: case Type::Pointer: case Type::BlockPointer: case Type::LValueReference: @@ -538,7 +539,7 @@ void TypePrinter::printConstantArrayAfter(const ConstantArrayType *T, if (T->getSizeModifier() == ArraySizeModifier::Static) OS << "static "; - OS << T->getSize().getZExtValue() << ']'; + OS << T->getZExtSize() << ']'; printAfter(T->getElementType(), OS); } @@ -595,6 +596,16 @@ void TypePrinter::printDecayedBefore(const DecayedType *T, raw_ostream &OS) { printAdjustedBefore(T, OS); } +void TypePrinter::printArrayParameterAfter(const ArrayParameterType *T, + raw_ostream &OS) { + printConstantArrayAfter(T, OS); +} + +void TypePrinter::printArrayParameterBefore(const ArrayParameterType *T, + raw_ostream &OS) { + printConstantArrayBefore(T, OS); +} + void TypePrinter::printDecayedAfter(const DecayedType *T, raw_ostream &OS) { printAdjustedAfter(T, OS); } @@ -1071,6 +1082,9 @@ void TypePrinter::printFunctionAfter(const FunctionType::ExtInfo &Info, case CC_PreserveNone: OS << " __attribute__((preserve_none))"; break; + case CC_RISCVVectorCall: + OS << "__attribute__((riscv_vector_cc))"; + break; } } @@ -1199,10 +1213,13 @@ void TypePrinter::printDecltypeBefore(const DecltypeType *T, raw_ostream &OS) { void TypePrinter::printPackIndexingBefore(const PackIndexingType *T, raw_ostream &OS) { - if (T->hasSelectedType()) + if (T->hasSelectedType()) { OS << T->getSelectedType(); - else - OS << T->getPattern() << "...[" << T->getIndexExpr() << "]"; + } else { + OS << T->getPattern() << "...["; + T->getIndexExpr()->printPretty(OS, nullptr, Policy); + OS << "]"; + } spaceBeforePlaceHolder(OS); } @@ -1732,14 +1749,15 @@ void TypePrinter::printPackExpansionAfter(const PackExpansionType *T, static void printCountAttributedImpl(const CountAttributedType *T, raw_ostream &OS, const PrintingPolicy &Policy) { + OS << ' '; if (T->isCountInBytes() && T->isOrNull()) - OS << " __sized_by_or_null("; + OS << "__sized_by_or_null("; else if (T->isCountInBytes()) - OS << " __sized_by("; + OS << "__sized_by("; else if (T->isOrNull()) - OS << " __counted_by_or_null("; + OS << "__counted_by_or_null("; else - OS << " __counted_by("; + OS << "__counted_by("; if (T->getCountExpr()) T->getCountExpr()->printPretty(OS, nullptr, Policy); OS << ')'; @@ -1748,14 +1766,14 @@ static void printCountAttributedImpl(const CountAttributedType *T, void TypePrinter::printCountAttributedBefore(const CountAttributedType *T, raw_ostream &OS) { printBefore(T->desugar(), OS); - if (!T->desugar()->isArrayType()) + if (!T->isArrayType()) printCountAttributedImpl(T, OS, Policy); } void TypePrinter::printCountAttributedAfter(const CountAttributedType *T, raw_ostream &OS) { printAfter(T->desugar(), OS); - if (T->desugar()->isArrayType()) + if (T->isArrayType()) printCountAttributedImpl(T, OS, Policy); } @@ -1960,6 +1978,9 @@ void TypePrinter::printAttributedAfter(const AttributedType *T, case attr::PreserveNone: OS << "preserve_none"; break; + case attr::RISCVVectorCC: + OS << "riscv_vector_cc"; + break; case attr::NoDeref: OS << "noderef"; break; @@ -2303,15 +2324,10 @@ printTo(raw_ostream &OS, ArrayRef Args, const PrintingPolicy &Policy, } else { if (!FirstArg) OS << Comma; - if (!Policy.SuppressTagKeyword && - Argument.getKind() == TemplateArgument::Type && - isa(Argument.getAsType())) - OS << Argument.getAsType().getAsString(); - else - // Tries to print the argument with location info if exists. - printArgument(Arg, Policy, ArgOS, - TemplateParameterList::shouldIncludeTypeForArgument( - Policy, TPL, ParmIndex)); + // Tries to print the argument with location info if exists. + printArgument(Arg, Policy, ArgOS, + TemplateParameterList::shouldIncludeTypeForArgument( + Policy, TPL, ParmIndex)); } StringRef ArgString = ArgOS.str(); diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index de70cbbf6cdb3801709cced4e36e2c1bd1859c8e..64e6155de090c5f3e0626968485ca104baa00f9e 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -2039,7 +2039,7 @@ void CFGBuilder::addImplicitDtorsForDestructor(const CXXDestructorDecl *DD) { QualType QT = FI->getType(); // It may be a multidimensional array. while (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) { - if (AT->getSize() == 0) + if (AT->isZeroSize()) break; QT = AT->getElementType(); } @@ -2133,7 +2133,7 @@ bool CFGBuilder::hasTrivialDestructor(const VarDecl *VD) const { // Check for constant size array. Set type to array element type. while (const ConstantArrayType *AT = Context->getAsConstantArrayType(QT)) { - if (AT->getSize() == 0) + if (AT->isZeroSize()) return true; QT = AT->getElementType(); } diff --git a/clang/lib/Analysis/FlowSensitive/AdornedCFG.cpp b/clang/lib/Analysis/FlowSensitive/AdornedCFG.cpp index daa73bed1bd9f5cefc81186d40cfec73b7d1bb1b..255543021a998c9dcb1801b9821b0ae37bd1bf14 100644 --- a/clang/lib/Analysis/FlowSensitive/AdornedCFG.cpp +++ b/clang/lib/Analysis/FlowSensitive/AdornedCFG.cpp @@ -144,7 +144,7 @@ llvm::Expected AdornedCFG::build(const Decl &D, Stmt &S, // The shape of certain elements of the AST can vary depending on the // language. We currently only support C++. - if (!C.getLangOpts().CPlusPlus) + if (!C.getLangOpts().CPlusPlus || C.getLangOpts().ObjC) return llvm::createStringError( std::make_error_code(std::errc::invalid_argument), "Can only analyze C++"); diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index cc1ebd511191a93d76a0528ee95ba6dd1907044c..bea15ce9bd24d11f5c8a5eaa0cda92e326d82801 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -15,6 +15,7 @@ #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Type.h" #include "clang/Analysis/FlowSensitive/DataflowLattice.h" #include "clang/Analysis/FlowSensitive/Value.h" @@ -26,6 +27,8 @@ #include #include +#define DEBUG_TYPE "dataflow" + namespace clang { namespace dataflow { @@ -166,17 +169,16 @@ static Value *joinDistinctValues(QualType Type, Value &Val1, return JoinedVal; } -// When widening does not change `Current`, return value will equal `&Prev`. -static Value &widenDistinctValues(QualType Type, Value &Prev, - const Environment &PrevEnv, Value &Current, - Environment &CurrentEnv, - Environment::ValueModel &Model) { +static WidenResult widenDistinctValues(QualType Type, Value &Prev, + const Environment &PrevEnv, + Value &Current, Environment &CurrentEnv, + Environment::ValueModel &Model) { // Boolean-model widening. if (auto *PrevBool = dyn_cast(&Prev)) { - // If previous value was already Top, re-use that to (implicitly) indicate - // that no change occurred. if (isa(Prev)) - return Prev; + // Safe to return `Prev` here, because Top is never dependent on the + // environment. + return {&Prev, LatticeEffect::Unchanged}; // We may need to widen to Top, but before we do so, check whether both // values are implied to be either true or false in the current environment. @@ -185,22 +187,24 @@ static Value &widenDistinctValues(QualType Type, Value &Prev, bool TruePrev = PrevEnv.proves(PrevBool->formula()); bool TrueCur = CurrentEnv.proves(CurBool.formula()); if (TruePrev && TrueCur) - return CurrentEnv.getBoolLiteralValue(true); + return {&CurrentEnv.getBoolLiteralValue(true), LatticeEffect::Unchanged}; if (!TruePrev && !TrueCur && PrevEnv.proves(PrevEnv.arena().makeNot(PrevBool->formula())) && CurrentEnv.proves(CurrentEnv.arena().makeNot(CurBool.formula()))) - return CurrentEnv.getBoolLiteralValue(false); + return {&CurrentEnv.getBoolLiteralValue(false), LatticeEffect::Unchanged}; - return CurrentEnv.makeTopBoolValue(); + return {&CurrentEnv.makeTopBoolValue(), LatticeEffect::Changed}; } // FIXME: Add other built-in model widening. // Custom-model widening. - if (auto *W = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv)) - return *W; + if (auto Result = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv)) + return *Result; - return equateUnknownValues(Prev.getKind()) ? Prev : Current; + return {&Current, equateUnknownValues(Prev.getKind()) + ? LatticeEffect::Unchanged + : LatticeEffect::Changed}; } // Returns whether the values in `Map1` and `Map2` compare equal for those @@ -271,7 +275,7 @@ llvm::MapVector widenKeyToValueMap(const llvm::MapVector &CurMap, const llvm::MapVector &PrevMap, Environment &CurEnv, const Environment &PrevEnv, - Environment::ValueModel &Model, LatticeJoinEffect &Effect) { + Environment::ValueModel &Model, LatticeEffect &Effect) { llvm::MapVector WidenedMap; for (auto &Entry : CurMap) { Key K = Entry.first; @@ -290,11 +294,11 @@ widenKeyToValueMap(const llvm::MapVector &CurMap, continue; } - Value &WidenedVal = widenDistinctValues(K->getType(), *PrevIt->second, - PrevEnv, *Val, CurEnv, Model); - WidenedMap.insert({K, &WidenedVal}); - if (&WidenedVal != PrevIt->second) - Effect = LatticeJoinEffect::Changed; + auto [WidenedVal, ValEffect] = widenDistinctValues( + K->getType(), *PrevIt->second, PrevEnv, *Val, CurEnv, Model); + WidenedMap.insert({K, WidenedVal}); + if (ValEffect == LatticeEffect::Changed) + Effect = LatticeEffect::Changed; } return WidenedMap; @@ -353,6 +357,8 @@ getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields, for (auto *Child : S.children()) if (Child != nullptr) getFieldsGlobalsAndFuncs(*Child, Fields, Vars, Funcs); + if (const auto *DefaultArg = dyn_cast(&S)) + getFieldsGlobalsAndFuncs(*DefaultArg->getExpr(), Fields, Vars, Funcs); if (const auto *DefaultInit = dyn_cast(&S)) getFieldsGlobalsAndFuncs(*DefaultInit->getExpr(), Fields, Vars, Funcs); @@ -385,6 +391,186 @@ getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields, } } +namespace { + +// Visitor that builds a map from record prvalues to result objects. +// This traverses the body of the function to be analyzed; for each result +// object that it encounters, it propagates the storage location of the result +// object to all record prvalues that can initialize it. +class ResultObjectVisitor : public RecursiveASTVisitor { +public: + // `ResultObjectMap` will be filled with a map from record prvalues to result + // object. If the function being analyzed returns a record by value, + // `LocForRecordReturnVal` is the location to which this record should be + // written; otherwise, it is null. + explicit ResultObjectVisitor( + llvm::DenseMap &ResultObjectMap, + RecordStorageLocation *LocForRecordReturnVal, + DataflowAnalysisContext &DACtx) + : ResultObjectMap(ResultObjectMap), + LocForRecordReturnVal(LocForRecordReturnVal), DACtx(DACtx) {} + + bool shouldVisitImplicitCode() { return true; } + + bool shouldVisitLambdaBody() const { return false; } + + // Traverse all member and base initializers of `Ctor`. This function is not + // called by `RecursiveASTVisitor`; it should be called manually if we are + // analyzing a constructor. `ThisPointeeLoc` is the storage location that + // `this` points to. + void TraverseConstructorInits(const CXXConstructorDecl *Ctor, + RecordStorageLocation *ThisPointeeLoc) { + assert(ThisPointeeLoc != nullptr); + for (const CXXCtorInitializer *Init : Ctor->inits()) { + Expr *InitExpr = Init->getInit(); + if (FieldDecl *Field = Init->getMember(); + Field != nullptr && Field->getType()->isRecordType()) { + PropagateResultObject(InitExpr, cast( + ThisPointeeLoc->getChild(*Field))); + } else if (Init->getBaseClass()) { + PropagateResultObject(InitExpr, ThisPointeeLoc); + } + + // Ensure that any result objects within `InitExpr` (e.g. temporaries) + // are also propagated to the prvalues that initialize them. + TraverseStmt(InitExpr); + + // If this is a `CXXDefaultInitExpr`, also propagate any result objects + // within the default expression. + if (auto *DefaultInit = dyn_cast(InitExpr)) + TraverseStmt(DefaultInit->getExpr()); + } + } + + bool TraverseBindingDecl(BindingDecl *BD) { + // `RecursiveASTVisitor` doesn't traverse holding variables for + // `BindingDecl`s by itself, so we need to tell it to. + if (VarDecl *HoldingVar = BD->getHoldingVar()) + TraverseDecl(HoldingVar); + return RecursiveASTVisitor::TraverseBindingDecl(BD); + } + + bool VisitVarDecl(VarDecl *VD) { + if (VD->getType()->isRecordType() && VD->hasInit()) + PropagateResultObject( + VD->getInit(), + &cast(DACtx.getStableStorageLocation(*VD))); + return true; + } + + bool VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *MTE) { + if (MTE->getType()->isRecordType()) + PropagateResultObject( + MTE->getSubExpr(), + &cast(DACtx.getStableStorageLocation(*MTE))); + return true; + } + + bool VisitReturnStmt(ReturnStmt *Return) { + Expr *RetValue = Return->getRetValue(); + if (RetValue != nullptr && RetValue->getType()->isRecordType() && + RetValue->isPRValue()) + PropagateResultObject(RetValue, LocForRecordReturnVal); + return true; + } + + bool VisitExpr(Expr *E) { + // Clang's AST can have record-type prvalues without a result object -- for + // example as full-expressions contained in a compound statement or as + // arguments of call expressions. We notice this if we get here and a + // storage location has not yet been associated with `E`. In this case, + // treat this as if it was a `MaterializeTemporaryExpr`. + if (E->isPRValue() && E->getType()->isRecordType() && + !ResultObjectMap.contains(E)) + PropagateResultObject( + E, &cast(DACtx.getStableStorageLocation(*E))); + return true; + } + + // Assigns `Loc` as the result object location of `E`, then propagates the + // location to all lower-level prvalues that initialize the same object as + // `E` (or one of its base classes or member variables). + void PropagateResultObject(Expr *E, RecordStorageLocation *Loc) { + if (!E->isPRValue() || !E->getType()->isRecordType()) { + assert(false); + // Ensure we don't propagate the result object if we hit this in a + // release build. + return; + } + + ResultObjectMap[E] = Loc; + + // The following AST node kinds are "original initializers": They are the + // lowest-level AST node that initializes a given object, and nothing + // below them can initialize the same object (or part of it). + if (isa(E) || isa(E) || isa(E) || + isa(E) || isa(E) || + isa(E)) { + return; + } + + if (auto *InitList = dyn_cast(E)) { + if (!InitList->isSemanticForm()) + return; + if (InitList->isTransparent()) { + PropagateResultObject(InitList->getInit(0), Loc); + return; + } + + RecordInitListHelper InitListHelper(InitList); + + for (auto [Base, Init] : InitListHelper.base_inits()) { + assert(Base->getType().getCanonicalType() == + Init->getType().getCanonicalType()); + + // Storage location for the base class is the same as that of the + // derived class because we "flatten" the object hierarchy and put all + // fields in `RecordStorageLocation` of the derived class. + PropagateResultObject(Init, Loc); + } + + for (auto [Field, Init] : InitListHelper.field_inits()) { + // Fields of non-record type are handled in + // `TransferVisitor::VisitInitListExpr()`. + if (!Field->getType()->isRecordType()) + continue; + PropagateResultObject( + Init, cast(Loc->getChild(*Field))); + } + return; + } + + if (auto *Op = dyn_cast(E); Op && Op->isCommaOp()) { + PropagateResultObject(Op->getRHS(), Loc); + return; + } + + if (auto *Cond = dyn_cast(E)) { + PropagateResultObject(Cond->getTrueExpr(), Loc); + PropagateResultObject(Cond->getFalseExpr(), Loc); + return; + } + + // All other expression nodes that propagate a record prvalue should have + // exactly one child. + SmallVector Children(E->child_begin(), E->child_end()); + LLVM_DEBUG({ + if (Children.size() != 1) + E->dump(); + }); + assert(Children.size() == 1); + for (Stmt *S : Children) + PropagateResultObject(cast(S), Loc); + } + +private: + llvm::DenseMap &ResultObjectMap; + RecordStorageLocation *LocForRecordReturnVal; + DataflowAnalysisContext &DACtx; +}; + +} // namespace + Environment::Environment(DataflowAnalysisContext &DACtx) : DACtx(&DACtx), FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {} @@ -400,23 +586,29 @@ void Environment::initialize() { if (DeclCtx == nullptr) return; - if (const auto *FuncDecl = dyn_cast(DeclCtx)) { - assert(FuncDecl->doesThisDeclarationHaveABody()); + const auto *FuncDecl = dyn_cast(DeclCtx); + if (FuncDecl == nullptr) + return; + + assert(FuncDecl->doesThisDeclarationHaveABody()); - initFieldsGlobalsAndFuncs(FuncDecl); + initFieldsGlobalsAndFuncs(FuncDecl); - for (const auto *ParamDecl : FuncDecl->parameters()) { - assert(ParamDecl != nullptr); - setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr)); - } + for (const auto *ParamDecl : FuncDecl->parameters()) { + assert(ParamDecl != nullptr); + setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr)); } + if (FuncDecl->getReturnType()->isRecordType()) + LocForRecordReturnVal = &cast( + createStorageLocation(FuncDecl->getReturnType())); + if (const auto *MethodDecl = dyn_cast(DeclCtx)) { auto *Parent = MethodDecl->getParent(); assert(Parent != nullptr); if (Parent->isLambda()) { - for (auto Capture : Parent->captures()) { + for (const auto &Capture : Parent->captures()) { if (Capture.capturesVariable()) { const auto *VarDecl = Capture.getCapturedVar(); assert(VarDecl != nullptr); @@ -443,6 +635,12 @@ void Environment::initialize() { initializeFieldsWithValues(ThisLoc); } } + + // We do this below the handling of `CXXMethodDecl` above so that we can + // be sure that the storage location for `this` has been set. + ResultObjectMap = std::make_shared( + buildResultObjectMap(DACtx, FuncDecl, getThisPointeeStorageLocation(), + LocForRecordReturnVal)); } // FIXME: Add support for resetting globals after function calls to enable @@ -483,13 +681,18 @@ void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) { if (getStorageLocation(*D) != nullptr) continue; - setStorageLocation(*D, createObject(*D)); + // We don't run transfer functions on the initializers of global variables, + // so they won't be associated with a value or storage location. We + // therefore intentionally don't pass an initializer to `createObject()`; + // in particular, this ensures that `createObject()` will initialize the + // fields of record-type variables with values. + setStorageLocation(*D, createObject(*D, nullptr)); } for (const FunctionDecl *FD : Funcs) { if (getStorageLocation(*FD) != nullptr) continue; - auto &Loc = createStorageLocation(FD->getType()); + auto &Loc = createStorageLocation(*FD); setStorageLocation(*FD, Loc); } } @@ -518,6 +721,9 @@ Environment Environment::pushCall(const CallExpr *Call) const { } } + if (Call->getType()->isRecordType() && Call->isPRValue()) + Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call); + Env.pushCallInternal(Call->getDirectCallee(), llvm::ArrayRef(Call->getArgs(), Call->getNumArgs())); @@ -528,6 +734,7 @@ Environment Environment::pushCall(const CXXConstructExpr *Call) const { Environment Env(*this); Env.ThisPointeeLoc = &Env.getResultObjectLocation(*Call); + Env.LocForRecordReturnVal = &Env.getResultObjectLocation(*Call); Env.pushCallInternal(Call->getConstructor(), llvm::ArrayRef(Call->getArgs(), Call->getNumArgs())); @@ -556,6 +763,10 @@ void Environment::pushCallInternal(const FunctionDecl *FuncDecl, const VarDecl *Param = *ParamIt; setStorageLocation(*Param, createObject(*Param, Args[ArgIndex])); } + + ResultObjectMap = std::make_shared( + buildResultObjectMap(DACtx, FuncDecl, getThisPointeeStorageLocation(), + LocForRecordReturnVal)); } void Environment::popCall(const CallExpr *Call, const Environment &CalleeEnv) { @@ -599,6 +810,9 @@ bool Environment::equivalentTo(const Environment &Other, if (ReturnLoc != Other.ReturnLoc) return false; + if (LocForRecordReturnVal != Other.LocForRecordReturnVal) + return false; + if (ThisPointeeLoc != Other.ThisPointeeLoc) return false; @@ -617,15 +831,17 @@ bool Environment::equivalentTo(const Environment &Other, return true; } -LatticeJoinEffect Environment::widen(const Environment &PrevEnv, - Environment::ValueModel &Model) { +LatticeEffect Environment::widen(const Environment &PrevEnv, + Environment::ValueModel &Model) { assert(DACtx == PrevEnv.DACtx); assert(ReturnVal == PrevEnv.ReturnVal); assert(ReturnLoc == PrevEnv.ReturnLoc); + assert(LocForRecordReturnVal == PrevEnv.LocForRecordReturnVal); assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc); assert(CallStack == PrevEnv.CallStack); + assert(ResultObjectMap == PrevEnv.ResultObjectMap); - auto Effect = LatticeJoinEffect::Unchanged; + auto Effect = LatticeEffect::Unchanged; // By the API, `PrevEnv` is a previous version of the environment for the same // block, so we have some guarantees about its shape. In particular, it will @@ -646,7 +862,7 @@ LatticeJoinEffect Environment::widen(const Environment &PrevEnv, ExprToLoc.size() != PrevEnv.ExprToLoc.size() || ExprToVal.size() != PrevEnv.ExprToVal.size() || LocToVal.size() != PrevEnv.LocToVal.size()) - Effect = LatticeJoinEffect::Changed; + Effect = LatticeEffect::Changed; return Effect; } @@ -655,12 +871,16 @@ Environment Environment::join(const Environment &EnvA, const Environment &EnvB, Environment::ValueModel &Model, ExprJoinBehavior ExprBehavior) { assert(EnvA.DACtx == EnvB.DACtx); + assert(EnvA.LocForRecordReturnVal == EnvB.LocForRecordReturnVal); assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc); assert(EnvA.CallStack == EnvB.CallStack); + assert(EnvA.ResultObjectMap == EnvB.ResultObjectMap); Environment JoinedEnv(*EnvA.DACtx); JoinedEnv.CallStack = EnvA.CallStack; + JoinedEnv.ResultObjectMap = EnvA.ResultObjectMap; + JoinedEnv.LocForRecordReturnVal = EnvA.LocForRecordReturnVal; JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc; if (EnvA.ReturnVal == nullptr || EnvB.ReturnVal == nullptr) { @@ -729,6 +949,12 @@ StorageLocation &Environment::createStorageLocation(const Expr &E) { void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { assert(!DeclToLoc.contains(&D)); + // The only kinds of declarations that may have a "variable" storage location + // are declarations of reference type and `BindingDecl`. For all other + // declaration, the storage location should be the stable storage location + // returned by `createStorageLocation()`. + assert(D.getType()->isReferenceType() || isa(D) || + &Loc == &createStorageLocation(D)); DeclToLoc[&D] = &Loc; } @@ -763,77 +989,34 @@ StorageLocation *Environment::getStorageLocation(const Expr &E) const { return It == ExprToLoc.end() ? nullptr : &*It->second; } -// Returns whether a prvalue of record type is the one that originally -// constructs the object (i.e. it doesn't propagate it from one of its -// children). -static bool isOriginalRecordConstructor(const Expr &RecordPRValue) { - if (auto *Init = dyn_cast(&RecordPRValue)) - return !Init->isSemanticForm() || !Init->isTransparent(); - return isa(RecordPRValue) || isa(RecordPRValue) || - isa(RecordPRValue) || - isa(RecordPRValue) || - isa(RecordPRValue) || - // The framework currently does not propagate the objects created in - // the two branches of a `ConditionalOperator` because there is no way - // to reconcile their storage locations, which are different. We - // therefore claim that the `ConditionalOperator` is the expression - // that originally constructs the object. - // Ultimately, this will be fixed by propagating locations down from - // the result object, rather than up from the original constructor as - // we do now (see also the FIXME in the documentation for - // `getResultObjectLocation()`). - isa(RecordPRValue); -} - RecordStorageLocation & Environment::getResultObjectLocation(const Expr &RecordPRValue) const { assert(RecordPRValue.getType()->isRecordType()); assert(RecordPRValue.isPRValue()); - // Returns a storage location that we can use if assertions fail. - auto FallbackForAssertFailure = - [this, &RecordPRValue]() -> RecordStorageLocation & { + assert(ResultObjectMap != nullptr); + RecordStorageLocation *Loc = ResultObjectMap->lookup(&RecordPRValue); + assert(Loc != nullptr); + // In release builds, use the "stable" storage location if the map lookup + // failed. + if (Loc == nullptr) return cast( DACtx->getStableStorageLocation(RecordPRValue)); - }; - - if (isOriginalRecordConstructor(RecordPRValue)) { - auto *Val = cast_or_null(getValue(RecordPRValue)); - // The builtin transfer function should have created a `RecordValue` for all - // original record constructors. - assert(Val); - if (!Val) - return FallbackForAssertFailure(); - return Val->getLoc(); - } - - if (auto *Op = dyn_cast(&RecordPRValue); - Op && Op->isCommaOp()) { - return getResultObjectLocation(*Op->getRHS()); - } - - // All other expression nodes that propagate a record prvalue should have - // exactly one child. - llvm::SmallVector children(RecordPRValue.child_begin(), - RecordPRValue.child_end()); - assert(children.size() == 1); - if (children.empty()) - return FallbackForAssertFailure(); - - return getResultObjectLocation(*cast(children[0])); + return *Loc; } PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) { return DACtx->getOrCreateNullPointerValue(PointeeType); } -void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc) { +void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc, + QualType Type) { llvm::DenseSet Visited; int CreatedValuesCount = 0; - initializeFieldsWithValues(Loc, Visited, 0, CreatedValuesCount); + initializeFieldsWithValues(Loc, Type, Visited, 0, CreatedValuesCount); if (CreatedValuesCount > MaxCompositeValueSize) { - llvm::errs() << "Attempting to initialize a huge value of type: " - << Loc.getType() << '\n'; + llvm::errs() << "Attempting to initialize a huge value of type: " << Type + << '\n'; } } @@ -847,8 +1030,8 @@ void Environment::setValue(const Expr &E, Value &Val) { const Expr &CanonE = ignoreCFGOmittedNodes(E); if (auto *RecordVal = dyn_cast(&Val)) { - assert(isOriginalRecordConstructor(CanonE) || - &RecordVal->getLoc() == &getResultObjectLocation(CanonE)); + assert(&RecordVal->getLoc() == &getResultObjectLocation(CanonE)); + (void)RecordVal; } assert(CanonE.isPRValue()); @@ -926,7 +1109,8 @@ Value *Environment::createValueUnlessSelfReferential( if (Type->isRecordType()) { CreatedValuesCount++; auto &Loc = cast(createStorageLocation(Type)); - initializeFieldsWithValues(Loc, Visited, Depth, CreatedValuesCount); + initializeFieldsWithValues(Loc, Loc.getType(), Visited, Depth, + CreatedValuesCount); return &refreshRecordValue(Loc, *this); } @@ -958,6 +1142,7 @@ Environment::createLocAndMaybeValue(QualType Ty, } void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc, + QualType Type, llvm::DenseSet &Visited, int Depth, int &CreatedValuesCount) { @@ -965,8 +1150,8 @@ void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc, if (FieldType->isRecordType()) { auto &FieldRecordLoc = cast(FieldLoc); setValue(FieldRecordLoc, create(FieldRecordLoc)); - initializeFieldsWithValues(FieldRecordLoc, Visited, Depth + 1, - CreatedValuesCount); + initializeFieldsWithValues(FieldRecordLoc, FieldRecordLoc.getType(), + Visited, Depth + 1, CreatedValuesCount); } else { if (!Visited.insert(FieldType.getCanonicalType()).second) return; @@ -977,7 +1162,7 @@ void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc, } }; - for (const auto &[Field, FieldLoc] : Loc.children()) { + for (const FieldDecl *Field : DACtx->getModeledFields(Type)) { assert(Field != nullptr); QualType FieldType = Field->getType(); @@ -986,14 +1171,12 @@ void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc, &createLocAndMaybeValue(FieldType, Visited, Depth + 1, CreatedValuesCount)); } else { + StorageLocation *FieldLoc = Loc.getChild(*Field); assert(FieldLoc != nullptr); initField(FieldType, *FieldLoc); } } - for (const auto &[FieldName, FieldLoc] : Loc.synthetic_fields()) { - assert(FieldLoc != nullptr); - QualType FieldType = FieldLoc->getType(); - + for (const auto &[FieldName, FieldType] : DACtx->getSyntheticFields(Type)) { // Synthetic fields cannot have reference type, so we don't need to deal // with this case. assert(!FieldType->isReferenceType()); @@ -1020,38 +1203,36 @@ StorageLocation &Environment::createObjectInternal(const ValueDecl *D, return createObjectInternal(D, Ty.getNonReferenceType(), nullptr); } - Value *Val = nullptr; - if (InitExpr) { - // In the (few) cases where an expression is intentionally - // "uninterpreted", `InitExpr` is not associated with a value. There are - // two ways to handle this situation: propagate the status, so that - // uninterpreted initializers result in uninterpreted variables, or - // provide a default value. We choose the latter so that later refinements - // of the variable can be used for reasoning about the surrounding code. - // For this reason, we let this case be handled by the `createValue()` - // call below. - // - // FIXME. If and when we interpret all language cases, change this to - // assert that `InitExpr` is interpreted, rather than supplying a - // default value (assuming we don't update the environment API to return - // references). - Val = getValue(*InitExpr); - - if (!Val && isa(InitExpr) && - InitExpr->getType()->isPointerType()) - Val = &getOrCreateNullPointerValue(InitExpr->getType()->getPointeeType()); - } - if (!Val) - Val = createValue(Ty); - - if (Ty->isRecordType()) - return cast(Val)->getLoc(); - StorageLocation &Loc = D ? createStorageLocation(*D) : createStorageLocation(Ty); - if (Val) - setValue(Loc, *Val); + if (Ty->isRecordType()) { + auto &RecordLoc = cast(Loc); + if (!InitExpr) + initializeFieldsWithValues(RecordLoc); + refreshRecordValue(RecordLoc, *this); + } else { + Value *Val = nullptr; + if (InitExpr) + // In the (few) cases where an expression is intentionally + // "uninterpreted", `InitExpr` is not associated with a value. There are + // two ways to handle this situation: propagate the status, so that + // uninterpreted initializers result in uninterpreted variables, or + // provide a default value. We choose the latter so that later refinements + // of the variable can be used for reasoning about the surrounding code. + // For this reason, we let this case be handled by the `createValue()` + // call below. + // + // FIXME. If and when we interpret all language cases, change this to + // assert that `InitExpr` is interpreted, rather than supplying a + // default value (assuming we don't update the environment API to return + // references). + Val = getValue(*InitExpr); + if (!Val) + Val = createValue(Ty); + if (Val) + setValue(Loc, *Val); + } return Loc; } @@ -1070,6 +1251,8 @@ bool Environment::allows(const Formula &F) const { void Environment::dump(raw_ostream &OS) const { llvm::DenseMap LocToName; + if (LocForRecordReturnVal != nullptr) + LocToName[LocForRecordReturnVal] = "(returned record)"; if (ThisPointeeLoc != nullptr) LocToName[ThisPointeeLoc] = "this"; @@ -1100,6 +1283,9 @@ void Environment::dump(raw_ostream &OS) const { if (auto Iter = LocToName.find(ReturnLoc); Iter != LocToName.end()) OS << " (" << Iter->second << ")"; OS << "\n"; + } else if (Func->getReturnType()->isRecordType() || + isa(Func)) { + OS << "LocForRecordReturnVal: " << LocForRecordReturnVal << "\n"; } else if (!Func->getReturnType()->isVoidType()) { if (ReturnVal == nullptr) OS << "ReturnVal: nullptr\n"; @@ -1120,6 +1306,22 @@ void Environment::dump() const { dump(llvm::dbgs()); } +Environment::PrValueToResultObject Environment::buildResultObjectMap( + DataflowAnalysisContext *DACtx, const FunctionDecl *FuncDecl, + RecordStorageLocation *ThisPointeeLoc, + RecordStorageLocation *LocForRecordReturnVal) { + assert(FuncDecl->doesThisDeclarationHaveABody()); + + PrValueToResultObject Map; + + ResultObjectVisitor Visitor(Map, LocForRecordReturnVal, *DACtx); + if (const auto *Ctor = dyn_cast(FuncDecl)) + Visitor.TraverseConstructorInits(Ctor, ThisPointeeLoc); + Visitor.TraverseStmt(FuncDecl->getBody()); + + return Map; +} + RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE, const Environment &Env) { Expr *ImplicitObject = MCE.getImplicitObjectArgument(); @@ -1169,6 +1371,42 @@ getFieldsForInitListExpr(const InitListExpr *InitList) { return Fields; } +RecordInitListHelper::RecordInitListHelper(const InitListExpr *InitList) { + auto *RD = InitList->getType()->getAsCXXRecordDecl(); + assert(RD != nullptr); + + std::vector Fields = getFieldsForInitListExpr(InitList); + ArrayRef Inits = InitList->inits(); + + // Unions initialized with an empty initializer list need special treatment. + // For structs/classes initialized with an empty initializer list, Clang + // puts `ImplicitValueInitExpr`s in `InitListExpr::inits()`, but for unions, + // it doesn't do this -- so we create an `ImplicitValueInitExpr` ourselves. + SmallVector InitsForUnion; + if (InitList->getType()->isUnionType() && Inits.empty()) { + assert(Fields.size() == 1); + ImplicitValueInitForUnion.emplace(Fields.front()->getType()); + InitsForUnion.push_back(&*ImplicitValueInitForUnion); + Inits = InitsForUnion; + } + + size_t InitIdx = 0; + + assert(Fields.size() + RD->getNumBases() == Inits.size()); + for (const CXXBaseSpecifier &Base : RD->bases()) { + assert(InitIdx < Inits.size()); + Expr *Init = Inits[InitIdx++]; + BaseInits.emplace_back(&Base, Init); + } + + assert(Fields.size() == Inits.size() - InitIdx); + for (const FieldDecl *Field : Fields) { + assert(InitIdx < Inits.size()); + Expr *Init = Inits[InitIdx++]; + FieldInits.emplace_back(Field, Init); + } +} + RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env) { auto &NewVal = Env.create(Loc); Env.setValue(Loc, NewVal); @@ -1178,24 +1416,11 @@ RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env) { RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env) { assert(Expr.getType()->isRecordType()); - if (Expr.isPRValue()) { - if (auto *ExistingVal = Env.get(Expr)) { - auto &NewVal = Env.create(ExistingVal->getLoc()); - Env.setValue(Expr, NewVal); - Env.setValue(NewVal.getLoc(), NewVal); - return NewVal; - } - - auto &NewVal = *cast(Env.createValue(Expr.getType())); - Env.setValue(Expr, NewVal); - return NewVal; - } + if (Expr.isPRValue()) + refreshRecordValue(Env.getResultObjectLocation(Expr), Env); - if (auto *Loc = Env.get(Expr)) { - auto &NewVal = Env.create(*Loc); - Env.setValue(*Loc, NewVal); - return NewVal; - } + if (auto *Loc = Env.get(Expr)) + refreshRecordValue(*Loc, Env); auto &NewVal = *cast(Env.createValue(Expr.getType())); Env.setStorageLocation(Expr, NewVal.getLoc()); diff --git a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp index dbf4878622eba93f731927987cad6153478af198..cadb1ceb2d850733829a9d18e1a0ddef67e80946 100644 --- a/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp +++ b/clang/lib/Analysis/FlowSensitive/Models/UncheckedOptionalAccessModel.cpp @@ -512,27 +512,26 @@ void constructOptionalValue(const Expr &E, Environment &Env, /// Returns a symbolic value for the "has_value" property of an `optional` /// value that is constructed/assigned from a value of type `U` or `optional` /// where `T` is constructible from `U`. -BoolValue &valueOrConversionHasValue(const FunctionDecl &F, const Expr &E, +BoolValue &valueOrConversionHasValue(QualType DestType, const Expr &E, const MatchFinder::MatchResult &MatchRes, LatticeTransferState &State) { - assert(F.getTemplateSpecializationArgs() != nullptr); - assert(F.getTemplateSpecializationArgs()->size() > 0); - - const int TemplateParamOptionalWrappersCount = - countOptionalWrappers(*MatchRes.Context, F.getTemplateSpecializationArgs() - ->get(0) - .getAsType() - .getNonReferenceType()); + const int DestTypeOptionalWrappersCount = + countOptionalWrappers(*MatchRes.Context, DestType); const int ArgTypeOptionalWrappersCount = countOptionalWrappers( *MatchRes.Context, E.getType().getNonReferenceType()); - // Check if this is a constructor/assignment call for `optional` with - // argument of type `U` such that `T` is constructible from `U`. - if (TemplateParamOptionalWrappersCount == ArgTypeOptionalWrappersCount) + // Is this an constructor of the form `template optional(U &&)` / + // assignment of the form `template optional& operator=(U &&)` + // (where `T` is assignable / constructible from `U`)? + // We recognize this because the number of optionals in the optional being + // assigned to is different from the function argument type. + if (DestTypeOptionalWrappersCount != ArgTypeOptionalWrappersCount) return State.Env.getBoolLiteralValue(true); - // This is a constructor/assignment call for `optional` with argument of - // type `optional` such that `T` is constructible from `U`. + // Otherwise, this must be a constructor of the form + // `template optional &&)` / assignment of the form + // `template optional& operator=(optional &&) + // (where, again, `T` is assignable / constructible from `U`). auto *Loc = State.Env.get(E); if (auto *HasValueVal = getHasValue(State.Env, Loc)) return *HasValueVal; @@ -544,10 +543,11 @@ void transferValueOrConversionConstructor( LatticeTransferState &State) { assert(E->getNumArgs() > 0); - constructOptionalValue(*E, State.Env, - valueOrConversionHasValue(*E->getConstructor(), - *E->getArg(0), MatchRes, - State)); + constructOptionalValue( + *E, State.Env, + valueOrConversionHasValue( + E->getConstructor()->getThisType()->getPointeeType(), *E->getArg(0), + MatchRes, State)); } void transferAssignment(const CXXOperatorCallExpr *E, BoolValue &HasValueVal, @@ -566,10 +566,11 @@ void transferValueOrConversionAssignment( const CXXOperatorCallExpr *E, const MatchFinder::MatchResult &MatchRes, LatticeTransferState &State) { assert(E->getNumArgs() > 1); - transferAssignment(E, - valueOrConversionHasValue(*E->getDirectCallee(), - *E->getArg(1), MatchRes, State), - State); + transferAssignment( + E, + valueOrConversionHasValue(E->getArg(0)->getType().getNonReferenceType(), + *E->getArg(1), MatchRes, State), + State); } void transferNulloptAssignment(const CXXOperatorCallExpr *E, diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 960e9688ffb725977dc035f2c43e594e52537c01..88a9c0eccbebc0e325cfaf17aacd0e852f3b4cd2 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -460,11 +460,9 @@ public: // So make sure we have a value if we didn't propagate one above. if (S->isPRValue() && S->getType()->isRecordType()) { if (Env.getValue(*S) == nullptr) { - Value *Val = Env.createValue(S->getType()); - // We're guaranteed to always be able to create a value for record - // types. - assert(Val != nullptr); - Env.setValue(*S, *Val); + auto &Loc = Env.getResultObjectLocation(*S); + Env.initializeFieldsWithValues(Loc); + refreshRecordValue(Loc, Env); } } } @@ -472,6 +470,13 @@ public: void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { const Expr *InitExpr = S->getExpr(); assert(InitExpr != nullptr); + + // If this is a prvalue of record type, the handler for `*InitExpr` (if one + // exists) will initialize the result object; there is no value to propgate + // here. + if (S->getType()->isRecordType() && S->isPRValue()) + return; + propagateValueOrStorageLocation(*InitExpr, *S, Env); } @@ -479,6 +484,17 @@ public: const CXXConstructorDecl *ConstructorDecl = S->getConstructor(); assert(ConstructorDecl != nullptr); + // `CXXConstructExpr` can have array type if default-initializing an array + // of records. We don't handle this specifically beyond potentially inlining + // the call. + if (!S->getType()->isRecordType()) { + transferInlineCall(S, ConstructorDecl); + return; + } + + RecordStorageLocation &Loc = Env.getResultObjectLocation(*S); + Env.setValue(*S, refreshRecordValue(Loc, Env)); + if (ConstructorDecl->isCopyOrMoveConstructor()) { // It is permissible for a copy/move constructor to have additional // parameters as long as they have default arguments defined for them. @@ -491,24 +507,14 @@ public: if (ArgLoc == nullptr) return; - if (S->isElidable()) { - if (Value *Val = Env.getValue(*ArgLoc)) - Env.setValue(*S, *Val); - } else { - auto &Val = *cast(Env.createValue(S->getType())); - Env.setValue(*S, Val); - copyRecord(*ArgLoc, Val.getLoc(), Env); - } + // Even if the copy/move constructor call is elidable, we choose to copy + // the record in all cases (which isn't wrong, just potentially not + // optimal). + copyRecord(*ArgLoc, Loc, Env); return; } - // `CXXConstructExpr` can have array type if default-initializing an array - // of records, and we currently can't create values for arrays. So check if - // we've got a record type. - if (S->getType()->isRecordType()) { - auto &InitialVal = *cast(Env.createValue(S->getType())); - Env.setValue(*S, InitialVal); - } + Env.initializeFieldsWithValues(Loc, S->getType()); transferInlineCall(S, ConstructorDecl); } @@ -551,19 +557,15 @@ public: if (S->isGLValue()) { Env.setStorageLocation(*S, *LocDst); } else if (S->getType()->isRecordType()) { - // Make sure that we have a `RecordValue` for this expression so that - // `Environment::getResultObjectLocation()` is able to return a location - // for it. - if (Env.getValue(*S) == nullptr) - refreshRecordValue(*S, Env); + // Assume that the assignment returns the assigned value. + copyRecord(*LocDst, Env.getResultObjectLocation(*S), Env); } return; } - // CXXOperatorCallExpr can be prvalues. Call `VisitCallExpr`() to create - // a `RecordValue` for them so that `Environment::getResultObjectLocation()` - // can return a value. + // `CXXOperatorCallExpr` can be a prvalue. Call `VisitCallExpr`() to + // initialize the prvalue's fields with values. VisitCallExpr(S); } @@ -580,11 +582,6 @@ public: } } - void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) { - if (Value *Val = Env.createValue(S->getType())) - Env.setValue(*S, *Val); - } - void VisitCallExpr(const CallExpr *S) { // Of clang's builtins, only `__builtin_expect` is handled explicitly, since // others (like trap, debugtrap, and unreachable) are handled by CFG @@ -612,13 +609,14 @@ public: } else if (const FunctionDecl *F = S->getDirectCallee()) { transferInlineCall(S, F); - // If this call produces a prvalue of record type, make sure that we have - // a `RecordValue` for it. This is required so that - // `Environment::getResultObjectLocation()` is able to return a location - // for this `CallExpr`. + // If this call produces a prvalue of record type, initialize its fields + // with values. if (S->getType()->isRecordType() && S->isPRValue()) - if (Env.getValue(*S) == nullptr) - refreshRecordValue(*S, Env); + if (Env.getValue(*S) == nullptr) { + RecordStorageLocation &Loc = Env.getResultObjectLocation(*S); + Env.initializeFieldsWithValues(Loc); + Env.setValue(*S, refreshRecordValue(Loc, Env)); + } } } @@ -666,8 +664,10 @@ public: // `getLogicOperatorSubExprValue()`. if (S->isGLValue()) Env.setStorageLocation(*S, Env.createObject(S->getType())); - else if (Value *Val = Env.createValue(S->getType())) - Env.setValue(*S, *Val); + else if (!S->getType()->isRecordType()) { + if (Value *Val = Env.createValue(S->getType())) + Env.setValue(*S, *Val); + } } void VisitInitListExpr(const InitListExpr *S) { @@ -688,100 +688,51 @@ public: return; } - llvm::DenseMap FieldLocs; - - // This only contains the direct fields for the given type. - std::vector FieldsForInit = getFieldsForInitListExpr(S); - - // `S->inits()` contains all the initializer expressions, including the - // ones for direct base classes. - ArrayRef Inits = S->inits(); - size_t InitIdx = 0; - - // Unions initialized with an empty initializer list need special treatment. - // For structs/classes initialized with an empty initializer list, Clang - // puts `ImplicitValueInitExpr`s in `InitListExpr::inits()`, but for unions, - // it doesn't do this -- so we create an `ImplicitValueInitExpr` ourselves. - std::optional ImplicitValueInitForUnion; - SmallVector InitsForUnion; - if (S->getType()->isUnionType() && Inits.empty()) { - assert(FieldsForInit.size() == 1); - ImplicitValueInitForUnion.emplace(FieldsForInit.front()->getType()); - InitsForUnion.push_back(&*ImplicitValueInitForUnion); - Inits = InitsForUnion; - } + RecordStorageLocation &Loc = Env.getResultObjectLocation(*S); + Env.setValue(*S, refreshRecordValue(Loc, Env)); - // Initialize base classes. - if (auto* R = S->getType()->getAsCXXRecordDecl()) { - assert(FieldsForInit.size() + R->getNumBases() == Inits.size()); - for ([[maybe_unused]] const CXXBaseSpecifier &Base : R->bases()) { - assert(InitIdx < Inits.size()); - auto Init = Inits[InitIdx++]; - assert(Base.getType().getCanonicalType() == - Init->getType().getCanonicalType()); - auto *BaseVal = Env.get(*Init); - if (!BaseVal) - BaseVal = cast(Env.createValue(Init->getType())); - // Take ownership of the fields of the `RecordValue` for the base class - // and incorporate them into the "flattened" set of fields for the - // derived class. - auto Children = BaseVal->getLoc().children(); - FieldLocs.insert(Children.begin(), Children.end()); - } - } + // Initialization of base classes and fields of record type happens when we + // visit the nested `CXXConstructExpr` or `InitListExpr` for that base class + // or field. We therefore only need to deal with fields of non-record type + // here. - assert(FieldsForInit.size() == Inits.size() - InitIdx); - for (auto Field : FieldsForInit) { - assert(InitIdx < Inits.size()); - auto Init = Inits[InitIdx++]; - assert( - // The types are same, or - Field->getType().getCanonicalType().getUnqualifiedType() == - Init->getType().getCanonicalType().getUnqualifiedType() || - // The field's type is T&, and initializer is T - (Field->getType()->isReferenceType() && - Field->getType().getCanonicalType()->getPointeeType() == - Init->getType().getCanonicalType())); - auto& Loc = Env.createObject(Field->getType(), Init); - FieldLocs.insert({Field, &Loc}); - } + RecordInitListHelper InitListHelper(S); - // In the case of a union, we don't in general have initializers for all - // of the fields. Create storage locations for the remaining fields (but - // don't associate them with values). - if (Type->isUnionType()) { - for (const FieldDecl *Field : - Env.getDataflowAnalysisContext().getModeledFields(Type)) { - if (auto [it, inserted] = FieldLocs.insert({Field, nullptr}); inserted) - it->second = &Env.createStorageLocation(Field->getType()); + for (auto [Field, Init] : InitListHelper.field_inits()) { + if (Field->getType()->isRecordType()) + continue; + if (Field->getType()->isReferenceType()) { + assert(Field->getType().getCanonicalType()->getPointeeType() == + Init->getType().getCanonicalType()); + Loc.setChild(*Field, &Env.createObject(Field->getType(), Init)); + continue; } + assert(Field->getType().getCanonicalType().getUnqualifiedType() == + Init->getType().getCanonicalType().getUnqualifiedType()); + StorageLocation *FieldLoc = Loc.getChild(*Field); + // Locations for non-reference fields must always be non-null. + assert(FieldLoc != nullptr); + Value *Val = Env.getValue(*Init); + if (Val == nullptr && isa(Init) && + Init->getType()->isPointerType()) + Val = + &Env.getOrCreateNullPointerValue(Init->getType()->getPointeeType()); + if (Val == nullptr) + Val = Env.createValue(Field->getType()); + if (Val != nullptr) + Env.setValue(*FieldLoc, *Val); } - // Check that we satisfy the invariant that a `RecordStorageLoation` - // contains exactly the set of modeled fields for that type. - // `ModeledFields` includes fields from all the bases, but only the - // modeled ones. However, if a class type is initialized with an - // `InitListExpr`, all fields in the class, including those from base - // classes, are included in the set of modeled fields. The code above - // should therefore populate exactly the modeled fields. - assert(containsSameFields( - Env.getDataflowAnalysisContext().getModeledFields(Type), FieldLocs)); - - RecordStorageLocation::SyntheticFieldMap SyntheticFieldLocs; - for (const auto &Entry : - Env.getDataflowAnalysisContext().getSyntheticFields(Type)) { - SyntheticFieldLocs.insert( - {Entry.getKey(), &Env.createObject(Entry.getValue())}); + for (const auto &[FieldName, FieldLoc] : Loc.synthetic_fields()) { + QualType FieldType = FieldLoc->getType(); + if (FieldType->isRecordType()) { + Env.initializeFieldsWithValues(*cast(FieldLoc)); + } else { + if (Value *Val = Env.createValue(FieldType)) + Env.setValue(*FieldLoc, *Val); + } } - auto &Loc = Env.getDataflowAnalysisContext().createRecordStorageLocation( - Type, std::move(FieldLocs), std::move(SyntheticFieldLocs)); - RecordValue &RecordVal = Env.create(Loc); - - Env.setValue(Loc, RecordVal); - - Env.setValue(*S, RecordVal); - // FIXME: Implement array initialization. } diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 595f70f819ddb518d01cf1a3ba2edbc3402cd21c..1b73c5d6830161070d66fa4c76614e4ab90d82a1 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -369,17 +369,10 @@ builtinTransferInitializer(const CFGInitializer &Elt, ParentLoc->setChild(*Member, InitExprLoc); } else if (auto *InitExprVal = Env.getValue(*InitExpr)) { assert(MemberLoc != nullptr); - if (Member->getType()->isRecordType()) { - auto *InitValStruct = cast(InitExprVal); - // FIXME: Rather than performing a copy here, we should really be - // initializing the field in place. This would require us to propagate the - // storage location of the field to the AST node that creates the - // `RecordValue`. - copyRecord(InitValStruct->getLoc(), - *cast(MemberLoc), Env); - } else { + // Record-type initializers construct themselves directly into the result + // object, so there is no need to handle them here. + if (!Member->getType()->isRecordType()) Env.setValue(*MemberLoc, *InitExprVal); - } } } diff --git a/clang/lib/Analysis/ObjCNoReturn.cpp b/clang/lib/Analysis/ObjCNoReturn.cpp index 9d7c365c3b9924d77dbaeb26adba6ddb67e7026d..9e651c29e085da395f424d4f6c12272c69a179c0 100644 --- a/clang/lib/Analysis/ObjCNoReturn.cpp +++ b/clang/lib/Analysis/ObjCNoReturn.cpp @@ -17,7 +17,8 @@ using namespace clang; -static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) { +static bool isSubclass(const ObjCInterfaceDecl *Class, + const IdentifierInfo *II) { if (!Class) return false; if (Class->getIdentifier() == II) @@ -30,7 +31,7 @@ ObjCNoReturn::ObjCNoReturn(ASTContext &C) NSExceptionII(&C.Idents.get("NSException")) { // Generate selectors. - SmallVector II; + SmallVector II; // raise:format: II.push_back(&C.Idents.get("raise")); diff --git a/clang/lib/Analysis/PathDiagnostic.cpp b/clang/lib/Analysis/PathDiagnostic.cpp index 79f337a91ec8fafd581e89d1205e58ad3611e3ac..35472e705cfd8d55ac227733a957b58f33abb69f 100644 --- a/clang/lib/Analysis/PathDiagnostic.cpp +++ b/clang/lib/Analysis/PathDiagnostic.cpp @@ -115,14 +115,17 @@ PathDiagnostic::PathDiagnostic( StringRef CheckerName, const Decl *declWithIssue, StringRef bugtype, StringRef verboseDesc, StringRef shortDesc, StringRef category, PathDiagnosticLocation LocationToUnique, const Decl *DeclToUnique, + const Decl *AnalysisEntryPoint, std::unique_ptr ExecutedLines) : CheckerName(CheckerName), DeclWithIssue(declWithIssue), BugType(StripTrailingDots(bugtype)), VerboseDesc(StripTrailingDots(verboseDesc)), ShortDesc(StripTrailingDots(shortDesc)), Category(StripTrailingDots(category)), UniqueingLoc(LocationToUnique), - UniqueingDecl(DeclToUnique), ExecutedLines(std::move(ExecutedLines)), - path(pathImpl) {} + UniqueingDecl(DeclToUnique), AnalysisEntryPoint(AnalysisEntryPoint), + ExecutedLines(std::move(ExecutedLines)), path(pathImpl) { + assert(AnalysisEntryPoint); +} void PathDiagnosticConsumer::anchor() {} diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp b/clang/lib/Analysis/UnsafeBufferUsage.cpp index e1ff0d92f6b2f87e39be002044d1d372c92e7af5..e03fe1b68300435f41c73ab9e44fdd7a33884a35 100644 --- a/clang/lib/Analysis/UnsafeBufferUsage.cpp +++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp @@ -403,10 +403,11 @@ AST_MATCHER(CXXConstructExpr, isSafeSpanTwoParamConstruct) { QualType Arg0Ty = Arg0->IgnoreImplicit()->getType(); if (Arg0Ty->isConstantArrayType()) { - const APInt &ConstArrSize = cast(Arg0Ty)->getSize(); + const APSInt ConstArrSize = + APSInt(cast(Arg0Ty)->getSize()); // Check form 4: - return Arg1CV && APSInt::compareValues(APSInt(ConstArrSize), *Arg1CV) == 0; + return Arg1CV && APSInt::compareValues(ConstArrSize, *Arg1CV) == 0; } return false; } @@ -429,14 +430,13 @@ AST_MATCHER(ArraySubscriptExpr, isSafeArraySubscript) { BaseDRE->getDecl()->getType()); if (!CATy) return false; - const APInt ArrSize = CATy->getSize(); if (const auto *IdxLit = dyn_cast(Node.getIdx())) { const APInt ArrIdx = IdxLit->getValue(); // FIXME: ArrIdx.isNegative() we could immediately emit an error as that's a // bug if (ArrIdx.isNonNegative() && - ArrIdx.getLimitedValue() < ArrSize.getLimitedValue()) + ArrIdx.getLimitedValue() < CATy->getLimitedSize()) return true; } diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp index a9b07aca65c0529483c43ee5c4b72749a61744ea..feea84544d62fbdb4e20a83671958491ab3824fe 100644 --- a/clang/lib/Basic/IdentifierTable.cpp +++ b/clang/lib/Basic/IdentifierTable.cpp @@ -541,7 +541,8 @@ unsigned Selector::getNumArgs() const { return SI->getNumArgs(); } -IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const { +const IdentifierInfo * +Selector::getIdentifierInfoForSlot(unsigned argIndex) const { if (getIdentifierInfoFlag() < MultiArg) { assert(argIndex == 0 && "illegal keyword index"); return getAsIdentifierInfo(); @@ -553,7 +554,7 @@ IdentifierInfo *Selector::getIdentifierInfoForSlot(unsigned argIndex) const { } StringRef Selector::getNameForSlot(unsigned int argIndex) const { - IdentifierInfo *II = getIdentifierInfoForSlot(argIndex); + const IdentifierInfo *II = getIdentifierInfoForSlot(argIndex); return II ? II->getName() : StringRef(); } @@ -574,7 +575,7 @@ std::string Selector::getAsString() const { return ""; if (getIdentifierInfoFlag() < MultiArg) { - IdentifierInfo *II = getAsIdentifierInfo(); + const IdentifierInfo *II = getAsIdentifierInfo(); if (getNumArgs() == 0) { assert(II && "If the number of arguments is 0 then II is guaranteed to " @@ -608,7 +609,7 @@ static bool startsWithWord(StringRef name, StringRef word) { } ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) { - IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); + const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); if (!first) return OMF_None; StringRef name = first->getName(); @@ -655,7 +656,7 @@ ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) { } ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) { - IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); + const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); if (!first) return OIT_None; StringRef name = first->getName(); @@ -683,7 +684,7 @@ ObjCInstanceTypeFamily Selector::getInstTypeMethodFamily(Selector sel) { } ObjCStringFormatFamily Selector::getStringFormatFamilyImpl(Selector sel) { - IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); + const IdentifierInfo *first = sel.getIdentifierInfoForSlot(0); if (!first) return SFF_None; StringRef name = first->getName(); @@ -750,7 +751,8 @@ size_t SelectorTable::getTotalMemory() const { return SelTabImpl.Allocator.getTotalMemory(); } -Selector SelectorTable::getSelector(unsigned nKeys, IdentifierInfo **IIV) { +Selector SelectorTable::getSelector(unsigned nKeys, + const IdentifierInfo **IIV) { if (nKeys < 2) return Selector(IIV[0], nKeys); diff --git a/clang/lib/Basic/TargetInfo.cpp b/clang/lib/Basic/TargetInfo.cpp index 5d9055174c089ad8d11bdf32e0eb46b952527d82..f96956f31d50dc404a05d7b691aec694ad9c4999 100644 --- a/clang/lib/Basic/TargetInfo.cpp +++ b/clang/lib/Basic/TargetInfo.cpp @@ -157,6 +157,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : Triple(T) { HasAArch64SVETypes = false; HasRISCVVTypes = false; AllowAMDGPUUnsafeFPAtomics = false; + HasUnalignedAccess = false; ARMCDECoprocMask = 0; // Default to no types using fpret. diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 1c3199bd76eed6591574013cdb4f4e7293a626d2..c8d243a8fb7aea25e5c02c308fc62ec5ad17b1c9 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -188,6 +188,8 @@ AArch64TargetInfo::AArch64TargetInfo(const llvm::Triple &Triple, assert(UseBitFieldTypeAlignment && "bitfields affect type alignment"); UseZeroLengthBitfieldAlignment = true; + HasUnalignedAccess = true; + // AArch64 targets default to using the ARM C++ ABI. TheCXXABI.set(TargetCXXABI::GenericAArch64); @@ -496,7 +498,7 @@ void AArch64TargetInfo::getTargetDefines(const LangOptions &Opts, if (HasPAuthLR) Builder.defineMacro("__ARM_FEATURE_PAUTH_LR", "1"); - if (HasUnaligned) + if (HasUnalignedAccess) Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); if ((FPU & NeonMode) && HasFullFP16) @@ -921,7 +923,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector &Features, HasSM4 = true; } if (Feature == "+strict-align") - HasUnaligned = false; + HasUnalignedAccess = false; + // All predecessor archs are added but select the latest one for ArchKind. if (Feature == "+v8a" && ArchInfo->Version < llvm::AArch64::ARMV8A.Version) ArchInfo = &llvm::AArch64::ARMV8A; @@ -1540,10 +1543,13 @@ WindowsARM64TargetInfo::getBuiltinVaListKind() const { TargetInfo::CallingConvCheckResult WindowsARM64TargetInfo::checkCallingConvention(CallingConv CC) const { switch (CC) { + case CC_X86VectorCall: + if (getTriple().isWindowsArm64EC()) + return CCCR_OK; + return CCCR_Ignore; case CC_X86StdCall: case CC_X86ThisCall: case CC_X86FastCall: - case CC_X86VectorCall: return CCCR_Ignore; case CC_C: case CC_OpenCLKernel: diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index 542894c66412dc88b09302fc526aed653678f576..12fb50286f7511a6c5bf461ba3cf041d5f8bda4b 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -38,7 +38,6 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo { bool HasSHA2 = false; bool HasSHA3 = false; bool HasSM4 = false; - bool HasUnaligned = true; bool HasFullFP16 = false; bool HasDotProd = false; bool HasFP16FML = false; diff --git a/clang/lib/Basic/Targets/ARM.cpp b/clang/lib/Basic/Targets/ARM.cpp index 55b71557452fa04db6b60512368d8ab17c45cac0..877799c66ec4f234cb2682d76a1fd40994b09304 100644 --- a/clang/lib/Basic/Targets/ARM.cpp +++ b/clang/lib/Basic/Targets/ARM.cpp @@ -509,7 +509,7 @@ bool ARMTargetInfo::handleTargetFeatures(std::vector &Features, SHA2 = 0; AES = 0; DSP = 0; - Unaligned = 1; + HasUnalignedAccess = true; SoftFloat = false; // Note that SoftFloatABI is initialized in our constructor. HWDiv = 0; @@ -576,7 +576,7 @@ bool ARMTargetInfo::handleTargetFeatures(std::vector &Features, return false; } } else if (Feature == "+strict-align") { - Unaligned = 0; + HasUnalignedAccess = false; } else if (Feature == "+fp16") { HW_FP |= HW_FP_HP; } else if (Feature == "+fullfp16") { @@ -785,7 +785,7 @@ void ARMTargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__ARM_ARCH_PROFILE", "'" + CPUProfile + "'"); // ACLE 6.4.3 Unaligned access supported in hardware - if (Unaligned) + if (HasUnalignedAccess) Builder.defineMacro("__ARM_FEATURE_UNALIGNED", "1"); // ACLE 6.4.4 LDREX/STREX diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h index 71322a094f5edba2cd9a31a433accc1efac54ebf..e69adbe754739f66f6084b252661404bf96b892b 100644 --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -88,8 +88,6 @@ class LLVM_LIBRARY_VISIBILITY ARMTargetInfo : public TargetInfo { LLVM_PREFERRED_TYPE(bool) unsigned DSP : 1; LLVM_PREFERRED_TYPE(bool) - unsigned Unaligned : 1; - LLVM_PREFERRED_TYPE(bool) unsigned DotProd : 1; LLVM_PREFERRED_TYPE(bool) unsigned HasMatMul : 1; diff --git a/clang/lib/Basic/Targets/LoongArch.cpp b/clang/lib/Basic/Targets/LoongArch.cpp index 88537989a05129f553b89ac2e74a444e9472bea0..280bd1d8033cc6ff7de12b5c122632276026e461 100644 --- a/clang/lib/Basic/Targets/LoongArch.cpp +++ b/clang/lib/Basic/Targets/LoongArch.cpp @@ -285,6 +285,8 @@ bool LoongArchTargetInfo::handleTargetFeatures( HasFeatureLSX = true; else if (Feature == "+lasx") HasFeatureLASX = true; + else if (Feature == "-ual") + HasUnalignedAccess = false; } return true; } diff --git a/clang/lib/Basic/Targets/LoongArch.h b/clang/lib/Basic/Targets/LoongArch.h index 3313102492cb8dc41b484c650630d5f451992c8c..68572843f2d7486398361271abda589ab075ca69 100644 --- a/clang/lib/Basic/Targets/LoongArch.h +++ b/clang/lib/Basic/Targets/LoongArch.h @@ -132,6 +132,7 @@ public: : LoongArchTargetInfo(Triple, Opts) { LongWidth = LongAlign = PointerWidth = PointerAlign = 64; IntMaxType = Int64Type = SignedLong; + HasUnalignedAccess = true; resetDataLayout("e-m:e-p:64:64-i64:64-i128:128-n64-S128"); // TODO: select appropriate ABI. setABI("lp64d"); diff --git a/clang/lib/Basic/Targets/M68k.cpp b/clang/lib/Basic/Targets/M68k.cpp index 1b7e0a7f32c9be516415c2d57dbdfe0e12a5a996..8b8bf97d6f99a1b1745e4aee928025d7b0e39877 100644 --- a/clang/lib/Basic/Targets/M68k.cpp +++ b/clang/lib/Basic/Targets/M68k.cpp @@ -127,16 +127,21 @@ bool M68kTargetInfo::hasFeature(StringRef Feature) const { const char *const M68kTargetInfo::GCCRegNames[] = { "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", - "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", + "a0", "a1", "a2", "a3", "a4", "a5", "a6", "sp", "pc"}; ArrayRef M68kTargetInfo::getGCCRegNames() const { return llvm::ArrayRef(GCCRegNames); } +const TargetInfo::GCCRegAlias M68kTargetInfo::GCCRegAliases[] = { + {{"bp"}, "a5"}, + {{"fp"}, "a6"}, + {{"usp", "ssp", "isp", "a7"}, "sp"}, +}; + ArrayRef M68kTargetInfo::getGCCRegAliases() const { - // No aliases. - return std::nullopt; + return llvm::ArrayRef(GCCRegAliases); } bool M68kTargetInfo::validateAsmConstraint( diff --git a/clang/lib/Basic/Targets/M68k.h b/clang/lib/Basic/Targets/M68k.h index a9c262e62fbad0bf37b2dd728edb896560361e3e..7ffa901127e504046908f0ce659a2b0bc4d2c89c 100644 --- a/clang/lib/Basic/Targets/M68k.h +++ b/clang/lib/Basic/Targets/M68k.h @@ -25,6 +25,7 @@ namespace targets { class LLVM_LIBRARY_VISIBILITY M68kTargetInfo : public TargetInfo { static const char *const GCCRegNames[]; + static const TargetInfo::GCCRegAlias GCCRegAliases[]; enum CPUKind { CK_Unknown, diff --git a/clang/lib/Basic/Targets/Mips.h b/clang/lib/Basic/Targets/Mips.h index 23d4e1b598fa1e44d470cea120c016a82a954431..0d6e4b4d0808906ba38020878c7e952ee1cf3346 100644 --- a/clang/lib/Basic/Targets/Mips.h +++ b/clang/lib/Basic/Targets/Mips.h @@ -318,6 +318,7 @@ public: FPMode = isFP64Default() ? FP64 : FPXX; NoOddSpreg = false; bool OddSpregGiven = false; + bool StrictAlign = false; for (const auto &Feature : Features) { if (Feature == "+single-float") @@ -328,6 +329,12 @@ public: IsMips16 = true; else if (Feature == "+micromips") IsMicromips = true; + else if (Feature == "+mips32r6" || Feature == "+mips64r6") + HasUnalignedAccess = true; + // We cannot be sure that the order of strict-align vs mips32r6. + // Thus we need an extra variable here. + else if (Feature == "+strict-align") + StrictAlign = true; else if (Feature == "+dsp") DspRev = std::max(DspRev, DSP1); else if (Feature == "+dspr2") @@ -366,6 +373,9 @@ public: if (FPMode == FPXX && !OddSpregGiven) NoOddSpreg = true; + if (StrictAlign) + HasUnalignedAccess = false; + setDataLayout(); return true; diff --git a/clang/lib/Basic/Targets/PPC.h b/clang/lib/Basic/Targets/PPC.h index 70683916a8b04f6616eb363c6c5f0501909bad4b..fa2f442e25846de4ed0386e543a8613a213120b2 100644 --- a/clang/lib/Basic/Targets/PPC.h +++ b/clang/lib/Basic/Targets/PPC.h @@ -92,6 +92,7 @@ public: LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble(); HasStrictFP = true; HasIbm128 = true; + HasUnalignedAccess = true; } // Set the language option for altivec based on our value. diff --git a/clang/lib/Basic/Targets/RISCV.cpp b/clang/lib/Basic/Targets/RISCV.cpp index a6d4af2b88111a4821b7292d3eacb3c1eafab6b5..f3d705e1551fe29fca69fcb610b9bc15d7ee3b24 100644 --- a/clang/lib/Basic/Targets/RISCV.cpp +++ b/clang/lib/Basic/Targets/RISCV.cpp @@ -467,3 +467,14 @@ ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const { } return Ret; } + +TargetInfo::CallingConvCheckResult +RISCVTargetInfo::checkCallingConvention(CallingConv CC) const { + switch (CC) { + default: + return CCCR_Warning; + case CC_C: + case CC_RISCVVectorCall: + return CCCR_OK; + } +} diff --git a/clang/lib/Basic/Targets/RISCV.h b/clang/lib/Basic/Targets/RISCV.h index bfbdafb682c851333d8371de12436f9dfaed278c..78580b5b1c1063cd5f39f44ca20dbafff121818a 100644 --- a/clang/lib/Basic/Targets/RISCV.h +++ b/clang/lib/Basic/Targets/RISCV.h @@ -110,6 +110,8 @@ public: bool hasBFloat16Type() const override { return true; } + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override; + bool useFP16ConversionIntrinsics() const override { return false; } diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h index 3e08b27972fa3966df5d5e5ffa83c21460b6773c..8e302acd51b8ad1d40e175e65c3e5ab7a2895dc6 100644 --- a/clang/lib/Basic/Targets/SystemZ.h +++ b/clang/lib/Basic/Targets/SystemZ.h @@ -47,6 +47,7 @@ public: LongDoubleFormat = &llvm::APFloat::IEEEquad(); DefaultAlignForAttributeAligned = 64; MinGlobalAlign = 16; + HasUnalignedAccess = true; if (Triple.isOSzOS()) { TLSSupported = false; // All vector types are default aligned on an 8-byte boundary, even if the diff --git a/clang/lib/Basic/Targets/VE.h b/clang/lib/Basic/Targets/VE.h index ea9a092cad80908539d279402458f93a9b06b45b..7e8fdf6096ef232c2212f883db2eb36309d6b3db 100644 --- a/clang/lib/Basic/Targets/VE.h +++ b/clang/lib/Basic/Targets/VE.h @@ -40,6 +40,7 @@ public: Int64Type = SignedLong; RegParmMax = 8; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 64; + HasUnalignedAccess = true; WCharType = UnsignedInt; WIntType = UnsignedInt; diff --git a/clang/lib/Basic/Targets/WebAssembly.h b/clang/lib/Basic/Targets/WebAssembly.h index 83b1711f9fdf6a8ce8632913b7666d348c6b4550..5568aa28eaefa7152637b70f4343937676f2a3d4 100644 --- a/clang/lib/Basic/Targets/WebAssembly.h +++ b/clang/lib/Basic/Targets/WebAssembly.h @@ -84,6 +84,7 @@ public: SizeType = UnsignedLong; PtrDiffType = SignedLong; IntPtrType = SignedLong; + HasUnalignedAccess = true; } StringRef getABI() const override; diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 1966af17904d65c98f923558bf15007ba75533b9..bf1767c87fe1cec99a985636108bfcd49152dcff 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -954,6 +954,9 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts, Builder.defineMacro("__CCMP__"); if (HasCF) Builder.defineMacro("__CF__"); + // Condition here is aligned with the feature set of mapxf in Options.td + if (HasEGPR && HasPush2Pop2 && HasPPX && HasNDD) + Builder.defineMacro("__APX_F__"); // Each case falls through to the previous one here. switch (SSELevel) { diff --git a/clang/lib/Basic/Targets/X86.h b/clang/lib/Basic/Targets/X86.h index d2232c7d5275abf47a4955b5e30c1ae36f5ad584..c14e4d5f433d8244f3a45e9752a6d19cd7bd2aac 100644 --- a/clang/lib/Basic/Targets/X86.h +++ b/clang/lib/Basic/Targets/X86.h @@ -188,6 +188,7 @@ public: LongDoubleFormat = &llvm::APFloat::x87DoubleExtended(); AddrSpaceMap = &X86AddrSpaceMap; HasStrictFP = true; + HasUnalignedAccess = true; bool IsWinCOFF = getTriple().isOSWindows() && getTriple().isOSBinFormatCOFF(); diff --git a/clang/lib/CodeGen/ABIInfo.cpp b/clang/lib/CodeGen/ABIInfo.cpp index efcff958ce545223d11932243f1fd7d8a9f3e2e0..acaae9f8c3d8437c840012a438978ee09f3507a5 100644 --- a/clang/lib/CodeGen/ABIInfo.cpp +++ b/clang/lib/CodeGen/ABIInfo.cpp @@ -61,7 +61,7 @@ bool ABIInfo::isZeroLengthBitfieldPermittedInHomogeneousAggregate() const { bool ABIInfo::isHomogeneousAggregate(QualType Ty, const Type *&Base, uint64_t &Members) const { if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) { - uint64_t NElements = AT->getSize().getZExtValue(); + uint64_t NElements = AT->getZExtSize(); if (NElements == 0) return false; if (!isHomogeneousAggregate(AT->getElementType(), Base, Members)) @@ -98,7 +98,7 @@ bool ABIInfo::isHomogeneousAggregate(QualType Ty, const Type *&Base, QualType FT = FD->getType(); while (const ConstantArrayType *AT = getContext().getAsConstantArrayType(FT)) { - if (AT->getSize().getZExtValue() == 0) + if (AT->isZeroSize()) return false; FT = AT->getElementType(); } diff --git a/clang/lib/CodeGen/ABIInfoImpl.cpp b/clang/lib/CodeGen/ABIInfoImpl.cpp index 2b20d5a13346d3414430268ef53dc8e0dcbf8972..3e34d82cb399ba05f880cc7fd470cfac0af08a8d 100644 --- a/clang/lib/CodeGen/ABIInfoImpl.cpp +++ b/clang/lib/CodeGen/ABIInfoImpl.cpp @@ -187,7 +187,7 @@ CodeGen::emitVoidPtrDirectVAArg(CodeGenFunction &CGF, Address VAListAddr, CharUnits FullDirectSize = DirectSize.alignTo(SlotSize); Address NextPtr = CGF.Builder.CreateConstInBoundsByteGEP(Addr, FullDirectSize, "argp.next"); - CGF.Builder.CreateStore(NextPtr.getPointer(), VAListAddr); + CGF.Builder.CreateStore(NextPtr.emitRawPointer(CGF), VAListAddr); // If the argument is smaller than a slot, and this is a big-endian // target, the argument will be right-adjusted in its slot. @@ -239,8 +239,8 @@ Address CodeGen::emitMergePHI(CodeGenFunction &CGF, Address Addr1, const llvm::Twine &Name) { assert(Addr1.getType() == Addr2.getType()); llvm::PHINode *PHI = CGF.Builder.CreatePHI(Addr1.getType(), 2, Name); - PHI->addIncoming(Addr1.getPointer(), Block1); - PHI->addIncoming(Addr2.getPointer(), Block2); + PHI->addIncoming(Addr1.emitRawPointer(CGF), Block1); + PHI->addIncoming(Addr2.emitRawPointer(CGF), Block2); CharUnits Align = std::min(Addr1.getAlignment(), Addr2.getAlignment()); return Address(PHI, Addr1.getElementType(), Align); } @@ -257,7 +257,7 @@ bool CodeGen::isEmptyField(ASTContext &Context, const FieldDecl *FD, bool WasArray = false; if (AllowArrays) while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) { - if (AT->getSize() == 0) + if (AT->isZeroSize()) return true; FT = AT->getElementType(); // The [[no_unique_address]] special case below does not apply to @@ -352,7 +352,7 @@ const Type *CodeGen::isSingleElementStruct(QualType T, ASTContext &Context) { // Treat single element arrays as the element. while (const ConstantArrayType *AT = Context.getAsConstantArrayType(FT)) { - if (AT->getSize().getZExtValue() != 1) + if (AT->getZExtSize() != 1) break; FT = AT->getElementType(); } @@ -400,7 +400,7 @@ Address CodeGen::EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr, llvm::Type *ElementTy = CGF.ConvertTypeForMem(Ty); llvm::Type *BaseTy = llvm::PointerType::getUnqual(ElementTy); llvm::Value *Addr = - CGF.Builder.CreateVAArg(VAListAddr.getPointer(), BaseTy); + CGF.Builder.CreateVAArg(VAListAddr.emitRawPointer(CGF), BaseTy); return Address(Addr, ElementTy, TyAlignForABI); } else { assert((AI.isDirect() || AI.isExtend()) && @@ -416,7 +416,7 @@ Address CodeGen::EmitVAArgInstr(CodeGenFunction &CGF, Address VAListAddr, "Unexpected CoerceToType seen in arginfo in generic VAArg emitter!"); Address Temp = CGF.CreateMemTemp(Ty, "varet"); - Val = CGF.Builder.CreateVAArg(VAListAddr.getPointer(), + Val = CGF.Builder.CreateVAArg(VAListAddr.emitRawPointer(CGF), CGF.ConvertTypeForMem(Ty)); CGF.Builder.CreateStore(Val, Temp); return Temp; diff --git a/clang/lib/CodeGen/Address.h b/clang/lib/CodeGen/Address.h index cf48df8f5e7367e0c3737f837b83cd057dc07142..35ec370a139c92efc4686eac311947d74952a270 100644 --- a/clang/lib/CodeGen/Address.h +++ b/clang/lib/CodeGen/Address.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_LIB_CODEGEN_ADDRESS_H #include "clang/AST/CharUnits.h" +#include "clang/AST/Type.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/IR/Constants.h" #include "llvm/Support/MathExtras.h" @@ -22,28 +23,41 @@ namespace clang { namespace CodeGen { +class Address; +class CGBuilderTy; +class CodeGenFunction; +class CodeGenModule; + // Indicates whether a pointer is known not to be null. enum KnownNonNull_t { NotKnownNonNull, KnownNonNull }; -/// An aligned address. -class Address { +/// An abstract representation of an aligned address. This is designed to be an +/// IR-level abstraction, carrying just the information necessary to perform IR +/// operations on an address like loads and stores. In particular, it doesn't +/// carry C type information or allow the representation of things like +/// bit-fields; clients working at that level should generally be using +/// `LValue`. +/// The pointer contained in this class is known to be unsigned. +class RawAddress { llvm::PointerIntPair PointerAndKnownNonNull; llvm::Type *ElementType; CharUnits Alignment; protected: - Address(std::nullptr_t) : ElementType(nullptr) {} + RawAddress(std::nullptr_t) : ElementType(nullptr) {} public: - Address(llvm::Value *Pointer, llvm::Type *ElementType, CharUnits Alignment, - KnownNonNull_t IsKnownNonNull = NotKnownNonNull) + RawAddress(llvm::Value *Pointer, llvm::Type *ElementType, CharUnits Alignment, + KnownNonNull_t IsKnownNonNull = NotKnownNonNull) : PointerAndKnownNonNull(Pointer, IsKnownNonNull), ElementType(ElementType), Alignment(Alignment) { assert(Pointer != nullptr && "Pointer cannot be null"); assert(ElementType != nullptr && "Element type cannot be null"); } - static Address invalid() { return Address(nullptr); } + inline RawAddress(Address Addr); + + static RawAddress invalid() { return RawAddress(nullptr); } bool isValid() const { return PointerAndKnownNonNull.getPointer() != nullptr; } @@ -80,6 +94,133 @@ public: return Alignment; } + /// Return address with different element type, but same pointer and + /// alignment. + RawAddress withElementType(llvm::Type *ElemTy) const { + return RawAddress(getPointer(), ElemTy, getAlignment(), isKnownNonNull()); + } + + KnownNonNull_t isKnownNonNull() const { + assert(isValid()); + return (KnownNonNull_t)PointerAndKnownNonNull.getInt(); + } +}; + +/// Like RawAddress, an abstract representation of an aligned address, but the +/// pointer contained in this class is possibly signed. +class Address { + friend class CGBuilderTy; + + // The boolean flag indicates whether the pointer is known to be non-null. + llvm::PointerIntPair Pointer; + + /// The expected IR type of the pointer. Carrying accurate element type + /// information in Address makes it more convenient to work with Address + /// values and allows frontend assertions to catch simple mistakes. + llvm::Type *ElementType = nullptr; + + CharUnits Alignment; + + /// Offset from the base pointer. + llvm::Value *Offset = nullptr; + + llvm::Value *emitRawPointerSlow(CodeGenFunction &CGF) const; + +protected: + Address(std::nullptr_t) : ElementType(nullptr) {} + +public: + Address(llvm::Value *pointer, llvm::Type *elementType, CharUnits alignment, + KnownNonNull_t IsKnownNonNull = NotKnownNonNull) + : Pointer(pointer, IsKnownNonNull), ElementType(elementType), + Alignment(alignment) { + assert(pointer != nullptr && "Pointer cannot be null"); + assert(elementType != nullptr && "Element type cannot be null"); + assert(!alignment.isZero() && "Alignment cannot be zero"); + } + + Address(llvm::Value *BasePtr, llvm::Type *ElementType, CharUnits Alignment, + llvm::Value *Offset, KnownNonNull_t IsKnownNonNull = NotKnownNonNull) + : Pointer(BasePtr, IsKnownNonNull), ElementType(ElementType), + Alignment(Alignment), Offset(Offset) {} + + Address(RawAddress RawAddr) + : Pointer(RawAddr.isValid() ? RawAddr.getPointer() : nullptr), + ElementType(RawAddr.isValid() ? RawAddr.getElementType() : nullptr), + Alignment(RawAddr.isValid() ? RawAddr.getAlignment() + : CharUnits::Zero()) {} + + static Address invalid() { return Address(nullptr); } + bool isValid() const { return Pointer.getPointer() != nullptr; } + + /// This function is used in situations where the caller is doing some sort of + /// opaque "laundering" of the pointer. + void replaceBasePointer(llvm::Value *P) { + assert(isValid() && "pointer isn't valid"); + assert(P->getType() == Pointer.getPointer()->getType() && + "Pointer's type changed"); + Pointer.setPointer(P); + assert(isValid() && "pointer is invalid after replacement"); + } + + CharUnits getAlignment() const { return Alignment; } + + void setAlignment(CharUnits Value) { Alignment = Value; } + + llvm::Value *getBasePointer() const { + assert(isValid() && "pointer isn't valid"); + return Pointer.getPointer(); + } + + /// Return the type of the pointer value. + llvm::PointerType *getType() const { + return llvm::PointerType::get( + ElementType, + llvm::cast(Pointer.getPointer()->getType()) + ->getAddressSpace()); + } + + /// Return the type of the values stored in this address. + llvm::Type *getElementType() const { + assert(isValid()); + return ElementType; + } + + /// Return the address space that this address resides in. + unsigned getAddressSpace() const { return getType()->getAddressSpace(); } + + /// Return the IR name of the pointer value. + llvm::StringRef getName() const { return Pointer.getPointer()->getName(); } + + // This function is called only in CGBuilderBaseTy::CreateElementBitCast. + void setElementType(llvm::Type *Ty) { + assert(hasOffset() && + "this funcion shouldn't be called when there is no offset"); + ElementType = Ty; + } + + /// Whether the pointer is known not to be null. + KnownNonNull_t isKnownNonNull() const { + assert(isValid()); + return (KnownNonNull_t)Pointer.getInt(); + } + + Address setKnownNonNull() { + assert(isValid()); + Pointer.setInt(KnownNonNull); + return *this; + } + + bool hasOffset() const { return Offset; } + + llvm::Value *getOffset() const { return Offset; } + + /// Return the pointer contained in this class after authenticating it and + /// adding offset to it if necessary. + llvm::Value *emitRawPointer(CodeGenFunction &CGF) const { + return getBasePointer(); + } + /// Return address with different pointer, but same element type and /// alignment. Address withPointer(llvm::Value *NewPointer, @@ -91,61 +232,59 @@ public: /// Return address with different alignment, but same pointer and element /// type. Address withAlignment(CharUnits NewAlignment) const { - return Address(getPointer(), getElementType(), NewAlignment, + return Address(Pointer.getPointer(), getElementType(), NewAlignment, isKnownNonNull()); } /// Return address with different element type, but same pointer and /// alignment. Address withElementType(llvm::Type *ElemTy) const { - return Address(getPointer(), ElemTy, getAlignment(), isKnownNonNull()); - } - - /// Whether the pointer is known not to be null. - KnownNonNull_t isKnownNonNull() const { - assert(isValid()); - return (KnownNonNull_t)PointerAndKnownNonNull.getInt(); - } - - /// Set the non-null bit. - Address setKnownNonNull() { - assert(isValid()); - PointerAndKnownNonNull.setInt(true); - return *this; + if (!hasOffset()) + return Address(getBasePointer(), ElemTy, getAlignment(), nullptr, + isKnownNonNull()); + Address A(*this); + A.ElementType = ElemTy; + return A; } }; +inline RawAddress::RawAddress(Address Addr) + : PointerAndKnownNonNull(Addr.isValid() ? Addr.getBasePointer() : nullptr, + Addr.isValid() ? Addr.isKnownNonNull() + : NotKnownNonNull), + ElementType(Addr.isValid() ? Addr.getElementType() : nullptr), + Alignment(Addr.isValid() ? Addr.getAlignment() : CharUnits::Zero()) {} + /// A specialization of Address that requires the address to be an /// LLVM Constant. -class ConstantAddress : public Address { - ConstantAddress(std::nullptr_t) : Address(nullptr) {} +class ConstantAddress : public RawAddress { + ConstantAddress(std::nullptr_t) : RawAddress(nullptr) {} public: ConstantAddress(llvm::Constant *pointer, llvm::Type *elementType, CharUnits alignment) - : Address(pointer, elementType, alignment) {} + : RawAddress(pointer, elementType, alignment) {} static ConstantAddress invalid() { return ConstantAddress(nullptr); } llvm::Constant *getPointer() const { - return llvm::cast(Address::getPointer()); + return llvm::cast(RawAddress::getPointer()); } ConstantAddress withElementType(llvm::Type *ElemTy) const { return ConstantAddress(getPointer(), ElemTy, getAlignment()); } - static bool isaImpl(Address addr) { + static bool isaImpl(RawAddress addr) { return llvm::isa(addr.getPointer()); } - static ConstantAddress castImpl(Address addr) { + static ConstantAddress castImpl(RawAddress addr) { return ConstantAddress(llvm::cast(addr.getPointer()), addr.getElementType(), addr.getAlignment()); } }; - } // Present a minimal LLVM-like casting interface. diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index 82b30b8d815629d367a9282abf1b4b3be99cce63..6cc00b85664f411f860d40d10d049ce99a37a8cb 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -73,10 +73,10 @@ #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h" #include "llvm/Transforms/Instrumentation/InstrProfiling.h" #include "llvm/Transforms/Instrumentation/KCFI.h" +#include "llvm/Transforms/Instrumentation/LowerAllowCheckPass.h" #include "llvm/Transforms/Instrumentation/MemProfiler.h" #include "llvm/Transforms/Instrumentation/MemorySanitizer.h" #include "llvm/Transforms/Instrumentation/PGOInstrumentation.h" -#include "llvm/Transforms/Instrumentation/RemoveTrapsPass.h" #include "llvm/Transforms/Instrumentation/SanitizerBinaryMetadata.h" #include "llvm/Transforms/Instrumentation/SanitizerCoverage.h" #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" @@ -84,7 +84,6 @@ #include "llvm/Transforms/Scalar/EarlyCSE.h" #include "llvm/Transforms/Scalar/GVN.h" #include "llvm/Transforms/Scalar/JumpThreading.h" -#include "llvm/Transforms/Scalar/SimplifyCFG.h" #include "llvm/Transforms/Utils/Debugify.h" #include "llvm/Transforms/Utils/EntryExitInstrumenter.h" #include "llvm/Transforms/Utils/ModuleUtils.h" @@ -100,21 +99,17 @@ using namespace llvm; namespace llvm { extern cl::opt PrintPipelinePasses; -cl::opt ClRemoveTraps("clang-remove-traps", cl::Optional, - cl::desc("Insert remove-traps pass."), - cl::init(false)); - // Experiment to move sanitizers earlier. static cl::opt ClSanitizeOnOptimizerEarlyEP( "sanitizer-early-opt-ep", cl::Optional, - cl::desc("Insert sanitizers on OptimizerEarlyEP."), cl::init(false)); + cl::desc("Insert sanitizers on OptimizerEarlyEP.")); extern cl::opt ProfileCorrelate; // Re-link builtin bitcodes after optimization cl::opt ClRelinkBuiltinBitcodePostop( "relink-builtin-bitcode-postop", cl::Optional, - cl::desc("Re-link builtin bitcodes after optimization."), cl::init(false)); + cl::desc("Re-link builtin bitcodes after optimization.")); } // namespace llvm namespace { @@ -751,18 +746,13 @@ static void addSanitizers(const Triple &TargetTriple, PB.registerOptimizerLastEPCallback(SanitizersCallback); } - if (ClRemoveTraps) { + if (LowerAllowCheckPass::IsRequested()) { // We can optimize after inliner, and PGO profile matching. The hook below // is called at the end `buildFunctionSimplificationPipeline`, which called // from `buildInlinerPipeline`, which called after profile matching. PB.registerScalarOptimizerLateEPCallback( [](FunctionPassManager &FPM, OptimizationLevel Level) { - // RemoveTrapsPass expects trap blocks preceded by conditional - // branches, which usually is not the case without SimplifyCFG. - // TODO: Remove `SimplifyCFGPass` after switching to dedicated - // intrinsic. - FPM.addPass(SimplifyCFGPass()); - FPM.addPass(RemoveTrapsPass()); + FPM.addPass(LowerAllowCheckPass()); }); } } diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp index fb03d013e8afc7ba7c9e952eadabd44ae9e005a9..d35ce0409d723258cd82ec955071efa6d850921e 100644 --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -80,7 +80,7 @@ namespace { AtomicSizeInBits = C.toBits( C.toCharUnitsFromBits(Offset + OrigBFI.Size + C.getCharWidth() - 1) .alignTo(lvalue.getAlignment())); - llvm::Value *BitFieldPtr = lvalue.getBitFieldPointer(); + llvm::Value *BitFieldPtr = lvalue.getRawBitFieldPointer(CGF); auto OffsetInChars = (C.toCharUnitsFromBits(OrigBFI.Offset) / lvalue.getAlignment()) * lvalue.getAlignment(); @@ -139,13 +139,13 @@ namespace { const LValue &getAtomicLValue() const { return LVal; } llvm::Value *getAtomicPointer() const { if (LVal.isSimple()) - return LVal.getPointer(CGF); + return LVal.emitRawPointer(CGF); else if (LVal.isBitField()) - return LVal.getBitFieldPointer(); + return LVal.getRawBitFieldPointer(CGF); else if (LVal.isVectorElt()) - return LVal.getVectorPointer(); + return LVal.getRawVectorPointer(CGF); assert(LVal.isExtVectorElt()); - return LVal.getExtVectorPointer(); + return LVal.getRawExtVectorPointer(CGF); } Address getAtomicAddress() const { llvm::Type *ElTy; @@ -197,11 +197,11 @@ namespace { llvm::Value *getScalarRValValueOrNull(RValue RVal) const; /// Converts an rvalue to integer value if needed. - llvm::Value *convertRValueToInt(RValue RVal, bool CastFP = true) const; + llvm::Value *convertRValueToInt(RValue RVal, bool CmpXchg = false) const; RValue ConvertToValueOrAtomic(llvm::Value *IntVal, AggValueSlot ResultSlot, SourceLocation Loc, bool AsValue, - bool CastFP = true) const; + bool CmpXchg = false) const; /// Copy an atomic r-value into atomic-layout memory. void emitCopyIntoMemory(RValue rvalue) const; @@ -264,7 +264,7 @@ namespace { llvm::AtomicOrdering AO, bool IsVolatile); /// Emits atomic load as LLVM instruction. llvm::Value *EmitAtomicLoadOp(llvm::AtomicOrdering AO, bool IsVolatile, - bool CastFP = true); + bool CmpXchg = false); /// Emits atomic compare-and-exchange op as a libcall. llvm::Value *EmitAtomicCompareExchangeLibcall( llvm::Value *ExpectedAddr, llvm::Value *DesiredAddr, @@ -368,7 +368,7 @@ bool AtomicInfo::emitMemSetZeroIfNecessary() const { return false; CGF.Builder.CreateMemSet( - addr.getPointer(), llvm::ConstantInt::get(CGF.Int8Ty, 0), + addr.emitRawPointer(CGF), llvm::ConstantInt::get(CGF.Int8Ty, 0), CGF.getContext().toCharUnitsFromBits(AtomicSizeInBits).getQuantity(), LVal.getAlignment().getAsAlign()); return true; @@ -1055,7 +1055,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { return getTargetHooks().performAddrSpaceCast( *this, V, AS, LangAS::opencl_generic, DestType, false); }; - Args.add(RValue::get(CastToGenericAddrSpace(Ptr.getPointer(), + + Args.add(RValue::get(CastToGenericAddrSpace(Ptr.emitRawPointer(*this), E->getPtr()->getType())), getContext().VoidPtrTy); @@ -1086,10 +1087,10 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { LibCallName = "__atomic_compare_exchange"; RetTy = getContext().BoolTy; HaveRetTy = true; - Args.add(RValue::get(CastToGenericAddrSpace(Val1.getPointer(), + Args.add(RValue::get(CastToGenericAddrSpace(Val1.emitRawPointer(*this), E->getVal1()->getType())), getContext().VoidPtrTy); - Args.add(RValue::get(CastToGenericAddrSpace(Val2.getPointer(), + Args.add(RValue::get(CastToGenericAddrSpace(Val2.emitRawPointer(*this), E->getVal2()->getType())), getContext().VoidPtrTy); Args.add(RValue::get(Order), getContext().IntTy); @@ -1105,7 +1106,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__scoped_atomic_exchange: case AtomicExpr::AO__scoped_atomic_exchange_n: LibCallName = "__atomic_exchange"; - Args.add(RValue::get(CastToGenericAddrSpace(Val1.getPointer(), + Args.add(RValue::get(CastToGenericAddrSpace(Val1.emitRawPointer(*this), E->getVal1()->getType())), getContext().VoidPtrTy); break; @@ -1120,7 +1121,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { LibCallName = "__atomic_store"; RetTy = getContext().VoidTy; HaveRetTy = true; - Args.add(RValue::get(CastToGenericAddrSpace(Val1.getPointer(), + Args.add(RValue::get(CastToGenericAddrSpace(Val1.emitRawPointer(*this), E->getVal1()->getType())), getContext().VoidPtrTy); break; @@ -1199,7 +1200,8 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { if (!HaveRetTy) { // Value is returned through parameter before the order. RetTy = getContext().VoidTy; - Args.add(RValue::get(CastToGenericAddrSpace(Dest.getPointer(), RetTy)), + Args.add(RValue::get( + CastToGenericAddrSpace(Dest.emitRawPointer(*this), RetTy)), getContext().VoidPtrTy); } // Order is always the last parameter. @@ -1399,13 +1401,26 @@ RValue AtomicInfo::convertAtomicTempToRValue(Address addr, LVal.getBaseInfo(), TBAAAccessInfo())); } +/// Return true if \param ValTy is a type that should be casted to integer +/// around the atomic memory operation. If \param CmpXchg is true, then the +/// cast of a floating point type is made as that instruction can not have +/// floating point operands. TODO: Allow compare-and-exchange and FP - see +/// comment in AtomicExpandPass.cpp. +static bool shouldCastToInt(llvm::Type *ValTy, bool CmpXchg) { + if (ValTy->isFloatingPointTy()) + return ValTy->isX86_FP80Ty() || CmpXchg; + return !ValTy->isIntegerTy() && !ValTy->isPointerTy(); +} + RValue AtomicInfo::ConvertToValueOrAtomic(llvm::Value *Val, AggValueSlot ResultSlot, SourceLocation Loc, bool AsValue, - bool CastFP) const { + bool CmpXchg) const { // Try not to in some easy cases. - assert((Val->getType()->isIntegerTy() || Val->getType()->isIEEELikeFPTy()) && - "Expected integer or floating point value"); + assert((Val->getType()->isIntegerTy() || Val->getType()->isPointerTy() || + Val->getType()->isIEEELikeFPTy()) && + "Expected integer, pointer or floating point value when converting " + "result."); if (getEvaluationKind() == TEK_Scalar && (((!LVal.isBitField() || LVal.getBitFieldInfo().Size == ValueSizeInBits) && @@ -1414,13 +1429,12 @@ RValue AtomicInfo::ConvertToValueOrAtomic(llvm::Value *Val, auto *ValTy = AsValue ? CGF.ConvertTypeForMem(ValueTy) : getAtomicAddress().getElementType(); - if (ValTy->isIntegerTy() || (!CastFP && ValTy->isIEEELikeFPTy())) { + if (!shouldCastToInt(ValTy, CmpXchg)) { assert((!ValTy->isIntegerTy() || Val->getType() == ValTy) && "Different integer types."); return RValue::get(CGF.EmitFromMemory(Val, ValueTy)); - } else if (ValTy->isPointerTy()) - return RValue::get(CGF.Builder.CreateIntToPtr(Val, ValTy)); - else if (llvm::CastInst::isBitCastable(Val->getType(), ValTy)) + } + if (llvm::CastInst::isBitCastable(Val->getType(), ValTy)) return RValue::get(CGF.Builder.CreateBitCast(Val, ValTy)); } @@ -1457,10 +1471,10 @@ void AtomicInfo::EmitAtomicLoadLibcall(llvm::Value *AddForLoaded, } llvm::Value *AtomicInfo::EmitAtomicLoadOp(llvm::AtomicOrdering AO, - bool IsVolatile, bool CastFP) { + bool IsVolatile, bool CmpXchg) { // Okay, we're doing this natively. Address Addr = getAtomicAddress(); - if (!(Addr.getElementType()->isIEEELikeFPTy() && !CastFP)) + if (shouldCastToInt(Addr.getElementType(), CmpXchg)) Addr = castToAtomicIntPointer(Addr); llvm::LoadInst *Load = CGF.Builder.CreateLoad(Addr, "atomic-load"); Load->setAtomic(AO); @@ -1513,7 +1527,7 @@ RValue AtomicInfo::EmitAtomicLoad(AggValueSlot ResultSlot, SourceLocation Loc, } else TempAddr = CreateTempAlloca(); - EmitAtomicLoadLibcall(TempAddr.getPointer(), AO, IsVolatile); + EmitAtomicLoadLibcall(TempAddr.emitRawPointer(CGF), AO, IsVolatile); // Okay, turn that back into the original value or whole atomic (for // non-simple lvalues) type. @@ -1521,7 +1535,7 @@ RValue AtomicInfo::EmitAtomicLoad(AggValueSlot ResultSlot, SourceLocation Loc, } // Okay, we're doing this natively. - auto *Load = EmitAtomicLoadOp(AO, IsVolatile, /*CastFP=*/false); + auto *Load = EmitAtomicLoadOp(AO, IsVolatile); // If we're ignoring an aggregate return, don't do anything. if (getEvaluationKind() == TEK_Aggregate && ResultSlot.isIgnored()) @@ -1529,8 +1543,7 @@ RValue AtomicInfo::EmitAtomicLoad(AggValueSlot ResultSlot, SourceLocation Loc, // Okay, turn that back into the original value or atomic (for non-simple // lvalues) type. - return ConvertToValueOrAtomic(Load, ResultSlot, Loc, AsValue, - /*CastFP=*/false); + return ConvertToValueOrAtomic(Load, ResultSlot, Loc, AsValue); } /// Emit a load from an l-value of atomic type. Note that the r-value @@ -1599,20 +1612,17 @@ llvm::Value *AtomicInfo::getScalarRValValueOrNull(RValue RVal) const { return nullptr; } -llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal, bool CastFP) const { +llvm::Value *AtomicInfo::convertRValueToInt(RValue RVal, bool CmpXchg) const { // If we've got a scalar value of the right size, try to avoid going // through memory. Floats get casted if needed by AtomicExpandPass. if (llvm::Value *Value = getScalarRValValueOrNull(RVal)) { - if (isa(Value->getType()) || - (!CastFP && Value->getType()->isIEEELikeFPTy())) + if (!shouldCastToInt(Value->getType(), CmpXchg)) return CGF.EmitToMemory(Value, ValueTy); else { llvm::IntegerType *InputIntTy = llvm::IntegerType::get( CGF.getLLVMContext(), LVal.isSimple() ? getValueSizeInBits() : getAtomicSizeInBits()); - if (isa(Value->getType())) - return CGF.Builder.CreatePtrToInt(Value, InputIntTy); - else if (llvm::BitCastInst::isBitCastable(Value->getType(), InputIntTy)) + if (llvm::BitCastInst::isBitCastable(Value->getType(), InputIntTy)) return CGF.Builder.CreateBitCast(Value, InputIntTy); } } @@ -1673,9 +1683,9 @@ std::pair AtomicInfo::EmitAtomicCompareExchange( if (shouldUseLibcall()) { // Produce a source address. Address ExpectedAddr = materializeRValue(Expected); - Address DesiredAddr = materializeRValue(Desired); - auto *Res = EmitAtomicCompareExchangeLibcall(ExpectedAddr.getPointer(), - DesiredAddr.getPointer(), + llvm::Value *ExpectedPtr = ExpectedAddr.emitRawPointer(CGF); + llvm::Value *DesiredPtr = materializeRValue(Desired).emitRawPointer(CGF); + auto *Res = EmitAtomicCompareExchangeLibcall(ExpectedPtr, DesiredPtr, Success, Failure); return std::make_pair( convertAtomicTempToRValue(ExpectedAddr, AggValueSlot::ignored(), @@ -1685,13 +1695,14 @@ std::pair AtomicInfo::EmitAtomicCompareExchange( // If we've got a scalar value of the right size, try to avoid going // through memory. - auto *ExpectedVal = convertRValueToInt(Expected); - auto *DesiredVal = convertRValueToInt(Desired); + auto *ExpectedVal = convertRValueToInt(Expected, /*CmpXchg=*/true); + auto *DesiredVal = convertRValueToInt(Desired, /*CmpXchg=*/true); auto Res = EmitAtomicCompareExchangeOp(ExpectedVal, DesiredVal, Success, Failure, IsWeak); return std::make_pair( ConvertToValueOrAtomic(Res.first, AggValueSlot::ignored(), - SourceLocation(), /*AsValue=*/false), + SourceLocation(), /*AsValue=*/false, + /*CmpXchg=*/true), Res.second); } @@ -1757,7 +1768,7 @@ void AtomicInfo::EmitAtomicUpdateLibcall( Address ExpectedAddr = CreateTempAlloca(); - EmitAtomicLoadLibcall(ExpectedAddr.getPointer(), AO, IsVolatile); + EmitAtomicLoadLibcall(ExpectedAddr.emitRawPointer(CGF), AO, IsVolatile); auto *ContBB = CGF.createBasicBlock("atomic_cont"); auto *ExitBB = CGF.createBasicBlock("atomic_exit"); CGF.EmitBlock(ContBB); @@ -1771,10 +1782,10 @@ void AtomicInfo::EmitAtomicUpdateLibcall( AggValueSlot::ignored(), SourceLocation(), /*AsValue=*/false); EmitAtomicUpdateValue(CGF, *this, OldRVal, UpdateOp, DesiredAddr); + llvm::Value *ExpectedPtr = ExpectedAddr.emitRawPointer(CGF); + llvm::Value *DesiredPtr = DesiredAddr.emitRawPointer(CGF); auto *Res = - EmitAtomicCompareExchangeLibcall(ExpectedAddr.getPointer(), - DesiredAddr.getPointer(), - AO, Failure); + EmitAtomicCompareExchangeLibcall(ExpectedPtr, DesiredPtr, AO, Failure); CGF.Builder.CreateCondBr(Res, ExitBB, ContBB); CGF.EmitBlock(ExitBB, /*IsFinished=*/true); } @@ -1785,7 +1796,7 @@ void AtomicInfo::EmitAtomicUpdateOp( auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO); // Do the atomic load. - auto *OldVal = EmitAtomicLoadOp(Failure, IsVolatile); + auto *OldVal = EmitAtomicLoadOp(Failure, IsVolatile, /*CmpXchg=*/true); // For non-simple lvalues perform compare-and-swap procedure. auto *ContBB = CGF.createBasicBlock("atomic_cont"); auto *ExitBB = CGF.createBasicBlock("atomic_exit"); @@ -1801,7 +1812,8 @@ void AtomicInfo::EmitAtomicUpdateOp( CGF.Builder.CreateStore(PHI, NewAtomicIntAddr); } auto OldRVal = ConvertToValueOrAtomic(PHI, AggValueSlot::ignored(), - SourceLocation(), /*AsValue=*/false); + SourceLocation(), /*AsValue=*/false, + /*CmpXchg=*/true); EmitAtomicUpdateValue(CGF, *this, OldRVal, UpdateOp, NewAtomicAddr); auto *DesiredVal = CGF.Builder.CreateLoad(NewAtomicIntAddr); // Try to write new value using cmpxchg operation. @@ -1843,7 +1855,7 @@ void AtomicInfo::EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO, Address ExpectedAddr = CreateTempAlloca(); - EmitAtomicLoadLibcall(ExpectedAddr.getPointer(), AO, IsVolatile); + EmitAtomicLoadLibcall(ExpectedAddr.emitRawPointer(CGF), AO, IsVolatile); auto *ContBB = CGF.createBasicBlock("atomic_cont"); auto *ExitBB = CGF.createBasicBlock("atomic_exit"); CGF.EmitBlock(ContBB); @@ -1854,10 +1866,10 @@ void AtomicInfo::EmitAtomicUpdateLibcall(llvm::AtomicOrdering AO, CGF.Builder.CreateStore(OldVal, DesiredAddr); } EmitAtomicUpdateValue(CGF, *this, UpdateRVal, DesiredAddr); + llvm::Value *ExpectedPtr = ExpectedAddr.emitRawPointer(CGF); + llvm::Value *DesiredPtr = DesiredAddr.emitRawPointer(CGF); auto *Res = - EmitAtomicCompareExchangeLibcall(ExpectedAddr.getPointer(), - DesiredAddr.getPointer(), - AO, Failure); + EmitAtomicCompareExchangeLibcall(ExpectedPtr, DesiredPtr, AO, Failure); CGF.Builder.CreateCondBr(Res, ExitBB, ContBB); CGF.EmitBlock(ExitBB, /*IsFinished=*/true); } @@ -1867,7 +1879,7 @@ void AtomicInfo::EmitAtomicUpdateOp(llvm::AtomicOrdering AO, RValue UpdateRVal, auto Failure = llvm::AtomicCmpXchgInst::getStrongestFailureOrdering(AO); // Do the atomic load. - auto *OldVal = EmitAtomicLoadOp(Failure, IsVolatile); + auto *OldVal = EmitAtomicLoadOp(Failure, IsVolatile, /*CmpXchg=*/true); // For non-simple lvalues perform compare-and-swap procedure. auto *ContBB = CGF.createBasicBlock("atomic_cont"); auto *ExitBB = CGF.createBasicBlock("atomic_exit"); @@ -1957,7 +1969,8 @@ void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest, args.add(RValue::get(atomics.getAtomicSizeValue()), getContext().getSizeType()); args.add(RValue::get(atomics.getAtomicPointer()), getContext().VoidPtrTy); - args.add(RValue::get(srcAddr.getPointer()), getContext().VoidPtrTy); + args.add(RValue::get(srcAddr.emitRawPointer(*this)), + getContext().VoidPtrTy); args.add( RValue::get(llvm::ConstantInt::get(IntTy, (int)llvm::toCABI(AO))), getContext().IntTy); @@ -1966,21 +1979,16 @@ void CodeGenFunction::EmitAtomicStore(RValue rvalue, LValue dest, } // Okay, we're doing this natively. - llvm::Value *ValToStore = - atomics.convertRValueToInt(rvalue, /*CastFP=*/false); + llvm::Value *ValToStore = atomics.convertRValueToInt(rvalue); // Do the atomic store. Address Addr = atomics.getAtomicAddress(); - bool ShouldCastToInt = true; if (llvm::Value *Value = atomics.getScalarRValValueOrNull(rvalue)) - if (isa(Value->getType()) || - Value->getType()->isIEEELikeFPTy()) - ShouldCastToInt = false; - if (ShouldCastToInt) { - Addr = atomics.castToAtomicIntPointer(Addr); - ValToStore = Builder.CreateIntCast(ValToStore, Addr.getElementType(), - /*isSigned=*/false); - } + if (shouldCastToInt(Value->getType(), /*CmpXchg=*/false)) { + Addr = atomics.castToAtomicIntPointer(Addr); + ValToStore = Builder.CreateIntCast(ValToStore, Addr.getElementType(), + /*isSigned=*/false); + } llvm::StoreInst *store = Builder.CreateStore(ValToStore, Addr); if (AO == llvm::AtomicOrdering::Acquire) diff --git a/clang/lib/CodeGen/CGBlocks.cpp b/clang/lib/CodeGen/CGBlocks.cpp index ad0b50d799618ed7ec7ecb581dd1bec84538a40c..2742c39965b2c86368231586497ad4b249e14560 100644 --- a/clang/lib/CodeGen/CGBlocks.cpp +++ b/clang/lib/CodeGen/CGBlocks.cpp @@ -36,7 +36,8 @@ CGBlockInfo::CGBlockInfo(const BlockDecl *block, StringRef name) : Name(name), CXXThisIndex(0), CanBeGlobal(false), NeedsCopyDispose(false), NoEscape(false), HasCXXObject(false), UsesStret(false), HasCapturedVariableLayout(false), CapturesNonExternalType(false), - LocalAddress(Address::invalid()), StructureType(nullptr), Block(block) { + LocalAddress(RawAddress::invalid()), StructureType(nullptr), + Block(block) { // Skip asm prefix, if any. 'name' is usually taken directly from // the mangled name of the enclosing function. @@ -794,7 +795,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { // Otherwise, we have to emit this as a local block. - Address blockAddr = blockInfo.LocalAddress; + RawAddress blockAddr = blockInfo.LocalAddress; assert(blockAddr.isValid() && "block has no address!"); llvm::Constant *isa; @@ -939,7 +940,7 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { if (CI.isNested()) byrefPointer = Builder.CreateLoad(src, "byref.capture"); else - byrefPointer = src.getPointer(); + byrefPointer = src.emitRawPointer(*this); // Write that void* into the capture field. Builder.CreateStore(byrefPointer, blockField); @@ -961,10 +962,10 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) { } // If it's a reference variable, copy the reference into the block field. - } else if (type->isReferenceType()) { - Builder.CreateStore(src.getPointer(), blockField); + } else if (type->getAs()) { + Builder.CreateStore(src.emitRawPointer(*this), blockField); - // If type is const-qualified, copy the value into the block field. + // If type is const-qualified, copy the value into the block field. } else if (type.isConstQualified() && type.getObjCLifetime() == Qualifiers::OCL_Strong && CGM.getCodeGenOpts().OptimizationLevel != 0) { @@ -1377,7 +1378,7 @@ void CodeGenFunction::setBlockContextParameter(const ImplicitParamDecl *D, // Allocate a stack slot like for any local variable to guarantee optimal // debug info at -O0. The mem2reg pass will eliminate it when optimizing. - Address alloc = CreateMemTemp(D->getType(), D->getName() + ".addr"); + RawAddress alloc = CreateMemTemp(D->getType(), D->getName() + ".addr"); Builder.CreateStore(arg, alloc); if (CGDebugInfo *DI = getDebugInfo()) { if (CGM.getCodeGenOpts().hasReducedDebugInfo()) { @@ -1446,7 +1447,7 @@ llvm::Function *CodeGenFunction::GenerateBlockFunction( selfTy = getContext().getPointerType(getContext().getAddrSpaceQualType( getContext().VoidTy, LangAS::opencl_generic)); - IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor"); + const IdentifierInfo *II = &CGM.getContext().Idents.get(".block_descriptor"); ImplicitParamDecl SelfDecl(getContext(), const_cast(blockDecl), SourceLocation(), II, selfTy, @@ -1497,7 +1498,7 @@ llvm::Function *CodeGenFunction::GenerateBlockFunction( // frame setup instruction by llvm::DwarfDebug::beginFunction(). auto NL = ApplyDebugLocation::CreateEmpty(*this); Builder.CreateStore(BlockPointer, Alloca); - BlockPointerDbgLoc = Alloca.getPointer(); + BlockPointerDbgLoc = Alloca.emitRawPointer(*this); } // If we have a C++ 'this' reference, go ahead and force it into @@ -1557,8 +1558,8 @@ llvm::Function *CodeGenFunction::GenerateBlockFunction( const CGBlockInfo::Capture &capture = blockInfo.getCapture(variable); if (capture.isConstant()) { auto addr = LocalDeclMap.find(variable)->second; - (void)DI->EmitDeclareOfAutoVariable(variable, addr.getPointer(), - Builder); + (void)DI->EmitDeclareOfAutoVariable( + variable, addr.emitRawPointer(*this), Builder); continue; } @@ -1662,7 +1663,7 @@ struct CallBlockRelease final : EHScopeStack::Cleanup { if (LoadBlockVarAddr) { BlockVarAddr = CGF.Builder.CreateLoad(Addr); } else { - BlockVarAddr = Addr.getPointer(); + BlockVarAddr = Addr.emitRawPointer(CGF); } CGF.BuildBlockRelease(BlockVarAddr, FieldFlags, CanThrow); @@ -1962,13 +1963,15 @@ CodeGenFunction::GenerateCopyHelperFunction(const CGBlockInfo &blockInfo) { // it. It's not quite worth the annoyance to avoid creating it in the // first place. if (!needsEHCleanup(captureType.isDestructedType())) - cast(dstField.getPointer())->eraseFromParent(); + if (auto *I = + cast_or_null(dstField.getBasePointer())) + I->eraseFromParent(); } break; } case BlockCaptureEntityKind::BlockObject: { llvm::Value *srcValue = Builder.CreateLoad(srcField, "blockcopy.src"); - llvm::Value *dstAddr = dstField.getPointer(); + llvm::Value *dstAddr = dstField.emitRawPointer(*this); llvm::Value *args[] = { dstAddr, srcValue, llvm::ConstantInt::get(Int32Ty, flags.getBitMask()) }; @@ -2139,7 +2142,7 @@ public: llvm::Value *flagsVal = llvm::ConstantInt::get(CGF.Int32Ty, flags); llvm::FunctionCallee fn = CGF.CGM.getBlockObjectAssign(); - llvm::Value *args[] = { destField.getPointer(), srcValue, flagsVal }; + llvm::Value *args[] = {destField.emitRawPointer(CGF), srcValue, flagsVal}; CGF.EmitNounwindRuntimeCall(fn, args); } @@ -2696,7 +2699,8 @@ void CodeGenFunction::emitByrefStructureInit(const AutoVarEmission &emission) { storeHeaderField(V, getPointerSize(), "byref.isa"); // Store the address of the variable into its own forwarding pointer. - storeHeaderField(addr.getPointer(), getPointerSize(), "byref.forwarding"); + storeHeaderField(addr.emitRawPointer(*this), getPointerSize(), + "byref.forwarding"); // Blocks ABI: // c) the flags field is set to either 0 if no helper functions are @@ -2787,7 +2791,7 @@ static void configureBlocksRuntimeObject(CodeGenModule &CGM, auto *GV = cast(C->stripPointerCasts()); if (CGM.getTarget().getTriple().isOSBinFormatCOFF()) { - IdentifierInfo &II = CGM.getContext().Idents.get(C->getName()); + const IdentifierInfo &II = CGM.getContext().Idents.get(C->getName()); TranslationUnitDecl *TUDecl = CGM.getContext().getTranslationUnitDecl(); DeclContext *DC = TranslationUnitDecl::castToDeclContext(TUDecl); diff --git a/clang/lib/CodeGen/CGBlocks.h b/clang/lib/CodeGen/CGBlocks.h index 4ef1ae9f33655cb8b76fbf19af4557be46f140c4..8d10c4f69b2026b4c5d254eadc2d037e88058d36 100644 --- a/clang/lib/CodeGen/CGBlocks.h +++ b/clang/lib/CodeGen/CGBlocks.h @@ -271,7 +271,8 @@ public: /// The block's captures. Non-constant captures are sorted by their offsets. llvm::SmallVector SortedCaptures; - Address LocalAddress; + // Currently we assume that block-pointer types are never signed. + RawAddress LocalAddress; llvm::StructType *StructureType; const BlockDecl *Block; const BlockExpr *BlockExpression; diff --git a/clang/lib/CodeGen/CGBuilder.h b/clang/lib/CodeGen/CGBuilder.h index bf5ab171d720d9b148544ac6467652a5efea0edb..6dd9da7c4cadefb2063b5f55fdf3230476128c22 100644 --- a/clang/lib/CodeGen/CGBuilder.h +++ b/clang/lib/CodeGen/CGBuilder.h @@ -10,7 +10,9 @@ #define LLVM_CLANG_LIB_CODEGEN_CGBUILDER_H #include "Address.h" +#include "CGValue.h" #include "CodeGenTypeCache.h" +#include "llvm/Analysis/Utils/Local.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Type.h" @@ -18,12 +20,15 @@ namespace clang { namespace CodeGen { +class CGBuilderTy; class CodeGenFunction; /// This is an IRBuilder insertion helper that forwards to /// CodeGenFunction::InsertHelper, which adds necessary metadata to /// instructions. class CGBuilderInserter final : public llvm::IRBuilderDefaultInserter { + friend CGBuilderTy; + public: CGBuilderInserter() = default; explicit CGBuilderInserter(CodeGenFunction *CGF) : CGF(CGF) {} @@ -43,10 +48,42 @@ typedef llvm::IRBuilder CGBuilderBaseTy; class CGBuilderTy : public CGBuilderBaseTy { + friend class Address; + /// Storing a reference to the type cache here makes it a lot easier /// to build natural-feeling, target-specific IR. const CodeGenTypeCache &TypeCache; + CodeGenFunction *getCGF() const { return getInserter().CGF; } + + llvm::Value *emitRawPointerFromAddress(Address Addr) const { + return Addr.getBasePointer(); + } + + template + Address createConstGEP2_32(Address Addr, unsigned Idx0, unsigned Idx1, + const llvm::Twine &Name) { + const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); + llvm::GetElementPtrInst *GEP; + if (IsInBounds) + GEP = cast(CreateConstInBoundsGEP2_32( + Addr.getElementType(), emitRawPointerFromAddress(Addr), Idx0, Idx1, + Name)); + else + GEP = cast(CreateConstGEP2_32( + Addr.getElementType(), emitRawPointerFromAddress(Addr), Idx0, Idx1, + Name)); + llvm::APInt Offset( + DL.getIndexSizeInBits(Addr.getType()->getPointerAddressSpace()), 0, + /*isSigned=*/true); + if (!GEP->accumulateConstantOffset(DL, Offset)) + llvm_unreachable("offset of GEP with constants is always computable"); + return Address(GEP, GEP->getResultElementType(), + Addr.getAlignment().alignmentAtOffset( + CharUnits::fromQuantity(Offset.getSExtValue())), + IsInBounds ? Addr.isKnownNonNull() : NotKnownNonNull); + } + public: CGBuilderTy(const CodeGenTypeCache &TypeCache, llvm::LLVMContext &C) : CGBuilderBaseTy(C), TypeCache(TypeCache) {} @@ -69,20 +106,22 @@ public: // Note that we intentionally hide the CreateLoad APIs that don't // take an alignment. llvm::LoadInst *CreateLoad(Address Addr, const llvm::Twine &Name = "") { - return CreateAlignedLoad(Addr.getElementType(), Addr.getPointer(), + return CreateAlignedLoad(Addr.getElementType(), + emitRawPointerFromAddress(Addr), Addr.getAlignment().getAsAlign(), Name); } llvm::LoadInst *CreateLoad(Address Addr, const char *Name) { // This overload is required to prevent string literals from // ending up in the IsVolatile overload. - return CreateAlignedLoad(Addr.getElementType(), Addr.getPointer(), + return CreateAlignedLoad(Addr.getElementType(), + emitRawPointerFromAddress(Addr), Addr.getAlignment().getAsAlign(), Name); } llvm::LoadInst *CreateLoad(Address Addr, bool IsVolatile, const llvm::Twine &Name = "") { - return CreateAlignedLoad(Addr.getElementType(), Addr.getPointer(), - Addr.getAlignment().getAsAlign(), IsVolatile, - Name); + return CreateAlignedLoad( + Addr.getElementType(), emitRawPointerFromAddress(Addr), + Addr.getAlignment().getAsAlign(), IsVolatile, Name); } using CGBuilderBaseTy::CreateAlignedLoad; @@ -96,7 +135,7 @@ public: // take an alignment. llvm::StoreInst *CreateStore(llvm::Value *Val, Address Addr, bool IsVolatile = false) { - return CreateAlignedStore(Val, Addr.getPointer(), + return CreateAlignedStore(Val, emitRawPointerFromAddress(Addr), Addr.getAlignment().getAsAlign(), IsVolatile); } @@ -132,33 +171,41 @@ public: llvm::AtomicOrdering FailureOrdering, llvm::SyncScope::ID SSID = llvm::SyncScope::System) { return CGBuilderBaseTy::CreateAtomicCmpXchg( - Addr.getPointer(), Cmp, New, Addr.getAlignment().getAsAlign(), - SuccessOrdering, FailureOrdering, SSID); + Addr.emitRawPointer(*getCGF()), Cmp, New, + Addr.getAlignment().getAsAlign(), SuccessOrdering, FailureOrdering, + SSID); } llvm::AtomicRMWInst * CreateAtomicRMW(llvm::AtomicRMWInst::BinOp Op, Address Addr, llvm::Value *Val, llvm::AtomicOrdering Ordering, llvm::SyncScope::ID SSID = llvm::SyncScope::System) { - return CGBuilderBaseTy::CreateAtomicRMW(Op, Addr.getPointer(), Val, - Addr.getAlignment().getAsAlign(), - Ordering, SSID); + return CGBuilderBaseTy::CreateAtomicRMW( + Op, Addr.emitRawPointer(*getCGF()), Val, + Addr.getAlignment().getAsAlign(), Ordering, SSID); } using CGBuilderBaseTy::CreateAddrSpaceCast; Address CreateAddrSpaceCast(Address Addr, llvm::Type *Ty, + llvm::Type *ElementTy, const llvm::Twine &Name = "") { - return Addr.withPointer(CreateAddrSpaceCast(Addr.getPointer(), Ty, Name), - Addr.isKnownNonNull()); + if (!Addr.hasOffset()) + return Address(CreateAddrSpaceCast(Addr.getBasePointer(), Ty, Name), + ElementTy, Addr.getAlignment(), nullptr, + Addr.isKnownNonNull()); + // Eagerly force a raw address if these is an offset. + return RawAddress( + CreateAddrSpaceCast(Addr.emitRawPointer(*getCGF()), Ty, Name), + ElementTy, Addr.getAlignment(), Addr.isKnownNonNull()); } using CGBuilderBaseTy::CreatePointerBitCastOrAddrSpaceCast; Address CreatePointerBitCastOrAddrSpaceCast(Address Addr, llvm::Type *Ty, llvm::Type *ElementTy, const llvm::Twine &Name = "") { - llvm::Value *Ptr = - CreatePointerBitCastOrAddrSpaceCast(Addr.getPointer(), Ty, Name); - return Address(Ptr, ElementTy, Addr.getAlignment(), Addr.isKnownNonNull()); + if (Addr.getType()->getAddressSpace() == Ty->getPointerAddressSpace()) + return Addr.withElementType(ElementTy); + return CreateAddrSpaceCast(Addr, Ty, ElementTy, Name); } /// Given @@ -176,10 +223,11 @@ public: const llvm::StructLayout *Layout = DL.getStructLayout(ElTy); auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index)); - return Address( - CreateStructGEP(Addr.getElementType(), Addr.getPointer(), Index, Name), - ElTy->getElementType(Index), - Addr.getAlignment().alignmentAtOffset(Offset), Addr.isKnownNonNull()); + return Address(CreateStructGEP(Addr.getElementType(), Addr.getBasePointer(), + Index, Name), + ElTy->getElementType(Index), + Addr.getAlignment().alignmentAtOffset(Offset), + Addr.isKnownNonNull()); } /// Given @@ -198,7 +246,7 @@ public: CharUnits::fromQuantity(DL.getTypeAllocSize(ElTy->getElementType())); return Address( - CreateInBoundsGEP(Addr.getElementType(), Addr.getPointer(), + CreateInBoundsGEP(Addr.getElementType(), Addr.getBasePointer(), {getSize(CharUnits::Zero()), getSize(Index)}, Name), ElTy->getElementType(), Addr.getAlignment().alignmentAtOffset(Index * EltSize), @@ -216,10 +264,10 @@ public: const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); CharUnits EltSize = CharUnits::fromQuantity(DL.getTypeAllocSize(ElTy)); - return Address(CreateInBoundsGEP(Addr.getElementType(), Addr.getPointer(), - getSize(Index), Name), - ElTy, Addr.getAlignment().alignmentAtOffset(Index * EltSize), - Addr.isKnownNonNull()); + return Address( + CreateInBoundsGEP(ElTy, Addr.getBasePointer(), getSize(Index), Name), + ElTy, Addr.getAlignment().alignmentAtOffset(Index * EltSize), + Addr.isKnownNonNull()); } /// Given @@ -229,110 +277,133 @@ public: /// where i64 is actually the target word size. Address CreateConstGEP(Address Addr, uint64_t Index, const llvm::Twine &Name = "") { + llvm::Type *ElTy = Addr.getElementType(); const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); - CharUnits EltSize = - CharUnits::fromQuantity(DL.getTypeAllocSize(Addr.getElementType())); + CharUnits EltSize = CharUnits::fromQuantity(DL.getTypeAllocSize(ElTy)); - return Address(CreateGEP(Addr.getElementType(), Addr.getPointer(), - getSize(Index), Name), + return Address(CreateGEP(ElTy, Addr.getBasePointer(), getSize(Index), Name), Addr.getElementType(), - Addr.getAlignment().alignmentAtOffset(Index * EltSize), - NotKnownNonNull); + Addr.getAlignment().alignmentAtOffset(Index * EltSize)); } /// Create GEP with single dynamic index. The address alignment is reduced /// according to the element size. using CGBuilderBaseTy::CreateGEP; - Address CreateGEP(Address Addr, llvm::Value *Index, + Address CreateGEP(CodeGenFunction &CGF, Address Addr, llvm::Value *Index, const llvm::Twine &Name = "") { const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); CharUnits EltSize = CharUnits::fromQuantity(DL.getTypeAllocSize(Addr.getElementType())); return Address( - CreateGEP(Addr.getElementType(), Addr.getPointer(), Index, Name), + CreateGEP(Addr.getElementType(), Addr.emitRawPointer(CGF), Index, Name), Addr.getElementType(), - Addr.getAlignment().alignmentOfArrayElement(EltSize), NotKnownNonNull); + Addr.getAlignment().alignmentOfArrayElement(EltSize)); } /// Given a pointer to i8, adjust it by a given constant offset. Address CreateConstInBoundsByteGEP(Address Addr, CharUnits Offset, const llvm::Twine &Name = "") { assert(Addr.getElementType() == TypeCache.Int8Ty); - return Address(CreateInBoundsGEP(Addr.getElementType(), Addr.getPointer(), - getSize(Offset), Name), - Addr.getElementType(), - Addr.getAlignment().alignmentAtOffset(Offset), - Addr.isKnownNonNull()); + return Address( + CreateInBoundsGEP(Addr.getElementType(), Addr.getBasePointer(), + getSize(Offset), Name), + Addr.getElementType(), Addr.getAlignment().alignmentAtOffset(Offset), + Addr.isKnownNonNull()); } + Address CreateConstByteGEP(Address Addr, CharUnits Offset, const llvm::Twine &Name = "") { assert(Addr.getElementType() == TypeCache.Int8Ty); - return Address(CreateGEP(Addr.getElementType(), Addr.getPointer(), + return Address(CreateGEP(Addr.getElementType(), Addr.getBasePointer(), getSize(Offset), Name), Addr.getElementType(), - Addr.getAlignment().alignmentAtOffset(Offset), - NotKnownNonNull); + Addr.getAlignment().alignmentAtOffset(Offset)); } using CGBuilderBaseTy::CreateConstInBoundsGEP2_32; Address CreateConstInBoundsGEP2_32(Address Addr, unsigned Idx0, unsigned Idx1, const llvm::Twine &Name = "") { - const llvm::DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); + return createConstGEP2_32(Addr, Idx0, Idx1, Name); + } - auto *GEP = cast(CreateConstInBoundsGEP2_32( - Addr.getElementType(), Addr.getPointer(), Idx0, Idx1, Name)); - llvm::APInt Offset( - DL.getIndexSizeInBits(Addr.getType()->getPointerAddressSpace()), 0, - /*isSigned=*/true); - if (!GEP->accumulateConstantOffset(DL, Offset)) - llvm_unreachable("offset of GEP with constants is always computable"); - return Address(GEP, GEP->getResultElementType(), - Addr.getAlignment().alignmentAtOffset( - CharUnits::fromQuantity(Offset.getSExtValue())), - Addr.isKnownNonNull()); + using CGBuilderBaseTy::CreateConstGEP2_32; + Address CreateConstGEP2_32(Address Addr, unsigned Idx0, unsigned Idx1, + const llvm::Twine &Name = "") { + return createConstGEP2_32(Addr, Idx0, Idx1, Name); + } + + Address CreateGEP(Address Addr, ArrayRef IdxList, + llvm::Type *ElementType, CharUnits Align, + const Twine &Name = "") { + llvm::Value *Ptr = emitRawPointerFromAddress(Addr); + return RawAddress(CreateGEP(Addr.getElementType(), Ptr, IdxList, Name), + ElementType, Align); + } + + using CGBuilderBaseTy::CreateInBoundsGEP; + Address CreateInBoundsGEP(Address Addr, ArrayRef IdxList, + llvm::Type *ElementType, CharUnits Align, + const Twine &Name = "") { + return RawAddress(CreateInBoundsGEP(Addr.getElementType(), + emitRawPointerFromAddress(Addr), + IdxList, Name), + ElementType, Align, Addr.isKnownNonNull()); + } + + using CGBuilderBaseTy::CreateIsNull; + llvm::Value *CreateIsNull(Address Addr, const Twine &Name = "") { + if (!Addr.hasOffset()) + return CreateIsNull(Addr.getBasePointer(), Name); + // The pointer isn't null if Addr has an offset since offsets can always + // be applied inbound. + return llvm::ConstantInt::getFalse(Context); } using CGBuilderBaseTy::CreateMemCpy; llvm::CallInst *CreateMemCpy(Address Dest, Address Src, llvm::Value *Size, bool IsVolatile = false) { - return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getAsAlign(), - Src.getPointer(), Src.getAlignment().getAsAlign(), Size, - IsVolatile); + llvm::Value *DestPtr = emitRawPointerFromAddress(Dest); + llvm::Value *SrcPtr = emitRawPointerFromAddress(Src); + return CreateMemCpy(DestPtr, Dest.getAlignment().getAsAlign(), SrcPtr, + Src.getAlignment().getAsAlign(), Size, IsVolatile); } llvm::CallInst *CreateMemCpy(Address Dest, Address Src, uint64_t Size, bool IsVolatile = false) { - return CreateMemCpy(Dest.getPointer(), Dest.getAlignment().getAsAlign(), - Src.getPointer(), Src.getAlignment().getAsAlign(), Size, - IsVolatile); + llvm::Value *DestPtr = emitRawPointerFromAddress(Dest); + llvm::Value *SrcPtr = emitRawPointerFromAddress(Src); + return CreateMemCpy(DestPtr, Dest.getAlignment().getAsAlign(), SrcPtr, + Src.getAlignment().getAsAlign(), Size, IsVolatile); } using CGBuilderBaseTy::CreateMemCpyInline; llvm::CallInst *CreateMemCpyInline(Address Dest, Address Src, uint64_t Size) { - return CreateMemCpyInline( - Dest.getPointer(), Dest.getAlignment().getAsAlign(), Src.getPointer(), - Src.getAlignment().getAsAlign(), getInt64(Size)); + llvm::Value *DestPtr = emitRawPointerFromAddress(Dest); + llvm::Value *SrcPtr = emitRawPointerFromAddress(Src); + return CreateMemCpyInline(DestPtr, Dest.getAlignment().getAsAlign(), SrcPtr, + Src.getAlignment().getAsAlign(), getInt64(Size)); } using CGBuilderBaseTy::CreateMemMove; llvm::CallInst *CreateMemMove(Address Dest, Address Src, llvm::Value *Size, bool IsVolatile = false) { - return CreateMemMove(Dest.getPointer(), Dest.getAlignment().getAsAlign(), - Src.getPointer(), Src.getAlignment().getAsAlign(), - Size, IsVolatile); + llvm::Value *DestPtr = emitRawPointerFromAddress(Dest); + llvm::Value *SrcPtr = emitRawPointerFromAddress(Src); + return CreateMemMove(DestPtr, Dest.getAlignment().getAsAlign(), SrcPtr, + Src.getAlignment().getAsAlign(), Size, IsVolatile); } using CGBuilderBaseTy::CreateMemSet; llvm::CallInst *CreateMemSet(Address Dest, llvm::Value *Value, llvm::Value *Size, bool IsVolatile = false) { - return CreateMemSet(Dest.getPointer(), Value, Size, + return CreateMemSet(emitRawPointerFromAddress(Dest), Value, Size, Dest.getAlignment().getAsAlign(), IsVolatile); } using CGBuilderBaseTy::CreateMemSetInline; llvm::CallInst *CreateMemSetInline(Address Dest, llvm::Value *Value, uint64_t Size) { - return CreateMemSetInline(Dest.getPointer(), + return CreateMemSetInline(emitRawPointerFromAddress(Dest), Dest.getAlignment().getAsAlign(), Value, getInt64(Size)); } @@ -346,16 +417,31 @@ public: const llvm::StructLayout *Layout = DL.getStructLayout(ElTy); auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index)); - return Address(CreatePreserveStructAccessIndex(ElTy, Addr.getPointer(), - Index, FieldIndex, DbgInfo), - ElTy->getElementType(Index), - Addr.getAlignment().alignmentAtOffset(Offset)); + return Address( + CreatePreserveStructAccessIndex(ElTy, emitRawPointerFromAddress(Addr), + Index, FieldIndex, DbgInfo), + ElTy->getElementType(Index), + Addr.getAlignment().alignmentAtOffset(Offset)); + } + + using CGBuilderBaseTy::CreatePreserveUnionAccessIndex; + Address CreatePreserveUnionAccessIndex(Address Addr, unsigned FieldIndex, + llvm::MDNode *DbgInfo) { + Addr.replaceBasePointer(CreatePreserveUnionAccessIndex( + Addr.getBasePointer(), FieldIndex, DbgInfo)); + return Addr; } using CGBuilderBaseTy::CreateLaunderInvariantGroup; Address CreateLaunderInvariantGroup(Address Addr) { - return Addr.withPointer(CreateLaunderInvariantGroup(Addr.getPointer()), - Addr.isKnownNonNull()); + Addr.replaceBasePointer(CreateLaunderInvariantGroup(Addr.getBasePointer())); + return Addr; + } + + using CGBuilderBaseTy::CreateStripInvariantGroup; + Address CreateStripInvariantGroup(Address Addr) { + Addr.replaceBasePointer(CreateStripInvariantGroup(Addr.getBasePointer())); + return Addr; } }; diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index e14e890882821853378fd7e814bb3bdb1093ecc2..c052367d287820bff7fb4498c84a5029775a32e0 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -13,6 +13,7 @@ #include "ABIInfo.h" #include "CGCUDARuntime.h" #include "CGCXXABI.h" +#include "CGHLSLRuntime.h" #include "CGObjCRuntime.h" #include "CGOpenCLRuntime.h" #include "CGRecordLayout.h" @@ -792,7 +793,8 @@ EncompassingIntegerType(ArrayRef Types) { Value *CodeGenFunction::EmitVAStartEnd(Value *ArgValue, bool IsStart) { Intrinsic::ID inst = IsStart ? Intrinsic::vastart : Intrinsic::vaend; - return Builder.CreateCall(CGM.getIntrinsic(inst), ArgValue); + return Builder.CreateCall(CGM.getIntrinsic(inst, {ArgValue->getType()}), + ArgValue); } /// Checks if using the result of __builtin_object_size(p, @p From) in place of @@ -1130,8 +1132,92 @@ struct BitTest { static BitTest decodeBitTestBuiltin(unsigned BuiltinID); }; + +// Returns the first convergence entry/loop/anchor instruction found in |BB|. +// std::nullptr otherwise. +llvm::IntrinsicInst *getConvergenceToken(llvm::BasicBlock *BB) { + for (auto &I : *BB) { + auto *II = dyn_cast(&I); + if (II && isConvergenceControlIntrinsic(II->getIntrinsicID())) + return II; + } + return nullptr; +} + } // namespace +llvm::CallBase * +CodeGenFunction::addConvergenceControlToken(llvm::CallBase *Input, + llvm::Value *ParentToken) { + llvm::Value *bundleArgs[] = {ParentToken}; + llvm::OperandBundleDef OB("convergencectrl", bundleArgs); + auto Output = llvm::CallBase::addOperandBundle( + Input, llvm::LLVMContext::OB_convergencectrl, OB, Input); + Input->replaceAllUsesWith(Output); + Input->eraseFromParent(); + return Output; +} + +llvm::IntrinsicInst * +CodeGenFunction::emitConvergenceLoopToken(llvm::BasicBlock *BB, + llvm::Value *ParentToken) { + CGBuilderTy::InsertPoint IP = Builder.saveIP(); + Builder.SetInsertPoint(&BB->front()); + auto CB = Builder.CreateIntrinsic( + llvm::Intrinsic::experimental_convergence_loop, {}, {}); + Builder.restoreIP(IP); + + auto I = addConvergenceControlToken(CB, ParentToken); + return cast(I); +} + +llvm::IntrinsicInst * +CodeGenFunction::getOrEmitConvergenceEntryToken(llvm::Function *F) { + auto *BB = &F->getEntryBlock(); + auto *token = getConvergenceToken(BB); + if (token) + return token; + + // Adding a convergence token requires the function to be marked as + // convergent. + F->setConvergent(); + + CGBuilderTy::InsertPoint IP = Builder.saveIP(); + Builder.SetInsertPoint(&BB->front()); + auto I = Builder.CreateIntrinsic( + llvm::Intrinsic::experimental_convergence_entry, {}, {}); + assert(isa(I)); + Builder.restoreIP(IP); + + return cast(I); +} + +llvm::IntrinsicInst * +CodeGenFunction::getOrEmitConvergenceLoopToken(const LoopInfo *LI) { + assert(LI != nullptr); + + auto *token = getConvergenceToken(LI->getHeader()); + if (token) + return token; + + llvm::IntrinsicInst *PII = + LI->getParent() + ? emitConvergenceLoopToken( + LI->getHeader(), getOrEmitConvergenceLoopToken(LI->getParent())) + : getOrEmitConvergenceEntryToken(LI->getHeader()->getParent()); + + return emitConvergenceLoopToken(LI->getHeader(), PII); +} + +llvm::CallBase * +CodeGenFunction::addControlledConvergenceToken(llvm::CallBase *Input) { + llvm::Value *ParentToken = + LoopStack.hasInfo() + ? getOrEmitConvergenceLoopToken(&LoopStack.getInfo()) + : getOrEmitConvergenceEntryToken(Input->getFunction()); + return addConvergenceControlToken(Input, ParentToken); +} + BitTest BitTest::decodeBitTestBuiltin(unsigned BuiltinID) { switch (BuiltinID) { // Main portable variants. @@ -2116,9 +2202,9 @@ llvm::Function *CodeGenFunction::generateBuiltinOSLogHelperFunction( auto AL = ApplyDebugLocation::CreateArtificial(*this); CharUnits Offset; - Address BufAddr = - Address(Builder.CreateLoad(GetAddrOfLocalVar(Args[0]), "buf"), Int8Ty, - BufferAlignment); + Address BufAddr = makeNaturalAddressForPointer( + Builder.CreateLoad(GetAddrOfLocalVar(Args[0]), "buf"), Ctx.VoidTy, + BufferAlignment); Builder.CreateStore(Builder.getInt8(Layout.getSummaryByte()), Builder.CreateConstByteGEP(BufAddr, Offset++, "summary")); Builder.CreateStore(Builder.getInt8(Layout.getNumArgsByte()), @@ -2161,7 +2247,7 @@ RValue CodeGenFunction::emitBuiltinOSLogFormat(const CallExpr &E) { // Ignore argument 1, the format string. It is not currently used. CallArgList Args; - Args.add(RValue::get(BufAddr.getPointer()), Ctx.VoidPtrTy); + Args.add(RValue::get(BufAddr.emitRawPointer(*this)), Ctx.VoidPtrTy); for (const auto &Item : Layout.Items) { int Size = Item.getSizeByte(); @@ -2201,8 +2287,8 @@ RValue CodeGenFunction::emitBuiltinOSLogFormat(const CallExpr &E) { if (!isa(ArgVal)) { CleanupKind Cleanup = getARCCleanupKind(); QualType Ty = TheExpr->getType(); - Address Alloca = Address::invalid(); - Address Addr = CreateMemTemp(Ty, "os.log.arg", &Alloca); + RawAddress Alloca = RawAddress::invalid(); + RawAddress Addr = CreateMemTemp(Ty, "os.log.arg", &Alloca); ArgVal = EmitARCRetain(Ty, ArgVal); Builder.CreateStore(ArgVal, Addr); pushLifetimeExtendedDestroy(Cleanup, Alloca, Ty, @@ -2235,7 +2321,7 @@ RValue CodeGenFunction::emitBuiltinOSLogFormat(const CallExpr &E) { llvm::Function *F = CodeGenFunction(CGM).generateBuiltinOSLogHelperFunction( Layout, BufAddr.getAlignment()); EmitCall(FI, CGCallee::forDirect(F), ReturnValueSlot(), Args); - return RValue::get(BufAddr.getPointer()); + return RValue::get(BufAddr, *this); } static bool isSpecialUnsignedMultiplySignedResult( @@ -2983,7 +3069,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, // Check NonnullAttribute/NullabilityArg and Alignment. auto EmitArgCheck = [&](TypeCheckKind Kind, Address A, const Expr *Arg, unsigned ParmNum) { - Value *Val = A.getPointer(); + Value *Val = A.emitRawPointer(*this); EmitNonNullArgCheck(RValue::get(Val), Arg->getType(), Arg->getExprLoc(), FD, ParmNum); @@ -3012,13 +3098,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_va_end: EmitVAStartEnd(BuiltinID == Builtin::BI__va_start ? EmitScalarExpr(E->getArg(0)) - : EmitVAListRef(E->getArg(0)).getPointer(), + : EmitVAListRef(E->getArg(0)).emitRawPointer(*this), BuiltinID != Builtin::BI__builtin_va_end); return RValue::get(nullptr); case Builtin::BI__builtin_va_copy: { - Value *DstPtr = EmitVAListRef(E->getArg(0)).getPointer(); - Value *SrcPtr = EmitVAListRef(E->getArg(1)).getPointer(); - Builder.CreateCall(CGM.getIntrinsic(Intrinsic::vacopy), {DstPtr, SrcPtr}); + Value *DstPtr = EmitVAListRef(E->getArg(0)).emitRawPointer(*this); + Value *SrcPtr = EmitVAListRef(E->getArg(1)).emitRawPointer(*this); + Builder.CreateCall(CGM.getIntrinsic(Intrinsic::vacopy, {DstPtr->getType()}), + {DstPtr, SrcPtr}); return RValue::get(nullptr); } case Builtin::BIabs: @@ -3847,13 +3934,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, bool IsVolatile = PtrTy->getPointeeType().isVolatileQualified(); Address Src = EmitPointerWithAlignment(E->getArg(0)); - EmitNonNullArgCheck(RValue::get(Src.getPointer()), E->getArg(0)->getType(), - E->getArg(0)->getExprLoc(), FD, 0); + EmitNonNullArgCheck(RValue::get(Src.emitRawPointer(*this)), + E->getArg(0)->getType(), E->getArg(0)->getExprLoc(), FD, + 0); Value *Result = MB.CreateColumnMajorLoad( - Src.getElementType(), Src.getPointer(), + Src.getElementType(), Src.emitRawPointer(*this), Align(Src.getAlignment().getQuantity()), Stride, IsVolatile, - ResultTy->getNumRows(), ResultTy->getNumColumns(), - "matrix"); + ResultTy->getNumRows(), ResultTy->getNumColumns(), "matrix"); return RValue::get(Result); } @@ -3868,11 +3955,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, assert(PtrTy && "arg1 must be of pointer type"); bool IsVolatile = PtrTy->getPointeeType().isVolatileQualified(); - EmitNonNullArgCheck(RValue::get(Dst.getPointer()), E->getArg(1)->getType(), - E->getArg(1)->getExprLoc(), FD, 0); + EmitNonNullArgCheck(RValue::get(Dst.emitRawPointer(*this)), + E->getArg(1)->getType(), E->getArg(1)->getExprLoc(), FD, + 0); Value *Result = MB.CreateColumnMajorStore( - Matrix, Dst.getPointer(), Align(Dst.getAlignment().getQuantity()), - Stride, IsVolatile, MatrixTy->getNumRows(), MatrixTy->getNumColumns()); + Matrix, Dst.emitRawPointer(*this), + Align(Dst.getAlignment().getQuantity()), Stride, IsVolatile, + MatrixTy->getNumRows(), MatrixTy->getNumColumns()); return RValue::get(Result); } @@ -4031,7 +4120,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_bzero: { Address Dest = EmitPointerWithAlignment(E->getArg(0)); Value *SizeVal = EmitScalarExpr(E->getArg(1)); - EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(), + EmitNonNullArgCheck(Dest, E->getArg(0)->getType(), E->getArg(0)->getExprLoc(), FD, 0); Builder.CreateMemSet(Dest, Builder.getInt8(0), SizeVal, false); return RValue::get(nullptr); @@ -4042,10 +4131,12 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Address Src = EmitPointerWithAlignment(E->getArg(0)); Address Dest = EmitPointerWithAlignment(E->getArg(1)); Value *SizeVal = EmitScalarExpr(E->getArg(2)); - EmitNonNullArgCheck(RValue::get(Src.getPointer()), E->getArg(0)->getType(), - E->getArg(0)->getExprLoc(), FD, 0); - EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(1)->getType(), - E->getArg(1)->getExprLoc(), FD, 0); + EmitNonNullArgCheck(RValue::get(Src.emitRawPointer(*this)), + E->getArg(0)->getType(), E->getArg(0)->getExprLoc(), FD, + 0); + EmitNonNullArgCheck(RValue::get(Dest.emitRawPointer(*this)), + E->getArg(1)->getType(), E->getArg(1)->getExprLoc(), FD, + 0); Builder.CreateMemMove(Dest, Src, SizeVal, false); return RValue::get(nullptr); } @@ -4062,10 +4153,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Builder.CreateMemCpy(Dest, Src, SizeVal, false); if (BuiltinID == Builtin::BImempcpy || BuiltinID == Builtin::BI__builtin_mempcpy) - return RValue::get(Builder.CreateInBoundsGEP(Dest.getElementType(), - Dest.getPointer(), SizeVal)); + return RValue::get(Builder.CreateInBoundsGEP( + Dest.getElementType(), Dest.emitRawPointer(*this), SizeVal)); else - return RValue::get(Dest.getPointer()); + return RValue::get(Dest, *this); } case Builtin::BI__builtin_memcpy_inline: { @@ -4097,7 +4188,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Address Src = EmitPointerWithAlignment(E->getArg(1)); Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size); Builder.CreateMemCpy(Dest, Src, SizeVal, false); - return RValue::get(Dest.getPointer()); + return RValue::get(Dest, *this); } case Builtin::BI__builtin_objc_memmove_collectable: { @@ -4106,7 +4197,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Value *SizeVal = EmitScalarExpr(E->getArg(2)); CGM.getObjCRuntime().EmitGCMemmoveCollectable(*this, DestAddr, SrcAddr, SizeVal); - return RValue::get(DestAddr.getPointer()); + return RValue::get(DestAddr, *this); } case Builtin::BI__builtin___memmove_chk: { @@ -4123,7 +4214,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Address Src = EmitPointerWithAlignment(E->getArg(1)); Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size); Builder.CreateMemMove(Dest, Src, SizeVal, false); - return RValue::get(Dest.getPointer()); + return RValue::get(Dest, *this); } case Builtin::BImemmove: @@ -4134,7 +4225,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, EmitArgCheck(TCK_Store, Dest, E->getArg(0), 0); EmitArgCheck(TCK_Load, Src, E->getArg(1), 1); Builder.CreateMemMove(Dest, Src, SizeVal, false); - return RValue::get(Dest.getPointer()); + return RValue::get(Dest, *this); } case Builtin::BImemset: case Builtin::BI__builtin_memset: { @@ -4142,10 +4233,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Value *ByteVal = Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)), Builder.getInt8Ty()); Value *SizeVal = EmitScalarExpr(E->getArg(2)); - EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(), + EmitNonNullArgCheck(Dest, E->getArg(0)->getType(), E->getArg(0)->getExprLoc(), FD, 0); Builder.CreateMemSet(Dest, ByteVal, SizeVal, false); - return RValue::get(Dest.getPointer()); + return RValue::get(Dest, *this); } case Builtin::BI__builtin_memset_inline: { Address Dest = EmitPointerWithAlignment(E->getArg(0)); @@ -4153,8 +4244,9 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Builder.CreateTrunc(EmitScalarExpr(E->getArg(1)), Builder.getInt8Ty()); uint64_t Size = E->getArg(2)->EvaluateKnownConstInt(getContext()).getZExtValue(); - EmitNonNullArgCheck(RValue::get(Dest.getPointer()), E->getArg(0)->getType(), - E->getArg(0)->getExprLoc(), FD, 0); + EmitNonNullArgCheck(RValue::get(Dest.emitRawPointer(*this)), + E->getArg(0)->getType(), E->getArg(0)->getExprLoc(), FD, + 0); Builder.CreateMemSetInline(Dest, ByteVal, Size); return RValue::get(nullptr); } @@ -4173,7 +4265,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Builder.getInt8Ty()); Value *SizeVal = llvm::ConstantInt::get(Builder.getContext(), Size); Builder.CreateMemSet(Dest, ByteVal, SizeVal, false); - return RValue::get(Dest.getPointer()); + return RValue::get(Dest, *this); } case Builtin::BI__builtin_wmemchr: { // The MSVC runtime library does not provide a definition of wmemchr, so we @@ -4395,14 +4487,14 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, // Store the stack pointer to the setjmp buffer. Value *StackAddr = Builder.CreateStackSave(); - assert(Buf.getPointer()->getType() == StackAddr->getType()); + assert(Buf.emitRawPointer(*this)->getType() == StackAddr->getType()); Address StackSaveSlot = Builder.CreateConstInBoundsGEP(Buf, 2); Builder.CreateStore(StackAddr, StackSaveSlot); // Call LLVM's EH setjmp, which is lightweight. Function *F = CGM.getIntrinsic(Intrinsic::eh_sjlj_setjmp); - return RValue::get(Builder.CreateCall(F, Buf.getPointer())); + return RValue::get(Builder.CreateCall(F, Buf.emitRawPointer(*this))); } case Builtin::BI__builtin_longjmp: { Value *Buf = EmitScalarExpr(E->getArg(0)); @@ -5575,7 +5667,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm::Value *Queue = EmitScalarExpr(E->getArg(0)); llvm::Value *Flags = EmitScalarExpr(E->getArg(1)); LValue NDRangeL = EmitAggExprToLValue(E->getArg(2)); - llvm::Value *Range = NDRangeL.getAddress(*this).getPointer(); + llvm::Value *Range = NDRangeL.getAddress(*this).emitRawPointer(*this); llvm::Type *RangeTy = NDRangeL.getAddress(*this).getType(); if (NumArgs == 4) { @@ -5684,9 +5776,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, getContext(), Expr::NPC_ValueDependentIsNotNull)) { EventWaitList = llvm::ConstantPointerNull::get(PtrTy); } else { - EventWaitList = E->getArg(4)->getType()->isArrayType() - ? EmitArrayToPointerDecay(E->getArg(4)).getPointer() - : EmitScalarExpr(E->getArg(4)); + EventWaitList = + E->getArg(4)->getType()->isArrayType() + ? EmitArrayToPointerDecay(E->getArg(4)).emitRawPointer(*this) + : EmitScalarExpr(E->getArg(4)); // Convert to generic address space. EventWaitList = Builder.CreatePointerCast(EventWaitList, PtrTy); } @@ -5743,7 +5836,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, EmitLifetimeEnd(TmpSize, TmpPtr); return Call; } - [[fallthrough]]; + llvm_unreachable("Unexpected enqueue_kernel signature"); } // OpenCL v2.0 s6.13.17.6 - Kernel query functions need bitcast of block // parameter. @@ -5782,7 +5875,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, llvm::Type *GenericVoidPtrTy = Builder.getPtrTy( getContext().getTargetAddressSpace(LangAS::opencl_generic)); LValue NDRangeL = EmitAggExprToLValue(E->getArg(0)); - llvm::Value *NDRange = NDRangeL.getAddress(*this).getPointer(); + llvm::Value *NDRange = NDRangeL.getAddress(*this).emitRawPointer(*this); auto Info = CGM.getOpenCLRuntime().emitOpenCLEnqueuedBlock(*this, E->getArg(1)); Value *Kernel = @@ -5800,7 +5893,6 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, Name), {NDRange, Kernel, Block})); } - case Builtin::BI__builtin_store_half: case Builtin::BI__builtin_store_halff: { Value *Val = EmitScalarExpr(E->getArg(0)); @@ -5867,7 +5959,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, auto PTy0 = FTy->getParamType(0); if (PTy0 != Arg0Val->getType()) { if (Arg0Ty->isArrayType()) - Arg0Val = EmitArrayToPointerDecay(Arg0).getPointer(); + Arg0Val = EmitArrayToPointerDecay(Arg0).emitRawPointer(*this); else Arg0Val = Builder.CreatePointerCast(Arg0Val, PTy0); } @@ -5905,7 +5997,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, auto PTy1 = FTy->getParamType(1); if (PTy1 != Arg1Val->getType()) { if (Arg1Ty->isArrayType()) - Arg1Val = EmitArrayToPointerDecay(Arg1).getPointer(); + Arg1Val = EmitArrayToPointerDecay(Arg1).emitRawPointer(*this); else Arg1Val = Builder.CreatePointerCast(Arg1Val, PTy1); } @@ -5919,7 +6011,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, case Builtin::BI__builtin_ms_va_start: case Builtin::BI__builtin_ms_va_end: return RValue::get( - EmitVAStartEnd(EmitMSVAListRef(E->getArg(0)).getPointer(), + EmitVAStartEnd(EmitMSVAListRef(E->getArg(0)).emitRawPointer(*this), BuiltinID == Builtin::BI__builtin_ms_va_start)); case Builtin::BI__builtin_ms_va_copy: { @@ -5961,8 +6053,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, // If this is a predefined lib function (e.g. malloc), emit the call // using exactly the normal call path. if (getContext().BuiltinInfo.isPredefinedLibFunction(BuiltinID)) - return emitLibraryCall(*this, FD, E, - cast(EmitScalarExpr(E->getCallee()))); + return emitLibraryCall( + *this, FD, E, cast(EmitScalarExpr(E->getCallee()))); // Check that a call to a target specific builtin has the correct target // features. @@ -6079,7 +6171,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, return RValue::get(nullptr); return RValue::get(V); case TEK_Aggregate: - return RValue::getAggregate(ReturnValue.getValue(), + return RValue::getAggregate(ReturnValue.getAddress(), ReturnValue.isVolatile()); case TEK_Complex: llvm_unreachable("No current target builtin returns complex"); @@ -7190,8 +7282,6 @@ static const std::pair NEONEquivalentIntrinsicMap[] = { { NEON::BI__builtin_neon_vabdq_f16, NEON::BI__builtin_neon_vabdq_v, }, { NEON::BI__builtin_neon_vabs_f16, NEON::BI__builtin_neon_vabs_v, }, { NEON::BI__builtin_neon_vabsq_f16, NEON::BI__builtin_neon_vabsq_v, }, - { NEON::BI__builtin_neon_vbsl_f16, NEON::BI__builtin_neon_vbsl_v, }, - { NEON::BI__builtin_neon_vbslq_f16, NEON::BI__builtin_neon_vbslq_v, }, { NEON::BI__builtin_neon_vcage_f16, NEON::BI__builtin_neon_vcage_v, }, { NEON::BI__builtin_neon_vcageq_f16, NEON::BI__builtin_neon_vcageq_v, }, { NEON::BI__builtin_neon_vcagt_f16, NEON::BI__builtin_neon_vcagt_v, }, @@ -7210,8 +7300,6 @@ static const std::pair NEONEquivalentIntrinsicMap[] = { { NEON::BI__builtin_neon_vclezq_f16, NEON::BI__builtin_neon_vclezq_v, }, { NEON::BI__builtin_neon_vcltz_f16, NEON::BI__builtin_neon_vcltz_v, }, { NEON::BI__builtin_neon_vcltzq_f16, NEON::BI__builtin_neon_vcltzq_v, }, - { NEON::BI__builtin_neon_vext_f16, NEON::BI__builtin_neon_vext_v, }, - { NEON::BI__builtin_neon_vextq_f16, NEON::BI__builtin_neon_vextq_v, }, { NEON::BI__builtin_neon_vfma_f16, NEON::BI__builtin_neon_vfma_v, }, { NEON::BI__builtin_neon_vfma_lane_f16, NEON::BI__builtin_neon_vfma_lane_v, }, { NEON::BI__builtin_neon_vfma_laneq_f16, NEON::BI__builtin_neon_vfma_laneq_v, }, @@ -7314,12 +7402,6 @@ static const std::pair NEONEquivalentIntrinsicMap[] = { { NEON::BI__builtin_neon_vst4_lane_bf16, NEON::BI__builtin_neon_vst4_lane_v }, { NEON::BI__builtin_neon_vst4q_bf16, NEON::BI__builtin_neon_vst4q_v }, { NEON::BI__builtin_neon_vst4q_lane_bf16, NEON::BI__builtin_neon_vst4q_lane_v }, - { NEON::BI__builtin_neon_vtrn_f16, NEON::BI__builtin_neon_vtrn_v, }, - { NEON::BI__builtin_neon_vtrnq_f16, NEON::BI__builtin_neon_vtrnq_v, }, - { NEON::BI__builtin_neon_vuzp_f16, NEON::BI__builtin_neon_vuzp_v, }, - { NEON::BI__builtin_neon_vuzpq_f16, NEON::BI__builtin_neon_vuzpq_v, }, - { NEON::BI__builtin_neon_vzip_f16, NEON::BI__builtin_neon_vzip_v, }, - { NEON::BI__builtin_neon_vzipq_f16, NEON::BI__builtin_neon_vzipq_v, }, // The mangling rules cause us to have one ID for each type for vldap1(q)_lane // and vstl1(q)_lane, but codegen is equivalent for all of them. Choose an // arbitrary one to be handled as tha canonical variation. @@ -8849,7 +8931,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, // Get the alignment for the argument in addition to the value; // we'll use it later. PtrOp0 = EmitPointerWithAlignment(E->getArg(0)); - Ops.push_back(PtrOp0.getPointer()); + Ops.push_back(PtrOp0.emitRawPointer(*this)); continue; } } @@ -8876,7 +8958,7 @@ Value *CodeGenFunction::EmitARMBuiltinExpr(unsigned BuiltinID, // Get the alignment for the argument in addition to the value; // we'll use it later. PtrOp1 = EmitPointerWithAlignment(E->getArg(1)); - Ops.push_back(PtrOp1.getPointer()); + Ops.push_back(PtrOp1.emitRawPointer(*this)); continue; } } @@ -9297,7 +9379,7 @@ Value *CodeGenFunction::EmitARMMVEBuiltinExpr(unsigned BuiltinID, if (ReturnValue.isNull()) return MvecOut; else - return Builder.CreateStore(MvecOut, ReturnValue.getValue()); + return Builder.CreateStore(MvecOut, ReturnValue.getAddress()); } case CustomCodeGen::VST24: { @@ -11477,7 +11559,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID, // Get the alignment for the argument in addition to the value; // we'll use it later. PtrOp0 = EmitPointerWithAlignment(E->getArg(0)); - Ops.push_back(PtrOp0.getPointer()); + Ops.push_back(PtrOp0.emitRawPointer(*this)); continue; } } @@ -13343,15 +13425,15 @@ Value *CodeGenFunction::EmitBPFBuiltinExpr(unsigned BuiltinID, if (!getDebugInfo()) { CGM.Error(E->getExprLoc(), "using __builtin_preserve_field_info() without -g"); - return IsBitField ? EmitLValue(Arg).getBitFieldPointer() - : EmitLValue(Arg).getPointer(*this); + return IsBitField ? EmitLValue(Arg).getRawBitFieldPointer(*this) + : EmitLValue(Arg).emitRawPointer(*this); } // Enable underlying preserve_*_access_index() generation. bool OldIsInPreservedAIRegion = IsInPreservedAIRegion; IsInPreservedAIRegion = true; - Value *FieldAddr = IsBitField ? EmitLValue(Arg).getBitFieldPointer() - : EmitLValue(Arg).getPointer(*this); + Value *FieldAddr = IsBitField ? EmitLValue(Arg).getRawBitFieldPointer(*this) + : EmitLValue(Arg).emitRawPointer(*this); IsInPreservedAIRegion = OldIsInPreservedAIRegion; ConstantInt *C = cast(EmitScalarExpr(E->getArg(1))); @@ -14343,14 +14425,14 @@ Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, } case X86::BI_mm_setcsr: case X86::BI__builtin_ia32_ldmxcsr: { - Address Tmp = CreateMemTemp(E->getArg(0)->getType()); + RawAddress Tmp = CreateMemTemp(E->getArg(0)->getType()); Builder.CreateStore(Ops[0], Tmp); return Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_ldmxcsr), Tmp.getPointer()); } case X86::BI_mm_getcsr: case X86::BI__builtin_ia32_stmxcsr: { - Address Tmp = CreateMemTemp(E->getType()); + RawAddress Tmp = CreateMemTemp(E->getType()); Builder.CreateCall(CGM.getIntrinsic(Intrinsic::x86_sse_stmxcsr), Tmp.getPointer()); return Builder.CreateLoad(Tmp, "stmxcsr"); @@ -17206,6 +17288,16 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, Value *Op1 = EmitScalarExpr(E->getArg(1)); Value *Op2 = EmitScalarExpr(E->getArg(2)); Value *Op3 = EmitScalarExpr(E->getArg(3)); + // rldimi is 64-bit instruction, expand the intrinsic before isel to + // leverage peephole and avoid legalization efforts. + if (BuiltinID == PPC::BI__builtin_ppc_rldimi && + !getTarget().getTriple().isPPC64()) { + Function *F = CGM.getIntrinsic(Intrinsic::fshl, Op0->getType()); + Op2 = Builder.CreateZExt(Op2, Int64Ty); + Value *Shift = Builder.CreateCall(F, {Op0, Op0, Op2}); + return Builder.CreateOr(Builder.CreateAnd(Shift, Op3), + Builder.CreateAnd(Op1, Builder.CreateNot(Op3))); + } return Builder.CreateCall( CGM.getIntrinsic(BuiltinID == PPC::BI__builtin_ppc_rldimi ? Intrinsic::ppc_rldimi @@ -17625,7 +17717,8 @@ Value *CodeGenFunction::EmitPPCBuiltinExpr(unsigned BuiltinID, SmallVector Ops; for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) if (E->getArg(i)->getType()->isArrayType()) - Ops.push_back(EmitArrayToPointerDecay(E->getArg(i)).getPointer()); + Ops.push_back( + EmitArrayToPointerDecay(E->getArg(i)).emitRawPointer(*this)); else Ops.push_back(EmitScalarExpr(E->getArg(i))); // The first argument of these two builtins is a pointer used to store their @@ -18066,15 +18159,22 @@ llvm::Value *CodeGenFunction::EmitScalarOrConstFoldImmArg(unsigned ICEArguments, return Arg; } -Intrinsic::ID getDotProductIntrinsic(QualType QT) { +Intrinsic::ID getDotProductIntrinsic(QualType QT, int elementCount) { + if (QT->hasFloatingRepresentation()) { + switch (elementCount) { + case 2: + return Intrinsic::dx_dot2; + case 3: + return Intrinsic::dx_dot3; + case 4: + return Intrinsic::dx_dot4; + } + } if (QT->hasSignedIntegerRepresentation()) return Intrinsic::dx_sdot; - if (QT->hasUnsignedIntegerRepresentation()) - return Intrinsic::dx_udot; - assert(QT->hasFloatingRepresentation()); - return Intrinsic::dx_dot; - ; + assert(QT->hasUnsignedIntegerRepresentation()); + return Intrinsic::dx_udot; } Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, @@ -18083,6 +18183,13 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, return nullptr; switch (BuiltinID) { + case Builtin::BI__builtin_hlsl_elementwise_all: { + Value *Op0 = EmitScalarExpr(E->getArg(0)); + return Builder.CreateIntrinsic( + /*ReturnType=*/llvm::Type::getInt1Ty(getLLVMContext()), + CGM.getHLSLRuntime().getAllIntrinsic(), ArrayRef{Op0}, nullptr, + "hlsl.all"); + } case Builtin::BI__builtin_hlsl_elementwise_any: { Value *Op0 = EmitScalarExpr(E->getArg(0)); return Builder.CreateIntrinsic( @@ -18128,8 +18235,7 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, assert(T0->getScalarType() == T1->getScalarType() && "Dot product of vectors need the same element types."); - [[maybe_unused]] auto *VecTy0 = - E->getArg(0)->getType()->getAs(); + auto *VecTy0 = E->getArg(0)->getType()->getAs(); [[maybe_unused]] auto *VecTy1 = E->getArg(1)->getType()->getAs(); // A HLSLVectorTruncation should have happend @@ -18138,7 +18244,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, return Builder.CreateIntrinsic( /*ReturnType=*/T0->getScalarType(), - getDotProductIntrinsic(E->getArg(0)->getType()), + getDotProductIntrinsic(E->getArg(0)->getType(), + VecTy0->getNumElements()), ArrayRef{Op0, Op1}, nullptr, "dx.dot"); } break; case Builtin::BI__builtin_hlsl_lerp: { @@ -18208,6 +18315,14 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, /*ReturnType=*/Op0->getType(), Intrinsic::dx_rsqrt, ArrayRef{Op0}, nullptr, "dx.rsqrt"); } + case Builtin::BI__builtin_hlsl_wave_get_lane_index: { + auto *CI = EmitRuntimeCall(CGM.CreateRuntimeFunction( + llvm::FunctionType::get(IntTy, {}, false), "__hlsl_wave_get_lane_index", + {}, false, true)); + if (getTarget().getTriple().isSPIRVLogical()) + CI = dyn_cast(addControlledConvergenceToken(CI)); + return CI; + } } return nullptr; } @@ -18531,43 +18646,25 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID, llvm::Function *F = CGM.getIntrinsic(IID, {ArgTy}); return Builder.CreateCall(F, {Addr, Val, ZeroI32, ZeroI32, ZeroI1}); } - case AMDGPU::BI__builtin_amdgcn_global_load_tr_i32: - case AMDGPU::BI__builtin_amdgcn_global_load_tr_v2i32: - case AMDGPU::BI__builtin_amdgcn_global_load_tr_v4f16: - case AMDGPU::BI__builtin_amdgcn_global_load_tr_v4i16: - case AMDGPU::BI__builtin_amdgcn_global_load_tr_v8f16: - case AMDGPU::BI__builtin_amdgcn_global_load_tr_v8i16: { + case AMDGPU::BI__builtin_amdgcn_global_load_tr_b64_i32: + case AMDGPU::BI__builtin_amdgcn_global_load_tr_b64_v2i32: + case AMDGPU::BI__builtin_amdgcn_global_load_tr_b128_v4i16: + case AMDGPU::BI__builtin_amdgcn_global_load_tr_b128_v8i16: { - llvm::Type *ArgTy; + Intrinsic::ID IID; switch (BuiltinID) { - case AMDGPU::BI__builtin_amdgcn_global_load_tr_i32: - ArgTy = llvm::Type::getInt32Ty(getLLVMContext()); + case AMDGPU::BI__builtin_amdgcn_global_load_tr_b64_i32: + case AMDGPU::BI__builtin_amdgcn_global_load_tr_b64_v2i32: + IID = Intrinsic::amdgcn_global_load_tr_b64; break; - case AMDGPU::BI__builtin_amdgcn_global_load_tr_v2i32: - ArgTy = llvm::FixedVectorType::get( - llvm::Type::getInt32Ty(getLLVMContext()), 2); - break; - case AMDGPU::BI__builtin_amdgcn_global_load_tr_v4f16: - ArgTy = llvm::FixedVectorType::get( - llvm::Type::getHalfTy(getLLVMContext()), 4); - break; - case AMDGPU::BI__builtin_amdgcn_global_load_tr_v4i16: - ArgTy = llvm::FixedVectorType::get( - llvm::Type::getInt16Ty(getLLVMContext()), 4); - break; - case AMDGPU::BI__builtin_amdgcn_global_load_tr_v8f16: - ArgTy = llvm::FixedVectorType::get( - llvm::Type::getHalfTy(getLLVMContext()), 8); - break; - case AMDGPU::BI__builtin_amdgcn_global_load_tr_v8i16: - ArgTy = llvm::FixedVectorType::get( - llvm::Type::getInt16Ty(getLLVMContext()), 8); + case AMDGPU::BI__builtin_amdgcn_global_load_tr_b128_v4i16: + case AMDGPU::BI__builtin_amdgcn_global_load_tr_b128_v8i16: + IID = Intrinsic::amdgcn_global_load_tr_b128; break; } - + llvm::Type *LoadTy = ConvertType(E->getType()); llvm::Value *Addr = EmitScalarExpr(E->getArg(0)); - llvm::Function *F = - CGM.getIntrinsic(Intrinsic::amdgcn_global_load_tr, {ArgTy}); + llvm::Function *F = CGM.getIntrinsic(IID, {LoadTy}); return Builder.CreateCall(F, {Addr}); } case AMDGPU::BI__builtin_amdgcn_get_fpenv: { @@ -20098,14 +20195,14 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, // Save returned values. assert(II.NumResults); if (II.NumResults == 1) { - Builder.CreateAlignedStore(Result, Dst.getPointer(), + Builder.CreateAlignedStore(Result, Dst.emitRawPointer(*this), CharUnits::fromQuantity(4)); } else { for (unsigned i = 0; i < II.NumResults; ++i) { Builder.CreateAlignedStore( Builder.CreateBitCast(Builder.CreateExtractValue(Result, i), Dst.getElementType()), - Builder.CreateGEP(Dst.getElementType(), Dst.getPointer(), + Builder.CreateGEP(Dst.getElementType(), Dst.emitRawPointer(*this), llvm::ConstantInt::get(IntTy, i)), CharUnits::fromQuantity(4)); } @@ -20145,7 +20242,7 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, for (unsigned i = 0; i < II.NumResults; ++i) { Value *V = Builder.CreateAlignedLoad( Src.getElementType(), - Builder.CreateGEP(Src.getElementType(), Src.getPointer(), + Builder.CreateGEP(Src.getElementType(), Src.emitRawPointer(*this), llvm::ConstantInt::get(IntTy, i)), CharUnits::fromQuantity(4)); Values.push_back(Builder.CreateBitCast(V, ParamType)); @@ -20217,7 +20314,7 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, for (unsigned i = 0; i < MI.NumEltsA; ++i) { Value *V = Builder.CreateAlignedLoad( SrcA.getElementType(), - Builder.CreateGEP(SrcA.getElementType(), SrcA.getPointer(), + Builder.CreateGEP(SrcA.getElementType(), SrcA.emitRawPointer(*this), llvm::ConstantInt::get(IntTy, i)), CharUnits::fromQuantity(4)); Values.push_back(Builder.CreateBitCast(V, AType)); @@ -20227,7 +20324,7 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, for (unsigned i = 0; i < MI.NumEltsB; ++i) { Value *V = Builder.CreateAlignedLoad( SrcB.getElementType(), - Builder.CreateGEP(SrcB.getElementType(), SrcB.getPointer(), + Builder.CreateGEP(SrcB.getElementType(), SrcB.emitRawPointer(*this), llvm::ConstantInt::get(IntTy, i)), CharUnits::fromQuantity(4)); Values.push_back(Builder.CreateBitCast(V, BType)); @@ -20238,7 +20335,7 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, for (unsigned i = 0; i < MI.NumEltsC; ++i) { Value *V = Builder.CreateAlignedLoad( SrcC.getElementType(), - Builder.CreateGEP(SrcC.getElementType(), SrcC.getPointer(), + Builder.CreateGEP(SrcC.getElementType(), SrcC.emitRawPointer(*this), llvm::ConstantInt::get(IntTy, i)), CharUnits::fromQuantity(4)); Values.push_back(Builder.CreateBitCast(V, CType)); @@ -20248,7 +20345,7 @@ Value *CodeGenFunction::EmitNVPTXBuiltinExpr(unsigned BuiltinID, for (unsigned i = 0; i < MI.NumEltsD; ++i) Builder.CreateAlignedStore( Builder.CreateBitCast(Builder.CreateExtractValue(Result, i), DType), - Builder.CreateGEP(Dst.getElementType(), Dst.getPointer(), + Builder.CreateGEP(Dst.getElementType(), Dst.emitRawPointer(*this), llvm::ConstantInt::get(IntTy, i)), CharUnits::fromQuantity(4)); return Result; @@ -20506,7 +20603,7 @@ struct BuiltinAlignArgs { BuiltinAlignArgs(const CallExpr *E, CodeGenFunction &CGF) { QualType AstType = E->getArg(0)->getType(); if (AstType->isArrayType()) - Src = CGF.EmitArrayToPointerDecay(E->getArg(0)).getPointer(); + Src = CGF.EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(CGF); else Src = CGF.EmitScalarExpr(E->getArg(0)); SrcType = Src->getType(); @@ -21124,7 +21221,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, } case WebAssembly::BI__builtin_wasm_table_get: { assert(E->getArg(0)->getType()->isArrayType()); - Value *Table = EmitArrayToPointerDecay(E->getArg(0)).getPointer(); + Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); Value *Index = EmitScalarExpr(E->getArg(1)); Function *Callee; if (E->getType().isWebAssemblyExternrefType()) @@ -21138,7 +21235,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, } case WebAssembly::BI__builtin_wasm_table_set: { assert(E->getArg(0)->getType()->isArrayType()); - Value *Table = EmitArrayToPointerDecay(E->getArg(0)).getPointer(); + Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); Value *Index = EmitScalarExpr(E->getArg(1)); Value *Val = EmitScalarExpr(E->getArg(2)); Function *Callee; @@ -21153,13 +21250,13 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, } case WebAssembly::BI__builtin_wasm_table_size: { assert(E->getArg(0)->getType()->isArrayType()); - Value *Value = EmitArrayToPointerDecay(E->getArg(0)).getPointer(); + Value *Value = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_size); return Builder.CreateCall(Callee, Value); } case WebAssembly::BI__builtin_wasm_table_grow: { assert(E->getArg(0)->getType()->isArrayType()); - Value *Table = EmitArrayToPointerDecay(E->getArg(0)).getPointer(); + Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); Value *Val = EmitScalarExpr(E->getArg(1)); Value *NElems = EmitScalarExpr(E->getArg(2)); @@ -21176,7 +21273,7 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, } case WebAssembly::BI__builtin_wasm_table_fill: { assert(E->getArg(0)->getType()->isArrayType()); - Value *Table = EmitArrayToPointerDecay(E->getArg(0)).getPointer(); + Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); Value *Index = EmitScalarExpr(E->getArg(1)); Value *Val = EmitScalarExpr(E->getArg(2)); Value *NElems = EmitScalarExpr(E->getArg(3)); @@ -21194,8 +21291,8 @@ Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID, } case WebAssembly::BI__builtin_wasm_table_copy: { assert(E->getArg(0)->getType()->isArrayType()); - Value *TableX = EmitArrayToPointerDecay(E->getArg(0)).getPointer(); - Value *TableY = EmitArrayToPointerDecay(E->getArg(1)).getPointer(); + Value *TableX = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this); + Value *TableY = EmitArrayToPointerDecay(E->getArg(1)).emitRawPointer(*this); Value *DstIdx = EmitScalarExpr(E->getArg(2)); Value *SrcIdx = EmitScalarExpr(E->getArg(3)); Value *NElems = EmitScalarExpr(E->getArg(4)); @@ -21274,7 +21371,7 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID, auto MakeCircOp = [this, E](unsigned IntID, bool IsLoad) { // The base pointer is passed by address, so it needs to be loaded. Address A = EmitPointerWithAlignment(E->getArg(0)); - Address BP = Address(A.getPointer(), Int8PtrTy, A.getAlignment()); + Address BP = Address(A.emitRawPointer(*this), Int8PtrTy, A.getAlignment()); llvm::Value *Base = Builder.CreateLoad(BP); // The treatment of both loads and stores is the same: the arguments for // the builtin are the same as the arguments for the intrinsic. @@ -21315,8 +21412,8 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID, // EmitPointerWithAlignment and EmitScalarExpr evaluates the expression // per call. Address DestAddr = EmitPointerWithAlignment(E->getArg(1)); - DestAddr = Address(DestAddr.getPointer(), Int8Ty, DestAddr.getAlignment()); - llvm::Value *DestAddress = DestAddr.getPointer(); + DestAddr = DestAddr.withElementType(Int8Ty); + llvm::Value *DestAddress = DestAddr.emitRawPointer(*this); // Operands are Base, Dest, Modifier. // The intrinsic format in LLVM IR is defined as @@ -21367,8 +21464,8 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID, {EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)), PredIn}); llvm::Value *PredOut = Builder.CreateExtractValue(Result, 1); - Builder.CreateAlignedStore(Q2V(PredOut), PredAddr.getPointer(), - PredAddr.getAlignment()); + Builder.CreateAlignedStore(Q2V(PredOut), PredAddr.emitRawPointer(*this), + PredAddr.getAlignment()); return Builder.CreateExtractValue(Result, 0); } // These are identical to the builtins above, except they don't consume @@ -21386,8 +21483,8 @@ Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID, {EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1))}); llvm::Value *PredOut = Builder.CreateExtractValue(Result, 1); - Builder.CreateAlignedStore(Q2V(PredOut), PredAddr.getPointer(), - PredAddr.getAlignment()); + Builder.CreateAlignedStore(Q2V(PredOut), PredAddr.emitRawPointer(*this), + PredAddr.getAlignment()); return Builder.CreateExtractValue(Result, 0); } diff --git a/clang/lib/CodeGen/CGCUDANV.cpp b/clang/lib/CodeGen/CGCUDANV.cpp index d3f2573fd5e38abd8e87b88a07dc2c7970638a45..370642cb3d5364f8622125c6298d00fc61f7194c 100644 --- a/clang/lib/CodeGen/CGCUDANV.cpp +++ b/clang/lib/CodeGen/CGCUDANV.cpp @@ -331,11 +331,11 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF, llvm::ConstantInt::get(SizeTy, std::max(1, Args.size()))); // Store pointers to the arguments in a locally allocated launch_args. for (unsigned i = 0; i < Args.size(); ++i) { - llvm::Value* VarPtr = CGF.GetAddrOfLocalVar(Args[i]).getPointer(); + llvm::Value *VarPtr = CGF.GetAddrOfLocalVar(Args[i]).emitRawPointer(CGF); llvm::Value *VoidVarPtr = CGF.Builder.CreatePointerCast(VarPtr, PtrTy); CGF.Builder.CreateDefaultAlignedStore( - VoidVarPtr, - CGF.Builder.CreateConstGEP1_32(PtrTy, KernelArgs.getPointer(), i)); + VoidVarPtr, CGF.Builder.CreateConstGEP1_32( + PtrTy, KernelArgs.emitRawPointer(CGF), i)); } llvm::BasicBlock *EndBlock = CGF.createBasicBlock("setup.end"); @@ -361,7 +361,7 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF, KernelLaunchAPI = KernelLaunchAPI + "_ptsz"; } auto LaunchKernelName = addPrefixToName(KernelLaunchAPI); - IdentifierInfo &cudaLaunchKernelII = + const IdentifierInfo &cudaLaunchKernelII = CGM.getContext().Idents.get(LaunchKernelName); FunctionDecl *cudaLaunchKernelFD = nullptr; for (auto *Result : DC->lookup(&cudaLaunchKernelII)) { @@ -393,9 +393,10 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF, /*isVarArg=*/false), addUnderscoredPrefixToName("PopCallConfiguration")); - CGF.EmitRuntimeCallOrInvoke(cudaPopConfigFn, - {GridDim.getPointer(), BlockDim.getPointer(), - ShmemSize.getPointer(), Stream.getPointer()}); + CGF.EmitRuntimeCallOrInvoke(cudaPopConfigFn, {GridDim.emitRawPointer(CGF), + BlockDim.emitRawPointer(CGF), + ShmemSize.emitRawPointer(CGF), + Stream.emitRawPointer(CGF)}); // Emit the call to cudaLaunch llvm::Value *Kernel = @@ -405,7 +406,7 @@ void CGNVCUDARuntime::emitDeviceStubBodyNew(CodeGenFunction &CGF, cudaLaunchKernelFD->getParamDecl(0)->getType()); LaunchKernelArgs.add(RValue::getAggregate(GridDim), Dim3Ty); LaunchKernelArgs.add(RValue::getAggregate(BlockDim), Dim3Ty); - LaunchKernelArgs.add(RValue::get(KernelArgs.getPointer()), + LaunchKernelArgs.add(RValue::get(KernelArgs, CGF), cudaLaunchKernelFD->getParamDecl(3)->getType()); LaunchKernelArgs.add(RValue::get(CGF.Builder.CreateLoad(ShmemSize)), cudaLaunchKernelFD->getParamDecl(4)->getType()); @@ -438,8 +439,8 @@ void CGNVCUDARuntime::emitDeviceStubBodyLegacy(CodeGenFunction &CGF, auto TInfo = CGM.getContext().getTypeInfoInChars(A->getType()); Offset = Offset.alignTo(TInfo.Align); llvm::Value *Args[] = { - CGF.Builder.CreatePointerCast(CGF.GetAddrOfLocalVar(A).getPointer(), - PtrTy), + CGF.Builder.CreatePointerCast( + CGF.GetAddrOfLocalVar(A).emitRawPointer(CGF), PtrTy), llvm::ConstantInt::get(SizeTy, TInfo.Width.getQuantity()), llvm::ConstantInt::get(SizeTy, Offset.getQuantity()), }; @@ -605,20 +606,10 @@ llvm::Function *CGNVCUDARuntime::makeRegisterGlobalsFn() { uint64_t VarSize = CGM.getDataLayout().getTypeAllocSize(Var->getValueType()); if (Info.Flags.isManaged()) { - auto *ManagedVar = new llvm::GlobalVariable( - CGM.getModule(), Var->getType(), - /*isConstant=*/false, Var->getLinkage(), - /*Init=*/Var->isDeclaration() - ? nullptr - : llvm::ConstantPointerNull::get(Var->getType()), - /*Name=*/"", /*InsertBefore=*/nullptr, - llvm::GlobalVariable::NotThreadLocal); - ManagedVar->setDSOLocal(Var->isDSOLocal()); - ManagedVar->setVisibility(Var->getVisibility()); - ManagedVar->setExternallyInitialized(true); - ManagedVar->takeName(Var); - Var->setName(Twine(ManagedVar->getName() + ".managed")); - replaceManagedVar(Var, ManagedVar); + assert(Var->getName().ends_with(".managed") && + "HIP managed variables not transformed"); + auto *ManagedVar = CGM.getModule().getNamedGlobal( + Var->getName().drop_back(StringRef(".managed").size())); llvm::Value *Args[] = { &GpuBinaryHandlePtr, ManagedVar, @@ -1093,7 +1084,9 @@ void CGNVCUDARuntime::transformManagedVars() { : llvm::ConstantPointerNull::get(Var->getType()), /*Name=*/"", /*InsertBefore=*/nullptr, llvm::GlobalVariable::NotThreadLocal, - CGM.getContext().getTargetAddressSpace(LangAS::cuda_device)); + CGM.getContext().getTargetAddressSpace(CGM.getLangOpts().CUDAIsDevice + ? LangAS::cuda_device + : LangAS::Default)); ManagedVar->setDSOLocal(Var->isDSOLocal()); ManagedVar->setVisibility(Var->getVisibility()); ManagedVar->setExternallyInitialized(true); @@ -1102,7 +1095,7 @@ void CGNVCUDARuntime::transformManagedVars() { Var->setName(Twine(ManagedVar->getName()) + ".managed"); // Keep managed variables even if they are not used in device code since // they need to be allocated by the runtime. - if (!Var->isDeclaration()) { + if (CGM.getLangOpts().CUDAIsDevice && !Var->isDeclaration()) { assert(!ManagedVar->isDeclaration()); CGM.addCompilerUsedGlobal(Var); CGM.addCompilerUsedGlobal(ManagedVar); @@ -1160,9 +1153,8 @@ void CGNVCUDARuntime::createOffloadingEntries() { // Returns module constructor to be added. llvm::Function *CGNVCUDARuntime::finalizeModule() { + transformManagedVars(); if (CGM.getLangOpts().CUDAIsDevice) { - transformManagedVars(); - // Mark ODR-used device variables as compiler used to prevent it from being // eliminated by optimization. This is necessary for device variables // ODR-used by host functions. Sema correctly marks them as ODR-used no diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp index a8bf57a277e90963350a58848acdaa6579ce2236..7c6dfc3e59d8c0eb547fbd786378db2457f6a96f 100644 --- a/clang/lib/CodeGen/CGCXXABI.cpp +++ b/clang/lib/CodeGen/CGCXXABI.cpp @@ -20,6 +20,12 @@ using namespace CodeGen; CGCXXABI::~CGCXXABI() { } +Address CGCXXABI::getThisAddress(CodeGenFunction &CGF) { + return CGF.makeNaturalAddressForPointer( + CGF.CXXABIThisValue, CGF.CXXABIThisDecl->getType()->getPointeeType(), + CGF.CXXABIThisAlignment); +} + void CGCXXABI::ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S) { DiagnosticsEngine &Diags = CGF.CGM.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, @@ -44,8 +50,12 @@ CGCallee CGCXXABI::EmitLoadOfMemberFunctionPointer( llvm::Value *MemPtr, const MemberPointerType *MPT) { ErrorUnsupportedABI(CGF, "calls through member pointers"); - ThisPtrForCall = This.getPointer(); - const auto *FPT = MPT->getPointeeType()->castAs(); + const auto *RD = + cast(MPT->getClass()->castAs()->getDecl()); + ThisPtrForCall = + CGF.getAsNaturalPointerTo(This, CGF.getContext().getRecordType(RD)); + const FunctionProtoType *FPT = + MPT->getPointeeType()->getAs(); llvm::Constant *FnPtr = llvm::Constant::getNullValue( llvm::PointerType::getUnqual(CGM.getLLVMContext())); return CGCallee::forDirect(FnPtr, FPT); @@ -251,16 +261,15 @@ void CGCXXABI::ReadArrayCookie(CodeGenFunction &CGF, Address ptr, // If we don't need an array cookie, bail out early. if (!requiresArrayCookie(expr, eltTy)) { - allocPtr = ptr.getPointer(); + allocPtr = ptr.emitRawPointer(CGF); numElements = nullptr; cookieSize = CharUnits::Zero(); return; } cookieSize = getArrayCookieSizeImpl(eltTy); - Address allocAddr = - CGF.Builder.CreateConstInBoundsByteGEP(ptr, -cookieSize); - allocPtr = allocAddr.getPointer(); + Address allocAddr = CGF.Builder.CreateConstInBoundsByteGEP(ptr, -cookieSize); + allocPtr = allocAddr.emitRawPointer(CGF); numElements = readArrayCookieImpl(CGF, allocAddr, cookieSize); } diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h index ad1ad08d0856887e9c37e9d9358e76a87f521a39..c7eccbd0095a94c494e13f9f3785294adad95aae 100644 --- a/clang/lib/CodeGen/CGCXXABI.h +++ b/clang/lib/CodeGen/CGCXXABI.h @@ -57,12 +57,8 @@ protected: llvm::Value *getThisValue(CodeGenFunction &CGF) { return CGF.CXXABIThisValue; } - Address getThisAddress(CodeGenFunction &CGF) { - return Address( - CGF.CXXABIThisValue, - CGF.ConvertTypeForMem(CGF.CXXABIThisDecl->getType()->getPointeeType()), - CGF.CXXABIThisAlignment); - } + + Address getThisAddress(CodeGenFunction &CGF); /// Issue a diagnostic about unsupported features in the ABI. void ErrorUnsupportedABI(CodeGenFunction &CGF, StringRef S); @@ -475,12 +471,6 @@ public: BaseSubobject Base, const CXXRecordDecl *NearestVBase) = 0; - /// Get the address point of the vtable for the given base subobject while - /// building a constexpr. - virtual llvm::Constant * - getVTableAddressPointForConstExpr(BaseSubobject Base, - const CXXRecordDecl *VTableClass) = 0; - /// Get the address of the vtable for the given record decl which should be /// used for the vptr at the given offset in RD. virtual llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD, diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index a28d7888715d858430ff9893a80a4d86c23f9dfd..3f5463a9a70e9d81a9da46e76bebe8955f9b3073 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -74,6 +74,9 @@ unsigned CodeGenTypes::ClangCallConvToLLVMCallConv(CallingConv CC) { case CC_SwiftAsync: return llvm::CallingConv::SwiftTail; case CC_M68kRTD: return llvm::CallingConv::M68k_RTD; case CC_PreserveNone: return llvm::CallingConv::PreserveNone; + // clang-format off + case CC_RISCVVectorCall: return llvm::CallingConv::RISCV_VectorCall; + // clang-format on } } @@ -260,6 +263,9 @@ static CallingConv getCallingConventionForDecl(const ObjCMethodDecl *D, if (D->hasAttr()) return CC_PreserveNone; + if (D->hasAttr()) + return CC_RISCVVectorCall; + return CC_C; } @@ -933,8 +939,8 @@ struct NoExpansion : TypeExpansion { static std::unique_ptr getTypeExpansion(QualType Ty, const ASTContext &Context) { if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { - return std::make_unique( - AT->getElementType(), AT->getSize().getZExtValue()); + return std::make_unique(AT->getElementType(), + AT->getZExtSize()); } if (const RecordType *RT = Ty->getAs()) { SmallVector Bases; @@ -1031,15 +1037,9 @@ static void forConstantArrayExpansion(CodeGenFunction &CGF, ConstantArrayExpansion *CAE, Address BaseAddr, llvm::function_ref Fn) { - CharUnits EltSize = CGF.getContext().getTypeSizeInChars(CAE->EltTy); - CharUnits EltAlign = - BaseAddr.getAlignment().alignmentOfArrayElement(EltSize); - llvm::Type *EltTy = CGF.ConvertTypeForMem(CAE->EltTy); - for (int i = 0, n = CAE->NumElts; i < n; i++) { - llvm::Value *EltAddr = CGF.Builder.CreateConstGEP2_32( - BaseAddr.getElementType(), BaseAddr.getPointer(), 0, i); - Fn(Address(EltAddr, EltTy, EltAlign)); + Address EltAddr = CGF.Builder.CreateConstGEP2_32(BaseAddr, 0, i); + Fn(EltAddr); } } @@ -1154,9 +1154,10 @@ void CodeGenFunction::ExpandTypeToArgs( } /// Create a temporary allocation for the purposes of coercion. -static Address CreateTempAllocaForCoercion(CodeGenFunction &CGF, llvm::Type *Ty, - CharUnits MinAlign, - const Twine &Name = "tmp") { +static RawAddress CreateTempAllocaForCoercion(CodeGenFunction &CGF, + llvm::Type *Ty, + CharUnits MinAlign, + const Twine &Name = "tmp") { // Don't use an alignment that's worse than what LLVM would prefer. auto PrefAlign = CGF.CGM.getDataLayout().getPrefTypeAlign(Ty); CharUnits Align = std::max(MinAlign, CharUnits::fromQuantity(PrefAlign)); @@ -1326,11 +1327,11 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty, } // Otherwise do coercion through memory. This is stupid, but simple. - Address Tmp = + RawAddress Tmp = CreateTempAllocaForCoercion(CGF, Ty, Src.getAlignment(), Src.getName()); CGF.Builder.CreateMemCpy( - Tmp.getPointer(), Tmp.getAlignment().getAsAlign(), Src.getPointer(), - Src.getAlignment().getAsAlign(), + Tmp.getPointer(), Tmp.getAlignment().getAsAlign(), + Src.emitRawPointer(CGF), Src.getAlignment().getAsAlign(), llvm::ConstantInt::get(CGF.IntPtrTy, SrcSize.getKnownMinValue())); return CGF.Builder.CreateLoad(Tmp); } @@ -1414,11 +1415,12 @@ static void CreateCoercedStore(llvm::Value *Src, // // FIXME: Assert that we aren't truncating non-padding bits when have access // to that information. - Address Tmp = CreateTempAllocaForCoercion(CGF, SrcTy, Dst.getAlignment()); + RawAddress Tmp = + CreateTempAllocaForCoercion(CGF, SrcTy, Dst.getAlignment()); CGF.Builder.CreateStore(Src, Tmp); CGF.Builder.CreateMemCpy( - Dst.getPointer(), Dst.getAlignment().getAsAlign(), Tmp.getPointer(), - Tmp.getAlignment().getAsAlign(), + Dst.emitRawPointer(CGF), Dst.getAlignment().getAsAlign(), + Tmp.getPointer(), Tmp.getAlignment().getAsAlign(), llvm::ConstantInt::get(CGF.IntPtrTy, DstSize.getFixedValue())); } } @@ -3018,17 +3020,17 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, case ABIArgInfo::Indirect: case ABIArgInfo::IndirectAliased: { assert(NumIRArgs == 1); - Address ParamAddr = Address(Fn->getArg(FirstIRArg), ConvertTypeForMem(Ty), - ArgI.getIndirectAlign(), KnownNonNull); + Address ParamAddr = makeNaturalAddressForPointer( + Fn->getArg(FirstIRArg), Ty, ArgI.getIndirectAlign(), false, nullptr, + nullptr, KnownNonNull); if (!hasScalarEvaluationKind(Ty)) { // Aggregates and complex variables are accessed by reference. All we // need to do is realign the value, if requested. Also, if the address // may be aliased, copy it to ensure that the parameter variable is // mutable and has a unique adress, as C requires. - Address V = ParamAddr; if (ArgI.getIndirectRealign() || ArgI.isIndirectAliased()) { - Address AlignedTemp = CreateMemTemp(Ty, "coerce"); + RawAddress AlignedTemp = CreateMemTemp(Ty, "coerce"); // Copy from the incoming argument pointer to the temporary with the // appropriate alignment. @@ -3038,11 +3040,12 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, CharUnits Size = getContext().getTypeSizeInChars(Ty); Builder.CreateMemCpy( AlignedTemp.getPointer(), AlignedTemp.getAlignment().getAsAlign(), - ParamAddr.getPointer(), ParamAddr.getAlignment().getAsAlign(), + ParamAddr.emitRawPointer(*this), + ParamAddr.getAlignment().getAsAlign(), llvm::ConstantInt::get(IntPtrTy, Size.getQuantity())); - V = AlignedTemp; + ParamAddr = AlignedTemp; } - ArgVals.push_back(ParamValue::forIndirect(V)); + ArgVals.push_back(ParamValue::forIndirect(ParamAddr)); } else { // Load scalar value from indirect argument. llvm::Value *V = @@ -3086,7 +3089,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, llvm::Align Alignment = CGM.getNaturalTypeAlignment(ETy).getAsAlign(); AI->addAttrs(llvm::AttrBuilder(getLLVMContext()).addAlignmentAttr(Alignment)); - uint64_t ArrSize = ArrTy->getSize().getZExtValue(); + uint64_t ArrSize = ArrTy->getZExtSize(); if (!ETy->isIncompleteType() && ETy->isConstantSizeType() && ArrSize) { llvm::AttrBuilder Attrs(getLLVMContext()); @@ -3156,10 +3159,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, == ParameterABI::SwiftErrorResult) { QualType pointeeTy = Ty->getPointeeType(); assert(pointeeTy->isPointerType()); - Address temp = - CreateMemTemp(pointeeTy, getPointerAlign(), "swifterror.temp"); - Address arg(V, ConvertTypeForMem(pointeeTy), - getContext().getTypeAlignInChars(pointeeTy)); + RawAddress temp = + CreateMemTemp(pointeeTy, getPointerAlign(), "swifterror.temp"); + Address arg = makeNaturalAddressForPointer( + V, pointeeTy, getContext().getTypeAlignInChars(pointeeTy)); llvm::Value *incomingErrorValue = Builder.CreateLoad(arg); Builder.CreateStore(incomingErrorValue, temp); V = temp.getPointer(); @@ -3496,7 +3499,7 @@ static llvm::Value *tryRemoveRetainOfSelf(CodeGenFunction &CGF, llvm::LoadInst *load = dyn_cast(retainedValue->stripPointerCasts()); if (!load || load->isAtomic() || load->isVolatile() || - load->getPointerOperand() != CGF.GetAddrOfLocalVar(self).getPointer()) + load->getPointerOperand() != CGF.GetAddrOfLocalVar(self).getBasePointer()) return nullptr; // Okay! Burn it all down. This relies for correctness on the @@ -3533,12 +3536,15 @@ static llvm::Value *emitAutoreleaseOfResult(CodeGenFunction &CGF, /// Heuristically search for a dominating store to the return-value slot. static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) { + llvm::Value *ReturnValuePtr = CGF.ReturnValue.getBasePointer(); + // Check if a User is a store which pointerOperand is the ReturnValue. // We are looking for stores to the ReturnValue, not for stores of the // ReturnValue to some other location. - auto GetStoreIfValid = [&CGF](llvm::User *U) -> llvm::StoreInst * { + auto GetStoreIfValid = [&CGF, + ReturnValuePtr](llvm::User *U) -> llvm::StoreInst * { auto *SI = dyn_cast(U); - if (!SI || SI->getPointerOperand() != CGF.ReturnValue.getPointer() || + if (!SI || SI->getPointerOperand() != ReturnValuePtr || SI->getValueOperand()->getType() != CGF.ReturnValue.getElementType()) return nullptr; // These aren't actually possible for non-coerced returns, and we @@ -3552,7 +3558,7 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) { // for something immediately preceding the IP. Sometimes this can // happen with how we generate implicit-returns; it can also happen // with noreturn cleanups. - if (!CGF.ReturnValue.getPointer()->hasOneUse()) { + if (!ReturnValuePtr->hasOneUse()) { llvm::BasicBlock *IP = CGF.Builder.GetInsertBlock(); if (IP->empty()) return nullptr; @@ -3570,8 +3576,7 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) { return nullptr; } - llvm::StoreInst *store = - GetStoreIfValid(CGF.ReturnValue.getPointer()->user_back()); + llvm::StoreInst *store = GetStoreIfValid(ReturnValuePtr->user_back()); if (!store) return nullptr; // Now do a first-and-dirty dominance check: just walk up the @@ -4115,7 +4120,11 @@ void CodeGenFunction::EmitDelegateCallArg(CallArgList &args, } static bool isProvablyNull(llvm::Value *addr) { - return isa(addr); + return llvm::isa_and_nonnull(addr); +} + +static bool isProvablyNonNull(Address Addr, CodeGenFunction &CGF) { + return llvm::isKnownNonZero(Addr.getBasePointer(), CGF.CGM.getDataLayout()); } /// Emit the actual writing-back of a writeback. @@ -4123,21 +4132,20 @@ static void emitWriteback(CodeGenFunction &CGF, const CallArgList::Writeback &writeback) { const LValue &srcLV = writeback.Source; Address srcAddr = srcLV.getAddress(CGF); - assert(!isProvablyNull(srcAddr.getPointer()) && + assert(!isProvablyNull(srcAddr.getBasePointer()) && "shouldn't have writeback for provably null argument"); llvm::BasicBlock *contBB = nullptr; // If the argument wasn't provably non-null, we need to null check // before doing the store. - bool provablyNonNull = llvm::isKnownNonZero(srcAddr.getPointer(), - CGF.CGM.getDataLayout()); + bool provablyNonNull = isProvablyNonNull(srcAddr, CGF); + if (!provablyNonNull) { llvm::BasicBlock *writebackBB = CGF.createBasicBlock("icr.writeback"); contBB = CGF.createBasicBlock("icr.done"); - llvm::Value *isNull = - CGF.Builder.CreateIsNull(srcAddr.getPointer(), "icr.isnull"); + llvm::Value *isNull = CGF.Builder.CreateIsNull(srcAddr, "icr.isnull"); CGF.Builder.CreateCondBr(isNull, contBB, writebackBB); CGF.EmitBlock(writebackBB); } @@ -4241,7 +4249,7 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, CGF.ConvertTypeForMem(CRE->getType()->getPointeeType()); // If the address is a constant null, just pass the appropriate null. - if (isProvablyNull(srcAddr.getPointer())) { + if (isProvablyNull(srcAddr.getBasePointer())) { args.add(RValue::get(llvm::ConstantPointerNull::get(destType)), CRE->getType()); return; @@ -4270,17 +4278,16 @@ static void emitWritebackArg(CodeGenFunction &CGF, CallArgList &args, // If the address is *not* known to be non-null, we need to switch. llvm::Value *finalArgument; - bool provablyNonNull = llvm::isKnownNonZero(srcAddr.getPointer(), - CGF.CGM.getDataLayout()); + bool provablyNonNull = isProvablyNonNull(srcAddr, CGF); + if (provablyNonNull) { - finalArgument = temp.getPointer(); + finalArgument = temp.emitRawPointer(CGF); } else { - llvm::Value *isNull = - CGF.Builder.CreateIsNull(srcAddr.getPointer(), "icr.isnull"); + llvm::Value *isNull = CGF.Builder.CreateIsNull(srcAddr, "icr.isnull"); - finalArgument = CGF.Builder.CreateSelect(isNull, - llvm::ConstantPointerNull::get(destType), - temp.getPointer(), "icr.argument"); + finalArgument = CGF.Builder.CreateSelect( + isNull, llvm::ConstantPointerNull::get(destType), + temp.emitRawPointer(CGF), "icr.argument"); // If we need to copy, then the load has to be conditional, which // means we need control flow. @@ -4372,7 +4379,8 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType, NNAttr = getNonNullAttr(AC.getDecl(), PVD, ArgType, ArgNo); bool CanCheckNullability = false; - if (SanOpts.has(SanitizerKind::NullabilityArg) && !NNAttr && PVD) { + if (SanOpts.has(SanitizerKind::NullabilityArg) && !NNAttr && PVD && + !PVD->getType()->isRecordType()) { auto Nullability = PVD->getType()->getNullability(); CanCheckNullability = Nullability && *Nullability == NullabilityKind::NonNull && @@ -4404,6 +4412,16 @@ void CodeGenFunction::EmitNonNullArgCheck(RValue RV, QualType ArgType, EmitCheck(std::make_pair(Cond, CheckKind), Handler, StaticData, std::nullopt); } +void CodeGenFunction::EmitNonNullArgCheck(Address Addr, QualType ArgType, + SourceLocation ArgLoc, + AbstractCallee AC, unsigned ParmNum) { + if (!AC.getDecl() || !(SanOpts.has(SanitizerKind::NonnullAttribute) || + SanOpts.has(SanitizerKind::NullabilityArg))) + return; + + EmitNonNullArgCheck(RValue::get(Addr, *this), ArgType, ArgLoc, AC, ParmNum); +} + // Check if the call is going to use the inalloca convention. This needs to // agree with CGFunctionInfo::usesInAlloca. The CGFunctionInfo is arranged // later, so we can't check it directly. @@ -4702,7 +4720,8 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, } if (HasAggregateEvalKind && isa(E) && - cast(E)->getCastKind() == CK_LValueToRValue) { + cast(E)->getCastKind() == CK_LValueToRValue && + !type->isArrayParameterType()) { LValue L = EmitLValue(cast(E)->getSubExpr()); assert(L.isSimple()); args.addUncopiedAggregate(L, type); @@ -4744,10 +4763,20 @@ CodeGenFunction::AddObjCARCExceptionMetadata(llvm::Instruction *Inst) { llvm::CallInst * CodeGenFunction::EmitNounwindRuntimeCall(llvm::FunctionCallee callee, const llvm::Twine &name) { - return EmitNounwindRuntimeCall(callee, std::nullopt, name); + return EmitNounwindRuntimeCall(callee, ArrayRef(), name); } /// Emits a call to the given nounwind runtime function. +llvm::CallInst * +CodeGenFunction::EmitNounwindRuntimeCall(llvm::FunctionCallee callee, + ArrayRef
args, + const llvm::Twine &name) { + SmallVector values; + for (auto arg : args) + values.push_back(arg.emitRawPointer(*this)); + return EmitNounwindRuntimeCall(callee, values, name); +} + llvm::CallInst * CodeGenFunction::EmitNounwindRuntimeCall(llvm::FunctionCallee callee, ArrayRef args, @@ -5026,7 +5055,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // If we're using inalloca, insert the allocation after the stack save. // FIXME: Do this earlier rather than hacking it in here! - Address ArgMemory = Address::invalid(); + RawAddress ArgMemory = RawAddress::invalid(); if (llvm::StructType *ArgStruct = CallInfo.getArgStruct()) { const llvm::DataLayout &DL = CGM.getDataLayout(); llvm::Instruction *IP = CallArgs.getStackBase(); @@ -5042,7 +5071,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, AI->setAlignment(Align.getAsAlign()); AI->setUsedWithInAlloca(true); assert(AI->isUsedWithInAlloca() && !AI->isStaticAlloca()); - ArgMemory = Address(AI, ArgStruct, Align); + ArgMemory = RawAddress(AI, ArgStruct, Align); } ClangToLLVMArgMapping IRFunctionArgs(CGM.getContext(), CallInfo); @@ -5051,11 +5080,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, // If the call returns a temporary with struct return, create a temporary // alloca to hold the result, unless one is given to us. Address SRetPtr = Address::invalid(); - Address SRetAlloca = Address::invalid(); + RawAddress SRetAlloca = RawAddress::invalid(); llvm::Value *UnusedReturnSizePtr = nullptr; if (RetAI.isIndirect() || RetAI.isInAlloca() || RetAI.isCoerceAndExpand()) { if (!ReturnValue.isNull()) { - SRetPtr = ReturnValue.getValue(); + SRetPtr = ReturnValue.getAddress(); } else { SRetPtr = CreateMemTemp(RetTy, "tmp", &SRetAlloca); if (HaveInsertPoint() && ReturnValue.isUnused()) { @@ -5065,15 +5094,16 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, } } if (IRFunctionArgs.hasSRetArg()) { - IRCallArgs[IRFunctionArgs.getSRetArgNo()] = SRetPtr.getPointer(); + IRCallArgs[IRFunctionArgs.getSRetArgNo()] = + getAsNaturalPointerTo(SRetPtr, RetTy); } else if (RetAI.isInAlloca()) { Address Addr = Builder.CreateStructGEP(ArgMemory, RetAI.getInAllocaFieldIndex()); - Builder.CreateStore(SRetPtr.getPointer(), Addr); + Builder.CreateStore(getAsNaturalPointerTo(SRetPtr, RetTy), Addr); } } - Address swiftErrorTemp = Address::invalid(); + RawAddress swiftErrorTemp = RawAddress::invalid(); Address swiftErrorArg = Address::invalid(); // When passing arguments using temporary allocas, we need to add the @@ -5106,9 +5136,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, assert(NumIRArgs == 0); assert(getTarget().getTriple().getArch() == llvm::Triple::x86); if (I->isAggregate()) { - Address Addr = I->hasLValue() - ? I->getKnownLValue().getAddress(*this) - : I->getKnownRValue().getAggregateAddress(); + RawAddress Addr = I->hasLValue() + ? I->getKnownLValue().getAddress(*this) + : I->getKnownRValue().getAggregateAddress(); llvm::Instruction *Placeholder = cast(Addr.getPointer()); @@ -5132,7 +5162,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, } else if (ArgInfo.getInAllocaIndirect()) { // Make a temporary alloca and store the address of it into the argument // struct. - Address Addr = CreateMemTempWithoutCast( + RawAddress Addr = CreateMemTempWithoutCast( I->Ty, getContext().getTypeAlignInChars(I->Ty), "indirect-arg-temp"); I->copyInto(*this, Addr); @@ -5154,12 +5184,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, assert(NumIRArgs == 1); if (!I->isAggregate()) { // Make a temporary alloca to pass the argument. - Address Addr = CreateMemTempWithoutCast( + RawAddress Addr = CreateMemTempWithoutCast( I->Ty, ArgInfo.getIndirectAlign(), "indirect-arg-temp"); - llvm::Value *Val = Addr.getPointer(); + llvm::Value *Val = getAsNaturalPointerTo(Addr, I->Ty); if (ArgHasMaybeUndefAttr) - Val = Builder.CreateFreeze(Addr.getPointer()); + Val = Builder.CreateFreeze(Val); IRCallArgs[FirstIRArg] = Val; I->copyInto(*this, Addr); @@ -5175,7 +5205,6 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, Address Addr = I->hasLValue() ? I->getKnownLValue().getAddress(*this) : I->getKnownRValue().getAggregateAddress(); - llvm::Value *V = Addr.getPointer(); CharUnits Align = ArgInfo.getIndirectAlign(); const llvm::DataLayout *TD = &CGM.getDataLayout(); @@ -5186,8 +5215,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, bool NeedCopy = false; if (Addr.getAlignment() < Align && - llvm::getOrEnforceKnownAlignment(V, Align.getAsAlign(), *TD) < - Align.getAsAlign()) { + llvm::getOrEnforceKnownAlignment(Addr.emitRawPointer(*this), + Align.getAsAlign(), + *TD) < Align.getAsAlign()) { NeedCopy = true; } else if (I->hasLValue()) { auto LV = I->getKnownLValue(); @@ -5218,11 +5248,11 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (NeedCopy) { // Create an aligned temporary, and copy to it. - Address AI = CreateMemTempWithoutCast( + RawAddress AI = CreateMemTempWithoutCast( I->Ty, ArgInfo.getIndirectAlign(), "byval-temp"); - llvm::Value *Val = AI.getPointer(); + llvm::Value *Val = getAsNaturalPointerTo(AI, I->Ty); if (ArgHasMaybeUndefAttr) - Val = Builder.CreateFreeze(AI.getPointer()); + Val = Builder.CreateFreeze(Val); IRCallArgs[FirstIRArg] = Val; // Emit lifetime markers for the temporary alloca. @@ -5239,6 +5269,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, I->copyInto(*this, AI); } else { // Skip the extra memcpy call. + llvm::Value *V = getAsNaturalPointerTo(Addr, I->Ty); auto *T = llvm::PointerType::get( CGM.getLLVMContext(), CGM.getDataLayout().getAllocaAddrSpace()); @@ -5278,8 +5309,8 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, assert(!swiftErrorTemp.isValid() && "multiple swifterror args"); QualType pointeeTy = I->Ty->getPointeeType(); - swiftErrorArg = Address(V, ConvertTypeForMem(pointeeTy), - getContext().getTypeAlignInChars(pointeeTy)); + swiftErrorArg = makeNaturalAddressForPointer( + V, pointeeTy, getContext().getTypeAlignInChars(pointeeTy)); swiftErrorTemp = CreateMemTemp(pointeeTy, getPointerAlign(), "swifterror.temp"); @@ -5416,7 +5447,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, llvm::Value *tempSize = nullptr; Address addr = Address::invalid(); - Address AllocaAddr = Address::invalid(); + RawAddress AllocaAddr = RawAddress::invalid(); if (I->isAggregate()) { addr = I->hasLValue() ? I->getKnownLValue().getAddress(*this) : I->getKnownRValue().getAggregateAddress(); @@ -5560,6 +5591,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, /*AttrOnCallSite=*/true, /*IsThunk=*/false); + if (CallingConv == llvm::CallingConv::X86_VectorCall && + getTarget().getTriple().isWindowsArm64EC()) { + CGM.Error(Loc, "__vectorcall calling convention is not currently " + "supported"); + } + if (const FunctionDecl *FD = dyn_cast_or_null(CurFuncDecl)) { if (FD->hasAttr()) // All calls within a strictfp function are marked strictfp @@ -5686,6 +5723,9 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, if (!CI->getType()->isVoidTy()) CI->setName("call"); + if (getTarget().getTriple().isSPIRVLogical() && CI->isConvergent()) + CI = addControlledConvergenceToken(CI); + // Update largest vector width from the return type. LargestVectorWidth = std::max(LargestVectorWidth, getMaxVectorWidth(CI->getType())); @@ -5850,7 +5890,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo, return RValue::getComplex(std::make_pair(Real, Imag)); } case TEK_Aggregate: { - Address DestPtr = ReturnValue.getValue(); + Address DestPtr = ReturnValue.getAddress(); bool DestIsVolatile = ReturnValue.isVolatile(); if (!DestPtr.isValid()) { diff --git a/clang/lib/CodeGen/CGCall.h b/clang/lib/CodeGen/CGCall.h index 1bd48a07259307486a53f2eba0de9f221274d219..6b676ac196db2a9a19f721b924da2e9ea274324c 100644 --- a/clang/lib/CodeGen/CGCall.h +++ b/clang/lib/CodeGen/CGCall.h @@ -377,6 +377,7 @@ public: Address getValue() const { return Addr; } bool isUnused() const { return IsUnused; } bool isExternallyDestructed() const { return IsExternallyDestructed; } + Address getAddress() const { return Addr; } }; /// Adds attributes to \p F according to our \p CodeGenOpts and \p LangOpts, as diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 34319381901af6c9458fd6cea2af18cf97be75e7..b3077292f4a206a0b1459fb5ea031416b88482db 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -139,8 +139,9 @@ Address CodeGenFunction::LoadCXXThisAddress() { CXXThisAlignment = CGM.getClassPointerAlignment(MD->getParent()); } - llvm::Type *Ty = ConvertType(MD->getFunctionObjectParameterType()); - return Address(LoadCXXThis(), Ty, CXXThisAlignment, KnownNonNull); + return makeNaturalAddressForPointer( + LoadCXXThis(), MD->getFunctionObjectParameterType(), CXXThisAlignment, + false, nullptr, nullptr, KnownNonNull); } /// Emit the address of a field using a member data pointer. @@ -270,7 +271,7 @@ ApplyNonVirtualAndVirtualOffset(CodeGenFunction &CGF, Address addr, } // Apply the base offset. - llvm::Value *ptr = addr.getPointer(); + llvm::Value *ptr = addr.emitRawPointer(CGF); ptr = CGF.Builder.CreateInBoundsGEP(CGF.Int8Ty, ptr, baseOffset, "add.ptr"); // If we have a virtual component, the alignment of the result will @@ -338,8 +339,8 @@ Address CodeGenFunction::GetAddressOfBaseClass( if (sanitizePerformTypeCheck()) { SanitizerSet SkippedChecks; SkippedChecks.set(SanitizerKind::Null, !NullCheckValue); - EmitTypeCheck(TCK_Upcast, Loc, Value.getPointer(), - DerivedTy, DerivedAlign, SkippedChecks); + EmitTypeCheck(TCK_Upcast, Loc, Value.emitRawPointer(*this), DerivedTy, + DerivedAlign, SkippedChecks); } return Value.withElementType(BaseValueTy); } @@ -354,7 +355,7 @@ Address CodeGenFunction::GetAddressOfBaseClass( llvm::BasicBlock *notNullBB = createBasicBlock("cast.notnull"); endBB = createBasicBlock("cast.end"); - llvm::Value *isNull = Builder.CreateIsNull(Value.getPointer()); + llvm::Value *isNull = Builder.CreateIsNull(Value); Builder.CreateCondBr(isNull, endBB, notNullBB); EmitBlock(notNullBB); } @@ -363,14 +364,15 @@ Address CodeGenFunction::GetAddressOfBaseClass( SanitizerSet SkippedChecks; SkippedChecks.set(SanitizerKind::Null, true); EmitTypeCheck(VBase ? TCK_UpcastToVirtualBase : TCK_Upcast, Loc, - Value.getPointer(), DerivedTy, DerivedAlign, SkippedChecks); + Value.emitRawPointer(*this), DerivedTy, DerivedAlign, + SkippedChecks); } // Compute the virtual offset. llvm::Value *VirtualOffset = nullptr; if (VBase) { VirtualOffset = - CGM.getCXXABI().GetVirtualBaseClassOffset(*this, Value, Derived, VBase); + CGM.getCXXABI().GetVirtualBaseClassOffset(*this, Value, Derived, VBase); } // Apply both offsets. @@ -387,7 +389,7 @@ Address CodeGenFunction::GetAddressOfBaseClass( EmitBlock(endBB); llvm::PHINode *PHI = Builder.CreatePHI(PtrTy, 2, "cast.result"); - PHI->addIncoming(Value.getPointer(), notNullBB); + PHI->addIncoming(Value.emitRawPointer(*this), notNullBB); PHI->addIncoming(llvm::Constant::getNullValue(PtrTy), origBB); Value = Value.withPointer(PHI, NotKnownNonNull); } @@ -424,15 +426,19 @@ CodeGenFunction::GetAddressOfDerivedClass(Address BaseAddr, CastNotNull = createBasicBlock("cast.notnull"); CastEnd = createBasicBlock("cast.end"); - llvm::Value *IsNull = Builder.CreateIsNull(BaseAddr.getPointer()); + llvm::Value *IsNull = Builder.CreateIsNull(BaseAddr); Builder.CreateCondBr(IsNull, CastNull, CastNotNull); EmitBlock(CastNotNull); } // Apply the offset. - llvm::Value *Value = BaseAddr.getPointer(); - Value = Builder.CreateInBoundsGEP( - Int8Ty, Value, Builder.CreateNeg(NonVirtualOffset), "sub.ptr"); + Address Addr = BaseAddr.withElementType(Int8Ty); + Addr = Builder.CreateInBoundsGEP( + Addr, Builder.CreateNeg(NonVirtualOffset), Int8Ty, + CGM.getClassPointerAlignment(Derived), "sub.ptr"); + + // Just cast. + Addr = Addr.withElementType(DerivedValueTy); // Produce a PHI if we had a null-check. if (NullCheckValue) { @@ -441,13 +447,15 @@ CodeGenFunction::GetAddressOfDerivedClass(Address BaseAddr, Builder.CreateBr(CastEnd); EmitBlock(CastEnd); + llvm::Value *Value = Addr.emitRawPointer(*this); llvm::PHINode *PHI = Builder.CreatePHI(Value->getType(), 2); PHI->addIncoming(Value, CastNotNull); PHI->addIncoming(llvm::Constant::getNullValue(Value->getType()), CastNull); - Value = PHI; + return Address(PHI, Addr.getElementType(), + CGM.getClassPointerAlignment(Derived)); } - return Address(Value, DerivedValueTy, CGM.getClassPointerAlignment(Derived)); + return Addr; } llvm::Value *CodeGenFunction::GetVTTParameter(GlobalDecl GD, @@ -1396,7 +1404,7 @@ FieldHasTrivialDestructorBody(ASTContext &Context, // The destructor for an implicit anonymous union member is never invoked. if (FieldClassDecl->isUnion() && FieldClassDecl->isAnonymousStructOrUnion()) - return false; + return true; return HasTrivialDestructorBody(Context, FieldClassDecl, FieldClassDecl); } @@ -1719,7 +1727,7 @@ namespace { // Use the base class declaration location as inline DebugLocation. All // fields of the class are destroyed. DeclAsInlineDebugLocation InlineHere(CGF, *BaseClass); - EmitSanitizerDtorFieldsCallback(CGF, Addr.getPointer(), + EmitSanitizerDtorFieldsCallback(CGF, Addr.emitRawPointer(CGF), BaseSize.getQuantity()); // Prevent the current stack frame from disappearing from the stack trace. @@ -2022,7 +2030,7 @@ void CodeGenFunction::EmitCXXAggrConstructorCall(const CXXConstructorDecl *ctor, // Find the end of the array. llvm::Type *elementType = arrayBase.getElementType(); - llvm::Value *arrayBegin = arrayBase.getPointer(); + llvm::Value *arrayBegin = arrayBase.emitRawPointer(*this); llvm::Value *arrayEnd = Builder.CreateInBoundsGEP( elementType, arrayBegin, numElements, "arrayctor.end"); @@ -2118,14 +2126,15 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, Address This = ThisAVS.getAddress(); LangAS SlotAS = ThisAVS.getQualifiers().getAddressSpace(); LangAS ThisAS = D->getFunctionObjectParameterType().getAddressSpace(); - llvm::Value *ThisPtr = This.getPointer(); + llvm::Value *ThisPtr = + getAsNaturalPointerTo(This, D->getThisType()->getPointeeType()); if (SlotAS != ThisAS) { unsigned TargetThisAS = getContext().getTargetAddressSpace(ThisAS); llvm::Type *NewType = llvm::PointerType::get(getLLVMContext(), TargetThisAS); - ThisPtr = getTargetHooks().performAddrSpaceCast(*this, This.getPointer(), - ThisAS, SlotAS, NewType); + ThisPtr = getTargetHooks().performAddrSpaceCast(*this, ThisPtr, ThisAS, + SlotAS, NewType); } // Push the this ptr. @@ -2194,7 +2203,7 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, const CXXRecordDecl *ClassDecl = D->getParent(); if (!NewPointerIsChecked) - EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall, Loc, This.getPointer(), + EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall, Loc, This, getContext().getRecordType(ClassDecl), CharUnits::Zero()); if (D->isTrivial() && D->isDefaultConstructor()) { @@ -2207,10 +2216,9 @@ void CodeGenFunction::EmitCXXConstructorCall(const CXXConstructorDecl *D, // model that copy. if (isMemcpyEquivalentSpecialMember(D)) { assert(Args.size() == 2 && "unexpected argcount for trivial ctor"); - QualType SrcTy = D->getParamDecl(0)->getType().getNonReferenceType(); - Address Src = Address(Args[1].getRValue(*this).getScalarVal(), ConvertTypeForMem(SrcTy), - CGM.getNaturalTypeAlignment(SrcTy)); + Address Src = makeNaturalAddressForPointer( + Args[1].getRValue(*this).getScalarVal(), SrcTy); LValue SrcLVal = MakeAddrLValue(Src, SrcTy); QualType DestTy = getContext().getTypeDeclType(ClassDecl); LValue DestLVal = MakeAddrLValue(This, DestTy); @@ -2263,7 +2271,9 @@ void CodeGenFunction::EmitInheritedCXXConstructorCall( const CXXConstructorDecl *D, bool ForVirtualBase, Address This, bool InheritedFromVBase, const CXXInheritedCtorInitExpr *E) { CallArgList Args; - CallArg ThisArg(RValue::get(This.getPointer()), D->getThisType()); + CallArg ThisArg(RValue::get(getAsNaturalPointerTo( + This, D->getThisType()->getPointeeType())), + D->getThisType()); // Forward the parameters. if (InheritedFromVBase && @@ -2388,12 +2398,14 @@ CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D, CallArgList Args; // Push the this ptr. - Args.add(RValue::get(This.getPointer()), D->getThisType()); + Args.add(RValue::get(getAsNaturalPointerTo(This, D->getThisType())), + D->getThisType()); // Push the src ptr. QualType QT = *(FPT->param_type_begin()); llvm::Type *t = CGM.getTypes().ConvertType(QT); - llvm::Value *SrcVal = Builder.CreateBitCast(Src.getPointer(), t); + llvm::Value *Val = getAsNaturalPointerTo(Src, D->getThisType()); + llvm::Value *SrcVal = Builder.CreateBitCast(Val, t); Args.add(RValue::get(SrcVal), QT); // Skip over first argument (Src). @@ -2418,7 +2430,9 @@ CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor, // this Address This = LoadCXXThisAddress(); - DelegateArgs.add(RValue::get(This.getPointer()), (*I)->getType()); + DelegateArgs.add(RValue::get(getAsNaturalPointerTo( + This, (*I)->getType()->getPointeeType())), + (*I)->getType()); ++I; // FIXME: The location of the VTT parameter in the parameter list is @@ -2775,7 +2789,7 @@ void CodeGenFunction::EmitVTablePtrCheckForCast(QualType T, Address Derived, if (MayBeNull) { llvm::Value *DerivedNotNull = - Builder.CreateIsNotNull(Derived.getPointer(), "cast.nonnull"); + Builder.CreateIsNotNull(Derived.emitRawPointer(*this), "cast.nonnull"); llvm::BasicBlock *CheckBlock = createBasicBlock("cast.check"); ContBlock = createBasicBlock("cast.cont"); @@ -2976,7 +2990,7 @@ void CodeGenFunction::EmitLambdaBlockInvokeBody() { QualType ThisType = getContext().getPointerType(getContext().getRecordType(Lambda)); Address ThisPtr = GetAddrOfBlockDecl(variable); - CallArgs.add(RValue::get(ThisPtr.getPointer()), ThisType); + CallArgs.add(RValue::get(getAsNaturalPointerTo(ThisPtr, ThisType)), ThisType); // Add the rest of the parameters. for (auto *param : BD->parameters()) @@ -3004,7 +3018,7 @@ void CodeGenFunction::EmitLambdaStaticInvokeBody(const CXXMethodDecl *MD) { QualType LambdaType = getContext().getRecordType(Lambda); QualType ThisType = getContext().getPointerType(LambdaType); Address ThisPtr = CreateMemTemp(LambdaType, "unused.capture"); - CallArgs.add(RValue::get(ThisPtr.getPointer()), ThisType); + CallArgs.add(RValue::get(ThisPtr.emitRawPointer(*this)), ThisType); EmitLambdaDelegatingInvokeBody(MD, CallArgs); } diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp index f87caf050eeaa74b31de1452327e67f6139afaa8..5bf48bc22a5495e483c0001dca7d2c0200bedf12 100644 --- a/clang/lib/CodeGen/CGCleanup.cpp +++ b/clang/lib/CodeGen/CGCleanup.cpp @@ -27,7 +27,7 @@ bool DominatingValue::saved_type::needsSaving(RValue rv) { if (rv.isScalar()) return DominatingLLVMValue::needsSaving(rv.getScalarVal()); if (rv.isAggregate()) - return DominatingLLVMValue::needsSaving(rv.getAggregatePointer()); + return DominatingValue
::needsSaving(rv.getAggregateAddress()); return true; } @@ -35,69 +35,40 @@ DominatingValue::saved_type DominatingValue::saved_type::save(CodeGenFunction &CGF, RValue rv) { if (rv.isScalar()) { llvm::Value *V = rv.getScalarVal(); - - // These automatically dominate and don't need to be saved. - if (!DominatingLLVMValue::needsSaving(V)) - return saved_type(V, nullptr, ScalarLiteral); - - // Everything else needs an alloca. - Address addr = - CGF.CreateDefaultAlignTempAlloca(V->getType(), "saved-rvalue"); - CGF.Builder.CreateStore(V, addr); - return saved_type(addr.getPointer(), nullptr, ScalarAddress); + return saved_type(DominatingLLVMValue::save(CGF, V), + DominatingLLVMValue::needsSaving(V) ? ScalarAddress + : ScalarLiteral); } if (rv.isComplex()) { CodeGenFunction::ComplexPairTy V = rv.getComplexVal(); - llvm::Type *ComplexTy = - llvm::StructType::get(V.first->getType(), V.second->getType()); - Address addr = CGF.CreateDefaultAlignTempAlloca(ComplexTy, "saved-complex"); - CGF.Builder.CreateStore(V.first, CGF.Builder.CreateStructGEP(addr, 0)); - CGF.Builder.CreateStore(V.second, CGF.Builder.CreateStructGEP(addr, 1)); - return saved_type(addr.getPointer(), nullptr, ComplexAddress); + return saved_type(DominatingLLVMValue::save(CGF, V.first), + DominatingLLVMValue::save(CGF, V.second)); } assert(rv.isAggregate()); - Address V = rv.getAggregateAddress(); // TODO: volatile? - if (!DominatingLLVMValue::needsSaving(V.getPointer())) - return saved_type(V.getPointer(), V.getElementType(), AggregateLiteral, - V.getAlignment().getQuantity()); - - Address addr = - CGF.CreateTempAlloca(V.getType(), CGF.getPointerAlign(), "saved-rvalue"); - CGF.Builder.CreateStore(V.getPointer(), addr); - return saved_type(addr.getPointer(), V.getElementType(), AggregateAddress, - V.getAlignment().getQuantity()); + Address V = rv.getAggregateAddress(); + return saved_type( + DominatingValue
::save(CGF, V), rv.isVolatileQualified(), + DominatingValue
::needsSaving(V) ? AggregateAddress + : AggregateLiteral); } /// Given a saved r-value produced by SaveRValue, perform the code /// necessary to restore it to usability at the current insertion /// point. RValue DominatingValue::saved_type::restore(CodeGenFunction &CGF) { - auto getSavingAddress = [&](llvm::Value *value) { - auto *AI = cast(value); - return Address(value, AI->getAllocatedType(), - CharUnits::fromQuantity(AI->getAlign().value())); - }; switch (K) { case ScalarLiteral: - return RValue::get(Value); case ScalarAddress: - return RValue::get(CGF.Builder.CreateLoad(getSavingAddress(Value))); + return RValue::get(DominatingLLVMValue::restore(CGF, Vals.first)); case AggregateLiteral: + case AggregateAddress: return RValue::getAggregate( - Address(Value, ElementType, CharUnits::fromQuantity(Align))); - case AggregateAddress: { - auto addr = CGF.Builder.CreateLoad(getSavingAddress(Value)); - return RValue::getAggregate( - Address(addr, ElementType, CharUnits::fromQuantity(Align))); - } + DominatingValue
::restore(CGF, AggregateAddr), IsVolatile); case ComplexAddress: { - Address address = getSavingAddress(Value); - llvm::Value *real = - CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(address, 0)); - llvm::Value *imag = - CGF.Builder.CreateLoad(CGF.Builder.CreateStructGEP(address, 1)); + llvm::Value *real = DominatingLLVMValue::restore(CGF, Vals.first); + llvm::Value *imag = DominatingLLVMValue::restore(CGF, Vals.second); return RValue::getComplex(real, imag); } } @@ -294,14 +265,14 @@ void EHScopeStack::popNullFixups() { BranchFixups.pop_back(); } -Address CodeGenFunction::createCleanupActiveFlag() { +RawAddress CodeGenFunction::createCleanupActiveFlag() { // Create a variable to decide whether the cleanup needs to be run. - Address active = CreateTempAllocaWithoutCast( + RawAddress active = CreateTempAllocaWithoutCast( Builder.getInt1Ty(), CharUnits::One(), "cleanup.cond"); // Initialize it to false at a site that's guaranteed to be run // before each evaluation. - setBeforeOutermostConditional(Builder.getFalse(), active); + setBeforeOutermostConditional(Builder.getFalse(), active, *this); // Initialize it to true at the current location. Builder.CreateStore(Builder.getTrue(), active); @@ -309,7 +280,7 @@ Address CodeGenFunction::createCleanupActiveFlag() { return active; } -void CodeGenFunction::initFullExprCleanupWithFlag(Address ActiveFlag) { +void CodeGenFunction::initFullExprCleanupWithFlag(RawAddress ActiveFlag) { // Set that as the active flag in the cleanup. EHCleanupScope &cleanup = cast(*EHStack.begin()); assert(!cleanup.hasActiveFlag() && "cleanup already has active flag?"); @@ -322,15 +293,17 @@ void CodeGenFunction::initFullExprCleanupWithFlag(Address ActiveFlag) { void EHScopeStack::Cleanup::anchor() {} static void createStoreInstBefore(llvm::Value *value, Address addr, - llvm::Instruction *beforeInst) { - auto store = new llvm::StoreInst(value, addr.getPointer(), beforeInst); + llvm::Instruction *beforeInst, + CodeGenFunction &CGF) { + auto store = new llvm::StoreInst(value, addr.emitRawPointer(CGF), beforeInst); store->setAlignment(addr.getAlignment().getAsAlign()); } static llvm::LoadInst *createLoadInstBefore(Address addr, const Twine &name, - llvm::Instruction *beforeInst) { - return new llvm::LoadInst(addr.getElementType(), addr.getPointer(), name, - false, addr.getAlignment().getAsAlign(), + llvm::Instruction *beforeInst, + CodeGenFunction &CGF) { + return new llvm::LoadInst(addr.getElementType(), addr.emitRawPointer(CGF), + name, false, addr.getAlignment().getAsAlign(), beforeInst); } @@ -357,8 +330,8 @@ static void ResolveAllBranchFixups(CodeGenFunction &CGF, // entry which we're currently popping. if (Fixup.OptimisticBranchBlock == nullptr) { createStoreInstBefore(CGF.Builder.getInt32(Fixup.DestinationIndex), - CGF.getNormalCleanupDestSlot(), - Fixup.InitialBranch); + CGF.getNormalCleanupDestSlot(), Fixup.InitialBranch, + CGF); Fixup.InitialBranch->setSuccessor(0, CleanupEntry); } @@ -385,7 +358,7 @@ static llvm::SwitchInst *TransitionToCleanupSwitch(CodeGenFunction &CGF, if (llvm::BranchInst *Br = dyn_cast(Term)) { assert(Br->isUnconditional()); auto Load = createLoadInstBefore(CGF.getNormalCleanupDestSlot(), - "cleanup.dest", Term); + "cleanup.dest", Term, CGF); llvm::SwitchInst *Switch = llvm::SwitchInst::Create(Load, Br->getSuccessor(0), 4, Block); Br->eraseFromParent(); @@ -513,8 +486,8 @@ void CodeGenFunction::PopCleanupBlocks( I += Header.getSize(); if (Header.isConditional()) { - Address ActiveFlag = - reinterpret_cast
(LifetimeExtendedCleanupStack[I]); + RawAddress ActiveFlag = + reinterpret_cast(LifetimeExtendedCleanupStack[I]); initFullExprCleanupWithFlag(ActiveFlag); I += sizeof(ActiveFlag); } @@ -694,7 +667,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { // - whether there's a fallthrough llvm::BasicBlock *FallthroughSource = Builder.GetInsertBlock(); - bool HasFallthrough = (FallthroughSource != nullptr && IsActive); + bool HasFallthrough = + FallthroughSource != nullptr && (IsActive || HasExistingBranches); // Branch-through fall-throughs leave the insertion point set to the // end of the last cleanup, which points to the current scope. The @@ -719,7 +693,11 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { // If we have a prebranched fallthrough into an inactive normal // cleanup, rewrite it so that it leads to the appropriate place. - if (Scope.isNormalCleanup() && HasPrebranchedFallthrough && !IsActive) { + if (Scope.isNormalCleanup() && HasPrebranchedFallthrough && + !RequiresNormalCleanup) { + // FIXME: Come up with a program which would need forwarding prebranched + // fallthrough and add tests. Otherwise delete this and assert against it. + assert(!IsActive); llvm::BasicBlock *prebranchDest; // If the prebranch is semantically branching through the next @@ -792,6 +770,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { EmitSehCppScopeEnd(); } destroyOptimisticNormalEntry(*this, Scope); + Scope.MarkEmitted(); EHStack.popCleanup(); } else { // If we have a fallthrough and no other need for the cleanup, @@ -808,6 +787,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { } destroyOptimisticNormalEntry(*this, Scope); + Scope.MarkEmitted(); EHStack.popCleanup(); EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag); @@ -888,7 +868,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { if (NormalCleanupDestSlot->hasOneUse()) { NormalCleanupDestSlot->user_back()->eraseFromParent(); NormalCleanupDestSlot->eraseFromParent(); - NormalCleanupDest = Address::invalid(); + NormalCleanupDest = RawAddress::invalid(); } llvm::BasicBlock *BranchAfter = Scope.getBranchAfterBlock(0); @@ -912,9 +892,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { // pass the abnormal exit flag to Fn (SEH cleanup) cleanupFlags.setHasExitSwitch(); - llvm::LoadInst *Load = - createLoadInstBefore(getNormalCleanupDestSlot(), "cleanup.dest", - nullptr); + llvm::LoadInst *Load = createLoadInstBefore( + getNormalCleanupDestSlot(), "cleanup.dest", nullptr, *this); llvm::SwitchInst *Switch = llvm::SwitchInst::Create(Load, Default, SwitchCapacity); @@ -944,6 +923,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { } // IV. Pop the cleanup and emit it. + Scope.MarkEmitted(); EHStack.popCleanup(); assert(EHStack.hasNormalCleanups() == HasEnclosingCleanups); @@ -961,8 +941,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) { if (!Fixup.Destination) continue; if (!Fixup.OptimisticBranchBlock) { createStoreInstBefore(Builder.getInt32(Fixup.DestinationIndex), - getNormalCleanupDestSlot(), - Fixup.InitialBranch); + getNormalCleanupDestSlot(), Fixup.InitialBranch, + *this); Fixup.InitialBranch->setSuccessor(0, NormalEntry); } Fixup.OptimisticBranchBlock = NormalExit; @@ -1135,7 +1115,7 @@ void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) { // Store the index at the start. llvm::ConstantInt *Index = Builder.getInt32(Dest.getDestIndex()); - createStoreInstBefore(Index, getNormalCleanupDestSlot(), BI); + createStoreInstBefore(Index, getNormalCleanupDestSlot(), BI, *this); // Adjust BI to point to the first cleanup block. { @@ -1269,9 +1249,9 @@ static void SetupCleanupBlockActivation(CodeGenFunction &CGF, // If we're in a conditional block, ignore the dominating IP and // use the outermost conditional branch. if (CGF.isInConditionalBranch()) { - CGF.setBeforeOutermostConditional(value, var); + CGF.setBeforeOutermostConditional(value, var, CGF); } else { - createStoreInstBefore(value, var, dominatingIP); + createStoreInstBefore(value, var, dominatingIP, CGF); } } @@ -1321,7 +1301,7 @@ void CodeGenFunction::DeactivateCleanupBlock(EHScopeStack::stable_iterator C, Scope.setActive(false); } -Address CodeGenFunction::getNormalCleanupDestSlot() { +RawAddress CodeGenFunction::getNormalCleanupDestSlot() { if (!NormalCleanupDest.isValid()) NormalCleanupDest = CreateDefaultAlignTempAlloca(Builder.getInt32Ty(), "cleanup.dest.slot"); diff --git a/clang/lib/CodeGen/CGCleanup.h b/clang/lib/CodeGen/CGCleanup.h index 7a7344c07160db388ba8d743a37c245069c9af9c..c73c97146abc4d4d5ec4adba51bf0a02106d7d89 100644 --- a/clang/lib/CodeGen/CGCleanup.h +++ b/clang/lib/CodeGen/CGCleanup.h @@ -16,8 +16,11 @@ #include "EHScopeStack.h" #include "Address.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/IR/Instruction.h" namespace llvm { class BasicBlock; @@ -266,6 +269,51 @@ class alignas(8) EHCleanupScope : public EHScope { }; mutable struct ExtInfo *ExtInfo; + /// Erases auxillary allocas and their usages for an unused cleanup. + /// Cleanups should mark these allocas as 'used' if the cleanup is + /// emitted, otherwise these instructions would be erased. + struct AuxillaryAllocas { + SmallVector AuxAllocas; + bool used = false; + + // Records a potentially unused instruction to be erased later. + void Add(llvm::AllocaInst *Alloca) { AuxAllocas.push_back(Alloca); } + + // Mark all recorded instructions as used. These will not be erased later. + void MarkUsed() { + used = true; + AuxAllocas.clear(); + } + + ~AuxillaryAllocas() { + if (used) + return; + llvm::SetVector Uses; + for (auto *Inst : llvm::reverse(AuxAllocas)) + CollectUses(Inst, Uses); + // Delete uses in the reverse order of insertion. + for (auto *I : llvm::reverse(Uses)) + I->eraseFromParent(); + } + + private: + void CollectUses(llvm::Instruction *I, + llvm::SetVector &Uses) { + if (!I || !Uses.insert(I)) + return; + for (auto *User : I->users()) + CollectUses(cast(User), Uses); + } + }; + mutable struct AuxillaryAllocas *AuxAllocas; + + AuxillaryAllocas &getAuxillaryAllocas() { + if (!AuxAllocas) { + AuxAllocas = new struct AuxillaryAllocas(); + } + return *AuxAllocas; + } + /// The number of fixups required by enclosing scopes (not including /// this one). If this is the top cleanup scope, all the fixups /// from this index onwards belong to this scope. @@ -298,7 +346,7 @@ public: EHScopeStack::stable_iterator enclosingEH) : EHScope(EHScope::Cleanup, enclosingEH), EnclosingNormal(enclosingNormal), NormalBlock(nullptr), - ActiveFlag(Address::invalid()), ExtInfo(nullptr), + ActiveFlag(Address::invalid()), ExtInfo(nullptr), AuxAllocas(nullptr), FixupDepth(fixupDepth) { CleanupBits.IsNormalCleanup = isNormal; CleanupBits.IsEHCleanup = isEH; @@ -312,8 +360,15 @@ public: } void Destroy() { + if (AuxAllocas) + delete AuxAllocas; delete ExtInfo; } + void AddAuxAllocas(llvm::SmallVector Allocas) { + for (auto *Alloca : Allocas) + getAuxillaryAllocas().Add(Alloca); + } + void MarkEmitted() { getAuxillaryAllocas().MarkUsed(); } // Objects of EHCleanupScope are not destructed. Use Destroy(). ~EHCleanupScope() = delete; @@ -333,7 +388,7 @@ public: Address getActiveFlag() const { return ActiveFlag; } - void setActiveFlag(Address Var) { + void setActiveFlag(RawAddress Var) { assert(Var.getAlignment().isOne()); ActiveFlag = Var; } diff --git a/clang/lib/CodeGen/CGCoroutine.cpp b/clang/lib/CodeGen/CGCoroutine.cpp index b7142ec08af986d16656fdb7e10aed35b98912d1..93ca711f716fce5bec80f56f81e0f3749de5d3f8 100644 --- a/clang/lib/CodeGen/CGCoroutine.cpp +++ b/clang/lib/CodeGen/CGCoroutine.cpp @@ -867,8 +867,8 @@ void CodeGenFunction::EmitCoroutineBody(const CoroutineBodyStmt &S) { EmitStmt(S.getPromiseDeclStmt()); Address PromiseAddr = GetAddrOfLocalVar(S.getPromiseDecl()); - auto *PromiseAddrVoidPtr = - new llvm::BitCastInst(PromiseAddr.getPointer(), VoidPtrTy, "", CoroId); + auto *PromiseAddrVoidPtr = new llvm::BitCastInst( + PromiseAddr.emitRawPointer(*this), VoidPtrTy, "", CoroId); // Update CoroId to refer to the promise. We could not do it earlier because // promise local variable was not emitted yet. CoroId->setArgOperand(1, PromiseAddrVoidPtr); diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 07ecaa81c47d84999e7f0a37a2fd3ad5e6d6f8f8..8c284c332171a1bbdd9a3af14692e7de5ac81ec2 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -1440,8 +1440,7 @@ static unsigned getDwarfCC(CallingConv CC) { case CC_Swift: return llvm::dwarf::DW_CC_LLVM_Swift; case CC_SwiftAsync: - // [FIXME: swiftasynccc] Update to SwiftAsync once LLVM support lands. - return llvm::dwarf::DW_CC_LLVM_Swift; + return llvm::dwarf::DW_CC_LLVM_SwiftTail; case CC_PreserveMost: return llvm::dwarf::DW_CC_LLVM_PreserveMost; case CC_PreserveAll: @@ -1452,6 +1451,8 @@ static unsigned getDwarfCC(CallingConv CC) { return llvm::dwarf::DW_CC_LLVM_M68kRTD; case CC_PreserveNone: return llvm::dwarf::DW_CC_LLVM_PreserveNone; + case CC_RISCVVectorCall: + return llvm::dwarf::DW_CC_LLVM_RISCVVectorCall; } return 0; } @@ -3239,7 +3240,7 @@ llvm::DIType *CGDebugInfo::CreateType(const ArrayType *Ty, llvm::DIFile *Unit) { // }; int64_t Count = -1; // Count == -1 is an unbounded array. if (const auto *CAT = dyn_cast(Ty)) - Count = CAT->getSize().getZExtValue(); + Count = CAT->getZExtSize(); else if (const auto *VAT = dyn_cast(Ty)) { if (Expr *Size = VAT->getSizeExpr()) { Expr::EvalResult Result; @@ -3463,6 +3464,9 @@ static QualType UnwrapTypeForDebugInfo(QualType T, const ASTContext &C) { case Type::BTFTagAttributed: T = cast(T)->getWrappedType(); break; + case Type::CountAttributed: + T = cast(T)->desugar(); + break; case Type::Elaborated: T = cast(T)->getNamedType(); break; @@ -3637,6 +3641,7 @@ llvm::DIType *CGDebugInfo::CreateTypeNode(QualType Ty, llvm::DIFile *Unit) { case Type::ConstantArray: case Type::VariableArray: case Type::IncompleteArray: + case Type::ArrayParameter: return CreateType(cast(Ty), Unit); case Type::LValueReference: diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index 2ef5ed04af30b6e99b59e2570e0c27da25500777..8bdafa7c569b0802c860a4734b54dab7d74ff2bd 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -19,6 +19,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" +#include "EHScopeStack.h" #include "PatternInit.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" @@ -1383,7 +1384,7 @@ void CodeGenFunction::EmitAndRegisterVariableArrayDimensions( // For each dimension stores its QualType and corresponding // size-expression Value. SmallVector Dimensions; - SmallVector VLAExprNames; + SmallVector VLAExprNames; // Break down the array into individual dimensions. QualType Type1D = D.getType(); @@ -1420,7 +1421,7 @@ void CodeGenFunction::EmitAndRegisterVariableArrayDimensions( MD = llvm::ConstantAsMetadata::get(C); else { // Create an artificial VarDecl to generate debug info for. - IdentifierInfo *NameIdent = VLAExprNames[NameIdx++]; + const IdentifierInfo *NameIdent = VLAExprNames[NameIdx++]; auto QT = getContext().getIntTypeForBitwidth( SizeTy->getScalarSizeInBits(), false); auto *ArtificialDecl = VarDecl::Create( @@ -1461,7 +1462,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { bool EmitDebugInfo = DI && CGM.getCodeGenOpts().hasReducedDebugInfo(); Address address = Address::invalid(); - Address AllocaAddr = Address::invalid(); + RawAddress AllocaAddr = RawAddress::invalid(); Address OpenMPLocalAddr = Address::invalid(); if (CGM.getLangOpts().OpenMPIRBuilder) OpenMPLocalAddr = OMPBuilderCBHelpers::getAddressOfLocalVariable(*this, &D); @@ -1524,7 +1525,10 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { // return slot, so that we can elide the copy when returning this // variable (C++0x [class.copy]p34). address = ReturnValue; - AllocaAddr = ReturnValue; + AllocaAddr = + RawAddress(ReturnValue.emitRawPointer(*this), + ReturnValue.getElementType(), ReturnValue.getAlignment()); + ; if (const RecordType *RecordTy = Ty->getAs()) { const auto *RD = RecordTy->getDecl(); @@ -1535,7 +1539,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { // to this variable. Set it to zero to indicate that NRVO was not // applied. llvm::Value *Zero = Builder.getFalse(); - Address NRVOFlag = + RawAddress NRVOFlag = CreateTempAlloca(Zero->getType(), CharUnits::One(), "nrvo"); EnsureInsertPoint(); Builder.CreateStore(Zero, NRVOFlag); @@ -1678,7 +1682,7 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) { } if (D.hasAttr() && HaveInsertPoint()) - EmitVarAnnotations(&D, address.getPointer()); + EmitVarAnnotations(&D, address.emitRawPointer(*this)); // Make sure we call @llvm.lifetime.end. if (emission.useLifetimeMarkers()) @@ -1851,12 +1855,13 @@ void CodeGenFunction::emitZeroOrPatternForAutoVarInit(QualType type, llvm::Value *BaseSizeInChars = llvm::ConstantInt::get(IntPtrTy, EltSize.getQuantity()); Address Begin = Loc.withElementType(Int8Ty); - llvm::Value *End = Builder.CreateInBoundsGEP( - Begin.getElementType(), Begin.getPointer(), SizeVal, "vla.end"); + llvm::Value *End = Builder.CreateInBoundsGEP(Begin.getElementType(), + Begin.emitRawPointer(*this), + SizeVal, "vla.end"); llvm::BasicBlock *OriginBB = Builder.GetInsertBlock(); EmitBlock(LoopBB); llvm::PHINode *Cur = Builder.CreatePHI(Begin.getType(), 2, "vla.cur"); - Cur->addIncoming(Begin.getPointer(), OriginBB); + Cur->addIncoming(Begin.emitRawPointer(*this), OriginBB); CharUnits CurAlign = Loc.getAlignment().alignmentOfArrayElement(EltSize); auto *I = Builder.CreateMemCpy(Address(Cur, Int8Ty, CurAlign), @@ -2197,6 +2202,24 @@ void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, Address addr, destroyer, useEHCleanupForArray); } +// Pushes a destroy and defers its deactivation until its +// CleanupDeactivationScope is exited. +void CodeGenFunction::pushDestroyAndDeferDeactivation( + QualType::DestructionKind dtorKind, Address addr, QualType type) { + assert(dtorKind && "cannot push destructor for trivial type"); + + CleanupKind cleanupKind = getCleanupKind(dtorKind); + pushDestroyAndDeferDeactivation( + cleanupKind, addr, type, getDestroyer(dtorKind), cleanupKind & EHCleanup); +} + +void CodeGenFunction::pushDestroyAndDeferDeactivation( + CleanupKind cleanupKind, Address addr, QualType type, Destroyer *destroyer, + bool useEHCleanupForArray) { + pushCleanupAndDeferDeactivation( + cleanupKind, addr, type, destroyer, useEHCleanupForArray); +} + void CodeGenFunction::pushStackRestore(CleanupKind Kind, Address SPMem) { EHStack.pushCleanup(Kind, SPMem); } @@ -2213,16 +2236,19 @@ void CodeGenFunction::pushLifetimeExtendedDestroy(CleanupKind cleanupKind, // If we're not in a conditional branch, we don't need to bother generating a // conditional cleanup. if (!isInConditionalBranch()) { - // Push an EH-only cleanup for the object now. // FIXME: When popping normal cleanups, we need to keep this EH cleanup // around in case a temporary's destructor throws an exception. - if (cleanupKind & EHCleanup) - EHStack.pushCleanup( - static_cast(cleanupKind & ~NormalCleanup), addr, type, - destroyer, useEHCleanupForArray); + // Add the cleanup to the EHStack. After the full-expr, this would be + // deactivated before being popped from the stack. + pushDestroyAndDeferDeactivation(cleanupKind, addr, type, destroyer, + useEHCleanupForArray); + + // Since this is lifetime-extended, push it once again to the EHStack after + // the full expression. return pushCleanupAfterFullExprWithActiveFlag( - cleanupKind, Address::invalid(), addr, type, destroyer, useEHCleanupForArray); + cleanupKind, Address::invalid(), addr, type, destroyer, + useEHCleanupForArray); } // Otherwise, we should only destroy the object if it's been initialized. @@ -2237,13 +2263,12 @@ void CodeGenFunction::pushLifetimeExtendedDestroy(CleanupKind cleanupKind, Address ActiveFlag = createCleanupActiveFlag(); SavedType SavedAddr = saveValueInCond(addr); - if (cleanupKind & EHCleanup) { - EHStack.pushCleanup( - static_cast(cleanupKind & ~NormalCleanup), SavedAddr, type, - destroyer, useEHCleanupForArray); - initFullExprCleanupWithFlag(ActiveFlag); - } + pushCleanupAndDeferDeactivation( + cleanupKind, SavedAddr, type, destroyer, useEHCleanupForArray); + initFullExprCleanupWithFlag(ActiveFlag); + // Since this is lifetime-extended, push it once again to the EHStack after + // the full expression. pushCleanupAfterFullExprWithActiveFlag( cleanupKind, ActiveFlag, SavedAddr, type, destroyer, useEHCleanupForArray); @@ -2283,7 +2308,7 @@ void CodeGenFunction::emitDestroy(Address addr, QualType type, checkZeroLength = false; } - llvm::Value *begin = addr.getPointer(); + llvm::Value *begin = addr.emitRawPointer(*this); llvm::Value *end = Builder.CreateInBoundsGEP(addr.getElementType(), begin, length); emitArrayDestroy(begin, end, type, elementAlign, destroyer, @@ -2438,9 +2463,9 @@ namespace { }; } // end anonymous namespace -/// pushIrregularPartialArrayCleanup - Push an EH cleanup to destroy -/// already-constructed elements of the given array. The cleanup -/// may be popped with DeactivateCleanupBlock or PopCleanupBlock. +/// pushIrregularPartialArrayCleanup - Push a NormalAndEHCleanup to +/// destroy already-constructed elements of the given array. The cleanup may be +/// popped with DeactivateCleanupBlock or PopCleanupBlock. /// /// \param elementType - the immediate element type of the array; /// possibly still an array type @@ -2449,10 +2474,9 @@ void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin, QualType elementType, CharUnits elementAlign, Destroyer *destroyer) { - pushFullExprCleanup(EHCleanup, - arrayBegin, arrayEndPointer, - elementType, elementAlign, - destroyer); + pushFullExprCleanup( + NormalAndEHCleanup, arrayBegin, arrayEndPointer, elementType, + elementAlign, destroyer); } /// pushRegularPartialArrayCleanup - Push an EH cleanup to destroy @@ -2543,7 +2567,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, } Address DeclPtr = Address::invalid(); - Address AllocaPtr = Address::invalid(); + RawAddress AllocaPtr = Address::invalid(); bool DoStore = false; bool IsScalar = hasScalarEvaluationKind(Ty); bool UseIndirectDebugAddress = false; @@ -2555,8 +2579,8 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, // Indirect argument is in alloca address space, which may be different // from the default address space. auto AllocaAS = CGM.getASTAllocaAddressSpace(); - auto *V = DeclPtr.getPointer(); - AllocaPtr = DeclPtr; + auto *V = DeclPtr.emitRawPointer(*this); + AllocaPtr = RawAddress(V, DeclPtr.getElementType(), DeclPtr.getAlignment()); // For truly ABI indirect arguments -- those that are not `byval` -- store // the address of the argument on the stack to preserve debug information. @@ -2695,7 +2719,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, } if (D.hasAttr()) - EmitVarAnnotations(&D, DeclPtr.getPointer()); + EmitVarAnnotations(&D, DeclPtr.emitRawPointer(*this)); // We can only check return value nullability if all arguments to the // function satisfy their nullability preconditions. This makes it necessary diff --git a/clang/lib/CodeGen/CGException.cpp b/clang/lib/CodeGen/CGException.cpp index 5a9d06da12de571ab376e8740b06fd63ac66cc9f..34f289334a7df90584d9b7f80bf57a99060a7af0 100644 --- a/clang/lib/CodeGen/CGException.cpp +++ b/clang/lib/CodeGen/CGException.cpp @@ -397,7 +397,7 @@ namespace { void CodeGenFunction::EmitAnyExprToExn(const Expr *e, Address addr) { // Make sure the exception object is cleaned up if there's an // exception during initialization. - pushFullExprCleanup(EHCleanup, addr.getPointer()); + pushFullExprCleanup(EHCleanup, addr.emitRawPointer(*this)); EHScopeStack::stable_iterator cleanup = EHStack.stable_begin(); // __cxa_allocate_exception returns a void*; we need to cast this @@ -416,8 +416,8 @@ void CodeGenFunction::EmitAnyExprToExn(const Expr *e, Address addr) { /*IsInit*/ true); // Deactivate the cleanup block. - DeactivateCleanupBlock(cleanup, - cast(typedAddr.getPointer())); + DeactivateCleanupBlock( + cleanup, cast(typedAddr.emitRawPointer(*this))); } Address CodeGenFunction::getExceptionSlot() { @@ -1834,7 +1834,8 @@ Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF, llvm::Value *ParentFP) { llvm::CallInst *RecoverCall = nullptr; CGBuilderTy Builder(*this, AllocaInsertPt); - if (auto *ParentAlloca = dyn_cast(ParentVar.getPointer())) { + if (auto *ParentAlloca = + dyn_cast_or_null(ParentVar.getBasePointer())) { // Mark the variable escaped if nobody else referenced it and compute the // localescape index. auto InsertPair = ParentCGF.EscapedLocals.insert( @@ -1851,8 +1852,8 @@ Address CodeGenFunction::recoverAddrOfEscapedLocal(CodeGenFunction &ParentCGF, // If the parent didn't have an alloca, we're doing some nested outlining. // Just clone the existing localrecover call, but tweak the FP argument to // use our FP value. All other arguments are constants. - auto *ParentRecover = - cast(ParentVar.getPointer()->stripPointerCasts()); + auto *ParentRecover = cast( + ParentVar.emitRawPointer(*this)->stripPointerCasts()); assert(ParentRecover->getIntrinsicID() == llvm::Intrinsic::localrecover && "expected alloca or localrecover in parent LocalDeclMap"); RecoverCall = cast(ParentRecover->clone()); @@ -1925,7 +1926,8 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, if (isa(D) && D->getType() == getContext().VoidPtrTy) { assert(D->getName().starts_with("frame_pointer")); - FramePtrAddrAlloca = cast(I.second.getPointer()); + FramePtrAddrAlloca = + cast(I.second.getBasePointer()); break; } } @@ -1986,7 +1988,8 @@ void CodeGenFunction::EmitCapturedLocals(CodeGenFunction &ParentCGF, LValue ThisFieldLValue = EmitLValueForLambdaField(LambdaThisCaptureField); if (!LambdaThisCaptureField->getType()->isPointerType()) { - CXXThisValue = ThisFieldLValue.getAddress(*this).getPointer(); + CXXThisValue = + ThisFieldLValue.getAddress(*this).emitRawPointer(*this); } else { CXXThisValue = EmitLoadOfLValue(ThisFieldLValue, SourceLocation()) .getScalarVal(); diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 85f5d739cef457a49d143d33c6689efe82b48696..c85a339f5e3f885c2524121c5d270a306cf9aeb9 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -56,8 +56,13 @@ using namespace CodeGen; // Experiment to make sanitizers easier to debug static llvm::cl::opt ClSanitizeDebugDeoptimization( "ubsan-unique-traps", llvm::cl::Optional, - llvm::cl::desc("Deoptimize traps for UBSAN so there is 1 trap per check"), - llvm::cl::init(false)); + llvm::cl::desc("Deoptimize traps for UBSAN so there is 1 trap per check.")); + +// TODO: Introduce frontend options to enabled per sanitizers, similar to +// `fsanitize-trap`. +static llvm::cl::opt ClSanitizeGuardChecks( + "ubsan-guard-checks", llvm::cl::Optional, + llvm::cl::desc("Guard UBSAN checks with `llvm.allow.ubsan.check()`.")); //===--------------------------------------------------------------------===// // Miscellaneous Helper Methods @@ -65,21 +70,21 @@ static llvm::cl::opt ClSanitizeDebugDeoptimization( /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. -Address CodeGenFunction::CreateTempAllocaWithoutCast(llvm::Type *Ty, - CharUnits Align, - const Twine &Name, - llvm::Value *ArraySize) { +RawAddress +CodeGenFunction::CreateTempAllocaWithoutCast(llvm::Type *Ty, CharUnits Align, + const Twine &Name, + llvm::Value *ArraySize) { auto Alloca = CreateTempAlloca(Ty, Name, ArraySize); Alloca->setAlignment(Align.getAsAlign()); - return Address(Alloca, Ty, Align, KnownNonNull); + return RawAddress(Alloca, Ty, Align, KnownNonNull); } /// CreateTempAlloca - This creates a alloca and inserts it into the entry /// block. The alloca is casted to default address space if necessary. -Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align, - const Twine &Name, - llvm::Value *ArraySize, - Address *AllocaAddr) { +RawAddress CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align, + const Twine &Name, + llvm::Value *ArraySize, + RawAddress *AllocaAddr) { auto Alloca = CreateTempAllocaWithoutCast(Ty, Align, Name, ArraySize); if (AllocaAddr) *AllocaAddr = Alloca; @@ -101,7 +106,7 @@ Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align, Ty->getPointerTo(DestAddrSpace), /*non-null*/ true); } - return Address(V, Ty, Align, KnownNonNull); + return RawAddress(V, Ty, Align, KnownNonNull); } /// CreateTempAlloca - This creates an alloca and inserts it into the entry @@ -110,38 +115,45 @@ Address CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align, llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, const Twine &Name, llvm::Value *ArraySize) { + llvm::AllocaInst *Alloca; if (ArraySize) - return Builder.CreateAlloca(Ty, ArraySize, Name); - return new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(), - ArraySize, Name, AllocaInsertPt); + Alloca = Builder.CreateAlloca(Ty, ArraySize, Name); + else + Alloca = new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(), + ArraySize, Name, AllocaInsertPt); + if (Allocas) { + Allocas->Add(Alloca); + } + return Alloca; } /// CreateDefaultAlignTempAlloca - This creates an alloca with the /// default alignment of the corresponding LLVM type, which is *not* /// guaranteed to be related in any way to the expected alignment of /// an AST type that might have been lowered to Ty. -Address CodeGenFunction::CreateDefaultAlignTempAlloca(llvm::Type *Ty, - const Twine &Name) { +RawAddress CodeGenFunction::CreateDefaultAlignTempAlloca(llvm::Type *Ty, + const Twine &Name) { CharUnits Align = CharUnits::fromQuantity(CGM.getDataLayout().getPrefTypeAlign(Ty)); return CreateTempAlloca(Ty, Align, Name); } -Address CodeGenFunction::CreateIRTemp(QualType Ty, const Twine &Name) { +RawAddress CodeGenFunction::CreateIRTemp(QualType Ty, const Twine &Name) { CharUnits Align = getContext().getTypeAlignInChars(Ty); return CreateTempAlloca(ConvertType(Ty), Align, Name); } -Address CodeGenFunction::CreateMemTemp(QualType Ty, const Twine &Name, - Address *Alloca) { +RawAddress CodeGenFunction::CreateMemTemp(QualType Ty, const Twine &Name, + RawAddress *Alloca) { // FIXME: Should we prefer the preferred type alignment here? return CreateMemTemp(Ty, getContext().getTypeAlignInChars(Ty), Name, Alloca); } -Address CodeGenFunction::CreateMemTemp(QualType Ty, CharUnits Align, - const Twine &Name, Address *Alloca) { - Address Result = CreateTempAlloca(ConvertTypeForMem(Ty), Align, Name, - /*ArraySize=*/nullptr, Alloca); +RawAddress CodeGenFunction::CreateMemTemp(QualType Ty, CharUnits Align, + const Twine &Name, + RawAddress *Alloca) { + RawAddress Result = CreateTempAlloca(ConvertTypeForMem(Ty), Align, Name, + /*ArraySize=*/nullptr, Alloca); if (Ty->isConstantMatrixType()) { auto *ArrayTy = cast(Result.getElementType()); @@ -154,13 +166,14 @@ Address CodeGenFunction::CreateMemTemp(QualType Ty, CharUnits Align, return Result; } -Address CodeGenFunction::CreateMemTempWithoutCast(QualType Ty, CharUnits Align, - const Twine &Name) { +RawAddress CodeGenFunction::CreateMemTempWithoutCast(QualType Ty, + CharUnits Align, + const Twine &Name) { return CreateTempAllocaWithoutCast(ConvertTypeForMem(Ty), Align, Name); } -Address CodeGenFunction::CreateMemTempWithoutCast(QualType Ty, - const Twine &Name) { +RawAddress CodeGenFunction::CreateMemTempWithoutCast(QualType Ty, + const Twine &Name) { return CreateMemTempWithoutCast(Ty, getContext().getTypeAlignInChars(Ty), Name); } @@ -359,7 +372,7 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M, } else { CleanupFn = CGF.CGM.getAddrAndTypeOfCXXStructor( GlobalDecl(ReferenceTemporaryDtor, Dtor_Complete)); - CleanupArg = cast(ReferenceTemporary.getPointer()); + CleanupArg = cast(ReferenceTemporary.emitRawPointer(CGF)); } CGF.CGM.getCXXABI().registerGlobalDtor( CGF, *cast(M->getExtendingDecl()), CleanupFn, CleanupArg); @@ -384,10 +397,10 @@ pushTemporaryCleanup(CodeGenFunction &CGF, const MaterializeTemporaryExpr *M, } } -static Address createReferenceTemporary(CodeGenFunction &CGF, - const MaterializeTemporaryExpr *M, - const Expr *Inner, - Address *Alloca = nullptr) { +static RawAddress createReferenceTemporary(CodeGenFunction &CGF, + const MaterializeTemporaryExpr *M, + const Expr *Inner, + RawAddress *Alloca = nullptr) { auto &TCG = CGF.getTargetHooks(); switch (M->getStorageDuration()) { case SD_FullExpression: @@ -416,7 +429,7 @@ static Address createReferenceTemporary(CodeGenFunction &CGF, GV->getValueType()->getPointerTo( CGF.getContext().getTargetAddressSpace(LangAS::Default))); // FIXME: Should we put the new global into a COMDAT? - return Address(C, GV->getValueType(), alignment); + return RawAddress(C, GV->getValueType(), alignment); } return CGF.CreateMemTemp(Ty, "ref.tmp", Alloca); } @@ -448,7 +461,7 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { auto ownership = M->getType().getObjCLifetime(); if (ownership != Qualifiers::OCL_None && ownership != Qualifiers::OCL_ExplicitNone) { - Address Object = createReferenceTemporary(*this, M, E); + RawAddress Object = createReferenceTemporary(*this, M, E); if (auto *Var = dyn_cast(Object.getPointer())) { llvm::Type *Ty = ConvertTypeForMem(E->getType()); Object = Object.withElementType(Ty); @@ -502,8 +515,8 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) { } // Create and initialize the reference temporary. - Address Alloca = Address::invalid(); - Address Object = createReferenceTemporary(*this, M, E, &Alloca); + RawAddress Alloca = Address::invalid(); + RawAddress Object = createReferenceTemporary(*this, M, E, &Alloca); if (auto *Var = dyn_cast( Object.getPointer()->stripPointerCasts())) { llvm::Type *TemporaryType = ConvertTypeForMem(E->getType()); @@ -1111,12 +1124,12 @@ llvm::Value *CodeGenFunction::EmitCountedByFieldExpr( } else if (const MemberExpr *ME = dyn_cast(StructBase)) { LValue LV = EmitMemberExpr(ME); Address Addr = LV.getAddress(*this); - Res = Addr.getPointer(); + Res = Addr.emitRawPointer(*this); } else if (StructBase->getType()->isPointerType()) { LValueBaseInfo BaseInfo; TBAAAccessInfo TBAAInfo; Address Addr = EmitPointerWithAlignment(StructBase, &BaseInfo, &TBAAInfo); - Res = Addr.getPointer(); + Res = Addr.emitRawPointer(*this); } else { return nullptr; } @@ -1282,8 +1295,7 @@ static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo, if (InnerBaseInfo.getAlignmentSource() != AlignmentSource::Decl) { if (BaseInfo) BaseInfo->mergeForCast(TargetTypeBaseInfo); - Addr = Address(Addr.getPointer(), Addr.getElementType(), Align, - IsKnownNonNull); + Addr.setAlignment(Align); } } @@ -1300,8 +1312,8 @@ static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo, CGF.ConvertTypeForMem(E->getType()->getPointeeType()); Addr = Addr.withElementType(ElemTy); if (CE->getCastKind() == CK_AddressSpaceConversion) - Addr = CGF.Builder.CreateAddrSpaceCast(Addr, - CGF.ConvertType(E->getType())); + Addr = CGF.Builder.CreateAddrSpaceCast( + Addr, CGF.ConvertType(E->getType()), ElemTy); return Addr; } break; @@ -1364,10 +1376,9 @@ static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo, // TODO: conditional operators, comma. // Otherwise, use the alignment of the type. - CharUnits Align = - CGF.CGM.getNaturalPointeeTypeAlignment(E->getType(), BaseInfo, TBAAInfo); - llvm::Type *ElemTy = CGF.ConvertTypeForMem(E->getType()->getPointeeType()); - return Address(CGF.EmitScalarExpr(E), ElemTy, Align, IsKnownNonNull); + return CGF.makeNaturalAddressForPointer( + CGF.EmitScalarExpr(E), E->getType()->getPointeeType(), CharUnits(), + /*ForPointeeType=*/true, BaseInfo, TBAAInfo, IsKnownNonNull); } /// EmitPointerWithAlignment - Given an expression of pointer type, try to @@ -1468,8 +1479,7 @@ LValue CodeGenFunction::EmitCheckedLValue(const Expr *E, TypeCheckKind TCK) { if (IsBaseCXXThis || isa(ME->getBase())) SkippedChecks.set(SanitizerKind::Null, true); } - EmitTypeCheck(TCK, E->getExprLoc(), LV.getPointer(*this), E->getType(), - LV.getAlignment(), SkippedChecks); + EmitTypeCheck(TCK, E->getExprLoc(), LV, E->getType(), SkippedChecks); } return LV; } @@ -1581,11 +1591,11 @@ LValue CodeGenFunction::EmitLValueHelper(const Expr *E, // Defend against branches out of gnu statement expressions surrounded by // cleanups. Address Addr = LV.getAddress(*this); - llvm::Value *V = Addr.getPointer(); + llvm::Value *V = Addr.getBasePointer(); Scope.ForceCleanup({&V}); - return LValue::MakeAddr(Addr.withPointer(V, Addr.isKnownNonNull()), - LV.getType(), getContext(), LV.getBaseInfo(), - LV.getTBAAInfo()); + Addr.replaceBasePointer(V); + return LValue::MakeAddr(Addr, LV.getType(), getContext(), + LV.getBaseInfo(), LV.getTBAAInfo()); } // FIXME: Is it possible to create an ExprWithCleanups that produces a // bitfield lvalue or some other non-simple lvalue? @@ -1929,7 +1939,7 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile, LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo, bool isNontemporal) { - if (auto *GV = dyn_cast(Addr.getPointer())) + if (auto *GV = dyn_cast(Addr.getBasePointer())) if (GV->isThreadLocal()) Addr = Addr.withPointer(Builder.CreateThreadLocalAddress(GV), NotKnownNonNull); @@ -2039,8 +2049,9 @@ llvm::Value *CodeGenFunction::EmitFromMemory(llvm::Value *Value, QualType Ty) { // Convert the pointer of \p Addr to a pointer to a vector (the value type of // MatrixType), if it points to a array (the memory type of MatrixType). -static Address MaybeConvertMatrixAddress(Address Addr, CodeGenFunction &CGF, - bool IsVector = true) { +static RawAddress MaybeConvertMatrixAddress(RawAddress Addr, + CodeGenFunction &CGF, + bool IsVector = true) { auto *ArrayTy = dyn_cast(Addr.getElementType()); if (ArrayTy && IsVector) { auto *VectorTy = llvm::FixedVectorType::get(ArrayTy->getElementType(), @@ -2077,7 +2088,7 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value *Value, Address Addr, LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo, bool isInit, bool isNontemporal) { - if (auto *GV = dyn_cast(Addr.getPointer())) + if (auto *GV = dyn_cast(Addr.getBasePointer())) if (GV->isThreadLocal()) Addr = Addr.withPointer(Builder.CreateThreadLocalAddress(GV), NotKnownNonNull); @@ -2432,14 +2443,12 @@ void CodeGenFunction::EmitStoreThroughLValue(RValue Src, LValue Dst, assert(Dst.getBaseIvarExp() && "BaseIvarExp is NULL"); llvm::Type *ResultType = IntPtrTy; Address dst = EmitPointerWithAlignment(Dst.getBaseIvarExp()); - llvm::Value *RHS = dst.getPointer(); + llvm::Value *RHS = dst.emitRawPointer(*this); RHS = Builder.CreatePtrToInt(RHS, ResultType, "sub.ptr.rhs.cast"); - llvm::Value *LHS = - Builder.CreatePtrToInt(LvalueDst.getPointer(), ResultType, - "sub.ptr.lhs.cast"); + llvm::Value *LHS = Builder.CreatePtrToInt(LvalueDst.emitRawPointer(*this), + ResultType, "sub.ptr.lhs.cast"); llvm::Value *BytesBetween = Builder.CreateSub(LHS, RHS, "ivar.offset"); - CGM.getObjCRuntime().EmitObjCIvarAssign(*this, src, dst, - BytesBetween); + CGM.getObjCRuntime().EmitObjCIvarAssign(*this, src, dst, BytesBetween); } else if (Dst.isGlobalObjCRef()) { CGM.getObjCRuntime().EmitObjCGlobalAssign(*this, src, LvalueDst, Dst.isThreadLocalRef()); @@ -2770,12 +2779,9 @@ CodeGenFunction::EmitLoadOfReference(LValue RefLVal, llvm::LoadInst *Load = Builder.CreateLoad(RefLVal.getAddress(*this), RefLVal.isVolatile()); CGM.DecorateInstructionWithTBAA(Load, RefLVal.getTBAAInfo()); - - QualType PointeeType = RefLVal.getType()->getPointeeType(); - CharUnits Align = CGM.getNaturalTypeAlignment( - PointeeType, PointeeBaseInfo, PointeeTBAAInfo, - /* forPointeeType= */ true); - return Address(Load, ConvertTypeForMem(PointeeType), Align); + return makeNaturalAddressForPointer(Load, RefLVal.getType()->getPointeeType(), + CharUnits(), /*ForPointeeType=*/true, + PointeeBaseInfo, PointeeTBAAInfo); } LValue CodeGenFunction::EmitLoadOfReferenceLValue(LValue RefLVal) { @@ -2792,10 +2798,9 @@ Address CodeGenFunction::EmitLoadOfPointer(Address Ptr, LValueBaseInfo *BaseInfo, TBAAAccessInfo *TBAAInfo) { llvm::Value *Addr = Builder.CreateLoad(Ptr); - return Address(Addr, ConvertTypeForMem(PtrTy->getPointeeType()), - CGM.getNaturalTypeAlignment(PtrTy->getPointeeType(), BaseInfo, - TBAAInfo, - /*forPointeeType=*/true)); + return makeNaturalAddressForPointer(Addr, PtrTy->getPointeeType(), + CharUnits(), /*ForPointeeType=*/true, + BaseInfo, TBAAInfo); } LValue CodeGenFunction::EmitLoadOfPointerLValue(Address PtrAddr, @@ -2991,7 +2996,7 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { /* BaseInfo= */ nullptr, /* TBAAInfo= */ nullptr, /* forPointeeType= */ true); - Addr = Address(Val, ConvertTypeForMem(E->getType()), Alignment); + Addr = makeNaturalAddressForPointer(Val, T, Alignment); } return MakeAddrLValue(Addr, T, AlignmentSource::Decl); } @@ -3023,11 +3028,12 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { EmitCapturedFieldLValue(*this, CapturedStmtInfo->lookup(VD), CapturedStmtInfo->getContextValue()); Address LValueAddress = CapLVal.getAddress(*this); - CapLVal = MakeAddrLValue( - Address(LValueAddress.getPointer(), LValueAddress.getElementType(), - getContext().getDeclAlign(VD)), - CapLVal.getType(), LValueBaseInfo(AlignmentSource::Decl), - CapLVal.getTBAAInfo()); + CapLVal = MakeAddrLValue(Address(LValueAddress.emitRawPointer(*this), + LValueAddress.getElementType(), + getContext().getDeclAlign(VD)), + CapLVal.getType(), + LValueBaseInfo(AlignmentSource::Decl), + CapLVal.getTBAAInfo()); // Mark lvalue as nontemporal if the variable is marked as nontemporal // in simd context. if (getLangOpts().OpenMP && @@ -3083,7 +3089,8 @@ LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) { // Handle threadlocal function locals. if (VD->getTLSKind() != VarDecl::TLS_None) addr = addr.withPointer( - Builder.CreateThreadLocalAddress(addr.getPointer()), NotKnownNonNull); + Builder.CreateThreadLocalAddress(addr.getBasePointer()), + NotKnownNonNull); // Check for OpenMP threadprivate variables. if (getLangOpts().OpenMP && !getLangOpts().OpenMPSimd && @@ -3351,7 +3358,7 @@ llvm::Value *CodeGenFunction::EmitCheckValue(llvm::Value *V) { // Pointers are passed directly, everything else is passed by address. if (!V->getType()->isPointerTy()) { - Address Ptr = CreateDefaultAlignTempAlloca(V->getType()); + RawAddress Ptr = CreateDefaultAlignTempAlloca(V->getType()); Builder.CreateStore(V, Ptr); V = Ptr.getPointer(); } @@ -3527,6 +3534,17 @@ void CodeGenFunction::EmitCheck( Cond = Cond ? Builder.CreateAnd(Cond, Check) : Check; } + if (ClSanitizeGuardChecks) { + llvm::Value *Allow = + Builder.CreateCall(CGM.getIntrinsic(llvm::Intrinsic::allow_ubsan_check), + llvm::ConstantInt::get(CGM.Int8Ty, CheckHandler)); + + for (llvm::Value **Cond : {&FatalCond, &RecoverableCond, &TrapCond}) { + if (*Cond) + *Cond = Builder.CreateOr(*Cond, Builder.CreateNot(Allow)); + } + } + if (TrapCond) EmitTrapCheck(TrapCond, CheckHandler); if (!FatalCond && !RecoverableCond) @@ -3663,12 +3681,29 @@ void CodeGenFunction::EmitCfiSlowPathCheck( // symbol in LTO mode. void CodeGenFunction::EmitCfiCheckStub() { llvm::Module *M = &CGM.getModule(); - auto &Ctx = M->getContext(); + ASTContext &C = getContext(); + QualType QInt64Ty = C.getIntTypeForBitwidth(64, false); + + FunctionArgList FnArgs; + ImplicitParamDecl ArgCallsiteTypeId(C, QInt64Ty, ImplicitParamKind::Other); + ImplicitParamDecl ArgAddr(C, C.VoidPtrTy, ImplicitParamKind::Other); + ImplicitParamDecl ArgCFICheckFailData(C, C.VoidPtrTy, + ImplicitParamKind::Other); + FnArgs.push_back(&ArgCallsiteTypeId); + FnArgs.push_back(&ArgAddr); + FnArgs.push_back(&ArgCFICheckFailData); + const CGFunctionInfo &FI = + CGM.getTypes().arrangeBuiltinFunctionDeclaration(C.VoidTy, FnArgs); + llvm::Function *F = llvm::Function::Create( - llvm::FunctionType::get(VoidTy, {Int64Ty, Int8PtrTy, Int8PtrTy}, false), + llvm::FunctionType::get(VoidTy, {Int64Ty, VoidPtrTy, VoidPtrTy}, false), llvm::GlobalValue::WeakAnyLinkage, "__cfi_check", M); + CGM.SetLLVMFunctionAttributes(GlobalDecl(), FI, F, /*IsThunk=*/false); + CGM.SetLLVMFunctionAttributesForDefinition(nullptr, F); F->setAlignment(llvm::Align(4096)); CGM.setDSOLocal(F); + + llvm::LLVMContext &Ctx = M->getContext(); llvm::BasicBlock *BB = llvm::BasicBlock::Create(Ctx, "entry", F); // CrossDSOCFI pass is not executed if there is no executable code. SmallVector Args{F->getArg(2), F->getArg(1)}; @@ -3907,6 +3942,21 @@ static llvm::Value *emitArraySubscriptGEP(CodeGenFunction &CGF, } } +static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, + ArrayRef indices, + llvm::Type *elementType, bool inbounds, + bool signedIndices, SourceLocation loc, + CharUnits align, + const llvm::Twine &name = "arrayidx") { + if (inbounds) { + return CGF.EmitCheckedInBoundsGEP(addr, indices, elementType, signedIndices, + CodeGenFunction::NotSubtraction, loc, + align, name); + } else { + return CGF.Builder.CreateGEP(addr, indices, elementType, align, name); + } +} + static CharUnits getArrayElementAlign(CharUnits arrayAlign, llvm::Value *idx, CharUnits eltSize) { @@ -3954,7 +4004,7 @@ static Address wrapWithBPFPreserveStaticOffset(CodeGenFunction &CGF, llvm::Function *Fn = CGF.CGM.getIntrinsic(llvm::Intrinsic::preserve_static_offset); - llvm::CallInst *Call = CGF.Builder.CreateCall(Fn, {Addr.getPointer()}); + llvm::CallInst *Call = CGF.Builder.CreateCall(Fn, {Addr.emitRawPointer(CGF)}); return Address(Call, Addr.getElementType(), Addr.getAlignment()); } @@ -4017,7 +4067,7 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, // We can use that to compute the best alignment of the element. CharUnits eltSize = CGF.getContext().getTypeSizeInChars(eltType); CharUnits eltAlign = - getArrayElementAlign(addr.getAlignment(), indices.back(), eltSize); + getArrayElementAlign(addr.getAlignment(), indices.back(), eltSize); if (hasBPFPreserveStaticOffset(Base)) addr = wrapWithBPFPreserveStaticOffset(CGF, addr); @@ -4026,19 +4076,19 @@ static Address emitArraySubscriptGEP(CodeGenFunction &CGF, Address addr, auto LastIndex = dyn_cast(indices.back()); if (!LastIndex || (!CGF.IsInPreservedAIRegion && !IsPreserveAIArrayBase(CGF, Base))) { - eltPtr = emitArraySubscriptGEP( - CGF, addr.getElementType(), addr.getPointer(), indices, inbounds, - signedIndices, loc, name); + addr = emitArraySubscriptGEP(CGF, addr, indices, + CGF.ConvertTypeForMem(eltType), inbounds, + signedIndices, loc, eltAlign, name); + return addr; } else { // Remember the original array subscript for bpf target unsigned idx = LastIndex->getZExtValue(); llvm::DIType *DbgInfo = nullptr; if (arrayType) DbgInfo = CGF.getDebugInfo()->getOrCreateStandaloneType(*arrayType, loc); - eltPtr = CGF.Builder.CreatePreserveArrayAccessIndex(addr.getElementType(), - addr.getPointer(), - indices.size() - 1, - idx, DbgInfo); + eltPtr = CGF.Builder.CreatePreserveArrayAccessIndex( + addr.getElementType(), addr.emitRawPointer(CGF), indices.size() - 1, + idx, DbgInfo); } return Address(eltPtr, CGF.ConvertTypeForMem(eltType), eltAlign); @@ -4207,8 +4257,8 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, CharUnits EltAlign = getArrayElementAlign(Addr.getAlignment(), Idx, InterfaceSize); llvm::Value *EltPtr = - emitArraySubscriptGEP(*this, Int8Ty, Addr.getPointer(), ScaledIdx, - false, SignedIndices, E->getExprLoc()); + emitArraySubscriptGEP(*this, Int8Ty, Addr.emitRawPointer(*this), + ScaledIdx, false, SignedIndices, E->getExprLoc()); Addr = Address(EltPtr, OrigBaseElemTy, EltAlign); } else if (const Expr *Array = isSimpleArrayDecayOperand(E->getBase())) { // If this is A[i] where A is an array, the frontend will have decayed the @@ -4254,7 +4304,7 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E, llvm::Type *CountTy = ConvertType(CountFD->getType()); llvm::Value *Res = Builder.CreateInBoundsGEP( - Int8Ty, Addr.getPointer(), + Int8Ty, Addr.emitRawPointer(*this), Builder.getInt32(OffsetDiff.getQuantity()), ".counted_by.gep"); Res = Builder.CreateAlignedLoad(CountTy, Res, getIntAlign(), ".counted_by.load"); @@ -4500,9 +4550,9 @@ LValue CodeGenFunction::EmitOMPArraySectionExpr(const OMPArraySectionExpr *E, BaseInfo = ArrayLV.getBaseInfo(); TBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, ResultExprTy); } else { - Address Base = emitOMPArraySectionBase(*this, E->getBase(), BaseInfo, - TBAAInfo, BaseTy, ResultExprTy, - IsLowerBound); + Address Base = + emitOMPArraySectionBase(*this, E->getBase(), BaseInfo, TBAAInfo, BaseTy, + ResultExprTy, IsLowerBound); EltPtr = emitArraySubscriptGEP(*this, Base, Idx, ResultExprTy, !getLangOpts().isSignedOverflowDefined(), /*signedIndices=*/false, E->getExprLoc()); @@ -4589,7 +4639,7 @@ LValue CodeGenFunction::EmitMemberExpr(const MemberExpr *E) { SkippedChecks.set(SanitizerKind::Alignment, true); if (IsBaseCXXThis || isa(BaseExpr)) SkippedChecks.set(SanitizerKind::Null, true); - EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Addr.getPointer(), PtrTy, + EmitTypeCheck(TCK_MemberAccess, E->getExprLoc(), Addr, PtrTy, /*Alignment=*/CharUnits::Zero(), SkippedChecks); BaseLV = MakeAddrLValue(Addr, PtrTy, BaseInfo, TBAAInfo); } else @@ -4638,8 +4688,8 @@ LValue CodeGenFunction::EmitLValueForLambdaField(const FieldDecl *Field, LambdaLV = EmitLoadOfReferenceLValue(AddrOfExplicitObject, D->getType(), AlignmentSource::Decl); else - LambdaLV = MakeNaturalAlignAddrLValue(AddrOfExplicitObject.getPointer(), - D->getType().getNonReferenceType()); + LambdaLV = MakeAddrLValue(AddrOfExplicitObject, + D->getType().getNonReferenceType()); } else { QualType LambdaTagType = getContext().getTagDeclType(Field->getParent()); LambdaLV = MakeNaturalAlignAddrLValue(ThisValue, LambdaTagType); @@ -4829,7 +4879,8 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, // information provided by invariant.group. This is because accessing // fields may leak the real address of dynamic object, which could result // in miscompilation when leaked pointer would be compared. - auto *stripped = Builder.CreateStripInvariantGroup(addr.getPointer()); + auto *stripped = + Builder.CreateStripInvariantGroup(addr.emitRawPointer(*this)); addr = Address(stripped, addr.getElementType(), addr.getAlignment()); } } @@ -4848,10 +4899,11 @@ LValue CodeGenFunction::EmitLValueForField(LValue base, // Remember the original union field index llvm::DIType *DbgInfo = getDebugInfo()->getOrCreateStandaloneType(base.getType(), rec->getLocation()); - addr = Address( - Builder.CreatePreserveUnionAccessIndex( - addr.getPointer(), getDebugInfoFIndex(rec, field->getFieldIndex()), DbgInfo), - addr.getElementType(), addr.getAlignment()); + addr = + Address(Builder.CreatePreserveUnionAccessIndex( + addr.emitRawPointer(*this), + getDebugInfoFIndex(rec, field->getFieldIndex()), DbgInfo), + addr.getElementType(), addr.getAlignment()); } if (FieldType->isReferenceType()) @@ -5088,11 +5140,9 @@ LValue CodeGenFunction::EmitConditionalOperatorLValue( if (Info.LHS && Info.RHS) { Address lhsAddr = Info.LHS->getAddress(*this); Address rhsAddr = Info.RHS->getAddress(*this); - llvm::PHINode *phi = Builder.CreatePHI(lhsAddr.getType(), 2, "cond-lvalue"); - phi->addIncoming(lhsAddr.getPointer(), Info.lhsBlock); - phi->addIncoming(rhsAddr.getPointer(), Info.rhsBlock); - Address result(phi, lhsAddr.getElementType(), - std::min(lhsAddr.getAlignment(), rhsAddr.getAlignment())); + Address result = mergeAddressesInConditionalExpr( + lhsAddr, rhsAddr, Info.lhsBlock, Info.rhsBlock, + Builder.GetInsertBlock(), expr->getType()); AlignmentSource alignSource = std::max(Info.LHS->getBaseInfo().getAlignmentSource(), Info.RHS->getBaseInfo().getAlignmentSource()); @@ -5162,6 +5212,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { case CK_IntegralToFixedPoint: case CK_MatrixCast: case CK_HLSLVectorTruncation: + case CK_HLSLArrayRValue: return EmitUnsupportedLValue(E, "unexpected cast lvalue"); case CK_Dependent: @@ -5179,7 +5230,7 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { LValue LV = EmitLValue(E->getSubExpr()); Address V = LV.getAddress(*this); const auto *DCE = cast(E); - return MakeNaturalAlignAddrLValue(EmitDynamicCast(V, DCE), E->getType()); + return MakeNaturalAlignRawAddrLValue(EmitDynamicCast(V, DCE), E->getType()); } case CK_ConstructorConversion: @@ -5244,8 +5295,8 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) { // C++11 [expr.static.cast]p2: Behavior is undefined if a downcast is // performed and the object is not of the derived type. if (sanitizePerformTypeCheck()) - EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(), - Derived.getPointer(), E->getType()); + EmitTypeCheck(TCK_DowncastReference, E->getExprLoc(), Derived, + E->getType()); if (SanOpts.has(SanitizerKind::CFIDerivedCast)) EmitVTablePtrCheckForCast(E->getType(), Derived, @@ -5552,11 +5603,44 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) { break; } - RValue RV = EmitAnyExpr(E->getRHS()); + // TODO: Can we de-duplicate this code with the corresponding code in + // CGExprScalar, similar to the way EmitCompoundAssignmentLValue works? + RValue RV; + llvm::Value *Previous = nullptr; + QualType SrcType = E->getRHS()->getType(); + // Check if LHS is a bitfield, if RHS contains an implicit cast expression + // we want to extract that value and potentially (if the bitfield sanitizer + // is enabled) use it to check for an implicit conversion. + if (E->getLHS()->refersToBitField()) { + llvm::Value *RHS = + EmitWithOriginalRHSBitfieldAssignment(E, &Previous, &SrcType); + RV = RValue::get(RHS); + } else + RV = EmitAnyExpr(E->getRHS()); + LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store); + if (RV.isScalar()) EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc()); - EmitStoreThroughLValue(RV, LV); + + if (LV.isBitField()) { + llvm::Value *Result = nullptr; + // If bitfield sanitizers are enabled we want to use the result + // to check whether a truncation or sign change has occurred. + if (SanOpts.has(SanitizerKind::ImplicitBitfieldConversion)) + EmitStoreThroughBitfieldLValue(RV, LV, &Result); + else + EmitStoreThroughBitfieldLValue(RV, LV); + + // If the expression contained an implicit conversion, make sure + // to use the value before the scalar conversion. + llvm::Value *Src = Previous ? Previous : RV.getScalarVal(); + QualType DstType = E->getLHS()->getType(); + EmitBitfieldConversionCheck(Src, SrcType, Result, DstType, + LV.getBitFieldInfo(), E->getExprLoc()); + } else + EmitStoreThroughLValue(RV, LV); + if (getLangOpts().OpenMP) CGM.getOpenMPRuntime().checkAndEmitLastprivateConditional(*this, E->getLHS()); @@ -5601,7 +5685,7 @@ LValue CodeGenFunction::EmitCXXConstructLValue(const CXXConstructExpr *E) { LValue CodeGenFunction::EmitCXXTypeidLValue(const CXXTypeidExpr *E) { - return MakeNaturalAlignAddrLValue(EmitCXXTypeidExpr(E), E->getType()); + return MakeNaturalAlignRawAddrLValue(EmitCXXTypeidExpr(E), E->getType()); } Address CodeGenFunction::EmitCXXUuidofExpr(const CXXUuidofExpr *E) { diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 5190b22bcc162254b09ef81bae7f7f3d7deb0502..560a9e2c5ead5c9c37eef219b08c42718d6263d3 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -15,6 +15,7 @@ #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" +#include "EHScopeStack.h" #include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" @@ -24,6 +25,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" #include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Instruction.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" using namespace clang; @@ -294,10 +296,10 @@ void AggExprEmitter::withReturnValueSlot( // Otherwise, EmitCall will emit its own, notice that it's "unused", and end // its lifetime before we have the chance to emit a proper destructor call. bool UseTemp = Dest.isPotentiallyAliased() || Dest.requiresGCollection() || - (RequiresDestruction && !Dest.getAddress().isValid()); + (RequiresDestruction && Dest.isIgnored()); Address RetAddr = Address::invalid(); - Address RetAllocaAddr = Address::invalid(); + RawAddress RetAllocaAddr = RawAddress::invalid(); EHScopeStack::stable_iterator LifetimeEndBlock; llvm::Value *LifetimeSizePtr = nullptr; @@ -329,7 +331,8 @@ void AggExprEmitter::withReturnValueSlot( if (!UseTemp) return; - assert(Dest.isIgnored() || Dest.getPointer() != Src.getAggregatePointer()); + assert(Dest.isIgnored() || Dest.emitRawPointer(CGF) != + Src.getAggregatePointer(E->getType(), CGF)); EmitFinalDestCopy(E->getType(), Src); if (!RequiresDestruction && LifetimeStartInst) { @@ -448,7 +451,8 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { llvm::Value *Zero = llvm::ConstantInt::get(CGF.PtrDiffTy, 0); llvm::Value *IdxStart[] = { Zero, Zero }; llvm::Value *ArrayStart = Builder.CreateInBoundsGEP( - ArrayPtr.getElementType(), ArrayPtr.getPointer(), IdxStart, "arraystart"); + ArrayPtr.getElementType(), ArrayPtr.emitRawPointer(CGF), IdxStart, + "arraystart"); CGF.EmitStoreThroughLValue(RValue::get(ArrayStart), Start); ++Field; @@ -465,7 +469,8 @@ AggExprEmitter::VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { // End pointer. llvm::Value *IdxEnd[] = { Zero, Size }; llvm::Value *ArrayEnd = Builder.CreateInBoundsGEP( - ArrayPtr.getElementType(), ArrayPtr.getPointer(), IdxEnd, "arrayend"); + ArrayPtr.getElementType(), ArrayPtr.emitRawPointer(CGF), IdxEnd, + "arrayend"); CGF.EmitStoreThroughLValue(RValue::get(ArrayEnd), EndOrLength); } else if (Ctx.hasSameType(Field->getType(), Ctx.getSizeType())) { // Length. @@ -516,9 +521,9 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType, // down a level. llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0); llvm::Value *indices[] = { zero, zero }; - llvm::Value *begin = Builder.CreateInBoundsGEP( - DestPtr.getElementType(), DestPtr.getPointer(), indices, - "arrayinit.begin"); + llvm::Value *begin = Builder.CreateInBoundsGEP(DestPtr.getElementType(), + DestPtr.emitRawPointer(CGF), + indices, "arrayinit.begin"); CharUnits elementSize = CGF.getContext().getTypeSizeInChars(elementType); CharUnits elementAlign = @@ -555,24 +560,27 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType, // For that, we'll need an EH cleanup. QualType::DestructionKind dtorKind = elementType.isDestructedType(); Address endOfInit = Address::invalid(); - EHScopeStack::stable_iterator cleanup; - llvm::Instruction *cleanupDominator = nullptr; - if (CGF.needsEHCleanup(dtorKind)) { + CodeGenFunction::CleanupDeactivationScope deactivation(CGF); + + if (dtorKind) { + CodeGenFunction::AllocaTrackerRAII allocaTracker(CGF); // In principle we could tell the cleanup where we are more // directly, but the control flow can get so varied here that it // would actually be quite complex. Therefore we go through an // alloca. + llvm::Instruction *dominatingIP = + Builder.CreateFlagLoad(llvm::ConstantInt::getNullValue(CGF.Int8PtrTy)); endOfInit = CGF.CreateTempAlloca(begin->getType(), CGF.getPointerAlign(), "arrayinit.endOfInit"); - cleanupDominator = Builder.CreateStore(begin, endOfInit); + Builder.CreateStore(begin, endOfInit); CGF.pushIrregularPartialArrayCleanup(begin, endOfInit, elementType, elementAlign, CGF.getDestroyer(dtorKind)); - cleanup = CGF.EHStack.stable_begin(); + cast(*CGF.EHStack.find(CGF.EHStack.stable_begin())) + .AddAuxAllocas(allocaTracker.Take()); - // Otherwise, remember that we didn't need a cleanup. - } else { - dtorKind = QualType::DK_none; + CGF.DeferredDeactivationCleanupStack.push_back( + {CGF.EHStack.stable_begin(), dominatingIP}); } llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1); @@ -668,9 +676,6 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType, CGF.EmitBlock(endBB); } - - // Leave the partial-array cleanup if we entered one. - if (dtorKind) CGF.DeactivateCleanupBlock(cleanup, cleanupDominator); } //===----------------------------------------------------------------------===// @@ -880,6 +885,9 @@ void AggExprEmitter::VisitCastExpr(CastExpr *E) { [[fallthrough]]; + case CK_HLSLArrayRValue: + Visit(E->getSubExpr()); + break; case CK_NoOp: case CK_UserDefinedConversion: @@ -1059,7 +1067,7 @@ void AggExprEmitter::VisitBinCmp(const BinaryOperator *E) { if (RV.isScalar()) return {RV.getScalarVal(), nullptr}; if (RV.isAggregate()) - return {RV.getAggregatePointer(), nullptr}; + return {RV.getAggregatePointer(E->getType(), CGF), nullptr}; assert(RV.isComplex()); return RV.getComplexVal(); }; @@ -1368,9 +1376,8 @@ AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) { LValue SlotLV = CGF.MakeAddrLValue(Slot.getAddress(), E->getType()); // We'll need to enter cleanup scopes in case any of the element - // initializers throws an exception. - SmallVector Cleanups; - llvm::Instruction *CleanupDominator = nullptr; + // initializers throws an exception or contains branch out of the expressions. + CodeGenFunction::CleanupDeactivationScope scope(CGF); CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin(); for (LambdaExpr::const_capture_init_iterator i = E->capture_init_begin(), @@ -1389,28 +1396,12 @@ AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) { if (QualType::DestructionKind DtorKind = CurField->getType().isDestructedType()) { assert(LV.isSimple()); - if (CGF.needsEHCleanup(DtorKind)) { - if (!CleanupDominator) - CleanupDominator = CGF.Builder.CreateAlignedLoad( - CGF.Int8Ty, - llvm::Constant::getNullValue(CGF.Int8PtrTy), - CharUnits::One()); // placeholder - - CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), CurField->getType(), - CGF.getDestroyer(DtorKind), false); - Cleanups.push_back(CGF.EHStack.stable_begin()); - } + if (DtorKind) + CGF.pushDestroyAndDeferDeactivation( + NormalAndEHCleanup, LV.getAddress(CGF), CurField->getType(), + CGF.getDestroyer(DtorKind), false); } } - - // Deactivate all the partial cleanups in reverse order, which - // generally means popping them. - for (unsigned i = Cleanups.size(); i != 0; --i) - CGF.DeactivateCleanupBlock(Cleanups[i-1], CleanupDominator); - - // Destroy the placeholder if we made one. - if (CleanupDominator) - CleanupDominator->eraseFromParent(); } void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) { @@ -1521,6 +1512,7 @@ static bool castPreservesZero(const CastExpr *CE) { case CK_LValueToRValue: case CK_LValueToRValueBitCast: case CK_UncheckedDerivedToBase: + case CK_HLSLArrayRValue: return false; } llvm_unreachable("Unhandled clang::CastKind enum"); @@ -1698,14 +1690,7 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( // We'll need to enter cleanup scopes in case any of the element // initializers throws an exception. SmallVector cleanups; - llvm::Instruction *cleanupDominator = nullptr; - auto addCleanup = [&](const EHScopeStack::stable_iterator &cleanup) { - cleanups.push_back(cleanup); - if (!cleanupDominator) // create placeholder once needed - cleanupDominator = CGF.Builder.CreateAlignedLoad( - CGF.Int8Ty, llvm::Constant::getNullValue(CGF.Int8PtrTy), - CharUnits::One()); - }; + CodeGenFunction::CleanupDeactivationScope DeactivateCleanups(CGF); unsigned curInitIndex = 0; @@ -1728,10 +1713,8 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( CGF.EmitAggExpr(InitExprs[curInitIndex++], AggSlot); if (QualType::DestructionKind dtorKind = - Base.getType().isDestructedType()) { - CGF.pushDestroy(dtorKind, V, Base.getType()); - addCleanup(CGF.EHStack.stable_begin()); - } + Base.getType().isDestructedType()) + CGF.pushDestroyAndDeferDeactivation(dtorKind, V, Base.getType()); } } @@ -1806,10 +1789,10 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( if (QualType::DestructionKind dtorKind = field->getType().isDestructedType()) { assert(LV.isSimple()); - if (CGF.needsEHCleanup(dtorKind)) { - CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), field->getType(), - CGF.getDestroyer(dtorKind), false); - addCleanup(CGF.EHStack.stable_begin()); + if (dtorKind) { + CGF.pushDestroyAndDeferDeactivation( + NormalAndEHCleanup, LV.getAddress(CGF), field->getType(), + CGF.getDestroyer(dtorKind), false); pushedCleanup = true; } } @@ -1818,21 +1801,10 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr( // else, clean it up for -O0 builds and general tidiness. if (!pushedCleanup && LV.isSimple()) if (llvm::GetElementPtrInst *GEP = - dyn_cast(LV.getPointer(CGF))) + dyn_cast(LV.emitRawPointer(CGF))) if (GEP->use_empty()) GEP->eraseFromParent(); } - - // Deactivate all the partial cleanups in reverse order, which - // generally means popping them. - assert((cleanupDominator || cleanups.empty()) && - "Missing cleanupDominator before deactivating cleanup blocks"); - for (unsigned i = cleanups.size(); i != 0; --i) - CGF.DeactivateCleanupBlock(cleanups[i-1], cleanupDominator); - - // Destroy the placeholder if we made one. - if (cleanupDominator) - cleanupDominator->eraseFromParent(); } void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E, @@ -1849,9 +1821,9 @@ void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E, // destPtr is an array*. Construct an elementType* by drilling down a level. llvm::Value *zero = llvm::ConstantInt::get(CGF.SizeTy, 0); llvm::Value *indices[] = {zero, zero}; - llvm::Value *begin = Builder.CreateInBoundsGEP( - destPtr.getElementType(), destPtr.getPointer(), indices, - "arrayinit.begin"); + llvm::Value *begin = Builder.CreateInBoundsGEP(destPtr.getElementType(), + destPtr.emitRawPointer(CGF), + indices, "arrayinit.begin"); // Prepare to special-case multidimensional array initialization: we avoid // emitting multiple destructor loops in that case. diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp index 2adbef6d55122c973a195260ad218354723ff035..a88b29b326bb927611719b04d38fcea1b5d153c6 100644 --- a/clang/lib/CodeGen/CGExprCXX.cpp +++ b/clang/lib/CodeGen/CGExprCXX.cpp @@ -280,7 +280,8 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( LValueBaseInfo BaseInfo; TBAAAccessInfo TBAAInfo; Address ThisValue = EmitPointerWithAlignment(Base, &BaseInfo, &TBAAInfo); - This = MakeAddrLValue(ThisValue, Base->getType(), BaseInfo, TBAAInfo); + This = MakeAddrLValue(ThisValue, Base->getType()->getPointeeType(), + BaseInfo, TBAAInfo); } else { This = EmitLValue(Base); } @@ -353,10 +354,12 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr( if (IsImplicitObjectCXXThis || isa(IOA)) SkippedChecks.set(SanitizerKind::Null, true); } - EmitTypeCheck(CodeGenFunction::TCK_MemberCall, CallLoc, - This.getPointer(*this), - C.getRecordType(CalleeDecl->getParent()), - /*Alignment=*/CharUnits::Zero(), SkippedChecks); + + if (sanitizePerformTypeCheck()) + EmitTypeCheck(CodeGenFunction::TCK_MemberCall, CallLoc, + This.emitRawPointer(*this), + C.getRecordType(CalleeDecl->getParent()), + /*Alignment=*/CharUnits::Zero(), SkippedChecks); // C++ [class.virtual]p12: // Explicit qualification with the scope operator (5.1) suppresses the @@ -455,7 +458,7 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, else This = EmitLValue(BaseExpr, KnownNonNull).getAddress(*this); - EmitTypeCheck(TCK_MemberCall, E->getExprLoc(), This.getPointer(), + EmitTypeCheck(TCK_MemberCall, E->getExprLoc(), This.emitRawPointer(*this), QualType(MPT->getClass(), 0)); // Get the member function pointer. @@ -1005,8 +1008,8 @@ void CodeGenFunction::EmitNewArrayInitializer( const Expr *Init = E->getInitializer(); Address EndOfInit = Address::invalid(); QualType::DestructionKind DtorKind = ElementType.isDestructedType(); - EHScopeStack::stable_iterator Cleanup; - llvm::Instruction *CleanupDominator = nullptr; + CleanupDeactivationScope deactivation(*this); + bool pushedCleanup = false; CharUnits ElementSize = getContext().getTypeSizeInChars(ElementType); CharUnits ElementAlign = @@ -1073,8 +1076,7 @@ void CodeGenFunction::EmitNewArrayInitializer( // Move past these elements. InitListElements = cast(Init->getType()->getAsArrayTypeUnsafe()) - ->getSize() - .getZExtValue(); + ->getZExtSize(); CurPtr = Builder.CreateConstInBoundsGEP( CurPtr, InitListElements, "string.init.end"); @@ -1103,18 +1105,24 @@ void CodeGenFunction::EmitNewArrayInitializer( } // Enter a partial-destruction Cleanup if necessary. - if (needsEHCleanup(DtorKind)) { + if (DtorKind) { + AllocaTrackerRAII AllocaTracker(*this); // In principle we could tell the Cleanup where we are more // directly, but the control flow can get so varied here that it // would actually be quite complex. Therefore we go through an // alloca. + llvm::Instruction *DominatingIP = + Builder.CreateFlagLoad(llvm::ConstantInt::getNullValue(Int8PtrTy)); EndOfInit = CreateTempAlloca(BeginPtr.getType(), getPointerAlign(), "array.init.end"); - CleanupDominator = Builder.CreateStore(BeginPtr.getPointer(), EndOfInit); - pushIrregularPartialArrayCleanup(BeginPtr.getPointer(), EndOfInit, - ElementType, ElementAlign, + pushIrregularPartialArrayCleanup(BeginPtr.emitRawPointer(*this), + EndOfInit, ElementType, ElementAlign, getDestroyer(DtorKind)); - Cleanup = EHStack.stable_begin(); + cast(*EHStack.find(EHStack.stable_begin())) + .AddAuxAllocas(AllocaTracker.Take()); + DeferredDeactivationCleanupStack.push_back( + {EHStack.stable_begin(), DominatingIP}); + pushedCleanup = true; } CharUnits StartAlign = CurPtr.getAlignment(); @@ -1124,16 +1132,17 @@ void CodeGenFunction::EmitNewArrayInitializer( // element. TODO: some of these stores can be trivially // observed to be unnecessary. if (EndOfInit.isValid()) { - Builder.CreateStore(CurPtr.getPointer(), EndOfInit); + Builder.CreateStore(CurPtr.emitRawPointer(*this), EndOfInit); } // FIXME: If the last initializer is an incomplete initializer list for // an array, and we have an array filler, we can fold together the two // initialization loops. StoreAnyExprIntoOneUnit(*this, IE, IE->getType(), CurPtr, AggValueSlot::DoesNotOverlap); - CurPtr = Address(Builder.CreateInBoundsGEP( - CurPtr.getElementType(), CurPtr.getPointer(), - Builder.getSize(1), "array.exp.next"), + CurPtr = Address(Builder.CreateInBoundsGEP(CurPtr.getElementType(), + CurPtr.emitRawPointer(*this), + Builder.getSize(1), + "array.exp.next"), CurPtr.getElementType(), StartAlign.alignmentAtOffset((++i) * ElementSize)); } @@ -1160,9 +1169,6 @@ void CodeGenFunction::EmitNewArrayInitializer( // initialization. llvm::ConstantInt *ConstNum = dyn_cast(NumElements); if (ConstNum && ConstNum->getZExtValue() <= InitListElements) { - // If there was a Cleanup, deactivate it. - if (CleanupDominator) - DeactivateCleanupBlock(Cleanup, CleanupDominator); return; } @@ -1187,7 +1193,7 @@ void CodeGenFunction::EmitNewArrayInitializer( // FIXME: Share this cleanup with the constructor call emission rather than // having it create a cleanup of its own. if (EndOfInit.isValid()) - Builder.CreateStore(CurPtr.getPointer(), EndOfInit); + Builder.CreateStore(CurPtr.emitRawPointer(*this), EndOfInit); // Emit a constructor call loop to initialize the remaining elements. if (InitListElements) @@ -1250,15 +1256,15 @@ void CodeGenFunction::EmitNewArrayInitializer( llvm::BasicBlock *ContBB = createBasicBlock("new.loop.end"); // Find the end of the array, hoisted out of the loop. - llvm::Value *EndPtr = - Builder.CreateInBoundsGEP(BeginPtr.getElementType(), BeginPtr.getPointer(), - NumElements, "array.end"); + llvm::Value *EndPtr = Builder.CreateInBoundsGEP( + BeginPtr.getElementType(), BeginPtr.emitRawPointer(*this), NumElements, + "array.end"); // If the number of elements isn't constant, we have to now check if there is // anything left to initialize. if (!ConstNum) { - llvm::Value *IsEmpty = - Builder.CreateICmpEQ(CurPtr.getPointer(), EndPtr, "array.isempty"); + llvm::Value *IsEmpty = Builder.CreateICmpEQ(CurPtr.emitRawPointer(*this), + EndPtr, "array.isempty"); Builder.CreateCondBr(IsEmpty, ContBB, LoopBB); } @@ -1268,21 +1274,23 @@ void CodeGenFunction::EmitNewArrayInitializer( // Set up the current-element phi. llvm::PHINode *CurPtrPhi = Builder.CreatePHI(CurPtr.getType(), 2, "array.cur"); - CurPtrPhi->addIncoming(CurPtr.getPointer(), EntryBB); + CurPtrPhi->addIncoming(CurPtr.emitRawPointer(*this), EntryBB); CurPtr = Address(CurPtrPhi, CurPtr.getElementType(), ElementAlign); // Store the new Cleanup position for irregular Cleanups. if (EndOfInit.isValid()) - Builder.CreateStore(CurPtr.getPointer(), EndOfInit); + Builder.CreateStore(CurPtr.emitRawPointer(*this), EndOfInit); // Enter a partial-destruction Cleanup if necessary. - if (!CleanupDominator && needsEHCleanup(DtorKind)) { - pushRegularPartialArrayCleanup(BeginPtr.getPointer(), CurPtr.getPointer(), - ElementType, ElementAlign, - getDestroyer(DtorKind)); - Cleanup = EHStack.stable_begin(); - CleanupDominator = Builder.CreateUnreachable(); + if (!pushedCleanup && needsEHCleanup(DtorKind)) { + llvm::Instruction *DominatingIP = + Builder.CreateFlagLoad(llvm::ConstantInt::getNullValue(Int8PtrTy)); + pushRegularPartialArrayCleanup(BeginPtr.emitRawPointer(*this), + CurPtr.emitRawPointer(*this), ElementType, + ElementAlign, getDestroyer(DtorKind)); + DeferredDeactivationCleanupStack.push_back( + {EHStack.stable_begin(), DominatingIP}); } // Emit the initializer into this element. @@ -1290,15 +1298,11 @@ void CodeGenFunction::EmitNewArrayInitializer( AggValueSlot::DoesNotOverlap); // Leave the Cleanup if we entered one. - if (CleanupDominator) { - DeactivateCleanupBlock(Cleanup, CleanupDominator); - CleanupDominator->eraseFromParent(); - } + deactivation.ForceDeactivate(); // Advance to the next element by adjusting the pointer type as necessary. - llvm::Value *NextPtr = - Builder.CreateConstInBoundsGEP1_32(ElementTy, CurPtr.getPointer(), 1, - "array.next"); + llvm::Value *NextPtr = Builder.CreateConstInBoundsGEP1_32( + ElementTy, CurPtr.emitRawPointer(*this), 1, "array.next"); // Check whether we've gotten to the end of the array and, if so, // exit the loop. @@ -1524,14 +1528,9 @@ static void EnterNewDeleteCleanup(CodeGenFunction &CGF, typedef CallDeleteDuringNew DirectCleanup; - DirectCleanup *Cleanup = CGF.EHStack - .pushCleanupWithExtra(EHCleanup, - E->getNumPlacementArgs(), - E->getOperatorDelete(), - NewPtr.getPointer(), - AllocSize, - E->passAlignment(), - AllocAlign); + DirectCleanup *Cleanup = CGF.EHStack.pushCleanupWithExtra( + EHCleanup, E->getNumPlacementArgs(), E->getOperatorDelete(), + NewPtr.emitRawPointer(CGF), AllocSize, E->passAlignment(), AllocAlign); for (unsigned I = 0, N = E->getNumPlacementArgs(); I != N; ++I) { auto &Arg = NewArgs[I + NumNonPlacementArgs]; Cleanup->setPlacementArg(I, Arg.getRValue(CGF), Arg.Ty); @@ -1542,7 +1541,7 @@ static void EnterNewDeleteCleanup(CodeGenFunction &CGF, // Otherwise, we need to save all this stuff. DominatingValue::saved_type SavedNewPtr = - DominatingValue::save(CGF, RValue::get(NewPtr.getPointer())); + DominatingValue::save(CGF, RValue::get(NewPtr, CGF)); DominatingValue::saved_type SavedAllocSize = DominatingValue::save(CGF, RValue::get(AllocSize)); @@ -1591,8 +1590,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { isa(IgnoreParen) || isa(IgnoreParen)) { minElements = cast(Init->getType()->getAsArrayTypeUnsafe()) - ->getSize() - .getZExtValue(); + ->getZExtSize(); } else if (ILE || CPLIE) { minElements = ILE ? ILE->getNumInits() : CPLIE->getInitExprs().size(); } @@ -1620,14 +1618,14 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { // In these cases, discard the computed alignment and use the // formal alignment of the allocated type. if (BaseInfo.getAlignmentSource() != AlignmentSource::Decl) - allocation = allocation.withAlignment(allocAlign); + allocation.setAlignment(allocAlign); // Set up allocatorArgs for the call to operator delete if it's not // the reserved global operator. if (E->getOperatorDelete() && !E->getOperatorDelete()->isReservedGlobalPlacementOperator()) { allocatorArgs.add(RValue::get(allocSize), getContext().getSizeType()); - allocatorArgs.add(RValue::get(allocation.getPointer()), arg->getType()); + allocatorArgs.add(RValue::get(allocation, *this), arg->getType()); } } else { @@ -1715,8 +1713,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { llvm::BasicBlock *notNullBB = createBasicBlock("new.notnull"); contBB = createBasicBlock("new.cont"); - llvm::Value *isNull = - Builder.CreateIsNull(allocation.getPointer(), "new.isnull"); + llvm::Value *isNull = Builder.CreateIsNull(allocation, "new.isnull"); Builder.CreateCondBr(isNull, contBB, notNullBB); EmitBlock(notNullBB); } @@ -1762,12 +1759,12 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) { SkippedChecks.set(SanitizerKind::Null, nullCheck); EmitTypeCheck(CodeGenFunction::TCK_ConstructorCall, E->getAllocatedTypeSourceInfo()->getTypeLoc().getBeginLoc(), - result.getPointer(), allocType, result.getAlignment(), - SkippedChecks, numElements); + result, allocType, result.getAlignment(), SkippedChecks, + numElements); EmitNewInitializer(*this, E, allocType, elementTy, result, numElements, allocSizeWithoutCookie); - llvm::Value *resultPtr = result.getPointer(); + llvm::Value *resultPtr = result.emitRawPointer(*this); if (E->isArray()) { // NewPtr is a pointer to the base element type. If we're // allocating an array of arrays, we'll need to cast back to the @@ -1911,7 +1908,8 @@ static void EmitDestroyingObjectDelete(CodeGenFunction &CGF, CGF.CGM.getCXXABI().emitVirtualObjectDelete(CGF, DE, Ptr, ElementType, Dtor); else - CGF.EmitDeleteCall(DE->getOperatorDelete(), Ptr.getPointer(), ElementType); + CGF.EmitDeleteCall(DE->getOperatorDelete(), Ptr.emitRawPointer(CGF), + ElementType); } /// Emit the code for deleting a single object. @@ -1927,8 +1925,7 @@ static bool EmitObjectDelete(CodeGenFunction &CGF, // dynamic type, the static type shall be a base class of the dynamic type // of the object to be deleted and the static type shall have a virtual // destructor or the behavior is undefined. - CGF.EmitTypeCheck(CodeGenFunction::TCK_MemberCall, - DE->getExprLoc(), Ptr.getPointer(), + CGF.EmitTypeCheck(CodeGenFunction::TCK_MemberCall, DE->getExprLoc(), Ptr, ElementType); const FunctionDecl *OperatorDelete = DE->getOperatorDelete(); @@ -1977,9 +1974,8 @@ static bool EmitObjectDelete(CodeGenFunction &CGF, // Make sure that we call delete even if the dtor throws. // This doesn't have to a conditional cleanup because we're going // to pop it off in a second. - CGF.EHStack.pushCleanup(NormalAndEHCleanup, - Ptr.getPointer(), - OperatorDelete, ElementType); + CGF.EHStack.pushCleanup( + NormalAndEHCleanup, Ptr.emitRawPointer(CGF), OperatorDelete, ElementType); if (Dtor) CGF.EmitCXXDestructorCall(Dtor, Dtor_Complete, @@ -2066,7 +2062,7 @@ static void EmitArrayDelete(CodeGenFunction &CGF, CharUnits elementAlign = deletedPtr.getAlignment().alignmentOfArrayElement(elementSize); - llvm::Value *arrayBegin = deletedPtr.getPointer(); + llvm::Value *arrayBegin = deletedPtr.emitRawPointer(CGF); llvm::Value *arrayEnd = CGF.Builder.CreateInBoundsGEP( deletedPtr.getElementType(), arrayBegin, numElements, "delete.end"); @@ -2097,7 +2093,7 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { llvm::BasicBlock *DeleteNotNull = createBasicBlock("delete.notnull"); llvm::BasicBlock *DeleteEnd = createBasicBlock("delete.end"); - llvm::Value *IsNull = Builder.CreateIsNull(Ptr.getPointer(), "isnull"); + llvm::Value *IsNull = Builder.CreateIsNull(Ptr, "isnull"); Builder.CreateCondBr(IsNull, DeleteEnd, DeleteNotNull); EmitBlock(DeleteNotNull); @@ -2132,10 +2128,8 @@ void CodeGenFunction::EmitCXXDeleteExpr(const CXXDeleteExpr *E) { GEP.push_back(Zero); } - Ptr = Address(Builder.CreateInBoundsGEP(Ptr.getElementType(), - Ptr.getPointer(), GEP, "del.first"), - ConvertTypeForMem(DeleteTy), Ptr.getAlignment(), - Ptr.isKnownNonNull()); + Ptr = Builder.CreateInBoundsGEP(Ptr, GEP, ConvertTypeForMem(DeleteTy), + Ptr.getAlignment(), "del.first"); } assert(ConvertTypeForMem(DeleteTy) == Ptr.getElementType()); @@ -2193,7 +2187,7 @@ static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E, // destruction and the static type of the operand is neither the constructor // or destructor’s class nor one of its bases, the behavior is undefined. CGF.EmitTypeCheck(CodeGenFunction::TCK_DynamicOperation, E->getExprLoc(), - ThisPtr.getPointer(), SrcRecordTy); + ThisPtr, SrcRecordTy); // C++ [expr.typeid]p2: // If the glvalue expression is obtained by applying the unary * operator to @@ -2209,7 +2203,7 @@ static llvm::Value *EmitTypeidFromVTable(CodeGenFunction &CGF, const Expr *E, CGF.createBasicBlock("typeid.bad_typeid"); llvm::BasicBlock *EndBlock = CGF.createBasicBlock("typeid.end"); - llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr.getPointer()); + llvm::Value *IsNull = CGF.Builder.CreateIsNull(ThisPtr); CGF.Builder.CreateCondBr(IsNull, BadTypeidBlock, EndBlock); CGF.EmitBlock(BadTypeidBlock); @@ -2295,8 +2289,7 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr, // construction or destruction and the static type of the operand is not a // pointer to or object of the constructor or destructor’s own class or one // of its bases, the dynamic_cast results in undefined behavior. - EmitTypeCheck(TCK_DynamicOperation, DCE->getExprLoc(), ThisAddr.getPointer(), - SrcRecordTy); + EmitTypeCheck(TCK_DynamicOperation, DCE->getExprLoc(), ThisAddr, SrcRecordTy); if (DCE->isAlwaysNull()) { if (llvm::Value *T = EmitDynamicCastToNull(*this, DestTy)) { @@ -2331,7 +2324,7 @@ llvm::Value *CodeGenFunction::EmitDynamicCast(Address ThisAddr, CastNull = createBasicBlock("dynamic_cast.null"); CastNotNull = createBasicBlock("dynamic_cast.notnull"); - llvm::Value *IsNull = Builder.CreateIsNull(ThisAddr.getPointer()); + llvm::Value *IsNull = Builder.CreateIsNull(ThisAddr); Builder.CreateCondBr(IsNull, CastNull, CastNotNull); EmitBlock(CastNotNull); } diff --git a/clang/lib/CodeGen/CGExprComplex.cpp b/clang/lib/CodeGen/CGExprComplex.cpp index b873bc6737bb0a61d17d2eaa6e29db0abca12619..1facadd82f1701c1644c705314e991bd6391b69f 100644 --- a/clang/lib/CodeGen/CGExprComplex.cpp +++ b/clang/lib/CodeGen/CGExprComplex.cpp @@ -289,7 +289,7 @@ public: const BinOpInfo &Op); QualType GetHigherPrecisionFPType(QualType ElementType) { - const auto *CurrentBT = dyn_cast(ElementType); + const auto *CurrentBT = cast(ElementType); switch (CurrentBT->getKind()) { case BuiltinType::Kind::Float16: return CGF.getContext().FloatTy; @@ -319,12 +319,12 @@ public: // doubles the exponent of SmallerType.LargestFiniteVal) if (llvm::APFloat::semanticsMaxExponent(ElementTypeSemantics) * 2 + 1 <= llvm::APFloat::semanticsMaxExponent(HigherElementTypeSemantics)) { + FPHasBeenPromoted = true; return CGF.getContext().getComplexType(HigherElementType); } else { - FPHasBeenPromoted = true; DiagnosticsEngine &Diags = CGF.CGM.getDiags(); Diags.Report(diag::warn_next_larger_fp_type_same_size_than_fp); - return CGF.getContext().getComplexType(ElementType); + return QualType(); } } @@ -616,6 +616,7 @@ ComplexPairTy ComplexExprEmitter::EmitCast(CastKind CK, Expr *Op, case CK_IntegralToFixedPoint: case CK_MatrixCast: case CK_HLSLVectorTruncation: + case CK_HLSLArrayRValue: llvm_unreachable("invalid cast kind for complex value"); case CK_FloatingRealToComplex: @@ -1036,7 +1037,7 @@ ComplexPairTy ComplexExprEmitter::EmitBinDiv(const BinOpInfo &Op) { LHSi = llvm::Constant::getNullValue(RHSi->getType()); if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Improved || (Op.FPFeatures.getComplexRange() == LangOptions::CX_Promoted && - FPHasBeenPromoted)) + !FPHasBeenPromoted)) return EmitRangeReductionDiv(LHSr, LHSi, RHSr, RHSi); else if (Op.FPFeatures.getComplexRange() == LangOptions::CX_Basic || Op.FPFeatures.getComplexRange() == LangOptions::CX_Promoted) diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index 75286dceb13a7b2bcd5c90bbdae95a227ea36078..9f1b06eebf9ed089c4dc1d2cbce75a203ff951f9 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -656,7 +656,7 @@ static bool EmitDesignatedInitUpdater(ConstantEmitter &Emitter, } unsigned NumElementsToUpdate = - FillC ? CAT->getSize().getZExtValue() : Updater->getNumInits(); + FillC ? CAT->getZExtSize() : Updater->getNumInits(); for (unsigned I = 0; I != NumElementsToUpdate; ++I, Offset += ElemSize) { Expr *Init = nullptr; if (I < Updater->getNumInits()) @@ -800,8 +800,8 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, // Add a vtable pointer, if we need one and it hasn't already been added. if (Layout.hasOwnVFPtr()) { llvm::Constant *VTableAddressPoint = - CGM.getCXXABI().getVTableAddressPointForConstExpr( - BaseSubobject(CD, Offset), VTableClass); + CGM.getCXXABI().getVTableAddressPoint(BaseSubobject(CD, Offset), + VTableClass); if (!AppendBytes(Offset, VTableAddressPoint)) return false; } @@ -1226,6 +1226,7 @@ public: case CK_ZeroToOCLOpaqueType: case CK_MatrixCast: case CK_HLSLVectorTruncation: + case CK_HLSLArrayRValue: return nullptr; } llvm_unreachable("Invalid CastKind"); @@ -1249,7 +1250,7 @@ public: auto *CAT = CGM.getContext().getAsConstantArrayType(ILE->getType()); assert(CAT && "can't emit array init for non-constant-bound array"); unsigned NumInitElements = ILE->getNumInits(); - unsigned NumElements = CAT->getSize().getZExtValue(); + unsigned NumElements = CAT->getZExtSize(); // Initialising an array requires us to automatically // initialise any elements that have not been initialised explicitly @@ -1374,7 +1375,7 @@ public: // Resize the string to the right size, adding zeros at the end, or // truncating as needed. - Str.resize(CAT->getSize().getZExtValue(), '\0'); + Str.resize(CAT->getZExtSize(), '\0'); return llvm::ConstantDataArray::getString(VMContext, Str, false); } @@ -2382,7 +2383,7 @@ llvm::Constant *CodeGenModule::EmitNullConstant(QualType T) { llvm::Constant *Element = ConstantEmitter::emitNullForMemory(*this, ElementTy); - unsigned NumElements = CAT->getSize().getZExtValue(); + unsigned NumElements = CAT->getZExtSize(); SmallVector Array(NumElements, Element); return llvm::ConstantArray::get(ATy, Array); } diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 8536570087ad0fe96016f169b6dfbbe031c3035d..1f18e0d5ba409a88b3e51b098219685d7a5fc8cb 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -15,6 +15,7 @@ #include "CGDebugInfo.h" #include "CGObjCRuntime.h" #include "CGOpenMPRuntime.h" +#include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "ConstantEmitter.h" @@ -308,6 +309,7 @@ public: llvm::Type *DstTy, SourceLocation Loc); /// Known implicit conversion check kinds. + /// This is used for bitfield conversion checks as well. /// Keep in sync with the enum of the same name in ubsan_handlers.h enum ImplicitConversionCheckKind : unsigned char { ICCK_IntegerTruncation = 0, // Legacy, was only used by clang 7. @@ -1098,11 +1100,28 @@ void ScalarExprEmitter::EmitIntegerTruncationCheck(Value *Src, QualType SrcType, llvm::Constant *StaticArgs[] = { CGF.EmitCheckSourceLocation(Loc), CGF.EmitCheckTypeDescriptor(SrcType), CGF.EmitCheckTypeDescriptor(DstType), - llvm::ConstantInt::get(Builder.getInt8Ty(), Check.first)}; + llvm::ConstantInt::get(Builder.getInt8Ty(), Check.first), + llvm::ConstantInt::get(Builder.getInt32Ty(), 0)}; + CGF.EmitCheck(Check.second, SanitizerHandler::ImplicitConversion, StaticArgs, {Src, Dst}); } +static llvm::Value *EmitIsNegativeTestHelper(Value *V, QualType VType, + const char *Name, + CGBuilderTy &Builder) { + bool VSigned = VType->isSignedIntegerOrEnumerationType(); + llvm::Type *VTy = V->getType(); + if (!VSigned) { + // If the value is unsigned, then it is never negative. + return llvm::ConstantInt::getFalse(VTy->getContext()); + } + llvm::Constant *Zero = llvm::ConstantInt::get(VTy, 0); + return Builder.CreateICmp(llvm::ICmpInst::ICMP_SLT, V, Zero, + llvm::Twine(Name) + "." + V->getName() + + ".negativitycheck"); +} + // Should be called within CodeGenFunction::SanitizerScope RAII scope. // Returns 'i1 false' when the conversion Src -> Dst changed the sign. static std::pair Value * { - // Is this value a signed type? - bool VSigned = VType->isSignedIntegerOrEnumerationType(); - llvm::Type *VTy = V->getType(); - if (!VSigned) { - // If the value is unsigned, then it is never negative. - // FIXME: can we encounter non-scalar VTy here? - return llvm::ConstantInt::getFalse(VTy->getContext()); - } - // Get the zero of the same type with which we will be comparing. - llvm::Constant *Zero = llvm::ConstantInt::get(VTy, 0); - // %V.isnegative = icmp slt %V, 0 - // I.e is %V *strictly* less than zero, does it have negative value? - return Builder.CreateICmp(llvm::ICmpInst::ICMP_SLT, V, Zero, - llvm::Twine(Name) + "." + V->getName() + - ".negativitycheck"); - }; - // 1. Was the old Value negative? - llvm::Value *SrcIsNegative = EmitIsNegativeTest(Src, SrcType, "src"); + llvm::Value *SrcIsNegative = + EmitIsNegativeTestHelper(Src, SrcType, "src", Builder); // 2. Is the new Value negative? - llvm::Value *DstIsNegative = EmitIsNegativeTest(Dst, DstType, "dst"); + llvm::Value *DstIsNegative = + EmitIsNegativeTestHelper(Dst, DstType, "dst", Builder); // 3. Now, was the 'negativity status' preserved during the conversion? // NOTE: conversion from negative to zero is considered to change the sign. // (We want to get 'false' when the conversion changed the sign) @@ -1239,12 +1240,143 @@ void ScalarExprEmitter::EmitIntegerSignChangeCheck(Value *Src, QualType SrcType, llvm::Constant *StaticArgs[] = { CGF.EmitCheckSourceLocation(Loc), CGF.EmitCheckTypeDescriptor(SrcType), CGF.EmitCheckTypeDescriptor(DstType), - llvm::ConstantInt::get(Builder.getInt8Ty(), CheckKind)}; + llvm::ConstantInt::get(Builder.getInt8Ty(), CheckKind), + llvm::ConstantInt::get(Builder.getInt32Ty(), 0)}; // EmitCheck() will 'and' all the checks together. CGF.EmitCheck(Checks, SanitizerHandler::ImplicitConversion, StaticArgs, {Src, Dst}); } +// Should be called within CodeGenFunction::SanitizerScope RAII scope. +// Returns 'i1 false' when the truncation Src -> Dst was lossy. +static std::pair> +EmitBitfieldTruncationCheckHelper(Value *Src, QualType SrcType, Value *Dst, + QualType DstType, CGBuilderTy &Builder) { + bool SrcSigned = SrcType->isSignedIntegerOrEnumerationType(); + bool DstSigned = DstType->isSignedIntegerOrEnumerationType(); + + ScalarExprEmitter::ImplicitConversionCheckKind Kind; + if (!SrcSigned && !DstSigned) + Kind = ScalarExprEmitter::ICCK_UnsignedIntegerTruncation; + else + Kind = ScalarExprEmitter::ICCK_SignedIntegerTruncation; + + llvm::Value *Check = nullptr; + // 1. Extend the truncated value back to the same width as the Src. + Check = Builder.CreateIntCast(Dst, Src->getType(), DstSigned, "bf.anyext"); + // 2. Equality-compare with the original source value + Check = Builder.CreateICmpEQ(Check, Src, "bf.truncheck"); + // If the comparison result is 'i1 false', then the truncation was lossy. + + return std::make_pair( + Kind, std::make_pair(Check, SanitizerKind::ImplicitBitfieldConversion)); +} + +// Should be called within CodeGenFunction::SanitizerScope RAII scope. +// Returns 'i1 false' when the conversion Src -> Dst changed the sign. +static std::pair> +EmitBitfieldSignChangeCheckHelper(Value *Src, QualType SrcType, Value *Dst, + QualType DstType, CGBuilderTy &Builder) { + // 1. Was the old Value negative? + llvm::Value *SrcIsNegative = + EmitIsNegativeTestHelper(Src, SrcType, "bf.src", Builder); + // 2. Is the new Value negative? + llvm::Value *DstIsNegative = + EmitIsNegativeTestHelper(Dst, DstType, "bf.dst", Builder); + // 3. Now, was the 'negativity status' preserved during the conversion? + // NOTE: conversion from negative to zero is considered to change the sign. + // (We want to get 'false' when the conversion changed the sign) + // So we should just equality-compare the negativity statuses. + llvm::Value *Check = nullptr; + Check = + Builder.CreateICmpEQ(SrcIsNegative, DstIsNegative, "bf.signchangecheck"); + // If the comparison result is 'false', then the conversion changed the sign. + return std::make_pair( + ScalarExprEmitter::ICCK_IntegerSignChange, + std::make_pair(Check, SanitizerKind::ImplicitBitfieldConversion)); +} + +void CodeGenFunction::EmitBitfieldConversionCheck(Value *Src, QualType SrcType, + Value *Dst, QualType DstType, + const CGBitFieldInfo &Info, + SourceLocation Loc) { + + if (!SanOpts.has(SanitizerKind::ImplicitBitfieldConversion)) + return; + + // We only care about int->int conversions here. + // We ignore conversions to/from pointer and/or bool. + if (!PromotionIsPotentiallyEligibleForImplicitIntegerConversionCheck(SrcType, + DstType)) + return; + + if (DstType->isBooleanType() || SrcType->isBooleanType()) + return; + + // This should be truncation of integral types. + assert(isa(Src->getType()) && + isa(Dst->getType()) && "non-integer llvm type"); + + // TODO: Calculate src width to avoid emitting code + // for unecessary cases. + unsigned SrcBits = ConvertType(SrcType)->getScalarSizeInBits(); + unsigned DstBits = Info.Size; + + bool SrcSigned = SrcType->isSignedIntegerOrEnumerationType(); + bool DstSigned = DstType->isSignedIntegerOrEnumerationType(); + + CodeGenFunction::SanitizerScope SanScope(this); + + std::pair> + Check; + + // Truncation + bool EmitTruncation = DstBits < SrcBits; + // If Dst is signed and Src unsigned, we want to be more specific + // about the CheckKind we emit, in this case we want to emit + // ICCK_SignedIntegerTruncationOrSignChange. + bool EmitTruncationFromUnsignedToSigned = + EmitTruncation && DstSigned && !SrcSigned; + // Sign change + bool SameTypeSameSize = SrcSigned == DstSigned && SrcBits == DstBits; + bool BothUnsigned = !SrcSigned && !DstSigned; + bool LargerSigned = (DstBits > SrcBits) && DstSigned; + // We can avoid emitting sign change checks in some obvious cases + // 1. If Src and Dst have the same signedness and size + // 2. If both are unsigned sign check is unecessary! + // 3. If Dst is signed and bigger than Src, either + // sign-extension or zero-extension will make sure + // the sign remains. + bool EmitSignChange = !SameTypeSameSize && !BothUnsigned && !LargerSigned; + + if (EmitTruncation) + Check = + EmitBitfieldTruncationCheckHelper(Src, SrcType, Dst, DstType, Builder); + else if (EmitSignChange) { + assert(((SrcBits != DstBits) || (SrcSigned != DstSigned)) && + "either the widths should be different, or the signednesses."); + Check = + EmitBitfieldSignChangeCheckHelper(Src, SrcType, Dst, DstType, Builder); + } else + return; + + ScalarExprEmitter::ImplicitConversionCheckKind CheckKind = Check.first; + if (EmitTruncationFromUnsignedToSigned) + CheckKind = ScalarExprEmitter::ICCK_SignedIntegerTruncationOrSignChange; + + llvm::Constant *StaticArgs[] = { + EmitCheckSourceLocation(Loc), EmitCheckTypeDescriptor(SrcType), + EmitCheckTypeDescriptor(DstType), + llvm::ConstantInt::get(Builder.getInt8Ty(), CheckKind), + llvm::ConstantInt::get(Builder.getInt32Ty(), Info.Size)}; + + EmitCheck(Check.second, SanitizerHandler::ImplicitConversion, StaticArgs, + {Src, Dst}); +} + Value *ScalarExprEmitter::EmitScalarCast(Value *Src, QualType SrcType, QualType DstType, llvm::Type *SrcTy, llvm::Type *DstTy, @@ -2250,7 +2382,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { // performed and the object is not of the derived type. if (CGF.sanitizePerformTypeCheck()) CGF.EmitTypeCheck(CodeGenFunction::TCK_DowncastPointer, CE->getExprLoc(), - Derived.getPointer(), DestTy->getPointeeType()); + Derived, DestTy->getPointeeType()); if (CGF.SanOpts.has(SanitizerKind::CFIDerivedCast)) CGF.EmitVTablePtrCheckForCast(DestTy->getPointeeType(), Derived, @@ -2258,13 +2390,14 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { CodeGenFunction::CFITCK_DerivedCast, CE->getBeginLoc()); - return Derived.getPointer(); + return CGF.getAsNaturalPointerTo(Derived, CE->getType()->getPointeeType()); } case CK_UncheckedDerivedToBase: case CK_DerivedToBase: { // The EmitPointerWithAlignment path does this fine; just discard // the alignment. - return CGF.EmitPointerWithAlignment(CE).getPointer(); + return CGF.getAsNaturalPointerTo(CGF.EmitPointerWithAlignment(CE), + CE->getType()->getPointeeType()); } case CK_Dynamic: { @@ -2274,7 +2407,8 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { } case CK_ArrayToPointerDecay: - return CGF.EmitArrayToPointerDecay(E).getPointer(); + return CGF.getAsNaturalPointerTo(CGF.EmitArrayToPointerDecay(E), + CE->getType()->getPointeeType()); case CK_FunctionToPointerDecay: return EmitLValue(E).getPointer(CGF); @@ -2327,6 +2461,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { case CK_FloatingComplexToIntegralComplex: case CK_ConstructorConversion: case CK_ToUnion: + case CK_HLSLArrayRValue: llvm_unreachable("scalar cast to non-scalar value"); case CK_LValueToRValue: @@ -2617,6 +2752,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, llvm::PHINode *atomicPHI = nullptr; llvm::Value *value; llvm::Value *input; + llvm::Value *Previous = nullptr; + QualType SrcType = E->getType(); int amount = (isInc ? 1 : -1); bool isSubtraction = !isInc; @@ -2705,7 +2842,8 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, "base or promoted) will be signed, or the bitwidths will match."); } if (CGF.SanOpts.hasOneOf( - SanitizerKind::ImplicitIntegerArithmeticValueChange) && + SanitizerKind::ImplicitIntegerArithmeticValueChange | + SanitizerKind::ImplicitBitfieldConversion) && canPerformLossyDemotionCheck) { // While `x += 1` (for `x` with width less than int) is modeled as // promotion+arithmetics+demotion, and we can catch lossy demotion with @@ -2716,13 +2854,26 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, // the increment/decrement in the wider type, and finally // perform the demotion. This will catch lossy demotions. + // We have a special case for bitfields defined using all the bits of the + // type. In this case we need to do the same trick as for the integer + // sanitizer checks, i.e., promotion -> increment/decrement -> demotion. + value = EmitScalarConversion(value, type, promotedType, E->getExprLoc()); Value *amt = llvm::ConstantInt::get(value->getType(), amount, true); value = Builder.CreateAdd(value, amt, isInc ? "inc" : "dec"); // Do pass non-default ScalarConversionOpts so that sanitizer check is - // emitted. + // emitted if LV is not a bitfield, otherwise the bitfield sanitizer + // checks will take care of the conversion. + ScalarConversionOpts Opts; + if (!LV.isBitField()) + Opts = ScalarConversionOpts(CGF.SanOpts); + else if (CGF.SanOpts.has(SanitizerKind::ImplicitBitfieldConversion)) { + Previous = value; + SrcType = promotedType; + } + value = EmitScalarConversion(value, promotedType, type, E->getExprLoc(), - ScalarConversionOpts(CGF.SanOpts)); + Opts); // Note that signed integer inc/dec with width less than int can't // overflow because of promotion rules; we're just eliding a few steps @@ -2907,9 +3058,12 @@ ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV, } // Store the updated result through the lvalue. - if (LV.isBitField()) + if (LV.isBitField()) { + Value *Src = Previous ? Previous : value; CGF.EmitStoreThroughBitfieldLValue(RValue::get(value), LV, &value); - else + CGF.EmitBitfieldConversionCheck(Src, SrcType, value, E->getType(), + LV.getBitFieldInfo(), E->getExprLoc()); + } else CGF.EmitStoreThroughLValue(RValue::get(value), LV); // If this is a postinc, return the value read from memory, otherwise use the @@ -3414,8 +3568,15 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue( // Convert the result back to the LHS type, // potentially with Implicit Conversion sanitizer check. - Result = EmitScalarConversion(Result, PromotionTypeCR, LHSTy, Loc, - ScalarConversionOpts(CGF.SanOpts)); + // If LHSLV is a bitfield, use default ScalarConversionOpts + // to avoid emit any implicit integer checks. + Value *Previous = nullptr; + if (LHSLV.isBitField()) { + Previous = Result; + Result = EmitScalarConversion(Result, PromotionTypeCR, LHSTy, Loc); + } else + Result = EmitScalarConversion(Result, PromotionTypeCR, LHSTy, Loc, + ScalarConversionOpts(CGF.SanOpts)); if (atomicPHI) { llvm::BasicBlock *curBlock = Builder.GetInsertBlock(); @@ -3434,9 +3595,14 @@ LValue ScalarExprEmitter::EmitCompoundAssignLValue( // specially because the result is altered by the store, i.e., [C99 6.5.16p1] // 'An assignment expression has the value of the left operand after the // assignment...'. - if (LHSLV.isBitField()) + if (LHSLV.isBitField()) { + Value *Src = Previous ? Previous : Result; + QualType SrcType = E->getRHS()->getType(); + QualType DstType = E->getLHS()->getType(); CGF.EmitStoreThroughBitfieldLValue(RValue::get(Result), LHSLV, &Result); - else + CGF.EmitBitfieldConversionCheck(Src, SrcType, Result, DstType, + LHSLV.getBitFieldInfo(), E->getExprLoc()); + } else CGF.EmitStoreThroughLValue(RValue::get(Result), LHSLV); if (CGF.getLangOpts().OpenMP) @@ -4548,6 +4714,24 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E, E->getExprLoc()); } +llvm::Value *CodeGenFunction::EmitWithOriginalRHSBitfieldAssignment( + const BinaryOperator *E, Value **Previous, QualType *SrcType) { + // In case we have the integer or bitfield sanitizer checks enabled + // we want to get the expression before scalar conversion. + if (auto *ICE = dyn_cast(E->getRHS())) { + CastKind Kind = ICE->getCastKind(); + if (Kind == CK_IntegralCast || Kind == CK_LValueToRValue) { + *SrcType = ICE->getSubExpr()->getType(); + *Previous = EmitScalarExpr(ICE->getSubExpr()); + // Pass default ScalarConversionOpts to avoid emitting + // integer sanitizer checks as E refers to bitfield. + return EmitScalarConversion(*Previous, *SrcType, ICE->getType(), + ICE->getExprLoc()); + } + } + return EmitScalarExpr(E->getRHS()); +} + Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { bool Ignore = TestAndClearIgnoreResultAssign(); @@ -4576,7 +4760,16 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { case Qualifiers::OCL_None: // __block variables need to have the rhs evaluated first, plus // this should improve codegen just a little. - RHS = Visit(E->getRHS()); + Value *Previous = nullptr; + QualType SrcType = E->getRHS()->getType(); + // Check if LHS is a bitfield, if RHS contains an implicit cast expression + // we want to extract that value and potentially (if the bitfield sanitizer + // is enabled) use it to check for an implicit conversion. + if (E->getLHS()->refersToBitField()) + RHS = CGF.EmitWithOriginalRHSBitfieldAssignment(E, &Previous, &SrcType); + else + RHS = Visit(E->getRHS()); + LHS = EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store); // Store the value into the LHS. Bit-fields are handled specially @@ -4585,6 +4778,12 @@ Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) { // the assignment...'. if (LHS.isBitField()) { CGF.EmitStoreThroughBitfieldLValue(RValue::get(RHS), LHS, &RHS); + // If the expression contained an implicit conversion, make sure + // to use the value before the scalar conversion. + Value *Src = Previous ? Previous : RHS; + QualType DstType = E->getLHS()->getType(); + CGF.EmitBitfieldConversionCheck(Src, SrcType, RHS, DstType, + LHS.getBitFieldInfo(), E->getExprLoc()); } else { CGF.EmitNullabilityCheck(LHS, RHS, E->getExprLoc()); CGF.EmitStoreThroughLValue(RValue::get(RHS), LHS); @@ -5588,3 +5787,16 @@ CodeGenFunction::EmitCheckedInBoundsGEP(llvm::Type *ElemTy, Value *Ptr, return GEPVal; } + +Address CodeGenFunction::EmitCheckedInBoundsGEP( + Address Addr, ArrayRef IdxList, llvm::Type *elementType, + bool SignedIndices, bool IsSubtraction, SourceLocation Loc, CharUnits Align, + const Twine &Name) { + if (!SanOpts.has(SanitizerKind::PointerOverflow)) + return Builder.CreateInBoundsGEP(Addr, IdxList, elementType, Align, Name); + + return RawAddress( + EmitCheckedInBoundsGEP(Addr.getElementType(), Addr.emitRawPointer(*this), + IdxList, SignedIndices, IsSubtraction, Loc, Name), + elementType, Align); +} diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 794d93358b0a4c3573524b15e21e83885506e3dd..5e6a3dd4878f46550216ed46f9cc94e59d18d522 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -17,8 +17,6 @@ #include "CodeGenModule.h" #include "clang/AST/Decl.h" #include "clang/Basic/TargetOptions.h" -#include "llvm/IR/IntrinsicsDirectX.h" -#include "llvm/IR/IntrinsicsSPIRV.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/Support/FormatVariadic.h" @@ -117,6 +115,10 @@ GlobalVariable *replaceBuffer(CGHLSLRuntime::Buffer &Buf) { } // namespace +llvm::Triple::ArchType CGHLSLRuntime::getArch() { + return CGM.getTarget().getTriple().getArch(); +} + void CGHLSLRuntime::addConstant(VarDecl *D, Buffer &CB) { if (D->getStorageClass() == SC_Static) { // For static inside cbuffer, take as global static. @@ -343,18 +345,8 @@ llvm::Value *CGHLSLRuntime::emitInputSemantic(IRBuilder<> &B, return B.CreateCall(FunctionCallee(DxGroupIndex)); } if (D.hasAttr()) { - llvm::Function *ThreadIDIntrinsic; - switch (CGM.getTarget().getTriple().getArch()) { - case llvm::Triple::dxil: - ThreadIDIntrinsic = CGM.getIntrinsic(Intrinsic::dx_thread_id); - break; - case llvm::Triple::spirv: - ThreadIDIntrinsic = CGM.getIntrinsic(Intrinsic::spv_thread_id); - break; - default: - llvm_unreachable("Input semantic not supported by target"); - break; - } + llvm::Function *ThreadIDIntrinsic = + CGM.getIntrinsic(getThreadIdIntrinsic()); return buildVectorInput(B, ThreadIDIntrinsic, Ty); } assert(false && "Unhandled parameter attribute"); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index bffefb66740a0010a999036293119227eca3d0f7..2b8073aef973f8e2a6391cdcf0701a609bcb1e41 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -16,7 +16,11 @@ #define LLVM_CLANG_LIB_CODEGEN_CGHLSLRUNTIME_H #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IntrinsicsDirectX.h" +#include "llvm/IR/IntrinsicsSPIRV.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/HLSLRuntime.h" #include "llvm/ADT/SmallVector.h" @@ -26,6 +30,22 @@ #include #include +// A function generator macro for picking the right intrinsic +// for the target backend +#define GENERATE_HLSL_INTRINSIC_FUNCTION(FunctionName, IntrinsicPostfix) \ + llvm::Intrinsic::ID get##FunctionName##Intrinsic() { \ + llvm::Triple::ArchType Arch = getArch(); \ + switch (Arch) { \ + case llvm::Triple::dxil: \ + return llvm::Intrinsic::dx_##IntrinsicPostfix; \ + case llvm::Triple::spirv: \ + return llvm::Intrinsic::spv_##IntrinsicPostfix; \ + default: \ + llvm_unreachable("Intrinsic " #IntrinsicPostfix \ + " not supported by target architecture"); \ + } \ + } + namespace llvm { class GlobalVariable; class Function; @@ -48,6 +68,17 @@ class CodeGenModule; class CGHLSLRuntime { public: + //===----------------------------------------------------------------------===// + // Start of reserved area for HLSL intrinsic getters. + //===----------------------------------------------------------------------===// + + GENERATE_HLSL_INTRINSIC_FUNCTION(All, all) + GENERATE_HLSL_INTRINSIC_FUNCTION(ThreadId, thread_id) + + //===----------------------------------------------------------------------===// + // End of reserved area for HLSL intrinsic getters. + //===----------------------------------------------------------------------===// + struct BufferResBinding { // The ID like 2 in register(b2, space1). std::optional Reg; @@ -96,6 +127,7 @@ private: BufferResBinding &Binding); void addConstant(VarDecl *D, Buffer &CB); void addBufferDecls(const DeclContext *DC, Buffer &CB); + llvm::Triple::ArchType getArch(); llvm::SmallVector Buffers; }; diff --git a/clang/lib/CodeGen/CGLoopInfo.h b/clang/lib/CodeGen/CGLoopInfo.h index a1c8c7e5307fd9c01b554a1e9cf98a40bd70e4af..0fe33b289130635586765a0714902eaf26012ce4 100644 --- a/clang/lib/CodeGen/CGLoopInfo.h +++ b/clang/lib/CodeGen/CGLoopInfo.h @@ -110,6 +110,10 @@ public: /// been processed. void finish(); + /// Returns the first outer loop containing this loop if any, nullptr + /// otherwise. + const LoopInfo *getParent() const { return Parent; } + private: /// Loop ID metadata. llvm::TempMDTuple TempLoopID; @@ -291,12 +295,13 @@ public: /// Set no progress for the next loop pushed. void setMustProgress(bool P) { StagedAttrs.MustProgress = P; } -private: /// Returns true if there is LoopInfo on the stack. bool hasInfo() const { return !Active.empty(); } /// Return the LoopInfo for the current loop. HasInfo should be called /// first to ensure LoopInfo is present. const LoopInfo &getInfo() const { return *Active.back(); } + +private: /// The set of attributes that will be applied to the next pushed loop. LoopAttributes StagedAttrs; /// Stack of active loops. diff --git a/clang/lib/CodeGen/CGNonTrivialStruct.cpp b/clang/lib/CodeGen/CGNonTrivialStruct.cpp index 75c1d7fbea840688ebe63d5939a08a09cdfd1243..8fade0fac21e9379df8c06aec1c301fdbaff6e85 100644 --- a/clang/lib/CodeGen/CGNonTrivialStruct.cpp +++ b/clang/lib/CodeGen/CGNonTrivialStruct.cpp @@ -366,7 +366,7 @@ template struct GenFuncBase { llvm::Value *SizeInBytes = CGF.Builder.CreateNUWMul(BaseEltSizeVal, NumElts); llvm::Value *DstArrayEnd = CGF.Builder.CreateInBoundsGEP( - CGF.Int8Ty, DstAddr.getPointer(), SizeInBytes); + CGF.Int8Ty, DstAddr.emitRawPointer(CGF), SizeInBytes); llvm::BasicBlock *PreheaderBB = CGF.Builder.GetInsertBlock(); // Create the header block and insert the phi instructions. @@ -376,7 +376,7 @@ template struct GenFuncBase { for (unsigned I = 0; I < N; ++I) { PHIs[I] = CGF.Builder.CreatePHI(CGF.CGM.Int8PtrPtrTy, 2, "addr.cur"); - PHIs[I]->addIncoming(StartAddrs[I].getPointer(), PreheaderBB); + PHIs[I]->addIncoming(StartAddrs[I].emitRawPointer(CGF), PreheaderBB); } // Create the exit and loop body blocks. @@ -410,7 +410,7 @@ template struct GenFuncBase { // Instrs to update the destination and source addresses. // Update phi instructions. NewAddrs[I] = getAddrWithOffset(NewAddrs[I], EltSize); - PHIs[I]->addIncoming(NewAddrs[I].getPointer(), LoopBB); + PHIs[I]->addIncoming(NewAddrs[I].emitRawPointer(CGF), LoopBB); } // Insert an unconditional branch to the header block. @@ -488,7 +488,7 @@ template struct GenFuncBase { for (unsigned I = 0; I < N; ++I) { Alignments[I] = Addrs[I].getAlignment(); - Ptrs[I] = Addrs[I].getPointer(); + Ptrs[I] = Addrs[I].emitRawPointer(CallerCGF); } if (llvm::Function *F = diff --git a/clang/lib/CodeGen/CGObjC.cpp b/clang/lib/CodeGen/CGObjC.cpp index f3a948cf13f9c9098f8497a28aa1ee9102f59939..ee571995ce4c3f4aab64b65af09d570ac89f22ea 100644 --- a/clang/lib/CodeGen/CGObjC.cpp +++ b/clang/lib/CodeGen/CGObjC.cpp @@ -94,8 +94,8 @@ CodeGenFunction::EmitObjCBoxedExpr(const ObjCBoxedExpr *E) { // and cast value to correct type Address Temporary = CreateMemTemp(SubExpr->getType()); EmitAnyExprToMem(SubExpr, Temporary, Qualifiers(), /*isInit*/ true); - llvm::Value *BitCast = - Builder.CreateBitCast(Temporary.getPointer(), ConvertType(ArgQT)); + llvm::Value *BitCast = Builder.CreateBitCast( + Temporary.emitRawPointer(*this), ConvertType(ArgQT)); Args.add(RValue::get(BitCast), ArgQT); // Create char array to store type encoding @@ -204,11 +204,11 @@ llvm::Value *CodeGenFunction::EmitObjCCollectionLiteral(const Expr *E, ObjCMethodDecl::param_const_iterator PI = MethodWithObjects->param_begin(); const ParmVarDecl *argDecl = *PI++; QualType ArgQT = argDecl->getType().getUnqualifiedType(); - Args.add(RValue::get(Objects.getPointer()), ArgQT); + Args.add(RValue::get(Objects, *this), ArgQT); if (DLE) { argDecl = *PI++; ArgQT = argDecl->getType().getUnqualifiedType(); - Args.add(RValue::get(Keys.getPointer()), ArgQT); + Args.add(RValue::get(Keys, *this), ArgQT); } argDecl = *PI; ArgQT = argDecl->getType().getUnqualifiedType(); @@ -827,7 +827,7 @@ static void emitStructGetterCall(CodeGenFunction &CGF, ObjCIvarDecl *ivar, // sizeof (Type of Ivar), isAtomic, false); CallArgList args; - llvm::Value *dest = CGF.ReturnValue.getPointer(); + llvm::Value *dest = CGF.ReturnValue.emitRawPointer(CGF); args.add(RValue::get(dest), Context.VoidPtrTy); args.add(RValue::get(src), Context.VoidPtrTy); @@ -1147,8 +1147,8 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, callCStructCopyConstructor(Dst, Src); } else { ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl(); - emitCPPObjectAtomicGetterCall(*this, ReturnValue.getPointer(), ivar, - AtomicHelperFn); + emitCPPObjectAtomicGetterCall(*this, ReturnValue.emitRawPointer(*this), + ivar, AtomicHelperFn); } return; } @@ -1163,7 +1163,7 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, } else { ObjCIvarDecl *ivar = propImpl->getPropertyIvarDecl(); - emitCPPObjectAtomicGetterCall(*this, ReturnValue.getPointer(), + emitCPPObjectAtomicGetterCall(*this, ReturnValue.emitRawPointer(*this), ivar, AtomicHelperFn); } return; @@ -1287,7 +1287,7 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl, case TEK_Scalar: { llvm::Value *value; if (propType->isReferenceType()) { - value = LV.getAddress(*this).getPointer(); + value = LV.getAddress(*this).emitRawPointer(*this); } else { // We want to load and autoreleaseReturnValue ARC __weak ivars. if (LV.getQuals().getObjCLifetime() == Qualifiers::OCL_Weak) { @@ -1789,11 +1789,10 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ static const unsigned NumItems = 16; // Fetch the countByEnumeratingWithState:objects:count: selector. - IdentifierInfo *II[] = { - &CGM.getContext().Idents.get("countByEnumeratingWithState"), - &CGM.getContext().Idents.get("objects"), - &CGM.getContext().Idents.get("count") - }; + const IdentifierInfo *II[] = { + &CGM.getContext().Idents.get("countByEnumeratingWithState"), + &CGM.getContext().Idents.get("objects"), + &CGM.getContext().Idents.get("count")}; Selector FastEnumSel = CGM.getContext().Selectors.getSelector(std::size(II), &II[0]); @@ -1821,16 +1820,14 @@ void CodeGenFunction::EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S){ CallArgList Args; // The first argument is a temporary of the enumeration-state type. - Args.add(RValue::get(StatePtr.getPointer()), - getContext().getPointerType(StateTy)); + Args.add(RValue::get(StatePtr, *this), getContext().getPointerType(StateTy)); // The second argument is a temporary array with space for NumItems // pointers. We'll actually be loading elements from the array // pointer written into the control state; this buffer is so that // collections that *aren't* backed by arrays can still queue up // batches of elements. - Args.add(RValue::get(ItemsPtr.getPointer()), - getContext().getPointerType(ItemsTy)); + Args.add(RValue::get(ItemsPtr, *this), getContext().getPointerType(ItemsTy)); // The third argument is the capacity of that temporary array. llvm::Type *NSUIntegerTy = ConvertType(getContext().getNSUIntegerType()); @@ -2198,7 +2195,7 @@ static llvm::Value *emitARCLoadOperation(CodeGenFunction &CGF, Address addr, if (!fn) fn = getARCIntrinsic(IntID, CGF.CGM); - return CGF.EmitNounwindRuntimeCall(fn, addr.getPointer()); + return CGF.EmitNounwindRuntimeCall(fn, addr.emitRawPointer(CGF)); } /// Perform an operation having the following signature: @@ -2216,9 +2213,8 @@ static llvm::Value *emitARCStoreOperation(CodeGenFunction &CGF, Address addr, llvm::Type *origType = value->getType(); llvm::Value *args[] = { - CGF.Builder.CreateBitCast(addr.getPointer(), CGF.Int8PtrPtrTy), - CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy) - }; + CGF.Builder.CreateBitCast(addr.emitRawPointer(CGF), CGF.Int8PtrPtrTy), + CGF.Builder.CreateBitCast(value, CGF.Int8PtrTy)}; llvm::CallInst *result = CGF.EmitNounwindRuntimeCall(fn, args); if (ignored) return nullptr; @@ -2237,9 +2233,8 @@ static void emitARCCopyOperation(CodeGenFunction &CGF, Address dst, Address src, fn = getARCIntrinsic(IntID, CGF.CGM); llvm::Value *args[] = { - CGF.Builder.CreateBitCast(dst.getPointer(), CGF.Int8PtrPtrTy), - CGF.Builder.CreateBitCast(src.getPointer(), CGF.Int8PtrPtrTy) - }; + CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), CGF.Int8PtrPtrTy), + CGF.Builder.CreateBitCast(src.emitRawPointer(CGF), CGF.Int8PtrPtrTy)}; CGF.EmitNounwindRuntimeCall(fn, args); } @@ -2490,9 +2485,8 @@ llvm::Value *CodeGenFunction::EmitARCStoreStrongCall(Address addr, fn = getARCIntrinsic(llvm::Intrinsic::objc_storeStrong, CGM); llvm::Value *args[] = { - Builder.CreateBitCast(addr.getPointer(), Int8PtrPtrTy), - Builder.CreateBitCast(value, Int8PtrTy) - }; + Builder.CreateBitCast(addr.emitRawPointer(*this), Int8PtrPtrTy), + Builder.CreateBitCast(value, Int8PtrTy)}; EmitNounwindRuntimeCall(fn, args); if (ignored) return nullptr; @@ -2643,7 +2637,7 @@ void CodeGenFunction::EmitARCDestroyWeak(Address addr) { if (!fn) fn = getARCIntrinsic(llvm::Intrinsic::objc_destroyWeak, CGM); - EmitNounwindRuntimeCall(fn, addr.getPointer()); + EmitNounwindRuntimeCall(fn, addr.emitRawPointer(*this)); } /// void \@objc_moveWeak(i8** %dest, i8** %src) @@ -2725,7 +2719,7 @@ llvm::Value *CodeGenFunction::EmitObjCMRRAutoreleasePoolPush() { CGObjCRuntime &Runtime = CGM.getObjCRuntime(); llvm::Value *Receiver = Runtime.EmitNSAutoreleasePoolClassRef(*this); // [NSAutoreleasePool alloc] - IdentifierInfo *II = &CGM.getContext().Idents.get("alloc"); + const IdentifierInfo *II = &CGM.getContext().Idents.get("alloc"); Selector AllocSel = getContext().Selectors.getSelector(0, &II); CallArgList Args; RValue AllocRV = @@ -2772,7 +2766,7 @@ llvm::Value *CodeGenFunction::EmitObjCAllocInit(llvm::Value *value, /// Produce the code to do a primitive release. /// [tmp drain]; void CodeGenFunction::EmitObjCMRRAutoreleasePoolPop(llvm::Value *Arg) { - IdentifierInfo *II = &CGM.getContext().Idents.get("drain"); + const IdentifierInfo *II = &CGM.getContext().Idents.get("drain"); Selector DrainSel = getContext().Selectors.getSelector(0, &II); CallArgList Args; CGM.getObjCRuntime().GenerateMessageSend(*this, ReturnValueSlot(), @@ -3720,8 +3714,8 @@ CodeGenFunction::GenerateObjCAtomicSetterCopyHelperFunction( if ((HelperFn = CGM.getAtomicSetterHelperFnMap(Ty))) return HelperFn; - IdentifierInfo *II - = &CGM.getContext().Idents.get("__assign_helper_atomic_property_"); + const IdentifierInfo *II = + &CGM.getContext().Idents.get("__assign_helper_atomic_property_"); QualType ReturnTy = C.VoidTy; QualType DestTy = C.getPointerType(Ty); @@ -3818,7 +3812,7 @@ llvm::Constant *CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction( if ((HelperFn = CGM.getAtomicGetterHelperFnMap(Ty))) return HelperFn; - IdentifierInfo *II = + const IdentifierInfo *II = &CGM.getContext().Idents.get("__copy_helper_atomic_property_"); QualType ReturnTy = C.VoidTy; @@ -3912,10 +3906,10 @@ llvm::Constant *CodeGenFunction::GenerateObjCAtomicGetterCopyHelperFunction( llvm::Value * CodeGenFunction::EmitBlockCopyAndAutorelease(llvm::Value *Block, QualType Ty) { // Get selectors for retain/autorelease. - IdentifierInfo *CopyID = &getContext().Idents.get("copy"); + const IdentifierInfo *CopyID = &getContext().Idents.get("copy"); Selector CopySelector = getContext().Selectors.getNullarySelector(CopyID); - IdentifierInfo *AutoreleaseID = &getContext().Idents.get("autorelease"); + const IdentifierInfo *AutoreleaseID = &getContext().Idents.get("autorelease"); Selector AutoreleaseSelector = getContext().Selectors.getNullarySelector(AutoreleaseID); diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp index a36b0cdddaf0afd293592aac7fe7124ab8613db2..4e7f777ba1d9160fd872c7a3466fcf2a438f12e2 100644 --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -706,7 +706,8 @@ protected: llvm::Value *cmd, MessageSendInfo &MSI) override { CGBuilderTy &Builder = CGF.Builder; llvm::Value *lookupArgs[] = { - EnforceType(Builder, ObjCSuper.getPointer(), PtrToObjCSuperTy), cmd}; + EnforceType(Builder, ObjCSuper.emitRawPointer(CGF), PtrToObjCSuperTy), + cmd}; return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs); } @@ -761,8 +762,8 @@ class CGObjCGNUstep : public CGObjCGNU { llvm::FunctionCallee LookupFn = SlotLookupFn; // Store the receiver on the stack so that we can reload it later - Address ReceiverPtr = - CGF.CreateTempAlloca(Receiver->getType(), CGF.getPointerAlign()); + RawAddress ReceiverPtr = + CGF.CreateTempAlloca(Receiver->getType(), CGF.getPointerAlign()); Builder.CreateStore(Receiver, ReceiverPtr); llvm::Value *self; @@ -778,9 +779,9 @@ class CGObjCGNUstep : public CGObjCGNU { LookupFn2->addParamAttr(0, llvm::Attribute::NoCapture); llvm::Value *args[] = { - EnforceType(Builder, ReceiverPtr.getPointer(), PtrToIdTy), - EnforceType(Builder, cmd, SelectorTy), - EnforceType(Builder, self, IdTy) }; + EnforceType(Builder, ReceiverPtr.getPointer(), PtrToIdTy), + EnforceType(Builder, cmd, SelectorTy), + EnforceType(Builder, self, IdTy)}; llvm::CallBase *slot = CGF.EmitRuntimeCallOrInvoke(LookupFn, args); slot->setOnlyReadsMemory(); slot->setMetadata(msgSendMDKind, node); @@ -800,7 +801,7 @@ class CGObjCGNUstep : public CGObjCGNU { llvm::Value *cmd, MessageSendInfo &MSI) override { CGBuilderTy &Builder = CGF.Builder; - llvm::Value *lookupArgs[] = {ObjCSuper.getPointer(), cmd}; + llvm::Value *lookupArgs[] = {ObjCSuper.emitRawPointer(CGF), cmd}; llvm::CallInst *slot = CGF.EmitNounwindRuntimeCall(SlotLookupSuperFn, lookupArgs); @@ -1221,10 +1222,10 @@ class CGObjCGNUstep2 : public CGObjCGNUstep { llvm::Value *cmd, MessageSendInfo &MSI) override { // Don't access the slot unless we're trying to cache the result. CGBuilderTy &Builder = CGF.Builder; - llvm::Value *lookupArgs[] = {CGObjCGNU::EnforceType(Builder, - ObjCSuper.getPointer(), - PtrToObjCSuperTy), - cmd}; + llvm::Value *lookupArgs[] = { + CGObjCGNU::EnforceType(Builder, ObjCSuper.emitRawPointer(CGF), + PtrToObjCSuperTy), + cmd}; return CGF.EmitNounwindRuntimeCall(MsgLookupSuperFn, lookupArgs); } @@ -2186,7 +2187,8 @@ protected: llvm::Value *cmd, MessageSendInfo &MSI) override { CGBuilderTy &Builder = CGF.Builder; llvm::Value *lookupArgs[] = { - EnforceType(Builder, ObjCSuper.getPointer(), PtrToObjCSuperTy), cmd, + EnforceType(Builder, ObjCSuper.emitRawPointer(CGF), PtrToObjCSuperTy), + cmd, }; if (CGM.ReturnTypeUsesSRet(MSI.CallInfo)) @@ -4201,15 +4203,15 @@ void CGObjCGNU::EmitThrowStmt(CodeGenFunction &CGF, llvm::Value * CGObjCGNU::EmitObjCWeakRead(CodeGenFunction &CGF, Address AddrWeakObj) { CGBuilderTy &B = CGF.Builder; - return B.CreateCall(WeakReadFn, - EnforceType(B, AddrWeakObj.getPointer(), PtrToIdTy)); + return B.CreateCall( + WeakReadFn, EnforceType(B, AddrWeakObj.emitRawPointer(CGF), PtrToIdTy)); } void CGObjCGNU::EmitObjCWeakAssign(CodeGenFunction &CGF, llvm::Value *src, Address dst) { CGBuilderTy &B = CGF.Builder; src = EnforceType(B, src, IdTy); - llvm::Value *dstVal = EnforceType(B, dst.getPointer(), PtrToIdTy); + llvm::Value *dstVal = EnforceType(B, dst.emitRawPointer(CGF), PtrToIdTy); B.CreateCall(WeakAssignFn, {src, dstVal}); } @@ -4218,7 +4220,7 @@ void CGObjCGNU::EmitObjCGlobalAssign(CodeGenFunction &CGF, bool threadlocal) { CGBuilderTy &B = CGF.Builder; src = EnforceType(B, src, IdTy); - llvm::Value *dstVal = EnforceType(B, dst.getPointer(), PtrToIdTy); + llvm::Value *dstVal = EnforceType(B, dst.emitRawPointer(CGF), PtrToIdTy); // FIXME. Add threadloca assign API assert(!threadlocal && "EmitObjCGlobalAssign - Threal Local API NYI"); B.CreateCall(GlobalAssignFn, {src, dstVal}); @@ -4229,7 +4231,7 @@ void CGObjCGNU::EmitObjCIvarAssign(CodeGenFunction &CGF, llvm::Value *ivarOffset) { CGBuilderTy &B = CGF.Builder; src = EnforceType(B, src, IdTy); - llvm::Value *dstVal = EnforceType(B, dst.getPointer(), IdTy); + llvm::Value *dstVal = EnforceType(B, dst.emitRawPointer(CGF), IdTy); B.CreateCall(IvarAssignFn, {src, dstVal, ivarOffset}); } @@ -4237,7 +4239,7 @@ void CGObjCGNU::EmitObjCStrongCastAssign(CodeGenFunction &CGF, llvm::Value *src, Address dst) { CGBuilderTy &B = CGF.Builder; src = EnforceType(B, src, IdTy); - llvm::Value *dstVal = EnforceType(B, dst.getPointer(), PtrToIdTy); + llvm::Value *dstVal = EnforceType(B, dst.emitRawPointer(CGF), PtrToIdTy); B.CreateCall(StrongCastAssignFn, {src, dstVal}); } @@ -4246,8 +4248,8 @@ void CGObjCGNU::EmitGCMemmoveCollectable(CodeGenFunction &CGF, Address SrcPtr, llvm::Value *Size) { CGBuilderTy &B = CGF.Builder; - llvm::Value *DestPtrVal = EnforceType(B, DestPtr.getPointer(), PtrTy); - llvm::Value *SrcPtrVal = EnforceType(B, SrcPtr.getPointer(), PtrTy); + llvm::Value *DestPtrVal = EnforceType(B, DestPtr.emitRawPointer(CGF), PtrTy); + llvm::Value *SrcPtrVal = EnforceType(B, SrcPtr.emitRawPointer(CGF), PtrTy); B.CreateCall(MemMoveFn, {DestPtrVal, SrcPtrVal, Size}); } diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp index e815e097e1fb48e7e3037d8983174ed471259245..042cd5d46da4b2eb608a9b5065c7514bde04df2a 100644 --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -1310,7 +1310,7 @@ private: /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy, /// for the given selector. llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel); - Address EmitSelectorAddr(Selector Sel); + ConstantAddress EmitSelectorAddr(Selector Sel); public: CGObjCMac(CodeGen::CodeGenModule &cgm); @@ -1538,7 +1538,7 @@ private: /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy, /// for the given selector. llvm::Value *EmitSelector(CodeGenFunction &CGF, Selector Sel); - Address EmitSelectorAddr(Selector Sel); + ConstantAddress EmitSelectorAddr(Selector Sel); /// GetInterfaceEHType - Get the cached ehtype for the given Objective-C /// interface. The return value has type EHTypePtrTy. @@ -1555,12 +1555,12 @@ private: // Shamelessly stolen from Analysis/CFRefCount.cpp Selector GetNullarySelector(const char* name) const { - IdentifierInfo* II = &CGM.getContext().Idents.get(name); + const IdentifierInfo *II = &CGM.getContext().Idents.get(name); return CGM.getContext().Selectors.getSelector(0, &II); } Selector GetUnarySelector(const char* name) const { - IdentifierInfo* II = &CGM.getContext().Idents.get(name); + const IdentifierInfo *II = &CGM.getContext().Idents.get(name); return CGM.getContext().Selectors.getSelector(1, &II); } @@ -2064,9 +2064,8 @@ CGObjCMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, const ObjCMethodDecl *Method) { // Create and init a super structure; this is a (receiver, class) // pair we will pass to objc_msgSendSuper. - Address ObjCSuper = - CGF.CreateTempAlloca(ObjCTypes.SuperTy, CGF.getPointerAlign(), - "objc_super"); + RawAddress ObjCSuper = CGF.CreateTempAlloca( + ObjCTypes.SuperTy, CGF.getPointerAlign(), "objc_super"); llvm::Value *ReceiverAsObject = CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy); CGF.Builder.CreateStore(ReceiverAsObject, @@ -2501,12 +2500,12 @@ void CGObjCCommonMac::BuildRCRecordLayout(const llvm::StructLayout *RecLayout, if (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) { auto *CArray = cast(Array); - uint64_t ElCount = CArray->getSize().getZExtValue(); + uint64_t ElCount = CArray->getZExtSize(); assert(CArray && "only array with known element size is supported"); FQT = CArray->getElementType(); while (const ArrayType *Array = CGM.getContext().getAsArrayType(FQT)) { auto *CArray = cast(Array); - ElCount *= CArray->getSize().getZExtValue(); + ElCount *= CArray->getZExtSize(); FQT = CArray->getElementType(); } if (FQT->isRecordType() && ElCount) { @@ -4259,7 +4258,7 @@ namespace { CGF.EmitBlock(FinallyCallExit); CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryExitFn(), - ExceptionData.getPointer()); + ExceptionData.emitRawPointer(CGF)); CGF.EmitBlock(FinallyNoCallExit); @@ -4425,7 +4424,9 @@ void FragileHazards::emitHazardsInNewBlocks() { } static void addIfPresent(llvm::DenseSet &S, Address V) { - if (V.isValid()) S.insert(V.getPointer()); + if (V.isValid()) + if (llvm::Value *Ptr = V.getBasePointer()) + S.insert(Ptr); } void FragileHazards::collectLocals() { @@ -4628,13 +4629,13 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // - Call objc_exception_try_enter to push ExceptionData on top of // the EH stack. CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(), - ExceptionData.getPointer()); + ExceptionData.emitRawPointer(CGF)); // - Call setjmp on the exception data buffer. llvm::Constant *Zero = llvm::ConstantInt::get(CGF.Builder.getInt32Ty(), 0); llvm::Value *GEPIndexes[] = { Zero, Zero, Zero }; llvm::Value *SetJmpBuffer = CGF.Builder.CreateGEP( - ObjCTypes.ExceptionDataTy, ExceptionData.getPointer(), GEPIndexes, + ObjCTypes.ExceptionDataTy, ExceptionData.emitRawPointer(CGF), GEPIndexes, "setjmp_buffer"); llvm::CallInst *SetJmpResult = CGF.EmitNounwindRuntimeCall( ObjCTypes.getSetJmpFn(), SetJmpBuffer, "setjmp_result"); @@ -4673,9 +4674,9 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, } else { // Retrieve the exception object. We may emit multiple blocks but // nothing can cross this so the value is already in SSA form. - llvm::CallInst *Caught = - CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(), - ExceptionData.getPointer(), "caught"); + llvm::CallInst *Caught = CGF.EmitNounwindRuntimeCall( + ObjCTypes.getExceptionExtractFn(), ExceptionData.emitRawPointer(CGF), + "caught"); // Push the exception to rethrow onto the EH value stack for the // benefit of any @throws in the handlers. @@ -4698,7 +4699,7 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // Enter a new exception try block (in case a @catch block // throws an exception). CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionTryEnterFn(), - ExceptionData.getPointer()); + ExceptionData.emitRawPointer(CGF)); llvm::CallInst *SetJmpResult = CGF.EmitNounwindRuntimeCall(ObjCTypes.getSetJmpFn(), @@ -4829,9 +4830,9 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // Extract the new exception and save it to the // propagating-exception slot. assert(PropagatingExnVar.isValid()); - llvm::CallInst *NewCaught = - CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(), - ExceptionData.getPointer(), "caught"); + llvm::CallInst *NewCaught = CGF.EmitNounwindRuntimeCall( + ObjCTypes.getExceptionExtractFn(), ExceptionData.emitRawPointer(CGF), + "caught"); CGF.Builder.CreateStore(NewCaught, PropagatingExnVar); // Don't pop the catch handler; the throw already did. @@ -4861,9 +4862,8 @@ void CGObjCMac::EmitTryOrSynchronizedStmt(CodeGen::CodeGenFunction &CGF, // Otherwise, just look in the buffer for the exception to throw. } else { - llvm::CallInst *Caught = - CGF.EmitNounwindRuntimeCall(ObjCTypes.getExceptionExtractFn(), - ExceptionData.getPointer()); + llvm::CallInst *Caught = CGF.EmitNounwindRuntimeCall( + ObjCTypes.getExceptionExtractFn(), ExceptionData.emitRawPointer(CGF)); PropagatingExn = Caught; } @@ -4906,7 +4906,7 @@ llvm::Value * CGObjCMac::EmitObjCWeakRead(CodeGen::CodeGenFunction &CGF, Address AddrWeakObj) { llvm::Type* DestTy = AddrWeakObj.getElementType(); llvm::Value *AddrWeakObjVal = CGF.Builder.CreateBitCast( - AddrWeakObj.getPointer(), ObjCTypes.PtrObjectPtrTy); + AddrWeakObj.emitRawPointer(CGF), ObjCTypes.PtrObjectPtrTy); llvm::Value *read_weak = CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(), AddrWeakObjVal, "weakread"); @@ -4928,8 +4928,8 @@ void CGObjCMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = { src, dstVal }; CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(), args, "weakassign"); @@ -4950,8 +4950,8 @@ void CGObjCMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = {src, dstVal}; if (!threadlocal) CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(), @@ -4977,8 +4977,8 @@ void CGObjCMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = {src, dstVal, ivarOffset}; CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args); } @@ -4997,8 +4997,8 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = {src, dstVal}; CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(), args, "strongassign"); @@ -5007,7 +5007,8 @@ void CGObjCMac::EmitObjCStrongCastAssign(CodeGen::CodeGenFunction &CGF, void CGObjCMac::EmitGCMemmoveCollectable(CodeGen::CodeGenFunction &CGF, Address DestPtr, Address SrcPtr, llvm::Value *size) { - llvm::Value *args[] = { DestPtr.getPointer(), SrcPtr.getPointer(), size }; + llvm::Value *args[] = {DestPtr.emitRawPointer(CGF), + SrcPtr.emitRawPointer(CGF), size}; CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args); } @@ -5243,7 +5244,7 @@ llvm::Value *CGObjCMac::EmitSelector(CodeGenFunction &CGF, Selector Sel) { return CGF.Builder.CreateLoad(EmitSelectorAddr(Sel)); } -Address CGObjCMac::EmitSelectorAddr(Selector Sel) { +ConstantAddress CGObjCMac::EmitSelectorAddr(Selector Sel) { CharUnits Align = CGM.getPointerAlign(); llvm::GlobalVariable *&Entry = SelectorReferences[Sel]; @@ -5254,7 +5255,7 @@ Address CGObjCMac::EmitSelectorAddr(Selector Sel) { Entry->setExternallyInitialized(true); } - return Address(Entry, ObjCTypes.SelectorPtrTy, Align); + return ConstantAddress(Entry, ObjCTypes.SelectorPtrTy, Align); } llvm::Constant *CGObjCCommonMac::GetClassName(StringRef RuntimeName) { @@ -5326,7 +5327,7 @@ void IvarLayoutBuilder::visitField(const FieldDecl *field, } // Unlike incomplete arrays, constant arrays can be nested. while (auto arrayType = CGM.getContext().getAsConstantArrayType(fieldType)) { - numElts *= arrayType->getSize().getZExtValue(); + numElts *= arrayType->getZExtSize(); fieldType = arrayType->getElementType(); } @@ -6267,11 +6268,10 @@ bool CGObjCNonFragileABIMac::isVTableDispatchedSelector(Selector Sel) { VTableDispatchMethods.insert(GetUnarySelector("addObject")); // "countByEnumeratingWithState:objects:count" - IdentifierInfo *KeyIdents[] = { - &CGM.getContext().Idents.get("countByEnumeratingWithState"), - &CGM.getContext().Idents.get("objects"), - &CGM.getContext().Idents.get("count") - }; + const IdentifierInfo *KeyIdents[] = { + &CGM.getContext().Idents.get("countByEnumeratingWithState"), + &CGM.getContext().Idents.get("objects"), + &CGM.getContext().Idents.get("count")}; VTableDispatchMethods.insert( CGM.getContext().Selectors.getSelector(3, KeyIdents)); } @@ -7323,7 +7323,7 @@ CGObjCNonFragileABIMac::EmitVTableMessageSend(CodeGenFunction &CGF, ObjCTypes.MessageRefTy, CGF.getPointerAlign()); // Update the message ref argument. - args[1].setRValue(RValue::get(mref.getPointer())); + args[1].setRValue(RValue::get(mref, CGF)); // Load the function to call from the message ref table. Address calleeAddr = CGF.Builder.CreateStructGEP(mref, 0); @@ -7552,9 +7552,8 @@ CGObjCNonFragileABIMac::GenerateMessageSendSuper(CodeGen::CodeGenFunction &CGF, // ... // Create and init a super structure; this is a (receiver, class) // pair we will pass to objc_msgSendSuper. - Address ObjCSuper = - CGF.CreateTempAlloca(ObjCTypes.SuperTy, CGF.getPointerAlign(), - "objc_super"); + RawAddress ObjCSuper = CGF.CreateTempAlloca( + ObjCTypes.SuperTy, CGF.getPointerAlign(), "objc_super"); llvm::Value *ReceiverAsObject = CGF.Builder.CreateBitCast(Receiver, ObjCTypes.ObjectPtrTy); @@ -7594,7 +7593,7 @@ llvm::Value *CGObjCNonFragileABIMac::EmitSelector(CodeGenFunction &CGF, return LI; } -Address CGObjCNonFragileABIMac::EmitSelectorAddr(Selector Sel) { +ConstantAddress CGObjCNonFragileABIMac::EmitSelectorAddr(Selector Sel) { llvm::GlobalVariable *&Entry = SelectorReferences[Sel]; CharUnits Align = CGM.getPointerAlign(); if (!Entry) { @@ -7610,7 +7609,7 @@ Address CGObjCNonFragileABIMac::EmitSelectorAddr(Selector Sel) { CGM.addCompilerUsedGlobal(Entry); } - return Address(Entry, ObjCTypes.SelectorPtrTy, Align); + return ConstantAddress(Entry, ObjCTypes.SelectorPtrTy, Align); } /// EmitObjCIvarAssign - Code gen for assigning to a __strong object. @@ -7629,8 +7628,8 @@ void CGObjCNonFragileABIMac::EmitObjCIvarAssign(CodeGen::CodeGenFunction &CGF, src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = {src, dstVal, ivarOffset}; CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignIvarFn(), args); } @@ -7650,8 +7649,8 @@ void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign( src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = {src, dstVal}; CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignStrongCastFn(), args, "weakassign"); @@ -7660,7 +7659,8 @@ void CGObjCNonFragileABIMac::EmitObjCStrongCastAssign( void CGObjCNonFragileABIMac::EmitGCMemmoveCollectable( CodeGen::CodeGenFunction &CGF, Address DestPtr, Address SrcPtr, llvm::Value *Size) { - llvm::Value *args[] = { DestPtr.getPointer(), SrcPtr.getPointer(), Size }; + llvm::Value *args[] = {DestPtr.emitRawPointer(CGF), + SrcPtr.emitRawPointer(CGF), Size}; CGF.EmitNounwindRuntimeCall(ObjCTypes.GcMemmoveCollectableFn(), args); } @@ -7672,7 +7672,7 @@ llvm::Value * CGObjCNonFragileABIMac::EmitObjCWeakRead( Address AddrWeakObj) { llvm::Type *DestTy = AddrWeakObj.getElementType(); llvm::Value *AddrWeakObjVal = CGF.Builder.CreateBitCast( - AddrWeakObj.getPointer(), ObjCTypes.PtrObjectPtrTy); + AddrWeakObj.emitRawPointer(CGF), ObjCTypes.PtrObjectPtrTy); llvm::Value *read_weak = CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcReadWeakFn(), AddrWeakObjVal, "weakread"); @@ -7694,8 +7694,8 @@ void CGObjCNonFragileABIMac::EmitObjCWeakAssign(CodeGen::CodeGenFunction &CGF, src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = {src, dstVal}; CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignWeakFn(), args, "weakassign"); @@ -7716,8 +7716,8 @@ void CGObjCNonFragileABIMac::EmitObjCGlobalAssign(CodeGen::CodeGenFunction &CGF, src = CGF.Builder.CreateIntToPtr(src, ObjCTypes.Int8PtrTy); } src = CGF.Builder.CreateBitCast(src, ObjCTypes.ObjectPtrTy); - llvm::Value *dstVal = - CGF.Builder.CreateBitCast(dst.getPointer(), ObjCTypes.PtrObjectPtrTy); + llvm::Value *dstVal = CGF.Builder.CreateBitCast(dst.emitRawPointer(CGF), + ObjCTypes.PtrObjectPtrTy); llvm::Value *args[] = {src, dstVal}; if (!threadlocal) CGF.EmitNounwindRuntimeCall(ObjCTypes.getGcAssignGlobalFn(), diff --git a/clang/lib/CodeGen/CGObjCRuntime.cpp b/clang/lib/CodeGen/CGObjCRuntime.cpp index 424564f9759995267ff2061cfbc6371ecbc7c2df..01d0f35da19643cf1d0b5b21439f6fbbe4ade22e 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.cpp +++ b/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -67,7 +67,7 @@ LValue CGObjCRuntime::EmitValueForIvarAtOffset(CodeGen::CodeGenFunction &CGF, V = CGF.Builder.CreateInBoundsGEP(CGF.Int8Ty, V, Offset, "add.ptr"); if (!Ivar->isBitField()) { - LValue LV = CGF.MakeNaturalAlignAddrLValue(V, IvarTy); + LValue LV = CGF.MakeNaturalAlignRawAddrLValue(V, IvarTy); return LV; } @@ -233,7 +233,7 @@ void CGObjCRuntime::EmitTryCatchStmt(CodeGenFunction &CGF, llvm::Instruction *CPICandidate = Handler.Block->getFirstNonPHI(); if (auto *CPI = dyn_cast_or_null(CPICandidate)) { CGF.CurrentFuncletPad = CPI; - CPI->setOperand(2, CGF.getExceptionSlot().getPointer()); + CPI->setOperand(2, CGF.getExceptionSlot().emitRawPointer(CGF)); CGF.EHStack.pushCleanup(NormalCleanup, CPI); } } @@ -405,7 +405,7 @@ bool CGObjCRuntime::canMessageReceiverBeNull(CodeGenFunction &CGF, auto self = curMethod->getSelfDecl(); if (self->getType().isConstQualified()) { if (auto LI = dyn_cast(receiver->stripPointerCasts())) { - llvm::Value *selfAddr = CGF.GetAddrOfLocalVar(self).getPointer(); + llvm::Value *selfAddr = CGF.GetAddrOfLocalVar(self).emitRawPointer(CGF); if (selfAddr == LI->getPointerOperand()) { return false; } diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index e8a68dbcc68709c7afd7249032674409dd711e9f..2ae11e129c75e42b88df5ceae7d3d1c71c3a6339 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -622,7 +622,7 @@ static void emitInitWithReductionInitializer(CodeGenFunction &CGF, auto *GV = new llvm::GlobalVariable( CGF.CGM.getModule(), Init->getType(), /*isConstant=*/true, llvm::GlobalValue::PrivateLinkage, Init, Name); - LValue LV = CGF.MakeNaturalAlignAddrLValue(GV, Ty); + LValue LV = CGF.MakeNaturalAlignRawAddrLValue(GV, Ty); RValue InitRVal; switch (CGF.getEvaluationKind(Ty)) { case TEK_Scalar: @@ -668,8 +668,8 @@ static void EmitOMPAggregateInit(CodeGenFunction &CGF, Address DestAddr, llvm::Value *SrcBegin = nullptr; if (DRD) - SrcBegin = SrcAddr.getPointer(); - llvm::Value *DestBegin = DestAddr.getPointer(); + SrcBegin = SrcAddr.emitRawPointer(CGF); + llvm::Value *DestBegin = DestAddr.emitRawPointer(CGF); // Cast from pointer to array type to pointer to single element. llvm::Value *DestEnd = CGF.Builder.CreateGEP(DestAddr.getElementType(), DestBegin, NumElements); @@ -912,7 +912,7 @@ static LValue loadToBegin(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy, static Address castToBase(CodeGenFunction &CGF, QualType BaseTy, QualType ElTy, Address OriginalBaseAddress, llvm::Value *Addr) { - Address Tmp = Address::invalid(); + RawAddress Tmp = RawAddress::invalid(); Address TopTmp = Address::invalid(); Address MostTopTmp = Address::invalid(); BaseTy = BaseTy.getNonReferenceType(); @@ -971,10 +971,10 @@ Address ReductionCodeGen::adjustPrivateAddress(CodeGenFunction &CGF, unsigned N, Address SharedAddr = SharedAddresses[N].first.getAddress(CGF); llvm::Value *Adjustment = CGF.Builder.CreatePtrDiff( SharedAddr.getElementType(), BaseLValue.getPointer(CGF), - SharedAddr.getPointer()); + SharedAddr.emitRawPointer(CGF)); llvm::Value *PrivatePointer = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - PrivateAddr.getPointer(), SharedAddr.getType()); + PrivateAddr.emitRawPointer(CGF), SharedAddr.getType()); llvm::Value *Ptr = CGF.Builder.CreateGEP( SharedAddr.getElementType(), PrivatePointer, Adjustment); return castToBase(CGF, OrigVD->getType(), @@ -1557,7 +1557,7 @@ static llvm::TargetRegionEntryInfo getEntryInfoFromPresumedLoc( return OMPBuilder.getTargetEntryUniqueInfo(FileInfoCallBack, ParentName); } -Address CGOpenMPRuntime::getAddrOfDeclareTargetVar(const VarDecl *VD) { +ConstantAddress CGOpenMPRuntime::getAddrOfDeclareTargetVar(const VarDecl *VD) { auto AddrOfGlobal = [&VD, this]() { return CGM.GetAddrOfGlobal(VD); }; auto LinkageForVariable = [&VD, this]() { @@ -1579,8 +1579,8 @@ Address CGOpenMPRuntime::getAddrOfDeclareTargetVar(const VarDecl *VD) { LinkageForVariable); if (!addr) - return Address::invalid(); - return Address(addr, LlvmPtrTy, CGM.getContext().getDeclAlign(VD)); + return ConstantAddress::invalid(); + return ConstantAddress(addr, LlvmPtrTy, CGM.getContext().getDeclAlign(VD)); } llvm::Constant * @@ -1604,7 +1604,7 @@ Address CGOpenMPRuntime::getAddrOfThreadPrivate(CodeGenFunction &CGF, llvm::Type *VarTy = VDAddr.getElementType(); llvm::Value *Args[] = { emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc), - CGF.Builder.CreatePointerCast(VDAddr.getPointer(), CGM.Int8PtrTy), + CGF.Builder.CreatePointerCast(VDAddr.emitRawPointer(CGF), CGM.Int8PtrTy), CGM.getSize(CGM.GetTargetTypeStoreSize(VarTy)), getOrCreateThreadPrivateCache(VD)}; return Address( @@ -1627,7 +1627,8 @@ void CGOpenMPRuntime::emitThreadPrivateVarInit( // Call __kmpc_threadprivate_register(&loc, &var, ctor, cctor/*NULL*/, dtor) // to register constructor/destructor for variable. llvm::Value *Args[] = { - OMPLoc, CGF.Builder.CreatePointerCast(VDAddr.getPointer(), CGM.VoidPtrTy), + OMPLoc, + CGF.Builder.CreatePointerCast(VDAddr.emitRawPointer(CGF), CGM.VoidPtrTy), Ctor, CopyCtor, Dtor}; CGF.EmitRuntimeCall( OMPBuilder.getOrCreateRuntimeFunction( @@ -1900,13 +1901,13 @@ void CGOpenMPRuntime::emitParallelCall(CodeGenFunction &CGF, SourceLocation Loc, // OutlinedFn(>id, &zero_bound, CapturedStruct); Address ThreadIDAddr = RT.emitThreadIDAddress(CGF, Loc); - Address ZeroAddrBound = + RawAddress ZeroAddrBound = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty, /*Name=*/".bound.zero.addr"); CGF.Builder.CreateStore(CGF.Builder.getInt32(/*C*/ 0), ZeroAddrBound); llvm::SmallVector OutlinedFnArgs; // ThreadId for serialized parallels is 0. - OutlinedFnArgs.push_back(ThreadIDAddr.getPointer()); + OutlinedFnArgs.push_back(ThreadIDAddr.emitRawPointer(CGF)); OutlinedFnArgs.push_back(ZeroAddrBound.getPointer()); OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end()); @@ -2272,7 +2273,7 @@ void CGOpenMPRuntime::emitSingleRegion(CodeGenFunction &CGF, emitUpdateLocation(CGF, Loc), // ident_t * getThreadID(CGF, Loc), // i32 BufSize, // size_t - CL.getPointer(), // void * + CL.emitRawPointer(CGF), // void * CpyFn, // void (*) (void *, void *) DidItVal // i32 did_it }; @@ -2591,10 +2592,10 @@ static void emitForStaticInitCall( ThreadId, CGF.Builder.getInt32(addMonoNonMonoModifier(CGF.CGM, Schedule, M1, M2)), // Schedule type - Values.IL.getPointer(), // &isLastIter - Values.LB.getPointer(), // &LB - Values.UB.getPointer(), // &UB - Values.ST.getPointer(), // &Stride + Values.IL.emitRawPointer(CGF), // &isLastIter + Values.LB.emitRawPointer(CGF), // &LB + Values.UB.emitRawPointer(CGF), // &UB + Values.ST.emitRawPointer(CGF), // &Stride CGF.Builder.getIntN(Values.IVSize, 1), // Incr Chunk // Chunk }; @@ -2647,19 +2648,20 @@ void CGOpenMPRuntime::emitDistributeStaticInit( void CGOpenMPRuntime::emitForStaticFinish(CodeGenFunction &CGF, SourceLocation Loc, OpenMPDirectiveKind DKind) { - assert(DKind == OMPD_distribute || DKind == OMPD_for || - DKind == OMPD_sections && - "Expected distribute, for, or sections directive kind"); + assert((DKind == OMPD_distribute || DKind == OMPD_for || + DKind == OMPD_sections) && + "Expected distribute, for, or sections directive kind"); if (!CGF.HaveInsertPoint()) return; // Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid); llvm::Value *Args[] = { emitUpdateLocation(CGF, Loc, - isOpenMPDistributeDirective(DKind) + isOpenMPDistributeDirective(DKind) || + (DKind == OMPD_target_teams_loop) ? OMP_IDENT_WORK_DISTRIBUTE - : isOpenMPLoopDirective(DKind) - ? OMP_IDENT_WORK_LOOP - : OMP_IDENT_WORK_SECTIONS), + : isOpenMPLoopDirective(DKind) + ? OMP_IDENT_WORK_LOOP + : OMP_IDENT_WORK_SECTIONS), getThreadID(CGF, Loc)}; auto DL = ApplyDebugLocation::CreateDefaultArtificial(CGF, Loc); if (isOpenMPDistributeDirective(DKind) && @@ -2697,12 +2699,11 @@ llvm::Value *CGOpenMPRuntime::emitForNext(CodeGenFunction &CGF, // kmp_int[32|64] *p_lower, kmp_int[32|64] *p_upper, // kmp_int[32|64] *p_stride); llvm::Value *Args[] = { - emitUpdateLocation(CGF, Loc), - getThreadID(CGF, Loc), - IL.getPointer(), // &isLastIter - LB.getPointer(), // &Lower - UB.getPointer(), // &Upper - ST.getPointer() // &Stride + emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc), + IL.emitRawPointer(CGF), // &isLastIter + LB.emitRawPointer(CGF), // &Lower + UB.emitRawPointer(CGF), // &Upper + ST.emitRawPointer(CGF) // &Stride }; llvm::Value *Call = CGF.EmitRuntimeCall( OMPBuilder.createDispatchNextFunction(IVSize, IVSigned), Args); @@ -3047,7 +3048,7 @@ emitProxyTaskFunction(CodeGenModule &CGM, SourceLocation Loc, CGF.Builder .CreatePointerBitCastOrAddrSpaceCast(TDBase.getAddress(CGF), CGF.VoidPtrTy, CGF.Int8Ty) - .getPointer()}; + .emitRawPointer(CGF)}; SmallVector CallArgs(std::begin(CommonArgs), std::end(CommonArgs)); if (isOpenMPTaskLoopDirective(Kind)) { @@ -3574,7 +3575,8 @@ getPointerAndSize(CodeGenFunction &CGF, const Expr *E) { CGF.EmitOMPArraySectionExpr(ASE, /*IsLowerBound=*/false); Address UpAddrAddress = UpAddrLVal.getAddress(CGF); llvm::Value *UpAddr = CGF.Builder.CreateConstGEP1_32( - UpAddrAddress.getElementType(), UpAddrAddress.getPointer(), /*Idx0=*/1); + UpAddrAddress.getElementType(), UpAddrAddress.emitRawPointer(CGF), + /*Idx0=*/1); llvm::Value *LowIntPtr = CGF.Builder.CreatePtrToInt(Addr, CGF.SizeTy); llvm::Value *UpIntPtr = CGF.Builder.CreatePtrToInt(UpAddr, CGF.SizeTy); SizeVal = CGF.Builder.CreateNUWSub(UpIntPtr, LowIntPtr); @@ -3888,8 +3890,9 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *Size; std::tie(Addr, Size) = getPointerAndSize(CGF, E); llvm::Value *Idx = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc()); - LValue Base = CGF.MakeAddrLValue( - CGF.Builder.CreateGEP(AffinitiesArray, Idx), KmpTaskAffinityInfoTy); + LValue Base = + CGF.MakeAddrLValue(CGF.Builder.CreateGEP(CGF, AffinitiesArray, Idx), + KmpTaskAffinityInfoTy); // affs[i].base_addr = &; LValue BaseAddrLVal = CGF.EmitLValueForField( Base, *std::next(KmpAffinityInfoRD->field_begin(), BaseAddr)); @@ -3910,7 +3913,7 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *LocRef = emitUpdateLocation(CGF, Loc); llvm::Value *GTid = getThreadID(CGF, Loc); llvm::Value *AffinListPtr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - AffinitiesArray.getPointer(), CGM.VoidPtrTy); + AffinitiesArray.emitRawPointer(CGF), CGM.VoidPtrTy); // FIXME: Emit the function and ignore its result for now unless the // runtime function is properly implemented. (void)CGF.EmitRuntimeCall( @@ -3921,8 +3924,8 @@ CGOpenMPRuntime::emitTaskInit(CodeGenFunction &CGF, SourceLocation Loc, llvm::Value *NewTaskNewTaskTTy = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( NewTask, KmpTaskTWithPrivatesPtrTy); - LValue Base = CGF.MakeNaturalAlignAddrLValue(NewTaskNewTaskTTy, - KmpTaskTWithPrivatesQTy); + LValue Base = CGF.MakeNaturalAlignRawAddrLValue(NewTaskNewTaskTTy, + KmpTaskTWithPrivatesQTy); LValue TDBase = CGF.EmitLValueForField(Base, *KmpTaskTWithPrivatesQTyRD->field_begin()); // Fill the data in the resulting kmp_task_t record. @@ -4047,7 +4050,7 @@ CGOpenMPRuntime::getDepobjElements(CodeGenFunction &CGF, LValue DepobjLVal, CGF.ConvertTypeForMem(KmpDependInfoPtrTy)), KmpDependInfoPtrTy->castAs()); Address DepObjAddr = CGF.Builder.CreateGEP( - Base.getAddress(CGF), + CGF, Base.getAddress(CGF), llvm::ConstantInt::get(CGF.IntPtrTy, -1, /*isSigned=*/true)); LValue NumDepsBase = CGF.MakeAddrLValue( DepObjAddr, KmpDependInfoTy, Base.getBaseInfo(), Base.getTBAAInfo()); @@ -4097,7 +4100,7 @@ static void emitDependData(CodeGenFunction &CGF, QualType &KmpDependInfoTy, LValue &PosLVal = *Pos.get(); llvm::Value *Idx = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc()); Base = CGF.MakeAddrLValue( - CGF.Builder.CreateGEP(DependenciesArray, Idx), KmpDependInfoTy); + CGF.Builder.CreateGEP(CGF, DependenciesArray, Idx), KmpDependInfoTy); } // deps[i].base_addr = &; LValue BaseAddrLVal = CGF.EmitLValueForField( @@ -4195,7 +4198,7 @@ void CGOpenMPRuntime::emitDepobjElements(CodeGenFunction &CGF, ElSize, CGF.Builder.CreateIntCast(NumDeps, CGF.SizeTy, /*isSigned=*/false)); llvm::Value *Pos = CGF.EmitLoadOfScalar(PosLVal, E->getExprLoc()); - Address DepAddr = CGF.Builder.CreateGEP(DependenciesArray, Pos); + Address DepAddr = CGF.Builder.CreateGEP(CGF, DependenciesArray, Pos); CGF.Builder.CreateMemCpy(DepAddr, Base.getAddress(CGF), Size); // Increase pos. @@ -4430,7 +4433,7 @@ void CGOpenMPRuntime::emitDestroyClause(CodeGenFunction &CGF, LValue DepobjLVal, Base.getAddress(CGF), CGF.ConvertTypeForMem(KmpDependInfoPtrTy), CGF.ConvertTypeForMem(KmpDependInfoTy)); llvm::Value *DepObjAddr = CGF.Builder.CreateGEP( - Addr.getElementType(), Addr.getPointer(), + Addr.getElementType(), Addr.emitRawPointer(CGF), llvm::ConstantInt::get(CGF.IntPtrTy, -1, /*isSigned=*/true)); DepObjAddr = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast(DepObjAddr, CGF.VoidPtrTy); @@ -4460,8 +4463,8 @@ void CGOpenMPRuntime::emitUpdateClause(CodeGenFunction &CGF, LValue DepobjLVal, Address Begin = Base.getAddress(CGF); // Cast from pointer to array type to pointer to single element. - llvm::Value *End = CGF.Builder.CreateGEP( - Begin.getElementType(), Begin.getPointer(), NumDeps); + llvm::Value *End = CGF.Builder.CreateGEP(Begin.getElementType(), + Begin.emitRawPointer(CGF), NumDeps); // The basic structure here is a while-do loop. llvm::BasicBlock *BodyBB = CGF.createBasicBlock("omp.body"); llvm::BasicBlock *DoneBB = CGF.createBasicBlock("omp.done"); @@ -4469,7 +4472,7 @@ void CGOpenMPRuntime::emitUpdateClause(CodeGenFunction &CGF, LValue DepobjLVal, CGF.EmitBlock(BodyBB); llvm::PHINode *ElementPHI = CGF.Builder.CreatePHI(Begin.getType(), 2, "omp.elementPast"); - ElementPHI->addIncoming(Begin.getPointer(), EntryBB); + ElementPHI->addIncoming(Begin.emitRawPointer(CGF), EntryBB); Begin = Begin.withPointer(ElementPHI, KnownNonNull); Base = CGF.MakeAddrLValue(Begin, KmpDependInfoTy, Base.getBaseInfo(), Base.getTBAAInfo()); @@ -4483,12 +4486,12 @@ void CGOpenMPRuntime::emitUpdateClause(CodeGenFunction &CGF, LValue DepobjLVal, FlagsLVal); // Shift the address forward by one element. - Address ElementNext = - CGF.Builder.CreateConstGEP(Begin, /*Index=*/1, "omp.elementNext"); - ElementPHI->addIncoming(ElementNext.getPointer(), - CGF.Builder.GetInsertBlock()); + llvm::Value *ElementNext = + CGF.Builder.CreateConstGEP(Begin, /*Index=*/1, "omp.elementNext") + .emitRawPointer(CGF); + ElementPHI->addIncoming(ElementNext, CGF.Builder.GetInsertBlock()); llvm::Value *IsEmpty = - CGF.Builder.CreateICmpEQ(ElementNext.getPointer(), End, "omp.isempty"); + CGF.Builder.CreateICmpEQ(ElementNext, End, "omp.isempty"); CGF.Builder.CreateCondBr(IsEmpty, DoneBB, BodyBB); // Done. CGF.EmitBlock(DoneBB, /*IsFinished=*/true); @@ -4531,7 +4534,7 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc, DepTaskArgs[1] = ThreadID; DepTaskArgs[2] = NewTask; DepTaskArgs[3] = NumOfElements; - DepTaskArgs[4] = DependenciesArray.getPointer(); + DepTaskArgs[4] = DependenciesArray.emitRawPointer(CGF); DepTaskArgs[5] = CGF.Builder.getInt32(0); DepTaskArgs[6] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy); } @@ -4563,7 +4566,7 @@ void CGOpenMPRuntime::emitTaskCall(CodeGenFunction &CGF, SourceLocation Loc, DepWaitTaskArgs[0] = UpLoc; DepWaitTaskArgs[1] = ThreadID; DepWaitTaskArgs[2] = NumOfElements; - DepWaitTaskArgs[3] = DependenciesArray.getPointer(); + DepWaitTaskArgs[3] = DependenciesArray.emitRawPointer(CGF); DepWaitTaskArgs[4] = CGF.Builder.getInt32(0); DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy); DepWaitTaskArgs[6] = @@ -4725,8 +4728,8 @@ static void EmitOMPAggregateReduction( const ArrayType *ArrayTy = Type->getAsArrayTypeUnsafe(); llvm::Value *NumElements = CGF.emitArrayLength(ArrayTy, ElementTy, LHSAddr); - llvm::Value *RHSBegin = RHSAddr.getPointer(); - llvm::Value *LHSBegin = LHSAddr.getPointer(); + llvm::Value *RHSBegin = RHSAddr.emitRawPointer(CGF); + llvm::Value *LHSBegin = LHSAddr.emitRawPointer(CGF); // Cast from pointer to array type to pointer to single element. llvm::Value *LHSEnd = CGF.Builder.CreateGEP(LHSAddr.getElementType(), LHSBegin, NumElements); @@ -4990,7 +4993,7 @@ void CGOpenMPRuntime::emitReduction(CodeGenFunction &CGF, SourceLocation Loc, QualType ReductionArrayTy = C.getConstantArrayType( C.VoidPtrTy, ArraySize, nullptr, ArraySizeModifier::Normal, /*IndexTypeQuals=*/0); - Address ReductionList = + RawAddress ReductionList = CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list"); const auto *IPriv = Privates.begin(); unsigned Idx = 0; @@ -5462,7 +5465,7 @@ llvm::Value *CGOpenMPRuntime::emitTaskReductionInit( C.getConstantArrayType(RDType, ArraySize, nullptr, ArraySizeModifier::Normal, /*IndexTypeQuals=*/0); // kmp_task_red_input_t .rd_input.[Size]; - Address TaskRedInput = CGF.CreateMemTemp(ArrayRDType, ".rd_input."); + RawAddress TaskRedInput = CGF.CreateMemTemp(ArrayRDType, ".rd_input."); ReductionCodeGen RCG(Data.ReductionVars, Data.ReductionOrigs, Data.ReductionCopies, Data.ReductionOps); for (unsigned Cnt = 0; Cnt < Size; ++Cnt) { @@ -5473,7 +5476,7 @@ llvm::Value *CGOpenMPRuntime::emitTaskReductionInit( TaskRedInput.getElementType(), TaskRedInput.getPointer(), Idxs, /*SignedIndices=*/false, /*IsSubtraction=*/false, Loc, ".rd_input.gep."); - LValue ElemLVal = CGF.MakeNaturalAlignAddrLValue(GEP, RDType); + LValue ElemLVal = CGF.MakeNaturalAlignRawAddrLValue(GEP, RDType); // ElemLVal.reduce_shar = &Shareds[Cnt]; LValue SharedLVal = CGF.EmitLValueForField(ElemLVal, SharedFD); RCG.emitSharedOrigLValue(CGF, Cnt); @@ -5629,7 +5632,7 @@ void CGOpenMPRuntime::emitTaskwaitCall(CodeGenFunction &CGF, SourceLocation Loc, DepWaitTaskArgs[0] = UpLoc; DepWaitTaskArgs[1] = ThreadID; DepWaitTaskArgs[2] = NumOfElements; - DepWaitTaskArgs[3] = DependenciesArray.getPointer(); + DepWaitTaskArgs[3] = DependenciesArray.emitRawPointer(CGF); DepWaitTaskArgs[4] = CGF.Builder.getInt32(0); DepWaitTaskArgs[5] = llvm::ConstantPointerNull::get(CGF.VoidPtrTy); DepWaitTaskArgs[6] = @@ -5852,7 +5855,7 @@ void CGOpenMPRuntime::emitUsesAllocatorsInit(CodeGenFunction &CGF, AllocatorTraitsLVal = CGF.MakeAddrLValue(Addr, CGF.getContext().VoidPtrTy, AllocatorTraitsLVal.getBaseInfo(), AllocatorTraitsLVal.getTBAAInfo()); - llvm::Value *Traits = Addr.getPointer(); + llvm::Value *Traits = Addr.emitRawPointer(CGF); llvm::Value *AllocatorVal = CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( @@ -6796,7 +6799,7 @@ private: OASE->getBase()->IgnoreParenImpCasts()) .getCanonicalType(); if (const auto *ATy = dyn_cast(BaseQTy.getTypePtr())) - return ATy->getSize().getSExtValue() != 1; + return ATy->getSExtSize() != 1; // If we don't have a constant dimension length, we have to consider // the current section as having any size, so it is not necessarily // unitary. If it happen to be unity size, that's user fault. @@ -7312,17 +7315,19 @@ private: CGF.EmitOMPSharedLValue(MC.getAssociatedExpression()) .getAddress(CGF); } - Size = CGF.Builder.CreatePtrDiff( - CGF.Int8Ty, ComponentLB.getPointer(), LB.getPointer()); + llvm::Value *ComponentLBPtr = ComponentLB.emitRawPointer(CGF); + llvm::Value *LBPtr = LB.emitRawPointer(CGF); + Size = CGF.Builder.CreatePtrDiff(CGF.Int8Ty, ComponentLBPtr, + LBPtr); break; } } assert(Size && "Failed to determine structure size"); CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr); - CombinedInfo.BasePointers.push_back(BP.getPointer()); + CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF)); CombinedInfo.DevicePtrDecls.push_back(nullptr); CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); - CombinedInfo.Pointers.push_back(LB.getPointer()); + CombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF)); CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast( Size, CGF.Int64Ty, /*isSigned=*/true)); CombinedInfo.Types.push_back(Flags); @@ -7332,13 +7337,14 @@ private: LB = CGF.Builder.CreateConstGEP(ComponentLB, 1); } CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr); - CombinedInfo.BasePointers.push_back(BP.getPointer()); + CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF)); CombinedInfo.DevicePtrDecls.push_back(nullptr); CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); - CombinedInfo.Pointers.push_back(LB.getPointer()); + CombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF)); + llvm::Value *LBPtr = LB.emitRawPointer(CGF); Size = CGF.Builder.CreatePtrDiff( - CGF.Int8Ty, CGF.Builder.CreateConstGEP(HB, 1).getPointer(), - LB.getPointer()); + CGF.Int8Ty, CGF.Builder.CreateConstGEP(HB, 1).emitRawPointer(CGF), + LBPtr); CombinedInfo.Sizes.push_back( CGF.Builder.CreateIntCast(Size, CGF.Int64Ty, /*isSigned=*/true)); CombinedInfo.Types.push_back(Flags); @@ -7356,20 +7362,21 @@ private: (Next == CE && MapType != OMPC_MAP_unknown)) { if (!IsMappingWholeStruct) { CombinedInfo.Exprs.emplace_back(MapDecl, MapExpr); - CombinedInfo.BasePointers.push_back(BP.getPointer()); + CombinedInfo.BasePointers.push_back(BP.emitRawPointer(CGF)); CombinedInfo.DevicePtrDecls.push_back(nullptr); CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); - CombinedInfo.Pointers.push_back(LB.getPointer()); + CombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF)); CombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast( Size, CGF.Int64Ty, /*isSigned=*/true)); CombinedInfo.NonContigInfo.Dims.push_back(IsNonContiguous ? DimSize : 1); } else { StructBaseCombinedInfo.Exprs.emplace_back(MapDecl, MapExpr); - StructBaseCombinedInfo.BasePointers.push_back(BP.getPointer()); + StructBaseCombinedInfo.BasePointers.push_back( + BP.emitRawPointer(CGF)); StructBaseCombinedInfo.DevicePtrDecls.push_back(nullptr); StructBaseCombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); - StructBaseCombinedInfo.Pointers.push_back(LB.getPointer()); + StructBaseCombinedInfo.Pointers.push_back(LB.emitRawPointer(CGF)); StructBaseCombinedInfo.Sizes.push_back(CGF.Builder.CreateIntCast( Size, CGF.Int64Ty, /*isSigned=*/true)); StructBaseCombinedInfo.NonContigInfo.Dims.push_back( @@ -7546,8 +7553,8 @@ private: // it. if (DimSizes.size() < Components.size() - 1) { if (CAT) - DimSizes.push_back(llvm::ConstantInt::get( - CGF.Int64Ty, CAT->getSize().getZExtValue())); + DimSizes.push_back( + llvm::ConstantInt::get(CGF.Int64Ty, CAT->getZExtSize())); else if (VAT) DimSizes.push_back(CGF.Builder.CreateIntCast( CGF.EmitScalarExpr(VAT->getSizeExpr()), CGF.Int64Ty, @@ -8211,11 +8218,11 @@ public: } CombinedInfo.Exprs.push_back(VD); // Base is the base of the struct - CombinedInfo.BasePointers.push_back(PartialStruct.Base.getPointer()); + CombinedInfo.BasePointers.push_back(PartialStruct.Base.emitRawPointer(CGF)); CombinedInfo.DevicePtrDecls.push_back(nullptr); CombinedInfo.DevicePointers.push_back(DeviceInfoTy::None); // Pointer is the address of the lowest element - llvm::Value *LB = LBAddr.getPointer(); + llvm::Value *LB = LBAddr.emitRawPointer(CGF); const CXXMethodDecl *MD = CGF.CurFuncDecl ? dyn_cast(CGF.CurFuncDecl) : nullptr; const CXXRecordDecl *RD = MD ? MD->getParent() : nullptr; @@ -8229,7 +8236,7 @@ public: // if the this[:1] expression had appeared in a map clause with a map-type // of tofrom. // Emit this[:1] - CombinedInfo.Pointers.push_back(PartialStruct.Base.getPointer()); + CombinedInfo.Pointers.push_back(PartialStruct.Base.emitRawPointer(CGF)); QualType Ty = MD->getFunctionObjectParameterType(); llvm::Value *Size = CGF.Builder.CreateIntCast(CGF.getTypeSize(Ty), CGF.Int64Ty, @@ -8238,7 +8245,7 @@ public: } else { CombinedInfo.Pointers.push_back(LB); // Size is (addr of {highest+1} element) - (addr of lowest element) - llvm::Value *HB = HBAddr.getPointer(); + llvm::Value *HB = HBAddr.emitRawPointer(CGF); llvm::Value *HAddr = CGF.Builder.CreateConstGEP1_32( HBAddr.getElementType(), HB, /*Idx0=*/1); llvm::Value *CLAddr = CGF.Builder.CreatePointerCast(LB, CGF.VoidPtrTy); @@ -8747,7 +8754,7 @@ public: Address PtrAddr = CGF.EmitLoadOfReference(CGF.MakeAddrLValue( CV, ElementType, CGF.getContext().getDeclAlign(VD), AlignmentSource::Decl)); - CombinedInfo.Pointers.push_back(PtrAddr.getPointer()); + CombinedInfo.Pointers.push_back(PtrAddr.emitRawPointer(CGF)); } else { CombinedInfo.Pointers.push_back(CV); } @@ -8879,7 +8886,8 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) { OpenMPDirectiveKind DKind = NestedDir->getDirectiveKind(); switch (D.getDirectiveKind()) { case OMPD_target: - // For now, just treat 'target teams loop' as if it's distributed. + // For now, treat 'target' with nested 'teams loop' as if it's + // distributed (target teams distribute). if (isOpenMPDistributeDirective(DKind) || DKind == OMPD_teams_loop) return NestedDir; if (DKind == OMPD_teams) { @@ -9363,7 +9371,8 @@ llvm::Value *CGOpenMPRuntime::emitTargetNumIterationsCall( SizeEmitter) { OpenMPDirectiveKind Kind = D.getDirectiveKind(); const OMPExecutableDirective *TD = &D; - // Get nested teams distribute kind directive, if any. + // Get nested teams distribute kind directive, if any. For now, treat + // 'target_teams_loop' as if it's really a target_teams_distribute. if ((!isOpenMPDistributeDirective(Kind) || !isOpenMPTeamsDirective(Kind)) && Kind != OMPD_target_teams_loop) TD = getNestedDistributeDirective(CGM.getContext(), D); @@ -9558,10 +9567,11 @@ static void emitTargetCallKernelLaunch( bool HasNoWait = D.hasClausesOfKind(); unsigned NumTargetItems = InputInfo.NumberOfTargetItems; - llvm::Value *BasePointersArray = InputInfo.BasePointersArray.getPointer(); - llvm::Value *PointersArray = InputInfo.PointersArray.getPointer(); - llvm::Value *SizesArray = InputInfo.SizesArray.getPointer(); - llvm::Value *MappersArray = InputInfo.MappersArray.getPointer(); + llvm::Value *BasePointersArray = + InputInfo.BasePointersArray.emitRawPointer(CGF); + llvm::Value *PointersArray = InputInfo.PointersArray.emitRawPointer(CGF); + llvm::Value *SizesArray = InputInfo.SizesArray.emitRawPointer(CGF); + llvm::Value *MappersArray = InputInfo.MappersArray.emitRawPointer(CGF); auto &&EmitTargetCallFallbackCB = [&OMPRuntime, OutlinedFn, &D, &CapturedVars, RequiresOuterTask, &CS, @@ -10309,15 +10319,16 @@ void CGOpenMPRuntime::emitTargetDataStandAloneCall( // Source location for the ident struct llvm::Value *RTLoc = emitUpdateLocation(CGF, D.getBeginLoc()); - llvm::Value *OffloadingArgs[] = {RTLoc, - DeviceID, - PointerNum, - InputInfo.BasePointersArray.getPointer(), - InputInfo.PointersArray.getPointer(), - InputInfo.SizesArray.getPointer(), - MapTypesArray, - MapNamesArray, - InputInfo.MappersArray.getPointer()}; + llvm::Value *OffloadingArgs[] = { + RTLoc, + DeviceID, + PointerNum, + InputInfo.BasePointersArray.emitRawPointer(CGF), + InputInfo.PointersArray.emitRawPointer(CGF), + InputInfo.SizesArray.emitRawPointer(CGF), + MapTypesArray, + MapNamesArray, + InputInfo.MappersArray.emitRawPointer(CGF)}; // Select the right runtime function call for each standalone // directive. @@ -11128,7 +11139,7 @@ void CGOpenMPRuntime::emitDoacrossInit(CodeGenFunction &CGF, getThreadID(CGF, D.getBeginLoc()), llvm::ConstantInt::getSigned(CGM.Int32Ty, NumIterations.size()), CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - CGF.Builder.CreateConstArrayGEP(DimsAddr, 0).getPointer(), + CGF.Builder.CreateConstArrayGEP(DimsAddr, 0).emitRawPointer(CGF), CGM.VoidPtrTy)}; llvm::FunctionCallee RTLFn = OMPBuilder.getOrCreateRuntimeFunction( @@ -11162,7 +11173,8 @@ static void EmitDoacrossOrdered(CodeGenFunction &CGF, CodeGenModule &CGM, /*Volatile=*/false, Int64Ty); } llvm::Value *Args[] = { - ULoc, ThreadID, CGF.Builder.CreateConstArrayGEP(CntAddr, 0).getPointer()}; + ULoc, ThreadID, + CGF.Builder.CreateConstArrayGEP(CntAddr, 0).emitRawPointer(CGF)}; llvm::FunctionCallee RTLFn; llvm::OpenMPIRBuilder &OMPBuilder = CGM.getOpenMPRuntime().getOMPBuilder(); OMPDoacrossKind ODK; @@ -11332,7 +11344,7 @@ Address CGOpenMPRuntime::getAddressOfLocalVariable(CodeGenFunction &CGF, Args[0] = CGF.CGM.getOpenMPRuntime().getThreadID( CGF, SourceLocation::getFromRawEncoding(LocEncoding)); Args[1] = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - Addr.getPointer(), CGF.VoidPtrTy); + Addr.emitRawPointer(CGF), CGF.VoidPtrTy); llvm::Value *AllocVal = getAllocatorVal(CGF, AllocExpr); Args[2] = AllocVal; CGF.EmitRuntimeCall(RTLFn, Args); @@ -11690,15 +11702,17 @@ void CGOpenMPRuntime::emitLastprivateConditionalUpdate(CodeGenFunction &CGF, LLIVTy, getName({UniqueDeclName, "iv"})); cast(LastIV)->setAlignment( IVLVal.getAlignment().getAsAlign()); - LValue LastIVLVal = CGF.MakeNaturalAlignAddrLValue(LastIV, IVLVal.getType()); + LValue LastIVLVal = + CGF.MakeNaturalAlignRawAddrLValue(LastIV, IVLVal.getType()); // Last value of the lastprivate conditional. // decltype(priv_a) last_a; llvm::GlobalVariable *Last = OMPBuilder.getOrCreateInternalVariable( CGF.ConvertTypeForMem(LVal.getType()), UniqueDeclName); - Last->setAlignment(LVal.getAlignment().getAsAlign()); - LValue LastLVal = CGF.MakeAddrLValue( - Address(Last, Last->getValueType(), LVal.getAlignment()), LVal.getType()); + cast(Last)->setAlignment( + LVal.getAlignment().getAsAlign()); + LValue LastLVal = + CGF.MakeRawAddrLValue(Last, LVal.getType(), LVal.getAlignment()); // Global loop counter. Required to handle inner parallel-for regions. // iv @@ -11871,9 +11885,8 @@ void CGOpenMPRuntime::emitLastprivateConditionalFinalUpdate( // The variable was not updated in the region - exit. if (!GV) return; - LValue LPLVal = CGF.MakeAddrLValue( - Address(GV, GV->getValueType(), PrivLVal.getAlignment()), - PrivLVal.getType().getNonReferenceType()); + LValue LPLVal = CGF.MakeRawAddrLValue( + GV, PrivLVal.getType().getNonReferenceType(), PrivLVal.getAlignment()); llvm::Value *Res = CGF.EmitLoadOfScalar(LPLVal, Loc); CGF.EmitStoreOfScalar(Res, PrivLVal); } diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.h b/clang/lib/CodeGen/CGOpenMPRuntime.h index c3206427b143e12b616bf5b1501ab6c6871870d0..522ae3d35d22d76e269b03ca0d26ef9ecc0b7bd2 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.h +++ b/clang/lib/CodeGen/CGOpenMPRuntime.h @@ -1068,13 +1068,12 @@ public: /// \param Loc Location of the reference to threadprivate var. /// \return Address of the threadprivate variable for the current thread. virtual Address getAddrOfThreadPrivate(CodeGenFunction &CGF, - const VarDecl *VD, - Address VDAddr, + const VarDecl *VD, Address VDAddr, SourceLocation Loc); /// Returns the address of the variable marked as declare target with link /// clause OR as declare target with to clause and unified memory. - virtual Address getAddrOfDeclareTargetVar(const VarDecl *VD); + virtual ConstantAddress getAddrOfDeclareTargetVar(const VarDecl *VD); /// Emit a code for initialization of threadprivate variable. It emits /// a call to runtime library which adds initial value to the newly created diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp index 299ee1460b3db0ef895c681246a8cc7f8bd42fb2..59ba03c6b862532575766a2985a7405ba0a6b3af 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp @@ -646,7 +646,6 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx, case OMPD_target: case OMPD_target_teams: return hasNestedSPMDDirective(Ctx, D); - case OMPD_target_teams_loop: case OMPD_target_parallel_loop: case OMPD_target_parallel: case OMPD_target_parallel_for: @@ -658,6 +657,12 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx, return true; case OMPD_target_teams_distribute: return false; + case OMPD_target_teams_loop: + // Whether this is true or not depends on how the directive will + // eventually be emitted. + if (auto *TTLD = dyn_cast(&D)) + return TTLD->canBeParallelFor(); + return false; case OMPD_parallel: case OMPD_for: case OMPD_parallel_for: @@ -1096,7 +1101,8 @@ void CGOpenMPRuntimeGPU::emitGenericVarsProlog(CodeGenFunction &CGF, llvm::PointerType *VarPtrTy = CGF.ConvertTypeForMem(VarTy)->getPointerTo(); llvm::Value *CastedVoidPtr = Bld.CreatePointerBitCastOrAddrSpaceCast( VoidPtr, VarPtrTy, VD->getName() + "_on_stack"); - LValue VarAddr = CGF.MakeNaturalAlignAddrLValue(CastedVoidPtr, VarTy); + LValue VarAddr = + CGF.MakeNaturalAlignPointeeRawAddrLValue(CastedVoidPtr, VarTy); Rec.second.PrivateAddr = VarAddr.getAddress(CGF); Rec.second.GlobalizedVal = VoidPtr; @@ -1206,8 +1212,8 @@ void CGOpenMPRuntimeGPU::emitTeamsCall(CodeGenFunction &CGF, bool IsBareKernel = D.getSingleClause(); - Address ZeroAddr = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty, - /*Name=*/".zero.addr"); + RawAddress ZeroAddr = CGF.CreateDefaultAlignTempAlloca(CGF.Int32Ty, + /*Name=*/".zero.addr"); CGF.Builder.CreateStore(CGF.Builder.getInt32(/*C*/ 0), ZeroAddr); llvm::SmallVector OutlinedFnArgs; // We don't emit any thread id function call in bare kernel, but because the @@ -1215,7 +1221,7 @@ void CGOpenMPRuntimeGPU::emitTeamsCall(CodeGenFunction &CGF, if (IsBareKernel) OutlinedFnArgs.push_back(llvm::ConstantPointerNull::get(CGM.VoidPtrTy)); else - OutlinedFnArgs.push_back(emitThreadIDAddress(CGF, Loc).getPointer()); + OutlinedFnArgs.push_back(emitThreadIDAddress(CGF, Loc).emitRawPointer(CGF)); OutlinedFnArgs.push_back(ZeroAddr.getPointer()); OutlinedFnArgs.append(CapturedVars.begin(), CapturedVars.end()); emitOutlinedFunctionCall(CGF, Loc, OutlinedFn, OutlinedFnArgs); @@ -1289,7 +1295,7 @@ void CGOpenMPRuntimeGPU::emitParallelCall(CodeGenFunction &CGF, llvm::ConstantInt::get(CGF.Int32Ty, -1), FnPtr, ID, - Bld.CreateBitOrPointerCast(CapturedVarsAddrs.getPointer(), + Bld.CreateBitOrPointerCast(CapturedVarsAddrs.emitRawPointer(CGF), CGF.VoidPtrPtrTy), llvm::ConstantInt::get(CGM.SizeTy, CapturedVars.size())}; CGF.EmitRuntimeCall(OMPBuilder.getOrCreateRuntimeFunction( @@ -1503,17 +1509,18 @@ static void shuffleAndStore(CodeGenFunction &CGF, Address SrcAddr, CGF.EmitBlock(PreCondBB); llvm::PHINode *PhiSrc = Bld.CreatePHI(Ptr.getType(), /*NumReservedValues=*/2); - PhiSrc->addIncoming(Ptr.getPointer(), CurrentBB); + PhiSrc->addIncoming(Ptr.emitRawPointer(CGF), CurrentBB); llvm::PHINode *PhiDest = Bld.CreatePHI(ElemPtr.getType(), /*NumReservedValues=*/2); - PhiDest->addIncoming(ElemPtr.getPointer(), CurrentBB); + PhiDest->addIncoming(ElemPtr.emitRawPointer(CGF), CurrentBB); Ptr = Address(PhiSrc, Ptr.getElementType(), Ptr.getAlignment()); ElemPtr = Address(PhiDest, ElemPtr.getElementType(), ElemPtr.getAlignment()); + llvm::Value *PtrEndRaw = PtrEnd.emitRawPointer(CGF); + llvm::Value *PtrRaw = Ptr.emitRawPointer(CGF); llvm::Value *PtrDiff = Bld.CreatePtrDiff( - CGF.Int8Ty, PtrEnd.getPointer(), - Bld.CreatePointerBitCastOrAddrSpaceCast(Ptr.getPointer(), - CGF.VoidPtrTy)); + CGF.Int8Ty, PtrEndRaw, + Bld.CreatePointerBitCastOrAddrSpaceCast(PtrRaw, CGF.VoidPtrTy)); Bld.CreateCondBr(Bld.CreateICmpSGT(PtrDiff, Bld.getInt64(IntSize - 1)), ThenBB, ExitBB); CGF.EmitBlock(ThenBB); @@ -1528,8 +1535,8 @@ static void shuffleAndStore(CodeGenFunction &CGF, Address SrcAddr, TBAAAccessInfo()); Address LocalPtr = Bld.CreateConstGEP(Ptr, 1); Address LocalElemPtr = Bld.CreateConstGEP(ElemPtr, 1); - PhiSrc->addIncoming(LocalPtr.getPointer(), ThenBB); - PhiDest->addIncoming(LocalElemPtr.getPointer(), ThenBB); + PhiSrc->addIncoming(LocalPtr.emitRawPointer(CGF), ThenBB); + PhiDest->addIncoming(LocalElemPtr.emitRawPointer(CGF), ThenBB); CGF.EmitBranch(PreCondBB); CGF.EmitBlock(ExitBB); } else { @@ -1676,10 +1683,10 @@ static void emitReductionListCopy( // scope and that of functions it invokes (i.e., reduce_function). // RemoteReduceData[i] = (void*)&RemoteElem if (UpdateDestListPtr) { - CGF.EmitStoreOfScalar(Bld.CreatePointerBitCastOrAddrSpaceCast( - DestElementAddr.getPointer(), CGF.VoidPtrTy), - DestElementPtrAddr, /*Volatile=*/false, - C.VoidPtrTy); + CGF.EmitStoreOfScalar( + Bld.CreatePointerBitCastOrAddrSpaceCast( + DestElementAddr.emitRawPointer(CGF), CGF.VoidPtrTy), + DestElementPtrAddr, /*Volatile=*/false, C.VoidPtrTy); } ++Idx; @@ -1830,7 +1837,7 @@ static llvm::Value *emitInterWarpCopyFunction(CodeGenModule &CGM, // elemptr = ((CopyType*)(elemptrptr)) + I Address ElemPtr(ElemPtrPtr, CopyType, Align); if (NumIters > 1) - ElemPtr = Bld.CreateGEP(ElemPtr, Cnt); + ElemPtr = Bld.CreateGEP(CGF, ElemPtr, Cnt); // Get pointer to location in transfer medium. // MediumPtr = &medium[warp_id] @@ -1894,7 +1901,7 @@ static llvm::Value *emitInterWarpCopyFunction(CodeGenModule &CGM, TargetElemPtrPtr, /*Volatile=*/false, C.VoidPtrTy, Loc); Address TargetElemPtr(TargetElemPtrVal, CopyType, Align); if (NumIters > 1) - TargetElemPtr = Bld.CreateGEP(TargetElemPtr, Cnt); + TargetElemPtr = Bld.CreateGEP(CGF, TargetElemPtr, Cnt); // *TargetElemPtr = SrcMediumVal; llvm::Value *SrcMediumValue = @@ -2105,9 +2112,9 @@ static llvm::Function *emitShuffleAndReduceFunction( CGF.EmitBlock(ThenBB); // reduce_function(LocalReduceList, RemoteReduceList) llvm::Value *LocalReduceListPtr = Bld.CreatePointerBitCastOrAddrSpaceCast( - LocalReduceList.getPointer(), CGF.VoidPtrTy); + LocalReduceList.emitRawPointer(CGF), CGF.VoidPtrTy); llvm::Value *RemoteReduceListPtr = Bld.CreatePointerBitCastOrAddrSpaceCast( - RemoteReduceList.getPointer(), CGF.VoidPtrTy); + RemoteReduceList.emitRawPointer(CGF), CGF.VoidPtrTy); CGM.getOpenMPRuntime().emitOutlinedFunctionCall( CGF, Loc, ReduceFn, {LocalReduceListPtr, RemoteReduceListPtr}); Bld.CreateBr(MergeBB); @@ -2218,9 +2225,9 @@ static llvm::Value *emitListToGlobalCopyFunction( llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(LLVMReductionsBufferTy, BufferArrPtr, Idxs); LValue GlobLVal = CGF.EmitLValueForField( - CGF.MakeNaturalAlignAddrLValue(BufferPtr, StaticTy), FD); + CGF.MakeNaturalAlignRawAddrLValue(BufferPtr, StaticTy), FD); Address GlobAddr = GlobLVal.getAddress(CGF); - GlobLVal.setAddress(Address(GlobAddr.getPointer(), + GlobLVal.setAddress(Address(GlobAddr.emitRawPointer(CGF), CGF.ConvertTypeForMem(Private->getType()), GlobAddr.getAlignment())); switch (CGF.getEvaluationKind(Private->getType())) { @@ -2304,7 +2311,7 @@ static llvm::Value *emitListToGlobalReduceFunction( // 1. Build a list of reduction variables. // void *RedList[] = {[0], ..., [-1]}; - Address ReductionList = + RawAddress ReductionList = CGF.CreateMemTemp(ReductionArrayTy, ".omp.reduction.red_list"); auto IPriv = Privates.begin(); llvm::Value *Idxs[] = {CGF.EmitLoadOfScalar(CGF.GetAddrOfLocalVar(&IdxArg), @@ -2319,10 +2326,10 @@ static llvm::Value *emitListToGlobalReduceFunction( llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(LLVMReductionsBufferTy, BufferArrPtr, Idxs); LValue GlobLVal = CGF.EmitLValueForField( - CGF.MakeNaturalAlignAddrLValue(BufferPtr, StaticTy), FD); + CGF.MakeNaturalAlignRawAddrLValue(BufferPtr, StaticTy), FD); Address GlobAddr = GlobLVal.getAddress(CGF); - CGF.EmitStoreOfScalar(GlobAddr.getPointer(), Elem, /*Volatile=*/false, - C.VoidPtrTy); + CGF.EmitStoreOfScalar(GlobAddr.emitRawPointer(CGF), Elem, + /*Volatile=*/false, C.VoidPtrTy); if ((*IPriv)->getType()->isVariablyModifiedType()) { // Store array size. ++Idx; @@ -2425,9 +2432,9 @@ static llvm::Value *emitGlobalToListCopyFunction( llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(LLVMReductionsBufferTy, BufferArrPtr, Idxs); LValue GlobLVal = CGF.EmitLValueForField( - CGF.MakeNaturalAlignAddrLValue(BufferPtr, StaticTy), FD); + CGF.MakeNaturalAlignRawAddrLValue(BufferPtr, StaticTy), FD); Address GlobAddr = GlobLVal.getAddress(CGF); - GlobLVal.setAddress(Address(GlobAddr.getPointer(), + GlobLVal.setAddress(Address(GlobAddr.emitRawPointer(CGF), CGF.ConvertTypeForMem(Private->getType()), GlobAddr.getAlignment())); switch (CGF.getEvaluationKind(Private->getType())) { @@ -2526,10 +2533,10 @@ static llvm::Value *emitGlobalToListReduceFunction( llvm::Value *BufferPtr = Bld.CreateInBoundsGEP(LLVMReductionsBufferTy, BufferArrPtr, Idxs); LValue GlobLVal = CGF.EmitLValueForField( - CGF.MakeNaturalAlignAddrLValue(BufferPtr, StaticTy), FD); + CGF.MakeNaturalAlignRawAddrLValue(BufferPtr, StaticTy), FD); Address GlobAddr = GlobLVal.getAddress(CGF); - CGF.EmitStoreOfScalar(GlobAddr.getPointer(), Elem, /*Volatile=*/false, - C.VoidPtrTy); + CGF.EmitStoreOfScalar(GlobAddr.emitRawPointer(CGF), Elem, + /*Volatile=*/false, C.VoidPtrTy); if ((*IPriv)->getType()->isVariablyModifiedType()) { // Store array size. ++Idx; @@ -2545,7 +2552,7 @@ static llvm::Value *emitGlobalToListReduceFunction( } // Call reduce_function(ReduceList, GlobalReduceList) - llvm::Value *GlobalReduceList = ReductionList.getPointer(); + llvm::Value *GlobalReduceList = ReductionList.emitRawPointer(CGF); Address AddrReduceListArg = CGF.GetAddrOfLocalVar(&ReduceListArg); llvm::Value *ReducedPtr = CGF.EmitLoadOfScalar( AddrReduceListArg, /*Volatile=*/false, C.VoidPtrTy, Loc); @@ -2876,7 +2883,7 @@ void CGOpenMPRuntimeGPU::emitReduction( } llvm::Value *RL = CGF.Builder.CreatePointerBitCastOrAddrSpaceCast( - ReductionList.getPointer(), CGF.VoidPtrTy); + ReductionList.emitRawPointer(CGF), CGF.VoidPtrTy); llvm::Function *ReductionFn = emitReductionFunction( CGF.CurFn->getName(), Loc, CGF.ConvertTypeForMem(ReductionArrayTy), Privates, LHSExprs, RHSExprs, ReductionOps); @@ -3106,15 +3113,15 @@ llvm::Function *CGOpenMPRuntimeGPU::createParallelDataSharingWrapper( // Get the array of arguments. SmallVector Args; - Args.emplace_back(CGF.GetAddrOfLocalVar(&WrapperArg).getPointer()); - Args.emplace_back(ZeroAddr.getPointer()); + Args.emplace_back(CGF.GetAddrOfLocalVar(&WrapperArg).emitRawPointer(CGF)); + Args.emplace_back(ZeroAddr.emitRawPointer(CGF)); CGBuilderTy &Bld = CGF.Builder; auto CI = CS.capture_begin(); // Use global memory for data sharing. // Handle passing of global args to workers. - Address GlobalArgs = + RawAddress GlobalArgs = CGF.CreateDefaultAlignTempAlloca(CGF.VoidPtrPtrTy, "global_args"); llvm::Value *GlobalArgsPtr = GlobalArgs.getPointer(); llvm::Value *DataSharingArgs[] = {GlobalArgsPtr}; @@ -3400,7 +3407,7 @@ void CGOpenMPRuntimeGPU::adjustTargetSpecificDataForLambdas( VDAddr = CGF.EmitLoadOfReferenceLValue(VDAddr, VD->getType().getCanonicalType()) .getAddress(CGF); - CGF.EmitStoreOfScalar(VDAddr.getPointer(), VarLVal); + CGF.EmitStoreOfScalar(VDAddr.emitRawPointer(CGF), VarLVal); } } } diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index 7822903b89ce47e174d24508d86609a42cb3dba7..634a55fec5182eb76dc0439b25c045dbc63bfa37 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -47,8 +47,10 @@ namespace { /// [i8 x 3] instead of i24. The function clipTailPadding does this. /// C++ examples that require clipping: /// struct { int a : 24; char b; }; // a must be clipped, b goes at offset 3 -/// struct A { int a : 24; }; // a must be clipped because a struct like B -// could exist: struct B : A { char b; }; // b goes at offset 3 +/// struct A { int a : 24; ~A(); }; // a must be clipped because: +/// struct B : A { char b; }; // b goes at offset 3 +/// * The allocation of bitfield access units is described in more detail in +/// CGRecordLowering::accumulateBitFields. /// * Clang ignores 0 sized bitfields and 0 sized bases but *not* zero sized /// fields. The existing asserts suggest that LLVM assumes that *every* field /// has an underlying storage type. Therefore empty structures containing @@ -183,17 +185,21 @@ struct CGRecordLowering { /// Lowers an ASTRecordLayout to a llvm type. void lower(bool NonVirtualBaseType); void lowerUnion(bool isNoUniqueAddress); - void accumulateFields(); - void accumulateBitFields(RecordDecl::field_iterator Field, - RecordDecl::field_iterator FieldEnd); + void accumulateFields(bool isNonVirtualBaseType); + RecordDecl::field_iterator + accumulateBitFields(bool isNonVirtualBaseType, + RecordDecl::field_iterator Field, + RecordDecl::field_iterator FieldEnd); void computeVolatileBitfields(); void accumulateBases(); void accumulateVPtrs(); void accumulateVBases(); /// Recursively searches all of the bases to find out if a vbase is /// not the primary vbase of some base class. - bool hasOwnStorage(const CXXRecordDecl *Decl, const CXXRecordDecl *Query); + bool hasOwnStorage(const CXXRecordDecl *Decl, + const CXXRecordDecl *Query) const; void calculateZeroInit(); + CharUnits calculateTailClippingOffset(bool isNonVirtualBaseType) const; /// Lowers bitfield storage types to I8 arrays for bitfields with tail /// padding that is or can potentially be used. void clipTailPadding(); @@ -284,7 +290,7 @@ void CGRecordLowering::lower(bool NVBaseType) { computeVolatileBitfields(); return; } - accumulateFields(); + accumulateFields(NVBaseType); // RD implies C++. if (RD) { accumulateVPtrs(); @@ -375,16 +381,18 @@ void CGRecordLowering::lowerUnion(bool isNoUniqueAddress) { Packed = true; } -void CGRecordLowering::accumulateFields() { +void CGRecordLowering::accumulateFields(bool isNonVirtualBaseType) { for (RecordDecl::field_iterator Field = D->field_begin(), FieldEnd = D->field_end(); - Field != FieldEnd;) { + Field != FieldEnd;) { if (Field->isBitField()) { - RecordDecl::field_iterator Start = Field; - // Iterate to gather the list of bitfields. - for (++Field; Field != FieldEnd && Field->isBitField(); ++Field); - accumulateBitFields(Start, Field); - } else if (!Field->isZeroSize(Context)) { + Field = accumulateBitFields(isNonVirtualBaseType, Field, FieldEnd); + assert((Field == FieldEnd || !Field->isBitField()) && + "Failed to accumulate all the bitfields"); + } else if (Field->isZeroSize(Context)) { + // Empty fields have no storage. + ++Field; + } else { // Use base subobject layout for the potentially-overlapping field, // as it is done in RecordLayoutBuilder Members.push_back(MemberInfo( @@ -394,33 +402,36 @@ void CGRecordLowering::accumulateFields() { : getStorageType(*Field), *Field)); ++Field; - } else { - ++Field; } } } -void -CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field, +// Create members for bitfields. Field is a bitfield, and FieldEnd is the end +// iterator of the record. Return the first non-bitfield encountered. We need +// to know whether this is the base or complete layout, as virtual bases could +// affect the upper bound of bitfield access unit allocation. +RecordDecl::field_iterator +CGRecordLowering::accumulateBitFields(bool isNonVirtualBaseType, + RecordDecl::field_iterator Field, RecordDecl::field_iterator FieldEnd) { - // Run stores the first element of the current run of bitfields. FieldEnd is - // used as a special value to note that we don't have a current run. A - // bitfield run is a contiguous collection of bitfields that can be stored in - // the same storage block. Zero-sized bitfields and bitfields that would - // cross an alignment boundary break a run and start a new one. - RecordDecl::field_iterator Run = FieldEnd; - // Tail is the offset of the first bit off the end of the current run. It's - // used to determine if the ASTRecordLayout is treating these two bitfields as - // contiguous. StartBitOffset is offset of the beginning of the Run. - uint64_t StartBitOffset, Tail = 0; if (isDiscreteBitFieldABI()) { - for (; Field != FieldEnd; ++Field) { - uint64_t BitOffset = getFieldBitOffset(*Field); + // Run stores the first element of the current run of bitfields. FieldEnd is + // used as a special value to note that we don't have a current run. A + // bitfield run is a contiguous collection of bitfields that can be stored + // in the same storage block. Zero-sized bitfields and bitfields that would + // cross an alignment boundary break a run and start a new one. + RecordDecl::field_iterator Run = FieldEnd; + // Tail is the offset of the first bit off the end of the current run. It's + // used to determine if the ASTRecordLayout is treating these two bitfields + // as contiguous. StartBitOffset is offset of the beginning of the Run. + uint64_t StartBitOffset, Tail = 0; + for (; Field != FieldEnd && Field->isBitField(); ++Field) { // Zero-width bitfields end runs. if (Field->isZeroLengthBitField(Context)) { Run = FieldEnd; continue; } + uint64_t BitOffset = getFieldBitOffset(*Field); llvm::Type *Type = Types.ConvertTypeForMem(Field->getType(), /*ForBitField=*/true); // If we don't have a run yet, or don't live within the previous run's @@ -439,82 +450,256 @@ CGRecordLowering::accumulateBitFields(RecordDecl::field_iterator Field, Members.push_back(MemberInfo(bitsToCharUnits(StartBitOffset), MemberInfo::Field, nullptr, *Field)); } - return; + return Field; } - // Check if OffsetInRecord (the size in bits of the current run) is better - // as a single field run. When OffsetInRecord has legal integer width, and - // its bitfield offset is naturally aligned, it is better to make the - // bitfield a separate storage component so as it can be accessed directly - // with lower cost. - auto IsBetterAsSingleFieldRun = [&](uint64_t OffsetInRecord, - uint64_t StartBitOffset) { - if (!Types.getCodeGenOpts().FineGrainedBitfieldAccesses) - return false; - if (OffsetInRecord < 8 || !llvm::isPowerOf2_64(OffsetInRecord) || - !DataLayout.fitsInLegalInteger(OffsetInRecord)) - return false; - // Make sure StartBitOffset is naturally aligned if it is treated as an - // IType integer. - if (StartBitOffset % - Context.toBits(getAlignment(getIntNType(OffsetInRecord))) != - 0) - return false; - return true; - }; + // The SysV ABI can overlap bitfield storage units with both other bitfield + // storage units /and/ other non-bitfield data members. Accessing a sequence + // of bitfields mustn't interfere with adjacent non-bitfields -- they're + // permitted to be accessed in separate threads for instance. + + // We split runs of bit-fields into a sequence of "access units". When we emit + // a load or store of a bit-field, we'll load/store the entire containing + // access unit. As mentioned, the standard requires that these loads and + // stores must not interfere with accesses to other memory locations, and it + // defines the bit-field's memory location as the current run of + // non-zero-width bit-fields. So an access unit must never overlap with + // non-bit-field storage or cross a zero-width bit-field. Otherwise, we're + // free to draw the lines as we see fit. + + // Drawing these lines well can be complicated. LLVM generally can't modify a + // program to access memory that it didn't before, so using very narrow access + // units can prevent the compiler from using optimal access patterns. For + // example, suppose a run of bit-fields occupies four bytes in a struct. If we + // split that into four 1-byte access units, then a sequence of assignments + // that doesn't touch all four bytes may have to be emitted with multiple + // 8-bit stores instead of a single 32-bit store. On the other hand, if we use + // very wide access units, we may find ourselves emitting accesses to + // bit-fields we didn't really need to touch, just because LLVM was unable to + // clean up after us. + + // It is desirable to have access units be aligned powers of 2 no larger than + // a register. (On non-strict alignment ISAs, the alignment requirement can be + // dropped.) A three byte access unit will be accessed using 2-byte and 1-byte + // accesses and bit manipulation. If no bitfield straddles across the two + // separate accesses, it is better to have separate 2-byte and 1-byte access + // units, as then LLVM will not generate unnecessary memory accesses, or bit + // manipulation. Similarly, on a strict-alignment architecture, it is better + // to keep access-units naturally aligned, to avoid similar bit + // manipulation synthesizing larger unaligned accesses. + + // Bitfields that share parts of a single byte are, of necessity, placed in + // the same access unit. That unit will encompass a consecutive run where + // adjacent bitfields share parts of a byte. (The first bitfield of such an + // access unit will start at the beginning of a byte.) + + // We then try and accumulate adjacent access units when the combined unit is + // naturally sized, no larger than a register, and (on a strict alignment + // ISA), naturally aligned. Note that this requires lookahead to one or more + // subsequent access units. For instance, consider a 2-byte access-unit + // followed by 2 1-byte units. We can merge that into a 4-byte access-unit, + // but we would not want to merge a 2-byte followed by a single 1-byte (and no + // available tail padding). We keep track of the best access unit seen so far, + // and use that when we determine we cannot accumulate any more. Then we start + // again at the bitfield following that best one. + + // The accumulation is also prevented when: + // *) it would cross a character-aigned zero-width bitfield, or + // *) fine-grained bitfield access option is in effect. + + CharUnits RegSize = + bitsToCharUnits(Context.getTargetInfo().getRegisterWidth()); + unsigned CharBits = Context.getCharWidth(); + + // Limit of useable tail padding at end of the record. Computed lazily and + // cached here. + CharUnits ScissorOffset = CharUnits::Zero(); + + // Data about the start of the span we're accumulating to create an access + // unit from. Begin is the first bitfield of the span. If Begin is FieldEnd, + // we've not got a current span. The span starts at the BeginOffset character + // boundary. BitSizeSinceBegin is the size (in bits) of the span -- this might + // include padding when we've advanced to a subsequent bitfield run. + RecordDecl::field_iterator Begin = FieldEnd; + CharUnits BeginOffset; + uint64_t BitSizeSinceBegin; + + // The (non-inclusive) end of the largest acceptable access unit we've found + // since Begin. If this is Begin, we're gathering the initial set of bitfields + // of a new span. BestEndOffset is the end of that acceptable access unit -- + // it might extend beyond the last character of the bitfield run, using + // available padding characters. + RecordDecl::field_iterator BestEnd = Begin; + CharUnits BestEndOffset; - // The start field is better as a single field run. - bool StartFieldAsSingleRun = false; for (;;) { - // Check to see if we need to start a new run. - if (Run == FieldEnd) { - // If we're out of fields, return. - if (Field == FieldEnd) + // AtAlignedBoundary is true iff Field is the (potential) start of a new + // span (or the end of the bitfields). When true, LimitOffset is the + // character offset of that span and Barrier indicates whether the new + // span cannot be merged into the current one. + bool AtAlignedBoundary = false; + bool Barrier = false; + + if (Field != FieldEnd && Field->isBitField()) { + uint64_t BitOffset = getFieldBitOffset(*Field); + if (Begin == FieldEnd) { + // Beginning a new span. + Begin = Field; + BestEnd = Begin; + + assert((BitOffset % CharBits) == 0 && "Not at start of char"); + BeginOffset = bitsToCharUnits(BitOffset); + BitSizeSinceBegin = 0; + } else if ((BitOffset % CharBits) != 0) { + // Bitfield occupies the same character as previous bitfield, it must be + // part of the same span. This can include zero-length bitfields, should + // the target not align them to character boundaries. Such non-alignment + // is at variance with the standards, which require zero-length + // bitfields be a barrier between access units. But of course we can't + // achieve that in the middle of a character. + assert(BitOffset == Context.toBits(BeginOffset) + BitSizeSinceBegin && + "Concatenating non-contiguous bitfields"); + } else { + // Bitfield potentially begins a new span. This includes zero-length + // bitfields on non-aligning targets that lie at character boundaries + // (those are barriers to merging). + if (Field->isZeroLengthBitField(Context)) + Barrier = true; + AtAlignedBoundary = true; + } + } else { + // We've reached the end of the bitfield run. Either we're done, or this + // is a barrier for the current span. + if (Begin == FieldEnd) break; - // Any non-zero-length bitfield can start a new run. - if (!Field->isZeroLengthBitField(Context)) { - Run = Field; - StartBitOffset = getFieldBitOffset(*Field); - Tail = StartBitOffset + Field->getBitWidthValue(Context); - StartFieldAsSingleRun = IsBetterAsSingleFieldRun(Tail - StartBitOffset, - StartBitOffset); + + Barrier = true; + AtAlignedBoundary = true; + } + + // InstallBest indicates whether we should create an access unit for the + // current best span: fields [Begin, BestEnd) occupying characters + // [BeginOffset, BestEndOffset). + bool InstallBest = false; + if (AtAlignedBoundary) { + // Field is the start of a new span or the end of the bitfields. The + // just-seen span now extends to BitSizeSinceBegin. + + // Determine if we can accumulate that just-seen span into the current + // accumulation. + CharUnits AccessSize = bitsToCharUnits(BitSizeSinceBegin + CharBits - 1); + if (BestEnd == Begin) { + // This is the initial run at the start of a new span. By definition, + // this is the best seen so far. + BestEnd = Field; + BestEndOffset = BeginOffset + AccessSize; + if (Types.getCodeGenOpts().FineGrainedBitfieldAccesses) + // Fine-grained access, so no merging of spans. + InstallBest = true; + else if (!BitSizeSinceBegin) + // A zero-sized initial span -- this will install nothing and reset + // for another. + InstallBest = true; + } else if (AccessSize > RegSize) + // Accumulating the just-seen span would create a multi-register access + // unit, which would increase register pressure. + InstallBest = true; + + if (!InstallBest) { + // Determine if accumulating the just-seen span will create an expensive + // access unit or not. + llvm::Type *Type = getIntNType(Context.toBits(AccessSize)); + if (!Context.getTargetInfo().hasCheapUnalignedBitFieldAccess()) { + // Unaligned accesses are expensive. Only accumulate if the new unit + // is naturally aligned. Otherwise install the best we have, which is + // either the initial access unit (can't do better), or a naturally + // aligned accumulation (since we would have already installed it if + // it wasn't naturally aligned). + CharUnits Align = getAlignment(Type); + if (Align > Layout.getAlignment()) + // The alignment required is greater than the containing structure + // itself. + InstallBest = true; + else if (!BeginOffset.isMultipleOf(Align)) + // The access unit is not at a naturally aligned offset within the + // structure. + InstallBest = true; + } + + if (!InstallBest) { + // Find the next used storage offset to determine what the limit of + // the current span is. That's either the offset of the next field + // with storage (which might be Field itself) or the end of the + // non-reusable tail padding. + CharUnits LimitOffset; + for (auto Probe = Field; Probe != FieldEnd; ++Probe) + if (!Probe->isZeroSize(Context)) { + // A member with storage sets the limit. + assert((getFieldBitOffset(*Probe) % CharBits) == 0 && + "Next storage is not byte-aligned"); + LimitOffset = bitsToCharUnits(getFieldBitOffset(*Probe)); + goto FoundLimit; + } + // We reached the end of the fields, determine the bounds of useable + // tail padding. As this can be complex for C++, we cache the result. + if (ScissorOffset.isZero()) { + ScissorOffset = calculateTailClippingOffset(isNonVirtualBaseType); + assert(!ScissorOffset.isZero() && "Tail clipping at zero"); + } + + LimitOffset = ScissorOffset; + FoundLimit:; + + CharUnits TypeSize = getSize(Type); + if (BeginOffset + TypeSize <= LimitOffset) { + // There is space before LimitOffset to create a naturally-sized + // access unit. + BestEndOffset = BeginOffset + TypeSize; + BestEnd = Field; + } + + if (Barrier) + // The next field is a barrier that we cannot merge across. + InstallBest = true; + else + // Otherwise, we're not installing. Update the bit size + // of the current span to go all the way to LimitOffset, which is + // the (aligned) offset of next bitfield to consider. + BitSizeSinceBegin = Context.toBits(LimitOffset - BeginOffset); + } } - ++Field; - continue; } - // If the start field of a new run is better as a single run, or - // if current field (or consecutive fields) is better as a single run, or - // if current field has zero width bitfield and either - // UseZeroLengthBitfieldAlignment or UseBitFieldTypeAlignment is set to - // true, or - // if the offset of current field is inconsistent with the offset of - // previous field plus its offset, - // skip the block below and go ahead to emit the storage. - // Otherwise, try to add bitfields to the run. - if (!StartFieldAsSingleRun && Field != FieldEnd && - !IsBetterAsSingleFieldRun(Tail - StartBitOffset, StartBitOffset) && - (!Field->isZeroLengthBitField(Context) || - (!Context.getTargetInfo().useZeroLengthBitfieldAlignment() && - !Context.getTargetInfo().useBitFieldTypeAlignment())) && - Tail == getFieldBitOffset(*Field)) { - Tail += Field->getBitWidthValue(Context); + if (InstallBest) { + assert((Field == FieldEnd || !Field->isBitField() || + (getFieldBitOffset(*Field) % CharBits) == 0) && + "Installing but not at an aligned bitfield or limit"); + CharUnits AccessSize = BestEndOffset - BeginOffset; + if (!AccessSize.isZero()) { + // Add the storage member for the access unit to the record. The + // bitfields get the offset of their storage but come afterward and + // remain there after a stable sort. + llvm::Type *Type = getIntNType(Context.toBits(AccessSize)); + Members.push_back(StorageInfo(BeginOffset, Type)); + for (; Begin != BestEnd; ++Begin) + if (!Begin->isZeroLengthBitField(Context)) + Members.push_back( + MemberInfo(BeginOffset, MemberInfo::Field, nullptr, *Begin)); + } + // Reset to start a new span. + Field = BestEnd; + Begin = FieldEnd; + } else { + assert(Field != FieldEnd && Field->isBitField() && + "Accumulating past end of bitfields"); + assert(!Barrier && "Accumulating across barrier"); + // Accumulate this bitfield into the current (potential) span. + BitSizeSinceBegin += Field->getBitWidthValue(Context); ++Field; - continue; } - - // We've hit a break-point in the run and need to emit a storage field. - llvm::Type *Type = getIntNType(Tail - StartBitOffset); - // Add the storage member to the record and set the bitfield info for all of - // the bitfields in the run. Bitfields get the offset of their storage but - // come afterward and remain there after a stable sort. - Members.push_back(StorageInfo(bitsToCharUnits(StartBitOffset), Type)); - for (; Run != Field; ++Run) - Members.push_back(MemberInfo(bitsToCharUnits(StartBitOffset), - MemberInfo::Field, nullptr, *Run)); - Run = FieldEnd; - StartFieldAsSingleRun = false; } + + return Field; } void CGRecordLowering::accumulateBases() { @@ -667,13 +852,17 @@ void CGRecordLowering::accumulateVPtrs() { llvm::PointerType::getUnqual(Types.getLLVMContext()))); } -void CGRecordLowering::accumulateVBases() { +CharUnits +CGRecordLowering::calculateTailClippingOffset(bool isNonVirtualBaseType) const { + if (!RD) + return Layout.getDataSize(); + CharUnits ScissorOffset = Layout.getNonVirtualSize(); // In the itanium ABI, it's possible to place a vbase at a dsize that is // smaller than the nvsize. Here we check to see if such a base is placed // before the nvsize and set the scissor offset to that, instead of the // nvsize. - if (isOverlappingVBaseABI()) + if (!isNonVirtualBaseType && isOverlappingVBaseABI()) for (const auto &Base : RD->vbases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); if (BaseDecl->isEmpty()) @@ -685,8 +874,13 @@ void CGRecordLowering::accumulateVBases() { ScissorOffset = std::min(ScissorOffset, Layout.getVBaseClassOffset(BaseDecl)); } - Members.push_back(MemberInfo(ScissorOffset, MemberInfo::Scissor, nullptr, - RD)); + + return ScissorOffset; +} + +void CGRecordLowering::accumulateVBases() { + Members.push_back(MemberInfo(calculateTailClippingOffset(false), + MemberInfo::Scissor, nullptr, RD)); for (const auto &Base : RD->vbases()) { const CXXRecordDecl *BaseDecl = Base.getType()->getAsCXXRecordDecl(); if (BaseDecl->isEmpty()) @@ -711,7 +905,7 @@ void CGRecordLowering::accumulateVBases() { } bool CGRecordLowering::hasOwnStorage(const CXXRecordDecl *Decl, - const CXXRecordDecl *Query) { + const CXXRecordDecl *Query) const { const ASTRecordLayout &DeclLayout = Context.getASTRecordLayout(Decl); if (DeclLayout.isPrimaryBaseVirtual() && DeclLayout.getPrimaryBase() == Query) return false; diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index cb5a004e4f4a6cf802758169cb211728b6d0e42e..576fe2f7a2d46f41aa6c60b4139a28753fd3314f 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -2294,7 +2294,7 @@ std::pair CodeGenFunction::EmitAsmInputLValue( Address Addr = InputValue.getAddress(*this); ConstraintStr += '*'; - return {Addr.getPointer(), Addr.getElementType()}; + return {InputValue.getPointer(*this), Addr.getElementType()}; } std::pair @@ -2701,7 +2701,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { ArgTypes.push_back(DestAddr.getType()); ArgElemTypes.push_back(DestAddr.getElementType()); - Args.push_back(DestAddr.getPointer()); + Args.push_back(DestAddr.emitRawPointer(*this)); Constraints += "=*"; Constraints += OutputConstraint; ReadOnly = ReadNone = false; @@ -3076,8 +3076,8 @@ CodeGenFunction::GenerateCapturedStmtFunction(const CapturedStmt &S) { CapturedStmtInfo->setContextValue(Builder.CreateLoad(DeclPtr)); // Initialize variable-length arrays. - LValue Base = MakeNaturalAlignAddrLValue(CapturedStmtInfo->getContextValue(), - Ctx.getTagDeclType(RD)); + LValue Base = MakeNaturalAlignRawAddrLValue( + CapturedStmtInfo->getContextValue(), Ctx.getTagDeclType(RD)); for (auto *FD : RD->fields()) { if (FD->hasCapturedVLAType()) { auto *ExprArg = diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index f37ac549d10a827ea0ad5b71fc656d0240d6c03a..a0a8a07c76ba16528fea5c39459684d7ee37a74c 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -24,6 +24,7 @@ #include "clang/AST/StmtVisitor.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/PrettyStackTrace.h" +#include "clang/Basic/SourceManager.h" #include "llvm/ADT/SmallSet.h" #include "llvm/BinaryFormat/Dwarf.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" @@ -34,11 +35,14 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Metadata.h" #include "llvm/Support/AtomicOrdering.h" +#include "llvm/Support/Debug.h" #include using namespace clang; using namespace CodeGen; using namespace llvm::omp; +#define TTL_CODEGEN_TYPE "target-teams-loop-codegen" + static const VarDecl *getBaseDecl(const Expr *Ref); namespace { @@ -350,7 +354,8 @@ void CodeGenFunction::GenerateOpenMPCapturedVars( LValue DstLV = MakeAddrLValue(DstAddr, Ctx.getUIntPtrType()); llvm::Value *SrcAddrVal = EmitScalarConversion( - DstAddr.getPointer(), Ctx.getPointerType(Ctx.getUIntPtrType()), + DstAddr.emitRawPointer(*this), + Ctx.getPointerType(Ctx.getUIntPtrType()), Ctx.getPointerType(CurField->getType()), CurCap->getLocation()); LValue SrcLV = MakeNaturalAlignAddrLValue(SrcAddrVal, CurField->getType()); @@ -364,7 +369,8 @@ void CodeGenFunction::GenerateOpenMPCapturedVars( CapturedVars.push_back(CV); } else { assert(CurCap->capturesVariable() && "Expected capture by reference."); - CapturedVars.push_back(EmitLValue(*I).getAddress(*this).getPointer()); + CapturedVars.push_back( + EmitLValue(*I).getAddress(*this).emitRawPointer(*this)); } } } @@ -375,8 +381,9 @@ static Address castValueFromUintptr(CodeGenFunction &CGF, SourceLocation Loc, ASTContext &Ctx = CGF.getContext(); llvm::Value *CastedPtr = CGF.EmitScalarConversion( - AddrLV.getAddress(CGF).getPointer(), Ctx.getUIntPtrType(), + AddrLV.getAddress(CGF).emitRawPointer(CGF), Ctx.getUIntPtrType(), Ctx.getPointerType(DstType), Loc); + // FIXME: should the pointee type (DstType) be passed? Address TmpAddr = CGF.MakeNaturalAlignAddrLValue(CastedPtr, DstType).getAddress(CGF); return TmpAddr; @@ -702,8 +709,8 @@ void CodeGenFunction::EmitOMPAggregateAssign( llvm::Value *NumElements = emitArrayLength(ArrayTy, ElementTy, DestAddr); SrcAddr = SrcAddr.withElementType(DestAddr.getElementType()); - llvm::Value *SrcBegin = SrcAddr.getPointer(); - llvm::Value *DestBegin = DestAddr.getPointer(); + llvm::Value *SrcBegin = SrcAddr.emitRawPointer(*this); + llvm::Value *DestBegin = DestAddr.emitRawPointer(*this); // Cast from pointer to array type to pointer to single element. llvm::Value *DestEnd = Builder.CreateInBoundsGEP(DestAddr.getElementType(), DestBegin, NumElements); @@ -1007,10 +1014,10 @@ bool CodeGenFunction::EmitOMPCopyinClause(const OMPExecutableDirective &D) { CopyBegin = createBasicBlock("copyin.not.master"); CopyEnd = createBasicBlock("copyin.not.master.end"); // TODO: Avoid ptrtoint conversion. - auto *MasterAddrInt = - Builder.CreatePtrToInt(MasterAddr.getPointer(), CGM.IntPtrTy); - auto *PrivateAddrInt = - Builder.CreatePtrToInt(PrivateAddr.getPointer(), CGM.IntPtrTy); + auto *MasterAddrInt = Builder.CreatePtrToInt( + MasterAddr.emitRawPointer(*this), CGM.IntPtrTy); + auto *PrivateAddrInt = Builder.CreatePtrToInt( + PrivateAddr.emitRawPointer(*this), CGM.IntPtrTy); Builder.CreateCondBr( Builder.CreateICmpNE(MasterAddrInt, PrivateAddrInt), CopyBegin, CopyEnd); @@ -1429,9 +1436,12 @@ void CodeGenFunction::EmitOMPReductionClauseFinal( *this, D.getBeginLoc(), isOpenMPWorksharingDirective(D.getDirectiveKind())); } + bool TeamsLoopCanBeParallel = false; + if (auto *TTLD = dyn_cast(&D)) + TeamsLoopCanBeParallel = TTLD->canBeParallelFor(); bool WithNowait = D.getSingleClause() || isOpenMPParallelDirective(D.getDirectiveKind()) || - ReductionKind == OMPD_simd; + TeamsLoopCanBeParallel || ReductionKind == OMPD_simd; bool SimpleReduction = ReductionKind == OMPD_simd; // Emit nowait reduction if nowait clause is present or directive is a // parallel directive (it always has implicit barrier). @@ -1666,7 +1676,7 @@ Address CodeGenFunction::OMPBuilderCBHelpers::getAddrOfThreadPrivate( llvm::Type *VarTy = VDAddr.getElementType(); llvm::Value *Data = - CGF.Builder.CreatePointerCast(VDAddr.getPointer(), CGM.Int8PtrTy); + CGF.Builder.CreatePointerCast(VDAddr.emitRawPointer(CGF), CGM.Int8PtrTy); llvm::ConstantInt *Size = CGM.getSize(CGM.GetTargetTypeStoreSize(VarTy)); std::string Suffix = getNameWithSeparators({"cache", ""}); llvm::Twine CacheName = Twine(CGM.getMangledName(VD)).concat(Suffix); @@ -2045,7 +2055,7 @@ void CodeGenFunction::EmitOMPCanonicalLoop(const OMPCanonicalLoop *S) { ->getParam(0) ->getType() .getNonReferenceType(); - Address CountAddr = CreateMemTemp(LogicalTy, ".count.addr"); + RawAddress CountAddr = CreateMemTemp(LogicalTy, ".count.addr"); emitCapturedStmtCall(*this, DistanceClosure, {CountAddr.getPointer()}); llvm::Value *DistVal = Builder.CreateLoad(CountAddr, ".count"); @@ -2061,7 +2071,7 @@ void CodeGenFunction::EmitOMPCanonicalLoop(const OMPCanonicalLoop *S) { LValue LCVal = EmitLValue(LoopVarRef); Address LoopVarAddress = LCVal.getAddress(*this); emitCapturedStmtCall(*this, LoopVarClosure, - {LoopVarAddress.getPointer(), IndVar}); + {LoopVarAddress.emitRawPointer(*this), IndVar}); RunCleanupsScope BodyScope(*this); EmitStmt(BodyStmt); @@ -4795,7 +4805,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( ParamTypes.push_back(PrivatesPtr->getType()); for (const Expr *E : Data.PrivateVars) { const auto *VD = cast(cast(E)->getDecl()); - Address PrivatePtr = CGF.CreateMemTemp( + RawAddress PrivatePtr = CGF.CreateMemTemp( CGF.getContext().getPointerType(E->getType()), ".priv.ptr.addr"); PrivatePtrs.emplace_back(VD, PrivatePtr); CallArgs.push_back(PrivatePtr.getPointer()); @@ -4803,7 +4813,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( } for (const Expr *E : Data.FirstprivateVars) { const auto *VD = cast(cast(E)->getDecl()); - Address PrivatePtr = + RawAddress PrivatePtr = CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()), ".firstpriv.ptr.addr"); PrivatePtrs.emplace_back(VD, PrivatePtr); @@ -4813,7 +4823,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( } for (const Expr *E : Data.LastprivateVars) { const auto *VD = cast(cast(E)->getDecl()); - Address PrivatePtr = + RawAddress PrivatePtr = CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()), ".lastpriv.ptr.addr"); PrivatePtrs.emplace_back(VD, PrivatePtr); @@ -4826,7 +4836,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( Ty = CGF.getContext().getPointerType(Ty); if (isAllocatableDecl(VD)) Ty = CGF.getContext().getPointerType(Ty); - Address PrivatePtr = CGF.CreateMemTemp( + RawAddress PrivatePtr = CGF.CreateMemTemp( CGF.getContext().getPointerType(Ty), ".local.ptr.addr"); auto Result = UntiedLocalVars.insert( std::make_pair(VD, std::make_pair(PrivatePtr, Address::invalid()))); @@ -4859,7 +4869,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( if (auto *DI = CGF.getDebugInfo()) if (CGF.CGM.getCodeGenOpts().hasReducedDebugInfo()) (void)DI->EmitDeclareOfAutoVariable( - Pair.first, Pair.second.getPointer(), CGF.Builder, + Pair.first, Pair.second.getBasePointer(), CGF.Builder, /*UsePointerValue*/ true); } // Adjust mapping for internal locals by mapping actual memory instead of @@ -4912,14 +4922,14 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( RedCG, Cnt); Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem( CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt)); - Replacement = - Address(CGF.EmitScalarConversion( - Replacement.getPointer(), CGF.getContext().VoidPtrTy, - CGF.getContext().getPointerType( - Data.ReductionCopies[Cnt]->getType()), - Data.ReductionCopies[Cnt]->getExprLoc()), - CGF.ConvertTypeForMem(Data.ReductionCopies[Cnt]->getType()), - Replacement.getAlignment()); + Replacement = Address( + CGF.EmitScalarConversion(Replacement.emitRawPointer(CGF), + CGF.getContext().VoidPtrTy, + CGF.getContext().getPointerType( + Data.ReductionCopies[Cnt]->getType()), + Data.ReductionCopies[Cnt]->getExprLoc()), + CGF.ConvertTypeForMem(Data.ReductionCopies[Cnt]->getType()), + Replacement.getAlignment()); Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement); Scope.addPrivate(RedCG.getBaseDecl(Cnt), Replacement); } @@ -4970,7 +4980,7 @@ void CodeGenFunction::EmitOMPTaskBasedDirective( CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt)); Replacement = Address( CGF.EmitScalarConversion( - Replacement.getPointer(), CGF.getContext().VoidPtrTy, + Replacement.emitRawPointer(CGF), CGF.getContext().VoidPtrTy, CGF.getContext().getPointerType(InRedPrivs[Cnt]->getType()), InRedPrivs[Cnt]->getExprLoc()), CGF.ConvertTypeForMem(InRedPrivs[Cnt]->getType()), @@ -5089,7 +5099,7 @@ void CodeGenFunction::EmitOMPTargetTaskBasedDirective( // If there is no user-defined mapper, the mapper array will be nullptr. In // this case, we don't need to privatize it. if (!isa_and_nonnull( - InputInfo.MappersArray.getPointer())) { + InputInfo.MappersArray.emitRawPointer(*this))) { MVD = createImplicitFirstprivateForType( getContext(), Data, BaseAndPointerAndMapperType, CD, S.getBeginLoc()); TargetScope.addPrivate(MVD, InputInfo.MappersArray); @@ -5115,7 +5125,7 @@ void CodeGenFunction::EmitOMPTargetTaskBasedDirective( ParamTypes.push_back(PrivatesPtr->getType()); for (const Expr *E : Data.FirstprivateVars) { const auto *VD = cast(cast(E)->getDecl()); - Address PrivatePtr = + RawAddress PrivatePtr = CGF.CreateMemTemp(CGF.getContext().getPointerType(E->getType()), ".firstpriv.ptr.addr"); PrivatePtrs.emplace_back(VD, PrivatePtr); @@ -5194,14 +5204,14 @@ void CodeGenFunction::processInReduction(const OMPExecutableDirective &S, RedCG, Cnt); Address Replacement = CGF.CGM.getOpenMPRuntime().getTaskReductionItem( CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt)); - Replacement = - Address(CGF.EmitScalarConversion( - Replacement.getPointer(), CGF.getContext().VoidPtrTy, - CGF.getContext().getPointerType( - Data.ReductionCopies[Cnt]->getType()), - Data.ReductionCopies[Cnt]->getExprLoc()), - CGF.ConvertTypeForMem(Data.ReductionCopies[Cnt]->getType()), - Replacement.getAlignment()); + Replacement = Address( + CGF.EmitScalarConversion(Replacement.emitRawPointer(CGF), + CGF.getContext().VoidPtrTy, + CGF.getContext().getPointerType( + Data.ReductionCopies[Cnt]->getType()), + Data.ReductionCopies[Cnt]->getExprLoc()), + CGF.ConvertTypeForMem(Data.ReductionCopies[Cnt]->getType()), + Replacement.getAlignment()); Replacement = RedCG.adjustPrivateAddress(CGF, Cnt, Replacement); Scope.addPrivate(RedCG.getBaseDecl(Cnt), Replacement); } @@ -5247,7 +5257,7 @@ void CodeGenFunction::processInReduction(const OMPExecutableDirective &S, CGF, S.getBeginLoc(), ReductionsPtr, RedCG.getSharedLValue(Cnt)); Replacement = Address( CGF.EmitScalarConversion( - Replacement.getPointer(), CGF.getContext().VoidPtrTy, + Replacement.emitRawPointer(CGF), CGF.getContext().VoidPtrTy, CGF.getContext().getPointerType(InRedPrivs[Cnt]->getType()), InRedPrivs[Cnt]->getExprLoc()), CGF.ConvertTypeForMem(InRedPrivs[Cnt]->getType()), @@ -5394,7 +5404,7 @@ void CodeGenFunction::EmitOMPDepobjDirective(const OMPDepobjDirective &S) { Dependencies.DepExprs.append(DC->varlist_begin(), DC->varlist_end()); Address DepAddr = CGM.getOpenMPRuntime().emitDepobjDependClause( *this, Dependencies, DC->getBeginLoc()); - EmitStoreOfScalar(DepAddr.getPointer(), DOLVal); + EmitStoreOfScalar(DepAddr.emitRawPointer(*this), DOLVal); return; } if (const auto *DC = S.getSingleClause()) { @@ -6471,21 +6481,21 @@ static void emitOMPAtomicCompareExpr( D->getType()->hasSignedIntegerRepresentation()); llvm::OpenMPIRBuilder::AtomicOpValue XOpVal{ - XAddr.getPointer(), XAddr.getElementType(), + XAddr.emitRawPointer(CGF), XAddr.getElementType(), X->getType()->hasSignedIntegerRepresentation(), X->getType().isVolatileQualified()}; llvm::OpenMPIRBuilder::AtomicOpValue VOpVal, ROpVal; if (V) { LValue LV = CGF.EmitLValue(V); Address Addr = LV.getAddress(CGF); - VOpVal = {Addr.getPointer(), Addr.getElementType(), + VOpVal = {Addr.emitRawPointer(CGF), Addr.getElementType(), V->getType()->hasSignedIntegerRepresentation(), V->getType().isVolatileQualified()}; } if (R) { LValue LV = CGF.EmitLValue(R); Address Addr = LV.getAddress(CGF); - ROpVal = {Addr.getPointer(), Addr.getElementType(), + ROpVal = {Addr.emitRawPointer(CGF), Addr.getElementType(), R->getType()->hasSignedIntegerRepresentation(), R->getType().isVolatileQualified()}; } @@ -7029,7 +7039,7 @@ void CodeGenFunction::EmitOMPInteropDirective(const OMPInteropDirective &S) { std::tie(NumDependences, DependenciesArray) = CGM.getOpenMPRuntime().emitDependClause(*this, Data.Dependences, S.getBeginLoc()); - DependenceList = DependenciesArray.getPointer(); + DependenceList = DependenciesArray.emitRawPointer(*this); } Data.HasNowaitClause = S.hasClausesOfKind(); @@ -7925,11 +7935,9 @@ void CodeGenFunction::EmitOMPParallelGenericLoopDirective( void CodeGenFunction::EmitOMPTeamsGenericLoopDirective( const OMPTeamsGenericLoopDirective &S) { // To be consistent with current behavior of 'target teams loop', emit - // 'teams loop' as if its constituent constructs are 'distribute, - // 'parallel, and 'for'. + // 'teams loop' as if its constituent constructs are 'teams' and 'distribute'. auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) { - CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined, - S.getDistInc()); + CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc()); }; // Emit teams region as a standalone region. @@ -7943,15 +7951,33 @@ void CodeGenFunction::EmitOMPTeamsGenericLoopDirective( CodeGenDistribute); CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams); }; - emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for, CodeGen); + emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen); emitPostUpdateForReductionClause(*this, S, [](CodeGenFunction &) { return nullptr; }); } -static void -emitTargetTeamsGenericLoopRegion(CodeGenFunction &CGF, - const OMPTargetTeamsGenericLoopDirective &S, - PrePostActionTy &Action) { +#ifndef NDEBUG +static void emitTargetTeamsLoopCodegenStatus(CodeGenFunction &CGF, + std::string StatusMsg, + const OMPExecutableDirective &D) { + bool IsDevice = CGF.CGM.getLangOpts().OpenMPIsTargetDevice; + if (IsDevice) + StatusMsg += ": DEVICE"; + else + StatusMsg += ": HOST"; + SourceLocation L = D.getBeginLoc(); + auto &SM = CGF.getContext().getSourceManager(); + PresumedLoc PLoc = SM.getPresumedLoc(L); + const char *FileName = PLoc.isValid() ? PLoc.getFilename() : nullptr; + unsigned LineNo = + PLoc.isValid() ? PLoc.getLine() : SM.getExpansionLineNumber(L); + llvm::dbgs() << StatusMsg << ": " << FileName << ": " << LineNo << "\n"; +} +#endif + +static void emitTargetTeamsGenericLoopRegionAsParallel( + CodeGenFunction &CGF, PrePostActionTy &Action, + const OMPTargetTeamsGenericLoopDirective &S) { Action.Enter(CGF); // Emit 'teams loop' as if its constituent constructs are 'distribute, // 'parallel, and 'for'. @@ -7971,19 +7997,50 @@ emitTargetTeamsGenericLoopRegion(CodeGenFunction &CGF, CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false); CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams); }; - + DEBUG_WITH_TYPE(TTL_CODEGEN_TYPE, + emitTargetTeamsLoopCodegenStatus( + CGF, TTL_CODEGEN_TYPE " as parallel for", S)); emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_parallel_for, CodeGenTeams); emitPostUpdateForReductionClause(CGF, S, [](CodeGenFunction &) { return nullptr; }); } -/// Emit combined directive 'target teams loop' as if its constituent -/// constructs are 'target', 'teams', 'distribute', 'parallel', and 'for'. +static void emitTargetTeamsGenericLoopRegionAsDistribute( + CodeGenFunction &CGF, PrePostActionTy &Action, + const OMPTargetTeamsGenericLoopDirective &S) { + Action.Enter(CGF); + // Emit 'teams loop' as if its constituent construct is 'distribute'. + auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) { + CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc()); + }; + + // Emit teams region as a standalone region. + auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF, + PrePostActionTy &Action) { + Action.Enter(CGF); + CodeGenFunction::OMPPrivateScope PrivateScope(CGF); + CGF.EmitOMPReductionClauseInit(S, PrivateScope); + (void)PrivateScope.Privatize(); + CGF.CGM.getOpenMPRuntime().emitInlinedDirective( + CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false); + CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams); + }; + DEBUG_WITH_TYPE(TTL_CODEGEN_TYPE, + emitTargetTeamsLoopCodegenStatus( + CGF, TTL_CODEGEN_TYPE " as distribute", S)); + emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute, CodeGen); + emitPostUpdateForReductionClause(CGF, S, + [](CodeGenFunction &) { return nullptr; }); +} + void CodeGenFunction::EmitOMPTargetTeamsGenericLoopDirective( const OMPTargetTeamsGenericLoopDirective &S) { auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { - emitTargetTeamsGenericLoopRegion(CGF, S, Action); + if (S.canBeParallelFor()) + emitTargetTeamsGenericLoopRegionAsParallel(CGF, Action, S); + else + emitTargetTeamsGenericLoopRegionAsDistribute(CGF, Action, S); }; emitCommonOMPTargetDirective(*this, S, CodeGen); } @@ -7993,7 +8050,10 @@ void CodeGenFunction::EmitOMPTargetTeamsGenericLoopDeviceFunction( const OMPTargetTeamsGenericLoopDirective &S) { // Emit SPMD target parallel loop region as a standalone region. auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) { - emitTargetTeamsGenericLoopRegion(CGF, S, Action); + if (S.canBeParallelFor()) + emitTargetTeamsGenericLoopRegionAsParallel(CGF, Action, S); + else + emitTargetTeamsGenericLoopRegionAsDistribute(CGF, Action, S); }; llvm::Function *Fn; llvm::Constant *Addr; diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 8dee3f74b44b4e66edfc8b2ffd1c41514671496b..862369ae009f4808c73cc0b32cd11101261fd4ba 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -201,14 +201,13 @@ CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn, // Find the first store of "this", which will be to the alloca associated // with "this". - Address ThisPtr = - Address(&*AI, ConvertTypeForMem(MD->getFunctionObjectParameterType()), - CGM.getClassPointerAlignment(MD->getParent())); + Address ThisPtr = makeNaturalAddressForPointer( + &*AI, MD->getFunctionObjectParameterType(), + CGM.getClassPointerAlignment(MD->getParent())); llvm::BasicBlock *EntryBB = &Fn->front(); llvm::BasicBlock::iterator ThisStore = llvm::find_if(*EntryBB, [&](llvm::Instruction &I) { - return isa(I) && - I.getOperand(0) == ThisPtr.getPointer(); + return isa(I) && I.getOperand(0) == &*AI; }); assert(ThisStore != EntryBB->end() && "Store of this should be in entry block?"); diff --git a/clang/lib/CodeGen/CGValue.h b/clang/lib/CodeGen/CGValue.h index 1e6f67250583d66fda9c2552d61ce1e9ea629695..cc9ad10ae5969df3c30eac0f9db5234349af9ae6 100644 --- a/clang/lib/CodeGen/CGValue.h +++ b/clang/lib/CodeGen/CGValue.h @@ -14,12 +14,13 @@ #ifndef LLVM_CLANG_LIB_CODEGEN_CGVALUE_H #define LLVM_CLANG_LIB_CODEGEN_CGVALUE_H +#include "Address.h" +#include "CodeGenTBAA.h" +#include "EHScopeStack.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Type.h" -#include "llvm/IR/Value.h" #include "llvm/IR/Type.h" -#include "Address.h" -#include "CodeGenTBAA.h" +#include "llvm/IR/Value.h" namespace llvm { class Constant; @@ -28,57 +29,64 @@ namespace llvm { namespace clang { namespace CodeGen { - class AggValueSlot; - class CodeGenFunction; - struct CGBitFieldInfo; +class AggValueSlot; +class CGBuilderTy; +class CodeGenFunction; +struct CGBitFieldInfo; /// RValue - This trivial value class is used to represent the result of an /// expression that is evaluated. It can be one of three things: either a /// simple LLVM SSA value, a pair of SSA values for complex numbers, or the /// address of an aggregate value in memory. class RValue { - enum Flavor { Scalar, Complex, Aggregate }; + friend struct DominatingValue; - // The shift to make to an aggregate's alignment to make it look - // like a pointer. - enum { AggAlignShift = 4 }; + enum FlavorEnum { Scalar, Complex, Aggregate }; - // Stores first value and flavor. - llvm::PointerIntPair V1; - // Stores second value and volatility. - llvm::PointerIntPair V2; - // Stores element type for aggregate values. - llvm::Type *ElementType; + union { + // Stores first and second value. + struct { + llvm::Value *first; + llvm::Value *second; + } Vals; + + // Stores aggregate address. + Address AggregateAddr; + }; + + unsigned IsVolatile : 1; + unsigned Flavor : 2; public: - bool isScalar() const { return V1.getInt() == Scalar; } - bool isComplex() const { return V1.getInt() == Complex; } - bool isAggregate() const { return V1.getInt() == Aggregate; } + RValue() : Vals{nullptr, nullptr}, Flavor(Scalar) {} + + bool isScalar() const { return Flavor == Scalar; } + bool isComplex() const { return Flavor == Complex; } + bool isAggregate() const { return Flavor == Aggregate; } - bool isVolatileQualified() const { return V2.getInt(); } + bool isVolatileQualified() const { return IsVolatile; } /// getScalarVal() - Return the Value* of this scalar value. llvm::Value *getScalarVal() const { assert(isScalar() && "Not a scalar!"); - return V1.getPointer(); + return Vals.first; } /// getComplexVal - Return the real/imag components of this complex value. /// std::pair getComplexVal() const { - return std::make_pair(V1.getPointer(), V2.getPointer()); + return std::make_pair(Vals.first, Vals.second); } /// getAggregateAddr() - Return the Value* of the address of the aggregate. Address getAggregateAddress() const { assert(isAggregate() && "Not an aggregate!"); - auto align = reinterpret_cast(V2.getPointer()) >> AggAlignShift; - return Address( - V1.getPointer(), ElementType, CharUnits::fromQuantity(align)); + return AggregateAddr; } - llvm::Value *getAggregatePointer() const { - assert(isAggregate() && "Not an aggregate!"); - return V1.getPointer(); + + llvm::Value *getAggregatePointer(QualType PointeeType, + CodeGenFunction &CGF) const { + return getAggregateAddress().getBasePointer(); } static RValue getIgnored() { @@ -88,17 +96,19 @@ public: static RValue get(llvm::Value *V) { RValue ER; - ER.V1.setPointer(V); - ER.V1.setInt(Scalar); - ER.V2.setInt(false); + ER.Vals.first = V; + ER.Flavor = Scalar; + ER.IsVolatile = false; return ER; } + static RValue get(Address Addr, CodeGenFunction &CGF) { + return RValue::get(Addr.emitRawPointer(CGF)); + } static RValue getComplex(llvm::Value *V1, llvm::Value *V2) { RValue ER; - ER.V1.setPointer(V1); - ER.V2.setPointer(V2); - ER.V1.setInt(Complex); - ER.V2.setInt(false); + ER.Vals = {V1, V2}; + ER.Flavor = Complex; + ER.IsVolatile = false; return ER; } static RValue getComplex(const std::pair &C) { @@ -107,15 +117,15 @@ public: // FIXME: Aggregate rvalues need to retain information about whether they are // volatile or not. Remove default to find all places that probably get this // wrong. + + /// Convert an Address to an RValue. If the Address is not + /// signed, create an RValue using the unsigned address. Otherwise, resign the + /// address using the provided type. static RValue getAggregate(Address addr, bool isVolatile = false) { RValue ER; - ER.V1.setPointer(addr.getPointer()); - ER.V1.setInt(Aggregate); - ER.ElementType = addr.getElementType(); - - auto align = static_cast(addr.getAlignment().getQuantity()); - ER.V2.setPointer(reinterpret_cast(align << AggAlignShift)); - ER.V2.setInt(isVolatile); + ER.AggregateAddr = addr; + ER.Flavor = Aggregate; + ER.IsVolatile = isVolatile; return ER; } }; @@ -178,8 +188,10 @@ class LValue { MatrixElt // This is a matrix element, use getVector* } LVType; - llvm::Value *V; - llvm::Type *ElementType; + union { + Address Addr = Address::invalid(); + llvm::Value *V; + }; union { // Index into a vector subscript: V[i] @@ -197,10 +209,6 @@ class LValue { // 'const' is unused here Qualifiers Quals; - // The alignment to use when accessing this lvalue. (For vector elements, - // this is the alignment of the whole vector.) - unsigned Alignment; - // objective-c's ivar bool Ivar:1; @@ -234,23 +242,19 @@ class LValue { Expr *BaseIvarExp; private: - void Initialize(QualType Type, Qualifiers Quals, CharUnits Alignment, + void Initialize(QualType Type, Qualifiers Quals, Address Addr, LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo) { - assert((!Alignment.isZero() || Type->isIncompleteType()) && - "initializing l-value with zero alignment!"); - if (isGlobalReg()) - assert(ElementType == nullptr && "Global reg does not store elem type"); - else - assert(ElementType != nullptr && "Must have elem type"); - this->Type = Type; this->Quals = Quals; const unsigned MaxAlign = 1U << 31; - this->Alignment = Alignment.getQuantity() <= MaxAlign - ? Alignment.getQuantity() - : MaxAlign; - assert(this->Alignment == Alignment.getQuantity() && - "Alignment exceeds allowed max!"); + CharUnits Alignment = Addr.getAlignment(); + assert((isGlobalReg() || !Alignment.isZero() || Type->isIncompleteType()) && + "initializing l-value with zero alignment!"); + if (Alignment.getQuantity() > MaxAlign) { + assert(false && "Alignment exceeds allowed max!"); + Alignment = CharUnits::fromQuantity(MaxAlign); + } + this->Addr = Addr; this->BaseInfo = BaseInfo; this->TBAAInfo = TBAAInfo; @@ -259,9 +263,20 @@ private: this->ImpreciseLifetime = false; this->Nontemporal = false; this->ThreadLocalRef = false; + this->IsKnownNonNull = false; this->BaseIvarExp = nullptr; } + void initializeSimpleLValue(Address Addr, QualType Type, + LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo, + ASTContext &Context) { + Qualifiers QS = Type.getQualifiers(); + QS.setObjCGCAttr(Context.getObjCGCAttrKind(Type)); + LVType = Simple; + Initialize(Type, QS, Addr, BaseInfo, TBAAInfo); + assert(Addr.getBasePointer()->getType()->isPointerTy()); + } + public: bool isSimple() const { return LVType == Simple; } bool isVectorElt() const { return LVType == VectorElt; } @@ -328,8 +343,8 @@ public: LangAS getAddressSpace() const { return Quals.getAddressSpace(); } - CharUnits getAlignment() const { return CharUnits::fromQuantity(Alignment); } - void setAlignment(CharUnits A) { Alignment = A.getQuantity(); } + CharUnits getAlignment() const { return Addr.getAlignment(); } + void setAlignment(CharUnits A) { Addr.setAlignment(A); } LValueBaseInfo getBaseInfo() const { return BaseInfo; } void setBaseInfo(LValueBaseInfo Info) { BaseInfo = Info; } @@ -345,28 +360,32 @@ public: // simple lvalue llvm::Value *getPointer(CodeGenFunction &CGF) const { assert(isSimple()); - return V; + return Addr.getBasePointer(); } - Address getAddress(CodeGenFunction &CGF) const { - return Address(getPointer(CGF), ElementType, getAlignment(), - isKnownNonNull()); - } - void setAddress(Address address) { + llvm::Value *emitRawPointer(CodeGenFunction &CGF) const { assert(isSimple()); - V = address.getPointer(); - ElementType = address.getElementType(); - Alignment = address.getAlignment().getQuantity(); - IsKnownNonNull = address.isKnownNonNull(); + return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr; } + Address getAddress(CodeGenFunction &CGF) const { + // FIXME: remove parameter. + return Addr; + } + + void setAddress(Address address) { Addr = address; } + // vector elt lvalue Address getVectorAddress() const { - return Address(getVectorPointer(), ElementType, getAlignment(), - (KnownNonNull_t)isKnownNonNull()); + assert(isVectorElt()); + return Addr; + } + llvm::Value *getRawVectorPointer(CodeGenFunction &CGF) const { + assert(isVectorElt()); + return Addr.emitRawPointer(CGF); } llvm::Value *getVectorPointer() const { assert(isVectorElt()); - return V; + return Addr.getBasePointer(); } llvm::Value *getVectorIdx() const { assert(isVectorElt()); @@ -374,12 +393,12 @@ public: } Address getMatrixAddress() const { - return Address(getMatrixPointer(), ElementType, getAlignment(), - (KnownNonNull_t)isKnownNonNull()); + assert(isMatrixElt()); + return Addr; } llvm::Value *getMatrixPointer() const { assert(isMatrixElt()); - return V; + return Addr.getBasePointer(); } llvm::Value *getMatrixIdx() const { assert(isMatrixElt()); @@ -388,12 +407,12 @@ public: // extended vector elements. Address getExtVectorAddress() const { - return Address(getExtVectorPointer(), ElementType, getAlignment(), - (KnownNonNull_t)isKnownNonNull()); + assert(isExtVectorElt()); + return Addr; } - llvm::Value *getExtVectorPointer() const { + llvm::Value *getRawExtVectorPointer(CodeGenFunction &CGF) const { assert(isExtVectorElt()); - return V; + return Addr.emitRawPointer(CGF); } llvm::Constant *getExtVectorElts() const { assert(isExtVectorElt()); @@ -402,10 +421,14 @@ public: // bitfield lvalue Address getBitFieldAddress() const { - return Address(getBitFieldPointer(), ElementType, getAlignment(), - (KnownNonNull_t)isKnownNonNull()); + assert(isBitField()); + return Addr; + } + llvm::Value *getRawBitFieldPointer(CodeGenFunction &CGF) const { + assert(isBitField()); + return Addr.emitRawPointer(CGF); } - llvm::Value *getBitFieldPointer() const { assert(isBitField()); return V; } + const CGBitFieldInfo &getBitFieldInfo() const { assert(isBitField()); return *BitFieldInfo; @@ -414,18 +437,13 @@ public: // global register lvalue llvm::Value *getGlobalReg() const { assert(isGlobalReg()); return V; } - static LValue MakeAddr(Address address, QualType type, ASTContext &Context, + static LValue MakeAddr(Address Addr, QualType type, ASTContext &Context, LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo) { - Qualifiers qs = type.getQualifiers(); - qs.setObjCGCAttr(Context.getObjCGCAttrKind(type)); - LValue R; R.LVType = Simple; - assert(address.getPointer()->getType()->isPointerTy()); - R.V = address.getPointer(); - R.ElementType = address.getElementType(); - R.IsKnownNonNull = address.isKnownNonNull(); - R.Initialize(type, qs, address.getAlignment(), BaseInfo, TBAAInfo); + R.initializeSimpleLValue(Addr, type, BaseInfo, TBAAInfo, Context); + R.Addr = Addr; + assert(Addr.getType()->isPointerTy()); return R; } @@ -434,26 +452,18 @@ public: TBAAAccessInfo TBAAInfo) { LValue R; R.LVType = VectorElt; - R.V = vecAddress.getPointer(); - R.ElementType = vecAddress.getElementType(); R.VectorIdx = Idx; - R.IsKnownNonNull = vecAddress.isKnownNonNull(); - R.Initialize(type, type.getQualifiers(), vecAddress.getAlignment(), - BaseInfo, TBAAInfo); + R.Initialize(type, type.getQualifiers(), vecAddress, BaseInfo, TBAAInfo); return R; } - static LValue MakeExtVectorElt(Address vecAddress, llvm::Constant *Elts, + static LValue MakeExtVectorElt(Address Addr, llvm::Constant *Elts, QualType type, LValueBaseInfo BaseInfo, TBAAAccessInfo TBAAInfo) { LValue R; R.LVType = ExtVectorElt; - R.V = vecAddress.getPointer(); - R.ElementType = vecAddress.getElementType(); R.VectorElts = Elts; - R.IsKnownNonNull = vecAddress.isKnownNonNull(); - R.Initialize(type, type.getQualifiers(), vecAddress.getAlignment(), - BaseInfo, TBAAInfo); + R.Initialize(type, type.getQualifiers(), Addr, BaseInfo, TBAAInfo); return R; } @@ -468,12 +478,8 @@ public: TBAAAccessInfo TBAAInfo) { LValue R; R.LVType = BitField; - R.V = Addr.getPointer(); - R.ElementType = Addr.getElementType(); R.BitFieldInfo = &Info; - R.IsKnownNonNull = Addr.isKnownNonNull(); - R.Initialize(type, type.getQualifiers(), Addr.getAlignment(), BaseInfo, - TBAAInfo); + R.Initialize(type, type.getQualifiers(), Addr, BaseInfo, TBAAInfo); return R; } @@ -481,11 +487,9 @@ public: QualType type) { LValue R; R.LVType = GlobalReg; - R.V = V; - R.ElementType = nullptr; - R.IsKnownNonNull = true; - R.Initialize(type, type.getQualifiers(), alignment, + R.Initialize(type, type.getQualifiers(), Address::invalid(), LValueBaseInfo(AlignmentSource::Decl), TBAAAccessInfo()); + R.V = V; return R; } @@ -494,12 +498,8 @@ public: TBAAAccessInfo TBAAInfo) { LValue R; R.LVType = MatrixElt; - R.V = matAddress.getPointer(); - R.ElementType = matAddress.getElementType(); R.VectorIdx = Idx; - R.IsKnownNonNull = matAddress.isKnownNonNull(); - R.Initialize(type, type.getQualifiers(), matAddress.getAlignment(), - BaseInfo, TBAAInfo); + R.Initialize(type, type.getQualifiers(), matAddress, BaseInfo, TBAAInfo); return R; } @@ -643,17 +643,17 @@ public: return NeedsGCBarriers_t(ObjCGCFlag); } - llvm::Value *getPointer() const { - return Addr.getPointer(); + llvm::Value *getPointer(QualType PointeeTy, CodeGenFunction &CGF) const; + + llvm::Value *emitRawPointer(CodeGenFunction &CGF) const { + return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr; } Address getAddress() const { return Addr; } - bool isIgnored() const { - return !Addr.isValid(); - } + bool isIgnored() const { return !Addr.isValid(); } CharUnits getAlignment() const { return Addr.getAlignment(); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index fad26c43da3d348b7ea2970bba1377d24c29d107..87766a758311d5f0e2b50e5a8dc8b58535735a30 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -91,6 +91,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext) CodeGenFunction::~CodeGenFunction() { assert(LifetimeExtendedCleanupStack.empty() && "failed to emit a cleanup"); + assert(DeferredDeactivationCleanupStack.empty() && + "missed to deactivate a cleanup"); if (getLangOpts().OpenMP && CurFn) CGM.getOpenMPRuntime().functionFinished(*this); @@ -193,26 +195,35 @@ CodeGenFunction::CGFPOptionsRAII::~CGFPOptionsRAII() { CGF.Builder.setDefaultConstrainedRounding(OldRounding); } -LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) { +static LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T, + bool ForPointeeType, + CodeGenFunction &CGF) { LValueBaseInfo BaseInfo; TBAAAccessInfo TBAAInfo; - CharUnits Alignment = CGM.getNaturalTypeAlignment(T, &BaseInfo, &TBAAInfo); - Address Addr(V, ConvertTypeForMem(T), Alignment); - return LValue::MakeAddr(Addr, T, getContext(), BaseInfo, TBAAInfo); + CharUnits Alignment = + CGF.CGM.getNaturalTypeAlignment(T, &BaseInfo, &TBAAInfo, ForPointeeType); + Address Addr = Address(V, CGF.ConvertTypeForMem(T), Alignment); + return CGF.MakeAddrLValue(Addr, T, BaseInfo, TBAAInfo); +} + +LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) { + return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ false, *this); } -/// Given a value of type T* that may not be to a complete object, -/// construct an l-value with the natural pointee alignment of T. LValue CodeGenFunction::MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T) { - LValueBaseInfo BaseInfo; - TBAAAccessInfo TBAAInfo; - CharUnits Align = CGM.getNaturalTypeAlignment(T, &BaseInfo, &TBAAInfo, - /* forPointeeType= */ true); - Address Addr(V, ConvertTypeForMem(T), Align); - return MakeAddrLValue(Addr, T, BaseInfo, TBAAInfo); + return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ true, *this); +} + +LValue CodeGenFunction::MakeNaturalAlignRawAddrLValue(llvm::Value *V, + QualType T) { + return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ false, *this); } +LValue CodeGenFunction::MakeNaturalAlignPointeeRawAddrLValue(llvm::Value *V, + QualType T) { + return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ true, *this); +} llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) { return CGM.getTypes().ConvertTypeForMem(T); @@ -267,6 +278,7 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) { case Type::Record: case Type::ObjCObject: case Type::ObjCInterface: + case Type::ArrayParameter: return TEK_Aggregate; // We operate on atomic values according to their underlying type. @@ -336,6 +348,10 @@ static void EmitIfUsed(CodeGenFunction &CGF, llvm::BasicBlock *BB) { void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { assert(BreakContinueStack.empty() && "mismatched push/pop in break/continue stack!"); + assert(LifetimeExtendedCleanupStack.empty() && + "mismatched push/pop of cleanups in EHStack!"); + assert(DeferredDeactivationCleanupStack.empty() && + "mismatched activate/deactivate of cleanups!"); bool OnlySimpleReturnStmts = NumSimpleReturnExprs > 0 && NumSimpleReturnExprs == NumReturnExprs @@ -525,7 +541,8 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) { ReturnBlock.getBlock()->eraseFromParent(); } if (ReturnValue.isValid()) { - auto *RetAlloca = dyn_cast(ReturnValue.getPointer()); + auto *RetAlloca = + dyn_cast(ReturnValue.emitRawPointer(*this)); if (RetAlloca && RetAlloca->use_empty()) { RetAlloca->eraseFromParent(); ReturnValue = Address::invalid(); @@ -811,7 +828,7 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, // .cxx_destruct, __destroy_helper_block_ and all of their calees at run time. if (SanOpts.has(SanitizerKind::Thread)) { if (const auto *OMD = dyn_cast_or_null(D)) { - IdentifierInfo *II = OMD->getSelector().getIdentifierInfoForSlot(0); + const IdentifierInfo *II = OMD->getSelector().getIdentifierInfoForSlot(0); if (OMD->getMethodFamily() == OMF_dealloc || OMD->getMethodFamily() == OMF_initialize || (OMD->getSelector().isUnarySelector() && II->isStr(".cxx_destruct"))) { @@ -979,7 +996,8 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, // return value. Initialize the flag to 'true' and refine it in EmitParmDecl. if (SanOpts.has(SanitizerKind::NullabilityReturn)) { auto Nullability = FnRetTy->getNullability(); - if (Nullability && *Nullability == NullabilityKind::NonNull) { + if (Nullability && *Nullability == NullabilityKind::NonNull && + !FnRetTy->isRecordType()) { if (!(SanOpts.has(SanitizerKind::ReturnsNonnullAttribute) && CurCodeDecl && CurCodeDecl->getAttr())) RetValNullabilityPrecondition = @@ -1122,13 +1140,14 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, auto AI = CurFn->arg_begin(); if (CurFnInfo->getReturnInfo().isSRetAfterThis()) ++AI; - ReturnValue = - Address(&*AI, ConvertType(RetTy), - CurFnInfo->getReturnInfo().getIndirectAlign(), KnownNonNull); + ReturnValue = makeNaturalAddressForPointer( + &*AI, RetTy, CurFnInfo->getReturnInfo().getIndirectAlign(), false, + nullptr, nullptr, KnownNonNull); if (!CurFnInfo->getReturnInfo().getIndirectByVal()) { - ReturnValuePointer = CreateDefaultAlignTempAlloca( - ReturnValue.getPointer()->getType(), "result.ptr"); - Builder.CreateStore(ReturnValue.getPointer(), ReturnValuePointer); + ReturnValuePointer = + CreateDefaultAlignTempAlloca(ReturnValue.getType(), "result.ptr"); + Builder.CreateStore(ReturnValue.emitRawPointer(*this), + ReturnValuePointer); } } else if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::InAlloca && !hasScalarEvaluationKind(CurFnInfo->getReturnType())) { @@ -1189,8 +1208,9 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, // or contains the address of the enclosing object). LValue ThisFieldLValue = EmitLValueForLambdaField(LambdaThisCaptureField); if (!LambdaThisCaptureField->getType()->isPointerType()) { - // If the enclosing object was captured by value, just use its address. - CXXThisValue = ThisFieldLValue.getAddress(*this).getPointer(); + // If the enclosing object was captured by value, just use its + // address. Sign this pointer. + CXXThisValue = ThisFieldLValue.getPointer(*this); } else { // Load the lvalue pointed to by the field, since '*this' was captured // by reference. @@ -2012,8 +2032,9 @@ static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType, = llvm::ConstantInt::get(CGF.IntPtrTy, baseSize.getQuantity()); Address begin = dest.withElementType(CGF.Int8Ty); - llvm::Value *end = Builder.CreateInBoundsGEP( - begin.getElementType(), begin.getPointer(), sizeInChars, "vla.end"); + llvm::Value *end = Builder.CreateInBoundsGEP(begin.getElementType(), + begin.emitRawPointer(CGF), + sizeInChars, "vla.end"); llvm::BasicBlock *originBB = CGF.Builder.GetInsertBlock(); llvm::BasicBlock *loopBB = CGF.createBasicBlock("vla-init.loop"); @@ -2024,7 +2045,7 @@ static void emitNonZeroVLAInit(CodeGenFunction &CGF, QualType baseType, CGF.EmitBlock(loopBB); llvm::PHINode *cur = Builder.CreatePHI(begin.getType(), 2, "vla.cur"); - cur->addIncoming(begin.getPointer(), originBB); + cur->addIncoming(begin.emitRawPointer(CGF), originBB); CharUnits curAlign = dest.getAlignment().alignmentOfArrayElement(baseSize); @@ -2189,8 +2210,8 @@ llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType, dyn_cast(addr.getElementType()); while (llvmArrayType) { assert(isa(arrayType)); - assert(cast(arrayType)->getSize().getZExtValue() - == llvmArrayType->getNumElements()); + assert(cast(arrayType)->getZExtSize() == + llvmArrayType->getNumElements()); gepIndices.push_back(zero); countFromCLAs *= llvmArrayType->getNumElements(); @@ -2208,8 +2229,7 @@ llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType, // as some other type (probably a packed struct). Compute the array // size, and just emit the 'begin' expression as a bitcast. while (arrayType) { - countFromCLAs *= - cast(arrayType)->getSize().getZExtValue(); + countFromCLAs *= cast(arrayType)->getZExtSize(); eltType = arrayType->getElementType(); arrayType = getContext().getAsArrayType(eltType); } @@ -2218,10 +2238,10 @@ llvm::Value *CodeGenFunction::emitArrayLength(const ArrayType *origArrayType, addr = addr.withElementType(baseType); } else { // Create the actual GEP. - addr = Address(Builder.CreateInBoundsGEP( - addr.getElementType(), addr.getPointer(), gepIndices, "array.begin"), - ConvertTypeForMem(eltType), - addr.getAlignment()); + addr = Address(Builder.CreateInBoundsGEP(addr.getElementType(), + addr.emitRawPointer(*this), + gepIndices, "array.begin"), + ConvertTypeForMem(eltType), addr.getAlignment()); } baseType = eltType; @@ -2349,6 +2369,7 @@ void CodeGenFunction::EmitVariablyModifiedType(QualType type) { type = cast(ty)->getPointeeType(); break; + case Type::ArrayParameter: case Type::ConstantArray: case Type::IncompleteArray: // Losing element qualification here is fine. @@ -2562,7 +2583,7 @@ void CodeGenFunction::EmitVarAnnotations(const VarDecl *D, llvm::Value *V) { Address CodeGenFunction::EmitFieldAnnotations(const FieldDecl *D, Address Addr) { assert(D->hasAttr() && "no annotate attribute"); - llvm::Value *V = Addr.getPointer(); + llvm::Value *V = Addr.emitRawPointer(*this); llvm::Type *VTy = V->getType(); auto *PTy = dyn_cast(VTy); unsigned AS = PTy ? PTy->getAddressSpace() : 0; diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index e8f8aa601ed017b559d2b87548110423e5c78107..c49e9fd00c8d3e0f43771f3d700090be9c48cc66 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -39,6 +39,7 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/Debug.h" #include "llvm/Transforms/Utils/SanitizerStats.h" @@ -151,6 +152,9 @@ struct DominatingLLVMValue { /// Answer whether the given value needs extra work to be saved. static bool needsSaving(llvm::Value *value) { + if (!value) + return false; + // If it's not an instruction, we don't need to save. if (!isa(value)) return false; @@ -177,21 +181,28 @@ template <> struct DominatingValue
{ typedef Address type; struct saved_type { - DominatingLLVMValue::saved_type SavedValue; + DominatingLLVMValue::saved_type BasePtr; llvm::Type *ElementType; CharUnits Alignment; + DominatingLLVMValue::saved_type Offset; + llvm::PointerType *EffectiveType; }; static bool needsSaving(type value) { - return DominatingLLVMValue::needsSaving(value.getPointer()); + if (DominatingLLVMValue::needsSaving(value.getBasePointer()) || + DominatingLLVMValue::needsSaving(value.getOffset())) + return true; + return false; } static saved_type save(CodeGenFunction &CGF, type value) { - return { DominatingLLVMValue::save(CGF, value.getPointer()), - value.getElementType(), value.getAlignment() }; + return {DominatingLLVMValue::save(CGF, value.getBasePointer()), + value.getElementType(), value.getAlignment(), + DominatingLLVMValue::save(CGF, value.getOffset()), value.getType()}; } static type restore(CodeGenFunction &CGF, saved_type value) { - return Address(DominatingLLVMValue::restore(CGF, value.SavedValue), - value.ElementType, value.Alignment); + return Address(DominatingLLVMValue::restore(CGF, value.BasePtr), + value.ElementType, value.Alignment, + DominatingLLVMValue::restore(CGF, value.Offset)); } }; @@ -201,14 +212,26 @@ template <> struct DominatingValue { class saved_type { enum Kind { ScalarLiteral, ScalarAddress, AggregateLiteral, AggregateAddress, ComplexAddress }; - - llvm::Value *Value; - llvm::Type *ElementType; + union { + struct { + DominatingLLVMValue::saved_type first, second; + } Vals; + DominatingValue
::saved_type AggregateAddr; + }; LLVM_PREFERRED_TYPE(Kind) unsigned K : 3; - unsigned Align : 29; - saved_type(llvm::Value *v, llvm::Type *e, Kind k, unsigned a = 0) - : Value(v), ElementType(e), K(k), Align(a) {} + unsigned IsVolatile : 1; + + saved_type(DominatingLLVMValue::saved_type Val1, unsigned K) + : Vals{Val1, DominatingLLVMValue::saved_type()}, K(K) {} + + saved_type(DominatingLLVMValue::saved_type Val1, + DominatingLLVMValue::saved_type Val2) + : Vals{Val1, Val2}, K(ComplexAddress) {} + + saved_type(DominatingValue
::saved_type AggregateAddr, + bool IsVolatile, unsigned K) + : AggregateAddr(AggregateAddr), K(K) {} public: static bool needsSaving(RValue value); @@ -648,6 +671,51 @@ public: EHScopeStack EHStack; llvm::SmallVector LifetimeExtendedCleanupStack; + + // A stack of cleanups which were added to EHStack but have to be deactivated + // later before being popped or emitted. These are usually deactivated on + // exiting a `CleanupDeactivationScope` scope. For instance, after a + // full-expr. + // + // These are specially useful for correctly emitting cleanups while + // encountering branches out of expression (through stmt-expr or coroutine + // suspensions). + struct DeferredDeactivateCleanup { + EHScopeStack::stable_iterator Cleanup; + llvm::Instruction *DominatingIP; + }; + llvm::SmallVector DeferredDeactivationCleanupStack; + + // Enters a new scope for capturing cleanups which are deferred to be + // deactivated, all of which will be deactivated once the scope is exited. + struct CleanupDeactivationScope { + CodeGenFunction &CGF; + size_t OldDeactivateCleanupStackSize; + bool Deactivated; + CleanupDeactivationScope(CodeGenFunction &CGF) + : CGF(CGF), OldDeactivateCleanupStackSize( + CGF.DeferredDeactivationCleanupStack.size()), + Deactivated(false) {} + + void ForceDeactivate() { + assert(!Deactivated && "Deactivating already deactivated scope"); + auto &Stack = CGF.DeferredDeactivationCleanupStack; + for (size_t I = Stack.size(); I > OldDeactivateCleanupStackSize; I--) { + CGF.DeactivateCleanupBlock(Stack[I - 1].Cleanup, + Stack[I - 1].DominatingIP); + Stack[I - 1].DominatingIP->eraseFromParent(); + } + Stack.resize(OldDeactivateCleanupStackSize); + Deactivated = true; + } + + ~CleanupDeactivationScope() { + if (Deactivated) + return; + ForceDeactivate(); + } + }; + llvm::SmallVector SEHTryEpilogueStack; llvm::Instruction *CurrentFuncletPad = nullptr; @@ -659,7 +727,7 @@ public: llvm::Value *Size; public: - CallLifetimeEnd(Address addr, llvm::Value *size) + CallLifetimeEnd(RawAddress addr, llvm::Value *size) : Addr(addr.getPointer()), Size(size) {} void Emit(CodeGenFunction &CGF, Flags flags) override { @@ -684,7 +752,7 @@ public: }; /// i32s containing the indexes of the cleanup destinations. - Address NormalCleanupDest = Address::invalid(); + RawAddress NormalCleanupDest = RawAddress::invalid(); unsigned NextCleanupDestIndex = 1; @@ -819,10 +887,10 @@ public: template void pushCleanupAfterFullExpr(CleanupKind Kind, As... A) { if (!isInConditionalBranch()) - return pushCleanupAfterFullExprWithActiveFlag(Kind, Address::invalid(), - A...); + return pushCleanupAfterFullExprWithActiveFlag( + Kind, RawAddress::invalid(), A...); - Address ActiveFlag = createCleanupActiveFlag(); + RawAddress ActiveFlag = createCleanupActiveFlag(); assert(!DominatingValue
::needsSaving(ActiveFlag) && "cleanup active flag should never need saving"); @@ -835,7 +903,7 @@ public: template void pushCleanupAfterFullExprWithActiveFlag(CleanupKind Kind, - Address ActiveFlag, As... A) { + RawAddress ActiveFlag, As... A) { LifetimeExtendedCleanupHeader Header = {sizeof(T), Kind, ActiveFlag.isValid()}; @@ -850,7 +918,20 @@ public: new (Buffer) LifetimeExtendedCleanupHeader(Header); new (Buffer + sizeof(Header)) T(A...); if (Header.IsConditional) - new (Buffer + sizeof(Header) + sizeof(T)) Address(ActiveFlag); + new (Buffer + sizeof(Header) + sizeof(T)) RawAddress(ActiveFlag); + } + + // Push a cleanup onto EHStack and deactivate it later. It is usually + // deactivated when exiting a `CleanupDeactivationScope` (for example: after a + // full expression). + template + void pushCleanupAndDeferDeactivation(CleanupKind Kind, As... A) { + // Placeholder dominating IP for this cleanup. + llvm::Instruction *DominatingIP = + Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy)); + EHStack.pushCleanup(Kind, A...); + DeferredDeactivationCleanupStack.push_back( + {EHStack.stable_begin(), DominatingIP}); } /// Set up the last cleanup that was pushed as a conditional @@ -859,8 +940,8 @@ public: initFullExprCleanupWithFlag(createCleanupActiveFlag()); } - void initFullExprCleanupWithFlag(Address ActiveFlag); - Address createCleanupActiveFlag(); + void initFullExprCleanupWithFlag(RawAddress ActiveFlag); + RawAddress createCleanupActiveFlag(); /// PushDestructorCleanup - Push a cleanup to call the /// complete-object destructor of an object of the given type at the @@ -904,6 +985,7 @@ public: class RunCleanupsScope { EHScopeStack::stable_iterator CleanupStackDepth, OldCleanupScopeDepth; size_t LifetimeExtendedCleanupStackSize; + CleanupDeactivationScope DeactivateCleanups; bool OldDidCallStackSave; protected: bool PerformCleanup; @@ -918,8 +1000,7 @@ public: public: /// Enter a new cleanup scope. explicit RunCleanupsScope(CodeGenFunction &CGF) - : PerformCleanup(true), CGF(CGF) - { + : DeactivateCleanups(CGF), PerformCleanup(true), CGF(CGF) { CleanupStackDepth = CGF.EHStack.stable_begin(); LifetimeExtendedCleanupStackSize = CGF.LifetimeExtendedCleanupStack.size(); @@ -949,6 +1030,7 @@ public: void ForceCleanup(std::initializer_list ValuesToReload = {}) { assert(PerformCleanup && "Already forced cleanup"); CGF.DidCallStackSave = OldDidCallStackSave; + DeactivateCleanups.ForceDeactivate(); CGF.PopCleanupBlocks(CleanupStackDepth, LifetimeExtendedCleanupStackSize, ValuesToReload); PerformCleanup = false; @@ -1048,7 +1130,7 @@ public: QualType VarTy = LocalVD->getType(); if (VarTy->isReferenceType()) { Address Temp = CGF.CreateMemTemp(VarTy); - CGF.Builder.CreateStore(TempAddr.getPointer(), Temp); + CGF.Builder.CreateStore(TempAddr.emitRawPointer(CGF), Temp); TempAddr = Temp; } SavedTempAddresses.try_emplace(LocalVD, TempAddr); @@ -1243,10 +1325,12 @@ public: /// one branch or the other of a conditional expression. bool isInConditionalBranch() const { return OutermostConditional != nullptr; } - void setBeforeOutermostConditional(llvm::Value *value, Address addr) { + void setBeforeOutermostConditional(llvm::Value *value, Address addr, + CodeGenFunction &CGF) { assert(isInConditionalBranch()); llvm::BasicBlock *block = OutermostConditional->getStartingBlock(); - auto store = new llvm::StoreInst(value, addr.getPointer(), &block->back()); + auto store = + new llvm::StoreInst(value, addr.emitRawPointer(CGF), &block->back()); store->setAlignment(addr.getAlignment().getAsAlign()); } @@ -1601,7 +1685,7 @@ public: /// If \p StepV is null, the default increment is 1. void maybeUpdateMCDCTestVectorBitmap(const Expr *E) { if (isMCDCCoverageEnabled() && isBinaryLogicalOp(E)) { - PGO.emitMCDCTestVectorBitmapUpdate(Builder, E, MCDCCondBitmapAddr); + PGO.emitMCDCTestVectorBitmapUpdate(Builder, E, MCDCCondBitmapAddr, *this); PGO.setCurrentStmt(E); } } @@ -1609,7 +1693,7 @@ public: /// Update the MCDC temp value with the condition's evaluated result. void maybeUpdateMCDCCondBitmap(const Expr *E, llvm::Value *Val) { if (isMCDCCoverageEnabled()) { - PGO.emitMCDCCondBitmapUpdate(Builder, E, MCDCCondBitmapAddr, Val); + PGO.emitMCDCCondBitmapUpdate(Builder, E, MCDCCondBitmapAddr, Val, *this); PGO.setCurrentStmt(E); } } @@ -1704,7 +1788,7 @@ public: : CGF(CGF), OldCXXThisValue(CGF.CXXThisValue), OldCXXThisAlignment(CGF.CXXThisAlignment), SourceLocScope(E, CGF.CurSourceLocExprScope) { - CGF.CXXThisValue = CGF.CXXDefaultInitExprThis.getPointer(); + CGF.CXXThisValue = CGF.CXXDefaultInitExprThis.getBasePointer(); CGF.CXXThisAlignment = CGF.CXXDefaultInitExprThis.getAlignment(); } ~CXXDefaultInitExprScope() { @@ -2090,7 +2174,7 @@ public: llvm::Value *getExceptionFromSlot(); llvm::Value *getSelectorFromSlot(); - Address getNormalCleanupDestSlot(); + RawAddress getNormalCleanupDestSlot(); llvm::BasicBlock *getUnreachableBlock() { if (!UnreachableBlock) { @@ -2136,6 +2220,11 @@ public: Address addr, QualType type); void pushDestroy(CleanupKind kind, Address addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray); + void pushDestroyAndDeferDeactivation(QualType::DestructionKind dtorKind, + Address addr, QualType type); + void pushDestroyAndDeferDeactivation(CleanupKind cleanupKind, Address addr, + QualType type, Destroyer *destroyer, + bool useEHCleanupForArray); void pushLifetimeExtendedDestroy(CleanupKind kind, Address addr, QualType type, Destroyer *destroyer, bool useEHCleanupForArray); @@ -2579,10 +2668,40 @@ public: // Helpers //===--------------------------------------------------------------------===// + Address mergeAddressesInConditionalExpr(Address LHS, Address RHS, + llvm::BasicBlock *LHSBlock, + llvm::BasicBlock *RHSBlock, + llvm::BasicBlock *MergeBlock, + QualType MergedType) { + Builder.SetInsertPoint(MergeBlock); + llvm::PHINode *PtrPhi = Builder.CreatePHI(LHS.getType(), 2, "cond"); + PtrPhi->addIncoming(LHS.getBasePointer(), LHSBlock); + PtrPhi->addIncoming(RHS.getBasePointer(), RHSBlock); + LHS.replaceBasePointer(PtrPhi); + LHS.setAlignment(std::min(LHS.getAlignment(), RHS.getAlignment())); + return LHS; + } + + /// Construct an address with the natural alignment of T. If a pointer to T + /// is expected to be signed, the pointer passed to this function must have + /// been signed, and the returned Address will have the pointer authentication + /// information needed to authenticate the signed pointer. + Address makeNaturalAddressForPointer( + llvm::Value *Ptr, QualType T, CharUnits Alignment = CharUnits::Zero(), + bool ForPointeeType = false, LValueBaseInfo *BaseInfo = nullptr, + TBAAAccessInfo *TBAAInfo = nullptr, + KnownNonNull_t IsKnownNonNull = NotKnownNonNull) { + if (Alignment.isZero()) + Alignment = + CGM.getNaturalTypeAlignment(T, BaseInfo, TBAAInfo, ForPointeeType); + return Address(Ptr, ConvertTypeForMem(T), Alignment, nullptr, + IsKnownNonNull); + } + LValue MakeAddrLValue(Address Addr, QualType T, AlignmentSource Source = AlignmentSource::Type) { - return LValue::MakeAddr(Addr, T, getContext(), LValueBaseInfo(Source), - CGM.getTBAAAccessInfo(T)); + return MakeAddrLValue(Addr, T, LValueBaseInfo(Source), + CGM.getTBAAAccessInfo(T)); } LValue MakeAddrLValue(Address Addr, QualType T, LValueBaseInfo BaseInfo, @@ -2592,6 +2711,14 @@ public: LValue MakeAddrLValue(llvm::Value *V, QualType T, CharUnits Alignment, AlignmentSource Source = AlignmentSource::Type) { + return MakeAddrLValue(makeNaturalAddressForPointer(V, T, Alignment), T, + LValueBaseInfo(Source), CGM.getTBAAAccessInfo(T)); + } + + /// Same as MakeAddrLValue above except that the pointer is known to be + /// unsigned. + LValue MakeRawAddrLValue(llvm::Value *V, QualType T, CharUnits Alignment, + AlignmentSource Source = AlignmentSource::Type) { Address Addr(V, ConvertTypeForMem(T), Alignment); return LValue::MakeAddr(Addr, T, getContext(), LValueBaseInfo(Source), CGM.getTBAAAccessInfo(T)); @@ -2604,9 +2731,18 @@ public: TBAAAccessInfo()); } + /// Given a value of type T* that may not be to a complete object, construct + /// an l-value with the natural pointee alignment of T. LValue MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T); + LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T); + /// Same as MakeNaturalAlignPointeeAddrLValue except that the pointer is known + /// to be unsigned. + LValue MakeNaturalAlignPointeeRawAddrLValue(llvm::Value *V, QualType T); + + LValue MakeNaturalAlignRawAddrLValue(llvm::Value *V, QualType T); + Address EmitLoadOfReference(LValue RefLVal, LValueBaseInfo *PointeeBaseInfo = nullptr, TBAAAccessInfo *PointeeTBAAInfo = nullptr); @@ -2627,6 +2763,33 @@ public: TBAAAccessInfo *TBAAInfo = nullptr); LValue EmitLoadOfPointerLValue(Address Ptr, const PointerType *PtrTy); +private: + struct AllocaTracker { + void Add(llvm::AllocaInst *I) { Allocas.push_back(I); } + llvm::SmallVector Take() { return std::move(Allocas); } + + private: + llvm::SmallVector Allocas; + }; + AllocaTracker *Allocas = nullptr; + +public: + // Captures all the allocas created during the scope of its RAII object. + struct AllocaTrackerRAII { + AllocaTrackerRAII(CodeGenFunction &CGF) + : CGF(CGF), OldTracker(CGF.Allocas) { + CGF.Allocas = &Tracker; + } + ~AllocaTrackerRAII() { CGF.Allocas = OldTracker; } + + llvm::SmallVector Take() { return Tracker.Take(); } + + private: + CodeGenFunction &CGF; + AllocaTracker *OldTracker; + AllocaTracker Tracker; + }; + /// CreateTempAlloca - This creates an alloca and inserts it into the entry /// block if \p ArraySize is nullptr, otherwise inserts it at the current /// insertion point of the builder. The caller is responsible for setting an @@ -2655,13 +2818,13 @@ public: /// more efficient if the caller knows that the address will not be exposed. llvm::AllocaInst *CreateTempAlloca(llvm::Type *Ty, const Twine &Name = "tmp", llvm::Value *ArraySize = nullptr); - Address CreateTempAlloca(llvm::Type *Ty, CharUnits align, - const Twine &Name = "tmp", - llvm::Value *ArraySize = nullptr, - Address *Alloca = nullptr); - Address CreateTempAllocaWithoutCast(llvm::Type *Ty, CharUnits align, - const Twine &Name = "tmp", - llvm::Value *ArraySize = nullptr); + RawAddress CreateTempAlloca(llvm::Type *Ty, CharUnits align, + const Twine &Name = "tmp", + llvm::Value *ArraySize = nullptr, + RawAddress *Alloca = nullptr); + RawAddress CreateTempAllocaWithoutCast(llvm::Type *Ty, CharUnits align, + const Twine &Name = "tmp", + llvm::Value *ArraySize = nullptr); /// CreateDefaultAlignedTempAlloca - This creates an alloca with the /// default ABI alignment of the given LLVM type. @@ -2673,8 +2836,8 @@ public: /// not hand this address off to arbitrary IRGen routines, and especially /// do not pass it as an argument to a function that might expect a /// properly ABI-aligned value. - Address CreateDefaultAlignTempAlloca(llvm::Type *Ty, - const Twine &Name = "tmp"); + RawAddress CreateDefaultAlignTempAlloca(llvm::Type *Ty, + const Twine &Name = "tmp"); /// CreateIRTemp - Create a temporary IR object of the given type, with /// appropriate alignment. This routine should only be used when an temporary @@ -2684,38 +2847,52 @@ public: /// /// That is, this is exactly equivalent to CreateMemTemp, but calling /// ConvertType instead of ConvertTypeForMem. - Address CreateIRTemp(QualType T, const Twine &Name = "tmp"); + RawAddress CreateIRTemp(QualType T, const Twine &Name = "tmp"); /// CreateMemTemp - Create a temporary memory object of the given type, with /// appropriate alignmen and cast it to the default address space. Returns /// the original alloca instruction by \p Alloca if it is not nullptr. - Address CreateMemTemp(QualType T, const Twine &Name = "tmp", - Address *Alloca = nullptr); - Address CreateMemTemp(QualType T, CharUnits Align, const Twine &Name = "tmp", - Address *Alloca = nullptr); + RawAddress CreateMemTemp(QualType T, const Twine &Name = "tmp", + RawAddress *Alloca = nullptr); + RawAddress CreateMemTemp(QualType T, CharUnits Align, + const Twine &Name = "tmp", + RawAddress *Alloca = nullptr); /// CreateMemTemp - Create a temporary memory object of the given type, with /// appropriate alignmen without casting it to the default address space. - Address CreateMemTempWithoutCast(QualType T, const Twine &Name = "tmp"); - Address CreateMemTempWithoutCast(QualType T, CharUnits Align, - const Twine &Name = "tmp"); + RawAddress CreateMemTempWithoutCast(QualType T, const Twine &Name = "tmp"); + RawAddress CreateMemTempWithoutCast(QualType T, CharUnits Align, + const Twine &Name = "tmp"); /// CreateAggTemp - Create a temporary memory object for the given /// aggregate type. AggValueSlot CreateAggTemp(QualType T, const Twine &Name = "tmp", - Address *Alloca = nullptr) { - return AggValueSlot::forAddr(CreateMemTemp(T, Name, Alloca), - T.getQualifiers(), - AggValueSlot::IsNotDestructed, - AggValueSlot::DoesNotNeedGCBarriers, - AggValueSlot::IsNotAliased, - AggValueSlot::DoesNotOverlap); + RawAddress *Alloca = nullptr) { + return AggValueSlot::forAddr( + CreateMemTemp(T, Name, Alloca), T.getQualifiers(), + AggValueSlot::IsNotDestructed, AggValueSlot::DoesNotNeedGCBarriers, + AggValueSlot::IsNotAliased, AggValueSlot::DoesNotOverlap); } /// EvaluateExprAsBool - Perform the usual unary conversions on the specified /// expression and compare the result against zero, returning an Int1Ty value. llvm::Value *EvaluateExprAsBool(const Expr *E); + /// Retrieve the implicit cast expression of the rhs in a binary operator + /// expression by passing pointers to Value and QualType + /// This is used for implicit bitfield conversion checks, which + /// must compare with the value before potential truncation. + llvm::Value *EmitWithOriginalRHSBitfieldAssignment(const BinaryOperator *E, + llvm::Value **Previous, + QualType *SrcType); + + /// Emit a check that an [implicit] conversion of a bitfield. It is not UB, + /// so we use the value after conversion. + void EmitBitfieldConversionCheck(llvm::Value *Src, QualType SrcType, + llvm::Value *Dst, QualType DstType, + const CGBitFieldInfo &Info, + SourceLocation Loc); + /// EmitIgnoredExpr - Emit an expression in a context which ignores the result. void EmitIgnoredExpr(const Expr *E); @@ -3083,6 +3260,25 @@ public: /// calls to EmitTypeCheck can be skipped. bool sanitizePerformTypeCheck() const; + void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, LValue LV, + QualType Type, SanitizerSet SkippedChecks = SanitizerSet(), + llvm::Value *ArraySize = nullptr) { + if (!sanitizePerformTypeCheck()) + return; + EmitTypeCheck(TCK, Loc, LV.emitRawPointer(*this), Type, LV.getAlignment(), + SkippedChecks, ArraySize); + } + + void EmitTypeCheck(TypeCheckKind TCK, SourceLocation Loc, Address Addr, + QualType Type, CharUnits Alignment = CharUnits::Zero(), + SanitizerSet SkippedChecks = SanitizerSet(), + llvm::Value *ArraySize = nullptr) { + if (!sanitizePerformTypeCheck()) + return; + EmitTypeCheck(TCK, Loc, Addr.emitRawPointer(*this), Type, Alignment, + SkippedChecks, ArraySize); + } + /// Emit a check that \p V is the address of storage of the /// appropriate size and alignment for an object of type \p Type /// (or if ArraySize is provided, for an array of that bound). @@ -3183,17 +3379,17 @@ public: /// Address with original alloca instruction. Invalid if the variable was /// emitted as a global constant. - Address AllocaAddr; + RawAddress AllocaAddr; struct Invalid {}; AutoVarEmission(Invalid) : Variable(nullptr), Addr(Address::invalid()), - AllocaAddr(Address::invalid()) {} + AllocaAddr(RawAddress::invalid()) {} AutoVarEmission(const VarDecl &variable) : Variable(&variable), Addr(Address::invalid()), NRVOFlag(nullptr), IsEscapingByRef(false), IsConstantAggregate(false), - SizeForLifetimeMarkers(nullptr), AllocaAddr(Address::invalid()) {} + SizeForLifetimeMarkers(nullptr), AllocaAddr(RawAddress::invalid()) {} bool wasEmittedAsGlobal() const { return !Addr.isValid(); } @@ -3216,7 +3412,7 @@ public: } /// Returns the address for the original alloca instruction. - Address getOriginalAllocatedAddress() const { return AllocaAddr; } + RawAddress getOriginalAllocatedAddress() const { return AllocaAddr; } /// Returns the address of the object within this declaration. /// Note that this does not chase the forwarding pointer for @@ -3246,23 +3442,32 @@ public: llvm::GlobalValue::LinkageTypes Linkage); class ParamValue { - llvm::Value *Value; - llvm::Type *ElementType; - unsigned Alignment; - ParamValue(llvm::Value *V, llvm::Type *T, unsigned A) - : Value(V), ElementType(T), Alignment(A) {} + union { + Address Addr; + llvm::Value *Value; + }; + + bool IsIndirect; + + ParamValue(llvm::Value *V) : Value(V), IsIndirect(false) {} + ParamValue(Address A) : Addr(A), IsIndirect(true) {} + public: static ParamValue forDirect(llvm::Value *value) { - return ParamValue(value, nullptr, 0); + return ParamValue(value); } static ParamValue forIndirect(Address addr) { assert(!addr.getAlignment().isZero()); - return ParamValue(addr.getPointer(), addr.getElementType(), - addr.getAlignment().getQuantity()); + return ParamValue(addr); } - bool isIndirect() const { return Alignment != 0; } - llvm::Value *getAnyValue() const { return Value; } + bool isIndirect() const { return IsIndirect; } + llvm::Value *getAnyValue() const { + if (!isIndirect()) + return Value; + assert(!Addr.hasOffset() && "unexpected offset"); + return Addr.getBasePointer(); + } llvm::Value *getDirectValue() const { assert(!isIndirect()); @@ -3271,8 +3476,7 @@ public: Address getIndirectAddress() const { assert(isIndirect()); - return Address(Value, ElementType, CharUnits::fromQuantity(Alignment), - KnownNonNull); + return Addr; } }; @@ -4182,6 +4386,9 @@ public: const Twine &name = ""); llvm::CallInst *EmitNounwindRuntimeCall(llvm::FunctionCallee callee, const Twine &name = ""); + llvm::CallInst *EmitNounwindRuntimeCall(llvm::FunctionCallee callee, + ArrayRef
args, + const Twine &name = ""); llvm::CallInst *EmitNounwindRuntimeCall(llvm::FunctionCallee callee, ArrayRef args, const Twine &name = ""); @@ -4208,6 +4415,12 @@ public: CXXDtorType Type, const CXXRecordDecl *RD); + llvm::Value *getAsNaturalPointerTo(Address Addr, QualType PointeeType) { + return Addr.getBasePointer(); + } + + bool isPointerKnownNonNull(const Expr *E); + // Return the copy constructor name with the prefix "__copy_constructor_" // removed. static std::string getNonTrivialCopyConstructorStr(QualType QT, @@ -4780,6 +4993,11 @@ public: SourceLocation Loc, const Twine &Name = ""); + Address EmitCheckedInBoundsGEP(Address Addr, ArrayRef IdxList, + llvm::Type *elementType, bool SignedIndices, + bool IsSubtraction, SourceLocation Loc, + CharUnits Align, const Twine &Name = ""); + /// Specifies which type of sanitizer check to apply when handling a /// particular builtin. enum BuiltinCheckKind { @@ -4842,6 +5060,10 @@ public: void EmitNonNullArgCheck(RValue RV, QualType ArgType, SourceLocation ArgLoc, AbstractCallee AC, unsigned ParmNum); + void EmitNonNullArgCheck(Address Addr, QualType ArgType, + SourceLocation ArgLoc, AbstractCallee AC, + unsigned ParmNum); + /// EmitCallArg - Emit a single call argument. void EmitCallArg(CallArgList &args, const Expr *E, QualType ArgType); @@ -4870,6 +5092,25 @@ public: llvm::Value *emitBoolVecConversion(llvm::Value *SrcVec, unsigned NumElementsDst, const llvm::Twine &Name = ""); + // Adds a convergence_ctrl token to |Input| and emits the required parent + // convergence instructions. + llvm::CallBase *addControlledConvergenceToken(llvm::CallBase *Input); + +private: + // Emits a convergence_loop instruction for the given |BB|, with |ParentToken| + // as it's parent convergence instr. + llvm::IntrinsicInst *emitConvergenceLoopToken(llvm::BasicBlock *BB, + llvm::Value *ParentToken); + // Adds a convergence_ctrl token with |ParentToken| as parent convergence + // instr to the call |Input|. + llvm::CallBase *addConvergenceControlToken(llvm::CallBase *Input, + llvm::Value *ParentToken); + // Find the convergence_entry instruction |F|, or emits ones if none exists. + // Returns the convergence instruction. + llvm::IntrinsicInst *getOrEmitConvergenceEntryToken(llvm::Function *F); + // Find the convergence_loop instruction for the loop defined by |LI|, or + // emits one if none exists. Returns the convergence instruction. + llvm::IntrinsicInst *getOrEmitConvergenceLoopToken(const LoopInfo *LI); private: llvm::MDNode *getRangeForLoadFromType(QualType Ty); @@ -5050,7 +5291,7 @@ DominatingLLVMValue::save(CodeGenFunction &CGF, llvm::Value *value) { CGF.CreateTempAlloca(value->getType(), align, "cond-cleanup.save"); CGF.Builder.CreateStore(value, alloca); - return saved_type(alloca.getPointer(), true); + return saved_type(alloca.emitRawPointer(CGF), true); } inline llvm::Value *DominatingLLVMValue::restore(CodeGenFunction &CGF, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index cb153066b28dd10eaaa3c6f2dafb35ebf4d77fdf..73a9cb9d6e0424ad38e0b874482015663766cbce 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2087,6 +2087,14 @@ void CodeGenModule::SetLLVMFunctionAttributes(GlobalDecl GD, llvm::AttributeList PAL; ConstructAttributeList(F->getName(), Info, GD, PAL, CallingConv, /*AttrOnCallSite=*/false, IsThunk); + if (CallingConv == llvm::CallingConv::X86_VectorCall && + getTarget().getTriple().isWindowsArm64EC()) { + SourceLocation Loc; + if (const Decl *D = GD.getDecl()) + Loc = D->getLocation(); + + Error(Loc, "__vectorcall calling convention is not currently supported"); + } F->setAttributes(PAL); F->setCallingConv(static_cast(CallingConv)); } @@ -2627,7 +2635,7 @@ void CodeGenModule::setNonAliasAttributes(GlobalDecl GD, addUsedGlobal(F); if (auto *SA = D->getAttr()) if (!D->getAttr()) - F->addFnAttr("implicit-section-name", SA->getName()); + F->setSection(SA->getName()); llvm::AttrBuilder Attrs(F->getContext()); if (GetCPUAndFeaturesAttributes(GD, Attrs)) { @@ -3711,7 +3719,9 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { // Forward declarations are emitted lazily on first use. if (!FD->doesThisDeclarationHaveABody()) { - if (!FD->doesDeclarationForceExternallyVisibleDefinition()) + if (!FD->doesDeclarationForceExternallyVisibleDefinition() && + (!FD->isMultiVersion() || + !FD->getASTContext().getTargetInfo().getTriple().isAArch64())) return; StringRef MangledName = getMangledName(GD); @@ -3993,10 +4003,11 @@ void CodeGenModule::EmitMultiVersionFunctionDefinition(GlobalDecl GD, auto *Spec = FD->getAttr(); for (unsigned I = 0; I < Spec->cpus_size(); ++I) EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr); - } else if (FD->isTargetClonesMultiVersion()) { - auto *Clone = FD->getAttr(); - for (unsigned I = 0; I < Clone->featuresStrs_size(); ++I) - if (Clone->isFirstOfVersion(I)) + } else if (auto *TC = FD->getAttr()) { + for (unsigned I = 0; I < TC->featuresStrs_size(); ++I) + // AArch64 favors the default target version over the clone if any. + if ((!TC->isDefaultVersion(I) || !getTarget().getTriple().isAArch64()) && + TC->isFirstOfVersion(I)) EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr); // Ensure that the resolver function is also emitted. GetOrCreateMultiVersionResolver(GD); @@ -4092,6 +4103,23 @@ llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM, return llvm::GlobalValue::WeakODRLinkage; } +static FunctionDecl *createDefaultTargetVersionFrom(const FunctionDecl *FD) { + DeclContext *DeclCtx = FD->getASTContext().getTranslationUnitDecl(); + TypeSourceInfo *TInfo = FD->getTypeSourceInfo(); + StorageClass SC = FD->getStorageClass(); + DeclarationName Name = FD->getNameInfo().getName(); + + FunctionDecl *NewDecl = + FunctionDecl::Create(FD->getASTContext(), DeclCtx, FD->getBeginLoc(), + FD->getEndLoc(), Name, TInfo->getType(), TInfo, SC); + + NewDecl->setIsMultiVersion(); + NewDecl->addAttr(TargetVersionAttr::CreateImplicit( + NewDecl->getASTContext(), "default", NewDecl->getSourceRange())); + + return NewDecl; +} + void CodeGenModule::emitMultiVersionFunctions() { std::vector MVFuncsToEmit; MultiVersionFuncs.swap(MVFuncsToEmit); @@ -4099,96 +4127,79 @@ void CodeGenModule::emitMultiVersionFunctions() { const auto *FD = cast(GD.getDecl()); assert(FD && "Expected a FunctionDecl"); - bool EmitResolver = !FD->isTargetVersionMultiVersion(); - SmallVector Options; - if (FD->isTargetMultiVersion()) { - getContext().forEachMultiversionedFunctionVersion( - FD, [this, &GD, &Options, &EmitResolver](const FunctionDecl *CurFD) { - GlobalDecl CurGD{ - (CurFD->isDefined() ? CurFD->getDefinition() : CurFD)}; - StringRef MangledName = getMangledName(CurGD); - llvm::Constant *Func = GetGlobalValue(MangledName); - if (!Func) { - if (CurFD->isDefined()) { - EmitGlobalFunctionDefinition(CurGD, nullptr); - Func = GetGlobalValue(MangledName); - } else { - const CGFunctionInfo &FI = - getTypes().arrangeGlobalDeclaration(GD); - llvm::FunctionType *Ty = getTypes().GetFunctionType(FI); - Func = GetAddrOfFunction(CurGD, Ty, /*ForVTable=*/false, - /*DontDefer=*/false, ForDefinition); - } - assert(Func && "This should have just been created"); - } - if (CurFD->getMultiVersionKind() == MultiVersionKind::Target) { - const auto *TA = CurFD->getAttr(); - llvm::SmallVector Feats; - TA->getAddedFeatures(Feats); - Options.emplace_back(cast(Func), - TA->getArchitecture(), Feats); - } else { - const auto *TVA = CurFD->getAttr(); - if (CurFD->isUsed() || (TVA->isDefaultVersion() && - CurFD->doesThisDeclarationHaveABody())) - EmitResolver = true; - llvm::SmallVector Feats; - TVA->getFeatures(Feats); - Options.emplace_back(cast(Func), - /*Architecture*/ "", Feats); - } - }); - } else if (FD->isTargetClonesMultiVersion()) { - const auto *TC = FD->getAttr(); - for (unsigned VersionIndex = 0; VersionIndex < TC->featuresStrs_size(); - ++VersionIndex) { - if (!TC->isFirstOfVersion(VersionIndex)) - continue; - GlobalDecl CurGD{(FD->isDefined() ? FD->getDefinition() : FD), - VersionIndex}; - StringRef Version = TC->getFeatureStr(VersionIndex); - StringRef MangledName = getMangledName(CurGD); - llvm::Constant *Func = GetGlobalValue(MangledName); - if (!Func) { - if (FD->isDefined()) { - EmitGlobalFunctionDefinition(CurGD, nullptr); - Func = GetGlobalValue(MangledName); - } else { - const CGFunctionInfo &FI = - getTypes().arrangeGlobalDeclaration(CurGD); - llvm::FunctionType *Ty = getTypes().GetFunctionType(FI); - Func = GetAddrOfFunction(CurGD, Ty, /*ForVTable=*/false, - /*DontDefer=*/false, ForDefinition); - } - assert(Func && "This should have just been created"); + auto createFunction = [&](const FunctionDecl *Decl, unsigned MVIdx = 0) { + GlobalDecl CurGD{Decl->isDefined() ? Decl->getDefinition() : Decl, MVIdx}; + StringRef MangledName = getMangledName(CurGD); + llvm::Constant *Func = GetGlobalValue(MangledName); + if (!Func) { + if (Decl->isDefined()) { + EmitGlobalFunctionDefinition(CurGD, nullptr); + Func = GetGlobalValue(MangledName); + } else { + const CGFunctionInfo &FI = getTypes().arrangeGlobalDeclaration(CurGD); + llvm::FunctionType *Ty = getTypes().GetFunctionType(FI); + Func = GetAddrOfFunction(CurGD, Ty, /*ForVTable=*/false, + /*DontDefer=*/false, ForDefinition); } + assert(Func && "This should have just been created"); + } + return cast(Func); + }; - StringRef Architecture; - llvm::SmallVector Feature; + bool HasDefaultDecl = !FD->isTargetVersionMultiVersion(); + bool ShouldEmitResolver = + !getContext().getTargetInfo().getTriple().isAArch64(); + SmallVector Options; - if (getTarget().getTriple().isAArch64()) { - if (Version != "default") { - llvm::SmallVector VerFeats; - Version.split(VerFeats, "+"); - for (auto &CurFeat : VerFeats) - Feature.push_back(CurFeat.trim()); - } - } else { - if (Version.starts_with("arch=")) - Architecture = Version.drop_front(sizeof("arch=") - 1); - else if (Version != "default") - Feature.push_back(Version); - } + getContext().forEachMultiversionedFunctionVersion( + FD, [&](const FunctionDecl *CurFD) { + llvm::SmallVector Feats; + + if (const auto *TA = CurFD->getAttr()) { + TA->getAddedFeatures(Feats); + llvm::Function *Func = createFunction(CurFD); + Options.emplace_back(Func, TA->getArchitecture(), Feats); + } else if (const auto *TVA = CurFD->getAttr()) { + bool HasDefaultDef = TVA->isDefaultVersion() && + CurFD->doesThisDeclarationHaveABody(); + HasDefaultDecl |= TVA->isDefaultVersion(); + ShouldEmitResolver |= (CurFD->isUsed() || HasDefaultDef); + TVA->getFeatures(Feats); + llvm::Function *Func = createFunction(CurFD); + Options.emplace_back(Func, /*Architecture*/ "", Feats); + } else if (const auto *TC = CurFD->getAttr()) { + ShouldEmitResolver |= CurFD->doesThisDeclarationHaveABody(); + for (unsigned I = 0; I < TC->featuresStrs_size(); ++I) { + if (!TC->isFirstOfVersion(I)) + continue; + + llvm::Function *Func = createFunction(CurFD, I); + StringRef Architecture; + Feats.clear(); + if (getTarget().getTriple().isAArch64()) + TC->getFeatures(Feats, I); + else { + StringRef Version = TC->getFeatureStr(I); + if (Version.starts_with("arch=")) + Architecture = Version.drop_front(sizeof("arch=") - 1); + else if (Version != "default") + Feats.push_back(Version); + } + Options.emplace_back(Func, Architecture, Feats); + } + } else + llvm_unreachable("unexpected MultiVersionKind"); + }); - Options.emplace_back(cast(Func), Architecture, Feature); - } - } else { - assert(0 && "Expected a target or target_clones multiversion function"); + if (!ShouldEmitResolver) continue; - } - if (!EmitResolver) - continue; + if (!HasDefaultDecl) { + FunctionDecl *NewFD = createDefaultTargetVersionFrom(FD); + llvm::Function *Func = createFunction(NewFD); + llvm::SmallVector Feats; + Options.emplace_back(Func, /*Architecture*/ "", Feats); + } llvm::Constant *ResolverConstant = GetOrCreateMultiVersionResolver(GD); if (auto *IFunc = dyn_cast(ResolverConstant)) { @@ -4369,7 +4380,7 @@ void CodeGenModule::AddDeferredMultiVersionResolverToEmit(GlobalDecl GD) { const auto *FD = cast(GD.getDecl()); assert(FD && "Not a FunctionDecl?"); - if (FD->isTargetVersionMultiVersion()) { + if (FD->isTargetVersionMultiVersion() || FD->isTargetClonesMultiVersion()) { std::string MangledName = getMangledNameImpl(*this, GD, FD, /*OmitMultiVersionMangling=*/true); if (!DeferredResolversToEmit.insert(MangledName).second) @@ -4480,7 +4491,10 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction( if (FD->isMultiVersion()) { UpdateMultiVersionNames(GD, FD, MangledName); - if (!IsForDefinition) + if (FD->getASTContext().getTargetInfo().getTriple().isAArch64() && + !FD->isUsed()) + AddDeferredMultiVersionResolverToEmit(GD); + else if (!IsForDefinition) return GetOrCreateMultiVersionResolver(GD); } } @@ -6275,7 +6289,7 @@ CodeGenModule::GetConstantArrayFromStringLiteral(const StringLiteral *E) { // Resize the string to the right size, which is indicated by its type. const ConstantArrayType *CAT = Context.getAsConstantArrayType(E->getType()); assert(CAT && "String literal not of constant array type!"); - Str.resize(CAT->getSize().getZExtValue()); + Str.resize(CAT->getZExtSize()); return llvm::ConstantDataArray::getString(VMContext, Str, false); } @@ -6612,7 +6626,7 @@ static bool AllTrivialInitializers(CodeGenModule &CGM, void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { // We might need a .cxx_destruct even if we don't have any ivar initializers. if (needsDestructMethod(D)) { - IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct"); + const IdentifierInfo *II = &getContext().Idents.get(".cxx_destruct"); Selector cxxSelector = getContext().Selectors.getSelector(0, &II); ObjCMethodDecl *DTORMethod = ObjCMethodDecl::Create( getContext(), D->getLocation(), D->getLocation(), cxxSelector, @@ -6632,7 +6646,7 @@ void CodeGenModule::EmitObjCIvarInitializations(ObjCImplementationDecl *D) { AllTrivialInitializers(*this, D)) return; - IdentifierInfo *II = &getContext().Idents.get(".cxx_construct"); + const IdentifierInfo *II = &getContext().Idents.get(".cxx_construct"); Selector cxxSelector = getContext().Selectors.getSelector(0, &II); // The constructor returns 'self'. ObjCMethodDecl *CTORMethod = ObjCMethodDecl::Create( @@ -7200,7 +7214,7 @@ void CodeGenModule::EmitStaticExternCAliases() { if (!getTargetCodeGenInfo().shouldEmitStaticExternCAliases()) return; for (auto &I : StaticExternCValues) { - IdentifierInfo *Name = I.first; + const IdentifierInfo *Name = I.first; llvm::GlobalValue *Val = I.second; // If Val is null, that implies there were multiple declarations that each @@ -7261,7 +7275,7 @@ void CodeGenFunction::EmitDeclMetadata() { for (auto &I : LocalDeclMap) { const Decl *D = I.first; - llvm::Value *Addr = I.second.getPointer(); + llvm::Value *Addr = I.second.emitRawPointer(*this); if (auto *Alloca = dyn_cast(Addr)) { llvm::Value *DAddr = GetPointerConstant(getLLVMContext(), D); Alloca->setMetadata( diff --git a/clang/lib/CodeGen/CodeGenPGO.cpp b/clang/lib/CodeGen/CodeGenPGO.cpp index 2619edfeb7dc76c3e482b3c2da13dfdca1afc74d..76704c4d7be4a49de647c9f64aac615724215bb7 100644 --- a/clang/lib/CodeGen/CodeGenPGO.cpp +++ b/clang/lib/CodeGen/CodeGenPGO.cpp @@ -1239,7 +1239,8 @@ void CodeGenPGO::emitMCDCParameters(CGBuilderTy &Builder) { void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder, const Expr *S, - Address MCDCCondBitmapAddr) { + Address MCDCCondBitmapAddr, + CodeGenFunction &CGF) { if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState) return; @@ -1262,7 +1263,7 @@ void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder, Builder.getInt64(FunctionHash), Builder.getInt32(RegionMCDCState->BitmapBytes), Builder.getInt32(MCDCTestVectorBitmapOffset), - MCDCCondBitmapAddr.getPointer()}; + MCDCCondBitmapAddr.emitRawPointer(CGF)}; Builder.CreateCall( CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_tvbitmap_update), Args); } @@ -1283,7 +1284,8 @@ void CodeGenPGO::emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S, void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S, Address MCDCCondBitmapAddr, - llvm::Value *Val) { + llvm::Value *Val, + CodeGenFunction &CGF) { if (!canEmitMCDCCoverage(Builder) || !RegionMCDCState) return; @@ -1312,7 +1314,7 @@ void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S, llvm::Value *Args[5] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy), Builder.getInt64(FunctionHash), Builder.getInt32(Branch.ID), - MCDCCondBitmapAddr.getPointer(), Val}; + MCDCCondBitmapAddr.emitRawPointer(CGF), Val}; Builder.CreateCall( CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_condbitmap_update), Args); diff --git a/clang/lib/CodeGen/CodeGenPGO.h b/clang/lib/CodeGen/CodeGenPGO.h index 036fbf6815a49da500970580c8ed6057bc317847..9d66ffad6f43509e991ca87c3605c94e27ea8833 100644 --- a/clang/lib/CodeGen/CodeGenPGO.h +++ b/clang/lib/CodeGen/CodeGenPGO.h @@ -113,12 +113,14 @@ public: void emitCounterSetOrIncrement(CGBuilderTy &Builder, const Stmt *S, llvm::Value *StepV); void emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder, const Expr *S, - Address MCDCCondBitmapAddr); + Address MCDCCondBitmapAddr, + CodeGenFunction &CGF); void emitMCDCParameters(CGBuilderTy &Builder); void emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S, Address MCDCCondBitmapAddr); void emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S, - Address MCDCCondBitmapAddr, llvm::Value *Val); + Address MCDCCondBitmapAddr, llvm::Value *Val, + CodeGenFunction &CGF); /// Return the region count for the counter at the given index. uint64_t getRegionCount(const Stmt *S) { diff --git a/clang/lib/CodeGen/CodeGenTBAA.cpp b/clang/lib/CodeGen/CodeGenTBAA.cpp index a1e14c5f0a8c784e58154c2c85cce1bd0b77e749..da689ee6a13d7087ee019caccbd18911888ee33b 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.cpp +++ b/clang/lib/CodeGen/CodeGenTBAA.cpp @@ -22,6 +22,7 @@ #include "clang/AST/Mangle.h" #include "clang/AST/RecordLayout.h" #include "clang/Basic/CodeGenOptions.h" +#include "clang/Basic/TargetInfo.h" #include "llvm/ADT/SmallSet.h" #include "llvm/IR/Constants.h" #include "llvm/IR/LLVMContext.h" @@ -97,8 +98,6 @@ static bool TypeHasMayAlias(QualType QTy) { /// Check if the given type is a valid base type to be used in access tags. static bool isValidBaseType(QualType QTy) { - if (QTy->isReferenceType()) - return false; if (const RecordType *TTy = QTy->getAs()) { const RecordDecl *RD = TTy->getDecl()->getDefinition(); // Incomplete types are not valid base access types. @@ -242,9 +241,10 @@ llvm::MDNode *CodeGenTBAA::getTypeInfo(QualType QTy) { // aggregate will result into the may-alias access descriptor, meaning all // subsequent accesses to direct and indirect members of that aggregate will // be considered may-alias too. - // TODO: Combine getTypeInfo() and getBaseTypeInfo() into a single function. + // TODO: Combine getTypeInfo() and getValidBaseTypeInfo() into a single + // function. if (isValidBaseType(QTy)) - return getBaseTypeInfo(QTy); + return getValidBaseTypeInfo(QTy); const Type *Ty = Context.getCanonicalType(QTy).getTypePtr(); if (llvm::MDNode *N = MetadataCache[Ty]) @@ -319,7 +319,13 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset, // base type. if ((*i)->isBitField()) { const CGBitFieldInfo &Info = CGRL.getBitFieldInfo(*i); - if (Info.Offset != 0) + // For big endian targets the first bitfield in the consecutive run is + // at the most-significant end; see CGRecordLowering::setBitFieldInfo + // for more information. + bool IsBE = Context.getTargetInfo().isBigEndian(); + bool IsFirst = IsBE ? Info.StorageSize - (Info.Offset + Info.Size) == 0 + : Info.Offset == 0; + if (!IsFirst) continue; unsigned CurrentBitFieldSize = Info.StorageSize; uint64_t Size = @@ -387,7 +393,7 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) { if (BaseRD->isEmpty()) continue; llvm::MDNode *TypeNode = isValidBaseType(BaseQTy) - ? getBaseTypeInfo(BaseQTy) + ? getValidBaseTypeInfo(BaseQTy) : getTypeInfo(BaseQTy); if (!TypeNode) return nullptr; @@ -411,8 +417,9 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) { if (Field->isZeroSize(Context) || Field->isUnnamedBitfield()) continue; QualType FieldQTy = Field->getType(); - llvm::MDNode *TypeNode = isValidBaseType(FieldQTy) ? - getBaseTypeInfo(FieldQTy) : getTypeInfo(FieldQTy); + llvm::MDNode *TypeNode = isValidBaseType(FieldQTy) + ? getValidBaseTypeInfo(FieldQTy) + : getTypeInfo(FieldQTy); if (!TypeNode) return nullptr; @@ -449,9 +456,8 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) { return nullptr; } -llvm::MDNode *CodeGenTBAA::getBaseTypeInfo(QualType QTy) { - if (!isValidBaseType(QTy)) - return nullptr; +llvm::MDNode *CodeGenTBAA::getValidBaseTypeInfo(QualType QTy) { + assert(isValidBaseType(QTy) && "Must be a valid base type"); const Type *Ty = Context.getCanonicalType(QTy).getTypePtr(); @@ -470,6 +476,10 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfo(QualType QTy) { return TypeNode; } +llvm::MDNode *CodeGenTBAA::getBaseTypeInfo(QualType QTy) { + return isValidBaseType(QTy) ? getValidBaseTypeInfo(QTy) : nullptr; +} + llvm::MDNode *CodeGenTBAA::getAccessTagInfo(TBAAAccessInfo Info) { assert(!Info.isIncomplete() && "Access to an object of an incomplete type!"); diff --git a/clang/lib/CodeGen/CodeGenTBAA.h b/clang/lib/CodeGen/CodeGenTBAA.h index aa6da2731a4163c055de0b76768b5833516ca876..5d9ecec3ff0fe2c8880b701f3830276d09aaac03 100644 --- a/clang/lib/CodeGen/CodeGenTBAA.h +++ b/clang/lib/CodeGen/CodeGenTBAA.h @@ -168,6 +168,10 @@ class CodeGenTBAA { /// used to describe accesses to objects of the given base type. llvm::MDNode *getBaseTypeInfoHelper(const Type *Ty); + /// getValidBaseTypeInfo - Return metadata that describes the given base + /// access type. The type must be suitable. + llvm::MDNode *getValidBaseTypeInfo(QualType QTy); + public: CodeGenTBAA(ASTContext &Ctx, CodeGenTypes &CGTypes, llvm::Module &M, const CodeGenOptions &CGO, const LangOptions &Features, @@ -190,8 +194,9 @@ public: /// the given type. llvm::MDNode *getTBAAStructInfo(QualType QTy); - /// getBaseTypeInfo - Get metadata that describes the given base access type. - /// Return null if the type is not suitable for use in TBAA access tags. + /// getBaseTypeInfo - Get metadata that describes the given base access + /// type. Return null if the type is not suitable for use in TBAA access + /// tags. llvm::MDNode *getBaseTypeInfo(QualType QTy); /// getAccessTagInfo - Get TBAA tag for a given memory access. diff --git a/clang/lib/CodeGen/CodeGenTypes.cpp b/clang/lib/CodeGen/CodeGenTypes.cpp index a6b51bfef87652d1b4101c0925ab92640a1ea0af..1568b6e6275b9dee1c65a56f872f2897c24cba0f 100644 --- a/clang/lib/CodeGen/CodeGenTypes.cpp +++ b/clang/lib/CodeGen/CodeGenTypes.cpp @@ -590,6 +590,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { ResultType = llvm::ArrayType::get(ResultType, 0); break; } + case Type::ArrayParameter: case Type::ConstantArray: { const ConstantArrayType *A = cast(Ty); llvm::Type *EltTy = ConvertTypeForMem(A->getElementType()); @@ -601,7 +602,7 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) { EltTy = llvm::Type::getInt8Ty(getLLVMContext()); } - ResultType = llvm::ArrayType::get(EltTy, A->getSize().getZExtValue()); + ResultType = llvm::ArrayType::get(EltTy, A->getZExtSize()); break; } case Type::ExtVector: diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp index bdd53a192f828adbe2999a7f54d3d805c4892146..18acf7784f714b4c8d083c086185efd1e45bdec2 100644 --- a/clang/lib/CodeGen/ItaniumCXXABI.cpp +++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp @@ -307,10 +307,6 @@ public: CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base, const CXXRecordDecl *NearestVBase); - llvm::Constant * - getVTableAddressPointForConstExpr(BaseSubobject Base, - const CXXRecordDecl *VTableClass) override; - llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD, CharUnits VPtrOffset) override; @@ -646,7 +642,7 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer( // Apply the adjustment and cast back to the original struct type // for consistency. - llvm::Value *This = ThisAddr.getPointer(); + llvm::Value *This = ThisAddr.emitRawPointer(CGF); This = Builder.CreateInBoundsGEP(Builder.getInt8Ty(), This, Adj); ThisPtrForCall = This; @@ -850,7 +846,7 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress( CGBuilderTy &Builder = CGF.Builder; // Apply the offset, which we assume is non-null. - return Builder.CreateInBoundsGEP(CGF.Int8Ty, Base.getPointer(), MemPtr, + return Builder.CreateInBoundsGEP(CGF.Int8Ty, Base.emitRawPointer(CGF), MemPtr, "memptr.offset"); } @@ -1245,7 +1241,7 @@ void ItaniumCXXABI::emitVirtualObjectDelete(CodeGenFunction &CGF, CGF.getPointerAlign()); // Apply the offset. - llvm::Value *CompletePtr = Ptr.getPointer(); + llvm::Value *CompletePtr = Ptr.emitRawPointer(CGF); CompletePtr = CGF.Builder.CreateInBoundsGEP(CGF.Int8Ty, CompletePtr, Offset); @@ -1482,7 +1478,8 @@ llvm::Value *ItaniumCXXABI::emitDynamicCastCall( computeOffsetHint(CGF.getContext(), SrcDecl, DestDecl).getQuantity()); // Emit the call to __dynamic_cast. - llvm::Value *Args[] = {ThisAddr.getPointer(), SrcRTTI, DestRTTI, OffsetHint}; + llvm::Value *Args[] = {ThisAddr.emitRawPointer(CGF), SrcRTTI, DestRTTI, + OffsetHint}; llvm::Value *Value = CGF.EmitNounwindRuntimeCall(getItaniumDynamicCastFn(CGF), Args); @@ -1571,7 +1568,7 @@ llvm::Value *ItaniumCXXABI::emitExactDynamicCast( VPtr, CGM.getTBAAVTablePtrAccessInfo(CGF.VoidPtrPtrTy)); llvm::Value *Success = CGF.Builder.CreateICmpEQ( VPtr, getVTableAddressPoint(BaseSubobject(SrcDecl, *Offset), DestDecl)); - llvm::Value *Result = ThisAddr.getPointer(); + llvm::Value *Result = ThisAddr.emitRawPointer(CGF); if (!Offset->isZero()) Result = CGF.Builder.CreateInBoundsGEP( CGF.CharTy, Result, @@ -1611,7 +1608,7 @@ llvm::Value *ItaniumCXXABI::emitDynamicCastToVoid(CodeGenFunction &CGF, PtrDiffLTy, OffsetToTop, CGF.getPointerAlign(), "offset.to.top"); } // Finally, add the offset to the pointer. - return CGF.Builder.CreateInBoundsGEP(CGF.Int8Ty, ThisAddr.getPointer(), + return CGF.Builder.CreateInBoundsGEP(CGF.Int8Ty, ThisAddr.emitRawPointer(CGF), OffsetToTop); } @@ -1792,8 +1789,8 @@ void ItaniumCXXABI::EmitDestructorCall(CodeGenFunction &CGF, else Callee = CGCallee::forDirect(CGM.getAddrOfCXXStructor(GD), GD); - CGF.EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy, VTT, VTTTy, - nullptr); + CGF.EmitCXXDestructorCall(GD, Callee, CGF.getAsNaturalPointerTo(This, ThisTy), + ThisTy, VTT, VTTTy, nullptr); } void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT, @@ -1952,11 +1949,6 @@ llvm::Value *ItaniumCXXABI::getVTableAddressPointInStructorWithVTT( CGF.getPointerAlign()); } -llvm::Constant *ItaniumCXXABI::getVTableAddressPointForConstExpr( - BaseSubobject Base, const CXXRecordDecl *VTableClass) { - return getVTableAddressPoint(Base, VTableClass); -} - llvm::GlobalVariable *ItaniumCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, CharUnits VPtrOffset) { assert(VPtrOffset.isZero() && "Itanium ABI only supports zero vptr offsets"); @@ -2088,8 +2080,8 @@ llvm::Value *ItaniumCXXABI::EmitVirtualDestructorCall( ThisTy = D->getDestroyedType(); } - CGF.EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy, nullptr, - QualType(), nullptr); + CGF.EmitCXXDestructorCall(GD, Callee, This.emitRawPointer(CGF), ThisTy, + nullptr, QualType(), nullptr); return nullptr; } @@ -2162,7 +2154,7 @@ static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF, int64_t VirtualAdjustment, bool IsReturnAdjustment) { if (!NonVirtualAdjustment && !VirtualAdjustment) - return InitialPtr.getPointer(); + return InitialPtr.emitRawPointer(CGF); Address V = InitialPtr.withElementType(CGF.Int8Ty); @@ -2195,10 +2187,10 @@ static llvm::Value *performTypeAdjustment(CodeGenFunction &CGF, CGF.getPointerAlign()); } // Adjust our pointer. - ResultPtr = CGF.Builder.CreateInBoundsGEP( - V.getElementType(), V.getPointer(), Offset); + ResultPtr = CGF.Builder.CreateInBoundsGEP(V.getElementType(), + V.emitRawPointer(CGF), Offset); } else { - ResultPtr = V.getPointer(); + ResultPtr = V.emitRawPointer(CGF); } // In a derived-to-base conversion, the non-virtual adjustment is @@ -2284,7 +2276,7 @@ Address ItaniumCXXABI::InitializeArrayCookie(CodeGenFunction &CGF, llvm::FunctionType::get(CGM.VoidTy, NumElementsPtr.getType(), false); llvm::FunctionCallee F = CGM.CreateRuntimeFunction(FTy, "__asan_poison_cxx_array_cookie"); - CGF.Builder.CreateCall(F, NumElementsPtr.getPointer()); + CGF.Builder.CreateCall(F, NumElementsPtr.emitRawPointer(CGF)); } // Finally, compute a pointer to the actual data buffer by skipping @@ -2315,7 +2307,7 @@ llvm::Value *ItaniumCXXABI::readArrayCookieImpl(CodeGenFunction &CGF, llvm::FunctionType::get(CGF.SizeTy, CGF.UnqualPtrTy, false); llvm::FunctionCallee F = CGM.CreateRuntimeFunction(FTy, "__asan_load_cxx_array_cookie"); - return CGF.Builder.CreateCall(F, numElementsPtr.getPointer()); + return CGF.Builder.CreateCall(F, numElementsPtr.emitRawPointer(CGF)); } CharUnits ARMCXXABI::getArrayCookieSizeImpl(QualType elementType) { @@ -2627,7 +2619,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // Call __cxa_guard_release. This cannot throw. CGF.EmitNounwindRuntimeCall(getGuardReleaseFn(CGM, guardPtrTy), - guardAddr.getPointer()); + guardAddr.emitRawPointer(CGF)); } else if (D.isLocalVarDecl()) { // For local variables, store 1 into the first byte of the guard variable // after the object initialization completes so that initialization is @@ -3120,10 +3112,10 @@ LValue ItaniumCXXABI::EmitThreadLocalVarDeclLValue(CodeGenFunction &CGF, LValue LV; if (VD->getType()->isReferenceType()) - LV = CGF.MakeNaturalAlignAddrLValue(CallVal, LValType); + LV = CGF.MakeNaturalAlignRawAddrLValue(CallVal, LValType); else - LV = CGF.MakeAddrLValue(CallVal, LValType, - CGF.getContext().getDeclAlign(VD)); + LV = CGF.MakeRawAddrLValue(CallVal, LValType, + CGF.getContext().getDeclAlign(VD)); // FIXME: need setObjCGCLValueClass? return LV; } @@ -3592,6 +3584,9 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) { case Type::Pipe: llvm_unreachable("Pipe types shouldn't get here"); + case Type::ArrayParameter: + llvm_unreachable("Array Parameter types should not get here."); + case Type::Builtin: case Type::BitInt: // GCC treats vector and complex types as fundamental types. @@ -3876,6 +3871,7 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo( case Type::ConstantArray: case Type::IncompleteArray: case Type::VariableArray: + case Type::ArrayParameter: // Itanium C++ ABI 2.9.5p5: // abi::__array_type_info adds no data members to std::type_info. break; @@ -4604,7 +4600,7 @@ static void InitCatchParam(CodeGenFunction &CGF, CGF.Builder.CreateStore(Casted, ExnPtrTmp); // Bind the reference to the temporary. - AdjustedExn = ExnPtrTmp.getPointer(); + AdjustedExn = ExnPtrTmp.emitRawPointer(CGF); } } diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp index 172c4c937b97280d30ca5689ec58b600a852a809..d38a26940a3cb613a29557019f92b60b49cb7a9e 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -327,10 +327,6 @@ public: CodeGenFunction &CGF, const CXXRecordDecl *VTableClass, BaseSubobject Base, const CXXRecordDecl *NearestVBase) override; - llvm::Constant * - getVTableAddressPointForConstExpr(BaseSubobject Base, - const CXXRecordDecl *VTableClass) override; - llvm::GlobalVariable *getAddrOfVTable(const CXXRecordDecl *RD, CharUnits VPtrOffset) override; @@ -937,7 +933,7 @@ void MicrosoftCXXABI::emitBeginCatch(CodeGenFunction &CGF, } CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam); - CPI->setArgOperand(2, var.getObjectAddress(CGF).getPointer()); + CPI->setArgOperand(2, var.getObjectAddress(CGF).emitRawPointer(CGF)); CGF.EHStack.pushCleanup(NormalCleanup, CPI); CGF.EmitAutoVarCleanups(var); } @@ -974,7 +970,7 @@ MicrosoftCXXABI::performBaseAdjustment(CodeGenFunction &CGF, Address Value, llvm::Value *Offset = GetVirtualBaseClassOffset(CGF, Value, SrcDecl, PolymorphicBase); llvm::Value *Ptr = CGF.Builder.CreateInBoundsGEP( - Value.getElementType(), Value.getPointer(), Offset); + Value.getElementType(), Value.emitRawPointer(CGF), Offset); CharUnits VBaseAlign = CGF.CGM.getVBaseAlignment(Value.getAlignment(), SrcDecl, PolymorphicBase); return std::make_tuple(Address(Ptr, CGF.Int8Ty, VBaseAlign), Offset, @@ -1011,7 +1007,7 @@ llvm::Value *MicrosoftCXXABI::EmitTypeid(CodeGenFunction &CGF, llvm::Type *StdTypeInfoPtrTy) { std::tie(ThisPtr, std::ignore, std::ignore) = performBaseAdjustment(CGF, ThisPtr, SrcRecordTy); - llvm::CallBase *Typeid = emitRTtypeidCall(CGF, ThisPtr.getPointer()); + llvm::CallBase *Typeid = emitRTtypeidCall(CGF, ThisPtr.emitRawPointer(CGF)); return CGF.Builder.CreateBitCast(Typeid, StdTypeInfoPtrTy); } @@ -1033,7 +1029,7 @@ llvm::Value *MicrosoftCXXABI::emitDynamicCastCall( llvm::Value *Offset; std::tie(This, Offset, std::ignore) = performBaseAdjustment(CGF, This, SrcRecordTy); - llvm::Value *ThisPtr = This.getPointer(); + llvm::Value *ThisPtr = This.emitRawPointer(CGF); Offset = CGF.Builder.CreateTrunc(Offset, CGF.Int32Ty); // PVOID __RTDynamicCast( @@ -1065,7 +1061,7 @@ llvm::Value *MicrosoftCXXABI::emitDynamicCastToVoid(CodeGenFunction &CGF, llvm::FunctionCallee Function = CGF.CGM.CreateRuntimeFunction( llvm::FunctionType::get(CGF.Int8PtrTy, ArgTypes, false), "__RTCastToVoid"); - llvm::Value *Args[] = {Value.getPointer()}; + llvm::Value *Args[] = {Value.emitRawPointer(CGF)}; return CGF.EmitRuntimeCall(Function, Args); } @@ -1493,7 +1489,7 @@ Address MicrosoftCXXABI::adjustThisArgumentForVirtualFunctionCall( llvm::Value *VBaseOffset = GetVirtualBaseClassOffset(CGF, Result, Derived, VBase); llvm::Value *VBasePtr = CGF.Builder.CreateInBoundsGEP( - Result.getElementType(), Result.getPointer(), VBaseOffset); + Result.getElementType(), Result.emitRawPointer(CGF), VBaseOffset); CharUnits VBaseAlign = CGF.CGM.getVBaseAlignment(Result.getAlignment(), Derived, VBase); Result = Address(VBasePtr, CGF.Int8Ty, VBaseAlign); @@ -1660,7 +1656,8 @@ void MicrosoftCXXABI::EmitDestructorCall(CodeGenFunction &CGF, llvm::Value *Implicit = getCXXDestructorImplicitParam(CGF, DD, Type, ForVirtualBase, Delegating); // = nullptr - CGF.EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy, + CGF.EmitCXXDestructorCall(GD, Callee, CGF.getAsNaturalPointerTo(This, ThisTy), + ThisTy, /*ImplicitParam=*/Implicit, /*ImplicitParamTy=*/QualType(), nullptr); if (BaseDtorEndBB) { @@ -1791,13 +1788,6 @@ MicrosoftCXXABI::getVTableAddressPoint(BaseSubobject Base, return VFTablesMap[ID]; } -llvm::Constant *MicrosoftCXXABI::getVTableAddressPointForConstExpr( - BaseSubobject Base, const CXXRecordDecl *VTableClass) { - llvm::Constant *VFTable = getVTableAddressPoint(Base, VTableClass); - assert(VFTable && "Couldn't find a vftable for the given base?"); - return VFTable; -} - llvm::GlobalVariable *MicrosoftCXXABI::getAddrOfVTable(const CXXRecordDecl *RD, CharUnits VPtrOffset) { // getAddrOfVTable may return 0 if asked to get an address of a vtable which @@ -2013,8 +2003,9 @@ llvm::Value *MicrosoftCXXABI::EmitVirtualDestructorCall( } This = adjustThisArgumentForVirtualFunctionCall(CGF, GD, This, true); - RValue RV = CGF.EmitCXXDestructorCall(GD, Callee, This.getPointer(), ThisTy, - ImplicitParam, Context.IntTy, CE); + RValue RV = + CGF.EmitCXXDestructorCall(GD, Callee, This.emitRawPointer(CGF), ThisTy, + ImplicitParam, Context.IntTy, CE); return RV.getScalarVal(); } @@ -2212,13 +2203,13 @@ llvm::Value *MicrosoftCXXABI::performThisAdjustment(CodeGenFunction &CGF, Address This, const ThisAdjustment &TA) { if (TA.isEmpty()) - return This.getPointer(); + return This.emitRawPointer(CGF); This = This.withElementType(CGF.Int8Ty); llvm::Value *V; if (TA.Virtual.isEmpty()) { - V = This.getPointer(); + V = This.emitRawPointer(CGF); } else { assert(TA.Virtual.Microsoft.VtordispOffset < 0); // Adjust the this argument based on the vtordisp value. @@ -2227,7 +2218,7 @@ llvm::Value *MicrosoftCXXABI::performThisAdjustment(CodeGenFunction &CGF, CharUnits::fromQuantity(TA.Virtual.Microsoft.VtordispOffset)); VtorDispPtr = VtorDispPtr.withElementType(CGF.Int32Ty); llvm::Value *VtorDisp = CGF.Builder.CreateLoad(VtorDispPtr, "vtordisp"); - V = CGF.Builder.CreateGEP(This.getElementType(), This.getPointer(), + V = CGF.Builder.CreateGEP(This.getElementType(), This.emitRawPointer(CGF), CGF.Builder.CreateNeg(VtorDisp)); // Unfortunately, having applied the vtordisp means that we no @@ -2264,11 +2255,11 @@ llvm::Value * MicrosoftCXXABI::performReturnAdjustment(CodeGenFunction &CGF, Address Ret, const ReturnAdjustment &RA) { if (RA.isEmpty()) - return Ret.getPointer(); + return Ret.emitRawPointer(CGF); Ret = Ret.withElementType(CGF.Int8Ty); - llvm::Value *V = Ret.getPointer(); + llvm::Value *V = Ret.emitRawPointer(CGF); if (RA.Virtual.Microsoft.VBIndex) { assert(RA.Virtual.Microsoft.VBIndex > 0); int32_t IntSize = CGF.getIntSize().getQuantity(); @@ -2583,7 +2574,7 @@ struct ResetGuardBit final : EHScopeStack::Cleanup { struct CallInitThreadAbort final : EHScopeStack::Cleanup { llvm::Value *Guard; - CallInitThreadAbort(Address Guard) : Guard(Guard.getPointer()) {} + CallInitThreadAbort(RawAddress Guard) : Guard(Guard.getPointer()) {} void Emit(CodeGenFunction &CGF, Flags flags) override { // Calling _Init_thread_abort will reset the guard's state. @@ -3123,8 +3114,8 @@ MicrosoftCXXABI::GetVBaseOffsetFromVBPtr(CodeGenFunction &CGF, llvm::Value **VBPtrOut) { CGBuilderTy &Builder = CGF.Builder; // Load the vbtable pointer from the vbptr in the instance. - llvm::Value *VBPtr = Builder.CreateInBoundsGEP(CGM.Int8Ty, This.getPointer(), - VBPtrOffset, "vbptr"); + llvm::Value *VBPtr = Builder.CreateInBoundsGEP( + CGM.Int8Ty, This.emitRawPointer(CGF), VBPtrOffset, "vbptr"); if (VBPtrOut) *VBPtrOut = VBPtr; @@ -3203,7 +3194,7 @@ llvm::Value *MicrosoftCXXABI::AdjustVirtualBase( Builder.CreateBr(SkipAdjustBB); CGF.EmitBlock(SkipAdjustBB); llvm::PHINode *Phi = Builder.CreatePHI(CGM.Int8PtrTy, 2, "memptr.base"); - Phi->addIncoming(Base.getPointer(), OriginalBB); + Phi->addIncoming(Base.emitRawPointer(CGF), OriginalBB); Phi->addIncoming(AdjustedBase, VBaseAdjustBB); return Phi; } @@ -3238,7 +3229,7 @@ llvm::Value *MicrosoftCXXABI::EmitMemberDataPointerAddress( Addr = AdjustVirtualBase(CGF, E, RD, Base, VirtualBaseAdjustmentOffset, VBPtrOffset); } else { - Addr = Base.getPointer(); + Addr = Base.emitRawPointer(CGF); } // Apply the offset, which we assume is non-null. @@ -3526,7 +3517,7 @@ CGCallee MicrosoftCXXABI::EmitLoadOfMemberFunctionPointer( ThisPtrForCall = AdjustVirtualBase(CGF, E, RD, This, VirtualBaseAdjustmentOffset, VBPtrOffset); } else { - ThisPtrForCall = This.getPointer(); + ThisPtrForCall = This.emitRawPointer(CGF); } if (NonVirtualBaseAdjustment) @@ -4445,10 +4436,7 @@ void MicrosoftCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) { llvm::GlobalVariable *TI = getThrowInfo(ThrowType); // Call into the runtime to throw the exception. - llvm::Value *Args[] = { - AI.getPointer(), - TI - }; + llvm::Value *Args[] = {AI.emitRawPointer(CGF), TI}; CGF.EmitNoreturnRuntimeCallOrInvoke(getThrowFn(), Args); } diff --git a/clang/lib/CodeGen/SwiftCallingConv.cpp b/clang/lib/CodeGen/SwiftCallingConv.cpp index 16fbf52a517db48ddf8ebdb0d6887a20f7ea330c..ab2e2bd0b30646557c91f26e8353412990cbd5db 100644 --- a/clang/lib/CodeGen/SwiftCallingConv.cpp +++ b/clang/lib/CodeGen/SwiftCallingConv.cpp @@ -78,7 +78,7 @@ void SwiftAggLowering::addTypedData(QualType type, CharUnits begin) { QualType eltType = arrayType->getElementType(); auto eltSize = CGM.getContext().getTypeSizeInChars(eltType); - for (uint64_t i = 0, e = arrayType->getSize().getZExtValue(); i != e; ++i) { + for (uint64_t i = 0, e = arrayType->getZExtSize(); i != e; ++i) { addTypedData(eltType, begin + i * eltSize); } diff --git a/clang/lib/CodeGen/TargetInfo.h b/clang/lib/CodeGen/TargetInfo.h index 6893b50a3cfe90861432da5f4a8055e534204a36..b1dfe5bf8f274d1b43c7e3f531faf8da526233a7 100644 --- a/clang/lib/CodeGen/TargetInfo.h +++ b/clang/lib/CodeGen/TargetInfo.h @@ -295,6 +295,11 @@ public: /// Get the AST address space for alloca. virtual LangAS getASTAllocaAddressSpace() const { return LangAS::Default; } + Address performAddrSpaceCast(CodeGen::CodeGenFunction &CGF, Address Addr, + LangAS SrcAddr, LangAS DestAddr, + llvm::Type *DestTy, + bool IsNonNull = false) const; + /// Perform address space cast of an expression of pointer type. /// \param V is the LLVM value to be casted to another address space. /// \param SrcAddr is the language address space of \p V. diff --git a/clang/lib/CodeGen/Targets/ARM.cpp b/clang/lib/CodeGen/Targets/ARM.cpp index 5d42e6286e525b426341d31f553b8732019bdc05..885d9c77d0e76fd9d62d74c7c54f8bf60809e0b5 100644 --- a/clang/lib/CodeGen/Targets/ARM.cpp +++ b/clang/lib/CodeGen/Targets/ARM.cpp @@ -671,7 +671,7 @@ bool ARMABIInfo::isIllegalVectorType(QualType Ty) const { /// Return true if a type contains any 16-bit floating point vectors bool ARMABIInfo::containsAnyFP16Vectors(QualType Ty) const { if (const ConstantArrayType *AT = getContext().getAsConstantArrayType(Ty)) { - uint64_t NElements = AT->getSize().getZExtValue(); + uint64_t NElements = AT->getZExtSize(); if (NElements == 0) return false; return containsAnyFP16Vectors(AT->getElementType()); diff --git a/clang/lib/CodeGen/Targets/LoongArch.cpp b/clang/lib/CodeGen/Targets/LoongArch.cpp index 63b9a1fdb988ceba4142c412bbbd1e0c777ac196..3f01d9ad90f132db7230cd835bc41f8313a1eb53 100644 --- a/clang/lib/CodeGen/Targets/LoongArch.cpp +++ b/clang/lib/CodeGen/Targets/LoongArch.cpp @@ -146,7 +146,7 @@ bool LoongArchABIInfo::detectFARsEligibleStructHelper( } if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(Ty)) { - uint64_t ArraySize = ATy->getSize().getZExtValue(); + uint64_t ArraySize = ATy->getZExtSize(); QualType EltTy = ATy->getElementType(); // Non-zero-length arrays of empty records make the struct ineligible to be // passed via FARs in C++. diff --git a/clang/lib/CodeGen/Targets/NVPTX.cpp b/clang/lib/CodeGen/Targets/NVPTX.cpp index 8718f1ecf3a7e076b70bc3d18e2d668e0783c93a..7dce5042c3dc203b5fc6e4f16903b90cc9eb1c61 100644 --- a/clang/lib/CodeGen/Targets/NVPTX.cpp +++ b/clang/lib/CodeGen/Targets/NVPTX.cpp @@ -85,7 +85,7 @@ private: LValue Src) { llvm::Value *Handle = nullptr; llvm::Constant *C = - llvm::dyn_cast(Src.getAddress(CGF).getPointer()); + llvm::dyn_cast(Src.getAddress(CGF).emitRawPointer(CGF)); // Lookup `addrspacecast` through the constant pointer if any. if (auto *ASC = llvm::dyn_cast_or_null(C)) C = llvm::cast(ASC->getPointerOperand()); diff --git a/clang/lib/CodeGen/Targets/PPC.cpp b/clang/lib/CodeGen/Targets/PPC.cpp index 00b04723f17dd2e0a2ed392b57aab43300379c1e..174fddabbbdb6b9284ee82890d41619b2715a76b 100644 --- a/clang/lib/CodeGen/Targets/PPC.cpp +++ b/clang/lib/CodeGen/Targets/PPC.cpp @@ -274,7 +274,7 @@ void AIXTargetCodeGenInfo::setTargetAttributes( if (!isa(GV)) return; - auto *GVar = dyn_cast(GV); + auto *GVar = cast(GV); auto GVId = GV->getName(); // Is this a global variable specified by the user as toc-data? @@ -513,9 +513,10 @@ Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList, CharUnits RegSize = CharUnits::fromQuantity((isInt || IsSoftFloatABI) ? 4 : 8); llvm::Value *RegOffset = Builder.CreateMul(NumRegs, Builder.getInt8(RegSize.getQuantity())); - RegAddr = Address( - Builder.CreateInBoundsGEP(CGF.Int8Ty, RegAddr.getPointer(), RegOffset), - DirectTy, RegAddr.getAlignment().alignmentOfArrayElement(RegSize)); + RegAddr = Address(Builder.CreateInBoundsGEP( + CGF.Int8Ty, RegAddr.emitRawPointer(CGF), RegOffset), + DirectTy, + RegAddr.getAlignment().alignmentOfArrayElement(RegSize)); // Increase the used-register count. NumRegs = @@ -551,7 +552,7 @@ Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList, // Round up address of argument to alignment CharUnits Align = CGF.getContext().getTypeAlignInChars(Ty); if (Align > OverflowAreaAlign) { - llvm::Value *Ptr = OverflowArea.getPointer(); + llvm::Value *Ptr = OverflowArea.emitRawPointer(CGF); OverflowArea = Address(emitRoundPointerUpToAlignment(CGF, Ptr, Align), OverflowArea.getElementType(), Align); } @@ -560,7 +561,7 @@ Address PPC32_SVR4_ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAList, // Increase the overflow area. OverflowArea = Builder.CreateConstInBoundsByteGEP(OverflowArea, Size); - Builder.CreateStore(OverflowArea.getPointer(), OverflowAreaAddr); + Builder.CreateStore(OverflowArea.emitRawPointer(CGF), OverflowAreaAddr); CGF.EmitBranch(Cont); } diff --git a/clang/lib/CodeGen/Targets/RISCV.cpp b/clang/lib/CodeGen/Targets/RISCV.cpp index 9a79424c4612ceb45c2f386c28d878d6b66ea655..7b32c797235621e1df5bb952372a0d538f690a57 100644 --- a/clang/lib/CodeGen/Targets/RISCV.cpp +++ b/clang/lib/CodeGen/Targets/RISCV.cpp @@ -152,7 +152,7 @@ bool RISCVABIInfo::detectFPCCEligibleStructHelper(QualType Ty, CharUnits CurOff, } if (const ConstantArrayType *ATy = getContext().getAsConstantArrayType(Ty)) { - uint64_t ArraySize = ATy->getSize().getZExtValue(); + uint64_t ArraySize = ATy->getZExtSize(); QualType EltTy = ATy->getElementType(); // Non-zero-length arrays of empty records make the struct ineligible for // the FP calling convention in C++. diff --git a/clang/lib/CodeGen/Targets/Sparc.cpp b/clang/lib/CodeGen/Targets/Sparc.cpp index a337a52a94eca940409eb6cb7b5c76bd001668f5..9025a633f328e272901d90ff8effd6222d9842b0 100644 --- a/clang/lib/CodeGen/Targets/Sparc.cpp +++ b/clang/lib/CodeGen/Targets/Sparc.cpp @@ -326,7 +326,7 @@ Address SparcV9ABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, // Update VAList. Address NextPtr = Builder.CreateConstInBoundsByteGEP(Addr, Stride, "ap.next"); - Builder.CreateStore(NextPtr.getPointer(), VAListAddr); + Builder.CreateStore(NextPtr.emitRawPointer(CGF), VAListAddr); return ArgAddr.withElementType(ArgTy); } diff --git a/clang/lib/CodeGen/Targets/SystemZ.cpp b/clang/lib/CodeGen/Targets/SystemZ.cpp index 6eb0c6ef2f7d637bce2093844ea5287c0ee217c2..deaafc85a31576b64379053669cfb678fbfc7cfd 100644 --- a/clang/lib/CodeGen/Targets/SystemZ.cpp +++ b/clang/lib/CodeGen/Targets/SystemZ.cpp @@ -306,7 +306,7 @@ Address SystemZABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, // Update overflow_arg_area_ptr pointer llvm::Value *NewOverflowArgArea = CGF.Builder.CreateGEP( - OverflowArgArea.getElementType(), OverflowArgArea.getPointer(), + OverflowArgArea.getElementType(), OverflowArgArea.emitRawPointer(CGF), PaddedSizeV, "overflow_arg_area"); CGF.Builder.CreateStore(NewOverflowArgArea, OverflowArgAreaPtr); @@ -382,10 +382,9 @@ Address SystemZABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, Address MemAddr = RawMemAddr.withElementType(DirectTy); // Update overflow_arg_area_ptr pointer - llvm::Value *NewOverflowArgArea = - CGF.Builder.CreateGEP(OverflowArgArea.getElementType(), - OverflowArgArea.getPointer(), PaddedSizeV, - "overflow_arg_area"); + llvm::Value *NewOverflowArgArea = CGF.Builder.CreateGEP( + OverflowArgArea.getElementType(), OverflowArgArea.emitRawPointer(CGF), + PaddedSizeV, "overflow_arg_area"); CGF.Builder.CreateStore(NewOverflowArgArea, OverflowArgAreaPtr); CGF.EmitBranch(ContBlock); diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp index 1ec0f159ebcb8af2f5c8a209df4a095708bec83f..f04db56db3357dd26364d4ce23fe0ecb6b7ccc1d 100644 --- a/clang/lib/CodeGen/Targets/X86.cpp +++ b/clang/lib/CodeGen/Targets/X86.cpp @@ -1069,6 +1069,12 @@ Address X86_32ABIInfo::EmitVAArg(CodeGenFunction &CGF, auto TypeInfo = getContext().getTypeInfoInChars(Ty); + CCState State(*const_cast(CGF.CurFnInfo)); + ABIArgInfo AI = classifyArgumentType(Ty, State, /*ArgIndex*/ 0); + // Empty records are ignored for parameter passing purposes. + if (AI.isIgnore()) + return CGF.CreateMemTemp(Ty); + // x86-32 changes the alignment of certain arguments on the stack. // // Just messing with TypeInfo like this works because we never pass @@ -1993,7 +1999,7 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo, // this, but it isn't worth it and would be harder to verify. Current = NoClass; uint64_t EltSize = getContext().getTypeSize(AT->getElementType()); - uint64_t ArraySize = AT->getSize().getZExtValue(); + uint64_t ArraySize = AT->getZExtSize(); // The only case a 256-bit wide vector could be used is when the array // contains a single 256-bit element. Since Lo and Hi logic isn't extended @@ -2100,8 +2106,11 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo, postMerge(Size, Lo, Hi); return; } + + bool IsInMemory = + Offset % getContext().getTypeAlign(i->getType().getCanonicalType()); // Note, skip this test for bit-fields, see below. - if (!BitField && Offset % getContext().getTypeAlign(i->getType())) { + if (!BitField && IsInMemory) { Lo = Memory; postMerge(Size, Lo, Hi); return; @@ -2295,7 +2304,7 @@ static bool BitsContainNoUserData(QualType Ty, unsigned StartBit, if (const ConstantArrayType *AT = Context.getAsConstantArrayType(Ty)) { unsigned EltSize = (unsigned)Context.getTypeSize(AT->getElementType()); - unsigned NumElts = (unsigned)AT->getSize().getZExtValue(); + unsigned NumElts = (unsigned)AT->getZExtSize(); // Check each element to see if the element overlaps with the queried range. for (unsigned i = 0; i != NumElts; ++i) { @@ -2788,12 +2797,11 @@ X86_64ABIInfo::classifyArgumentType(QualType Ty, unsigned freeIntRegs, // memory), except in situations involving unions. case X87Up: case SSE: + ++neededSSE; HighPart = GetSSETypeAtOffset(CGT.ConvertType(Ty), 8, Ty, 8); if (Lo == NoClass) // Pass HighPart at offset 8 in memory. return ABIArgInfo::getDirect(HighPart, 8); - - ++neededSSE; break; // AMD64-ABI 3.2.3p3: Rule 4. If the class is SSEUP, the diff --git a/clang/lib/CodeGen/Targets/XCore.cpp b/clang/lib/CodeGen/Targets/XCore.cpp index aeb48f851e16936fea7c188e75cdebea3f2df927..88edb781a947b1f4be7efb7b722d034b9be322c7 100644 --- a/clang/lib/CodeGen/Targets/XCore.cpp +++ b/clang/lib/CodeGen/Targets/XCore.cpp @@ -180,7 +180,7 @@ Address XCoreABIInfo::EmitVAArg(CodeGenFunction &CGF, Address VAListAddr, // Increment the VAList. if (!ArgSize.isZero()) { Address APN = Builder.CreateConstInBoundsByteGEP(AP, ArgSize); - Builder.CreateStore(APN.getPointer(), VAListAddr); + Builder.CreateStore(APN.emitRawPointer(CGF), VAListAddr); } return Val; diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 7a53764364ce4dd91f09e5fc677261a7874f58c1..e7335a61b10c533ecfafd5d3149a167a542518fb 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -49,6 +49,7 @@ #include "ToolChains/WebAssembly.h" #include "ToolChains/XCore.h" #include "ToolChains/ZOS.h" +#include "clang/Basic/DiagnosticDriver.h" #include "clang/Basic/TargetID.h" #include "clang/Basic/Version.h" #include "clang/Config/config.h" @@ -2002,6 +2003,12 @@ void Driver::PrintVersion(const Compilation &C, raw_ostream &OS) const { // Print out the install directory. OS << "InstalledDir: " << Dir << '\n'; + // Print the build config if it's non-default. + // Intended to help LLVM developers understand the configs of compilers + // they're investigating. + if (!llvm::cl::getCompilerBuildConfig().empty()) + llvm::cl::printBuildConfig(OS); + // If configuration files were used, print their paths. for (auto ConfigFile : ConfigFiles) OS << "Configuration file: " << ConfigFile << '\n'; @@ -5814,19 +5821,9 @@ static const char *GetModuleOutputPath(Compilation &C, const JobAction &JA, (C.getArgs().hasArg(options::OPT_fmodule_output) || C.getArgs().hasArg(options::OPT_fmodule_output_EQ))); - if (Arg *ModuleOutputEQ = - C.getArgs().getLastArg(options::OPT_fmodule_output_EQ)) - return C.addResultFile(ModuleOutputEQ->getValue(), &JA); + SmallString<256> OutputPath = + tools::getCXX20NamedModuleOutputPath(C.getArgs(), BaseInput); - SmallString<64> OutputPath; - Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o); - if (FinalOutput && C.getArgs().hasArg(options::OPT_c)) - OutputPath = FinalOutput->getValue(); - else - OutputPath = BaseInput; - - const char *Extension = types::getTypeTempSuffix(JA.getType()); - llvm::sys::path::replace_extension(OutputPath, Extension); return C.addResultFile(C.getArgs().MakeArgString(OutputPath.c_str()), &JA); } @@ -5899,6 +5896,12 @@ const char *Driver::GetNamedOutputPath(Compilation &C, const JobAction &JA, &JA); } + if (JA.getType() == types::TY_API_INFO && + C.getArgs().hasArg(options::OPT_emit_extension_symbol_graphs) && + C.getArgs().hasArg(options::OPT_o)) + Diag(clang::diag::err_drv_unexpected_symbol_graph_output) + << C.getArgs().getLastArgValue(options::OPT_o); + // DXC defaults to standard out when generating assembly. We check this after // any DXC flags that might specify a file. if (AtTopLevel && JA.getType() == types::TY_PP_Asm && IsDXCMode()) diff --git a/clang/lib/Driver/ToolChains/AIX.cpp b/clang/lib/Driver/ToolChains/AIX.cpp index 6e089903a3158a4e79e4cd4f516be2df19d4e6dd..3f10888596a29a04d7dea3f1af0962be4c680b01 100644 --- a/clang/lib/Driver/ToolChains/AIX.cpp +++ b/clang/lib/Driver/ToolChains/AIX.cpp @@ -17,6 +17,8 @@ #include "llvm/ProfileData/InstrProf.h" #include "llvm/Support/Path.h" +#include + using AIX = clang::driver::toolchains::AIX; using namespace clang::driver; using namespace clang::driver::tools; @@ -471,7 +473,7 @@ static void addTocDataOptions(const llvm::opt::ArgList &Args, // the global setting of tocdata in TOCDataGloballyinEffect. // Those that have the opposite setting to TOCDataGloballyinEffect, are added // to ExplicitlySpecifiedGlobals. - llvm::StringSet<> ExplicitlySpecifiedGlobals; + std::set ExplicitlySpecifiedGlobals; for (const auto Arg : Args.filtered(options::OPT_mtocdata_EQ, options::OPT_mno_tocdata_EQ)) { TOCDataSetting ArgTocDataSetting = @@ -486,7 +488,7 @@ static void addTocDataOptions(const llvm::opt::ArgList &Args, ExplicitlySpecifiedGlobals.erase(Val); } - auto buildExceptionList = [](const llvm::StringSet<> &ExplicitValues, + auto buildExceptionList = [](const std::set &ExplicitValues, const char *OptionSpelling) { std::string Option(OptionSpelling); bool IsFirst = true; @@ -495,7 +497,7 @@ static void addTocDataOptions(const llvm::opt::ArgList &Args, Option += ","; IsFirst = false; - Option += E.first(); + Option += E.str(); } return Option; }; diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp index e122379e860e208b3008e4df160a1b16f7627fb6..4e6362a0f40632246ae10abc6512d703332164f0 100644 --- a/clang/lib/Driver/ToolChains/AMDGPU.cpp +++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp @@ -670,6 +670,10 @@ void amdgpu::getAMDGPUTargetFeatures(const Driver &D, options::OPT_mno_wavefrontsize64, false)) Features.push_back("+wavefrontsize64"); + if (Args.hasFlag(options::OPT_mamdgpu_precise_memory_op, + options::OPT_mno_amdgpu_precise_memory_op, false)) + Features.push_back("+precise-memory"); + handleTargetFeaturesGroup(D, Triple, Args, Features, options::OPT_m_amdgpu_Features_Group); } diff --git a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp index 3e6e29584df3ac719a340293419fb2c0a11e6fb5..2cd2b35ee51bc68a7fccda3e76e7f8286a811e2b 100644 --- a/clang/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/clang/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -402,9 +402,6 @@ void aarch64::getAArch64TargetFeatures(const Driver &D, if (Args.hasArg(options::OPT_ffixed_x28)) Features.push_back("+reserve-x28"); - if (Args.hasArg(options::OPT_ffixed_x30)) - Features.push_back("+reserve-x30"); - if (Args.hasArg(options::OPT_fcall_saved_x8)) Features.push_back("+call-saved-x8"); diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 86a287db72a4eb8a95522aab0d7e102e6ff669ec..766a9b91e3c0ada294a3dc4a33f3fa4aeeeca201 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1776,6 +1776,9 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, } AddUnalignedAccessWarning(CmdArgs); + + Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_intrinsics, + options::OPT_fno_ptrauth_intrinsics); } void Clang::AddLoongArchTargetArgs(const ArgList &Args, @@ -3836,6 +3839,24 @@ bool Driver::getDefaultModuleCachePath(SmallVectorImpl &Result) { return false; } +llvm::SmallString<256> +clang::driver::tools::getCXX20NamedModuleOutputPath(const ArgList &Args, + const char *BaseInput) { + if (Arg *ModuleOutputEQ = Args.getLastArg(options::OPT_fmodule_output_EQ)) + return StringRef(ModuleOutputEQ->getValue()); + + SmallString<256> OutputPath; + if (Arg *FinalOutput = Args.getLastArg(options::OPT_o); + FinalOutput && Args.hasArg(options::OPT_c)) + OutputPath = FinalOutput->getValue(); + else + OutputPath = BaseInput; + + const char *Extension = types::getTypeTempSuffix(types::TY_ModuleFile); + llvm::sys::path::replace_extension(OutputPath, Extension); + return OutputPath; +} + static bool RenderModulesOptions(Compilation &C, const Driver &D, const ArgList &Args, const InputInfo &Input, const InputInfo &Output, bool HaveStd20, @@ -4024,9 +4045,18 @@ static bool RenderModulesOptions(Compilation &C, const Driver &D, // module fragment. CmdArgs.push_back("-fskip-odr-check-in-gmf"); - // Claim `-fmodule-output` and `-fmodule-output=` to avoid unused warnings. - Args.ClaimAllArgs(options::OPT_fmodule_output); - Args.ClaimAllArgs(options::OPT_fmodule_output_EQ); + // We need to include the case the input file is a module file here. + // Since the default compilation model for C++ module interface unit will + // create temporary module file and compile the temporary module file + // to get the object file. Then the `-fmodule-output` flag will be + // brought to the second compilation process. So we have to claim it for + // the case too. + if (Input.getType() == driver::types::TY_CXXModule || + Input.getType() == driver::types::TY_PP_CXXModule || + Input.getType() == driver::types::TY_ModuleFile) { + Args.ClaimAllArgs(options::OPT_fmodule_output); + Args.ClaimAllArgs(options::OPT_fmodule_output_EQ); + } return HaveModules; } @@ -5016,11 +5046,26 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, assert(JA.getType() == types::TY_API_INFO && "Extract API actions must generate a API information."); CmdArgs.push_back("-extract-api"); + + if (Arg *PrettySGFArg = Args.getLastArg(options::OPT_emit_pretty_sgf)) + PrettySGFArg->render(Args, CmdArgs); + + Arg *SymbolGraphDirArg = Args.getLastArg(options::OPT_symbol_graph_dir_EQ); + if (Arg *ProductNameArg = Args.getLastArg(options::OPT_product_name_EQ)) ProductNameArg->render(Args, CmdArgs); if (Arg *ExtractAPIIgnoresFileArg = Args.getLastArg(options::OPT_extract_api_ignores_EQ)) ExtractAPIIgnoresFileArg->render(Args, CmdArgs); + if (Arg *EmitExtensionSymbolGraphs = + Args.getLastArg(options::OPT_emit_extension_symbol_graphs)) { + if (!SymbolGraphDirArg) + D.Diag(diag::err_drv_missing_symbol_graph_dir); + + EmitExtensionSymbolGraphs->render(Args, CmdArgs); + } + if (SymbolGraphDirArg) + SymbolGraphDirArg->render(Args, CmdArgs); } else { assert((isa(JA) || isa(JA)) && "Invalid action for clang tool."); @@ -5837,7 +5882,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CM = "large"; if (Triple.isAArch64(64)) { Ok = CM == "tiny" || CM == "small" || CM == "large"; - if (CM == "large" && RelocationModel != llvm::Reloc::Static) + if (CM == "large" && !Triple.isOSBinFormatMachO() && + RelocationModel != llvm::Reloc::Static) D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) << "-fno-pic"; } else if (Triple.isLoongArch()) { @@ -7258,10 +7304,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fno-common is the default, set -fcommon only when that flag is set. Args.addOptInFlag(CmdArgs, options::OPT_fcommon, options::OPT_fno_common); - if (Args.hasFlag(options::OPT_fptrauth_intrinsics, - options::OPT_fno_ptrauth_intrinsics, false)) - CmdArgs.push_back("-fptrauth-intrinsics"); - // -fsigned-bitfields is default, and clang doesn't yet support // -funsigned-bitfields. if (!Args.hasFlag(options::OPT_fsigned_bitfields, diff --git a/clang/lib/Driver/ToolChains/Clang.h b/clang/lib/Driver/ToolChains/Clang.h index 0f503c4bd1c4fea9cc45c47159cf40079fef6f63..18f6c5ed06a59aeed6f627f1829b418eb7648a43 100644 --- a/clang/lib/Driver/ToolChains/Clang.h +++ b/clang/lib/Driver/ToolChains/Clang.h @@ -193,6 +193,21 @@ DwarfFissionKind getDebugFissionKind(const Driver &D, const llvm::opt::ArgList &Args, llvm::opt::Arg *&Arg); +// Calculate the output path of the module file when compiling a module unit +// with the `-fmodule-output` option or `-fmodule-output=` option specified. +// The behavior is: +// - If `-fmodule-output=` is specfied, then the module file is +// writing to the value. +// - Otherwise if the output object file of the module unit is specified, the +// output path +// of the module file should be the same with the output object file except +// the corresponding suffix. This requires both `-o` and `-c` are specified. +// - Otherwise, the output path of the module file will be the same with the +// input with the corresponding suffix. +llvm::SmallString<256> +getCXX20NamedModuleOutputPath(const llvm::opt::ArgList &Args, + const char *BaseInput); + } // end namespace tools } // end namespace driver diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp index 4478865313636d964003035eccbac16911bfda3a..62a53b85ce098b89c83a54701e5c4e6d0bd63bd2 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -758,15 +758,15 @@ bool tools::isTLSDESCEnabled(const ToolChain &TC, void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, ArgStringList &CmdArgs, const InputInfo &Output, const InputInfo &Input, bool IsThinLTO) { - const bool IsOSAIX = ToolChain.getTriple().isOSAIX(); - const bool IsAMDGCN = ToolChain.getTriple().isAMDGCN(); + const llvm::Triple &Triple = ToolChain.getTriple(); + const bool IsOSAIX = Triple.isOSAIX(); + const bool IsAMDGCN = Triple.isAMDGCN(); const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath()); const Driver &D = ToolChain.getDriver(); const bool IsFatLTO = Args.hasArg(options::OPT_ffat_lto_objects); const bool IsUnifiedLTO = Args.hasArg(options::OPT_funified_lto); if (llvm::sys::path::filename(Linker) != "ld.lld" && - llvm::sys::path::stem(Linker) != "ld.lld" && - !ToolChain.getTriple().isOSOpenBSD()) { + llvm::sys::path::stem(Linker) != "ld.lld" && !Triple.isOSOpenBSD()) { // Tell the linker to load the plugin. This has to come before // AddLinkerInputs as gold requires -plugin and AIX ld requires -bplugin to // come before any -plugin-opt/-bplugin_opt that -Wl might forward. @@ -835,7 +835,7 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, // the plugin. // Handle flags for selecting CPU variants. - std::string CPU = getCPUName(D, Args, ToolChain.getTriple()); + std::string CPU = getCPUName(D, Args, Triple); if (!CPU.empty()) CmdArgs.push_back( Args.MakeArgString(Twine(PluginOptPrefix) + ExtraDash + "mcpu=" + CPU)); @@ -966,10 +966,9 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, bool HasRoptr = Args.hasFlag(options::OPT_mxcoff_roptr, options::OPT_mno_xcoff_roptr, false); StringRef OptStr = HasRoptr ? "-mxcoff-roptr" : "-mno-xcoff-roptr"; - if (!IsOSAIX) D.Diag(diag::err_drv_unsupported_opt_for_target) - << OptStr << ToolChain.getTriple().str(); + << OptStr << Triple.str(); if (HasRoptr) { // The data sections option is on by default on AIX. We only need to error @@ -1032,7 +1031,7 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, } if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls, - ToolChain.getTriple().hasDefaultEmulatedTLS())) { + Triple.hasDefaultEmulatedTLS())) { CmdArgs.push_back( Args.MakeArgString(Twine(PluginOptPrefix) + "-emulated-tls")); } @@ -1076,14 +1075,14 @@ void tools::addLTOOptions(const ToolChain &ToolChain, const ArgList &Args, /// Adds the '-lcgpu' and '-lmgpu' libraries to the compilation to include the /// LLVM C library for GPUs. -static void addOpenMPDeviceLibC(const ToolChain &TC, const ArgList &Args, +static void addOpenMPDeviceLibC(const Compilation &C, const ArgList &Args, ArgStringList &CmdArgs) { if (Args.hasArg(options::OPT_nogpulib) || Args.hasArg(options::OPT_nolibc)) return; // Check the resource directory for the LLVM libc GPU declarations. If it's // found we can assume that LLVM was built with support for the GPU libc. - SmallString<256> LibCDecls(TC.getDriver().ResourceDir); + SmallString<256> LibCDecls(C.getDriver().ResourceDir); llvm::sys::path::append(LibCDecls, "include", "llvm_libc_wrappers", "llvm-libc-decls"); bool HasLibC = llvm::sys::fs::exists(LibCDecls) && @@ -1091,38 +1090,23 @@ static void addOpenMPDeviceLibC(const ToolChain &TC, const ArgList &Args, if (!Args.hasFlag(options::OPT_gpulibc, options::OPT_nogpulibc, HasLibC)) return; - // We don't have access to the offloading toolchains here, so determine from - // the arguments if we have any active NVPTX or AMDGPU toolchains. - llvm::DenseSet Libraries; - if (const Arg *Targets = Args.getLastArg(options::OPT_fopenmp_targets_EQ)) { - if (llvm::any_of(Targets->getValues(), - [](auto S) { return llvm::Triple(S).isAMDGPU(); })) { - Libraries.insert("-lcgpu-amdgpu"); - Libraries.insert("-lmgpu-amdgpu"); - } - if (llvm::any_of(Targets->getValues(), - [](auto S) { return llvm::Triple(S).isNVPTX(); })) { - Libraries.insert("-lcgpu-nvptx"); - Libraries.insert("-lmgpu-nvptx"); - } - } + SmallVector ToolChains; + auto TCRange = C.getOffloadToolChains(Action::OFK_OpenMP); + for (auto TI = TCRange.first, TE = TCRange.second; TI != TE; ++TI) + ToolChains.push_back(TI->second); - for (StringRef Arch : Args.getAllArgValues(options::OPT_offload_arch_EQ)) { - if (llvm::any_of(llvm::split(Arch, ","), [](StringRef Str) { - return IsAMDGpuArch(StringToCudaArch(Str)); - })) { - Libraries.insert("-lcgpu-amdgpu"); - Libraries.insert("-lmgpu-amdgpu"); - } - if (llvm::any_of(llvm::split(Arch, ","), [](StringRef Str) { - return IsNVIDIAGpuArch(StringToCudaArch(Str)); - })) { - Libraries.insert("-lcgpu-nvptx"); - Libraries.insert("-lmgpu-nvptx"); - } + if (llvm::any_of(ToolChains, [](const ToolChain *TC) { + return TC->getTriple().isAMDGPU(); + })) { + CmdArgs.push_back("-lcgpu-amdgpu"); + CmdArgs.push_back("-lmgpu-amdgpu"); + } + if (llvm::any_of(ToolChains, [](const ToolChain *TC) { + return TC->getTriple().isNVPTX(); + })) { + CmdArgs.push_back("-lcgpu-nvptx"); + CmdArgs.push_back("-lmgpu-nvptx"); } - - llvm::append_range(CmdArgs, Libraries); } void tools::addOpenMPRuntimeLibraryPath(const ToolChain &TC, @@ -1142,7 +1126,11 @@ void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, options::OPT_fno_rtlib_add_rpath, false)) return; - for (const auto &CandidateRPath : TC.getArchSpecificLibPaths()) { + SmallVector CandidateRPaths(TC.getArchSpecificLibPaths()); + if (const auto CandidateRPath = TC.getStdlibPath()) + CandidateRPaths.emplace_back(*CandidateRPath); + + for (const auto &CandidateRPath : CandidateRPaths) { if (TC.getVFS().exists(CandidateRPath)) { CmdArgs.push_back("-rpath"); CmdArgs.push_back(Args.MakeArgString(CandidateRPath)); @@ -1150,9 +1138,10 @@ void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, } } -bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, - const ArgList &Args, bool ForceStaticHostRuntime, - bool IsOffloadingHost, bool GompNeedsRT) { +bool tools::addOpenMPRuntime(const Compilation &C, ArgStringList &CmdArgs, + const ToolChain &TC, const ArgList &Args, + bool ForceStaticHostRuntime, bool IsOffloadingHost, + bool GompNeedsRT) { if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, options::OPT_fno_openmp, false)) return false; @@ -1193,7 +1182,7 @@ bool tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, CmdArgs.push_back("-lomptarget.devicertl"); if (IsOffloadingHost) - addOpenMPDeviceLibC(TC, Args, CmdArgs); + addOpenMPDeviceLibC(C, Args, CmdArgs); addArchSpecificRPath(TC, Args, CmdArgs); addOpenMPRuntimeLibraryPath(TC, Args, CmdArgs); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h index bb37be4bd6ea05f04d08f3abad37ec256a59850f..5581905db3114463c118802e7d721d9e5a68f0d0 100644 --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -111,8 +111,8 @@ void addOpenMPRuntimeLibraryPath(const ToolChain &TC, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs); /// Returns true, if an OpenMP runtime has been added. -bool addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC, - const llvm::opt::ArgList &Args, +bool addOpenMPRuntime(const Compilation &C, llvm::opt::ArgStringList &CmdArgs, + const ToolChain &TC, const llvm::opt::ArgList &Args, bool ForceStaticHostRuntime = false, bool IsOffloadingHost = false, bool GompNeedsRT = false); diff --git a/clang/lib/Driver/ToolChains/Cuda.cpp b/clang/lib/Driver/ToolChains/Cuda.cpp index 5f0b516e1a1a08f0d40bec2c8f66ba42a277c1b2..6634e6d818b33e5e9c93dce48a346b0877d8faa8 100644 --- a/clang/lib/Driver/ToolChains/Cuda.cpp +++ b/clang/lib/Driver/ToolChains/Cuda.cpp @@ -990,7 +990,10 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, } for (Arg *A : Args) { - DAL->append(A); + // Make sure flags are not duplicated. + if (!llvm::is_contained(*DAL, A)) { + DAL->append(A); + } } if (!BoundArch.empty()) { diff --git a/clang/lib/Driver/ToolChains/Darwin.cpp b/clang/lib/Driver/ToolChains/Darwin.cpp index c7682c7f1d337999670b7ccfd3fa4e84ff0540b5..caf6c4a444fdcec76007c09ffc73c15bc4d3002c 100644 --- a/clang/lib/Driver/ToolChains/Darwin.cpp +++ b/clang/lib/Driver/ToolChains/Darwin.cpp @@ -686,7 +686,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) - addOpenMPRuntime(CmdArgs, getToolChain(), Args); + addOpenMPRuntime(C, CmdArgs, getToolChain(), Args); if (isObjCRuntimeLinked(Args) && !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { diff --git a/clang/lib/Driver/ToolChains/DragonFly.cpp b/clang/lib/Driver/ToolChains/DragonFly.cpp index b59a172bd6ae869633e65ccd436b9bfcb42c3195..1dbc46763c1156c47a771a326e38f268ea7f189b 100644 --- a/clang/lib/Driver/ToolChains/DragonFly.cpp +++ b/clang/lib/Driver/ToolChains/DragonFly.cpp @@ -136,7 +136,7 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; - addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp index 70daa699e3a9497b6e8cf4cc59dc4d798d3f5608..b00068c8098b9ab1ddb0df62949ac66fc28bedb1 100644 --- a/clang/lib/Driver/ToolChains/Flang.cpp +++ b/clang/lib/Driver/ToolChains/Flang.cpp @@ -35,27 +35,18 @@ static void addDashXForInput(const ArgList &Args, const InputInfo &Input, void Flang::addFortranDialectOptions(const ArgList &Args, ArgStringList &CmdArgs) const { - Args.addAllArgs(CmdArgs, {options::OPT_ffixed_form, - options::OPT_ffree_form, - options::OPT_ffixed_line_length_EQ, - options::OPT_fopenmp, - options::OPT_fopenmp_version_EQ, - options::OPT_fopenacc, - options::OPT_finput_charset_EQ, - options::OPT_fimplicit_none, - options::OPT_fno_implicit_none, - options::OPT_fbackslash, - options::OPT_fno_backslash, - options::OPT_flogical_abbreviations, - options::OPT_fno_logical_abbreviations, - options::OPT_fxor_operator, - options::OPT_fno_xor_operator, - options::OPT_falternative_parameter_statement, - options::OPT_fdefault_real_8, - options::OPT_fdefault_integer_8, - options::OPT_fdefault_double_8, - options::OPT_flarge_sizes, - options::OPT_fno_automatic}); + Args.addAllArgs( + CmdArgs, {options::OPT_ffixed_form, options::OPT_ffree_form, + options::OPT_ffixed_line_length_EQ, options::OPT_fopenacc, + options::OPT_finput_charset_EQ, options::OPT_fimplicit_none, + options::OPT_fno_implicit_none, options::OPT_fbackslash, + options::OPT_fno_backslash, options::OPT_flogical_abbreviations, + options::OPT_fno_logical_abbreviations, + options::OPT_fxor_operator, options::OPT_fno_xor_operator, + options::OPT_falternative_parameter_statement, + options::OPT_fdefault_real_8, options::OPT_fdefault_integer_8, + options::OPT_fdefault_double_8, options::OPT_flarge_sizes, + options::OPT_fno_automatic}); } void Flang::addPreprocessingOptions(const ArgList &Args, @@ -273,7 +264,7 @@ static void addVSDefines(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back(Args.MakeArgString("-D_MSC_FULL_VER=" + Twine(ver))); CmdArgs.push_back(Args.MakeArgString("-D_WIN32")); - llvm::Triple triple = TC.getTriple(); + const llvm::Triple &triple = TC.getTriple(); if (triple.isAArch64()) { CmdArgs.push_back("-D_M_ARM64=1"); } else if (triple.isX86() && triple.isArch32Bit()) { @@ -598,7 +589,7 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args, if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath && ApproxFunc && !SignedZeros && - (FPContract == "fast" || FPContract == "")) { + (FPContract == "fast" || FPContract.empty())) { CmdArgs.push_back("-ffast-math"); return; } @@ -688,7 +679,10 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(TripleStr)); if (isa(JA)) { - CmdArgs.push_back("-E"); + CmdArgs.push_back("-E"); + if (Args.getLastArg(options::OPT_dM)) { + CmdArgs.push_back("-dM"); + } } else if (isa(JA) || isa(JA)) { if (JA.getType() == types::TY_Nothing) { CmdArgs.push_back("-fsyntax-only"); @@ -763,6 +757,35 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA, // Add other compile options addOtherOptions(Args, CmdArgs); + // Forward flags for OpenMP. We don't do this if the current action is an + // device offloading action other than OpenMP. + if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, + options::OPT_fno_openmp, false) && + (JA.isDeviceOffloading(Action::OFK_None) || + JA.isDeviceOffloading(Action::OFK_OpenMP))) { + switch (D.getOpenMPRuntime(Args)) { + case Driver::OMPRT_OMP: + case Driver::OMPRT_IOMP5: + // Clang can generate useful OpenMP code for these two runtime libraries. + CmdArgs.push_back("-fopenmp"); + Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); + + // FIXME: Clang supports a whole bunch more flags here. + break; + default: + // By default, if Clang doesn't know how to generate useful OpenMP code + // for a specific runtime library, we just don't pass the '-fopenmp' flag + // down to the actual compilation. + // FIXME: It would be better to have a mode which *only* omits IR + // generation based on the OpenMP support so that we get consistent + // semantic analysis, etc. + const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ); + D.Diag(diag::warn_drv_unsupported_openmp_library) + << A->getSpelling() << A->getValue(); + break; + } + } + // Offloading related options addOffloadOptions(C, Inputs, JA, Args, CmdArgs); diff --git a/clang/lib/Driver/ToolChains/FreeBSD.cpp b/clang/lib/Driver/ToolChains/FreeBSD.cpp index c5757ddebb0f3eed4b96200be1f5f0243d93dd03..a8ee6540001ee4faeef7ad5303c4c4b741314314 100644 --- a/clang/lib/Driver/ToolChains/FreeBSD.cpp +++ b/clang/lib/Driver/ToolChains/FreeBSD.cpp @@ -295,7 +295,7 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Args.hasArg(options::OPT_static); - addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index a9c9d2475809d70d73a13829829ffe8cb62d5ba9..dedbfac6cb25d26b67587d4ed273597366f1296d 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -598,7 +598,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, // FIXME: Only pass GompNeedsRT = true for platforms with libgomp that // require librt. Most modern Linux platforms do, but some may not. - if (addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP, + if (addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP, JA.isHostOffloading(Action::OFK_OpenMP), /* GompNeedsRT= */ true)) // OpenMP runtimes implies pthreads when using the GNU toolchain. diff --git a/clang/lib/Driver/ToolChains/HLSL.cpp b/clang/lib/Driver/ToolChains/HLSL.cpp index 05aac9caa7fb296f893318e2f59d9706ab151f6d..1169b5d8c92dd683495736b429809e1dd452f207 100644 --- a/clang/lib/Driver/ToolChains/HLSL.cpp +++ b/clang/lib/Driver/ToolChains/HLSL.cpp @@ -255,9 +255,7 @@ HLSLToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, if (!DAL->hasArg(options::OPT_O_Group)) { DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), "3"); } - // FIXME: add validation for enable_16bit_types should be after HLSL 2018 and - // shader model 6.2. - // See: https://github.com/llvm/llvm-project/issues/57876 + return DAL; } diff --git a/clang/lib/Driver/ToolChains/Haiku.cpp b/clang/lib/Driver/ToolChains/Haiku.cpp index 30464e2229e65be28b81ddf7941320b754607233..346652a7e4bd8e4581699553769c87f56dda4353 100644 --- a/clang/lib/Driver/ToolChains/Haiku.cpp +++ b/clang/lib/Driver/ToolChains/Haiku.cpp @@ -107,7 +107,7 @@ void haiku::Linker::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_r)) { // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; - addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX() && ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); diff --git a/clang/lib/Driver/ToolChains/MSVC.cpp b/clang/lib/Driver/ToolChains/MSVC.cpp index dc534a33e6d0efe6549e670b8cea660feb8b35d1..fbf2f45b543844827f388bcd24fc88b9e9b6f842 100644 --- a/clang/lib/Driver/ToolChains/MSVC.cpp +++ b/clang/lib/Driver/ToolChains/MSVC.cpp @@ -79,6 +79,11 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back( Args.MakeArgString(std::string("-out:") + Output.getFilename())); + if (Args.hasArg(options::OPT_marm64x)) + CmdArgs.push_back("-machine:arm64x"); + else if (TC.getTriple().isWindowsArm64EC()) + CmdArgs.push_back("-machine:arm64ec"); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && !C.getDriver().IsCLMode() && !C.getDriver().IsFlangMode()) { CmdArgs.push_back("-defaultlib:libcmt"); @@ -1017,4 +1022,7 @@ void MSVCToolChain::addClangTargetOptions( if (DriverArgs.hasFlag(options::OPT_fno_rtti, options::OPT_frtti, /*Default=*/false)) CC1Args.push_back("-D_HAS_STATIC_RTTI=0"); + + if (Arg *A = DriverArgs.getLastArgNoClaim(options::OPT_marm64x)) + A->ignoreTargetSpecific(); } diff --git a/clang/lib/Driver/ToolChains/NetBSD.cpp b/clang/lib/Driver/ToolChains/NetBSD.cpp index 0eec8fddabd5db6c53f18162549fc5516be95ddb..d54f2288294949f7f649931a86512b07a038a956 100644 --- a/clang/lib/Driver/ToolChains/NetBSD.cpp +++ b/clang/lib/Driver/ToolChains/NetBSD.cpp @@ -311,7 +311,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_r)) { // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; - addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) diff --git a/clang/lib/Driver/ToolChains/OpenBSD.cpp b/clang/lib/Driver/ToolChains/OpenBSD.cpp index 6da6728585df93582b6e00ad6fc92264910239e6..e20d9fb1cfc41748cf81fd18ab4ad13f32a9284d 100644 --- a/clang/lib/Driver/ToolChains/OpenBSD.cpp +++ b/clang/lib/Driver/ToolChains/OpenBSD.cpp @@ -221,7 +221,7 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_r)) { // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Static; - addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) diff --git a/clang/lib/Driver/ToolChains/Solaris.cpp b/clang/lib/Driver/ToolChains/Solaris.cpp index 5d7f0ae2a392a675d454a0aa8834c2cfb2efdb5a..7126e018ca5b6f4db3ffe118156b22e544d25f4a 100644 --- a/clang/lib/Driver/ToolChains/Solaris.cpp +++ b/clang/lib/Driver/ToolChains/Solaris.cpp @@ -211,7 +211,7 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, // Use the static OpenMP runtime with -static-openmp bool StaticOpenMP = Args.hasArg(options::OPT_static_openmp) && !Args.hasArg(options::OPT_static); - addOpenMPRuntime(CmdArgs, ToolChain, Args, StaticOpenMP); + addOpenMPRuntime(C, CmdArgs, ToolChain, Args, StaticOpenMP); if (D.CCCIsCXX()) { if (ToolChain.ShouldLinkCXXStdlib(Args)) diff --git a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp index 22f2c47e1d6a13ce02519177432dd90fcfb2f46a..81797c8c4dc75a21f0ab2d48fd6a03ae974a4008 100644 --- a/clang/lib/Edit/RewriteObjCFoundationAPI.cpp +++ b/clang/lib/Edit/RewriteObjCFoundationAPI.cpp @@ -1000,6 +1000,7 @@ static bool rewriteToNumericBoxedExpression(const ObjCMessageExpr *Msg, case CK_LValueToRValue: case CK_NoOp: case CK_UserDefinedConversion: + case CK_HLSLArrayRValue: break; case CK_IntegralCast: { diff --git a/clang/lib/ExtractAPI/API.cpp b/clang/lib/ExtractAPI/API.cpp index aa7a1e9360f47460defaae030f2c10fe7c5eb23d..5a62c5deb240836aeeb4c73d54b7c3faa371db16 100644 --- a/clang/lib/ExtractAPI/API.cpp +++ b/clang/lib/ExtractAPI/API.cpp @@ -13,514 +13,67 @@ //===----------------------------------------------------------------------===// #include "clang/ExtractAPI/API.h" -#include "clang/AST/CommentCommandTraits.h" -#include "clang/AST/CommentLexer.h" #include "clang/AST/RawCommentList.h" +#include "clang/Basic/Module.h" #include "clang/Index/USRGeneration.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/ErrorHandling.h" #include using namespace clang::extractapi; using namespace llvm; -namespace { +SymbolReference::SymbolReference(const APIRecord *R) + : Name(R->Name), USR(R->USR), Record(R) {} -template -RecordTy *addTopLevelRecord(DenseMap &USRLookupTable, - APISet::RecordMap &RecordMap, - StringRef USR, CtorArgsTy &&...CtorArgs) { - auto Result = RecordMap.insert({USR, nullptr}); - - // Create the record if it does not already exist - if (Result.second) - Result.first->second = - std::make_unique(USR, std::forward(CtorArgs)...); - - auto *Record = Result.first->second.get(); - USRLookupTable.insert({USR, Record}); - return Record; -} - -} // namespace - -NamespaceRecord * -APISet::addNamespace(APIRecord *Parent, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, - LinkageInfo Linkage, const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader) { - auto *Record = addTopLevelRecord( - USRBasedLookupTable, Namespaces, USR, Name, Loc, std::move(Availability), - Linkage, Comment, Declaration, SubHeading, IsFromSystemHeader); - - if (Parent) - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - return Record; -} - -GlobalVariableRecord * -APISet::addGlobalVar(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Fragments, - DeclarationFragments SubHeading, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, GlobalVariables, USR, Name, Loc, - std::move(Availability), Linkage, Comment, Fragments, - SubHeading, IsFromSystemHeader); -} - -GlobalVariableTemplateRecord *APISet::addGlobalVariableTemplate( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, Template Template, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, GlobalVariableTemplates, USR, - Name, Loc, std::move(Availability), Linkage, Comment, - Declaration, SubHeading, Template, - IsFromSystemHeader); -} - -GlobalFunctionRecord *APISet::addGlobalFunction( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Fragments, - DeclarationFragments SubHeading, FunctionSignature Signature, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, GlobalFunctions, USR, Name, Loc, - std::move(Availability), Linkage, Comment, Fragments, - SubHeading, Signature, IsFromSystemHeader); -} - -GlobalFunctionTemplateRecord *APISet::addGlobalFunctionTemplate( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, FunctionSignature Signature, - Template Template, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, GlobalFunctionTemplates, USR, - Name, Loc, std::move(Availability), Linkage, Comment, - Declaration, SubHeading, Signature, Template, - IsFromSystemHeader); -} - -GlobalFunctionTemplateSpecializationRecord * -APISet::addGlobalFunctionTemplateSpecialization( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, FunctionSignature Signature, - bool IsFromSystemHeader) { - return addTopLevelRecord( - USRBasedLookupTable, GlobalFunctionTemplateSpecializations, USR, Name, - Loc, std::move(Availability), Linkage, Comment, Declaration, SubHeading, - Signature, IsFromSystemHeader); -} - -EnumConstantRecord *APISet::addEnumConstant(EnumRecord *Enum, StringRef Name, - StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - bool IsFromSystemHeader) { - auto Record = std::make_unique( - USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, - IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Enum->USR, Enum->Name, Enum->getKind(), Enum); - USRBasedLookupTable.insert({USR, Record.get()}); - return Enum->Constants.emplace_back(std::move(Record)).get(); -} - -EnumRecord *APISet::addEnum(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, Enums, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, IsFromSystemHeader); -} - -RecordFieldRecord *APISet::addRecordField( - RecordRecord *Record, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - APIRecord::RecordKind Kind, bool IsFromSystemHeader) { - auto RecordField = std::make_unique( - USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, - Kind, IsFromSystemHeader); - RecordField->ParentInformation = APIRecord::HierarchyInformation( - Record->USR, Record->Name, Record->getKind(), Record); - USRBasedLookupTable.insert({USR, RecordField.get()}); - return Record->Fields.emplace_back(std::move(RecordField)).get(); -} - -RecordRecord *APISet::addRecord(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - APIRecord::RecordKind Kind, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, Records, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Kind, IsFromSystemHeader); -} - -StaticFieldRecord * -APISet::addStaticField(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, SymbolReference Context, - AccessControl Access, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, StaticFields, USR, Name, Loc, - std::move(Availability), Linkage, Comment, - Declaration, SubHeading, Context, Access, - IsFromSystemHeader); -} - -CXXFieldRecord * -APISet::addCXXField(APIRecord *CXXClass, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, AccessControl Access, - bool IsFromSystemHeader) { - auto *Record = addTopLevelRecord( - USRBasedLookupTable, CXXFields, USR, Name, Loc, std::move(Availability), - Comment, Declaration, SubHeading, Access, IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - CXXClass->USR, CXXClass->Name, CXXClass->getKind(), CXXClass); - return Record; -} - -CXXFieldTemplateRecord *APISet::addCXXFieldTemplate( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - AccessControl Access, Template Template, bool IsFromSystemHeader) { - auto *Record = - addTopLevelRecord(USRBasedLookupTable, CXXFieldTemplates, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Access, Template, IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - - return Record; -} - -CXXClassRecord * -APISet::addCXXClass(APIRecord *Parent, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, APIRecord::RecordKind Kind, - AccessControl Access, bool IsFromSystemHeader) { - auto *Record = addTopLevelRecord( - USRBasedLookupTable, CXXClasses, USR, Name, Loc, std::move(Availability), - Comment, Declaration, SubHeading, Kind, Access, IsFromSystemHeader); - if (Parent) - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - return Record; -} - -ClassTemplateRecord *APISet::addClassTemplate( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - Template Template, AccessControl Access, bool IsFromSystemHeader) { - auto *Record = - addTopLevelRecord(USRBasedLookupTable, ClassTemplates, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Template, Access, IsFromSystemHeader); - if (Parent) - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - return Record; -} - -ClassTemplateSpecializationRecord *APISet::addClassTemplateSpecialization( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - AccessControl Access, bool IsFromSystemHeader) { - auto *Record = - addTopLevelRecord(USRBasedLookupTable, ClassTemplateSpecializations, USR, - Name, Loc, std::move(Availability), Comment, - Declaration, SubHeading, Access, IsFromSystemHeader); - if (Parent) - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - return Record; -} - -ClassTemplatePartialSpecializationRecord * -APISet::addClassTemplatePartialSpecialization( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - Template Template, AccessControl Access, bool IsFromSystemHeader) { - auto *Record = addTopLevelRecord( - USRBasedLookupTable, ClassTemplatePartialSpecializations, USR, Name, Loc, - std::move(Availability), Comment, Declaration, SubHeading, Template, - Access, IsFromSystemHeader); - if (Parent) - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - return Record; -} - -GlobalVariableTemplateSpecializationRecord * -APISet::addGlobalVariableTemplateSpecialization( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, - GlobalVariableTemplateSpecializations, USR, Name, - Loc, std::move(Availability), Linkage, Comment, - Declaration, SubHeading, IsFromSystemHeader); -} - -GlobalVariableTemplatePartialSpecializationRecord * -APISet::addGlobalVariableTemplatePartialSpecialization( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, DeclarationFragments Declaration, - DeclarationFragments SubHeading, Template Template, - bool IsFromSystemHeader) { - return addTopLevelRecord( - USRBasedLookupTable, GlobalVariableTemplatePartialSpecializations, USR, - Name, Loc, std::move(Availability), Linkage, Comment, Declaration, - SubHeading, Template, IsFromSystemHeader); -} - -ConceptRecord *APISet::addConcept(StringRef Name, StringRef USR, - PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - Template Template, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, Concepts, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Template, IsFromSystemHeader); -} - -CXXMethodRecord *APISet::addCXXInstanceMethod( - APIRecord *CXXClassRecord, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, - bool IsFromSystemHeader) { - CXXMethodRecord *Record = - addTopLevelRecord(USRBasedLookupTable, CXXInstanceMethods, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Signature, Access, IsFromSystemHeader); - - Record->ParentInformation = APIRecord::HierarchyInformation( - CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(), - CXXClassRecord); - return Record; -} - -CXXMethodRecord *APISet::addCXXStaticMethod( - APIRecord *CXXClassRecord, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, - bool IsFromSystemHeader) { - CXXMethodRecord *Record = - addTopLevelRecord(USRBasedLookupTable, CXXStaticMethods, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Signature, Access, IsFromSystemHeader); - - Record->ParentInformation = APIRecord::HierarchyInformation( - CXXClassRecord->USR, CXXClassRecord->Name, CXXClassRecord->getKind(), - CXXClassRecord); - return Record; -} - -CXXMethodTemplateRecord *APISet::addCXXMethodTemplate( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, Template Template, - bool IsFromSystemHeader) { - auto *Record = addTopLevelRecord(USRBasedLookupTable, CXXMethodTemplates, USR, - Name, Loc, std::move(Availability), Comment, - Declaration, SubHeading, Signature, Access, - Template, IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - - return Record; -} - -CXXMethodTemplateSpecializationRecord *APISet::addCXXMethodTemplateSpec( - APIRecord *Parent, StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, AccessControl Access, - bool IsFromSystemHeader) { - - auto *Record = addTopLevelRecord( - USRBasedLookupTable, CXXMethodTemplateSpecializations, USR, Name, Loc, - std::move(Availability), Comment, Declaration, SubHeading, Signature, - Access, IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Parent->USR, Parent->Name, Parent->getKind(), Parent); - - return Record; -} - -ObjCCategoryRecord *APISet::addObjCCategory( - StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - SymbolReference Interface, bool IsFromSystemHeader, - bool IsFromExternalModule) { - // Create the category record. - auto *Record = - addTopLevelRecord(USRBasedLookupTable, ObjCCategories, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, Interface, IsFromSystemHeader); - - Record->IsFromExternalModule = IsFromExternalModule; - - auto It = ObjCInterfaces.find(Interface.USR); - if (It != ObjCInterfaces.end()) - It->second->Categories.push_back(Record); - - return Record; -} - -ObjCInterfaceRecord * -APISet::addObjCInterface(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, LinkageInfo Linkage, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - SymbolReference SuperClass, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, ObjCInterfaces, USR, Name, Loc, - std::move(Availability), Linkage, Comment, - Declaration, SubHeading, SuperClass, - IsFromSystemHeader); -} - -ObjCMethodRecord *APISet::addObjCMethod( - ObjCContainerRecord *Container, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - FunctionSignature Signature, bool IsInstanceMethod, - bool IsFromSystemHeader) { - std::unique_ptr Record; - if (IsInstanceMethod) - Record = std::make_unique( - USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, IsFromSystemHeader); - else - Record = std::make_unique( - USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Signature, IsFromSystemHeader); - - Record->ParentInformation = APIRecord::HierarchyInformation( - Container->USR, Container->Name, Container->getKind(), Container); - USRBasedLookupTable.insert({USR, Record.get()}); - return Container->Methods.emplace_back(std::move(Record)).get(); -} - -ObjCPropertyRecord *APISet::addObjCProperty( - ObjCContainerRecord *Container, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - ObjCPropertyRecord::AttributeKind Attributes, StringRef GetterName, - StringRef SetterName, bool IsOptional, bool IsInstanceProperty, - bool IsFromSystemHeader) { - std::unique_ptr Record; - if (IsInstanceProperty) - Record = std::make_unique( - USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Attributes, GetterName, SetterName, IsOptional, - IsFromSystemHeader); - else - Record = std::make_unique( - USR, Name, Loc, std::move(Availability), Comment, Declaration, - SubHeading, Attributes, GetterName, SetterName, IsOptional, - IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Container->USR, Container->Name, Container->getKind(), Container); - USRBasedLookupTable.insert({USR, Record.get()}); - return Container->Properties.emplace_back(std::move(Record)).get(); -} - -ObjCInstanceVariableRecord *APISet::addObjCInstanceVariable( - ObjCContainerRecord *Container, StringRef Name, StringRef USR, - PresumedLoc Loc, AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, DeclarationFragments SubHeading, - ObjCInstanceVariableRecord::AccessControl Access, bool IsFromSystemHeader) { - auto Record = std::make_unique( - USR, Name, Loc, std::move(Availability), Comment, Declaration, SubHeading, - Access, IsFromSystemHeader); - Record->ParentInformation = APIRecord::HierarchyInformation( - Container->USR, Container->Name, Container->getKind(), Container); - USRBasedLookupTable.insert({USR, Record.get()}); - return Container->Ivars.emplace_back(std::move(Record)).get(); +APIRecord *APIRecord::castFromRecordContext(const RecordContext *Ctx) { + switch (Ctx->getKind()) { +#define RECORD_CONTEXT(CLASS, KIND) \ + case KIND: \ + return static_cast(const_cast(Ctx)); +#include "clang/ExtractAPI/APIRecords.inc" + default: + return nullptr; + // llvm_unreachable("RecordContext derived class isn't propertly + // implemented"); + } } -ObjCProtocolRecord *APISet::addObjCProtocol(StringRef Name, StringRef USR, - PresumedLoc Loc, - AvailabilityInfo Availability, - const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, ObjCProtocols, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, IsFromSystemHeader); +RecordContext *APIRecord::castToRecordContext(const APIRecord *Record) { + if (!Record) + return nullptr; + switch (Record->getKind()) { +#define RECORD_CONTEXT(CLASS, KIND) \ + case KIND: \ + return static_cast(const_cast(Record)); +#include "clang/ExtractAPI/APIRecords.inc" + default: + return nullptr; + // llvm_unreachable("RecordContext derived class isn't propertly + // implemented"); + } } -MacroDefinitionRecord * -APISet::addMacroDefinition(StringRef Name, StringRef USR, PresumedLoc Loc, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, Macros, USR, Name, Loc, - Declaration, SubHeading, IsFromSystemHeader); -} +void RecordContext::addToRecordChain(APIRecord *Record) const { + if (!First) { + First = Record; + Last = Record; + return; + } -TypedefRecord * -APISet::addTypedef(StringRef Name, StringRef USR, PresumedLoc Loc, - AvailabilityInfo Availability, const DocComment &Comment, - DeclarationFragments Declaration, - DeclarationFragments SubHeading, - SymbolReference UnderlyingType, bool IsFromSystemHeader) { - return addTopLevelRecord(USRBasedLookupTable, Typedefs, USR, Name, Loc, - std::move(Availability), Comment, Declaration, - SubHeading, UnderlyingType, IsFromSystemHeader); + Last->NextInContext = Record; + Last = Record; } APIRecord *APISet::findRecordForUSR(StringRef USR) const { if (USR.empty()) return nullptr; - return USRBasedLookupTable.lookup(USR); -} - -StringRef APISet::recordUSR(const Decl *D) { - SmallString<128> USR; - index::generateUSRForDecl(D, USR); - return copyString(USR); -} + auto FindIt = USRBasedLookupTable.find(USR); + if (FindIt != USRBasedLookupTable.end()) + return FindIt->getSecond().get(); -StringRef APISet::recordUSRForMacro(StringRef Name, SourceLocation SL, - const SourceManager &SM) { - SmallString<128> USR; - index::generateUSRForMacro(Name, SL, SM, USR); - return copyString(USR); + return nullptr; } StringRef APISet::copyString(StringRef String) { @@ -528,15 +81,22 @@ StringRef APISet::copyString(StringRef String) { return {}; // No need to allocate memory and copy if the string has already been stored. - if (StringAllocator.identifyObject(String.data())) + if (Allocator.identifyObject(String.data())) return String; - void *Ptr = StringAllocator.Allocate(String.size(), 1); + void *Ptr = Allocator.Allocate(String.size(), 1); memcpy(Ptr, String.data(), String.size()); return StringRef(reinterpret_cast(Ptr), String.size()); } +SymbolReference APISet::createSymbolReference(StringRef Name, StringRef USR, + StringRef Source) { + return SymbolReference(copyString(Name), copyString(USR), copyString(Source)); +} + APIRecord::~APIRecord() {} +RecordRecord::~RecordRecord() {} +RecordFieldRecord::~RecordFieldRecord() {} ObjCContainerRecord::~ObjCContainerRecord() {} ObjCMethodRecord::~ObjCMethodRecord() {} ObjCPropertyRecord::~ObjCPropertyRecord() {} @@ -546,8 +106,10 @@ void GlobalFunctionRecord::anchor() {} void GlobalVariableRecord::anchor() {} void EnumConstantRecord::anchor() {} void EnumRecord::anchor() {} -void RecordFieldRecord::anchor() {} -void RecordRecord::anchor() {} +void StructFieldRecord::anchor() {} +void StructRecord::anchor() {} +void UnionFieldRecord::anchor() {} +void UnionRecord::anchor() {} void CXXFieldRecord::anchor() {} void CXXClassRecord::anchor() {} void CXXConstructorRecord::anchor() {} diff --git a/clang/lib/ExtractAPI/DeclarationFragments.cpp b/clang/lib/ExtractAPI/DeclarationFragments.cpp index 80a0a498dc40016238cb5bc9ae21bebbe8344afd..0a243120b7c0e35c409ca7a70a269d2a7ff0ac08 100644 --- a/clang/lib/ExtractAPI/DeclarationFragments.cpp +++ b/clang/lib/ExtractAPI/DeclarationFragments.cpp @@ -14,14 +14,11 @@ #include "clang/ExtractAPI/DeclarationFragments.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" -#include "clang/AST/QualTypeNames.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" -#include "clang/Basic/OperatorKinds.h" #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" #include "clang/Index/USRGeneration.h" #include "llvm/ADT/StringSwitch.h" -#include using namespace clang::extractapi; using namespace llvm; @@ -60,23 +57,44 @@ void findTypeLocForBlockDecl(const clang::TypeSourceInfo *TSInfo, } // namespace -DeclarationFragments &DeclarationFragments::appendSpace() { +DeclarationFragments & +DeclarationFragments::appendUnduplicatedTextCharacter(char Character) { if (!Fragments.empty()) { Fragment &Last = Fragments.back(); if (Last.Kind == FragmentKind::Text) { // Merge the extra space into the last fragment if the last fragment is // also text. - if (Last.Spelling.back() != ' ') { // avoid extra trailing spaces. - Last.Spelling.push_back(' '); + if (Last.Spelling.back() != Character) { // avoid duplicates at end + Last.Spelling.push_back(Character); } } else { - append(" ", FragmentKind::Text); + append("", FragmentKind::Text); + Fragments.back().Spelling.push_back(Character); } } return *this; } +DeclarationFragments &DeclarationFragments::appendSpace() { + return appendUnduplicatedTextCharacter(' '); +} + +DeclarationFragments &DeclarationFragments::appendSemicolon() { + return appendUnduplicatedTextCharacter(';'); +} + +DeclarationFragments &DeclarationFragments::removeTrailingSemicolon() { + if (Fragments.empty()) + return *this; + + Fragment &Last = Fragments.back(); + if (Last.Kind == FragmentKind::Text && Last.Spelling.back() == ';') + Last.Spelling.pop_back(); + + return *this; +} + StringRef DeclarationFragments::getFragmentKindString( DeclarationFragments::FragmentKind Kind) { switch (Kind) { @@ -469,7 +487,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForNamespace( if (!Decl->isAnonymousNamespace()) Fragments.appendSpace().append( Decl->getName(), DeclarationFragments::FragmentKind::Identifier); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments @@ -511,7 +529,7 @@ DeclarationFragmentsBuilder::getFragmentsForVar(const VarDecl *Var) { return Fragments .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier) .append(std::move(After)) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -535,15 +553,13 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplate(const VarDecl *Var) { getFragmentsForType(T, Var->getASTContext(), After); if (StringRef(ArgumentFragment.begin()->Spelling) .starts_with("type-parameter")) { - std::string ProperArgName = getNameForTemplateArgument( - Var->getDescribedVarTemplate()->getTemplateParameters()->asArray(), - ArgumentFragment.begin()->Spelling); + std::string ProperArgName = T.getAsString(); ArgumentFragment.begin()->Spelling.swap(ProperArgName); } Fragments.append(std::move(ArgumentFragment)) .appendSpace() .append(Var->getName(), DeclarationFragments::FragmentKind::Identifier) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); return Fragments; } @@ -570,12 +586,7 @@ DeclarationFragmentsBuilder::getFragmentsForParam(const ParmVarDecl *Param) { if (StringRef(TypeFragments.begin()->Spelling) .starts_with("type-parameter")) { - std::string ProperArgName = getNameForTemplateArgument( - dyn_cast(Param->getDeclContext()) - ->getDescribedFunctionTemplate() - ->getTemplateParameters() - ->asArray(), - TypeFragments.begin()->Spelling); + std::string ProperArgName = Param->getOriginalType().getAsString(); TypeFragments.begin()->Spelling.swap(ProperArgName); } @@ -668,11 +679,7 @@ DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) { getFragmentsForType(Func->getReturnType(), Func->getASTContext(), After); if (StringRef(ReturnValueFragment.begin()->Spelling) .starts_with("type-parameter")) { - std::string ProperArgName = - getNameForTemplateArgument(Func->getDescribedFunctionTemplate() - ->getTemplateParameters() - ->asArray(), - ReturnValueFragment.begin()->Spelling); + std::string ProperArgName = Func->getReturnType().getAsString(); ReturnValueFragment.begin()->Spelling.swap(ProperArgName); } @@ -712,7 +719,7 @@ DeclarationFragmentsBuilder::getFragmentsForFunction(const FunctionDecl *Func) { Fragments.append(DeclarationFragments::getExceptionSpecificationString( Func->getExceptionSpecType())); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForEnumConstant( @@ -741,7 +748,7 @@ DeclarationFragmentsBuilder::getFragmentsForEnum(const EnumDecl *EnumDecl) { getFragmentsForType(IntegerType, EnumDecl->getASTContext(), After)) .append(std::move(After)); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments @@ -757,7 +764,7 @@ DeclarationFragmentsBuilder::getFragmentsForField(const FieldDecl *Field) { .appendSpace() .append(Field->getName(), DeclarationFragments::FragmentKind::Identifier) .append(std::move(After)) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForRecordDecl( @@ -775,7 +782,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForRecordDecl( Fragments.appendSpace().append( Record->getName(), DeclarationFragments::FragmentKind::Identifier); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXClass( @@ -790,7 +797,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXClass( Fragments.appendSpace().append( Record->getName(), DeclarationFragments::FragmentKind::Identifier); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments @@ -820,7 +827,7 @@ DeclarationFragmentsBuilder::getFragmentsForSpecialCXXMethod( Fragments.append(DeclarationFragments::getExceptionSpecificationString( Method->getExceptionSpecType())); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXMethod( @@ -860,7 +867,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForCXXMethod( Fragments.append(DeclarationFragments::getExceptionSpecificationString( Method->getExceptionSpecType())); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments @@ -891,7 +898,7 @@ DeclarationFragmentsBuilder::getFragmentsForConversionFunction( Fragments.appendSpace().append("const", DeclarationFragments::FragmentKind::Keyword); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments @@ -923,7 +930,7 @@ DeclarationFragmentsBuilder::getFragmentsForOverloadedOperator( Fragments.append(DeclarationFragments::getExceptionSpecificationString( Method->getExceptionSpecType())); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } // Get fragments for template parameters, e.g. T in tempalte ... @@ -961,25 +968,6 @@ DeclarationFragmentsBuilder::getFragmentsForTemplateParameters( return Fragments; } -// Find the name of a template argument from the template's parameters. -std::string DeclarationFragmentsBuilder::getNameForTemplateArgument( - const ArrayRef TemplateParameters, std::string TypeParameter) { - // The arg is a generic parameter from a partial spec, e.g. - // T in template Foo. - // - // Those names appear as "type-parameter--", so we must find its - // name from the template's parameter list. - for (unsigned i = 0; i < TemplateParameters.size(); ++i) { - const auto *Parameter = - dyn_cast(TemplateParameters[i]); - if (TypeParameter.compare("type-parameter-" + - std::to_string(Parameter->getDepth()) + "-" + - std::to_string(Parameter->getIndex())) == 0) - return std::string(TemplateParameters[i]->getName()); - } - llvm_unreachable("Could not find the name of a template argument."); -} - // Get fragments for template arguments, e.g. int in template // Foo; // @@ -989,7 +977,7 @@ std::string DeclarationFragmentsBuilder::getNameForTemplateArgument( DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForTemplateArguments( const ArrayRef TemplateArguments, ASTContext &Context, - const std::optional> TemplateParameters) { + const std::optional> TemplateArgumentLocs) { DeclarationFragments Fragments; for (unsigned i = 0, end = TemplateArguments.size(); i != end; ++i) { if (i) @@ -1003,8 +991,10 @@ DeclarationFragmentsBuilder::getFragmentsForTemplateArguments( if (StringRef(ArgumentFragment.begin()->Spelling) .starts_with("type-parameter")) { - std::string ProperArgName = getNameForTemplateArgument( - TemplateParameters.value(), ArgumentFragment.begin()->Spelling); + std::string ProperArgName = TemplateArgumentLocs.value()[i] + .getTypeSourceInfo() + ->getType() + .getAsString(); ArgumentFragment.begin()->Spelling.swap(ProperArgName); } Fragments.append(std::move(ArgumentFragment)); @@ -1028,7 +1018,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForConcept( .appendSpace() .append(Concept->getName().str(), DeclarationFragments::FragmentKind::Identifier) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -1069,7 +1059,7 @@ DeclarationFragmentsBuilder::getFragmentsForClassTemplateSpecialization( getFragmentsForTemplateArguments(Decl->getTemplateArgs().asArray(), Decl->getASTContext(), std::nullopt)) .append(">", DeclarationFragments::FragmentKind::Text) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -1089,9 +1079,9 @@ DeclarationFragmentsBuilder::getFragmentsForClassTemplatePartialSpecialization( .append("<", DeclarationFragments::FragmentKind::Text) .append(getFragmentsForTemplateArguments( Decl->getTemplateArgs().asArray(), Decl->getASTContext(), - Decl->getTemplateParameters()->asArray())) + Decl->getTemplateArgsAsWritten()->arguments())) .append(">", DeclarationFragments::FragmentKind::Text) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -1110,7 +1100,7 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplateSpecialization( getFragmentsForTemplateArguments(Decl->getTemplateArgs().asArray(), Decl->getASTContext(), std::nullopt)) .append(">", DeclarationFragments::FragmentKind::Text) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -1130,9 +1120,9 @@ DeclarationFragmentsBuilder::getFragmentsForVarTemplatePartialSpecialization( .append("<", DeclarationFragments::FragmentKind::Text) .append(getFragmentsForTemplateArguments( Decl->getTemplateArgs().asArray(), Decl->getASTContext(), - Decl->getTemplateParameters()->asArray())) + Decl->getTemplateArgsAsWritten()->arguments())) .append(">", DeclarationFragments::FragmentKind::Text) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments @@ -1203,7 +1193,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCCategory( Fragments.append("@interface", DeclarationFragments::FragmentKind::Keyword) .appendSpace() - .append(Category->getClassInterface()->getName(), + .append(Interface->getName(), DeclarationFragments::FragmentKind::TypeIdentifier, InterfaceUSR, Interface) .append(" (", DeclarationFragments::FragmentKind::Text) @@ -1277,7 +1267,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCMethod( Fragments.append(getFragmentsForParam(Param)); } - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty( @@ -1378,7 +1368,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProperty( .append(Property->getName(), DeclarationFragments::FragmentKind::Identifier) .append(std::move(After)) - .append(";", DeclarationFragments::FragmentKind::Text); + .appendSemicolon(); } DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForObjCProtocol( @@ -1422,7 +1412,7 @@ DeclarationFragments DeclarationFragmentsBuilder::getFragmentsForTypedef( .appendSpace() .append(Decl->getName(), DeclarationFragments::FragmentKind::Identifier); - return Fragments.append(";", DeclarationFragments::FragmentKind::Text); + return Fragments.appendSemicolon(); } // Instantiate template for FunctionDecl. diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp index 275f49be22e15ab42c0c6f057c3c61e66a272532..d6335854cbf262c3b80f4c8ba16beb146f0acc73 100644 --- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp +++ b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp @@ -30,6 +30,7 @@ #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/FrontendOptions.h" #include "clang/Frontend/MultiplexConsumer.h" +#include "clang/Index/USRGeneration.h" #include "clang/InstallAPI/HeaderFile.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/PPCallbacks.h" @@ -39,6 +40,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" @@ -327,11 +329,12 @@ public: StringRef Name = PM.MacroNameToken.getIdentifierInfo()->getName(); PresumedLoc Loc = SM.getPresumedLoc(PM.MacroNameToken.getLocation()); - StringRef USR = - API.recordUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM); + SmallString<128> USR; + index::generateUSRForMacro(Name, PM.MacroNameToken.getLocation(), SM, + USR); - API.addMacroDefinition( - Name, USR, Loc, + API.createRecord( + USR, Name, SymbolReference(), Loc, DeclarationFragmentsBuilder::getFragmentsForMacro(Name, PM.MD), DeclarationFragmentsBuilder::getSubHeadingForMacro(Name), SM.isInSystemHeader(PM.MacroNameToken.getLocation())); @@ -372,40 +375,57 @@ private: LocationFileChecker &LCF; }; +std::unique_ptr +createAdditionalSymbolGraphFile(CompilerInstance &CI, Twine BaseName) { + auto OutputDirectory = CI.getFrontendOpts().SymbolGraphOutputDir; + + SmallString<256> FileName; + llvm::sys::path::append(FileName, OutputDirectory, + BaseName + ".symbols.json"); + return CI.createOutputFile( + FileName, /*Binary*/ false, /*RemoveFileOnSignal*/ false, + /*UseTemporary*/ true, /*CreateMissingDirectories*/ true); +} + } // namespace -void ExtractAPIActionBase::ImplEndSourceFileAction() { - if (!OS) - return; +void ExtractAPIActionBase::ImplEndSourceFileAction(CompilerInstance &CI) { + SymbolGraphSerializerOption SerializationOptions; + SerializationOptions.Compact = !CI.getFrontendOpts().EmitPrettySymbolGraphs; + SerializationOptions.EmitSymbolLabelsForTesting = + CI.getFrontendOpts().EmitSymbolGraphSymbolLabelsForTesting; + + if (CI.getFrontendOpts().EmitExtensionSymbolGraphs) { + auto ConstructOutputFile = [&CI](Twine BaseName) { + return createAdditionalSymbolGraphFile(CI, BaseName); + }; + + SymbolGraphSerializer::serializeWithExtensionGraphs( + *OS, *API, IgnoresList, ConstructOutputFile, SerializationOptions); + } else { + SymbolGraphSerializer::serializeMainSymbolGraph(*OS, *API, IgnoresList, + SerializationOptions); + } - // Setup a SymbolGraphSerializer to write out collected API information in - // the Symbol Graph format. - // FIXME: Make the kind of APISerializer configurable. - SymbolGraphSerializer SGSerializer(*API, IgnoresList); - SGSerializer.serialize(*OS); + // Flush the stream and close the main output stream. OS.reset(); } -std::unique_ptr -ExtractAPIAction::CreateOutputFile(CompilerInstance &CI, StringRef InFile) { - std::unique_ptr OS; - OS = CI.createDefaultOutputFile(/*Binary=*/false, InFile, - /*Extension=*/"json", - /*RemoveFileOnSignal=*/false); - if (!OS) - return nullptr; - return OS; -} - std::unique_ptr ExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) { - OS = CreateOutputFile(CI, InFile); + auto ProductName = CI.getFrontendOpts().ProductName; + + if (CI.getFrontendOpts().SymbolGraphOutputDir.empty()) + OS = CI.createDefaultOutputFile(/*Binary*/ false, InFile, + /*Extension*/ "symbols.json", + /*RemoveFileOnSignal*/ false, + /*CreateMissingDirectories*/ true); + else + OS = createAdditionalSymbolGraphFile(CI, ProductName); if (!OS) return nullptr; - auto ProductName = CI.getFrontendOpts().ProductName; - // Now that we have enough information about the language options and the // target triple, let's create the APISet before anyone uses it. API = std::make_unique( @@ -495,7 +515,9 @@ bool ExtractAPIAction::PrepareToExecuteAction(CompilerInstance &CI) { return true; } -void ExtractAPIAction::EndSourceFileAction() { ImplEndSourceFileAction(); } +void ExtractAPIAction::EndSourceFileAction() { + ImplEndSourceFileAction(getCompilerInstance()); +} std::unique_ptr WrappingExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, @@ -506,11 +528,9 @@ WrappingExtractAPIAction::CreateASTConsumer(CompilerInstance &CI, CreatedASTConsumer = true; - OS = CreateOutputFile(CI, InFile); - if (!OS) - return nullptr; - - auto ProductName = CI.getFrontendOpts().ProductName; + ProductName = CI.getFrontendOpts().ProductName; + auto InputFilename = llvm::sys::path::filename(InFile); + OS = createAdditionalSymbolGraphFile(CI, InputFilename); // Now that we have enough information about the language options and the // target triple, let's create the APISet before anyone uses it. @@ -552,32 +572,6 @@ void WrappingExtractAPIAction::EndSourceFileAction() { WrapperFrontendAction::EndSourceFileAction(); if (CreatedASTConsumer) { - ImplEndSourceFileAction(); + ImplEndSourceFileAction(getCompilerInstance()); } } - -std::unique_ptr -WrappingExtractAPIAction::CreateOutputFile(CompilerInstance &CI, - StringRef InFile) { - std::unique_ptr OS; - std::string OutputDir = CI.getFrontendOpts().SymbolGraphOutputDir; - - // The symbol graphs need to be generated as a side effect of regular - // compilation so the output should be dumped in the directory provided with - // the command line option. - llvm::SmallString<128> OutFilePath(OutputDir); - auto Seperator = llvm::sys::path::get_separator(); - auto Infilename = llvm::sys::path::filename(InFile); - OutFilePath.append({Seperator, Infilename}); - llvm::sys::path::replace_extension(OutFilePath, "json"); - // StringRef outputFilePathref = *OutFilePath; - - // don't use the default output file - OS = CI.createOutputFile(/*OutputPath=*/OutFilePath, /*Binary=*/false, - /*RemoveFileOnSignal=*/true, - /*UseTemporary=*/true, - /*CreateMissingDirectories=*/true); - if (!OS) - return nullptr; - return OS; -} diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp index 545860acb7db804fbe99321698b28db30ecc1eac..57f966c8b2be35def3a2b0ca408d6c52e79a07cb 100644 --- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -14,13 +14,17 @@ #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Version.h" +#include "clang/ExtractAPI/API.h" #include "clang/ExtractAPI/DeclarationFragments.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLFunctionalExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Path.h" #include "llvm/Support/VersionTuple.h" +#include "llvm/Support/raw_ostream.h" +#include #include #include @@ -33,26 +37,27 @@ namespace { /// Helper function to inject a JSON object \p Obj into another object \p Paren /// at position \p Key. -void serializeObject(Object &Paren, StringRef Key, std::optional Obj) { +void serializeObject(Object &Paren, StringRef Key, + std::optional &&Obj) { if (Obj) Paren[Key] = std::move(*Obj); } -/// Helper function to inject a StringRef \p String into an object \p Paren at -/// position \p Key -void serializeString(Object &Paren, StringRef Key, - std::optional String) { - if (String) - Paren[Key] = std::move(*String); -} - /// Helper function to inject a JSON array \p Array into object \p Paren at /// position \p Key. -void serializeArray(Object &Paren, StringRef Key, std::optional Array) { +void serializeArray(Object &Paren, StringRef Key, + std::optional &&Array) { if (Array) Paren[Key] = std::move(*Array); } +/// Helper function to inject a JSON array composed of the values in \p C into +/// object \p Paren at position \p Key. +template +void serializeArray(Object &Paren, StringRef Key, ContainerTy &&C) { + Paren[Key] = Array(C); +} + /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version /// format. /// @@ -248,6 +253,7 @@ std::optional serializeDocComment(const DocComment &Comment) { return std::nullopt; Object DocComment; + Array LinesArray; for (const auto &CommentLine : Comment) { Object Line; @@ -256,7 +262,8 @@ std::optional serializeDocComment(const DocComment &Comment) { serializeSourceRange(CommentLine.Begin, CommentLine.End)); LinesArray.emplace_back(std::move(Line)); } - serializeArray(DocComment, "lines", LinesArray); + + serializeArray(DocComment, "lines", std::move(LinesArray)); return DocComment; } @@ -322,19 +329,14 @@ serializeDeclarationFragments(const DeclarationFragments &DF) { /// - \c subHeading : An array of declaration fragments that provides tags, /// and potentially more tokens (for example the \c +/- symbol for /// Objective-C methods). Can be used as sub-headings for documentation. -Object serializeNames(const APIRecord &Record) { +Object serializeNames(const APIRecord *Record) { Object Names; - if (auto *CategoryRecord = - dyn_cast_or_null(&Record)) - Names["title"] = - (CategoryRecord->Interface.Name + " (" + Record.Name + ")").str(); - else - Names["title"] = Record.Name; + Names["title"] = Record->Name; serializeArray(Names, "subHeading", - serializeDeclarationFragments(Record.SubHeading)); + serializeDeclarationFragments(Record->SubHeading)); DeclarationFragments NavigatorFragments; - NavigatorFragments.append(Record.Name, + NavigatorFragments.append(Record->Name, DeclarationFragments::FragmentKind::Identifier, /*PreciseIdentifier*/ ""); serializeArray(Names, "navigator", @@ -351,7 +353,8 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { Object Kind; switch (RK) { case APIRecord::RK_Unknown: - llvm_unreachable("Records should have an explicit kind"); + Kind["identifier"] = AddLangPrefix("unknown"); + Kind["displayName"] = "Unknown"; break; case APIRecord::RK_Namespace: Kind["identifier"] = AddLangPrefix("namespace"); @@ -484,10 +487,6 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { Kind["identifier"] = AddLangPrefix("class.extension"); Kind["displayName"] = "Class Extension"; break; - case APIRecord::RK_ObjCCategoryModule: - Kind["identifier"] = AddLangPrefix("module.extension"); - Kind["displayName"] = "Module Extension"; - break; case APIRecord::RK_ObjCProtocol: Kind["identifier"] = AddLangPrefix("protocol"); Kind["displayName"] = "Protocol"; @@ -500,6 +499,8 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { Kind["identifier"] = AddLangPrefix("typealias"); Kind["displayName"] = "Type Alias"; break; + default: + llvm_unreachable("API Record with uninstantiable kind"); } return Kind; @@ -514,12 +515,18 @@ Object serializeSymbolKind(const APIRecord &Record, Language Lang) { return serializeSymbolKind(Record.getKind(), Lang); } +/// Serialize the function signature field, as specified by the +/// Symbol Graph format. +/// +/// The Symbol Graph function signature property contains two arrays. +/// - The \c returns array is the declaration fragments of the return type; +/// - The \c parameters array contains names and declaration fragments of the +/// parameters. template -std::optional -serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) { +void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { const auto &FS = Record.Signature; if (FS.empty()) - return std::nullopt; + return; Object Signature; serializeArray(Signature, "returns", @@ -537,63 +544,14 @@ serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) { if (!Parameters.empty()) Signature["parameters"] = std::move(Parameters); - return Signature; + serializeObject(Paren, "functionSignature", std::move(Signature)); } template -std::optional -serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) { - return std::nullopt; -} - -/// Serialize the function signature field, as specified by the -/// Symbol Graph format. -/// -/// The Symbol Graph function signature property contains two arrays. -/// - The \c returns array is the declaration fragments of the return type; -/// - The \c parameters array contains names and declaration fragments of the -/// parameters. -/// -/// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the -/// formatted function signature. -template -void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { - serializeObject(Paren, "functionSignature", - serializeFunctionSignatureMixinImpl( - Record, has_function_signature())); -} - -template -std::optional serializeAccessMixinImpl(const RecordTy &Record, - std::true_type) { - const auto &AccessControl = Record.Access; - std::string Access; - if (AccessControl.empty()) - return std::nullopt; - Access = AccessControl.getAccess(); - return Access; -} - -template -std::optional serializeAccessMixinImpl(const RecordTy &Record, - std::false_type) { - return std::nullopt; -} - -template -void serializeAccessMixin(Object &Paren, const RecordTy &Record) { - auto accessLevel = serializeAccessMixinImpl(Record, has_access()); - if (!accessLevel.has_value()) - accessLevel = "public"; - serializeString(Paren, "accessLevel", accessLevel); -} - -template -std::optional serializeTemplateMixinImpl(const RecordTy &Record, - std::true_type) { +void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { const auto &Template = Record.Templ; if (Template.empty()) - return std::nullopt; + return; Object Generics; Array GenericParameters; @@ -619,97 +577,66 @@ std::optional serializeTemplateMixinImpl(const RecordTy &Record, if (!GenericConstraints.empty()) Generics["constraints"] = std::move(GenericConstraints); - return Generics; -} - -template -std::optional serializeTemplateMixinImpl(const RecordTy &Record, - std::false_type) { - return std::nullopt; + serializeObject(Paren, "swiftGenerics", Generics); } -template -void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { - serializeObject(Paren, "swiftGenerics", - serializeTemplateMixinImpl(Record, has_template())); -} +Array generateParentContexts(const SmallVectorImpl &Parents, + Language Lang) { + Array ParentContexts; -struct PathComponent { - StringRef USR; - StringRef Name; - APIRecord::RecordKind Kind; + for (const auto &Parent : Parents) { + Object Elem; + Elem["usr"] = Parent.USR; + Elem["name"] = Parent.Name; + if (Parent.Record) + Elem["kind"] = + serializeSymbolKind(Parent.Record->getKind(), Lang)["identifier"]; + else + Elem["kind"] = + serializeSymbolKind(APIRecord::RK_Unknown, Lang)["identifier"]; + ParentContexts.emplace_back(std::move(Elem)); + } - PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind) - : USR(USR), Name(Name), Kind(Kind) {} -}; + return ParentContexts; +} -template -bool generatePathComponents( - const RecordTy &Record, const APISet &API, - function_ref ComponentTransformer) { - SmallVector ReverseComponenents; - ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind()); - const auto *CurrentParent = &Record.ParentInformation; - bool FailedToFindParent = false; - while (CurrentParent && !CurrentParent->empty()) { - PathComponent CurrentParentComponent(CurrentParent->ParentUSR, - CurrentParent->ParentName, - CurrentParent->ParentKind); - - auto *ParentRecord = CurrentParent->ParentRecord; - // Slow path if we don't have a direct reference to the ParentRecord - if (!ParentRecord) - ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR); - - // If the parent is a category extended from internal module then we need to - // pretend this belongs to the associated interface. - if (auto *CategoryRecord = - dyn_cast_or_null(ParentRecord)) { - if (!CategoryRecord->IsFromExternalModule) { - ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR); - CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR, - CategoryRecord->Interface.Name, - APIRecord::RK_ObjCInterface); - } - } - - // The parent record doesn't exist which means the symbol shouldn't be - // treated as part of the current product. - if (!ParentRecord) { - FailedToFindParent = true; - break; - } - - ReverseComponenents.push_back(std::move(CurrentParentComponent)); - CurrentParent = &ParentRecord->ParentInformation; +/// Walk the records parent information in reverse to generate a hierarchy +/// suitable for serialization. +SmallVector +generateHierarchyFromRecord(const APIRecord *Record) { + SmallVector ReverseHierarchy; + for (const auto *Current = Record; Current != nullptr; + Current = Current->Parent.Record) + ReverseHierarchy.emplace_back(Current); + + return SmallVector( + std::make_move_iterator(ReverseHierarchy.rbegin()), + std::make_move_iterator(ReverseHierarchy.rend())); +} + +SymbolReference getHierarchyReference(const APIRecord *Record, + const APISet &API) { + // If the parent is a category extended from internal module then we need to + // pretend this belongs to the associated interface. + if (auto *CategoryRecord = dyn_cast_or_null(Record)) { + return CategoryRecord->Interface; + // FIXME: TODO generate path components correctly for categories extending + // an external module. } - for (const auto &PC : reverse(ReverseComponenents)) - ComponentTransformer(PC); - - return FailedToFindParent; + return SymbolReference(Record); } -Object serializeParentContext(const PathComponent &PC, Language Lang) { - Object ParentContextElem; - ParentContextElem["usr"] = PC.USR; - ParentContextElem["name"] = PC.Name; - ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"]; - return ParentContextElem; -} +} // namespace -template -Array generateParentContexts(const RecordTy &Record, const APISet &API, - Language Lang) { - Array ParentContexts; - generatePathComponents( - Record, API, [Lang, &ParentContexts](const PathComponent &PC) { - ParentContexts.push_back(serializeParentContext(PC, Lang)); - }); +Object *ExtendedModule::addSymbol(Object &&Symbol) { + Symbols.emplace_back(std::move(Symbol)); + return Symbols.back().getAsObject(); +} - return ParentContexts; +void ExtendedModule::addRelationship(Object &&Relationship) { + Relationships.emplace_back(std::move(Relationship)); } -} // namespace /// Defines the format version emitted by SymbolGraphSerializer. const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3}; @@ -722,84 +649,44 @@ Object SymbolGraphSerializer::serializeMetadata() const { return Metadata; } -Object SymbolGraphSerializer::serializeModule() const { +Object +SymbolGraphSerializer::serializeModuleObject(StringRef ModuleName) const { Object Module; - // The user is expected to always pass `--product-name=` on the command line - // to populate this field. - Module["name"] = API.ProductName; + Module["name"] = ModuleName; serializeObject(Module, "platform", serializePlatform(API.getTarget())); return Module; } -bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const { - // Skip explicitly ignored symbols. - if (IgnoresList.shouldIgnore(Record.Name)) +bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const { + if (!Record) return true; // Skip unconditionally unavailable symbols - if (Record.Availability.isUnconditionallyUnavailable()) + if (Record->Availability.isUnconditionallyUnavailable()) return true; // Filter out symbols prefixed with an underscored as they are understood to // be symbols clients should not use. - if (Record.Name.starts_with("_")) + if (Record->Name.starts_with("_")) + return true; + + // Skip explicitly ignored symbols. + if (IgnoresList.shouldIgnore(Record->Name)) return true; return false; } -template -std::optional -SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const { - if (shouldSkip(Record)) - return std::nullopt; - - Object Obj; - serializeObject(Obj, "identifier", - serializeIdentifier(Record, API.getLanguage())); - serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage())); - serializeObject(Obj, "names", serializeNames(Record)); - serializeObject( - Obj, "location", - serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true)); - serializeArray(Obj, "availability", - serializeAvailability(Record.Availability)); - serializeObject(Obj, "docComment", serializeDocComment(Record.Comment)); - serializeArray(Obj, "declarationFragments", - serializeDeclarationFragments(Record.Declaration)); - SmallVector PathComponentsNames; - // If this returns true it indicates that we couldn't find a symbol in the - // hierarchy. - if (generatePathComponents(Record, API, - [&PathComponentsNames](const PathComponent &PC) { - PathComponentsNames.push_back(PC.Name); - })) - return {}; - - serializeArray(Obj, "pathComponents", Array(PathComponentsNames)); +ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() { + if (!ForceEmitToMainModule && ModuleForCurrentSymbol) + return *ModuleForCurrentSymbol; - serializeFunctionSignatureMixin(Obj, Record); - serializeAccessMixin(Obj, Record); - serializeTemplateMixin(Obj, Record); - - return Obj; + return MainModule; } -template -void SymbolGraphSerializer::serializeMembers( - const APIRecord &Record, - const SmallVector> &Members) { - // Members should not be serialized if we aren't recursing. - if (!ShouldRecurse) - return; - for (const auto &Member : Members) { - auto MemberRecord = serializeAPIRecord(*Member); - if (!MemberRecord) - continue; - - Symbols.emplace_back(std::move(*MemberRecord)); - serializeRelationship(RelationshipKind::MemberOf, *Member, Record); - } +Array SymbolGraphSerializer::serializePathComponents( + const APIRecord *Record) const { + return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; })); } StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { @@ -816,6 +703,33 @@ StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { llvm_unreachable("Unhandled relationship kind"); } +void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, + const SymbolReference &Source, + const SymbolReference &Target, + ExtendedModule &Into) { + Object Relationship; + SmallString<64> TestRelLabel; + if (EmitSymbolLabelsForTesting) { + llvm::raw_svector_ostream OS(TestRelLabel); + OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ " + << Source.USR << " $ "; + if (Target.USR.empty()) + OS << Target.Name; + else + OS << Target.USR; + Relationship["!testRelLabel"] = TestRelLabel; + } + Relationship["source"] = Source.USR; + Relationship["target"] = Target.USR; + Relationship["targetFallback"] = Target.Name; + Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind); + + if (ForceEmitToMainModule) + MainModule.addRelationship(std::move(Relationship)); + else + Into.addRelationship(std::move(Relationship)); +} + StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { switch (Kind) { case ConstraintKind::Conformance: @@ -826,430 +740,324 @@ StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { llvm_unreachable("Unhandled constraint kind"); } -void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, - SymbolReference Source, - SymbolReference Target) { - Object Relationship; - Relationship["source"] = Source.USR; - Relationship["target"] = Target.USR; - Relationship["targetFallback"] = Target.Name; - Relationship["kind"] = getRelationshipString(Kind); - - Relationships.emplace_back(std::move(Relationship)); -} +void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) { + Object Obj; -void SymbolGraphSerializer::visitNamespaceRecord( - const NamespaceRecord &Record) { - auto Namespace = serializeAPIRecord(Record); - if (!Namespace) - return; - Symbols.emplace_back(std::move(*Namespace)); - if (!Record.ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); -} + // If we need symbol labels for testing emit the USR as the value and the key + // starts with '!'' to ensure it ends up at the top of the object. + if (EmitSymbolLabelsForTesting) + Obj["!testLabel"] = Record->USR; -void SymbolGraphSerializer::visitGlobalFunctionRecord( - const GlobalFunctionRecord &Record) { - auto Obj = serializeAPIRecord(Record); - if (!Obj) - return; + serializeObject(Obj, "identifier", + serializeIdentifier(*Record, API.getLanguage())); + serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage())); + serializeObject(Obj, "names", serializeNames(Record)); + serializeObject( + Obj, "location", + serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true)); + serializeArray(Obj, "availability", + serializeAvailability(Record->Availability)); + serializeObject(Obj, "docComment", serializeDocComment(Record->Comment)); + serializeArray(Obj, "declarationFragments", + serializeDeclarationFragments(Record->Declaration)); - Symbols.emplace_back(std::move(*Obj)); -} + Obj["pathComponents"] = serializePathComponents(Record); + Obj["accessLevel"] = Record->Access.getAccess(); -void SymbolGraphSerializer::visitGlobalVariableRecord( - const GlobalVariableRecord &Record) { - auto Obj = serializeAPIRecord(Record); - if (!Obj) - return; + ExtendedModule &Module = getModuleForCurrentSymbol(); + // If the hierarchy has at least one parent and child. + if (Hierarchy.size() >= 2) + serializeRelationship(MemberOf, Hierarchy.back(), + Hierarchy[Hierarchy.size() - 2], Module); - Symbols.emplace_back(std::move(*Obj)); + CurrentSymbol = Module.addSymbol(std::move(Obj)); } -void SymbolGraphSerializer::visitEnumRecord(const EnumRecord &Record) { - auto Enum = serializeAPIRecord(Record); - if (!Enum) - return; - - Symbols.emplace_back(std::move(*Enum)); - serializeMembers(Record, Record.Constants); +bool SymbolGraphSerializer::traverseAPIRecord(const APIRecord *Record) { + if (!Record) + return true; + if (shouldSkip(Record)) + return true; + Hierarchy.push_back(getHierarchyReference(Record, API)); + // Defer traversal mechanics to APISetVisitor base implementation + auto RetVal = Base::traverseAPIRecord(Record); + Hierarchy.pop_back(); + return RetVal; } -void SymbolGraphSerializer::visitRecordRecord(const RecordRecord &Record) { - auto SerializedRecord = serializeAPIRecord(Record); - if (!SerializedRecord) - return; - - Symbols.emplace_back(std::move(*SerializedRecord)); - serializeMembers(Record, Record.Fields); +bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) { + serializeAPIRecord(Record); + return true; } -void SymbolGraphSerializer::visitStaticFieldRecord( - const StaticFieldRecord &Record) { - auto StaticField = serializeAPIRecord(Record); - if (!StaticField) - return; - Symbols.emplace_back(std::move(*StaticField)); - serializeRelationship(RelationshipKind::MemberOf, Record, Record.Context); +bool SymbolGraphSerializer::visitGlobalFunctionRecord( + const GlobalFunctionRecord *Record) { + if (!CurrentSymbol) + return true; + + serializeFunctionSignatureMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) { - auto Class = serializeAPIRecord(Record); - if (!Class) - return; +bool SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*Class)); - for (const auto &Base : Record.Bases) - serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); - if (!Record.ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + for (const auto &Base : Record->Bases) + serializeRelationship(RelationshipKind::InheritsFrom, Record, Base, + getModuleForCurrentSymbol()); + return true; } -void SymbolGraphSerializer::visitClassTemplateRecord( - const ClassTemplateRecord &Record) { - auto Class = serializeAPIRecord(Record); - if (!Class) - return; +bool SymbolGraphSerializer::visitClassTemplateRecord( + const ClassTemplateRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*Class)); - for (const auto &Base : Record.Bases) - serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); - if (!Record.ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitClassTemplateSpecializationRecord( - const ClassTemplateSpecializationRecord &Record) { - auto Class = serializeAPIRecord(Record); - if (!Class) - return; - - Symbols.emplace_back(std::move(*Class)); +bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( + const ClassTemplatePartialSpecializationRecord *Record) { + if (!CurrentSymbol) + return true; - for (const auto &Base : Record.Bases) - serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); - if (!Record.ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( - const ClassTemplatePartialSpecializationRecord &Record) { - auto Class = serializeAPIRecord(Record); - if (!Class) - return; - - Symbols.emplace_back(std::move(*Class)); +bool SymbolGraphSerializer::visitCXXMethodRecord( + const CXXMethodRecord *Record) { + if (!CurrentSymbol) + return true; - for (const auto &Base : Record.Bases) - serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); - if (!Record.ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeFunctionSignatureMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitCXXInstanceMethodRecord( - const CXXInstanceMethodRecord &Record) { - auto InstanceMethod = serializeAPIRecord(Record); - if (!InstanceMethod) - return; +bool SymbolGraphSerializer::visitCXXMethodTemplateRecord( + const CXXMethodTemplateRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*InstanceMethod)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitCXXStaticMethodRecord( - const CXXStaticMethodRecord &Record) { - auto StaticMethod = serializeAPIRecord(Record); - if (!StaticMethod) - return; +bool SymbolGraphSerializer::visitCXXFieldTemplateRecord( + const CXXFieldTemplateRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*StaticMethod)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitMethodTemplateRecord( - const CXXMethodTemplateRecord &Record) { - if (!ShouldRecurse) - // Ignore child symbols - return; - auto MethodTemplate = serializeAPIRecord(Record); - if (!MethodTemplate) - return; - Symbols.emplace_back(std::move(*MethodTemplate)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); -} +bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) { + if (!CurrentSymbol) + return true; -void SymbolGraphSerializer::visitMethodTemplateSpecializationRecord( - const CXXMethodTemplateSpecializationRecord &Record) { - if (!ShouldRecurse) - // Ignore child symbols - return; - auto MethodTemplateSpecialization = serializeAPIRecord(Record); - if (!MethodTemplateSpecialization) - return; - Symbols.emplace_back(std::move(*MethodTemplateSpecialization)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitCXXFieldRecord(const CXXFieldRecord &Record) { - if (!ShouldRecurse) - return; - auto CXXField = serializeAPIRecord(Record); - if (!CXXField) - return; - Symbols.emplace_back(std::move(*CXXField)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); -} +bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord( + const GlobalVariableTemplateRecord *Record) { + if (!CurrentSymbol) + return true; -void SymbolGraphSerializer::visitCXXFieldTemplateRecord( - const CXXFieldTemplateRecord &Record) { - if (!ShouldRecurse) - // Ignore child symbols - return; - auto CXXFieldTemplate = serializeAPIRecord(Record); - if (!CXXFieldTemplate) - return; - Symbols.emplace_back(std::move(*CXXFieldTemplate)); - serializeRelationship(RelationshipKind::MemberOf, Record, - Record.ParentInformation.ParentRecord); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitConceptRecord(const ConceptRecord &Record) { - auto Concept = serializeAPIRecord(Record); - if (!Concept) - return; +bool SymbolGraphSerializer:: + visitGlobalVariableTemplatePartialSpecializationRecord( + const GlobalVariableTemplatePartialSpecializationRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*Concept)); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer::visitGlobalVariableTemplateRecord( - const GlobalVariableTemplateRecord &Record) { - auto GlobalVariableTemplate = serializeAPIRecord(Record); - if (!GlobalVariableTemplate) - return; - Symbols.emplace_back(std::move(*GlobalVariableTemplate)); -} +bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( + const GlobalFunctionTemplateRecord *Record) { + if (!CurrentSymbol) + return true; -void SymbolGraphSerializer::visitGlobalVariableTemplateSpecializationRecord( - const GlobalVariableTemplateSpecializationRecord &Record) { - auto GlobalVariableTemplateSpecialization = serializeAPIRecord(Record); - if (!GlobalVariableTemplateSpecialization) - return; - Symbols.emplace_back(std::move(*GlobalVariableTemplateSpecialization)); + serializeTemplateMixin(*CurrentSymbol, *Record); + return true; } -void SymbolGraphSerializer:: - visitGlobalVariableTemplatePartialSpecializationRecord( - const GlobalVariableTemplatePartialSpecializationRecord &Record) { - auto GlobalVariableTemplatePartialSpecialization = serializeAPIRecord(Record); - if (!GlobalVariableTemplatePartialSpecialization) - return; - Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpecialization)); -} +bool SymbolGraphSerializer::visitObjCContainerRecord( + const ObjCContainerRecord *Record) { + if (!CurrentSymbol) + return true; -void SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( - const GlobalFunctionTemplateRecord &Record) { - auto GlobalFunctionTemplate = serializeAPIRecord(Record); - if (!GlobalFunctionTemplate) - return; - Symbols.emplace_back(std::move(*GlobalFunctionTemplate)); -} + for (const auto &Protocol : Record->Protocols) + serializeRelationship(ConformsTo, Record, Protocol, + getModuleForCurrentSymbol()); -void SymbolGraphSerializer::visitGlobalFunctionTemplateSpecializationRecord( - const GlobalFunctionTemplateSpecializationRecord &Record) { - auto GlobalFunctionTemplateSpecialization = serializeAPIRecord(Record); - if (!GlobalFunctionTemplateSpecialization) - return; - Symbols.emplace_back(std::move(*GlobalFunctionTemplateSpecialization)); + return true; } -void SymbolGraphSerializer::visitObjCContainerRecord( - const ObjCContainerRecord &Record) { - auto ObjCContainer = serializeAPIRecord(Record); - if (!ObjCContainer) - return; +bool SymbolGraphSerializer::visitObjCInterfaceRecord( + const ObjCInterfaceRecord *Record) { + if (!CurrentSymbol) + return true; - Symbols.emplace_back(std::move(*ObjCContainer)); - - serializeMembers(Record, Record.Ivars); - serializeMembers(Record, Record.Methods); - serializeMembers(Record, Record.Properties); - - for (const auto &Protocol : Record.Protocols) - // Record that Record conforms to Protocol. - serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); - - if (auto *ObjCInterface = dyn_cast(&Record)) { - if (!ObjCInterface->SuperClass.empty()) - // If Record is an Objective-C interface record and it has a super class, - // record that Record is inherited from SuperClass. - serializeRelationship(RelationshipKind::InheritsFrom, Record, - ObjCInterface->SuperClass); - - // Members of categories extending an interface are serialized as members of - // the interface. - for (const auto *Category : ObjCInterface->Categories) { - serializeMembers(Record, Category->Ivars); - serializeMembers(Record, Category->Methods); - serializeMembers(Record, Category->Properties); - - // Surface the protocols of the category to the interface. - for (const auto &Protocol : Category->Protocols) - serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); - } - } + if (!Record->SuperClass.empty()) + serializeRelationship(InheritsFrom, Record, Record->SuperClass, + getModuleForCurrentSymbol()); + return true; } -void SymbolGraphSerializer::visitObjCCategoryRecord( - const ObjCCategoryRecord &Record) { - if (!Record.IsFromExternalModule) - return; - - // Check if the current Category' parent has been visited before, if so skip. - if (!visitedCategories.contains(Record.Interface.Name)) { - visitedCategories.insert(Record.Interface.Name); - Object Obj; - serializeObject(Obj, "identifier", - serializeIdentifier(Record, API.getLanguage())); - serializeObject(Obj, "kind", - serializeSymbolKind(APIRecord::RK_ObjCCategoryModule, - API.getLanguage())); - Obj["accessLevel"] = "public"; - Symbols.emplace_back(std::move(Obj)); - } +bool SymbolGraphSerializer::traverseObjCCategoryRecord( + const ObjCCategoryRecord *Record) { + auto *CurrentModule = ModuleForCurrentSymbol; + if (Record->isExtendingExternalModule()) + ModuleForCurrentSymbol = &ExtendedModules[Record->Interface.Source]; - Object Relationship; - Relationship["source"] = Record.USR; - Relationship["target"] = Record.Interface.USR; - Relationship["targetFallback"] = Record.Interface.Name; - Relationship["kind"] = getRelationshipString(RelationshipKind::ExtensionTo); - Relationships.emplace_back(std::move(Relationship)); + if (!walkUpFromObjCCategoryRecord(Record)) + return false; - auto ObjCCategory = serializeAPIRecord(Record); + bool RetVal = traverseRecordContext(Record); + ModuleForCurrentSymbol = CurrentModule; + return RetVal; +} - if (!ObjCCategory) - return; +bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord( + const ObjCCategoryRecord *Record) { + return visitObjCCategoryRecord(Record); +} - Symbols.emplace_back(std::move(*ObjCCategory)); - serializeMembers(Record, Record.Methods); - serializeMembers(Record, Record.Properties); +bool SymbolGraphSerializer::visitObjCCategoryRecord( + const ObjCCategoryRecord *Record) { + // If we need to create a record for the category in the future do so here, + // otherwise everything is set up to pretend that the category is in fact the + // interface it extends. + for (const auto &Protocol : Record->Protocols) + serializeRelationship(ConformsTo, Record->Interface, Protocol, + getModuleForCurrentSymbol()); - // Surface the protocols of the category to the interface. - for (const auto &Protocol : Record.Protocols) - serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); + return true; } -void SymbolGraphSerializer::visitMacroDefinitionRecord( - const MacroDefinitionRecord &Record) { - auto Macro = serializeAPIRecord(Record); +bool SymbolGraphSerializer::visitObjCMethodRecord( + const ObjCMethodRecord *Record) { + if (!CurrentSymbol) + return true; - if (!Macro) - return; + serializeFunctionSignatureMixin(*CurrentSymbol, *Record); + return true; +} - Symbols.emplace_back(std::move(*Macro)); +bool SymbolGraphSerializer::visitObjCInstanceVariableRecord( + const ObjCInstanceVariableRecord *Record) { + // FIXME: serialize ivar access control here. + return true; } -void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { - switch (Record->getKind()) { - case APIRecord::RK_Unknown: - llvm_unreachable("Records should have a known kind!"); - case APIRecord::RK_GlobalFunction: - visitGlobalFunctionRecord(*cast(Record)); - break; - case APIRecord::RK_GlobalVariable: - visitGlobalVariableRecord(*cast(Record)); - break; - case APIRecord::RK_Enum: - visitEnumRecord(*cast(Record)); - break; - case APIRecord::RK_Struct: - LLVM_FALLTHROUGH; - case APIRecord::RK_Union: - visitRecordRecord(*cast(Record)); - break; - case APIRecord::RK_StaticField: - visitStaticFieldRecord(*cast(Record)); - break; - case APIRecord::RK_CXXClass: - visitCXXClassRecord(*cast(Record)); - break; - case APIRecord::RK_ObjCInterface: - visitObjCContainerRecord(*cast(Record)); - break; - case APIRecord::RK_ObjCProtocol: - visitObjCContainerRecord(*cast(Record)); - break; - case APIRecord::RK_ObjCCategory: - visitObjCCategoryRecord(*cast(Record)); - break; - case APIRecord::RK_MacroDefinition: - visitMacroDefinitionRecord(*cast(Record)); - break; - case APIRecord::RK_Typedef: - visitTypedefRecord(*cast(Record)); - break; - default: - if (auto Obj = serializeAPIRecord(*Record)) { - Symbols.emplace_back(std::move(*Obj)); - auto &ParentInformation = Record->ParentInformation; - if (!ParentInformation.empty()) - serializeRelationship(RelationshipKind::MemberOf, *Record, - *ParentInformation.ParentRecord); - } - break; - } +bool SymbolGraphSerializer::walkUpFromTypedefRecord( + const TypedefRecord *Record) { + // Short-circuit walking up the class hierarchy and handle creating typedef + // symbol objects manually as there are additional symbol dropping rules to + // respect. + return visitTypedefRecord(Record); } -void SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord &Record) { +bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) { // Typedefs of anonymous types have their entries unified with the underlying // type. - bool ShouldDrop = Record.UnderlyingType.Name.empty(); + bool ShouldDrop = Record->UnderlyingType.Name.empty(); // enums declared with `NS_OPTION` have a named enum and a named typedef, with // the same name - ShouldDrop |= (Record.UnderlyingType.Name == Record.Name); + ShouldDrop |= (Record->UnderlyingType.Name == Record->Name); if (ShouldDrop) - return; + return true; - auto Typedef = serializeAPIRecord(Record); - if (!Typedef) - return; + // Create the symbol record if the other symbol droppping rules permit it. + serializeAPIRecord(Record); + if (!CurrentSymbol) + return true; - (*Typedef)["type"] = Record.UnderlyingType.USR; + (*CurrentSymbol)["type"] = Record->UnderlyingType.USR; - Symbols.emplace_back(std::move(*Typedef)); + return true; } -Object SymbolGraphSerializer::serialize() { - traverseAPISet(); - return serializeCurrentGraph(); +void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { + switch (Record->getKind()) { + // dispatch to the relevant walkUpFromMethod +#define CONCRETE_RECORD(CLASS, BASE, KIND) \ + case APIRecord::KIND: { \ + walkUpFrom##CLASS(static_cast(Record)); \ + break; \ + } +#include "clang/ExtractAPI/APIRecords.inc" + // otherwise fallback on the only behavior we can implement safely. + case APIRecord::RK_Unknown: + visitAPIRecord(Record); + break; + default: + llvm_unreachable("API Record with uninstantiable kind"); + } } -Object SymbolGraphSerializer::serializeCurrentGraph() { +Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName, + ExtendedModule &&EM) { Object Root; serializeObject(Root, "metadata", serializeMetadata()); - serializeObject(Root, "module", serializeModule()); + serializeObject(Root, "module", serializeModuleObject(ModuleName)); - Root["symbols"] = std::move(Symbols); - Root["relationships"] = std::move(Relationships); + Root["symbols"] = std::move(EM.Symbols); + Root["relationships"] = std::move(EM.Relationships); return Root; } -void SymbolGraphSerializer::serialize(raw_ostream &os) { - Object root = serialize(); +void SymbolGraphSerializer::serializeGraphToStream( + raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName, + ExtendedModule &&EM) { + Object Root = serializeGraph(ModuleName, std::move(EM)); if (Options.Compact) - os << formatv("{0}", Value(std::move(root))) << "\n"; + OS << formatv("{0}", Value(std::move(Root))) << "\n"; else - os << formatv("{0:2}", Value(std::move(root))) << "\n"; + OS << formatv("{0:2}", Value(std::move(Root))) << "\n"; +} + +void SymbolGraphSerializer::serializeMainSymbolGraph( + raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList, + SymbolGraphSerializerOption Options) { + SymbolGraphSerializer Serializer(API, IgnoresList, + Options.EmitSymbolLabelsForTesting); + Serializer.traverseAPISet(); + Serializer.serializeGraphToStream(OS, Options, API.ProductName, + std::move(Serializer.MainModule)); + // FIXME: TODO handle extended modules here +} + +void SymbolGraphSerializer::serializeWithExtensionGraphs( + raw_ostream &MainOutput, const APISet &API, + const APIIgnoresList &IgnoresList, + llvm::function_ref(Twine BaseName)> + CreateOutputStream, + SymbolGraphSerializerOption Options) { + SymbolGraphSerializer Serializer(API, IgnoresList, + Options.EmitSymbolLabelsForTesting); + Serializer.traverseAPISet(); + + Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName, + std::move(Serializer.MainModule)); + + for (auto &ExtensionSGF : Serializer.ExtendedModules) { + if (auto ExtensionOS = + CreateOutputStream(ExtensionSGF.getKey() + "@" + API.ProductName)) + Serializer.serializeGraphToStream(*ExtensionOS, Options, + ExtensionSGF.getKey(), + std::move(ExtensionSGF.getValue())); + } } std::optional @@ -1262,14 +1070,20 @@ SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR, Object Root; APIIgnoresList EmptyIgnores; SymbolGraphSerializer Serializer(API, EmptyIgnores, - /*Options.Compact*/ {true}, - /*ShouldRecurse*/ false); + /*EmitSymbolLabelsForTesting*/ false, + /*ForceEmitToMainModule*/ true); + + // Set up serializer parent chain + Serializer.Hierarchy = generateHierarchyFromRecord(Record); + Serializer.serializeSingleRecord(Record); - serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph()); + serializeObject(Root, "symbolGraph", + Serializer.serializeGraph(API.ProductName, + std::move(Serializer.MainModule))); Language Lang = API.getLanguage(); serializeArray(Root, "parentContexts", - generateParentContexts(*Record, API, Lang)); + generateParentContexts(Serializer.Hierarchy, Lang)); Array RelatedSymbols; @@ -1287,14 +1101,15 @@ SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR, Object RelatedSymbol; RelatedSymbol["usr"] = RelatedRecord->USR; RelatedSymbol["declarationLanguage"] = getLanguageName(Lang); - // TODO: once we record this properly let's serialize it right. - RelatedSymbol["accessLevel"] = "public"; + RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess(); RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename(); RelatedSymbol["moduleName"] = API.ProductName; RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader; serializeArray(RelatedSymbol, "parentContexts", - generateParentContexts(*RelatedRecord, API, Lang)); + generateParentContexts( + generateHierarchyFromRecord(RelatedRecord), Lang)); + RelatedSymbols.push_back(std::move(RelatedSymbol)); } diff --git a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp index 3a5f62c9b2e6cc505987cf7c06deca60f1ce47b7..41e4e0cf1795f9f5a3abad295ed2a33661cc9aeb 100644 --- a/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp +++ b/clang/lib/ExtractAPI/TypedefUnderlyingTypeResolver.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/ExtractAPI/TypedefUnderlyingTypeResolver.h" +#include "clang/Basic/Module.h" #include "clang/Index/USRGeneration.h" using namespace clang; @@ -50,17 +51,20 @@ TypedefUnderlyingTypeResolver::getSymbolReferenceForType(QualType Type, SmallString<128> TypeUSR; const NamedDecl *TypeDecl = getUnderlyingTypeDecl(Type); const TypedefType *TypedefTy = Type->getAs(); + StringRef OwningModuleName; if (TypeDecl) { if (!TypedefTy) TypeName = TypeDecl->getName().str(); clang::index::generateUSRForDecl(TypeDecl, TypeUSR); + if (auto *OwningModule = TypeDecl->getImportedOwningModule()) + OwningModuleName = OwningModule->Name; } else { clang::index::generateUSRForType(Type, Context, TypeUSR); } - return {API.copyString(TypeName), API.copyString(TypeUSR)}; + return API.createSymbolReference(TypeName, TypeUSR, OwningModuleName); } std::string TypedefUnderlyingTypeResolver::getUSRForType(QualType Type) const { diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 63ec3a88978dd914bc06b6e2759ac4039338221c..89e6c19b0af45c10e975c36f50fbbc3ca2ad85ba 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -895,6 +895,8 @@ template <> struct MappingTraits { IO.mapOptional("AlignConsecutiveMacros", Style.AlignConsecutiveMacros); IO.mapOptional("AlignConsecutiveShortCaseStatements", Style.AlignConsecutiveShortCaseStatements); + IO.mapOptional("AlignConsecutiveTableGenBreakingDAGArgColons", + Style.AlignConsecutiveTableGenBreakingDAGArgColons); IO.mapOptional("AlignConsecutiveTableGenCondOperatorColons", Style.AlignConsecutiveTableGenCondOperatorColons); IO.mapOptional("AlignConsecutiveTableGenDefinitionColons", @@ -953,6 +955,8 @@ template <> struct MappingTraits { Style.BreakBeforeTernaryOperators); IO.mapOptional("BreakConstructorInitializers", Style.BreakConstructorInitializers); + IO.mapOptional("BreakFunctionDefinitionParameters", + Style.BreakFunctionDefinitionParameters); IO.mapOptional("BreakInheritanceList", Style.BreakInheritanceList); IO.mapOptional("BreakStringLiterals", Style.BreakStringLiterals); IO.mapOptional("BreakTemplateDeclarations", @@ -1408,6 +1412,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.AlignConsecutiveDeclarations = {}; LLVMStyle.AlignConsecutiveMacros = {}; LLVMStyle.AlignConsecutiveShortCaseStatements = {}; + LLVMStyle.AlignConsecutiveTableGenBreakingDAGArgColons = {}; LLVMStyle.AlignConsecutiveTableGenCondOperatorColons = {}; LLVMStyle.AlignConsecutiveTableGenDefinitionColons = {}; LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right; @@ -1462,6 +1467,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) { LLVMStyle.BreakBeforeInlineASMColon = FormatStyle::BBIAS_OnlyMultiline; LLVMStyle.BreakBeforeTernaryOperators = true; LLVMStyle.BreakConstructorInitializers = FormatStyle::BCIS_BeforeColon; + LLVMStyle.BreakFunctionDefinitionParameters = false; LLVMStyle.BreakInheritanceList = FormatStyle::BILS_BeforeColon; LLVMStyle.BreakStringLiterals = true; LLVMStyle.BreakTemplateDeclarations = FormatStyle::BTDS_MultiLine; @@ -3575,7 +3581,7 @@ cleanupAroundReplacements(StringRef Code, const tooling::Replacements &Replaces, // We need to use lambda function here since there are two versions of // `cleanup`. auto Cleanup = [](const FormatStyle &Style, StringRef Code, - std::vector Ranges, + ArrayRef Ranges, StringRef FileName) -> tooling::Replacements { return cleanup(Style, Code, Ranges, FileName); }; diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index 06f567059c3576deaf2df63fe0f7dfaa50987b9a..f651e6228c206da58363e5d7482e108001cba788 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -35,6 +35,8 @@ namespace format { TYPE(BinaryOperator) \ TYPE(BitFieldColon) \ TYPE(BlockComment) \ + /* l_brace of a block that is not the body of a (e.g. loop) statement. */ \ + TYPE(BlockLBrace) \ TYPE(BracedListLBrace) \ /* The colon at the end of a case label. */ \ TYPE(CaseLabelColon) \ @@ -152,6 +154,7 @@ namespace format { TYPE(TableGenCondOperatorComma) \ TYPE(TableGenDAGArgCloser) \ TYPE(TableGenDAGArgListColon) \ + TYPE(TableGenDAGArgListColonToAlign) \ TYPE(TableGenDAGArgListComma) \ TYPE(TableGenDAGArgListCommaToBreak) \ TYPE(TableGenDAGArgOpener) \ @@ -573,6 +576,9 @@ public: /// Is optional and can be removed. bool Optional = false; + /// Might be function declaration open/closing paren. + bool MightBeFunctionDeclParen = false; + /// Number of optional braces to be inserted after this token: /// -1: a single left brace /// 0: no braces diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index 036f7e6a4efc1ea9f12689b6accaec700d527595..f430d3764babeb270fb937ab4119ec7827738510 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -404,7 +404,7 @@ bool FormatTokenLexer::tryMergeNullishCoalescingEqual() { return false; auto &NullishCoalescing = *(Tokens.end() - 2); auto &Equal = *(Tokens.end() - 1); - if (NullishCoalescing->getType() != TT_NullCoalescingOperator || + if (NullishCoalescing->isNot(TT_NullCoalescingOperator) || Equal->isNot(tok::equal)) { return false; } diff --git a/clang/lib/Format/FormatTokenSource.h b/clang/lib/Format/FormatTokenSource.h index cce19f527a9236df8dc8df12cdcfbe09cf87bd6e..2b93f302d360340dd0aa6862b32fc3d6665aa813 100644 --- a/clang/lib/Format/FormatTokenSource.h +++ b/clang/lib/Format/FormatTokenSource.h @@ -72,6 +72,15 @@ public: // getNextToken() -> a1 // getNextToken() -> a2 virtual FormatToken *insertTokens(ArrayRef Tokens) = 0; + + [[nodiscard]] FormatToken *getNextNonComment() { + FormatToken *Tok; + do { + Tok = getNextToken(); + assert(Tok); + } while (Tok->is(tok::comment)); + return Tok; + } }; class IndexedTokenSource : public FormatTokenSource { diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index 94d2266555f6b9ad141b713e51a6582b95116333..628f70417866c38505cf01128d26ffbfa345b22b 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -825,8 +825,7 @@ private: Parent->overwriteFixedType(TT_BinaryOperator); } // An arrow after an ObjC method expression is not a lambda arrow. - if (CurrentToken->getType() == TT_ObjCMethodExpr && - CurrentToken->Next && + if (CurrentToken->is(TT_ObjCMethodExpr) && CurrentToken->Next && CurrentToken->Next->is(TT_TrailingReturnArrow)) { CurrentToken->Next->overwriteFixedType(TT_Unknown); } @@ -975,12 +974,15 @@ private: // DagArg ::= Value [":" TokVarName] | TokVarName // Appears as a part of SimpleValue6. - bool parseTableGenDAGArg() { + bool parseTableGenDAGArg(bool AlignColon = false) { if (tryToParseTableGenTokVar()) return true; if (parseTableGenValue()) { if (CurrentToken && CurrentToken->is(tok::colon)) { - CurrentToken->setType(TT_TableGenDAGArgListColon); + if (AlignColon) + CurrentToken->setType(TT_TableGenDAGArgListColonToAlign); + else + CurrentToken->setType(TT_TableGenDAGArgListColon); skipToNextNonComment(); return tryToParseTableGenTokVar(); } @@ -1051,8 +1053,11 @@ private: skipToNextNonComment(); return true; } - if (!parseTableGenDAGArg()) + if (!parseTableGenDAGArg( + BreakInside && + Style.AlignConsecutiveTableGenBreakingDAGArgColons.Enabled)) { return false; + } FirstDAGArgListElm = false; } return false; @@ -1544,6 +1549,7 @@ private: (!Previous->isAttribute() && !Previous->isOneOf(TT_RequiresClause, TT_LeadingJavaAnnotation))) { Line.MightBeFunctionDecl = true; + Tok->MightBeFunctionDeclParen = true; } } break; @@ -1556,7 +1562,7 @@ private: case tok::l_brace: if (Style.Language == FormatStyle::LK_TextProto) { FormatToken *Previous = Tok->getPreviousNonComment(); - if (Previous && Previous->getType() != TT_DictLiteral) + if (Previous && Previous->isNot(TT_DictLiteral)) Previous->setType(TT_SelectorName); } Scopes.push_back(getScopeType(*Tok)); @@ -1576,7 +1582,7 @@ private: Tok->Previous->isOneOf(TT_SelectorName, TT_DictLiteral))) { Tok->setType(TT_DictLiteral); FormatToken *Previous = Tok->getPreviousNonComment(); - if (Previous && Previous->getType() != TT_DictLiteral) + if (Previous && Previous->isNot(TT_DictLiteral)) Previous->setType(TT_SelectorName); } if (Style.isTableGen()) @@ -2348,7 +2354,8 @@ private: // Line.MightBeFunctionDecl can only be true after the parentheses of a // function declaration have been found. In this case, 'Current' is a // trailing token of this declaration and thus cannot be a name. - if (Current.is(Keywords.kw_instanceof)) { + if ((Style.isJavaScript() || Style.Language == FormatStyle::LK_Java) && + Current.is(Keywords.kw_instanceof)) { Current.setType(TT_BinaryOperator); } else if (isStartOfName(Current) && (!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) { @@ -2747,10 +2754,9 @@ private: } // Heuristically try to determine whether the parentheses contain a type. - auto IsQualifiedPointerOrReference = [this](FormatToken *T) { + auto IsQualifiedPointerOrReference = [](FormatToken *T, bool IsCpp) { // This is used to handle cases such as x = (foo *const)&y; assert(!T->isTypeName(IsCpp) && "Should have already been checked"); - (void)IsCpp; // Avoid -Wunused-lambda-capture when assertion is disabled. // Strip trailing qualifiers such as const or volatile when checking // whether the parens could be a cast to a pointer/reference type. while (T) { @@ -2783,7 +2789,7 @@ private: !Tok.Previous || Tok.Previous->isOneOf(TT_TemplateCloser, TT_TypeDeclarationParen) || Tok.Previous->isTypeName(IsCpp) || - IsQualifiedPointerOrReference(Tok.Previous); + IsQualifiedPointerOrReference(Tok.Previous, IsCpp); bool ParensCouldEndDecl = Tok.Next->isOneOf(tok::equal, tok::semi, tok::l_brace, tok::greater); if (ParensAreType && !ParensCouldEndDecl) @@ -3883,6 +3889,8 @@ void TokenAnnotator::calculateFormattingInformation(AnnotatedLine &Line) const { } } else if (ClosingParen) { for (auto *Tok = ClosingParen->Next; Tok; Tok = Tok->Next) { + if (Tok->is(TT_CtorInitializerColon)) + break; if (Tok->is(tok::arrow)) { Tok->setType(TT_TrailingReturnArrow); break; @@ -4351,9 +4359,11 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Left.is(tok::kw_auto) && Right.isOneOf(tok::l_paren, tok::l_brace)) return false; + const auto *BeforeLeft = Left.Previous; + // operator co_await(x) - if (Right.is(tok::l_paren) && Left.is(tok::kw_co_await) && Left.Previous && - Left.Previous->is(tok::kw_operator)) { + if (Right.is(tok::l_paren) && Left.is(tok::kw_co_await) && BeforeLeft && + BeforeLeft->is(tok::kw_operator)) { return false; } // co_await (x), co_yield (x), co_return (x) @@ -4388,8 +4398,10 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, } if (Left.is(tok::colon)) return Left.isNot(TT_ObjCMethodExpr); - if (Left.is(tok::coloncolon)) - return false; + if (Left.is(tok::coloncolon)) { + return Right.is(tok::star) && Right.is(TT_PointerOrReference) && + Style.PointerAlignment != FormatStyle::PAS_Left; + } if (Left.is(tok::less) || Right.isOneOf(tok::greater, tok::less)) { if (Style.Language == FormatStyle::LK_TextProto || (Style.Language == FormatStyle::LK_Proto && @@ -4404,8 +4416,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return false; } if (Right.is(tok::ellipsis)) { - return Left.Tok.isLiteral() || (Left.is(tok::identifier) && Left.Previous && - Left.Previous->is(tok::kw_case)); + return Left.Tok.isLiteral() || (Left.is(tok::identifier) && BeforeLeft && + BeforeLeft->is(tok::kw_case)); } if (Left.is(tok::l_square) && Right.is(tok::amp)) return Style.SpacesInSquareBrackets; @@ -4473,8 +4485,8 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, if (Right.is(tok::l_brace) && Right.is(BK_Block)) return true; // for (auto a = 0, b = 0; const auto& c : {1, 2, 3}) - if (Left.Previous && Left.Previous->isTypeOrIdentifier(IsCpp) && - Right.Next && Right.Next->is(TT_RangeBasedForLoopColon)) { + if (BeforeLeft && BeforeLeft->isTypeOrIdentifier(IsCpp) && Right.Next && + Right.Next->is(TT_RangeBasedForLoopColon)) { return getTokenPointerOrReferenceAlignment(Left) != FormatStyle::PAS_Right; } @@ -4496,12 +4508,17 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, startsWithInitStatement(Line)))) { return false; } - return Left.Previous && !Left.Previous->isOneOf( - tok::l_paren, tok::coloncolon, tok::l_square); + if (!BeforeLeft) + return false; + if (BeforeLeft->is(tok::coloncolon)) { + return Left.is(tok::star) && + Style.PointerAlignment != FormatStyle::PAS_Right; + } + return !BeforeLeft->isOneOf(tok::l_paren, tok::l_square); } // Ensure right pointer alignment with ellipsis e.g. int *...P - if (Left.is(tok::ellipsis) && Left.Previous && - Left.Previous->isPointerOrReference()) { + if (Left.is(tok::ellipsis) && BeforeLeft && + BeforeLeft->isPointerOrReference()) { return Style.PointerAlignment != FormatStyle::PAS_Right; } @@ -4663,13 +4680,13 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, return Style.SpaceBeforeParensOptions.AfterFunctionDefinitionName || spaceRequiredBeforeParens(Right); } - if (!Left.Previous || !Left.Previous->isOneOf(tok::period, tok::arrow)) { + if (!BeforeLeft || !BeforeLeft->isOneOf(tok::period, tok::arrow)) { if (Left.isOneOf(tok::kw_try, Keywords.kw___except, tok::kw_catch)) { return Style.SpaceBeforeParensOptions.AfterControlStatements || spaceRequiredBeforeParens(Right); } if (Left.isOneOf(tok::kw_new, tok::kw_delete)) { - return ((!Line.MightBeFunctionDecl || !Left.Previous) && + return ((!Line.MightBeFunctionDecl || !BeforeLeft) && Style.SpaceBeforeParens != FormatStyle::SBPO_Never) || spaceRequiredBeforeParens(Right); } @@ -4737,8 +4754,7 @@ bool TokenAnnotator::spaceRequiredBetween(const AnnotatedLine &Line, // Objective-C dictionary literal -> no space before closing brace. return false; } - if (Right.getType() == TT_TrailingAnnotation && - Right.isOneOf(tok::amp, tok::ampamp) && + if (Right.is(TT_TrailingAnnotation) && Right.isOneOf(tok::amp, tok::ampamp) && Left.isOneOf(tok::kw_const, tok::kw_volatile) && (!Right.Next || Right.Next->is(tok::semi))) { // Match const and volatile ref-qualifiers without any additional @@ -4813,6 +4829,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, Right.is(TT_TemplateOpener)) { return true; } + if (Left.is(tok::identifier) && Right.is(tok::numeric_constant) && + Right.TokenText[0] == '.') { + return false; + } } else if (Style.isProto()) { if (Right.is(tok::period) && Left.isOneOf(Keywords.kw_optional, Keywords.kw_required, @@ -5130,8 +5150,10 @@ bool TokenAnnotator::spaceRequiredBefore(const AnnotatedLine &Line, if (Left.is(tok::r_brace) && Right.is(tok::r_square)) return true; // Do not insert around colon in DAGArg and cond operator. - if (Right.is(TT_TableGenDAGArgListColon) || - Left.is(TT_TableGenDAGArgListColon)) { + if (Right.isOneOf(TT_TableGenDAGArgListColon, + TT_TableGenDAGArgListColonToAlign) || + Left.isOneOf(TT_TableGenDAGArgListColon, + TT_TableGenDAGArgListColonToAlign)) { return false; } if (Right.is(TT_TableGenCondOperatorColon)) @@ -5372,6 +5394,12 @@ bool TokenAnnotator::mustBreakBefore(const AnnotatedLine &Line, if (Right.NewlinesBefore > 1 && Style.MaxEmptyLinesToKeep > 0) return true; + if (Style.BreakFunctionDefinitionParameters && Line.MightBeFunctionDecl && + Line.mightBeFunctionDefinition() && Left.MightBeFunctionDeclParen && + Left.ParameterCount > 0) { + return true; + } + if (Style.isCSharp()) { if (Left.is(TT_FatArrow) && Right.is(tok::l_brace) && Style.BraceWrapping.AfterFunction) { diff --git a/clang/lib/Format/UnwrappedLineFormatter.cpp b/clang/lib/Format/UnwrappedLineFormatter.cpp index fb31980ab9f491bedddcfb93de529af20e7145f1..4ae54e56331bdcfcfb8c606618de71a0762cb652 100644 --- a/clang/lib/Format/UnwrappedLineFormatter.cpp +++ b/clang/lib/Format/UnwrappedLineFormatter.cpp @@ -796,8 +796,12 @@ private: } } - if (const auto *LastNonComment = Line.getLastNonComment(); - LastNonComment && LastNonComment->is(tok::l_brace)) { + if (Line.endsWith(tok::l_brace)) { + if (Style.AllowShortBlocksOnASingleLine == FormatStyle::SBS_Never && + Line.First->is(TT_BlockLBrace)) { + return 0; + } + if (IsSplitBlock && Line.First == Line.Last && I > AnnotatedLines.begin() && (I[-1]->endsWith(tok::kw_else) || IsCtrlStmt(*I[-1]))) { diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 98ae1c8f62bbc259248a3ae2df9bee71707482fb..603268f771ac5226165ba33e30c0c97918c11c4a 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -365,11 +365,11 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, nextToken(); continue; } - tok::TokenKind kind = FormatTok->Tok.getKind(); - if (FormatTok->getType() == TT_MacroBlockBegin) - kind = tok::l_brace; - else if (FormatTok->getType() == TT_MacroBlockEnd) - kind = tok::r_brace; + tok::TokenKind Kind = FormatTok->Tok.getKind(); + if (FormatTok->is(TT_MacroBlockBegin)) + Kind = tok::l_brace; + else if (FormatTok->is(TT_MacroBlockEnd)) + Kind = tok::r_brace; auto ParseDefault = [this, OpeningBrace, IfKind, &IfLBrace, &HasDoWhile, &HasLabel, &StatementCount] { @@ -380,7 +380,7 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, assert(StatementCount > 0 && "StatementCount overflow!"); }; - switch (kind) { + switch (Kind) { case tok::comment: nextToken(); addUnwrappedLine(); @@ -395,9 +395,10 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, ParseDefault(); continue; } - if (!InRequiresExpression && FormatTok->isNot(TT_MacroBlockBegin) && - tryToParseBracedList()) { - continue; + if (!InRequiresExpression && FormatTok->isNot(TT_MacroBlockBegin)) { + if (tryToParseBracedList()) + continue; + FormatTok->setFinalizedType(TT_BlockLBrace); } parseBlock(); ++StatementCount; @@ -427,11 +428,7 @@ bool UnwrappedLineParser::parseLevel(const FormatToken *OpeningBrace, break; case tok::kw_default: { unsigned StoredPosition = Tokens->getPosition(); - FormatToken *Next; - do { - Next = Tokens->getNextToken(); - assert(Next); - } while (Next->is(tok::comment)); + auto *Next = Tokens->getNextNonComment(); FormatTok = Tokens->setPosition(StoredPosition); if (Next->isNot(tok::colon)) { // default not followed by ':' is not a case label; treat it like @@ -495,20 +492,19 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { }; SmallVector LBraceStack; assert(Tok->is(tok::l_brace)); + do { - // Get next non-comment, non-preprocessor token. - FormatToken *NextTok; - do { - NextTok = Tokens->getNextToken(); - } while (NextTok->is(tok::comment)); - if (!Style.isTableGen()) { - // InTableGen, '#' is like binary operator. Not a preprocessor directive. - while (NextTok->is(tok::hash) && !Line->InMacroBody) { - NextTok = Tokens->getNextToken(); + auto *NextTok = Tokens->getNextNonComment(); + + if (!Line->InMacroBody && !Style.isTableGen()) { + // Skip PPDirective lines and comments. + while (NextTok->is(tok::hash)) { do { NextTok = Tokens->getNextToken(); - } while (NextTok->is(tok::comment) || - (NextTok->NewlinesBefore == 0 && NextTok->isNot(tok::eof))); + } while (NextTok->NewlinesBefore == 0 && NextTok->isNot(tok::eof)); + + while (NextTok->is(tok::comment)) + NextTok = Tokens->getNextToken(); } } @@ -543,16 +539,6 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { if (Style.Language == FormatStyle::LK_Proto) { ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square); } else { - // Skip NextTok over preprocessor lines, otherwise we may not - // properly diagnose the block as a braced intializer - // if the comma separator appears after the pp directive. - while (NextTok->is(tok::hash)) { - ScopedMacroState MacroState(*Line, Tokens, NextTok); - do { - NextTok = Tokens->getNextToken(); - } while (NextTok->isNot(tok::eof)); - } - // Using OriginalColumn to distinguish between ObjC methods and // binary operators is a bit hacky. bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) && @@ -611,6 +597,16 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { NextTok = Tokens->getNextToken(); ProbablyBracedList = NextTok->isNot(tok::l_square); } + + // Cpp macro definition body that is a nonempty braced list or block: + if (IsCpp && Line->InMacroBody && PrevTok != FormatTok && + !FormatTok->Previous && NextTok->is(tok::eof) && + // A statement can end with only `;` (simple statement), a block + // closing brace (compound statement), or `:` (label statement). + // If PrevTok is a block opening brace, Tok ends an empty block. + !PrevTok->isOneOf(tok::semi, BK_Block, tok::colon)) { + ProbablyBracedList = true; + } } if (ProbablyBracedList) { Tok->setBlockKind(BK_BracedInit); @@ -640,6 +636,7 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { default: break; } + PrevTok = Tok; Tok = NextTok; } while (Tok->isNot(tok::eof) && !LBraceStack.empty()); @@ -3277,8 +3274,8 @@ void UnwrappedLineParser::parseSwitch() { } // Operators that can follow a C variable. -static bool isCOperatorFollowingVar(tok::TokenKind kind) { - switch (kind) { +static bool isCOperatorFollowingVar(tok::TokenKind Kind) { + switch (Kind) { case tok::ampamp: case tok::ampequal: case tok::arrow: @@ -4706,14 +4703,13 @@ void UnwrappedLineParser::readToken(int LevelDifference) { do { FormatTok = Tokens->getNextToken(); assert(FormatTok); - while (FormatTok->getType() == TT_ConflictStart || - FormatTok->getType() == TT_ConflictEnd || - FormatTok->getType() == TT_ConflictAlternative) { - if (FormatTok->getType() == TT_ConflictStart) + while (FormatTok->isOneOf(TT_ConflictStart, TT_ConflictEnd, + TT_ConflictAlternative)) { + if (FormatTok->is(TT_ConflictStart)) conditionalCompilationStart(/*Unreachable=*/false); - else if (FormatTok->getType() == TT_ConflictAlternative) + else if (FormatTok->is(TT_ConflictAlternative)) conditionalCompilationAlternative(); - else if (FormatTok->getType() == TT_ConflictEnd) + else if (FormatTok->is(TT_ConflictEnd)) conditionalCompilationEnd(); FormatTok = Tokens->getNextToken(); FormatTok->MustBreakBefore = true; diff --git a/clang/lib/Format/WhitespaceManager.cpp b/clang/lib/Format/WhitespaceManager.cpp index 753be25bfd67585380ad61be9c00fa7167ca9764..4f822807dd987dc8ceeb43e8a550c4c135f50b86 100644 --- a/clang/lib/Format/WhitespaceManager.cpp +++ b/clang/lib/Format/WhitespaceManager.cpp @@ -112,6 +112,7 @@ const tooling::Replacements &WhitespaceManager::generateReplacements() { alignConsecutiveBitFields(); alignConsecutiveAssignments(); if (Style.isTableGen()) { + alignConsecutiveTableGenBreakingDAGArgColons(); alignConsecutiveTableGenCondOperatorColons(); alignConsecutiveTableGenDefinitions(); } @@ -463,16 +464,16 @@ AlignTokenSequence(const FormatStyle &Style, unsigned Start, unsigned End, if (i + 1 != Changes.size()) Changes[i + 1].PreviousEndOfTokenColumn += Shift; - // If PointerAlignment is PAS_Right, keep *s or &s next to the token + // If PointerAlignment is PAS_Right, keep *s or &s next to the token, + // except if the token is equal, then a space is needed. if ((Style.PointerAlignment == FormatStyle::PAS_Right || Style.ReferenceAlignment == FormatStyle::RAS_Right) && - CurrentChange.Spaces != 0) { + CurrentChange.Spaces != 0 && CurrentChange.Tok->isNot(tok::equal)) { const bool ReferenceNotRightAligned = Style.ReferenceAlignment != FormatStyle::RAS_Right && Style.ReferenceAlignment != FormatStyle::RAS_Pointer; for (int Previous = i - 1; - Previous >= 0 && - Changes[Previous].Tok->getType() == TT_PointerOrReference; + Previous >= 0 && Changes[Previous].Tok->is(TT_PointerOrReference); --Previous) { assert(Changes[Previous].Tok->isPointerOrReference()); if (Changes[Previous].Tok->isNot(tok::star)) { @@ -981,6 +982,11 @@ void WhitespaceManager::alignConsecutiveShortCaseStatements() { Changes); } +void WhitespaceManager::alignConsecutiveTableGenBreakingDAGArgColons() { + alignConsecutiveColons(Style.AlignConsecutiveTableGenBreakingDAGArgColons, + TT_TableGenDAGArgListColonToAlign); +} + void WhitespaceManager::alignConsecutiveTableGenCondOperatorColons() { alignConsecutiveColons(Style.AlignConsecutiveTableGenCondOperatorColons, TT_TableGenCondOperatorColon); @@ -1485,7 +1491,7 @@ WhitespaceManager::CellDescriptions WhitespaceManager::getCells(unsigned Start, : Cell); // Go to the next non-comment and ensure there is a break in front const auto *NextNonComment = C.Tok->getNextNonComment(); - while (NextNonComment->is(tok::comma)) + while (NextNonComment && NextNonComment->is(tok::comma)) NextNonComment = NextNonComment->getNextNonComment(); auto j = i; while (j < End && Changes[j].Tok != NextNonComment) diff --git a/clang/lib/Format/WhitespaceManager.h b/clang/lib/Format/WhitespaceManager.h index 0ebc6cf8377cdb293a6895a851c25e117001ae93..98cf4a260cc46891ed7844fbca370c6d8921787e 100644 --- a/clang/lib/Format/WhitespaceManager.h +++ b/clang/lib/Format/WhitespaceManager.h @@ -235,6 +235,9 @@ private: /// Align consecutive short case statements over all \c Changes. void alignConsecutiveShortCaseStatements(); + /// Align consecutive TableGen DAGArg colon over all \c Changes. + void alignConsecutiveTableGenBreakingDAGArgColons(); + /// Align consecutive TableGen cond operator colon over all \c Changes. void alignConsecutiveTableGenCondOperatorColons(); diff --git a/clang/lib/Frontend/CompilerInstance.cpp b/clang/lib/Frontend/CompilerInstance.cpp index 019f847ccbaad0278e1ec9b010ea22beb9a7d22d..6e3baf8386441593bd767ce2260bd1b107be3e6c 100644 --- a/clang/lib/Frontend/CompilerInstance.cpp +++ b/clang/lib/Frontend/CompilerInstance.cpp @@ -1206,16 +1206,6 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, // Note the name of the module we're building. Invocation->getLangOpts().CurrentModule = std::string(ModuleName); - // Make sure that the failed-module structure has been allocated in - // the importing instance, and propagate the pointer to the newly-created - // instance. - PreprocessorOptions &ImportingPPOpts - = ImportingInstance.getInvocation().getPreprocessorOpts(); - if (!ImportingPPOpts.FailedModules) - ImportingPPOpts.FailedModules = - std::make_shared(); - PPOpts.FailedModules = ImportingPPOpts.FailedModules; - // If there is a module map file, build the module using the module map. // Set up the inputs/outputs so that we build the module from its umbrella // header. @@ -1269,6 +1259,13 @@ compileModuleImpl(CompilerInstance &ImportingInstance, SourceLocation ImportLoc, SourceMgr.pushModuleBuildStack(ModuleName, FullSourceLoc(ImportLoc, ImportingInstance.getSourceManager())); + // Make sure that the failed-module structure has been allocated in + // the importing instance, and propagate the pointer to the newly-created + // instance. + if (!ImportingInstance.hasFailedModulesSet()) + ImportingInstance.createFailedModulesSet(); + Instance.setFailedModulesSet(ImportingInstance.getFailedModulesSetPtr()); + // If we're collecting module dependencies, we need to share a collector // between all of the module CompilerInstances. Other than that, we don't // want to produce any dependency output from the module build. @@ -1337,9 +1334,24 @@ static bool compileModule(CompilerInstance &ImportingInstance, // Get or create the module map that we'll use to build this module. ModuleMap &ModMap = ImportingInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); + SourceManager &SourceMgr = ImportingInstance.getSourceManager(); bool Result; - if (OptionalFileEntryRef ModuleMapFile = - ModMap.getContainingModuleMapFile(Module)) { + if (FileID ModuleMapFID = ModMap.getContainingModuleMapFileID(Module); + ModuleMapFID.isValid()) { + // We want to use the top-level module map. If we don't, the compiling + // instance may think the containing module map is a top-level one, while + // the importing instance knows it's included from a parent module map via + // the extern directive. This mismatch could bite us later. + SourceLocation Loc = SourceMgr.getIncludeLoc(ModuleMapFID); + while (Loc.isValid() && isModuleMap(SourceMgr.getFileCharacteristic(Loc))) { + ModuleMapFID = SourceMgr.getFileID(Loc); + Loc = SourceMgr.getIncludeLoc(ModuleMapFID); + } + + OptionalFileEntryRef ModuleMapFile = + SourceMgr.getFileEntryRefForID(ModuleMapFID); + assert(ModuleMapFile && "Top-level module map with no FileID"); + // Canonicalize compilation to start with the public module map. This is // vital for submodules declarations in the private module maps to be // correctly parsed when depending on a top level module in the public one. @@ -1977,10 +1989,8 @@ ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST( return nullptr; } - // Check whether we have already attempted to build this module (but - // failed). - if (getPreprocessorOpts().FailedModules && - getPreprocessorOpts().FailedModules->hasAlreadyFailed(ModuleName)) { + // Check whether we have already attempted to build this module (but failed). + if (FailedModules && FailedModules->hasAlreadyFailed(ModuleName)) { getDiagnostics().Report(ModuleNameLoc, diag::err_module_not_built) << ModuleName << SourceRange(ImportLoc, ModuleNameLoc); return nullptr; @@ -1991,8 +2001,8 @@ ModuleLoadResult CompilerInstance::findOrCompileModuleAndReadAST( ModuleFilename)) { assert(getDiagnostics().hasErrorOccurred() && "undiagnosed error in compileModuleAndReadAST"); - if (getPreprocessorOpts().FailedModules) - getPreprocessorOpts().FailedModules->addFailed(ModuleName); + if (FailedModules) + FailedModules->addFailed(ModuleName); return nullptr; } diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 7bd91d4791ecf0b9d9657c9937c0d71940b8837e..1f1f5440ddd75faadabdf076943f8b4e031250e0 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -533,10 +533,10 @@ static T extractMaskValue(T KeyPath) { #define PARSE_OPTION_WITH_MARSHALLING( \ ARGS, DIAGS, PREFIX_TYPE, SPELLING, ID, KIND, GROUP, ALIAS, ALIASARGS, \ - FLAGS, VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES, SHOULD_PARSE, \ - ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, \ - NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \ - if ((VISIBILITY)&options::CC1Option) { \ + FLAGS, VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, VALUES, \ + SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, \ + IMPLIED_VALUE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \ + if ((VISIBILITY) & options::CC1Option) { \ KEYPATH = MERGER(KEYPATH, DEFAULT_VALUE); \ if (IMPLIED_CHECK) \ KEYPATH = MERGER(KEYPATH, IMPLIED_VALUE); \ @@ -550,10 +550,10 @@ static T extractMaskValue(T KeyPath) { // with lifetime extension of the reference. #define GENERATE_OPTION_WITH_MARSHALLING( \ CONSUMER, PREFIX_TYPE, SPELLING, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, \ - VISIBILITY, PARAM, HELPTEXT, METAVAR, VALUES, SHOULD_PARSE, ALWAYS_EMIT, \ - KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, IMPLIED_VALUE, NORMALIZER, \ - DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \ - if ((VISIBILITY)&options::CC1Option) { \ + VISIBILITY, PARAM, HELPTEXT, HELPTEXTSFORVARIANTS, METAVAR, VALUES, \ + SHOULD_PARSE, ALWAYS_EMIT, KEYPATH, DEFAULT_VALUE, IMPLIED_CHECK, \ + IMPLIED_VALUE, NORMALIZER, DENORMALIZER, MERGER, EXTRACTOR, TABLE_INDEX) \ + if ((VISIBILITY) & options::CC1Option) { \ [&](const auto &Extracted) { \ if (ALWAYS_EMIT || \ (Extracted != \ @@ -3516,7 +3516,8 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts, GenerateArg(Consumer, OPT_fblocks); if (Opts.ConvergentFunctions && - !(Opts.OpenCL || (Opts.CUDA && Opts.CUDAIsDevice) || Opts.SYCLIsDevice)) + !(Opts.OpenCL || (Opts.CUDA && Opts.CUDAIsDevice) || Opts.SYCLIsDevice || + Opts.HLSL)) GenerateArg(Consumer, OPT_fconvergent_functions); if (Opts.NoBuiltin && !Opts.Freestanding) @@ -3914,7 +3915,7 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.ConvergentFunctions = Args.hasArg(OPT_fconvergent_functions) || Opts.OpenCL || (Opts.CUDA && Opts.CUDAIsDevice) || - Opts.SYCLIsDevice; + Opts.SYCLIsDevice || Opts.HLSL; Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding; if (!Opts.NoBuiltin) @@ -4284,11 +4285,30 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args, Diags.Report(diag::err_drv_hlsl_bad_shader_unsupported) << ShaderModel << T.getOSName() << T.str(); } + // Validate that if fnative-half-type is given, that + // the language standard is at least hlsl2018, and that + // the target shader model is at least 6.2. + if (Args.getLastArg(OPT_fnative_half_type)) { + const LangStandard &Std = + LangStandard::getLangStandardForKind(Opts.LangStd); + if (!(Opts.LangStd >= LangStandard::lang_hlsl2018 && + T.getOSVersion() >= VersionTuple(6, 2))) + Diags.Report(diag::err_drv_hlsl_16bit_types_unsupported) + << "-enable-16bit-types" << true << Std.getName() + << T.getOSVersion().getAsString(); + } } else if (T.isSPIRVLogical()) { if (!T.isVulkanOS() || T.getVulkanVersion() == VersionTuple(0)) { Diags.Report(diag::err_drv_hlsl_bad_shader_unsupported) << VulkanEnv << T.getOSName() << T.str(); } + if (Args.getLastArg(OPT_fnative_half_type)) { + const LangStandard &Std = + LangStandard::getLangStandardForKind(Opts.LangStd); + if (!(Opts.LangStd >= LangStandard::lang_hlsl2018)) + Diags.Report(diag::err_drv_hlsl_16bit_types_unsupported) + << "-fnative-half-type" << false << Std.getName(); + } } else { llvm_unreachable("expected DXIL or SPIR-V target"); } diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp index b9fd9b8897b7e7187bedd5789de4fbcd769e0295..b7c9967316f0b82ff2b211315d1be87a05d6340c 100644 --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -535,8 +535,14 @@ static Module *prepareToBuildModule(CompilerInstance &CI, if (*OriginalModuleMap != CI.getSourceManager().getFileEntryRefForID( CI.getSourceManager().getMainFileID())) { M->IsInferred = true; - CI.getPreprocessor().getHeaderSearchInfo().getModuleMap() - .setInferredModuleAllowedBy(M, *OriginalModuleMap); + auto FileCharacter = + M->IsSystem ? SrcMgr::C_System_ModuleMap : SrcMgr::C_User_ModuleMap; + FileID OriginalModuleMapFID = CI.getSourceManager().getOrCreateFileID( + *OriginalModuleMap, FileCharacter); + CI.getPreprocessor() + .getHeaderSearchInfo() + .getModuleMap() + .setInferredModuleAllowedBy(M, OriginalModuleMapFID); } } diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 3fd1cdd3b4794262979ae19f7baed673e8dbc220..642b14d8b09d944e4832fa3bf7545d745ccadf53 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -450,6 +450,8 @@ private: return "BuildingBuiltinDumpStructCall"; case CodeSynthesisContext::BuildingDeductionGuides: return "BuildingDeductionGuides"; + case CodeSynthesisContext::TypeAliasTemplateInstantiation: + return "TypeAliasTemplateInstantiation"; } return ""; } diff --git a/clang/lib/Frontend/InitPreprocessor.cpp b/clang/lib/Frontend/InitPreprocessor.cpp index 48ad92063bd46165c5ed481c38708fe4a6733090..84069e96f41464b5e649ad0ffa93220e9102aef8 100644 --- a/clang/lib/Frontend/InitPreprocessor.cpp +++ b/clang/lib/Frontend/InitPreprocessor.cpp @@ -720,10 +720,7 @@ static void InitializeCPlusPlusFeatureTestMacros(const LangOptions &LangOpts, if (LangOpts.CPlusPlus20) { Builder.defineMacro("__cpp_aggregate_paren_init", "201902L"); - // P0848 is implemented, but we're still waiting for other concepts - // issues to be addressed before bumping __cpp_concepts up to 202002L. - // Refer to the discussion of this at https://reviews.llvm.org/D128619. - Builder.defineMacro("__cpp_concepts", "201907L"); + Builder.defineMacro("__cpp_concepts", "202002"); Builder.defineMacro("__cpp_conditional_explicit", "201806L"); Builder.defineMacro("__cpp_consteval", "202211L"); Builder.defineMacro("__cpp_constexpr_dynamic_alloc", "201907L"); diff --git a/clang/lib/Frontend/PrecompiledPreamble.cpp b/clang/lib/Frontend/PrecompiledPreamble.cpp index 9b0ef30a14121bc67dddb2fe91795a7aac42648f..fdf05c3613c9563eee7433e613562de007fe68bc 100644 --- a/clang/lib/Frontend/PrecompiledPreamble.cpp +++ b/clang/lib/Frontend/PrecompiledPreamble.cpp @@ -290,8 +290,7 @@ private: class PrecompilePreambleConsumer : public PCHGenerator { public: - PrecompilePreambleConsumer(PrecompilePreambleAction &Action, - const Preprocessor &PP, + PrecompilePreambleConsumer(PrecompilePreambleAction &Action, Preprocessor &PP, InMemoryModuleCache &ModuleCache, StringRef isysroot, std::shared_ptr Buffer) diff --git a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp index 1f40db785981d6cb633d48883d8a7010d0a7ea4e..6ae955a2380b74c58f72afdde91eeec658c96d8e 100644 --- a/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteModernObjC.cpp @@ -592,7 +592,7 @@ namespace { } bool ImplementationIsNonLazy(const ObjCImplDecl *OD) const { - IdentifierInfo* II = &Context->Idents.get("load"); + const IdentifierInfo *II = &Context->Idents.get("load"); Selector LoadSel = Context->Selectors.getSelector(0, &II); return OD->getClassMethod(LoadSel) != nullptr; } diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp index 2446aee571f440e9ee95803d7962325f8e4f9e95..f85f0365616f9ad8a92805a753bbc385aaa7a304 100644 --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -181,9 +181,13 @@ CreateFrontendAction(CompilerInstance &CI) { #endif // Wrap the base FE action in an extract api action to generate - // symbol graph as a biproduct of compilation ( enabled with - // --emit-symbol-graph option ) - if (!FEOpts.SymbolGraphOutputDir.empty()) { + // symbol graph as a biproduct of compilation (enabled with + // --emit-symbol-graph option) + if (FEOpts.EmitSymbolGraph) { + if (FEOpts.SymbolGraphOutputDir.empty()) { + CI.getDiagnostics().Report(diag::warn_missing_symbol_graph_dir); + CI.getFrontendOpts().SymbolGraphOutputDir = "."; + } CI.getCodeGenOpts().ClearASTBeforeBackend = false; Act = std::make_unique(std::move(Act)); } diff --git a/clang/lib/Headers/__stddef_unreachable.h b/clang/lib/Headers/__stddef_unreachable.h index 518580c92d3f5d01ae73e45be3e6e2b2e0b3075b..61df43e9732f8acfb02cacd2ed7f27d475ca183c 100644 --- a/clang/lib/Headers/__stddef_unreachable.h +++ b/clang/lib/Headers/__stddef_unreachable.h @@ -7,6 +7,8 @@ *===-----------------------------------------------------------------------=== */ +#ifndef __cplusplus + /* * When -fbuiltin-headers-in-system-modules is set this is a non-modular header * and needs to behave as if it was textual. @@ -15,3 +17,5 @@ (__has_feature(modules) && !__building_module(_Builtin_stddef)) #define unreachable() __builtin_unreachable() #endif + +#endif diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h index 5e703772b7ee4f539d21efba95ece7b3737af31f..06409c6fc77417c38e432efd34293dca8a47e2cf 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h @@ -100,6 +100,118 @@ double3 abs(double3); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_abs) double4 abs(double4); +//===----------------------------------------------------------------------===// +// all builtins +//===----------------------------------------------------------------------===// + +/// \fn bool all(T x) +/// \brief Returns True if all components of the \a x parameter are non-zero; +/// otherwise, false. \param x The input value. + +#ifdef __HLSL_ENABLE_16_BIT +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(int16_t); +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(int16_t2); +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(int16_t3); +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(int16_t4); +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(uint16_t); +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(uint16_t2); +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(uint16_t3); +_HLSL_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(uint16_t4); +#endif + +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(half); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(half2); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(half3); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(half4); + +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(bool); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(bool2); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(bool3); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(bool4); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) + +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(int); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(int2); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(int3); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(int4); + +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(uint); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(uint2); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(uint3); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(uint4); + +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(float); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(float2); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(float3); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(float4); + +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(int64_t); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(int64_t2); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(int64_t3); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(int64_t4); + +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(uint64_t); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(uint64_t2); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(uint64_t3); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(uint64_t4); + +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(double); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(double2); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(double3); +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_elementwise_all) +bool all(double4); + //===----------------------------------------------------------------------===// // any builtins //===----------------------------------------------------------------------===// @@ -243,15 +355,6 @@ float3 ceil(float3); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_ceil) float4 ceil(float4); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_ceil) -double ceil(double); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_ceil) -double2 ceil(double2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_ceil) -double3 ceil(double3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_ceil) -double4 ceil(double4); - //===----------------------------------------------------------------------===// // clamp builtins //===----------------------------------------------------------------------===// @@ -392,15 +495,6 @@ float3 cos(float3); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_cos) float4 cos(float4); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_cos) -double cos(double); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_cos) -double2 cos(double2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_cos) -double3 cos(double3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_cos) -double4 cos(double4); - //===----------------------------------------------------------------------===// // dot product builtins //===----------------------------------------------------------------------===// @@ -594,15 +688,6 @@ float3 floor(float3); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_floor) float4 floor(float4); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_floor) -double floor(double); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_floor) -double2 floor(double2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_floor) -double3 floor(double3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_floor) -double4 floor(double4); - //===----------------------------------------------------------------------===// // frac builtins //===----------------------------------------------------------------------===// @@ -737,15 +822,6 @@ float3 log(float3); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_log) float4 log(float4); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_log) -double log(double); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_log) -double2 log(double2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_log) -double3 log(double3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_log) -double4 log(double4); - //===----------------------------------------------------------------------===// // log10 builtins //===----------------------------------------------------------------------===// @@ -779,15 +855,6 @@ float3 log10(float3); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_log10) float4 log10(float4); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_log10) -double log10(double); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_log10) -double2 log10(double2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_log10) -double3 log10(double3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_log10) -double4 log10(double4); - //===----------------------------------------------------------------------===// // log2 builtins //===----------------------------------------------------------------------===// @@ -821,15 +888,6 @@ float3 log2(float3); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_log2) float4 log2(float4); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_log2) -double log2(double); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_log2) -double2 log2(double2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_log2) -double3 log2(double3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_log2) -double4 log2(double4); - //===----------------------------------------------------------------------===// // mad builtins //===----------------------------------------------------------------------===// @@ -1174,15 +1232,6 @@ float3 pow(float3, float3); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_pow) float4 pow(float4, float4); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_pow) -double pow(double, double); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_pow) -double2 pow(double2, double2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_pow) -double3 pow(double3, double3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_pow) -double4 pow(double4, double4); - //===----------------------------------------------------------------------===// // reversebits builtins //===----------------------------------------------------------------------===// @@ -1192,19 +1241,6 @@ double4 pow(double4, double4); /// \param Val The input value. #ifdef __HLSL_ENABLE_16_BIT -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int16_t reversebits(int16_t); -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int16_t2 reversebits(int16_t2); -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int16_t3 reversebits(int16_t3); -_HLSL_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int16_t4 reversebits(int16_t4); - _HLSL_AVAILABILITY(shadermodel, 6.2) _HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) uint16_t reversebits(uint16_t); @@ -1219,15 +1255,6 @@ _HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) uint16_t4 reversebits(uint16_t4); #endif -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int reversebits(int); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int2 reversebits(int2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int3 reversebits(int3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int4 reversebits(int4); - _HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) uint reversebits(uint); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) @@ -1237,15 +1264,6 @@ uint3 reversebits(uint3); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) uint4 reversebits(uint4); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int64_t reversebits(int64_t); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int64_t2 reversebits(int64_t2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int64_t3 reversebits(int64_t3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) -int64_t4 reversebits(int64_t4); - _HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) uint64_t reversebits(uint64_t); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_bitreverse) @@ -1342,25 +1360,25 @@ float4 rsqrt(float4); /// rounded to the nearest even value. _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) half round(half); _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) half2 round(half2); _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) half3 round(half3); _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) half4 round(half4); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) float round(float); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) float2 round(float2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) float3 round(float3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_round) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_roundeven) float4 round(float4); //===----------------------------------------------------------------------===// @@ -1393,15 +1411,6 @@ float3 sin(float3); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_sin) float4 sin(float4); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_sin) -double sin(double); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_sin) -double2 sin(double2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_sin) -double3 sin(double3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_sin) -double4 sin(double4); - //===----------------------------------------------------------------------===// // sqrt builtins //===----------------------------------------------------------------------===// @@ -1411,14 +1420,26 @@ double4 sin(double4); /// \param Val The input value. _HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) -_HLSL_BUILTIN_ALIAS(__builtin_sqrtf16) -half sqrt(half In); - -_HLSL_BUILTIN_ALIAS(__builtin_sqrtf) -float sqrt(float In); +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_sqrt) +half sqrt(half); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_sqrt) +half2 sqrt(half2); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_sqrt) +half3 sqrt(half3); +_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2) +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_sqrt) +half4 sqrt(half4); -_HLSL_BUILTIN_ALIAS(__builtin_sqrt) -double sqrt(double In); +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_sqrt) +float sqrt(float); +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_sqrt) +float2 sqrt(float2); +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_sqrt) +float3 sqrt(float3); +_HLSL_BUILTIN_ALIAS(__builtin_elementwise_sqrt) +float4 sqrt(float4); //===----------------------------------------------------------------------===// // trunc builtins @@ -1450,15 +1471,6 @@ float3 trunc(float3); _HLSL_BUILTIN_ALIAS(__builtin_elementwise_trunc) float4 trunc(float4); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_trunc) -double trunc(double); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_trunc) -double2 trunc(double2); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_trunc) -double3 trunc(double3); -_HLSL_BUILTIN_ALIAS(__builtin_elementwise_trunc) -double4 trunc(double4); - //===----------------------------------------------------------------------===// // Wave* builtins //===----------------------------------------------------------------------===// @@ -1471,7 +1483,12 @@ double4 trunc(double4); /// true, across all active lanes in the current wave. _HLSL_AVAILABILITY(shadermodel, 6.0) _HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_active_count_bits) -uint WaveActiveCountBits(bool Val); +__attribute__((convergent)) uint WaveActiveCountBits(bool Val); + +/// \brief Returns the index of the current lane within the current wave. +_HLSL_AVAILABILITY(shadermodel, 6.0) +_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_get_lane_index) +__attribute__((convergent)) uint WaveGetLaneIndex(); } // namespace hlsl #endif //_HLSL_HLSL_INTRINSICS_H_ diff --git a/clang/lib/Headers/intrin.h b/clang/lib/Headers/intrin.h index fd27955fbe002d8069a55d04de8f933edd7b2d75..7eb6dceaabfaeb611123945343d43d15bfece664 100644 --- a/clang/lib/Headers/intrin.h +++ b/clang/lib/Headers/intrin.h @@ -18,7 +18,7 @@ #include /* First include the standard intrinsics. */ -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) #include #endif @@ -26,7 +26,7 @@ #include #endif -#if defined(__aarch64__) +#if defined(__aarch64__) || defined(__arm64ec__) #include #endif @@ -166,7 +166,7 @@ unsigned __int32 xbegin(void); void _xend(void); /* These additional intrinsics are turned on in x64/amd64/x86_64 mode. */ -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__arm64ec__) void __addgsbyte(unsigned long, unsigned char); void __addgsdword(unsigned long, unsigned long); void __addgsqword(unsigned long, unsigned __int64); @@ -236,7 +236,8 @@ __int64 _mul128(__int64, __int64, __int64 *); /*----------------------------------------------------------------------------*\ |* movs, stos \*----------------------------------------------------------------------------*/ -#if defined(__i386__) || defined(__x86_64__) + +#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) static __inline__ void __DEFAULT_FN_ATTRS __movsb(unsigned char *__dst, unsigned char const *__src, size_t __n) { @@ -305,7 +306,7 @@ static __inline__ void __DEFAULT_FN_ATTRS __stosw(unsigned short *__dst, : "memory"); } #endif -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__arm64ec__) static __inline__ void __DEFAULT_FN_ATTRS __movsq( unsigned long long *__dst, unsigned long long const *__src, size_t __n) { __asm__ __volatile__("rep movsq" @@ -324,7 +325,7 @@ static __inline__ void __DEFAULT_FN_ATTRS __stosq(unsigned __int64 *__dst, /*----------------------------------------------------------------------------*\ |* Misc \*----------------------------------------------------------------------------*/ -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) static __inline__ void __DEFAULT_FN_ATTRS __halt(void) { __asm__ volatile("hlt"); } @@ -339,7 +340,7 @@ static __inline__ void __DEFAULT_FN_ATTRS __nop(void) { /*----------------------------------------------------------------------------*\ |* MS AArch64 specific \*----------------------------------------------------------------------------*/ -#if defined(__aarch64__) +#if defined(__aarch64__) || defined(__arm64ec__) unsigned __int64 __getReg(int); long _InterlockedAdd(long volatile *Addend, long Value); __int64 _InterlockedAdd64(__int64 volatile *Addend, __int64 Value); @@ -383,7 +384,7 @@ void __cdecl __prefetch(void *); /*----------------------------------------------------------------------------*\ |* Privileged intrinsics \*----------------------------------------------------------------------------*/ -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) static __inline__ unsigned __int64 __DEFAULT_FN_ATTRS __readmsr(unsigned long __register) { // Loads the contents of a 64-bit model specific register (MSR) specified in @@ -397,7 +398,6 @@ __readmsr(unsigned long __register) { __asm__ ("rdmsr" : "=d"(__edx), "=a"(__eax) : "c"(__register)); return (((unsigned __int64)__edx) << 32) | (unsigned __int64)__eax; } -#endif static __inline__ unsigned __LPTRINT_TYPE__ __DEFAULT_FN_ATTRS __readcr3(void) { unsigned __LPTRINT_TYPE__ __cr3_val; @@ -413,6 +413,7 @@ static __inline__ void __DEFAULT_FN_ATTRS __writecr3(unsigned __INTPTR_TYPE__ __cr3_val) { __asm__ ("mov {%0, %%cr3|cr3, %0}" : : "r"(__cr3_val) : "memory"); } +#endif #ifdef __cplusplus } diff --git a/clang/lib/Headers/intrin0.h b/clang/lib/Headers/intrin0.h index 31f362ec84d5c571113c34f1ac2932d1af0ba699..866c8896617d22aea66ef301f68a623318bddc6e 100644 --- a/clang/lib/Headers/intrin0.h +++ b/clang/lib/Headers/intrin0.h @@ -15,7 +15,7 @@ #ifndef __INTRIN0_H #define __INTRIN0_H -#ifdef __x86_64__ +#if defined(__x86_64__) && !defined(__arm64ec__) #include #endif @@ -27,7 +27,7 @@ unsigned char _BitScanForward(unsigned long *_Index, unsigned long _Mask); unsigned char _BitScanReverse(unsigned long *_Index, unsigned long _Mask); void _ReadWriteBarrier(void); -#if defined(__aarch64__) +#if defined(__aarch64__) || defined(__arm64ec__) unsigned int _CountLeadingZeros(unsigned long); unsigned int _CountLeadingZeros64(unsigned _int64); unsigned char _InterlockedCompareExchange128_acq(__int64 volatile *_Destination, @@ -44,7 +44,7 @@ unsigned char _InterlockedCompareExchange128_rel(__int64 volatile *_Destination, __int64 *_ComparandResult); #endif -#ifdef __x86_64__ +#ifdef __x86_64__ && !defined(__arm64ec__) unsigned __int64 _umul128(unsigned __int64, unsigned __int64, unsigned __int64 *); unsigned __int64 __shiftleft128(unsigned __int64 _LowPart, @@ -55,7 +55,7 @@ unsigned __int64 __shiftright128(unsigned __int64 _LowPart, unsigned char _Shift); #endif -#if defined(__x86_64__) || defined(__i386__) +#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) void _mm_pause(void); #endif @@ -83,7 +83,7 @@ __int64 _InterlockedXor64(__int64 volatile *_Value, __int64 _Mask); __int64 _InterlockedAnd64(__int64 volatile *_Value, __int64 _Mask); #endif -#if defined(__arm__) || defined(__aarch64__) +#if defined(__arm__) || defined(__aarch64__) || defined(__arm64ec__) /*----------------------------------------------------------------------------*\ |* Interlocked Exchange Add \*----------------------------------------------------------------------------*/ diff --git a/clang/lib/Headers/mmintrin.h b/clang/lib/Headers/mmintrin.h index 962d24738e7aa48e338e57141952ebf5d359c492..4e154e2d85935303eddf0dbaf0f62c7401adc09d 100644 --- a/clang/lib/Headers/mmintrin.h +++ b/clang/lib/Headers/mmintrin.h @@ -1141,7 +1141,7 @@ _mm_xor_si64(__m64 __m1, __m64 __m2) /// [8 x i8] to determine if the element of the first vector is equal to the /// corresponding element of the second vector. /// -/// The comparison yields 0 for false, 0xFF for true. +/// Each comparison returns 0 for false, 0xFF for true. /// /// \headerfile /// @@ -1163,7 +1163,7 @@ _mm_cmpeq_pi8(__m64 __m1, __m64 __m2) /// [4 x i16] to determine if the element of the first vector is equal to the /// corresponding element of the second vector. /// -/// The comparison yields 0 for false, 0xFFFF for true. +/// Each comparison returns 0 for false, 0xFFFF for true. /// /// \headerfile /// @@ -1185,7 +1185,7 @@ _mm_cmpeq_pi16(__m64 __m1, __m64 __m2) /// [2 x i32] to determine if the element of the first vector is equal to the /// corresponding element of the second vector. /// -/// The comparison yields 0 for false, 0xFFFFFFFF for true. +/// Each comparison returns 0 for false, 0xFFFFFFFF for true. /// /// \headerfile /// @@ -1207,7 +1207,7 @@ _mm_cmpeq_pi32(__m64 __m1, __m64 __m2) /// [8 x i8] to determine if the element of the first vector is greater than /// the corresponding element of the second vector. /// -/// The comparison yields 0 for false, 0xFF for true. +/// Each comparison returns 0 for false, 0xFF for true. /// /// \headerfile /// @@ -1229,7 +1229,7 @@ _mm_cmpgt_pi8(__m64 __m1, __m64 __m2) /// [4 x i16] to determine if the element of the first vector is greater than /// the corresponding element of the second vector. /// -/// The comparison yields 0 for false, 0xFFFF for true. +/// Each comparison returns 0 for false, 0xFFFF for true. /// /// \headerfile /// @@ -1251,7 +1251,7 @@ _mm_cmpgt_pi16(__m64 __m1, __m64 __m2) /// [2 x i32] to determine if the element of the first vector is greater than /// the corresponding element of the second vector. /// -/// The comparison yields 0 for false, 0xFFFFFFFF for true. +/// Each comparison returns 0 for false, 0xFFFFFFFF for true. /// /// \headerfile /// diff --git a/clang/lib/Headers/smmintrin.h b/clang/lib/Headers/smmintrin.h index 9fb9cc9b01348cae2302249e55020fc0c36a58fb..b3fec474e35a1e03e7b4de6e434355a959caeb25 100644 --- a/clang/lib/Headers/smmintrin.h +++ b/clang/lib/Headers/smmintrin.h @@ -1188,7 +1188,7 @@ static __inline__ int __DEFAULT_FN_ATTRS _mm_testnzc_si128(__m128i __M, /// Compares each of the corresponding 64-bit values of the 128-bit /// integer vectors for equality. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFFFFFFFFFF for true. +/// Each comparison returns 0x0 for false, 0xFFFFFFFFFFFFFFFF for true. /// /// \headerfile /// @@ -2303,7 +2303,7 @@ static __inline__ __m128i __DEFAULT_FN_ATTRS _mm_minpos_epu16(__m128i __V) { /// integer vectors to determine if the values in the first operand are /// greater than those in the second operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFFFFFFFFFF for true. +/// Each comparison returns 0x0 for false, 0xFFFFFFFFFFFFFFFF for true. /// /// \headerfile /// diff --git a/clang/lib/Headers/xmmintrin.h b/clang/lib/Headers/xmmintrin.h index 040194786a27998610bdd3e770055f6e3785a85f..1ef89de9c9f5622d60b63fa19c06ddf7589488ef 100644 --- a/clang/lib/Headers/xmmintrin.h +++ b/clang/lib/Headers/xmmintrin.h @@ -484,7 +484,7 @@ _mm_xor_ps(__m128 __a, __m128 __b) /// Compares two 32-bit float values in the low-order bits of both /// operands for equality. /// -/// The comparison yields 0x0 for false, 0xFFFFFFFF for true, in the +/// The comparison returns 0x0 for false, 0xFFFFFFFF for true, in the /// low-order bits of a vector [4 x float]. /// If either value in a comparison is NaN, returns false. /// @@ -509,7 +509,7 @@ _mm_cmpeq_ss(__m128 __a, __m128 __b) /// Compares each of the corresponding 32-bit float values of the /// 128-bit vectors of [4 x float] for equality. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFF for true. +/// Each comparison returns 0x0 for false, 0xFFFFFFFF for true. /// If either value in a comparison is NaN, returns false. /// /// \headerfile @@ -531,7 +531,7 @@ _mm_cmpeq_ps(__m128 __a, __m128 __b) /// operands to determine if the value in the first operand is less than the /// corresponding value in the second operand. /// -/// The comparison yields 0x0 for false, 0xFFFFFFFF for true, in the +/// The comparison returns 0x0 for false, 0xFFFFFFFF for true, in the /// low-order bits of a vector of [4 x float]. /// If either value in a comparison is NaN, returns false. /// @@ -557,7 +557,7 @@ _mm_cmplt_ss(__m128 __a, __m128 __b) /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are less than those in the second operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFFFFFFFFFF for true. +/// Each comparison returns 0x0 for false, 0xFFFFFFFFFFFFFFFF for true. /// If either value in a comparison is NaN, returns false. /// /// \headerfile @@ -579,7 +579,7 @@ _mm_cmplt_ps(__m128 __a, __m128 __b) /// operands to determine if the value in the first operand is less than or /// equal to the corresponding value in the second operand. /// -/// The comparison yields 0x0 for false, 0xFFFFFFFFFFFFFFFF for true, in +/// The comparison returns 0x0 for false, 0xFFFFFFFFFFFFFFFF for true, in /// the low-order bits of a vector of [4 x float]. /// If either value in a comparison is NaN, returns false. /// @@ -605,7 +605,7 @@ _mm_cmple_ss(__m128 __a, __m128 __b) /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are less than or equal to those in the second operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFF for true. +/// Each comparison returns 0x0 for false, 0xFFFFFFFF for true. /// If either value in a comparison is NaN, returns false. /// /// \headerfile @@ -627,7 +627,7 @@ _mm_cmple_ps(__m128 __a, __m128 __b) /// operands to determine if the value in the first operand is greater than /// the corresponding value in the second operand. /// -/// The comparison yields 0x0 for false, 0xFFFFFFFF for true, in the +/// The comparison returns 0x0 for false, 0xFFFFFFFF for true, in the /// low-order bits of a vector of [4 x float]. /// If either value in a comparison is NaN, returns false. /// @@ -655,7 +655,7 @@ _mm_cmpgt_ss(__m128 __a, __m128 __b) /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are greater than those in the second operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFF for true. +/// Each comparison returns 0x0 for false, 0xFFFFFFFF for true. /// If either value in a comparison is NaN, returns false. /// /// \headerfile @@ -677,7 +677,7 @@ _mm_cmpgt_ps(__m128 __a, __m128 __b) /// operands to determine if the value in the first operand is greater than /// or equal to the corresponding value in the second operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFF for true, in the +/// Each comparison returns 0x0 for false, 0xFFFFFFFF for true, in the /// low-order bits of a vector of [4 x float]. /// If either value in a comparison is NaN, returns false. /// @@ -705,7 +705,7 @@ _mm_cmpge_ss(__m128 __a, __m128 __b) /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are greater than or equal to those in the second operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFFFFFFFFFF for true. +/// Each comparison returns 0x0 for false, 0xFFFFFFFFFFFFFFFF for true. /// If either value in a comparison is NaN, returns false. /// /// \headerfile @@ -726,7 +726,7 @@ _mm_cmpge_ps(__m128 __a, __m128 __b) /// Compares two 32-bit float values in the low-order bits of both operands /// for inequality. /// -/// The comparison yields 0x0 for false, 0xFFFFFFFF for true, in the +/// The comparison returns 0x0 for false, 0xFFFFFFFF for true, in the /// low-order bits of a vector of [4 x float]. /// If either value in a comparison is NaN, returns true. /// @@ -752,7 +752,7 @@ _mm_cmpneq_ss(__m128 __a, __m128 __b) /// Compares each of the corresponding 32-bit float values of the /// 128-bit vectors of [4 x float] for inequality. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFF for true. +/// Each comparison returns 0x0 for false, 0xFFFFFFFF for true. /// If either value in a comparison is NaN, returns true. /// /// \headerfile @@ -775,7 +775,7 @@ _mm_cmpneq_ps(__m128 __a, __m128 __b) /// operands to determine if the value in the first operand is not less than /// the corresponding value in the second operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFF for true, in the +/// Each comparison returns 0x0 for false, 0xFFFFFFFF for true, in the /// low-order bits of a vector of [4 x float]. /// If either value in a comparison is NaN, returns true. /// @@ -802,7 +802,7 @@ _mm_cmpnlt_ss(__m128 __a, __m128 __b) /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are not less than those in the second operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFF for true. +/// Each comparison returns 0x0 for false, 0xFFFFFFFF for true. /// If either value in a comparison is NaN, returns true. /// /// \headerfile @@ -825,7 +825,7 @@ _mm_cmpnlt_ps(__m128 __a, __m128 __b) /// operands to determine if the value in the first operand is not less than /// or equal to the corresponding value in the second operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFF for true, in the +/// Each comparison returns 0x0 for false, 0xFFFFFFFF for true, in the /// low-order bits of a vector of [4 x float]. /// If either value in a comparison is NaN, returns true. /// @@ -852,7 +852,7 @@ _mm_cmpnle_ss(__m128 __a, __m128 __b) /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are not less than or equal to those in the second operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFF for true. +/// Each comparison returns 0x0 for false, 0xFFFFFFFF for true. /// If either value in a comparison is NaN, returns true. /// /// \headerfile @@ -875,7 +875,7 @@ _mm_cmpnle_ps(__m128 __a, __m128 __b) /// operands to determine if the value in the first operand is not greater /// than the corresponding value in the second operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFF for true, in the +/// Each comparison returns 0x0 for false, 0xFFFFFFFF for true, in the /// low-order bits of a vector of [4 x float]. /// If either value in a comparison is NaN, returns true. /// @@ -904,7 +904,7 @@ _mm_cmpngt_ss(__m128 __a, __m128 __b) /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are not greater than those in the second operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFF for true. +/// Each comparison returns 0x0 for false, 0xFFFFFFFF for true. /// If either value in a comparison is NaN, returns true. /// /// \headerfile @@ -927,7 +927,7 @@ _mm_cmpngt_ps(__m128 __a, __m128 __b) /// operands to determine if the value in the first operand is not greater /// than or equal to the corresponding value in the second operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFF for true, in the +/// Each comparison returns 0x0 for false, 0xFFFFFFFF for true, in the /// low-order bits of a vector of [4 x float]. /// If either value in a comparison is NaN, returns true. /// @@ -956,7 +956,7 @@ _mm_cmpnge_ss(__m128 __a, __m128 __b) /// 128-bit vectors of [4 x float] to determine if the values in the first /// operand are not greater than or equal to those in the second operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFF for true. +/// Each comparison returns 0x0 for false, 0xFFFFFFFF for true. /// If either value in a comparison is NaN, returns true. /// /// \headerfile @@ -3061,7 +3061,7 @@ _mm_movemask_ps(__m128 __a) /// [4 x float], using the operation specified by the immediate integer /// operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFF for true. +/// Each comparison returns 0x0 for false, 0xFFFFFFFF for true. /// If either value in a comparison is NaN, comparisons that are ordered /// return false, and comparisons that are unordered return true. /// @@ -3096,7 +3096,7 @@ _mm_movemask_ps(__m128 __a) /// vectors of [4 x float], using the operation specified by the immediate /// integer operand. /// -/// Each comparison yields 0x0 for false, 0xFFFFFFFF for true. +/// Each comparison returns 0x0 for false, 0xFFFFFFFF for true. /// If either value in a comparison is NaN, comparisons that are ordered /// return false, and comparisons that are unordered return true. /// diff --git a/clang/lib/InstallAPI/CMakeLists.txt b/clang/lib/InstallAPI/CMakeLists.txt index 894db699578f209a3300cd53fa7527b70d1229bd..b36493942300b6b44a30b221575ae09a9022e710 100644 --- a/clang/lib/InstallAPI/CMakeLists.txt +++ b/clang/lib/InstallAPI/CMakeLists.txt @@ -1,11 +1,13 @@ set(LLVM_LINK_COMPONENTS Support TextAPI + TextAPIBinaryReader Demangle Core ) add_clang_library(clangInstallAPI + DiagnosticBuilderWrappers.cpp DylibVerifier.cpp FileList.cpp Frontend.cpp diff --git a/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc252d51e3b67711ac6449949f4880586b2a6b25 --- /dev/null +++ b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.cpp @@ -0,0 +1,110 @@ +//===- DiagnosticBuilderWrappers.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 "DiagnosticBuilderWrappers.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TextAPI/Platform.h" + +using clang::DiagnosticBuilder; + +namespace llvm { +namespace MachO { +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const Architecture &Arch) { + DB.AddString(getArchitectureName(Arch)); + return DB; +} + +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const ArchitectureSet &ArchSet) { + DB.AddString(std::string(ArchSet)); + return DB; +} + +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const PlatformType &Platform) { + DB.AddString(getPlatformName(Platform)); + return DB; +} + +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const PlatformVersionSet &Platforms) { + std::string PlatformAsString; + raw_string_ostream Stream(PlatformAsString); + + Stream << "[ "; + llvm::interleaveComma( + Platforms, Stream, + [&Stream](const std::pair &PV) { + Stream << getPlatformName(PV.first); + if (!PV.second.empty()) + Stream << PV.second.getAsString(); + }); + Stream << " ]"; + DB.AddString(Stream.str()); + return DB; +} + +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const FileType &Type) { + switch (Type) { + case FileType::MachO_Bundle: + DB.AddString("mach-o bundle"); + return DB; + case FileType::MachO_DynamicLibrary: + DB.AddString("mach-o dynamic library"); + return DB; + case FileType::MachO_DynamicLibrary_Stub: + DB.AddString("mach-o dynamic library stub"); + return DB; + case FileType::TBD_V1: + DB.AddString("tbd-v1"); + return DB; + case FileType::TBD_V2: + DB.AddString("tbd-v2"); + return DB; + case FileType::TBD_V3: + DB.AddString("tbd-v3"); + return DB; + case FileType::TBD_V4: + DB.AddString("tbd-v4"); + return DB; + case FileType::TBD_V5: + DB.AddString("tbd-v5"); + return DB; + case FileType::Invalid: + case FileType::All: + break; + } + llvm_unreachable("Unexpected file type for diagnostics."); +} + +const DiagnosticBuilder &operator<<(const DiagnosticBuilder &DB, + const PackedVersion &Version) { + std::string VersionString; + raw_string_ostream OS(VersionString); + OS << Version; + DB.AddString(OS.str()); + return DB; +} + +const clang::DiagnosticBuilder & +operator<<(const clang::DiagnosticBuilder &DB, + const StringMapEntry &LibAttr) { + std::string IFAsString; + raw_string_ostream OS(IFAsString); + + OS << LibAttr.getKey() << " [ " << LibAttr.getValue() << " ]"; + DB.AddString(OS.str()); + return DB; +} + +} // namespace MachO +} // namespace llvm diff --git a/clang/lib/InstallAPI/DiagnosticBuilderWrappers.h b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.h new file mode 100644 index 0000000000000000000000000000000000000000..48cfefbf65e6bc225dd615f1754846942bdc024c --- /dev/null +++ b/clang/lib/InstallAPI/DiagnosticBuilderWrappers.h @@ -0,0 +1,49 @@ +//===- DiagnosticBuilderWrappers.h -----------------------------*- 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 +// +//===----------------------------------------------------------------------===// +// +/// Diagnostic wrappers for TextAPI types for error reporting. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_INSTALLAPI_DIAGNOSTICBUILDER_WRAPPER_H +#define LLVM_CLANG_INSTALLAPI_DIAGNOSTICBUILDER_WRAPPER_H + +#include "clang/Basic/Diagnostic.h" +#include "llvm/TextAPI/Architecture.h" +#include "llvm/TextAPI/ArchitectureSet.h" +#include "llvm/TextAPI/InterfaceFile.h" +#include "llvm/TextAPI/Platform.h" + +namespace llvm { +namespace MachO { + +const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB, + const PlatformType &Platform); + +const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB, + const PlatformVersionSet &Platforms); + +const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB, + const Architecture &Arch); + +const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB, + const ArchitectureSet &ArchSet); + +const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB, + const FileType &Type); + +const clang::DiagnosticBuilder &operator<<(const clang::DiagnosticBuilder &DB, + const PackedVersion &Version); + +const clang::DiagnosticBuilder & +operator<<(const clang::DiagnosticBuilder &DB, + const StringMapEntry &LibAttr); + +} // namespace MachO +} // namespace llvm +#endif // LLVM_CLANG_INSTALLAPI_DIAGNOSTICBUILDER_WRAPPER_H diff --git a/clang/lib/InstallAPI/DylibVerifier.cpp b/clang/lib/InstallAPI/DylibVerifier.cpp index 94b8e9cd3233a9213562b243d204208ef1e268e4..4fa2d4e9292c72e2307f9eb5712f1f8b2dd324e0 100644 --- a/clang/lib/InstallAPI/DylibVerifier.cpp +++ b/clang/lib/InstallAPI/DylibVerifier.cpp @@ -1,7 +1,17 @@ +//===- DylibVerifier.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 "clang/InstallAPI/DylibVerifier.h" +#include "DiagnosticBuilderWrappers.h" #include "clang/InstallAPI/FrontendRecords.h" #include "clang/InstallAPI/InstallAPIDiagnostic.h" #include "llvm/Demangle/Demangle.h" +#include "llvm/TextAPI/DylibReader.h" using namespace llvm::MachO; @@ -27,6 +37,14 @@ struct DylibVerifier::SymbolContext { bool Inlined = false; }; +struct DylibVerifier::DWARFContext { + // Track whether DSYM parsing has already been attempted to avoid re-parsing. + bool ParsedDSYM{false}; + + // Lookup table for source locations by symbol name. + DylibReader::SymbolToSourceLocMap SourceLocs{}; +}; + static bool isCppMangled(StringRef Name) { // InstallAPI currently only supports itanium manglings. return (Name.starts_with("_Z") || Name.starts_with("__Z") || @@ -161,6 +179,22 @@ bool DylibVerifier::shouldIgnoreObsolete(const Record *R, SymbolContext &SymCtx, return SymCtx.FA->Avail.isObsoleted(); } +bool DylibVerifier::shouldIgnoreReexport(const Record *R, + SymbolContext &SymCtx) const { + if (Reexports.empty()) + return false; + + for (const InterfaceFile &Lib : Reexports) { + if (!Lib.hasTarget(Ctx.Target)) + continue; + if (auto Sym = + Lib.getSymbol(SymCtx.Kind, SymCtx.SymbolName, SymCtx.ObjCIFKind)) + if ((*Sym)->hasTarget(Ctx.Target)) + return true; + } + return false; +} + bool DylibVerifier::compareObjCInterfaceSymbols(const Record *R, SymbolContext &SymCtx, const ObjCInterfaceRecord *DR) { @@ -180,16 +214,16 @@ bool DylibVerifier::compareObjCInterfaceSymbols(const Record *R, StringRef SymName, bool PrintAsWarning = false) { if (SymLinkage == RecordLinkage::Unknown) Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - PrintAsWarning ? diag::warn_library_missing_symbol - : diag::err_library_missing_symbol) + Ctx.Diag->Report(SymCtx.FA->Loc, PrintAsWarning + ? diag::warn_library_missing_symbol + : diag::err_library_missing_symbol) << SymName; }); else Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - PrintAsWarning ? diag::warn_library_hidden_symbol - : diag::err_library_hidden_symbol) + Ctx.Diag->Report(SymCtx.FA->Loc, PrintAsWarning + ? diag::warn_library_hidden_symbol + : diag::err_library_hidden_symbol) << SymName; }); }; @@ -236,16 +270,14 @@ DylibVerifier::Result DylibVerifier::compareVisibility(const Record *R, if (R->isExported()) { if (!DR) { Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::err_library_missing_symbol) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_library_missing_symbol) << getAnnotatedName(R, SymCtx); }); return Result::Invalid; } if (DR->isInternal()) { Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::err_library_hidden_symbol) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_library_hidden_symbol) << getAnnotatedName(R, SymCtx); }); return Result::Invalid; @@ -272,8 +304,7 @@ DylibVerifier::Result DylibVerifier::compareVisibility(const Record *R, Outcome = Result::Invalid; } Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), ID) - << getAnnotatedName(R, SymCtx); + Ctx.Diag->Report(SymCtx.FA->Loc, ID) << getAnnotatedName(R, SymCtx); }); return Outcome; } @@ -295,15 +326,13 @@ DylibVerifier::Result DylibVerifier::compareAvailability(const Record *R, switch (Mode) { case VerificationMode::ErrorsAndWarnings: Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::warn_header_availability_mismatch) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::warn_header_availability_mismatch) << getAnnotatedName(R, SymCtx) << IsDeclAvailable << IsDeclAvailable; }); return Result::Ignore; case VerificationMode::Pedantic: Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::err_header_availability_mismatch) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_header_availability_mismatch) << getAnnotatedName(R, SymCtx) << IsDeclAvailable << IsDeclAvailable; }); return Result::Invalid; @@ -319,16 +348,14 @@ bool DylibVerifier::compareSymbolFlags(const Record *R, SymbolContext &SymCtx, const Record *DR) { if (DR->isThreadLocalValue() && !R->isThreadLocalValue()) { Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::err_dylib_symbol_flags_mismatch) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_dylib_symbol_flags_mismatch) << getAnnotatedName(DR, SymCtx) << DR->isThreadLocalValue(); }); return false; } if (!DR->isThreadLocalValue() && R->isThreadLocalValue()) { Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::err_header_symbol_flags_mismatch) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_header_symbol_flags_mismatch) << getAnnotatedName(R, SymCtx) << R->isThreadLocalValue(); }); return false; @@ -336,16 +363,14 @@ bool DylibVerifier::compareSymbolFlags(const Record *R, SymbolContext &SymCtx, if (DR->isWeakDefined() && !R->isWeakDefined()) { Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::err_dylib_symbol_flags_mismatch) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_dylib_symbol_flags_mismatch) << getAnnotatedName(DR, SymCtx) << R->isWeakDefined(); }); return false; } if (!DR->isWeakDefined() && R->isWeakDefined()) { Ctx.emitDiag([&]() { - Ctx.Diag->Report(SymCtx.FA->D->getLocation(), - diag::err_header_symbol_flags_mismatch) + Ctx.Diag->Report(SymCtx.FA->Loc, diag::err_header_symbol_flags_mismatch) << getAnnotatedName(R, SymCtx) << R->isWeakDefined(); }); return false; @@ -366,6 +391,11 @@ DylibVerifier::Result DylibVerifier::verifyImpl(Record *R, return Ctx.FrontendState; } + if (shouldIgnoreReexport(R, SymCtx)) { + updateState(Result::Ignore); + return Ctx.FrontendState; + } + Record *DR = findRecordFromSlice(Ctx.DylibSlice, SymCtx.SymbolName, SymCtx.Kind); if (DR) @@ -448,6 +478,14 @@ void DylibVerifier::setTarget(const Target &T) { assignSlice(T); } +void DylibVerifier::setSourceManager( + IntrusiveRefCntPtr SourceMgr) { + if (!Ctx.Diag) + return; + SourceManagers.push_back(std::move(SourceMgr)); + Ctx.Diag->setSourceManager(SourceManagers.back().get()); +} + DylibVerifier::Result DylibVerifier::verify(ObjCIVarRecord *R, const FrontendAttrs *FA, const StringRef SuperClass) { @@ -503,14 +541,16 @@ DylibVerifier::Result DylibVerifier::verify(GlobalRecord *R, return verifyImpl(R, SymCtx); } -void DylibVerifier::VerifierContext::emitDiag( - llvm::function_ref Report) { +void DylibVerifier::VerifierContext::emitDiag(llvm::function_ref Report, + RecordLoc *Loc) { if (!DiscoveredFirstError) { Diag->Report(diag::warn_target) << (PrintArch ? getArchitectureName(Target.Arch) : getTargetTripleName(Target)); DiscoveredFirstError = true; } + if (Loc && Loc->isValid()) + llvm::errs() << Loc->File << ":" << Loc->Line << ":" << 0 << ": "; Report(); } @@ -553,26 +593,36 @@ void DylibVerifier::visitSymbolInDylib(const Record &R, SymbolContext &SymCtx) { return; } - // All checks at this point classify as some kind of violation that should be - // reported. + const bool IsLinkerSymbol = SymbolName.starts_with("$ld$"); + + // All checks at this point classify as some kind of violation. + // The different verification modes dictate whether they are reported to the + // user. + if (IsLinkerSymbol || (Mode > VerificationMode::ErrorsOnly)) + accumulateSrcLocForDylibSymbols(); + RecordLoc Loc = DWARFCtx->SourceLocs.lookup(SymCtx.SymbolName); // Regardless of verification mode, error out on mismatched special linker // symbols. - if (SymbolName.starts_with("$ld$")) { - Ctx.emitDiag([&]() { - Ctx.Diag->Report(diag::err_header_symbol_missing) - << getAnnotatedName(&R, SymCtx, /*ValidSourceLoc=*/false); - }); + if (IsLinkerSymbol) { + Ctx.emitDiag( + [&]() { + Ctx.Diag->Report(diag::err_header_symbol_missing) + << getAnnotatedName(&R, SymCtx, Loc.isValid()); + }, + &Loc); updateState(Result::Invalid); return; } // Missing declarations for exported symbols are hard errors on Pedantic mode. if (Mode == VerificationMode::Pedantic) { - Ctx.emitDiag([&]() { - Ctx.Diag->Report(diag::err_header_symbol_missing) - << getAnnotatedName(&R, SymCtx, /*ValidSourceLoc=*/false); - }); + Ctx.emitDiag( + [&]() { + Ctx.Diag->Report(diag::err_header_symbol_missing) + << getAnnotatedName(&R, SymCtx, Loc.isValid()); + }, + &Loc); updateState(Result::Invalid); return; } @@ -580,10 +630,12 @@ void DylibVerifier::visitSymbolInDylib(const Record &R, SymbolContext &SymCtx) { // Missing declarations for exported symbols are warnings on ErrorsAndWarnings // mode. if (Mode == VerificationMode::ErrorsAndWarnings) { - Ctx.emitDiag([&]() { - Ctx.Diag->Report(diag::warn_header_symbol_missing) - << getAnnotatedName(&R, SymCtx, /*ValidSourceLoc=*/false); - }); + Ctx.emitDiag( + [&]() { + Ctx.Diag->Report(diag::warn_header_symbol_missing) + << getAnnotatedName(&R, SymCtx, Loc.isValid()); + }, + &Loc); updateState(Result::Ignore); return; } @@ -614,6 +666,18 @@ void DylibVerifier::visitObjCIVar(const ObjCIVarRecord &R, visitSymbolInDylib(R, SymCtx); } +void DylibVerifier::accumulateSrcLocForDylibSymbols() { + if (DSYMPath.empty()) + return; + + assert(DWARFCtx != nullptr && "Expected an initialized DWARFContext"); + if (DWARFCtx->ParsedDSYM) + return; + DWARFCtx->ParsedDSYM = true; + DWARFCtx->SourceLocs = + DylibReader::accumulateSourceLocFromDSYM(DSYMPath, Ctx.Target); +} + void DylibVerifier::visitObjCInterface(const ObjCInterfaceRecord &R) { if (R.isVerified()) return; @@ -647,6 +711,8 @@ DylibVerifier::Result DylibVerifier::verifyRemainingSymbols() { return Result::NoVerify; assert(!Dylib.empty() && "No binary to verify against"); + DWARFContext DWARFInfo; + DWARFCtx = &DWARFInfo; Ctx.DiscoveredFirstError = false; Ctx.PrintArch = true; for (std::shared_ptr Slice : Dylib) { @@ -657,5 +723,179 @@ DylibVerifier::Result DylibVerifier::verifyRemainingSymbols() { return getState(); } +bool DylibVerifier::verifyBinaryAttrs(const ArrayRef ProvidedTargets, + const BinaryAttrs &ProvidedBA, + const LibAttrs &ProvidedReexports, + const LibAttrs &ProvidedClients, + const LibAttrs &ProvidedRPaths, + const FileType &FT) { + assert(!Dylib.empty() && "Need dylib to verify."); + + // Pickup any load commands that can differ per slice to compare. + TargetList DylibTargets; + LibAttrs DylibReexports; + LibAttrs DylibClients; + LibAttrs DylibRPaths; + for (const std::shared_ptr &RS : Dylib) { + DylibTargets.push_back(RS->getTarget()); + const BinaryAttrs &BinInfo = RS->getBinaryAttrs(); + for (const StringRef LibName : BinInfo.RexportedLibraries) + DylibReexports[LibName].set(DylibTargets.back().Arch); + for (const StringRef LibName : BinInfo.AllowableClients) + DylibClients[LibName].set(DylibTargets.back().Arch); + // Compare attributes that are only representable in >= TBD_V5. + if (FT >= FileType::TBD_V5) + for (const StringRef Name : BinInfo.RPaths) + DylibRPaths[Name].set(DylibTargets.back().Arch); + } + + // Check targets first. + ArchitectureSet ProvidedArchs = mapToArchitectureSet(ProvidedTargets); + ArchitectureSet DylibArchs = mapToArchitectureSet(DylibTargets); + if (ProvidedArchs != DylibArchs) { + Ctx.Diag->Report(diag::err_architecture_mismatch) + << ProvidedArchs << DylibArchs; + return false; + } + auto ProvidedPlatforms = mapToPlatformVersionSet(ProvidedTargets); + auto DylibPlatforms = mapToPlatformVersionSet(DylibTargets); + if (ProvidedPlatforms != DylibPlatforms) { + const bool DiffMinOS = + mapToPlatformSet(ProvidedTargets) == mapToPlatformSet(DylibTargets); + if (DiffMinOS) + Ctx.Diag->Report(diag::warn_platform_mismatch) + << ProvidedPlatforms << DylibPlatforms; + else { + Ctx.Diag->Report(diag::err_platform_mismatch) + << ProvidedPlatforms << DylibPlatforms; + return false; + } + } + + // Because InstallAPI requires certain attributes to match across architecture + // slices, take the first one to compare those with. + const BinaryAttrs &DylibBA = (*Dylib.begin())->getBinaryAttrs(); + + if (ProvidedBA.InstallName != DylibBA.InstallName) { + Ctx.Diag->Report(diag::err_install_name_mismatch) + << ProvidedBA.InstallName << DylibBA.InstallName; + return false; + } + + if (ProvidedBA.CurrentVersion != DylibBA.CurrentVersion) { + Ctx.Diag->Report(diag::err_current_version_mismatch) + << ProvidedBA.CurrentVersion << DylibBA.CurrentVersion; + return false; + } + + if (ProvidedBA.CompatVersion != DylibBA.CompatVersion) { + Ctx.Diag->Report(diag::err_compatibility_version_mismatch) + << ProvidedBA.CompatVersion << DylibBA.CompatVersion; + return false; + } + + if (ProvidedBA.AppExtensionSafe != DylibBA.AppExtensionSafe) { + Ctx.Diag->Report(diag::err_appextension_safe_mismatch) + << (ProvidedBA.AppExtensionSafe ? "true" : "false") + << (DylibBA.AppExtensionSafe ? "true" : "false"); + return false; + } + + if (!DylibBA.TwoLevelNamespace) { + Ctx.Diag->Report(diag::err_no_twolevel_namespace); + return false; + } + + if (ProvidedBA.OSLibNotForSharedCache != DylibBA.OSLibNotForSharedCache) { + Ctx.Diag->Report(diag::err_shared_cache_eligiblity_mismatch) + << (ProvidedBA.OSLibNotForSharedCache ? "true" : "false") + << (DylibBA.OSLibNotForSharedCache ? "true" : "false"); + return false; + } + + if (ProvidedBA.ParentUmbrella.empty() && !DylibBA.ParentUmbrella.empty()) { + Ctx.Diag->Report(diag::err_parent_umbrella_missing) + << "installAPI option" << DylibBA.ParentUmbrella; + return false; + } + + if (!ProvidedBA.ParentUmbrella.empty() && DylibBA.ParentUmbrella.empty()) { + Ctx.Diag->Report(diag::err_parent_umbrella_missing) + << "binary file" << ProvidedBA.ParentUmbrella; + return false; + } + + if ((!ProvidedBA.ParentUmbrella.empty()) && + (ProvidedBA.ParentUmbrella != DylibBA.ParentUmbrella)) { + Ctx.Diag->Report(diag::err_parent_umbrella_mismatch) + << ProvidedBA.ParentUmbrella << DylibBA.ParentUmbrella; + return false; + } + + auto CompareLibraries = [&](const LibAttrs &Provided, const LibAttrs &Dylib, + unsigned DiagID_missing, unsigned DiagID_mismatch, + bool Fatal = true) { + if (Provided == Dylib) + return true; + + for (const llvm::StringMapEntry &PAttr : Provided) { + const auto DAttrIt = Dylib.find(PAttr.getKey()); + if (DAttrIt == Dylib.end()) { + Ctx.Diag->Report(DiagID_missing) << "binary file" << PAttr; + if (Fatal) + return false; + } + + if (PAttr.getValue() != DAttrIt->getValue()) { + Ctx.Diag->Report(DiagID_mismatch) << PAttr << *DAttrIt; + if (Fatal) + return false; + } + } + + for (const llvm::StringMapEntry &DAttr : Dylib) { + const auto PAttrIt = Provided.find(DAttr.getKey()); + if (PAttrIt == Provided.end()) { + Ctx.Diag->Report(DiagID_missing) << "installAPI option" << DAttr; + if (!Fatal) + continue; + return false; + } + + if (PAttrIt->getValue() != DAttr.getValue()) { + if (Fatal) + llvm_unreachable("this case was already covered above."); + } + } + return true; + }; + + if (!CompareLibraries(ProvidedReexports, DylibReexports, + diag::err_reexported_libraries_missing, + diag::err_reexported_libraries_mismatch)) + return false; + + if (!CompareLibraries(ProvidedClients, DylibClients, + diag::err_allowable_clients_missing, + diag::err_allowable_clients_mismatch)) + return false; + + if (FT >= FileType::TBD_V5) { + // Ignore rpath differences if building an asan variant, since the + // compiler injects additional paths. + // FIXME: Building with sanitizers does not always change the install + // name, so this is not a foolproof solution. + if (!ProvidedBA.InstallName.ends_with("_asan")) { + if (!CompareLibraries(ProvidedRPaths, DylibRPaths, + diag::warn_rpaths_missing, + diag::warn_rpaths_mismatch, + /*Fatal=*/false)) + return true; + } + } + + return true; +} + } // namespace installapi } // namespace clang diff --git a/clang/lib/InstallAPI/Frontend.cpp b/clang/lib/InstallAPI/Frontend.cpp index 12cd5fcbc22bf73fd40225d8c2b3457efeacf2c7..04d06f46d2652086014eb1fbcb19655fdfa3028d 100644 --- a/clang/lib/InstallAPI/Frontend.cpp +++ b/clang/lib/InstallAPI/Frontend.cpp @@ -23,7 +23,8 @@ std::pair FrontendRecordsSlice::addGlobal( GlobalRecord *GR = llvm::MachO::RecordsSlice::addGlobal(Name, Linkage, GV, Flags, Inlined); - auto Result = FrontendRecords.insert({GR, FrontendAttrs{Avail, D, Access}}); + auto Result = FrontendRecords.insert( + {GR, FrontendAttrs{Avail, D, D->getLocation(), Access}}); return {GR, &(Result.first->second)}; } @@ -39,8 +40,8 @@ FrontendRecordsSlice::addObjCInterface(StringRef Name, RecordLinkage Linkage, ObjCInterfaceRecord *ObjCR = llvm::MachO::RecordsSlice::addObjCInterface(Name, Linkage, SymType); - auto Result = - FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}}); + auto Result = FrontendRecords.insert( + {ObjCR, FrontendAttrs{Avail, D, D->getLocation(), Access}}); return {ObjCR, &(Result.first->second)}; } @@ -51,8 +52,8 @@ FrontendRecordsSlice::addObjCCategory(StringRef ClassToExtend, const Decl *D, HeaderType Access) { ObjCCategoryRecord *ObjCR = llvm::MachO::RecordsSlice::addObjCCategory(ClassToExtend, CategoryName); - auto Result = - FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}}); + auto Result = FrontendRecords.insert( + {ObjCR, FrontendAttrs{Avail, D, D->getLocation(), Access}}); return {ObjCR, &(Result.first->second)}; } @@ -67,8 +68,8 @@ std::pair FrontendRecordsSlice::addObjCIVar( Linkage = RecordLinkage::Internal; ObjCIVarRecord *ObjCR = llvm::MachO::RecordsSlice::addObjCIVar(Container, IvarName, Linkage); - auto Result = - FrontendRecords.insert({ObjCR, FrontendAttrs{Avail, D, Access}}); + auto Result = FrontendRecords.insert( + {ObjCR, FrontendAttrs{Avail, D, D->getLocation(), Access}}); return {ObjCR, &(Result.first->second)}; } @@ -138,6 +139,8 @@ std::unique_ptr createInputBuffer(InstallAPIContext &Ctx) { SmallString<4096> Contents; raw_svector_ostream OS(Contents); for (const HeaderFile &H : Ctx.InputHeaders) { + if (H.isExcluded()) + continue; if (H.getType() != Ctx.Type) continue; if (Ctx.LangMode == Language::C || Ctx.LangMode == Language::CXX) @@ -160,4 +163,58 @@ std::unique_ptr createInputBuffer(InstallAPIContext &Ctx) { return llvm::MemoryBuffer::getMemBufferCopy(Contents, BufferName); } +std::string findLibrary(StringRef InstallName, FileManager &FM, + ArrayRef FrameworkSearchPaths, + ArrayRef LibrarySearchPaths, + ArrayRef SearchPaths) { + auto getLibrary = + [&](const StringRef FullPath) -> std::optional { + // Prefer TextAPI files when possible. + SmallString TextAPIFilePath = FullPath; + replace_extension(TextAPIFilePath, ".tbd"); + + if (FM.getOptionalFileRef(TextAPIFilePath)) + return std::string(TextAPIFilePath); + + if (FM.getOptionalFileRef(FullPath)) + return std::string(FullPath); + + return std::nullopt; + }; + + const StringRef Filename = sys::path::filename(InstallName); + const bool IsFramework = sys::path::parent_path(InstallName) + .ends_with((Filename + ".framework").str()); + if (IsFramework) { + for (const StringRef Path : FrameworkSearchPaths) { + SmallString FullPath(Path); + sys::path::append(FullPath, Filename + StringRef(".framework"), Filename); + if (auto LibOrNull = getLibrary(FullPath)) + return *LibOrNull; + } + } else { + // Copy Apple's linker behavior: If this is a .dylib inside a framework, do + // not search -L paths. + bool IsEmbeddedDylib = (sys::path::extension(InstallName) == ".dylib") && + InstallName.contains(".framework/"); + if (!IsEmbeddedDylib) { + for (const StringRef Path : LibrarySearchPaths) { + SmallString FullPath(Path); + sys::path::append(FullPath, Filename); + if (auto LibOrNull = getLibrary(FullPath)) + return *LibOrNull; + } + } + } + + for (const StringRef Path : SearchPaths) { + SmallString FullPath(Path); + sys::path::append(FullPath, InstallName); + if (auto LibOrNull = getLibrary(FullPath)) + return *LibOrNull; + } + + return {}; +} + } // namespace clang::installapi diff --git a/clang/lib/InstallAPI/HeaderFile.cpp b/clang/lib/InstallAPI/HeaderFile.cpp index c2d8372741ee07e801dff5d4c3edd5f4963e88f8..0b7041ec8147eb95fc96ad6899d065aa5b6dd185 100644 --- a/clang/lib/InstallAPI/HeaderFile.cpp +++ b/clang/lib/InstallAPI/HeaderFile.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/InstallAPI/HeaderFile.h" +#include "llvm/TextAPI/Utils.h" using namespace llvm; namespace clang::installapi { @@ -34,4 +35,54 @@ std::optional createIncludeHeaderName(const StringRef FullPath) { return Matches[1].drop_front(Matches[1].rfind('/') + 1).str() + "/" + Matches[3].str(); } + +bool isHeaderFile(StringRef Path) { + return StringSwitch(sys::path::extension(Path)) + .Cases(".h", ".H", ".hh", ".hpp", ".hxx", true) + .Default(false); +} + +llvm::Expected enumerateFiles(FileManager &FM, StringRef Directory) { + PathSeq Files; + std::error_code EC; + auto &FS = FM.getVirtualFileSystem(); + for (llvm::vfs::recursive_directory_iterator i(FS, Directory, EC), ie; + i != ie; i.increment(EC)) { + if (EC) + return errorCodeToError(EC); + + // Skip files that do not exist. This usually happens for broken symlinks. + if (FS.status(i->path()) == std::errc::no_such_file_or_directory) + continue; + + StringRef Path = i->path(); + if (isHeaderFile(Path)) + Files.emplace_back(Path); + } + + return Files; +} + +HeaderGlob::HeaderGlob(StringRef GlobString, Regex &&Rule, HeaderType Type) + : GlobString(GlobString), Rule(std::move(Rule)), Type(Type) {} + +bool HeaderGlob::match(const HeaderFile &Header) { + if (Header.getType() != Type) + return false; + + bool Match = Rule.match(Header.getPath()); + if (Match) + FoundMatch = true; + return Match; +} + +Expected> HeaderGlob::create(StringRef GlobString, + HeaderType Type) { + auto Rule = MachO::createRegexFromGlob(GlobString); + if (!Rule) + return Rule.takeError(); + + return std::make_unique(GlobString, std::move(*Rule), Type); +} + } // namespace clang::installapi diff --git a/clang/lib/InstallAPI/Visitor.cpp b/clang/lib/InstallAPI/Visitor.cpp index 452c8f2fb1e489b76666b1657ceb213834524612..cf3aaa4c6ec93115834bd65e993b35852a0c49e7 100644 --- a/clang/lib/InstallAPI/Visitor.cpp +++ b/clang/lib/InstallAPI/Visitor.cpp @@ -205,9 +205,10 @@ bool InstallAPIVisitor::VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { const ObjCInterfaceDecl *InterfaceD = D->getClassInterface(); const StringRef InterfaceName = InterfaceD->getName(); - auto [Category, FA] = Ctx.Slice->addObjCCategory(InterfaceName, CategoryName, - Avail, D, *Access); - recordObjCInstanceVariables(D->getASTContext(), Category, InterfaceName, + ObjCCategoryRecord *CategoryRecord = + Ctx.Slice->addObjCCategory(InterfaceName, CategoryName, Avail, D, *Access) + .first; + recordObjCInstanceVariables(D->getASTContext(), CategoryRecord, InterfaceName, D->ivars()); return true; } @@ -254,7 +255,7 @@ bool InstallAPIVisitor::VisitFunctionDecl(const FunctionDecl *D) { return true; // Skip methods in CXX RecordDecls. - for (auto P : D->getASTContext().getParents(*M)) { + for (const DynTypedNode &P : D->getASTContext().getParents(*M)) { if (P.get()) return true; } diff --git a/clang/lib/Interpreter/IncrementalExecutor.cpp b/clang/lib/Interpreter/IncrementalExecutor.cpp index 40bcef94797d43d7b847a51691d6c06fbbc2bd90..6f036107c14a9c51143323ad7f59766aaac1fbd8 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.cpp +++ b/clang/lib/Interpreter/IncrementalExecutor.cpp @@ -20,6 +20,7 @@ #include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h" #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" +#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/LLJIT.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h" @@ -36,26 +37,28 @@ LLVM_ATTRIBUTE_USED void linkComponents() { namespace clang { +llvm::Expected> +IncrementalExecutor::createDefaultJITBuilder( + llvm::orc::JITTargetMachineBuilder JTMB) { + auto JITBuilder = std::make_unique(); + JITBuilder->setJITTargetMachineBuilder(std::move(JTMB)); + JITBuilder->setPrePlatformSetup([](llvm::orc::LLJIT &J) { + // Try to enable debugging of JIT'd code (only works with JITLink for + // ELF and MachO). + consumeError(llvm::orc::enableDebuggerSupport(J)); + return llvm::Error::success(); + }); + return std::move(JITBuilder); +} + IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, - llvm::Error &Err, - const clang::TargetInfo &TI) + llvm::orc::LLJITBuilder &JITBuilder, + llvm::Error &Err) : TSCtx(TSC) { using namespace llvm::orc; llvm::ErrorAsOutParameter EAO(&Err); - auto JTMB = JITTargetMachineBuilder(TI.getTriple()); - JTMB.addFeatures(TI.getTargetOpts().Features); - LLJITBuilder Builder; - Builder.setJITTargetMachineBuilder(JTMB); - Builder.setPrePlatformSetup( - [](LLJIT &J) { - // Try to enable debugging of JIT'd code (only works with JITLink for - // ELF and MachO). - consumeError(enableDebuggerSupport(J)); - return llvm::Error::success(); - }); - - if (auto JitOrErr = Builder.create()) + if (auto JitOrErr = JITBuilder.create()) Jit = std::move(*JitOrErr); else { Err = JitOrErr.takeError(); diff --git a/clang/lib/Interpreter/IncrementalExecutor.h b/clang/lib/Interpreter/IncrementalExecutor.h index dd0a210a0614154f3d81db726de059375533d6d6..b4347209e14fe33b782bcdf036b2ead590726a1b 100644 --- a/clang/lib/Interpreter/IncrementalExecutor.h +++ b/clang/lib/Interpreter/IncrementalExecutor.h @@ -23,7 +23,9 @@ namespace llvm { class Error; namespace orc { +class JITTargetMachineBuilder; class LLJIT; +class LLJITBuilder; class ThreadSafeContext; } // namespace orc } // namespace llvm @@ -44,8 +46,8 @@ class IncrementalExecutor { public: enum SymbolNameKind { IRName, LinkerName }; - IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, llvm::Error &Err, - const clang::TargetInfo &TI); + IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC, + llvm::orc::LLJITBuilder &JITBuilder, llvm::Error &Err); ~IncrementalExecutor(); llvm::Error addModule(PartialTranslationUnit &PTU); @@ -56,6 +58,9 @@ public: getSymbolAddress(llvm::StringRef Name, SymbolNameKind NameKind) const; llvm::orc::LLJIT &GetExecutionEngine() { return *Jit; } + + static llvm::Expected> + createDefaultJITBuilder(llvm::orc::JITTargetMachineBuilder JTMB); }; } // end namespace clang diff --git a/clang/lib/Interpreter/IncrementalParser.cpp b/clang/lib/Interpreter/IncrementalParser.cpp index 370bcbfee8b014c1dea231949bc899c407b1bcdb..5eec2a2fd6d1a69c76a3464997394b681cb133a6 100644 --- a/clang/lib/Interpreter/IncrementalParser.cpp +++ b/clang/lib/Interpreter/IncrementalParser.cpp @@ -375,16 +375,22 @@ void IncrementalParser::CleanUpPTU(PartialTranslationUnit &PTU) { TranslationUnitDecl *MostRecentTU = PTU.TUPart; TranslationUnitDecl *FirstTU = MostRecentTU->getFirstDecl(); if (StoredDeclsMap *Map = FirstTU->getPrimaryContext()->getLookupPtr()) { - for (auto I = Map->begin(); I != Map->end(); ++I) { - StoredDeclsList &List = I->second; + for (auto &&[Key, List] : *Map) { DeclContextLookupResult R = List.getLookupResult(); + std::vector NamedDeclsToRemove; + bool RemoveAll = true; for (NamedDecl *D : R) { - if (D->getTranslationUnitDecl() == MostRecentTU) { + if (D->getTranslationUnitDecl() == MostRecentTU) + NamedDeclsToRemove.push_back(D); + else + RemoveAll = false; + } + if (LLVM_LIKELY(RemoveAll)) { + Map->erase(Key); + } else { + for (NamedDecl *D : NamedDeclsToRemove) List.remove(D); - } } - if (List.isNull()) - Map->erase(I); } } } diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp index 7fa52f2f15fc4951da35e5700deb54ecc4e6b64d..cf31456b6950ac51de7c220c65d7f374c63ea781 100644 --- a/clang/lib/Interpreter/Interpreter.cpp +++ b/clang/lib/Interpreter/Interpreter.cpp @@ -372,15 +372,35 @@ Interpreter::Parse(llvm::StringRef Code) { return IncrParser->Parse(Code); } +static llvm::Expected +createJITTargetMachineBuilder(const std::string &TT) { + if (TT == llvm::sys::getProcessTriple()) + // This fails immediately if the target backend is not registered + return llvm::orc::JITTargetMachineBuilder::detectHost(); + + // If the target backend is not registered, LLJITBuilder::create() will fail + return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT)); +} + +llvm::Expected> +Interpreter::CreateJITBuilder(CompilerInstance &CI) { + auto JTMB = createJITTargetMachineBuilder(CI.getTargetOpts().Triple); + if (!JTMB) + return JTMB.takeError(); + return IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB)); +} + llvm::Error Interpreter::CreateExecutor() { - const clang::TargetInfo &TI = - getCompilerInstance()->getASTContext().getTargetInfo(); if (IncrExecutor) return llvm::make_error("Operation failed. " "Execution engine exists", std::error_code()); + llvm::Expected> JB = + CreateJITBuilder(*getCompilerInstance()); + if (!JB) + return JB.takeError(); llvm::Error Err = llvm::Error::success(); - auto Executor = std::make_unique(*TSCtx, Err, TI); + auto Executor = std::make_unique(*TSCtx, **JB, Err); if (!Err) IncrExecutor = std::move(Executor); diff --git a/clang/lib/Interpreter/Value.cpp b/clang/lib/Interpreter/Value.cpp index 1d6b2da087e9fbe40d85111bddc3159199ebd94d..eb2ce9c9fd330200bf10453fff74fb8789fe7b42 100644 --- a/clang/lib/Interpreter/Value.cpp +++ b/clang/lib/Interpreter/Value.cpp @@ -1,4 +1,4 @@ -//===--- Interpreter.h - Incremental Compiation and Execution---*- C++ -*-===// +//===------------ Value.cpp - Definition of interpreter value -------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -22,8 +22,6 @@ #include #include -using namespace clang; - namespace { // This is internal buffer maintained by Value, used to hold temporaries. @@ -61,7 +59,7 @@ public: void Release() { assert(RefCnt > 0 && "Can't release if reference count is already zero"); if (--RefCnt == 0) { - // We hace a non-trivial dtor. + // We have a non-trivial dtor. if (Dtor && IsAlive()) { assert(Elements && "We at least should have 1 element in Value"); size_t Stride = AllocSize / Elements; @@ -97,6 +95,8 @@ private: }; } // namespace +namespace clang { + static Value::Kind ConvertQualTypeToKind(const ASTContext &Ctx, QualType QT) { if (Ctx.hasSameType(QT, Ctx.VoidTy)) return Value::K_Void; @@ -265,3 +265,5 @@ void Value::print(llvm::raw_ostream &Out) const { assert(OpaqueType != nullptr && "Can't print default Value"); Out << "Not implement yet.\n"; } + +} // namespace clang diff --git a/clang/lib/Lex/HeaderSearch.cpp b/clang/lib/Lex/HeaderSearch.cpp index fcc2b56df166b8a0d5f214d4459954bdad23dcd5..f0750e5336b6a507c7ab42b6c797daedfa8f03bc 100644 --- a/clang/lib/Lex/HeaderSearch.cpp +++ b/clang/lib/Lex/HeaderSearch.cpp @@ -64,8 +64,7 @@ HeaderFileInfo::getControllingMacro(ExternalPreprocessorSource *External) { if (ControllingMacro->isOutOfDate()) { assert(External && "We must have an external source if we have a " "controlling macro that is out of date."); - External->updateOutOfDateIdentifier( - *const_cast(ControllingMacro)); + External->updateOutOfDateIdentifier(*ControllingMacro); } return ControllingMacro; } @@ -1307,6 +1306,23 @@ OptionalFileEntryRef HeaderSearch::LookupSubframeworkHeader( // File Info Management. //===----------------------------------------------------------------------===// +static void mergeHeaderFileInfoModuleBits(HeaderFileInfo &HFI, + bool isModuleHeader, + bool isTextualModuleHeader) { + assert((!isModuleHeader || !isTextualModuleHeader) && + "A header can't build with a module and be textual at the same time"); + HFI.isModuleHeader |= isModuleHeader; + if (HFI.isModuleHeader) + HFI.isTextualModuleHeader = false; + else + HFI.isTextualModuleHeader |= isTextualModuleHeader; +} + +void HeaderFileInfo::mergeModuleMembership(ModuleMap::ModuleHeaderRole Role) { + mergeHeaderFileInfoModuleBits(*this, ModuleMap::isModular(Role), + (Role & ModuleMap::TextualHeader)); +} + /// Merge the header file info provided by \p OtherHFI into the current /// header file info (\p HFI) static void mergeHeaderFileInfo(HeaderFileInfo &HFI, @@ -1315,7 +1331,8 @@ static void mergeHeaderFileInfo(HeaderFileInfo &HFI, HFI.isImport |= OtherHFI.isImport; HFI.isPragmaOnce |= OtherHFI.isPragmaOnce; - HFI.isModuleHeader |= OtherHFI.isModuleHeader; + mergeHeaderFileInfoModuleBits(HFI, OtherHFI.isModuleHeader, + OtherHFI.isTextualModuleHeader); if (!HFI.ControllingMacro && !HFI.ControllingMacroID) { HFI.ControllingMacro = OtherHFI.ControllingMacro; @@ -1403,11 +1420,9 @@ bool HeaderSearch::isFileMultipleIncludeGuarded(FileEntryRef File) const { void HeaderSearch::MarkFileModuleHeader(FileEntryRef FE, ModuleMap::ModuleHeaderRole Role, bool isCompilingModuleHeader) { - bool isModularHeader = ModuleMap::isModular(Role); - // Don't mark the file info as non-external if there's nothing to change. if (!isCompilingModuleHeader) { - if (!isModularHeader) + if ((Role & ModuleMap::ExcludedHeader)) return; auto *HFI = getExistingFileInfo(FE); if (HFI && HFI->isModuleHeader) @@ -1415,7 +1430,7 @@ void HeaderSearch::MarkFileModuleHeader(FileEntryRef FE, } auto &HFI = getFileInfo(FE); - HFI.isModuleHeader |= isModularHeader; + HFI.mergeModuleMembership(Role); HFI.isCompilingModuleHeader |= isCompilingModuleHeader; } @@ -1423,74 +1438,128 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP, FileEntryRef File, bool isImport, bool ModulesEnabled, Module *M, bool &IsFirstIncludeOfFile) { - ++NumIncluded; // Count # of attempted #includes. - + // An include file should be entered if either: + // 1. This is the first include of the file. + // 2. This file can be included multiple times, that is it's not an + // "include-once" file. + // + // Include-once is controlled by these preprocessor directives. + // + // #pragma once + // This directive is in the include file, and marks it as an include-once + // file. + // + // #import + // This directive is in the includer, and indicates that the include file + // should only be entered if this is the first include. + ++NumIncluded; IsFirstIncludeOfFile = false; - - // Get information about this file. HeaderFileInfo &FileInfo = getFileInfo(File); - // FIXME: this is a workaround for the lack of proper modules-aware support - // for #import / #pragma once - auto TryEnterImported = [&]() -> bool { - if (!ModulesEnabled) + auto MaybeReenterImportedFile = [&]() -> bool { + // Modules add a wrinkle though: what's included isn't necessarily visible. + // Consider this module. + // module Example { + // module A { header "a.h" export * } + // module B { header "b.h" export * } + // } + // b.h includes c.h. The main file includes a.h, which will trigger a module + // build of Example, and c.h will be included. However, c.h isn't visible to + // the main file. Normally this is fine, the main file can just include c.h + // if it needs it. If c.h is in a module, the include will translate into a + // module import, this function will be skipped, and everything will work as + // expected. However, if c.h is not in a module (or is `textual`), then this + // function will run. If c.h is include-once, it will not be entered from + // the main file and it will still not be visible. + + // If modules aren't enabled then there's no visibility issue. Always + // respect `#pragma once`. + if (!ModulesEnabled || FileInfo.isPragmaOnce) return false; + // Ensure FileInfo bits are up to date. ModMap.resolveHeaderDirectives(File); - // Modules with builtins are special; multiple modules use builtins as - // modular headers, example: - // - // module stddef { header "stddef.h" export * } - // - // After module map parsing, this expands to: - // - // module stddef { - // header "/path_to_builtin_dirs/stddef.h" - // textual "stddef.h" - // } + + // This brings up a subtlety of #import - it's not a very good indicator of + // include-once. Developers are often unaware of the difference between + // #include and #import, and tend to use one or the other indiscrimiately. + // In order to support #include on include-once headers that lack macro + // guards and `#pragma once` (which is the vast majority of Objective-C + // headers), if a file is ever included with #import, it's marked as + // isImport in the HeaderFileInfo and treated as include-once. This allows + // #include to work in Objective-C. + // #include + // #include + // Foundation.h has an #import of NSString.h, and so the second #include is + // skipped even though NSString.h has no `#pragma once` and no macro guard. // - // It's common that libc++ and system modules will both define such - // submodules. Make sure cached results for a builtin header won't - // prevent other builtin modules from potentially entering the builtin - // header. Note that builtins are header guarded and the decision to - // actually enter them is postponed to the controlling macros logic below. - bool TryEnterHdr = false; - if (FileInfo.isCompilingModuleHeader && FileInfo.isModuleHeader) - TryEnterHdr = ModMap.isBuiltinHeader(File); - - // Textual headers can be #imported from different modules. Since ObjC - // headers find in the wild might rely only on #import and do not contain - // controlling macros, be conservative and only try to enter textual headers - // if such macro is present. - if (!FileInfo.isModuleHeader && - FileInfo.getControllingMacro(ExternalLookup)) - TryEnterHdr = true; - return TryEnterHdr; + // However, this helpfulness causes problems with modules. If c.h is not an + // include-once file, but something included it with #import anyway (as is + // typical in Objective-C code), this include will be skipped and c.h will + // not be visible. Consider it not include-once if it is a `textual` header + // in a module. + if (FileInfo.isTextualModuleHeader) + return true; + + if (FileInfo.isCompilingModuleHeader) { + // It's safer to re-enter a file whose module is being built because its + // declarations will still be scoped to a single module. + if (FileInfo.isModuleHeader) { + // Headers marked as "builtin" are covered by the system module maps + // rather than the builtin ones. Some versions of the Darwin module fail + // to mark stdarg.h and stddef.h as textual. Attempt to re-enter these + // files while building their module to allow them to function properly. + if (ModMap.isBuiltinHeader(File)) + return true; + } else { + // Files that are excluded from their module can potentially be + // re-entered from their own module. This might cause redeclaration + // errors if another module saw this file first, but there's a + // reasonable chance that its module will build first. However if + // there's no controlling macro, then trust the #import and assume this + // really is an include-once file. + if (FileInfo.getControllingMacro(ExternalLookup)) + return true; + } + } + // If the include file has a macro guard, then it might still not be + // re-entered if the controlling macro is visibly defined. e.g. another + // header in the module being built included this file and local submodule + // visibility is not enabled. + + // It might be tempting to re-enter the include-once file if it's not + // visible in an attempt to make it visible. However this will still cause + // redeclaration errors against the known-but-not-visible declarations. The + // include file not being visible will most likely cause "undefined x" + // errors, but at least there's a slim chance of compilation succeeding. + return false; }; - // If this is a #import directive, check that we have not already imported - // this header. if (isImport) { - // If this has already been imported, don't import it again. + // As discussed above, record that this file was ever `#import`ed, and treat + // it as an include-once file from here out. FileInfo.isImport = true; - - // Has this already been #import'ed or #include'd? - if (PP.alreadyIncluded(File) && !TryEnterImported()) + if (PP.alreadyIncluded(File) && !MaybeReenterImportedFile()) return false; } else { - // Otherwise, if this is a #include of a file that was previously #import'd - // or if this is the second #include of a #pragma once file, ignore it. - if ((FileInfo.isPragmaOnce || FileInfo.isImport) && !TryEnterImported()) + // isPragmaOnce and isImport are only set after the file has been included + // at least once. If either are set then this is a repeat #include of an + // include-once file. + if (FileInfo.isPragmaOnce || + (FileInfo.isImport && !MaybeReenterImportedFile())) return false; } - // Next, check to see if the file is wrapped with #ifndef guards. If so, and - // if the macro that guards it is defined, we know the #include has no effect. - if (const IdentifierInfo *ControllingMacro - = FileInfo.getControllingMacro(ExternalLookup)) { + // As a final optimization, check for a macro guard and skip entering the file + // if the controlling macro is defined. The macro guard will effectively erase + // the file's contents, and the include would have no effect other than to + // waste time opening and reading a file. + if (const IdentifierInfo *ControllingMacro = + FileInfo.getControllingMacro(ExternalLookup)) { // If the header corresponds to a module, check whether the macro is already - // defined in that module rather than checking in the current set of visible - // modules. + // defined in that module rather than checking all visible modules. This is + // mainly to cover corner cases where the same controlling macro is used in + // different files in multiple modules. if (M ? PP.isMacroDefinedInLocalModule(ControllingMacro, M) : PP.isMacroDefined(ControllingMacro)) { ++NumMultiIncludeFileOptzn; @@ -1499,7 +1568,6 @@ bool HeaderSearch::ShouldEnterIncludeFile(Preprocessor &PP, } IsFirstIncludeOfFile = PP.markIncluded(File); - return true; } diff --git a/clang/lib/Lex/MacroInfo.cpp b/clang/lib/Lex/MacroInfo.cpp index 39bb0f44eff25ba1e502c9b9b0b05c5a6f7cfcb7..dfdf463665f3c137aa6e1ec1c931f009620dc005 100644 --- a/clang/lib/Lex/MacroInfo.cpp +++ b/clang/lib/Lex/MacroInfo.cpp @@ -257,7 +257,7 @@ LLVM_DUMP_METHOD void MacroDirective::dump() const { } ModuleMacro *ModuleMacro::create(Preprocessor &PP, Module *OwningModule, - IdentifierInfo *II, MacroInfo *Macro, + const IdentifierInfo *II, MacroInfo *Macro, ArrayRef Overrides) { void *Mem = PP.getPreprocessorAllocator().Allocate( sizeof(ModuleMacro) + sizeof(ModuleMacro *) * Overrides.size(), diff --git a/clang/lib/Lex/ModuleMap.cpp b/clang/lib/Lex/ModuleMap.cpp index 10c475f617d48549b2b0943bf8b2851c59a70a4c..eed7eca2e73562da5d819410fcde0535b410668d 100644 --- a/clang/lib/Lex/ModuleMap.cpp +++ b/clang/lib/Lex/ModuleMap.cpp @@ -648,8 +648,7 @@ ModuleMap::findOrCreateModuleForHeaderInUmbrellaDir(FileEntryRef File) { UmbrellaModule = UmbrellaModule->Parent; if (UmbrellaModule->InferSubmodules) { - OptionalFileEntryRef UmbrellaModuleMap = - getModuleMapFileForUniquing(UmbrellaModule); + FileID UmbrellaModuleMap = getModuleMapFileIDForUniquing(UmbrellaModule); // Infer submodules for each of the directories we found between // the directory of the umbrella header and the directory where @@ -1021,7 +1020,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, // If the framework has a parent path from which we're allowed to infer // a framework module, do so. - OptionalFileEntryRef ModuleMapFile; + FileID ModuleMapFID; if (!Parent) { // Determine whether we're allowed to infer a module map. bool canInfer = false; @@ -1060,7 +1059,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, Attrs.IsExhaustive |= inferred->second.Attrs.IsExhaustive; Attrs.NoUndeclaredIncludes |= inferred->second.Attrs.NoUndeclaredIncludes; - ModuleMapFile = inferred->second.ModuleMapFile; + ModuleMapFID = inferred->second.ModuleMapFID; } } } @@ -1069,7 +1068,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, if (!canInfer) return nullptr; } else { - ModuleMapFile = getModuleMapFileForUniquing(Parent); + ModuleMapFID = getModuleMapFileIDForUniquing(Parent); } // Look for an umbrella header. @@ -1086,7 +1085,7 @@ Module *ModuleMap::inferFrameworkModule(DirectoryEntryRef FrameworkDir, Module *Result = new Module(ModuleName, SourceLocation(), Parent, /*IsFramework=*/true, /*IsExplicit=*/false, NumCreatedModules++); - InferredModuleAllowedBy[Result] = ModuleMapFile; + InferredModuleAllowedBy[Result] = ModuleMapFID; Result->IsInferred = true; if (!Parent) { if (LangOpts.CurrentModule == ModuleName) @@ -1307,28 +1306,34 @@ void ModuleMap::addHeader(Module *Mod, Module::Header Header, Cb->moduleMapAddHeader(Header.Entry.getName()); } -OptionalFileEntryRef -ModuleMap::getContainingModuleMapFile(const Module *Module) const { +FileID ModuleMap::getContainingModuleMapFileID(const Module *Module) const { if (Module->DefinitionLoc.isInvalid()) - return std::nullopt; + return {}; - return SourceMgr.getFileEntryRefForID( - SourceMgr.getFileID(Module->DefinitionLoc)); + return SourceMgr.getFileID(Module->DefinitionLoc); } OptionalFileEntryRef -ModuleMap::getModuleMapFileForUniquing(const Module *M) const { +ModuleMap::getContainingModuleMapFile(const Module *Module) const { + return SourceMgr.getFileEntryRefForID(getContainingModuleMapFileID(Module)); +} + +FileID ModuleMap::getModuleMapFileIDForUniquing(const Module *M) const { if (M->IsInferred) { assert(InferredModuleAllowedBy.count(M) && "missing inferred module map"); return InferredModuleAllowedBy.find(M)->second; } - return getContainingModuleMapFile(M); + return getContainingModuleMapFileID(M); +} + +OptionalFileEntryRef +ModuleMap::getModuleMapFileForUniquing(const Module *M) const { + return SourceMgr.getFileEntryRefForID(getModuleMapFileIDForUniquing(M)); } -void ModuleMap::setInferredModuleAllowedBy(Module *M, - OptionalFileEntryRef ModMap) { +void ModuleMap::setInferredModuleAllowedBy(Module *M, FileID ModMapFID) { assert(M->IsInferred && "module not inferred"); - InferredModuleAllowedBy[M] = ModMap; + InferredModuleAllowedBy[M] = ModMapFID; } std::error_code @@ -1517,7 +1522,7 @@ namespace clang { ModuleMap ⤅ /// The current module map file. - FileEntryRef ModuleMapFile; + FileID ModuleMapFID; /// Source location of most recent parsed module declaration SourceLocation CurrModuleDeclLoc; @@ -1585,13 +1590,12 @@ namespace clang { bool parseOptionalAttributes(Attributes &Attrs); public: - explicit ModuleMapParser(Lexer &L, SourceManager &SourceMgr, - const TargetInfo *Target, DiagnosticsEngine &Diags, - ModuleMap &Map, FileEntryRef ModuleMapFile, - DirectoryEntryRef Directory, bool IsSystem) + ModuleMapParser(Lexer &L, SourceManager &SourceMgr, + const TargetInfo *Target, DiagnosticsEngine &Diags, + ModuleMap &Map, FileID ModuleMapFID, + DirectoryEntryRef Directory, bool IsSystem) : L(L), SourceMgr(SourceMgr), Target(Target), Diags(Diags), Map(Map), - ModuleMapFile(ModuleMapFile), Directory(Directory), - IsSystem(IsSystem) { + ModuleMapFID(ModuleMapFID), Directory(Directory), IsSystem(IsSystem) { Tok.clear(); consumeToken(); } @@ -2011,11 +2015,13 @@ void ModuleMapParser::parseModuleDecl() { } if (TopLevelModule && - ModuleMapFile != Map.getContainingModuleMapFile(TopLevelModule)) { - assert(ModuleMapFile != Map.getModuleMapFileForUniquing(TopLevelModule) && + ModuleMapFID != Map.getContainingModuleMapFileID(TopLevelModule)) { + assert(ModuleMapFID != + Map.getModuleMapFileIDForUniquing(TopLevelModule) && "submodule defined in same file as 'module *' that allowed its " "top-level module"); - Map.addAdditionalModuleMapFile(TopLevelModule, ModuleMapFile); + Map.addAdditionalModuleMapFile( + TopLevelModule, *SourceMgr.getFileEntryRefForID(ModuleMapFID)); } } @@ -2120,7 +2126,8 @@ void ModuleMapParser::parseModuleDecl() { ActiveModule->NoUndeclaredIncludes = true; ActiveModule->Directory = Directory; - StringRef MapFileName(ModuleMapFile.getName()); + StringRef MapFileName( + SourceMgr.getFileEntryRefForID(ModuleMapFID)->getName()); if (MapFileName.ends_with("module.private.modulemap") || MapFileName.ends_with("module_private.map")) { ActiveModule->ModuleMapIsPrivate = true; @@ -2906,7 +2913,7 @@ void ModuleMapParser::parseInferredModuleDecl(bool Framework, bool Explicit) { // We'll be inferring framework modules for this directory. Map.InferredDirectories[Directory].InferModules = true; Map.InferredDirectories[Directory].Attrs = Attrs; - Map.InferredDirectories[Directory].ModuleMapFile = ModuleMapFile; + Map.InferredDirectories[Directory].ModuleMapFID = ModuleMapFID; // FIXME: Handle the 'framework' keyword. } @@ -3139,8 +3146,7 @@ bool ModuleMap::parseModuleMapFile(FileEntryRef File, bool IsSystem, Buffer->getBufferStart() + (Offset ? *Offset : 0), Buffer->getBufferEnd()); SourceLocation Start = L.getSourceLocation(); - ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, File, Dir, - IsSystem); + ModuleMapParser Parser(L, SourceMgr, Target, Diags, *this, ID, Dir, IsSystem); bool Result = Parser.parseModuleMapFile(); ParsedModuleMap[File] = Result; diff --git a/clang/lib/Lex/PPLexerChange.cpp b/clang/lib/Lex/PPLexerChange.cpp index 3b1b6df1dbae4e6a8b6d09af637dadda150d3f05..2ca2122ac71099bf3e9903353878ccff48a6214b 100644 --- a/clang/lib/Lex/PPLexerChange.cpp +++ b/clang/lib/Lex/PPLexerChange.cpp @@ -368,8 +368,7 @@ bool Preprocessor::HandleEndOfFile(Token &Result, bool isEndOfMacro) { // Okay, this has a controlling macro, remember in HeaderFileInfo. if (OptionalFileEntryRef FE = CurPPLexer->getFileEntry()) { HeaderInfo.SetFileControllingMacro(*FE, ControllingMacro); - if (MacroInfo *MI = - getMacroInfo(const_cast(ControllingMacro))) + if (MacroInfo *MI = getMacroInfo(ControllingMacro)) MI->setUsedForHeaderGuard(true); if (const IdentifierInfo *DefinedMacro = CurPPLexer->MIOpt.GetDefinedMacro()) { @@ -805,7 +804,7 @@ Module *Preprocessor::LeaveSubmodule(bool ForPragma) { llvm::SmallPtrSet VisitedMacros; for (unsigned I = Info.OuterPendingModuleMacroNames; I != PendingModuleMacroNames.size(); ++I) { - auto *II = const_cast(PendingModuleMacroNames[I]); + const auto *II = PendingModuleMacroNames[I]; if (!VisitedMacros.insert(II).second) continue; @@ -855,8 +854,8 @@ Module *Preprocessor::LeaveSubmodule(bool ForPragma) { // Don't bother creating a module macro if it would represent a #undef // that doesn't override anything. if (Def || !Macro.getOverriddenMacros().empty()) - addModuleMacro(LeavingMod, II, Def, - Macro.getOverriddenMacros(), IsNew); + addModuleMacro(LeavingMod, II, Def, Macro.getOverriddenMacros(), + IsNew); if (!getLangOpts().ModulesLocalVisibility) { // This macro is exposed to the rest of this compilation as a diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index 516269c0c6013e965e657713ef53ee2ce5dc2eff..a5f22f01682d252c1ff05de0acde3c3962b244c4 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -129,7 +129,7 @@ void Preprocessor::setLoadedMacroDirective(IdentifierInfo *II, II->setHasMacroDefinition(false); } -ModuleMacro *Preprocessor::addModuleMacro(Module *Mod, IdentifierInfo *II, +ModuleMacro *Preprocessor::addModuleMacro(Module *Mod, const IdentifierInfo *II, MacroInfo *Macro, ArrayRef Overrides, bool &New) { @@ -162,7 +162,7 @@ ModuleMacro *Preprocessor::addModuleMacro(Module *Mod, IdentifierInfo *II, // The new macro is always a leaf macro. LeafMacros.push_back(MM); // The identifier now has defined macros (that may or may not be visible). - II->setHasMacroDefinition(true); + const_cast(II)->setHasMacroDefinition(true); New = true; return MM; diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp index 031ed1e16bb8fce58682d32adf08410d2d6dbf8b..0b70192743a399e396f4b0b2854fae42168dbbe3 100644 --- a/clang/lib/Lex/Preprocessor.cpp +++ b/clang/lib/Lex/Preprocessor.cpp @@ -759,7 +759,7 @@ void Preprocessor::HandlePoisonedIdentifier(Token & Identifier) { Diag(Identifier,it->second) << Identifier.getIdentifierInfo(); } -void Preprocessor::updateOutOfDateIdentifier(IdentifierInfo &II) const { +void Preprocessor::updateOutOfDateIdentifier(const IdentifierInfo &II) const { assert(II.isOutOfDate() && "not out of date"); getExternalSource()->updateOutOfDateIdentifier(II); } diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 0aa14b0510746b9378b4a82d540b4751e78e4422..583232f2d610d0aebb4bb47873c4a3b81327f863 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -7700,7 +7700,7 @@ void Parser::ParseParameterDeclarationClause( } // Remember this parsed parameter in ParamInfo. - IdentifierInfo *ParmII = ParmDeclarator.getIdentifier(); + const IdentifierInfo *ParmII = ParmDeclarator.getIdentifier(); // DefArgToks is used when the parsing of default arguments needs // to be delayed. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 77d2382ea6d907ae94d1caeefb7b0d0e8756331d..477d81cdc2c230b53521003b826cf558985a82e5 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -140,6 +140,14 @@ Parser::DeclGroupPtrTy Parser::ParseNamespace(DeclaratorContext Context, SkipUntil(tok::semi); return nullptr; } + if (!ExtraNSs.empty()) { + Diag(ExtraNSs.front().NamespaceLoc, + diag::err_unexpected_qualified_namespace_alias) + << SourceRange(ExtraNSs.front().NamespaceLoc, + ExtraNSs.back().IdentLoc); + SkipUntil(tok::semi); + return nullptr; + } if (attrLoc.isValid()) Diag(attrLoc, diag::err_unexpected_namespace_attributes_alias); if (InlineLoc.isValid()) @@ -608,7 +616,7 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context, } // Parse nested-name-specifier. - IdentifierInfo *LastII = nullptr; + const IdentifierInfo *LastII = nullptr; if (ParseOptionalCXXScopeSpecifier(D.SS, /*ObjectType=*/nullptr, /*ObjectHasErrors=*/false, /*EnteringContext=*/false, @@ -1494,6 +1502,15 @@ void Parser::ParseMicrosoftInheritanceClassAttributes(ParsedAttributes &attrs) { } } +void Parser::ParseNullabilityClassAttributes(ParsedAttributes &attrs) { + while (Tok.is(tok::kw__Nullable)) { + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + auto Kind = Tok.getKind(); + SourceLocation AttrNameLoc = ConsumeToken(); + attrs.addNew(AttrName, AttrNameLoc, nullptr, AttrNameLoc, nullptr, 0, Kind); + } +} + /// Determine whether the following tokens are valid after a type-specifier /// which could be a standalone declaration. This will conservatively return /// true if there's any doubt, and is appropriate for insert-';' fixits. @@ -1675,15 +1692,21 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, ParsedAttributes attrs(AttrFactory); // If attributes exist after tag, parse them. - MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs); - - // Parse inheritance specifiers. - if (Tok.isOneOf(tok::kw___single_inheritance, tok::kw___multiple_inheritance, - tok::kw___virtual_inheritance)) - ParseMicrosoftInheritanceClassAttributes(attrs); - - // Allow attributes to precede or succeed the inheritance specifiers. - MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs); + for (;;) { + MaybeParseAttributes(PAKM_CXX11 | PAKM_Declspec | PAKM_GNU, attrs); + // Parse inheritance specifiers. + if (Tok.isOneOf(tok::kw___single_inheritance, + tok::kw___multiple_inheritance, + tok::kw___virtual_inheritance)) { + ParseMicrosoftInheritanceClassAttributes(attrs); + continue; + } + if (Tok.is(tok::kw__Nullable)) { + ParseNullabilityClassAttributes(attrs); + continue; + } + break; + } // Source location used by FIXIT to insert misplaced // C++11 attributes diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index ae23cb432c43913b3d26cf663df93d7eb0eb8b1e..d08e675604d19c511e369aaff88a70d21b790e7d 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -30,6 +30,7 @@ #include "clang/Sema/EnterExpressionEvaluationContext.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/SemaSYCL.h" #include "clang/Sema/TypoCorrection.h" #include "llvm/ADT/SmallVector.h" #include @@ -2490,8 +2491,8 @@ ExprResult Parser::ParseSYCLUniqueStableNameExpression() { if (T.consumeClose()) return ExprError(); - return Actions.ActOnSYCLUniqueStableNameExpr(OpLoc, T.getOpenLocation(), - T.getCloseLocation(), Ty.get()); + return Actions.SYCL().ActOnUniqueStableNameExpr( + OpLoc, T.getOpenLocation(), T.getCloseLocation(), Ty.get()); } /// Parse a sizeof or alignof expression. diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 73c85c585baae4f42dd52e75400af6fee40f1d6a..43d6105dcf31c43ee9c56621907e5c7cc192dba0 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -157,7 +157,8 @@ void Parser::CheckForTemplateAndDigraph(Token &Next, ParsedType ObjectType, bool Parser::ParseOptionalCXXScopeSpecifier( CXXScopeSpec &SS, ParsedType ObjectType, bool ObjectHadErrors, bool EnteringContext, bool *MayBePseudoDestructor, bool IsTypename, - IdentifierInfo **LastII, bool OnlyNamespace, bool InUsingDeclaration) { + const IdentifierInfo **LastII, bool OnlyNamespace, + bool InUsingDeclaration) { assert(getLangOpts().CPlusPlus && "Call sites of this function should be guarded by checking for C++"); @@ -2626,7 +2627,7 @@ bool Parser::ParseUnqualifiedIdTemplateId( // UnqualifiedId. // FIXME: Store name for literal operator too. - IdentifierInfo *TemplateII = + const IdentifierInfo *TemplateII = Id.getKind() == UnqualifiedIdKind::IK_Identifier ? Id.Identifier : nullptr; OverloadedOperatorKind OpKind = diff --git a/clang/lib/Parse/ParseHLSL.cpp b/clang/lib/Parse/ParseHLSL.cpp index 4fc6a2203cec367b783e2ee30f43f75ee5b09fd3..5afc958600fa558148d39b128900bbb8454fd473 100644 --- a/clang/lib/Parse/ParseHLSL.cpp +++ b/clang/lib/Parse/ParseHLSL.cpp @@ -15,6 +15,7 @@ #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" +#include "clang/Sema/SemaHLSL.h" using namespace clang; @@ -71,9 +72,9 @@ Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) { return nullptr; } - Decl *D = Actions.ActOnStartHLSLBuffer(getCurScope(), IsCBuffer, BufferLoc, - Identifier, IdentifierLoc, - T.getOpenLocation()); + Decl *D = Actions.HLSL().ActOnStartHLSLBuffer( + getCurScope(), IsCBuffer, BufferLoc, Identifier, IdentifierLoc, + T.getOpenLocation()); while (Tok.isNot(tok::r_brace) && Tok.isNot(tok::eof)) { // FIXME: support attribute on constants inside cbuffer/tbuffer. @@ -87,7 +88,7 @@ Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) { T.skipToEnd(); DeclEnd = T.getCloseLocation(); BufferScope.Exit(); - Actions.ActOnFinishHLSLBuffer(D, DeclEnd); + Actions.HLSL().ActOnFinishHLSLBuffer(D, DeclEnd); return nullptr; } } @@ -95,7 +96,7 @@ Decl *Parser::ParseHLSLBuffer(SourceLocation &DeclEnd) { T.consumeClose(); DeclEnd = T.getCloseLocation(); BufferScope.Exit(); - Actions.ActOnFinishHLSLBuffer(D, DeclEnd); + Actions.HLSL().ActOnFinishHLSLBuffer(D, DeclEnd); Actions.ProcessDeclAttributeList(Actions.CurScope, D, Attrs); return D; diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp index 88bab0eb27a3edf479f18b6f03460ee5a8f9fdb9..887d7a36cee7e976112792c65b45940a871e7756 100644 --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -799,11 +799,11 @@ void Parser::ParseObjCInterfaceDeclList(tok::ObjCKeywordKind contextKey, addedToDeclSpec); // Install the property declarator into interfaceDecl. - IdentifierInfo *SelName = + const IdentifierInfo *SelName = OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier(); Selector GetterSel = PP.getSelectorTable().getNullarySelector(SelName); - IdentifierInfo *SetterName = OCDS.getSetterName(); + const IdentifierInfo *SetterName = OCDS.getSetterName(); Selector SetterSel; if (SetterName) SetterSel = PP.getSelectorTable().getSelector(1, &SetterName); @@ -1445,7 +1445,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, return Result; } - SmallVector KeyIdents; + SmallVector KeyIdents; SmallVector KeyLocs; SmallVector ArgInfos; ParseScope PrototypeScope(this, Scope::FunctionPrototypeScope | @@ -1541,7 +1541,7 @@ Decl *Parser::ParseObjCMethodDecl(SourceLocation mLoc, Declarator ParmDecl(DS, ParsedAttributesView::none(), DeclaratorContext::Prototype); ParseDeclarator(ParmDecl); - IdentifierInfo *ParmII = ParmDecl.getIdentifier(); + const IdentifierInfo *ParmII = ParmDecl.getIdentifier(); Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl); CParamInfo.push_back(DeclaratorChunk::ParamInfo(ParmII, ParmDecl.getIdentifierLoc(), @@ -3242,7 +3242,7 @@ Parser::ParseObjCMessageExpressionBody(SourceLocation LBracLoc, SourceLocation Loc; IdentifierInfo *selIdent = ParseObjCSelectorPiece(Loc); - SmallVector KeyIdents; + SmallVector KeyIdents; SmallVector KeyLocs; ExprVector KeyExprs; @@ -3642,7 +3642,7 @@ ExprResult Parser::ParseObjCSelectorExpression(SourceLocation AtLoc) { if (Tok.isNot(tok::l_paren)) return ExprError(Diag(Tok, diag::err_expected_lparen_after) << "@selector"); - SmallVector KeyIdents; + SmallVector KeyIdents; SourceLocation sLoc; BalancedDelimiterTracker T(*this, tok::l_paren); diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index 50e3c39f60919b8d0d7a60c241f9a9f4f1d923a5..b487a1968d1ec87192aefb904b4524b48fc90d06 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -10,10 +10,12 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/OpenACCClause.h" #include "clang/Basic/OpenACCKinds.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" #include "clang/Parse/RAIIObjectsForParser.h" +#include "clang/Sema/SemaOpenACC.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" @@ -581,12 +583,26 @@ unsigned getOpenACCScopeFlags(OpenACCDirectiveKind DirKind) { } // namespace +Parser::OpenACCClauseParseResult Parser::OpenACCCanContinue() { + return {nullptr, OpenACCParseCanContinue::Can}; +} + +Parser::OpenACCClauseParseResult Parser::OpenACCCannotContinue() { + return {nullptr, OpenACCParseCanContinue::Cannot}; +} + +Parser::OpenACCClauseParseResult Parser::OpenACCSuccess(OpenACCClause *Clause) { + return {Clause, OpenACCParseCanContinue::Can}; +} + // OpenACC 3.3, section 1.7: // To simplify the specification and convey appropriate constraint information, // a pqr-list is a comma-separated list of pdr items. The one exception is a // clause-list, which is a list of one or more clauses optionally separated by // commas. -void Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) { +SmallVector +Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) { + SmallVector Clauses; bool FirstClause = true; while (getCurToken().isNot(tok::annot_pragma_openacc_end)) { // Comma is optional in a clause-list. @@ -594,13 +610,17 @@ void Parser::ParseOpenACCClauseList(OpenACCDirectiveKind DirKind) { ConsumeToken(); FirstClause = false; - // Recovering from a bad clause is really difficult, so we just give up on - // error. - if (ParseOpenACCClause(DirKind)) { + OpenACCClauseParseResult Result = ParseOpenACCClause(Clauses, DirKind); + if (OpenACCClause *Clause = Result.getPointer()) { + Clauses.push_back(Clause); + } else if (Result.getInt() == OpenACCParseCanContinue::Cannot) { + // Recovering from a bad clause is really difficult, so we just give up on + // error. SkipUntilEndOfDirective(*this); - return; + return Clauses; } } + return Clauses; } ExprResult Parser::ParseOpenACCIntExpr() { @@ -761,42 +781,48 @@ bool Parser::ParseOpenACCGangArgList() { // really have its owner grammar and each individual one has its own definition. // However, they all are named with a single-identifier (or auto/default!) // token, followed in some cases by either braces or parens. -bool Parser::ParseOpenACCClause(OpenACCDirectiveKind DirKind) { +Parser::OpenACCClauseParseResult +Parser::ParseOpenACCClause(ArrayRef ExistingClauses, + OpenACCDirectiveKind DirKind) { // A number of clause names are actually keywords, so accept a keyword that // can be converted to a name. if (expectIdentifierOrKeyword(*this)) - return true; + return OpenACCCannotContinue(); OpenACCClauseKind Kind = getOpenACCClauseKind(getCurToken()); - if (Kind == OpenACCClauseKind::Invalid) - return Diag(getCurToken(), diag::err_acc_invalid_clause) - << getCurToken().getIdentifierInfo(); + if (Kind == OpenACCClauseKind::Invalid) { + Diag(getCurToken(), diag::err_acc_invalid_clause) + << getCurToken().getIdentifierInfo(); + return OpenACCCannotContinue(); + } // Consume the clause name. SourceLocation ClauseLoc = ConsumeToken(); - bool Result = ParseOpenACCClauseParams(DirKind, Kind); - getActions().ActOnOpenACCClause(Kind, ClauseLoc); - return Result; + return ParseOpenACCClauseParams(ExistingClauses, DirKind, Kind, ClauseLoc); } -bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, - OpenACCClauseKind Kind) { +Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams( + ArrayRef ExistingClauses, + OpenACCDirectiveKind DirKind, OpenACCClauseKind ClauseKind, + SourceLocation ClauseLoc) { BalancedDelimiterTracker Parens(*this, tok::l_paren, tok::annot_pragma_openacc_end); + SemaOpenACC::OpenACCParsedClause ParsedClause(DirKind, ClauseKind, ClauseLoc); - if (ClauseHasRequiredParens(DirKind, Kind)) { + if (ClauseHasRequiredParens(DirKind, ClauseKind)) { + ParsedClause.setLParenLoc(getCurToken().getLocation()); if (Parens.expectAndConsume()) { // We are missing a paren, so assume that the person just forgot the // parameter. Return 'false' so we try to continue on and parse the next // clause. SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openacc_end, Parser::StopBeforeMatch); - return false; + return OpenACCCanContinue(); } - switch (Kind) { + switch (ClauseKind) { case OpenACCClauseKind::Default: { Token DefKindTok = getCurToken(); @@ -805,46 +831,49 @@ bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, ConsumeToken(); - if (getOpenACCDefaultClauseKind(DefKindTok) == - OpenACCDefaultClauseKind::Invalid) + OpenACCDefaultClauseKind DefKind = + getOpenACCDefaultClauseKind(DefKindTok); + + if (DefKind == OpenACCDefaultClauseKind::Invalid) Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind); + else + ParsedClause.setDefaultDetails(DefKind); break; } case OpenACCClauseKind::If: { ExprResult CondExpr = ParseOpenACCConditionalExpr(*this); - // An invalid expression can be just about anything, so just give up on - // this clause list. + if (CondExpr.isInvalid()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; } case OpenACCClauseKind::CopyIn: tryParseAndConsumeSpecialTokenKind( - *this, OpenACCSpecialTokenKind::ReadOnly, Kind); - if (ParseOpenACCClauseVarList(Kind)) { + *this, OpenACCSpecialTokenKind::ReadOnly, ClauseKind); + if (ParseOpenACCClauseVarList(ClauseKind)) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; case OpenACCClauseKind::Create: case OpenACCClauseKind::CopyOut: tryParseAndConsumeSpecialTokenKind(*this, OpenACCSpecialTokenKind::Zero, - Kind); - if (ParseOpenACCClauseVarList(Kind)) { + ClauseKind); + if (ParseOpenACCClauseVarList(ClauseKind)) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; case OpenACCClauseKind::Reduction: // If we're missing a clause-kind (or it is invalid), see if we can parse // the var-list anyway. ParseReductionOperator(*this); - if (ParseOpenACCClauseVarList(Kind)) { + if (ParseOpenACCClauseVarList(ClauseKind)) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; case OpenACCClauseKind::Self: @@ -867,19 +896,19 @@ bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, case OpenACCClauseKind::Present: case OpenACCClauseKind::Private: case OpenACCClauseKind::UseDevice: - if (ParseOpenACCClauseVarList(Kind)) { + if (ParseOpenACCClauseVarList(ClauseKind)) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; case OpenACCClauseKind::Collapse: { tryParseAndConsumeSpecialTokenKind(*this, OpenACCSpecialTokenKind::Force, - Kind); + ClauseKind); ExprResult NumLoops = getActions().CorrectDelayedTyposInExpr(ParseConstantExpression()); if (NumLoops.isInvalid()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; } @@ -887,7 +916,7 @@ bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, ExprResult BindArg = ParseOpenACCBindClauseArgument(); if (BindArg.isInvalid()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; } @@ -899,7 +928,7 @@ bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, ExprResult IntExpr = ParseOpenACCIntExpr(); if (IntExpr.isInvalid()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; } @@ -911,45 +940,50 @@ bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, ConsumeToken(); } else if (ParseOpenACCDeviceTypeList()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; case OpenACCClauseKind::Tile: if (ParseOpenACCSizeExprList()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; default: llvm_unreachable("Not a required parens type?"); } - return Parens.consumeClose(); - } else if (ClauseHasOptionalParens(DirKind, Kind)) { + ParsedClause.setEndLoc(getCurToken().getLocation()); + + if (Parens.consumeClose()) + return OpenACCCannotContinue(); + + } else if (ClauseHasOptionalParens(DirKind, ClauseKind)) { + ParsedClause.setLParenLoc(getCurToken().getLocation()); if (!Parens.consumeOpen()) { - switch (Kind) { + switch (ClauseKind) { case OpenACCClauseKind::Self: { assert(DirKind != OpenACCDirectiveKind::Update); ExprResult CondExpr = ParseOpenACCConditionalExpr(*this); - // An invalid expression can be just about anything, so just give up on - // this clause list. + if (CondExpr.isInvalid()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; } case OpenACCClauseKind::Vector: case OpenACCClauseKind::Worker: { tryParseAndConsumeSpecialTokenKind(*this, - Kind == OpenACCClauseKind::Vector + ClauseKind == + OpenACCClauseKind::Vector ? OpenACCSpecialTokenKind::Length : OpenACCSpecialTokenKind::Num, - Kind); + ClauseKind); ExprResult IntExpr = ParseOpenACCIntExpr(); if (IntExpr.isInvalid()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; } @@ -957,29 +991,32 @@ bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, ExprResult AsyncArg = ParseOpenACCAsyncArgument(); if (AsyncArg.isInvalid()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; } case OpenACCClauseKind::Gang: if (ParseOpenACCGangArgList()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; case OpenACCClauseKind::Wait: if (ParseOpenACCWaitArgument()) { Parens.skipToEnd(); - return false; + return OpenACCCanContinue(); } break; default: llvm_unreachable("Not an optional parens type?"); } - Parens.consumeClose(); + ParsedClause.setEndLoc(getCurToken().getLocation()); + if (Parens.consumeClose()) + return OpenACCCannotContinue(); } } - return false; + return OpenACCSuccess( + Actions.OpenACC().ActOnClause(ExistingClauses, ParsedClause)); } /// OpenACC 3.3 section 2.16: @@ -1151,7 +1188,7 @@ Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() { SourceLocation StartLoc = getCurToken().getLocation(); OpenACCDirectiveKind DirKind = ParseOpenACCDirectiveKind(*this); - getActions().ActOnOpenACCConstruct(DirKind, StartLoc); + getActions().OpenACC().ActOnConstruct(DirKind, StartLoc); // Once we've parsed the construct/directive name, some have additional // specifiers that need to be taken care of. Atomic has an 'atomic-clause' @@ -1203,15 +1240,17 @@ Parser::OpenACCDirectiveParseInfo Parser::ParseOpenACCDirective() { Diag(Tok, diag::err_expected) << tok::l_paren; } - // Parses the list of clauses, if present. - ParseOpenACCClauseList(DirKind); + // Parses the list of clauses, if present, plus set up return value. + OpenACCDirectiveParseInfo ParseInfo{DirKind, StartLoc, SourceLocation{}, + ParseOpenACCClauseList(DirKind)}; assert(Tok.is(tok::annot_pragma_openacc_end) && "Didn't parse all OpenACC Clauses"); - SourceLocation EndLoc = ConsumeAnnotationToken(); - assert(EndLoc.isValid()); + ParseInfo.EndLoc = ConsumeAnnotationToken(); + assert(ParseInfo.EndLoc.isValid() && + "Terminating annotation token not present"); - return OpenACCDirectiveParseInfo{DirKind, StartLoc, EndLoc}; + return ParseInfo; } // Parse OpenACC directive on a declaration. @@ -1223,12 +1262,12 @@ Parser::DeclGroupPtrTy Parser::ParseOpenACCDirectiveDecl() { OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective(); - if (getActions().ActOnStartOpenACCDeclDirective(DirInfo.DirKind, - DirInfo.StartLoc)) + if (getActions().OpenACC().ActOnStartDeclDirective(DirInfo.DirKind, + DirInfo.StartLoc)) return nullptr; // TODO OpenACC: Do whatever decl parsing is required here. - return DeclGroupPtrTy::make(getActions().ActOnEndOpenACCDeclDirective()); + return DeclGroupPtrTy::make(getActions().OpenACC().ActOnEndDeclDirective()); } // Parse OpenACC Directive on a Statement. @@ -1239,8 +1278,8 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() { ConsumeAnnotationToken(); OpenACCDirectiveParseInfo DirInfo = ParseOpenACCDirective(); - if (getActions().ActOnStartOpenACCStmtDirective(DirInfo.DirKind, - DirInfo.StartLoc)) + if (getActions().OpenACC().ActOnStartStmtDirective(DirInfo.DirKind, + DirInfo.StartLoc)) return StmtError(); StmtResult AssocStmt; @@ -1249,10 +1288,11 @@ StmtResult Parser::ParseOpenACCDirectiveStmt() { ParsingOpenACCDirectiveRAII DirScope(*this, /*Value=*/false); ParseScope ACCScope(this, getOpenACCScopeFlags(DirInfo.DirKind)); - AssocStmt = getActions().ActOnOpenACCAssociatedStmt(DirInfo.DirKind, - ParseStatement()); + AssocStmt = getActions().OpenACC().ActOnAssociatedStmt(DirInfo.DirKind, + ParseStatement()); } - return getActions().ActOnEndOpenACCStmtDirective( - DirInfo.DirKind, DirInfo.StartLoc, DirInfo.EndLoc, AssocStmt); + return getActions().OpenACC().ActOnEndStmtDirective( + DirInfo.DirKind, DirInfo.StartLoc, DirInfo.EndLoc, DirInfo.Clauses, + AssocStmt); } diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index d4897f8f66072ea08f372ce91eb5bfcca22e8d08..b07ce451e878eb3a3d9a17a3b5db9c6c8f52e6e7 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -313,7 +313,7 @@ Parser::ParseConceptDefinition(const ParsedTemplateInfo &TemplateInfo, return nullptr; } - IdentifierInfo *Id = Result.Identifier; + const IdentifierInfo *Id = Result.Identifier; SourceLocation IdLoc = Result.getBeginLoc(); DiagnoseAndSkipCXX11Attributes(); @@ -805,10 +805,12 @@ NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth, // identifier, comma, or greater. Provide a fixit if the identifier, comma, // or greater appear immediately or after 'struct'. In the latter case, // replace the keyword with 'class'. + bool TypenameKeyword = false; if (!TryConsumeToken(tok::kw_class)) { bool Replace = Tok.isOneOf(tok::kw_typename, tok::kw_struct); const Token &Next = Tok.is(tok::kw_struct) ? NextToken() : Tok; if (Tok.is(tok::kw_typename)) { + TypenameKeyword = true; Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_template_template_param_typename @@ -878,10 +880,9 @@ NamedDecl *Parser::ParseTemplateTemplateParameter(unsigned Depth, } } - return Actions.ActOnTemplateTemplateParameter(getCurScope(), TemplateLoc, - ParamList, EllipsisLoc, - ParamName, NameLoc, Depth, - Position, EqualLoc, DefaultArg); + return Actions.ActOnTemplateTemplateParameter( + getCurScope(), TemplateLoc, ParamList, TypenameKeyword, EllipsisLoc, + ParamName, NameLoc, Depth, Position, EqualLoc, DefaultArg); } /// ParseNonTypeTemplateParameter - Handle the parsing of non-type @@ -1289,7 +1290,7 @@ bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK, // later. Tok.setKind(tok::annot_template_id); - IdentifierInfo *TemplateII = + const IdentifierInfo *TemplateII = TemplateName.getKind() == UnqualifiedIdKind::IK_Identifier ? TemplateName.Identifier : nullptr; diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt index e8bff07ced0cfa60064d69b3a879ddaa0099f42c..ab3b813a9ccd97efc5d99104cd1d493024aff78a 100644 --- a/clang/lib/Sema/CMakeLists.txt +++ b/clang/lib/Sema/CMakeLists.txt @@ -29,6 +29,7 @@ add_clang_library(clangSema SemaAttr.cpp SemaAPINotes.cpp SemaAvailability.cpp + SemaBase.cpp SemaCXXScopeSpec.cpp SemaCast.cpp SemaChecking.cpp diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp index 350bd78b57107bbfaa0dde13af5ec7c18af9b503..91713d71786ee5eeffa9b050f2d72d6593490aec 100644 --- a/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -854,7 +854,8 @@ StringRef CodeCompletionResult::getOrderedName(std::string &Saved) const { if (IdentifierInfo *Id = Name.getAsIdentifierInfo()) return Id->getName(); if (Name.isObjCZeroArgSelector()) - if (IdentifierInfo *Id = Name.getObjCSelector().getIdentifierInfoForSlot(0)) + if (const IdentifierInfo *Id = + Name.getObjCSelector().getIdentifierInfoForSlot(0)) return Id->getName(); Saved = Name.getAsString(); diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp index 6722878883be8ed2c27dd023d65fea3f68df747c..ce6211c23218bbd2024bad7aa5dcb690e005ebeb 100644 --- a/clang/lib/Sema/JumpDiagnostics.cpp +++ b/clang/lib/Sema/JumpDiagnostics.cpp @@ -16,6 +16,7 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" +#include "clang/AST/StmtOpenACC.h" #include "clang/AST/StmtOpenMP.h" #include "clang/Basic/SourceLocation.h" #include "clang/Sema/SemaInternal.h" diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index cd0c42d5ffbacd3de3e7a744fa48762293d3cff6..a2ea66f339c8e37e8f914f0845af191bcd71db6d 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -42,7 +42,10 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaConsumer.h" +#include "clang/Sema/SemaHLSL.h" #include "clang/Sema/SemaInternal.h" +#include "clang/Sema/SemaOpenACC.h" +#include "clang/Sema/SemaSYCL.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" #include "clang/Sema/TypoCorrection.h" @@ -89,9 +92,8 @@ DarwinSDKInfo *Sema::getDarwinSDKInfoForAvailabilityChecking() { return nullptr; } -IdentifierInfo * -Sema::InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName, - unsigned int Index) { +IdentifierInfo *Sema::InventAbbreviatedTemplateParameterTypeName( + const IdentifierInfo *ParamName, unsigned int Index) { std::string InventedName; llvm::raw_string_ostream OS(InventedName); @@ -135,6 +137,7 @@ namespace sema { class SemaPPCallbacks : public PPCallbacks { Sema *S = nullptr; llvm::SmallVector IncludeStack; + llvm::SmallVector ProfilerStack; public: void set(Sema &S) { this->S = &S; } @@ -153,8 +156,8 @@ public: if (IncludeLoc.isValid()) { if (llvm::timeTraceProfilerEnabled()) { OptionalFileEntryRef FE = SM.getFileEntryRefForID(SM.getFileID(Loc)); - llvm::timeTraceProfilerBegin("Source", FE ? FE->getName() - : StringRef("")); + ProfilerStack.push_back(llvm::timeTraceAsyncProfilerBegin( + "Source", FE ? FE->getName() : StringRef(""))); } IncludeStack.push_back(IncludeLoc); @@ -167,7 +170,7 @@ public: case ExitFile: if (!IncludeStack.empty()) { if (llvm::timeTraceProfilerEnabled()) - llvm::timeTraceProfilerEnd(); + llvm::timeTraceProfilerEnd(ProfilerStack.pop_back_val()); S->DiagnoseNonDefaultPragmaAlignPack( Sema::PragmaAlignPackDiagnoseKind::ChangedStateAtExit, @@ -188,14 +191,17 @@ const uint64_t Sema::MaximumAlignment; Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter) - : CollectStats(false), TUKind(TUKind), CurFPFeatures(pp.getLangOpts()), - LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer), - Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), - APINotes(SourceMgr, LangOpts), AnalysisWarnings(*this), - ThreadSafetyDeclCache(nullptr), LateTemplateParser(nullptr), - LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), - CurContext(nullptr), ExternalSource(nullptr), CurScope(nullptr), - Ident_super(nullptr), + : SemaBase(*this), CollectStats(false), TUKind(TUKind), + CurFPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp), + Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), + SourceMgr(PP.getSourceManager()), APINotes(SourceMgr, LangOpts), + AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr), + LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr), + OpaqueParser(nullptr), CurContext(nullptr), ExternalSource(nullptr), + CurScope(nullptr), Ident_super(nullptr), + HLSLPtr(std::make_unique(*this)), + OpenACCPtr(std::make_unique(*this)), + SYCLPtr(std::make_unique(*this)), MSPointerToMemberRepresentationMethod( LangOpts.getMSPointerToMemberRepresentationMethod()), MSStructPragmaOn(false), VtorDispStack(LangOpts.getVtorDispMode()), @@ -652,6 +658,7 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, case CK_FunctionToPointerDecay: case CK_ToVoid: case CK_NonAtomicToAtomic: + case CK_HLSLArrayRValue: break; } } @@ -1609,11 +1616,6 @@ void Sema::EmitCurrentDiagnostic(unsigned DiagID) { PrintContextStack(); } -Sema::SemaDiagnosticBuilder -Sema::Diag(SourceLocation Loc, const PartialDiagnostic &PD, bool DeferHint) { - return Diag(Loc, PD.getDiagID(), DeferHint) << PD; -} - bool Sema::hasUncompilableErrorOccurred() const { if (getDiagnostics().hasUncompilableErrorOccurred()) return true; @@ -1902,35 +1904,12 @@ Sema::targetDiag(SourceLocation Loc, unsigned DiagID, const FunctionDecl *FD) { : CUDADiagIfHostCode(Loc, DiagID); if (getLangOpts().SYCLIsDevice) - return SYCLDiagIfDeviceCode(Loc, DiagID); + return SYCL().DiagIfDeviceCode(Loc, DiagID); return SemaDiagnosticBuilder(SemaDiagnosticBuilder::K_Immediate, Loc, DiagID, FD, *this); } -Sema::SemaDiagnosticBuilder Sema::Diag(SourceLocation Loc, unsigned DiagID, - bool DeferHint) { - bool IsError = Diags.getDiagnosticIDs()->isDefaultMappingAsError(DiagID); - bool ShouldDefer = getLangOpts().CUDA && LangOpts.GPUDeferDiag && - DiagnosticIDs::isDeferrable(DiagID) && - (DeferHint || DeferDiags || !IsError); - auto SetIsLastErrorImmediate = [&](bool Flag) { - if (IsError) - IsLastErrorImmediate = Flag; - }; - if (!ShouldDefer) { - SetIsLastErrorImmediate(true); - return SemaDiagnosticBuilder(SemaDiagnosticBuilder::K_Immediate, Loc, - DiagID, getCurFunctionDecl(), *this); - } - - SemaDiagnosticBuilder DB = getLangOpts().CUDAIsDevice - ? CUDADiagIfDeviceCode(Loc, DiagID) - : CUDADiagIfHostCode(Loc, DiagID); - SetIsLastErrorImmediate(DB.isImmediate()); - return DB; -} - void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { if (isUnevaluatedContext() || Ty.isNull()) return; @@ -1941,7 +1920,7 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { // constant byte size like zero length arrays. So, do a deep check for SYCL. if (D && LangOpts.SYCLIsDevice) { llvm::DenseSet Visited; - deepTypeCheckForSYCLDevice(Loc, Visited, D); + SYCL().deepTypeCheckForDevice(Loc, Visited, D); } Decl *C = cast(getCurLexicalContext()); @@ -2064,8 +2043,11 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) { targetDiag(D->getLocation(), diag::note_defined_here, FD) << D; } - if (TI.hasRISCVVTypes() && Ty->isRVVSizelessBuiltinType()) - checkRVVTypeSupport(Ty, Loc, D); + if (TI.hasRISCVVTypes() && Ty->isRVVSizelessBuiltinType() && FD) { + llvm::StringMap CallerFeatureMap; + Context.getFunctionFeatureMap(CallerFeatureMap, FD); + checkRVVTypeSupport(Ty, Loc, D, CallerFeatureMap); + } // Don't allow SVE types in functions without a SVE target. if (Ty->isSVESizelessBuiltinType() && FD && FD->hasBody()) { @@ -2206,7 +2188,7 @@ static void checkEscapingByref(VarDecl *VD, Sema &S) { // block copy/destroy functions. Resolve it here. if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) if (CXXDestructorDecl *DD = RD->getDestructor()) { - auto *FPT = DD->getType()->getAs(); + auto *FPT = DD->getType()->castAs(); S.ResolveExceptionSpec(Loc, FPT); } } diff --git a/clang/lib/Sema/SemaAPINotes.cpp b/clang/lib/Sema/SemaAPINotes.cpp index 836c633e9d20421e4be008599f001e211f75984b..a3128306c664fe17ffa439ceda3dda798c2e2f50 100644 --- a/clang/lib/Sema/SemaAPINotes.cpp +++ b/clang/lib/Sema/SemaAPINotes.cpp @@ -52,49 +52,54 @@ static void applyNullability(Sema &S, Decl *D, NullabilityKind Nullability, if (!Metadata.IsActive) return; - auto IsModified = [&](Decl *D, QualType QT, - NullabilityKind Nullability) -> bool { + auto GetModified = + [&](Decl *D, QualType QT, + NullabilityKind Nullability) -> std::optional { QualType Original = QT; S.CheckImplicitNullabilityTypeSpecifier(QT, Nullability, D->getLocation(), isa(D), /*OverrideExisting=*/true); - return QT.getTypePtr() != Original.getTypePtr(); + return (QT.getTypePtr() != Original.getTypePtr()) ? std::optional(QT) + : std::nullopt; }; if (auto Function = dyn_cast(D)) { - if (IsModified(D, Function->getReturnType(), Nullability)) { - QualType FnType = Function->getType(); - Function->setType(FnType); + if (auto Modified = + GetModified(D, Function->getReturnType(), Nullability)) { + const FunctionType *FnType = Function->getType()->castAs(); + if (const FunctionProtoType *proto = dyn_cast(FnType)) + Function->setType(S.Context.getFunctionType( + *Modified, proto->getParamTypes(), proto->getExtProtoInfo())); + else + Function->setType( + S.Context.getFunctionNoProtoType(*Modified, FnType->getExtInfo())); } } else if (auto Method = dyn_cast(D)) { - QualType Type = Method->getReturnType(); - if (IsModified(D, Type, Nullability)) { - Method->setReturnType(Type); + if (auto Modified = GetModified(D, Method->getReturnType(), Nullability)) { + Method->setReturnType(*Modified); // Make it a context-sensitive keyword if we can. - if (!isIndirectPointerType(Type)) + if (!isIndirectPointerType(*Modified)) Method->setObjCDeclQualifier(Decl::ObjCDeclQualifier( Method->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); } } else if (auto Value = dyn_cast(D)) { - QualType Type = Value->getType(); - if (IsModified(D, Type, Nullability)) { - Value->setType(Type); + if (auto Modified = GetModified(D, Value->getType(), Nullability)) { + Value->setType(*Modified); // Make it a context-sensitive keyword if we can. if (auto Parm = dyn_cast(D)) { - if (Parm->isObjCMethodParameter() && !isIndirectPointerType(Type)) + if (Parm->isObjCMethodParameter() && !isIndirectPointerType(*Modified)) Parm->setObjCDeclQualifier(Decl::ObjCDeclQualifier( Parm->getObjCDeclQualifier() | Decl::OBJC_TQ_CSNullability)); } } } else if (auto Property = dyn_cast(D)) { - QualType Type = Property->getType(); - if (IsModified(D, Type, Nullability)) { - Property->setType(Type, Property->getTypeSourceInfo()); + if (auto Modified = GetModified(D, Property->getType(), Nullability)) { + Property->setType(*Modified, Property->getTypeSourceInfo()); // Make it a property attribute if we can. - if (!isIndirectPointerType(Type)) + if (!isIndirectPointerType(*Modified)) Property->setPropertyAttributes( ObjCPropertyAttribute::kind_null_resettable); } diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index 0dcf42e489971344d516153c872a36c1df03e188..a5dd158808f26b4bed173943d9940f7f76602d10 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -215,6 +215,18 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) { inferGslPointerAttribute(Record, Record); } +void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) { + static llvm::StringSet<> Nullable{ + "auto_ptr", "shared_ptr", "unique_ptr", "exception_ptr", + "coroutine_handle", "function", "move_only_function", + }; + + if (CRD->isInStdNamespace() && Nullable.count(CRD->getName()) && + !CRD->hasAttr()) + for (Decl *Redecl : CRD->redecls()) + Redecl->addAttr(TypeNullableAttr::CreateImplicit(Context)); +} + void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, SourceLocation PragmaLoc) { PragmaMsStackAction Action = Sema::PSK_Reset; diff --git a/clang/lib/Sema/SemaBase.cpp b/clang/lib/Sema/SemaBase.cpp new file mode 100644 index 0000000000000000000000000000000000000000..95c0cfbe283b0e3a81bc0e69b9ebf3ba893fe053 --- /dev/null +++ b/clang/lib/Sema/SemaBase.cpp @@ -0,0 +1,85 @@ +#include "clang/Sema/SemaBase.h" +#include "clang/Sema/Sema.h" + +namespace clang { + +SemaBase::SemaBase(Sema &S) : SemaRef(S) {} + +ASTContext &SemaBase::getASTContext() const { return SemaRef.Context; } +DiagnosticsEngine &SemaBase::getDiagnostics() const { return SemaRef.Diags; } +const LangOptions &SemaBase::getLangOpts() const { return SemaRef.LangOpts; } + +SemaBase::ImmediateDiagBuilder::~ImmediateDiagBuilder() { + // If we aren't active, there is nothing to do. + if (!isActive()) + return; + + // Otherwise, we need to emit the diagnostic. First clear the diagnostic + // builder itself so it won't emit the diagnostic in its own destructor. + // + // This seems wasteful, in that as written the DiagnosticBuilder dtor will + // do its own needless checks to see if the diagnostic needs to be + // emitted. However, because we take care to ensure that the builder + // objects never escape, a sufficiently smart compiler will be able to + // eliminate that code. + Clear(); + + // Dispatch to Sema to emit the diagnostic. + SemaRef.EmitCurrentDiagnostic(DiagID); +} + +const SemaBase::SemaDiagnosticBuilder & +operator<<(const SemaBase::SemaDiagnosticBuilder &Diag, + const PartialDiagnostic &PD) { + if (Diag.ImmediateDiag) + PD.Emit(*Diag.ImmediateDiag); + else if (Diag.PartialDiagId) + Diag.S.DeviceDeferredDiags[Diag.Fn][*Diag.PartialDiagId].second = PD; + return Diag; +} + +void SemaBase::SemaDiagnosticBuilder::AddFixItHint( + const FixItHint &Hint) const { + if (ImmediateDiag) + ImmediateDiag->AddFixItHint(Hint); + else if (PartialDiagId) + S.DeviceDeferredDiags[Fn][*PartialDiagId].second.AddFixItHint(Hint); +} + +llvm::DenseMap, + std::vector> & +SemaBase::SemaDiagnosticBuilder::getDeviceDeferredDiags() const { + return S.DeviceDeferredDiags; +} + +Sema::SemaDiagnosticBuilder SemaBase::Diag(SourceLocation Loc, unsigned DiagID, + bool DeferHint) { + bool IsError = + getDiagnostics().getDiagnosticIDs()->isDefaultMappingAsError(DiagID); + bool ShouldDefer = getLangOpts().CUDA && getLangOpts().GPUDeferDiag && + DiagnosticIDs::isDeferrable(DiagID) && + (DeferHint || SemaRef.DeferDiags || !IsError); + auto SetIsLastErrorImmediate = [&](bool Flag) { + if (IsError) + SemaRef.IsLastErrorImmediate = Flag; + }; + if (!ShouldDefer) { + SetIsLastErrorImmediate(true); + return SemaDiagnosticBuilder(SemaDiagnosticBuilder::K_Immediate, Loc, + DiagID, SemaRef.getCurFunctionDecl(), SemaRef); + } + + SemaDiagnosticBuilder DB = getLangOpts().CUDAIsDevice + ? SemaRef.CUDADiagIfDeviceCode(Loc, DiagID) + : SemaRef.CUDADiagIfHostCode(Loc, DiagID); + SetIsLastErrorImmediate(DB.isImmediate()); + return DB; +} + +Sema::SemaDiagnosticBuilder SemaBase::Diag(SourceLocation Loc, + const PartialDiagnostic &PD, + bool DeferHint) { + return Diag(Loc, PD.getDiagID(), DeferHint) << PD; +} + +} // namespace clang diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 246e3577809a795f939ea223d739351437b141a7..abfd9a3031577bb0616c458894caeb27a7c43197 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -27,6 +27,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" #include "clang/AST/FormatString.h" +#include "clang/AST/IgnoreExpr.h" #include "clang/AST/NSAPI.h" #include "clang/AST/NonTrivialTypeVisitor.h" #include "clang/AST/OperationKinds.h" @@ -187,7 +188,7 @@ static bool convertArgumentToType(Sema &S, Expr *&Value, QualType Ty) { /// Check that the first argument to __builtin_annotation is an integer /// and the second argument is a non-wide string literal. -static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) { +static bool BuiltinAnnotation(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 2)) return true; @@ -213,7 +214,7 @@ static bool SemaBuiltinAnnotation(Sema &S, CallExpr *TheCall) { return false; } -static bool SemaBuiltinMSVCAnnotation(Sema &S, CallExpr *TheCall) { +static bool BuiltinMSVCAnnotation(Sema &S, CallExpr *TheCall) { // We need at least one argument. if (TheCall->getNumArgs() < 1) { S.Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least) @@ -237,7 +238,7 @@ static bool SemaBuiltinMSVCAnnotation(Sema &S, CallExpr *TheCall) { /// Check that the argument to __builtin_addressof is a glvalue, and set the /// result type to the corresponding pointer type. -static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) { +static bool BuiltinAddressof(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) return true; @@ -252,7 +253,7 @@ static bool SemaBuiltinAddressof(Sema &S, CallExpr *TheCall) { } /// Check that the argument to __builtin_function_start is a function. -static bool SemaBuiltinFunctionStart(Sema &S, CallExpr *TheCall) { +static bool BuiltinFunctionStart(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) return true; @@ -276,7 +277,7 @@ static bool SemaBuiltinFunctionStart(Sema &S, CallExpr *TheCall) { /// Check the number of arguments and set the result type to /// the argument type. -static bool SemaBuiltinPreserveAI(Sema &S, CallExpr *TheCall) { +static bool BuiltinPreserveAI(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) return true; @@ -287,7 +288,7 @@ static bool SemaBuiltinPreserveAI(Sema &S, CallExpr *TheCall) { /// Check that the value argument for __builtin_is_aligned(value, alignment) and /// __builtin_aligned_{up,down}(value, alignment) is an integer or a pointer /// type (but not a function pointer) and that the alignment is a power-of-two. -static bool SemaBuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) { +static bool BuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) { if (checkArgCount(S, TheCall, 2)) return true; @@ -365,8 +366,7 @@ static bool SemaBuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) { return false; } -static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall, - unsigned BuiltinID) { +static bool BuiltinOverflow(Sema &S, CallExpr *TheCall, unsigned BuiltinID) { if (checkArgCount(S, TheCall, 3)) return true; @@ -694,7 +694,7 @@ struct BuiltinDumpStructGenerator { }; } // namespace -static ExprResult SemaBuiltinDumpStruct(Sema &S, CallExpr *TheCall) { +static ExprResult BuiltinDumpStruct(Sema &S, CallExpr *TheCall) { if (checkArgCountAtLeast(S, TheCall, 2)) return ExprError(); @@ -760,7 +760,7 @@ static ExprResult SemaBuiltinDumpStruct(Sema &S, CallExpr *TheCall) { return Generator.buildWrapper(); } -static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { +static bool BuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { if (checkArgCount(S, BuiltinCall, 2)) return true; @@ -1098,7 +1098,7 @@ static bool ProcessFormatStringLiteral(const Expr *FormatExpr, const ConstantArrayType *T = Context.getAsConstantArrayType(Format->getType()); assert(T && "String literal not of constant array type!"); - size_t TypeSize = T->getSize().getZExtValue(); + size_t TypeSize = T->getZExtSize(); // In case there's a null byte somewhere. StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, FormatStrRef.find(0)); return true; @@ -1426,9 +1426,9 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, << FunctionName << DestinationStr << SourceStr); } -static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, - Scope::ScopeFlags NeededScopeFlags, - unsigned DiagID) { +static bool BuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, + Scope::ScopeFlags NeededScopeFlags, + unsigned DiagID) { // Scopes aren't available during instantiation. Fortunately, builtin // functions cannot be template args so they cannot be formed through template // instantiation. Therefore checking once during the parse is sufficient. @@ -1502,7 +1502,7 @@ static bool checkOpenCLSubgroupExt(Sema &S, CallExpr *Call) { return false; } -static bool SemaOpenCLBuiltinNDRangeAndBlock(Sema &S, CallExpr *TheCall) { +static bool OpenCLBuiltinNDRangeAndBlock(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 2)) return true; @@ -1529,7 +1529,7 @@ static bool SemaOpenCLBuiltinNDRangeAndBlock(Sema &S, CallExpr *TheCall) { /// OpenCL C v2.0, s6.13.17.6 - Check the argument to the /// get_kernel_work_group_size /// and get_kernel_preferred_work_group_size_multiple builtin functions. -static bool SemaOpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) { +static bool OpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) return true; @@ -1605,7 +1605,7 @@ static bool checkOpenCLEnqueueVariadicArgs(Sema &S, CallExpr *TheCall, /// clk_event_t *event_ret, /// void (^block)(local void*, ...), /// uint size0, ...) -static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { +static bool OpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { unsigned NumArgs = TheCall->getNumArgs(); if (NumArgs < 4) { @@ -1804,7 +1804,7 @@ static bool checkOpenCLPipePacketType(Sema &S, CallExpr *Call, unsigned Idx) { // \param S Reference to the semantic analyzer. // \param Call A pointer to the builtin call. // \return True if a semantic error has been found, false otherwise. -static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { +static bool BuiltinRWPipe(Sema &S, CallExpr *Call) { // OpenCL v2.0 s6.13.16.2 - The built-in read/write // functions have two forms. switch (Call->getNumArgs()) { @@ -1859,7 +1859,7 @@ static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. // \return True if a semantic error was found, false otherwise. -static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) { +static bool BuiltinReserveRWPipe(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 2)) return true; @@ -1888,7 +1888,7 @@ static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) { // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. // \return True if a semantic error was found, false otherwise. -static bool SemaBuiltinCommitRWPipe(Sema &S, CallExpr *Call) { +static bool BuiltinCommitRWPipe(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 2)) return true; @@ -1911,7 +1911,7 @@ static bool SemaBuiltinCommitRWPipe(Sema &S, CallExpr *Call) { // \param S Reference to the semantic analyzer. // \param Call The call to the builtin function to be analyzed. // \return True if a semantic error was found, false otherwise. -static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) { +static bool BuiltinPipePackets(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 1)) return true; @@ -1930,8 +1930,7 @@ static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) { // \param BuiltinID ID of the builtin function. // \param Call A pointer to the builtin call. // \return True if a semantic error has been found, false otherwise. -static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID, - CallExpr *Call) { +static bool OpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID, CallExpr *Call) { if (checkArgCount(S, Call, 1)) return true; @@ -2086,7 +2085,7 @@ static bool checkPointerAuthValue(Sema &S, Expr *&Arg, return false; } -static ExprResult SemaPointerAuthStrip(Sema &S, CallExpr *Call) { +static ExprResult PointerAuthStrip(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 2)) return ExprError(); if (checkPointerAuthEnabled(S, Call)) @@ -2099,7 +2098,7 @@ static ExprResult SemaPointerAuthStrip(Sema &S, CallExpr *Call) { return Call; } -static ExprResult SemaPointerAuthBlendDiscriminator(Sema &S, CallExpr *Call) { +static ExprResult PointerAuthBlendDiscriminator(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 2)) return ExprError(); if (checkPointerAuthEnabled(S, Call)) @@ -2112,7 +2111,7 @@ static ExprResult SemaPointerAuthBlendDiscriminator(Sema &S, CallExpr *Call) { return Call; } -static ExprResult SemaPointerAuthSignGenericData(Sema &S, CallExpr *Call) { +static ExprResult PointerAuthSignGenericData(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 2)) return ExprError(); if (checkPointerAuthEnabled(S, Call)) @@ -2125,8 +2124,8 @@ static ExprResult SemaPointerAuthSignGenericData(Sema &S, CallExpr *Call) { return Call; } -static ExprResult SemaPointerAuthSignOrAuth(Sema &S, CallExpr *Call, - PointerAuthOpKind OpKind) { +static ExprResult PointerAuthSignOrAuth(Sema &S, CallExpr *Call, + PointerAuthOpKind OpKind) { if (checkArgCount(S, Call, 3)) return ExprError(); if (checkPointerAuthEnabled(S, Call)) @@ -2140,7 +2139,7 @@ static ExprResult SemaPointerAuthSignOrAuth(Sema &S, CallExpr *Call, return Call; } -static ExprResult SemaPointerAuthAuthAndResign(Sema &S, CallExpr *Call) { +static ExprResult PointerAuthAuthAndResign(Sema &S, CallExpr *Call) { if (checkArgCount(S, Call, 5)) return ExprError(); if (checkPointerAuthEnabled(S, Call)) @@ -2156,7 +2155,7 @@ static ExprResult SemaPointerAuthAuthAndResign(Sema &S, CallExpr *Call) { return Call; } -static ExprResult SemaBuiltinLaunder(Sema &S, CallExpr *TheCall) { +static ExprResult BuiltinLaunder(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) return ExprError(); @@ -2329,11 +2328,11 @@ static bool checkFPMathBuiltinElementType(Sema &S, SourceLocation Loc, return false; } -/// SemaBuiltinCpu{Supports|Is} - Handle __builtin_cpu_{supports|is}(char *). +/// BuiltinCpu{Supports|Is} - Handle __builtin_cpu_{supports|is}(char *). /// This checks that the target supports the builtin and that the string /// argument is constant and valid. -static bool SemaBuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall, - const TargetInfo *AuxTI, unsigned BuiltinID) { +static bool BuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall, + const TargetInfo *AuxTI, unsigned BuiltinID) { assert((BuiltinID == Builtin::BI__builtin_cpu_supports || BuiltinID == Builtin::BI__builtin_cpu_is) && "Expecting __builtin_cpu_..."); @@ -2378,7 +2377,7 @@ static bool SemaBuiltinCpu(Sema &S, const TargetInfo &TI, CallExpr *TheCall, /// Checks that __builtin_popcountg was called with a single argument, which is /// an unsigned integer. -static bool SemaBuiltinPopcountg(Sema &S, CallExpr *TheCall) { +static bool BuiltinPopcountg(Sema &S, CallExpr *TheCall) { if (checkArgCount(S, TheCall, 1)) return true; @@ -2402,7 +2401,7 @@ static bool SemaBuiltinPopcountg(Sema &S, CallExpr *TheCall) { /// Checks that __builtin_{clzg,ctzg} was called with a first argument, which is /// an unsigned integer, and an optional second argument, which is promoted to /// an 'int'. -static bool SemaBuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) { +static bool BuiltinCountZeroBitsGeneric(Sema &S, CallExpr *TheCall) { if (checkArgCountRange(S, TheCall, 1, 2)) return true; @@ -2462,7 +2461,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, // If we don't have enough arguments, continue so we can issue better // diagnostic in checkArgCount(...) if (ArgNo < TheCall->getNumArgs() && - SemaBuiltinConstantArg(TheCall, ArgNo, Result)) + BuiltinConstantArg(TheCall, ArgNo, Result)) return true; ICEArguments &= ~(1 << ArgNo); } @@ -2471,8 +2470,8 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, switch (BuiltinID) { case Builtin::BI__builtin_cpu_supports: case Builtin::BI__builtin_cpu_is: - if (SemaBuiltinCpu(*this, Context.getTargetInfo(), TheCall, - Context.getAuxTargetInfo(), BuiltinID)) + if (BuiltinCpu(*this, Context.getTargetInfo(), TheCall, + Context.getAuxTargetInfo(), BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_cpu_init: @@ -2497,7 +2496,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_ms_va_start: case Builtin::BI__builtin_stdarg_start: case Builtin::BI__builtin_va_start: - if (SemaBuiltinVAStart(BuiltinID, TheCall)) + if (BuiltinVAStart(BuiltinID, TheCall)) return ExprError(); break; case Builtin::BI__va_start: { @@ -2505,11 +2504,11 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case llvm::Triple::aarch64: case llvm::Triple::arm: case llvm::Triple::thumb: - if (SemaBuiltinVAStartARMMicrosoft(TheCall)) + if (BuiltinVAStartARMMicrosoft(TheCall)) return ExprError(); break; default: - if (SemaBuiltinVAStart(BuiltinID, TheCall)) + if (BuiltinVAStart(BuiltinID, TheCall)) return ExprError(); break; } @@ -2557,15 +2556,15 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_islessequal: case Builtin::BI__builtin_islessgreater: case Builtin::BI__builtin_isunordered: - if (SemaBuiltinUnorderedCompare(TheCall, BuiltinID)) + if (BuiltinUnorderedCompare(TheCall, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_fpclassify: - if (SemaBuiltinFPClassification(TheCall, 6, BuiltinID)) + if (BuiltinFPClassification(TheCall, 6, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_isfpclass: - if (SemaBuiltinFPClassification(TheCall, 2, BuiltinID)) + if (BuiltinFPClassification(TheCall, 2, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_isfinite: @@ -2579,20 +2578,20 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_signbit: case Builtin::BI__builtin_signbitf: case Builtin::BI__builtin_signbitl: - if (SemaBuiltinFPClassification(TheCall, 1, BuiltinID)) + if (BuiltinFPClassification(TheCall, 1, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_shufflevector: - return SemaBuiltinShuffleVector(TheCall); + return BuiltinShuffleVector(TheCall); // TheCall will be freed by the smart pointer here, but that's fine, since - // SemaBuiltinShuffleVector guts it, but then doesn't release it. + // BuiltinShuffleVector guts it, but then doesn't release it. case Builtin::BI__builtin_prefetch: - if (SemaBuiltinPrefetch(TheCall)) + if (BuiltinPrefetch(TheCall)) return ExprError(); break; case Builtin::BI__builtin_alloca_with_align: case Builtin::BI__builtin_alloca_with_align_uninitialized: - if (SemaBuiltinAllocaWithAlign(TheCall)) + if (BuiltinAllocaWithAlign(TheCall)) return ExprError(); [[fallthrough]]; case Builtin::BI__builtin_alloca: @@ -2601,29 +2600,29 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, << TheCall->getDirectCallee(); break; case Builtin::BI__arithmetic_fence: - if (SemaBuiltinArithmeticFence(TheCall)) + if (BuiltinArithmeticFence(TheCall)) return ExprError(); break; case Builtin::BI__assume: case Builtin::BI__builtin_assume: - if (SemaBuiltinAssume(TheCall)) + if (BuiltinAssume(TheCall)) return ExprError(); break; case Builtin::BI__builtin_assume_aligned: - if (SemaBuiltinAssumeAligned(TheCall)) + if (BuiltinAssumeAligned(TheCall)) return ExprError(); break; case Builtin::BI__builtin_dynamic_object_size: case Builtin::BI__builtin_object_size: - if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 3)) + if (BuiltinConstantArgRange(TheCall, 1, 0, 3)) return ExprError(); break; case Builtin::BI__builtin_longjmp: - if (SemaBuiltinLongjmp(TheCall)) + if (BuiltinLongjmp(TheCall)) return ExprError(); break; case Builtin::BI__builtin_setjmp: - if (SemaBuiltinSetjmp(TheCall)) + if (BuiltinSetjmp(TheCall)) return ExprError(); break; case Builtin::BI__builtin_classify_type: @@ -2631,7 +2630,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, TheCall->setType(Context.IntTy); break; case Builtin::BI__builtin_complex: - if (SemaBuiltinComplex(TheCall)) + if (BuiltinComplex(TheCall)) return ExprError(); break; case Builtin::BI__builtin_constant_p: { @@ -2643,7 +2642,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } case Builtin::BI__builtin_launder: - return SemaBuiltinLaunder(*this, TheCall); + return BuiltinLaunder(*this, TheCall); case Builtin::BI__sync_fetch_and_add: case Builtin::BI__sync_fetch_and_add_1: case Builtin::BI__sync_fetch_and_add_2: @@ -2746,14 +2745,14 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__sync_swap_4: case Builtin::BI__sync_swap_8: case Builtin::BI__sync_swap_16: - return SemaBuiltinAtomicOverloaded(TheCallResult); + return BuiltinAtomicOverloaded(TheCallResult); case Builtin::BI__sync_synchronize: Diag(TheCall->getBeginLoc(), diag::warn_atomic_implicit_seq_cst) << TheCall->getCallee()->getSourceRange(); break; case Builtin::BI__builtin_nontemporal_load: case Builtin::BI__builtin_nontemporal_store: - return SemaBuiltinNontemporalOverloaded(TheCallResult); + return BuiltinNontemporalOverloaded(TheCallResult); case Builtin::BI__builtin_memcpy_inline: { clang::Expr *SizeOp = TheCall->getArg(2); // We warn about copying to or from `nullptr` pointers when `size` is @@ -2779,49 +2778,49 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } #define BUILTIN(ID, TYPE, ATTRS) -#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ - case Builtin::BI##ID: \ - return SemaAtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID); +#define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ + case Builtin::BI##ID: \ + return AtomicOpsOverloaded(TheCallResult, AtomicExpr::AO##ID); #include "clang/Basic/Builtins.inc" case Builtin::BI__annotation: - if (SemaBuiltinMSVCAnnotation(*this, TheCall)) + if (BuiltinMSVCAnnotation(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_annotation: - if (SemaBuiltinAnnotation(*this, TheCall)) + if (BuiltinAnnotation(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_addressof: - if (SemaBuiltinAddressof(*this, TheCall)) + if (BuiltinAddressof(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_function_start: - if (SemaBuiltinFunctionStart(*this, TheCall)) + if (BuiltinFunctionStart(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_is_aligned: case Builtin::BI__builtin_align_up: case Builtin::BI__builtin_align_down: - if (SemaBuiltinAlignment(*this, TheCall, BuiltinID)) + if (BuiltinAlignment(*this, TheCall, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_add_overflow: case Builtin::BI__builtin_sub_overflow: case Builtin::BI__builtin_mul_overflow: - if (SemaBuiltinOverflow(*this, TheCall, BuiltinID)) + if (BuiltinOverflow(*this, TheCall, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_operator_new: case Builtin::BI__builtin_operator_delete: { bool IsDelete = BuiltinID == Builtin::BI__builtin_operator_delete; ExprResult Res = - SemaBuiltinOperatorNewDeleteOverloaded(TheCallResult, IsDelete); + BuiltinOperatorNewDeleteOverloaded(TheCallResult, IsDelete); if (Res.isInvalid()) CorrectDelayedTyposInExpr(TheCallResult.get()); return Res; } case Builtin::BI__builtin_dump_struct: - return SemaBuiltinDumpStruct(*this, TheCall); + return BuiltinDumpStruct(*this, TheCall); case Builtin::BI__builtin_expect_with_probability: { // We first want to ensure we are called with 3 arguments if (checkArgCount(*this, TheCall, 3)) @@ -2852,23 +2851,23 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } case Builtin::BI__builtin_preserve_access_index: - if (SemaBuiltinPreserveAI(*this, TheCall)) + if (BuiltinPreserveAI(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_call_with_static_chain: - if (SemaBuiltinCallWithStaticChain(*this, TheCall)) + if (BuiltinCallWithStaticChain(*this, TheCall)) return ExprError(); break; case Builtin::BI__exception_code: case Builtin::BI_exception_code: - if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHExceptScope, - diag::err_seh___except_block)) + if (BuiltinSEHScopeCheck(*this, TheCall, Scope::SEHExceptScope, + diag::err_seh___except_block)) return ExprError(); break; case Builtin::BI__exception_info: case Builtin::BI_exception_info: - if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHFilterScope, - diag::err_seh___except_filter)) + if (BuiltinSEHScopeCheck(*this, TheCall, Scope::SEHFilterScope, + diag::err_seh___except_filter)) return ExprError(); break; case Builtin::BI__GetExceptionInfo: @@ -2911,87 +2910,87 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } case Builtin::BI__builtin_ptrauth_strip: - return SemaPointerAuthStrip(*this, TheCall); + return PointerAuthStrip(*this, TheCall); case Builtin::BI__builtin_ptrauth_blend_discriminator: - return SemaPointerAuthBlendDiscriminator(*this, TheCall); + return PointerAuthBlendDiscriminator(*this, TheCall); case Builtin::BI__builtin_ptrauth_sign_unauthenticated: - return SemaPointerAuthSignOrAuth(*this, TheCall, PAO_Sign); + return PointerAuthSignOrAuth(*this, TheCall, PAO_Sign); case Builtin::BI__builtin_ptrauth_auth: - return SemaPointerAuthSignOrAuth(*this, TheCall, PAO_Auth); + return PointerAuthSignOrAuth(*this, TheCall, PAO_Auth); case Builtin::BI__builtin_ptrauth_sign_generic_data: - return SemaPointerAuthSignGenericData(*this, TheCall); + return PointerAuthSignGenericData(*this, TheCall); case Builtin::BI__builtin_ptrauth_auth_and_resign: - return SemaPointerAuthAuthAndResign(*this, TheCall); + return PointerAuthAuthAndResign(*this, TheCall); // OpenCL v2.0, s6.13.16 - Pipe functions case Builtin::BIread_pipe: case Builtin::BIwrite_pipe: // Since those two functions are declared with var args, we need a semantic // check for the argument. - if (SemaBuiltinRWPipe(*this, TheCall)) + if (BuiltinRWPipe(*this, TheCall)) return ExprError(); break; case Builtin::BIreserve_read_pipe: case Builtin::BIreserve_write_pipe: case Builtin::BIwork_group_reserve_read_pipe: case Builtin::BIwork_group_reserve_write_pipe: - if (SemaBuiltinReserveRWPipe(*this, TheCall)) + if (BuiltinReserveRWPipe(*this, TheCall)) return ExprError(); break; case Builtin::BIsub_group_reserve_read_pipe: case Builtin::BIsub_group_reserve_write_pipe: if (checkOpenCLSubgroupExt(*this, TheCall) || - SemaBuiltinReserveRWPipe(*this, TheCall)) + BuiltinReserveRWPipe(*this, TheCall)) return ExprError(); break; case Builtin::BIcommit_read_pipe: case Builtin::BIcommit_write_pipe: case Builtin::BIwork_group_commit_read_pipe: case Builtin::BIwork_group_commit_write_pipe: - if (SemaBuiltinCommitRWPipe(*this, TheCall)) + if (BuiltinCommitRWPipe(*this, TheCall)) return ExprError(); break; case Builtin::BIsub_group_commit_read_pipe: case Builtin::BIsub_group_commit_write_pipe: if (checkOpenCLSubgroupExt(*this, TheCall) || - SemaBuiltinCommitRWPipe(*this, TheCall)) + BuiltinCommitRWPipe(*this, TheCall)) return ExprError(); break; case Builtin::BIget_pipe_num_packets: case Builtin::BIget_pipe_max_packets: - if (SemaBuiltinPipePackets(*this, TheCall)) + if (BuiltinPipePackets(*this, TheCall)) return ExprError(); break; case Builtin::BIto_global: case Builtin::BIto_local: case Builtin::BIto_private: - if (SemaOpenCLBuiltinToAddr(*this, BuiltinID, TheCall)) + if (OpenCLBuiltinToAddr(*this, BuiltinID, TheCall)) return ExprError(); break; // OpenCL v2.0, s6.13.17 - Enqueue kernel functions. case Builtin::BIenqueue_kernel: - if (SemaOpenCLBuiltinEnqueueKernel(*this, TheCall)) + if (OpenCLBuiltinEnqueueKernel(*this, TheCall)) return ExprError(); break; case Builtin::BIget_kernel_work_group_size: case Builtin::BIget_kernel_preferred_work_group_size_multiple: - if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) + if (OpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) return ExprError(); break; case Builtin::BIget_kernel_max_sub_group_size_for_ndrange: case Builtin::BIget_kernel_sub_group_count_for_ndrange: - if (SemaOpenCLBuiltinNDRangeAndBlock(*this, TheCall)) + if (OpenCLBuiltinNDRangeAndBlock(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_os_log_format: Cleanup.setExprNeedsCleanups(true); [[fallthrough]]; case Builtin::BI__builtin_os_log_format_buffer_size: - if (SemaBuiltinOSLogFormat(TheCall)) + if (BuiltinOSLogFormat(TheCall)) return ExprError(); break; case Builtin::BI__builtin_frame_address: case Builtin::BI__builtin_return_address: { - if (SemaBuiltinConstantArgRange(TheCall, 0, 0, 0xFFFF)) + if (BuiltinConstantArgRange(TheCall, 0, 0, 0xFFFF)) return ExprError(); // -Wframe-address warning if non-zero passed to builtin @@ -3009,7 +3008,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, } case Builtin::BI__builtin_nondeterministic_value: { - if (SemaBuiltinNonDeterministicValue(TheCall)) + if (BuiltinNonDeterministicValue(TheCall)) return ExprError(); break; } @@ -3062,7 +3061,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } case Builtin::BI__builtin_elementwise_fma: { - if (SemaBuiltinElementwiseTernaryMath(TheCall)) + if (BuiltinElementwiseTernaryMath(TheCall)) return ExprError(); break; } @@ -3070,7 +3069,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, // These builtins restrict the element type to floating point // types only, and take in two arguments. case Builtin::BI__builtin_elementwise_pow: { - if (SemaBuiltinElementwiseMath(TheCall)) + if (BuiltinElementwiseMath(TheCall)) return ExprError(); QualType ArgTy = TheCall->getArg(0)->getType(); @@ -3086,7 +3085,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, // types only. case Builtin::BI__builtin_elementwise_add_sat: case Builtin::BI__builtin_elementwise_sub_sat: { - if (SemaBuiltinElementwiseMath(TheCall)) + if (BuiltinElementwiseMath(TheCall)) return ExprError(); const Expr *Arg = TheCall->getArg(0); @@ -3106,7 +3105,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_elementwise_min: case Builtin::BI__builtin_elementwise_max: - if (SemaBuiltinElementwiseMath(TheCall)) + if (BuiltinElementwiseMath(TheCall)) return ExprError(); break; @@ -3197,13 +3196,13 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, } case Builtin::BI__builtin_matrix_transpose: - return SemaBuiltinMatrixTranspose(TheCall, TheCallResult); + return BuiltinMatrixTranspose(TheCall, TheCallResult); case Builtin::BI__builtin_matrix_column_major_load: - return SemaBuiltinMatrixColumnMajorLoad(TheCall, TheCallResult); + return BuiltinMatrixColumnMajorLoad(TheCall, TheCallResult); case Builtin::BI__builtin_matrix_column_major_store: - return SemaBuiltinMatrixColumnMajorStore(TheCall, TheCallResult); + return BuiltinMatrixColumnMajorStore(TheCall, TheCallResult); case Builtin::BI__builtin_get_device_side_mangled_name: { auto Check = [](CallExpr *TheCall) { @@ -3226,12 +3225,12 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, break; } case Builtin::BI__builtin_popcountg: - if (SemaBuiltinPopcountg(*this, TheCall)) + if (BuiltinPopcountg(*this, TheCall)) return ExprError(); break; case Builtin::BI__builtin_clzg: case Builtin::BI__builtin_ctzg: - if (SemaBuiltinCountZeroBitsGeneric(*this, TheCall)) + if (BuiltinCountZeroBitsGeneric(*this, TheCall)) return ExprError(); break; } @@ -3377,7 +3376,7 @@ bool Sema::ParseSVEImmChecks( // Check constant-ness first. llvm::APSInt Imm; - if (SemaBuiltinConstantArg(TheCall, ArgNum, Imm)) + if (BuiltinConstantArg(TheCall, ArgNum, Imm)) return true; if (!CheckImm(Imm.getSExtValue())) @@ -3387,65 +3386,63 @@ bool Sema::ParseSVEImmChecks( switch ((SVETypeFlags::ImmCheckType)CheckTy) { case SVETypeFlags::ImmCheck0_31: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 31)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 31)) HasError = true; break; case SVETypeFlags::ImmCheck0_13: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 13)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 13)) HasError = true; break; case SVETypeFlags::ImmCheck1_16: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, 16)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 16)) HasError = true; break; case SVETypeFlags::ImmCheck0_7: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 7)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 7)) HasError = true; break; case SVETypeFlags::ImmCheck1_1: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, 1)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 1)) HasError = true; break; case SVETypeFlags::ImmCheck1_3: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, 3)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 3)) HasError = true; break; case SVETypeFlags::ImmCheck1_7: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, 7)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 1, 7)) HasError = true; break; case SVETypeFlags::ImmCheckExtract: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, - (2048 / ElementSizeInBits) - 1)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, + (2048 / ElementSizeInBits) - 1)) HasError = true; break; case SVETypeFlags::ImmCheckShiftRight: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, ElementSizeInBits)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 1, ElementSizeInBits)) HasError = true; break; case SVETypeFlags::ImmCheckShiftRightNarrow: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, - ElementSizeInBits / 2)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 1, ElementSizeInBits / 2)) HasError = true; break; case SVETypeFlags::ImmCheckShiftLeft: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, - ElementSizeInBits - 1)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, ElementSizeInBits - 1)) HasError = true; break; case SVETypeFlags::ImmCheckLaneIndex: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, - (128 / (1 * ElementSizeInBits)) - 1)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, + (128 / (1 * ElementSizeInBits)) - 1)) HasError = true; break; case SVETypeFlags::ImmCheckLaneIndexCompRotate: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, - (128 / (2 * ElementSizeInBits)) - 1)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, + (128 / (2 * ElementSizeInBits)) - 1)) HasError = true; break; case SVETypeFlags::ImmCheckLaneIndexDot: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, - (128 / (4 * ElementSizeInBits)) - 1)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, + (128 / (4 * ElementSizeInBits)) - 1)) HasError = true; break; case SVETypeFlags::ImmCheckComplexRot90_270: @@ -3462,32 +3459,32 @@ bool Sema::ParseSVEImmChecks( HasError = true; break; case SVETypeFlags::ImmCheck0_1: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 1)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 1)) HasError = true; break; case SVETypeFlags::ImmCheck0_2: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 2)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 2)) HasError = true; break; case SVETypeFlags::ImmCheck0_3: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 3)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 3)) HasError = true; break; case SVETypeFlags::ImmCheck0_0: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 0)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 0)) HasError = true; break; case SVETypeFlags::ImmCheck0_15: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 15)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 15)) HasError = true; break; case SVETypeFlags::ImmCheck0_255: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 255)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 0, 255)) HasError = true; break; case SVETypeFlags::ImmCheck2_4_Mul2: - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 2, 4) || - SemaBuiltinConstantArgMultiple(TheCall, ArgNum, 2)) + if (BuiltinConstantArgRange(TheCall, ArgNum, 2, 4) || + BuiltinConstantArgMultiple(TheCall, ArgNum, 2)) HasError = true; break; } @@ -3663,7 +3660,7 @@ bool Sema::CheckNeonBuiltinFunctionCall(const TargetInfo &TI, // the immediate which specifies which variant to emit. unsigned ImmArg = TheCall->getNumArgs()-1; if (mask) { - if (SemaBuiltinConstantArg(TheCall, ImmArg, Result)) + if (BuiltinConstantArg(TheCall, ImmArg, Result)) return true; TV = Result.getLimitedValue(64); @@ -3711,7 +3708,7 @@ bool Sema::CheckNeonBuiltinFunctionCall(const TargetInfo &TI, #undef GET_NEON_IMMEDIATE_CHECK } - return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); + return BuiltinConstantArgRange(TheCall, i, l, u + l); } bool Sema::CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { @@ -3885,19 +3882,19 @@ bool Sema::CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, } if (BuiltinID == ARM::BI__builtin_arm_prefetch) { - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 1); + return BuiltinConstantArgRange(TheCall, 1, 0, 1) || + BuiltinConstantArgRange(TheCall, 2, 0, 1); } if (BuiltinID == ARM::BI__builtin_arm_rsr64 || BuiltinID == ARM::BI__builtin_arm_wsr64) - return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, false); + return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 3, false); if (BuiltinID == ARM::BI__builtin_arm_rsr || BuiltinID == ARM::BI__builtin_arm_rsrp || BuiltinID == ARM::BI__builtin_arm_wsr || BuiltinID == ARM::BI__builtin_arm_wsrp) - return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall)) return true; @@ -3912,21 +3909,21 @@ bool Sema::CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, switch (BuiltinID) { default: return false; case ARM::BI__builtin_arm_ssat: - return SemaBuiltinConstantArgRange(TheCall, 1, 1, 32); + return BuiltinConstantArgRange(TheCall, 1, 1, 32); case ARM::BI__builtin_arm_usat: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + return BuiltinConstantArgRange(TheCall, 1, 0, 31); case ARM::BI__builtin_arm_ssat16: - return SemaBuiltinConstantArgRange(TheCall, 1, 1, 16); + return BuiltinConstantArgRange(TheCall, 1, 1, 16); case ARM::BI__builtin_arm_usat16: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 15); case ARM::BI__builtin_arm_vcvtr_f: case ARM::BI__builtin_arm_vcvtr_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); + return BuiltinConstantArgRange(TheCall, 1, 0, 1); case ARM::BI__builtin_arm_dmb: case ARM::BI__builtin_arm_dsb: case ARM::BI__builtin_arm_isb: case ARM::BI__builtin_arm_dbg: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 15); + return BuiltinConstantArgRange(TheCall, 0, 0, 15); case ARM::BI__builtin_arm_cdp: case ARM::BI__builtin_arm_cdp2: case ARM::BI__builtin_arm_mcr: @@ -3945,7 +3942,7 @@ bool Sema::CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case ARM::BI__builtin_arm_stcl: case ARM::BI__builtin_arm_stc2: case ARM::BI__builtin_arm_stc2l: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 15) || + return BuiltinConstantArgRange(TheCall, 0, 0, 15) || CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), /*WantCDE*/ false); } @@ -3962,17 +3959,17 @@ bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, } if (BuiltinID == AArch64::BI__builtin_arm_prefetch) { - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 1) || - SemaBuiltinConstantArgRange(TheCall, 4, 0, 1); + return BuiltinConstantArgRange(TheCall, 1, 0, 1) || + BuiltinConstantArgRange(TheCall, 2, 0, 3) || + BuiltinConstantArgRange(TheCall, 3, 0, 1) || + BuiltinConstantArgRange(TheCall, 4, 0, 1); } if (BuiltinID == AArch64::BI__builtin_arm_rsr64 || BuiltinID == AArch64::BI__builtin_arm_wsr64 || BuiltinID == AArch64::BI__builtin_arm_rsr128 || BuiltinID == AArch64::BI__builtin_arm_wsr128) - return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); // Memory Tagging Extensions (MTE) Intrinsics if (BuiltinID == AArch64::BI__builtin_arm_irg || @@ -3981,27 +3978,27 @@ bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, BuiltinID == AArch64::BI__builtin_arm_ldg || BuiltinID == AArch64::BI__builtin_arm_stg || BuiltinID == AArch64::BI__builtin_arm_subp) { - return SemaBuiltinARMMemoryTaggingCall(BuiltinID, TheCall); + return BuiltinARMMemoryTaggingCall(BuiltinID, TheCall); } if (BuiltinID == AArch64::BI__builtin_arm_rsr || BuiltinID == AArch64::BI__builtin_arm_rsrp || BuiltinID == AArch64::BI__builtin_arm_wsr || BuiltinID == AArch64::BI__builtin_arm_wsrp) - return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); + return BuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); // Only check the valid encoding range. Any constant in this range would be // converted to a register of the form S1_2_C3_C4_5. Let the hardware throw // an exception for incorrect registers. This matches MSVC behavior. if (BuiltinID == AArch64::BI_ReadStatusReg || BuiltinID == AArch64::BI_WriteStatusReg) - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 0x7fff); + return BuiltinConstantArgRange(TheCall, 0, 0, 0x7fff); if (BuiltinID == AArch64::BI__getReg) - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31); + return BuiltinConstantArgRange(TheCall, 0, 0, 31); if (BuiltinID == AArch64::BI__break) - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 0xffff); + return BuiltinConstantArgRange(TheCall, 0, 0, 0xffff); if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall)) return true; @@ -4023,7 +4020,7 @@ bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, case AArch64::BI__builtin_arm_tcancel: l = 0; u = 65535; break; } - return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); + return BuiltinConstantArgRange(TheCall, i, l, u + l); } static bool isValidBPFPreserveFieldInfoArg(Expr *Arg) { @@ -4422,13 +4419,13 @@ bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { int32_t Min = A.IsSigned ? -(1 << (A.BitWidth - 1)) : 0; int32_t Max = (1 << (A.IsSigned ? A.BitWidth - 1 : A.BitWidth)) - 1; if (!A.Align) { - Error |= SemaBuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); + Error |= BuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); } else { unsigned M = 1 << A.Align; Min *= M; Max *= M; - Error |= SemaBuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); - Error |= SemaBuiltinConstantArgMultiple(TheCall, A.OpNum, M); + Error |= BuiltinConstantArgRange(TheCall, A.OpNum, Min, Max); + Error |= BuiltinConstantArgMultiple(TheCall, A.OpNum, M); } } return Error; @@ -4448,9 +4445,8 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, // Basic intrinsics. case LoongArch::BI__builtin_loongarch_cacop_d: case LoongArch::BI__builtin_loongarch_cacop_w: { - SemaBuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(5)); - SemaBuiltinConstantArgRange(TheCall, 2, llvm::minIntN(12), - llvm::maxIntN(12)); + BuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(5)); + BuiltinConstantArgRange(TheCall, 2, llvm::minIntN(12), llvm::maxIntN(12)); break; } case LoongArch::BI__builtin_loongarch_break: @@ -4458,22 +4454,22 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_loongarch_ibar: case LoongArch::BI__builtin_loongarch_syscall: // Check if immediate is in [0, 32767]. - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 32767); + return BuiltinConstantArgRange(TheCall, 0, 0, 32767); case LoongArch::BI__builtin_loongarch_csrrd_w: case LoongArch::BI__builtin_loongarch_csrrd_d: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 16383); + return BuiltinConstantArgRange(TheCall, 0, 0, 16383); case LoongArch::BI__builtin_loongarch_csrwr_w: case LoongArch::BI__builtin_loongarch_csrwr_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 16383); + return BuiltinConstantArgRange(TheCall, 1, 0, 16383); case LoongArch::BI__builtin_loongarch_csrxchg_w: case LoongArch::BI__builtin_loongarch_csrxchg_d: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 16383); + return BuiltinConstantArgRange(TheCall, 2, 0, 16383); case LoongArch::BI__builtin_loongarch_lddir_d: case LoongArch::BI__builtin_loongarch_ldpte_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + return BuiltinConstantArgRange(TheCall, 1, 0, 31); case LoongArch::BI__builtin_loongarch_movfcsr2gr: case LoongArch::BI__builtin_loongarch_movgr2fcsr: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(2)); + return BuiltinConstantArgRange(TheCall, 0, 0, llvm::maxUIntN(2)); // LSX intrinsics. case LoongArch::BI__builtin_lsx_vbitclri_b: @@ -4489,7 +4485,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vsllwil_hu_bu: case LoongArch::BI__builtin_lsx_vrotri_b: case LoongArch::BI__builtin_lsx_vsrlri_b: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 7); + return BuiltinConstantArgRange(TheCall, 1, 0, 7); case LoongArch::BI__builtin_lsx_vbitclri_h: case LoongArch::BI__builtin_lsx_vbitrevi_h: case LoongArch::BI__builtin_lsx_vbitseti_h: @@ -4503,7 +4499,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vsllwil_wu_hu: case LoongArch::BI__builtin_lsx_vrotri_h: case LoongArch::BI__builtin_lsx_vsrlri_h: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 15); case LoongArch::BI__builtin_lsx_vssrarni_b_h: case LoongArch::BI__builtin_lsx_vssrarni_bu_h: case LoongArch::BI__builtin_lsx_vssrani_b_h: @@ -4516,7 +4512,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vssrlrni_b_h: case LoongArch::BI__builtin_lsx_vssrlrni_bu_h: case LoongArch::BI__builtin_lsx_vsrani_b_h: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); + return BuiltinConstantArgRange(TheCall, 2, 0, 15); case LoongArch::BI__builtin_lsx_vslei_bu: case LoongArch::BI__builtin_lsx_vslei_hu: case LoongArch::BI__builtin_lsx_vslei_wu: @@ -4556,7 +4552,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vbsll_v: case LoongArch::BI__builtin_lsx_vsubi_wu: case LoongArch::BI__builtin_lsx_vsubi_du: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + return BuiltinConstantArgRange(TheCall, 1, 0, 31); case LoongArch::BI__builtin_lsx_vssrarni_h_w: case LoongArch::BI__builtin_lsx_vssrarni_hu_w: case LoongArch::BI__builtin_lsx_vssrani_h_w: @@ -4571,7 +4567,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vssrlni_hu_w: case LoongArch::BI__builtin_lsx_vssrlrni_h_w: case LoongArch::BI__builtin_lsx_vssrlrni_hu_w: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + return BuiltinConstantArgRange(TheCall, 2, 0, 31); case LoongArch::BI__builtin_lsx_vbitclri_d: case LoongArch::BI__builtin_lsx_vbitrevi_d: case LoongArch::BI__builtin_lsx_vbitseti_d: @@ -4583,7 +4579,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vsrari_d: case LoongArch::BI__builtin_lsx_vrotri_d: case LoongArch::BI__builtin_lsx_vsrlri_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 63); + return BuiltinConstantArgRange(TheCall, 1, 0, 63); case LoongArch::BI__builtin_lsx_vssrarni_w_d: case LoongArch::BI__builtin_lsx_vssrarni_wu_d: case LoongArch::BI__builtin_lsx_vssrani_w_d: @@ -4596,7 +4592,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vssrlrni_w_d: case LoongArch::BI__builtin_lsx_vssrlrni_wu_d: case LoongArch::BI__builtin_lsx_vsrani_w_d: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 63); + return BuiltinConstantArgRange(TheCall, 2, 0, 63); case LoongArch::BI__builtin_lsx_vssrarni_d_q: case LoongArch::BI__builtin_lsx_vssrarni_du_q: case LoongArch::BI__builtin_lsx_vssrani_d_q: @@ -4609,7 +4605,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vsrani_d_q: case LoongArch::BI__builtin_lsx_vsrlrni_d_q: case LoongArch::BI__builtin_lsx_vsrlni_d_q: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 127); + return BuiltinConstantArgRange(TheCall, 2, 0, 127); case LoongArch::BI__builtin_lsx_vseqi_b: case LoongArch::BI__builtin_lsx_vseqi_h: case LoongArch::BI__builtin_lsx_vseqi_w: @@ -4630,7 +4626,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vmini_h: case LoongArch::BI__builtin_lsx_vmini_w: case LoongArch::BI__builtin_lsx_vmini_d: - return SemaBuiltinConstantArgRange(TheCall, 1, -16, 15); + return BuiltinConstantArgRange(TheCall, 1, -16, 15); case LoongArch::BI__builtin_lsx_vandi_b: case LoongArch::BI__builtin_lsx_vnori_b: case LoongArch::BI__builtin_lsx_vori_b: @@ -4638,7 +4634,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vshuf4i_h: case LoongArch::BI__builtin_lsx_vshuf4i_w: case LoongArch::BI__builtin_lsx_vxori_b: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 255); + return BuiltinConstantArgRange(TheCall, 1, 0, 255); case LoongArch::BI__builtin_lsx_vbitseli_b: case LoongArch::BI__builtin_lsx_vshuf4i_d: case LoongArch::BI__builtin_lsx_vextrins_b: @@ -4646,61 +4642,61 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lsx_vextrins_w: case LoongArch::BI__builtin_lsx_vextrins_d: case LoongArch::BI__builtin_lsx_vpermi_w: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 255); + return BuiltinConstantArgRange(TheCall, 2, 0, 255); case LoongArch::BI__builtin_lsx_vpickve2gr_b: case LoongArch::BI__builtin_lsx_vpickve2gr_bu: case LoongArch::BI__builtin_lsx_vreplvei_b: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 15); case LoongArch::BI__builtin_lsx_vinsgr2vr_b: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); + return BuiltinConstantArgRange(TheCall, 2, 0, 15); case LoongArch::BI__builtin_lsx_vpickve2gr_h: case LoongArch::BI__builtin_lsx_vpickve2gr_hu: case LoongArch::BI__builtin_lsx_vreplvei_h: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 7); + return BuiltinConstantArgRange(TheCall, 1, 0, 7); case LoongArch::BI__builtin_lsx_vinsgr2vr_h: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 7); + return BuiltinConstantArgRange(TheCall, 2, 0, 7); case LoongArch::BI__builtin_lsx_vpickve2gr_w: case LoongArch::BI__builtin_lsx_vpickve2gr_wu: case LoongArch::BI__builtin_lsx_vreplvei_w: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3); + return BuiltinConstantArgRange(TheCall, 1, 0, 3); case LoongArch::BI__builtin_lsx_vinsgr2vr_w: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3); + return BuiltinConstantArgRange(TheCall, 2, 0, 3); case LoongArch::BI__builtin_lsx_vpickve2gr_d: case LoongArch::BI__builtin_lsx_vpickve2gr_du: case LoongArch::BI__builtin_lsx_vreplvei_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); + return BuiltinConstantArgRange(TheCall, 1, 0, 1); case LoongArch::BI__builtin_lsx_vinsgr2vr_d: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 1); + return BuiltinConstantArgRange(TheCall, 2, 0, 1); case LoongArch::BI__builtin_lsx_vstelm_b: - return SemaBuiltinConstantArgRange(TheCall, 2, -128, 127) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 15); + return BuiltinConstantArgRange(TheCall, 2, -128, 127) || + BuiltinConstantArgRange(TheCall, 3, 0, 15); case LoongArch::BI__builtin_lsx_vstelm_h: - return SemaBuiltinConstantArgRange(TheCall, 2, -256, 254) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 7); + return BuiltinConstantArgRange(TheCall, 2, -256, 254) || + BuiltinConstantArgRange(TheCall, 3, 0, 7); case LoongArch::BI__builtin_lsx_vstelm_w: - return SemaBuiltinConstantArgRange(TheCall, 2, -512, 508) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 3); + return BuiltinConstantArgRange(TheCall, 2, -512, 508) || + BuiltinConstantArgRange(TheCall, 3, 0, 3); case LoongArch::BI__builtin_lsx_vstelm_d: - return SemaBuiltinConstantArgRange(TheCall, 2, -1024, 1016) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 1); + return BuiltinConstantArgRange(TheCall, 2, -1024, 1016) || + BuiltinConstantArgRange(TheCall, 3, 0, 1); case LoongArch::BI__builtin_lsx_vldrepl_b: case LoongArch::BI__builtin_lsx_vld: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2047); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2047); case LoongArch::BI__builtin_lsx_vldrepl_h: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2046); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2046); case LoongArch::BI__builtin_lsx_vldrepl_w: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2044); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2044); case LoongArch::BI__builtin_lsx_vldrepl_d: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2040); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2040); case LoongArch::BI__builtin_lsx_vst: - return SemaBuiltinConstantArgRange(TheCall, 2, -2048, 2047); + return BuiltinConstantArgRange(TheCall, 2, -2048, 2047); case LoongArch::BI__builtin_lsx_vldi: - return SemaBuiltinConstantArgRange(TheCall, 0, -4096, 4095); + return BuiltinConstantArgRange(TheCall, 0, -4096, 4095); case LoongArch::BI__builtin_lsx_vrepli_b: case LoongArch::BI__builtin_lsx_vrepli_h: case LoongArch::BI__builtin_lsx_vrepli_w: case LoongArch::BI__builtin_lsx_vrepli_d: - return SemaBuiltinConstantArgRange(TheCall, 0, -512, 511); + return BuiltinConstantArgRange(TheCall, 0, -512, 511); // LASX intrinsics. case LoongArch::BI__builtin_lasx_xvbitclri_b: @@ -4716,7 +4712,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvsllwil_hu_bu: case LoongArch::BI__builtin_lasx_xvrotri_b: case LoongArch::BI__builtin_lasx_xvsrlri_b: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 7); + return BuiltinConstantArgRange(TheCall, 1, 0, 7); case LoongArch::BI__builtin_lasx_xvbitclri_h: case LoongArch::BI__builtin_lasx_xvbitrevi_h: case LoongArch::BI__builtin_lasx_xvbitseti_h: @@ -4730,7 +4726,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvsllwil_wu_hu: case LoongArch::BI__builtin_lasx_xvrotri_h: case LoongArch::BI__builtin_lasx_xvsrlri_h: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 15); case LoongArch::BI__builtin_lasx_xvssrarni_b_h: case LoongArch::BI__builtin_lasx_xvssrarni_bu_h: case LoongArch::BI__builtin_lasx_xvssrani_b_h: @@ -4743,7 +4739,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvssrlrni_b_h: case LoongArch::BI__builtin_lasx_xvssrlrni_bu_h: case LoongArch::BI__builtin_lasx_xvsrani_b_h: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); + return BuiltinConstantArgRange(TheCall, 2, 0, 15); case LoongArch::BI__builtin_lasx_xvslei_bu: case LoongArch::BI__builtin_lasx_xvslei_hu: case LoongArch::BI__builtin_lasx_xvslei_wu: @@ -4783,7 +4779,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvsubi_du: case LoongArch::BI__builtin_lasx_xvbsrl_v: case LoongArch::BI__builtin_lasx_xvbsll_v: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + return BuiltinConstantArgRange(TheCall, 1, 0, 31); case LoongArch::BI__builtin_lasx_xvssrarni_h_w: case LoongArch::BI__builtin_lasx_xvssrarni_hu_w: case LoongArch::BI__builtin_lasx_xvssrani_h_w: @@ -4798,7 +4794,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvssrlni_hu_w: case LoongArch::BI__builtin_lasx_xvssrlrni_h_w: case LoongArch::BI__builtin_lasx_xvssrlrni_hu_w: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + return BuiltinConstantArgRange(TheCall, 2, 0, 31); case LoongArch::BI__builtin_lasx_xvbitclri_d: case LoongArch::BI__builtin_lasx_xvbitrevi_d: case LoongArch::BI__builtin_lasx_xvbitseti_d: @@ -4810,7 +4806,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvsrari_d: case LoongArch::BI__builtin_lasx_xvrotri_d: case LoongArch::BI__builtin_lasx_xvsrlri_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 63); + return BuiltinConstantArgRange(TheCall, 1, 0, 63); case LoongArch::BI__builtin_lasx_xvssrarni_w_d: case LoongArch::BI__builtin_lasx_xvssrarni_wu_d: case LoongArch::BI__builtin_lasx_xvssrani_w_d: @@ -4823,7 +4819,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvssrlrni_w_d: case LoongArch::BI__builtin_lasx_xvssrlrni_wu_d: case LoongArch::BI__builtin_lasx_xvsrani_w_d: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 63); + return BuiltinConstantArgRange(TheCall, 2, 0, 63); case LoongArch::BI__builtin_lasx_xvssrarni_d_q: case LoongArch::BI__builtin_lasx_xvssrarni_du_q: case LoongArch::BI__builtin_lasx_xvssrani_d_q: @@ -4836,7 +4832,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvsrani_d_q: case LoongArch::BI__builtin_lasx_xvsrlni_d_q: case LoongArch::BI__builtin_lasx_xvsrlrni_d_q: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 127); + return BuiltinConstantArgRange(TheCall, 2, 0, 127); case LoongArch::BI__builtin_lasx_xvseqi_b: case LoongArch::BI__builtin_lasx_xvseqi_h: case LoongArch::BI__builtin_lasx_xvseqi_w: @@ -4857,7 +4853,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvmini_h: case LoongArch::BI__builtin_lasx_xvmini_w: case LoongArch::BI__builtin_lasx_xvmini_d: - return SemaBuiltinConstantArgRange(TheCall, 1, -16, 15); + return BuiltinConstantArgRange(TheCall, 1, -16, 15); case LoongArch::BI__builtin_lasx_xvandi_b: case LoongArch::BI__builtin_lasx_xvnori_b: case LoongArch::BI__builtin_lasx_xvori_b: @@ -4866,7 +4862,7 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvshuf4i_w: case LoongArch::BI__builtin_lasx_xvxori_b: case LoongArch::BI__builtin_lasx_xvpermi_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 255); + return BuiltinConstantArgRange(TheCall, 1, 0, 255); case LoongArch::BI__builtin_lasx_xvbitseli_b: case LoongArch::BI__builtin_lasx_xvshuf4i_d: case LoongArch::BI__builtin_lasx_xvextrins_b: @@ -4875,59 +4871,59 @@ bool Sema::CheckLoongArchBuiltinFunctionCall(const TargetInfo &TI, case LoongArch::BI__builtin_lasx_xvextrins_d: case LoongArch::BI__builtin_lasx_xvpermi_q: case LoongArch::BI__builtin_lasx_xvpermi_w: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 255); + return BuiltinConstantArgRange(TheCall, 2, 0, 255); case LoongArch::BI__builtin_lasx_xvrepl128vei_b: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 15); case LoongArch::BI__builtin_lasx_xvrepl128vei_h: case LoongArch::BI__builtin_lasx_xvpickve2gr_w: case LoongArch::BI__builtin_lasx_xvpickve2gr_wu: case LoongArch::BI__builtin_lasx_xvpickve_w_f: case LoongArch::BI__builtin_lasx_xvpickve_w: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 7); + return BuiltinConstantArgRange(TheCall, 1, 0, 7); case LoongArch::BI__builtin_lasx_xvinsgr2vr_w: case LoongArch::BI__builtin_lasx_xvinsve0_w: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 7); + return BuiltinConstantArgRange(TheCall, 2, 0, 7); case LoongArch::BI__builtin_lasx_xvrepl128vei_w: case LoongArch::BI__builtin_lasx_xvpickve2gr_d: case LoongArch::BI__builtin_lasx_xvpickve2gr_du: case LoongArch::BI__builtin_lasx_xvpickve_d_f: case LoongArch::BI__builtin_lasx_xvpickve_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3); + return BuiltinConstantArgRange(TheCall, 1, 0, 3); case LoongArch::BI__builtin_lasx_xvinsve0_d: case LoongArch::BI__builtin_lasx_xvinsgr2vr_d: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3); + return BuiltinConstantArgRange(TheCall, 2, 0, 3); case LoongArch::BI__builtin_lasx_xvstelm_b: - return SemaBuiltinConstantArgRange(TheCall, 2, -128, 127) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 31); + return BuiltinConstantArgRange(TheCall, 2, -128, 127) || + BuiltinConstantArgRange(TheCall, 3, 0, 31); case LoongArch::BI__builtin_lasx_xvstelm_h: - return SemaBuiltinConstantArgRange(TheCall, 2, -256, 254) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 15); + return BuiltinConstantArgRange(TheCall, 2, -256, 254) || + BuiltinConstantArgRange(TheCall, 3, 0, 15); case LoongArch::BI__builtin_lasx_xvstelm_w: - return SemaBuiltinConstantArgRange(TheCall, 2, -512, 508) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 7); + return BuiltinConstantArgRange(TheCall, 2, -512, 508) || + BuiltinConstantArgRange(TheCall, 3, 0, 7); case LoongArch::BI__builtin_lasx_xvstelm_d: - return SemaBuiltinConstantArgRange(TheCall, 2, -1024, 1016) || - SemaBuiltinConstantArgRange(TheCall, 3, 0, 3); + return BuiltinConstantArgRange(TheCall, 2, -1024, 1016) || + BuiltinConstantArgRange(TheCall, 3, 0, 3); case LoongArch::BI__builtin_lasx_xvrepl128vei_d: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); + return BuiltinConstantArgRange(TheCall, 1, 0, 1); case LoongArch::BI__builtin_lasx_xvldrepl_b: case LoongArch::BI__builtin_lasx_xvld: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2047); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2047); case LoongArch::BI__builtin_lasx_xvldrepl_h: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2046); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2046); case LoongArch::BI__builtin_lasx_xvldrepl_w: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2044); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2044); case LoongArch::BI__builtin_lasx_xvldrepl_d: - return SemaBuiltinConstantArgRange(TheCall, 1, -2048, 2040); + return BuiltinConstantArgRange(TheCall, 1, -2048, 2040); case LoongArch::BI__builtin_lasx_xvst: - return SemaBuiltinConstantArgRange(TheCall, 2, -2048, 2047); + return BuiltinConstantArgRange(TheCall, 2, -2048, 2047); case LoongArch::BI__builtin_lasx_xvldi: - return SemaBuiltinConstantArgRange(TheCall, 0, -4096, 4095); + return BuiltinConstantArgRange(TheCall, 0, -4096, 4095); case LoongArch::BI__builtin_lasx_xvrepli_b: case LoongArch::BI__builtin_lasx_xvrepli_h: case LoongArch::BI__builtin_lasx_xvrepli_w: case LoongArch::BI__builtin_lasx_xvrepli_d: - return SemaBuiltinConstantArgRange(TheCall, 0, -512, 511); + return BuiltinConstantArgRange(TheCall, 0, -512, 511); } return false; } @@ -5143,10 +5139,10 @@ bool Sema::CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { } if (!m) - return SemaBuiltinConstantArgRange(TheCall, i, l, u); + return BuiltinConstantArgRange(TheCall, i, l, u); - return SemaBuiltinConstantArgRange(TheCall, i, l, u) || - SemaBuiltinConstantArgMultiple(TheCall, i, m); + return BuiltinConstantArgRange(TheCall, i, l, u) || + BuiltinConstantArgMultiple(TheCall, i, m); } /// DecodePPCMMATypeFromStr - This decodes one PPC MMA type descriptor from Str, @@ -5236,7 +5232,6 @@ static bool isPPC_64Builtin(unsigned BuiltinID) { case PPC::BI__builtin_ppc_fetch_and_andlp: case PPC::BI__builtin_ppc_fetch_and_orlp: case PPC::BI__builtin_ppc_fetch_and_swaplp: - case PPC::BI__builtin_ppc_rldimi: return true; } return false; @@ -5246,7 +5241,7 @@ static bool isPPC_64Builtin(unsigned BuiltinID) { /// number of 0s on either side. The 1s are allowed to wrap from LSB to MSB, so /// 0x000FFF0, 0x0000FFFF, 0xFF0000FF, 0x0 are all runs. 0x0F0F0000 is not, /// since all 1s are not contiguous. -bool Sema::SemaValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum) { +bool Sema::ValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum) { llvm::APSInt Result; // We can't check the value of a dependent argument. Expr *Arg = TheCall->getArg(ArgNum); @@ -5254,7 +5249,7 @@ bool Sema::SemaValueIsRunOfOnes(CallExpr *TheCall, unsigned ArgNum) { return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; // Check contiguous run of 1s, 0xFF0000FF is also a run of 1s. @@ -5280,27 +5275,27 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, default: return false; case PPC::BI__builtin_altivec_crypto_vshasigmaw: case PPC::BI__builtin_altivec_crypto_vshasigmad: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 1) || + BuiltinConstantArgRange(TheCall, 2, 0, 15); case PPC::BI__builtin_altivec_dss: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3); + return BuiltinConstantArgRange(TheCall, 0, 0, 3); case PPC::BI__builtin_tbegin: case PPC::BI__builtin_tend: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1); + return BuiltinConstantArgRange(TheCall, 0, 0, 1); case PPC::BI__builtin_tsr: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 7); + return BuiltinConstantArgRange(TheCall, 0, 0, 7); case PPC::BI__builtin_tabortwc: case PPC::BI__builtin_tabortdc: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31); + return BuiltinConstantArgRange(TheCall, 0, 0, 31); case PPC::BI__builtin_tabortwci: case PPC::BI__builtin_tabortdci: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + return BuiltinConstantArgRange(TheCall, 0, 0, 31) || + BuiltinConstantArgRange(TheCall, 2, 0, 31); // According to GCC 'Basic PowerPC Built-in Functions Available on ISA 2.05', // __builtin_(un)pack_longdouble are available only if long double uses IBM // extended double representation. case PPC::BI__builtin_unpack_longdouble: - if (SemaBuiltinConstantArgRange(TheCall, 1, 0, 1)) + if (BuiltinConstantArgRange(TheCall, 1, 0, 1)) return true; [[fallthrough]]; case PPC::BI__builtin_pack_longdouble: @@ -5312,39 +5307,39 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, case PPC::BI__builtin_altivec_dstt: case PPC::BI__builtin_altivec_dstst: case PPC::BI__builtin_altivec_dststt: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3); + return BuiltinConstantArgRange(TheCall, 2, 0, 3); case PPC::BI__builtin_vsx_xxpermdi: case PPC::BI__builtin_vsx_xxsldwi: - return SemaBuiltinVSX(TheCall); + return BuiltinVSX(TheCall); case PPC::BI__builtin_unpack_vector_int128: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); + return BuiltinConstantArgRange(TheCall, 1, 0, 1); case PPC::BI__builtin_altivec_vgnb: - return SemaBuiltinConstantArgRange(TheCall, 1, 2, 7); + return BuiltinConstantArgRange(TheCall, 1, 2, 7); case PPC::BI__builtin_vsx_xxeval: - return SemaBuiltinConstantArgRange(TheCall, 3, 0, 255); + return BuiltinConstantArgRange(TheCall, 3, 0, 255); case PPC::BI__builtin_altivec_vsldbi: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 7); + return BuiltinConstantArgRange(TheCall, 2, 0, 7); case PPC::BI__builtin_altivec_vsrdbi: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 7); + return BuiltinConstantArgRange(TheCall, 2, 0, 7); case PPC::BI__builtin_vsx_xxpermx: - return SemaBuiltinConstantArgRange(TheCall, 3, 0, 7); + return BuiltinConstantArgRange(TheCall, 3, 0, 7); case PPC::BI__builtin_ppc_tw: case PPC::BI__builtin_ppc_tdw: - return SemaBuiltinConstantArgRange(TheCall, 2, 1, 31); + return BuiltinConstantArgRange(TheCall, 2, 1, 31); case PPC::BI__builtin_ppc_cmprb: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1); + return BuiltinConstantArgRange(TheCall, 0, 0, 1); // For __rlwnm, __rlwimi and __rldimi, the last parameter mask must // be a constant that represents a contiguous bit field. case PPC::BI__builtin_ppc_rlwnm: - return SemaValueIsRunOfOnes(TheCall, 2); + return ValueIsRunOfOnes(TheCall, 2); case PPC::BI__builtin_ppc_rlwimi: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 31) || - SemaValueIsRunOfOnes(TheCall, 3); + return BuiltinConstantArgRange(TheCall, 2, 0, 31) || + ValueIsRunOfOnes(TheCall, 3); case PPC::BI__builtin_ppc_rldimi: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 63) || - SemaValueIsRunOfOnes(TheCall, 3); + return BuiltinConstantArgRange(TheCall, 2, 0, 63) || + ValueIsRunOfOnes(TheCall, 3); case PPC::BI__builtin_ppc_addex: { - if (SemaBuiltinConstantArgRange(TheCall, 2, 0, 3)) + if (BuiltinConstantArgRange(TheCall, 2, 0, 3)) return true; // Output warning for reserved values 1 to 3. int ArgValue = @@ -5356,29 +5351,29 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, } case PPC::BI__builtin_ppc_mtfsb0: case PPC::BI__builtin_ppc_mtfsb1: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31); + return BuiltinConstantArgRange(TheCall, 0, 0, 31); case PPC::BI__builtin_ppc_mtfsf: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 255); + return BuiltinConstantArgRange(TheCall, 0, 0, 255); case PPC::BI__builtin_ppc_mtfsfi: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 7) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + return BuiltinConstantArgRange(TheCall, 0, 0, 7) || + BuiltinConstantArgRange(TheCall, 1, 0, 15); case PPC::BI__builtin_ppc_alignx: - return SemaBuiltinConstantArgPower2(TheCall, 0); + return BuiltinConstantArgPower2(TheCall, 0); case PPC::BI__builtin_ppc_rdlam: - return SemaValueIsRunOfOnes(TheCall, 2); + return ValueIsRunOfOnes(TheCall, 2); case PPC::BI__builtin_vsx_ldrmb: case PPC::BI__builtin_vsx_strmb: - return SemaBuiltinConstantArgRange(TheCall, 1, 1, 16); + return BuiltinConstantArgRange(TheCall, 1, 1, 16); case PPC::BI__builtin_altivec_vcntmbb: case PPC::BI__builtin_altivec_vcntmbh: case PPC::BI__builtin_altivec_vcntmbw: case PPC::BI__builtin_altivec_vcntmbd: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); + return BuiltinConstantArgRange(TheCall, 1, 0, 1); case PPC::BI__builtin_vsx_xxgenpcvbm: case PPC::BI__builtin_vsx_xxgenpcvhm: case PPC::BI__builtin_vsx_xxgenpcvwm: case PPC::BI__builtin_vsx_xxgenpcvdm: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3); + return BuiltinConstantArgRange(TheCall, 1, 0, 3); case PPC::BI__builtin_ppc_test_data_class: { // Check if the first argument of the __builtin_ppc_test_data_class call is // valid. The argument must be 'float' or 'double' or '__float128'. @@ -5388,7 +5383,7 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, ArgType != QualType(Context.Float128Ty)) return Diag(TheCall->getBeginLoc(), diag::err_ppc_invalid_test_data_class_type); - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 127); + return BuiltinConstantArgRange(TheCall, 1, 0, 127); } case PPC::BI__builtin_ppc_maxfe: case PPC::BI__builtin_ppc_minfe: @@ -5417,12 +5412,12 @@ bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, << TheCall->getArg(I)->getType() << ArgType << 1 << 0 << 0; return false; } -#define CUSTOM_BUILTIN(Name, Intr, Types, Acc, Feature) \ +#define CUSTOM_BUILTIN(Name, Intr, Types, Acc, Feature) \ case PPC::BI__builtin_##Name: \ - return SemaBuiltinPPCMMACall(TheCall, BuiltinID, Types); + return BuiltinPPCMMACall(TheCall, BuiltinID, Types); #include "clang/Basic/BuiltinsPPC.def" } - return SemaBuiltinConstantArgRange(TheCall, i, l, u); + return BuiltinConstantArgRange(TheCall, i, l, u); } // Check if the given type is a non-pointer PPC MMA type. This function is used @@ -5541,6 +5536,14 @@ bool CheckNoDoubleVectors(Sema *S, CallExpr *TheCall) { checkDoubleVector); } +bool CheckUnsignedIntRepresentation(Sema *S, CallExpr *TheCall) { + auto checkAllUnsignedTypes = [](clang::QualType PassedType) -> bool { + return !PassedType->hasUnsignedIntegerRepresentation(); + }; + return CheckArgsTypesAreCorrect(S, TheCall, S->Context.UnsignedIntTy, + checkAllUnsignedTypes); +} + void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, QualType ReturnType) { auto *VecTyA = TheCall->getArg(0)->getType()->getAs(); @@ -5554,6 +5557,7 @@ void SetElementTypeAsReturnType(Sema *S, CallExpr *TheCall, // returning an ExprError bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { switch (BuiltinID) { + case Builtin::BI__builtin_hlsl_elementwise_all: case Builtin::BI__builtin_hlsl_elementwise_any: { if (checkArgCount(*this, TheCall, 1)) return true; @@ -5564,7 +5568,7 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return true; if (CheckVectorElementCallArgs(this, TheCall)) return true; - if (SemaBuiltinElementwiseTernaryMath( + if (BuiltinElementwiseTernaryMath( TheCall, /*CheckForFloatArgs*/ TheCall->getArg(0)->getType()->hasFloatingRepresentation())) return true; @@ -5575,7 +5579,7 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return true; if (CheckVectorElementCallArgs(this, TheCall)) return true; - if (SemaBuiltinVectorToScalarMath(TheCall)) + if (BuiltinVectorToScalarMath(TheCall)) return true; if (CheckNoDoubleVectors(this, TheCall)) return true; @@ -5609,7 +5613,7 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return true; if (CheckVectorElementCallArgs(this, TheCall)) return true; - if (SemaBuiltinElementwiseTernaryMath(TheCall)) + if (BuiltinElementwiseTernaryMath(TheCall)) return true; if (CheckFloatOrHalfRepresentations(this, TheCall)) return true; @@ -5620,10 +5624,35 @@ bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return true; if (CheckVectorElementCallArgs(this, TheCall)) return true; - if (SemaBuiltinElementwiseTernaryMath( + if (BuiltinElementwiseTernaryMath( TheCall, /*CheckForFloatArgs*/ TheCall->getArg(0)->getType()->hasFloatingRepresentation())) return true; + break; + } + // Note these are llvm builtins that we want to catch invalid intrinsic + // generation. Normal handling of these builitns will occur elsewhere. + case Builtin::BI__builtin_elementwise_bitreverse: { + if (CheckUnsignedIntRepresentation(this, TheCall)) + return true; + break; + } + case Builtin::BI__builtin_elementwise_ceil: + case Builtin::BI__builtin_elementwise_cos: + case Builtin::BI__builtin_elementwise_exp: + case Builtin::BI__builtin_elementwise_exp2: + case Builtin::BI__builtin_elementwise_floor: + case Builtin::BI__builtin_elementwise_log: + case Builtin::BI__builtin_elementwise_log2: + case Builtin::BI__builtin_elementwise_log10: + case Builtin::BI__builtin_elementwise_pow: + case Builtin::BI__builtin_elementwise_roundeven: + case Builtin::BI__builtin_elementwise_sin: + case Builtin::BI__builtin_elementwise_sqrt: + case Builtin::BI__builtin_elementwise_trunc: { + if (CheckFloatOrHalfRepresentations(this, TheCall)) + return true; + break; } } return false; @@ -5702,7 +5731,7 @@ bool Sema::CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum) { return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; int64_t Val = Result.getSExtValue(); @@ -5745,57 +5774,6 @@ static bool CheckInvalidVLENandLMUL(const TargetInfo &TI, CallExpr *TheCall, bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, CallExpr *TheCall) { - // CodeGenFunction can also detect this, but this gives a better error - // message. - bool FeatureMissing = false; - SmallVector ReqFeatures; - StringRef Features = Context.BuiltinInfo.getRequiredFeatures(BuiltinID); - Features.split(ReqFeatures, ',', -1, false); - - // Check if each required feature is included - for (StringRef F : ReqFeatures) { - SmallVector ReqOpFeatures; - F.split(ReqOpFeatures, '|'); - - if (llvm::none_of(ReqOpFeatures, - [&TI](StringRef OF) { return TI.hasFeature(OF); })) { - std::string FeatureStrs; - bool IsExtension = true; - for (StringRef OF : ReqOpFeatures) { - // If the feature is 64bit, alter the string so it will print better in - // the diagnostic. - if (OF == "64bit") { - assert(ReqOpFeatures.size() == 1 && "Expected '64bit' to be alone"); - OF = "RV64"; - IsExtension = false; - } - if (OF == "32bit") { - assert(ReqOpFeatures.size() == 1 && "Expected '32bit' to be alone"); - OF = "RV32"; - IsExtension = false; - } - - // Convert features like "zbr" and "experimental-zbr" to "Zbr". - OF.consume_front("experimental-"); - std::string FeatureStr = OF.str(); - FeatureStr[0] = std::toupper(FeatureStr[0]); - // Combine strings. - FeatureStrs += FeatureStrs.empty() ? "" : ", "; - FeatureStrs += "'"; - FeatureStrs += FeatureStr; - FeatureStrs += "'"; - } - // Error message - FeatureMissing = true; - Diag(TheCall->getBeginLoc(), diag::err_riscv_builtin_requires_extension) - << IsExtension - << TheCall->getSourceRange() << StringRef(FeatureStrs); - } - } - - if (FeatureMissing) - return true; - // vmulh.vv, vmulh.vx, vmulhu.vv, vmulhu.vx, vmulhsu.vv, vmulhsu.vx, // vsmul.vv, vsmul.vx are not included for EEW=64 in Zve64*. switch (BuiltinID) { @@ -5863,10 +5841,10 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, switch (BuiltinID) { case RISCVVector::BI__builtin_rvv_vsetvli: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 3) || + return BuiltinConstantArgRange(TheCall, 1, 0, 3) || CheckRISCVLMUL(TheCall, 2); case RISCVVector::BI__builtin_rvv_vsetvlimax: - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || CheckRISCVLMUL(TheCall, 1); case RISCVVector::BI__builtin_rvv_vget_v: { ASTContext::BuiltinVectorTypeInfo ResVecInfo = @@ -5881,7 +5859,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, else // vget for non-tuple type MaxIndex = (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors) / (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors); - return SemaBuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); + return BuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); } case RISCVVector::BI__builtin_rvv_vset_v: { ASTContext::BuiltinVectorTypeInfo ResVecInfo = @@ -5896,7 +5874,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, else // vset fo non-tuple type MaxIndex = (ResVecInfo.EC.getKnownMinValue() * ResVecInfo.NumVectors) / (VecInfo.EC.getKnownMinValue() * VecInfo.NumVectors); - return SemaBuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); + return BuiltinConstantArgRange(TheCall, 1, 0, MaxIndex - 1); } // Vector Crypto case RISCVVector::BI__builtin_rvv_vaeskf1_vi_tu: @@ -5907,19 +5885,19 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, QualType Op2Type = TheCall->getArg(1)->getType(); return CheckInvalidVLENandLMUL(TI, TheCall, *this, Op1Type, 128) || CheckInvalidVLENandLMUL(TI, TheCall, *this, Op2Type, 128) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + BuiltinConstantArgRange(TheCall, 2, 0, 31); } case RISCVVector::BI__builtin_rvv_vsm3c_vi_tu: case RISCVVector::BI__builtin_rvv_vsm3c_vi: { QualType Op1Type = TheCall->getArg(0)->getType(); return CheckInvalidVLENandLMUL(TI, TheCall, *this, Op1Type, 256) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + BuiltinConstantArgRange(TheCall, 2, 0, 31); } case RISCVVector::BI__builtin_rvv_vaeskf1_vi: case RISCVVector::BI__builtin_rvv_vsm4k_vi: { QualType Op1Type = TheCall->getArg(0)->getType(); return CheckInvalidVLENandLMUL(TI, TheCall, *this, Op1Type, 128) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + BuiltinConstantArgRange(TheCall, 1, 0, 31); } case RISCVVector::BI__builtin_rvv_vaesdf_vv: case RISCVVector::BI__builtin_rvv_vaesdf_vs: @@ -5972,27 +5950,27 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_sf_vc_i_se: // bit_27_26, bit_24_20, bit_11_7, simm5, sew, log2lmul - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 31) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 31) || - SemaBuiltinConstantArgRange(TheCall, 3, -16, 15) || + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || + BuiltinConstantArgRange(TheCall, 1, 0, 31) || + BuiltinConstantArgRange(TheCall, 2, 0, 31) || + BuiltinConstantArgRange(TheCall, 3, -16, 15) || CheckRISCVLMUL(TheCall, 5); case RISCVVector::BI__builtin_rvv_sf_vc_iv_se: // bit_27_26, bit_11_7, vs2, simm5 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 31) || - SemaBuiltinConstantArgRange(TheCall, 3, -16, 15); + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || + BuiltinConstantArgRange(TheCall, 1, 0, 31) || + BuiltinConstantArgRange(TheCall, 3, -16, 15); case RISCVVector::BI__builtin_rvv_sf_vc_v_i: case RISCVVector::BI__builtin_rvv_sf_vc_v_i_se: // bit_27_26, bit_24_20, simm5 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 31) || - SemaBuiltinConstantArgRange(TheCall, 2, -16, 15); + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || + BuiltinConstantArgRange(TheCall, 1, 0, 31) || + BuiltinConstantArgRange(TheCall, 2, -16, 15); case RISCVVector::BI__builtin_rvv_sf_vc_v_iv: case RISCVVector::BI__builtin_rvv_sf_vc_v_iv_se: // bit_27_26, vs2, simm5 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 2, -16, 15); + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || + BuiltinConstantArgRange(TheCall, 2, -16, 15); case RISCVVector::BI__builtin_rvv_sf_vc_ivv_se: case RISCVVector::BI__builtin_rvv_sf_vc_ivw_se: case RISCVVector::BI__builtin_rvv_sf_vc_v_ivv: @@ -6000,13 +5978,13 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_sf_vc_v_ivv_se: case RISCVVector::BI__builtin_rvv_sf_vc_v_ivw_se: // bit_27_26, vd, vs2, simm5 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 3, -16, 15); + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || + BuiltinConstantArgRange(TheCall, 3, -16, 15); case RISCVVector::BI__builtin_rvv_sf_vc_x_se: // bit_27_26, bit_24_20, bit_11_7, xs1, sew, log2lmul - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 31) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 31) || + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || + BuiltinConstantArgRange(TheCall, 1, 0, 31) || + BuiltinConstantArgRange(TheCall, 2, 0, 31) || CheckRISCVLMUL(TheCall, 5); case RISCVVector::BI__builtin_rvv_sf_vc_xv_se: case RISCVVector::BI__builtin_rvv_sf_vc_vv_se: @@ -6014,8 +5992,8 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_sf_vc_v_x: case RISCVVector::BI__builtin_rvv_sf_vc_v_x_se: // bit_27_26, bit_24-20, xs1 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + return BuiltinConstantArgRange(TheCall, 0, 0, 3) || + BuiltinConstantArgRange(TheCall, 1, 0, 31); case RISCVVector::BI__builtin_rvv_sf_vc_vvv_se: case RISCVVector::BI__builtin_rvv_sf_vc_xvv_se: case RISCVVector::BI__builtin_rvv_sf_vc_vvw_se: @@ -6035,11 +6013,11 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_sf_vc_v_xvw_se: case RISCVVector::BI__builtin_rvv_sf_vc_v_vvw_se: // bit_27_26, vd, vs2, xs1/vs1 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 3); + return BuiltinConstantArgRange(TheCall, 0, 0, 3); case RISCVVector::BI__builtin_rvv_sf_vc_fv_se: // bit_26, bit_11_7, vs2, fs1 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1) || - SemaBuiltinConstantArgRange(TheCall, 1, 0, 31); + return BuiltinConstantArgRange(TheCall, 0, 0, 1) || + BuiltinConstantArgRange(TheCall, 1, 0, 31); case RISCVVector::BI__builtin_rvv_sf_vc_fvv_se: case RISCVVector::BI__builtin_rvv_sf_vc_fvw_se: case RISCVVector::BI__builtin_rvv_sf_vc_v_fvv: @@ -6050,7 +6028,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_sf_vc_v_fv: case RISCVVector::BI__builtin_rvv_sf_vc_v_fv_se: // bit_26, vs2, fs1 - return SemaBuiltinConstantArgRange(TheCall, 0, 0, 1); + return BuiltinConstantArgRange(TheCall, 0, 0, 1); // Check if byteselect is in [0, 3] case RISCV::BI__builtin_riscv_aes32dsi: case RISCV::BI__builtin_riscv_aes32dsmi: @@ -6058,10 +6036,10 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCV::BI__builtin_riscv_aes32esmi: case RISCV::BI__builtin_riscv_sm4ks: case RISCV::BI__builtin_riscv_sm4ed: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3); + return BuiltinConstantArgRange(TheCall, 2, 0, 3); // Check if rnum is in [0, 10] case RISCV::BI__builtin_riscv_aes64ks1i: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 10); + return BuiltinConstantArgRange(TheCall, 1, 0, 10); // Check if value range for vxrm is in [0, 3] case RISCVVector::BI__builtin_rvv_vaaddu_vv: case RISCVVector::BI__builtin_rvv_vaaddu_vx: @@ -6081,7 +6059,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vnclip_wx: case RISCVVector::BI__builtin_rvv_vnclipu_wv: case RISCVVector::BI__builtin_rvv_vnclipu_wx: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 3); + return BuiltinConstantArgRange(TheCall, 2, 0, 3); case RISCVVector::BI__builtin_rvv_vaaddu_vv_tu: case RISCVVector::BI__builtin_rvv_vaaddu_vx_tu: case RISCVVector::BI__builtin_rvv_vaadd_vv_tu: @@ -6118,7 +6096,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vnclip_wx_m: case RISCVVector::BI__builtin_rvv_vnclipu_wv_m: case RISCVVector::BI__builtin_rvv_vnclipu_wx_m: - return SemaBuiltinConstantArgRange(TheCall, 3, 0, 3); + return BuiltinConstantArgRange(TheCall, 3, 0, 3); case RISCVVector::BI__builtin_rvv_vaaddu_vv_tum: case RISCVVector::BI__builtin_rvv_vaaddu_vv_tumu: case RISCVVector::BI__builtin_rvv_vaaddu_vv_mu: @@ -6173,7 +6151,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vnclip_wx_tumu: case RISCVVector::BI__builtin_rvv_vnclipu_wv_tumu: case RISCVVector::BI__builtin_rvv_vnclipu_wx_tumu: - return SemaBuiltinConstantArgRange(TheCall, 4, 0, 3); + return BuiltinConstantArgRange(TheCall, 4, 0, 3); case RISCVVector::BI__builtin_rvv_vfsqrt_v_rm: case RISCVVector::BI__builtin_rvv_vfrec7_v_rm: case RISCVVector::BI__builtin_rvv_vfcvt_x_f_v_rm: @@ -6187,7 +6165,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm: case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm: case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 4); + return BuiltinConstantArgRange(TheCall, 1, 0, 4); case RISCVVector::BI__builtin_rvv_vfadd_vv_rm: case RISCVVector::BI__builtin_rvv_vfadd_vf_rm: case RISCVVector::BI__builtin_rvv_vfsub_vv_rm: @@ -6238,7 +6216,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_m: case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_m: case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_m: - return SemaBuiltinConstantArgRange(TheCall, 2, 0, 4); + return BuiltinConstantArgRange(TheCall, 2, 0, 4); case RISCVVector::BI__builtin_rvv_vfadd_vv_rm_tu: case RISCVVector::BI__builtin_rvv_vfadd_vf_rm_tu: case RISCVVector::BI__builtin_rvv_vfsub_vv_rm_tu: @@ -6374,7 +6352,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfncvt_f_x_w_rm_mu: case RISCVVector::BI__builtin_rvv_vfncvt_f_xu_w_rm_mu: case RISCVVector::BI__builtin_rvv_vfncvt_f_f_w_rm_mu: - return SemaBuiltinConstantArgRange(TheCall, 3, 0, 4); + return BuiltinConstantArgRange(TheCall, 3, 0, 4); case RISCVVector::BI__builtin_rvv_vfmacc_vv_rm_m: case RISCVVector::BI__builtin_rvv_vfmacc_vf_rm_m: case RISCVVector::BI__builtin_rvv_vfnmacc_vv_rm_m: @@ -6535,7 +6513,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, case RISCVVector::BI__builtin_rvv_vfwmsac_vf_rm_mu: case RISCVVector::BI__builtin_rvv_vfwnmsac_vv_rm_mu: case RISCVVector::BI__builtin_rvv_vfwnmsac_vf_rm_mu: - return SemaBuiltinConstantArgRange(TheCall, 4, 0, 4); + return BuiltinConstantArgRange(TheCall, 4, 0, 4); case RISCV::BI__builtin_riscv_ntl_load: case RISCV::BI__builtin_riscv_ntl_store: DeclRefExpr *DRE = @@ -6555,7 +6533,7 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, // Domain value should be compile-time constant. // 2 <= domain <= 5 if (TheCall->getNumArgs() == NumArgs && - SemaBuiltinConstantArgRange(TheCall, NumArgs - 1, 2, 5)) + BuiltinConstantArgRange(TheCall, NumArgs - 1, 2, 5)) return true; Expr *PointerArg = TheCall->getArg(0); @@ -6639,8 +6617,8 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, case SystemZ::BI__builtin_s390_vfaezfs: i = 2; l = 0; u = 15; break; case SystemZ::BI__builtin_s390_vfisb: case SystemZ::BI__builtin_s390_vfidb: - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15) || - SemaBuiltinConstantArgRange(TheCall, 2, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 15) || + BuiltinConstantArgRange(TheCall, 2, 0, 15); case SystemZ::BI__builtin_s390_vftcisb: case SystemZ::BI__builtin_s390_vftcidb: i = 1; l = 0; u = 4095; break; case SystemZ::BI__builtin_s390_vlbb: i = 1; l = 0; u = 15; break; @@ -6671,7 +6649,7 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, case SystemZ::BI__builtin_s390_vcnf: i = 1; l = 0; u = 15; break; case SystemZ::BI__builtin_s390_vcrnfs: i = 2; l = 0; u = 15; break; } - return SemaBuiltinConstantArgRange(TheCall, i, l, u); + return BuiltinConstantArgRange(TheCall, i, l, u); } bool Sema::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, @@ -6699,36 +6677,35 @@ bool Sema::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI, return false; } -void Sema::checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D) { - const TargetInfo &TI = Context.getTargetInfo(); - +void Sema::checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D, + const llvm::StringMap &FeatureMap) { ASTContext::BuiltinVectorTypeInfo Info = Context.getBuiltinVectorTypeInfo(Ty->castAs()); unsigned EltSize = Context.getTypeSize(Info.ElementType); unsigned MinElts = Info.EC.getKnownMinValue(); if (Info.ElementType->isSpecificBuiltinType(BuiltinType::Double) && - !TI.hasFeature("zve64d")) + !FeatureMap.lookup("zve64d")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve64d"; // (ELEN, LMUL) pairs of (8, mf8), (16, mf4), (32, mf2), (64, m1) requires at // least zve64x else if (((EltSize == 64 && Info.ElementType->isIntegerType()) || MinElts == 1) && - !TI.hasFeature("zve64x")) + !FeatureMap.lookup("zve64x")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve64x"; - else if (Info.ElementType->isFloat16Type() && !TI.hasFeature("zvfh") && - !TI.hasFeature("zvfhmin")) + else if (Info.ElementType->isFloat16Type() && !FeatureMap.lookup("zvfh") && + !FeatureMap.lookup("zvfhmin")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zvfh or zvfhmin"; else if (Info.ElementType->isBFloat16Type() && - !TI.hasFeature("experimental-zvfbfmin")) + !FeatureMap.lookup("experimental-zvfbfmin")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zvfbfmin"; else if (Info.ElementType->isSpecificBuiltinType(BuiltinType::Float) && - !TI.hasFeature("zve32f")) + !FeatureMap.lookup("zve32f")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve32f"; // Given that caller already checked isRVVType() before calling this function, // if we don't have at least zve32x supported, then we need to emit error. - else if (!TI.hasFeature("zve32x")) + else if (!FeatureMap.lookup("zve32x")) Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve32x"; } @@ -7025,7 +7002,7 @@ bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; // Make sure rounding mode is either ROUND_CUR_DIRECTION or ROUND_NO_EXC bit @@ -7135,7 +7112,7 @@ bool Sema::CheckX86BuiltinGatherScatterScale(unsigned BuiltinID, return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; if (Result == 1 || Result == 2 || Result == 4 || Result == 8) @@ -7150,7 +7127,7 @@ enum { TileRegLow = 0, TileRegHigh = 7 }; bool Sema::CheckX86BuiltinTileArgumentsRange(CallExpr *TheCall, ArrayRef ArgNums) { for (int ArgNum : ArgNums) { - if (SemaBuiltinConstantArgRange(TheCall, ArgNum, TileRegLow, TileRegHigh)) + if (BuiltinConstantArgRange(TheCall, ArgNum, TileRegLow, TileRegHigh)) return true; } return false; @@ -7167,7 +7144,7 @@ bool Sema::CheckX86BuiltinTileDuplicate(CallExpr *TheCall, continue; llvm::APSInt Result; - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; int ArgExtValue = Result.getExtValue(); assert((ArgExtValue >= TileRegLow && ArgExtValue <= TileRegHigh) && @@ -7593,7 +7570,7 @@ bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, // template-generated or macro-generated dead code to potentially have out-of- // range values. These need to code generate, but don't need to necessarily // make any sense. We use a warning that defaults to an error. - return SemaBuiltinConstantArgRange(TheCall, i, l, u, /*RangeIsError*/ false); + return BuiltinConstantArgRange(TheCall, i, l, u, /*RangeIsError*/ false); } /// Given a FunctionDecl's FormatAttr, attempts to populate the FomatStringInfo @@ -7629,6 +7606,14 @@ bool Sema::getFormatStringInfo(const FormatAttr *Format, bool IsCXXMember, /// /// Returns true if the value evaluates to null. static bool CheckNonNullExpr(Sema &S, const Expr *Expr) { + // Treat (smart) pointers constructed from nullptr as null, whether we can + // const-evaluate them or not. + // This must happen first: the smart pointer expr might have _Nonnull type! + if (isa( + IgnoreExprNodes(Expr, IgnoreImplicitAsWrittenSingleStep, + IgnoreElidableImplicitConstructorSingleStep))) + return true; + // If the expression has non-null type, it doesn't evaluate to null. if (auto nullability = Expr->IgnoreImplicit()->getType()->getNullability()) { if (*nullability == NullabilityKind::NonNull) @@ -7953,6 +7938,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, // For variadic functions, we may have more args than parameters. // For some K&R functions, we may have less args than parameters. const auto N = std::min(Proto->getNumParams(), Args.size()); + bool AnyScalableArgsOrRet = Proto->getReturnType()->isSizelessVectorType(); for (unsigned ArgIdx = 0; ArgIdx < N; ++ArgIdx) { // Args[ArgIdx] can be null in malformed code. if (const Expr *Arg = Args[ArgIdx]) { @@ -7966,6 +7952,8 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, checkAIXMemberAlignment((Arg->getExprLoc()), Arg); QualType ParamTy = Proto->getParamType(ArgIdx); + if (ParamTy->isSizelessVectorType()) + AnyScalableArgsOrRet = true; QualType ArgTy = Arg->getType(); CheckArgAlignment(Arg->getExprLoc(), FDecl, std::to_string(ArgIdx + 1), ArgTy, ParamTy); @@ -7986,6 +7974,23 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, } } + // If the call requires a streaming-mode change and has scalable vector + // arguments or return values, then warn the user that the streaming and + // non-streaming vector lengths may be different. + const auto *CallerFD = dyn_cast(CurContext); + if (CallerFD && (!FD || !FD->getBuiltinID()) && AnyScalableArgsOrRet) { + bool IsCalleeStreaming = + ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask; + bool IsCalleeStreamingCompatible = + ExtInfo.AArch64SMEAttributes & + FunctionType::SME_PStateSMCompatibleMask; + ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD); + if (!IsCalleeStreamingCompatible && + (CallerFnType == ArmStreamingCompatible || + ((CallerFnType == ArmStreaming) ^ IsCalleeStreaming))) + Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming); + } + FunctionType::ArmStateValue CalleeArmZAState = FunctionType::getArmZAState(ExtInfo.AArch64SMEAttributes); FunctionType::ArmStateValue CalleeArmZT0State = @@ -7994,7 +7999,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, CalleeArmZT0State != FunctionType::ARM_None) { bool CallerHasZAState = false; bool CallerHasZT0State = false; - if (const auto *CallerFD = dyn_cast(CurContext)) { + if (CallerFD) { auto *Attr = CallerFD->getAttr(); if (Attr && Attr->isNewZA()) CallerHasZAState = true; @@ -8246,8 +8251,8 @@ static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) { } } -ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, - AtomicExpr::AtomicOp Op) { +ExprResult Sema::AtomicOpsOverloaded(ExprResult TheCallResult, + AtomicExpr::AtomicOp Op) { CallExpr *TheCall = cast(TheCallResult.get()); DeclRefExpr *DRE =cast(TheCall->getCallee()->IgnoreParenCasts()); MultiExprArg Args{TheCall->getArgs(), TheCall->getNumArgs()}; @@ -8876,8 +8881,7 @@ bool Sema::BuiltinWasmRefNullFunc(CallExpr *TheCall) { /// /// This function goes through and does final semantic checking for these /// builtins, as well as generating any warnings. -ExprResult -Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { +ExprResult Sema::BuiltinAtomicOverloaded(ExprResult TheCallResult) { CallExpr *TheCall = static_cast(TheCallResult.get()); Expr *Callee = TheCall->getCallee(); DeclRefExpr *DRE = cast(Callee->IgnoreParenCasts()); @@ -9248,13 +9252,13 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { return TheCallResult; } -/// SemaBuiltinNontemporalOverloaded - We have a call to +/// BuiltinNontemporalOverloaded - We have a call to /// __builtin_nontemporal_store or __builtin_nontemporal_load, which is an /// overloaded function based on the pointer type of its last argument. /// /// This function goes through and does final semantic checking for these /// builtins. -ExprResult Sema::SemaBuiltinNontemporalOverloaded(ExprResult TheCallResult) { +ExprResult Sema::BuiltinNontemporalOverloaded(ExprResult TheCallResult) { CallExpr *TheCall = (CallExpr *)TheCallResult.get(); DeclRefExpr *DRE = cast(TheCall->getCallee()->IgnoreParenCasts()); @@ -9455,7 +9459,7 @@ static bool checkVAStartIsInVariadicFunction(Sema &S, Expr *Fn, /// Check the arguments to '__builtin_va_start' or '__builtin_ms_va_start' /// for validity. Emit an error and return true on failure; return false /// on success. -bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { +bool Sema::BuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { Expr *Fn = TheCall->getCallee(); if (checkVAStartABI(*this, BuiltinID, Fn)) @@ -9529,7 +9533,7 @@ bool Sema::SemaBuiltinVAStart(unsigned BuiltinID, CallExpr *TheCall) { return false; } -bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) { +bool Sema::BuiltinVAStartARMMicrosoft(CallExpr *Call) { auto IsSuitablyTypedFormatArgument = [this](const Expr *Arg) -> bool { const LangOptions &LO = getLangOpts(); @@ -9592,9 +9596,9 @@ bool Sema::SemaBuiltinVAStartARMMicrosoft(CallExpr *Call) { return false; } -/// SemaBuiltinUnorderedCompare - Handle functions like __builtin_isgreater and +/// BuiltinUnorderedCompare - Handle functions like __builtin_isgreater and /// friends. This is declared to take (...), so we have to check everything. -bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) { +bool Sema::BuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) { if (checkArgCount(*this, TheCall, 2)) return true; @@ -9634,11 +9638,11 @@ bool Sema::SemaBuiltinUnorderedCompare(CallExpr *TheCall, unsigned BuiltinID) { return false; } -/// SemaBuiltinSemaBuiltinFPClassification - Handle functions like +/// BuiltinSemaBuiltinFPClassification - Handle functions like /// __builtin_isnan and friends. This is declared to take (...), so we have /// to check everything. -bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, - unsigned BuiltinID) { +bool Sema::BuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, + unsigned BuiltinID) { if (checkArgCount(*this, TheCall, NumArgs)) return true; @@ -9694,7 +9698,7 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, // vector argument can be supported in all of them. if (ElementTy->isVectorType() && IsFPClass) { VectorResultTy = GetSignedVectorType(ElementTy); - ElementTy = ElementTy->getAs()->getElementType(); + ElementTy = ElementTy->castAs()->getElementType(); } // This operation requires a non-_Complex floating-point number. @@ -9706,7 +9710,7 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, // __builtin_isfpclass has integer parameter that specify test mask. It is // passed in (...), so it should be analyzed completely here. if (IsFPClass) - if (SemaBuiltinConstantArgRange(TheCall, 1, 0, llvm::fcAllFlags)) + if (BuiltinConstantArgRange(TheCall, 1, 0, llvm::fcAllFlags)) return true; // TODO: enable this code to all classification functions. @@ -9723,7 +9727,7 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs, } /// Perform semantic analysis for a call to __builtin_complex. -bool Sema::SemaBuiltinComplex(CallExpr *TheCall) { +bool Sema::BuiltinComplex(CallExpr *TheCall) { if (checkArgCount(*this, TheCall, 2)) return true; @@ -9784,7 +9788,7 @@ bool Sema::SemaBuiltinComplex(CallExpr *TheCall) { // Example builtins are : // vector double vec_xxpermdi(vector double, vector double, int); // vector short vec_xxsldwi(vector short, vector short, int); -bool Sema::SemaBuiltinVSX(CallExpr *TheCall) { +bool Sema::BuiltinVSX(CallExpr *TheCall) { unsigned ExpectedNumArgs = 3; if (checkArgCount(*this, TheCall, ExpectedNumArgs)) return true; @@ -9826,9 +9830,9 @@ bool Sema::SemaBuiltinVSX(CallExpr *TheCall) { return false; } -/// SemaBuiltinShuffleVector - Handle __builtin_shufflevector. +/// BuiltinShuffleVector - Handle __builtin_shufflevector. // This is declared to take (...), so we have to check everything. -ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { +ExprResult Sema::BuiltinShuffleVector(CallExpr *TheCall) { if (TheCall->getNumArgs() < 2) return ExprError(Diag(TheCall->getEndLoc(), diag::err_typecheck_call_too_few_args_at_least) @@ -9916,10 +9920,10 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { TheCall->getRParenLoc()); } -/// SemaConvertVectorExpr - Handle __builtin_convertvector -ExprResult Sema::SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, - SourceLocation BuiltinLoc, - SourceLocation RParenLoc) { +/// ConvertVectorExpr - Handle __builtin_convertvector +ExprResult Sema::ConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc) { ExprValueKind VK = VK_PRValue; ExprObjectKind OK = OK_Ordinary; QualType DstTy = TInfo->getType(); @@ -9943,14 +9947,14 @@ ExprResult Sema::SemaConvertVectorExpr(Expr *E, TypeSourceInfo *TInfo, << E->getSourceRange()); } - return new (Context) - ConvertVectorExpr(E, TInfo, DstTy, VK, OK, BuiltinLoc, RParenLoc); + return new (Context) class ConvertVectorExpr(E, TInfo, DstTy, VK, OK, + BuiltinLoc, RParenLoc); } -/// SemaBuiltinPrefetch - Handle __builtin_prefetch. +/// BuiltinPrefetch - Handle __builtin_prefetch. // This is declared to take (const void*, ...) and can take two // optional constant int args. -bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { +bool Sema::BuiltinPrefetch(CallExpr *TheCall) { unsigned NumArgs = TheCall->getNumArgs(); if (NumArgs > 3) @@ -9962,14 +9966,14 @@ bool Sema::SemaBuiltinPrefetch(CallExpr *TheCall) { // Argument 0 is checked for us and the remaining arguments must be // constant integers. for (unsigned i = 1; i != NumArgs; ++i) - if (SemaBuiltinConstantArgRange(TheCall, i, 0, i == 1 ? 1 : 3)) + if (BuiltinConstantArgRange(TheCall, i, 0, i == 1 ? 1 : 3)) return true; return false; } -/// SemaBuiltinArithmeticFence - Handle __arithmetic_fence. -bool Sema::SemaBuiltinArithmeticFence(CallExpr *TheCall) { +/// BuiltinArithmeticFence - Handle __arithmetic_fence. +bool Sema::BuiltinArithmeticFence(CallExpr *TheCall) { if (!Context.getTargetInfo().checkArithmeticFenceSupported()) return Diag(TheCall->getBeginLoc(), diag::err_builtin_target_unsupported) << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc()); @@ -9991,10 +9995,10 @@ bool Sema::SemaBuiltinArithmeticFence(CallExpr *TheCall) { return false; } -/// SemaBuiltinAssume - Handle __assume (MS Extension). +/// BuiltinAssume - Handle __assume (MS Extension). // __assume does not evaluate its arguments, and should warn if its argument // has side effects. -bool Sema::SemaBuiltinAssume(CallExpr *TheCall) { +bool Sema::BuiltinAssume(CallExpr *TheCall) { Expr *Arg = TheCall->getArg(0); if (Arg->isInstantiationDependent()) return false; @@ -10009,7 +10013,7 @@ bool Sema::SemaBuiltinAssume(CallExpr *TheCall) { /// Handle __builtin_alloca_with_align. This is declared /// as (size_t, size_t) where the second size_t must be a power of 2 greater /// than 8. -bool Sema::SemaBuiltinAllocaWithAlign(CallExpr *TheCall) { +bool Sema::BuiltinAllocaWithAlign(CallExpr *TheCall) { // The alignment must be a constant integer. Expr *Arg = TheCall->getArg(1); @@ -10042,7 +10046,7 @@ bool Sema::SemaBuiltinAllocaWithAlign(CallExpr *TheCall) { /// Handle __builtin_assume_aligned. This is declared /// as (const void*, size_t, ...) and can take one optional constant int arg. -bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { +bool Sema::BuiltinAssumeAligned(CallExpr *TheCall) { if (checkArgCountRange(*this, TheCall, 2, 3)) return true; @@ -10064,7 +10068,7 @@ bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { // We can't check the value of a dependent argument. if (!SecondArg->isValueDependent()) { llvm::APSInt Result; - if (SemaBuiltinConstantArg(TheCall, 1, Result)) + if (BuiltinConstantArg(TheCall, 1, Result)) return true; if (!Result.isPowerOf2()) @@ -10086,7 +10090,7 @@ bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { return false; } -bool Sema::SemaBuiltinOSLogFormat(CallExpr *TheCall) { +bool Sema::BuiltinOSLogFormat(CallExpr *TheCall) { unsigned BuiltinID = cast(TheCall->getCalleeDecl())->getBuiltinID(); bool IsSizeCall = BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size; @@ -10166,10 +10170,10 @@ bool Sema::SemaBuiltinOSLogFormat(CallExpr *TheCall) { return false; } -/// SemaBuiltinConstantArg - Handle a check if argument ArgNum of CallExpr +/// BuiltinConstantArg - Handle a check if argument ArgNum of CallExpr /// TheCall is a constant expression. -bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, - llvm::APSInt &Result) { +bool Sema::BuiltinConstantArg(CallExpr *TheCall, int ArgNum, + llvm::APSInt &Result) { Expr *Arg = TheCall->getArg(ArgNum); DeclRefExpr *DRE =cast(TheCall->getCallee()->IgnoreParenCasts()); FunctionDecl *FDecl = cast(DRE->getDecl()); @@ -10184,10 +10188,10 @@ bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, return false; } -/// SemaBuiltinConstantArgRange - Handle a check if argument ArgNum of CallExpr +/// BuiltinConstantArgRange - Handle a check if argument ArgNum of CallExpr /// TheCall is a constant expression in the range [Low, High]. -bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, - int Low, int High, bool RangeIsError) { +bool Sema::BuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, int Low, + int High, bool RangeIsError) { if (isConstantEvaluatedContext()) return false; llvm::APSInt Result; @@ -10198,7 +10202,7 @@ bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; if (Result.getSExtValue() < Low || Result.getSExtValue() > High) { @@ -10217,10 +10221,10 @@ bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, return false; } -/// SemaBuiltinConstantArgMultiple - Handle a check if argument ArgNum of CallExpr +/// BuiltinConstantArgMultiple - Handle a check if argument ArgNum of CallExpr /// TheCall is a constant expression is a multiple of Num.. -bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, - unsigned Num) { +bool Sema::BuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, + unsigned Num) { llvm::APSInt Result; // We can't check the value of a dependent argument. @@ -10229,7 +10233,7 @@ bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; if (Result.getSExtValue() % Num != 0) @@ -10239,9 +10243,9 @@ bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, return false; } -/// SemaBuiltinConstantArgPower2 - Check if argument ArgNum of TheCall is a +/// BuiltinConstantArgPower2 - Check if argument ArgNum of TheCall is a /// constant expression representing a power of 2. -bool Sema::SemaBuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum) { +bool Sema::BuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum) { llvm::APSInt Result; // We can't check the value of a dependent argument. @@ -10250,7 +10254,7 @@ bool Sema::SemaBuiltinConstantArgPower2(CallExpr *TheCall, int ArgNum) { return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; // Bit-twiddling to test for a power of 2: for x > 0, x & (x-1) is zero if @@ -10284,11 +10288,11 @@ static bool IsShiftedByte(llvm::APSInt Value) { } } -/// SemaBuiltinConstantArgShiftedByte - Check if argument ArgNum of TheCall is +/// BuiltinConstantArgShiftedByte - Check if argument ArgNum of TheCall is /// a constant expression representing an arbitrary byte value shifted left by /// a multiple of 8 bits. -bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, - unsigned ArgBits) { +bool Sema::BuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, + unsigned ArgBits) { llvm::APSInt Result; // We can't check the value of a dependent argument. @@ -10297,7 +10301,7 @@ bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; // Truncate to the given size. @@ -10311,14 +10315,13 @@ bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, << Arg->getSourceRange(); } -/// SemaBuiltinConstantArgShiftedByteOr0xFF - Check if argument ArgNum of +/// BuiltinConstantArgShiftedByteOr0xFF - Check if argument ArgNum of /// TheCall is a constant expression representing either a shifted byte value, /// or a value of the form 0x??FF (i.e. a member of the arithmetic progression /// 0x00FF, 0x01FF, ..., 0xFFFF). This strange range check is needed for some /// Arm MVE intrinsics. -bool Sema::SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, - int ArgNum, - unsigned ArgBits) { +bool Sema::BuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, int ArgNum, + unsigned ArgBits) { llvm::APSInt Result; // We can't check the value of a dependent argument. @@ -10327,7 +10330,7 @@ bool Sema::SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, return false; // Check constant-ness first. - if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + if (BuiltinConstantArg(TheCall, ArgNum, Result)) return true; // Truncate to the given size. @@ -10344,8 +10347,8 @@ bool Sema::SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, << Arg->getSourceRange(); } -/// SemaBuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions -bool Sema::SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall) { +/// BuiltinARMMemoryTaggingCall - Handle calls of memory tagging extensions +bool Sema::BuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == AArch64::BI__builtin_arm_irg) { if (checkArgCount(*this, TheCall, 2)) return true; @@ -10392,7 +10395,7 @@ bool Sema::SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall TheCall->setType(FirstArgType); // Second arg must be an constant in range [0,15] - return SemaBuiltinConstantArgRange(TheCall, 1, 0, 15); + return BuiltinConstantArgRange(TheCall, 1, 0, 15); } if (BuiltinID == AArch64::BI__builtin_arm_gmi) { @@ -10498,11 +10501,11 @@ bool Sema::SemaBuiltinARMMemoryTaggingCall(unsigned BuiltinID, CallExpr *TheCall return true; } -/// SemaBuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr +/// BuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr /// TheCall is an ARM/AArch64 special register string literal. -bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, - int ArgNum, unsigned ExpectedFieldNum, - bool AllowName) { +bool Sema::BuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, + int ArgNum, unsigned ExpectedFieldNum, + bool AllowName) { bool IsARMBuiltin = BuiltinID == ARM::BI__builtin_arm_rsr64 || BuiltinID == ARM::BI__builtin_arm_wsr64 || BuiltinID == ARM::BI__builtin_arm_rsr || @@ -10624,18 +10627,18 @@ bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, // If a programmer wants to codegen the MSR (register) form of `msr tco, // xN`, they can still do so by specifying the register using five // colon-separated numbers in a string. - return SemaBuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit); + return BuiltinConstantArgRange(TheCall, 1, 0, *MaxLimit); } return false; } -/// SemaBuiltinPPCMMACall - Check the call to a PPC MMA builtin for validity. +/// BuiltinPPCMMACall - Check the call to a PPC MMA builtin for validity. /// Emit an error and return true on failure; return false on success. /// TypeStr is a string containing the type descriptor of the value returned by /// the builtin and the descriptors of the expected type of the arguments. -bool Sema::SemaBuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, - const char *TypeStr) { +bool Sema::BuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, + const char *TypeStr) { assert((TypeStr[0] != '\0') && "Invalid types in PPC MMA builtin declaration"); @@ -10678,8 +10681,7 @@ bool Sema::SemaBuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, // If the value of the Mask is not 0, we have a constraint in the size of // the integer argument so here we ensure the argument is a constant that // is in the valid range. - if (Mask != 0 && - SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, Mask, true)) + if (Mask != 0 && BuiltinConstantArgRange(TheCall, ArgNum, 0, Mask, true)) return true; ArgNum++; @@ -10699,10 +10701,10 @@ bool Sema::SemaBuiltinPPCMMACall(CallExpr *TheCall, unsigned BuiltinID, return false; } -/// SemaBuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val). +/// BuiltinLongjmp - Handle __builtin_longjmp(void *env[5], int val). /// This checks that the target supports __builtin_longjmp and /// that val is a constant 1. -bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { +bool Sema::BuiltinLongjmp(CallExpr *TheCall) { if (!Context.getTargetInfo().hasSjLjLowering()) return Diag(TheCall->getBeginLoc(), diag::err_builtin_longjmp_unsupported) << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc()); @@ -10711,7 +10713,7 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { llvm::APSInt Result; // TODO: This is less than ideal. Overload this to take a value. - if (SemaBuiltinConstantArg(TheCall, 1, Result)) + if (BuiltinConstantArg(TheCall, 1, Result)) return true; if (Result != 1) @@ -10721,9 +10723,9 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { return false; } -/// SemaBuiltinSetjmp - Handle __builtin_setjmp(void *env[5]). +/// BuiltinSetjmp - Handle __builtin_setjmp(void *env[5]). /// This checks that the target supports __builtin_setjmp. -bool Sema::SemaBuiltinSetjmp(CallExpr *TheCall) { +bool Sema::BuiltinSetjmp(CallExpr *TheCall) { if (!Context.getTargetInfo().hasSjLjLowering()) return Diag(TheCall->getBeginLoc(), diag::err_builtin_setjmp_unsupported) << SourceRange(TheCall->getBeginLoc(), TheCall->getEndLoc()); @@ -12465,6 +12467,19 @@ isArithmeticArgumentPromotion(Sema &S, const ImplicitCastExpr *ICE) { S.Context.getFloatingTypeOrder(From, To) < 0; } +static analyze_format_string::ArgType::MatchKind +handleFormatSignedness(analyze_format_string::ArgType::MatchKind Match, + DiagnosticsEngine &Diags, SourceLocation Loc) { + if (Match == analyze_format_string::ArgType::NoMatchSignedness) { + Match = + Diags.isIgnored( + diag::warn_format_conversion_argument_type_mismatch_signedness, Loc) + ? analyze_format_string::ArgType::Match + : analyze_format_string::ArgType::NoMatch; + } + return Match; +} + bool CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, const char *StartSpecifier, @@ -12508,6 +12523,9 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, ArgType::MatchKind ImplicitMatch = ArgType::NoMatch; ArgType::MatchKind Match = AT.matchesType(S.Context, ExprTy); + ArgType::MatchKind OrigMatch = Match; + + Match = handleFormatSignedness(Match, S.getDiagnostics(), E->getExprLoc()); if (Match == ArgType::Match) return true; @@ -12531,6 +12549,14 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, ICE->getType() == S.Context.UnsignedIntTy) { // All further checking is done on the subexpression ImplicitMatch = AT.matchesType(S.Context, ExprTy); + if (OrigMatch == ArgType::NoMatchSignedness && + ImplicitMatch != ArgType::NoMatchSignedness) + // If the original match was a signedness match this match on the + // implicit cast type also need to be signedness match otherwise we + // might introduce new unexpected warnings from -Wformat-signedness. + return true; + ImplicitMatch = handleFormatSignedness( + ImplicitMatch, S.getDiagnostics(), E->getExprLoc()); if (ImplicitMatch == ArgType::Match) return true; } @@ -12652,6 +12678,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, case ArgType::Match: case ArgType::MatchPromotion: case ArgType::NoMatchPromotionTypeConfusion: + case ArgType::NoMatchSignedness: llvm_unreachable("expected non-matching"); case ArgType::NoMatchPedantic: Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; @@ -12687,8 +12714,10 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, CastFix << (S.LangOpts.CPlusPlus ? ">" : ")"); SmallVector Hints; - if (AT.matchesType(S.Context, IntendedTy) != ArgType::Match || - ShouldNotPrintDirectly) + ArgType::MatchKind IntendedMatch = AT.matchesType(S.Context, IntendedTy); + IntendedMatch = handleFormatSignedness(IntendedMatch, S.getDiagnostics(), + E->getExprLoc()); + if ((IntendedMatch != ArgType::Match) || ShouldNotPrintDirectly) Hints.push_back(FixItHint::CreateReplacement(SpecRange, os.str())); if (const CStyleCastExpr *CCast = dyn_cast(E)) { @@ -12757,6 +12786,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, case ArgType::Match: case ArgType::MatchPromotion: case ArgType::NoMatchPromotionTypeConfusion: + case ArgType::NoMatchSignedness: llvm_unreachable("expected non-matching"); case ArgType::NoMatchPedantic: Diag = diag::warn_format_conversion_argument_type_mismatch_pedantic; @@ -12968,6 +12998,7 @@ bool CheckScanfHandler::HandleScanfSpecifier( analyze_format_string::ArgType::MatchKind Match = AT.matchesType(S.Context, Ex->getType()); + Match = handleFormatSignedness(Match, S.getDiagnostics(), Ex->getExprLoc()); bool Pedantic = Match == analyze_format_string::ArgType::NoMatchPedantic; if (Match == analyze_format_string::ArgType::Match) return true; @@ -13029,7 +13060,7 @@ static void CheckFormatString( const ConstantArrayType *T = S.Context.getAsConstantArrayType(FExpr->getType()); assert(T && "String literal not of constant array type!"); - size_t TypeSize = T->getSize().getZExtValue(); + size_t TypeSize = T->getZExtSize(); size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size()); const unsigned numDataArgs = Args.size() - firstDataArg; @@ -13089,7 +13120,7 @@ bool Sema::FormatStringHasSArg(const StringLiteral *FExpr) { // Account for cases where the string literal is truncated in a declaration. const ConstantArrayType *T = Context.getAsConstantArrayType(FExpr->getType()); assert(T && "String literal not of constant array type!"); - size_t TypeSize = T->getSize().getZExtValue(); + size_t TypeSize = T->getZExtSize(); size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size()); return analyze_format_string::ParseFormatStringHasSArg(Str, Str + StrLen, getLangOpts(), @@ -14052,7 +14083,7 @@ static bool isConstantSizeArrayWithMoreThanOneElement(QualType Ty, // Only handle constant-sized or VLAs, but not flexible members. if (const ConstantArrayType *CAT = Context.getAsConstantArrayType(Ty)) { // Only issue the FIXIT for arrays of size > 1. - if (CAT->getSize().getSExtValue() <= 1) + if (CAT->getZExtSize() <= 1) return false; } else if (!Ty->isVariableArrayType()) { return false; @@ -20114,17 +20145,17 @@ bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) { return false; } -bool Sema::SemaBuiltinElementwiseMath(CallExpr *TheCall) { +bool Sema::BuiltinElementwiseMath(CallExpr *TheCall) { QualType Res; - if (SemaBuiltinVectorMath(TheCall, Res)) + if (BuiltinVectorMath(TheCall, Res)) return true; TheCall->setType(Res); return false; } -bool Sema::SemaBuiltinVectorToScalarMath(CallExpr *TheCall) { +bool Sema::BuiltinVectorToScalarMath(CallExpr *TheCall) { QualType Res; - if (SemaBuiltinVectorMath(TheCall, Res)) + if (BuiltinVectorMath(TheCall, Res)) return true; if (auto *VecTy0 = Res->getAs()) @@ -20135,7 +20166,7 @@ bool Sema::SemaBuiltinVectorToScalarMath(CallExpr *TheCall) { return false; } -bool Sema::SemaBuiltinVectorMath(CallExpr *TheCall, QualType &Res) { +bool Sema::BuiltinVectorMath(CallExpr *TheCall, QualType &Res) { if (checkArgCount(*this, TheCall, 2)) return true; @@ -20163,8 +20194,8 @@ bool Sema::SemaBuiltinVectorMath(CallExpr *TheCall, QualType &Res) { return false; } -bool Sema::SemaBuiltinElementwiseTernaryMath(CallExpr *TheCall, - bool CheckForFloatArgs) { +bool Sema::BuiltinElementwiseTernaryMath(CallExpr *TheCall, + bool CheckForFloatArgs) { if (checkArgCount(*this, TheCall, 3)) return true; @@ -20219,7 +20250,7 @@ bool Sema::PrepareBuiltinReduceMathOneArgCall(CallExpr *TheCall) { return false; } -bool Sema::SemaBuiltinNonDeterministicValue(CallExpr *TheCall) { +bool Sema::BuiltinNonDeterministicValue(CallExpr *TheCall) { if (checkArgCount(*this, TheCall, 1)) return true; @@ -20234,8 +20265,8 @@ bool Sema::SemaBuiltinNonDeterministicValue(CallExpr *TheCall) { return false; } -ExprResult Sema::SemaBuiltinMatrixTranspose(CallExpr *TheCall, - ExprResult CallResult) { +ExprResult Sema::BuiltinMatrixTranspose(CallExpr *TheCall, + ExprResult CallResult) { if (checkArgCount(*this, TheCall, 1)) return ExprError(); @@ -20284,8 +20315,8 @@ getAndVerifyMatrixDimension(Expr *Expr, StringRef Name, Sema &S) { return Dim; } -ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall, - ExprResult CallResult) { +ExprResult Sema::BuiltinMatrixColumnMajorLoad(CallExpr *TheCall, + ExprResult CallResult) { if (!getLangOpts().MatrixTypes) { Diag(TheCall->getBeginLoc(), diag::err_builtin_matrix_disabled); return ExprError(); @@ -20400,8 +20431,8 @@ ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall, return CallResult; } -ExprResult Sema::SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall, - ExprResult CallResult) { +ExprResult Sema::BuiltinMatrixColumnMajorStore(CallExpr *TheCall, + ExprResult CallResult) { if (checkArgCount(*this, TheCall, 3)) return ExprError(); diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 73e6baa5278262e29397f9b617e512ffa5d8423c..c335017f243eb27b59d83da452f02bb657e05f99 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -20,6 +20,7 @@ #include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/NestedNameSpecifier.h" +#include "clang/AST/OperationKinds.h" #include "clang/AST/QualTypeNames.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Type.h" @@ -3690,7 +3691,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( std::string Keyword; if (Idx > StartParameter) Result.AddChunk(CodeCompletionString::CK_HorizontalSpace); - if (IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx)) + if (const IdentifierInfo *II = Sel.getIdentifierInfoForSlot(Idx)) Keyword += II->getName(); Keyword += ":"; if (Idx < StartParameter || AllParametersAreInformative) @@ -3719,7 +3720,7 @@ CodeCompletionString *CodeCompletionResult::createCodeCompletionStringForDecl( Arg = "(" + formatObjCParamQualifiers((*P)->getObjCDeclQualifier(), ParamType); Arg += ParamType.getAsString(Policy) + ")"; - if (IdentifierInfo *II = (*P)->getIdentifier()) + if (const IdentifierInfo *II = (*P)->getIdentifier()) if (DeclaringEntity || AllParametersAreInformative) Arg += II->getName(); } @@ -4499,11 +4500,11 @@ void Sema::CodeCompleteOrdinaryName(Scope *S, Results.data(), Results.size()); } -static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, - ParsedType Receiver, - ArrayRef SelIdents, - bool AtArgumentExpression, bool IsSuper, - ResultBuilder &Results); +static void +AddClassMessageCompletions(Sema &SemaRef, Scope *S, ParsedType Receiver, + ArrayRef SelIdents, + bool AtArgumentExpression, bool IsSuper, + ResultBuilder &Results); void Sema::CodeCompleteDeclSpec(Scope *S, DeclSpec &DS, bool AllowNonIdentifiers, @@ -4927,7 +4928,7 @@ void Sema::CodeCompletePostfixExpression(Scope *S, ExprResult E, /// The set of properties that have already been added, referenced by /// property name. -typedef llvm::SmallPtrSet AddedPropertiesSet; +typedef llvm::SmallPtrSet AddedPropertiesSet; /// Retrieve the container definition, if any? static ObjCContainerDecl *getContainerDef(ObjCContainerDecl *Container) { @@ -5089,7 +5090,7 @@ AddObjCProperties(const CodeCompletionContext &CCContext, PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema()); // Adds a method result const auto AddMethod = [&](const ObjCMethodDecl *M) { - IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0); + const IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0); if (!Name) return; if (!AddedProperties.insert(Name).second) @@ -5678,6 +5679,10 @@ QualType getApproximateType(const Expr *E) { return getApproximateType(VD->getInit()); } } + if (const auto *UO = llvm::dyn_cast(E)) { + if (UO->getOpcode() == UnaryOperatorKind::UO_Deref) + return UO->getSubExpr()->getType()->getPointeeType(); + } return Unresolved; } @@ -5854,10 +5859,10 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, } void Sema::CodeCompleteObjCClassPropertyRefExpr(Scope *S, - IdentifierInfo &ClassName, + const IdentifierInfo &ClassName, SourceLocation ClassNameLoc, bool IsBaseExprStatement) { - IdentifierInfo *ClassNamePtr = &ClassName; + const IdentifierInfo *ClassNamePtr = &ClassName; ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(ClassNamePtr, ClassNameLoc); if (!IFace) return; @@ -7522,7 +7527,7 @@ enum ObjCMethodKind { }; static bool isAcceptableObjCSelector(Selector Sel, ObjCMethodKind WantKind, - ArrayRef SelIdents, + ArrayRef SelIdents, bool AllowSameLength = true) { unsigned NumSelIdents = SelIdents.size(); if (NumSelIdents > Sel.getNumArgs()) @@ -7549,7 +7554,7 @@ static bool isAcceptableObjCSelector(Selector Sel, ObjCMethodKind WantKind, static bool isAcceptableObjCMethod(ObjCMethodDecl *Method, ObjCMethodKind WantKind, - ArrayRef SelIdents, + ArrayRef SelIdents, bool AllowSameLength = true) { return isAcceptableObjCSelector(Method->getSelector(), WantKind, SelIdents, AllowSameLength); @@ -7581,7 +7586,7 @@ typedef llvm::SmallPtrSet VisitedSelectorSet; /// \param Results the structure into which we'll add results. static void AddObjCMethods(ObjCContainerDecl *Container, bool WantInstanceMethods, ObjCMethodKind WantKind, - ArrayRef SelIdents, + ArrayRef SelIdents, DeclContext *CurContext, VisitedSelectorSet &Selectors, bool AllowSameLength, ResultBuilder &Results, bool InOriginalClass = true, @@ -7814,7 +7819,7 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) { if (Sel.isNull()) return nullptr; - IdentifierInfo *Id = Sel.getIdentifierInfoForSlot(0); + const IdentifierInfo *Id = Sel.getIdentifierInfoForSlot(0); if (!Id) return nullptr; @@ -7890,7 +7895,7 @@ static ObjCInterfaceDecl *GetAssumedMessageSendExprType(Expr *E) { /// this "super" completion. If NULL, no completion was added. static ObjCMethodDecl * AddSuperSendCompletion(Sema &S, bool NeedSuperKeyword, - ArrayRef SelIdents, + ArrayRef SelIdents, ResultBuilder &Results) { ObjCMethodDecl *CurMethod = S.getCurMethodDecl(); if (!CurMethod) @@ -8027,9 +8032,9 @@ void Sema::CodeCompleteObjCMessageReceiver(Scope *S) { Results.data(), Results.size()); } -void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, - ArrayRef SelIdents, - bool AtArgumentExpression) { +void Sema::CodeCompleteObjCSuperMessage( + Scope *S, SourceLocation SuperLoc, + ArrayRef SelIdents, bool AtArgumentExpression) { ObjCInterfaceDecl *CDecl = nullptr; if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) { // Figure out which interface we're in. @@ -8054,7 +8059,7 @@ void Sema::CodeCompleteObjCSuperMessage(Scope *S, SourceLocation SuperLoc, } else { // "super" may be the name of a type or variable. Figure out which // it is. - IdentifierInfo *Super = getSuperIdentifier(); + const IdentifierInfo *Super = getSuperIdentifier(); NamedDecl *ND = LookupSingleName(S, Super, SuperLoc, LookupOrdinaryName); if ((CDecl = dyn_cast_or_null(ND))) { // "super" names an interface. Use it. @@ -8122,11 +8127,11 @@ static QualType getPreferredArgumentTypeForMessageSend(ResultBuilder &Results, return PreferredType; } -static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, - ParsedType Receiver, - ArrayRef SelIdents, - bool AtArgumentExpression, bool IsSuper, - ResultBuilder &Results) { +static void +AddClassMessageCompletions(Sema &SemaRef, Scope *S, ParsedType Receiver, + ArrayRef SelIdents, + bool AtArgumentExpression, bool IsSuper, + ResultBuilder &Results) { typedef CodeCompletionResult Result; ObjCInterfaceDecl *CDecl = nullptr; @@ -8197,10 +8202,9 @@ static void AddClassMessageCompletions(Sema &SemaRef, Scope *S, Results.ExitScope(); } -void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, - ArrayRef SelIdents, - bool AtArgumentExpression, - bool IsSuper) { +void Sema::CodeCompleteObjCClassMessage( + Scope *S, ParsedType Receiver, ArrayRef SelIdents, + bool AtArgumentExpression, bool IsSuper) { QualType T = this->GetTypeFromParser(Receiver); @@ -8232,10 +8236,9 @@ void Sema::CodeCompleteObjCClassMessage(Scope *S, ParsedType Receiver, Results.data(), Results.size()); } -void Sema::CodeCompleteObjCInstanceMessage(Scope *S, Expr *Receiver, - ArrayRef SelIdents, - bool AtArgumentExpression, - ObjCInterfaceDecl *Super) { +void Sema::CodeCompleteObjCInstanceMessage( + Scope *S, Expr *Receiver, ArrayRef SelIdents, + bool AtArgumentExpression, ObjCInterfaceDecl *Super) { typedef CodeCompletionResult Result; Expr *RecExpr = static_cast(Receiver); @@ -8405,8 +8408,8 @@ void Sema::CodeCompleteObjCForCollection(Scope *S, CodeCompleteExpression(S, Data); } -void Sema::CodeCompleteObjCSelector(Scope *S, - ArrayRef SelIdents) { +void Sema::CodeCompleteObjCSelector( + Scope *S, ArrayRef SelIdents) { // If we have an external source, load the entire class method // pool from the AST file. if (ExternalSource) { @@ -9161,8 +9164,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // Add -(void)getKey:(type **)buffer range:(NSRange)inRange if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("get") + UpperKey).str(); - IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName), - &Context.Idents.get("range")}; + const IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName), + &Context.Idents.get("range")}; if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { @@ -9193,8 +9196,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)insertObject:(type *)object inKeyAtIndex:(NSUInteger)index if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("in") + UpperKey + "AtIndex").str(); - IdentifierInfo *SelectorIds[2] = {&Context.Idents.get("insertObject"), - &Context.Idents.get(SelectorName)}; + const IdentifierInfo *SelectorIds[2] = {&Context.Idents.get("insertObject"), + &Context.Idents.get(SelectorName)}; if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { @@ -9223,8 +9226,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)insertKey:(NSArray *)array atIndexes:(NSIndexSet *)indexes if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("insert") + UpperKey).str(); - IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName), - &Context.Idents.get("atIndexes")}; + const IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName), + &Context.Idents.get("atIndexes")}; if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { @@ -9253,7 +9256,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("removeObjectFrom") + UpperKey + "AtIndex").str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9274,7 +9277,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // -(void)removeKeyAtIndexes:(NSIndexSet *)indexes if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("remove") + UpperKey + "AtIndexes").str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9296,8 +9299,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("replaceObjectIn") + UpperKey + "AtIndex").str(); - IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName), - &Context.Idents.get("withObject")}; + const IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName), + &Context.Idents.get("withObject")}; if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { @@ -9327,8 +9330,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, std::string SelectorName1 = (Twine("replace") + UpperKey + "AtIndexes").str(); std::string SelectorName2 = (Twine("with") + UpperKey).str(); - IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName1), - &Context.Idents.get(SelectorName2)}; + const IdentifierInfo *SelectorIds[2] = {&Context.Idents.get(SelectorName1), + &Context.Idents.get(SelectorName2)}; if (KnownSelectors.insert(Selectors.getSelector(2, SelectorIds)).second) { if (ReturnType.isNull()) { @@ -9363,7 +9366,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ->getInterfaceDecl() ->getName() == "NSEnumerator"))) { std::string SelectorName = (Twine("enumeratorOf") + UpperKey).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) .second) { if (ReturnType.isNull()) { @@ -9382,7 +9385,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && (ReturnType.isNull() || ReturnType->isObjCObjectPointerType())) { std::string SelectorName = (Twine("memberOf") + UpperKey).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9412,7 +9415,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("add") + UpperKey + Twine("Object")).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9434,7 +9437,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)addKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("add") + UpperKey).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9456,7 +9459,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("remove") + UpperKey + Twine("Object")).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9478,7 +9481,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)removeKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("remove") + UpperKey).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9499,7 +9502,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, // - (void)intersectKey:(NSSet *)objects if (IsInstanceMethod && ReturnTypeMatchesVoid) { std::string SelectorName = (Twine("intersect") + UpperKey).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getUnarySelector(SelectorId)).second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); @@ -9528,7 +9531,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ->getName() == "NSSet"))) { std::string SelectorName = (Twine("keyPathsForValuesAffecting") + UpperKey).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) .second) { if (ReturnType.isNull()) { @@ -9549,7 +9552,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, ReturnType->isBooleanType())) { std::string SelectorName = (Twine("automaticallyNotifiesObserversOf") + UpperKey).str(); - IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); + const IdentifierInfo *SelectorId = &Context.Idents.get(SelectorName); if (KnownSelectors.insert(Selectors.getNullarySelector(SelectorId)) .second) { if (ReturnType.isNull()) { @@ -9744,7 +9747,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, void Sema::CodeCompleteObjCMethodDeclSelector( Scope *S, bool IsInstanceMethod, bool AtParameterName, ParsedType ReturnTy, - ArrayRef SelIdents) { + ArrayRef SelIdents) { // If we have an external source, load the entire class method // pool from the AST file. if (ExternalSource) { diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 1c546e9f5894f024521d2410062e35204f35fa0b..e00c972602829ebf4b44f7a88e66102bf596dbcc 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -615,10 +615,12 @@ bool Sema::SetupConstraintScope( // reference the original primary template. // We walk up the instantiated template chain so that nested lambdas get // handled properly. - for (FunctionTemplateDecl *FromMemTempl = - PrimaryTemplate->getInstantiatedFromMemberTemplate(); - FromMemTempl; - FromMemTempl = FromMemTempl->getInstantiatedFromMemberTemplate()) { + // We should only collect instantiated parameters from the primary template. + // Otherwise, we may have mismatched template parameter depth! + if (FunctionTemplateDecl *FromMemTempl = + PrimaryTemplate->getInstantiatedFromMemberTemplate()) { + while (FromMemTempl->getInstantiatedFromMemberTemplate()) + FromMemTempl = FromMemTempl->getInstantiatedFromMemberTemplate(); if (addInstantiatedParametersToScope(FD, FromMemTempl->getTemplatedDecl(), Scope, MLTAL)) return true; @@ -1269,10 +1271,20 @@ substituteParameterMappings(Sema &S, NormalizedConstraint &N, : SourceLocation())); Atomic.ParameterMapping.emplace(TempArgs, OccurringIndices.count()); } + SourceLocation InstLocBegin = + ArgsAsWritten->arguments().empty() + ? ArgsAsWritten->getLAngleLoc() + : ArgsAsWritten->arguments().front().getSourceRange().getBegin(); + SourceLocation InstLocEnd = + ArgsAsWritten->arguments().empty() + ? ArgsAsWritten->getRAngleLoc() + : ArgsAsWritten->arguments().front().getSourceRange().getEnd(); Sema::InstantiatingTemplate Inst( - S, ArgsAsWritten->arguments().front().getSourceRange().getBegin(), + S, InstLocBegin, Sema::InstantiatingTemplate::ParameterMappingSubstitution{}, Concept, - ArgsAsWritten->arguments().front().getSourceRange()); + {InstLocBegin, InstLocEnd}); + if (Inst.isInvalid()) + return true; if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs)) return true; @@ -1346,6 +1358,8 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { S, CSE->getExprLoc(), Sema::InstantiatingTemplate::ConstraintNormalization{}, D, CSE->getSourceRange()); + if (Inst.isInvalid()) + return std::nullopt; // C++ [temp.constr.normal]p1.1 // [...] // The normal form of an id-expression of the form C, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index aa754d47a0c43a0620753b427b33314175b5294a..a4699d6ba2c735b944436f062a73d696fa807b56 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -1537,6 +1537,10 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { cast(D)->isFunctionTemplateSpecialization()) return; + if (isa(D) && D->getDeclName().isEmpty()) { + S->AddDecl(D); + return; + } // If this replaces anything in the current scope, IdentifierResolver::iterator I = IdResolver.begin(D->getDeclName()), IEnd = IdResolver.end(); @@ -2188,8 +2192,21 @@ void Sema::DiagnoseUnusedButSetDecl(const VarDecl *VD, assert(iter->getSecond() >= 0 && "Found a negative number of references to a VarDecl"); - if (iter->getSecond() != 0) - return; + if (int RefCnt = iter->getSecond(); RefCnt > 0) { + // Assume the given VarDecl is "used" if its ref count stored in + // `RefMinusAssignments` is positive, with one exception. + // + // For a C++ variable whose decl (with initializer) entirely consist the + // condition expression of a if/while/for construct, + // Clang creates a DeclRefExpr for the condition expression rather than a + // BinaryOperator of AssignmentOp. Thus, the C++ variable's ref + // count stored in `RefMinusAssignment` equals 1 when the variable is never + // used in the body of the if/while/for construct. + bool UnusedCXXCondDecl = VD->isCXXCondDecl() && (RefCnt == 1); + if (!UnusedCXXCondDecl) + return; + } + unsigned DiagID = isa(VD) ? diag::warn_unused_but_set_parameter : diag::warn_unused_but_set_variable; DiagReceiver(VD->getLocation(), PDiag(DiagID) << VD); @@ -2301,7 +2318,7 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { /// /// \returns The declaration of the named Objective-C class, or NULL if the /// class could not be found. -ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id, +ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(const IdentifierInfo *&Id, SourceLocation IdLoc, bool DoTypoCorrection) { // The third "scope" argument is 0 since we aren't enabling lazy built-in @@ -6318,16 +6335,15 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, if (TST->isDependentType() && TST->isTypeAlias()) Diag(Loc, diag::ext_alias_template_in_declarative_nns) << SpecLoc.getLocalSourceRange(); - } else if (T->isDecltypeType()) { + } else if (T->isDecltypeType() || T->getAsAdjusted()) { // C++23 [expr.prim.id.qual]p2: // [...] A declarative nested-name-specifier shall not have a - // decltype-specifier. + // computed-type-specifier. // - // FIXME: This wording appears to be defective as it does not forbid - // declarative nested-name-specifiers with pack-index-specifiers. - // See https://github.com/cplusplus/CWG/issues/499. - Diag(Loc, diag::err_decltype_in_declarator) - << SpecLoc.getTypeLoc().getSourceRange(); + // CWG2858 changed this from 'decltype-specifier' to + // 'computed-type-specifier'. + Diag(Loc, diag::err_computed_type_in_declarative_nns) + << T->isDecltypeType() << SpecLoc.getTypeLoc().getSourceRange(); } } } while ((SpecLoc = SpecLoc.getPrefix())); @@ -8837,7 +8853,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { return; } const auto *ATy = dyn_cast(T.getTypePtr()); - if (!ATy || ATy->getSize().getSExtValue() != 0) { + if (!ATy || ATy->getZExtSize() != 0) { Diag(NewVD->getLocation(), diag::err_typecheck_wasm_table_must_have_zero_length); NewVD->setInvalidDecl(); @@ -8962,8 +8978,13 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { } } - if (T->isRVVSizelessBuiltinType()) - checkRVVTypeSupport(T, NewVD->getLocation(), cast(CurContext)); + if (T->isRVVSizelessBuiltinType() && isa(CurContext)) { + const FunctionDecl *FD = cast(CurContext); + llvm::StringMap CallerFeatureMap; + Context.getFunctionFeatureMap(CallerFeatureMap, FD); + checkRVVTypeSupport(T, NewVD->getLocation(), cast(CurContext), + CallerFeatureMap); + } } /// Perform semantic checking on a newly-created variable @@ -9910,7 +9931,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // FIXME: We need a better way to separate C++ standard and clang modules. bool ImplicitInlineCXX20 = !getLangOpts().CPlusPlusModules || !NewFD->getOwningModule() || - NewFD->getOwningModule()->isGlobalModule() || + NewFD->isFromExplicitGlobalModule() || NewFD->getOwningModule()->isHeaderLikeModule(); bool isInline = D.getDeclSpec().isInlineSpecified(); bool isVirtual = D.getDeclSpec().isVirtualSpecified(); @@ -10119,23 +10140,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_auto_fn_virtual); } - if (getLangOpts().CPlusPlus14 && - (NewFD->isDependentContext() || - (isFriend && CurContext->isDependentContext())) && - NewFD->getReturnType()->isUndeducedType()) { - // If the function template is referenced directly (for instance, as a - // member of the current instantiation), pretend it has a dependent type. - // This is not really justified by the standard, but is the only sane - // thing to do. - // FIXME: For a friend function, we have not marked the function as being - // a friend yet, so 'isDependentContext' on the FD doesn't work. - const FunctionProtoType *FPT = - NewFD->getType()->castAs(); - QualType Result = SubstAutoTypeDependent(FPT->getReturnType()); - NewFD->setType(Context.getFunctionType(Result, FPT->getParamTypes(), - FPT->getExtProtoInfo())); - } - // C++ [dcl.fct.spec]p3: // The inline specifier shall not appear on a block scope function // declaration. @@ -11260,11 +11264,13 @@ static bool checkNonMultiVersionCompatAttributes(Sema &S, return Diagnose(S, A); break; case attr::TargetVersion: - if (MVKind != MultiVersionKind::TargetVersion) + if (MVKind != MultiVersionKind::TargetVersion && + MVKind != MultiVersionKind::TargetClones) return Diagnose(S, A); break; case attr::TargetClones: - if (MVKind != MultiVersionKind::TargetClones) + if (MVKind != MultiVersionKind::TargetClones && + MVKind != MultiVersionKind::TargetVersion) return Diagnose(S, A); break; default: @@ -11441,9 +11447,9 @@ static bool CheckMultiVersionFirstFunction(Sema &S, FunctionDecl *FD) { "Function lacks multiversion attribute"); const auto *TA = FD->getAttr(); const auto *TVA = FD->getAttr(); - // Target and target_version only causes MV if it is default, otherwise this - // is a normal function. - if ((TA && !TA->isDefaultVersion()) || (TVA && !TVA->isDefaultVersion())) + // The target attribute only causes MV if this declaration is the default, + // otherwise it is treated as a normal function. + if (TA && !TA->isDefaultVersion()) return false; if ((TA || TVA) && CheckMultiVersionValue(S, FD)) { @@ -11469,6 +11475,22 @@ static bool PreviousDeclsHaveMultiVersionAttribute(const FunctionDecl *FD) { return false; } +static void patchDefaultTargetVersion(FunctionDecl *From, FunctionDecl *To) { + if (!From->getASTContext().getTargetInfo().getTriple().isAArch64()) + return; + + MultiVersionKind MVKindFrom = From->getMultiVersionKind(); + MultiVersionKind MVKindTo = To->getMultiVersionKind(); + + if (MVKindTo == MultiVersionKind::None && + (MVKindFrom == MultiVersionKind::TargetVersion || + MVKindFrom == MultiVersionKind::TargetClones)) { + To->setIsMultiVersion(); + To->addAttr(TargetVersionAttr::CreateImplicit( + To->getASTContext(), "default", To->getSourceRange())); + } +} + static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, bool &Redeclaration, @@ -11479,10 +11501,7 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, // The definitions should be allowed in any order. If we have discovered // a new target version and the preceeding was the default, then add the // corresponding attribute to it. - if (OldFD->getMultiVersionKind() == MultiVersionKind::None && - NewFD->getMultiVersionKind() == MultiVersionKind::TargetVersion) - OldFD->addAttr(TargetVersionAttr::CreateImplicit(S.Context, "default", - OldFD->getSourceRange())); + patchDefaultTargetVersion(NewFD, OldFD); const auto *NewTA = NewFD->getAttr(); const auto *NewTVA = NewFD->getAttr(); @@ -11583,36 +11602,60 @@ static bool CheckTargetCausesMultiVersioning(Sema &S, FunctionDecl *OldFD, return false; } -static bool MultiVersionTypesCompatible(MultiVersionKind Old, - MultiVersionKind New) { - if (Old == New || Old == MultiVersionKind::None || - New == MultiVersionKind::None) +static bool MultiVersionTypesCompatible(FunctionDecl *Old, FunctionDecl *New) { + MultiVersionKind OldKind = Old->getMultiVersionKind(); + MultiVersionKind NewKind = New->getMultiVersionKind(); + + if (OldKind == NewKind || OldKind == MultiVersionKind::None || + NewKind == MultiVersionKind::None) return true; - return (Old == MultiVersionKind::CPUDispatch && - New == MultiVersionKind::CPUSpecific) || - (Old == MultiVersionKind::CPUSpecific && - New == MultiVersionKind::CPUDispatch); + if (Old->getASTContext().getTargetInfo().getTriple().isAArch64()) { + switch (OldKind) { + case MultiVersionKind::TargetVersion: + return NewKind == MultiVersionKind::TargetClones; + case MultiVersionKind::TargetClones: + return NewKind == MultiVersionKind::TargetVersion; + default: + return false; + } + } else { + switch (OldKind) { + case MultiVersionKind::CPUDispatch: + return NewKind == MultiVersionKind::CPUSpecific; + case MultiVersionKind::CPUSpecific: + return NewKind == MultiVersionKind::CPUDispatch; + default: + return false; + } + } } /// Check the validity of a new function declaration being added to an existing /// multiversioned declaration collection. static bool CheckMultiVersionAdditionalDecl( Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD, - MultiVersionKind NewMVKind, const CPUDispatchAttr *NewCPUDisp, - const CPUSpecificAttr *NewCPUSpec, const TargetClonesAttr *NewClones, - bool &Redeclaration, NamedDecl *&OldDecl, LookupResult &Previous) { - const auto *NewTA = NewFD->getAttr(); - const auto *NewTVA = NewFD->getAttr(); - MultiVersionKind OldMVKind = OldFD->getMultiVersionKind(); + const CPUDispatchAttr *NewCPUDisp, const CPUSpecificAttr *NewCPUSpec, + const TargetClonesAttr *NewClones, bool &Redeclaration, NamedDecl *&OldDecl, + LookupResult &Previous) { + // Disallow mixing of multiversioning types. - if (!MultiVersionTypesCompatible(OldMVKind, NewMVKind)) { + if (!MultiVersionTypesCompatible(OldFD, NewFD)) { S.Diag(NewFD->getLocation(), diag::err_multiversion_types_mixed); S.Diag(OldFD->getLocation(), diag::note_previous_declaration); NewFD->setInvalidDecl(); return true; } + // Add the default target_version attribute if it's missing. + patchDefaultTargetVersion(OldFD, NewFD); + patchDefaultTargetVersion(NewFD, OldFD); + + const auto *NewTA = NewFD->getAttr(); + const auto *NewTVA = NewFD->getAttr(); + MultiVersionKind NewMVKind = NewFD->getMultiVersionKind(); + [[maybe_unused]] MultiVersionKind OldMVKind = OldFD->getMultiVersionKind(); + ParsedTargetAttr NewParsed; if (NewTA) { NewParsed = S.getASTContext().getTargetInfo().parseTargetAttr( @@ -11641,19 +11684,6 @@ static bool CheckMultiVersionAdditionalDecl( S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules)) continue; - if (NewMVKind == MultiVersionKind::None && - OldMVKind == MultiVersionKind::TargetVersion) { - NewFD->addAttr(TargetVersionAttr::CreateImplicit( - S.Context, "default", NewFD->getSourceRange())); - NewFD->setIsMultiVersion(); - NewMVKind = MultiVersionKind::TargetVersion; - if (!NewTVA) { - NewTVA = NewFD->getAttr(); - NewTVA->getFeatures(NewFeats); - llvm::sort(NewFeats); - } - } - switch (NewMVKind) { case MultiVersionKind::None: assert(OldMVKind == MultiVersionKind::TargetClones && @@ -11681,43 +11711,81 @@ static bool CheckMultiVersionAdditionalDecl( break; } case MultiVersionKind::TargetVersion: { - const auto *CurTVA = CurFD->getAttr(); - if (CurTVA->getName() == NewTVA->getName()) { - NewFD->setIsMultiVersion(); - Redeclaration = true; - OldDecl = ND; - return false; - } - llvm::SmallVector CurFeats; - if (CurTVA) { + if (const auto *CurTVA = CurFD->getAttr()) { + if (CurTVA->getName() == NewTVA->getName()) { + NewFD->setIsMultiVersion(); + Redeclaration = true; + OldDecl = ND; + return false; + } + llvm::SmallVector CurFeats; CurTVA->getFeatures(CurFeats); llvm::sort(CurFeats); - } - if (CurFeats == NewFeats) { - S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); - S.Diag(CurFD->getLocation(), diag::note_previous_declaration); - NewFD->setInvalidDecl(); - return true; + + if (CurFeats == NewFeats) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); + S.Diag(CurFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + } else if (const auto *CurClones = CurFD->getAttr()) { + // Default + if (NewFeats.empty()) + break; + + for (unsigned I = 0; I < CurClones->featuresStrs_size(); ++I) { + llvm::SmallVector CurFeats; + CurClones->getFeatures(CurFeats, I); + llvm::sort(CurFeats); + + if (CurFeats == NewFeats) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); + S.Diag(CurFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + } } break; } case MultiVersionKind::TargetClones: { - const auto *CurClones = CurFD->getAttr(); + assert(NewClones && "MultiVersionKind does not match attribute type"); + if (const auto *CurClones = CurFD->getAttr()) { + if (CurClones->featuresStrs_size() != NewClones->featuresStrs_size() || + !std::equal(CurClones->featuresStrs_begin(), + CurClones->featuresStrs_end(), + NewClones->featuresStrs_begin())) { + S.Diag(NewFD->getLocation(), diag::err_target_clone_doesnt_match); + S.Diag(CurFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + } else if (const auto *CurTVA = CurFD->getAttr()) { + llvm::SmallVector CurFeats; + CurTVA->getFeatures(CurFeats); + llvm::sort(CurFeats); + + // Default + if (CurFeats.empty()) + break; + + for (unsigned I = 0; I < NewClones->featuresStrs_size(); ++I) { + NewFeats.clear(); + NewClones->getFeatures(NewFeats, I); + llvm::sort(NewFeats); + + if (CurFeats == NewFeats) { + S.Diag(NewFD->getLocation(), diag::err_multiversion_duplicate); + S.Diag(CurFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + return true; + } + } + break; + } Redeclaration = true; OldDecl = CurFD; NewFD->setIsMultiVersion(); - - if (CurClones && NewClones && - (CurClones->featuresStrs_size() != NewClones->featuresStrs_size() || - !std::equal(CurClones->featuresStrs_begin(), - CurClones->featuresStrs_end(), - NewClones->featuresStrs_begin()))) { - S.Diag(NewFD->getLocation(), diag::err_target_clone_doesnt_match); - S.Diag(CurFD->getLocation(), diag::note_previous_declaration); - NewFD->setInvalidDecl(); - return true; - } - return false; } case MultiVersionKind::CPUSpecific: @@ -11913,7 +11981,7 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD, // At this point, we have a multiversion function decl (in OldFD) AND an // appropriate attribute in the current function decl. Resolve that these are // still compatible with previous declarations. - return CheckMultiVersionAdditionalDecl(S, OldFD, NewFD, MVKind, NewCPUDisp, + return CheckMultiVersionAdditionalDecl(S, OldFD, NewFD, NewCPUDisp, NewCPUSpec, NewClones, Redeclaration, OldDecl, Previous); } @@ -12043,6 +12111,35 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, CheckConstPureAttributesUsage(*this, NewFD); + // C++ [dcl.spec.auto.general]p12: + // Return type deduction for a templated function with a placeholder in its + // declared type occurs when the definition is instantiated even if the + // function body contains a return statement with a non-type-dependent + // operand. + // + // C++ [temp.dep.expr]p3: + // An id-expression is type-dependent if it is a template-id that is not a + // concept-id and is dependent; or if its terminal name is: + // - [...] + // - associated by name lookup with one or more declarations of member + // functions of a class that is the current instantiation declared with a + // return type that contains a placeholder type, + // - [...] + // + // If this is a templated function with a placeholder in its return type, + // make the placeholder type dependent since it won't be deduced until the + // definition is instantiated. We do this here because it needs to happen + // for implicitly instantiated member functions/member function templates. + if (getLangOpts().CPlusPlus14 && + (NewFD->isDependentContext() && + NewFD->getReturnType()->isUndeducedType())) { + const FunctionProtoType *FPT = + NewFD->getType()->castAs(); + QualType NewReturnType = SubstAutoTypeDependent(FPT->getReturnType()); + NewFD->setType(Context.getFunctionType(NewReturnType, FPT->getParamTypes(), + FPT->getExtProtoInfo())); + } + // C++11 [dcl.constexpr]p8: // A constexpr specifier for a non-static member function that is not // a constructor declares that member function to be const. @@ -12297,12 +12394,22 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } // Check if the function definition uses any AArch64 SME features without - // having the '+sme' feature enabled. + // having the '+sme' feature enabled and warn user if sme locally streaming + // function returns or uses arguments with VL-based types. if (DeclIsDefn) { const auto *Attr = NewFD->getAttr(); bool UsesSM = NewFD->hasAttr(); bool UsesZA = Attr && Attr->isNewZA(); bool UsesZT0 = Attr && Attr->isNewZT0(); + + if (NewFD->hasAttr()) { + if (NewFD->getReturnType()->isSizelessVectorType() || + llvm::any_of(NewFD->parameters(), [](ParmVarDecl *P) { + return P->getOriginalType()->isSizelessVectorType(); + })) + Diag(NewFD->getLocation(), + diag::warn_sme_locally_streaming_has_vl_args_returns); + } if (const auto *FPT = NewFD->getType()->getAs()) { FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); UsesSM |= @@ -15199,7 +15306,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D, QualType parmDeclType = TInfo->getType(); // Check for redeclaration of parameters, e.g. int foo(int x, int x); - IdentifierInfo *II = D.getIdentifier(); + const IdentifierInfo *II = D.getIdentifier(); if (II) { LookupResult R(*this, II, D.getIdentifierLoc(), LookupOrdinaryName, ForVisibleRedeclaration); @@ -15351,9 +15458,9 @@ QualType Sema::AdjustParameterTypeForObjCAutoRefCount(QualType T, } ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, - SourceLocation NameLoc, IdentifierInfo *Name, - QualType T, TypeSourceInfo *TSInfo, - StorageClass SC) { + SourceLocation NameLoc, + const IdentifierInfo *Name, QualType T, + TypeSourceInfo *TSInfo, StorageClass SC) { // In ARC, infer a lifetime qualifier for appropriate parameter types. if (getLangOpts().ObjCAutoRefCount && T.getObjCLifetime() == Qualifiers::OCL_None && @@ -18101,7 +18208,9 @@ CreateNewDecl: cast_or_null(PrevDecl)); } - if (OOK != OOK_Outside && TUK == TUK_Definition && !getLangOpts().CPlusPlus) + // Only C23 and later allow defining new types in 'offsetof()'. + if (OOK != OOK_Outside && TUK == TUK_Definition && !getLangOpts().CPlusPlus && + !getLangOpts().C23) Diag(New->getLocation(), diag::ext_type_defined_in_offsetof) << (OOK == OOK_Macro) << New->getSourceRange(); @@ -18248,8 +18357,10 @@ CreateNewDecl: if (PrevDecl) mergeDeclAttributes(New, PrevDecl); - if (auto *CXXRD = dyn_cast(New)) + if (auto *CXXRD = dyn_cast(New)) { inferGslOwnerPointerAttribute(CXXRD); + inferNullableClassAttribute(CXXRD); + } // If there's a #pragma GCC visibility in scope, set the visibility of this // record. @@ -18439,8 +18550,9 @@ void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) { // Note that FieldName may be null for anonymous bitfields. ExprResult Sema::VerifyBitField(SourceLocation FieldLoc, - IdentifierInfo *FieldName, QualType FieldTy, - bool IsMsStruct, Expr *BitWidth) { + const IdentifierInfo *FieldName, + QualType FieldTy, bool IsMsStruct, + Expr *BitWidth) { assert(BitWidth); if (BitWidth->containsErrors()) return ExprError(); @@ -18549,7 +18661,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, return nullptr; } - IdentifierInfo *II = D.getIdentifier(); + const IdentifierInfo *II = D.getIdentifier(); SourceLocation Loc = DeclStart; if (II) Loc = D.getIdentifierLoc(); @@ -18650,7 +18762,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, SourceLocation TSSL, AccessSpecifier AS, NamedDecl *PrevDecl, Declarator *D) { - IdentifierInfo *II = Name.getAsIdentifierInfo(); + const IdentifierInfo *II = Name.getAsIdentifierInfo(); bool InvalidDecl = false; if (D) InvalidDecl = D->isInvalidType(); @@ -18910,7 +19022,7 @@ TranslateIvarVisibility(tok::ObjCKeywordKind ivarVisibility) { Decl *Sema::ActOnIvar(Scope *S, SourceLocation DeclStart, Declarator &D, Expr *BitWidth, tok::ObjCKeywordKind Visibility) { - IdentifierInfo *II = D.getIdentifier(); + const IdentifierInfo *II = D.getIdentifier(); SourceLocation Loc = DeclStart; if (II) Loc = D.getIdentifierLoc(); @@ -19360,15 +19472,11 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, } else if (Record->isUnion()) DiagID = getLangOpts().MicrosoftExt ? diag::ext_flexible_array_union_ms - : getLangOpts().CPlusPlus - ? diag::ext_flexible_array_union_gnu - : diag::err_flexible_array_union; + : diag::ext_flexible_array_union_gnu; else if (NumNamedMembers < 1) DiagID = getLangOpts().MicrosoftExt ? diag::ext_flexible_array_empty_aggregate_ms - : getLangOpts().CPlusPlus - ? diag::ext_flexible_array_empty_aggregate_gnu - : diag::err_flexible_array_empty_aggregate; + : diag::ext_flexible_array_empty_aggregate_gnu; if (DiagID) Diag(FD->getLocation(), DiagID) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 0a62c656d824ffc47d7c28a989dd5dfa4a13e54b..8bce04640e748e8a419f6f76cfa38844568ea2c6 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5271,6 +5271,9 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { case ParsedAttr::AT_PreserveNone: D->addAttr(::new (S.Context) PreserveNoneAttr(S.Context, AL)); return; + case ParsedAttr::AT_RISCVVectorCC: + D->addAttr(::new (S.Context) RISCVVectorCCAttr(S.Context, AL)); + return; default: llvm_unreachable("unexpected attribute kind"); } @@ -5475,6 +5478,9 @@ bool Sema::CheckCallingConvAttr(const ParsedAttr &Attrs, CallingConv &CC, case ParsedAttr::AT_PreserveNone: CC = CC_PreserveNone; break; + case ParsedAttr::AT_RISCVVectorCC: + CC = CC_RISCVVectorCall; + break; default: llvm_unreachable("unexpected attribute kind"); } @@ -5976,6 +5982,20 @@ static void handleBuiltinAliasAttr(Sema &S, Decl *D, D->addAttr(::new (S.Context) BuiltinAliasAttr(S.Context, AL, Ident)); } +static void handleNullableTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (AL.isUsedAsTypeAttr()) + return; + + if (auto *CRD = dyn_cast(D); + !CRD || !(CRD->isClass() || CRD->isStruct())) { + S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type_str) + << AL << AL.isRegularKeywordAttribute() << "classes"; + return; + } + + handleSimpleAttribute(S, D, AL); +} + static void handlePreferredTypeAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.hasParsedType()) { S.Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1; @@ -9637,6 +9657,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_AMDGPUKernelCall: case ParsedAttr::AT_M68kRTD: case ParsedAttr::AT_PreserveNone: + case ParsedAttr::AT_RISCVVectorCC: handleCallConvAttr(S, D, AL); break; case ParsedAttr::AT_Suppress: @@ -9926,6 +9947,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_UsingIfExists: handleSimpleAttribute(S, D, AL); break; + + case ParsedAttr::AT_TypeNullable: + handleNullableTypeAttr(S, D, AL); + break; } } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index ee732679417e37c5c5584a6591e16f87c2ebd54e..858951580ea45b9eddfae4427310ff8b1dcca90a 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -5282,7 +5282,7 @@ static bool isIncompleteOrZeroLengthArrayType(ASTContext &Context, QualType T) { return true; while (const ConstantArrayType *ArrayT = Context.getAsConstantArrayType(T)) { - if (!ArrayT->getSize()) + if (ArrayT->isZeroSize()) return true; T = ArrayT->getElementType(); @@ -11353,7 +11353,7 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { if (ConvType->isUndeducedAutoType()) { Diag(Conversion->getTypeSpecStartLoc(), diag::err_auto_not_allowed) << getReturnTypeLoc(Conversion).getSourceRange() - << llvm::to_underlying(ConvType->getAs()->getKeyword()) + << llvm::to_underlying(ConvType->castAs()->getKeyword()) << /* in declaration of conversion function template= */ 24; } @@ -13589,6 +13589,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS, Diag(UsingLoc, diag::err_alias_template_extra_headers) << SourceRange(TemplateParamLists[1]->getTemplateLoc(), TemplateParamLists[TemplateParamLists.size()-1]->getRAngleLoc()); + Invalid = true; } TemplateParameterList *TemplateParams = TemplateParamLists[0]; @@ -16202,7 +16203,8 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { // Emit warning for non-trivial dtor in global scope (a real global, // class-static, function-static). - Diag(VD->getLocation(), diag::warn_exit_time_destructor); + if (!VD->hasAttr()) + Diag(VD->getLocation(), diag::warn_exit_time_destructor); // TODO: this should be re-enabled for static locals by !CXAAtExit if (!VD->isStaticLocal()) @@ -16911,11 +16913,10 @@ Decl *Sema::ActOnEmptyDeclaration(Scope *S, /// Perform semantic analysis for the variable declaration that /// occurs within a C++ catch clause, returning the newly-created /// variable. -VarDecl *Sema::BuildExceptionDeclaration(Scope *S, - TypeSourceInfo *TInfo, +VarDecl *Sema::BuildExceptionDeclaration(Scope *S, TypeSourceInfo *TInfo, SourceLocation StartLoc, SourceLocation Loc, - IdentifierInfo *Name) { + const IdentifierInfo *Name) { bool Invalid = false; QualType ExDeclType = TInfo->getType(); @@ -17060,7 +17061,7 @@ Decl *Sema::ActOnExceptionDeclarator(Scope *S, Declarator &D) { Invalid = true; } - IdentifierInfo *II = D.getIdentifier(); + const IdentifierInfo *II = D.getIdentifier(); if (NamedDecl *PrevDecl = LookupSingleName(S, II, D.getIdentifierLoc(), LookupOrdinaryName, ForVisibleRedeclaration)) { @@ -18562,6 +18563,9 @@ DeclResult Sema::ActOnCXXConditionDeclaration(Scope *S, Declarator &D) { return true; } + if (auto *VD = dyn_cast(Dcl)) + VD->setCXXCondDecl(); + return Dcl; } @@ -19153,7 +19157,7 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record, InClassInitStyle InitStyle, AccessSpecifier AS, const ParsedAttr &MSPropertyAttr) { - IdentifierInfo *II = D.getIdentifier(); + const IdentifierInfo *II = D.getIdentifier(); if (!II) { Diag(DeclStart, diag::err_anonymous_property); return nullptr; diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 94a245f0f905f33a2bc9d2512b30419f6646eb47..74d6f0700b0e4f52e79864564426133328a0e723 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -1818,9 +1818,9 @@ Sema::ActOnForwardProtocolDeclaration(SourceLocation AtProtocolLoc, } ObjCCategoryDecl *Sema::ActOnStartCategoryInterface( - SourceLocation AtInterfaceLoc, IdentifierInfo *ClassName, + SourceLocation AtInterfaceLoc, const IdentifierInfo *ClassName, SourceLocation ClassLoc, ObjCTypeParamList *typeParamList, - IdentifierInfo *CategoryName, SourceLocation CategoryLoc, + const IdentifierInfo *CategoryName, SourceLocation CategoryLoc, Decl *const *ProtoRefs, unsigned NumProtoRefs, const SourceLocation *ProtoLocs, SourceLocation EndProtoLoc, const ParsedAttributesView &AttrList) { @@ -1916,9 +1916,9 @@ ObjCCategoryDecl *Sema::ActOnStartCategoryInterface( /// category implementation declaration and build an ObjCCategoryImplDecl /// object. ObjCCategoryImplDecl *Sema::ActOnStartCategoryImplementation( - SourceLocation AtCatImplLoc, IdentifierInfo *ClassName, - SourceLocation ClassLoc, IdentifierInfo *CatName, SourceLocation CatLoc, - const ParsedAttributesView &Attrs) { + SourceLocation AtCatImplLoc, const IdentifierInfo *ClassName, + SourceLocation ClassLoc, const IdentifierInfo *CatName, + SourceLocation CatLoc, const ParsedAttributesView &Attrs) { ObjCInterfaceDecl *IDecl = getObjCInterfaceDecl(ClassName, ClassLoc, true); ObjCCategoryDecl *CatIDecl = nullptr; if (IDecl && IDecl->hasDefinition()) { @@ -1982,8 +1982,8 @@ ObjCCategoryImplDecl *Sema::ActOnStartCategoryImplementation( } ObjCImplementationDecl *Sema::ActOnStartClassImplementation( - SourceLocation AtClassImplLoc, IdentifierInfo *ClassName, - SourceLocation ClassLoc, IdentifierInfo *SuperClassname, + SourceLocation AtClassImplLoc, const IdentifierInfo *ClassName, + SourceLocation ClassLoc, const IdentifierInfo *SuperClassname, SourceLocation SuperClassLoc, const ParsedAttributesView &Attrs) { ObjCInterfaceDecl *IDecl = nullptr; // Check for another declaration kind with the same name. @@ -2751,7 +2751,7 @@ static void CheckProtocolMethodDefs( // implemented in the class, we should not issue "Method definition not // found" warnings. // FIXME: Use a general GetUnarySelector method for this. - IdentifierInfo* II = &S.Context.Idents.get("forwardInvocation"); + const IdentifierInfo *II = &S.Context.Idents.get("forwardInvocation"); Selector fISelector = S.Context.Selectors.getSelector(1, &II); if (InsMap.count(fISelector)) // Is IDecl derived from 'NSProxy'? If so, no instance methods @@ -5105,8 +5105,8 @@ bool Sema::CheckObjCDeclScope(Decl *D) { /// Called whenever \@defs(ClassName) is encountered in the source. Inserts the /// instance variables of ClassName into Decls. void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, - IdentifierInfo *ClassName, - SmallVectorImpl &Decls) { + const IdentifierInfo *ClassName, + SmallVectorImpl &Decls) { // Check that ClassName is a valid class ObjCInterfaceDecl *Class = getObjCInterfaceDecl(ClassName, DeclStart); if (!Class) { @@ -5148,8 +5148,7 @@ void Sema::ActOnDefs(Scope *S, Decl *TagD, SourceLocation DeclStart, VarDecl *Sema::BuildObjCExceptionDecl(TypeSourceInfo *TInfo, QualType T, SourceLocation StartLoc, SourceLocation IdLoc, - IdentifierInfo *Id, - bool Invalid) { + const IdentifierInfo *Id, bool Invalid) { // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage // duration shall not be qualified by an address-space qualifier." // Since all parameters have automatic store duration, they can not have diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 5f03b981428251ca23c34d5cd96b4bec370222b2..846e7d5d3ab92b7ef6d1fb13aee536bf53c0961f 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -658,8 +658,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { QualType T = E->getType(); assert(!T.isNull() && "r-value conversion on typeless expression?"); - // lvalue-to-rvalue conversion cannot be applied to function or array types. - if (T->isFunctionType() || T->isArrayType()) + // lvalue-to-rvalue conversion cannot be applied to types that decay to + // pointers (i.e. function or array types). + if (T->canDecayToPointerType()) return E; // We don't want to throw lvalue-to-rvalue casts on top of @@ -2750,7 +2751,7 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, QualType type = VD->getType().getNonReferenceType(); // This will eventually be translated into MemberExpr upon // the use of instantiated struct fields. - return BuildDeclRefExpr(VD, type, VK_PRValue, NameLoc); + return BuildDeclRefExpr(VD, type, VK_LValue, NameLoc); } } } @@ -2911,26 +2912,9 @@ Sema::ActOnIdExpression(Scope *S, CXXScopeSpec &SS, // to get this right here so that we don't end up making a // spuriously dependent expression if we're inside a dependent // instance method. - if (getLangOpts().CPlusPlus && !R.empty() && - (*R.begin())->isCXXClassMember()) { - bool MightBeImplicitMember; - if (!IsAddressOfOperand) - MightBeImplicitMember = true; - else if (!SS.isEmpty()) - MightBeImplicitMember = false; - else if (R.isOverloadedResult()) - MightBeImplicitMember = false; - else if (R.isUnresolvableResult()) - MightBeImplicitMember = true; - else - MightBeImplicitMember = isa(R.getFoundDecl()) || - isa(R.getFoundDecl()) || - isa(R.getFoundDecl()); - - if (MightBeImplicitMember) - return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, - R, TemplateArgs, S); - } + if (isPotentialImplicitMemberAccess(SS, R, IsAddressOfOperand)) + return BuildPossibleImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, + S); if (TemplateArgs || TemplateKWLoc.isValid()) { @@ -3441,10 +3425,11 @@ static bool ShouldLookupResultBeMultiVersionOverload(const LookupResult &R) { ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R, bool NeedsADL, - bool AcceptInvalidDecl) { + bool AcceptInvalidDecl, + bool NeedUnresolved) { // If this is a single, fully-resolved result and we don't need ADL, // just build an ordinary singleton decl ref. - if (!NeedsADL && R.isSingleResult() && + if (!NeedUnresolved && !NeedsADL && R.isSingleResult() && !R.getAsSingle() && !ShouldLookupResultBeMultiVersionOverload(R)) return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(), @@ -3793,28 +3778,6 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, SL); } -ExprResult Sema::BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc, - SourceLocation LParen, - SourceLocation RParen, - TypeSourceInfo *TSI) { - return SYCLUniqueStableNameExpr::Create(Context, OpLoc, LParen, RParen, TSI); -} - -ExprResult Sema::ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc, - SourceLocation LParen, - SourceLocation RParen, - ParsedType ParsedTy) { - TypeSourceInfo *TSI = nullptr; - QualType Ty = GetTypeFromParser(ParsedTy, &TSI); - - if (Ty.isNull()) - return ExprError(); - if (!TSI) - TSI = Context.getTrivialTypeSourceInfo(Ty, LParen); - - return BuildSYCLUniqueStableNameExpr(OpLoc, LParen, RParen, TSI); -} - ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { return BuildPredefinedExpr(Loc, getPredefinedExprKind(Kind)); } @@ -4116,7 +4079,8 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { } else if (Literal.isFloatingLiteral()) { QualType Ty; if (Literal.isHalf){ - if (getOpenCLOptions().isAvailableOption("cl_khr_fp16", getLangOpts())) + if (getLangOpts().HLSL || + getOpenCLOptions().isAvailableOption("cl_khr_fp16", getLangOpts())) Ty = Context.HalfTy; else { Diag(Tok.getLocation(), diag::err_half_const_requires_fp16); @@ -4125,7 +4089,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { } else if (Literal.isFloat) Ty = Context.FloatTy; else if (Literal.isLong) - Ty = Context.LongDoubleTy; + Ty = !getLangOpts().HLSL ? Context.LongDoubleTy : Context.DoubleTy; else if (Literal.isFloat16) Ty = Context.Float16Ty; else if (Literal.isFloat128) @@ -4686,6 +4650,9 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, case Type::Decayed: T = cast(Ty)->getPointeeType(); break; + case Type::ArrayParameter: + T = cast(Ty)->getElementType(); + break; case Type::Pointer: T = cast(Ty)->getPointeeType(); break; @@ -6857,9 +6824,8 @@ Sema::CheckStaticArrayArgument(SourceLocation CallLoc, ArgCAT->getElementType())) { if (ArgCAT->getSize().ult(CAT->getSize())) { Diag(CallLoc, diag::warn_static_array_too_small) - << ArgExpr->getSourceRange() - << (unsigned)ArgCAT->getSize().getZExtValue() - << (unsigned)CAT->getSize().getZExtValue() << 0; + << ArgExpr->getSourceRange() << (unsigned)ArgCAT->getZExtSize() + << (unsigned)CAT->getZExtSize() << 0; DiagnoseCalleeStaticArrayParam(*this, Param); } return; @@ -7475,7 +7441,7 @@ ExprResult Sema::ActOnConvertVectorExpr(Expr *E, ParsedType ParsedDestTy, SourceLocation RParenLoc) { TypeSourceInfo *TInfo; GetTypeFromParser(ParsedDestTy, &TInfo); - return SemaConvertVectorExpr(E, TInfo, BuiltinLoc, RParenLoc); + return ConvertVectorExpr(E, TInfo, BuiltinLoc, RParenLoc); } /// BuildResolvedCallExpr - Build a call to a resolved expression, @@ -12909,6 +12875,8 @@ static ImplicitConversionKind castKindToImplicitConversionKind(CastKind CK) { case CK_IntegralComplexToReal: case CK_IntegralRealToComplex: return ICK_Complex_Real; + case CK_HLSLArrayRValue: + return ICK_HLSL_Array_RValue; } } @@ -18975,8 +18943,10 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // Note that we skip the implicit instantiation of templates that are only // used in unused default arguments or by recursive calls to themselves. // This is formally non-conforming, but seems reasonable in practice. - bool NeedDefinition = !IsRecursiveCall && (OdrUse == OdrUseContext::Used || - NeededForConstantEvaluation); + bool NeedDefinition = + !IsRecursiveCall && + (OdrUse == OdrUseContext::Used || + (NeededForConstantEvaluation && !Func->isPureVirtual())); // C++14 [temp.expl.spec]p6: // If a template [...] is explicitly specialized then that specialization @@ -20713,20 +20683,42 @@ void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) { static void FixDependencyOfIdExpressionsInLambdaWithDependentObjectParameter( Sema &SemaRef, ValueDecl *D, Expr *E) { auto *ID = dyn_cast(E); - if (!ID || ID->isTypeDependent()) + if (!ID || ID->isTypeDependent() || !ID->refersToEnclosingVariableOrCapture()) return; + // If any enclosing lambda with a dependent explicit object parameter either + // explicitly captures the variable by value, or has a capture default of '=' + // and does not capture the variable by reference, then the type of the DRE + // is dependent on the type of that lambda's explicit object parameter. auto IsDependent = [&]() { - const LambdaScopeInfo *LSI = SemaRef.getCurLambda(); - if (!LSI) - return false; - if (!LSI->ExplicitObjectParameter || - !LSI->ExplicitObjectParameter->getType()->isDependentType()) - return false; - if (!LSI->CaptureMap.count(D)) - return false; - const Capture &Cap = LSI->getCapture(D); - return !Cap.isCopyCapture(); + for (auto *Scope : llvm::reverse(SemaRef.FunctionScopes)) { + auto *LSI = dyn_cast(Scope); + if (!LSI) + continue; + + if (LSI->Lambda && !LSI->Lambda->Encloses(SemaRef.CurContext) && + LSI->AfterParameterList) + return false; + + const auto *MD = LSI->CallOperator; + if (MD->getType().isNull()) + continue; + + const auto *Ty = cast(MD->getType()); + if (!Ty || !MD->isExplicitObjectMemberFunction() || + !Ty->getParamType(0)->isDependentType()) + continue; + + if (auto *C = LSI->CaptureMap.count(D) ? &LSI->getCapture(D) : nullptr) { + if (C->isCopyCapture()) + return true; + continue; + } + + if (LSI->ImpCaptureStyle == LambdaScopeInfo::ImpCap_LambdaByval) + return true; + } + return false; }(); ID->setCapturedByCopyInLambdaWithExplicitObjectParameter( diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index c34a40fa7c81ac9ac3d3c67371a1da05ebe17a92..763901d4418d20c587a3fb6768c2730401c2229c 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -57,7 +57,7 @@ using namespace sema; /// name of the corresponding type. ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS, SourceLocation NameLoc, - IdentifierInfo &Name) { + const IdentifierInfo &Name) { NestedNameSpecifier *NNS = SS.getScopeRep(); // Convert the nested-name-specifier into a type. @@ -89,10 +89,9 @@ ParsedType Sema::getInheritingConstructorName(CXXScopeSpec &SS, Context.getTrivialTypeSourceInfo(Type, NameLoc)); } -ParsedType Sema::getConstructorName(IdentifierInfo &II, - SourceLocation NameLoc, - Scope *S, CXXScopeSpec &SS, - bool EnteringContext) { +ParsedType Sema::getConstructorName(const IdentifierInfo &II, + SourceLocation NameLoc, Scope *S, + CXXScopeSpec &SS, bool EnteringContext) { CXXRecordDecl *CurClass = getCurrentClass(S, &SS); assert(CurClass && &II == CurClass->getIdentifier() && "not a constructor name"); @@ -140,9 +139,9 @@ ParsedType Sema::getConstructorName(IdentifierInfo &II, return ParsedType::make(T); } -ParsedType Sema::getDestructorName(IdentifierInfo &II, SourceLocation NameLoc, - Scope *S, CXXScopeSpec &SS, - ParsedType ObjectTypePtr, +ParsedType Sema::getDestructorName(const IdentifierInfo &II, + SourceLocation NameLoc, Scope *S, + CXXScopeSpec &SS, ParsedType ObjectTypePtr, bool EnteringContext) { // Determine where to perform name lookup. @@ -500,7 +499,7 @@ bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, // // double operator""_Bq(long double); // OK: not a reserved identifier // double operator"" _Bq(long double); // ill-formed, no diagnostic required - IdentifierInfo *II = Name.Identifier; + const IdentifierInfo *II = Name.Identifier; ReservedIdentifierStatus Status = II->isReserved(PP.getLangOpts()); SourceLocation Loc = Name.getEndLoc(); if (!PP.getSourceManager().isInSystemHeader(Loc)) { @@ -1415,26 +1414,42 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, } ExprResult Sema::ActOnCXXThis(SourceLocation Loc) { - /// C++ 9.3.2: In the body of a non-static member function, the keyword this - /// is a non-lvalue expression whose value is the address of the object for - /// which the function is called. + // C++20 [expr.prim.this]p1: + // The keyword this names a pointer to the object for which an + // implicit object member function is invoked or a non-static + // data member's initializer is evaluated. QualType ThisTy = getCurrentThisType(); - if (ThisTy.isNull()) { - DeclContext *DC = getFunctionLevelDeclContext(); + if (CheckCXXThisType(Loc, ThisTy)) + return ExprError(); - if (const auto *Method = dyn_cast(DC); - Method && Method->isExplicitObjectMemberFunction()) { - return Diag(Loc, diag::err_invalid_this_use) << 1; - } + return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false); +} - if (isLambdaCallWithExplicitObjectParameter(CurContext)) - return Diag(Loc, diag::err_invalid_this_use) << 1; +bool Sema::CheckCXXThisType(SourceLocation Loc, QualType Type) { + if (!Type.isNull()) + return false; - return Diag(Loc, diag::err_invalid_this_use) << 0; + // C++20 [expr.prim.this]p3: + // If a declaration declares a member function or member function template + // of a class X, the expression this is a prvalue of type + // "pointer to cv-qualifier-seq X" wherever X is the current class between + // the optional cv-qualifier-seq and the end of the function-definition, + // member-declarator, or declarator. It shall not appear within the + // declaration of either a static member function or an explicit object + // member function of the current class (although its type and value + // category are defined within such member functions as they are within + // an implicit object member function). + DeclContext *DC = getFunctionLevelDeclContext(); + if (const auto *Method = dyn_cast(DC); + Method && Method->isExplicitObjectMemberFunction()) { + Diag(Loc, diag::err_invalid_this_use) << 1; + } else if (isLambdaCallWithExplicitObjectParameter(CurContext)) { + Diag(Loc, diag::err_invalid_this_use) << 1; + } else { + Diag(Loc, diag::err_invalid_this_use) << 0; } - - return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false); + return true; } Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type, @@ -1446,6 +1461,42 @@ Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type, void Sema::MarkThisReferenced(CXXThisExpr *This) { CheckCXXThisCapture(This->getExprLoc()); + if (This->isTypeDependent()) + return; + + // Check if 'this' is captured by value in a lambda with a dependent explicit + // object parameter, and mark it as type-dependent as well if so. + auto IsDependent = [&]() { + for (auto *Scope : llvm::reverse(FunctionScopes)) { + auto *LSI = dyn_cast(Scope); + if (!LSI) + continue; + + if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext) && + LSI->AfterParameterList) + return false; + + // If this lambda captures 'this' by value, then 'this' is dependent iff + // this lambda has a dependent explicit object parameter. If we can't + // determine whether it does (e.g. because the CXXMethodDecl's type is + // null), assume it doesn't. + if (LSI->isCXXThisCaptured()) { + if (!LSI->getCXXThisCapture().isCopyCapture()) + continue; + + const auto *MD = LSI->CallOperator; + if (MD->getType().isNull()) + return false; + + const auto *Ty = cast(MD->getType()); + return Ty && MD->isExplicitObjectMemberFunction() && + Ty->getParamType(0)->isDependentType(); + } + } + return false; + }(); + + This->setCapturedByCopyInLambdaWithExplicitObjectParameter(IsDependent); } bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) { @@ -3938,9 +3989,8 @@ static bool resolveBuiltinNewDeleteOverload(Sema &S, CallExpr *TheCall, llvm_unreachable("Unreachable, bad result from BestViableFunction"); } -ExprResult -Sema::SemaBuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, - bool IsDelete) { +ExprResult Sema::BuiltinOperatorNewDeleteOverloaded(ExprResult TheCallResult, + bool IsDelete) { CallExpr *TheCall = cast(TheCallResult.get()); if (!getLangOpts().CPlusPlus) { Diag(TheCall->getExprLoc(), diag::err_builtin_requires_language) @@ -4416,6 +4466,13 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, .get(); break; + case ICK_HLSL_Array_RValue: + FromType = Context.getArrayParameterType(FromType); + From = ImpCastExprToType(From, FromType, CK_HLSLArrayRValue, VK_PRValue, + /*BasePath=*/nullptr, CCK) + .get(); + break; + case ICK_Function_To_Pointer: FromType = Context.getPointerType(FromType); From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay, @@ -4793,6 +4850,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_Num_Conversion_Kinds: case ICK_C_Only_Conversion: case ICK_Incompatible_Pointer_Conversion: + case ICK_HLSL_Array_RValue: llvm_unreachable("Improper second standard conversion"); } @@ -5559,8 +5617,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, } } -static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, - QualType RhsT, SourceLocation KeyLoc); +static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceInfo *Lhs, + const TypeSourceInfo *Rhs, SourceLocation KeyLoc); static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, @@ -5576,8 +5634,8 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind, // Evaluate ReferenceBindsToTemporary and ReferenceConstructsFromTemporary // alongside the IsConstructible traits to avoid duplication. if (Kind <= BTT_Last && Kind != BTT_ReferenceBindsToTemporary && Kind != BTT_ReferenceConstructsFromTemporary) - return EvaluateBinaryTypeTrait(S, Kind, Args[0]->getType(), - Args[1]->getType(), RParenLoc); + return EvaluateBinaryTypeTrait(S, Kind, Args[0], + Args[1], RParenLoc); switch (Kind) { case clang::BTT_ReferenceBindsToTemporary: @@ -5672,8 +5730,8 @@ static bool EvaluateBooleanTypeTrait(Sema &S, TypeTrait Kind, if (U->isReferenceType()) return false; - QualType TPtr = S.Context.getPointerType(S.BuiltinRemoveReference(T, UnaryTransformType::RemoveCVRef, {})); - QualType UPtr = S.Context.getPointerType(S.BuiltinRemoveReference(U, UnaryTransformType::RemoveCVRef, {})); + TypeSourceInfo *TPtr = S.Context.CreateTypeSourceInfo(S.Context.getPointerType(S.BuiltinRemoveReference(T, UnaryTransformType::RemoveCVRef, {}))); + TypeSourceInfo *UPtr = S.Context.CreateTypeSourceInfo(S.Context.getPointerType(S.BuiltinRemoveReference(U, UnaryTransformType::RemoveCVRef, {}))); return EvaluateBinaryTypeTrait(S, TypeTrait::BTT_IsConvertibleTo, UPtr, TPtr, RParenLoc); } @@ -5807,8 +5865,11 @@ ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, return BuildTypeTrait(Kind, KWLoc, ConvertedArgs, RParenLoc); } -static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, - QualType RhsT, SourceLocation KeyLoc) { +static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceInfo *Lhs, + const TypeSourceInfo *Rhs, SourceLocation KeyLoc) { + QualType LhsT = Lhs->getType(); + QualType RhsT = Rhs->getType(); + assert(!LhsT->isDependentType() && !RhsT->isDependentType() && "Cannot evaluate traits of dependent types"); @@ -5833,7 +5894,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, return false; if (Self.RequireCompleteType( - KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) + Rhs->getTypeLoc().getBeginLoc(), RhsT, + diag::err_incomplete_type_used_in_type_trait_expr)) return false; return BaseInterface->isSuperClassOf(DerivedInterface); @@ -5856,8 +5918,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, // If Base and Derived are class types and are different types // (ignoring possible cv-qualifiers) then Derived shall be a // complete type. - if (Self.RequireCompleteType(KeyLoc, RhsT, - diag::err_incomplete_type_used_in_type_trait_expr)) + if (Self.RequireCompleteType( + Rhs->getTypeLoc().getBeginLoc(), RhsT, + diag::err_incomplete_type_used_in_type_trait_expr)) return false; return cast(rhsRecord->getDecl()) @@ -5909,7 +5972,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, return LhsT->isVoidType(); // A function definition requires a complete, non-abstract return type. - if (!Self.isCompleteType(KeyLoc, RhsT) || Self.isAbstractType(KeyLoc, RhsT)) + if (!Self.isCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT) || + Self.isAbstractType(Rhs->getTypeLoc().getBeginLoc(), RhsT)) return false; // Compute the result of add_rvalue_reference. @@ -5959,12 +6023,14 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, // For both, T and U shall be complete types, (possibly cv-qualified) // void, or arrays of unknown bound. if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() && - Self.RequireCompleteType(KeyLoc, LhsT, - diag::err_incomplete_type_used_in_type_trait_expr)) + Self.RequireCompleteType( + Lhs->getTypeLoc().getBeginLoc(), LhsT, + diag::err_incomplete_type_used_in_type_trait_expr)) return false; if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() && - Self.RequireCompleteType(KeyLoc, RhsT, - diag::err_incomplete_type_used_in_type_trait_expr)) + Self.RequireCompleteType( + Rhs->getTypeLoc().getBeginLoc(), RhsT, + diag::err_incomplete_type_used_in_type_trait_expr)) return false; // cv void is never assignable. @@ -6018,6 +6084,19 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, return false; } case BTT_IsLayoutCompatible: { + if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType()) + Self.RequireCompleteType(Lhs->getTypeLoc().getBeginLoc(), LhsT, + diag::err_incomplete_type); + if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType()) + Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT, + diag::err_incomplete_type); + + if (LhsT->isVariableArrayType()) + Self.Diag(Lhs->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported) + << 1 << tok::kw___is_layout_compatible; + if (RhsT->isVariableArrayType()) + Self.Diag(Rhs->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported) + << 1 << tok::kw___is_layout_compatible; return Self.IsLayoutCompatible(LhsT, RhsT); } default: llvm_unreachable("not a BTT"); @@ -6083,7 +6162,7 @@ static uint64_t EvaluateArrayTypeTrait(Sema &Self, ArrayTypeTrait ATT, if (Matched && T->isArrayType()) { if (const ConstantArrayType *CAT = Self.Context.getAsConstantArrayType(T)) - return CAT->getSize().getLimitedValue(); + return CAT->getLimitedSize(); } } return 0; @@ -8563,21 +8642,8 @@ static ExprResult attemptRecovery(Sema &SemaRef, // Detect and handle the case where the decl might be an implicit // member. - bool MightBeImplicitMember; - if (!Consumer.isAddressOfOperand()) - MightBeImplicitMember = true; - else if (!NewSS.isEmpty()) - MightBeImplicitMember = false; - else if (R.isOverloadedResult()) - MightBeImplicitMember = false; - else if (R.isUnresolvableResult()) - MightBeImplicitMember = true; - else - MightBeImplicitMember = isa(ND) || - isa(ND) || - isa(ND); - - if (MightBeImplicitMember) + if (SemaRef.isPotentialImplicitMemberAccess( + NewSS, R, Consumer.isAddressOfOperand())) return SemaRef.BuildPossibleImplicitMemberExpr( NewSS, /*TemplateKWLoc*/ SourceLocation(), R, /*TemplateArgs*/ nullptr, /*S*/ nullptr); @@ -9114,10 +9180,9 @@ concepts::Requirement *Sema::ActOnSimpleRequirement(Expr *E) { /*ReturnTypeRequirement=*/{}); } -concepts::Requirement * -Sema::ActOnTypeRequirement(SourceLocation TypenameKWLoc, CXXScopeSpec &SS, - SourceLocation NameLoc, IdentifierInfo *TypeName, - TemplateIdAnnotation *TemplateId) { +concepts::Requirement *Sema::ActOnTypeRequirement( + SourceLocation TypenameKWLoc, CXXScopeSpec &SS, SourceLocation NameLoc, + const IdentifierInfo *TypeName, TemplateIdAnnotation *TemplateId) { assert(((!TypeName && TemplateId) || (TypeName && !TemplateId)) && "Exactly one of TypeName and TemplateId must be specified."); TypeSourceInfo *TSI = nullptr; diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp index 32998ae60eafe2b3836b6bf8af40c1fc0d623079..eeac753a3489794df316186c32c7051c2d0533c0 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -61,6 +61,10 @@ enum IMAKind { /// The reference is a contextually-permitted abstract member reference. IMA_Abstract, + /// Whether the context is static is dependent on the enclosing template (i.e. + /// in a dependent class scope explicit specialization). + IMA_Dependent, + /// The reference may be to an unresolved using declaration and the /// context is not an instance method. IMA_Unresolved_StaticOrExplicitContext, @@ -91,10 +95,18 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, DeclContext *DC = SemaRef.getFunctionLevelDeclContext(); - bool isStaticOrExplicitContext = - SemaRef.CXXThisTypeOverride.isNull() && - (!isa(DC) || cast(DC)->isStatic() || - cast(DC)->isExplicitObjectMemberFunction()); + bool couldInstantiateToStatic = false; + bool isStaticOrExplicitContext = SemaRef.CXXThisTypeOverride.isNull(); + + if (auto *MD = dyn_cast(DC)) { + if (MD->isImplicitObjectMemberFunction()) { + isStaticOrExplicitContext = false; + // A dependent class scope function template explicit specialization + // that is neither declared 'static' nor with an explicit object + // parameter could instantiate to a static or non-static member function. + couldInstantiateToStatic = MD->getDependentSpecializationInfo(); + } + } if (R.isUnresolvableResult()) return isStaticOrExplicitContext ? IMA_Unresolved_StaticOrExplicitContext @@ -123,6 +135,9 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, if (Classes.empty()) return IMA_Static; + if (couldInstantiateToStatic) + return IMA_Dependent; + // C++11 [expr.prim.general]p12: // An id-expression that denotes a non-static data member or non-static // member function of a class can only be used: @@ -263,32 +278,52 @@ static void diagnoseInstanceReference(Sema &SemaRef, } } +bool Sema::isPotentialImplicitMemberAccess(const CXXScopeSpec &SS, + LookupResult &R, + bool IsAddressOfOperand) { + if (!getLangOpts().CPlusPlus) + return false; + else if (R.empty() || !R.begin()->isCXXClassMember()) + return false; + else if (!IsAddressOfOperand) + return true; + else if (!SS.isEmpty()) + return false; + else if (R.isOverloadedResult()) + return false; + else if (R.isUnresolvableResult()) + return true; + else + return isa(R.getFoundDecl()); +} + /// Builds an expression which might be an implicit member expression. ExprResult Sema::BuildPossibleImplicitMemberExpr( const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R, - const TemplateArgumentListInfo *TemplateArgs, const Scope *S, - UnresolvedLookupExpr *AsULE) { - switch (ClassifyImplicitMemberAccess(*this, R)) { + const TemplateArgumentListInfo *TemplateArgs, const Scope *S) { + switch (IMAKind Classification = ClassifyImplicitMemberAccess(*this, R)) { case IMA_Instance: - return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true, S); - case IMA_Mixed: case IMA_Mixed_Unrelated: case IMA_Unresolved: - return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, false, - S); - + return BuildImplicitMemberExpr( + SS, TemplateKWLoc, R, TemplateArgs, + /*IsKnownInstance=*/Classification == IMA_Instance, S); case IMA_Field_Uneval_Context: Diag(R.getNameLoc(), diag::warn_cxx98_compat_non_static_member_use) << R.getLookupNameInfo().getName(); [[fallthrough]]; case IMA_Static: case IMA_Abstract: + case IMA_Dependent: case IMA_Mixed_StaticOrExplicitContext: case IMA_Unresolved_StaticOrExplicitContext: if (TemplateArgs || TemplateKWLoc.isValid()) - return BuildTemplateIdExpr(SS, TemplateKWLoc, R, false, TemplateArgs); - return AsULE ? AsULE : BuildDeclarationNameExpr(SS, R, false); + return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*RequiresADL=*/false, + TemplateArgs); + return BuildDeclarationNameExpr( + SS, R, /*NeedsADL=*/false, /*AcceptInvalidDecl=*/false, + /*NeedUnresolved=*/Classification == IMA_Dependent); case IMA_Error_StaticOrExplicitContext: case IMA_Error_Unrelated: diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index a8853f634c9cc95d2fbc92de20945cf860c49939..3148f0db6e20c86bd3632f241fe756ecfe3583cb 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -663,10 +663,8 @@ ExprResult Sema::BuildObjCBoxedExpr(SourceRange SR, Expr *ValueExpr) { } if (!ValueWithBytesObjCTypeMethod) { - IdentifierInfo *II[] = { - &Context.Idents.get("valueWithBytes"), - &Context.Idents.get("objCType") - }; + const IdentifierInfo *II[] = {&Context.Idents.get("valueWithBytes"), + &Context.Idents.get("objCType")}; Selector ValueWithBytesObjCType = Context.Selectors.getSelector(2, II); // Look for the appropriate method within NSValue. @@ -2155,13 +2153,12 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, return ExprError(); } -ExprResult Sema:: -ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, - IdentifierInfo &propertyName, - SourceLocation receiverNameLoc, - SourceLocation propertyNameLoc) { +ExprResult Sema::ActOnClassPropertyRefExpr(const IdentifierInfo &receiverName, + const IdentifierInfo &propertyName, + SourceLocation receiverNameLoc, + SourceLocation propertyNameLoc) { - IdentifierInfo *receiverNamePtr = &receiverName; + const IdentifierInfo *receiverNamePtr = &receiverName; ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(receiverNamePtr, receiverNameLoc); diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index cf82cc9bccdf51cfe04ecab5f47e2277772953bc..681849d6e6c8a2065088e46a8a504cf9f80ac1f8 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -8,27 +8,31 @@ // This implements Semantic Analysis for HLSL constructs. //===----------------------------------------------------------------------===// +#include "clang/Sema/SemaHLSL.h" #include "clang/Sema/Sema.h" using namespace clang; -Decl *Sema::ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer, - SourceLocation KwLoc, IdentifierInfo *Ident, - SourceLocation IdentLoc, - SourceLocation LBrace) { +SemaHLSL::SemaHLSL(Sema &S) : SemaBase(S) {} + +Decl *SemaHLSL::ActOnStartHLSLBuffer(Scope *BufferScope, bool CBuffer, + SourceLocation KwLoc, + IdentifierInfo *Ident, + SourceLocation IdentLoc, + SourceLocation LBrace) { // For anonymous namespace, take the location of the left brace. - DeclContext *LexicalParent = getCurLexicalContext(); + DeclContext *LexicalParent = SemaRef.getCurLexicalContext(); HLSLBufferDecl *Result = HLSLBufferDecl::Create( - Context, LexicalParent, CBuffer, KwLoc, Ident, IdentLoc, LBrace); + getASTContext(), LexicalParent, CBuffer, KwLoc, Ident, IdentLoc, LBrace); - PushOnScopeChains(Result, BufferScope); - PushDeclContext(BufferScope, Result); + SemaRef.PushOnScopeChains(Result, BufferScope); + SemaRef.PushDeclContext(BufferScope, Result); return Result; } -void Sema::ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace) { +void SemaHLSL::ActOnFinishHLSLBuffer(Decl *Dcl, SourceLocation RBrace) { auto *BufDecl = cast(Dcl); BufDecl->setRBraceLoc(RBrace); - PopDeclContext(); + SemaRef.PopDeclContext(); } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index aa470adb30b47f545e063cf7102c8c2ac7c32e02..a75e9925a431468e6dfbeca50fae10c01dc07fe7 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -213,7 +213,7 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, // Get the length of the string as parsed. auto *ConstantArrayTy = cast(Str->getType()->getAsArrayTypeUnsafe()); - uint64_t StrLength = ConstantArrayTy->getSize().getZExtValue(); + uint64_t StrLength = ConstantArrayTy->getZExtSize(); if (CheckC23ConstexprInit) if (const StringLiteral *SL = dyn_cast(Str->IgnoreParens())) @@ -246,14 +246,13 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, } // [dcl.init.string]p2 - if (StrLength > CAT->getSize().getZExtValue()) + if (StrLength > CAT->getZExtSize()) S.Diag(Str->getBeginLoc(), diag::err_initializer_string_for_char_array_too_long) - << CAT->getSize().getZExtValue() << StrLength - << Str->getSourceRange(); + << CAT->getZExtSize() << StrLength << Str->getSourceRange(); } else { // C99 6.7.8p14. - if (StrLength-1 > CAT->getSize().getZExtValue()) + if (StrLength - 1 > CAT->getZExtSize()) S.Diag(Str->getBeginLoc(), diag::ext_initializer_string_for_char_array_too_long) << Str->getSourceRange(); @@ -879,7 +878,7 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, if (const ArrayType *AType = SemaRef.Context.getAsArrayType(ILE->getType())) { ElementType = AType->getElementType(); if (const auto *CAType = dyn_cast(AType)) - NumElements = CAType->getSize().getZExtValue(); + NumElements = CAType->getZExtSize(); // For an array new with an unknown bound, ask for one additional element // in order to populate the array filler. if (Entity.isVariableLengthArrayNew()) @@ -1016,7 +1015,7 @@ int InitListChecker::numArrayElements(QualType DeclType) { int maxElements = 0x7FFFFFFF; if (const ConstantArrayType *CAT = SemaRef.Context.getAsConstantArrayType(DeclType)) { - maxElements = static_cast(CAT->getSize().getZExtValue()); + maxElements = static_cast(CAT->getZExtSize()); } return maxElements; } @@ -2330,11 +2329,11 @@ void InitListChecker::CheckStructUnionTypes( break; } - // We've already initialized a member of a union. We're done. + // We've already initialized a member of a union. We can stop entirely. if (InitializedSomething && RD->isUnion()) - break; + return; - // If we've hit the flexible array member at the end, we're done. + // Stop if we've hit a flexible array member. if (Field->getType()->isIncompleteArrayType()) break; @@ -2457,6 +2456,11 @@ void InitListChecker::CheckStructUnionTypes( else CheckImplicitInitList(MemberEntity, IList, Field->getType(), Index, StructuredList, StructuredIndex); + + if (RD->isUnion() && StructuredList) { + // Initialize the first field within the union. + StructuredList->setInitializedFieldInUnion(*Field); + } } /// Expand a field designator that refers to a member of an @@ -3101,7 +3105,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Get the length of the string. uint64_t StrLen = SL->getLength(); if (cast(AT)->getSize().ult(StrLen)) - StrLen = cast(AT)->getSize().getZExtValue(); + StrLen = cast(AT)->getZExtSize(); StructuredList->resizeInits(Context, StrLen); // Build a literal for each character in the string, and put them into @@ -3124,7 +3128,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Get the length of the string. uint64_t StrLen = Str.size(); if (cast(AT)->getSize().ult(StrLen)) - StrLen = cast(AT)->getSize().getZExtValue(); + StrLen = cast(AT)->getZExtSize(); StructuredList->resizeInits(Context, StrLen); // Build a literal for each character in the string, and put them into @@ -3283,7 +3287,7 @@ InitListChecker::createInitListExpr(QualType CurrentObjectType, if (const ArrayType *AType = SemaRef.Context.getAsArrayType(CurrentObjectType)) { if (const ConstantArrayType *CAType = dyn_cast(AType)) { - NumElements = CAType->getSize().getZExtValue(); + NumElements = CAType->getZExtSize(); // Simple heuristic so that we don't allocate a very large // initializer with many empty entries at the end. if (NumElements > ExpectedNumInits) @@ -5492,7 +5496,7 @@ static void TryOrBuildParenListInitialization( // having k elements. if (const ConstantArrayType *CAT = S.getASTContext().getAsConstantArrayType(Entity.getType())) { - ArrayLength = CAT->getSize().getZExtValue(); + ArrayLength = CAT->getZExtSize(); ResultType = Entity.getType(); } else if (const VariableArrayType *VAT = S.getASTContext().getAsVariableArrayType(Entity.getType())) { @@ -6265,7 +6269,10 @@ void InitializationSequence::InitializeFrom(Sema &S, // initializer is a string literal, see 8.5.2. // - Otherwise, if the destination type is an array, the program is // ill-formed. - if (const ArrayType *DestAT = Context.getAsArrayType(DestType)) { + // - Except in HLSL, where non-decaying array parameters behave like + // non-array types for initialization. + if (DestType->isArrayType() && !DestType->isArrayParameterType()) { + const ArrayType *DestAT = Context.getAsArrayType(DestType); if (Initializer && isa(DestAT)) { SetFailed(FK_VariableLengthArrayHasInitializer); return; @@ -7075,6 +7082,11 @@ PerformConstructorInitialization(Sema &S, hasCopyOrMoveCtorParam(S.Context, getConstructorInfo(Step.Function.FoundDecl)); + // A smart pointer constructed from a nullable pointer is nullable. + if (NumArgs == 1 && !Kind.isExplicitCast()) + S.diagnoseNullableToNonnullConversion( + Entity.getType(), Args.front()->getType(), Kind.getLocation()); + // Determine the arguments required to actually perform the constructor // call. if (S.CompleteConstructorCall(Constructor, Step.Type, Args, Loc, @@ -10918,32 +10930,16 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( Context.getLValueReferenceType(ElementTypes[I].withConst()); } - llvm::FoldingSetNodeID ID; - ID.AddPointer(Template); - for (auto &T : ElementTypes) - T.getCanonicalType().Profile(ID); - unsigned Hash = ID.ComputeHash(); - if (AggregateDeductionCandidates.count(Hash) == 0) { - if (FunctionTemplateDecl *TD = - DeclareImplicitDeductionGuideFromInitList( - Template, ElementTypes, - TSInfo->getTypeLoc().getEndLoc())) { - auto *GD = cast(TD->getTemplatedDecl()); - GD->setDeductionCandidateKind(DeductionCandidate::Aggregate); - AggregateDeductionCandidates[Hash] = GD; - addDeductionCandidate(TD, GD, DeclAccessPair::make(TD, AS_public), - OnlyListConstructors, - /*AllowAggregateDeductionCandidate=*/true); - } - } else { - CXXDeductionGuideDecl *GD = AggregateDeductionCandidates[Hash]; - FunctionTemplateDecl *TD = GD->getDescribedFunctionTemplate(); - assert(TD && "aggregate deduction candidate is function template"); + if (FunctionTemplateDecl *TD = + DeclareAggregateDeductionGuideFromInitList( + LookupTemplateDecl, ElementTypes, + TSInfo->getTypeLoc().getEndLoc())) { + auto *GD = cast(TD->getTemplatedDecl()); addDeductionCandidate(TD, GD, DeclAccessPair::make(TD, AS_public), OnlyListConstructors, /*AllowAggregateDeductionCandidate=*/true); + HasAnyDeductionGuide = true; } - HasAnyDeductionGuide = true; } }; diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index d3a9c7abd0e94465f307691e6ba7b0ed2962de48..38237ee578079db65a94f5af9614cd1d744f0a6f 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -3243,6 +3243,10 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { case Type::Pipe: T = cast(T)->getElementType().getTypePtr(); continue; + + // Array parameter types are treated as fundamental types. + case Type::ArrayParameter: + break; } if (Queue.empty()) diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index 4636d89ebf2b84f5d817509495f5e3a6cb551c5e..222a65a13dd0b2f9cbbcf4999352c81a0a43203a 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -419,7 +419,7 @@ Sema::HandlePropertyInClassExtension(Scope *S, ObjCCategoryDecl *CDecl = cast(CurContext); // Diagnose if this property is already in continuation class. DeclContext *DC = CurContext; - IdentifierInfo *PropertyId = FD.D.getIdentifier(); + const IdentifierInfo *PropertyId = FD.D.getIdentifier(); ObjCInterfaceDecl *CCPrimary = CDecl->getClassInterface(); // We need to look in the @interface to see if the @property was @@ -571,7 +571,7 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, TypeSourceInfo *TInfo, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC){ - IdentifierInfo *PropertyId = FD.D.getIdentifier(); + const IdentifierInfo *PropertyId = FD.D.getIdentifier(); // Property defaults to 'assign' if it is readwrite, unless this is ARC // and the type is retainable. @@ -638,8 +638,6 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, PDecl->setInvalidDecl(); } - ProcessDeclAttributes(S, PDecl, FD.D); - // Regardless of setter/getter attribute, we save the default getter/setter // selector names in anticipation of declaration of setter/getter methods. PDecl->setGetterName(GetterSel, GetterNameLoc); @@ -647,6 +645,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, PDecl->setPropertyAttributesAsWritten( makePropertyAttributesAsWritten(AttributesAsWritten)); + ProcessDeclAttributes(S, PDecl, FD.D); + if (Attributes & ObjCPropertyAttribute::kind_readonly) PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_readonly); diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp index d3a602d1c382fa601b7eda1c369402a20bc0fc72..a6f4453e525d0136ee4b1f3c996d3dec360781dd 100644 --- a/clang/lib/Sema/SemaOpenACC.cpp +++ b/clang/lib/Sema/SemaOpenACC.cpp @@ -11,14 +11,15 @@ /// //===----------------------------------------------------------------------===// +#include "clang/Sema/SemaOpenACC.h" +#include "clang/AST/StmtOpenACC.h" #include "clang/Basic/DiagnosticSema.h" -#include "clang/Basic/OpenACCKinds.h" #include "clang/Sema/Sema.h" using namespace clang; namespace { -bool diagnoseConstructAppertainment(Sema &S, OpenACCDirectiveKind K, +bool diagnoseConstructAppertainment(SemaOpenACC &S, OpenACCDirectiveKind K, SourceLocation StartLoc, bool IsStmt) { switch (K) { default: @@ -35,19 +36,93 @@ bool diagnoseConstructAppertainment(Sema &S, OpenACCDirectiveKind K, } return false; } + +bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind, + OpenACCClauseKind ClauseKind) { + switch (ClauseKind) { + // FIXME: For each clause as we implement them, we can add the + // 'legalization' list here. + case OpenACCClauseKind::Default: + switch (DirectiveKind) { + case OpenACCDirectiveKind::Parallel: + case OpenACCDirectiveKind::Serial: + case OpenACCDirectiveKind::Kernels: + case OpenACCDirectiveKind::ParallelLoop: + case OpenACCDirectiveKind::SerialLoop: + case OpenACCDirectiveKind::KernelsLoop: + case OpenACCDirectiveKind::Data: + return true; + default: + return false; + } + default: + // Do nothing so we can go to the 'unimplemented' diagnostic instead. + return true; + } + llvm_unreachable("Invalid clause kind"); +} } // namespace -bool Sema::ActOnOpenACCClause(OpenACCClauseKind ClauseKind, - SourceLocation StartLoc) { - if (ClauseKind == OpenACCClauseKind::Invalid) - return false; - // For now just diagnose that it is unsupported and leave the parsing to do - // whatever it can do. This function will eventually need to start returning - // some sort of Clause AST type, but for now just return true/false based on - // success. - return Diag(StartLoc, diag::warn_acc_clause_unimplemented) << ClauseKind; +SemaOpenACC::SemaOpenACC(Sema &S) : SemaBase(S) {} + +OpenACCClause * +SemaOpenACC::ActOnClause(ArrayRef ExistingClauses, + OpenACCParsedClause &Clause) { + if (Clause.getClauseKind() == OpenACCClauseKind::Invalid) + return nullptr; + + // Diagnose that we don't support this clause on this directive. + if (!doesClauseApplyToDirective(Clause.getDirectiveKind(), + Clause.getClauseKind())) { + Diag(Clause.getBeginLoc(), diag::err_acc_clause_appertainment) + << Clause.getDirectiveKind() << Clause.getClauseKind(); + return nullptr; + } + + switch (Clause.getClauseKind()) { + case OpenACCClauseKind::Default: { + // Restrictions only properly implemented on 'compute' constructs, and + // 'compute' constructs are the only construct that can do anything with + // this yet, so skip/treat as unimplemented in this case. + if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Parallel && + Clause.getDirectiveKind() != OpenACCDirectiveKind::Serial && + Clause.getDirectiveKind() != OpenACCDirectiveKind::Kernels) + break; + + // Don't add an invalid clause to the AST. + if (Clause.getDefaultClauseKind() == OpenACCDefaultClauseKind::Invalid) + return nullptr; + + // OpenACC 3.3, Section 2.5.4: + // At most one 'default' clause may appear, and it must have a value of + // either 'none' or 'present'. + // Second half of the sentence is diagnosed during parsing. + auto Itr = llvm::find_if(ExistingClauses, [](const OpenACCClause *C) { + return C->getClauseKind() == OpenACCClauseKind::Default; + }); + + if (Itr != ExistingClauses.end()) { + Diag(Clause.getBeginLoc(), + diag::err_acc_duplicate_clause_disallowed) + << Clause.getDirectiveKind() << Clause.getClauseKind(); + Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here); + return nullptr; + } + + return OpenACCDefaultClause::Create( + getASTContext(), Clause.getDefaultClauseKind(), Clause.getBeginLoc(), + Clause.getLParenLoc(), Clause.getEndLoc()); + } + default: + break; + } + + Diag(Clause.getBeginLoc(), diag::warn_acc_clause_unimplemented) + << Clause.getClauseKind(); + return nullptr; } -void Sema::ActOnOpenACCConstruct(OpenACCDirectiveKind K, + +void SemaOpenACC::ActOnConstruct(OpenACCDirectiveKind K, SourceLocation StartLoc) { switch (K) { case OpenACCDirectiveKind::Invalid: @@ -68,14 +143,15 @@ void Sema::ActOnOpenACCConstruct(OpenACCDirectiveKind K, } } -bool Sema::ActOnStartOpenACCStmtDirective(OpenACCDirectiveKind K, +bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc) { return diagnoseConstructAppertainment(*this, K, StartLoc, /*IsStmt=*/true); } -StmtResult Sema::ActOnEndOpenACCStmtDirective(OpenACCDirectiveKind K, +StmtResult SemaOpenACC::ActOnEndStmtDirective(OpenACCDirectiveKind K, SourceLocation StartLoc, SourceLocation EndLoc, + ArrayRef Clauses, StmtResult AssocStmt) { switch (K) { default: @@ -85,14 +161,15 @@ StmtResult Sema::ActOnEndOpenACCStmtDirective(OpenACCDirectiveKind K, case OpenACCDirectiveKind::Parallel: case OpenACCDirectiveKind::Serial: case OpenACCDirectiveKind::Kernels: + // TODO OpenACC: Add clauses to the construct here. return OpenACCComputeConstruct::Create( - getASTContext(), K, StartLoc, EndLoc, + getASTContext(), K, StartLoc, EndLoc, Clauses, AssocStmt.isUsable() ? AssocStmt.get() : nullptr); } llvm_unreachable("Unhandled case in directive handling?"); } -StmtResult Sema::ActOnOpenACCAssociatedStmt(OpenACCDirectiveKind K, +StmtResult SemaOpenACC::ActOnAssociatedStmt(OpenACCDirectiveKind K, StmtResult AssocStmt) { switch (K) { default: @@ -114,9 +191,9 @@ StmtResult Sema::ActOnOpenACCAssociatedStmt(OpenACCDirectiveKind K, llvm_unreachable("Invalid associated statement application"); } -bool Sema::ActOnStartOpenACCDeclDirective(OpenACCDirectiveKind K, +bool SemaOpenACC::ActOnStartDeclDirective(OpenACCDirectiveKind K, SourceLocation StartLoc) { return diagnoseConstructAppertainment(*this, K, StartLoc, /*IsStmt=*/false); } -DeclGroupRef Sema::ActOnEndOpenACCDeclDirective() { return DeclGroupRef{}; } +DeclGroupRef SemaOpenACC::ActOnEndDeclDirective() { return DeclGroupRef{}; } diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index e9ad7bbde0f9b5d71e51e929a825b0e253d43cb3..e9efb4721133fe1f12181d9207b0035292f526e7 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -4478,6 +4478,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } + // For 'target teams loop', collect all captured regions so codegen can + // later decide the best IR to emit given the associated loop-nest. case OMPD_target_teams_loop: case OMPD_target_teams_distribute_parallel_for: case OMPD_target_teams_distribute_parallel_for_simd: { @@ -6135,6 +6137,79 @@ processImplicitMapsWithDefaultMappers(Sema &S, DSAStackTy *Stack, } } +namespace { +/// A 'teams loop' with a nested 'loop bind(parallel)' or generic function +/// call in the associated loop-nest cannot be a 'parallel for'. +class TeamsLoopChecker final : public ConstStmtVisitor { + Sema &SemaRef; + +public: + bool teamsLoopCanBeParallelFor() const { return TeamsLoopCanBeParallelFor; } + + // Is there a nested OpenMP loop bind(parallel) + void VisitOMPExecutableDirective(const OMPExecutableDirective *D) { + if (D->getDirectiveKind() == llvm::omp::Directive::OMPD_loop) { + if (const auto *C = D->getSingleClause()) + if (C->getBindKind() == OMPC_BIND_parallel) { + TeamsLoopCanBeParallelFor = false; + // No need to continue visiting any more + return; + } + } + for (const Stmt *Child : D->children()) + if (Child) + Visit(Child); + } + + void VisitCallExpr(const CallExpr *C) { + // Function calls inhibit parallel loop translation of 'target teams loop' + // unless the assume-no-nested-parallelism flag has been specified. + // OpenMP API runtime library calls do not inhibit parallel loop + // translation, regardless of the assume-no-nested-parallelism. + if (C) { + bool IsOpenMPAPI = false; + auto *FD = dyn_cast_or_null(C->getCalleeDecl()); + if (FD) { + std::string Name = FD->getNameInfo().getAsString(); + IsOpenMPAPI = Name.find("omp_") == 0; + } + TeamsLoopCanBeParallelFor = + IsOpenMPAPI || SemaRef.getLangOpts().OpenMPNoNestedParallelism; + if (!TeamsLoopCanBeParallelFor) + return; + } + for (const Stmt *Child : C->children()) + if (Child) + Visit(Child); + } + + void VisitCapturedStmt(const CapturedStmt *S) { + if (!S) + return; + Visit(S->getCapturedDecl()->getBody()); + } + + void VisitStmt(const Stmt *S) { + if (!S) + return; + for (const Stmt *Child : S->children()) + if (Child) + Visit(Child); + } + explicit TeamsLoopChecker(Sema &SemaRef) + : SemaRef(SemaRef), TeamsLoopCanBeParallelFor(true) {} + +private: + bool TeamsLoopCanBeParallelFor; +}; +} // namespace + +static bool teamsLoopCanBeParallelFor(Stmt *AStmt, Sema &SemaRef) { + TeamsLoopChecker Checker(SemaRef); + Checker.Visit(AStmt); + return Checker.teamsLoopCanBeParallelFor(); +} + bool Sema::mapLoopConstruct(llvm::SmallVector &ClausesWithoutBind, ArrayRef Clauses, OpenMPBindClauseKind &BindKind, @@ -7300,7 +7375,7 @@ void Sema::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope( llvm::omp::TraitProperty::implementation_extension_allow_templates)) return; - IdentifierInfo *BaseII = D.getIdentifier(); + const IdentifierInfo *BaseII = D.getIdentifier(); LookupResult Lookup(*this, DeclarationName(BaseII), D.getIdentifierLoc(), LookupOrdinaryName); LookupParsedName(Lookup, S, &D.getCXXScopeSpec()); @@ -10895,7 +10970,8 @@ StmtResult Sema::ActOnOpenMPTargetTeamsGenericLoopDirective( setFunctionHasBranchProtectedScope(); return OMPTargetTeamsGenericLoopDirective::Create( - Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, + teamsLoopCanBeParallelFor(AStmt, *this)); } StmtResult Sema::ActOnOpenMPParallelGenericLoopDirective( @@ -15645,6 +15721,12 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel) CaptureRegion = OMPD_target; break; + case OMPD_teams_loop: + case OMPD_target_teams_loop: + // For [target] teams loop, assume capture region is 'teams' so it's + // available for codegen later to use if/when necessary. + CaptureRegion = OMPD_teams; + break; case OMPD_target_teams_distribute_parallel_for_simd: if (OpenMPVersion >= 50 && (NameModifier == OMPD_unknown || NameModifier == OMPD_simd)) { @@ -15652,7 +15734,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( break; } [[fallthrough]]; - case OMPD_target_teams_loop: case OMPD_target_teams_distribute_parallel_for: // If this clause applies to the nested 'parallel' region, capture within // the 'teams' region, otherwise do not capture. @@ -15775,7 +15856,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_loop: - case OMPD_teams_loop: case OMPD_teams: case OMPD_tile: case OMPD_unroll: @@ -21284,7 +21364,7 @@ static bool checkArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef, if (isa(E) || (OASE && OASE->getColonLocFirst().isInvalid())) { if (const auto *ATy = dyn_cast(BaseQTy.getTypePtr())) - return ATy->getSize().getSExtValue() != 1; + return ATy->getSExtSize() != 1; // Size can't be evaluated statically. return false; } @@ -21325,7 +21405,7 @@ static bool checkArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef, return false; // Can't get the integer value as a constant. llvm::APSInt ConstLength = Result.Val.getInt(); - return CATy->getSize().getSExtValue() != ConstLength.getSExtValue(); + return CATy->getSExtSize() != ConstLength.getSExtValue(); } // Return true if it can be proven that the provided array expression (array @@ -21350,7 +21430,7 @@ static bool checkArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef, // is pointer. if (!Length) { if (const auto *ATy = dyn_cast(BaseQTy.getTypePtr())) - return ATy->getSize().getSExtValue() != 1; + return ATy->getSExtSize() != 1; // We cannot assume anything. return false; } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index f6bd85bdc64692e3de882b9006694bdf40e505eb..3808af37ff54a8ee65334baea4af9f2d3f828ba3 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -160,6 +160,7 @@ ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) { ICR_C_Conversion_Extension, ICR_Conversion, ICR_Conversion, + ICR_Conversion, }; static_assert(std::size(Rank) == (int)ICK_Num_Conversion_Kinds); return Rank[(int)Kind]; @@ -201,6 +202,7 @@ static const char *GetImplicitConversionName(ImplicitConversionKind Kind) { "Incompatible pointer conversion", "Fixed point conversion", "HLSL vector truncation", + "Non-decaying array conversion", }; static_assert(std::size(Name) == (int)ICK_Num_Conversion_Kinds); return Name[Kind]; @@ -2131,8 +2133,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // A glvalue (3.10) of a non-function, non-array type T can // be converted to a prvalue. bool argIsLValue = From->isGLValue(); - if (argIsLValue && - !FromType->isFunctionType() && !FromType->isArrayType() && + if (argIsLValue && !FromType->canDecayToPointerType() && S.Context.getCanonicalType(FromType) != S.Context.OverloadTy) { SCS.First = ICK_Lvalue_To_Rvalue; @@ -2147,6 +2148,19 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // is T (C++ 4.1p1). C++ can't get here with class types; in C, we // just strip the qualifiers because they don't matter. FromType = FromType.getUnqualifiedType(); + } else if (S.getLangOpts().HLSL && FromType->isConstantArrayType() && + ToType->isArrayParameterType()) { + // HLSL constant array parameters do not decay, so if the argument is a + // constant array and the parameter is an ArrayParameterType we have special + // handling here. + FromType = S.Context.getArrayParameterType(FromType); + if (S.Context.getCanonicalType(FromType) != + S.Context.getCanonicalType(ToType)) + return false; + + SCS.First = ICK_HLSL_Array_RValue; + SCS.setAllToTypes(ToType); + return true; } else if (FromType->isArrayType()) { // Array-to-pointer conversion (C++ 4.2) SCS.First = ICK_Array_To_Pointer; @@ -6100,6 +6114,7 @@ static bool CheckConvertedConstantConversions(Sema &S, case ICK_Lvalue_To_Rvalue: case ICK_Array_To_Pointer: case ICK_Function_To_Pointer: + case ICK_HLSL_Array_RValue: llvm_unreachable("found a first conversion kind in Second"); case ICK_Function_Conversion: @@ -6339,6 +6354,7 @@ Sema::EvaluateConvertedConstantExpression(Expr *E, QualType T, APValue &Value, // by this point. assert(CE->getResultStorageKind() != ConstantResultStorageKind::None && "ConstantExpr has no value associated with it"); + (void)CE; } else { E = ConstantExpr::Create(Context, Result.get(), Value); } @@ -6865,6 +6881,32 @@ static bool IsAcceptableNonMemberOperatorCandidate(ASTContext &Context, return false; } +static bool isNonViableMultiVersionOverload(FunctionDecl *FD) { + if (FD->isTargetMultiVersionDefault()) + return false; + + if (!FD->getASTContext().getTargetInfo().getTriple().isAArch64()) + return FD->isTargetMultiVersion(); + + if (!FD->isMultiVersion()) + return false; + + // Among multiple target versions consider either the default, + // or the first non-default in the absence of default version. + unsigned SeenAt = 0; + unsigned I = 0; + bool HasDefault = false; + FD->getASTContext().forEachMultiversionedFunctionVersion( + FD, [&](const FunctionDecl *CurFD) { + if (FD == CurFD) + SeenAt = I; + else if (CurFD->isTargetMultiVersionDefault()) + HasDefault = true; + ++I; + }); + return HasDefault || SeenAt != 0; +} + /// AddOverloadCandidate - Adds the given function to the set of /// candidate functions, using the given function call arguments. If /// @p SuppressUserConversions, then don't allow user-defined @@ -6970,11 +7012,7 @@ void Sema::AddOverloadCandidate( } } - if (Function->isMultiVersion() && - ((Function->hasAttr() && - !Function->getAttr()->isDefaultVersion()) || - (Function->hasAttr() && - !Function->getAttr()->isDefaultVersion()))) { + if (isNonViableMultiVersionOverload(Function)) { Candidate.Viable = false; Candidate.FailureKind = ovl_non_default_multiversion_function; return; @@ -7637,11 +7675,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, return; } - if (Method->isMultiVersion() && - ((Method->hasAttr() && - !Method->getAttr()->isDefaultVersion()) || - (Method->hasAttr() && - !Method->getAttr()->isDefaultVersion()))) { + if (isNonViableMultiVersionOverload(Method)) { Candidate.Viable = false; Candidate.FailureKind = ovl_non_default_multiversion_function; } @@ -8127,11 +8161,7 @@ void Sema::AddConversionCandidate( return; } - if (Conversion->isMultiVersion() && - ((Conversion->hasAttr() && - !Conversion->getAttr()->isDefaultVersion()) || - (Conversion->hasAttr() && - !Conversion->getAttr()->isDefaultVersion()))) { + if (isNonViableMultiVersionOverload(Conversion)) { Candidate.Viable = false; Candidate.FailureKind = ovl_non_default_multiversion_function; } @@ -14797,6 +14827,13 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, } } + // Check for nonnull = nullable. + // This won't be caught in the arg's initialization: the parameter to + // the assignment operator is not marked nonnull. + if (Op == OO_Equal) + diagnoseNullableToNonnullConversion(Args[0]->getType(), + Args[1]->getType(), OpLoc); + // Convert the arguments. if (CXXMethodDecl *Method = dyn_cast(FnDecl)) { // Best->Access is only meaningful for class members. diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index 528c261c4a297f5b4ca6a530be5be741062f4dac..82774760b34d440a1a014129845a9c480091a165 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -613,9 +613,9 @@ bool ObjCPropertyOpBuilder::findGetter() { // Must build the getter selector the hard way. ObjCMethodDecl *setter = RefExpr->getImplicitPropertySetter(); assert(setter && "both setter and getter are null - cannot happen"); - IdentifierInfo *setterName = - setter->getSelector().getIdentifierInfoForSlot(0); - IdentifierInfo *getterName = + const IdentifierInfo *setterName = + setter->getSelector().getIdentifierInfoForSlot(0); + const IdentifierInfo *getterName = &S.Context.Idents.get(setterName->getName().substr(3)); GetterSelector = S.PP.getSelectorTable().getNullarySelector(getterName); @@ -640,9 +640,9 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) { SetterSelector = setter->getSelector(); return true; } else { - IdentifierInfo *getterName = - RefExpr->getImplicitPropertyGetter()->getSelector() - .getIdentifierInfoForSlot(0); + const IdentifierInfo *getterName = RefExpr->getImplicitPropertyGetter() + ->getSelector() + .getIdentifierInfoForSlot(0); SetterSelector = SelectorTable::constructSetterSelector(S.PP.getIdentifierTable(), S.PP.getSelectorTable(), @@ -667,7 +667,8 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) { front = isLowercase(front) ? toUppercase(front) : toLowercase(front); SmallString<100> PropertyName = thisPropertyName; PropertyName[0] = front; - IdentifierInfo *AltMember = &S.PP.getIdentifierTable().get(PropertyName); + const IdentifierInfo *AltMember = + &S.PP.getIdentifierTable().get(PropertyName); if (ObjCPropertyDecl *prop1 = IFace->FindPropertyDeclaration( AltMember, prop->getQueryKind())) if (prop != prop1 && (prop1->getSetterMethodDecl() == setter)) { @@ -1126,9 +1127,8 @@ static void CheckKeyForObjCARCConversion(Sema &S, QualType ContainerT, return; // dictionary subscripting. // - (id)objectForKeyedSubscript:(id)key; - IdentifierInfo *KeyIdents[] = { - &S.Context.Idents.get("objectForKeyedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &S.Context.Idents.get("objectForKeyedSubscript")}; Selector GetterSelector = S.Context.Selectors.getSelector(1, KeyIdents); ObjCMethodDecl *Getter = S.LookupMethodInObjectType(GetterSelector, ContainerT, true /*instance*/); @@ -1169,16 +1169,14 @@ bool ObjCSubscriptOpBuilder::findAtIndexGetter() { if (!arrayRef) { // dictionary subscripting. // - (id)objectForKeyedSubscript:(id)key; - IdentifierInfo *KeyIdents[] = { - &S.Context.Idents.get("objectForKeyedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &S.Context.Idents.get("objectForKeyedSubscript")}; AtIndexGetterSelector = S.Context.Selectors.getSelector(1, KeyIdents); } else { // - (id)objectAtIndexedSubscript:(size_t)index; - IdentifierInfo *KeyIdents[] = { - &S.Context.Idents.get("objectAtIndexedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &S.Context.Idents.get("objectAtIndexedSubscript")}; AtIndexGetterSelector = S.Context.Selectors.getSelector(1, KeyIdents); } @@ -1274,18 +1272,16 @@ bool ObjCSubscriptOpBuilder::findAtIndexSetter() { if (!arrayRef) { // dictionary subscripting. // - (void)setObject:(id)object forKeyedSubscript:(id)key; - IdentifierInfo *KeyIdents[] = { - &S.Context.Idents.get("setObject"), - &S.Context.Idents.get("forKeyedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &S.Context.Idents.get("setObject"), + &S.Context.Idents.get("forKeyedSubscript")}; AtIndexSetterSelector = S.Context.Selectors.getSelector(2, KeyIdents); } else { // - (void)setObject:(id)object atIndexedSubscript:(NSInteger)index; - IdentifierInfo *KeyIdents[] = { - &S.Context.Idents.get("setObject"), - &S.Context.Idents.get("atIndexedSubscript") - }; + const IdentifierInfo *KeyIdents[] = { + &S.Context.Idents.get("setObject"), + &S.Context.Idents.get("atIndexedSubscript")}; AtIndexSetterSelector = S.Context.Selectors.getSelector(2, KeyIdents); } AtIndexSetter = S.LookupMethodInObjectType(AtIndexSetterSelector, ResultType, @@ -1474,7 +1470,7 @@ ExprResult MSPropertyOpBuilder::buildGet() { } UnqualifiedId GetterName; - IdentifierInfo *II = RefExpr->getPropertyDecl()->getGetterId(); + const IdentifierInfo *II = RefExpr->getPropertyDecl()->getGetterId(); GetterName.setIdentifier(II, RefExpr->getMemberLoc()); CXXScopeSpec SS; SS.Adopt(RefExpr->getQualifierLoc()); @@ -1503,7 +1499,7 @@ ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl, } UnqualifiedId SetterName; - IdentifierInfo *II = RefExpr->getPropertyDecl()->getSetterId(); + const IdentifierInfo *II = RefExpr->getPropertyDecl()->getSetterId(); SetterName.setIdentifier(II, RefExpr->getMemberLoc()); CXXScopeSpec SS; SS.Adopt(RefExpr->getQualifierLoc()); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp index ca0254d29e7f408a2499a895b428606933dcd3f5..18f6d8f03047376d55d760bd94b174d08a42f2d1 100644 --- a/clang/lib/Sema/SemaSYCL.cpp +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -8,6 +8,7 @@ // This implements Semantic Analysis for SYCL constructs. //===----------------------------------------------------------------------===// +#include "clang/Sema/SemaSYCL.h" #include "clang/AST/Mangle.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" @@ -18,28 +19,30 @@ using namespace clang; // SYCL device specific diagnostics implementation // ----------------------------------------------------------------------------- -Sema::SemaDiagnosticBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc, +SemaSYCL::SemaSYCL(Sema &S) : SemaBase(S) {} + +Sema::SemaDiagnosticBuilder SemaSYCL::DiagIfDeviceCode(SourceLocation Loc, unsigned DiagID) { assert(getLangOpts().SYCLIsDevice && "Should only be called during SYCL compilation"); - FunctionDecl *FD = dyn_cast(getCurLexicalContext()); + FunctionDecl *FD = dyn_cast(SemaRef.getCurLexicalContext()); SemaDiagnosticBuilder::Kind DiagKind = [this, FD] { if (!FD) return SemaDiagnosticBuilder::K_Nop; - if (getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted) + if (SemaRef.getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted) return SemaDiagnosticBuilder::K_ImmediateWithCallStack; return SemaDiagnosticBuilder::K_Deferred; }(); - return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, *this); + return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, SemaRef); } -static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) { - if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(Ty)) - return CAT->getSize() == 0; +static bool isZeroSizedArray(SemaSYCL &S, QualType Ty) { + if (const auto *CAT = S.getASTContext().getAsConstantArrayType(Ty)) + return CAT->isZeroSize(); return false; } -void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt, +void SemaSYCL::deepTypeCheckForDevice(SourceLocation UsedAt, llvm::DenseSet Visited, ValueDecl *DeclToCheck) { assert(getLangOpts().SYCLIsDevice && @@ -51,18 +54,18 @@ void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt, auto Check = [&](QualType TypeToCheck, const ValueDecl *D) { bool ErrorFound = false; if (isZeroSizedArray(*this, TypeToCheck)) { - SYCLDiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1; + DiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1; ErrorFound = true; } // Checks for other types can also be done here. if (ErrorFound) { if (NeedToEmitNotes) { if (auto *FD = dyn_cast(D)) - SYCLDiagIfDeviceCode(FD->getLocation(), - diag::note_illegal_field_declared_here) + DiagIfDeviceCode(FD->getLocation(), + diag::note_illegal_field_declared_here) << FD->getType()->isPointerType() << FD->getType(); else - SYCLDiagIfDeviceCode(D->getLocation(), diag::note_declared_at); + DiagIfDeviceCode(D->getLocation(), diag::note_declared_at); } } @@ -93,8 +96,8 @@ void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt, auto EmitHistory = [&]() { // The first element is always nullptr. for (uint64_t Index = 1; Index < History.size(); ++Index) { - SYCLDiagIfDeviceCode(History[Index]->getLocation(), - diag::note_within_field_of_type) + DiagIfDeviceCode(History[Index]->getLocation(), + diag::note_within_field_of_type) << History[Index]->getType(); } }; @@ -130,3 +133,26 @@ void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt, } } while (!StackForRecursion.empty()); } + +ExprResult SemaSYCL::BuildUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + TypeSourceInfo *TSI) { + return SYCLUniqueStableNameExpr::Create(getASTContext(), OpLoc, LParen, + RParen, TSI); +} + +ExprResult SemaSYCL::ActOnUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation LParen, + SourceLocation RParen, + ParsedType ParsedTy) { + TypeSourceInfo *TSI = nullptr; + QualType Ty = SemaRef.GetTypeFromParser(ParsedTy, &TSI); + + if (Ty.isNull()) + return ExprError(); + if (!TSI) + TSI = getASTContext().getTrivialTypeSourceInfo(Ty, LParen); + + return BuildUniqueStableNameExpr(OpLoc, LParen, RParen, TSI); +} diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index e72397adec24fb9e505ad39e4ccc54937e421d6d..e53c76e65b03d240355b4e27f0691341b988a22d 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2275,11 +2275,9 @@ Sema::CheckObjCForCollectionOperand(SourceLocation forLoc, Expr *collection) { // Otherwise, if we have any useful type information, check that // the type declares the appropriate method. } else if (iface || !objectType->qual_empty()) { - IdentifierInfo *selectorIdents[] = { - &Context.Idents.get("countByEnumeratingWithState"), - &Context.Idents.get("objects"), - &Context.Idents.get("count") - }; + const IdentifierInfo *selectorIdents[] = { + &Context.Idents.get("countByEnumeratingWithState"), + &Context.Idents.get("objects"), &Context.Idents.get("count")}; Selector selector = Context.Selectors.getSelector(3, &selectorIdents[0]); ObjCMethodDecl *method = nullptr; diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 691857e88beb490089f23789e85e7c1709ceaeae..a0339273a0ba35ec6826ae58ab2e9f1e683cf2a0 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -406,8 +406,8 @@ static void CheckForDuplicateLoopAttrs(Sema &S, ArrayRef Attrs) { << *FirstItr; S.Diag((*FirstItr)->getLocation(), diag::note_previous_attribute); } - return; } + return; } static Attr *handleMSConstexprAttr(Sema &S, Stmt *St, const ParsedAttr &A, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 005529a53270c30a25124e94559ed190f32bf86e..e0f5e53dc2481e5ba00fb5024ff8e6b75c4709b4 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -970,7 +970,7 @@ void Sema::translateTemplateArguments(const ASTTemplateArgsPtr &TemplateArgsIn, static void maybeDiagnoseTemplateParameterShadow(Sema &SemaRef, Scope *S, SourceLocation Loc, - IdentifierInfo *Name) { + const IdentifierInfo *Name) { NamedDecl *PrevDecl = SemaRef.LookupSingleName( S, Name, Loc, Sema::LookupOrdinaryName, Sema::ForVisibleRedeclaration); if (PrevDecl && PrevDecl->isTemplateParameter()) @@ -1578,7 +1578,7 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, CheckFunctionOrTemplateParamDeclarator(S, D); - IdentifierInfo *ParamName = D.getIdentifier(); + const IdentifierInfo *ParamName = D.getIdentifier(); bool IsParameterPack = D.hasEllipsis(); NonTypeTemplateParmDecl *Param = NonTypeTemplateParmDecl::Create( Context, Context.getTranslationUnitDecl(), D.getBeginLoc(), @@ -1630,26 +1630,20 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, /// ActOnTemplateTemplateParameter - Called when a C++ template template /// parameter (e.g. T in template