Merge ref '873d4682c7' from rust-lang/rust

Pull recent changes from https://github.com/rust-lang/rust via Josh.

Upstream ref: rust-lang/rust@873d4682c7
Filtered ref: rust-lang/stdarch@003d326514
Upstream diff: 48622726c4...873d4682c7

This merge was created using https://github.com/rust-lang/josh-sync.
This commit is contained in:
The rustc-josh-sync Cronjob Bot 2026-01-26 04:34:26 +00:00
commit 7168e5d9e1
4129 changed files with 53440 additions and 29094 deletions

View file

@ -2,6 +2,7 @@
name: Internal Compiler Error
about: Create a report for an internal compiler error in rustc.
labels: C-bug, I-ICE, T-compiler
title: "[ICE]: "
---
<!--
Thank you for finding an Internal Compiler Error! 🧊 If possible, try to provide

View file

@ -11,11 +11,9 @@ name: CI
on:
push:
branches:
- auto
- try
- try-perf
- automation/bors/try
- automation/bors/auto
- automation/bors/try
- try-perf
pull_request:
branches:
- "**"
@ -33,9 +31,10 @@ defaults:
concurrency:
# For a given workflow, if we push to the same branch, cancel all previous builds on that branch.
# We add an exception for try builds (try branch) and unrolled rollup builds (try-perf), which
# are all triggered on the same branch, but which should be able to run concurrently.
group: ${{ github.workflow }}-${{ ((github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try') && github.sha) || github.ref }}
# We add an exception for try builds (automation/bors/try branch) and unrolled rollup builds
# (try-perf), which are all triggered on the same branch, but which should be able to run
# concurrently.
group: ${{ github.workflow }}-${{ ((github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try') && github.sha) || github.ref }}
cancel-in-progress: true
env:
TOOLSTATE_REPO: "https://github.com/rust-lang-nursery/rust-toolstate"
@ -57,7 +56,7 @@ jobs:
- name: Test citool
# Only test citool on the auto branch, to reduce latency of the calculate matrix job
# on PR/try builds.
if: ${{ github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto' }}
if: ${{ github.ref == 'refs/heads/automation/bors/auto' }}
run: |
cd src/ci/citool
CARGO_INCREMENTAL=0 cargo test
@ -80,7 +79,7 @@ jobs:
# access the environment.
#
# We only enable the environment for the rust-lang/rust repository, so that CI works on forks.
environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }}
environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }}
env:
CI_JOB_NAME: ${{ matrix.name }}
CI_JOB_DOC_URL: ${{ matrix.doc_url }}
@ -289,7 +288,7 @@ jobs:
fi
# Get closest bors merge commit
PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1`
PARENT_COMMIT=`git rev-list --author='bors@rust-lang.org' --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1`
./build/citool/debug/citool postprocess-metrics \
--job-name ${CI_JOB_NAME} \
@ -306,30 +305,22 @@ jobs:
DD_GITHUB_JOB_NAME: ${{ matrix.full_name }}
run: ./build/citool/debug/citool upload-build-metrics build/cpu-usage.csv
# This job isused to tell bors the final status of the build, as there is no practical way to detect
# when a workflow is successful listening to webhooks only in our current bors implementation (homu).
# This job is used to publish toolstate for successful auto builds.
outcome:
name: bors build finished
name: publish toolstate
runs-on: ubuntu-24.04
needs: [ calculate_matrix, job ]
# !cancelled() executes the job regardless of whether the previous jobs passed or failed
if: ${{ !cancelled() && contains(fromJSON('["auto", "try"]'), needs.calculate_matrix.outputs.run_type) }}
environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }}
if: ${{ needs.calculate_matrix.outputs.run_type == 'auto' }}
environment: ${{ (github.repository == 'rust-lang/rust' && 'bors') || '' }}
steps:
- name: checkout the source code
uses: actions/checkout@v5
with:
fetch-depth: 2
# Calculate the exit status of the whole CI workflow.
# If all dependent jobs were successful, this exits with 0 (and the outcome job continues successfully).
# If a some dependent job has failed, this exits with 1.
- name: calculate the correct exit status
run: jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< '${{ toJson(needs) }}'
# Publish the toolstate if an auto build succeeds (just before push to the default branch)
- name: publish toolstate
run: src/ci/publish_toolstate.sh
shell: bash
if: needs.calculate_matrix.outputs.run_type == 'auto'
env:
TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues
TOOLSTATE_PUBLISH: 1

View file

@ -62,19 +62,9 @@ jobs:
rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN
rustup default $TOOLCHAIN
- name: cargo update compiler & tools
# Remove first line that always just says "Updating crates.io index"
run: |
echo -e "\ncompiler & tools dependencies:" >> cargo_update.log
cargo update 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
- name: cargo update library
run: |
echo -e "\nlibrary dependencies:" >> cargo_update.log
cargo update --manifest-path library/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
- name: cargo update rustbook
run: |
echo -e "\nrustbook dependencies:" >> cargo_update.log
cargo update --manifest-path src/tools/rustbook/Cargo.toml 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log
- name: cargo update
run: ./src/tools/update-lockfile.sh
- name: upload Cargo.lock artifact for use in PR
uses: actions/upload-artifact@v4
with:

View file

@ -29,7 +29,7 @@ jobs:
sleep 60
# Get closest bors merge commit
PARENT_COMMIT=`git rev-list --author='bors <bors@rust-lang.org>' -n1 --first-parent HEAD^1`
PARENT_COMMIT=`git rev-list --author='bors@rust-lang.org' --author='122020455+rust-bors\[bot\]@users.noreply.github.com' -n1 --first-parent HEAD^1`
echo "Parent: ${PARENT_COMMIT}"
# Find PR for the current commit

View file

@ -96,6 +96,7 @@ boolean_coercion <booleancoercion@gmail.com>
Boris Egorov <jightuse@gmail.com> <egorov@linux.com>
bors <bors@rust-lang.org> bors[bot] <26634292+bors[bot]@users.noreply.github.com>
bors <bors@rust-lang.org> bors[bot] <bors[bot]@users.noreply.github.com>
bors <bors@rust-lang.org> <122020455+rust-bors[bot]@users.noreply.github.com>
BoxyUwU <rust@boxyuwu.dev>
BoxyUwU <rust@boxyuwu.dev> <supbscripter@gmail.com>
Braden Nelson <moonheart08@users.noreply.github.com>

View file

@ -182,19 +182,6 @@ version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50"
[[package]]
name = "askama"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
dependencies = [
"askama_derive 0.14.0",
"itoa",
"percent-encoding",
"serde",
"serde_json",
]
[[package]]
name = "askama"
version = "0.15.1"
@ -208,30 +195,13 @@ dependencies = [
"serde_json",
]
[[package]]
name = "askama_derive"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
dependencies = [
"askama_parser 0.14.0",
"basic-toml",
"memchr",
"proc-macro2",
"quote",
"rustc-hash 2.1.1",
"serde",
"serde_derive",
"syn 2.0.110",
]
[[package]]
name = "askama_derive"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ba5e7259a1580c61571e3116ebaaa01e3c001b2132b17c4cc5c70780ca3e994"
dependencies = [
"askama_parser 0.15.1",
"askama_parser",
"basic-toml",
"memchr",
"proc-macro2",
@ -248,19 +218,7 @@ version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "236ce20b77cb13506eaf5024899f4af6e12e8825f390bd943c4c37fd8f322e46"
dependencies = [
"askama_derive 0.15.1",
]
[[package]]
name = "askama_parser"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358"
dependencies = [
"memchr",
"serde",
"serde_derive",
"winnow 0.7.13",
"askama_derive",
]
[[package]]
@ -445,22 +403,21 @@ dependencies = [
[[package]]
name = "capstone"
version = "0.13.0"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "015ef5d5ca1743e3f94af9509ba6bd2886523cfee46e48d15c2ef5216fd4ac9a"
checksum = "f442ae0f2f3f1b923334b4a5386c95c69c1cfa072bafa23d6fae6d9682eb1dd4"
dependencies = [
"capstone-sys",
"libc",
"static_assertions",
]
[[package]]
name = "capstone-sys"
version = "0.17.0"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2267cb8d16a1e4197863ec4284ffd1aec26fe7e57c58af46b02590a0235809a0"
checksum = "a4e8087cab6731295f5a2a2bd82989ba4f41d3a428aab2e7c98d8f4db38aac05"
dependencies = [
"cc",
"libc",
]
[[package]]
@ -673,10 +630,10 @@ checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d"
[[package]]
name = "clippy"
version = "0.1.94"
version = "0.1.95"
dependencies = [
"anstream",
"askama 0.14.0",
"askama",
"cargo_metadata 0.18.1",
"clippy_config",
"clippy_lints",
@ -700,7 +657,7 @@ dependencies = [
[[package]]
name = "clippy_config"
version = "0.1.94"
version = "0.1.95"
dependencies = [
"clippy_utils",
"itertools",
@ -724,7 +681,7 @@ dependencies = [
[[package]]
name = "clippy_lints"
version = "0.1.94"
version = "0.1.95"
dependencies = [
"arrayvec",
"cargo_metadata 0.18.1",
@ -756,7 +713,7 @@ dependencies = [
[[package]]
name = "clippy_utils"
version = "0.1.94"
version = "0.1.95"
dependencies = [
"arrayvec",
"itertools",
@ -1160,7 +1117,7 @@ dependencies = [
[[package]]
name = "declare_clippy_lint"
version = "0.1.94"
version = "0.1.95"
[[package]]
name = "derive-where"
@ -1567,7 +1524,7 @@ name = "generate-copyright"
version = "0.1.0"
dependencies = [
"anyhow",
"askama 0.15.1",
"askama",
"cargo_metadata 0.21.0",
"serde",
"serde_json",
@ -1713,9 +1670,12 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.16.0"
version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
dependencies = [
"foldhash 0.2.0",
]
[[package]]
name = "heck"
@ -1993,12 +1953,12 @@ checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5"
[[package]]
name = "indexmap"
version = "2.12.0"
version = "2.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f"
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017"
dependencies = [
"equivalent",
"hashbrown 0.16.0",
"hashbrown 0.16.1",
"serde",
"serde_core",
]
@ -2232,9 +2192,9 @@ dependencies = [
[[package]]
name = "libffi"
version = "5.0.0"
version = "5.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0444124f3ffd67e1b0b0c661a7f81a278a135eb54aaad4078e79fbc8be50c8a5"
checksum = "0498fe5655f857803e156523e644dcdcdc3b3c7edda42ea2afdae2e09b2db87b"
dependencies = [
"libc",
"libffi-sys",
@ -2242,9 +2202,9 @@ dependencies = [
[[package]]
name = "libffi-sys"
version = "4.0.0"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d722da8817ea580d0669da6babe2262d7b86a1af1103da24102b8bb9c101ce7"
checksum = "71d4f1d4ce15091955144350b75db16a96d4a63728500122706fb4d29a26afbb"
dependencies = [
"cc",
]
@ -3377,6 +3337,7 @@ dependencies = [
"rustdoc-json-types",
"serde_json",
"similar",
"tempfile",
"wasmparser 0.236.1",
]
@ -3395,9 +3356,9 @@ dependencies = [
[[package]]
name = "rustc-demangle"
version = "0.1.26"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d"
[[package]]
name = "rustc-hash"
@ -3413,9 +3374,9 @@ checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
[[package]]
name = "rustc-literal-escaper"
version = "0.0.5"
version = "0.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4ee29da77c5a54f42697493cd4c9b9f31b74df666a6c04dfc4fde77abe0438b"
checksum = "8be87abb9e40db7466e0681dc8ecd9dcfd40360cb10b4c8fe24a7c4c3669b198"
[[package]]
name = "rustc-main"
@ -3773,7 +3734,7 @@ dependencies = [
"either",
"elsa",
"ena",
"hashbrown 0.15.5",
"hashbrown 0.16.1",
"indexmap",
"jobserver",
"libc",
@ -3810,6 +3771,7 @@ dependencies = [
name = "rustc_driver_impl"
version = "0.0.0"
dependencies = [
"anstyle",
"ctrlc",
"jiff",
"libc",
@ -3835,6 +3797,7 @@ dependencies = [
"rustc_index",
"rustc_infer",
"rustc_interface",
"rustc_lexer",
"rustc_lint",
"rustc_log",
"rustc_macros",
@ -3902,7 +3865,6 @@ dependencies = [
"rustc_fluent_macro",
"rustc_hashes",
"rustc_index",
"rustc_lexer",
"rustc_lint_defs",
"rustc_macros",
"rustc_serialize",
@ -3930,11 +3892,13 @@ dependencies = [
"rustc_lexer",
"rustc_lint_defs",
"rustc_macros",
"rustc_middle",
"rustc_parse",
"rustc_proc_macro",
"rustc_serialize",
"rustc_session",
"rustc_span",
"scoped-tls",
"smallvec",
"thin-vec",
"tracing",
@ -4389,7 +4353,7 @@ name = "rustc_mir_transform"
version = "0.0.0"
dependencies = [
"either",
"hashbrown 0.15.5",
"hashbrown 0.16.1",
"itertools",
"rustc_abi",
"rustc_arena",
@ -4403,7 +4367,6 @@ dependencies = [
"rustc_infer",
"rustc_macros",
"rustc_middle",
"rustc_mir_build",
"rustc_mir_dataflow",
"rustc_session",
"rustc_span",
@ -4422,6 +4385,7 @@ dependencies = [
"rustc_errors",
"rustc_fluent_macro",
"rustc_hir",
"rustc_index",
"rustc_macros",
"rustc_middle",
"rustc_session",
@ -4600,7 +4564,7 @@ dependencies = [
name = "rustc_query_system"
version = "0.0.0"
dependencies = [
"hashbrown 0.15.5",
"hashbrown 0.16.1",
"parking_lot",
"rustc_abi",
"rustc_ast",
@ -4624,7 +4588,6 @@ dependencies = [
name = "rustc_resolve"
version = "0.0.0"
dependencies = [
"bitflags",
"indexmap",
"itertools",
"pulldown-cmark",
@ -4914,7 +4877,7 @@ name = "rustdoc"
version = "0.0.0"
dependencies = [
"arrayvec",
"askama 0.15.1",
"askama",
"base64",
"expect-test",
"indexmap",
@ -5660,6 +5623,7 @@ dependencies = [
"build_helper",
"cargo_metadata 0.21.0",
"fluent-syntax",
"globset",
"ignore",
"miropt-test-tools",
"regex",
@ -6223,9 +6187,9 @@ dependencies = [
[[package]]
name = "wasi-preview1-component-adapter-provider"
version = "38.0.4"
version = "40.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ec3ef3783e18f2457796ed91b1e6c2adc46f2905f740d1527ab3053fe8e5682"
checksum = "bb5e2b9858989c3a257de4ca169977f4f79897b64e4f482f188f4fcf8ac557d1"
[[package]]
name = "wasm-bindgen"
@ -6274,17 +6238,18 @@ dependencies = [
[[package]]
name = "wasm-component-ld"
version = "0.5.19"
version = "0.5.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bfc50dd0b883d841bc1dba5ff7020ca52fa7b2c3bb1266d8bf6a09dd032e115"
checksum = "846d20ed66ae37b7a237e36dfcd2fdc979eae82a46cdb0586f9bba80782fd789"
dependencies = [
"anyhow",
"clap",
"clap_lex",
"lexopt",
"libc",
"tempfile",
"wasi-preview1-component-adapter-provider",
"wasmparser 0.241.2",
"wasmparser 0.243.0",
"wat",
"windows-sys 0.61.2",
"winsplit",
@ -6311,24 +6276,24 @@ dependencies = [
[[package]]
name = "wasm-encoder"
version = "0.241.2"
version = "0.243.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e01164c9dda68301e34fdae536c23ed6fe90ce6d97213ccc171eebbd3d02d6b8"
checksum = "c55db9c896d70bd9fa535ce83cd4e1f2ec3726b0edd2142079f594fc3be1cb35"
dependencies = [
"leb128fmt",
"wasmparser 0.241.2",
"wasmparser 0.243.0",
]
[[package]]
name = "wasm-metadata"
version = "0.241.2"
version = "0.243.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "876fe286f2fa416386deedebe8407e6f19e0b5aeaef3d03161e77a15fa80f167"
checksum = "eae05bf9579f45a62e8d0a4e3f52eaa8da518883ac5afa482ec8256c329ecd56"
dependencies = [
"anyhow",
"indexmap",
"wasm-encoder 0.241.2",
"wasmparser 0.241.2",
"wasm-encoder 0.243.0",
"wasmparser 0.243.0",
]
[[package]]
@ -6353,9 +6318,9 @@ dependencies = [
[[package]]
name = "wasmparser"
version = "0.241.2"
version = "0.243.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46d90019b1afd4b808c263e428de644f3003691f243387d30d673211ee0cb8e8"
checksum = "f6d8db401b0528ec316dfbe579e6ab4152d61739cfe076706d2009127970159d"
dependencies = [
"bitflags",
"hashbrown 0.15.5",
@ -6366,22 +6331,22 @@ dependencies = [
[[package]]
name = "wast"
version = "241.0.2"
version = "243.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63f66e07e2ddf531fef6344dbf94d112df7c2f23ed6ffb10962e711500b8d816"
checksum = "df21d01c2d91e46cb7a221d79e58a2d210ea02020d57c092e79255cc2999ca7f"
dependencies = [
"bumpalo",
"leb128fmt",
"memchr",
"unicode-width 0.2.2",
"wasm-encoder 0.241.2",
"wasm-encoder 0.243.0",
]
[[package]]
name = "wat"
version = "1.241.2"
version = "1.243.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45f923705c40830af909c5dec2352ec2821202e4a66008194585e1917458a26d"
checksum = "226a9a91cd80a50449312fef0c75c23478fcecfcc4092bdebe1dc8e760ef521b"
dependencies = [
"wast",
]
@ -6777,9 +6742,9 @@ dependencies = [
[[package]]
name = "wit-component"
version = "0.241.2"
version = "0.243.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0c57df25e7ee612d946d3b7646c1ddb2310f8280aa2c17e543b66e0812241"
checksum = "36f9fc53513e461ce51dcf17a3e331752cb829f1d187069e54af5608fc998fe4"
dependencies = [
"anyhow",
"bitflags",
@ -6788,17 +6753,17 @@ dependencies = [
"serde",
"serde_derive",
"serde_json",
"wasm-encoder 0.241.2",
"wasm-encoder 0.243.0",
"wasm-metadata",
"wasmparser 0.241.2",
"wasmparser 0.243.0",
"wit-parser",
]
[[package]]
name = "wit-parser"
version = "0.241.2"
version = "0.243.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ef1c6ad67f35c831abd4039c02894de97034100899614d1c44e2268ad01c91"
checksum = "df983a8608e513d8997f435bb74207bf0933d0e49ca97aa9d8a6157164b9b7fc"
dependencies = [
"anyhow",
"id-arena",
@ -6809,7 +6774,7 @@ dependencies = [
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser 0.241.2",
"wasmparser 0.243.0",
]
[[package]]

View file

@ -97,7 +97,7 @@ See [the rustc-dev-guide for more info][sysllvm].
--set llvm.ninja=false \
--set rust.debug-assertions=false \
--set rust.jemalloc \
--set rust.use-lld=true \
--set rust.bootstrap-override-lld=true \
--set rust.lto=thin \
--set rust.codegen-units=1
```

View file

@ -1,3 +1,114 @@
Version 1.93.0 (2026-01-22)
==========================
<a id="1.93.0-Language"></a>
Language
--------
- [Stabilize several s390x `vector`-related target features and the `is_s390x_feature_detected!` macro](https://github.com/rust-lang/rust/pull/145656)
- [Stabilize declaration of C-style variadic functions for the `system` ABI](https://github.com/rust-lang/rust/pull/145954)
- [Emit error when using some keyword as a `cfg` predicate](https://github.com/rust-lang/rust/pull/146978)
- [Stabilize `asm_cfg`](https://github.com/rust-lang/rust/pull/147736)
- [During const-evaluation, support copying pointers byte-by-byte](https://github.com/rust-lang/rust/pull/148259)
- [LUB coercions now correctly handle function item types, and functions with differing safeties](https://github.com/rust-lang/rust/pull/148602)
- [Allow `const` items that contain mutable references to `static` (which is *very* unsafe, but not *always* UB)](https://github.com/rust-lang/rust/pull/148746)
- [Add warn-by-default `const_item_interior_mutations` lint to warn against calls which mutate interior mutable `const` items](https://github.com/rust-lang/rust/pull/148407)
- [Add warn-by-default `function_casts_as_integer` lint](https://github.com/rust-lang/rust/pull/141470)
<a id="1.93.0-Compiler"></a>
Compiler
--------
- [Stabilize `-Cjump-tables=bool`](https://github.com/rust-lang/rust/pull/145974). The flag was previously called `-Zno-jump-tables`.
<a id="1.93.0-Platform-Support"></a>
Platform Support
----------------
- [Promote `riscv64a23-unknown-linux-gnu` to Tier 2 (without host tools)](https://github.com/rust-lang/rust/pull/148435)
Refer to Rust's [platform support page][platform-support-doc]
for more information on Rust's tiered platform support.
[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html
<a id="1.93.0-Libraries"></a>
Libraries
---------
- [Stop internally using `specialization` on the `Copy` trait as it is unsound in the presence of lifetime dependent `Copy` implementations. This may result in some performance regressions as some standard library APIs may now call `Clone::clone` instead of performing bitwise copies](https://github.com/rust-lang/rust/pull/135634)
- [Allow the global allocator to use thread-local storage and `std::thread::current()`](https://github.com/rust-lang/rust/pull/144465)
- [Make `BTree::append` not update existing keys when appending an entry which already exists](https://github.com/rust-lang/rust/pull/145628)
- [Don't require `T: RefUnwindSafe` for `vec::IntoIter<T>: UnwindSafe`](https://github.com/rust-lang/rust/pull/145665)
<a id="1.93.0-Stabilized-APIs"></a>
Stabilized APIs
---------------
- [`<[MaybeUninit<T>]>::assume_init_drop`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.assume_init_drop)
- [`<[MaybeUninit<T>]>::assume_init_ref`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.assume_init_ref)
- [`<[MaybeUninit<T>]>::assume_init_mut`](https://doc.rust-lang.org/stable/core/primitive.slice.html#method.assume_init_mut)
- [`<[MaybeUninit<T>]>::write_copy_of_slice`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.write_copy_of_slice)
- [`<[MaybeUninit<T>]>::write_clone_of_slice`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.write_clone_of_slice)
- [`String::into_raw_parts`](https://doc.rust-lang.org/stable/std/string/struct.String.html#method.into_raw_parts)
- [`Vec::into_raw_parts`](https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.into_raw_parts)
- [`<iN>::unchecked_neg`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unchecked_neg)
- [`<iN>::unchecked_shl`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unchecked_shl)
- [`<iN>::unchecked_shr`](https://doc.rust-lang.org/stable/std/primitive.isize.html#method.unchecked_shr)
- [`<uN>::unchecked_shl`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unchecked_shl)
- [`<uN>::unchecked_shr`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.unchecked_shr)
- [`<[T]>::as_array`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_array)
- [`<[T]>::as_mut_array`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.as_mut_array)
- [`<*const [T]>::as_array`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_array)
- [`<*mut [T]>::as_mut_array`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.as_mut_array)
- [`VecDeque::pop_front_if`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.pop_front_if)
- [`VecDeque::pop_back_if`](https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.pop_back_if)
- [`Duration::from_nanos_u128`](https://doc.rust-lang.org/stable/std/time/struct.Duration.html#method.from_nanos_u128)
- [`char::MAX_LEN_UTF8`](https://doc.rust-lang.org/stable/std/primitive.char.html#associatedconstant.MAX_LEN_UTF8)
- [`char::MAX_LEN_UTF16`](https://doc.rust-lang.org/stable/std/primitive.char.html#associatedconstant.MAX_LEN_UTF16)
- [`std::fmt::from_fn`](https://doc.rust-lang.org/stable/std/fmt/fn.from_fn.html)
- [`std::fmt::FromFn`](https://doc.rust-lang.org/stable/std/fmt/struct.FromFn.html)
<a id="1.93.0-Cargo"></a>
Cargo
-----
- [Enable CARGO_CFG_DEBUG_ASSERTIONS in build scripts based on profile](https://github.com/rust-lang/cargo/pull/16160/)
- [In `cargo tree`, support long forms for `--format` variables](https://github.com/rust-lang/cargo/pull/16204/)
- [Add `--workspace` to `cargo clean`](https://github.com/rust-lang/cargo/pull/16263/)
<a id="1.93.0-Rustdoc"></a>
Rustdoc
-----
- [Remove `#![doc(document_private_items)]`](https://github.com/rust-lang/rust/pull/146495)
- [Include attribute and derive macros in search filters for "macros"](https://github.com/rust-lang/rust/pull/148176)
- [Include extern crates in search filters for `import`](https://github.com/rust-lang/rust/pull/148301)
- [Validate usage of crate-level doc attributes](https://github.com/rust-lang/rust/pull/149197). This means if any of `html_favicon_url`, `html_logo_url`, `html_playground_url`, `issue_tracker_base_url`, or `html_no_source` either has a missing value, an unexpected value, or a value of the wrong type, rustdoc will emit the deny-by-default lint `rustdoc::invalid_doc_attributes`.
<a id="1.93.0-Compatibility-Notes"></a>
Compatibility Notes
-------------------
- [Introduce `pin_v2` into the builtin attributes namespace](https://github.com/rust-lang/rust/pull/139751)
- [Update bundled musl to 1.2.5](https://github.com/rust-lang/rust/pull/142682)
- [On Emscripten, the unwinding ABI used when compiling with `panic=unwind` was changed from the JS exception handling ABI to the wasm exception handling ABI.](https://github.com/rust-lang/rust/pull/147224) If linking C/C++ object files with Rust objects, `-fwasm-exceptions` must be passed to the linker now. On nightly Rust, it is possible to get the old behavior with `-Zwasm-emscripten-eh=false -Zbuild-std`, but it will be removed in a future release.
- The `#[test]` attribute, used to define tests, was previously ignored in various places where it had no meaning (e.g on trait methods or types). Putting the `#[test]` attribute in these places is no longer ignored, and will now result in an error; this may also result in errors when generating rustdoc. [Error when `test` attribute is applied to structs](https://github.com/rust-lang/rust/pull/147841)
- Cargo now sets the `CARGO_CFG_DEBUG_ASSERTIONS` environment variable in more situations. This will cause crates depending on `static-init` versions 1.0.1 to 1.0.3 to fail compilation with "failed to resolve: use of unresolved module or unlinked crate `parking_lot`". See [the linked issue](https://github.com/rust-lang/rust/issues/150646#issuecomment-3718964342) for details.
- [User written types in the `offset_of!` macro are now checked to be well formed.](https://github.com/rust-lang/rust/issues/150465/)
- `cargo publish` no longer emits `.crate` files as a final artifact for user access when the `build.build-dir` config is unset
- [Upgrade the `deref_nullptr` lint from warn-by-default to deny-by-default](https://github.com/rust-lang/rust/pull/148122)
- [Add future-incompatibility warning for `...` function parameters without a pattern outside of `extern` blocks](https://github.com/rust-lang/rust/pull/143619)
- [Introduce future-compatibility warning for `repr(C)` enums whose discriminant values do not fit into a `c_int` or `c_uint`](https://github.com/rust-lang/rust/pull/147017)
- [Introduce future-compatibility warning against ignoring `repr(C)` types as part of `repr(transparent)`](https://github.com/rust-lang/rust/pull/147185)
Version 1.92.0 (2025-12-11)
==========================

View file

@ -27,6 +27,7 @@ pub enum CanonAbi {
C,
Rust,
RustCold,
RustPreserveNone,
/// An ABI that rustc does not know how to call or define.
Custom,
@ -54,7 +55,7 @@ pub enum CanonAbi {
impl CanonAbi {
pub fn is_rustic_abi(self) -> bool {
match self {
CanonAbi::Rust | CanonAbi::RustCold => true,
CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone => true,
CanonAbi::C
| CanonAbi::Custom
| CanonAbi::Arm(_)
@ -74,6 +75,7 @@ impl fmt::Display for CanonAbi {
CanonAbi::C => ExternAbi::C { unwind: false },
CanonAbi::Rust => ExternAbi::Rust,
CanonAbi::RustCold => ExternAbi::RustCold,
CanonAbi::RustPreserveNone => ExternAbi::RustPreserveNone,
CanonAbi::Custom => ExternAbi::Custom,
CanonAbi::Arm(arm_call) => match arm_call {
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },

View file

@ -42,6 +42,13 @@ pub enum ExternAbi {
/// in a platform-agnostic way.
RustInvalid,
/// Preserves no registers.
///
/// Note, that this ABI is not stable in the registers it uses, is intended as an optimization
/// and may fall-back to a more conservative calling convention if the backend does not support
/// forcing callers to save all registers.
RustPreserveNone,
/// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM.
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
Unadjusted,
@ -67,7 +74,6 @@ pub enum ExternAbi {
/* gpu */
/// An entry-point function called by the GPU's host
// FIXME: should not be callable from Rust on GPU targets, is for host's use only
GpuKernel,
/// An entry-point function called by the GPU's host
// FIXME: why do we have two of these?
@ -164,6 +170,7 @@ abi_impls! {
RustCall =><= "rust-call",
RustCold =><= "rust-cold",
RustInvalid =><= "rust-invalid",
RustPreserveNone =><= "rust-preserve-none",
Stdcall { unwind: false } =><= "stdcall",
Stdcall { unwind: true } =><= "stdcall-unwind",
System { unwind: false } =><= "system",
@ -244,7 +251,7 @@ impl ExternAbi {
/// - are subject to change between compiler versions
pub fn is_rustic_abi(self) -> bool {
use ExternAbi::*;
matches!(self, Rust | RustCall | RustCold)
matches!(self, Rust | RustCall | RustCold | RustPreserveNone)
}
/// Returns whether the ABI supports C variadics. This only controls whether we allow *imports*
@ -316,7 +323,8 @@ impl ExternAbi {
| Self::Thiscall { .. }
| Self::Vectorcall { .. }
| Self::SysV64 { .. }
| Self::Win64 { .. } => true,
| Self::Win64 { .. }
| Self::RustPreserveNone => true,
}
}
}

View file

@ -1,6 +1,7 @@
use std::assert_matches::assert_matches;
use std::str::FromStr;
use rustc_data_structures::assert_matches;
use super::*;
#[allow(non_snake_case)]

View file

@ -618,7 +618,7 @@ impl DroplessArena {
/// - Types that are `!Copy` and `Drop`: these must be specified in the
/// arguments. The `TypedArena` will be used for them.
///
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) {
#[derive(Default)]
pub struct Arena<'tcx> {

View file

@ -7,7 +7,7 @@ edition = "2024"
# tidy-alphabetical-start
bitflags = "2.4.1"
memchr = "2.7.6"
rustc-literal-escaper = "0.0.5"
rustc-literal-escaper = "0.0.7"
rustc_ast_ir = { path = "../rustc_ast_ir" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_index = { path = "../rustc_index" }

View file

@ -34,6 +34,7 @@ use rustc_span::source_map::{Spanned, respan};
use rustc_span::{ByteSymbol, DUMMY_SP, ErrorGuaranteed, Ident, Span, Symbol, kw, sym};
use thin_vec::{ThinVec, thin_vec};
use crate::attr::data_structures::CfgEntry;
pub use crate::format::*;
use crate::token::{self, CommentKind, Delimiter};
use crate::tokenstream::{DelimSpan, LazyAttrTokenStream, TokenStream};
@ -2108,18 +2109,19 @@ pub struct MacroDef {
/// `true` if macro was defined with `macro_rules`.
pub macro_rules: bool,
/// If this is a macro used for externally implementable items,
/// it refers to an extern item which is its "target". This requires
/// name resolution so can't just be an attribute, so we store it in this field.
pub eii_extern_target: Option<EiiExternTarget>,
/// Corresponds to `#[eii_declaration(...)]`.
/// `#[eii_declaration(...)]` is a built-in attribute macro, not a built-in attribute,
/// because we require some name resolution to occur in the parameters of this attribute.
/// Name resolution isn't possible in attributes otherwise, so we encode it in the AST.
/// During ast lowering, we turn it back into an attribute again
pub eii_declaration: Option<EiiDecl>,
}
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic, Walkable)]
pub struct EiiExternTarget {
/// path to the extern item we're targetting
pub extern_item_path: Path,
pub struct EiiDecl {
/// path to the extern item we're targeting
pub foreign_item: Path,
pub impl_unsafe: bool,
pub span: Span,
}
#[derive(Clone, Encodable, Decodable, Debug, Copy, Hash, Eq, PartialEq)]
@ -2394,7 +2396,7 @@ impl FnSig {
/// * the `G<Ty> = Ty` in `Trait<G<Ty> = Ty>`
/// * the `A: Bound` in `Trait<A: Bound>`
/// * the `RetTy` in `Trait(ArgTy, ArgTy) -> RetTy`
/// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `associated_const_equality`)
/// * the `C = { Ct }` in `Trait<C = { Ct }>` (feature `min_generic_const_args`)
/// * the `f(..): Bound` in `Trait<f(..): Bound>` (feature `return_type_notation`)
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct AssocItemConstraint {
@ -3346,7 +3348,8 @@ impl UseTree {
/// Distinguishes between `Attribute`s that decorate items and Attributes that
/// are contained as statements within items. These two cases need to be
/// distinguished for pretty-printing.
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, HashStable_Generic, Walkable)]
#[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)]
#[derive(Encodable, Decodable, HashStable_Generic, Walkable)]
pub enum AttrStyle {
Outer,
Inner,
@ -3390,7 +3393,7 @@ impl NormalAttr {
item: AttrItem {
unsafety: Safety::Default,
path: Path::from_ident(ident),
args: AttrArgs::Empty,
args: AttrItemKind::Unparsed(AttrArgs::Empty),
tokens: None,
},
tokens: None,
@ -3402,11 +3405,53 @@ impl NormalAttr {
pub struct AttrItem {
pub unsafety: Safety,
pub path: Path,
pub args: AttrArgs,
pub args: AttrItemKind,
// Tokens for the meta item, e.g. just the `foo` within `#[foo]` or `#![foo]`.
pub tokens: Option<LazyAttrTokenStream>,
}
/// Some attributes are stored in a parsed form, for performance reasons.
/// Their arguments don't have to be reparsed everytime they're used
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub enum AttrItemKind {
Parsed(EarlyParsedAttribute),
Unparsed(AttrArgs),
}
impl AttrItemKind {
pub fn unparsed(self) -> Option<AttrArgs> {
match self {
AttrItemKind::Unparsed(args) => Some(args),
AttrItemKind::Parsed(_) => None,
}
}
pub fn unparsed_ref(&self) -> Option<&AttrArgs> {
match self {
AttrItemKind::Unparsed(args) => Some(args),
AttrItemKind::Parsed(_) => None,
}
}
pub fn span(&self) -> Option<Span> {
match self {
AttrItemKind::Unparsed(args) => args.span(),
AttrItemKind::Parsed(_) => None,
}
}
}
/// Some attributes are stored in parsed form in the AST.
/// This is done for performance reasons, so the attributes don't need to be reparsed on every use.
///
/// Currently all early parsed attributes are excluded from pretty printing at rustc_ast_pretty::pprust::state::print_attribute_inline.
/// When adding new early parsed attributes, consider whether they should be pretty printed.
#[derive(Clone, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum EarlyParsedAttribute {
CfgTrace(CfgEntry),
CfgAttrTrace,
}
impl AttrItem {
pub fn is_valid_for_outer_style(&self) -> bool {
self.path == sym::cfg_attr
@ -3581,6 +3626,7 @@ impl Item {
pub fn opt_generics(&self) -> Option<&Generics> {
match &self.kind {
ItemKind::ExternCrate(..)
| ItemKind::ConstBlock(_)
| ItemKind::Use(_)
| ItemKind::Mod(..)
| ItemKind::ForeignMod(_)
@ -3770,6 +3816,19 @@ pub struct Fn {
pub struct EiiImpl {
pub node_id: NodeId,
pub eii_macro_path: Path,
/// This field is an implementation detail that prevents a lot of bugs.
/// See <https://github.com/rust-lang/rust/issues/149981> for an example.
///
/// The problem is, that if we generate a declaration *together* with its default,
/// we generate both a declaration and an implementation. The generated implementation
/// uses the same mechanism to register itself as a user-defined implementation would,
/// despite being invisible to users. What does happen is a name resolution step.
/// The invisible default implementation has to find the declaration.
/// Both are generated at the same time, so we can skip that name resolution step.
///
/// This field is that shortcut: we prefill the extern target to skip a name resolution step,
/// making sure it never fails. It'd be awful UX if we fail name resolution in code invisible to the user.
pub known_eii_macro_resolution: Option<EiiDecl>,
pub impl_safety: Safety,
pub span: Span,
pub inner_span: Span,
@ -3837,6 +3896,17 @@ impl ConstItemRhs {
}
}
#[derive(Clone, Encodable, Decodable, Debug, Walkable)]
pub struct ConstBlockItem {
pub id: NodeId,
pub span: Span,
pub block: Box<Block>,
}
impl ConstBlockItem {
pub const IDENT: Ident = Ident { name: kw::Underscore, span: DUMMY_SP };
}
// Adding a new variant? Please update `test_item` in `tests/ui/macros/stringify.rs`.
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum ItemKind {
@ -3856,6 +3926,11 @@ pub enum ItemKind {
///
/// E.g., `const FOO: i32 = 42;`.
Const(Box<ConstItem>),
/// A module-level const block.
/// Equivalent to `const _: () = const { ... };`.
///
/// E.g., `const { assert!(true) }`.
ConstBlock(ConstBlockItem),
/// A function declaration (`fn`).
///
/// E.g., `fn foo(bar: usize) -> usize { .. }`.
@ -3932,6 +4007,8 @@ impl ItemKind {
| ItemKind::MacroDef(ident, _)
| ItemKind::Delegation(box Delegation { ident, .. }) => Some(ident),
ItemKind::ConstBlock(_) => Some(ConstBlockItem::IDENT),
ItemKind::Use(_)
| ItemKind::ForeignMod(_)
| ItemKind::GlobalAsm(_)
@ -3945,9 +4022,9 @@ impl ItemKind {
pub fn article(&self) -> &'static str {
use ItemKind::*;
match self {
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
| Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
| Delegation(..) | DelegationMac(..) => "a",
Use(..) | Static(..) | Const(..) | ConstBlock(..) | Fn(..) | Mod(..)
| GlobalAsm(..) | TyAlias(..) | Struct(..) | Union(..) | Trait(..) | TraitAlias(..)
| MacroDef(..) | Delegation(..) | DelegationMac(..) => "a",
ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
}
}
@ -3958,6 +4035,7 @@ impl ItemKind {
ItemKind::Use(..) => "`use` import",
ItemKind::Static(..) => "static item",
ItemKind::Const(..) => "constant item",
ItemKind::ConstBlock(..) => "const block",
ItemKind::Fn(..) => "function",
ItemKind::Mod(..) => "module",
ItemKind::ForeignMod(..) => "extern block",
@ -3987,7 +4065,18 @@ impl ItemKind {
| Self::Trait(box Trait { generics, .. })
| Self::TraitAlias(box TraitAlias { generics, .. })
| Self::Impl(Impl { generics, .. }) => Some(generics),
_ => None,
Self::ExternCrate(..)
| Self::Use(..)
| Self::Static(..)
| Self::ConstBlock(..)
| Self::Mod(..)
| Self::ForeignMod(..)
| Self::GlobalAsm(..)
| Self::MacCall(..)
| Self::MacroDef(..)
| Self::Delegation(..)
| Self::DelegationMac(..) => None,
}
}
}

View file

@ -0,0 +1,101 @@
use std::fmt;
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_span::{Span, Symbol};
use thin_vec::ThinVec;
use crate::attr::version::RustcVersion;
#[derive(Encodable, Decodable, Clone, Debug, PartialEq, Eq, Hash, HashStable_Generic)]
pub enum CfgEntry {
All(ThinVec<CfgEntry>, Span),
Any(ThinVec<CfgEntry>, Span),
Not(Box<CfgEntry>, Span),
Bool(bool, Span),
NameValue { name: Symbol, value: Option<Symbol>, span: Span },
Version(Option<RustcVersion>, Span),
}
impl CfgEntry {
pub fn lower_spans(&mut self, lower_span: impl Copy + Fn(Span) -> Span) {
match self {
CfgEntry::All(subs, span) | CfgEntry::Any(subs, span) => {
*span = lower_span(*span);
subs.iter_mut().for_each(|sub| sub.lower_spans(lower_span));
}
CfgEntry::Not(sub, span) => {
*span = lower_span(*span);
sub.lower_spans(lower_span);
}
CfgEntry::Bool(_, span)
| CfgEntry::NameValue { span, .. }
| CfgEntry::Version(_, span) => {
*span = lower_span(*span);
}
}
}
pub fn span(&self) -> Span {
let (Self::All(_, span)
| Self::Any(_, span)
| Self::Not(_, span)
| Self::Bool(_, span)
| Self::NameValue { span, .. }
| Self::Version(_, span)) = self;
*span
}
/// Same as `PartialEq` but doesn't check spans and ignore order of cfgs.
pub fn is_equivalent_to(&self, other: &Self) -> bool {
match (self, other) {
(Self::All(a, _), Self::All(b, _)) | (Self::Any(a, _), Self::Any(b, _)) => {
a.len() == b.len() && a.iter().all(|a| b.iter().any(|b| a.is_equivalent_to(b)))
}
(Self::Not(a, _), Self::Not(b, _)) => a.is_equivalent_to(b),
(Self::Bool(a, _), Self::Bool(b, _)) => a == b,
(
Self::NameValue { name: name1, value: value1, .. },
Self::NameValue { name: name2, value: value2, .. },
) => name1 == name2 && value1 == value2,
(Self::Version(a, _), Self::Version(b, _)) => a == b,
_ => false,
}
}
}
impl fmt::Display for CfgEntry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fn write_entries(
name: &str,
entries: &[CfgEntry],
f: &mut fmt::Formatter<'_>,
) -> fmt::Result {
write!(f, "{name}(")?;
for (nb, entry) in entries.iter().enumerate() {
if nb != 0 {
f.write_str(", ")?;
}
entry.fmt(f)?;
}
f.write_str(")")
}
match self {
Self::All(entries, _) => write_entries("all", entries, f),
Self::Any(entries, _) => write_entries("any", entries, f),
Self::Not(entry, _) => write!(f, "not({entry})"),
Self::Bool(value, _) => write!(f, "{value}"),
Self::NameValue { name, value, .. } => {
match value {
// We use `as_str` and debug display to have characters escaped and `"`
// characters surrounding the string.
Some(value) => write!(f, "{name} = {:?}", value.as_str()),
None => write!(f, "{name}"),
}
}
Self::Version(version, _) => match version {
Some(version) => write!(f, "{version}"),
None => Ok(()),
},
}
}
}

View file

@ -1,5 +1,8 @@
//! Functions dealing with attributes and meta items.
pub mod data_structures;
pub mod version;
use std::fmt::Debug;
use std::sync::atomic::{AtomicU32, Ordering};
@ -8,6 +11,7 @@ use rustc_span::{Ident, Span, Symbol, sym};
use smallvec::{SmallVec, smallvec};
use thin_vec::{ThinVec, thin_vec};
use crate::AttrItemKind;
use crate::ast::{
AttrArgs, AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute, DUMMY_NODE_ID, DelimArgs,
Expr, ExprKind, LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit, NormalAttr, Path,
@ -62,6 +66,15 @@ impl Attribute {
}
}
/// Replaces the arguments of this attribute with new arguments `AttrItemKind`.
/// This is useful for making this attribute into a trace attribute, and should otherwise be avoided.
pub fn replace_args(&mut self, new_args: AttrItemKind) {
match &mut self.kind {
AttrKind::Normal(normal) => normal.item.args = new_args,
AttrKind::DocComment(..) => panic!("unexpected doc comment"),
}
}
pub fn unwrap_normal_item(self) -> AttrItem {
match self.kind {
AttrKind::Normal(normal) => normal.item,
@ -77,7 +90,7 @@ impl AttributeExt for Attribute {
fn value_span(&self) -> Option<Span> {
match &self.kind {
AttrKind::Normal(normal) => match &normal.item.args {
AttrKind::Normal(normal) => match &normal.item.args.unparsed_ref()? {
AttrArgs::Eq { expr, .. } => Some(expr.span),
_ => None,
},
@ -96,11 +109,11 @@ impl AttributeExt for Attribute {
}
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
fn ident(&self) -> Option<Ident> {
fn name(&self) -> Option<Symbol> {
match &self.kind {
AttrKind::Normal(normal) => {
if let [ident] = &*normal.item.path.segments {
Some(ident.ident)
Some(ident.ident.name)
} else {
None
}
@ -109,9 +122,18 @@ impl AttributeExt for Attribute {
}
}
fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>> {
match &self.kind {
AttrKind::Normal(p) => Some(p.item.path.segments.iter().map(|i| i.ident).collect()),
AttrKind::Normal(p) => {
Some(p.item.path.segments.iter().map(|i| i.ident.name).collect())
}
AttrKind::DocComment(_, _) => None,
}
}
fn path_span(&self) -> Option<Span> {
match &self.kind {
AttrKind::Normal(attr) => Some(attr.item.path.span),
AttrKind::DocComment(_, _) => None,
}
}
@ -138,7 +160,7 @@ impl AttributeExt for Attribute {
fn is_word(&self) -> bool {
if let AttrKind::Normal(normal) = &self.kind {
matches!(normal.item.args, AttrArgs::Empty)
matches!(normal.item.args, AttrItemKind::Unparsed(AttrArgs::Empty))
} else {
false
}
@ -213,6 +235,34 @@ impl AttributeExt for Attribute {
}
}
fn deprecation_note(&self) -> Option<Ident> {
match &self.kind {
AttrKind::Normal(normal) if normal.item.path == sym::deprecated => {
let meta = &normal.item;
// #[deprecated = "..."]
if let Some(s) = meta.value_str() {
return Some(Ident { name: s, span: meta.span() });
}
// #[deprecated(note = "...")]
if let Some(list) = meta.meta_item_list() {
for nested in list {
if let Some(mi) = nested.meta_item()
&& mi.path == sym::note
&& let Some(s) = mi.value_str()
{
return Some(Ident { name: s, span: mi.span });
}
}
}
None
}
_ => None,
}
}
fn doc_resolution_scope(&self) -> Option<AttrStyle> {
match &self.kind {
AttrKind::DocComment(..) => Some(self.style),
@ -255,6 +305,7 @@ impl Attribute {
pub fn may_have_doc_links(&self) -> bool {
self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
|| self.deprecation_note().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
}
/// Extracts the MetaItem from inside this Attribute.
@ -294,7 +345,7 @@ impl AttrItem {
}
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
match &self.args {
match &self.args.unparsed_ref()? {
AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => {
MetaItemKind::list_from_tokens(args.tokens.clone())
}
@ -315,7 +366,7 @@ impl AttrItem {
/// #[attr("value")]
/// ```
fn value_str(&self) -> Option<Symbol> {
match &self.args {
match &self.args.unparsed_ref()? {
AttrArgs::Eq { expr, .. } => match expr.kind {
ExprKind::Lit(token_lit) => {
LitKind::from_token_lit(token_lit).ok().and_then(|lit| lit.str())
@ -339,7 +390,7 @@ impl AttrItem {
/// #[attr("value")]
/// ```
fn value_span(&self) -> Option<Span> {
match &self.args {
match &self.args.unparsed_ref()? {
AttrArgs::Eq { expr, .. } => Some(expr.span),
AttrArgs::Delimited(_) | AttrArgs::Empty => None,
}
@ -355,7 +406,7 @@ impl AttrItem {
}
pub fn meta_kind(&self) -> Option<MetaItemKind> {
MetaItemKind::from_attr_args(&self.args)
MetaItemKind::from_attr_args(self.args.unparsed_ref()?)
}
}
@ -690,7 +741,13 @@ fn mk_attr(
args: AttrArgs,
span: Span,
) -> Attribute {
mk_attr_from_item(g, AttrItem { unsafety, path, args, tokens: None }, None, style, span)
mk_attr_from_item(
g,
AttrItem { unsafety, path, args: AttrItemKind::Unparsed(args), tokens: None },
None,
style,
span,
)
}
pub fn mk_attr_from_item(
@ -794,9 +851,7 @@ pub trait AttributeExt: Debug {
/// For a single-segment attribute (i.e., `#[attr]` and not `#[path::atrr]`),
/// return the name of the attribute; otherwise, returns `None`.
fn name(&self) -> Option<Symbol> {
self.ident().map(|ident| ident.name)
}
fn name(&self) -> Option<Symbol>;
/// Get the meta item list, `#[attr(meta item list)]`
fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>>;
@ -807,9 +862,6 @@ pub trait AttributeExt: Debug {
/// Gets the span of the value literal, as string, when using `#[attr = value]`
fn value_span(&self) -> Option<Span>;
/// For a single-segment attribute, returns its ident; otherwise, returns `None`.
fn ident(&self) -> Option<Ident>;
/// Checks whether the path of this attribute matches the name.
///
/// Matches one segment of the path to each element in `name`
@ -822,7 +874,7 @@ pub trait AttributeExt: Debug {
#[inline]
fn has_name(&self, name: Symbol) -> bool {
self.ident().map(|x| x.name == name).unwrap_or(false)
self.name().map(|x| x == name).unwrap_or(false)
}
#[inline]
@ -836,13 +888,13 @@ pub trait AttributeExt: Debug {
fn is_word(&self) -> bool;
fn path(&self) -> SmallVec<[Symbol; 1]> {
self.ident_path()
.map(|i| i.into_iter().map(|i| i.name).collect())
.unwrap_or(smallvec![sym::doc])
self.symbol_path().unwrap_or(smallvec![sym::doc])
}
fn path_span(&self) -> Option<Span>;
/// Returns None for doc comments
fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>>;
fn symbol_path(&self) -> Option<SmallVec<[Symbol; 1]>>;
/// Returns the documentation if this is a doc comment or a sugared doc comment.
/// * `///doc` returns `Some("doc")`.
@ -850,6 +902,11 @@ pub trait AttributeExt: Debug {
/// * `#[doc(...)]` returns `None`.
fn doc_str(&self) -> Option<Symbol>;
/// Returns the deprecation note if this is deprecation attribute.
/// * `#[deprecated = "note"]` returns `Some("note")`.
/// * `#[deprecated(note = "note", ...)]` returns `Some("note")`.
fn deprecation_note(&self) -> Option<Ident>;
fn is_proc_macro_attr(&self) -> bool {
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
.iter()
@ -903,10 +960,6 @@ impl Attribute {
AttributeExt::value_span(self)
}
pub fn ident(&self) -> Option<Ident> {
AttributeExt::ident(self)
}
pub fn path_matches(&self, name: &[Symbol]) -> bool {
AttributeExt::path_matches(self, name)
}
@ -938,10 +991,6 @@ impl Attribute {
AttributeExt::path(self)
}
pub fn ident_path(&self) -> Option<SmallVec<[Ident; 1]>> {
AttributeExt::ident_path(self)
}
pub fn doc_str(&self) -> Option<Symbol> {
AttributeExt::doc_str(self)
}

View file

@ -1,16 +1,10 @@
use std::borrow::Cow;
use std::fmt::{self, Display};
use std::sync::OnceLock;
use rustc_error_messages::{DiagArgValue, IntoDiagArg};
use rustc_macros::{
BlobDecodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version,
};
use crate::attrs::PrintAttribute;
use rustc_macros::{BlobDecodable, Encodable, HashStable_Generic, current_rustc_version};
#[derive(Encodable, BlobDecodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(HashStable_Generic, PrintAttribute)]
#[derive(HashStable_Generic)]
pub struct RustcVersion {
pub major: u16,
pub minor: u16,
@ -47,9 +41,3 @@ impl Display for RustcVersion {
write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
}
}
impl IntoDiagArg for RustcVersion {
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> DiagArgValue {
DiagArgValue::Str(Cow::Owned(self.to_string()))
}
}

View file

@ -5,7 +5,6 @@
//! This API is completely unstable and subject to change.
// tidy-alphabetical-start
#![cfg_attr(bootstrap, feature(array_windows))]
#![doc(test(attr(deny(warnings), allow(internal_features))))]
#![feature(associated_type_defaults)]
#![feature(box_patterns)]

View file

@ -40,13 +40,13 @@ impl DocFragmentKind {
}
}
#[derive(Clone, Copy, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum CommentKind {
Line,
Block,
}
#[derive(Copy, Clone, PartialEq, Debug, Encodable, Decodable, HashStable_Generic)]
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
pub enum InvisibleOrigin {
// From the expansion of a metavariable in a declarative macro.
MetaVar(MetaVarKind),
@ -123,7 +123,7 @@ impl fmt::Display for MetaVarKind {
/// Describes how a sequence of token trees is delimited.
/// Cannot use `proc_macro::Delimiter` directly because this
/// structure should implement some additional traits.
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
pub enum Delimiter {
/// `( ... )`
Parenthesis,
@ -186,7 +186,7 @@ impl Delimiter {
// type. This means that float literals like `1f32` are classified by this type
// as `Int`. Only upon conversion to `ast::LitKind` will such a literal be
// given the `Float` kind.
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum LitKind {
Bool, // AST only, must never appear in a `Token`
Byte,
@ -203,7 +203,7 @@ pub enum LitKind {
}
/// A literal token.
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct Lit {
pub kind: LitKind,
pub symbol: Symbol,
@ -349,7 +349,7 @@ fn ident_can_begin_type(name: Symbol, span: Span, is_raw: IdentIsRaw) -> bool {
.contains(&name)
}
#[derive(PartialEq, Encodable, Decodable, Debug, Copy, Clone, HashStable_Generic)]
#[derive(PartialEq, Eq, Encodable, Decodable, Hash, Debug, Copy, Clone, HashStable_Generic)]
pub enum IdentIsRaw {
No,
Yes,
@ -376,7 +376,7 @@ impl From<bool> for IdentIsRaw {
}
}
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum TokenKind {
/* Expression-operator symbols. */
/// `=`
@ -526,7 +526,7 @@ pub enum TokenKind {
Eof,
}
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
#[derive(Clone, Copy, PartialEq, Eq, Hash, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct Token {
pub kind: TokenKind,
pub span: Span,
@ -625,12 +625,12 @@ impl TokenKind {
}
impl Token {
pub fn new(kind: TokenKind, span: Span) -> Self {
pub const fn new(kind: TokenKind, span: Span) -> Self {
Token { kind, span }
}
/// Some token that will be thrown away later.
pub fn dummy() -> Self {
pub const fn dummy() -> Self {
Token::new(TokenKind::Question, DUMMY_SP)
}

View file

@ -5,6 +5,7 @@
//! which are themselves a single [`Token`] or a `Delimited` subsequence of tokens.
use std::borrow::Cow;
use std::hash::Hash;
use std::ops::Range;
use std::sync::Arc;
use std::{cmp, fmt, iter, mem};
@ -22,7 +23,7 @@ use crate::token::{self, Delimiter, Token, TokenKind};
use crate::{AttrVec, Attribute};
/// Part of a `TokenStream`.
#[derive(Debug, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
pub enum TokenTree {
/// A single token. Should never be `OpenDelim` or `CloseDelim`, because
/// delimiters are implicitly represented by `Delimited`.
@ -538,7 +539,7 @@ pub struct AttrsTarget {
/// compound token. Used for conversions to `proc_macro::Spacing`. Also used to
/// guide pretty-printing, which is where the `JointHidden` value (which isn't
/// part of `proc_macro::Spacing`) comes in useful.
#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
pub enum Spacing {
/// The token cannot join with the following token to form a compound
/// token.
@ -595,7 +596,7 @@ pub enum Spacing {
}
/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
#[derive(Clone, Debug, Default, Encodable, Decodable)]
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Encodable, Decodable)]
pub struct TokenStream(pub(crate) Arc<Vec<TokenTree>>);
impl TokenStream {
@ -811,14 +812,6 @@ impl TokenStream {
}
}
impl PartialEq<TokenStream> for TokenStream {
fn eq(&self, other: &TokenStream) -> bool {
self.iter().eq(other.iter())
}
}
impl Eq for TokenStream {}
impl FromIterator<TokenTree> for TokenStream {
fn from_iter<I: IntoIterator<Item = TokenTree>>(iter: I) -> Self {
TokenStream::new(iter.into_iter().collect::<Vec<TokenTree>>())
@ -970,7 +963,8 @@ impl TokenCursor {
}
}
#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic, Walkable)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Encodable, Decodable, HashStable_Generic, Walkable)]
pub struct DelimSpan {
pub open: Span,
pub close: Span,
@ -994,7 +988,7 @@ impl DelimSpan {
}
}
#[derive(Copy, Clone, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable, HashStable_Generic)]
pub struct DelimSpacing {
pub open: Spacing,
pub close: Spacing,

View file

@ -366,6 +366,7 @@ macro_rules! common_visitor_and_walkers {
crate::token::LitKind,
crate::tokenstream::LazyAttrTokenStream,
crate::tokenstream::TokenStream,
EarlyParsedAttribute,
Movability,
Mutability,
Pinnedness,
@ -424,6 +425,7 @@ macro_rules! common_visitor_and_walkers {
ByRef,
Closure,
Const,
ConstBlockItem,
ConstItem,
ConstItemRhs,
Defaultness,
@ -457,6 +459,7 @@ macro_rules! common_visitor_and_walkers {
ModSpans,
MutTy,
NormalAttr,
AttrItemKind,
Parens,
ParenthesizedArgs,
PatFieldsRest,
@ -487,7 +490,7 @@ macro_rules! common_visitor_and_walkers {
WhereEqPredicate,
WhereRegionPredicate,
YieldKind,
EiiExternTarget,
EiiDecl,
EiiImpl,
);
@ -823,6 +826,8 @@ macro_rules! common_visitor_and_walkers {
visit_visitable!($($mut)? vis, use_tree),
ItemKind::Static(item) =>
visit_visitable!($($mut)? vis, item),
ItemKind::ConstBlock(item) =>
visit_visitable!($($mut)? vis, item),
ItemKind::Const(item) =>
visit_visitable!($($mut)? vis, item),
ItemKind::Mod(safety, ident, mod_kind) =>

View file

@ -52,7 +52,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
| asm::InlineAsmArch::LoongArch64
| asm::InlineAsmArch::S390x
);
if !is_stable && !self.tcx.features().asm_experimental_arch() {
if !is_stable
&& !self.tcx.features().asm_experimental_arch()
&& sp
.ctxt()
.outer_expn_data()
.allow_internal_unstable
.filter(|features| features.contains(&sym::asm_experimental_arch))
.is_none()
{
feature_err(
&self.tcx.sess,
sym::asm_experimental_arch,

View file

@ -98,7 +98,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Let statements are allowed to have impl trait in bindings.
let super_ = l.super_.map(|span| self.lower_span(span));
let ty = l.ty.as_ref().map(|t| {
self.lower_ty(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
self.lower_ty_alloc(t, self.impl_trait_in_bindings_ctxt(ImplTraitPosition::Variable))
});
let init = l.kind.init().map(|init| self.lower_expr(init));
let hir_id = self.lower_node_id(l.id);

View file

@ -152,10 +152,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
) -> DelegationResults<'hir> {
let span = self.lower_span(delegation.path.segments.last().unwrap().ident.span);
let ids = self.get_delegation_ids(
self.resolver.delegation_infos[&self.local_def_id(item_id)].resolution_node,
span,
);
// Delegation can be unresolved in illegal places such as function bodies in extern blocks (see #151356)
let ids = if let Some(delegation_info) =
self.resolver.delegation_infos.get(&self.local_def_id(item_id))
{
self.get_delegation_ids(delegation_info.resolution_node, span)
} else {
return self.generate_delegation_error(
self.dcx().span_delayed_bug(
span,
format!("LoweringContext: the delegation {:?} is unresolved", item_id),
),
span,
delegation,
);
};
match ids {
Ok(ids) => {

View file

@ -158,14 +158,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
ExprKind::Cast(expr, ty) => {
let expr = self.lower_expr(expr);
let ty =
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
let ty = self
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
hir::ExprKind::Cast(expr, ty)
}
ExprKind::Type(expr, ty) => {
let expr = self.lower_expr(expr);
let ty =
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
let ty = self
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast));
hir::ExprKind::Type(expr, ty)
}
ExprKind::AddrOf(k, m, ohs) => {
@ -335,7 +335,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt),
ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf(
self.lower_ty(
self.lower_ty_alloc(
container,
ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),
),
@ -371,7 +371,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
*kind,
self.lower_expr(expr),
ty.as_ref().map(|ty| {
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Cast))
self.lower_ty_alloc(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::Cast),
)
}),
),
@ -617,7 +620,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
});
if let Some(ty) = opt_ty {
let ty = self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path));
let ty = self.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path));
let block_expr = self.arena.alloc(self.expr_block(whole_block));
hir::ExprKind::Type(block_expr, ty)
} else {

View file

@ -312,7 +312,7 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> {
fn visit_const_arg(&mut self, const_arg: &'hir ConstArg<'hir, AmbigArg>) {
self.insert(
const_arg.as_unambig_ct().span(),
const_arg.as_unambig_ct().span,
const_arg.hir_id,
Node::ConstArg(const_arg.as_unambig_ct()),
);

View file

@ -2,7 +2,7 @@ use rustc_abi::ExternAbi;
use rustc_ast::visit::AssocCtxt;
use rustc_ast::*;
use rustc_errors::{E0570, ErrorGuaranteed, struct_span_code_err};
use rustc_hir::attrs::{AttributeKind, EiiDecl};
use rustc_hir::attrs::{AttributeKind, EiiImplResolution};
use rustc_hir::def::{DefKind, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LocalDefId};
use rustc_hir::{
@ -134,6 +134,56 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
}
fn lower_eii_decl(
&mut self,
id: NodeId,
name: Ident,
EiiDecl { foreign_item, impl_unsafe }: &EiiDecl,
) -> Option<hir::attrs::EiiDecl> {
self.lower_path_simple_eii(id, foreign_item).map(|did| hir::attrs::EiiDecl {
foreign_item: did,
impl_unsafe: *impl_unsafe,
name,
})
}
fn lower_eii_impl(
&mut self,
EiiImpl {
node_id,
eii_macro_path,
impl_safety,
span,
inner_span,
is_default,
known_eii_macro_resolution,
}: &EiiImpl,
) -> hir::attrs::EiiImpl {
let resolution = if let Some(target) = known_eii_macro_resolution
&& let Some(decl) = self.lower_eii_decl(
*node_id,
// the expect is ok here since we always generate this path in the eii macro.
eii_macro_path.segments.last().expect("at least one segment").ident,
target,
) {
EiiImplResolution::Known(decl)
} else if let Some(macro_did) = self.lower_path_simple_eii(*node_id, eii_macro_path) {
EiiImplResolution::Macro(macro_did)
} else {
EiiImplResolution::Error(
self.dcx().span_delayed_bug(*span, "eii never resolved without errors given"),
)
};
hir::attrs::EiiImpl {
span: self.lower_span(*span),
inner_span: self.lower_span(*inner_span),
impl_marked_unsafe: self.lower_safety(*impl_safety, hir::Safety::Safe).is_unsafe(),
is_default: *is_default,
resolution,
}
}
fn generate_extra_attrs_for_item_kind(
&mut self,
id: NodeId,
@ -143,53 +193,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
ItemKind::Fn(box Fn { eii_impls, .. }) if eii_impls.is_empty() => Vec::new(),
ItemKind::Fn(box Fn { eii_impls, .. }) => {
vec![hir::Attribute::Parsed(AttributeKind::EiiImpls(
eii_impls
.iter()
.flat_map(
|EiiImpl {
node_id,
eii_macro_path,
impl_safety,
span,
inner_span,
is_default,
}| {
self.lower_path_simple_eii(*node_id, eii_macro_path).map(|did| {
hir::attrs::EiiImpl {
eii_macro: did,
span: self.lower_span(*span),
inner_span: self.lower_span(*inner_span),
impl_marked_unsafe: self
.lower_safety(*impl_safety, hir::Safety::Safe)
.is_unsafe(),
is_default: *is_default,
}
})
},
)
.collect(),
eii_impls.iter().map(|i| self.lower_eii_impl(i)).collect(),
))]
}
ItemKind::MacroDef(
_,
MacroDef {
eii_extern_target: Some(EiiExternTarget { extern_item_path, impl_unsafe, span }),
..
},
) => self
.lower_path_simple_eii(id, extern_item_path)
.map(|did| {
vec![hir::Attribute::Parsed(AttributeKind::EiiExternTarget(EiiDecl {
eii_extern_target: did,
impl_unsafe: *impl_unsafe,
span: self.lower_span(*span),
}))]
})
ItemKind::MacroDef(name, MacroDef { eii_declaration: Some(target), .. }) => self
.lower_eii_decl(id, *name, target)
.map(|decl| vec![hir::Attribute::Parsed(AttributeKind::EiiDeclaration(decl))])
.unwrap_or_default(),
ItemKind::ExternCrate(..)
| ItemKind::Use(..)
| ItemKind::Static(..)
| ItemKind::Const(..)
| ItemKind::ConstBlock(..)
| ItemKind::Mod(..)
| ItemKind::ForeignMod(..)
| ItemKind::GlobalAsm(..)
@ -227,10 +243,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
vis_span,
span: self.lower_span(i.span),
has_delayed_lints: !self.delayed_lints.is_empty(),
eii: find_attr!(
attrs,
AttributeKind::EiiImpls(..) | AttributeKind::EiiExternTarget(..)
),
eii: find_attr!(attrs, AttributeKind::EiiImpls(..) | AttributeKind::EiiDeclaration(..)),
};
self.arena.alloc(item)
}
@ -264,14 +277,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
define_opaque,
}) => {
let ident = self.lower_ident(*ident);
let ty =
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
let ty = self
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
let body_id = self.lower_const_body(span, e.as_deref());
self.lower_define_opaque(hir_id, define_opaque);
hir::ItemKind::Static(*m, ident, ty, body_id)
}
ItemKind::Const(box ast::ConstItem {
ident, generics, ty, rhs, define_opaque, ..
ItemKind::Const(box ConstItem {
defaultness: _,
ident,
generics,
ty,
rhs,
define_opaque,
}) => {
let ident = self.lower_ident(*ident);
let (generics, (ty, rhs)) = self.lower_generics(
@ -279,8 +297,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
let ty = this
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
let ty = this.lower_ty_alloc(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
);
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), span);
(ty, rhs)
},
@ -288,6 +308,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
self.lower_define_opaque(hir_id, &define_opaque);
hir::ItemKind::Const(ident, generics, ty, rhs)
}
ItemKind::ConstBlock(ConstBlockItem { span, id, block }) => hir::ItemKind::Const(
self.lower_ident(ConstBlockItem::IDENT),
hir::Generics::empty(),
self.arena.alloc(self.ty_tup(DUMMY_SP, &[])),
hir::ConstItemRhs::Body({
let body = hir::Expr {
hir_id: self.lower_node_id(*id),
kind: hir::ExprKind::Block(self.lower_block(block, false), None),
span: self.lower_span(*span),
};
self.record_body(&[], body)
}),
),
ItemKind::Fn(box Fn {
sig: FnSig { decl, header, span: fn_sig_span },
ident,
@ -379,7 +412,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
this.arena.alloc(this.ty(span, hir::TyKind::Err(guar)))
}
Some(ty) => this.lower_ty(
Some(ty) => this.lower_ty_alloc(
ty,
ImplTraitContext::OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias {
@ -453,7 +486,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
.as_deref()
.map(|of_trait| this.lower_trait_impl_header(of_trait));
let lowered_ty = this.lower_ty(
let lowered_ty = this.lower_ty_alloc(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::ImplSelf),
);
@ -522,7 +555,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
hir::ItemKind::TraitAlias(constness, ident, generics, bounds)
}
ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_extern_target: _ }) => {
ItemKind::MacroDef(ident, MacroDef { body, macro_rules, eii_declaration: _ }) => {
let ident = self.lower_ident(*ident);
let body = Box::new(self.lower_delim_args(body));
let def_id = self.local_def_id(id);
@ -536,7 +569,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let macro_def = self.arena.alloc(ast::MacroDef {
body,
macro_rules: *macro_rules,
eii_extern_target: None,
eii_declaration: None,
});
hir::ItemKind::Macro(ident, macro_def, macro_kinds)
}
@ -676,7 +709,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
has_delayed_lints: !this.delayed_lints.is_empty(),
eii: find_attr!(
attrs,
AttributeKind::EiiImpls(..) | AttributeKind::EiiExternTarget(..)
AttributeKind::EiiImpls(..) | AttributeKind::EiiDeclaration(..)
),
};
hir::OwnerNode::Item(this.arena.alloc(item))
@ -758,8 +791,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
safety,
define_opaque,
}) => {
let ty =
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
let ty = self
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::StaticTy));
let safety = self.lower_safety(*safety, hir::Safety::Unsafe);
if define_opaque.is_some() {
self.dcx().span_err(i.span, "foreign statics cannot define opaque types");
@ -870,7 +903,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
&mut self,
(index, f): (usize, &FieldDef),
) -> hir::FieldDef<'hir> {
let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy));
let ty =
self.lower_ty_alloc(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy));
let hir_id = self.lower_node_id(f.id);
self.lower_attrs(hir_id, &f.attrs, f.span, Target::Field);
hir::FieldDef {
@ -908,8 +942,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
let ty = this
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
let ty = this.lower_ty_alloc(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
);
let rhs = rhs
.as_ref()
.map(|rhs| this.lower_const_item_rhs(attrs, Some(rhs), i.span));
@ -1008,7 +1044,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
let ty = ty.as_ref().map(|x| {
this.lower_ty(
this.lower_ty_alloc(
x,
ImplTraitContext::Disallowed(ImplTraitPosition::AssocTy),
)
@ -1120,8 +1156,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
i.id,
ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
|this| {
let ty = this
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy));
let ty = this.lower_ty_alloc(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::ConstTy),
);
this.lower_define_opaque(hir_id, &define_opaque);
let rhs = this.lower_const_item_rhs(attrs, rhs.as_ref(), i.span);
hir::ImplItemKind::Const(ty, rhs)
@ -1180,7 +1218,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ImplItemKind::Type(ty)
}
Some(ty) => {
let ty = this.lower_ty(
let ty = this.lower_ty_alloc(
ty,
ImplTraitContext::OpaqueTy {
origin: hir::OpaqueTyOrigin::TyAlias {
@ -1916,7 +1954,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
bound_generic_params,
hir::GenericParamSource::Binder,
),
bounded_ty: self.lower_ty(
bounded_ty: self.lower_ty_alloc(
bounded_ty,
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
),
@ -1945,10 +1983,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
WherePredicateKind::EqPredicate(WhereEqPredicate { lhs_ty, rhs_ty }) => {
hir::WherePredicateKind::EqPredicate(hir::WhereEqPredicate {
lhs_ty: self
.lower_ty(lhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
rhs_ty: self
.lower_ty(rhs_ty, ImplTraitContext::Disallowed(ImplTraitPosition::Bound)),
lhs_ty: self.lower_ty_alloc(
lhs_ty,
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
),
rhs_ty: self.lower_ty_alloc(
rhs_ty,
ImplTraitContext::Disallowed(ImplTraitPosition::Bound),
),
})
}
});

View file

@ -51,7 +51,7 @@ use rustc_hir::attrs::AttributeKind;
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
use rustc_hir::lints::DelayedLint;
use rustc_hir::lints::{AttributeLint, DelayedLint};
use rustc_hir::{
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource,
LifetimeSyntax, ParamName, Target, TraitCandidate, find_attr,
@ -1022,12 +1022,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.attribute_parser.parse_attribute_list(
attrs,
target_span,
target_hir_id,
target,
OmitDoc::Lower,
|s| l.lower(s),
|l| {
self.delayed_lints.push(DelayedLint::AttributeParsing(l));
|lint_id, span, kind| {
self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
lint_id,
id: target_hir_id,
span,
kind,
}));
},
)
}
@ -1125,8 +1129,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let kind = match &constraint.kind {
AssocItemConstraintKind::Equality { term } => {
let term = match term {
Term::Ty(ty) => self.lower_ty(ty, itctx).into(),
Term::Const(c) => self.lower_anon_const_to_const_arg(c).into(),
Term::Ty(ty) => self.lower_ty_alloc(ty, itctx).into(),
Term::Const(c) => self.lower_anon_const_to_const_arg_and_alloc(c).into(),
};
hir::AssocItemConstraintKind::Equality { term }
}
@ -1250,17 +1254,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
_ => {}
}
GenericArg::Type(self.lower_ty(ty, itctx).try_as_ambig_ty().unwrap())
}
ast::GenericArg::Const(ct) => {
GenericArg::Const(self.lower_anon_const_to_const_arg(ct).try_as_ambig_ct().unwrap())
GenericArg::Type(self.lower_ty_alloc(ty, itctx).try_as_ambig_ty().unwrap())
}
ast::GenericArg::Const(ct) => GenericArg::Const(
self.lower_anon_const_to_const_arg_and_alloc(ct).try_as_ambig_ct().unwrap(),
),
}
}
#[instrument(level = "debug", skip(self))]
fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
self.arena.alloc(self.lower_ty_direct(t, itctx))
fn lower_ty_alloc(&mut self, t: &Ty, itctx: ImplTraitContext) -> &'hir hir::Ty<'hir> {
self.arena.alloc(self.lower_ty(t, itctx))
}
fn lower_path_ty(
@ -1324,11 +1328,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.ty(span, hir::TyKind::Tup(tys))
}
fn lower_ty_direct(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
fn lower_ty(&mut self, t: &Ty, itctx: ImplTraitContext) -> hir::Ty<'hir> {
let kind = match &t.kind {
TyKind::Infer => hir::TyKind::Infer(()),
TyKind::Err(guar) => hir::TyKind::Err(*guar),
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty_alloc(ty, itctx)),
TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
TyKind::Ref(region, mt) => {
let lifetime = self.lower_ty_direct_lifetime(t, *region);
@ -1362,15 +1366,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
hir::TyKind::UnsafeBinder(self.arena.alloc(hir::UnsafeBinderTy {
generic_params,
inner_ty: self.lower_ty(&f.inner_ty, itctx),
inner_ty: self.lower_ty_alloc(&f.inner_ty, itctx),
}))
}
TyKind::Never => hir::TyKind::Never,
TyKind::Tup(tys) => hir::TyKind::Tup(
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty_direct(ty, itctx))),
self.arena.alloc_from_iter(tys.iter().map(|ty| self.lower_ty(ty, itctx))),
),
TyKind::Paren(ty) => {
return self.lower_ty_direct(ty, itctx);
return self.lower_ty(ty, itctx);
}
TyKind::Path(qself, path) => {
return self.lower_path_ty(t, qself, path, ParamMode::Explicit, itctx);
@ -1393,7 +1397,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
))
}
TyKind::Array(ty, length) => hir::TyKind::Array(
self.lower_ty(ty, itctx),
self.lower_ty_alloc(ty, itctx),
self.lower_array_length_to_const_arg(length),
),
TyKind::TraitObject(bounds, kind) => {
@ -1493,7 +1497,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
}
TyKind::Pat(ty, pat) => {
hir::TyKind::Pat(self.lower_ty(ty, itctx), self.lower_ty_pat(pat, ty.span))
hir::TyKind::Pat(self.lower_ty_alloc(ty, itctx), self.lower_ty_pat(pat, ty.span))
}
TyKind::MacCall(_) => {
span_bug!(t.span, "`TyKind::MacCall` should have been expanded by now")
@ -1693,7 +1697,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ImplTraitContext::Disallowed(ImplTraitPosition::PointerParam)
}
};
self.lower_ty_direct(&param.ty, itctx)
self.lower_ty(&param.ty, itctx)
}));
let output = match coro {
@ -1732,7 +1736,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
ImplTraitContext::Disallowed(ImplTraitPosition::PointerReturn)
}
};
hir::FnRetTy::Return(self.lower_ty(ty, itctx))
hir::FnRetTy::Return(self.lower_ty_alloc(ty, itctx))
}
FnRetTy::Default(span) => hir::FnRetTy::DefaultReturn(self.lower_span(*span)),
},
@ -1843,7 +1847,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// Not `OpaqueTyOrigin::AsyncFn`: that's only used for the
// `impl Future` opaque type that `async fn` implicitly
// generates.
self.lower_ty(ty, itctx)
self.lower_ty_alloc(ty, itctx)
}
FnRetTy::Default(ret_ty_span) => self.arena.alloc(self.ty_tup(*ret_ty_span, &[])),
};
@ -1986,8 +1990,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let (name, kind) = self.lower_generic_param_kind(param, source);
let hir_id = self.lower_node_id(param.id);
self.lower_attrs(hir_id, &param.attrs, param.span(), Target::Param);
hir::GenericParam {
let param_attrs = &param.attrs;
let param_span = param.span();
let param = hir::GenericParam {
hir_id,
def_id: self.local_def_id(param.id),
name,
@ -1996,7 +2001,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
kind,
colon_span: param.colon_span.map(|s| self.lower_span(s)),
source,
}
};
self.lower_attrs(hir_id, param_attrs, param_span, Target::from_generic_param(&param));
param
}
fn lower_generic_param_kind(
@ -2036,7 +2043,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
})
.map(|def| {
self.lower_ty(
self.lower_ty_alloc(
def,
ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
)
@ -2047,8 +2054,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
(hir::ParamName::Plain(self.lower_ident(param.ident)), kind)
}
GenericParamKind::Const { ty, span: _, default } => {
let ty = self
.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault));
let ty = self.lower_ty_alloc(
ty,
ImplTraitContext::Disallowed(ImplTraitPosition::GenericDefault),
);
// Not only do we deny const param defaults in binders but we also map them to `None`
// since later compiler stages cannot handle them (and shouldn't need to be able to).
@ -2064,7 +2073,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
false
}
})
.map(|def| self.lower_anon_const_to_const_arg(def));
.map(|def| self.lower_anon_const_to_const_arg_and_alloc(def));
(
hir::ParamName::Plain(self.lower_ident(param.ident)),
@ -2198,7 +2207,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
}
fn lower_mt(&mut self, mt: &MutTy, itctx: ImplTraitContext) -> hir::MutTy<'hir> {
hir::MutTy { ty: self.lower_ty(&mt.ty, itctx), mutbl: mt.mutbl }
hir::MutTy { ty: self.lower_ty_alloc(&mt.ty, itctx), mutbl: mt.mutbl }
}
#[instrument(level = "debug", skip(self), ret)]
@ -2283,10 +2292,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// `ExprKind::Paren(ExprKind::Underscore)` and should also be lowered to `GenericArg::Infer`
match c.value.peel_parens().kind {
ExprKind::Underscore => {
let ct_kind = hir::ConstArgKind::Infer(self.lower_span(c.value.span), ());
self.arena.alloc(hir::ConstArg { hir_id: self.lower_node_id(c.id), kind: ct_kind })
let ct_kind = hir::ConstArgKind::Infer(());
self.arena.alloc(hir::ConstArg {
hir_id: self.lower_node_id(c.id),
kind: ct_kind,
span: self.lower_span(c.value.span),
})
}
_ => self.lower_anon_const_to_const_arg(c),
_ => self.lower_anon_const_to_const_arg_and_alloc(c),
}
}
@ -2354,7 +2367,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
hir::ConstArgKind::Anon(ct)
};
self.arena.alloc(hir::ConstArg { hir_id: self.next_id(), kind: ct_kind })
self.arena.alloc(hir::ConstArg {
hir_id: self.next_id(),
kind: ct_kind,
span: self.lower_span(span),
})
}
fn lower_const_item_rhs(
@ -2365,15 +2382,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
) -> hir::ConstItemRhs<'hir> {
match rhs {
Some(ConstItemRhs::TypeConst(anon)) => {
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg(anon))
hir::ConstItemRhs::TypeConst(self.lower_anon_const_to_const_arg_and_alloc(anon))
}
None if attr::contains_name(attrs, sym::type_const) => {
None if find_attr!(attrs, AttributeKind::TypeConst(_)) => {
let const_arg = ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Error(
DUMMY_SP,
self.dcx().span_delayed_bug(DUMMY_SP, "no block"),
),
span: DUMMY_SP,
};
hir::ConstItemRhs::TypeConst(self.arena.alloc(const_arg))
}
@ -2386,16 +2403,65 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
#[instrument(level = "debug", skip(self), ret)]
fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir> {
let span = self.lower_span(expr.span);
let overly_complex_const = |this: &mut Self| {
let e = this.dcx().struct_span_err(
expr.span,
"complex const arguments must be placed inside of a `const` block",
);
ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(expr.span, e.emit()) }
ConstArg { hir_id: this.next_id(), kind: hir::ConstArgKind::Error(e.emit()), span }
};
match &expr.kind {
ExprKind::Call(func, args) if let ExprKind::Path(qself, path) = &func.kind => {
let qpath = self.lower_qpath(
func.id,
qself,
path,
ParamMode::Explicit,
AllowReturnTypeNotation::No,
ImplTraitContext::Disallowed(ImplTraitPosition::Path),
None,
);
let lowered_args = self.arena.alloc_from_iter(args.iter().map(|arg| {
let const_arg = if let ExprKind::ConstBlock(anon_const) = &arg.kind {
let def_id = self.local_def_id(anon_const.id);
let def_kind = self.tcx.def_kind(def_id);
assert_eq!(DefKind::AnonConst, def_kind);
self.lower_anon_const_to_const_arg(anon_const)
} else {
self.lower_expr_to_const_arg_direct(arg)
};
&*self.arena.alloc(const_arg)
}));
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::TupleCall(qpath, lowered_args),
span,
}
}
ExprKind::Tup(exprs) => {
let exprs = self.arena.alloc_from_iter(exprs.iter().map(|expr| {
let expr = if let ExprKind::ConstBlock(anon_const) = &expr.kind {
let def_id = self.local_def_id(anon_const.id);
let def_kind = self.tcx.def_kind(def_id);
assert_eq!(DefKind::AnonConst, def_kind);
self.lower_anon_const_to_const_arg(anon_const)
} else {
self.lower_expr_to_const_arg_direct(&expr)
};
&*self.arena.alloc(expr)
}));
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Tup(exprs), span }
}
ExprKind::Path(qself, path) => {
let qpath = self.lower_qpath(
expr.id,
@ -2408,7 +2474,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
None,
);
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) }
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath), span }
}
ExprKind::Struct(se) => {
let path = self.lower_qpath(
@ -2436,7 +2502,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let def_kind = self.tcx.def_kind(def_id);
assert_eq!(DefKind::AnonConst, def_kind);
self.lower_anon_const_to_const_arg_direct(anon_const)
self.lower_anon_const_to_const_arg(anon_const)
} else {
self.lower_expr_to_const_arg_direct(&f.expr)
};
@ -2449,18 +2515,50 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
})
}));
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Struct(path, fields) }
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Struct(path, fields),
span,
}
}
ExprKind::Array(elements) => {
let lowered_elems = self.arena.alloc_from_iter(elements.iter().map(|element| {
let const_arg = if let ExprKind::ConstBlock(anon_const) = &element.kind {
let def_id = self.local_def_id(anon_const.id);
assert_eq!(DefKind::AnonConst, self.tcx.def_kind(def_id));
self.lower_anon_const_to_const_arg(anon_const)
} else {
self.lower_expr_to_const_arg_direct(element)
};
&*self.arena.alloc(const_arg)
}));
let array_expr = self.arena.alloc(hir::ConstArgArrayExpr {
span: self.lower_span(expr.span),
elems: lowered_elems,
});
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Array(array_expr),
span,
}
}
ExprKind::Underscore => ConstArg {
hir_id: self.lower_node_id(expr.id),
kind: hir::ConstArgKind::Infer(expr.span, ()),
kind: hir::ConstArgKind::Infer(()),
span,
},
ExprKind::Block(block, _) => {
if let [stmt] = block.stmts.as_slice()
&& let StmtKind::Expr(expr) = &stmt.kind
&& matches!(
expr.kind,
ExprKind::Block(..) | ExprKind::Path(..) | ExprKind::Struct(..)
ExprKind::Block(..)
| ExprKind::Path(..)
| ExprKind::Struct(..)
| ExprKind::Call(..)
| ExprKind::Tup(..)
| ExprKind::Array(..)
)
{
return self.lower_expr_to_const_arg_direct(expr);
@ -2468,18 +2566,31 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
overly_complex_const(self)
}
ExprKind::Lit(literal) => {
let span = expr.span;
let literal = self.lower_lit(literal, span);
ConstArg {
hir_id: self.lower_node_id(expr.id),
kind: hir::ConstArgKind::Literal(literal.node),
span,
}
}
_ => overly_complex_const(self),
}
}
/// See [`hir::ConstArg`] for when to use this function vs
/// [`Self::lower_anon_const_to_anon_const`].
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> &'hir hir::ConstArg<'hir> {
self.arena.alloc(self.lower_anon_const_to_const_arg_direct(anon))
fn lower_anon_const_to_const_arg_and_alloc(
&mut self,
anon: &AnonConst,
) -> &'hir hir::ConstArg<'hir> {
self.arena.alloc(self.lower_anon_const_to_const_arg(anon))
}
#[instrument(level = "debug", skip(self))]
fn lower_anon_const_to_const_arg_direct(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
fn lower_anon_const_to_const_arg(&mut self, anon: &AnonConst) -> hir::ConstArg<'hir> {
let tcx = self.tcx;
// We cannot change parsing depending on feature gates available,
@ -2491,7 +2602,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
return match anon.mgca_disambiguation {
MgcaDisambiguation::AnonConst => {
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) }
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Anon(lowered_anon),
span: lowered_anon.span,
}
}
MgcaDisambiguation::Direct => self.lower_expr_to_const_arg_direct(&anon.value),
};
@ -2528,11 +2643,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
return ConstArg {
hir_id: self.lower_node_id(anon.id),
kind: hir::ConstArgKind::Path(qpath),
span: self.lower_span(expr.span),
};
}
let lowered_anon = self.lower_anon_const_to_anon_const(anon);
ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Anon(lowered_anon) }
ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Anon(lowered_anon),
span: self.lower_span(expr.span),
}
}
/// See [`hir::ConstArg`] for when to use this function vs

View file

@ -444,16 +444,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let pat_hir_id = self.lower_node_id(pattern.id);
let node = match &pattern.kind {
TyPatKind::Range(e1, e2, Spanned { node: end, span }) => hir::TyPatKind::Range(
e1.as_deref().map(|e| self.lower_anon_const_to_const_arg(e)).unwrap_or_else(|| {
self.lower_ty_pat_range_end(
hir::LangItem::RangeMin,
span.shrink_to_lo(),
base_type,
)
}),
e1.as_deref()
.map(|e| self.lower_anon_const_to_const_arg_and_alloc(e))
.unwrap_or_else(|| {
self.lower_ty_pat_range_end(
hir::LangItem::RangeMin,
span.shrink_to_lo(),
base_type,
)
}),
e2.as_deref()
.map(|e| match end {
RangeEnd::Included(..) => self.lower_anon_const_to_const_arg(e),
RangeEnd::Included(..) => self.lower_anon_const_to_const_arg_and_alloc(e),
RangeEnd::Excluded => self.lower_excluded_range_end(e),
})
.unwrap_or_else(|| {
@ -511,6 +513,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.arena.alloc(hir::ConstArg {
hir_id: self.next_id(),
kind: hir::ConstArgKind::Anon(self.arena.alloc(anon_const)),
span,
})
}
@ -555,6 +558,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
})
});
let hir_id = self.next_id();
self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id })
self.arena.alloc(hir::ConstArg { kind: hir::ConstArgKind::Anon(ct), hir_id, span })
}
}

View file

@ -36,7 +36,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let qself = qself
.as_ref()
// Reject cases like `<impl Trait>::Assoc` and `<impl Trait as Trait>::Assoc`.
.map(|q| self.lower_ty(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path)));
.map(|q| {
self.lower_ty_alloc(&q.ty, ImplTraitContext::Disallowed(ImplTraitPosition::Path))
});
let partial_res =
self.resolver.get_partial_res(id).unwrap_or_else(|| PartialRes::new(Res::Err));
@ -510,7 +512,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// we generally don't permit such things (see #51008).
let ParenthesizedArgs { span, inputs, inputs_span, output } = data;
let inputs = self.arena.alloc_from_iter(inputs.iter().map(|ty| {
self.lower_ty_direct(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
}));
let output_ty = match output {
// Only allow `impl Trait` in return position. i.e.:
@ -520,9 +522,9 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// ```
FnRetTy::Ty(ty) if matches!(itctx, ImplTraitContext::OpaqueTy { .. }) => {
if self.tcx.features().impl_trait_in_fn_trait_return() {
self.lower_ty(ty, itctx)
self.lower_ty_alloc(ty, itctx)
} else {
self.lower_ty(
self.lower_ty_alloc(
ty,
ImplTraitContext::FeatureGated(
ImplTraitPosition::FnTraitReturn,
@ -531,9 +533,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
)
}
}
FnRetTy::Ty(ty) => {
self.lower_ty(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
}
FnRetTy::Ty(ty) => self
.lower_ty_alloc(ty, ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn)),
FnRetTy::Default(_) => self.arena.alloc(self.ty_tup(*span, &[])),
};
let args = smallvec![GenericArg::Type(

View file

@ -29,7 +29,6 @@ pub(crate) fn extern_abi_enabled(
})
}
#[allow(rustc::untranslatable_diagnostic)]
pub(crate) fn gate_unstable_abi(sess: &Session, features: &Features, span: Span, abi: ExternAbi) {
match extern_abi_enabled(features, span, abi) {
Ok(_) => (),
@ -96,6 +95,11 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
ExternAbi::RustCold => {
Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental })
}
ExternAbi::RustPreserveNone => Err(UnstableAbi {
abi,
feature: sym::rust_preserve_none_cc,
explain: GateReason::Experimental,
}),
ExternAbi::RustInvalid => {
Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail })
}

View file

@ -400,10 +400,18 @@ impl<'a> AstValidator<'a> {
CanonAbi::C
| CanonAbi::Rust
| CanonAbi::RustCold
| CanonAbi::RustPreserveNone
| CanonAbi::Arm(_)
| CanonAbi::GpuKernel
| CanonAbi::X86(_) => { /* nothing to check */ }
CanonAbi::GpuKernel => {
// An `extern "gpu-kernel"` function cannot be `async` and/or `gen`.
self.reject_coroutine(abi, sig);
// An `extern "gpu-kernel"` function cannot return a value.
self.reject_return(abi, sig);
}
CanonAbi::Custom => {
// An `extern "custom"` function must be unsafe.
self.reject_safe_fn(abi, ctxt, sig);
@ -433,18 +441,7 @@ impl<'a> AstValidator<'a> {
self.dcx().emit_err(errors::AbiX86Interrupt { spans, param_count });
}
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output
&& match &ret_ty.kind {
TyKind::Never => false,
TyKind::Tup(tup) if tup.is_empty() => false,
_ => true,
}
{
self.dcx().emit_err(errors::AbiMustNotHaveReturnType {
span: ret_ty.span,
abi,
});
}
self.reject_return(abi, sig);
} else {
// An `extern "interrupt"` function must have type `fn()`.
self.reject_params_or_return(abi, ident, sig);
@ -496,6 +493,18 @@ impl<'a> AstValidator<'a> {
}
}
fn reject_return(&self, abi: ExternAbi, sig: &FnSig) {
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output
&& match &ret_ty.kind {
TyKind::Never => false,
TyKind::Tup(tup) if tup.is_empty() => false,
_ => true,
}
{
self.dcx().emit_err(errors::AbiMustNotHaveReturnType { span: ret_ty.span, abi });
}
}
fn reject_params_or_return(&self, abi: ExternAbi, ident: &Ident, sig: &FnSig) {
let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect();
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output

View file

@ -13,15 +13,11 @@ use crate::errors;
macro_rules! gate {
($visitor:expr, $feature:ident, $span:expr, $explain:expr) => {{
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
feature_err(&$visitor.sess, sym::$feature, $span, $explain).emit();
}
}};
($visitor:expr, $feature:ident, $span:expr, $explain:expr, $help:expr) => {{
if !$visitor.features.$feature() && !$span.allows_unstable(sym::$feature) {
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
feature_err(&$visitor.sess, sym::$feature, $span, $explain).with_help($help).emit();
}
}};
@ -31,13 +27,11 @@ macro_rules! gate {
macro_rules! gate_alt {
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr) => {{
if !$has_feature && !$span.allows_unstable($name) {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
feature_err(&$visitor.sess, $name, $span, $explain).emit();
}
}};
($visitor:expr, $has_feature:expr, $name:expr, $span:expr, $explain:expr, $notes: expr) => {{
if !$has_feature && !$span.allows_unstable($name) {
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
let mut diag = feature_err(&$visitor.sess, $name, $span, $explain);
for note in $notes {
diag.note(*note);
@ -160,7 +154,7 @@ impl<'a> PostExpansionVisitor<'a> {
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
fn visit_attribute(&mut self, attr: &ast::Attribute) {
let attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
let attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
// Check feature gates for built-in attributes.
if let Some(BuiltinAttribute {
gate: AttributeGate::Gated { feature, message, check, notes, .. },
@ -491,7 +485,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
&& (!visitor.features.gen_blocks() && !span.allows_unstable(sym::gen_blocks))
&& (!visitor.features.yield_expr() && !span.allows_unstable(sym::yield_expr))
{
#[allow(rustc::untranslatable_diagnostic)]
// Emit yield_expr as the error, since that will be sufficient. You can think of it
// as coroutines and gen_blocks imply yield_expr.
feature_err(&visitor.sess, sym::yield_expr, *span, "yield syntax is experimental")
@ -505,7 +498,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
half_open_range_patterns_in_slices,
"half-open range patterns in slices are unstable"
);
gate_all!(associated_const_equality, "associated const equality is incomplete");
gate_all!(yeet_expr, "`do yeet` expression is experimental");
gate_all!(const_closures, "const closures are experimental");
gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
@ -518,6 +510,22 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(postfix_match, "postfix match is experimental");
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
gate_all!(min_generic_const_args, "unbraced const blocks as const args are experimental");
// associated_const_equality is stabilized as part of min_generic_const_args
if let Some(spans) = spans.get(&sym::associated_const_equality) {
for span in spans {
if !visitor.features.min_generic_const_args()
&& !span.allows_unstable(sym::min_generic_const_args)
{
feature_err(
&visitor.sess,
sym::min_generic_const_args,
*span,
"associated const equality is incomplete",
)
.emit();
}
}
}
gate_all!(global_registration, "global registration is experimental");
gate_all!(return_type_notation, "return type notation is experimental");
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
@ -529,6 +537,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
gate_all!(super_let, "`super let` is experimental");
gate_all!(frontmatter, "frontmatters are experimental");
gate_all!(coroutines, "coroutine syntax is experimental");
gate_all!(const_block_items, "const block items are experimental");
if !visitor.features.never_patterns() {
if let Some(spans) = spans.get(&sym::never_patterns) {
@ -543,7 +552,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
if let Ok(snippet) = sm.span_to_snippet(span)
&& snippet == "!"
{
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
feature_err(sess, sym::never_patterns, span, "`!` patterns are experimental")
.emit();
} else {

View file

@ -694,7 +694,7 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
}
ast::Safety::Default | ast::Safety::Safe(_) => {}
}
match &item.args {
match &item.args.unparsed_ref().expect("Parsed attributes are never printed") {
AttrArgs::Delimited(DelimArgs { dspan: _, delim, tokens }) => self.print_mac_common(
Some(MacHeader::Path(&item.path)),
false,
@ -865,10 +865,10 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere
sp: Span,
print_visibility: impl FnOnce(&mut Self),
) {
if let Some(eii_extern_target) = &macro_def.eii_extern_target {
self.word("#[eii_extern_target(");
self.print_path(&eii_extern_target.extern_item_path, false, 0);
if eii_extern_target.impl_unsafe {
if let Some(eii_decl) = &macro_def.eii_declaration {
self.word("#[eii_declaration(");
self.print_path(&eii_decl.foreign_item, false, 0);
if eii_decl.impl_unsafe {
self.word(",");
self.space();
self.word("unsafe");

View file

@ -205,6 +205,17 @@ impl<'a> State<'a> {
define_opaque.as_deref(),
);
}
ast::ItemKind::ConstBlock(ast::ConstBlockItem { id: _, span: _, block }) => {
let ib = self.ibox(INDENT_UNIT);
self.word("const");
self.nbsp();
{
let cb = self.cbox(0);
let ib = self.ibox(0);
self.print_block_with_attrs(block, &[], cb, ib);
}
self.end(ib);
}
ast::ItemKind::Const(box ast::ConstItem {
defaultness,
ident,

View file

@ -23,6 +23,9 @@ attr_parsing_doc_alias_malformed =
attr_parsing_doc_alias_start_end =
{$attr_str} cannot start or end with ' '
attr_parsing_doc_attr_not_crate_level =
`#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute
attr_parsing_doc_attribute_not_attribute =
nonexistent builtin attribute `{$attribute}` used in `#[doc(attribute = "...")]`
.help = only existing builtin attributes are allowed in core/std
@ -227,7 +230,7 @@ attr_parsing_unstable_cfg_target_compact =
compact `cfg(target(..))` is experimental and subject to change
attr_parsing_unstable_feature_bound_incompatible_stability = item annotated with `#[unstable_feature_bound]` should not be stable
.help = If this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
.help = if this item is meant to be stable, do not use any functions annotated with `#[unstable_feature_bound]`. Otherwise, mark this item as unstable with `#[unstable]`
attr_parsing_unsupported_instruction_set = target `{$current_target}` does not support `#[instruction_set({$instruction_set}::*)]`

View file

@ -9,7 +9,7 @@ use rustc_feature::{
};
use rustc_hir::attrs::CfgEntry;
use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{AttrPath, RustcVersion};
use rustc_hir::{AttrPath, RustcVersion, Target};
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_parse::{exp, parse_in};
use rustc_session::Session;
@ -94,7 +94,6 @@ pub fn parse_cfg_entry<S: Stage>(
LitKind::Bool(b) => CfgEntry::Bool(b, lit.span),
_ => return Err(cx.expected_identifier(lit.span)),
},
MetaItemOrLitParser::Err(_, err) => return Err(*err),
})
}
@ -294,11 +293,9 @@ pub fn parse_cfg_attr(
sess: &Session,
features: Option<&Features>,
) -> Option<(CfgEntry, Vec<(AttrItem, Span)>)> {
match cfg_attr.get_normal_item().args {
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
if !tokens.is_empty() =>
{
check_cfg_attr_bad_delim(&sess.psess, dspan, delim);
match cfg_attr.get_normal_item().args.unparsed_ref().unwrap() {
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, tokens }) if !tokens.is_empty() => {
check_cfg_attr_bad_delim(&sess.psess, *dspan, *delim);
match parse_in(&sess.psess, tokens.clone(), "`cfg_attr` input", |p| {
parse_cfg_attr_internal(p, sess, features, cfg_attr)
}) {
@ -322,7 +319,7 @@ pub fn parse_cfg_attr(
}
_ => {
let (span, reason) = if let ast::AttrArgs::Delimited(ast::DelimArgs { dspan, .. }) =
cfg_attr.get_normal_item().args
cfg_attr.get_normal_item().args.unparsed_ref()?
{
(dspan.entire(), AttributeParseErrorReason::ExpectedAtLeastOneArgument)
} else {
@ -363,7 +360,8 @@ fn parse_cfg_attr_internal<'a>(
) -> PResult<'a, (CfgEntry, Vec<(ast::AttrItem, Span)>)> {
// Parse cfg predicate
let pred_start = parser.token.span;
let meta = MetaItemOrLitParser::parse_single(parser, ShouldEmit::ErrorsAndLints)?;
let meta =
MetaItemOrLitParser::parse_single(parser, ShouldEmit::ErrorsAndLints { recover: true })?;
let pred_span = pred_start.with_hi(parser.token.span.hi());
let cfg_predicate = AttributeParser::parse_single_args(
@ -371,19 +369,14 @@ fn parse_cfg_attr_internal<'a>(
attribute.span,
attribute.get_normal_item().span(),
attribute.style,
AttrPath {
segments: attribute
.ident_path()
.expect("cfg_attr is not a doc comment")
.into_boxed_slice(),
span: attribute.span,
},
AttrPath { segments: attribute.path().into_boxed_slice(), span: attribute.span },
Some(attribute.get_normal_item().unsafety),
ParsedDescription::Attribute,
pred_span,
CRATE_NODE_ID,
Target::Crate,
features,
ShouldEmit::ErrorsAndLints,
ShouldEmit::ErrorsAndLints { recover: true },
&meta,
parse_cfg_entry,
&CFG_ATTR_TEMPLATE,
@ -420,7 +413,6 @@ fn try_gate_cfg(name: Symbol, span: Span, sess: &Session, features: Option<&Feat
}
}
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &Session, features: &Features) {
let (cfg, feature, has_feature) = gated_cfg;
if !has_feature(features) && !cfg_span.allows_unstable(*feature) {

View file

@ -2,12 +2,12 @@ use rustc_ast::token::Token;
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AttrStyle, NodeId, token};
use rustc_feature::{AttributeTemplate, Features};
use rustc_hir::AttrPath;
use rustc_hir::attrs::CfgEntry;
use rustc_hir::{AttrPath, Target};
use rustc_parse::exp;
use rustc_parse::parser::Parser;
use rustc_session::Session;
use rustc_span::{ErrorGuaranteed, Ident, Span};
use rustc_span::{ErrorGuaranteed, Span, sym};
use crate::parser::MetaItemOrLitParser;
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
@ -78,24 +78,24 @@ pub fn parse_cfg_select(
}
}
} else {
let meta = MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints)
.map_err(|diag| diag.emit())?;
let meta =
MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints { recover: true })
.map_err(|diag| diag.emit())?;
let cfg_span = meta.span();
let cfg = AttributeParser::parse_single_args(
sess,
cfg_span,
cfg_span,
AttrStyle::Inner,
AttrPath {
segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(),
span: cfg_span,
},
AttrPath { segments: vec![sym::cfg_select].into_boxed_slice(), span: cfg_span },
None,
ParsedDescription::Macro,
cfg_span,
lint_node_id,
// Doesn't matter what the target actually is here.
Target::Crate,
features,
ShouldEmit::ErrorsAndLints,
ShouldEmit::ErrorsAndLints { recover: true },
&meta,
parse_cfg_entry,
&AttributeTemplate::default(),

View file

@ -709,11 +709,108 @@ impl<S: Stage> NoArgsAttributeParser<S> for RustcPassIndirectlyInNonRusticAbisPa
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
}
pub(crate) struct EiiExternItemParser;
pub(crate) struct EiiForeignItemParser;
impl<S: Stage> NoArgsAttributeParser<S> for EiiExternItemParser {
const PATH: &[Symbol] = &[sym::rustc_eii_extern_item];
impl<S: Stage> NoArgsAttributeParser<S> for EiiForeignItemParser {
const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::EiiExternItem;
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::EiiForeignItem;
}
pub(crate) struct PatchableFunctionEntryParser;
impl<S: Stage> SingleAttributeParser<S> for PatchableFunctionEntryParser {
const PATH: &[Symbol] = &[sym::patchable_function_entry];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const TEMPLATE: AttributeTemplate = template!(List: &["prefix_nops = m, entry_nops = n"]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let Some(meta_item_list) = args.list() else {
cx.expected_list(cx.attr_span, args);
return None;
};
let mut prefix = None;
let mut entry = None;
if meta_item_list.len() == 0 {
cx.expected_list(meta_item_list.span, args);
return None;
}
let mut errored = false;
for item in meta_item_list.mixed() {
let Some(meta_item) = item.meta_item() else {
errored = true;
cx.expected_name_value(item.span(), None);
continue;
};
let Some(name_value_lit) = meta_item.args().name_value() else {
errored = true;
cx.expected_name_value(item.span(), None);
continue;
};
let attrib_to_write = match meta_item.ident().map(|ident| ident.name) {
Some(sym::prefix_nops) => {
// Duplicate prefixes are not allowed
if prefix.is_some() {
errored = true;
cx.duplicate_key(meta_item.path().span(), sym::prefix_nops);
continue;
}
&mut prefix
}
Some(sym::entry_nops) => {
// Duplicate entries are not allowed
if entry.is_some() {
errored = true;
cx.duplicate_key(meta_item.path().span(), sym::entry_nops);
continue;
}
&mut entry
}
_ => {
errored = true;
cx.expected_specific_argument(
meta_item.path().span(),
&[sym::prefix_nops, sym::entry_nops],
);
continue;
}
};
let rustc_ast::LitKind::Int(val, _) = name_value_lit.value_as_lit().kind else {
errored = true;
cx.expected_integer_literal(name_value_lit.value_span);
continue;
};
let Ok(val) = val.get().try_into() else {
errored = true;
cx.expected_integer_literal_in_range(
name_value_lit.value_span,
u8::MIN as isize,
u8::MAX as isize,
);
continue;
};
*attrib_to_write = Some(val);
}
if errored {
None
} else {
Some(AttributeKind::PatchableFunctionEntry {
prefix: prefix.unwrap_or(0),
entry: entry.unwrap_or(0),
})
}
}
}

View file

@ -1,4 +1,8 @@
use rustc_hir::attrs::WindowsSubsystemKind;
use rustc_hir::attrs::{CrateType, WindowsSubsystemKind};
use rustc_hir::lints::AttributeLintKind;
use rustc_session::lint::builtin::UNKNOWN_CRATE_TYPES;
use rustc_span::Symbol;
use rustc_span::edit_distance::find_best_match_for_name;
use super::prelude::*;
@ -9,7 +13,7 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let ArgParser::NameValue(n) = args else {
@ -26,6 +30,56 @@ impl<S: Stage> SingleAttributeParser<S> for CrateNameParser {
}
}
pub(crate) struct CrateTypeParser;
impl<S: Stage> CombineAttributeParser<S> for CrateTypeParser {
const PATH: &[Symbol] = &[sym::crate_type];
type Item = CrateType;
const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::CrateType(items);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const TEMPLATE: AttributeTemplate =
template!(NameValueStr: "crate type", "https://doc.rust-lang.org/reference/linkage.html");
fn extend(
cx: &mut AcceptContext<'_, '_, S>,
args: &ArgParser,
) -> impl IntoIterator<Item = Self::Item> {
let ArgParser::NameValue(n) = args else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
let Some(crate_type) = n.value_as_str() else {
cx.expected_string_literal(n.value_span, Some(n.value_as_lit()));
return None;
};
let Ok(crate_type) = crate_type.try_into() else {
// We don't error on invalid `#![crate_type]` when not applied to a crate
if cx.shared.target == Target::Crate {
let candidate = find_best_match_for_name(
&CrateType::all_stable().iter().map(|(name, _)| *name).collect::<Vec<_>>(),
crate_type,
None,
);
cx.emit_lint(
UNKNOWN_CRATE_TYPES,
AttributeLintKind::CrateTypeUnknown {
span: n.value_span,
suggested: candidate,
},
n.value_span,
);
}
return None;
};
Some(crate_type)
}
}
pub(crate) struct RecursionLimitParser;
impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
@ -33,7 +87,7 @@ impl<S: Stage> SingleAttributeParser<S> for RecursionLimitParser {
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let ArgParser::NameValue(nv) = args else {
@ -56,7 +110,7 @@ impl<S: Stage> SingleAttributeParser<S> for MoveSizeLimitParser {
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let ArgParser::NameValue(nv) = args else {
@ -79,7 +133,7 @@ impl<S: Stage> SingleAttributeParser<S> for TypeLengthLimitParser {
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let ArgParser::NameValue(nv) = args else {
@ -102,7 +156,7 @@ impl<S: Stage> SingleAttributeParser<S> for PatternComplexityLimitParser {
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let ArgParser::NameValue(nv) = args else {
@ -123,7 +177,7 @@ pub(crate) struct NoCoreParser;
impl<S: Stage> NoArgsAttributeParser<S> for NoCoreParser {
const PATH: &[Symbol] = &[sym::no_core];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoCore;
}
@ -132,16 +186,25 @@ pub(crate) struct NoStdParser;
impl<S: Stage> NoArgsAttributeParser<S> for NoStdParser {
const PATH: &[Symbol] = &[sym::no_std];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoStd;
}
pub(crate) struct NoMainParser;
impl<S: Stage> NoArgsAttributeParser<S> for NoMainParser {
const PATH: &[Symbol] = &[sym::no_main];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoMain;
}
pub(crate) struct RustcCoherenceIsCoreParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcCoherenceIsCoreParser {
const PATH: &[Symbol] = &[sym::rustc_coherence_is_core];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcCoherenceIsCore;
}
@ -151,7 +214,7 @@ impl<S: Stage> SingleAttributeParser<S> for WindowsSubsystemParser {
const PATH: &[Symbol] = &[sym::windows_subsystem];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::CrateLevel;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
@ -175,3 +238,39 @@ impl<S: Stage> SingleAttributeParser<S> for WindowsSubsystemParser {
Some(AttributeKind::WindowsSubsystem(kind, cx.attr_span))
}
}
pub(crate) struct PanicRuntimeParser;
impl<S: Stage> NoArgsAttributeParser<S> for PanicRuntimeParser {
const PATH: &[Symbol] = &[sym::panic_runtime];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PanicRuntime;
}
pub(crate) struct NeedsPanicRuntimeParser;
impl<S: Stage> NoArgsAttributeParser<S> for NeedsPanicRuntimeParser {
const PATH: &[Symbol] = &[sym::needs_panic_runtime];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsPanicRuntime;
}
pub(crate) struct ProfilerRuntimeParser;
impl<S: Stage> NoArgsAttributeParser<S> for ProfilerRuntimeParser {
const PATH: &[Symbol] = &[sym::profiler_runtime];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ProfilerRuntime;
}
pub(crate) struct NoBuiltinsParser;
impl<S: Stage> NoArgsAttributeParser<S> for NoBuiltinsParser {
const PATH: &[Symbol] = &[sym::no_builtins];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NoBuiltins;
}

View file

@ -13,14 +13,14 @@ fn get<S: Stage>(
name: Symbol,
param_span: Span,
arg: &ArgParser,
item: &Option<Symbol>,
) -> Option<Symbol> {
item: Option<Symbol>,
) -> Option<Ident> {
if item.is_some() {
cx.duplicate_key(param_span, name);
return None;
}
if let Some(v) = arg.name_value() {
if let Some(value_str) = v.value_as_str() {
if let Some(value_str) = v.value_as_ident() {
Some(value_str)
} else {
cx.expected_string_literal(v.value_span, Some(&v.value_as_lit()));
@ -72,7 +72,7 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
let features = cx.features();
let mut since = None;
let mut note = None;
let mut note: Option<Ident> = None;
let mut suggestion = None;
let is_rustc = features.staged_api();
@ -92,10 +92,16 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
match ident_name {
Some(name @ sym::since) => {
since = Some(get(cx, name, param.span(), param.args(), &since)?);
since = Some(get(cx, name, param.span(), param.args(), since)?.name);
}
Some(name @ sym::note) => {
note = Some(get(cx, name, param.span(), param.args(), &note)?);
note = Some(get(
cx,
name,
param.span(),
param.args(),
note.map(|ident| ident.name),
)?);
}
Some(name @ sym::suggestion) => {
if !features.deprecated_suggestion() {
@ -107,7 +113,7 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
}
suggestion =
Some(get(cx, name, param.span(), param.args(), &suggestion)?);
Some(get(cx, name, param.span(), param.args(), suggestion)?.name);
}
_ => {
cx.expected_specific_argument(
@ -124,7 +130,7 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
}
}
ArgParser::NameValue(v) => {
let Some(value) = v.value_as_str() else {
let Some(value) = v.value_as_ident() else {
cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
return None;
};

View file

@ -0,0 +1,31 @@
use rustc_feature::{AttributeTemplate, template};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::AttributeLintKind;
use rustc_session::lint::builtin::MALFORMED_DIAGNOSTIC_ATTRIBUTES;
use rustc_span::{Symbol, sym};
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
use crate::context::{AcceptContext, Stage};
use crate::parser::ArgParser;
use crate::target_checking::{ALL_TARGETS, AllowedTargets};
pub(crate) struct DoNotRecommendParser;
impl<S: Stage> SingleAttributeParser<S> for DoNotRecommendParser {
const PATH: &[Symbol] = &[sym::diagnostic, sym::do_not_recommend];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Checked in check_attr.
const TEMPLATE: AttributeTemplate = template!(Word /*doesn't matter */);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let attr_span = cx.attr_span;
if !matches!(args, ArgParser::NoArgs) {
cx.emit_lint(
MALFORMED_DIAGNOSTIC_ATTRIBUTES,
AttributeLintKind::DoNotRecommendDoesNotExpectArgs,
attr_span,
);
}
Some(AttributeKind::DoNotRecommend { attr_span })
}
}

View file

@ -1,5 +1,6 @@
use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit};
use rustc_feature::template;
use rustc_hir::Target;
use rustc_hir::attrs::{
AttributeKind, CfgEntry, CfgHideShow, CfgInfo, DocAttribute, DocInline, HideOrShow,
};
@ -12,8 +13,8 @@ use super::{AcceptMapping, AttributeParser};
use crate::context::{AcceptContext, FinalizeContext, Stage};
use crate::parser::{ArgParser, MetaItemOrLitParser, MetaItemParser, OwnedPathParser};
use crate::session_diagnostics::{
DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttributeNotAttribute,
DocKeywordNotKeyword,
DocAliasBadChar, DocAliasEmpty, DocAliasMalformed, DocAliasStartEnd, DocAttrNotCrateLevel,
DocAttributeNotAttribute, DocKeywordNotKeyword,
};
fn check_keyword<S: Stage>(cx: &mut AcceptContext<'_, '_, S>, keyword: Symbol, span: Span) -> bool {
@ -43,16 +44,39 @@ fn check_attribute<S: Stage>(
false
}
fn parse_keyword_and_attribute<S, F>(
/// Checks that an attribute is *not* used at the crate level. Returns `true` if valid.
fn check_attr_not_crate_level<S: Stage>(
cx: &mut AcceptContext<'_, '_, S>,
span: Span,
attr_name: Symbol,
) -> bool {
if cx.shared.target == Target::Crate {
cx.emit_err(DocAttrNotCrateLevel { span, attr_name });
return false;
}
true
}
/// Checks that an attribute is used at the crate level. Returns `true` if valid.
fn check_attr_crate_level<S: Stage>(cx: &mut AcceptContext<'_, '_, S>, span: Span) -> bool {
if cx.shared.target != Target::Crate {
cx.emit_lint(
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
AttributeLintKind::AttrCrateLevelOnly,
span,
);
return false;
}
true
}
fn parse_keyword_and_attribute<S: Stage>(
cx: &mut AcceptContext<'_, '_, S>,
path: &OwnedPathParser,
args: &ArgParser,
attr_value: &mut Option<(Symbol, Span)>,
callback: F,
) where
S: Stage,
F: FnOnce(&mut AcceptContext<'_, '_, S>, Symbol, Span) -> bool,
{
attr_name: Symbol,
) {
let Some(nv) = args.name_value() else {
cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym());
return;
@ -63,16 +87,26 @@ fn parse_keyword_and_attribute<S, F>(
return;
};
if !callback(cx, value, nv.value_span) {
let ret = if attr_name == sym::keyword {
check_keyword(cx, value, nv.value_span)
} else {
check_attribute(cx, value, nv.value_span)
};
if !ret {
return;
}
let span = path.span();
if attr_value.is_some() {
cx.duplicate_key(path.span(), path.word_sym().unwrap());
cx.duplicate_key(span, path.word_sym().unwrap());
return;
}
*attr_value = Some((value, path.span()));
if !check_attr_not_crate_level(cx, span, attr_name) {
return;
}
*attr_value = Some((value, span));
}
#[derive(Default, Debug)]
@ -102,6 +136,10 @@ impl DocParser {
return;
}
if !check_attr_crate_level(cx, path.span()) {
return;
}
self.attribute.no_crate_inject = Some(path.span())
}
Some(sym::attr) => {
@ -155,6 +193,9 @@ impl DocParser {
cx.emit_err(DocAliasStartEnd { span, attr_str });
return;
}
if !check_attr_not_crate_level(cx, span, sym::alias) {
return;
}
if let Some(first_definition) = self.attribute.aliases.get(&alias).copied() {
cx.emit_lint(
@ -366,7 +407,33 @@ impl DocParser {
self.attribute.$ident = Some(path.span());
}};
}
macro_rules! string_arg {
macro_rules! no_args_and_not_crate_level {
($ident: ident) => {{
if let Err(span) = args.no_args() {
cx.expected_no_args(span);
return;
}
let span = path.span();
if !check_attr_not_crate_level(cx, span, sym::$ident) {
return;
}
self.attribute.$ident = Some(span);
}};
}
macro_rules! no_args_and_crate_level {
($ident: ident) => {{
if let Err(span) = args.no_args() {
cx.expected_no_args(span);
return;
}
let span = path.span();
if !check_attr_crate_level(cx, span) {
return;
}
self.attribute.$ident = Some(span);
}};
}
macro_rules! string_arg_and_crate_level {
($ident: ident) => {{
let Some(nv) = args.name_value() else {
cx.expected_name_value(args.span().unwrap_or(path.span()), path.word_sym());
@ -378,6 +445,10 @@ impl DocParser {
return;
};
if !check_attr_crate_level(cx, path.span()) {
return;
}
// FIXME: It's errorring when the attribute is passed multiple times on the command
// line.
// The right fix for this would be to only check this rule if the attribute is
@ -394,12 +465,14 @@ impl DocParser {
match path.word_sym() {
Some(sym::alias) => self.parse_alias(cx, path, args),
Some(sym::hidden) => no_args!(hidden),
Some(sym::html_favicon_url) => string_arg!(html_favicon_url),
Some(sym::html_logo_url) => string_arg!(html_logo_url),
Some(sym::html_no_source) => no_args!(html_no_source),
Some(sym::html_playground_url) => string_arg!(html_playground_url),
Some(sym::html_root_url) => string_arg!(html_root_url),
Some(sym::issue_tracker_base_url) => string_arg!(issue_tracker_base_url),
Some(sym::html_favicon_url) => string_arg_and_crate_level!(html_favicon_url),
Some(sym::html_logo_url) => string_arg_and_crate_level!(html_logo_url),
Some(sym::html_no_source) => no_args_and_crate_level!(html_no_source),
Some(sym::html_playground_url) => string_arg_and_crate_level!(html_playground_url),
Some(sym::html_root_url) => string_arg_and_crate_level!(html_root_url),
Some(sym::issue_tracker_base_url) => {
string_arg_and_crate_level!(issue_tracker_base_url)
}
Some(sym::inline) => self.parse_inline(cx, path, args, DocInline::Inline),
Some(sym::no_inline) => self.parse_inline(cx, path, args, DocInline::NoInline),
Some(sym::masked) => no_args!(masked),
@ -410,18 +483,18 @@ impl DocParser {
path,
args,
&mut self.attribute.keyword,
check_keyword,
sym::keyword,
),
Some(sym::attribute) => parse_keyword_and_attribute(
cx,
path,
args,
&mut self.attribute.attribute,
check_attribute,
sym::attribute,
),
Some(sym::fake_variadic) => no_args!(fake_variadic),
Some(sym::search_unbox) => no_args!(search_unbox),
Some(sym::rust_logo) => no_args!(rust_logo),
Some(sym::fake_variadic) => no_args_and_not_crate_level!(fake_variadic),
Some(sym::search_unbox) => no_args_and_not_crate_level!(search_unbox),
Some(sym::rust_logo) => no_args_and_crate_level!(rust_logo),
Some(sym::auto_cfg) => self.parse_auto_cfg(cx, path, args),
Some(sym::test) => {
let Some(list) = args.list() else {
@ -441,9 +514,6 @@ impl DocParser {
MetaItemOrLitParser::Lit(lit) => {
cx.unexpected_literal(lit.span);
}
MetaItemOrLitParser::Err(..) => {
// already had an error here, move on.
}
}
}
}
@ -527,9 +597,6 @@ impl DocParser {
MetaItemOrLitParser::Lit(lit) => {
cx.expected_name_value(lit.span, None);
}
MetaItemOrLitParser::Err(..) => {
// already had an error here, move on.
}
}
}
}

View file

@ -141,8 +141,6 @@ impl<S: Stage> CombineAttributeParser<S> for LinkParser {
macro report_unstable_modifier($feature: ident) {
if !features.$feature() {
// FIXME: make this translatable
#[expect(rustc::untranslatable_diagnostic)]
feature_err(
sess,
sym::$feature,
@ -658,3 +656,21 @@ impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
Some(AttributeKind::Linkage(linkage, cx.attr_span))
}
}
pub(crate) struct NeedsAllocatorParser;
impl<S: Stage> NoArgsAttributeParser<S> for NeedsAllocatorParser {
const PATH: &[Symbol] = &[sym::needs_allocator];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
}
pub(crate) struct CompilerBuiltinsParser;
impl<S: Stage> NoArgsAttributeParser<S> for CompilerBuiltinsParser {
const PATH: &[Symbol] = &[sym::compiler_builtins];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins;
}

View file

@ -1,4 +1,4 @@
use rustc_hir::attrs::MacroUseArgs;
use rustc_hir::attrs::{CollapseMacroDebuginfo, MacroUseArgs};
use rustc_session::lint::builtin::INVALID_MACRO_EXPORT_ARGUMENTS;
use super::prelude::*;
@ -163,3 +163,46 @@ impl<S: Stage> SingleAttributeParser<S> for MacroExportParser {
Some(AttributeKind::MacroExport { span: cx.attr_span, local_inner_macros })
}
}
pub(crate) struct CollapseDebugInfoParser;
impl<S: Stage> SingleAttributeParser<S> for CollapseDebugInfoParser {
const PATH: &[Symbol] = &[sym::collapse_debuginfo];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const TEMPLATE: AttributeTemplate = template!(
List: &["no", "external", "yes"],
"https://doc.rust-lang.org/reference/attributes/debugger.html#the-collapse_debuginfo-attribute"
);
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let Some(list) = args.list() else {
cx.expected_list(cx.attr_span, args);
return None;
};
let Some(single) = list.single() else {
cx.expected_single_argument(list.span);
return None;
};
let Some(mi) = single.meta_item() else {
cx.unexpected_literal(single.span());
return None;
};
if let Err(err) = mi.args().no_args() {
cx.expected_no_args(err);
}
let path = mi.path().word_sym();
let info = match path {
Some(sym::yes) => CollapseMacroDebuginfo::Yes,
Some(sym::no) => CollapseMacroDebuginfo::No,
Some(sym::external) => CollapseMacroDebuginfo::External,
_ => {
cx.expected_specific_argument(mi.span(), &[sym::yes, sym::no, sym::external]);
return None;
}
};
Some(AttributeKind::CollapseDebugInfo(info))
}
}

View file

@ -39,6 +39,7 @@ pub(crate) mod confusables;
pub(crate) mod crate_level;
pub(crate) mod debugger;
pub(crate) mod deprecation;
pub(crate) mod do_not_recommend;
pub(crate) mod doc;
pub(crate) mod dummy;
pub(crate) mod inline;
@ -47,6 +48,7 @@ pub(crate) mod link_attrs;
pub(crate) mod lint_helpers;
pub(crate) mod loop_match;
pub(crate) mod macro_attrs;
pub(crate) mod must_not_suspend;
pub(crate) mod must_use;
pub(crate) mod no_implicit_prelude;
pub(crate) mod no_link;
@ -56,6 +58,8 @@ pub(crate) mod pin_v2;
pub(crate) mod proc_macro_attrs;
pub(crate) mod prototype;
pub(crate) mod repr;
pub(crate) mod rustc_allocator;
pub(crate) mod rustc_dump;
pub(crate) mod rustc_internal;
pub(crate) mod semantics;
pub(crate) mod stability;

View file

@ -0,0 +1,35 @@
use super::prelude::*;
pub(crate) struct MustNotSuspendParser;
impl<S: Stage> SingleAttributeParser<S> for MustNotSuspendParser {
const PATH: &[rustc_span::Symbol] = &[sym::must_not_suspend];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Struct),
Allow(Target::Enum),
Allow(Target::Union),
Allow(Target::Trait),
]);
const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let reason = match args {
ArgParser::NameValue(reason) => match reason.value_as_str() {
Some(val) => Some(val),
None => {
cx.expected_nv_or_no_args(reason.value_span);
return None;
}
},
ArgParser::NoArgs => None,
ArgParser::List(list) => {
cx.expected_nv_or_no_args(list.span);
return None;
}
};
Some(AttributeKind::MustNotSupend { reason })
}
}

View file

@ -0,0 +1,60 @@
use super::prelude::*;
pub(crate) struct RustcAllocatorParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcAllocatorParser {
const PATH: &[Symbol] = &[sym::rustc_allocator];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocator;
}
pub(crate) struct RustcAllocatorZeroedParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcAllocatorZeroedParser {
const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcAllocatorZeroed;
}
pub(crate) struct RustcAllocatorZeroedVariantParser;
impl<S: Stage> SingleAttributeParser<S> for RustcAllocatorZeroedVariantParser {
const PATH: &[Symbol] = &[sym::rustc_allocator_zeroed_variant];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "function");
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let Some(name) = args.name_value().and_then(NameValueParser::value_as_str) else {
cx.expected_name_value(cx.attr_span, None);
return None;
};
Some(AttributeKind::RustcAllocatorZeroedVariant { name })
}
}
pub(crate) struct RustcDeallocatorParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDeallocatorParser {
const PATH: &[Symbol] = &[sym::rustc_deallocator];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDeallocator;
}
pub(crate) struct RustcReallocatorParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcReallocatorParser {
const PATH: &[Symbol] = &[sym::rustc_reallocator];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets =
AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcReallocator;
}

View file

@ -0,0 +1,62 @@
use rustc_hir::Target;
use rustc_hir::attrs::AttributeKind;
use rustc_span::{Span, Symbol, sym};
use crate::attributes::prelude::Allow;
use crate::attributes::{NoArgsAttributeParser, OnDuplicate};
use crate::context::Stage;
use crate::target_checking::AllowedTargets;
pub(crate) struct RustcDumpUserArgs;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpUserArgs {
const PATH: &[Symbol] = &[sym::rustc_dump_user_args];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpUserArgs;
}
pub(crate) struct RustcDumpDefParents;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpDefParents {
const PATH: &[Symbol] = &[sym::rustc_dump_def_parents];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpDefParents;
}
pub(crate) struct RustcDumpItemBounds;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpItemBounds {
const PATH: &[Symbol] = &[sym::rustc_dump_item_bounds];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::AssocTy)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpItemBounds;
}
pub(crate) struct RustcDumpPredicates;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpPredicates {
const PATH: &[Symbol] = &[sym::rustc_dump_predicates];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Struct),
Allow(Target::Enum),
Allow(Target::Union),
Allow(Target::Trait),
Allow(Target::AssocTy),
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDumpPredicates;
}
pub(crate) struct RustcDumpVtable;
impl<S: Stage> NoArgsAttributeParser<S> for RustcDumpVtable {
const PATH: &[Symbol] = &[sym::rustc_dump_vtable];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Impl { of_trait: true }),
Allow(Target::TyAlias),
]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcDumpVtable;
}

View file

@ -164,21 +164,6 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLegacyConstGenericsParser {
}
}
pub(crate) struct RustcLintDiagnosticsParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcLintDiagnosticsParser {
const PATH: &[Symbol] = &[sym::rustc_lint_diagnostics];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::Trait { body: false })),
Allow(Target::Method(MethodKind::Trait { body: true })),
Allow(Target::Method(MethodKind::TraitImpl)),
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintDiagnostics;
}
pub(crate) struct RustcLintOptDenyFieldAccessParser;
impl<S: Stage> SingleAttributeParser<S> for RustcLintOptDenyFieldAccessParser {
@ -305,3 +290,42 @@ impl<S: Stage> SingleAttributeParser<S> for RustcScalableVectorParser {
Some(AttributeKind::RustcScalableVector { element_count: Some(n), span: cx.attr_span })
}
}
pub(crate) struct RustcHasIncoherentInherentImplsParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcHasIncoherentInherentImplsParser {
const PATH: &[Symbol] = &[sym::rustc_has_incoherent_inherent_impls];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Trait),
Allow(Target::Struct),
Allow(Target::Enum),
Allow(Target::Union),
Allow(Target::ForeignTy),
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls;
}
pub(crate) struct RustcNounwindParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcNounwindParser {
const PATH: &[Symbol] = &[sym::rustc_nounwind];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Fn),
Allow(Target::ForeignFn),
Allow(Target::Method(MethodKind::Inherent)),
Allow(Target::Method(MethodKind::TraitImpl)),
Allow(Target::Method(MethodKind::Trait { body: true })),
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNounwind;
}
pub(crate) struct RustcOffloadKernelParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcOffloadKernelParser {
const PATH: &[Symbol] = &[sym::rustc_offload_kernel];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel;
}

View file

@ -1,6 +1,7 @@
use std::num::NonZero;
use rustc_errors::ErrorGuaranteed;
use rustc_hir::target::GenericParamKind;
use rustc_hir::{
DefaultBodyStability, MethodKind, PartialConstStability, Stability, StabilityLevel,
StableSince, Target, UnstableReason, VERSION_PLACEHOLDER,
@ -43,7 +44,7 @@ const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::TyAlias),
Allow(Target::Variant),
Allow(Target::Field),
Allow(Target::Param),
Allow(Target::GenericParam { kind: GenericParamKind::Type, has_default: true }),
Allow(Target::Static),
Allow(Target::ForeignFn),
Allow(Target::ForeignStatic),

View file

@ -91,3 +91,25 @@ impl<S: Stage> SingleAttributeParser<S> for ShouldPanicParser {
})
}
}
pub(crate) struct RustcVarianceParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcVarianceParser {
const PATH: &[Symbol] = &[sym::rustc_variance];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
Allow(Target::Struct),
Allow(Target::Enum),
Allow(Target::Union),
]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcVariance;
}
pub(crate) struct RustcVarianceOfOpaquesParser;
impl<S: Stage> NoArgsAttributeParser<S> for RustcVarianceOfOpaquesParser {
const PATH: &[Symbol] = &[sym::rustc_variance_of_opaques];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcVarianceOfOpaques;
}

View file

@ -94,12 +94,12 @@ impl<S: Stage> NoArgsAttributeParser<S> for DenyExplicitImplParser {
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DenyExplicitImpl;
}
pub(crate) struct DoNotImplementViaObjectParser;
impl<S: Stage> NoArgsAttributeParser<S> for DoNotImplementViaObjectParser {
const PATH: &[Symbol] = &[sym::rustc_do_not_implement_via_object];
pub(crate) struct DynIncompatibleTraitParser;
impl<S: Stage> NoArgsAttributeParser<S> for DynIncompatibleTraitParser {
const PATH: &[Symbol] = &[sym::rustc_dyn_incompatible_trait];
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DoNotImplementViaObject;
const CREATE: fn(Span) -> AttributeKind = AttributeKind::DynIncompatibleTrait;
}
// Specialization

View file

@ -4,9 +4,6 @@ use super::prelude::*;
pub(crate) struct TransparencyParser;
// FIXME(jdonszelmann): make these proper diagnostics
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
const PATH: &[Symbol] = &[sym::rustc_macro_transparency];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
@ -15,7 +12,7 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
});
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::MacroDef)]);
const TEMPLATE: AttributeTemplate =
template!(NameValueStr: ["transparent", "semitransparent", "opaque"]);
template!(NameValueStr: ["transparent", "semiopaque", "opaque"]);
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
let Some(nv) = args.name_value() else {
@ -24,12 +21,12 @@ impl<S: Stage> SingleAttributeParser<S> for TransparencyParser {
};
match nv.value_as_str() {
Some(sym::transparent) => Some(Transparency::Transparent),
Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
Some(sym::semiopaque) => Some(Transparency::SemiOpaque),
Some(sym::opaque) => Some(Transparency::Opaque),
Some(_) => {
cx.expected_specific_argument_strings(
nv.value_span,
&[sym::transparent, sym::semitransparent, sym::opaque],
&[sym::transparent, sym::semiopaque, sym::opaque],
);
None
}

View file

@ -28,8 +28,7 @@ pub fn parse_version(s: Symbol) -> Option<RustcVersion> {
}
pub fn is_builtin_attr(attr: &impl AttributeExt) -> bool {
attr.is_doc_comment().is_some()
|| attr.ident().is_some_and(|ident| is_builtin_attr_name(ident.name))
attr.is_doc_comment().is_some() || attr.name().is_some_and(|name| is_builtin_attr_name(name))
}
/// Parse a single integer.

View file

@ -4,12 +4,12 @@ use std::ops::{Deref, DerefMut};
use std::sync::LazyLock;
use private::Sealed;
use rustc_ast::{AttrStyle, CRATE_NODE_ID, MetaItemLit, NodeId};
use rustc_ast::{AttrStyle, MetaItemLit, NodeId};
use rustc_errors::{Diag, Diagnostic, Level};
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
use rustc_hir::{AttrPath, CRATE_HIR_ID, HirId};
use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{AttrPath, HirId};
use rustc_session::Session;
use rustc_session::lint::{Lint, LintId};
use rustc_span::{ErrorGuaranteed, Span, Symbol};
@ -21,26 +21,29 @@ use crate::attributes::allow_unstable::{
use crate::attributes::body::CoroutineParser;
use crate::attributes::cfi_encoding::CfiEncodingParser;
use crate::attributes::codegen_attrs::{
ColdParser, CoverageParser, EiiExternItemParser, ExportNameParser, ForceTargetFeatureParser,
ColdParser, CoverageParser, EiiForeignItemParser, ExportNameParser, ForceTargetFeatureParser,
NakedParser, NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser,
RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser, TargetFeatureParser,
ThreadLocalParser, TrackCallerParser, UsedParser,
PatchableFunctionEntryParser, RustcPassIndirectlyInNonRusticAbisParser, SanitizeParser,
TargetFeatureParser, ThreadLocalParser, TrackCallerParser, UsedParser,
};
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::crate_level::{
CrateNameParser, MoveSizeLimitParser, NoCoreParser, NoStdParser, PatternComplexityLimitParser,
RecursionLimitParser, RustcCoherenceIsCoreParser, TypeLengthLimitParser,
WindowsSubsystemParser,
CrateNameParser, CrateTypeParser, MoveSizeLimitParser, NeedsPanicRuntimeParser,
NoBuiltinsParser, NoCoreParser, NoMainParser, NoStdParser, PanicRuntimeParser,
PatternComplexityLimitParser, ProfilerRuntimeParser, RecursionLimitParser,
RustcCoherenceIsCoreParser, TypeLengthLimitParser, WindowsSubsystemParser,
};
use crate::attributes::debugger::DebuggerViualizerParser;
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::do_not_recommend::DoNotRecommendParser;
use crate::attributes::doc::DocParser;
use crate::attributes::dummy::DummyParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
use crate::attributes::instruction_set::InstructionSetParser;
use crate::attributes::link_attrs::{
ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser, LinkOrdinalParser,
LinkParser, LinkSectionParser, LinkageParser, StdInternalSymbolParser,
CompilerBuiltinsParser, ExportStableParser, FfiConstParser, FfiPureParser, LinkNameParser,
LinkOrdinalParser, LinkParser, LinkSectionParser, LinkageParser, NeedsAllocatorParser,
StdInternalSymbolParser,
};
use crate::attributes::lint_helpers::{
AsPtrParser, AutomaticallyDerivedParser, PassByValueParser, PubTransparentParser,
@ -48,8 +51,10 @@ use crate::attributes::lint_helpers::{
};
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
use crate::attributes::macro_attrs::{
AllowInternalUnsafeParser, MacroEscapeParser, MacroExportParser, MacroUseParser,
AllowInternalUnsafeParser, CollapseDebugInfoParser, MacroEscapeParser, MacroExportParser,
MacroUseParser,
};
use crate::attributes::must_not_suspend::MustNotSuspendParser;
use crate::attributes::must_use::MustUseParser;
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
use crate::attributes::no_link::NoLinkParser;
@ -61,24 +66,34 @@ use crate::attributes::proc_macro_attrs::{
};
use crate::attributes::prototype::CustomMirParser;
use crate::attributes::repr::{AlignParser, AlignStaticParser, ReprParser};
use crate::attributes::rustc_allocator::{
RustcAllocatorParser, RustcAllocatorZeroedParser, RustcAllocatorZeroedVariantParser,
RustcDeallocatorParser, RustcReallocatorParser,
};
use crate::attributes::rustc_dump::{
RustcDumpDefParents, RustcDumpItemBounds, RustcDumpPredicates, RustcDumpUserArgs,
RustcDumpVtable,
};
use crate::attributes::rustc_internal::{
RustcLayoutScalarValidRangeEndParser, RustcLayoutScalarValidRangeStartParser,
RustcLegacyConstGenericsParser, RustcLintDiagnosticsParser, RustcLintOptDenyFieldAccessParser,
RustcLintOptTyParser, RustcLintQueryInstabilityParser,
RustcHasIncoherentInherentImplsParser, RustcLayoutScalarValidRangeEndParser,
RustcLayoutScalarValidRangeStartParser, RustcLegacyConstGenericsParser,
RustcLintOptDenyFieldAccessParser, RustcLintOptTyParser, RustcLintQueryInstabilityParser,
RustcLintUntrackedQueryInformationParser, RustcMainParser, RustcMustImplementOneOfParser,
RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser,
RustcObjectLifetimeDefaultParser, RustcScalableVectorParser,
RustcNeverReturnsNullPointerParser, RustcNoImplicitAutorefsParser, RustcNounwindParser,
RustcObjectLifetimeDefaultParser, RustcOffloadKernelParser, RustcScalableVectorParser,
RustcSimdMonomorphizeLaneLimitParser,
};
use crate::attributes::semantics::MayDangleParser;
use crate::attributes::stability::{
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
};
use crate::attributes::test_attrs::{IgnoreParser, ShouldPanicParser};
use crate::attributes::test_attrs::{
IgnoreParser, RustcVarianceOfOpaquesParser, RustcVarianceParser, ShouldPanicParser,
};
use crate::attributes::traits::{
AllowIncoherentImplParser, CoinductiveParser, DenyExplicitImplParser,
DoNotImplementViaObjectParser, FundamentalParser, MarkerParser, ParenSugarParser,
PointeeParser, SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser,
DynIncompatibleTraitParser, FundamentalParser, MarkerParser, ParenSugarParser, PointeeParser,
SkipDuringMethodDispatchParser, SpecializationTraitParser, TypeConstParser,
UnsafeSpecializationMarkerParser,
};
use crate::attributes::transparency::TransparencyParser;
@ -88,23 +103,22 @@ use crate::session_diagnostics::{
AttributeParseError, AttributeParseErrorReason, ParsedDescription,
};
use crate::target_checking::AllowedTargets;
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
pub(super) struct GroupTypeInner<S: Stage> {
pub(super) accepters: BTreeMap<&'static [Symbol], Vec<GroupTypeInnerAccept<S>>>,
pub(super) finalizers: Vec<FinalizeFn<S>>,
}
pub(super) struct GroupTypeInnerAccept<S: Stage> {
pub(super) template: AttributeTemplate,
pub(super) accept_fn: AcceptFn<S>,
pub(super) allowed_targets: AllowedTargets,
pub(super) finalizer: FinalizeFn<S>,
}
type AcceptFn<S> =
pub(crate) type AcceptFn<S> =
Box<dyn for<'sess, 'a> Fn(&mut AcceptContext<'_, 'sess, S>, &ArgParser) + Send + Sync>;
type FinalizeFn<S> =
pub(crate) type FinalizeFn<S> =
Box<dyn Send + Sync + Fn(&mut FinalizeContext<'_, '_, S>) -> Option<AttributeKind>>;
macro_rules! attribute_parsers {
@ -132,8 +146,7 @@ macro_rules! attribute_parsers {
@[$stage: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?];
) => {
pub(crate) static $name: GroupType<$stage> = LazyLock::new(|| {
let mut accepts = BTreeMap::<_, Vec<GroupTypeInnerAccept<$stage>>>::new();
let mut finalizes = Vec::<FinalizeFn<$stage>>::new();
let mut accepters = BTreeMap::<_, Vec<GroupTypeInnerAccept<$stage>>>::new();
$(
{
thread_local! {
@ -141,7 +154,7 @@ macro_rules! attribute_parsers {
};
for (path, template, accept_fn) in <$names>::ATTRIBUTES {
accepts.entry(*path).or_default().push(GroupTypeInnerAccept {
accepters.entry(*path).or_default().push(GroupTypeInnerAccept {
template: *template,
accept_fn: Box::new(|cx, args| {
STATE_OBJECT.with_borrow_mut(|s| {
@ -149,17 +162,16 @@ macro_rules! attribute_parsers {
})
}),
allowed_targets: <$names as crate::attributes::AttributeParser<$stage>>::ALLOWED_TARGETS,
finalizer: Box::new(|cx| {
let state = STATE_OBJECT.take();
state.finalize(cx)
}),
});
}
finalizes.push(Box::new(|cx| {
let state = STATE_OBJECT.take();
state.finalize(cx)
}));
}
)*
GroupTypeInner { accepters:accepts, finalizers:finalizes }
GroupTypeInner { accepters }
});
};
}
@ -181,6 +193,7 @@ attribute_parsers!(
// tidy-alphabetical-start
Combine<AllowConstFnUnstableParser>,
Combine<AllowInternalUnstableParser>,
Combine<CrateTypeParser>,
Combine<DebuggerViualizerParser>,
Combine<ForceTargetFeatureParser>,
Combine<LinkParser>,
@ -191,10 +204,12 @@ attribute_parsers!(
// tidy-alphabetical-start
Single<CfiEncodingParser>,
Single<CollapseDebugInfoParser>,
Single<CoverageParser>,
Single<CrateNameParser>,
Single<CustomMirParser>,
Single<DeprecationParser>,
Single<DoNotRecommendParser>,
Single<DummyParser>,
Single<ExportNameParser>,
Single<IgnoreParser>,
@ -206,14 +221,17 @@ attribute_parsers!(
Single<LinkageParser>,
Single<MacroExportParser>,
Single<MoveSizeLimitParser>,
Single<MustNotSuspendParser>,
Single<MustUseParser>,
Single<ObjcClassParser>,
Single<ObjcSelectorParser>,
Single<OptimizeParser>,
Single<PatchableFunctionEntryParser>,
Single<PathAttributeParser>,
Single<PatternComplexityLimitParser>,
Single<ProcMacroDeriveParser>,
Single<RecursionLimitParser>,
Single<RustcAllocatorZeroedVariantParser>,
Single<RustcBuiltinMacroParser>,
Single<RustcForceInlineParser>,
Single<RustcLayoutScalarValidRangeEndParser>,
@ -236,12 +254,13 @@ attribute_parsers!(
Single<WithoutArgs<AutomaticallyDerivedParser>>,
Single<WithoutArgs<CoinductiveParser>>,
Single<WithoutArgs<ColdParser>>,
Single<WithoutArgs<CompilerBuiltinsParser>>,
Single<WithoutArgs<ConstContinueParser>>,
Single<WithoutArgs<ConstStabilityIndirectParser>>,
Single<WithoutArgs<CoroutineParser>>,
Single<WithoutArgs<DenyExplicitImplParser>>,
Single<WithoutArgs<DoNotImplementViaObjectParser>>,
Single<WithoutArgs<EiiExternItemParser>>,
Single<WithoutArgs<DynIncompatibleTraitParser>>,
Single<WithoutArgs<EiiForeignItemParser>>,
Single<WithoutArgs<ExportStableParser>>,
Single<WithoutArgs<FfiConstParser>>,
Single<WithoutArgs<FfiPureParser>>,
@ -250,29 +269,48 @@ attribute_parsers!(
Single<WithoutArgs<MacroEscapeParser>>,
Single<WithoutArgs<MarkerParser>>,
Single<WithoutArgs<MayDangleParser>>,
Single<WithoutArgs<NeedsAllocatorParser>>,
Single<WithoutArgs<NeedsPanicRuntimeParser>>,
Single<WithoutArgs<NoBuiltinsParser>>,
Single<WithoutArgs<NoCoreParser>>,
Single<WithoutArgs<NoImplicitPreludeParser>>,
Single<WithoutArgs<NoLinkParser>>,
Single<WithoutArgs<NoMainParser>>,
Single<WithoutArgs<NoMangleParser>>,
Single<WithoutArgs<NoStdParser>>,
Single<WithoutArgs<NonExhaustiveParser>>,
Single<WithoutArgs<PanicRuntimeParser>>,
Single<WithoutArgs<ParenSugarParser>>,
Single<WithoutArgs<PassByValueParser>>,
Single<WithoutArgs<PinV2Parser>>,
Single<WithoutArgs<PointeeParser>>,
Single<WithoutArgs<ProcMacroAttributeParser>>,
Single<WithoutArgs<ProcMacroParser>>,
Single<WithoutArgs<ProfilerRuntimeParser>>,
Single<WithoutArgs<PubTransparentParser>>,
Single<WithoutArgs<RustcAllocatorParser>>,
Single<WithoutArgs<RustcAllocatorZeroedParser>>,
Single<WithoutArgs<RustcCoherenceIsCoreParser>>,
Single<WithoutArgs<RustcLintDiagnosticsParser>>,
Single<WithoutArgs<RustcDeallocatorParser>>,
Single<WithoutArgs<RustcDumpDefParents>>,
Single<WithoutArgs<RustcDumpItemBounds>>,
Single<WithoutArgs<RustcDumpPredicates>>,
Single<WithoutArgs<RustcDumpUserArgs>>,
Single<WithoutArgs<RustcDumpVtable>>,
Single<WithoutArgs<RustcHasIncoherentInherentImplsParser>>,
Single<WithoutArgs<RustcLintOptTyParser>>,
Single<WithoutArgs<RustcLintQueryInstabilityParser>>,
Single<WithoutArgs<RustcLintUntrackedQueryInformationParser>>,
Single<WithoutArgs<RustcMainParser>>,
Single<WithoutArgs<RustcNeverReturnsNullPointerParser>>,
Single<WithoutArgs<RustcNoImplicitAutorefsParser>>,
Single<WithoutArgs<RustcNounwindParser>>,
Single<WithoutArgs<RustcOffloadKernelParser>>,
Single<WithoutArgs<RustcPassIndirectlyInNonRusticAbisParser>>,
Single<WithoutArgs<RustcReallocatorParser>>,
Single<WithoutArgs<RustcShouldNotBeCalledOnConstItems>>,
Single<WithoutArgs<RustcVarianceOfOpaquesParser>>,
Single<WithoutArgs<RustcVarianceParser>>,
Single<WithoutArgs<SpecializationTraitParser>>,
Single<WithoutArgs<StdInternalSymbolParser>>,
Single<WithoutArgs<ThreadLocalParser>>,
@ -303,8 +341,6 @@ pub trait Stage: Sized + 'static + Sealed {
) -> ErrorGuaranteed;
fn should_emit(&self) -> ShouldEmit;
fn id_is_crate_root(id: Self::Id) -> bool;
}
// allow because it's a sealed trait
@ -326,10 +362,6 @@ impl Stage for Early {
fn should_emit(&self) -> ShouldEmit {
self.emit_errors
}
fn id_is_crate_root(id: Self::Id) -> bool {
id == CRATE_NODE_ID
}
}
// allow because it's a sealed trait
@ -349,11 +381,7 @@ impl Stage for Late {
}
fn should_emit(&self) -> ShouldEmit {
ShouldEmit::ErrorsAndLints
}
fn id_is_crate_root(id: Self::Id) -> bool {
id == CRATE_HIR_ID
ShouldEmit::ErrorsAndLints { recover: true }
}
}
@ -410,12 +438,11 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) {
if !matches!(
self.stage.should_emit(),
ShouldEmit::ErrorsAndLints | ShouldEmit::EarlyFatal { also_emit_lints: true }
ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true }
) {
return;
}
let id = self.target_id;
(self.emit_lint)(AttributeLint { lint_id: LintId::of(lint), id, span, kind });
(self.emit_lint)(LintId::of(lint), span, kind);
}
pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
@ -487,6 +514,18 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
self.emit_parse_error(span, AttributeParseErrorReason::ExpectedIntegerLiteral)
}
pub(crate) fn expected_integer_literal_in_range(
&self,
span: Span,
lower_bound: isize,
upper_bound: isize,
) -> ErrorGuaranteed {
self.emit_parse_error(
span,
AttributeParseErrorReason::ExpectedIntegerLiteralInRange { lower_bound, upper_bound },
)
}
pub(crate) fn expected_list(&self, span: Span, args: &ArgParser) -> ErrorGuaranteed {
let span = match args {
ArgParser::NoArgs => span,
@ -660,10 +699,11 @@ pub struct SharedContext<'p, 'sess, S: Stage> {
pub(crate) cx: &'p mut AttributeParser<'sess, S>,
/// The span of the syntactical component this attribute was applied to
pub(crate) target_span: Span,
/// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to
pub(crate) target_id: S::Id,
pub(crate) target: rustc_hir::Target,
pub(crate) emit_lint: &'p mut dyn FnMut(AttributeLint<S::Id>),
/// The second argument of the closure is a [`NodeId`] if `S` is `Early` and a [`HirId`] if `S`
/// is `Late` and is the ID of the syntactical component this attribute was applied to.
pub(crate) emit_lint: &'p mut dyn FnMut(LintId, Span, AttributeLintKind),
}
/// Context given to every attribute parser during finalization.
@ -725,9 +765,18 @@ pub enum ShouldEmit {
EarlyFatal { also_emit_lints: bool },
/// The operation will emit errors and lints.
/// This is usually what you need.
ErrorsAndLints,
/// The operation will emit *not* errors and lints.
/// Use this if you are *sure* that this operation will be called at a different time with `ShouldEmit::ErrorsAndLints`.
ErrorsAndLints {
/// Whether [`ArgParser`] will attempt to recover from errors.
///
/// If true, it will attempt to recover from bad input (like an invalid literal). Setting
/// this to false will instead return early, and not raise errors except at the top level
/// (in [`ArgParser::from_attr_args`]).
recover: bool,
},
/// The operation will *not* emit errors and lints.
///
/// The parser can still call `delay_bug`, so you *must* ensure that this operation will also be
/// called with `ShouldEmit::ErrorsAndLints`.
Nothing,
}
@ -736,7 +785,7 @@ impl ShouldEmit {
match self {
ShouldEmit::EarlyFatal { .. } if diag.level() == Level::DelayedBug => diag.emit(),
ShouldEmit::EarlyFatal { .. } => diag.upgrade_to_fatal().emit(),
ShouldEmit::ErrorsAndLints => diag.emit(),
ShouldEmit::ErrorsAndLints { .. } => diag.emit(),
ShouldEmit::Nothing => diag.delay_as_bug(),
}
}

View file

@ -0,0 +1,53 @@
use rustc_ast::EarlyParsedAttribute;
use rustc_ast::attr::data_structures::CfgEntry;
use rustc_hir::Attribute;
use rustc_hir::attrs::AttributeKind;
use rustc_span::{Span, Symbol, sym};
use thin_vec::ThinVec;
pub(crate) const EARLY_PARSED_ATTRIBUTES: &[&[Symbol]] =
&[&[sym::cfg_trace], &[sym::cfg_attr_trace]];
/// This struct contains the state necessary to convert early parsed attributes to hir attributes
/// The only conversion that really happens here is that multiple early parsed attributes are
/// merged into a single hir attribute, representing their combined state.
/// FIXME: We should make this a nice and extendable system if this is going to be used more often
#[derive(Default)]
pub(crate) struct EarlyParsedState {
/// Attribute state for `#[cfg]` trace attributes
cfg_trace: ThinVec<(CfgEntry, Span)>,
/// Attribute state for `#[cfg_attr]` trace attributes
/// The arguments of these attributes is no longer relevant for any later passes, only their presence.
/// So we discard the arguments here.
cfg_attr_trace: bool,
}
impl EarlyParsedState {
pub(crate) fn accept_early_parsed_attribute(
&mut self,
attr_span: Span,
lower_span: impl Copy + Fn(Span) -> Span,
parsed: &EarlyParsedAttribute,
) {
match parsed {
EarlyParsedAttribute::CfgTrace(cfg) => {
let mut cfg = cfg.clone();
cfg.lower_spans(lower_span);
self.cfg_trace.push((cfg, attr_span));
}
EarlyParsedAttribute::CfgAttrTrace => {
self.cfg_attr_trace = true;
}
}
}
pub(crate) fn finalize_early_parsed_attributes(self, attributes: &mut Vec<Attribute>) {
if !self.cfg_trace.is_empty() {
attributes.push(Attribute::Parsed(AttributeKind::CfgTrace(self.cfg_trace)));
}
if self.cfg_attr_trace {
attributes.push(Attribute::Parsed(AttributeKind::CfgAttrTrace));
}
}
}

View file

@ -2,17 +2,18 @@ use std::convert::identity;
use rustc_ast as ast;
use rustc_ast::token::DocFragmentKind;
use rustc_ast::{AttrStyle, NodeId, Safety};
use rustc_ast::{AttrItemKind, AttrStyle, NodeId, Safety};
use rustc_errors::DiagCtxtHandle;
use rustc_feature::{AttributeTemplate, Features};
use rustc_hir::attrs::AttributeKind;
use rustc_hir::lints::AttributeLint;
use rustc_hir::lints::AttributeLintKind;
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target};
use rustc_session::Session;
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::{BuiltinLintDiag, LintId};
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
use crate::context::{AcceptContext, FinalizeContext, SharedContext, Stage};
use crate::context::{AcceptContext, FinalizeContext, FinalizeFn, SharedContext, Stage};
use crate::early_parsed::{EARLY_PARSED_ATTRIBUTES, EarlyParsedState};
use crate::parser::{ArgParser, PathParser, RefPathParser};
use crate::session_diagnostics::ParsedDescription;
use crate::{Early, Late, OmitDoc, ShouldEmit};
@ -112,16 +113,15 @@ impl<'sess> AttributeParser<'sess, Early> {
p.parse_attribute_list(
attrs,
target_span,
target_node_id,
target,
OmitDoc::Skip,
std::convert::identity,
|lint| {
|lint_id, span, kind| {
sess.psess.buffer_lint(
lint.lint_id.lint,
lint.span,
lint.id,
BuiltinLintDiag::AttributeLint(lint.kind),
lint_id.lint,
span,
target_node_id,
BuiltinLintDiag::AttributeLint(kind),
)
},
)
@ -134,6 +134,7 @@ impl<'sess> AttributeParser<'sess, Early> {
attr: &ast::Attribute,
target_span: Span,
target_node_id: NodeId,
target: Target,
features: Option<&'sess Features>,
emit_errors: ShouldEmit,
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option<T>,
@ -146,8 +147,12 @@ impl<'sess> AttributeParser<'sess, Early> {
normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
let path = AttrPath::from_ast(&normal_attr.item.path, identity);
let args =
ArgParser::from_attr_args(&normal_attr.item.args, &parts, &sess.psess, emit_errors)?;
let args = ArgParser::from_attr_args(
&normal_attr.item.args.unparsed_ref().unwrap(),
&parts,
&sess.psess,
emit_errors,
)?;
Self::parse_single_args(
sess,
attr.span,
@ -158,6 +163,7 @@ impl<'sess> AttributeParser<'sess, Early> {
ParsedDescription::Attribute,
target_span,
target_node_id,
target,
features,
emit_errors,
&args,
@ -178,6 +184,7 @@ impl<'sess> AttributeParser<'sess, Early> {
parsed_description: ParsedDescription,
target_span: Span,
target_node_id: NodeId,
target: Target,
features: Option<&'sess Features>,
emit_errors: ShouldEmit,
args: &I,
@ -191,28 +198,22 @@ impl<'sess> AttributeParser<'sess, Early> {
sess,
stage: Early { emit_errors },
};
let mut emit_lint = |lint: AttributeLint<NodeId>| {
let mut emit_lint = |lint_id: LintId, span: Span, kind: AttributeLintKind| {
sess.psess.buffer_lint(
lint.lint_id.lint,
lint.span,
lint.id,
BuiltinLintDiag::AttributeLint(lint.kind),
lint_id.lint,
span,
target_node_id,
BuiltinLintDiag::AttributeLint(kind),
)
};
if let Some(safety) = attr_safety {
parser.check_attribute_safety(
&attr_path,
inner_span,
safety,
&mut emit_lint,
target_node_id,
)
parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint)
}
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
shared: SharedContext {
cx: &mut parser,
target_span,
target_id: target_node_id,
target,
emit_lint: &mut emit_lint,
},
attr_span,
@ -260,15 +261,16 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
&mut self,
attrs: &[ast::Attribute],
target_span: Span,
target_id: S::Id,
target: Target,
omit_doc: OmitDoc,
lower_span: impl Copy + Fn(Span) -> Span,
mut emit_lint: impl FnMut(AttributeLint<S::Id>),
mut emit_lint: impl FnMut(LintId, Span, AttributeLintKind),
) -> Vec<Attribute> {
let mut attributes = Vec::new();
let mut attr_paths: Vec<RefPathParser<'_>> = Vec::new();
let mut early_parsed_state = EarlyParsedState::default();
let mut finalizers: Vec<&FinalizeFn<S>> = Vec::with_capacity(attrs.len());
for attr in attrs {
// If we're only looking for a single attribute, skip all the ones we don't care about.
@ -288,6 +290,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
continue;
}
let attr_span = lower_span(attr.span);
match &attr.kind {
ast::AttrKind::DocComment(comment_kind, symbol) => {
if omit_doc == OmitDoc::Skip {
@ -297,7 +300,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
attributes.push(Attribute::Parsed(AttributeKind::DocComment {
style: attr.style,
kind: DocFragmentKind::Sugared(*comment_kind),
span: lower_span(attr.span),
span: attr_span,
comment: *symbol,
}))
}
@ -305,12 +308,20 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
attr_paths.push(PathParser(&n.item.path));
let attr_path = AttrPath::from_ast(&n.item.path, lower_span);
let args = match &n.item.args {
AttrItemKind::Unparsed(args) => args,
AttrItemKind::Parsed(parsed) => {
early_parsed_state
.accept_early_parsed_attribute(attr_span, lower_span, parsed);
continue;
}
};
self.check_attribute_safety(
&attr_path,
lower_span(n.item.span()),
n.item.unsafety,
&mut emit_lint,
target_id,
);
let parts =
@ -318,7 +329,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) {
let Some(args) = ArgParser::from_attr_args(
&n.item.args,
args,
&parts,
&self.sess.psess,
self.stage.should_emit(),
@ -351,7 +362,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
attributes.push(Attribute::Parsed(AttributeKind::DocComment {
style: attr.style,
kind: DocFragmentKind::Raw(nv.value_span),
span: attr.span,
span: attr_span,
comment,
}));
continue;
@ -362,10 +373,10 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
shared: SharedContext {
cx: self,
target_span,
target_id,
target,
emit_lint: &mut emit_lint,
},
attr_span: lower_span(attr.span),
attr_span,
inner_span: lower_span(n.item.span()),
attr_style: attr.style,
parsed_description: ParsedDescription::Attribute,
@ -374,6 +385,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
};
(accept.accept_fn)(&mut cx, &args);
finalizers.push(&accept.finalizer);
if !matches!(cx.stage.should_emit(), ShouldEmit::Nothing) {
Self::check_target(&accept.allowed_targets, target, &mut cx);
}
@ -396,39 +409,43 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
attributes.push(Attribute::Unparsed(Box::new(AttrItem {
path: attr_path.clone(),
args: self.lower_attr_args(&n.item.args, lower_span),
args: self
.lower_attr_args(n.item.args.unparsed_ref().unwrap(), lower_span),
id: HashIgnoredAttrId { attr_id: attr.id },
style: attr.style,
span: lower_span(attr.span),
span: attr_span,
})));
}
}
}
}
let mut parsed_attributes = Vec::new();
for f in &S::parsers().finalizers {
early_parsed_state.finalize_early_parsed_attributes(&mut attributes);
for f in &finalizers {
if let Some(attr) = f(&mut FinalizeContext {
shared: SharedContext {
cx: self,
target_span,
target_id,
emit_lint: &mut emit_lint,
},
shared: SharedContext { cx: self, target_span, target, emit_lint: &mut emit_lint },
all_attrs: &attr_paths,
}) {
parsed_attributes.push(Attribute::Parsed(attr));
attributes.push(Attribute::Parsed(attr));
}
}
attributes.extend(parsed_attributes);
attributes
}
/// Returns whether there is a parser for an attribute with this name
pub fn is_parsed_attribute(path: &[Symbol]) -> bool {
/// The list of attributes that are parsed attributes,
/// even though they don't have a parser in `Late::parsers()`
const SPECIAL_ATTRIBUTES: &[&[Symbol]] = &[
// Cfg attrs are removed after being early-parsed, so don't need to be in the parser list
&[sym::cfg],
&[sym::cfg_attr],
];
Late::parsers().accepters.contains_key(path)
|| EARLY_PARSED_ATTRIBUTES.contains(&path)
|| SPECIAL_ATTRIBUTES.contains(&path)
}
fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Span) -> AttrArgs {

View file

@ -99,6 +99,7 @@ mod interface;
/// like lists or name-value pairs.
pub mod parser;
mod early_parsed;
mod safety;
mod session_diagnostics;
mod target_checking;

View file

@ -16,9 +16,9 @@ use rustc_errors::{Diag, PResult};
use rustc_hir::{self as hir, AttrPath};
use rustc_parse::exp;
use rustc_parse::parser::{ForceCollect, Parser, PathStyle, token_descr};
use rustc_session::errors::{create_lit_error, report_lit_error};
use rustc_session::errors::create_lit_error;
use rustc_session::parse::ParseSess;
use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol, sym};
use rustc_span::{Ident, Span, Symbol, sym};
use thin_vec::ThinVec;
use crate::ShouldEmit;
@ -36,7 +36,7 @@ pub type RefPathParser<'p> = PathParser<&'p Path>;
impl<P: Borrow<Path>> PathParser<P> {
pub fn get_attribute_path(&self) -> hir::AttrPath {
AttrPath {
segments: self.segments().copied().collect::<Vec<_>>().into_boxed_slice(),
segments: self.segments().map(|s| s.name).collect::<Vec<_>>().into_boxed_slice(),
span: self.span(),
}
}
@ -113,19 +113,36 @@ impl ArgParser {
Some(match value {
AttrArgs::Empty => Self::NoArgs,
AttrArgs::Delimited(args) => {
// The arguments of rustc_dummy are not validated if the arguments are delimited
if parts == &[sym::rustc_dummy] {
return Some(ArgParser::List(MetaItemListParser {
sub_parsers: ThinVec::new(),
span: args.dspan.entire(),
}));
// Diagnostic attributes can't error if they encounter non meta item syntax.
// However, the current syntax for diagnostic attributes is meta item syntax.
// Therefore we can substitute with a dummy value on invalid syntax.
if matches!(parts, [sym::rustc_dummy] | [sym::diagnostic, ..]) {
match MetaItemListParser::new(
&args.tokens,
args.dspan.entire(),
psess,
ShouldEmit::ErrorsAndLints { recover: false },
) {
Ok(p) => return Some(ArgParser::List(p)),
Err(e) => {
// We can just dispose of the diagnostic and not bother with a lint,
// because this will look like `#[diagnostic::attr()]` was used. This
// is invalid for all diagnostic attrs, so a lint explaining the proper
// form will be issued later.
e.cancel();
return Some(ArgParser::List(MetaItemListParser {
sub_parsers: ThinVec::new(),
span: args.dspan.entire(),
}));
}
}
}
if args.delim != Delimiter::Parenthesis {
psess.dcx().emit_err(MetaBadDelim {
should_emit.emit_err(psess.dcx().create_err(MetaBadDelim {
span: args.dspan.entire(),
sugg: MetaBadDelimSugg { open: args.dspan.open, close: args.dspan.close },
});
}));
return None;
}
@ -137,7 +154,9 @@ impl ArgParser {
}
AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
eq_span: *eq_span,
value: expr_to_lit(psess, &expr, expr.span, should_emit)?,
value: expr_to_lit(psess, &expr, expr.span, should_emit)
.map_err(|e| should_emit.emit_err(e))
.ok()??,
value_span: expr.span,
}),
})
@ -192,7 +211,6 @@ impl ArgParser {
pub enum MetaItemOrLitParser {
MetaItemParser(MetaItemParser),
Lit(MetaItemLit),
Err(Span, ErrorGuaranteed),
}
impl MetaItemOrLitParser {
@ -210,21 +228,20 @@ impl MetaItemOrLitParser {
generic_meta_item_parser.span()
}
MetaItemOrLitParser::Lit(meta_item_lit) => meta_item_lit.span,
MetaItemOrLitParser::Err(span, _) => *span,
}
}
pub fn lit(&self) -> Option<&MetaItemLit> {
match self {
MetaItemOrLitParser::Lit(meta_item_lit) => Some(meta_item_lit),
_ => None,
MetaItemOrLitParser::MetaItemParser(_) => None,
}
}
pub fn meta_item(&self) -> Option<&MetaItemParser> {
match self {
MetaItemOrLitParser::MetaItemParser(parser) => Some(parser),
_ => None,
MetaItemOrLitParser::Lit(_) => None,
}
}
}
@ -322,63 +339,65 @@ impl NameValueParser {
self.value_as_lit().kind.str()
}
/// If the value is a string literal, it will return its value associated with its span (an
/// `Ident` in short).
pub fn value_as_ident(&self) -> Option<Ident> {
let meta_item = self.value_as_lit();
meta_item.kind.str().map(|name| Ident { name, span: meta_item.span })
}
pub fn args_span(&self) -> Span {
self.eq_span.to(self.value_span)
}
}
fn expr_to_lit(
psess: &ParseSess,
fn expr_to_lit<'sess>(
psess: &'sess ParseSess,
expr: &Expr,
span: Span,
should_emit: ShouldEmit,
) -> Option<MetaItemLit> {
) -> PResult<'sess, Option<MetaItemLit>> {
if let ExprKind::Lit(token_lit) = expr.kind {
let res = MetaItemLit::from_token_lit(token_lit, expr.span);
match res {
Ok(lit) => {
if token_lit.suffix.is_some() {
should_emit.emit_err(
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
);
None
Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
} else {
if !lit.kind.is_unsuffixed() {
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
should_emit.emit_err(
psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
);
if lit.kind.is_unsuffixed() {
Ok(Some(lit))
} else {
Err(psess.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }))
}
Some(lit)
}
}
Err(err) => {
let guar = report_lit_error(psess, err, token_lit, expr.span);
let lit = MetaItemLit {
symbol: token_lit.symbol,
suffix: token_lit.suffix,
kind: LitKind::Err(guar),
span: expr.span,
};
Some(lit)
let err = create_lit_error(psess, err, token_lit, expr.span);
if matches!(should_emit, ShouldEmit::ErrorsAndLints { recover: false }) {
Err(err)
} else {
let lit = MetaItemLit {
symbol: token_lit.symbol,
suffix: token_lit.suffix,
kind: LitKind::Err(err.emit()),
span: expr.span,
};
Ok(Some(lit))
}
}
}
} else {
if matches!(should_emit, ShouldEmit::Nothing) {
return None;
return Ok(None);
}
// Example cases:
// - `#[foo = 1+1]`: results in `ast::ExprKind::BinOp`.
// - `#[foo = include_str!("nonexistent-file.rs")]`:
// results in `ast::ExprKind::Err`. In that case we delay
// the error because an earlier error will have already
// been reported.
// results in `ast::ExprKind::Err`.
let msg = "attribute value must be a literal";
let err = psess.dcx().struct_span_err(span, msg);
should_emit.emit_err(err);
None
Err(err)
}
}
@ -411,9 +430,12 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
if !lit.kind.is_unsuffixed() {
// Emit error and continue, we can still parse the attribute as if the suffix isn't there
self.should_emit.emit_err(
self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span }),
);
let err = self.parser.dcx().create_err(SuffixedLiteralInAttribute { span: lit.span });
if matches!(self.should_emit, ShouldEmit::ErrorsAndLints { recover: false }) {
return Err(err);
} else {
self.should_emit.emit_err(err)
};
}
Ok(lit)

View file

@ -1,10 +1,10 @@
use rustc_ast::Safety;
use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir::AttrPath;
use rustc_hir::lints::{AttributeLint, AttributeLintKind};
use rustc_hir::lints::AttributeLintKind;
use rustc_session::lint::LintId;
use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE;
use rustc_span::{Span, sym};
use rustc_span::Span;
use crate::context::Stage;
use crate::{AttributeParser, ShouldEmit};
@ -15,19 +15,13 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
attr_path: &AttrPath,
attr_span: Span,
attr_safety: Safety,
emit_lint: &mut impl FnMut(AttributeLint<S::Id>),
target_id: S::Id,
emit_lint: &mut impl FnMut(LintId, Span, AttributeLintKind),
) {
if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
return;
}
let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0].name);
if let Some(name) = name
&& [sym::cfg_trace, sym::cfg_attr_trace].contains(&name)
{
return;
}
let name = (attr_path.segments.len() == 1).then_some(attr_path.segments[0]);
// FIXME: We should retrieve this information from the attribute parsers instead of from `BUILTIN_ATTRIBUTE_MAP`
let builtin_attr_info = name.and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
@ -87,16 +81,15 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
},
);
} else {
emit_lint(AttributeLint {
lint_id: LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE),
id: target_id,
span: path_span,
kind: AttributeLintKind::UnsafeAttrOutsideUnsafe {
emit_lint(
LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE),
path_span,
AttributeLintKind::UnsafeAttrOutsideUnsafe {
attribute_name_span: path_span,
sugg_spans: not_from_proc_macro
.then(|| (diag_span.shrink_to_lo(), diag_span.shrink_to_hi())),
},
})
)
}
}

View file

@ -47,6 +47,14 @@ pub(crate) struct DocAliasStartEnd<'a> {
pub attr_str: &'a str,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_doc_attr_not_crate_level)]
pub(crate) struct DocAttrNotCrateLevel {
#[primary_span]
pub span: Span,
pub attr_name: Symbol,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_doc_keyword_not_keyword)]
#[help]
@ -517,6 +525,10 @@ pub(crate) enum AttributeParseErrorReason<'a> {
byte_string: Option<Span>,
},
ExpectedIntegerLiteral,
ExpectedIntegerLiteralInRange {
lower_bound: isize,
upper_bound: isize,
},
ExpectedAtLeastOneArgument,
ExpectedSingleArgument,
ExpectedList,
@ -588,6 +600,17 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError<'_> {
AttributeParseErrorReason::ExpectedIntegerLiteral => {
diag.span_label(self.span, "expected an integer literal here");
}
AttributeParseErrorReason::ExpectedIntegerLiteralInRange {
lower_bound,
upper_bound,
} => {
diag.span_label(
self.span,
format!(
"expected an integer literal in the range of {lower_bound}..={upper_bound}"
),
);
}
AttributeParseErrorReason::ExpectedSingleArgument => {
diag.span_label(self.span, "expected a single argument here");
diag.code(E0805);

View file

@ -10,16 +10,12 @@ use rustc_span::sym;
use crate::AttributeParser;
use crate::context::{AcceptContext, Stage};
use crate::session_diagnostics::InvalidTarget;
use crate::target_checking::Policy::Allow;
#[derive(Debug)]
pub(crate) enum AllowedTargets {
AllowList(&'static [Policy]),
AllowListWarnRest(&'static [Policy]),
/// Special, and not the same as `AllowList(&[Allow(Target::Crate)])`.
/// For crate-level attributes we emit a specific set of lints to warn
/// people about accidentally not using them on the crate.
/// Only use this for attributes that are *exclusively* valid at the crate level.
CrateLevel,
}
pub(crate) enum AllowedResult {
@ -53,7 +49,6 @@ impl AllowedTargets {
AllowedResult::Warn
}
}
AllowedTargets::CrateLevel => AllowedResult::Allowed,
}
}
@ -61,7 +56,6 @@ impl AllowedTargets {
match self {
AllowedTargets::AllowList(list) => list,
AllowedTargets::AllowListWarnRest(list) => list,
AllowedTargets::CrateLevel => ALL_TARGETS,
}
.iter()
.filter_map(|target| match target {
@ -95,7 +89,12 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
target: Target,
cx: &mut AcceptContext<'_, 'sess, S>,
) {
Self::check_type(matches!(allowed_targets, AllowedTargets::CrateLevel), target, cx);
// For crate-level attributes we emit a specific set of lints to warn
// people about accidentally not using them on the crate.
if let &AllowedTargets::AllowList(&[Allow(Target::Crate)]) = allowed_targets {
Self::check_crate_level(target, cx);
return;
}
match allowed_targets.is_allowed(target) {
AllowedResult::Allowed => {}
@ -104,7 +103,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
let (applied, only) = allowed_targets_applied(allowed_targets, target, cx.features);
let name = cx.attr_path.clone();
let lint = if name.segments[0].name == sym::deprecated
let lint = if name.segments[0] == sym::deprecated
&& ![
Target::Closure,
Target::Expression,
@ -149,18 +148,8 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
}
}
pub(crate) fn check_type(
crate_level: bool,
target: Target,
cx: &mut AcceptContext<'_, 'sess, S>,
) {
let is_crate_root = S::id_is_crate_root(cx.target_id);
if is_crate_root {
return;
}
if !crate_level {
pub(crate) fn check_crate_level(target: Target, cx: &mut AcceptContext<'_, 'sess, S>) {
if target == Target::Crate {
return;
}
@ -310,5 +299,29 @@ pub(crate) const ALL_TARGETS: &'static [Policy] = {
Allow(Target::Crate),
Allow(Target::Delegation { mac: false }),
Allow(Target::Delegation { mac: true }),
Allow(Target::GenericParam {
kind: rustc_hir::target::GenericParamKind::Const,
has_default: false,
}),
Allow(Target::GenericParam {
kind: rustc_hir::target::GenericParamKind::Const,
has_default: true,
}),
Allow(Target::GenericParam {
kind: rustc_hir::target::GenericParamKind::Lifetime,
has_default: false,
}),
Allow(Target::GenericParam {
kind: rustc_hir::target::GenericParamKind::Lifetime,
has_default: true,
}),
Allow(Target::GenericParam {
kind: rustc_hir::target::GenericParamKind::Type,
has_default: false,
}),
Allow(Target::GenericParam {
kind: rustc_hir::target::GenericParamKind::Type,
has_default: true,
}),
]
};

View file

@ -27,7 +27,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
return;
}
let builtin_attr_info = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
let builtin_attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
// Check input tokens for built-in and key-value attributes.
match builtin_attr_info {
@ -48,7 +48,7 @@ pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
}
_ => {
let attr_item = attr.get_normal_item();
if let AttrArgs::Eq { .. } = attr_item.args {
if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() {
// All key-value attributes are restricted to meta-item syntax.
match parse_meta(psess, attr) {
Ok(_) => {}
@ -67,7 +67,7 @@ pub fn parse_meta<'a>(psess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Met
unsafety: item.unsafety,
span: attr.span,
path: item.path.clone(),
kind: match &item.args {
kind: match &item.args.unparsed_ref().unwrap() {
AttrArgs::Empty => MetaItemKind::Word,
AttrArgs::Delimited(DelimArgs { dspan, delim, tokens }) => {
check_meta_bad_delim(psess, *dspan, *delim);

View file

@ -253,19 +253,52 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
}
let region = region.as_var();
let borrow = BorrowData {
let borrow = |activation_location| BorrowData {
kind,
region,
reserve_location: location,
activation_location: TwoPhaseActivation::NotTwoPhase,
activation_location,
borrowed_place,
assigned_place: *assigned_place,
};
let (idx, _) = self.location_map.insert_full(location, borrow);
let idx = BorrowIndex::from(idx);
self.insert_as_pending_if_two_phase(location, assigned_place, kind, idx);
let idx = if !kind.is_two_phase_borrow() {
debug!(" -> {:?}", location);
let (idx, _) = self
.location_map
.insert_full(location, borrow(TwoPhaseActivation::NotTwoPhase));
BorrowIndex::from(idx)
} else {
// When we encounter a 2-phase borrow statement, it will always
// be assigning into a temporary TEMP:
//
// TEMP = &foo
//
// so extract `temp`.
let Some(temp) = assigned_place.as_local() else {
span_bug!(
self.body.source_info(location).span,
"expected 2-phase borrow to assign to a local, not `{:?}`",
assigned_place,
);
};
// Consider the borrow not activated to start. When we find an activation, we'll update
// this field.
let (idx, _) = self
.location_map
.insert_full(location, borrow(TwoPhaseActivation::NotActivated));
let idx = BorrowIndex::from(idx);
// Insert `temp` into the list of pending activations. From
// now on, we'll be on the lookout for a use of it. Note that
// we are guaranteed that this use will come after the
// assignment.
let prev = self.pending_activations.insert(temp, idx);
assert_eq!(prev, None, "temporary associated with multiple two phase borrows");
idx
};
self.local_map.entry(borrowed_place.local).or_default().insert(idx);
}
@ -334,62 +367,3 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherBorrows<'a, 'tcx> {
self.super_rvalue(rvalue, location)
}
}
impl<'a, 'tcx> GatherBorrows<'a, 'tcx> {
/// If this is a two-phase borrow, then we will record it
/// as "pending" until we find the activating use.
fn insert_as_pending_if_two_phase(
&mut self,
start_location: Location,
assigned_place: &mir::Place<'tcx>,
kind: mir::BorrowKind,
borrow_index: BorrowIndex,
) {
debug!(
"Borrows::insert_as_pending_if_two_phase({:?}, {:?}, {:?})",
start_location, assigned_place, borrow_index,
);
if !kind.allows_two_phase_borrow() {
debug!(" -> {:?}", start_location);
return;
}
// When we encounter a 2-phase borrow statement, it will always
// be assigning into a temporary TEMP:
//
// TEMP = &foo
//
// so extract `temp`.
let Some(temp) = assigned_place.as_local() else {
span_bug!(
self.body.source_info(start_location).span,
"expected 2-phase borrow to assign to a local, not `{:?}`",
assigned_place,
);
};
// Consider the borrow not activated to start. When we find an activation, we'll update
// this field.
{
let borrow_data = &mut self.location_map[borrow_index.as_usize()];
borrow_data.activation_location = TwoPhaseActivation::NotActivated;
}
// Insert `temp` into the list of pending activations. From
// now on, we'll be on the lookout for a use of it. Note that
// we are guaranteed that this use will come after the
// assignment.
let old_value = self.pending_activations.insert(temp, borrow_index);
if let Some(old_index) = old_value {
span_bug!(
self.body.source_info(start_location).span,
"found already pending activation for temp: {:?} \
at borrow_index: {:?} with associated data {:?}",
temp,
old_index,
self.location_map[old_index.as_usize()]
);
}
}
}

View file

@ -1,6 +1,3 @@
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, struct_span_code_err};
use rustc_hir as hir;

View file

@ -1,8 +1,5 @@
// ignore-tidy-filelength
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use std::iter;
use std::ops::ControlFlow;

View file

@ -1,10 +1,6 @@
//! Print diagnostics to explain why values are borrowed.
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use std::assert_matches::assert_matches;
use rustc_data_structures::assert_matches;
use rustc_errors::{Applicability, Diag, EmissionGuarantee};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;

View file

@ -162,8 +162,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
for (_, (mut diag, count)) in std::mem::take(&mut self.diags_buffer.buffered_mut_errors) {
if count > 10 {
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
diag.note(format!("...and {} other attempted mutable borrows", count - 10));
}
self.buffer_error(diag);
@ -236,7 +234,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
/// LL | for (key, value) in dict {
/// | ^^^^
/// ```
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
pub(super) fn add_moved_or_invoked_closure_note(
&self,
location: Location,
@ -820,7 +817,6 @@ impl UseSpans<'_> {
}
/// Add a span label to the arguments of the closure, if it exists.
#[allow(rustc::diagnostic_outside_of_impl)]
pub(super) fn args_subdiag(self, err: &mut Diag<'_>, f: impl FnOnce(Span) -> CaptureArgLabel) {
if let UseSpans::ClosureUse { args_span, .. } = self {
err.subdiagnostic(f(args_span));
@ -829,7 +825,6 @@ impl UseSpans<'_> {
/// Add a span label to the use of the captured variable, if it exists.
/// only adds label to the `path_span`
#[allow(rustc::diagnostic_outside_of_impl)]
pub(super) fn var_path_only_subdiag(
self,
err: &mut Diag<'_>,
@ -861,7 +856,6 @@ impl UseSpans<'_> {
}
/// Add a subdiagnostic to the use of the captured variable, if it exists.
#[allow(rustc::diagnostic_outside_of_impl)]
pub(super) fn var_subdiag(
self,
err: &mut Diag<'_>,
@ -1225,8 +1219,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.borrow_spans(span, borrow.reserve_location)
}
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn explain_captures(
&mut self,
err: &mut Diag<'infcx>,

View file

@ -1,6 +1,3 @@
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, Diag};
use rustc_hir::intravisit::Visitor;

View file

@ -1,6 +1,3 @@
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use core::ops::ControlFlow;
use either::Either;

View file

@ -1,6 +1,3 @@
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use std::ops::ControlFlow;
use either::Either;

View file

@ -1,9 +1,6 @@
//! Contains utilities for generating suggestions for borrowck errors related to unsatisfied
//! outlives constraints.
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use std::collections::BTreeMap;
use rustc_data_structures::fx::FxIndexSet;

View file

@ -196,7 +196,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
// For generic associated types (GATs) which implied 'static requirement
// from higher-ranked trait bounds (HRTB). Try to locate span of the trait
// and the span which bounded to the trait for adding 'static lifetime suggestion
#[allow(rustc::diagnostic_outside_of_impl)]
fn suggest_static_lifetime_for_gat_from_hrtb(
&self,
diag: &mut Diag<'_>,
@ -421,9 +420,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
/// ```
///
/// Here we would be invoked with `fr = 'a` and `outlived_fr = 'b`.
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
pub(crate) fn report_region_error(
&mut self,
fr: RegionVid,
@ -577,7 +573,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
/// executing...
/// = note: ...therefore, returned references to captured variables will escape the closure
/// ```
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
fn report_fnmut_error(
&self,
errci: &ErrorConstraintInfo<'tcx>,
@ -686,18 +681,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
borrowck_errors::borrowed_data_escapes_closure(self.infcx.tcx, *span, escapes_from);
if let Some((Some(outlived_fr_name), outlived_fr_span)) = outlived_fr_name_and_span {
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
diag.span_label(
outlived_fr_span,
format!("`{outlived_fr_name}` declared here, outside of the {escapes_from} body",),
);
}
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
if let Some((Some(fr_name), fr_span)) = fr_name_and_span {
diag.span_label(
fr_span,
@ -732,9 +721,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
outlived_fr_region_name.highlight_region_name(&mut diag);
// FIXME: make this translatable
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
diag.span_label(
*span,
format!(
@ -766,7 +752,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
/// | ^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it
/// | is returning data with lifetime `'b`
/// ```
#[allow(rustc::diagnostic_outside_of_impl)] // FIXME
fn report_general_error(&self, errci: &ErrorConstraintInfo<'tcx>) -> Diag<'infcx> {
let ErrorConstraintInfo { fr, outlived_fr, span, category, .. } = errci;
@ -824,8 +809,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
/// LL | fn iter_values_anon(&self) -> impl Iterator<Item=u32> + 'a {
/// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/// ```
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
fn add_static_impl_trait_suggestion(
&self,
diag: &mut Diag<'_>,
@ -966,7 +949,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
self.suggest_constrain_dyn_trait_in_impl(diag, &visitor.0, ident, self_ty);
}
#[allow(rustc::diagnostic_outside_of_impl)]
#[instrument(skip(self, err), level = "debug")]
fn suggest_constrain_dyn_trait_in_impl(
&self,
@ -1032,7 +1014,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
);
}
#[allow(rustc::diagnostic_outside_of_impl)]
/// When encountering a lifetime error caused by the return type of a closure, check the
/// corresponding trait bound and see if dereferencing the closure return value would satisfy
/// them. If so, we produce a structured suggestion.
@ -1160,7 +1141,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}
}
#[allow(rustc::diagnostic_outside_of_impl)]
fn suggest_move_on_borrowing_closure(&self, diag: &mut Diag<'_>) {
let body = self.infcx.tcx.hir_body_owned_by(self.mir_def_id());
let expr = &body.value.peel_blocks();

View file

@ -1,6 +1,3 @@
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use std::fmt::{self, Display};
use std::iter;

View file

@ -1301,7 +1301,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
(Read(kind), BorrowKind::Mut { .. }) => {
// Reading from mere reservations of mutable-borrows is OK.
if !is_active(this.dominators(), borrow, location) {
assert!(borrow.kind.allows_two_phase_borrow());
assert!(borrow.kind.is_two_phase_borrow());
return ControlFlow::Continue(());
}
@ -1464,7 +1464,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
}
BorrowKind::Mut { .. } => {
let wk = WriteKind::MutableBorrow(bk);
if bk.allows_two_phase_borrow() {
if bk.is_two_phase_borrow() {
(Deep, Reservation(wk))
} else {
(Deep, Write(wk))

View file

@ -287,8 +287,6 @@ pub(crate) fn emit_nll_mir<'tcx>(
Ok(())
}
#[allow(rustc::diagnostic_outside_of_impl)]
#[allow(rustc::untranslatable_diagnostic)]
pub(super) fn dump_annotation<'tcx, 'infcx>(
infcx: &'infcx BorrowckInferCtxt<'tcx>,
body: &Body<'tcx>,

View file

@ -264,7 +264,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
}
BorrowKind::Mut { .. } => {
let wk = WriteKind::MutableBorrow(bk);
if bk.allows_two_phase_borrow() {
if bk.is_two_phase_borrow() {
(Deep, Reservation(wk))
} else {
(Deep, Write(wk))
@ -384,7 +384,7 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> {
// Reading from mere reservations of mutable-borrows is OK.
if !is_active(this.dominators, borrow, location) {
// If the borrow isn't active yet, reads don't invalidate it
assert!(borrow.kind.allows_two_phase_borrow());
assert!(borrow.kind.is_two_phase_borrow());
return ControlFlow::Continue(());
}

View file

@ -45,7 +45,6 @@ pub(super) fn convert_typeck_constraints<'tcx>(
{
localize_statement_constraint(
tcx,
body,
stmt,
&outlives_constraint,
point,
@ -74,7 +73,6 @@ pub(super) fn convert_typeck_constraints<'tcx>(
/// needed CFG `from`-`to` intra-block nodes.
fn localize_statement_constraint<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
stmt: &Statement<'tcx>,
outlives_constraint: &OutlivesConstraint<'tcx>,
current_point: PointIndex,
@ -114,28 +112,22 @@ fn localize_statement_constraint<'tcx>(
},
"there should be no common regions between the LHS and RHS of an assignment"
);
let lhs_ty = body.local_decls[lhs.local].ty;
let successor_point = current_point;
compute_constraint_direction(
tcx,
outlives_constraint,
&lhs_ty,
current_point,
successor_point,
universal_regions,
)
}
_ => {
// For the other cases, we localize an outlives constraint to where it arises.
LocalizedOutlivesConstraint {
source: outlives_constraint.sup,
from: current_point,
target: outlives_constraint.sub,
to: current_point,
}
// Assignments should be the only statement that can both generate constraints that
// apply on entry (specific to the RHS place) *and* others that only apply on exit (the
// subset of RHS regions that actually flow into the LHS): i.e., where midpoints would
// be used to ensure the former happen before the latter, within the same MIR Location.
}
}
// We generally localize an outlives constraint to where it arises.
LocalizedOutlivesConstraint {
source: outlives_constraint.sup,
from: current_point,
target: outlives_constraint.sub,
to: current_point,
}
}
/// For a given outlives constraint arising from a MIR terminator, localize the constraint with the
@ -150,14 +142,12 @@ fn localize_terminator_constraint<'tcx>(
universal_regions: &UniversalRegions<'tcx>,
) -> LocalizedOutlivesConstraint {
// FIXME: check if other terminators need the same handling as `Call`s, in particular
// Assert/Yield/Drop. A handful of tests are failing with Drop related issues, as well as some
// coroutine tests, and that may be why.
// Assert/Yield/Drop.
match &terminator.kind {
// FIXME: also handle diverging calls.
TerminatorKind::Call { destination, target: Some(target), .. } => {
// Calls are similar to assignments, and thus follow the same pattern. If there is a
// target for the call we also relate what flows into the destination here to entry to
// that successor.
// If there is a target for the call we also relate what flows into the destination here
// to entry to that successor.
let destination_ty = destination.ty(&body.local_decls, tcx);
let successor_location = Location { block: *target, statement_index: 0 };
let successor_point = liveness.point_from_location(successor_location);

View file

@ -229,8 +229,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
// not ready to process them yet.
// - Then compute the implied bounds. This will adjust
// the `region_bound_pairs` and so forth.
// - After this is done, we'll process the constraints, once
// the `relations` is built.
// - After this is done, we'll register the constraints in
// the `BorrowckInferCtxt`. Checking these constraints is
// handled later by actual borrow checking.
let mut normalized_inputs_and_output =
Vec::with_capacity(self.universal_regions.unnormalized_input_tys.len() + 1);
for ty in unnormalized_input_output_tys {
@ -254,6 +255,15 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
constraints.push(c)
}
// Currently `implied_outlives_bounds` will normalize the provided
// `Ty`, despite this it's still important to normalize the ty ourselves
// as normalization may introduce new region variables (#136547).
//
// If we do not add implied bounds for the type involving these new
// region variables then we'll wind up with the normalized form of
// the signature having not-wf types due to unsatisfied region
// constraints.
//
// Note: we need this in examples like
// ```
// trait Foo {
@ -262,7 +272,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
// }
// impl Foo for () {
// type Bar = ();
// fn foo(&self) ->&() {}
// fn foo(&self) -> &() {}
// }
// ```
// Both &Self::Bar and &() are WF
@ -277,6 +287,15 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
}
// Add implied bounds from impl header.
//
// We don't use `assumed_wf_types` to source the entire set of implied bounds for
// a few reasons:
// - `DefiningTy` for closure has the `&'env Self` type while `assumed_wf_types` doesn't
// - We compute implied bounds from the unnormalized types in the `DefiningTy` but do not
// do so for types in impl headers
// - We must compute the normalized signature and then compute implied bounds from that
// in order to connect any unconstrained region vars created during normalization to
// the types of the locals corresponding to the inputs and outputs of the item. (#136547)
if matches!(tcx.def_kind(defining_ty_def_id), DefKind::AssocFn | DefKind::AssocConst) {
for &(ty, _) in tcx.assumed_wf_types(tcx.local_parent(defining_ty_def_id)) {
let result: Result<_, ErrorGuaranteed> = param_env
@ -352,10 +371,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
known_type_outlives_obligations.push(outlives);
}
/// Update the type of a single local, which should represent
/// either the return type of the MIR or one of its arguments. At
/// the same time, compute and add any implied bounds that come
/// from this local.
/// Compute and add any implied bounds that come from a given type.
#[instrument(level = "debug", skip(self))]
fn add_implied_bounds(
&mut self,

View file

@ -7,9 +7,8 @@
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
//! contain revealed `impl Trait` values).
use std::assert_matches::assert_matches;
use itertools::Itertools;
use rustc_data_structures::assert_matches;
use rustc_hir as hir;
use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin};
use rustc_middle::mir::*;

View file

@ -19,6 +19,7 @@ use rustc_infer::infer::{
BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin,
};
use rustc_infer::traits::PredicateObligations;
use rustc_middle::bug;
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::traits::query::NoSolution;
@ -28,7 +29,6 @@ use rustc_middle::ty::{
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CoroutineArgsExt,
GenericArgsRef, Ty, TyCtxt, TypeVisitableExt, UserArgs, UserTypeAnnotationIndex, fold_regions,
};
use rustc_middle::{bug, span_bug};
use rustc_mir_dataflow::move_paths::MoveData;
use rustc_mir_dataflow::points::DenseLocationMap;
use rustc_span::def_id::CRATE_DEF_ID;
@ -387,18 +387,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
#[instrument(skip(self), level = "debug")]
fn check_user_type_annotations(&mut self) {
debug!(?self.user_type_annotations);
let tcx = self.tcx();
for user_annotation in self.user_type_annotations {
let CanonicalUserTypeAnnotation { span, ref user_ty, inferred_ty } = *user_annotation;
let annotation = self.instantiate_canonical(span, user_ty);
if let ty::UserTypeKind::TypeOf(def, args) = annotation.kind
&& let DefKind::InlineConst = tcx.def_kind(def)
{
assert!(annotation.bounds.is_empty());
self.check_inline_const(inferred_ty, def.expect_local(), args, span);
} else {
self.ascribe_user_type(inferred_ty, annotation, span);
}
self.ascribe_user_type(inferred_ty, annotation, span);
}
}
@ -560,36 +552,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.constraints.liveness_constraints.add_location(region, location);
}
}
fn check_inline_const(
&mut self,
inferred_ty: Ty<'tcx>,
def_id: LocalDefId,
args: UserArgs<'tcx>,
span: Span,
) {
assert!(args.user_self_ty.is_none());
let tcx = self.tcx();
let const_ty = tcx.type_of(def_id).instantiate(tcx, args.args);
if let Err(terr) =
self.eq_types(const_ty, inferred_ty, Locations::All(span), ConstraintCategory::Boring)
{
span_bug!(
span,
"bad inline const pattern: ({:?} = {:?}) {:?}",
const_ty,
inferred_ty,
terr
);
}
let args = self.infcx.resolve_vars_if_possible(args.args);
let predicates = self.prove_closure_bounds(tcx, def_id, args, Locations::All(span));
self.normalize_and_prove_instantiated_predicates(
def_id.to_def_id(),
predicates,
Locations::All(span),
);
}
}
impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
@ -1581,12 +1543,18 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
.unwrap();
}
(None, None) => {
// `struct_tail` returns regions which haven't been mapped
// to nll vars yet so we do it here as `outlives_constraints`
// expects nll vars.
let src_lt = self.universal_regions.to_region_vid(src_lt);
let dst_lt = self.universal_regions.to_region_vid(dst_lt);
// The principalless (no non-auto traits) case:
// You can only cast `dyn Send + 'long` to `dyn Send + 'short`.
self.constraints.outlives_constraints.push(
OutlivesConstraint {
sup: src_lt.as_var(),
sub: dst_lt.as_var(),
sup: src_lt,
sub: dst_lt,
locations: location.to_locations(),
span: location.to_locations().span(self.body),
category: ConstraintCategory::Cast {
@ -1725,12 +1693,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
let def_id = uv.def;
if tcx.def_kind(def_id) == DefKind::InlineConst {
let def_id = def_id.expect_local();
let predicates = self.prove_closure_bounds(
tcx,
def_id,
uv.args,
location.to_locations(),
);
let predicates = self.prove_closure_bounds(tcx, def_id, uv.args, location);
self.normalize_and_prove_instantiated_predicates(
def_id.to_def_id(),
predicates,
@ -2513,15 +2476,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// clauses on the struct.
AggregateKind::Closure(def_id, args)
| AggregateKind::CoroutineClosure(def_id, args)
| AggregateKind::Coroutine(def_id, args) => (
def_id,
self.prove_closure_bounds(
tcx,
def_id.expect_local(),
args,
location.to_locations(),
),
),
| AggregateKind::Coroutine(def_id, args) => {
(def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), args, location))
}
AggregateKind::Array(_) | AggregateKind::Tuple | AggregateKind::RawPtr(..) => {
(CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty())
@ -2540,12 +2497,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
args: GenericArgsRef<'tcx>,
locations: Locations,
location: Location,
) -> ty::InstantiatedPredicates<'tcx> {
let root_def_id = self.root_cx.root_def_id();
// We will have to handle propagated closure requirements for this closure,
// but need to defer this until the nested body has been fully borrow checked.
self.deferred_closure_requirements.push((def_id, args, locations));
self.deferred_closure_requirements.push((def_id, args, location.to_locations()));
// Equate closure args to regions inherited from `root_def_id`. Fixes #98589.
let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, root_def_id);
@ -2569,7 +2526,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
if let Err(_) = self.eq_args(
typeck_root_args,
parent_args,
locations,
location.to_locations(),
ConstraintCategory::BoringNoLocation,
) {
span_mirbug!(

View file

@ -11,9 +11,6 @@
//! The code in this file doesn't *do anything* with those results; it
//! just returns them for other code to use.
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
use std::cell::Cell;
use std::iter;
@ -207,10 +204,10 @@ struct UniversalRegionIndices<'tcx> {
/// `ty::Region` to the internal `RegionVid` we are using. This is
/// used because trait matching and type-checking will feed us
/// region constraints that reference those regions and we need to
/// be able to map them to our internal `RegionVid`. This is
/// basically equivalent to an `GenericArgs`, except that it also
/// contains an entry for `ReStatic` -- it might be nice to just
/// use an args, and then handle `ReStatic` another way.
/// be able to map them to our internal `RegionVid`.
///
/// This is similar to just using `GenericArgs`, except that it contains
/// an entry for `'static`, and also late bound parameters in scope.
indices: FxIndexMap<ty::Region<'tcx>, RegionVid>,
/// The vid assigned to `'static`. Used only for diagnostics.
@ -543,38 +540,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
&indices,
);
let (unnormalized_output_ty, mut unnormalized_input_tys) =
let (unnormalized_output_ty, unnormalized_input_tys) =
inputs_and_output.split_last().unwrap();
// C-variadic fns also have a `VaList` input that's not listed in the signature
// (as it's created inside the body itself, not passed in from outside).
if let DefiningTy::FnDef(def_id, _) = defining_ty {
if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() {
let va_list_did = self
.infcx
.tcx
.require_lang_item(LangItem::VaList, self.infcx.tcx.def_span(self.mir_def));
let reg_vid = self
.infcx
.next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || {
RegionCtxt::Free(sym::c_dash_variadic)
})
.as_var();
let region = ty::Region::new_var(self.infcx.tcx, reg_vid);
let va_list_ty = self
.infcx
.tcx
.type_of(va_list_did)
.instantiate(self.infcx.tcx, &[region.into()]);
unnormalized_input_tys = self.infcx.tcx.mk_type_list_from_iter(
unnormalized_input_tys.iter().copied().chain(iter::once(va_list_ty)),
);
}
}
let fr_fn_body = self
.infcx
.next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || {
@ -816,7 +784,40 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
DefiningTy::FnDef(def_id, _) => {
let sig = tcx.fn_sig(def_id).instantiate_identity();
let sig = indices.fold_to_region_vids(tcx, sig);
sig.inputs_and_output()
let inputs_and_output = sig.inputs_and_output();
// C-variadic fns also have a `VaList` input that's not listed in the signature
// (as it's created inside the body itself, not passed in from outside).
if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() {
let va_list_did = self
.infcx
.tcx
.require_lang_item(LangItem::VaList, self.infcx.tcx.def_span(self.mir_def));
let reg_vid = self
.infcx
.next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || {
RegionCtxt::Free(sym::c_dash_variadic)
})
.as_var();
let region = ty::Region::new_var(self.infcx.tcx, reg_vid);
let va_list_ty = self
.infcx
.tcx
.type_of(va_list_did)
.instantiate(self.infcx.tcx, &[region.into()]);
// The signature needs to follow the order [input_tys, va_list_ty, output_ty]
return inputs_and_output.map_bound(|tys| {
let (output_ty, input_tys) = tys.split_last().unwrap();
tcx.mk_type_list_from_iter(
input_tys.iter().copied().chain([va_list_ty, *output_ty]),
)
});
}
inputs_and_output
}
DefiningTy::Const(def_id, _) => {

View file

@ -151,9 +151,9 @@ builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept
builtin_macros_duplicate_macro_attribute = duplicated attribute
builtin_macros_eii_extern_target_expected_list = `#[eii_extern_target(...)]` expects a list of one or two elements
builtin_macros_eii_extern_target_expected_macro = `#[eii_extern_target(...)]` is only valid on macros
builtin_macros_eii_extern_target_expected_unsafe = expected this argument to be "unsafe"
builtin_macros_eii_declaration_expected_list = `#[eii_declaration(...)]` expects a list of one or two elements
builtin_macros_eii_declaration_expected_macro = `#[eii_declaration(...)]` is only valid on macros
builtin_macros_eii_declaration_expected_unsafe = expected this argument to be "unsafe"
.note = the second argument is optional
builtin_macros_eii_only_once = `#[{$name}]` can only be specified once
@ -161,6 +161,8 @@ builtin_macros_eii_only_once = `#[{$name}]` can only be specified once
builtin_macros_eii_shared_macro_expected_function = `#[{$name}]` is only valid on functions
builtin_macros_eii_shared_macro_expected_max_one_argument = `#[{$name}]` expected no arguments or a single argument: `#[{$name}(default)]`
builtin_macros_eii_shared_macro_in_statement_position = `#[{$name}]` can only be used on functions inside a module
.label = `#[{$name}]` is used on this item, which is part of another item's local scope
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
.cargo = Cargo sets build script variables at run time. Use `std::env::var({$var_expr})` instead
@ -182,6 +184,8 @@ builtin_macros_expected_other = expected operand, {$is_inline_asm ->
builtin_macros_export_macro_rules = cannot export macro_rules! macros from a `proc-macro` crate type currently
builtin_macros_format_add_missing_colon = add a colon before the format specifier
builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}`
.label1 = previously here
.label2 = duplicate argument

View file

@ -358,7 +358,7 @@ mod llvm_enzyme {
let inline_item = ast::AttrItem {
unsafety: ast::Safety::Default,
path: ast::Path::from_ident(Ident::with_dummy_span(sym::inline)),
args: ast::AttrArgs::Delimited(never_arg),
args: rustc_ast::ast::AttrItemKind::Unparsed(ast::AttrArgs::Delimited(never_arg)),
tokens: None,
};
let inline_never_attr = Box::new(ast::NormalAttr { item: inline_item, tokens: None });
@ -421,11 +421,13 @@ mod llvm_enzyme {
}
};
// Now update for d_fn
rustc_ad_attr.item.args = rustc_ast::AttrArgs::Delimited(rustc_ast::DelimArgs {
dspan: DelimSpan::dummy(),
delim: rustc_ast::token::Delimiter::Parenthesis,
tokens: ts,
});
rustc_ad_attr.item.args = rustc_ast::ast::AttrItemKind::Unparsed(
rustc_ast::AttrArgs::Delimited(rustc_ast::DelimArgs {
dspan: DelimSpan::dummy(),
delim: rustc_ast::token::Delimiter::Parenthesis,
tokens: ts,
}),
);
let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id();
let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span);

View file

@ -10,10 +10,10 @@ use rustc_attr_parsing::{
AttributeParser, CFG_TEMPLATE, ParsedDescription, ShouldEmit, parse_cfg_entry,
};
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacEager, MacroExpanderResult};
use rustc_hir::AttrPath;
use rustc_hir::attrs::CfgEntry;
use rustc_hir::{AttrPath, Target};
use rustc_parse::exp;
use rustc_span::{ErrorGuaranteed, Ident, Span};
use rustc_span::{ErrorGuaranteed, Span, sym};
use crate::errors;
@ -40,20 +40,25 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
return Err(cx.dcx().emit_err(errors::RequiresCfgPattern { span }));
}
let meta = MetaItemOrLitParser::parse_single(&mut parser, ShouldEmit::ErrorsAndLints)
.map_err(|diag| diag.emit())?;
let meta = MetaItemOrLitParser::parse_single(
&mut parser,
ShouldEmit::ErrorsAndLints { recover: true },
)
.map_err(|diag| diag.emit())?;
let cfg = AttributeParser::parse_single_args(
cx.sess,
span,
span,
AttrStyle::Inner,
AttrPath { segments: vec![Ident::from_str("cfg")].into_boxed_slice(), span },
AttrPath { segments: vec![sym::cfg].into_boxed_slice(), span },
None,
ParsedDescription::Macro,
span,
cx.current_expansion.lint_node_id,
// Doesn't matter what the target actually is here.
Target::Crate,
Some(cx.ecfg.features),
ShouldEmit::ErrorsAndLints,
ShouldEmit::ErrorsAndLints { recover: true },
&meta,
parse_cfg_entry,
&CFG_TEMPLATE,

View file

@ -9,7 +9,7 @@ use rustc_expand::base::{Annotatable, ExtCtxt};
use rustc_expand::config::StripUnconfigured;
use rustc_expand::configure;
use rustc_feature::Features;
use rustc_parse::parser::{ForceCollect, Parser};
use rustc_parse::parser::{AllowConstBlockItems, ForceCollect, Parser};
use rustc_session::Session;
use rustc_span::{Span, sym};
use smallvec::SmallVec;
@ -47,10 +47,7 @@ fn has_cfg_or_cfg_attr(annotatable: &Annotatable) -> bool {
impl<'ast> visit::Visitor<'ast> for CfgFinder {
type Result = ControlFlow<()>;
fn visit_attribute(&mut self, attr: &'ast Attribute) -> ControlFlow<()> {
if attr
.ident()
.is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr)
{
if attr.name().is_some_and(|name| name == sym::cfg || name == sym::cfg_attr) {
ControlFlow::Break(())
} else {
ControlFlow::Continue(())
@ -113,7 +110,8 @@ impl CfgEval<'_> {
let res: PResult<'_, Annotatable> = try {
match annotatable {
Annotatable::Item(_) => {
let item = parser.parse_item(ForceCollect::Yes)?.unwrap();
let item =
parser.parse_item(ForceCollect::Yes, AllowConstBlockItems::Yes)?.unwrap();
Annotatable::Item(self.flat_map_item(item).pop().unwrap())
}
Annotatable::AssocItem(_, ctxt) => {

View file

@ -19,9 +19,8 @@ pub(crate) fn expand_compile_error<'cx>(
Err(guar) => return ExpandResult::Ready(DummyResult::any(sp, guar)),
};
#[expect(rustc::diagnostic_outside_of_impl, reason = "diagnostic message is specified by user")]
#[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")]
let guar = cx.dcx().span_err(sp, var.to_string());
cx.resolver.mark_scope_with_compile_error(cx.current_expansion.lint_node_id);
ExpandResult::Ready(DummyResult::any(sp, guar))
}

View file

@ -807,24 +807,29 @@ impl<'a> TraitDef<'a> {
rustc_ast::AttrItem {
unsafety: Safety::Default,
path: rustc_const_unstable,
args: AttrArgs::Delimited(DelimArgs {
dspan: DelimSpan::from_single(self.span),
delim: rustc_ast::token::Delimiter::Parenthesis,
tokens: [
TokenKind::Ident(sym::feature, IdentIsRaw::No),
TokenKind::Eq,
TokenKind::lit(LitKind::Str, sym::derive_const, None),
TokenKind::Comma,
TokenKind::Ident(sym::issue, IdentIsRaw::No),
TokenKind::Eq,
TokenKind::lit(LitKind::Str, sym::derive_const_issue, None),
]
.into_iter()
.map(|kind| {
TokenTree::Token(Token { kind, span: self.span }, Spacing::Alone)
})
.collect(),
}),
args: rustc_ast::ast::AttrItemKind::Unparsed(AttrArgs::Delimited(
DelimArgs {
dspan: DelimSpan::from_single(self.span),
delim: rustc_ast::token::Delimiter::Parenthesis,
tokens: [
TokenKind::Ident(sym::feature, IdentIsRaw::No),
TokenKind::Eq,
TokenKind::lit(LitKind::Str, sym::derive_const, None),
TokenKind::Comma,
TokenKind::Ident(sym::issue, IdentIsRaw::No),
TokenKind::Eq,
TokenKind::lit(LitKind::Str, sym::derive_const_issue, None),
]
.into_iter()
.map(|kind| {
TokenTree::Token(
Token { kind, span: self.span },
Spacing::Alone,
)
})
.collect(),
},
)),
tokens: None,
},
self.span,
@ -981,16 +986,6 @@ impl<'a> MethodDef<'a> {
f(cx, span, &substructure)
}
fn get_ret_ty(
&self,
cx: &ExtCtxt<'_>,
trait_: &TraitDef<'_>,
generics: &Generics,
type_ident: Ident,
) -> Box<ast::Ty> {
self.ret_ty.to_ty(cx, trait_.span, type_ident, generics)
}
fn is_static(&self) -> bool {
!self.explicit_self
}
@ -1063,10 +1058,14 @@ impl<'a> MethodDef<'a> {
self_arg.into_iter().chain(nonself_args).collect()
};
let ret_type = self.get_ret_ty(cx, trait_, generics, type_ident);
let ret_type = if let Ty::Unit = &self.ret_ty {
ast::FnRetTy::Default(span)
} else {
ast::FnRetTy::Ty(self.ret_ty.to_ty(cx, span, type_ident, generics))
};
let method_ident = Ident::new(self.name, span);
let fn_decl = cx.fn_decl(args, ast::FnRetTy::Ty(ret_type));
let fn_decl = cx.fn_decl(args, ret_type);
let body_block = body.into_block(cx, span);
let trait_lo_sp = span.shrink_to_lo();

View file

@ -1,8 +1,7 @@
use rustc_ast::token::{Delimiter, TokenKind};
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
use rustc_ast::{
Attribute, DUMMY_NODE_ID, EiiExternTarget, EiiImpl, ItemKind, MetaItem, Path, Stmt, StmtKind,
Visibility, ast,
Attribute, DUMMY_NODE_ID, EiiDecl, EiiImpl, ItemKind, MetaItem, Path, StmtKind, Visibility, ast,
};
use rustc_ast_pretty::pprust::path_to_string;
use rustc_expand::base::{Annotatable, ExtCtxt};
@ -12,6 +11,7 @@ use thin_vec::{ThinVec, thin_vec};
use crate::errors::{
EiiExternTargetExpectedList, EiiExternTargetExpectedMacro, EiiExternTargetExpectedUnsafe,
EiiMacroExpectedMaxOneArgument, EiiOnlyOnce, EiiSharedMacroExpectedFunction,
EiiSharedMacroInStatementPosition,
};
/// ```rust
@ -30,7 +30,7 @@ use crate::errors::{
/// }
///
/// #[rustc_builtin_macro(eii_shared_macro)]
/// #[eii_extern_target(panic_handler)]
/// #[eii_declaration(panic_handler)]
/// macro panic_handler() {}
/// ```
pub(crate) fn eii(
@ -55,29 +55,29 @@ fn eii_(
ecx: &mut ExtCtxt<'_>,
eii_attr_span: Span,
meta_item: &ast::MetaItem,
item: Annotatable,
orig_item: Annotatable,
impl_unsafe: bool,
) -> Vec<Annotatable> {
let eii_attr_span = ecx.with_def_site_ctxt(eii_attr_span);
let (item, wrap_item): (_, &dyn Fn(_) -> _) = if let Annotatable::Item(item) = item {
(item, &Annotatable::Item)
} else if let Annotatable::Stmt(ref stmt) = item
let item = if let Annotatable::Item(item) = orig_item {
item
} else if let Annotatable::Stmt(ref stmt) = orig_item
&& let StmtKind::Item(ref item) = stmt.kind
&& let ItemKind::Fn(ref f) = item.kind
{
(item.clone(), &|item| {
Annotatable::Stmt(Box::new(Stmt {
id: DUMMY_NODE_ID,
kind: StmtKind::Item(item),
span: eii_attr_span,
}))
})
ecx.dcx().emit_err(EiiSharedMacroInStatementPosition {
span: eii_attr_span.to(item.span),
name: path_to_string(&meta_item.path),
item_span: f.ident.span,
});
return vec![orig_item];
} else {
ecx.dcx().emit_err(EiiSharedMacroExpectedFunction {
span: eii_attr_span,
name: path_to_string(&meta_item.path),
});
return vec![item];
return vec![orig_item];
};
let ast::Item { attrs, id: _, span: _, vis, kind: ItemKind::Fn(func), tokens: _ } =
@ -87,7 +87,7 @@ fn eii_(
span: eii_attr_span,
name: path_to_string(&meta_item.path),
});
return vec![wrap_item(item)];
return vec![Annotatable::Item(item)];
};
// only clone what we need
let attrs = attrs.clone();
@ -98,45 +98,49 @@ fn eii_(
filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path);
let Ok(macro_name) = name_for_impl_macro(ecx, &func, &meta_item) else {
return vec![wrap_item(item)];
// we don't need to wrap in Annotatable::Stmt conditionally since
// EII can't be used on items in statement position
return vec![Annotatable::Item(item)];
};
// span of the declaring item without attributes
let item_span = func.sig.span;
// span of the eii attribute and the item below it, i.e. the full declaration
let decl_span = eii_attr_span.to(item_span);
let foreign_item_name = func.ident;
let mut return_items = Vec::new();
let mut module_items = Vec::new();
if func.body.is_some() {
return_items.push(Box::new(generate_default_impl(
module_items.push(generate_default_impl(
ecx,
&func,
impl_unsafe,
macro_name,
eii_attr_span,
item_span,
)))
foreign_item_name,
))
}
return_items.push(Box::new(generate_foreign_item(
module_items.push(generate_foreign_item(
ecx,
eii_attr_span,
item_span,
func,
vis,
&attrs_from_decl,
)));
return_items.push(Box::new(generate_attribute_macro_to_implement(
));
module_items.push(generate_attribute_macro_to_implement(
ecx,
eii_attr_span,
macro_name,
foreign_item_name,
impl_unsafe,
decl_span,
)));
&attrs_from_decl,
));
return_items.into_iter().map(wrap_item).collect()
// we don't need to wrap in Annotatable::Stmt conditionally since
// EII can't be used on items in statement position
module_items.into_iter().map(Annotatable::Item).collect()
}
/// Decide on the name of the macro that can be used to implement the EII.
@ -187,12 +191,14 @@ fn filter_attrs_for_multiple_eii_attr(
}
fn generate_default_impl(
ecx: &mut ExtCtxt<'_>,
func: &ast::Fn,
impl_unsafe: bool,
macro_name: Ident,
eii_attr_span: Span,
item_span: Span,
) -> ast::Item {
foreign_item_name: Ident,
) -> Box<ast::Item> {
// FIXME: re-add some original attrs
let attrs = ThinVec::new();
@ -208,62 +214,38 @@ fn generate_default_impl(
},
span: eii_attr_span,
is_default: true,
known_eii_macro_resolution: Some(ast::EiiDecl {
foreign_item: ecx.path(
foreign_item_name.span,
// prefix self to explicitly escape the const block generated below
// NOTE: this is why EIIs can't be used on statements
vec![Ident::from_str_and_span("self", foreign_item_name.span), foreign_item_name],
),
impl_unsafe,
}),
});
ast::Item {
attrs: ThinVec::new(),
id: ast::DUMMY_NODE_ID,
span: eii_attr_span,
vis: ast::Visibility {
span: eii_attr_span,
kind: ast::VisibilityKind::Inherited,
tokens: None,
},
kind: ast::ItemKind::Const(Box::new(ast::ConstItem {
ident: Ident { name: kw::Underscore, span: eii_attr_span },
defaultness: ast::Defaultness::Final,
generics: ast::Generics::default(),
ty: Box::new(ast::Ty {
id: DUMMY_NODE_ID,
kind: ast::TyKind::Tup(ThinVec::new()),
span: eii_attr_span,
tokens: None,
}),
rhs: Some(ast::ConstItemRhs::Body(Box::new(ast::Expr {
id: DUMMY_NODE_ID,
kind: ast::ExprKind::Block(
Box::new(ast::Block {
stmts: thin_vec![ast::Stmt {
id: DUMMY_NODE_ID,
kind: ast::StmtKind::Item(Box::new(ast::Item {
attrs,
id: DUMMY_NODE_ID,
span: item_span,
vis: ast::Visibility {
span: eii_attr_span,
kind: ast::VisibilityKind::Inherited,
tokens: None
},
kind: ItemKind::Fn(Box::new(default_func)),
tokens: None,
})),
span: eii_attr_span
}],
id: DUMMY_NODE_ID,
rules: ast::BlockCheckMode::Default,
span: eii_attr_span,
tokens: None,
}),
None,
),
span: eii_attr_span,
attrs: ThinVec::new(),
tokens: None,
}))),
define_opaque: None,
})),
tokens: None,
}
let anon_mod = |span: Span, stmts: ThinVec<ast::Stmt>| {
let unit = ecx.ty(item_span, ast::TyKind::Tup(ThinVec::new()));
let underscore = Ident::new(kw::Underscore, item_span);
ecx.item_const(
span,
underscore,
unit,
ast::ConstItemRhs::Body(ecx.expr_block(ecx.block(span, stmts))),
)
};
// const _: () = {
// <orig fn>
// }
anon_mod(
item_span,
thin_vec![ecx.stmt_item(
item_span,
ecx.item(item_span, attrs, ItemKind::Fn(Box::new(default_func)))
),],
)
}
/// Generates a foreign item, like
@ -278,13 +260,13 @@ fn generate_foreign_item(
mut func: ast::Fn,
vis: Visibility,
attrs_from_decl: &[Attribute],
) -> ast::Item {
) -> Box<ast::Item> {
let mut foreign_item_attrs = ThinVec::new();
foreign_item_attrs.extend_from_slice(attrs_from_decl);
// Add the rustc_eii_extern_item on the foreign item. Usually, foreign items are mangled.
// Add the rustc_eii_foreign_item on the foreign item. Usually, foreign items are mangled.
// This attribute makes sure that we later know that this foreign item's symbol should not be.
foreign_item_attrs.push(ecx.attr_word(sym::rustc_eii_extern_item, eii_attr_span));
foreign_item_attrs.push(ecx.attr_word(sym::rustc_eii_foreign_item, eii_attr_span));
let abi = match func.sig.header.ext {
// extern "X" fn => extern "X" {}
@ -310,16 +292,10 @@ fn generate_foreign_item(
func.sig.header.safety = ast::Safety::Safe(func.sig.span);
}
ast::Item {
attrs: ast::AttrVec::default(),
id: ast::DUMMY_NODE_ID,
span: eii_attr_span,
vis: ast::Visibility {
span: eii_attr_span,
kind: ast::VisibilityKind::Inherited,
tokens: None,
},
kind: ast::ItemKind::ForeignMod(ast::ForeignMod {
ecx.item(
eii_attr_span,
ThinVec::new(),
ast::ItemKind::ForeignMod(ast::ForeignMod {
extern_span: eii_attr_span,
safety: ast::Safety::Unsafe(eii_attr_span),
abi,
@ -332,8 +308,7 @@ fn generate_foreign_item(
tokens: None,
})]),
}),
tokens: None,
}
)
}
/// Generate a stub macro (a bit like in core) that will roughly look like:
@ -343,7 +318,7 @@ fn generate_foreign_item(
/// // This attribute tells the compiler that
/// #[builtin_macro(eii_shared_macro)]
/// // the metadata to link this macro to the generated foreign item.
/// #[eii_extern_target(<related_reign_item>)]
/// #[eii_declaration(<related_foreign_item>)]
/// macro macro_name { () => {} }
/// ```
fn generate_attribute_macro_to_implement(
@ -352,14 +327,22 @@ fn generate_attribute_macro_to_implement(
macro_name: Ident,
foreign_item_name: Ident,
impl_unsafe: bool,
decl_span: Span,
) -> ast::Item {
attrs_from_decl: &[Attribute],
) -> Box<ast::Item> {
let mut macro_attrs = ThinVec::new();
// To avoid e.g. `error: attribute macro has missing stability attribute`
// errors for eii's in std.
macro_attrs.extend_from_slice(attrs_from_decl);
// Avoid "missing stability attribute" errors for eiis in std. See #146993.
macro_attrs.push(ecx.attr_name_value_str(sym::rustc_macro_transparency, sym::semiopaque, span));
// #[builtin_macro(eii_shared_macro)]
macro_attrs.push(ecx.attr_nested_word(sym::rustc_builtin_macro, sym::eii_shared_macro, span));
ast::Item {
// cant use ecx methods here to construct item since we need it to be public
Box::new(ast::Item {
attrs: macro_attrs,
id: ast::DUMMY_NODE_ID,
span,
@ -390,19 +373,18 @@ fn generate_attribute_macro_to_implement(
]),
}),
macro_rules: false,
// #[eii_extern_target(foreign_item_ident)]
eii_extern_target: Some(ast::EiiExternTarget {
extern_item_path: ast::Path::from_ident(foreign_item_name),
// #[eii_declaration(foreign_item_ident)]
eii_declaration: Some(ast::EiiDecl {
foreign_item: ast::Path::from_ident(foreign_item_name),
impl_unsafe,
span: decl_span,
}),
},
),
tokens: None,
}
})
}
pub(crate) fn eii_extern_target(
pub(crate) fn eii_declaration(
ecx: &mut ExtCtxt<'_>,
span: Span,
meta_item: &ast::MetaItem,
@ -451,7 +433,7 @@ pub(crate) fn eii_extern_target(
false
};
d.eii_extern_target = Some(EiiExternTarget { extern_item_path, impl_unsafe, span });
d.eii_declaration = Some(EiiDecl { foreign_item: extern_item_path, impl_unsafe });
// Return the original item and the new methods.
vec![item]
@ -508,6 +490,7 @@ pub(crate) fn eii_shared_macro(
impl_safety: meta_item.unsafety,
span,
is_default,
known_eii_macro_resolution: None,
});
vec![item]

View file

@ -503,10 +503,6 @@ pub(crate) struct EnvNotDefinedWithUserMessage {
impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for EnvNotDefinedWithUserMessage {
#[track_caller]
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
#[expect(
rustc::untranslatable_diagnostic,
reason = "cannot translate user-provided messages"
)]
let mut diag = Diag::new(dcx, level, self.msg_from_user.to_string());
diag.span(self.span);
diag
@ -643,6 +639,15 @@ pub(crate) enum InvalidFormatStringSuggestion {
span: Span,
replacement: String,
},
#[suggestion(
builtin_macros_format_add_missing_colon,
code = ":?",
applicability = "machine-applicable"
)]
AddMissingColon {
#[primary_span]
span: Span,
},
}
#[derive(Diagnostic)]
@ -1001,21 +1006,21 @@ pub(crate) struct CfgSelectUnreachable {
}
#[derive(Diagnostic)]
#[diag(builtin_macros_eii_extern_target_expected_macro)]
#[diag(builtin_macros_eii_declaration_expected_macro)]
pub(crate) struct EiiExternTargetExpectedMacro {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_eii_extern_target_expected_list)]
#[diag(builtin_macros_eii_declaration_expected_list)]
pub(crate) struct EiiExternTargetExpectedList {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_eii_extern_target_expected_unsafe)]
#[diag(builtin_macros_eii_declaration_expected_unsafe)]
pub(crate) struct EiiExternTargetExpectedUnsafe {
#[primary_span]
#[note]
@ -1030,6 +1035,16 @@ pub(crate) struct EiiSharedMacroExpectedFunction {
pub name: String,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_eii_shared_macro_in_statement_position)]
pub(crate) struct EiiSharedMacroInStatementPosition {
#[primary_span]
pub span: Span,
pub name: String,
#[label]
pub item_span: Span,
}
#[derive(Diagnostic)]
#[diag(builtin_macros_eii_only_once)]
pub(crate) struct EiiOnlyOnce {

View file

@ -329,6 +329,10 @@ fn make_format_args(
replacement,
});
}
parse::Suggestion::AddMissingColon(span) => {
let span = fmt_span.from_inner(InnerSpan::new(span.start, span.end));
e.sugg_ = Some(errors::InvalidFormatStringSuggestion::AddMissingColon { span });
}
}
let guar = ecx.dcx().emit_err(e);
return ExpandResult::Ready(Err(guar));

View file

@ -3,8 +3,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(decl_macro)]
@ -119,7 +117,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
derive: derive::Expander { is_const: false },
derive_const: derive::Expander { is_const: true },
eii: eii::eii,
eii_extern_target: eii::eii_extern_target,
eii_declaration: eii::eii_declaration,
eii_shared_macro: eii::eii_shared_macro,
global_allocator: global_allocator::expand,
test: test::expand_test,

View file

@ -13,7 +13,7 @@ use rustc_expand::base::{
};
use rustc_expand::module::DirOwnership;
use rustc_parse::lexer::StripTokens;
use rustc_parse::parser::ForceCollect;
use rustc_parse::parser::{AllowConstBlockItems, ForceCollect};
use rustc_parse::{new_parser_from_file, unwrap_or_emit_fatal, utf8_error};
use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
use rustc_session::parse::ParseSess;
@ -168,7 +168,7 @@ pub(crate) fn expand_include<'cx>(
));
let mut ret = SmallVec::new();
loop {
match p.parse_item(ForceCollect::No) {
match p.parse_item(ForceCollect::No, AllowConstBlockItems::Yes) {
Err(err) => {
err.emit();
break;

View file

@ -43,7 +43,7 @@ pub fn inject(
let item = cx.item(
span,
thin_vec![cx.attr_word(sym::macro_use, span)],
ast::AttrVec::new(),
ast::ItemKind::ExternCrate(None, Ident::new(name, ident_span)),
);

View file

@ -1,12 +1,12 @@
//! The expansion from a test function to the appropriate test struct for libtest
//! Ideally, this code would be in libtest but for efficiency and error messages it lives here.
use std::assert_matches::assert_matches;
use std::iter;
use rustc_ast::{self as ast, GenericParamKind, HasNodeId, attr, join_path_idents};
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::AttributeParser;
use rustc_data_structures::assert_matches;
use rustc_errors::{Applicability, Diag, Level};
use rustc_expand::base::*;
use rustc_hir::Attribute;

View file

@ -78,8 +78,6 @@ type UnexpectedExprKind<'a> = Result<(Diag<'a>, bool /* has_suggestions */), Err
/// The returned bool indicates whether an applicable suggestion has already been
/// added to the diagnostic to avoid emitting multiple suggestions. `Err(Err(ErrorGuaranteed))`
/// indicates that an ast error was encountered.
// FIXME(Nilstrieb) Make this function setup translatable
#[allow(rustc::untranslatable_diagnostic)]
pub(crate) fn expr_to_spanned_string<'a>(
cx: &'a mut ExtCtxt<'_>,
expr: Box<ast::Expr>,

View file

@ -744,43 +744,43 @@ unsafe extern "C" {
pub struct VaList<'a>(&'a mut VaListImpl);
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro stringify($($t:tt)*) {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro file() {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro line() {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro cfg() {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro asm() {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro global_asm() {
/* compiler built-in */
}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
#[rustc_macro_transparency = "semiopaque"]
pub macro naked_asm() {
/* compiler built-in */
}

View file

@ -14,11 +14,10 @@ diff --git a/coretests/tests/lib.rs b/coretests/tests/lib.rs
index 1e336bf..35e6f54 100644
--- a/coretests/tests/lib.rs
+++ b/coretests/tests/lib.rs
@@ -2,5 +2,4 @@
@@ -2,4 +2,3 @@
// tidy-alphabetical-start
-#![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
#![cfg_attr(test, feature(cfg_select))]
#![feature(alloc_layout_extra)]
#![feature(array_ptr_get)]
diff --git a/coretests/tests/atomic.rs b/coretests/tests/atomic.rs
index b735957..ea728b6 100644

View file

@ -56,6 +56,9 @@ pub(crate) fn conv_to_call_conv(
CanonAbi::Rust | CanonAbi::C => default_call_conv,
CanonAbi::RustCold => CallConv::Cold,
// Cranelift doesn't currently have anything for this.
CanonAbi::RustPreserveNone => default_call_conv,
// Functions with this calling convention can only be called from assembly, but it is
// possible to declare an `extern "custom"` block, so the backend still needs a calling
// convention for declaring foreign functions.

Some files were not shown because too many files have changed in this diff Show more