Rollup merge of #139450 - NobodyXu:new-api/make-fifo, r=tgross35
Impl new API `std::os::unix::fs::mkfifo` under feature `unix_fifo`
Tracking issue #139324
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index d2a017b..af071c7 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -31,3 +31,5 @@
c682aa162b0d41e21cc6748f4fecfe01efb69d1f
# reformat with updated edition 2024
1fcae03369abb4c2cc180cd5a49e1f4440a81300
+# Breaking up of compiletest runtest.rs
+60600a6fa403216bfd66e04f948b1822f6450af7
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 51dd0f8..efe4157 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -53,6 +53,13 @@
steps:
- name: Checkout the source code
uses: actions/checkout@v4
+ # Cache citool to make its build faster, as it's in the critical path.
+ # The rust-cache doesn't bleed into the main `job`, so it should not affect any other
+ # Rust compilation.
+ - name: Cache citool
+ uses: Swatinem/rust-cache@9d47c6ad4b02e050fd481d890b2ea34778fd09d6 # v2.7.8
+ with:
+ workspaces: src/ci/citool
- name: Calculate the CI job matrix
env:
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
@@ -118,9 +125,6 @@
# which then uses log commands to actually set them.
EXTRA_VARIABLES: ${{ toJson(matrix.env) }}
- - name: setup upstream remote
- run: src/ci/scripts/setup-upstream-remote.sh
-
- name: ensure the channel matches the target branch
run: src/ci/scripts/verify-channel.sh
diff --git a/.mailmap b/.mailmap
index b09aebd..c3ce111 100644
--- a/.mailmap
+++ b/.mailmap
@@ -292,6 +292,7 @@
James Miller <bladeon@gmail.com> <james@aatch.net>
James Perry <james.austin.perry@gmail.com>
James Sanderson <zofrex@gmail.com>
+Jamie Hill-Daniel <jamie@hill-daniel.co.uk> <clubby789@gmail.com>
Jana Dönszelmann <jana@donsz.nl>
Jana Dönszelmann <jana@donsz.nl> <jonathan@donsz.nl>
Jana Dönszelmann <jana@donsz.nl> <jonabent@gmail.com>
diff --git a/Cargo.lock b/Cargo.lock
index 41288c5..e867e02 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -225,7 +225,7 @@
"memchr",
"serde",
"serde_derive",
- "winnow 0.7.4",
+ "winnow 0.7.6",
]
[[package]]
@@ -303,9 +303,9 @@
[[package]]
name = "bstr"
-version = "1.11.3"
+version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
+checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
dependencies = [
"memchr",
"regex-automata 0.4.9",
@@ -496,9 +496,9 @@
[[package]]
name = "clap"
-version = "4.5.35"
+version = "4.5.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
+checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
dependencies = [
"clap_builder",
"clap_derive",
@@ -516,9 +516,9 @@
[[package]]
name = "clap_builder"
-version = "4.5.35"
+version = "4.5.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
+checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
dependencies = [
"anstream",
"anstyle",
@@ -546,12 +546,14 @@
[[package]]
name = "clippy"
-version = "0.1.87"
+version = "0.1.88"
dependencies = [
"anstream",
+ "askama",
"cargo_metadata 0.18.1",
"clippy_config",
"clippy_lints",
+ "clippy_lints_internal",
"clippy_utils",
"color-print",
"filetime",
@@ -562,7 +564,6 @@
"pulldown-cmark 0.11.3",
"quote",
"regex",
- "rinja",
"rustc_tools_util 0.4.2",
"serde",
"serde_json",
@@ -577,7 +578,7 @@
[[package]]
name = "clippy_config"
-version = "0.1.87"
+version = "0.1.88"
dependencies = [
"clippy_utils",
"itertools",
@@ -602,7 +603,7 @@
[[package]]
name = "clippy_lints"
-version = "0.1.87"
+version = "0.1.88"
dependencies = [
"arrayvec",
"cargo_metadata 0.18.1",
@@ -610,12 +611,9 @@
"clippy_utils",
"itertools",
"quine-mc_cluskey",
- "regex",
"regex-syntax 0.8.5",
"semver",
"serde",
- "serde_json",
- "tempfile",
"toml 0.7.8",
"unicode-normalization",
"unicode-script",
@@ -624,8 +622,18 @@
]
[[package]]
+name = "clippy_lints_internal"
+version = "0.0.1"
+dependencies = [
+ "clippy_config",
+ "clippy_utils",
+ "regex",
+ "rustc-semver",
+]
+
+[[package]]
name = "clippy_utils"
-version = "0.1.87"
+version = "0.1.88"
dependencies = [
"arrayvec",
"itertools",
@@ -719,6 +727,7 @@
dependencies = [
"anstyle-svg",
"build_helper",
+ "camino",
"colored",
"diff",
"getopts",
@@ -797,9 +806,9 @@
[[package]]
name = "crossbeam-channel"
-version = "0.5.14"
+version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
+checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
dependencies = [
"crossbeam-utils",
]
@@ -932,15 +941,6 @@
]
[[package]]
-name = "deranged"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e"
-dependencies = [
- "powerfmt",
-]
-
-[[package]]
name = "derive-where"
version = "1.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1221,7 +1221,7 @@
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
dependencies = [
"crc32fast",
- "miniz_oxide 0.8.7",
+ "miniz_oxide 0.8.8",
]
[[package]]
@@ -1918,9 +1918,9 @@
[[package]]
name = "jiff"
-version = "0.2.5"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c102670231191d07d37a35af3eb77f1f0dbf7a71be51a962dcd57ea607be7260"
+checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488"
dependencies = [
"jiff-static",
"log",
@@ -1931,9 +1931,9 @@
[[package]]
name = "jiff-static"
-version = "0.2.5"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cdde31a9d349f1b1f51a0b3714a5940ac022976f4b49485fc04be052b183b4c"
+checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19"
dependencies = [
"proc-macro2",
"quote",
@@ -1987,9 +1987,9 @@
[[package]]
name = "jsonpath-rust"
-version = "1.0.0"
+version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b0231bb404a6cd6c8f0ab41b907049063a089fc02aa7636cc5cd9a4d87364c9"
+checksum = "6a37c2c87b8d16e788ce359660fead0ea5f4ed29ff400d55be74a4e01d1817d9"
dependencies = [
"pest",
"pest_derive",
@@ -2030,9 +2030,9 @@
[[package]]
name = "libc"
-version = "0.2.171"
+version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
+checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "libdbus-sys"
@@ -2046,9 +2046,9 @@
[[package]]
name = "libffi"
-version = "3.2.0"
+version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce826c243048e3d5cec441799724de52e2d42f820468431fc3fceee2341871e2"
+checksum = "4a9434b6fc77375fb624698d5f8c49d7e80b10d59eb1219afda27d1f824d4074"
dependencies = [
"libc",
"libffi-sys",
@@ -2056,9 +2056,9 @@
[[package]]
name = "libffi-sys"
-version = "2.3.0"
+version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f36115160c57e8529781b4183c2bb51fdc1f6d6d1ed345591d84be7703befb3c"
+checksum = "ead36a2496acfc8edd6cc32352110e9478ac5b9b5f5b9856ebd3d28019addb84"
dependencies = [
"cc",
]
@@ -2121,9 +2121,9 @@
[[package]]
name = "linux-raw-sys"
-version = "0.9.3"
+version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
+checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
name = "litemap"
@@ -2253,22 +2253,6 @@
]
[[package]]
-name = "mime"
-version = "0.3.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
-
-[[package]]
-name = "mime_guess"
-version = "2.0.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
-dependencies = [
- "mime",
- "unicase",
-]
-
-[[package]]
name = "minifier"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2291,9 +2275,9 @@
[[package]]
name = "miniz_oxide"
-version = "0.8.7"
+version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
+checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [
"adler2",
]
@@ -2426,12 +2410,6 @@
]
[[package]]
-name = "num-conv"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
-
-[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2587,16 +2565,6 @@
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
-name = "os_pipe"
-version = "1.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982"
-dependencies = [
- "libc",
- "windows-sys 0.59.0",
-]
-
-[[package]]
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2809,12 +2777,6 @@
]
[[package]]
-name = "powerfmt"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
-
-[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3115,45 +3077,6 @@
]
[[package]]
-name = "rinja"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dc4940d00595430b3d7d5a01f6222b5e5b51395d1120bdb28d854bb8abb17a5"
-dependencies = [
- "itoa",
- "rinja_derive",
-]
-
-[[package]]
-name = "rinja_derive"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08d9ed0146aef6e2825f1b1515f074510549efba38d71f4554eec32eb36ba18b"
-dependencies = [
- "basic-toml",
- "memchr",
- "mime",
- "mime_guess",
- "proc-macro2",
- "quote",
- "rinja_parser",
- "rustc-hash 2.1.1",
- "serde",
- "syn 2.0.100",
-]
-
-[[package]]
-name = "rinja_parser"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93f9a866e2e00a7a1fb27e46e9e324a6f7c0e7edc4543cae1d38f4e4a100c610"
-dependencies = [
- "memchr",
- "nom",
- "serde",
-]
-
-[[package]]
name = "run_make_support"
version = "0.2.0"
dependencies = [
@@ -3162,7 +3085,6 @@
"gimli 0.31.1",
"libc",
"object 0.36.7",
- "os_pipe",
"regex",
"serde_json",
"similar",
@@ -3219,17 +3141,21 @@
[[package]]
name = "rustc-rayon-core"
-version = "0.5.0"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67668daaf00e359c126f6dcb40d652d89b458a008c8afa727a42a2d20fca0b7f"
+checksum = "2f42932dcd3bcbe484b38a3ccf79b7906fac41c02d408b5b1bac26da3416efdb"
dependencies = [
- "crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
- "num_cpus",
]
[[package]]
+name = "rustc-semver"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5be1bdc7edf596692617627bbfeaba522131b18e06ca4df2b6b689e3c5d5ce84"
+
+[[package]]
name = "rustc-stable-hash"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3616,6 +3542,7 @@
version = "0.0.0"
dependencies = [
"ctrlc",
+ "jiff",
"libc",
"rustc_abi",
"rustc_ast",
@@ -3662,7 +3589,6 @@
"rustc_ty_utils",
"serde_json",
"shlex",
- "time",
"tracing",
"windows 0.59.0",
]
@@ -4692,6 +4618,7 @@
version = "0.1.0"
dependencies = [
"build_helper",
+ "camino",
"compiletest",
"getopts",
"walkdir",
@@ -4839,14 +4766,14 @@
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d"
dependencies = [
- "self_cell 1.1.0",
+ "self_cell 1.2.0",
]
[[package]]
name = "self_cell"
-version = "1.1.0"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe"
+checksum = "0f7d95a54511e0c7be3f51e8867aa8cf35148d7b9445d44de2f943e2b206e749"
[[package]]
name = "semver"
@@ -5357,37 +5284,6 @@
]
[[package]]
-name = "time"
-version = "0.3.41"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40"
-dependencies = [
- "deranged",
- "itoa",
- "num-conv",
- "powerfmt",
- "serde",
- "time-core",
- "time-macros",
-]
-
-[[package]]
-name = "time-core"
-version = "0.1.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c"
-
-[[package]]
-name = "time-macros"
-version = "0.2.22"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49"
-dependencies = [
- "num-conv",
- "time-core",
-]
-
-[[package]]
name = "tinystr"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6111,11 +6007,13 @@
[[package]]
name = "windows-bindgen"
-version = "0.59.0"
+version = "0.61.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b7fb600834d7e868f6e5bb748a86101427330fafbf9485c331b9d5f562d54a5"
+checksum = "ac1c59c20569610dd9ed784d5f003fb493ec57b4cf39d974eb03a84bb7156c90"
dependencies = [
"rayon",
+ "serde",
+ "serde_json",
]
[[package]]
@@ -6476,9 +6374,9 @@
[[package]]
name = "winnow"
-version = "0.7.4"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
+checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
dependencies = [
"memchr",
]
diff --git a/bootstrap.example.toml b/bootstrap.example.toml
index 0927f64..72c4492 100644
--- a/bootstrap.example.toml
+++ b/bootstrap.example.toml
@@ -19,6 +19,14 @@
# Note that this has no default value (x.py uses the defaults in `bootstrap.example.toml`).
#profile = <none>
+# Inherits configuration values from different configuration files (a.k.a. config extensions).
+# Supports absolute paths, and uses the current directory (where the bootstrap was invoked)
+# as the base if the given path is not absolute.
+#
+# The overriding logic follows a right-to-left order. For example, in `include = ["a.toml", "b.toml"]`,
+# extension `b.toml` overrides `a.toml`. Also, parent extensions always overrides the inner ones.
+#include = []
+
# Keeps track of major changes made to this configuration.
#
# This value also represents ID of the PR that caused major changes. Meaning,
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index 7bffeaf..42250aa 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -315,7 +315,7 @@ pub fn layout_of_struct_or_enum<
repr: &ReprOptions,
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
is_enum: bool,
- is_unsafe_cell: bool,
+ is_special_no_niche: bool,
scalar_valid_range: (Bound<u128>, Bound<u128>),
discr_range_of_repr: impl Fn(i128, i128) -> (Integer, bool),
discriminants: impl Iterator<Item = (VariantIdx, i128)>,
@@ -348,7 +348,7 @@ pub fn layout_of_struct_or_enum<
repr,
variants,
is_enum,
- is_unsafe_cell,
+ is_special_no_niche,
scalar_valid_range,
always_sized,
present_first,
@@ -505,7 +505,7 @@ fn layout_of_struct<
repr: &ReprOptions,
variants: &IndexSlice<VariantIdx, IndexVec<FieldIdx, F>>,
is_enum: bool,
- is_unsafe_cell: bool,
+ is_special_no_niche: bool,
scalar_valid_range: (Bound<u128>, Bound<u128>),
always_sized: bool,
present_first: VariantIdx,
@@ -524,7 +524,7 @@ fn layout_of_struct<
let mut st = self.univariant(&variants[v], repr, kind)?;
st.variants = Variants::Single { index: v };
- if is_unsafe_cell {
+ if is_special_no_niche {
let hide_niches = |scalar: &mut _| match scalar {
Scalar::Initialized { value, valid_range } => {
*valid_range = WrappingRange::full(value.size(dl))
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 3fb88c9..1532ca7 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -120,6 +120,17 @@ pub fn from_ident(ident: Ident) -> Path {
Path { segments: thin_vec![PathSegment::from_ident(ident)], span: ident.span, tokens: None }
}
+ pub fn is_ident(&self, name: Symbol) -> bool {
+ if let [segment] = self.segments.as_ref()
+ && segment.args.is_none()
+ && segment.ident.name == name
+ {
+ true
+ } else {
+ false
+ }
+ }
+
pub fn is_global(&self) -> bool {
self.segments.first().is_some_and(|segment| segment.ident.name == kw::PathRoot)
}
diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs
index c9e2e99..7f98e7b 100644
--- a/compiler/rustc_ast/src/ast_traits.rs
+++ b/compiler/rustc_ast/src/ast_traits.rs
@@ -6,7 +6,6 @@
use std::marker::PhantomData;
use crate::ptr::P;
-use crate::token::Nonterminal;
use crate::tokenstream::LazyAttrTokenStream;
use crate::{
Arm, AssocItem, AttrItem, AttrKind, AttrVec, Attribute, Block, Crate, Expr, ExprField,
@@ -206,19 +205,6 @@ fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
}
}
-impl HasTokens for Nonterminal {
- fn tokens(&self) -> Option<&LazyAttrTokenStream> {
- match self {
- Nonterminal::NtBlock(block) => block.tokens(),
- }
- }
- fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
- match self {
- Nonterminal::NtBlock(block) => block.tokens_mut(),
- }
- }
-}
-
/// A trait for AST nodes having (or not having) attributes.
pub trait HasAttrs {
/// This is `true` if this `HasAttrs` might support 'custom' (proc-macro) inner
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 0b65246..f165c4d 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -305,8 +305,8 @@ pub fn ident(&self) -> Option<Ident> {
if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None }
}
- pub fn name_or_empty(&self) -> Symbol {
- self.ident().unwrap_or_else(Ident::empty).name
+ pub fn name(&self) -> Option<Symbol> {
+ self.ident().map(|ident| ident.name)
}
pub fn has_name(&self, name: Symbol) -> bool {
@@ -416,10 +416,7 @@ fn from_tokens(iter: &mut TokenStreamIter<'_>) -> Option<MetaItem> {
// This path is currently unreachable in the test suite.
unreachable!()
}
- Some(TokenTree::Token(
- Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. },
- _,
- )) => {
+ Some(TokenTree::Token(Token { kind, .. }, _)) if kind.is_delim() => {
panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tt);
}
_ => return None,
@@ -511,13 +508,14 @@ pub fn span(&self) -> Span {
}
}
- /// For a single-segment meta item, returns its name; otherwise, returns `None`.
+ /// For a single-segment meta item, returns its identifier; otherwise, returns `None`.
pub fn ident(&self) -> Option<Ident> {
self.meta_item().and_then(|meta_item| meta_item.ident())
}
- pub fn name_or_empty(&self) -> Symbol {
- self.ident().unwrap_or_else(Ident::empty).name
+ /// For a single-segment meta item, returns its name; otherwise, returns `None`.
+ pub fn name(&self) -> Option<Symbol> {
+ self.ident().map(|ident| ident.name)
}
/// Returns `true` if this list item is a MetaItem with a name of `name`.
@@ -627,7 +625,7 @@ pub fn mk_doc_comment(
Attribute { kind: AttrKind::DocComment(comment_kind, data), id: g.mk_attr_id(), style, span }
}
-pub fn mk_attr(
+fn mk_attr(
g: &AttrIdGenerator,
style: AttrStyle,
unsafety: Safety,
@@ -738,9 +736,9 @@ pub trait AttributeExt: Debug {
fn id(&self) -> AttrId;
/// For a single-segment attribute (i.e., `#[attr]` and not `#[path::atrr]`),
- /// return the name of the attribute, else return the empty identifier.
- fn name_or_empty(&self) -> Symbol {
- self.ident().unwrap_or_else(Ident::empty).name
+ /// return the name of the attribute; otherwise, returns `None`.
+ fn name(&self) -> Option<Symbol> {
+ self.ident().map(|ident| ident.name)
}
/// Get the meta item list, `#[attr(meta item list)]`
@@ -752,7 +750,7 @@ fn name_or_empty(&self) -> Symbol {
/// 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 name; otherwise, returns `None`.
+ /// 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.
@@ -770,6 +768,11 @@ fn has_name(&self, name: Symbol) -> bool {
self.ident().map(|x| x.name == name).unwrap_or(false)
}
+ #[inline]
+ fn has_any_name(&self, names: &[Symbol]) -> bool {
+ names.iter().any(|&name| self.has_name(name))
+ }
+
/// get the span of the entire attribute
fn span(&self) -> Span;
@@ -813,8 +816,8 @@ pub fn id(&self) -> AttrId {
AttributeExt::id(self)
}
- pub fn name_or_empty(&self) -> Symbol {
- AttributeExt::name_or_empty(self)
+ pub fn name(&self) -> Option<Symbol> {
+ AttributeExt::name(self)
}
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
@@ -846,6 +849,11 @@ pub fn has_name(&self, name: Symbol) -> bool {
AttributeExt::has_name(self, name)
}
+ #[inline]
+ pub fn has_any_name(&self, names: &[Symbol]) -> bool {
+ AttributeExt::has_any_name(self, names)
+ }
+
pub fn span(&self) -> Span {
AttributeExt::span(self)
}
diff --git a/compiler/rustc_ast/src/expand/autodiff_attrs.rs b/compiler/rustc_ast/src/expand/autodiff_attrs.rs
index 13a7c5a..2f918fa 100644
--- a/compiler/rustc_ast/src/expand/autodiff_attrs.rs
+++ b/compiler/rustc_ast/src/expand/autodiff_attrs.rs
@@ -50,8 +50,16 @@ pub enum DiffActivity {
/// with it.
Dual,
/// Forward Mode, Compute derivatives for this input/output and *overwrite* the shadow argument
+ /// with it. It expects the shadow argument to be `width` times larger than the original
+ /// input/output.
+ Dualv,
+ /// Forward Mode, Compute derivatives for this input/output and *overwrite* the shadow argument
/// with it. Drop the code which updates the original input/output for maximum performance.
DualOnly,
+ /// Forward Mode, Compute derivatives for this input/output and *overwrite* the shadow argument
+ /// with it. Drop the code which updates the original input/output for maximum performance.
+ /// It expects the shadow argument to be `width` times larger than the original input/output.
+ DualvOnly,
/// Reverse Mode, Compute derivatives for this &T or *T input and *add* it to the shadow argument.
Duplicated,
/// Reverse Mode, Compute derivatives for this &T or *T input and *add* it to the shadow argument.
@@ -59,7 +67,15 @@ pub enum DiffActivity {
DuplicatedOnly,
/// All Integers must be Const, but these are used to mark the integer which represents the
/// length of a slice/vec. This is used for safety checks on slices.
- FakeActivitySize,
+ /// The integer (if given) specifies the size of the slice element in bytes.
+ FakeActivitySize(Option<u32>),
+}
+
+impl DiffActivity {
+ pub fn is_dual_or_const(&self) -> bool {
+ use DiffActivity::*;
+ matches!(self, |Dual| DualOnly | Dualv | DualvOnly | Const)
+ }
}
/// We generate one of these structs for each `#[autodiff(...)]` attribute.
#[derive(Clone, Eq, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
@@ -131,11 +147,7 @@ pub fn valid_ret_activity(mode: DiffMode, activity: DiffActivity) -> bool {
match mode {
DiffMode::Error => false,
DiffMode::Source => false,
- DiffMode::Forward => {
- activity == DiffActivity::Dual
- || activity == DiffActivity::DualOnly
- || activity == DiffActivity::Const
- }
+ DiffMode::Forward => activity.is_dual_or_const(),
DiffMode::Reverse => {
activity == DiffActivity::Const
|| activity == DiffActivity::Active
@@ -153,10 +165,8 @@ pub fn valid_ret_activity(mode: DiffMode, activity: DiffActivity) -> bool {
pub fn valid_ty_for_activity(ty: &P<Ty>, activity: DiffActivity) -> bool {
use DiffActivity::*;
// It's always allowed to mark something as Const, since we won't compute derivatives wrt. it.
- if matches!(activity, Const) {
- return true;
- }
- if matches!(activity, Dual | DualOnly) {
+ // Dual variants also support all types.
+ if activity.is_dual_or_const() {
return true;
}
// FIXME(ZuseZ4) We should make this more robust to also
@@ -172,9 +182,7 @@ pub fn valid_input_activity(mode: DiffMode, activity: DiffActivity) -> bool {
return match mode {
DiffMode::Error => false,
DiffMode::Source => false,
- DiffMode::Forward => {
- matches!(activity, Dual | DualOnly | Const)
- }
+ DiffMode::Forward => activity.is_dual_or_const(),
DiffMode::Reverse => {
matches!(activity, Active | ActiveOnly | Duplicated | DuplicatedOnly | Const)
}
@@ -189,10 +197,12 @@ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
DiffActivity::Active => write!(f, "Active"),
DiffActivity::ActiveOnly => write!(f, "ActiveOnly"),
DiffActivity::Dual => write!(f, "Dual"),
+ DiffActivity::Dualv => write!(f, "Dualv"),
DiffActivity::DualOnly => write!(f, "DualOnly"),
+ DiffActivity::DualvOnly => write!(f, "DualvOnly"),
DiffActivity::Duplicated => write!(f, "Duplicated"),
DiffActivity::DuplicatedOnly => write!(f, "DuplicatedOnly"),
- DiffActivity::FakeActivitySize => write!(f, "FakeActivitySize"),
+ DiffActivity::FakeActivitySize(s) => write!(f, "FakeActivitySize({:?})", s),
}
}
}
@@ -220,7 +230,9 @@ fn from_str(s: &str) -> Result<DiffActivity, ()> {
"ActiveOnly" => Ok(DiffActivity::ActiveOnly),
"Const" => Ok(DiffActivity::Const),
"Dual" => Ok(DiffActivity::Dual),
+ "Dualv" => Ok(DiffActivity::Dualv),
"DualOnly" => Ok(DiffActivity::DualOnly),
+ "DualvOnly" => Ok(DiffActivity::DualvOnly),
"Duplicated" => Ok(DiffActivity::Duplicated),
"DuplicatedOnly" => Ok(DiffActivity::DuplicatedOnly),
_ => Err(()),
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index da510e4..294c6c9 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -6,7 +6,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
test(attr(deny(warnings)))
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index b083e87..6aae2e4 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -844,9 +844,9 @@ fn visit_lazy_tts<T: MutVisitor>(vis: &mut T, lazy_tts: &mut Option<LazyAttrToke
visit_lazy_tts_opt_mut(vis, lazy_tts.as_mut());
}
-/// Applies ident visitor if it's an ident; applies other visits to interpolated nodes.
-/// In practice the ident part is not actually used by specific visitors right now,
-/// but there's a test below checking that it works.
+/// Applies ident visitor if it's an ident. In practice this is not actually
+/// used by specific visitors right now, but there's a test below checking that
+/// it works.
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
pub fn visit_token<T: MutVisitor>(vis: &mut T, t: &mut Token) {
let Token { kind, span } = t;
@@ -864,46 +864,12 @@ pub fn visit_token<T: MutVisitor>(vis: &mut T, t: &mut Token) {
token::NtLifetime(ident, _is_raw) => {
vis.visit_ident(ident);
}
- token::Interpolated(nt) => {
- let nt = Arc::make_mut(nt);
- visit_nonterminal(vis, nt);
- }
_ => {}
}
vis.visit_span(span);
}
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-/// Applies the visitor to elements of interpolated nodes.
-//
-// N.B., this can occur only when applying a visitor to partially expanded
-// code, where parsed pieces have gotten implanted ito *other* macro
-// invocations. This is relevant for macro hygiene, but possibly not elsewhere.
-//
-// One problem here occurs because the types for flat_map_item, flat_map_stmt,
-// etc., allow the visitor to return *multiple* items; this is a problem for the
-// nodes here, because they insist on having exactly one piece. One solution
-// would be to mangle the MutVisitor trait to include one-to-many and
-// one-to-one versions of these entry points, but that would probably confuse a
-// lot of people and help very few. Instead, I'm just going to put in dynamic
-// checks. I think the performance impact of this will be pretty much
-// nonexistent. The danger is that someone will apply a `MutVisitor` to a
-// partially expanded node, and will be confused by the fact that their
-// `flat_map_item` or `flat_map_stmt` isn't getting called on `NtItem` or `NtStmt`
-// nodes. Hopefully they'll wind up reading this comment, and doing something
-// appropriate.
-//
-// BTW, design choice: I considered just changing the type of, e.g., `NtItem` to
-// contain multiple items, but decided against it when I looked at
-// `parse_item_or_view_item` and tried to figure out what I would do with
-// multiple items there....
-fn visit_nonterminal<T: MutVisitor>(vis: &mut T, nt: &mut token::Nonterminal) {
- match nt {
- token::NtBlock(block) => vis.visit_block(block),
- }
-}
-
-// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
fn visit_defaultness<T: MutVisitor>(vis: &mut T, defaultness: &mut Defaultness) {
match defaultness {
Defaultness::Default(span) => vis.visit_span(span),
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index d57a369..54781e8 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -1,13 +1,10 @@
use std::borrow::Cow;
use std::fmt;
-use std::sync::Arc;
pub use LitKind::*;
-pub use Nonterminal::*;
pub use NtExprKind::*;
pub use NtPatKind::*;
pub use TokenKind::*;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
use rustc_span::edition::Edition;
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, kw, sym};
@@ -16,7 +13,6 @@
use rustc_span::{Ident, Symbol};
use crate::ast;
-use crate::ptr::P;
use crate::util::case::Case;
#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
@@ -34,10 +30,18 @@ pub enum InvisibleOrigin {
// Converted from `proc_macro::Delimiter` in
// `proc_macro::Delimiter::to_internal`, i.e. returned by a proc macro.
ProcMacro,
+}
- // Converted from `TokenKind::Interpolated` in
- // `TokenStream::flatten_token`. Treated similarly to `ProcMacro`.
- FlattenToken,
+impl InvisibleOrigin {
+ // Should the parser skip these invisible delimiters? Ideally this function
+ // will eventually disappear and no invisible delimiters will be skipped.
+ #[inline]
+ pub fn skip(&self) -> bool {
+ match self {
+ InvisibleOrigin::MetaVar(_) => false,
+ InvisibleOrigin::ProcMacro => true,
+ }
+ }
}
impl PartialEq for InvisibleOrigin {
@@ -133,10 +137,7 @@ impl Delimiter {
pub fn skip(&self) -> bool {
match self {
Delimiter::Parenthesis | Delimiter::Bracket | Delimiter::Brace => false,
- Delimiter::Invisible(InvisibleOrigin::MetaVar(_)) => false,
- Delimiter::Invisible(InvisibleOrigin::FlattenToken | InvisibleOrigin::ProcMacro) => {
- true
- }
+ Delimiter::Invisible(origin) => origin.skip(),
}
}
@@ -150,6 +151,24 @@ pub fn eq_ignoring_invisible_origin(&self, other: &Delimiter) -> bool {
_ => false,
}
}
+
+ pub fn as_open_token_kind(&self) -> TokenKind {
+ match *self {
+ Delimiter::Parenthesis => OpenParen,
+ Delimiter::Brace => OpenBrace,
+ Delimiter::Bracket => OpenBracket,
+ Delimiter::Invisible(origin) => OpenInvisible(origin),
+ }
+ }
+
+ pub fn as_close_token_kind(&self) -> TokenKind {
+ match *self {
+ Delimiter::Parenthesis => CloseParen,
+ Delimiter::Brace => CloseBrace,
+ Delimiter::Bracket => CloseBracket,
+ Delimiter::Invisible(origin) => CloseInvisible(origin),
+ }
+ }
}
// Note that the suffix is *not* considered when deciding the `LitKind` in this
@@ -204,9 +223,9 @@ pub fn from_token(token: &Token) -> Option<Lit> {
match token.uninterpolate().kind {
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
Literal(token_lit) => Some(token_lit),
- OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
+ OpenInvisible(InvisibleOrigin::MetaVar(
MetaVarKind::Literal | MetaVarKind::Expr { .. },
- ))) => {
+ )) => {
// Unreachable with the current test suite.
panic!("from_token metavar");
}
@@ -337,9 +356,7 @@ fn from(is_raw: IdentIsRaw) -> bool {
}
}
-// SAFETY: due to the `Clone` impl below, all fields of all variants other than
-// `Interpolated` must impl `Copy`.
-#[derive(PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
+#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
pub enum TokenKind {
/* Expression-operator symbols. */
/// `=`
@@ -438,10 +455,22 @@ pub enum TokenKind {
Question,
/// Used by proc macros for representing lifetimes, not generated by lexer right now.
SingleQuote,
- /// An opening delimiter (e.g., `{`).
- OpenDelim(Delimiter),
- /// A closing delimiter (e.g., `}`).
- CloseDelim(Delimiter),
+ /// `(`
+ OpenParen,
+ /// `)`
+ CloseParen,
+ /// `{`
+ OpenBrace,
+ /// `}`
+ CloseBrace,
+ /// `[`
+ OpenBracket,
+ /// `]`
+ CloseBracket,
+ /// Invisible opening delimiter, produced by a macro.
+ OpenInvisible(InvisibleOrigin),
+ /// Invisible closing delimiter, produced by a macro.
+ CloseInvisible(InvisibleOrigin),
/* Literals */
Literal(Lit),
@@ -468,21 +497,6 @@ pub enum TokenKind {
/// the `lifetime` metavariable in the macro's RHS.
NtLifetime(Ident, IdentIsRaw),
- /// An embedded AST node, as produced by a macro. This only exists for
- /// historical reasons. We'd like to get rid of it, for multiple reasons.
- /// - It's conceptually very strange. Saying a token can contain an AST
- /// node is like saying, in natural language, that a word can contain a
- /// sentence.
- /// - It requires special handling in a bunch of places in the parser.
- /// - It prevents `Token` from implementing `Copy`.
- /// It adds complexity and likely slows things down. Please don't add new
- /// occurrences of this token kind!
- ///
- /// The span in the surrounding `Token` is that of the metavariable in the
- /// macro's RHS. The span within the Nonterminal is that of the fragment
- /// passed to the macro at the call site.
- Interpolated(Arc<Nonterminal>),
-
/// A doc comment token.
/// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
/// similarly to symbols in string literal tokens.
@@ -492,20 +506,7 @@ pub enum TokenKind {
Eof,
}
-impl Clone for TokenKind {
- fn clone(&self) -> Self {
- // `TokenKind` would impl `Copy` if it weren't for `Interpolated`. So
- // for all other variants, this implementation of `clone` is just like
- // a copy. This is faster than the `derive(Clone)` version which has a
- // separate path for every variant.
- match self {
- Interpolated(nt) => Interpolated(Arc::clone(nt)),
- _ => unsafe { std::ptr::read(self) },
- }
- }
-}
-
-#[derive(Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
+#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct Token {
pub kind: TokenKind,
pub span: Span,
@@ -570,6 +571,37 @@ pub fn similar_tokens(&self) -> &[TokenKind] {
pub fn should_end_const_arg(&self) -> bool {
matches!(self, Gt | Ge | Shr | ShrEq)
}
+
+ pub fn is_delim(&self) -> bool {
+ self.open_delim().is_some() || self.close_delim().is_some()
+ }
+
+ pub fn open_delim(&self) -> Option<Delimiter> {
+ match *self {
+ OpenParen => Some(Delimiter::Parenthesis),
+ OpenBrace => Some(Delimiter::Brace),
+ OpenBracket => Some(Delimiter::Bracket),
+ OpenInvisible(origin) => Some(Delimiter::Invisible(origin)),
+ _ => None,
+ }
+ }
+
+ pub fn close_delim(&self) -> Option<Delimiter> {
+ match *self {
+ CloseParen => Some(Delimiter::Parenthesis),
+ CloseBrace => Some(Delimiter::Brace),
+ CloseBracket => Some(Delimiter::Bracket),
+ CloseInvisible(origin) => Some(Delimiter::Invisible(origin)),
+ _ => None,
+ }
+ }
+
+ pub fn is_close_delim_or_eof(&self) -> bool {
+ match self {
+ CloseParen | CloseBrace | CloseBracket | CloseInvisible(_) | Eof => true,
+ _ => false,
+ }
+ }
}
impl Token {
@@ -599,8 +631,9 @@ pub fn is_punct(&self) -> bool {
| DotDotDot | DotDotEq | Comma | Semi | Colon | PathSep | RArrow | LArrow
| FatArrow | Pound | Dollar | Question | SingleQuote => true,
- OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
- | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Interpolated(..) | Eof => false,
+ OpenParen | CloseParen | OpenBrace | CloseBrace | OpenBracket | CloseBracket
+ | OpenInvisible(_) | CloseInvisible(_) | Literal(..) | DocComment(..) | Ident(..)
+ | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Eof => false,
}
}
@@ -613,11 +646,12 @@ pub fn is_like_plus(&self) -> bool {
/// **NB**: Take care when modifying this function, since it will change
/// the stable set of tokens that are allowed to match an expr nonterminal.
pub fn can_begin_expr(&self) -> bool {
- use Delimiter::*;
match self.uninterpolate().kind {
Ident(name, is_raw) =>
ident_can_begin_expr(name, self.span, is_raw), // value name or keyword
- OpenDelim(Parenthesis | Brace | Bracket) | // tuple, array or block
+ OpenParen | // tuple
+ OpenBrace | // block
+ OpenBracket | // array
Literal(..) | // literal
Bang | // operator not
Minus | // unary minus
@@ -631,13 +665,12 @@ pub fn can_begin_expr(&self) -> bool {
PathSep | // global path
Lifetime(..) | // labeled loop
Pound => true, // expression attributes
- Interpolated(ref nt) => matches!(&**nt, NtBlock(..)),
- OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
+ OpenInvisible(InvisibleOrigin::MetaVar(
MetaVarKind::Block |
MetaVarKind::Expr { .. } |
MetaVarKind::Literal |
MetaVarKind::Path
- ))) => true,
+ )) => true,
_ => false,
}
}
@@ -649,8 +682,8 @@ pub fn can_begin_pattern(&self, pat_kind: NtPatKind) -> bool {
match &self.uninterpolate().kind {
// box, ref, mut, and other identifiers (can stricten)
Ident(..) | NtIdent(..) |
- OpenDelim(Delimiter::Parenthesis) | // tuple pattern
- OpenDelim(Delimiter::Bracket) | // slice pattern
+ OpenParen | // tuple pattern
+ OpenBracket | // slice pattern
And | // reference
Minus | // negative literal
AndAnd | // double reference
@@ -661,14 +694,14 @@ pub fn can_begin_pattern(&self, pat_kind: NtPatKind) -> bool {
Lt | // path (UFCS constant)
Shl => true, // path (double UFCS)
Or => matches!(pat_kind, PatWithOr), // leading vert `|` or-pattern
- OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
+ OpenInvisible(InvisibleOrigin::MetaVar(
MetaVarKind::Expr { .. } |
MetaVarKind::Literal |
MetaVarKind::Meta { .. } |
MetaVarKind::Pat(_) |
MetaVarKind::Path |
MetaVarKind::Ty { .. }
- ))) => true,
+ )) => true,
_ => false,
}
}
@@ -678,8 +711,8 @@ pub fn can_begin_type(&self) -> bool {
match self.uninterpolate().kind {
Ident(name, is_raw) =>
ident_can_begin_type(name, self.span, is_raw), // type name or keyword
- OpenDelim(Delimiter::Parenthesis) | // tuple
- OpenDelim(Delimiter::Bracket) | // array
+ OpenParen | // tuple
+ OpenBracket | // array
Bang | // never
Star | // raw pointer
And | // reference
@@ -688,10 +721,10 @@ pub fn can_begin_type(&self) -> bool {
Lifetime(..) | // lifetime bound in trait object
Lt | Shl | // associated path
PathSep => true, // global path
- OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
+ OpenInvisible(InvisibleOrigin::MetaVar(
MetaVarKind::Ty { .. } |
MetaVarKind::Path
- ))) => true,
+ )) => true,
// For anonymous structs or unions, which only appear in specific positions
// (type of struct fields or union fields), we don't consider them as regular types
_ => false,
@@ -701,12 +734,11 @@ pub fn can_begin_type(&self) -> bool {
/// Returns `true` if the token can appear at the start of a const param.
pub fn can_begin_const_arg(&self) -> bool {
match self.kind {
- OpenDelim(Delimiter::Brace) | Literal(..) | Minus => true,
+ OpenBrace | Literal(..) | Minus => true,
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
- Interpolated(ref nt) => matches!(&**nt, NtBlock(..)),
- OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
+ OpenInvisible(InvisibleOrigin::MetaVar(
MetaVarKind::Expr { .. } | MetaVarKind::Block | MetaVarKind::Literal,
- ))) => true,
+ )) => true,
_ => false,
}
}
@@ -753,7 +785,7 @@ pub fn can_begin_literal_maybe_minus(&self) -> bool {
match self.uninterpolate().kind {
Literal(..) | Minus => true,
Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
- OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
+ OpenInvisible(InvisibleOrigin::MetaVar(mv_kind)) => match mv_kind {
MetaVarKind::Literal => true,
MetaVarKind::Expr { can_begin_literal_maybe_minus, .. } => {
can_begin_literal_maybe_minus
@@ -767,7 +799,7 @@ pub fn can_begin_literal_maybe_minus(&self) -> bool {
pub fn can_begin_string_literal(&self) -> bool {
match self.uninterpolate().kind {
Literal(..) => true,
- OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind))) => match mv_kind {
+ OpenInvisible(InvisibleOrigin::MetaVar(mv_kind)) => match mv_kind {
MetaVarKind::Literal => true,
MetaVarKind::Expr { can_begin_string_literal, .. } => can_begin_string_literal,
_ => false,
@@ -831,31 +863,20 @@ pub fn is_ident_named(&self, name: Symbol) -> bool {
/// Is this a pre-parsed expression dropped into the token stream
/// (which happens while parsing the result of macro expansion)?
pub fn is_metavar_expr(&self) -> bool {
- #[allow(irrefutable_let_patterns)] // FIXME: temporary
- if let Interpolated(nt) = &self.kind
- && let NtBlock(_) = &**nt
- {
- true
- } else if matches!(
+ matches!(
self.is_metavar_seq(),
- Some(MetaVarKind::Expr { .. } | MetaVarKind::Literal | MetaVarKind::Path)
- ) {
- true
- } else {
- matches!(self.is_metavar_seq(), Some(MetaVarKind::Path))
- }
+ Some(
+ MetaVarKind::Expr { .. }
+ | MetaVarKind::Literal
+ | MetaVarKind::Path
+ | MetaVarKind::Block
+ )
+ )
}
- /// Is the token an interpolated block (`$b:block`)?
- pub fn is_whole_block(&self) -> bool {
- #[allow(irrefutable_let_patterns)] // FIXME: temporary
- if let Interpolated(nt) = &self.kind
- && let NtBlock(..) = &**nt
- {
- return true;
- }
-
- false
+ /// Are we at a block from a metavar (`$b:block`)?
+ pub fn is_metavar_block(&self) -> bool {
+ matches!(self.is_metavar_seq(), Some(MetaVarKind::Block))
}
/// Returns `true` if the token is either the `mut` or `const` keyword.
@@ -945,7 +966,7 @@ pub fn is_non_raw_ident_where(&self, pred: impl FnOnce(Ident) -> bool) -> bool {
/// from an expanded metavar?
pub fn is_metavar_seq(&self) -> Option<MetaVarKind> {
match self.kind {
- OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => Some(kind),
+ OpenInvisible(InvisibleOrigin::MetaVar(kind)) => Some(kind),
_ => None,
}
}
@@ -1023,8 +1044,9 @@ pub fn glue(&self, joint: &Token) -> Option<Token> {
Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | PlusEq | MinusEq | StarEq | SlashEq
| PercentEq | CaretEq | AndEq | OrEq | ShlEq | ShrEq | At | DotDotDot | DotDotEq
| Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question
- | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..)
- | Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof,
+ | OpenParen | CloseParen | OpenBrace | CloseBrace | OpenBracket | CloseBracket
+ | OpenInvisible(_) | CloseInvisible(_) | Literal(..) | Ident(..) | NtIdent(..)
+ | Lifetime(..) | NtLifetime(..) | DocComment(..) | Eof,
_,
) => {
return None;
@@ -1063,12 +1085,6 @@ pub enum NtExprKind {
Expr2021 { inferred: bool },
}
-#[derive(Clone, Encodable, Decodable)]
-/// For interpolation during macro expansion.
-pub enum Nonterminal {
- NtBlock(P<ast::Block>),
-}
-
#[derive(Debug, Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, HashStable_Generic)]
pub enum NonterminalKind {
Item,
@@ -1152,47 +1168,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
-impl Nonterminal {
- pub fn use_span(&self) -> Span {
- match self {
- NtBlock(block) => block.span,
- }
- }
-
- pub fn descr(&self) -> &'static str {
- match self {
- NtBlock(..) => "block",
- }
- }
-}
-
-impl PartialEq for Nonterminal {
- fn eq(&self, _rhs: &Self) -> bool {
- // FIXME: Assume that all nonterminals are not equal, we can't compare them
- // correctly based on data from AST. This will prevent them from matching each other
- // in macros. The comparison will become possible only when each nonterminal has an
- // attached token stream from which it was parsed.
- false
- }
-}
-
-impl fmt::Debug for Nonterminal {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
- NtBlock(..) => f.pad("NtBlock(..)"),
- }
- }
-}
-
-impl<CTX> HashStable<CTX> for Nonterminal
-where
- CTX: crate::HashStableContext,
-{
- fn hash_stable(&self, _hcx: &mut CTX, _hasher: &mut StableHasher) {
- panic!("interpolated tokens should not be present in the HIR")
- }
-}
-
// Some types are used a lot. Make sure they don't unintentionally get bigger.
#[cfg(target_pointer_width = "64")]
mod size_asserts {
@@ -1202,7 +1177,6 @@ mod size_asserts {
// tidy-alphabetical-start
static_assert_size!(Lit, 12);
static_assert_size!(LitKind, 2);
- static_assert_size!(Nonterminal, 8);
static_assert_size!(Token, 24);
static_assert_size!(TokenKind, 16);
// tidy-alphabetical-end
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index fb331e7..43d25d1 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -25,7 +25,7 @@
use crate::ast::AttrStyle;
use crate::ast_traits::{HasAttrs, HasTokens};
-use crate::token::{self, Delimiter, InvisibleOrigin, Nonterminal, Token, TokenKind};
+use crate::token::{self, Delimiter, Token, TokenKind};
use crate::{AttrVec, Attribute};
/// Part of a `TokenStream`.
@@ -305,11 +305,6 @@ pub struct AttrsTarget {
}
/// A `TokenStream` is an abstract sequence of tokens, organized into [`TokenTree`]s.
-///
-/// The goal is for procedural macros to work with `TokenStream`s and `TokenTree`s
-/// instead of a representation of the abstract syntax tree.
-/// Today's `TokenTree`s can still contain AST via `token::Interpolated` for
-/// backwards compatibility.
#[derive(Clone, Debug, Default, Encodable, Decodable)]
pub struct TokenStream(pub(crate) Arc<Vec<TokenTree>>);
@@ -476,61 +471,6 @@ pub fn from_ast(node: &(impl HasAttrs + HasTokens + fmt::Debug)) -> TokenStream
TokenStream::new(tts)
}
- pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
- match nt {
- Nonterminal::NtBlock(block) => TokenStream::from_ast(block),
- }
- }
-
- fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree {
- match token.kind {
- token::NtIdent(ident, is_raw) => {
- TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing)
- }
- token::NtLifetime(ident, is_raw) => TokenTree::Delimited(
- DelimSpan::from_single(token.span),
- DelimSpacing::new(Spacing::JointHidden, spacing),
- Delimiter::Invisible(InvisibleOrigin::FlattenToken),
- TokenStream::token_alone(token::Lifetime(ident.name, is_raw), ident.span),
- ),
- token::Interpolated(ref nt) => TokenTree::Delimited(
- DelimSpan::from_single(token.span),
- DelimSpacing::new(Spacing::JointHidden, spacing),
- Delimiter::Invisible(InvisibleOrigin::FlattenToken),
- TokenStream::from_nonterminal_ast(&nt).flattened(),
- ),
- _ => TokenTree::Token(token.clone(), spacing),
- }
- }
-
- fn flatten_token_tree(tree: &TokenTree) -> TokenTree {
- match tree {
- TokenTree::Token(token, spacing) => TokenStream::flatten_token(token, *spacing),
- TokenTree::Delimited(span, spacing, delim, tts) => {
- TokenTree::Delimited(*span, *spacing, *delim, tts.flattened())
- }
- }
- }
-
- #[must_use]
- pub fn flattened(&self) -> TokenStream {
- fn can_skip(stream: &TokenStream) -> bool {
- stream.iter().all(|tree| match tree {
- TokenTree::Token(token, _) => !matches!(
- token.kind,
- token::NtIdent(..) | token::NtLifetime(..) | token::Interpolated(..)
- ),
- TokenTree::Delimited(.., inner) => can_skip(inner),
- })
- }
-
- if can_skip(self) {
- return self.clone();
- }
-
- self.iter().map(|tree| TokenStream::flatten_token_tree(tree)).collect()
- }
-
// If `vec` is not empty, try to glue `tt` onto its last token. The return
// value indicates if gluing took place.
fn try_glue_to_last(vec: &mut Vec<TokenTree>, tt: &TokenTree) -> bool {
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index 2296b05..93c627f 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -85,7 +85,7 @@ fn is_method(&self, def_id: DefId, span: Span) -> bool {
.delegation_fn_sigs
.get(&local_def_id)
.is_some_and(|sig| sig.has_self),
- None => self.tcx.associated_item(def_id).fn_has_self_parameter,
+ None => self.tcx.associated_item(def_id).is_method(),
},
_ => span_bug!(span, "unexpected DefKind for delegation item"),
}
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index df4fd2e..8e1a3cd 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -399,12 +399,16 @@ pub(crate) fn inject_ensures_check(
&mut self,
expr: &'hir hir::Expr<'hir>,
span: Span,
- check_ident: Ident,
- check_hir_id: HirId,
+ cond_ident: Ident,
+ cond_hir_id: HirId,
) -> &'hir hir::Expr<'hir> {
- let checker_fn = self.expr_ident(span, check_ident, check_hir_id);
- let span = self.mark_span_with_reason(DesugaringKind::Contract, span, None);
- self.expr_call(span, checker_fn, std::slice::from_ref(expr))
+ let cond_fn = self.expr_ident(span, cond_ident, cond_hir_id);
+ let call_expr = self.expr_call_lang_item_fn_mut(
+ span,
+ hir::LangItem::ContractCheckEnsures,
+ arena_vec![self; *cond_fn, *expr],
+ );
+ self.arena.alloc(call_expr)
}
pub(crate) fn lower_const_block(&mut self, c: &AnonConst) -> hir::ConstBlock {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 59099e5..fc32c4e 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -1206,8 +1206,13 @@ pub(super) fn lower_fn_body(
let precond = if let Some(req) = &contract.requires {
// Lower the precondition check intrinsic.
let lowered_req = this.lower_expr_mut(&req);
+ let req_span = this.mark_span_with_reason(
+ DesugaringKind::Contract,
+ lowered_req.span,
+ None,
+ );
let precond = this.expr_call_lang_item_fn_mut(
- req.span,
+ req_span,
hir::LangItem::ContractCheckRequires,
&*arena_vec![this; lowered_req],
);
@@ -1217,6 +1222,8 @@ pub(super) fn lower_fn_body(
};
let (postcond, body) = if let Some(ens) = &contract.ensures {
let ens_span = this.lower_span(ens.span);
+ let ens_span =
+ this.mark_span_with_reason(DesugaringKind::Contract, ens_span, None);
// Set up the postcondition `let` statement.
let check_ident: Ident =
Ident::from_str_and_span("__ensures_checker", ens_span);
@@ -1303,7 +1310,7 @@ fn lower_maybe_coroutine_body(
// create a fake body so that the entire rest of the compiler doesn't have to deal with
// this as a special case.
return self.lower_fn_body(decl, contract, |this| {
- if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic) {
+ if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)) {
let span = this.lower_span(span);
let empty_block = hir::Block {
hir_id: this.next_id(),
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 22a293d..c409875 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -32,7 +32,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(box_patterns)]
@@ -917,7 +916,7 @@ fn alias_attrs(&mut self, id: HirId, target_id: HirId) {
}
fn lower_delim_args(&self, args: &DelimArgs) -> DelimArgs {
- DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.flattened() }
+ DelimArgs { dspan: args.dspan, delim: args.delim, tokens: args.tokens.clone() }
}
/// Lower an associated item constraint.
@@ -1766,24 +1765,23 @@ fn new_named_lifetime(
ident: Ident,
is_anon_in_path: IsAnonInPath,
) -> &'hir hir::Lifetime {
- debug_assert_ne!(ident.name, kw::Empty);
let res = self.resolver.get_lifetime_res(id).unwrap_or(LifetimeRes::Error);
let res = match res {
- LifetimeRes::Param { param, .. } => hir::LifetimeName::Param(param),
+ LifetimeRes::Param { param, .. } => hir::LifetimeKind::Param(param),
LifetimeRes::Fresh { param, .. } => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
let param = self.local_def_id(param);
- hir::LifetimeName::Param(param)
+ hir::LifetimeKind::Param(param)
}
LifetimeRes::Infer => {
debug_assert_eq!(ident.name, kw::UnderscoreLifetime);
- hir::LifetimeName::Infer
+ hir::LifetimeKind::Infer
}
LifetimeRes::Static { .. } => {
debug_assert!(matches!(ident.name, kw::StaticLifetime | kw::UnderscoreLifetime));
- hir::LifetimeName::Static
+ hir::LifetimeKind::Static
}
- LifetimeRes::Error => hir::LifetimeName::Error,
+ LifetimeRes::Error => hir::LifetimeKind::Error,
LifetimeRes::ElidedAnchor { .. } => {
panic!("Unexpected `ElidedAnchar` {:?} at {:?}", ident, ident.span);
}
@@ -2390,7 +2388,7 @@ fn elided_dyn_bound(&mut self, span: Span) -> &'hir hir::Lifetime {
let r = hir::Lifetime::new(
self.next_id(),
Ident::new(kw::UnderscoreLifetime, self.lower_span(span)),
- hir::LifetimeName::ImplicitObjectLifetimeDefault,
+ hir::LifetimeKind::ImplicitObjectLifetimeDefault,
IsAnonInPath::No,
);
debug!("elided_dyn_bound: r={:?}", r);
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index c464c15..8dfc11b 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -5,7 +5,7 @@
use rustc_hir::GenericArg;
use rustc_hir::def::{DefKind, PartialRes, Res};
use rustc_hir::def_id::DefId;
-use rustc_middle::span_bug;
+use rustc_middle::{span_bug, ty};
use rustc_session::parse::add_feature_diagnostics;
use rustc_span::{BytePos, DUMMY_SP, DesugaringKind, Ident, Span, Symbol, sym};
use smallvec::{SmallVec, smallvec};
@@ -448,8 +448,7 @@ fn maybe_insert_elided_lifetimes_in_path(
generic_args.args.insert_many(
0,
- (start.as_u32()..end.as_u32()).map(|i| {
- let id = NodeId::from_u32(i);
+ (start..end).map(|id| {
let l = self.lower_lifetime_anon_in_path(id, elided_lifetime_span);
GenericArg::Lifetime(l)
}),
@@ -591,14 +590,10 @@ pub(crate) fn assoc_ty_binding(
/// lowering of `async Fn()` bounds to desugar to another trait like `LendingFn`.
fn map_trait_to_async_trait(&self, def_id: DefId) -> Option<DefId> {
let lang_items = self.tcx.lang_items();
- if Some(def_id) == lang_items.fn_trait() {
- lang_items.async_fn_trait()
- } else if Some(def_id) == lang_items.fn_mut_trait() {
- lang_items.async_fn_mut_trait()
- } else if Some(def_id) == lang_items.fn_once_trait() {
- lang_items.async_fn_once_trait()
- } else {
- None
+ match self.tcx.fn_trait_kind_from_def_id(def_id)? {
+ ty::ClosureKind::Fn => lang_items.async_fn_trait(),
+ ty::ClosureKind::FnMut => lang_items.async_fn_mut_trait(),
+ ty::ClosureKind::FnOnce => lang_items.async_fn_once_trait(),
}
}
}
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index 2594439..80754a8 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -79,6 +79,10 @@
.suggestion = remove the {$remove_descr}
.label = `extern` block begins here
+ast_passes_extern_without_abi = `extern` declarations without an explicit ABI are disallowed
+ .suggestion = specify an ABI
+ .help = prior to Rust 2024, a default ABI was inferred
+
ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
.suggestion = remove the attribute
.stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index dc77e7b..1feb3e9 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -347,7 +347,7 @@ fn check_decl_attrs(&self, fn_decl: &FnDecl) {
sym::forbid,
sym::warn,
];
- !arr.contains(&attr.name_or_empty()) && rustc_attr_parsing::is_builtin_attr(*attr)
+ !attr.has_any_name(&arr) && rustc_attr_parsing::is_builtin_attr(*attr)
})
.for_each(|attr| {
if attr.is_doc_comment() {
@@ -684,7 +684,7 @@ fn visit_ty_common(&mut self, ty: &'a Ty) {
self.dcx().emit_err(errors::PatternFnPointer { span });
});
if let Extern::Implicit(extern_span) = bfty.ext {
- self.maybe_lint_missing_abi(extern_span, ty.id);
+ self.handle_missing_abi(extern_span, ty.id);
}
}
TyKind::TraitObject(bounds, ..) => {
@@ -717,10 +717,12 @@ fn visit_ty_common(&mut self, ty: &'a Ty) {
}
}
- fn maybe_lint_missing_abi(&mut self, span: Span, id: NodeId) {
+ fn handle_missing_abi(&mut self, span: Span, id: NodeId) {
// FIXME(davidtwco): This is a hack to detect macros which produce spans of the
// call site which do not have a macro backtrace. See #61963.
- if self
+ if span.edition().at_least_edition_future() && self.features.explicit_extern_abis() {
+ self.dcx().emit_err(errors::MissingAbi { span });
+ } else if self
.sess
.source_map()
.span_to_snippet(span)
@@ -945,8 +947,7 @@ fn visit_item(&mut self, item: &'a Item) {
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
self.check_defaultness(item.span, *defaultness);
- let is_intrinsic =
- item.attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic);
+ let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic));
if body.is_none() && !is_intrinsic {
self.dcx().emit_err(errors::FnWithoutBody {
span: item.span,
@@ -996,7 +997,7 @@ fn visit_item(&mut self, item: &'a Item) {
}
if abi.is_none() {
- self.maybe_lint_missing_abi(*extern_span, item.id);
+ self.handle_missing_abi(*extern_span, item.id);
}
self.with_in_extern_mod(*safety, |this| {
visit::walk_item(this, item);
@@ -1370,7 +1371,7 @@ fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) {
},
) = fk
{
- self.maybe_lint_missing_abi(*extern_span, id);
+ self.handle_missing_abi(*extern_span, id);
}
// Functions without bodies cannot have patterns.
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 8e53e60..6f9737e 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -2,7 +2,7 @@
use rustc_ast::ParamKindOrd;
use rustc_errors::codes::*;
-use rustc_errors::{Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
+use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Ident, Span, Symbol};
@@ -394,11 +394,7 @@ pub(crate) struct ArgsBeforeConstraint {
// The derive for `Vec<Span>` does multiple calls to `span_label`, adding commas between each
impl Subdiagnostic for EmptyLabelManySpans {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.span_labels(self.0, "");
}
}
@@ -749,11 +745,7 @@ pub(crate) struct StableFeature {
}
impl Subdiagnostic for StableFeature {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("name", self.name);
diag.arg("since", self.since);
diag.help(fluent::ast_passes_stable_since);
@@ -823,3 +815,12 @@ pub(crate) struct DuplicatePreciseCapturing {
#[label]
pub bound2: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_extern_without_abi)]
+#[help]
+pub(crate) struct MissingAbi {
+ #[primary_span]
+ #[suggestion(code = "extern \"<abi>\"", applicability = "has-placeholders")]
+ pub span: Span,
+}
diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs
index 97cb6e5..551506f 100644
--- a/compiler/rustc_ast_pretty/src/pprust/mod.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs
@@ -5,14 +5,10 @@
use std::borrow::Cow;
use rustc_ast as ast;
-use rustc_ast::token::{Nonterminal, Token, TokenKind};
+use rustc_ast::token::{Token, TokenKind};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
pub use state::{AnnNode, Comments, PpAnn, PrintState, State, print_crate};
-pub fn nonterminal_to_string(nt: &Nonterminal) -> String {
- State::new().nonterminal_to_string(nt)
-}
-
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
pub fn token_kind_to_string(tok: &TokenKind) -> Cow<'static, str> {
State::new().token_kind_to_string(tok)
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 90caad1c..6959cbd 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -11,7 +11,7 @@
use rustc_ast::attr::AttrIdGenerator;
use rustc_ast::ptr::P;
-use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind};
+use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind};
use rustc_ast::tokenstream::{Spacing, TokenStream, TokenTree};
use rustc_ast::util::classify;
use rustc_ast::util::comments::{Comment, CommentStyle};
@@ -770,12 +770,12 @@ fn print_mac_common(
self.bclose(span, empty);
}
delim => {
- let token_str = self.token_kind_to_string(&token::OpenDelim(delim));
+ let token_str = self.token_kind_to_string(&delim.as_open_token_kind());
self.word(token_str);
self.ibox(0);
self.print_tts(tts, convert_dollar_crate);
self.end();
- let token_str = self.token_kind_to_string(&token::CloseDelim(delim));
+ let token_str = self.token_kind_to_string(&delim.as_close_token_kind());
self.word(token_str);
}
}
@@ -876,14 +876,6 @@ fn break_offset_if_not_bol(&mut self, n: usize, off: isize) {
}
}
- fn nonterminal_to_string(&self, nt: &Nonterminal) -> String {
- // We extract the token stream from the AST fragment and pretty print
- // it, rather than using AST pretty printing, because `Nonterminal` is
- // slated for removal in #124141. (This method will also then be
- // removed.)
- self.tts_to_string(&TokenStream::from_nonterminal_ast(nt))
- }
-
/// Print the token kind precisely, without converting `$crate` into its respective crate name.
fn token_kind_to_string(&self, tok: &TokenKind) -> Cow<'static, str> {
self.token_kind_to_string_ext(tok, None)
@@ -940,14 +932,13 @@ fn token_kind_to_string_ext(
token::RArrow => "->".into(),
token::LArrow => "<-".into(),
token::FatArrow => "=>".into(),
- token::OpenDelim(Delimiter::Parenthesis) => "(".into(),
- token::CloseDelim(Delimiter::Parenthesis) => ")".into(),
- token::OpenDelim(Delimiter::Bracket) => "[".into(),
- token::CloseDelim(Delimiter::Bracket) => "]".into(),
- token::OpenDelim(Delimiter::Brace) => "{".into(),
- token::CloseDelim(Delimiter::Brace) => "}".into(),
- token::OpenDelim(Delimiter::Invisible(_))
- | token::CloseDelim(Delimiter::Invisible(_)) => "".into(),
+ token::OpenParen => "(".into(),
+ token::CloseParen => ")".into(),
+ token::OpenBracket => "[".into(),
+ token::CloseBracket => "]".into(),
+ token::OpenBrace => "{".into(),
+ token::CloseBrace => "}".into(),
+ token::OpenInvisible(_) | token::CloseInvisible(_) => "".into(),
token::Pound => "#".into(),
token::Dollar => "$".into(),
token::Question => "?".into(),
@@ -976,8 +967,6 @@ fn token_kind_to_string_ext(
doc_comment_to_string(comment_kind, attr_style, data).into()
}
token::Eof => "<eof>".into(),
-
- token::Interpolated(ref nt) => self.nonterminal_to_string(&nt).into(),
}
}
diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs
index 969bce7..d2d1285 100644
--- a/compiler/rustc_attr_data_structures/src/attributes.rs
+++ b/compiler/rustc_attr_data_structures/src/attributes.rs
@@ -191,7 +191,6 @@ pub enum AttributeKind {
},
MacroTransparency(Transparency),
Repr(ThinVec<(ReprAttr, Span)>),
- RustcMacroEdition2021,
Stability {
stability: Stability,
/// Span of the `#[stable(...)]` or `#[unstable(...)]` attribute
diff --git a/compiler/rustc_attr_parsing/src/attributes/cfg.rs b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
index 0d6d521..7cb1fed 100644
--- a/compiler/rustc_attr_parsing/src/attributes/cfg.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/cfg.rs
@@ -7,7 +7,6 @@
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
use rustc_session::parse::feature_err;
-use rustc_span::symbol::kw;
use rustc_span::{Span, Symbol, sym};
use crate::session_diagnostics::{self, UnsupportedLiteralReason};
@@ -89,20 +88,6 @@ pub fn eval_condition(
let cfg = match cfg {
MetaItemInner::MetaItem(meta_item) => meta_item,
MetaItemInner::Lit(MetaItemLit { kind: LitKind::Bool(b), .. }) => {
- if let Some(features) = features {
- // we can't use `try_gate_cfg` as symbols don't differentiate between `r#true`
- // and `true`, and we want to keep the former working without feature gate
- gate_cfg(
- &(
- if *b { kw::True } else { kw::False },
- sym::cfg_boolean_literals,
- |features: &Features| features.cfg_boolean_literals(),
- ),
- cfg.span(),
- sess,
- features,
- );
- }
return *b;
}
_ => {
@@ -117,7 +102,7 @@ pub fn eval_condition(
};
match &cfg.kind {
- MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
+ MetaItemKind::List(mis) if cfg.has_name(sym::version) => {
try_gate_cfg(sym::version, cfg.span, sess, features);
let (min_version, span) = match &mis[..] {
[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => {
@@ -164,18 +149,18 @@ pub fn eval_condition(
// The unwraps below may look dangerous, but we've already asserted
// that they won't fail with the loop above.
- match cfg.name_or_empty() {
- sym::any => mis
+ match cfg.name() {
+ Some(sym::any) => mis
.iter()
// We don't use any() here, because we want to evaluate all cfg condition
// as eval_condition can (and does) extra checks
.fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)),
- sym::all => mis
+ Some(sym::all) => mis
.iter()
// We don't use all() here, because we want to evaluate all cfg condition
// as eval_condition can (and does) extra checks
.fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)),
- sym::not => {
+ Some(sym::not) => {
let [mi] = mis.as_slice() else {
dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
return false;
@@ -183,7 +168,7 @@ pub fn eval_condition(
!eval_condition(mi, sess, features, eval)
}
- sym::target => {
+ Some(sym::target) => {
if let Some(features) = features
&& !features.cfg_target_compact()
{
diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs
index bac1111..6ecd6b4 100644
--- a/compiler/rustc_attr_parsing/src/attributes/mod.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs
@@ -28,7 +28,6 @@
pub(crate) mod confusables;
pub(crate) mod deprecation;
pub(crate) mod repr;
-pub(crate) mod rustc;
pub(crate) mod stability;
pub(crate) mod transparency;
pub(crate) mod util;
diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc.rs b/compiler/rustc_attr_parsing/src/attributes/rustc.rs
deleted file mode 100644
index bdd3bef..0000000
--- a/compiler/rustc_attr_parsing/src/attributes/rustc.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-use rustc_attr_data_structures::AttributeKind;
-use rustc_span::sym;
-
-use super::{AcceptContext, SingleAttributeParser};
-use crate::parser::ArgParser;
-
-pub(crate) struct RustcMacroEdition2021Parser;
-
-// FIXME(jdonszelmann): make these proper diagnostics
-impl SingleAttributeParser for RustcMacroEdition2021Parser {
- const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_edition_2021];
-
- fn on_duplicate(_cx: &crate::context::AcceptContext<'_>, _first_span: rustc_span::Span) {}
-
- fn convert(_cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
- assert!(args.no_args());
- Some(AttributeKind::RustcMacroEdition2021)
- }
-}
diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
index ad83a1f..ce42b050 100644
--- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs
@@ -20,7 +20,7 @@ fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: rustc_span::
fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
match args.name_value().and_then(|nv| nv.value_as_str()) {
Some(sym::transparent) => Some(Transparency::Transparent),
- Some(sym::semitransparent) => Some(Transparency::SemiTransparent),
+ Some(sym::semiopaque | sym::semitransparent) => Some(Transparency::SemiOpaque),
Some(sym::opaque) => Some(Transparency::Opaque),
Some(other) => {
cx.dcx().span_err(cx.attr_span, format!("unknown macro transparency: `{other}`"));
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index a68d457..63597b3 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -15,7 +15,6 @@
use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::repr::ReprParser;
-use crate::attributes::rustc::RustcMacroEdition2021Parser;
use crate::attributes::stability::{
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
};
@@ -77,7 +76,6 @@ macro_rules! attribute_groups {
// tidy-alphabetical-start
Single<ConstStabilityIndirectParser>,
Single<DeprecationParser>,
- Single<RustcMacroEdition2021Parser>,
Single<TransparencyParser>,
// tidy-alphabetical-end
];
@@ -222,7 +220,7 @@ pub fn parse_attribute_list<'a>(
// if we're only looking for a single attribute,
// skip all the ones we don't care about
if let Some(expected) = self.parse_only {
- if attr.name_or_empty() != expected {
+ if !attr.has_name(expected) {
continue;
}
}
@@ -232,7 +230,7 @@ pub fn parse_attribute_list<'a>(
// that's expanded right? But no, sometimes, when parsing attributes on macros,
// we already use the lowering logic and these are still there. So, when `omit_doc`
// is set we *also* want to ignore these
- if omit_doc == OmitDoc::Skip && attr.name_or_empty() == sym::doc {
+ if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) {
continue;
}
@@ -250,7 +248,7 @@ pub fn parse_attribute_list<'a>(
}))
}
// // FIXME: make doc attributes go through a proper attribute parser
- // ast::AttrKind::Normal(n) if n.name_or_empty() == sym::doc => {
+ // ast::AttrKind::Normal(n) if n.has_name(sym::doc) => {
// let p = GenericMetaItemParser::from_attr(&n, self.dcx());
//
// attributes.push(Attribute::Parsed(AttributeKind::DocComment {
@@ -320,7 +318,7 @@ fn lower_attr_args(&self, args: &ast::AttrArgs, lower_span: impl Fn(Span) -> Spa
ast::AttrArgs::Delimited(args) => AttrArgs::Delimited(DelimArgs {
dspan: args.dspan,
delim: args.delim,
- tokens: args.tokens.flattened(),
+ tokens: args.tokens.clone(),
}),
// This is an inert key-value attribute - it will never be visible to macros
// after it gets lowered to HIR. Therefore, we can extract literals to handle
diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs
index a746584..249e71e 100644
--- a/compiler/rustc_attr_parsing/src/lib.rs
+++ b/compiler/rustc_attr_parsing/src/lib.rs
@@ -77,7 +77,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(rust_logo)]
#![feature(let_chains)]
#![feature(rustdoc_internals)]
diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs
index a8a1460..40aa397 100644
--- a/compiler/rustc_attr_parsing/src/parser.rs
+++ b/compiler/rustc_attr_parsing/src/parser.rs
@@ -430,9 +430,7 @@ fn next_path(&mut self) -> Option<AttrPath> {
let span = span.with_hi(segments.last().unwrap().span.hi());
Some(AttrPath { segments: segments.into_boxed_slice(), span })
}
- TokenTree::Token(Token { kind: token::OpenDelim(_) | token::CloseDelim(_), .. }, _) => {
- None
- }
+ TokenTree::Token(Token { kind, .. }, _) if kind.is_delim() => None,
_ => {
// malformed attributes can get here. We can't crash, but somewhere else should've
// already warned for this.
@@ -485,25 +483,7 @@ fn next(&mut self) -> Option<MetaItemOrLitParser<'a>> {
}
// or a path.
- let path =
- if let Some(TokenTree::Token(Token { kind: token::Interpolated(_), span, .. }, _)) =
- self.inside_delimiters.peek()
- {
- self.inside_delimiters.next();
- // We go into this path if an expr ended up in an attribute that
- // expansion did not turn into a literal. Say, `#[repr(align(macro!()))]`
- // where the macro didn't expand to a literal. An error is already given
- // for this at this point, and then we do continue. This makes this path
- // reachable...
- let e = self.dcx.span_delayed_bug(
- *span,
- "expr in place where literal is expected (builtin attr parsing)",
- );
-
- return Some(MetaItemOrLitParser::Err(*span, e));
- } else {
- self.next_path()?
- };
+ let path = self.next_path()?;
// Paths can be followed by:
// - `(more meta items)` (another list)
diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs
index 263f68d..b9ced81 100644
--- a/compiler/rustc_borrowck/src/def_use.rs
+++ b/compiler/rustc_borrowck/src/def_use.rs
@@ -77,6 +77,9 @@ pub(crate) fn categorize(context: PlaceContext) -> Option<DefUse> {
// Debug info is neither def nor use.
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None,
+ // Backwards incompatible drop hint is not a use, just a marker for linting.
+ PlaceContext::NonUse(NonUseContext::BackwardIncompatibleDropHint) => None,
+
PlaceContext::MutatingUse(MutatingUseContext::Deinit | MutatingUseContext::SetDiscriminant) => {
bug!("These statements are not allowed in this MIR phase")
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 8a8ecc3..0f8acad 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -647,7 +647,7 @@ fn suggest_borrow_generic_arg(
&& tc.polarity() == ty::PredicatePolarity::Positive
&& supertrait_def_ids(tcx, tc.def_id())
.flat_map(|trait_did| tcx.associated_items(trait_did).in_definition_order())
- .any(|item| item.fn_has_self_parameter)
+ .any(|item| item.is_method())
})
}) {
return None;
@@ -1265,12 +1265,7 @@ pub(crate) fn suggest_cloning(
&& let CallKind::FnCall { fn_trait_id, self_ty } = kind
&& let ty::Param(_) = self_ty.kind()
&& ty == self_ty
- && [
- self.infcx.tcx.lang_items().fn_once_trait(),
- self.infcx.tcx.lang_items().fn_mut_trait(),
- self.infcx.tcx.lang_items().fn_trait(),
- ]
- .contains(&Some(fn_trait_id))
+ && self.infcx.tcx.fn_trait_kind_from_def_id(fn_trait_id).is_some()
{
// Do not suggest `F: FnOnce() + Clone`.
false
@@ -2959,21 +2954,27 @@ fn report_local_value_does_not_live_long_enough(
}
}
- let mut err = self.path_does_not_live_long_enough(borrow_span, &format!("`{name}`"));
+ let name = if borrow_span.in_external_macro(self.infcx.tcx.sess.source_map()) {
+ // Don't name local variables in external macros.
+ "value".to_string()
+ } else {
+ format!("`{name}`")
+ };
+
+ let mut err = self.path_does_not_live_long_enough(borrow_span, &name);
if let Some(annotation) = self.annotate_argument_and_return_for_borrow(borrow) {
let region_name = annotation.emit(self, &mut err);
err.span_label(
borrow_span,
- format!("`{name}` would have to be valid for `{region_name}`..."),
+ format!("{name} would have to be valid for `{region_name}`..."),
);
err.span_label(
drop_span,
format!(
- "...but `{}` will be dropped here, when the {} returns",
- name,
+ "...but {name} will be dropped here, when the {} returns",
self.infcx
.tcx
.opt_item_name(self.mir_def_id().to_def_id())
@@ -3011,7 +3012,7 @@ fn report_local_value_does_not_live_long_enough(
}
} else {
err.span_label(borrow_span, "borrowed value does not live long enough");
- err.span_label(drop_span, format!("`{name}` dropped here while still borrowed"));
+ err.span_label(drop_span, format!("{name} dropped here while still borrowed"));
borrow_spans.args_subdiag(&mut err, |args_span| {
crate::session_diagnostics::CaptureArgLabel::Capture {
@@ -3376,10 +3377,15 @@ fn report_escaping_closure_capture(
let (sugg_span, suggestion) = match tcx.sess.source_map().span_to_snippet(args_span) {
Ok(string) => {
- let coro_prefix = if string.starts_with("async") {
- // `async` is 5 chars long. Not using `.len()` to avoid the cast from `usize`
- // to `u32`.
- Some(5)
+ let coro_prefix = if let Some(sub) = string.strip_prefix("async") {
+ let trimmed_sub = sub.trim_end();
+ if trimmed_sub.ends_with("gen") {
+ // `async` is 5 chars long.
+ Some((trimmed_sub.len() + 5) as _)
+ } else {
+ // `async` is 5 chars long.
+ Some(5)
+ }
} else if string.starts_with("gen") {
// `gen` is 3 chars long
Some(3)
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index f77dda0..a845431 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -95,7 +95,9 @@ pub(crate) fn add_explanation_to_diagnostic<G: EmissionGuarantee>(
&& let hir::def::Res::Local(hir_id) = p.res
&& let hir::Node::Pat(pat) = tcx.hir_node(hir_id)
{
- err.span_label(pat.span, format!("binding `{ident}` declared here"));
+ if !ident.span.in_external_macro(tcx.sess.source_map()) {
+ err.span_label(pat.span, format!("binding `{ident}` declared here"));
+ }
}
}
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 8d530b5..4423edb 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -888,7 +888,7 @@ fn add_static_impl_trait_suggestion(
// Skip `async` desugaring `impl Future`.
}
if let TyKind::TraitObject(_, lt) = alias_ty.kind {
- if lt.res == hir::LifetimeName::ImplicitObjectLifetimeDefault {
+ if lt.kind == hir::LifetimeKind::ImplicitObjectLifetimeDefault {
spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
} else {
spans_suggs.push((lt.ident.span, "'a".to_string()));
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 64ad1c9..83a9827 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -2,7 +2,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(box_patterns)]
@@ -22,6 +21,7 @@
use std::marker::PhantomData;
use std::ops::{ControlFlow, Deref};
+use borrow_set::LocalsStateAtExit;
use root_cx::BorrowCheckRootCtxt;
use rustc_abi::FieldIdx;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@@ -304,33 +304,13 @@ fn do_mir_borrowck<'tcx>(
root_cx.set_tainted_by_errors(e);
}
- let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
- for var_debug_info in &input_body.var_debug_info {
- if let VarDebugInfoContents::Place(place) = var_debug_info.value {
- if let Some(local) = place.as_local() {
- if let Some(prev_name) = local_names[local]
- && var_debug_info.name != prev_name
- {
- span_bug!(
- var_debug_info.source_info.span,
- "local {:?} has many names (`{}` vs `{}`)",
- local,
- prev_name,
- var_debug_info.name
- );
- }
- local_names[local] = Some(var_debug_info.name);
- }
- }
- }
-
// Replace all regions with fresh inference variables. This
// requires first making our own copy of the MIR. This copy will
// be modified (in place) to contain non-lexical lifetimes. It
// will have a lifetime tied to the inference context.
let mut body_owned = input_body.clone();
let mut promoted = input_promoted.to_owned();
- let free_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
+ let universal_regions = nll::replace_regions_in_mir(&infcx, &mut body_owned, &mut promoted);
let body = &body_owned; // no further changes
let location_table = PoloniusLocationTable::new(body);
@@ -355,7 +335,7 @@ fn do_mir_borrowck<'tcx>(
} = nll::compute_regions(
root_cx,
&infcx,
- free_regions,
+ universal_regions,
body,
&promoted,
&location_table,
@@ -368,24 +348,23 @@ fn do_mir_borrowck<'tcx>(
// Dump MIR results into a file, if that is enabled. This lets us
// write unit-tests, as well as helping with debugging.
nll::dump_nll_mir(&infcx, body, ®ioncx, &opt_closure_req, &borrow_set);
+ polonius::dump_polonius_mir(
+ &infcx,
+ body,
+ ®ioncx,
+ &opt_closure_req,
+ &borrow_set,
+ polonius_diagnostics.as_ref(),
+ );
// We also have a `#[rustc_regions]` annotation that causes us to dump
// information.
+ nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req);
+
+ let movable_coroutine = body.coroutine.is_some()
+ && tcx.coroutine_movability(def.to_def_id()) == hir::Movability::Movable;
+
let diags_buffer = &mut BorrowckDiagnosticsBuffer::default();
- nll::dump_annotation(&infcx, body, ®ioncx, &opt_closure_req, diags_buffer);
-
- let movable_coroutine =
- // The first argument is the coroutine type passed by value
- if let Some(local) = body.local_decls.raw.get(1)
- // Get the interior types and args which typeck computed
- && let ty::Coroutine(def_id, _) = *local.ty.kind()
- && tcx.coroutine_movability(def_id) == hir::Movability::Movable
-{
- true
-} else {
- false
-};
-
// While promoteds should mostly be correct by construction, we need to check them for
// invalid moves to detect moving out of arrays:`struct S; fn main() { &([S][0]); }`.
for promoted_body in &promoted {
@@ -403,7 +382,6 @@ fn do_mir_borrowck<'tcx>(
location_table: &location_table,
movable_coroutine,
fn_self_span_reported: Default::default(),
- locals_are_invalidated_at_exit,
access_place_error_reported: Default::default(),
reservation_error_reported: Default::default(),
uninitialized_error_reported: Default::default(),
@@ -435,6 +413,26 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
promoted_mbcx.report_move_errors();
}
+ let mut local_names = IndexVec::from_elem(None, &body.local_decls);
+ for var_debug_info in &body.var_debug_info {
+ if let VarDebugInfoContents::Place(place) = var_debug_info.value {
+ if let Some(local) = place.as_local() {
+ if let Some(prev_name) = local_names[local]
+ && var_debug_info.name != prev_name
+ {
+ span_bug!(
+ var_debug_info.source_info.span,
+ "local {:?} has many names (`{}` vs `{}`)",
+ local,
+ prev_name,
+ var_debug_info.name
+ );
+ }
+ local_names[local] = Some(var_debug_info.name);
+ }
+ }
+ }
+
let mut mbcx = MirBorrowckCtxt {
root_cx,
infcx: &infcx,
@@ -442,7 +440,6 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
move_data: &move_data,
location_table: &location_table,
movable_coroutine,
- locals_are_invalidated_at_exit,
fn_self_span_reported: Default::default(),
access_place_error_reported: Default::default(),
reservation_error_reported: Default::default(),
@@ -455,9 +452,9 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
local_names,
region_names: RefCell::default(),
next_region_name: RefCell::new(1),
- polonius_output,
move_errors: Vec::new(),
diags_buffer,
+ polonius_output: polonius_output.as_deref(),
polonius_diagnostics: polonius_diagnostics.as_ref(),
};
@@ -474,16 +471,6 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
mbcx.report_move_errors();
- // If requested, dump polonius MIR.
- polonius::dump_polonius_mir(
- &infcx,
- body,
- ®ioncx,
- &borrow_set,
- polonius_diagnostics.as_ref(),
- &opt_closure_req,
- );
-
// For each non-user used mutable variable, check if it's been assigned from
// a user-declared local. If so, then put that local into the used_mut set.
// Note that this set is expected to be small - only upvars from closures
@@ -514,7 +501,6 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
};
let body_with_facts = if consumer_options.is_some() {
- let output_facts = mbcx.polonius_output;
Some(Box::new(BodyWithBorrowckFacts {
body: body_owned,
promoted,
@@ -522,7 +508,7 @@ fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
region_inference_context: regioncx,
location_table: polonius_input.as_ref().map(|_| location_table),
input_facts: polonius_input,
- output_facts,
+ output_facts: polonius_output,
}))
} else {
None
@@ -655,13 +641,6 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
location_table: &'a PoloniusLocationTable,
movable_coroutine: bool,
- /// This keeps track of whether local variables are free-ed when the function
- /// exits even without a `StorageDead`, which appears to be the case for
- /// constants.
- ///
- /// I'm not sure this is the right approach - @eddyb could you try and
- /// figure this out?
- locals_are_invalidated_at_exit: bool,
/// This field keeps track of when borrow errors are reported in the access_place function
/// so that there is no duplicate reporting. This field cannot also be used for the conflicting
/// borrow errors that is handled by the `reservation_error_reported` field as the inclusion
@@ -709,12 +688,11 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
/// The counter for generating new region names.
next_region_name: RefCell<usize>,
- /// Results of Polonius analysis.
- polonius_output: Option<Box<PoloniusOutput>>,
-
diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
move_errors: Vec<MoveError<'tcx>>,
+ /// Results of Polonius analysis.
+ polonius_output: Option<&'a PoloniusOutput>,
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
}
@@ -724,12 +702,12 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {
// 2. loans made in overlapping scopes do not conflict
// 3. assignments do not affect things loaned out as immutable
// 4. moves do not affect things loaned out in any way
-impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
+impl<'a, 'tcx> ResultsVisitor<'tcx, Borrowck<'a, 'tcx>> for MirBorrowckCtxt<'a, '_, 'tcx> {
fn visit_after_early_statement_effect(
&mut self,
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
state: &BorrowckDomain,
- stmt: &'a Statement<'tcx>,
+ stmt: &Statement<'tcx>,
location: Location,
) {
debug!("MirBorrowckCtxt::process_statement({:?}, {:?}): {:?}", location, stmt, state);
@@ -805,7 +783,7 @@ fn visit_after_early_terminator_effect(
&mut self,
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
state: &BorrowckDomain,
- term: &'a Terminator<'tcx>,
+ term: &Terminator<'tcx>,
loc: Location,
) {
debug!("MirBorrowckCtxt::process_terminator({:?}, {:?}): {:?}", loc, term, state);
@@ -918,7 +896,7 @@ fn visit_after_primary_terminator_effect(
&mut self,
_results: &mut Results<'tcx, Borrowck<'a, 'tcx>>,
state: &BorrowckDomain,
- term: &'a Terminator<'tcx>,
+ term: &Terminator<'tcx>,
loc: Location,
) {
let span = term.source_info.span;
@@ -938,13 +916,20 @@ fn visit_after_primary_terminator_effect(
| TerminatorKind::Return
| TerminatorKind::TailCall { .. }
| TerminatorKind::CoroutineDrop => {
- // Returning from the function implicitly kills storage for all locals and statics.
- // Often, the storage will already have been killed by an explicit
- // StorageDead, but we don't always emit those (notably on unwind paths),
- // so this "extra check" serves as a kind of backup.
- for i in state.borrows.iter() {
- let borrow = &self.borrow_set[i];
- self.check_for_invalidation_at_exit(loc, borrow, span);
+ match self.borrow_set.locals_state_at_exit() {
+ LocalsStateAtExit::AllAreInvalidated => {
+ // Returning from the function implicitly kills storage for all locals and statics.
+ // Often, the storage will already have been killed by an explicit
+ // StorageDead, but we don't always emit those (notably on unwind paths),
+ // so this "extra check" serves as a kind of backup.
+ for i in state.borrows.iter() {
+ let borrow = &self.borrow_set[i];
+ self.check_for_invalidation_at_exit(loc, borrow, span);
+ }
+ }
+ // If we do not implicitly invalidate all locals on exit,
+ // we check for conflicts when dropping or moving this local.
+ LocalsStateAtExit::SomeAreInvalidated { has_storage_dead_or_moved: _ } => {}
}
}
@@ -1301,7 +1286,7 @@ fn check_access_for_conflict(
error_reported
}
- /// Through #123739, backward incompatible drops (BIDs) are introduced.
+ /// Through #123739, `BackwardIncompatibleDropHint`s (BIDs) are introduced.
/// We would like to emit lints whether borrow checking fails at these future drop locations.
#[instrument(level = "debug", skip(self, state))]
fn check_backward_incompatible_drop(
@@ -1378,7 +1363,7 @@ fn mutate_place(
fn consume_rvalue(
&mut self,
location: Location,
- (rvalue, span): (&'a Rvalue<'tcx>, Span),
+ (rvalue, span): (&Rvalue<'tcx>, Span),
state: &BorrowckDomain,
) {
match rvalue {
@@ -1651,7 +1636,7 @@ fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) {
fn consume_operand(
&mut self,
location: Location,
- (operand, span): (&'a Operand<'tcx>, Span),
+ (operand, span): (&Operand<'tcx>, Span),
state: &BorrowckDomain,
) {
match *operand {
@@ -1716,22 +1701,15 @@ fn check_for_invalidation_at_exit(
// we'll have a memory leak) and assume that all statics have a destructor.
//
// FIXME: allow thread-locals to borrow other thread locals?
-
- let (might_be_alive, will_be_dropped) =
- if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
- // Thread-locals might be dropped after the function exits
- // We have to dereference the outer reference because
- // borrows don't conflict behind shared references.
- root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
- (true, true)
- } else {
- (false, self.locals_are_invalidated_at_exit)
- };
-
- if !will_be_dropped {
- debug!("place_is_invalidated_at_exit({:?}) - won't be dropped", place);
- return;
- }
+ let might_be_alive = if self.body.local_decls[root_place.local].is_ref_to_thread_local() {
+ // Thread-locals might be dropped after the function exits
+ // We have to dereference the outer reference because
+ // borrows don't conflict behind shared references.
+ root_place.projection = TyCtxtConsts::DEREF_PROJECTION;
+ true
+ } else {
+ false
+ };
let sd = if might_be_alive { Deep } else { Shallow(None) };
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 8a2a34f..fe899bb 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -21,7 +21,7 @@
use crate::borrow_set::BorrowSet;
use crate::consumers::ConsumerOptions;
-use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
+use crate::diagnostics::RegionErrors;
use crate::polonius::PoloniusDiagnosticsContext;
use crate::polonius::legacy::{
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
@@ -117,11 +117,6 @@ pub(crate) fn compute_regions<'a, 'tcx>(
Rc::clone(&location_map),
);
- // Create the region inference context, taking ownership of the
- // region inference data that was contained in `infcx`, and the
- // base constraints generated by the type-check.
- let var_infos = infcx.get_region_var_infos();
-
// If requested, emit legacy polonius facts.
polonius::legacy::emit_facts(
&mut polonius_facts,
@@ -134,13 +129,8 @@ pub(crate) fn compute_regions<'a, 'tcx>(
&constraints,
);
- let mut regioncx = RegionInferenceContext::new(
- infcx,
- var_infos,
- constraints,
- universal_region_relations,
- location_map,
- );
+ let mut regioncx =
+ RegionInferenceContext::new(infcx, constraints, universal_region_relations, location_map);
// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints
// and use them to compute loan liveness.
@@ -297,7 +287,6 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
- diagnostics_buffer: &mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
) {
let tcx = infcx.tcx;
let base_def_id = tcx.typeck_root_def_id(body.source.def_id());
@@ -335,13 +324,11 @@ pub(super) fn dump_annotation<'tcx, 'infcx>(
} else {
let mut err = infcx.dcx().struct_span_note(def_span, "no external requirements");
regioncx.annotate(tcx, &mut err);
-
err
};
// FIXME(@lcnr): We currently don't dump the inferred hidden types here.
-
- diagnostics_buffer.buffer_non_error(err);
+ err.emit();
}
fn for_each_region_constraint<'tcx>(
diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs
index eb53a98..6a943e1 100644
--- a/compiler/rustc_borrowck/src/polonius/dump.rs
+++ b/compiler/rustc_borrowck/src/polonius/dump.rs
@@ -24,9 +24,9 @@ pub(crate) fn dump_polonius_mir<'tcx>(
infcx: &BorrowckInferCtxt<'tcx>,
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
+ closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
borrow_set: &BorrowSet<'tcx>,
polonius_diagnostics: Option<&PoloniusDiagnosticsContext>,
- closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
) {
let tcx = infcx.tcx;
if !tcx.sess.opts.unstable_opts.polonius.is_next_enabled() {
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 569c46e..f8af9e5 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -9,7 +9,7 @@
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_index::IndexVec;
use rustc_infer::infer::outlives::test_type_match;
-use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
+use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound, VerifyIfEq};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
use rustc_middle::bug;
use rustc_middle::mir::{
@@ -145,7 +145,7 @@ pub struct RegionInferenceContext<'tcx> {
/// variables are identified by their index (`RegionVid`). The
/// definition contains information about where the region came
/// from as well as its final inferred value.
- pub(crate) definitions: IndexVec<RegionVid, RegionDefinition<'tcx>>,
+ pub(crate) definitions: Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>>,
/// The liveness constraints added to each region. For most
/// regions, these start out empty and steadily grow, though for
@@ -338,8 +338,7 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
let num_components = sccs.num_sccs();
let mut components = vec![FxIndexSet::default(); num_components];
- for (reg_var_idx, scc_idx) in sccs.scc_indices().iter().enumerate() {
- let reg_var = ty::RegionVid::from_usize(reg_var_idx);
+ for (reg_var, scc_idx) in sccs.scc_indices().iter_enumerated() {
let origin = var_to_origin.get(®_var).unwrap_or(&RegionCtxt::Unknown);
components[scc_idx.as_usize()].insert((reg_var, *origin));
}
@@ -385,6 +384,26 @@ fn sccs_info<'tcx>(infcx: &BorrowckInferCtxt<'tcx>, sccs: &ConstraintSccs) {
debug!("SCC edges {:#?}", scc_node_to_edges);
}
+fn create_definitions<'tcx>(
+ infcx: &BorrowckInferCtxt<'tcx>,
+ universal_regions: &UniversalRegions<'tcx>,
+) -> Frozen<IndexVec<RegionVid, RegionDefinition<'tcx>>> {
+ // Create a RegionDefinition for each inference variable.
+ let mut definitions: IndexVec<_, _> = infcx
+ .get_region_var_infos()
+ .iter()
+ .map(|info| RegionDefinition::new(info.universe, info.origin))
+ .collect();
+
+ // Add the external name for all universal regions.
+ for (external_name, variable) in universal_regions.named_universal_regions_iter() {
+ debug!("region {variable:?} has external name {external_name:?}");
+ definitions[variable].external_name = Some(external_name);
+ }
+
+ Frozen::freeze(definitions)
+}
+
impl<'tcx> RegionInferenceContext<'tcx> {
/// Creates a new region inference context with a total of
/// `num_region_variables` valid inference variables; the first N
@@ -395,7 +414,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// of constraints produced by the MIR type check.
pub(crate) fn new(
infcx: &BorrowckInferCtxt<'tcx>,
- var_infos: VarInfos,
constraints: MirTypeckRegionConstraints<'tcx>,
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
location_map: Rc<DenseLocationMap>,
@@ -426,11 +444,7 @@ pub(crate) fn new(
infcx.set_tainted_by_errors(guar);
}
- // Create a RegionDefinition for each inference variable.
- let definitions: IndexVec<_, _> = var_infos
- .iter()
- .map(|info| RegionDefinition::new(info.universe, info.origin))
- .collect();
+ let definitions = create_definitions(infcx, &universal_regions);
let constraint_sccs =
outlives_constraints.add_outlives_static(&universal_regions, &definitions);
@@ -526,18 +540,6 @@ pub(crate) fn new(
/// means that the `R1: !1` constraint here will cause
/// `R1` to become `'static`.
fn init_free_and_bound_regions(&mut self) {
- // Update the names (if any)
- // This iterator has unstable order but we collect it all into an IndexVec
- for (external_name, variable) in
- self.universal_region_relations.universal_regions.named_universal_regions_iter()
- {
- debug!(
- "init_free_and_bound_regions: region {:?} has external name {:?}",
- variable, external_name
- );
- self.definitions[variable].external_name = Some(external_name);
- }
-
for variable in self.definitions.indices() {
let scc = self.constraint_sccs.scc(variable);
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index ccb257a..5751656 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -21,7 +21,6 @@
pub(crate) struct ConstraintConversion<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
- tcx: TyCtxt<'tcx>,
universal_regions: &'a UniversalRegions<'tcx>,
/// Each RBP `GK: 'a` is assumed to be true. These encode
/// relationships like `T: 'a` that are added via implicit bounds
@@ -34,7 +33,6 @@ pub(crate) struct ConstraintConversion<'a, 'tcx> {
/// logic expecting to see (e.g.) `ReStatic`, and if we supplied
/// our special inference variable there, we would mess that up.
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
- implicit_region_bound: ty::Region<'tcx>,
param_env: ty::ParamEnv<'tcx>,
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
locations: Locations,
@@ -49,7 +47,6 @@ pub(crate) fn new(
infcx: &'a InferCtxt<'tcx>,
universal_regions: &'a UniversalRegions<'tcx>,
region_bound_pairs: &'a RegionBoundPairs<'tcx>,
- implicit_region_bound: ty::Region<'tcx>,
param_env: ty::ParamEnv<'tcx>,
known_type_outlives_obligations: &'a [ty::PolyTypeOutlivesPredicate<'tcx>],
locations: Locations,
@@ -59,10 +56,8 @@ pub(crate) fn new(
) -> Self {
Self {
infcx,
- tcx: infcx.tcx,
universal_regions,
region_bound_pairs,
- implicit_region_bound,
param_env,
known_type_outlives_obligations,
locations,
@@ -96,7 +91,7 @@ pub(crate) fn apply_closure_requirements(
// into a vector. These are the regions that we will be
// relating to one another.
let closure_mapping = &UniversalRegions::closure_mapping(
- self.tcx,
+ self.infcx.tcx,
closure_args,
closure_requirements.num_external_vids,
closure_def_id,
@@ -111,7 +106,7 @@ pub(crate) fn apply_closure_requirements(
let subject = match outlives_requirement.subject {
ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
ClosureOutlivesSubject::Ty(subject_ty) => {
- subject_ty.instantiate(self.tcx, |vid| closure_mapping[vid]).into()
+ subject_ty.instantiate(self.infcx.tcx, |vid| closure_mapping[vid]).into()
}
};
@@ -127,14 +122,14 @@ fn convert(
predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
constraint_category: ConstraintCategory<'tcx>,
) {
+ let tcx = self.infcx.tcx;
debug!("generate: constraints at: {:#?}", self.locations);
// Extract out various useful fields we'll need below.
let ConstraintConversion {
- tcx,
infcx,
+ universal_regions,
region_bound_pairs,
- implicit_region_bound,
known_type_outlives_obligations,
..
} = *self;
@@ -145,7 +140,7 @@ fn convert(
break;
}
- if !self.tcx.recursion_limit().value_within_limit(iteration) {
+ if !tcx.recursion_limit().value_within_limit(iteration) {
bug!(
"FIXME(-Znext-solver): Overflowed when processing region obligations: {outlives_predicates:#?}"
);
@@ -170,10 +165,11 @@ fn convert(
);
}
+ let implicit_region_bound =
+ ty::Region::new_var(tcx, universal_regions.implicit_region_bound());
// we don't actually use this for anything, but
// the `TypeOutlives` code needs an origin.
let origin = infer::RelateParamBound(self.span, t1, None);
-
TypeOutlives::new(
&mut *self,
tcx,
@@ -205,7 +201,7 @@ fn convert(
/// are dealt with during trait solving.
fn replace_placeholders_with_nll<T: TypeFoldable<TyCtxt<'tcx>>>(&mut self, value: T) -> T {
if value.has_placeholders() {
- fold_regions(self.tcx, value, |r, _| match r.kind() {
+ fold_regions(self.infcx.tcx, value, |r, _| match r.kind() {
ty::RePlaceholder(placeholder) => {
self.constraints.placeholder_region(self.infcx, placeholder)
}
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index eaac633..536a277 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -49,14 +49,12 @@ pub(crate) struct CreateResult<'tcx> {
pub(crate) fn create<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- implicit_region_bound: ty::Region<'tcx>,
universal_regions: UniversalRegions<'tcx>,
constraints: &mut MirTypeckRegionConstraints<'tcx>,
) -> CreateResult<'tcx> {
UniversalRegionRelationsBuilder {
infcx,
param_env,
- implicit_region_bound,
constraints,
universal_regions,
region_bound_pairs: Default::default(),
@@ -181,7 +179,6 @@ struct UniversalRegionRelationsBuilder<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
universal_regions: UniversalRegions<'tcx>,
- implicit_region_bound: ty::Region<'tcx>,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
// outputs:
@@ -320,7 +317,6 @@ pub(crate) fn create(mut self) -> CreateResult<'tcx> {
self.infcx,
&self.universal_regions,
&self.region_bound_pairs,
- self.implicit_region_bound,
param_env,
&known_type_outlives_obligations,
Locations::All(span),
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index a17dff5..3c00b81 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -113,7 +113,6 @@ pub(crate) fn type_check<'a, 'tcx>(
move_data: &MoveData<'tcx>,
location_map: Rc<DenseLocationMap>,
) -> MirTypeckResults<'tcx> {
- let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body);
let mut constraints = MirTypeckRegionConstraints {
placeholder_indices: PlaceholderIndices::default(),
placeholder_index_to_region: IndexVec::default(),
@@ -129,13 +128,7 @@ pub(crate) fn type_check<'a, 'tcx>(
region_bound_pairs,
normalized_inputs_and_output,
known_type_outlives_obligations,
- } = free_region_relations::create(
- infcx,
- infcx.param_env,
- implicit_region_bound,
- universal_regions,
- &mut constraints,
- );
+ } = free_region_relations::create(infcx, infcx.param_env, universal_regions, &mut constraints);
let pre_obligations = infcx.take_registered_region_obligations();
assert!(
@@ -160,7 +153,6 @@ pub(crate) fn type_check<'a, 'tcx>(
user_type_annotations: &body.user_type_annotations,
region_bound_pairs,
known_type_outlives_obligations,
- implicit_region_bound,
reported_errors: Default::default(),
universal_regions: &universal_region_relations.universal_regions,
location_table,
@@ -226,7 +218,6 @@ struct TypeChecker<'a, 'tcx> {
user_type_annotations: &'a CanonicalUserTypeAnnotations<'tcx>,
region_bound_pairs: RegionBoundPairs<'tcx>,
known_type_outlives_obligations: Vec<ty::PolyTypeOutlivesPredicate<'tcx>>,
- implicit_region_bound: ty::Region<'tcx>,
reported_errors: FxIndexSet<(Ty<'tcx>, Span)>,
universal_regions: &'a UniversalRegions<'tcx>,
location_table: &'a PoloniusLocationTable,
@@ -422,7 +413,6 @@ fn push_region_constraints(
self.infcx,
self.universal_regions,
&self.region_bound_pairs,
- self.implicit_region_bound,
self.infcx.param_env,
&self.known_type_outlives_obligations,
locations,
@@ -1567,11 +1557,15 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
}
}
CastKind::Transmute => {
- span_mirbug!(
- self,
- rvalue,
- "Unexpected CastKind::Transmute, which is not permitted in Analysis MIR",
- );
+ let ty_from = op.ty(self.body, tcx);
+ match ty_from.kind() {
+ ty::Pat(base, _) if base == ty => {}
+ _ => span_mirbug!(
+ self,
+ rvalue,
+ "Unexpected CastKind::Transmute {ty_from:?} -> {ty:?}, which is not permitted in Analysis MIR",
+ ),
+ }
}
}
}
@@ -2507,7 +2501,6 @@ fn prove_closure_bounds(
self.infcx,
self.universal_regions,
&self.region_bound_pairs,
- self.implicit_region_bound,
self.infcx.param_env,
&self.known_type_outlives_obligations,
locations,
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 5c57ab9..c11e14d 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -438,6 +438,10 @@ pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diag<'_, ()>) {
}
}
+ pub(crate) fn implicit_region_bound(&self) -> RegionVid {
+ self.fr_fn_body
+ }
+
pub(crate) fn tainted_by_errors(&self) -> Option<ErrorGuaranteed> {
self.indices.tainted_by_errors.get()
}
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 603dc90..73be954 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -231,8 +231,6 @@
builtin_macros_format_use_positional = consider using a positional formatting argument instead
-builtin_macros_invalid_crate_attribute = invalid crate attribute
-
builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
.note = only one `#[default]` attribute is needed
.label = `#[default]` used here
@@ -249,9 +247,9 @@
.suggestion = make `{$ident}` default
builtin_macros_naked_functions_testing_attribute =
- cannot use `#[naked]` with testing attributes
+ cannot use `#[unsafe(naked)]` with testing attributes
.label = function marked with testing attribute here
- .naked_attribute = `#[naked]` is incompatible with testing attributes
+ .naked_attribute = `#[unsafe(naked)]` is incompatible with testing attributes
builtin_macros_no_default_variant = `#[derive(Default)]` on enum with no `#[default]`
.label = this enum needs a unit variant marked with `#[default]`
diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs
index 4161829..6d97dfa 100644
--- a/compiler/rustc_builtin_macros/src/autodiff.rs
+++ b/compiler/rustc_builtin_macros/src/autodiff.rs
@@ -217,14 +217,12 @@ pub(crate) fn expand(
ast::StmtKind::Item(iitem) => extract_item_info(iitem),
_ => None,
},
- Annotatable::AssocItem(assoc_item, Impl { of_trait: false }) => {
- match &assoc_item.kind {
- ast::AssocItemKind::Fn(box ast::Fn { sig, ident, .. }) => {
- Some((assoc_item.vis.clone(), sig.clone(), ident.clone()))
- }
- _ => None,
+ Annotatable::AssocItem(assoc_item, Impl { .. }) => match &assoc_item.kind {
+ ast::AssocItemKind::Fn(box ast::Fn { sig, ident, .. }) => {
+ Some((assoc_item.vis.clone(), sig.clone(), ident.clone()))
}
- }
+ _ => None,
+ },
_ => None,
}) else {
dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() });
@@ -365,7 +363,7 @@ fn same_attribute(attr: &ast::AttrKind, item: &ast::AttrKind) -> bool {
}
Annotatable::Item(iitem.clone())
}
- Annotatable::AssocItem(ref mut assoc_item, i @ Impl { of_trait: false }) => {
+ Annotatable::AssocItem(ref mut assoc_item, i @ Impl { .. }) => {
if !assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) {
assoc_item.attrs.push(attr);
}
@@ -596,15 +594,14 @@ fn gen_enzyme_body(
}
};
let arg = ty.kind.is_simple_path().unwrap();
- let sl: Vec<Symbol> = vec![arg, kw::Default];
- let tmp = ecx.def_site_path(&sl);
+ let tmp = ecx.def_site_path(&[arg, kw::Default]);
let default_call_expr = ecx.expr_path(ecx.path(span, tmp));
let default_call_expr = ecx.expr_call(new_decl_span, default_call_expr, thin_vec![]);
body.stmts.push(ecx.stmt_expr(default_call_expr));
return body;
}
- let mut exprs: P<ast::Expr> = primal_call.clone();
+ let mut exprs: P<ast::Expr> = primal_call;
let d_ret_ty = match d_sig.decl.output {
FnRetTy::Ty(ref ty) => ty.clone(),
FnRetTy::Default(span) => {
@@ -622,7 +619,7 @@ fn gen_enzyme_body(
// type due to the Const return activity.
exprs = ecx.expr_call(new_decl_span, bb_call_expr, thin_vec![exprs]);
} else {
- let q = QSelf { ty: d_ret_ty.clone(), path_span: span, position: 0 };
+ let q = QSelf { ty: d_ret_ty, path_span: span, position: 0 };
let y =
ExprKind::Path(Some(P(q)), ecx.path_ident(span, Ident::from_str("default")));
let default_call_expr = ecx.expr(span, y);
@@ -640,8 +637,7 @@ fn gen_enzyme_body(
let mut exprs2 = thin_vec![exprs];
for arg in args.iter().skip(1) {
let arg = arg.kind.is_simple_path().unwrap();
- let sl: Vec<Symbol> = vec![arg, kw::Default];
- let tmp = ecx.def_site_path(&sl);
+ let tmp = ecx.def_site_path(&[arg, kw::Default]);
let default_call_expr = ecx.expr_path(ecx.path(span, tmp));
let default_call_expr =
ecx.expr_call(new_decl_span, default_call_expr, thin_vec![]);
@@ -799,8 +795,19 @@ fn gen_enzyme_decl(
d_inputs.push(shadow_arg.clone());
}
}
- DiffActivity::Dual | DiffActivity::DualOnly => {
- for i in 0..x.width {
+ DiffActivity::Dual
+ | DiffActivity::DualOnly
+ | DiffActivity::Dualv
+ | DiffActivity::DualvOnly => {
+ // the *v variants get lowered to enzyme_dupv and enzyme_dupnoneedv, which cause
+ // Enzyme to not expect N arguments, but one argument (which is instead larger).
+ let iterations =
+ if matches!(activity, DiffActivity::Dualv | DiffActivity::DualvOnly) {
+ 1
+ } else {
+ x.width
+ };
+ for i in 0..iterations {
let mut shadow_arg = arg.clone();
let old_name = if let PatKind::Ident(_, ident, _) = arg.pat.kind {
ident.name
@@ -823,7 +830,7 @@ fn gen_enzyme_decl(
DiffActivity::Const => {
// Nothing to do here.
}
- DiffActivity::None | DiffActivity::FakeActivitySize => {
+ DiffActivity::None | DiffActivity::FakeActivitySize(_) => {
panic!("Should not happen");
}
}
@@ -887,8 +894,8 @@ fn gen_enzyme_decl(
}
};
- if let DiffActivity::Dual = x.ret_activity {
- let kind = if x.width == 1 {
+ if matches!(x.ret_activity, DiffActivity::Dual | DiffActivity::Dualv) {
+ let kind = if x.width == 1 || matches!(x.ret_activity, DiffActivity::Dualv) {
// Dual can only be used for f32/f64 ret.
// In that case we return now a tuple with two floats.
TyKind::Tup(thin_vec![ty.clone(), ty.clone()])
@@ -903,7 +910,7 @@ fn gen_enzyme_decl(
let ty = P(rustc_ast::Ty { kind, id: ty.id, span: ty.span, tokens: None });
d_decl.output = FnRetTy::Ty(ty);
}
- if let DiffActivity::DualOnly = x.ret_activity {
+ if matches!(x.ret_activity, DiffActivity::DualOnly | DiffActivity::DualvOnly) {
// No need to change the return type,
// we will just return the shadow in place of the primal return.
// However, if we have a width > 1, then we don't return -> T, but -> [T; width]
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index b3ba907..da01e3e 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -92,11 +92,7 @@ fn configure_annotatable(mut self, annotatable: Annotatable) -> Annotatable {
// the location of `#[cfg]` and `#[cfg_attr]` in the token stream. The tokenization
// process is lossless, so this process is invisible to proc-macros.
- // 'Flatten' all nonterminals (i.e. `TokenKind::Interpolated`)
- // to `None`-delimited groups containing the corresponding tokens. This
- // is normally delayed until the proc-macro server actually needs to
- // provide a `TokenKind::Interpolated` to a proc-macro. We do this earlier,
- // so that we can handle cases like:
+ // Interesting cases:
//
// ```rust
// #[cfg_eval] #[cfg] $item
@@ -104,8 +100,8 @@ fn configure_annotatable(mut self, annotatable: Annotatable) -> Annotatable {
//
// where `$item` is `#[cfg_attr] struct Foo {}`. We want to make
// sure to evaluate *all* `#[cfg]` and `#[cfg_attr]` attributes - the simplest
- // way to do this is to do a single parse of a stream without any nonterminals.
- let orig_tokens = annotatable.to_tokens().flattened();
+ // way to do this is to do a single parse of the token stream.
+ let orig_tokens = annotatable.to_tokens();
// Re-parse the tokens, setting the `capture_cfg` flag to save extra information
// to the captured `AttrTokenStream` (specifically, we capture
diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
index 6afd8c4..423b6a1 100644
--- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
+++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
@@ -1,44 +1,37 @@
//! Attributes injected into the crate root from command line using `-Z crate-attr`.
-use rustc_ast::attr::mk_attr;
-use rustc_ast::{self as ast, AttrItem, AttrStyle, token};
-use rustc_parse::parser::ForceCollect;
-use rustc_parse::{new_parser_from_source_str, unwrap_or_emit_fatal};
+use rustc_ast::{self as ast};
+use rustc_errors::Diag;
+use rustc_parse::parser::attr::InnerAttrPolicy;
+use rustc_parse::{parse_in, source_str_to_stream};
use rustc_session::parse::ParseSess;
use rustc_span::FileName;
-use crate::errors;
-
pub fn inject(krate: &mut ast::Crate, psess: &ParseSess, attrs: &[String]) {
for raw_attr in attrs {
- let mut parser = unwrap_or_emit_fatal(new_parser_from_source_str(
- psess,
- FileName::cli_crate_attr_source_code(raw_attr),
- raw_attr.clone(),
- ));
-
- let start_span = parser.token.span;
- let AttrItem { unsafety, path, args, tokens: _ } =
- match parser.parse_attr_item(ForceCollect::No) {
- Ok(ai) => ai,
- Err(err) => {
+ let source = format!("#![{raw_attr}]");
+ let parse = || -> Result<ast::Attribute, Vec<Diag<'_>>> {
+ let tokens = source_str_to_stream(
+ psess,
+ FileName::cli_crate_attr_source_code(raw_attr),
+ source,
+ None,
+ )?;
+ parse_in(psess, tokens, "<crate attribute>", |p| {
+ p.parse_attribute(InnerAttrPolicy::Permitted)
+ })
+ .map_err(|e| vec![e])
+ };
+ let meta = match parse() {
+ Ok(meta) => meta,
+ Err(errs) => {
+ for err in errs {
err.emit();
- continue;
}
- };
- let end_span = parser.token.span;
- if parser.token != token::Eof {
- psess.dcx().emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
- continue;
- }
+ continue;
+ }
+ };
- krate.attrs.push(mk_attr(
- &psess.attr_id_generator,
- AttrStyle::Inner,
- unsafety,
- path,
- args,
- start_span.to(end_span),
- ));
+ krate.attrs.push(meta);
}
}
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index b9197be..d9aac54 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -527,15 +527,14 @@ pub(crate) fn expand_ext(
item.attrs
.iter()
.filter(|a| {
- [
+ a.has_any_name(&[
sym::allow,
sym::warn,
sym::deny,
sym::forbid,
sym::stable,
sym::unstable,
- ]
- .contains(&a.name_or_empty())
+ ])
})
.cloned(),
);
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 4bbe212..d14ad8f 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -1,7 +1,7 @@
use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan, SingleLabelManySpans,
- SubdiagMessageOp, Subdiagnostic,
+ Subdiagnostic,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{Ident, Span, Symbol};
@@ -110,13 +110,6 @@ pub(crate) struct ProcMacro {
}
#[derive(Diagnostic)]
-#[diag(builtin_macros_invalid_crate_attribute)]
-pub(crate) struct InvalidCrateAttr {
- #[primary_span]
- pub(crate) span: Span,
-}
-
-#[derive(Diagnostic)]
#[diag(builtin_macros_non_abi)]
pub(crate) struct NonABI {
#[primary_span]
@@ -691,13 +684,9 @@ pub(crate) struct FormatUnusedArg {
// Allow the singular form to be a subdiagnostic of the multiple-unused
// form of diagnostic.
impl Subdiagnostic for FormatUnusedArg {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("named", self.named);
- let msg = f(diag, crate::fluent_generated::builtin_macros_format_unused_arg.into());
+ let msg = diag.eagerly_translate(crate::fluent_generated::builtin_macros_format_unused_arg);
diag.span_label(self.span, msg);
}
}
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 606e855..bcd40f9 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -5,7 +5,6 @@
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(assert_matches)]
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index 09d5b73..93ca2e0 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -1,13 +1,4 @@
-#![feature(
- no_core,
- lang_items,
- never_type,
- linkage,
- extern_types,
- naked_functions,
- thread_local,
- repr_simd
-)]
+#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, repr_simd)]
#![no_core]
#![allow(dead_code, non_camel_case_types, internal_features)]
@@ -387,11 +378,9 @@ fn stack_val_align() {
}
#[cfg(all(not(jit), target_arch = "x86_64"))]
-#[naked]
+#[unsafe(naked)]
extern "C" fn naked_test() {
- unsafe {
- naked_asm!("ret");
- }
+ naked_asm!("ret")
}
#[repr(C)]
diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs
index ffdc6a7..2d9de2a 100644
--- a/compiler/rustc_codegen_cranelift/example/std_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/std_example.rs
@@ -8,9 +8,6 @@
unboxed_closures
)]
#![allow(internal_features)]
-// FIXME once abi_unsupported_vector_types is a hard error disable the foo test when the respective
-// target feature is not enabled.
-#![allow(abi_unsupported_vector_types)]
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index 3b48adb..6eef97c 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -1,6 +1,6 @@
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
use rustc_hir::LangItem;
-use rustc_middle::ty::{AssocKind, GenericArg};
+use rustc_middle::ty::{AssocTag, GenericArg};
use rustc_session::config::EntryFnType;
use rustc_span::{DUMMY_SP, Ident};
@@ -107,7 +107,7 @@ fn create_entry_fn(
.find_by_ident_and_kind(
tcx,
Ident::from_str("report"),
- AssocKind::Fn,
+ AssocTag::Fn,
termination_trait,
)
.unwrap();
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/ci.yml b/compiler/rustc_codegen_gcc/.github/workflows/ci.yml
index f96912e..ef02425 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/ci.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/ci.yml
@@ -1,8 +1,10 @@
name: CI
on:
- - push
- - pull_request
+ push:
+ branches:
+ - master
+ pull_request:
permissions:
contents: read
@@ -121,3 +123,22 @@
run: |
cd build_system
cargo test
+
+ # Summary job for the merge queue.
+ # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
+ success:
+ needs: [build, duplicates, build_system]
+ # We need to ensure this job does *not* get skipped if its dependencies fail,
+ # because a skipped job is considered a success by GitHub. So we have to
+ # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
+ # when the workflow is canceled manually.
+ if: ${{ !cancelled() }}
+ runs-on: ubuntu-latest
+ steps:
+ # Manually check the status of all dependencies. `if: failure()` does not work.
+ - name: Conclusion
+ run: |
+ # Print the dependent jobs to see them in the CI log
+ jq -C <<< '${{ toJson(needs) }}'
+ # Check if all jobs that we depend on (in the needs array) were successful.
+ jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/failures.yml b/compiler/rustc_codegen_gcc/.github/workflows/failures.yml
index d080bbf..bc42eb1 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/failures.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/failures.yml
@@ -2,7 +2,10 @@
name: Failures
on:
- - pull_request
+ push:
+ branches:
+ - master
+ pull_request:
permissions:
contents: read
@@ -108,3 +111,22 @@
echo "Error: 'the compiler unexpectedly panicked' found in output logs. CI Error!!"
exit 1
fi
+
+ # Summary job for the merge queue.
+ # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
+ success_failures:
+ needs: [build]
+ # We need to ensure this job does *not* get skipped if its dependencies fail,
+ # because a skipped job is considered a success by GitHub. So we have to
+ # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
+ # when the workflow is canceled manually.
+ if: ${{ !cancelled() }}
+ runs-on: ubuntu-latest
+ steps:
+ # Manually check the status of all dependencies. `if: failure()` does not work.
+ - name: Conclusion
+ run: |
+ # Print the dependent jobs to see them in the CI log
+ jq -C <<< '${{ toJson(needs) }}'
+ # Check if all jobs that we depend on (in the needs array) were successful.
+ jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml b/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml
index bb9e020..da9a150 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/gcc12.yml
@@ -1,8 +1,10 @@
name: CI libgccjit 12
on:
- - push
- - pull_request
+ push:
+ branches:
+ - master
+ pull_request:
permissions:
contents: read
@@ -85,3 +87,22 @@
#- name: Run tests
#run: |
#./y.sh test --release --clean --build-sysroot ${{ matrix.commands }} --no-default-features
+
+ # Summary job for the merge queue.
+ # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
+ success_gcc12:
+ needs: [build]
+ # We need to ensure this job does *not* get skipped if its dependencies fail,
+ # because a skipped job is considered a success by GitHub. So we have to
+ # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
+ # when the workflow is canceled manually.
+ if: ${{ !cancelled() }}
+ runs-on: ubuntu-latest
+ steps:
+ # Manually check the status of all dependencies. `if: failure()` does not work.
+ - name: Conclusion
+ run: |
+ # Print the dependent jobs to see them in the CI log
+ jq -C <<< '${{ toJson(needs) }}'
+ # Check if all jobs that we depend on (in the needs array) were successful.
+ jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml b/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml
index ed1fc02..21731f7 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/m68k.yml
@@ -3,8 +3,10 @@
name: m68k CI
on:
- - push
- - pull_request
+ push:
+ branches:
+ - master
+ pull_request:
permissions:
contents: read
@@ -105,3 +107,22 @@
- name: Run tests
run: |
./y.sh test --release --clean --build-sysroot --sysroot-features compiler_builtins/no-f16-f128 ${{ matrix.commands }}
+
+ # Summary job for the merge queue.
+ # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
+ success_m68k:
+ needs: [build]
+ # We need to ensure this job does *not* get skipped if its dependencies fail,
+ # because a skipped job is considered a success by GitHub. So we have to
+ # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
+ # when the workflow is canceled manually.
+ if: ${{ !cancelled() }}
+ runs-on: ubuntu-latest
+ steps:
+ # Manually check the status of all dependencies. `if: failure()` does not work.
+ - name: Conclusion
+ run: |
+ # Print the dependent jobs to see them in the CI log
+ jq -C <<< '${{ toJson(needs) }}'
+ # Check if all jobs that we depend on (in the needs array) were successful.
+ jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/release.yml b/compiler/rustc_codegen_gcc/.github/workflows/release.yml
index 886ce90..47a4028 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/release.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/release.yml
@@ -1,8 +1,10 @@
name: CI with sysroot compiled in release mode
on:
- - push
- - pull_request
+ push:
+ branches:
+ - master
+ pull_request:
permissions:
contents: read
@@ -82,3 +84,22 @@
echo "Test is done with LTO enabled, hence inlining should occur across crates"
exit 1
fi
+
+ # Summary job for the merge queue.
+ # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
+ success_release:
+ needs: [build]
+ # We need to ensure this job does *not* get skipped if its dependencies fail,
+ # because a skipped job is considered a success by GitHub. So we have to
+ # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
+ # when the workflow is canceled manually.
+ if: ${{ !cancelled() }}
+ runs-on: ubuntu-latest
+ steps:
+ # Manually check the status of all dependencies. `if: failure()` does not work.
+ - name: Conclusion
+ run: |
+ # Print the dependent jobs to see them in the CI log
+ jq -C <<< '${{ toJson(needs) }}'
+ # Check if all jobs that we depend on (in the needs array) were successful.
+ jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml b/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml
index d5ae614..4b9f48e 100644
--- a/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml
+++ b/compiler/rustc_codegen_gcc/.github/workflows/stdarch.yml
@@ -1,8 +1,10 @@
name: stdarch tests with sysroot compiled in release mode
on:
- - push
- - pull_request
+ push:
+ branches:
+ - master
+ pull_request:
permissions:
contents: read
@@ -102,3 +104,22 @@
# TODO: remove --skip test_mm512_stream_ps when stdarch is updated in rustc.
# TODO: remove --skip test_tile_ when it's implemented.
STDARCH_TEST_EVERYTHING=1 CHANNEL=release CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER="${{ matrix.cargo_runner }}" TARGET=x86_64-unknown-linux-gnu CG_RUSTFLAGS="-Ainternal_features --cfg stdarch_intel_sde" ./y.sh cargo test --manifest-path build/build_sysroot/sysroot_src/library/stdarch/Cargo.toml -- --skip rtm --skip tbm --skip sse4a --skip test_mm512_stream_ps --skip test_tile_
+
+ # Summary job for the merge queue.
+ # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
+ success_stdarch:
+ needs: [build]
+ # We need to ensure this job does *not* get skipped if its dependencies fail,
+ # because a skipped job is considered a success by GitHub. So we have to
+ # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run
+ # when the workflow is canceled manually.
+ if: ${{ !cancelled() }}
+ runs-on: ubuntu-latest
+ steps:
+ # Manually check the status of all dependencies. `if: failure()` does not work.
+ - name: Conclusion
+ run: |
+ # Print the dependent jobs to see them in the CI log
+ jq -C <<< '${{ toJson(needs) }}'
+ # Check if all jobs that we depend on (in the needs array) were successful.
+ jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}'
diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock
index 636e75b..832603a 100644
--- a/compiler/rustc_codegen_gcc/Cargo.lock
+++ b/compiler/rustc_codegen_gcc/Cargo.lock
@@ -56,18 +56,18 @@
[[package]]
name = "gccjit"
-version = "2.4.0"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72fd91f4adbf02b53cfc73c97bc33c5f253009043f30c56a5ec08dd5c8094dc8"
+checksum = "2895ddec764de7ac76fe6c056050c4801a80109c066f177a00a9cc8dee02b29b"
dependencies = [
"gccjit_sys",
]
[[package]]
name = "gccjit_sys"
-version = "0.5.0"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fb7b8f48a75e2cfe78c3d9a980b32771c34ffd12d196021ab3f98c49fbd2f0d"
+checksum = "ac133db68db8a6a8b2c51ef4b18d8ea16682d5814c4641272fe37bbbc223d5f3"
dependencies = [
"libc",
]
diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml
index 63d3735..b50f2a6 100644
--- a/compiler/rustc_codegen_gcc/Cargo.toml
+++ b/compiler/rustc_codegen_gcc/Cargo.toml
@@ -22,7 +22,7 @@
default = ["master"]
[dependencies]
-gccjit = "2.4"
+gccjit = "2.5"
#gccjit = { git = "https://github.com/rust-lang/gccjit.rs" }
# Local copy.
diff --git a/compiler/rustc_codegen_gcc/Readme.md b/compiler/rustc_codegen_gcc/Readme.md
index e92c16e..d0e4dbb 100644
--- a/compiler/rustc_codegen_gcc/Readme.md
+++ b/compiler/rustc_codegen_gcc/Readme.md
@@ -23,7 +23,7 @@
## Building
**This requires a patched libgccjit in order to work.
-You need to use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.**
+You need to use my [fork of gcc](https://github.com/rust-lang/gcc) which already includes these patches.**
```bash
$ cp config.example.toml config.toml
@@ -40,7 +40,7 @@
To build it (most of these instructions come from [here](https://gcc.gnu.org/onlinedocs/jit/internals/index.html), so don't hesitate to take a look there if you encounter an issue):
```bash
-$ git clone https://github.com/antoyo/gcc
+$ git clone https://github.com/rust-lang/gcc
$ sudo apt install flex libmpfr-dev libgmp-dev libmpc3 libmpc-dev
$ mkdir gcc-build gcc-install
$ cd gcc-build
diff --git a/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs b/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs
index e28ee87..b49dd47 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/clone_gcc.rs
@@ -61,7 +61,7 @@ pub fn run() -> Result<(), String> {
return Ok(());
};
- let result = git_clone("https://github.com/antoyo/gcc", Some(&args.out_path), false)?;
+ let result = git_clone("https://github.com/rust-lang/gcc", Some(&args.out_path), false)?;
if result.ran_clone {
let gcc_commit = args.config_info.get_gcc_commit()?;
println!("Checking out GCC commit `{}`...", gcc_commit);
diff --git a/compiler/rustc_codegen_gcc/build_system/src/test.rs b/compiler/rustc_codegen_gcc/build_system/src/test.rs
index 6c29c7d..df4ac85 100644
--- a/compiler/rustc_codegen_gcc/build_system/src/test.rs
+++ b/compiler/rustc_codegen_gcc/build_system/src/test.rs
@@ -529,20 +529,21 @@ fn asm_tests(env: &Env, args: &TestArg) -> Result<(), String> {
env.insert("COMPILETEST_FORCE_STAGE0".to_string(), "1".to_string());
- let extra =
- if args.is_using_gcc_master_branch() { "" } else { " -Csymbol-mangling-version=v0" };
-
- let rustc_args = &format!(
- r#"-Zpanic-abort-tests \
- -Zcodegen-backend="{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}" \
- --sysroot "{sysroot_dir}" -Cpanic=abort{extra}"#,
+ let codegen_backend_path = format!(
+ "{pwd}/target/{channel}/librustc_codegen_gcc.{dylib_ext}",
pwd = std::env::current_dir()
.map_err(|error| format!("`current_dir` failed: {:?}", error))?
.display(),
channel = args.config_info.channel.as_str(),
dylib_ext = args.config_info.dylib_ext,
- sysroot_dir = args.config_info.sysroot_path,
- extra = extra,
+ );
+
+ let extra =
+ if args.is_using_gcc_master_branch() { "" } else { " -Csymbol-mangling-version=v0" };
+
+ let rustc_args = format!(
+ "-Zpanic-abort-tests -Zcodegen-backend={codegen_backend_path} --sysroot {} -Cpanic=abort{extra}",
+ args.config_info.sysroot_path
);
run_command_with_env(
@@ -677,7 +678,7 @@ fn test_projects(env: &Env, args: &TestArg) -> Result<(), String> {
fn test_libcore(env: &Env, args: &TestArg) -> Result<(), String> {
// FIXME: create a function "display_if_not_quiet" or something along the line.
println!("[TEST] libcore");
- let path = get_sysroot_dir().join("sysroot_src/library/core/tests");
+ let path = get_sysroot_dir().join("sysroot_src/library/coretests");
let _ = remove_dir_all(path.join("target"));
run_cargo_command(&[&"test"], Some(&path), env, args)?;
Ok(())
diff --git a/compiler/rustc_codegen_gcc/doc/add-attribute.md b/compiler/rustc_codegen_gcc/doc/add-attribute.md
index ae3bcc5..267c181 100644
--- a/compiler/rustc_codegen_gcc/doc/add-attribute.md
+++ b/compiler/rustc_codegen_gcc/doc/add-attribute.md
@@ -14,4 +14,4 @@
To test it, build `gcc`, run `cargo update -p gccjit` and then you can test the generated output for a given Rust crate.
-[gccjit.rs]: https://github.com/antoyo/gccjit.rs
+[gccjit.rs]: https://github.com/rust-lang/gccjit.rs
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
index 5544aee..c554a87 100644
--- a/compiler/rustc_codegen_gcc/example/mini_core.rs
+++ b/compiler/rustc_codegen_gcc/example/mini_core.rs
@@ -51,6 +51,10 @@ impl<T: ?Sized> LegacyReceiver for &T {}
impl<T: ?Sized> LegacyReceiver for &mut T {}
impl<T: ?Sized, A: Allocator> LegacyReceiver for Box<T, A> {}
+#[lang = "receiver"]
+trait Receiver {
+}
+
#[lang = "copy"]
pub trait Copy {}
@@ -134,6 +138,14 @@ fn mul(self, rhs: Self) -> Self::Output {
}
}
+impl Mul for i32 {
+ type Output = Self;
+
+ fn mul(self, rhs: Self) -> Self::Output {
+ self * rhs
+ }
+}
+
impl Mul for usize {
type Output = Self;
@@ -142,6 +154,14 @@ fn mul(self, rhs: Self) -> Self::Output {
}
}
+impl Mul for isize {
+ type Output = Self;
+
+ fn mul(self, rhs: Self) -> Self::Output {
+ self * rhs
+ }
+}
+
#[lang = "add"]
pub trait Add<RHS = Self> {
type Output;
@@ -165,6 +185,14 @@ fn add(self, rhs: Self) -> Self {
}
}
+impl Add for i32 {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self {
+ self + rhs
+ }
+}
+
impl Add for usize {
type Output = Self;
@@ -196,6 +224,14 @@ fn sub(self, rhs: Self) -> Self {
}
}
+impl Sub for isize {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
impl Sub for u8 {
type Output = Self;
@@ -220,6 +256,14 @@ fn sub(self, rhs: Self) -> Self {
}
}
+impl Sub for i32 {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self {
+ self - rhs
+ }
+}
+
#[lang = "rem"]
pub trait Rem<RHS = Self> {
type Output;
@@ -628,6 +672,10 @@ pub mod libc {
pub fn memcpy(dst: *mut u8, src: *const u8, size: usize);
pub fn memmove(dst: *mut u8, src: *const u8, size: usize);
pub fn strncpy(dst: *mut u8, src: *const u8, size: usize);
+ pub fn fflush(stream: *mut i32) -> i32;
+ pub fn exit(status: i32);
+
+ pub static stdout: *mut i32;
}
}
diff --git a/compiler/rustc_codegen_gcc/libgccjit.version b/compiler/rustc_codegen_gcc/libgccjit.version
index 417fd5b..125b040 100644
--- a/compiler/rustc_codegen_gcc/libgccjit.version
+++ b/compiler/rustc_codegen_gcc/libgccjit.version
@@ -1 +1 @@
-e607be166673a8de9fc07f6f02c60426e556c5f2
+0ea98a1365b81f7488073512c850e8ee951a4afd
diff --git a/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch
deleted file mode 100644
index 70e3e2b..0000000
--- a/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch
+++ /dev/null
@@ -1,44 +0,0 @@
-From af0e237f056fa838c77463381a19b0dc993c0a35 Mon Sep 17 00:00:00 2001
-From: None <none@example.com>
-Date: Sun, 1 Sep 2024 11:42:17 -0400
-Subject: [PATCH] Disable not compiling tests
-
----
- library/core/tests/Cargo.toml | 14 ++++++++++++++
- library/core/tests/lib.rs | 1 +
- 2 files changed, 15 insertions(+)
- create mode 100644 library/core/tests/Cargo.toml
-
-diff --git a/library/core/tests/Cargo.toml b/library/core/tests/Cargo.toml
-new file mode 100644
-index 0000000..ca326ac
---- /dev/null
-+++ b/library/core/tests/Cargo.toml
-@@ -0,0 +1,14 @@
-+[workspace]
-+
-+[package]
-+name = "coretests"
-+version = "0.0.0"
-+edition = "2021"
-+
-+[lib]
-+name = "coretests"
-+path = "lib.rs"
-+
-+[dependencies]
-+rand = { version = "0.8.5", default-features = false }
-+rand_xorshift = { version = "0.3.0", default-features = false }
-diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
-index a4a7946..ecfe43f 100644
---- a/library/core/tests/lib.rs
-+++ b/library/core/tests/lib.rs
-@@ -1,4 +1,5 @@
- // tidy-alphabetical-start
-+#![cfg(test)]
- #![cfg_attr(target_has_atomic = "128", feature(integer_atomics))]
- #![cfg_attr(test, feature(cfg_match))]
- #![feature(alloc_layout_extra)]
---
-2.47.1
-
diff --git a/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch b/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch
index dc1beae..20df424 100644
--- a/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch
+++ b/compiler/rustc_codegen_gcc/patches/0028-core-Disable-long-running-tests.patch
@@ -1,17 +1,17 @@
-From eb703e627e7a84f1cd8d0d87f0f69da1f0acf765 Mon Sep 17 00:00:00 2001
-From: bjorn3 <bjorn3@users.noreply.github.com>
-Date: Fri, 3 Dec 2021 12:16:30 +0100
+From ec2d0dc77fb484d926b45bb626b0db6a4bb0ab5c Mon Sep 17 00:00:00 2001
+From: None <none@example.com>
+Date: Thu, 27 Mar 2025 09:20:41 -0400
Subject: [PATCH] Disable long running tests
---
- library/core/tests/slice.rs | 2 ++
+ library/coretests/tests/slice.rs | 2 ++
1 file changed, 2 insertions(+)
-diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
-index 8402833..84592e0 100644
---- a/library/core/tests/slice.rs
-+++ b/library/core/tests/slice.rs
-@@ -2462,6 +2462,7 @@ take_tests! {
+diff --git a/library/coretests/tests/slice.rs b/library/coretests/tests/slice.rs
+index d17e681..fba5cd6 100644
+--- a/library/coretests/tests/slice.rs
++++ b/library/coretests/tests/slice.rs
+@@ -2486,6 +2486,7 @@ split_off_tests! {
#[cfg(not(miri))] // unused in Miri
const EMPTY_MAX: &'static [()] = &[(); usize::MAX];
@@ -19,14 +19,14 @@
// can't be a constant due to const mutability rules
#[cfg(not(miri))] // unused in Miri
macro_rules! empty_max_mut {
-@@ -2485,6 +2486,7 @@ take_tests! {
- (take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()),
- (take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()),
+@@ -2509,6 +2510,7 @@ split_off_tests! {
+ (split_off_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()),
+ (split_off_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()),
}
+*/
#[test]
fn test_slice_from_ptr_range() {
--
-2.26.2.7.g19db9cfb68
+2.49.0
diff --git a/compiler/rustc_codegen_gcc/patches/cross_patches/0001-Disable-libstd-and-libtest-dylib.patch b/compiler/rustc_codegen_gcc/patches/cross_patches/0001-Disable-libstd-and-libtest-dylib.patch
index c220f53..fa360fe 100644
--- a/compiler/rustc_codegen_gcc/patches/cross_patches/0001-Disable-libstd-and-libtest-dylib.patch
+++ b/compiler/rustc_codegen_gcc/patches/cross_patches/0001-Disable-libstd-and-libtest-dylib.patch
@@ -1,19 +1,18 @@
-From 966beefe08be6045bfcca26079b76a7a80413080 Mon Sep 17 00:00:00 2001
+From b2911e732d1bf0e28872495c4c47af1dad3c7911 Mon Sep 17 00:00:00 2001
From: None <none@example.com>
-Date: Thu, 28 Sep 2023 17:37:38 -0400
+Date: Thu, 27 Mar 2025 14:30:10 -0400
Subject: [PATCH] Disable libstd and libtest dylib
---
- library/std/Cargo.toml | 2 +-
- library/test/Cargo.toml | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
+ library/std/Cargo.toml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
-index 5b21355..cb0c49b 100644
+index 176da60..c183cdb 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
-@@ -9,7 +9,7 @@ description = "The Rust Standard Library"
- edition = "2021"
+@@ -10,7 +10,7 @@ edition = "2024"
+ autobenches = false
[lib]
-crate-type = ["dylib", "rlib"]
@@ -21,3 +20,6 @@
[dependencies]
alloc = { path = "../alloc", public = true }
+--
+2.49.0
+
diff --git a/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch b/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch
index 9ef5e0e..9d5b2dc 100644
--- a/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch
+++ b/compiler/rustc_codegen_gcc/patches/libgccjit12/0001-core-Disable-portable-simd-test.patch
@@ -1,25 +1,17 @@
-From 124a11ce086952a5794d5cfbaa45175809497b81 Mon Sep 17 00:00:00 2001
+From 1a8f6b8e39f343959d4d2e6b6957a6d780ac3fc0 Mon Sep 17 00:00:00 2001
From: None <none@example.com>
-Date: Sat, 18 Nov 2023 10:50:36 -0500
-Subject: [PATCH] [core] Disable portable-simd test
+Date: Thu, 27 Mar 2025 14:32:14 -0400
+Subject: [PATCH] Disable portable-simd test
---
- library/core/tests/lib.rs | 2 --
- 1 file changed, 2 deletions(-)
+ library/coretests/tests/lib.rs | 1 -
+ 1 file changed, 1 deletion(-)
-diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
-index b71786c..cf484d5 100644
---- a/library/core/tests/lib.rs
-+++ b/library/core/tests/lib.rs
-@@ -87,7 +87,6 @@
- #![feature(numfmt)]
- #![feature(pattern)]
- #![feature(pointer_is_aligned_to)]
--#![feature(portable_simd)]
- #![feature(ptr_metadata)]
- #![feature(slice_from_ptr_range)]
- #![feature(slice_internals)]
-@@ -155,7 +154,6 @@ mod pin;
+diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
+index 79022fe..9223b2f 100644
+--- a/library/coretests/tests/lib.rs
++++ b/library/coretests/tests/lib.rs
+@@ -165,7 +165,6 @@ mod pin;
mod pin_macro;
mod ptr;
mod result;
@@ -27,4 +19,6 @@
mod slice;
mod str;
mod str_lossy;
--- 2.45.2
+--
+2.49.0
+
diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain
index 940b3de..fd898c5 100644
--- a/compiler/rustc_codegen_gcc/rust-toolchain
+++ b/compiler/rustc_codegen_gcc/rust-toolchain
@@ -1,3 +1,3 @@
[toolchain]
-channel = "nightly-2025-01-12"
+channel = "nightly-2025-04-17"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs
index 9fe6baa..a96b18e 100644
--- a/compiler/rustc_codegen_gcc/src/abi.rs
+++ b/compiler/rustc_codegen_gcc/src/abi.rs
@@ -9,6 +9,8 @@
use rustc_middle::ty::layout::LayoutOf;
#[cfg(feature = "master")]
use rustc_session::config;
+#[cfg(feature = "master")]
+use rustc_target::callconv::Conv;
use rustc_target::callconv::{ArgAttributes, CastTarget, FnAbi, PassMode};
use crate::builder::Builder;
@@ -105,6 +107,8 @@ pub trait FnAbiGccExt<'gcc, 'tcx> {
// TODO(antoyo): return a function pointer type instead?
fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> FnAbiGcc<'gcc>;
fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+ #[cfg(feature = "master")]
+ fn gcc_cconv(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Option<FnAttribute<'gcc>>;
}
impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
@@ -227,4 +231,47 @@ fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
);
pointer_type
}
+
+ #[cfg(feature = "master")]
+ fn gcc_cconv(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Option<FnAttribute<'gcc>> {
+ conv_to_fn_attribute(self.conv, &cx.tcx.sess.target.arch)
+ }
+}
+
+#[cfg(feature = "master")]
+pub fn conv_to_fn_attribute<'gcc>(conv: Conv, arch: &str) -> Option<FnAttribute<'gcc>> {
+ // TODO: handle the calling conventions returning None.
+ let attribute = match conv {
+ Conv::C
+ | Conv::Rust
+ | Conv::CCmseNonSecureCall
+ | Conv::CCmseNonSecureEntry
+ | Conv::RiscvInterrupt { .. } => return None,
+ Conv::Cold => return None,
+ Conv::PreserveMost => return None,
+ Conv::PreserveAll => return None,
+ Conv::GpuKernel => {
+ // TODO(antoyo): remove clippy allow attribute when this is implemented.
+ #[allow(clippy::if_same_then_else)]
+ if arch == "amdgpu" {
+ return None;
+ } else if arch == "nvptx64" {
+ return None;
+ } else {
+ panic!("Architecture {} does not support GpuKernel calling convention", arch);
+ }
+ }
+ Conv::AvrInterrupt => return None,
+ Conv::AvrNonBlockingInterrupt => return None,
+ Conv::ArmAapcs => return None,
+ Conv::Msp430Intr => return None,
+ Conv::X86Fastcall => return None,
+ Conv::X86Intr => return None,
+ Conv::X86Stdcall => return None,
+ Conv::X86ThisCall => return None,
+ Conv::X86VectorCall => return None,
+ Conv::X86_64SysV => FnAttribute::SysvAbi,
+ Conv::X86_64Win64 => FnAttribute::MsAbi,
+ };
+ Some(attribute)
}
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 415f8af..dbdf37e 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -36,7 +36,8 @@
//
// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes.
// Contrary, Rust expresses clobbers through "out" operands that aren't tied to
-// a variable (`_`), and such "clobbers" do have index.
+// a variable (`_`), and such "clobbers" do have index. Input operands cannot also
+// be clobbered.
//
// 4. Furthermore, GCC Extended Asm does not support explicit register constraints
// (like `out("eax")`) directly, offering so-called "local register variables"
@@ -161,6 +162,16 @@ fn codegen_inline_asm(
// Also, we don't emit any asm operands immediately; we save them to
// the one of the buffers to be emitted later.
+ let mut input_registers = vec![];
+
+ for op in rust_operands {
+ if let InlineAsmOperandRef::In { reg, .. } = *op {
+ if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
+ input_registers.push(reg_name);
+ }
+ }
+ }
+
// 1. Normal variables (and saving operands to buffers).
for (rust_idx, op) in rust_operands.iter().enumerate() {
match *op {
@@ -183,25 +194,39 @@ fn codegen_inline_asm(
continue;
}
(Register(reg_name), None) => {
- // `clobber_abi` can add lots of clobbers that are not supported by the target,
- // such as AVX-512 registers, so we just ignore unsupported registers
- let is_target_supported =
- reg.reg_class().supported_types(asm_arch, true).iter().any(
- |&(_, feature)| {
- if let Some(feature) = feature {
- self.tcx
- .asm_target_features(instance.def_id())
- .contains(&feature)
- } else {
- true // Register class is unconditionally supported
- }
- },
- );
+ if input_registers.contains(®_name) {
+ // the `clobber_abi` operand is converted into a series of
+ // `lateout("reg") _` operands. Of course, a user could also
+ // explicitly define such an output operand.
+ //
+ // GCC does not allow input registers to be clobbered, so if this out register
+ // is also used as an in register, do not add it to the clobbers list.
+ // it will be treated as a lateout register with `out_place: None`
+ if !late {
+ bug!("input registers can only be used as lateout regisers");
+ }
+ ("r", dummy_output_type(self.cx, reg.reg_class()))
+ } else {
+ // `clobber_abi` can add lots of clobbers that are not supported by the target,
+ // such as AVX-512 registers, so we just ignore unsupported registers
+ let is_target_supported =
+ reg.reg_class().supported_types(asm_arch, true).iter().any(
+ |&(_, feature)| {
+ if let Some(feature) = feature {
+ self.tcx
+ .asm_target_features(instance.def_id())
+ .contains(&feature)
+ } else {
+ true // Register class is unconditionally supported
+ }
+ },
+ );
- if is_target_supported && !clobbers.contains(®_name) {
- clobbers.push(reg_name);
+ if is_target_supported && !clobbers.contains(®_name) {
+ clobbers.push(reg_name);
+ }
+ continue;
}
- continue;
}
};
@@ -230,13 +255,10 @@ fn codegen_inline_asm(
}
InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
- let constraint =
- if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
- constraint
- } else {
- // left for the next pass
- continue;
- };
+ let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) else {
+ // left for the next pass
+ continue;
+ };
// Rustc frontend guarantees that input and output types are "compatible",
// so we can just use input var's type for the output variable.
@@ -589,114 +611,127 @@ fn estimate_template_length(
}
/// Converts a register class to a GCC constraint code.
-fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
- let constraint = match reg {
- // For vector registers LLVM wants the register name to match the type size.
+fn reg_to_gcc(reg_or_reg_class: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
+ match reg_or_reg_class {
InlineAsmRegOrRegClass::Reg(reg) => {
- match reg {
- InlineAsmReg::X86(_) => {
- // TODO(antoyo): add support for vector register.
- //
- // // For explicit registers, we have to create a register variable: https://stackoverflow.com/a/31774784/389119
- return ConstraintOrRegister::Register(match reg.name() {
- // Some of registers' names does not map 1-1 from rust to gcc
- "st(0)" => "st",
+ ConstraintOrRegister::Register(explicit_reg_to_gcc(reg))
+ }
+ InlineAsmRegOrRegClass::RegClass(reg_class) => {
+ ConstraintOrRegister::Constraint(reg_class_to_gcc(reg_class))
+ }
+ }
+}
- name => name,
- });
+fn explicit_reg_to_gcc(reg: InlineAsmReg) -> &'static str {
+ // For explicit registers, we have to create a register variable: https://stackoverflow.com/a/31774784/389119
+ match reg {
+ InlineAsmReg::X86(reg) => {
+ // TODO(antoyo): add support for vector register.
+ match reg.reg_class() {
+ X86InlineAsmRegClass::reg_byte => {
+ // GCC does not support the `b` suffix, so we just strip it
+ // see https://github.com/rust-lang/rustc_codegen_gcc/issues/485
+ reg.name().trim_end_matches('b')
}
+ _ => match reg.name() {
+ // Some of registers' names does not map 1-1 from rust to gcc
+ "st(0)" => "st",
- _ => unimplemented!(),
+ name => name,
+ },
}
}
- // They can be retrieved from https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html
- InlineAsmRegOrRegClass::RegClass(reg) => match reg {
- InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r",
- InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w",
- InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x",
- InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
- unreachable!("clobber-only")
- }
- InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r",
- InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
- | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
- | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8)
- | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16)
- | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8)
- | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4)
- | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
- | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "t",
- InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => "r",
- InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_upper) => "d",
- InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => "r",
- InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w",
- InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e",
- InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
- InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
- InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
- InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::preg) => {
- unreachable!("clobber-only")
- }
- InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
- InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f",
- InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r",
- InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a",
- InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d",
- InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::reg) => "r",
- InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::freg) => "f",
- InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "d", // more specific than "r"
- InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f",
- InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r",
- // https://github.com/gcc-mirror/gcc/blob/master/gcc/config/nvptx/nvptx.md -> look for
- // "define_constraint".
- InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
- InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
- InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
- InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
- InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
- InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
- InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => "v",
- InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
- | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
- unreachable!("clobber-only")
- }
- InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
- InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
- InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
- unreachable!("clobber-only")
- }
- InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
- InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q",
- InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q",
- InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
- | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
- InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
- InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "Yk",
- InlineAsmRegClass::X86(
- X86InlineAsmRegClass::kreg0
- | X86InlineAsmRegClass::x87_reg
- | X86InlineAsmRegClass::mmx_reg
- | X86InlineAsmRegClass::tmm_reg,
- ) => unreachable!("clobber-only"),
- InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
- bug!("GCC backend does not support SPIR-V")
- }
- InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
- InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
- InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
- InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
- InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => "v",
- InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
- unreachable!("clobber-only")
- }
- InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => "r",
- InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"),
- InlineAsmRegClass::Err => unreachable!(),
- },
- };
+ _ => unimplemented!(),
+ }
+}
- ConstraintOrRegister::Constraint(constraint)
+/// They can be retrieved from https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html
+fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str {
+ match reg_class {
+ InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w",
+ InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x",
+ InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
+ unreachable!("clobber-only")
+ }
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
+ | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "t",
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_upper) => "d",
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => "r",
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w",
+ InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e",
+ InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
+ InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::preg) => {
+ unreachable!("clobber-only")
+ }
+ InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f",
+ InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a",
+ InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d",
+ InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::freg) => "f",
+ InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "d", // more specific than "r"
+ InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f",
+ InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r",
+ // https://github.com/gcc-mirror/gcc/blob/master/gcc/config/nvptx/nvptx.md -> look for
+ // "define_constraint".
+ InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
+ InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
+ InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
+
+ InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
+ InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
+ InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => "v",
+ InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
+ | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
+ unreachable!("clobber-only")
+ }
+ InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
+ InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
+ unreachable!("clobber-only")
+ }
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q",
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q",
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
+ | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
+ InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "Yk",
+ InlineAsmRegClass::X86(
+ X86InlineAsmRegClass::kreg0
+ | X86InlineAsmRegClass::x87_reg
+ | X86InlineAsmRegClass::mmx_reg
+ | X86InlineAsmRegClass::tmm_reg,
+ ) => unreachable!("clobber-only"),
+ InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
+ bug!("GCC backend does not support SPIR-V")
+ }
+ InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
+ InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
+ InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
+ InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => "v",
+ InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
+ unreachable!("clobber-only")
+ }
+ InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"),
+ InlineAsmRegClass::Err => unreachable!(),
+ }
}
/// Type to use for outputs that are discarded. It doesn't really matter what
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 6573b5b..5c70f4a 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -368,16 +368,8 @@ fn function_ptr_call(
let previous_arg_count = args.len();
let orig_args = args;
let args = {
- let function_address_names = self.function_address_names.borrow();
- let original_function_name = function_address_names.get(&func_ptr);
func_ptr = llvm::adjust_function(self.context, &func_name, func_ptr, args);
- llvm::adjust_intrinsic_arguments(
- self,
- gcc_func,
- args.into(),
- &func_name,
- original_function_name,
- )
+ llvm::adjust_intrinsic_arguments(self, gcc_func, args.into(), &func_name)
};
let args_adjusted = args.len() != previous_arg_count;
let args = self.check_ptr_call("call", func_ptr, &args);
@@ -1271,7 +1263,50 @@ fn icmp(&mut self, op: IntPredicate, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RV
}
fn fcmp(&mut self, op: RealPredicate, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
- self.context.new_comparison(self.location, op.to_gcc_comparison(), lhs, rhs)
+ // LLVM has a concept of "unordered compares", where eg ULT returns true if either the two
+ // arguments are unordered (i.e. either is NaN), or the lhs is less than the rhs. GCC does
+ // not natively have this concept, so in some cases we must manually handle NaNs
+ let must_handle_nan = match op {
+ RealPredicate::RealPredicateFalse => unreachable!(),
+ RealPredicate::RealOEQ => false,
+ RealPredicate::RealOGT => false,
+ RealPredicate::RealOGE => false,
+ RealPredicate::RealOLT => false,
+ RealPredicate::RealOLE => false,
+ RealPredicate::RealONE => false,
+ RealPredicate::RealORD => unreachable!(),
+ RealPredicate::RealUNO => unreachable!(),
+ RealPredicate::RealUEQ => false,
+ RealPredicate::RealUGT => true,
+ RealPredicate::RealUGE => true,
+ RealPredicate::RealULT => true,
+ RealPredicate::RealULE => true,
+ RealPredicate::RealUNE => false,
+ RealPredicate::RealPredicateTrue => unreachable!(),
+ };
+
+ let cmp = self.context.new_comparison(self.location, op.to_gcc_comparison(), lhs, rhs);
+
+ if must_handle_nan {
+ let is_nan = self.context.new_binary_op(
+ self.location,
+ BinaryOp::LogicalOr,
+ self.cx.bool_type,
+ // compare a value to itself to check whether it is NaN
+ self.context.new_comparison(self.location, ComparisonOp::NotEquals, lhs, lhs),
+ self.context.new_comparison(self.location, ComparisonOp::NotEquals, rhs, rhs),
+ );
+
+ self.context.new_binary_op(
+ self.location,
+ BinaryOp::LogicalOr,
+ self.cx.bool_type,
+ is_nan,
+ cmp,
+ )
+ } else {
+ cmp
+ }
}
/* Miscellaneous instructions */
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index 1e1f577..7371899 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -23,6 +23,8 @@
HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, TlsModel, WasmCAbi, X86Abi,
};
+#[cfg(feature = "master")]
+use crate::abi::conv_to_fn_attribute;
use crate::callee::get_fn;
use crate::common::SignType;
@@ -213,33 +215,7 @@ pub fn new(
let bool_type = context.new_type::<bool>();
let mut functions = FxHashMap::default();
- let builtins = [
- "__builtin_unreachable",
- "abort",
- "__builtin_expect", /*"__builtin_expect_with_probability",*/
- "__builtin_constant_p",
- "__builtin_add_overflow",
- "__builtin_mul_overflow",
- "__builtin_saddll_overflow",
- /*"__builtin_sadd_overflow",*/
- "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/
- "__builtin_ssubll_overflow",
- /*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow",
- "__builtin_uaddll_overflow",
- "__builtin_uadd_overflow",
- "__builtin_umulll_overflow",
- "__builtin_umul_overflow",
- "__builtin_usubll_overflow",
- "__builtin_usub_overflow",
- "__builtin_powif",
- "__builtin_powi",
- "fabsf",
- "fabs",
- "copysignf",
- "copysign",
- "nearbyintf",
- "nearbyint",
- ];
+ let builtins = ["abort"];
for builtin in builtins.iter() {
functions.insert(builtin.to_string(), context.get_builtin_function(builtin));
@@ -509,7 +485,11 @@ fn apply_target_cpu_attr(&self, _llfn: RValue<'gcc>) {
fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
let entry_name = self.sess().target.entry_name.as_ref();
if !self.functions.borrow().contains_key(entry_name) {
- Some(self.declare_entry_fn(entry_name, fn_type, ()))
+ #[cfg(feature = "master")]
+ let conv = conv_to_fn_attribute(self.sess().target.entry_abi, &self.sess().target.arch);
+ #[cfg(not(feature = "master"))]
+ let conv = None;
+ Some(self.declare_entry_fn(entry_name, fn_type, conv))
} else {
// If the symbol already exists, it is an error: for example, the user wrote
// #[no_mangle] extern "C" fn main(..) {..}
@@ -605,7 +585,10 @@ pub fn generate_local_symbol_name(&self, prefix: &str) -> String {
let mut name = String::with_capacity(prefix.len() + 6);
name.push_str(prefix);
name.push('.');
- name.push_str(&(idx as u64).to_base(ALPHANUMERIC_ONLY));
+ // Offset the index by the base so that always at least two characters
+ // are generated. This avoids cases where the suffix is interpreted as
+ // size by the assembler (for m68k: .b, .w, .l).
+ name.push_str(&(idx as u64 + ALPHANUMERIC_ONLY as u64).to_base(ALPHANUMERIC_ONLY));
name
}
}
diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs
index 7cdbe3c..c1ca3eb 100644
--- a/compiler/rustc_codegen_gcc/src/declare.rs
+++ b/compiler/rustc_codegen_gcc/src/declare.rs
@@ -58,7 +58,7 @@ pub fn declare_func(
variadic: bool,
) -> Function<'gcc> {
self.linkage.set(FunctionType::Extern);
- declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic)
+ declare_raw_fn(self, name, None, return_type, params, variadic)
}
pub fn declare_global(
@@ -92,7 +92,8 @@ pub fn declare_entry_fn(
&self,
name: &str,
_fn_type: Type<'gcc>,
- callconv: (), /*llvm::CCallConv*/
+ #[cfg(feature = "master")] callconv: Option<FnAttribute<'gcc>>,
+ #[cfg(not(feature = "master"))] callconv: Option<()>,
) -> RValue<'gcc> {
// TODO(antoyo): use the fn_type parameter.
let const_string = self.context.new_type::<u8>().make_pointer().make_pointer();
@@ -123,14 +124,11 @@ pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Function
#[cfg(feature = "master")]
fn_attributes,
} = fn_abi.gcc_type(self);
- let func = declare_raw_fn(
- self,
- name,
- (), /*fn_abi.llvm_cconv()*/
- return_type,
- &arguments_type,
- is_c_variadic,
- );
+ #[cfg(feature = "master")]
+ let conv = fn_abi.gcc_cconv(self);
+ #[cfg(not(feature = "master"))]
+ let conv = None;
+ let func = declare_raw_fn(self, name, conv, return_type, &arguments_type, is_c_variadic);
self.on_stack_function_params.borrow_mut().insert(func, on_stack_param_indices);
#[cfg(feature = "master")]
for fn_attr in fn_attributes {
@@ -162,7 +160,8 @@ pub fn get_declared_value(&self, name: &str) -> Option<RValue<'gcc>> {
fn declare_raw_fn<'gcc>(
cx: &CodegenCx<'gcc, '_>,
name: &str,
- _callconv: (), /*llvm::CallConv*/
+ #[cfg(feature = "master")] callconv: Option<FnAttribute<'gcc>>,
+ #[cfg(not(feature = "master"))] _callconv: Option<()>,
return_type: Type<'gcc>,
param_types: &[Type<'gcc>],
variadic: bool,
@@ -192,6 +191,10 @@ fn declare_raw_fn<'gcc>(
let name = &mangle_name(name);
let func =
cx.context.new_function(None, cx.linkage.get(), return_type, ¶ms, name, variadic);
+ #[cfg(feature = "master")]
+ if let Some(attribute) = callconv {
+ func.add_attribute(attribute);
+ }
cx.functions.borrow_mut().insert(name.to_string(), func);
#[cfg(feature = "master")]
diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs
index 6eae0c2..202764d 100644
--- a/compiler/rustc_codegen_gcc/src/gcc_util.rs
+++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs
@@ -194,6 +194,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
fn arch_to_gcc(name: &str) -> &str {
match name {
+ "M68000" => "68000",
"M68020" => "68020",
_ => name,
}
diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs
index f3552d9..9b5b0fd 100644
--- a/compiler/rustc_codegen_gcc/src/int.rs
+++ b/compiler/rustc_codegen_gcc/src/int.rs
@@ -404,7 +404,7 @@ pub fn operation_with_overflow(
let ret_indirect = matches!(fn_abi.ret.mode, PassMode::Indirect { .. });
- let result = if ret_indirect {
+ let call = if ret_indirect {
let res_value = self.current_func().new_local(self.location, res_type, "result_value");
let res_addr = res_value.get_address(self.location);
let res_param_type = res_type.make_pointer();
@@ -432,8 +432,17 @@ pub fn operation_with_overflow(
);
self.context.new_call(self.location, func, &[lhs, rhs, overflow_addr])
};
+ // NOTE: we must assign the result of the operation to a variable at this point to make
+ // sure it will be evaluated by libgccjit now.
+ // Otherwise, it will only be evaluated when the rvalue for the call is used somewhere else
+ // and overflow_value will not be initialized at the correct point in the program.
+ let result = self.current_func().new_local(self.location, res_type, "result");
+ self.block.add_assignment(self.location, result, call);
- (result, self.context.new_cast(self.location, overflow_value, self.bool_type).to_rvalue())
+ (
+ result.to_rvalue(),
+ self.context.new_cast(self.location, overflow_value, self.bool_type).to_rvalue(),
+ )
}
pub fn gcc_icmp(
@@ -865,6 +874,7 @@ pub fn gcc_int_cast(&self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<
let value_type = value.get_type();
if self.is_native_int_type_or_bool(dest_typ) && self.is_native_int_type_or_bool(value_type)
{
+ // TODO: use self.location.
self.context.new_cast(None, value, dest_typ)
} else if self.is_native_int_type_or_bool(dest_typ) {
self.context.new_cast(None, self.low(value), dest_typ)
@@ -905,6 +915,7 @@ fn int_to_float_cast(
let name_suffix = match self.type_kind(dest_typ) {
TypeKind::Float => "tisf",
TypeKind::Double => "tidf",
+ TypeKind::FP128 => "tixf",
kind => panic!("cannot cast a non-native integer to type {:?}", kind),
};
let sign = if signed { "" } else { "un" };
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
index 2d731f8..0eebd21 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
@@ -1,11 +1,90 @@
use std::borrow::Cow;
-use gccjit::{CType, Context, Function, FunctionPtrType, RValue, ToRValue, UnaryOp};
+use gccjit::{CType, Context, Field, Function, FunctionPtrType, RValue, ToRValue, Type};
use rustc_codegen_ssa::traits::BuilderMethods;
use crate::builder::Builder;
use crate::context::CodegenCx;
+fn encode_key_128_type<'a, 'gcc, 'tcx>(
+ builder: &Builder<'a, 'gcc, 'tcx>,
+) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) {
+ let m128i = builder.context.new_vector_type(builder.i64_type, 2);
+ let field1 = builder.context.new_field(None, builder.u32_type, "field1");
+ let field2 = builder.context.new_field(None, m128i, "field2");
+ let field3 = builder.context.new_field(None, m128i, "field3");
+ let field4 = builder.context.new_field(None, m128i, "field4");
+ let field5 = builder.context.new_field(None, m128i, "field5");
+ let field6 = builder.context.new_field(None, m128i, "field6");
+ let field7 = builder.context.new_field(None, m128i, "field7");
+ let encode_type = builder.context.new_struct_type(
+ None,
+ "EncodeKey128Output",
+ &[field1, field2, field3, field4, field5, field6, field7],
+ );
+ #[cfg(feature = "master")]
+ encode_type.as_type().set_packed();
+ (encode_type.as_type(), field1, field2)
+}
+
+fn encode_key_256_type<'a, 'gcc, 'tcx>(
+ builder: &Builder<'a, 'gcc, 'tcx>,
+) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) {
+ let m128i = builder.context.new_vector_type(builder.i64_type, 2);
+ let field1 = builder.context.new_field(None, builder.u32_type, "field1");
+ let field2 = builder.context.new_field(None, m128i, "field2");
+ let field3 = builder.context.new_field(None, m128i, "field3");
+ let field4 = builder.context.new_field(None, m128i, "field4");
+ let field5 = builder.context.new_field(None, m128i, "field5");
+ let field6 = builder.context.new_field(None, m128i, "field6");
+ let field7 = builder.context.new_field(None, m128i, "field7");
+ let field8 = builder.context.new_field(None, m128i, "field8");
+ let encode_type = builder.context.new_struct_type(
+ None,
+ "EncodeKey256Output",
+ &[field1, field2, field3, field4, field5, field6, field7, field8],
+ );
+ #[cfg(feature = "master")]
+ encode_type.as_type().set_packed();
+ (encode_type.as_type(), field1, field2)
+}
+
+fn aes_output_type<'a, 'gcc, 'tcx>(
+ builder: &Builder<'a, 'gcc, 'tcx>,
+) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) {
+ let m128i = builder.context.new_vector_type(builder.i64_type, 2);
+ let field1 = builder.context.new_field(None, builder.u8_type, "field1");
+ let field2 = builder.context.new_field(None, m128i, "field2");
+ let aes_output_type = builder.context.new_struct_type(None, "AesOutput", &[field1, field2]);
+ let typ = aes_output_type.as_type();
+ #[cfg(feature = "master")]
+ typ.set_packed();
+ (typ, field1, field2)
+}
+
+fn wide_aes_output_type<'a, 'gcc, 'tcx>(
+ builder: &Builder<'a, 'gcc, 'tcx>,
+) -> (Type<'gcc>, Field<'gcc>, Field<'gcc>) {
+ let m128i = builder.context.new_vector_type(builder.i64_type, 2);
+ let field1 = builder.context.new_field(None, builder.u8_type, "field1");
+ let field2 = builder.context.new_field(None, m128i, "field2");
+ let field3 = builder.context.new_field(None, m128i, "field3");
+ let field4 = builder.context.new_field(None, m128i, "field4");
+ let field5 = builder.context.new_field(None, m128i, "field5");
+ let field6 = builder.context.new_field(None, m128i, "field6");
+ let field7 = builder.context.new_field(None, m128i, "field7");
+ let field8 = builder.context.new_field(None, m128i, "field8");
+ let field9 = builder.context.new_field(None, m128i, "field9");
+ let aes_output_type = builder.context.new_struct_type(
+ None,
+ "WideAesOutput",
+ &[field1, field2, field3, field4, field5, field6, field7, field8, field9],
+ );
+ #[cfg(feature = "master")]
+ aes_output_type.as_type().set_packed();
+ (aes_output_type.as_type(), field1, field2)
+}
+
#[cfg_attr(not(feature = "master"), allow(unused_variables))]
pub fn adjust_function<'gcc>(
context: &'gcc Context<'gcc>,
@@ -43,7 +122,6 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
gcc_func: FunctionPtrType<'gcc>,
mut args: Cow<'b, [RValue<'gcc>]>,
func_name: &str,
- original_function_name: Option<&String>,
) -> Cow<'b, [RValue<'gcc>]> {
// TODO: this might not be a good way to workaround the missing tile builtins.
if func_name == "__builtin_trap" {
@@ -504,6 +582,72 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
let arg4 = builder.context.new_rvalue_from_int(arg4_type, -1);
args = vec![a, b, c, arg4, new_args[3]].into();
}
+ "__builtin_ia32_encodekey128_u32" => {
+ let mut new_args = args.to_vec();
+ let m128i = builder.context.new_vector_type(builder.i64_type, 2);
+ let array_type = builder.context.new_array_type(None, m128i, 6);
+ let result = builder.current_func().new_local(None, array_type, "result");
+ new_args.push(result.get_address(None));
+ args = new_args.into();
+ }
+ "__builtin_ia32_encodekey256_u32" => {
+ let mut new_args = args.to_vec();
+ let m128i = builder.context.new_vector_type(builder.i64_type, 2);
+ let array_type = builder.context.new_array_type(None, m128i, 7);
+ let result = builder.current_func().new_local(None, array_type, "result");
+ new_args.push(result.get_address(None));
+ args = new_args.into();
+ }
+ "__builtin_ia32_aesenc128kl_u8"
+ | "__builtin_ia32_aesdec128kl_u8"
+ | "__builtin_ia32_aesenc256kl_u8"
+ | "__builtin_ia32_aesdec256kl_u8" => {
+ let mut new_args = vec![];
+ let m128i = builder.context.new_vector_type(builder.i64_type, 2);
+ let result = builder.current_func().new_local(None, m128i, "result");
+ new_args.push(result.get_address(None));
+ new_args.extend(args.to_vec());
+ args = new_args.into();
+ }
+ "__builtin_ia32_aesencwide128kl_u8"
+ | "__builtin_ia32_aesdecwide128kl_u8"
+ | "__builtin_ia32_aesencwide256kl_u8"
+ | "__builtin_ia32_aesdecwide256kl_u8" => {
+ let mut new_args = vec![];
+
+ let mut old_args = args.to_vec();
+ let handle = old_args.swap_remove(0); // Called __P in GCC.
+ let first_value = old_args.swap_remove(0);
+
+ let element_type = first_value.get_type();
+ let array_type = builder.context.new_array_type(None, element_type, 8);
+ let result = builder.current_func().new_local(None, array_type, "result");
+ new_args.push(result.get_address(None));
+
+ let array = builder.current_func().new_local(None, array_type, "array");
+ let input = builder.context.new_array_constructor(
+ None,
+ array_type,
+ &[
+ first_value,
+ old_args.swap_remove(0),
+ old_args.swap_remove(0),
+ old_args.swap_remove(0),
+ old_args.swap_remove(0),
+ old_args.swap_remove(0),
+ old_args.swap_remove(0),
+ old_args.swap_remove(0),
+ ],
+ );
+ builder.llbb().add_assignment(None, array, input);
+ let input_ptr = array.get_address(None);
+ let arg2_type = gcc_func.get_param_type(1);
+ let input_ptr = builder.context.new_cast(None, input_ptr, arg2_type);
+ new_args.push(input_ptr);
+
+ new_args.push(handle);
+ args = new_args.into();
+ }
_ => (),
}
} else {
@@ -541,33 +685,6 @@ pub fn adjust_intrinsic_arguments<'a, 'b, 'gcc, 'tcx>(
let c = builder.context.new_rvalue_from_vector(None, arg3_type, &[new_args[2]; 2]);
args = vec![a, b, c, new_args[3]].into();
}
- "__builtin_ia32_vfmaddsubpd256"
- | "__builtin_ia32_vfmaddsubps"
- | "__builtin_ia32_vfmaddsubps256"
- | "__builtin_ia32_vfmaddsubpd" => {
- if let Some(original_function_name) = original_function_name {
- match &**original_function_name {
- "llvm.x86.fma.vfmsubadd.pd.256"
- | "llvm.x86.fma.vfmsubadd.ps"
- | "llvm.x86.fma.vfmsubadd.ps.256"
- | "llvm.x86.fma.vfmsubadd.pd" => {
- // NOTE: since both llvm.x86.fma.vfmsubadd.ps and llvm.x86.fma.vfmaddsub.ps maps to
- // __builtin_ia32_vfmaddsubps, only add minus if this comes from a
- // subadd LLVM intrinsic, e.g. _mm256_fmsubadd_pd.
- let mut new_args = args.to_vec();
- let arg3 = &mut new_args[2];
- *arg3 = builder.context.new_unary_op(
- None,
- UnaryOp::Minus,
- arg3.get_type(),
- *arg3,
- );
- args = new_args.into();
- }
- _ => (),
- }
- }
- }
"__builtin_ia32_ldmxcsr" => {
// The builtin __builtin_ia32_ldmxcsr takes an integer value while llvm.x86.sse.ldmxcsr takes a pointer,
// so dereference the pointer.
@@ -728,6 +845,96 @@ pub fn adjust_intrinsic_return_value<'a, 'gcc, 'tcx>(
let f16_type = builder.context.new_c_type(CType::Float16);
return_value = builder.context.new_cast(None, return_value, f16_type);
}
+ "__builtin_ia32_encodekey128_u32" => {
+ // The builtin __builtin_ia32_encodekey128_u32 writes the result in its pointer argument while
+ // llvm.x86.encodekey128 returns a value.
+ // We added a result pointer argument and now need to assign its value to the return_value expected by
+ // the LLVM intrinsic.
+ let (encode_type, field1, field2) = encode_key_128_type(builder);
+ let result = builder.current_func().new_local(None, encode_type, "result");
+ let field1 = result.access_field(None, field1);
+ builder.llbb().add_assignment(None, field1, return_value);
+ let field2 = result.access_field(None, field2);
+ let field2_type = field2.to_rvalue().get_type();
+ let array_type = builder.context.new_array_type(None, field2_type, 6);
+ let ptr = builder.context.new_cast(None, args[2], array_type.make_pointer());
+ let field2_ptr =
+ builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer());
+ builder.llbb().add_assignment(
+ None,
+ field2_ptr.dereference(None),
+ ptr.dereference(None),
+ );
+ return_value = result.to_rvalue();
+ }
+ "__builtin_ia32_encodekey256_u32" => {
+ // The builtin __builtin_ia32_encodekey256_u32 writes the result in its pointer argument while
+ // llvm.x86.encodekey256 returns a value.
+ // We added a result pointer argument and now need to assign its value to the return_value expected by
+ // the LLVM intrinsic.
+ let (encode_type, field1, field2) = encode_key_256_type(builder);
+ let result = builder.current_func().new_local(None, encode_type, "result");
+ let field1 = result.access_field(None, field1);
+ builder.llbb().add_assignment(None, field1, return_value);
+ let field2 = result.access_field(None, field2);
+ let field2_type = field2.to_rvalue().get_type();
+ let array_type = builder.context.new_array_type(None, field2_type, 7);
+ let ptr = builder.context.new_cast(None, args[3], array_type.make_pointer());
+ let field2_ptr =
+ builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer());
+ builder.llbb().add_assignment(
+ None,
+ field2_ptr.dereference(None),
+ ptr.dereference(None),
+ );
+ return_value = result.to_rvalue();
+ }
+ "__builtin_ia32_aesdec128kl_u8"
+ | "__builtin_ia32_aesenc128kl_u8"
+ | "__builtin_ia32_aesdec256kl_u8"
+ | "__builtin_ia32_aesenc256kl_u8" => {
+ // The builtin for aesdec/aesenc writes the result in its pointer argument while
+ // llvm.x86.aesdec128kl returns a value.
+ // We added a result pointer argument and now need to assign its value to the return_value expected by
+ // the LLVM intrinsic.
+ let (aes_output_type, field1, field2) = aes_output_type(builder);
+ let result = builder.current_func().new_local(None, aes_output_type, "result");
+ let field1 = result.access_field(None, field1);
+ builder.llbb().add_assignment(None, field1, return_value);
+ let field2 = result.access_field(None, field2);
+ let ptr = builder.context.new_cast(
+ None,
+ args[0],
+ field2.to_rvalue().get_type().make_pointer(),
+ );
+ builder.llbb().add_assignment(None, field2, ptr.dereference(None));
+ return_value = result.to_rvalue();
+ }
+ "__builtin_ia32_aesencwide128kl_u8"
+ | "__builtin_ia32_aesdecwide128kl_u8"
+ | "__builtin_ia32_aesencwide256kl_u8"
+ | "__builtin_ia32_aesdecwide256kl_u8" => {
+ // The builtin for aesdecwide/aesencwide writes the result in its pointer argument while
+ // llvm.x86.aesencwide128kl returns a value.
+ // We added a result pointer argument and now need to assign its value to the return_value expected by
+ // the LLVM intrinsic.
+ let (aes_output_type, field1, field2) = wide_aes_output_type(builder);
+ let result = builder.current_func().new_local(None, aes_output_type, "result");
+ let field1 = result.access_field(None, field1);
+ builder.llbb().add_assignment(None, field1, return_value);
+ let field2 = result.access_field(None, field2);
+ let field2_type = field2.to_rvalue().get_type();
+ let array_type = builder.context.new_array_type(None, field2_type, 8);
+ let ptr = builder.context.new_cast(None, args[0], array_type.make_pointer());
+ let field2_ptr =
+ builder.context.new_cast(None, field2.get_address(None), array_type.make_pointer());
+ builder.llbb().add_assignment(
+ None,
+ field2_ptr.dereference(None),
+ ptr.dereference(None),
+ );
+ return_value = result.to_rvalue();
+ }
_ => (),
}
@@ -915,16 +1122,6 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
"llvm.ctlz.v4i64" => "__builtin_ia32_vplzcntq_256_mask",
"llvm.ctlz.v2i64" => "__builtin_ia32_vplzcntq_128_mask",
"llvm.ctpop.v32i16" => "__builtin_ia32_vpopcountw_v32hi",
- "llvm.x86.fma.vfmsub.sd" => "__builtin_ia32_vfmsubsd3",
- "llvm.x86.fma.vfmsub.ss" => "__builtin_ia32_vfmsubss3",
- "llvm.x86.fma.vfmsubadd.pd" => "__builtin_ia32_vfmaddsubpd",
- "llvm.x86.fma.vfmsubadd.pd.256" => "__builtin_ia32_vfmaddsubpd256",
- "llvm.x86.fma.vfmsubadd.ps" => "__builtin_ia32_vfmaddsubps",
- "llvm.x86.fma.vfmsubadd.ps.256" => "__builtin_ia32_vfmaddsubps256",
- "llvm.x86.fma.vfnmadd.sd" => "__builtin_ia32_vfnmaddsd3",
- "llvm.x86.fma.vfnmadd.ss" => "__builtin_ia32_vfnmaddss3",
- "llvm.x86.fma.vfnmsub.sd" => "__builtin_ia32_vfnmsubsd3",
- "llvm.x86.fma.vfnmsub.ss" => "__builtin_ia32_vfnmsubss3",
"llvm.x86.avx512.conflict.d.512" => "__builtin_ia32_vpconflictsi_512_mask",
"llvm.x86.avx512.conflict.d.256" => "__builtin_ia32_vpconflictsi_256_mask",
"llvm.x86.avx512.conflict.d.128" => "__builtin_ia32_vpconflictsi_128_mask",
@@ -1002,8 +1199,6 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
"llvm.fshr.v32i16" => "__builtin_ia32_vpshrdv_v32hi",
"llvm.fshr.v16i16" => "__builtin_ia32_vpshrdv_v16hi",
"llvm.fshr.v8i16" => "__builtin_ia32_vpshrdv_v8hi",
- "llvm.x86.fma.vfmadd.sd" => "__builtin_ia32_vfmaddsd3",
- "llvm.x86.fma.vfmadd.ss" => "__builtin_ia32_vfmaddss3",
"llvm.x86.rdrand.64" => "__builtin_ia32_rdrand64_step",
// The above doc points to unknown builtins for the following, so override them:
@@ -1324,6 +1519,16 @@ pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function
"llvm.x86.avx512fp16.mask.vfmadd.cph.256" => "__builtin_ia32_vfmaddcph256_mask3",
"llvm.x86.avx512fp16.mask.vfcmadd.cph.128" => "__builtin_ia32_vfcmaddcph128_mask3",
"llvm.x86.avx512fp16.mask.vfmadd.cph.128" => "__builtin_ia32_vfmaddcph128_mask3",
+ "llvm.x86.encodekey128" => "__builtin_ia32_encodekey128_u32",
+ "llvm.x86.encodekey256" => "__builtin_ia32_encodekey256_u32",
+ "llvm.x86.aesenc128kl" => "__builtin_ia32_aesenc128kl_u8",
+ "llvm.x86.aesdec128kl" => "__builtin_ia32_aesdec128kl_u8",
+ "llvm.x86.aesenc256kl" => "__builtin_ia32_aesenc256kl_u8",
+ "llvm.x86.aesdec256kl" => "__builtin_ia32_aesdec256kl_u8",
+ "llvm.x86.aesencwide128kl" => "__builtin_ia32_aesencwide128kl_u8",
+ "llvm.x86.aesdecwide128kl" => "__builtin_ia32_aesdecwide128kl_u8",
+ "llvm.x86.aesencwide256kl" => "__builtin_ia32_aesencwide256kl_u8",
+ "llvm.x86.aesdecwide256kl" => "__builtin_ia32_aesdecwide256kl_u8",
// TODO: support the tile builtins:
"llvm.x86.ldtilecfg" => "__builtin_trap",
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index f386220..d22f422 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -78,6 +78,7 @@ fn get_simple_intrinsic<'gcc, 'tcx>(
sym::maxnumf64 => "fmax",
sym::copysignf32 => "copysignf",
sym::copysignf64 => "copysign",
+ sym::copysignf128 => "copysignl",
sym::floorf32 => "floorf",
sym::floorf64 => "floor",
sym::ceilf32 => "ceilf",
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
index 8b454ab..b897d07 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -399,7 +399,7 @@ macro_rules! require_simd {
}
#[cfg(feature = "master")]
- if name == sym::simd_insert {
+ if name == sym::simd_insert || name == sym::simd_insert_dyn {
require!(
in_elem == arg_tys[2],
InvalidMonomorphization::InsertedType {
@@ -410,6 +410,8 @@ macro_rules! require_simd {
out_ty: arg_tys[2]
}
);
+
+ // TODO(antoyo): For simd_insert, check if the index is a constant of the correct size.
let vector = args[0].immediate();
let index = args[1].immediate();
let value = args[2].immediate();
@@ -422,13 +424,15 @@ macro_rules! require_simd {
}
#[cfg(feature = "master")]
- if name == sym::simd_extract {
+ if name == sym::simd_extract || name == sym::simd_extract_dyn {
require!(
ret_ty == in_elem,
InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
);
+ // TODO(antoyo): For simd_extract, check if the index is a constant of the correct size.
let vector = args[0].immediate();
- return Ok(bx.context.new_vector_access(None, vector, args[1].immediate()).to_rvalue());
+ let index = args[1].immediate();
+ return Ok(bx.context.new_vector_access(None, vector, index).to_rvalue());
}
if name == sym::simd_select {
@@ -443,9 +447,14 @@ macro_rules! require_simd {
m_len == v_len,
InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
);
+ // TODO: also support unsigned integers.
match *m_elem_ty.kind() {
ty::Int(_) => {}
- _ => return_error!(InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }),
+ _ => return_error!(InvalidMonomorphization::MaskWrongElementType {
+ span,
+ name,
+ ty: m_elem_ty
+ }),
}
return Ok(bx.vector_select(args[0].immediate(), args[1].immediate(), args[2].immediate()));
}
@@ -987,19 +996,15 @@ fn non_ptr(t: Ty<'_>) -> Ty<'_> {
assert_eq!(pointer_count - 1, ptr_count(element_ty0));
assert_eq!(underlying_ty, non_ptr(element_ty0));
- // The element type of the third argument must be a signed integer type of any width:
+ // The element type of the third argument must be an integer type of any width:
+ // TODO: also support unsigned integers.
let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
match *element_ty2.kind() {
ty::Int(_) => (),
_ => {
require!(
false,
- InvalidMonomorphization::ThirdArgElementType {
- span,
- name,
- expected_element: element_ty2,
- third_arg: arg_tys[2]
- }
+ InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 }
);
}
}
@@ -1105,17 +1110,13 @@ fn non_ptr(t: Ty<'_>) -> Ty<'_> {
assert_eq!(underlying_ty, non_ptr(element_ty0));
// The element type of the third argument must be a signed integer type of any width:
+ // TODO: also support unsigned integers.
match *element_ty2.kind() {
ty::Int(_) => (),
_ => {
require!(
false,
- InvalidMonomorphization::ThirdArgElementType {
- span,
- name,
- expected_element: element_ty2,
- third_arg: arg_tys[2]
- }
+ InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 }
);
}
}
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index bfa2317..624fdb4 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -188,10 +188,10 @@ fn locale_resource(&self) -> &'static str {
crate::DEFAULT_LOCALE_RESOURCE
}
- fn init(&self, sess: &Session) {
+ fn init(&self, _sess: &Session) {
#[cfg(feature = "master")]
{
- let target_cpu = target_cpu(sess);
+ let target_cpu = target_cpu(_sess);
// Get the second TargetInfo with the correct CPU features by setting the arch.
let context = Context::default();
diff --git a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt
index 082958b..499c1a9 100644
--- a/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt
+++ b/compiler/rustc_codegen_gcc/tests/failing-ui-tests.txt
@@ -1,11 +1,9 @@
tests/ui/allocator/no_std-alloc-error-handler-custom.rs
tests/ui/allocator/no_std-alloc-error-handler-default.rs
tests/ui/asm/may_unwind.rs
-tests/ui/asm/x86_64/multiple-clobber-abi.rs
tests/ui/functions-closures/parallel-codegen-closures.rs
tests/ui/linkage-attr/linkage1.rs
tests/ui/lto/dylib-works.rs
-tests/ui/numbers-arithmetic/saturating-float-casts.rs
tests/ui/sepcomp/sepcomp-cci.rs
tests/ui/sepcomp/sepcomp-extern.rs
tests/ui/sepcomp/sepcomp-fns-backwards.rs
@@ -33,7 +31,6 @@
tests/ui/parser/unclosed-delimiter-in-dep.rs
tests/ui/consts/missing_span_in_backtrace.rs
tests/ui/drop/dynamic-drop.rs
-tests/ui/issues/issue-40883.rs
tests/ui/issues/issue-43853.rs
tests/ui/issues/issue-47364.rs
tests/ui/macros/rfc-2011-nicer-assert-messages/assert-without-captures-does-not-create-unnecessary-code.rs
@@ -102,14 +99,12 @@
tests/ui/codegen/equal-pointers-unequal/as-cast/inline1.rs
tests/ui/codegen/equal-pointers-unequal/as-cast/print.rs
tests/ui/codegen/equal-pointers-unequal/as-cast/inline2.rs
-tests/ui/codegen/equal-pointers-unequal/as-cast/print3.rs
tests/ui/codegen/equal-pointers-unequal/as-cast/segfault.rs
tests/ui/codegen/equal-pointers-unequal/exposed-provenance/function.rs
tests/ui/codegen/equal-pointers-unequal/exposed-provenance/basic.rs
tests/ui/codegen/equal-pointers-unequal/as-cast/zero.rs
tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline1.rs
tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print.rs
-tests/ui/codegen/equal-pointers-unequal/exposed-provenance/print3.rs
tests/ui/codegen/equal-pointers-unequal/exposed-provenance/inline2.rs
tests/ui/codegen/equal-pointers-unequal/exposed-provenance/segfault.rs
tests/ui/codegen/equal-pointers-unequal/exposed-provenance/zero.rs
@@ -117,8 +112,9 @@
tests/ui/codegen/equal-pointers-unequal/strict-provenance/function.rs
tests/ui/codegen/equal-pointers-unequal/strict-provenance/print.rs
tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline1.rs
-tests/ui/codegen/equal-pointers-unequal/strict-provenance/print3.rs
tests/ui/codegen/equal-pointers-unequal/strict-provenance/inline2.rs
tests/ui/codegen/equal-pointers-unequal/strict-provenance/segfault.rs
tests/ui/codegen/equal-pointers-unequal/strict-provenance/zero.rs
tests/ui/simd/simd-bitmask-notpow2.rs
+tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs
+tests/ui/uninhabited/uninhabited-transparent-return-abi.rs
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort1.rs b/compiler/rustc_codegen_gcc/tests/run/abort1.rs
index fe46d9a..ff2bb75 100644
--- a/compiler/rustc_codegen_gcc/tests/run/abort1.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/abort1.rs
@@ -3,45 +3,13 @@
// Run-time:
// status: signal
-#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)]
-#![allow(internal_features)]
-
+#![feature(no_core)]
#![no_std]
#![no_core]
#![no_main]
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
-
-mod intrinsics {
- use super::Sized;
-
- #[rustc_nounwind]
- #[rustc_intrinsic]
- pub fn abort() -> !;
-}
-
-/*
- * Code
- */
+extern crate mini_core;
+use mini_core::*;
fn test_fail() -> ! {
unsafe { intrinsics::abort() };
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort2.rs b/compiler/rustc_codegen_gcc/tests/run/abort2.rs
index 4123f4f..781f518 100644
--- a/compiler/rustc_codegen_gcc/tests/run/abort2.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/abort2.rs
@@ -3,45 +3,13 @@
// Run-time:
// status: signal
-#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)]
-#![allow(internal_features)]
-
+#![feature(no_core)]
#![no_std]
#![no_core]
#![no_main]
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
-
-mod intrinsics {
- use super::Sized;
-
- #[rustc_nounwind]
- #[rustc_intrinsic]
- pub fn abort() -> !;
-}
-
-/*
- * Code
- */
+extern crate mini_core;
+use mini_core::*;
fn fail() -> i32 {
unsafe { intrinsics::abort() };
diff --git a/compiler/rustc_codegen_gcc/tests/run/array.rs b/compiler/rustc_codegen_gcc/tests/run/array.rs
index e18a4ce..3ab0c30 100644
--- a/compiler/rustc_codegen_gcc/tests/run/array.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/array.rs
@@ -8,20 +8,12 @@
// 10
#![feature(no_core)]
-
#![no_std]
#![no_core]
#![no_main]
extern crate mini_core;
-
-mod libc {
- #[link(name = "c")]
- extern "C" {
- pub fn printf(format: *const i8, ...) -> i32;
- pub fn puts(s: *const u8) -> i32;
- }
-}
+use mini_core::*;
static mut ONE: usize = 1;
diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs
index 4e05d02..2dbf43b 100644
--- a/compiler/rustc_codegen_gcc/tests/run/asm.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/asm.rs
@@ -174,6 +174,59 @@ extern "C" fn foo() -> u64 {
mem_cpy(array2.as_mut_ptr(), array1.as_ptr(), 3);
}
assert_eq!(array1, array2);
+
+ // in and clobber registers cannot overlap. This tests that the lateout register without an
+ // output place (indicated by the `_`) is not added to the list of clobbered registers
+ let x = 8;
+ let y: i32;
+ unsafe {
+ asm!(
+ "mov rax, rdi",
+ in("rdi") x,
+ lateout("rdi") _,
+ out("rax") y,
+ );
+ }
+ assert_eq!((x, y), (8, 8));
+
+ // sysv64 is the default calling convention on unix systems. The rdi register is
+ // used to pass arguments in the sysv64 calling convention, so this register will be clobbered
+ #[cfg(unix)]
+ {
+ let x = 16;
+ let y: i32;
+ unsafe {
+ asm!(
+ "mov rax, rdi",
+ in("rdi") x,
+ out("rax") y,
+ clobber_abi("sysv64"),
+ );
+ }
+ assert_eq!((x, y), (16, 16));
+ }
+
+ // the `b` suffix for registers in the `reg_byte` register class is not supported in GCC
+ // and needs to be stripped in order to use these registers.
+ unsafe {
+ core::arch::asm!(
+ "",
+ out("al") _,
+ out("bl") _,
+ out("cl") _,
+ out("dl") _,
+ out("sil") _,
+ out("dil") _,
+ out("r8b") _,
+ out("r9b") _,
+ out("r10b") _,
+ out("r11b") _,
+ out("r12b") _,
+ out("r13b") _,
+ out("r14b") _,
+ out("r15b") _,
+ );
+ }
}
#[cfg(not(target_arch = "x86_64"))]
diff --git a/compiler/rustc_codegen_gcc/tests/run/assign.rs b/compiler/rustc_codegen_gcc/tests/run/assign.rs
index 2861558..4535ab5 100644
--- a/compiler/rustc_codegen_gcc/tests/run/assign.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/assign.rs
@@ -5,130 +5,13 @@
// 7 8
// 10
-#![allow(internal_features, unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs, track_caller)]
-
+#![feature(no_core)]
#![no_std]
#![no_core]
#![no_main]
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-impl Copy for *mut i32 {}
-impl Copy for usize {}
-impl Copy for u8 {}
-impl Copy for i8 {}
-impl Copy for i32 {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
-
-#[lang = "panic_location"]
-struct PanicLocation {
- file: &'static str,
- line: u32,
- column: u32,
-}
-
-mod libc {
- #[link(name = "c")]
- extern "C" {
- pub fn puts(s: *const u8) -> i32;
- pub fn fflush(stream: *mut i32) -> i32;
- pub fn printf(format: *const i8, ...) -> i32;
-
- pub static stdout: *mut i32;
- }
-}
-
-mod intrinsics {
- #[rustc_nounwind]
- #[rustc_intrinsic]
- pub fn abort() -> !;
-}
-
-#[lang = "panic"]
-#[track_caller]
-#[no_mangle]
-pub fn panic(_msg: &'static str) -> ! {
- unsafe {
- libc::puts("Panicking\0" as *const str as *const u8);
- libc::fflush(libc::stdout);
- intrinsics::abort();
- }
-}
-
-#[lang = "add"]
-trait Add<RHS = Self> {
- type Output;
-
- fn add(self, rhs: RHS) -> Self::Output;
-}
-
-impl Add for u8 {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- self + rhs
- }
-}
-
-impl Add for i8 {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- self + rhs
- }
-}
-
-impl Add for i32 {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- self + rhs
- }
-}
-
-impl Add for usize {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- self + rhs
- }
-}
-
-impl Add for isize {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- self + rhs
- }
-}
-
-#[track_caller]
-#[lang = "panic_const_add_overflow"]
-pub fn panic_const_add_overflow() -> ! {
- panic("attempt to add with overflow");
-}
-
-/*
- * Code
- */
+extern crate mini_core;
+use mini_core::*;
fn inc_ref(num: &mut isize) -> isize {
*num = *num + 5;
@@ -139,9 +22,8 @@ fn inc(num: isize) -> isize {
num + 1
}
-
#[no_mangle]
-extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
+extern "C" fn main(mut argc: isize, _argv: *const *const u8) -> i32 {
argc = inc(argc);
unsafe {
libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
diff --git a/compiler/rustc_codegen_gcc/tests/run/closure.rs b/compiler/rustc_codegen_gcc/tests/run/closure.rs
index c7a236f..a8a3fad 100644
--- a/compiler/rustc_codegen_gcc/tests/run/closure.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/closure.rs
@@ -9,55 +9,38 @@
// Both args: 11
#![feature(no_core)]
-
#![no_std]
#![no_core]
#![no_main]
extern crate mini_core;
-
-mod libc {
- #[link(name = "c")]
- extern "C" {
- pub fn printf(format: *const i8, ...) -> i32;
- }
-}
+use mini_core::*;
#[no_mangle]
-extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
+extern "C" fn main(argc: isize, _argv: *const *const u8) -> i32 {
let string = "Arg: %d\n\0";
- let mut closure = || {
- unsafe {
- libc::printf(string as *const str as *const i8, argc);
- }
+ let mut closure = || unsafe {
+ libc::printf(string as *const str as *const i8, argc);
};
closure();
- let mut closure = || {
- unsafe {
- libc::printf("Argument: %d\n\0" as *const str as *const i8, argc);
- }
+ let mut closure = || unsafe {
+ libc::printf("Argument: %d\n\0" as *const str as *const i8, argc);
};
closure();
- let mut closure = |string| {
- unsafe {
- libc::printf(string as *const str as *const i8, argc);
- }
+ let mut closure = |string| unsafe {
+ libc::printf(string as *const str as *const i8, argc);
};
closure("String arg: %d\n\0");
- let mut closure = |arg: isize| {
- unsafe {
- libc::printf("Int argument: %d\n\0" as *const str as *const i8, arg);
- }
+ let mut closure = |arg: isize| unsafe {
+ libc::printf("Int argument: %d\n\0" as *const str as *const i8, arg);
};
closure(argc + 1);
- let mut closure = |string, arg: isize| {
- unsafe {
- libc::printf(string as *const str as *const i8, arg);
- }
+ let mut closure = |string, arg: isize| unsafe {
+ libc::printf(string as *const str as *const i8, arg);
};
closure("Both args: %d\n\0", argc + 10);
diff --git a/compiler/rustc_codegen_gcc/tests/run/condition.rs b/compiler/rustc_codegen_gcc/tests/run/condition.rs
index b023597..bd3b6f7 100644
--- a/compiler/rustc_codegen_gcc/tests/run/condition.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/condition.rs
@@ -6,19 +6,12 @@
// 1
#![feature(no_core)]
-
#![no_std]
#![no_core]
#![no_main]
extern crate mini_core;
-
-mod libc {
- #[link(name = "c")]
- extern "C" {
- pub fn printf(format: *const i8, ...) -> i32;
- }
-}
+use mini_core::*;
#[no_mangle]
extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
@@ -27,15 +20,14 @@ extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
libc::printf(b"true\n\0" as *const u8 as *const i8);
}
- let string =
- match argc {
- 1 => b"1\n\0",
- 2 => b"2\n\0",
- 3 => b"3\n\0",
- 4 => b"4\n\0",
- 5 => b"5\n\0",
- _ => b"_\n\0",
- };
+ let string = match argc {
+ 1 => b"1\n\0",
+ 2 => b"2\n\0",
+ 3 => b"3\n\0",
+ 4 => b"4\n\0",
+ 5 => b"5\n\0",
+ _ => b"_\n\0",
+ };
libc::printf(string as *const u8 as *const i8);
}
0
diff --git a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
index 042e440..fe3df5a 100644
--- a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
@@ -3,37 +3,13 @@
// Run-time:
// status: 0
-#![feature(auto_traits, lang_items, no_core)]
-#![allow(internal_features)]
-
+#![feature(no_core)]
#![no_std]
#![no_core]
#![no_main]
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
-
-/*
- * Code
- */
+extern crate mini_core;
+use mini_core::*;
#[no_mangle]
extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
diff --git a/compiler/rustc_codegen_gcc/tests/run/exit.rs b/compiler/rustc_codegen_gcc/tests/run/exit.rs
index 9a7c91c..e0a5917 100644
--- a/compiler/rustc_codegen_gcc/tests/run/exit.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/exit.rs
@@ -3,44 +3,13 @@
// Run-time:
// status: 2
-#![feature(auto_traits, lang_items, no_core, intrinsics)]
-#![allow(internal_features)]
-
+#![feature(no_core)]
#![no_std]
#![no_core]
#![no_main]
-mod libc {
- #[link(name = "c")]
- extern "C" {
- pub fn exit(status: i32);
- }
-}
-
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
-
-/*
- * Code
- */
+extern crate mini_core;
+use mini_core::*;
#[no_mangle]
extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
diff --git a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
index c50d2b0..376824d 100644
--- a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
@@ -3,37 +3,13 @@
// Run-time:
// status: 1
-#![feature(auto_traits, lang_items, no_core)]
-#![allow(internal_features)]
-
+#![feature(no_core)]
#![no_std]
#![no_core]
#![no_main]
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
-
-/*
- * Code
- */
+extern crate mini_core;
+use mini_core::*;
#[no_mangle]
extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
diff --git a/compiler/rustc_codegen_gcc/tests/run/float.rs b/compiler/rustc_codegen_gcc/tests/run/float.rs
new file mode 100644
index 0000000..424fa1c
--- /dev/null
+++ b/compiler/rustc_codegen_gcc/tests/run/float.rs
@@ -0,0 +1,28 @@
+// Compiler:
+//
+// Run-time:
+// status: 0
+
+#![feature(const_black_box)]
+
+fn main() {
+ use std::hint::black_box;
+
+ macro_rules! check {
+ ($ty:ty, $expr:expr) => {{
+ const EXPECTED: $ty = $expr;
+ assert_eq!($expr, EXPECTED);
+ }};
+ }
+
+ check!(i32, (black_box(0.0f32) as i32));
+
+ check!(u64, (black_box(f32::NAN) as u64));
+ check!(u128, (black_box(f32::NAN) as u128));
+
+ check!(i64, (black_box(f64::NAN) as i64));
+ check!(u64, (black_box(f64::NAN) as u64));
+
+ check!(i16, (black_box(f32::MIN) as i16));
+ check!(i16, (black_box(f32::MAX) as i16));
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
index 98b351e..93b9bae 100644
--- a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
@@ -5,19 +5,12 @@
// stdout: 1
#![feature(no_core)]
-
#![no_std]
#![no_core]
#![no_main]
extern crate mini_core;
-
-mod libc {
- #[link(name = "c")]
- extern "C" {
- pub fn printf(format: *const i8, ...) -> i32;
- }
-}
+use mini_core::*;
fn i16_as_i8(a: i16) -> i8 {
a as i8
diff --git a/compiler/rustc_codegen_gcc/tests/run/int.rs b/compiler/rustc_codegen_gcc/tests/run/int.rs
index 58a2680..47b5dea 100644
--- a/compiler/rustc_codegen_gcc/tests/run/int.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/int.rs
@@ -3,9 +3,7 @@
// Run-time:
// status: 0
-/*
- * Code
- */
+#![feature(const_black_box)]
fn main() {
use std::hint::black_box;
diff --git a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
index b021586..fa50d5b 100644
--- a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
@@ -1,4 +1,3 @@
-
// Compiler:
//
// Run-time:
@@ -7,139 +6,20 @@
// 6
// 11
-#![allow(internal_features, unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs, track_caller)]
-
+#![feature(no_core)]
#![no_std]
#![no_core]
#![no_main]
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-impl Copy for *mut i32 {}
-impl Copy for usize {}
-impl Copy for u8 {}
-impl Copy for i8 {}
-impl Copy for i32 {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
-
-#[lang = "panic_location"]
-struct PanicLocation {
- file: &'static str,
- line: u32,
- column: u32,
-}
-
-mod libc {
- #[link(name = "c")]
- extern "C" {
- pub fn puts(s: *const u8) -> i32;
- pub fn fflush(stream: *mut i32) -> i32;
- pub fn printf(format: *const i8, ...) -> i32;
-
- pub static stdout: *mut i32;
- }
-}
-
-mod intrinsics {
- #[rustc_nounwind]
- #[rustc_intrinsic]
- pub fn abort() -> !;
-}
-
-#[lang = "panic"]
-#[track_caller]
-#[no_mangle]
-pub fn panic(_msg: &'static str) -> ! {
- unsafe {
- libc::puts("Panicking\0" as *const str as *const u8);
- libc::fflush(libc::stdout);
- intrinsics::abort();
- }
-}
-
-#[lang = "add"]
-trait Add<RHS = Self> {
- type Output;
-
- fn add(self, rhs: RHS) -> Self::Output;
-}
-
-impl Add for u8 {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- self + rhs
- }
-}
-
-impl Add for i8 {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- self + rhs
- }
-}
-
-impl Add for i32 {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- self + rhs
- }
-}
-
-impl Add for usize {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- self + rhs
- }
-}
-
-impl Add for isize {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- self + rhs
- }
-}
-
-#[track_caller]
-#[lang = "panic_const_add_overflow"]
-pub fn panic_const_add_overflow() -> ! {
- panic("attempt to add with overflow");
-}
-
-/*
- * Code
- */
+extern crate mini_core;
+use mini_core::*;
struct Test {
field: isize,
}
fn test(num: isize) -> Test {
- Test {
- field: num + 1,
- }
+ Test { field: num + 1 }
}
fn update_num(num: &mut isize) {
@@ -147,7 +27,7 @@ fn update_num(num: &mut isize) {
}
#[no_mangle]
-extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
+extern "C" fn main(mut argc: isize, _argv: *const *const u8) -> i32 {
let mut test = test(argc);
unsafe {
libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field);
diff --git a/compiler/rustc_codegen_gcc/tests/run/operations.rs b/compiler/rustc_codegen_gcc/tests/run/operations.rs
index 8ba7a4c..a1b0772 100644
--- a/compiler/rustc_codegen_gcc/tests/run/operations.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/operations.rs
@@ -5,229 +5,13 @@
// 39
// 10
-#![allow(internal_features, unused_attributes)]
-#![feature(auto_traits, lang_items, no_core, intrinsics, arbitrary_self_types, rustc_attrs)]
-
+#![feature(no_core)]
#![no_std]
#![no_core]
#![no_main]
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-impl Copy for *mut i32 {}
-impl Copy for usize {}
-impl Copy for u8 {}
-impl Copy for i8 {}
-impl Copy for i16 {}
-impl Copy for i32 {}
-
-#[lang = "deref"]
-pub trait Deref {
- type Target: ?Sized;
-
- fn deref(&self) -> &Self::Target;
-}
-
-#[lang = "legacy_receiver"]
-trait LegacyReceiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
-
-#[lang = "panic_location"]
-struct PanicLocation {
- file: &'static str,
- line: u32,
- column: u32,
-}
-
-mod libc {
- #[link(name = "c")]
- extern "C" {
- pub fn printf(format: *const i8, ...) -> i32;
- pub fn puts(s: *const u8) -> i32;
- pub fn fflush(stream: *mut i32) -> i32;
-
- pub static stdout: *mut i32;
- }
-}
-
-mod intrinsics {
- #[rustc_nounwind]
- #[rustc_intrinsic]
- pub fn abort() -> !;
-}
-
-#[lang = "panic"]
-#[track_caller]
-#[no_mangle]
-pub fn panic(_msg: &'static str) -> ! {
- unsafe {
- libc::puts("Panicking\0" as *const str as *const u8);
- libc::fflush(libc::stdout);
- intrinsics::abort();
- }
-}
-
-#[lang = "add"]
-trait Add<RHS = Self> {
- type Output;
-
- fn add(self, rhs: RHS) -> Self::Output;
-}
-
-impl Add for u8 {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- self + rhs
- }
-}
-
-impl Add for i8 {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- self + rhs
- }
-}
-
-impl Add for i32 {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- self + rhs
- }
-}
-
-impl Add for usize {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- self + rhs
- }
-}
-
-impl Add for isize {
- type Output = Self;
-
- fn add(self, rhs: Self) -> Self {
- self + rhs
- }
-}
-
-#[lang = "sub"]
-pub trait Sub<RHS = Self> {
- type Output;
-
- fn sub(self, rhs: RHS) -> Self::Output;
-}
-
-impl Sub for usize {
- type Output = Self;
-
- fn sub(self, rhs: Self) -> Self {
- self - rhs
- }
-}
-
-impl Sub for isize {
- type Output = Self;
-
- fn sub(self, rhs: Self) -> Self {
- self - rhs
- }
-}
-
-impl Sub for u8 {
- type Output = Self;
-
- fn sub(self, rhs: Self) -> Self {
- self - rhs
- }
-}
-
-impl Sub for i8 {
- type Output = Self;
-
- fn sub(self, rhs: Self) -> Self {
- self - rhs
- }
-}
-
-impl Sub for i16 {
- type Output = Self;
-
- fn sub(self, rhs: Self) -> Self {
- self - rhs
- }
-}
-
-#[lang = "mul"]
-pub trait Mul<RHS = Self> {
- type Output;
-
- #[must_use]
- fn mul(self, rhs: RHS) -> Self::Output;
-}
-
-impl Mul for u8 {
- type Output = Self;
-
- fn mul(self, rhs: Self) -> Self::Output {
- self * rhs
- }
-}
-
-impl Mul for usize {
- type Output = Self;
-
- fn mul(self, rhs: Self) -> Self::Output {
- self * rhs
- }
-}
-
-impl Mul for isize {
- type Output = Self;
-
- fn mul(self, rhs: Self) -> Self::Output {
- self * rhs
- }
-}
-
-#[track_caller]
-#[lang = "panic_const_add_overflow"]
-pub fn panic_const_add_overflow() -> ! {
- panic("attempt to add with overflow");
-}
-
-#[track_caller]
-#[lang = "panic_const_sub_overflow"]
-pub fn panic_const_sub_overflow() -> ! {
- panic("attempt to subtract with overflow");
-}
-
-#[track_caller]
-#[lang = "panic_const_mul_overflow"]
-pub fn panic_const_mul_overflow() -> ! {
- panic("attempt to multiply with overflow");
-}
-
-/*
- * Code
- */
+extern crate mini_core;
+use mini_core::*;
#[no_mangle]
extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
diff --git a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
index 0ba49e7..c1254c5 100644
--- a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
@@ -2,35 +2,32 @@
//
// Run-time:
// status: 0
-// stdout: 1
+// stdout: 10
+// 10
+// 42
#![feature(no_core)]
-
#![no_std]
#![no_core]
#![no_main]
extern crate mini_core;
+use mini_core::*;
-mod libc {
- #[link(name = "c")]
- extern "C" {
- pub fn printf(format: *const i8, ...) -> i32;
- }
-}
-
-static mut ONE: usize = 1;
-
-fn make_array() -> [u8; 3] {
- [42, 10, 5]
+fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) {
+ (
+ a as u8, a as u16, a as u32, a as usize, a as i8, a as i16, a as i32, a as isize, b as u8,
+ b as u32,
+ )
}
#[no_mangle]
extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
+ let (a, b, c, d, e, f, g, h, i, j) = int_cast(10, 42);
unsafe {
- let ptr = ONE as *mut usize;
- let value = ptr as usize;
- libc::printf(b"%ld\n\0" as *const u8 as *const i8, value);
+ libc::printf(b"%d\n\0" as *const u8 as *const i8, c);
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, d);
+ libc::printf(b"%ld\n\0" as *const u8 as *const i8, j);
}
0
}
diff --git a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
index 3cc1e27..c1254c5 100644
--- a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
@@ -6,54 +6,13 @@
// 10
// 42
-#![feature(auto_traits, lang_items, no_core, intrinsics)]
-#![allow(internal_features)]
-
+#![feature(no_core)]
#![no_std]
#![no_core]
#![no_main]
-#[lang = "copy"]
-pub unsafe trait Copy {}
-
-impl Copy for bool {}
-impl Copy for u8 {}
-impl Copy for u16 {}
-impl Copy for u32 {}
-impl Copy for u64 {}
-impl Copy for usize {}
-impl Copy for i8 {}
-impl Copy for i16 {}
-impl Copy for i32 {}
-impl Copy for isize {}
-impl Copy for f32 {}
-impl Copy for char {}
-
-mod libc {
- #[link(name = "c")]
- extern "C" {
- pub fn printf(format: *const i8, ...) -> i32;
- }
-}
-
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "legacy_receiver"]
-trait LegacyReceiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
-
-/*
- * Code
- */
+extern crate mini_core;
+use mini_core::*;
fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) {
(
diff --git a/compiler/rustc_codegen_gcc/tests/run/slice.rs b/compiler/rustc_codegen_gcc/tests/run/slice.rs
index 825fcb8..449ccab 100644
--- a/compiler/rustc_codegen_gcc/tests/run/slice.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/slice.rs
@@ -5,26 +5,17 @@
// stdout: 5
#![feature(no_core)]
-
#![no_std]
#![no_core]
#![no_main]
extern crate mini_core;
-
-mod libc {
- #[link(name = "c")]
- extern "C" {
- pub fn printf(format: *const i8, ...) -> i32;
- }
-}
+use mini_core::*;
static mut TWO: usize = 2;
fn index_slice(s: &[u32]) -> u32 {
- unsafe {
- s[TWO]
- }
+ unsafe { s[TWO] }
}
#[no_mangle]
diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs
index c3c8121..1e36cf4 100644
--- a/compiler/rustc_codegen_gcc/tests/run/static.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/static.rs
@@ -9,70 +9,13 @@
// 12
// 1
-#![feature(auto_traits, lang_items, no_core, intrinsics, rustc_attrs)]
-#![allow(internal_features)]
-
+#![feature(no_core)]
#![no_std]
#![no_core]
#![no_main]
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "destruct"]
-pub trait Destruct {}
-
-#[lang = "drop"]
-pub trait Drop {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-impl<T: ?Sized> Copy for *mut T {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
-
-mod intrinsics {
- use super::Sized;
-
- #[rustc_nounwind]
- #[rustc_intrinsic]
- pub fn abort() -> !;
-}
-
-mod libc {
- #[link(name = "c")]
- extern "C" {
- pub fn printf(format: *const i8, ...) -> i32;
- }
-}
-
-#[lang = "structural_peq"]
-pub trait StructuralPartialEq {}
-
-#[lang = "drop_in_place"]
-#[allow(unconditional_recursion)]
-pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
- // Code here does not matter - this is replaced by the
- // real drop glue by the compiler.
- drop_in_place(to_drop);
-}
-
-/*
- * Code
- */
+extern crate mini_core;
+use mini_core::*;
struct Test {
field: isize,
@@ -84,20 +27,14 @@ struct WithRef {
static mut CONSTANT: isize = 10;
-static mut TEST: Test = Test {
- field: 12,
-};
+static mut TEST: Test = Test { field: 12 };
-static mut TEST2: Test = Test {
- field: 14,
-};
+static mut TEST2: Test = Test { field: 14 };
-static mut WITH_REF: WithRef = WithRef {
- refe: unsafe { &TEST },
-};
+static mut WITH_REF: WithRef = WithRef { refe: unsafe { &TEST } };
#[no_mangle]
-extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
+extern "C" fn main(argc: isize, _argv: *const *const u8) -> i32 {
unsafe {
libc::printf(b"%ld\n\0" as *const u8 as *const i8, CONSTANT);
libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field);
diff --git a/compiler/rustc_codegen_gcc/tests/run/structs.rs b/compiler/rustc_codegen_gcc/tests/run/structs.rs
index 59b8f35..da73cbe 100644
--- a/compiler/rustc_codegen_gcc/tests/run/structs.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/structs.rs
@@ -5,44 +5,13 @@
// stdout: 1
// 2
-#![feature(auto_traits, lang_items, no_core, intrinsics)]
-#![allow(internal_features)]
-
+#![feature(no_core)]
#![no_std]
#![no_core]
#![no_main]
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
-
-mod libc {
- #[link(name = "c")]
- extern "C" {
- pub fn printf(format: *const i8, ...) -> i32;
- }
-}
-
-/*
- * Code
- */
+extern crate mini_core;
+use mini_core::*;
struct Test {
field: isize,
diff --git a/compiler/rustc_codegen_gcc/tests/run/tuple.rs b/compiler/rustc_codegen_gcc/tests/run/tuple.rs
index ed60a56..e0f2e95 100644
--- a/compiler/rustc_codegen_gcc/tests/run/tuple.rs
+++ b/compiler/rustc_codegen_gcc/tests/run/tuple.rs
@@ -4,44 +4,13 @@
// status: 0
// stdout: 3
-#![feature(auto_traits, lang_items, no_core, intrinsics)]
-#![allow(internal_features)]
-
+#![feature(no_core)]
#![no_std]
#![no_core]
#![no_main]
-/*
- * Core
- */
-
-// Because we don't have core yet.
-#[lang = "sized"]
-pub trait Sized {}
-
-#[lang = "copy"]
-trait Copy {
-}
-
-impl Copy for isize {}
-
-#[lang = "receiver"]
-trait Receiver {
-}
-
-#[lang = "freeze"]
-pub(crate) unsafe auto trait Freeze {}
-
-mod libc {
- #[link(name = "c")]
- extern "C" {
- pub fn printf(format: *const i8, ...) -> i32;
- }
-}
-
-/*
- * Code
- */
+extern crate mini_core;
+use mini_core::*;
#[no_mangle]
extern "C" fn main(argc: i32, _argv: *const *const u8) -> i32 {
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 35134e9..27f7f95 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -123,7 +123,7 @@ pub(crate) fn build(cx: &'a GenericCx<'ll, CX>, llbb: &'ll BasicBlock) -> Self {
/// Empty string, to be used where LLVM expects an instruction name, indicating
/// that the instruction is to be left unnamed (i.e. numbered, in textual IR).
// FIXME(eddyb) pass `&CStr` directly to FFI once it's a thin pointer.
-const UNNAMED: *const c_char = c"".as_ptr();
+pub(crate) const UNNAMED: *const c_char = c"".as_ptr();
impl<'ll, CX: Borrow<SCx<'ll>>> BackendTypes for GenericBuilder<'_, 'll, CX> {
type Value = <GenericCx<'ll, CX> as BackendTypes>::Value;
diff --git a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
index 5e7ef27..e7c071d 100644
--- a/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
+++ b/compiler/rustc_codegen_llvm/src/builder/autodiff.rs
@@ -10,7 +10,7 @@
use tracing::{debug, trace};
use crate::back::write::llvm_err;
-use crate::builder::SBuilder;
+use crate::builder::{SBuilder, UNNAMED};
use crate::context::SimpleCx;
use crate::declare::declare_simple_fn;
use crate::errors::{AutoDiffWithoutEnable, LlvmError};
@@ -51,6 +51,7 @@ fn has_sret(fnc: &Value) -> bool {
// using iterators and peek()?
fn match_args_from_caller_to_enzyme<'ll>(
cx: &SimpleCx<'ll>,
+ builder: &SBuilder<'ll, 'll>,
width: u32,
args: &mut Vec<&'ll llvm::Value>,
inputs: &[DiffActivity],
@@ -78,7 +79,9 @@ fn match_args_from_caller_to_enzyme<'ll>(
let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap();
let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap();
let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap();
+ let enzyme_dupv = cx.create_metadata("enzyme_dupv".to_string()).unwrap();
let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap();
+ let enzyme_dupnoneedv = cx.create_metadata("enzyme_dupnoneedv".to_string()).unwrap();
while activity_pos < inputs.len() {
let diff_activity = inputs[activity_pos as usize];
@@ -90,13 +93,34 @@ fn match_args_from_caller_to_enzyme<'ll>(
DiffActivity::Active => (enzyme_out, false),
DiffActivity::ActiveOnly => (enzyme_out, false),
DiffActivity::Dual => (enzyme_dup, true),
+ DiffActivity::Dualv => (enzyme_dupv, true),
DiffActivity::DualOnly => (enzyme_dupnoneed, true),
+ DiffActivity::DualvOnly => (enzyme_dupnoneedv, true),
DiffActivity::Duplicated => (enzyme_dup, true),
DiffActivity::DuplicatedOnly => (enzyme_dupnoneed, true),
- DiffActivity::FakeActivitySize => (enzyme_const, false),
+ DiffActivity::FakeActivitySize(_) => (enzyme_const, false),
};
let outer_arg = outer_args[outer_pos];
args.push(cx.get_metadata_value(activity));
+ if matches!(diff_activity, DiffActivity::Dualv) {
+ let next_outer_arg = outer_args[outer_pos + 1];
+ let elem_bytes_size: u64 = match inputs[activity_pos + 1] {
+ DiffActivity::FakeActivitySize(Some(s)) => s.into(),
+ _ => bug!("incorrect Dualv handling recognized."),
+ };
+ // stride: sizeof(T) * n_elems.
+ // n_elems is the next integer.
+ // Now we multiply `4 * next_outer_arg` to get the stride.
+ let mul = unsafe {
+ llvm::LLVMBuildMul(
+ builder.llbuilder,
+ cx.get_const_i64(elem_bytes_size),
+ next_outer_arg,
+ UNNAMED,
+ )
+ };
+ args.push(mul);
+ }
args.push(outer_arg);
if duplicated {
// We know that duplicated args by construction have a following argument,
@@ -114,7 +138,7 @@ fn match_args_from_caller_to_enzyme<'ll>(
} else {
let next_activity = inputs[activity_pos + 1];
// We analyze the MIR types and add this dummy activity if we visit a slice.
- next_activity == DiffActivity::FakeActivitySize
+ matches!(next_activity, DiffActivity::FakeActivitySize(_))
}
};
if slice {
@@ -125,7 +149,10 @@ fn match_args_from_caller_to_enzyme<'ll>(
// int2 >= int1, which means the shadow vector is large enough to store the gradient.
assert_eq!(cx.type_kind(next_outer_ty), TypeKind::Integer);
- for i in 0..(width as usize) {
+ let iterations =
+ if matches!(diff_activity, DiffActivity::Dualv) { 1 } else { width as usize };
+
+ for i in 0..iterations {
let next_outer_arg2 = outer_args[outer_pos + 2 * (i + 1)];
let next_outer_ty2 = cx.val_ty(next_outer_arg2);
assert_eq!(cx.type_kind(next_outer_ty2), TypeKind::Pointer);
@@ -136,7 +163,7 @@ fn match_args_from_caller_to_enzyme<'ll>(
}
args.push(cx.get_metadata_value(enzyme_const));
args.push(next_outer_arg);
- outer_pos += 2 + 2 * width as usize;
+ outer_pos += 2 + 2 * iterations;
activity_pos += 2;
} else {
// A duplicated pointer will have the following two outer_fn arguments:
@@ -360,6 +387,7 @@ fn generate_enzyme_call<'ll>(
let outer_args: Vec<&llvm::Value> = get_params(outer_fn);
match_args_from_caller_to_enzyme(
&cx,
+ &builder,
attrs.width,
&mut args,
&attrs.input_activity,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index f52991b..d259113 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -3,7 +3,6 @@
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext};
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::fx::FxHashMap;
-use rustc_index::Idx;
use rustc_index::bit_set::DenseBitSet;
use rustc_middle::mir::{Body, SourceScope};
use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv};
@@ -43,8 +42,7 @@ pub(crate) fn compute_mir_scopes<'ll, 'tcx>(
let mut instantiated = DenseBitSet::new_empty(mir.source_scopes.len());
let mut discriminators = FxHashMap::default();
// Instantiate all scopes.
- for idx in 0..mir.source_scopes.len() {
- let scope = SourceScope::new(idx);
+ for scope in mir.source_scopes.indices() {
make_mir_scope(
cx,
instance,
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 1eb8f36..7f3e486 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -1315,31 +1315,21 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>(
ty: Ty<'tcx>,
) -> SmallVec<Option<&'ll DIType>> {
if let ty::Adt(def, args) = *ty.kind() {
- let generics = cx.tcx.generics_of(def.did());
- return get_template_parameters(cx, generics, args);
- }
-
- return smallvec![];
-}
-
-pub(super) fn get_template_parameters<'ll, 'tcx>(
- cx: &CodegenCx<'ll, 'tcx>,
- generics: &ty::Generics,
- args: ty::GenericArgsRef<'tcx>,
-) -> SmallVec<Option<&'ll DIType>> {
- if args.types().next().is_some() {
- let names = get_parameter_names(cx, generics);
- let template_params: SmallVec<_> = iter::zip(args, names)
- .filter_map(|(kind, name)| {
- kind.as_type().map(|ty| {
- let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
- let actual_type_di_node = type_di_node(cx, actual_type);
- Some(cx.create_template_type_parameter(name.as_str(), actual_type_di_node))
+ if args.types().next().is_some() {
+ let generics = cx.tcx.generics_of(def.did());
+ let names = get_parameter_names(cx, generics);
+ let template_params: SmallVec<_> = iter::zip(args, names)
+ .filter_map(|(kind, name)| {
+ kind.as_type().map(|ty| {
+ let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
+ let actual_type_di_node = type_di_node(cx, actual_type);
+ Some(cx.create_template_type_parameter(name.as_str(), actual_type_di_node))
+ })
})
- })
- .collect();
+ .collect();
- return template_params;
+ return template_params;
+ }
}
return smallvec![];
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
index 6792c30..7c70192 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
@@ -363,7 +363,6 @@ fn build_coroutine_variant_struct_type_di_node<'ll, 'tcx>(
state_specific_fields.into_iter().chain(common_fields).collect()
},
- // FIXME: this is a no-op. `build_generic_type_param_di_nodes` only works for Adts.
|cx| build_generic_type_param_di_nodes(cx, coroutine_type_and_layout.ty),
)
.di_node
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
index ae2ab32..56fb12d 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs
@@ -247,6 +247,16 @@ pub(super) fn stub<'ll, 'tcx>(
StubInfo { metadata, unique_type_id }
}
+struct AdtStackPopGuard<'ll, 'tcx, 'a> {
+ cx: &'a CodegenCx<'ll, 'tcx>,
+}
+
+impl<'ll, 'tcx, 'a> Drop for AdtStackPopGuard<'ll, 'tcx, 'a> {
+ fn drop(&mut self) {
+ debug_context(self.cx).adt_stack.borrow_mut().pop();
+ }
+}
+
/// This function enables creating debuginfo nodes that can recursively refer to themselves.
/// It will first insert the given stub into the type map and only then execute the `members`
/// and `generics` closures passed in. These closures have access to the stub so they can
@@ -261,6 +271,44 @@ pub(super) fn build_type_with_children<'ll, 'tcx>(
) -> DINodeCreationResult<'ll> {
assert_eq!(debug_context(cx).type_map.di_node_for_unique_id(stub_info.unique_type_id), None);
+ let mut _adt_stack_pop_guard = None;
+ if let UniqueTypeId::Ty(ty, ..) = stub_info.unique_type_id
+ && let ty::Adt(adt_def, args) = ty.kind()
+ {
+ let def_id = adt_def.did();
+ // If any sub type reference the original type definition and the sub type has a type
+ // parameter that strictly contains the original parameter, the original type is a recursive
+ // type that can expanding indefinitely. Example,
+ // ```
+ // enum Recursive<T> {
+ // Recurse(*const Recursive<Wrap<T>>),
+ // Item(T),
+ // }
+ // ```
+ let is_expanding_recursive =
+ debug_context(cx).adt_stack.borrow().iter().any(|(parent_def_id, parent_args)| {
+ if def_id == *parent_def_id {
+ args.iter().zip(parent_args.iter()).any(|(arg, parent_arg)| {
+ if let (Some(arg), Some(parent_arg)) = (arg.as_type(), parent_arg.as_type())
+ {
+ arg != parent_arg && arg.contains(parent_arg)
+ } else {
+ false
+ }
+ })
+ } else {
+ false
+ }
+ });
+ if is_expanding_recursive {
+ // FIXME: indicate that this is an expanding recursive type in stub metadata?
+ return DINodeCreationResult::new(stub_info.metadata, false);
+ } else {
+ debug_context(cx).adt_stack.borrow_mut().push((def_id, args));
+ _adt_stack_pop_guard = Some(AdtStackPopGuard { cx });
+ }
+ }
+
debug_context(cx).type_map.insert(stub_info.unique_type_id, stub_info.metadata);
let members: SmallVec<_> =
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index ae7d080..c508592 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -2,8 +2,8 @@
use std::cell::{OnceCell, RefCell};
use std::ops::Range;
-use std::ptr;
use std::sync::Arc;
+use std::{iter, ptr};
use libc::c_uint;
use metadata::create_subroutine_type;
@@ -66,6 +66,7 @@ pub(crate) struct CodegenUnitDebugContext<'ll, 'tcx> {
created_files: RefCell<UnordMap<Option<(StableSourceFileId, SourceFileHash)>, &'ll DIFile>>,
type_map: metadata::TypeMap<'ll, 'tcx>,
+ adt_stack: RefCell<Vec<(DefId, GenericArgsRef<'tcx>)>>,
namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
recursion_marker_type: OnceCell<&'ll DIType>,
}
@@ -80,6 +81,7 @@ pub(crate) fn new(llmod: &'ll llvm::Module) -> Self {
builder,
created_files: Default::default(),
type_map: Default::default(),
+ adt_stack: Default::default(),
namespace_map: RefCell::new(Default::default()),
recursion_marker_type: OnceCell::new(),
}
@@ -486,10 +488,40 @@ fn get_template_parameters<'ll, 'tcx>(
generics: &ty::Generics,
args: GenericArgsRef<'tcx>,
) -> &'ll DIArray {
- let template_params = metadata::get_template_parameters(cx, generics, args);
+ if args.types().next().is_none() {
+ return create_DIArray(DIB(cx), &[]);
+ }
+
+ // Again, only create type information if full debuginfo is enabled
+ let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
+ let names = get_parameter_names(cx, generics);
+ iter::zip(args, names)
+ .filter_map(|(kind, name)| {
+ kind.as_type().map(|ty| {
+ let actual_type = cx.tcx.normalize_erasing_regions(cx.typing_env(), ty);
+ let actual_type_metadata = type_di_node(cx, actual_type);
+ Some(cx.create_template_type_parameter(
+ name.as_str(),
+ actual_type_metadata,
+ ))
+ })
+ })
+ .collect()
+ } else {
+ vec![]
+ };
+
create_DIArray(DIB(cx), &template_params)
}
+ fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec<Symbol> {
+ let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
+ get_parameter_names(cx, cx.tcx.generics_of(def_id))
+ });
+ names.extend(generics.own_params.iter().map(|param| param.name));
+ names
+ }
+
/// Returns a scope, plus `true` if that's a type scope for "class" methods,
/// otherwise `false` for plain namespace scopes.
fn get_containing_scope<'ll, 'tcx>(
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index d1d6bce..ffeab59 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -1184,18 +1184,6 @@ macro_rules! require_simd {
}};
}
- /// Returns the bitwidth of the `$ty` argument if it is an `Int` type.
- macro_rules! require_int_ty {
- ($ty: expr, $diag: expr) => {
- match $ty {
- ty::Int(i) => i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()),
- _ => {
- return_error!($diag);
- }
- }
- };
- }
-
/// Returns the bitwidth of the `$ty` argument if it is an `Int` or `Uint` type.
macro_rules! require_int_or_uint_ty {
($ty: expr, $diag: expr) => {
@@ -1485,9 +1473,9 @@ fn vector_mask_to_bitmask<'a, 'll, 'tcx>(
m_len == v_len,
InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
);
- let in_elem_bitwidth = require_int_ty!(
+ let in_elem_bitwidth = require_int_or_uint_ty!(
m_elem_ty.kind(),
- InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }
+ InvalidMonomorphization::MaskWrongElementType { span, name, ty: m_elem_ty }
);
let m_i1s = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len);
return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
@@ -1508,7 +1496,7 @@ fn vector_mask_to_bitmask<'a, 'll, 'tcx>(
// Integer vector <i{in_bitwidth} x in_len>:
let in_elem_bitwidth = require_int_or_uint_ty!(
in_elem.kind(),
- InvalidMonomorphization::VectorArgument { span, name, in_ty, in_elem }
+ InvalidMonomorphization::MaskWrongElementType { span, name, ty: in_elem }
);
let i1xn = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, in_len);
@@ -1732,14 +1720,9 @@ fn llvm_vector_ty<'ll>(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: u64) -
}
);
- let mask_elem_bitwidth = require_int_ty!(
+ let mask_elem_bitwidth = require_int_or_uint_ty!(
element_ty2.kind(),
- InvalidMonomorphization::ThirdArgElementType {
- span,
- name,
- expected_element: element_ty2,
- third_arg: arg_tys[2]
- }
+ InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 }
);
// Alignment of T, must be a constant integer value:
@@ -1834,14 +1817,9 @@ fn llvm_vector_ty<'ll>(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: u64) -
}
);
- let m_elem_bitwidth = require_int_ty!(
+ let m_elem_bitwidth = require_int_or_uint_ty!(
mask_elem.kind(),
- InvalidMonomorphization::ThirdArgElementType {
- span,
- name,
- expected_element: values_elem,
- third_arg: mask_ty,
- }
+ InvalidMonomorphization::MaskWrongElementType { span, name, ty: mask_elem }
);
let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
@@ -1924,14 +1902,9 @@ fn llvm_vector_ty<'ll>(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: u64) -
}
);
- let m_elem_bitwidth = require_int_ty!(
+ let m_elem_bitwidth = require_int_or_uint_ty!(
mask_elem.kind(),
- InvalidMonomorphization::ThirdArgElementType {
- span,
- name,
- expected_element: values_elem,
- third_arg: mask_ty,
- }
+ InvalidMonomorphization::MaskWrongElementType { span, name, ty: mask_elem }
);
let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
@@ -2019,15 +1992,10 @@ fn llvm_vector_ty<'ll>(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: u64) -
}
);
- // The element type of the third argument must be a signed integer type of any width:
- let mask_elem_bitwidth = require_int_ty!(
+ // The element type of the third argument must be an integer type of any width:
+ let mask_elem_bitwidth = require_int_or_uint_ty!(
element_ty2.kind(),
- InvalidMonomorphization::ThirdArgElementType {
- span,
- name,
- expected_element: element_ty2,
- third_arg: arg_tys[2]
- }
+ InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 }
);
// Alignment of T, must be a constant integer value:
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 1dabf01..2621935 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -125,8 +125,7 @@
codegen_ssa_invalid_monomorphization_invalid_bitmask = invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$mask_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
-codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: found mask element type is `{$ty}`, expected a signed integer type
- .note = the mask may be widened, which only has the correct behavior for signed integers
+codegen_ssa_invalid_monomorphization_mask_wrong_element_type = invalid monomorphization of `{$name}` intrinsic: expected mask element type to be an integer, found `{$ty}`
codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
@@ -158,8 +157,6 @@
codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}`
-codegen_ssa_invalid_monomorphization_third_arg_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of third argument `{$third_arg}` to be a signed integer type
-
codegen_ssa_invalid_monomorphization_third_argument_length = invalid monomorphization of `{$name}` intrinsic: expected third argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
codegen_ssa_invalid_monomorphization_unrecognized_intrinsic = invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}`
@@ -172,8 +169,6 @@
codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}`
-codegen_ssa_invalid_monomorphization_vector_argument = invalid monomorphization of `{$name}` intrinsic: vector argument `{$in_ty}`'s element type `{$in_elem}`, expected integer element type
-
codegen_ssa_invalid_no_sanitize = invalid argument for `no_sanitize`
.note = expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index ddb6118..b0c53ec 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -114,7 +114,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
AttributeKind::Repr(reprs) => {
codegen_fn_attrs.alignment = reprs
.iter()
- .find_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None });
+ .filter_map(|(r, _)| if let ReprAlign(x) = r { Some(*x) } else { None })
+ .max();
}
_ => {}
@@ -345,20 +346,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
no_sanitize_span = Some(attr.span());
if let Some(list) = attr.meta_item_list() {
for item in list.iter() {
- match item.name_or_empty() {
- sym::address => {
+ match item.name() {
+ Some(sym::address) => {
codegen_fn_attrs.no_sanitize |=
SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS
}
- sym::cfi => codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI,
- sym::kcfi => codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI,
- sym::memory => codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY,
- sym::memtag => codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG,
- sym::shadow_call_stack => {
+ Some(sym::cfi) => codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI,
+ Some(sym::kcfi) => codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI,
+ Some(sym::memory) => {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY
+ }
+ Some(sym::memtag) => {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG
+ }
+ Some(sym::shadow_call_stack) => {
codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK
}
- sym::thread => codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD,
- sym::hwaddress => {
+ Some(sym::thread) => {
+ codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD
+ }
+ Some(sym::hwaddress) => {
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS
}
_ => {
@@ -419,9 +426,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
continue;
};
- let attrib_to_write = match meta_item.name_or_empty() {
- sym::prefix_nops => &mut prefix,
- sym::entry_nops => &mut entry,
+ let attrib_to_write = match meta_item.name() {
+ Some(sym::prefix_nops) => &mut prefix,
+ Some(sym::entry_nops) => &mut entry,
_ => {
tcx.dcx().emit_err(errors::UnexpectedParameterName {
span: item.span(),
@@ -785,8 +792,7 @@ fn lint_if_mixed(self, tcx: TyCtxt<'_>) {
fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
let attrs = tcx.get_attrs(id, sym::rustc_autodiff);
- let attrs =
- attrs.filter(|attr| attr.name_or_empty() == sym::rustc_autodiff).collect::<Vec<_>>();
+ let attrs = attrs.filter(|attr| attr.has_name(sym::rustc_autodiff)).collect::<Vec<_>>();
// check for exactly one autodiff attribute on placeholder functions.
// There should only be one, since we generate a new placeholder per ad macro.
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 42cea5c8..c206439 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -1037,24 +1037,14 @@ pub enum InvalidMonomorphization<'tcx> {
v_len: u64,
},
- #[diag(codegen_ssa_invalid_monomorphization_mask_type, code = E0511)]
- #[note]
- MaskType {
+ #[diag(codegen_ssa_invalid_monomorphization_mask_wrong_element_type, code = E0511)]
+ MaskWrongElementType {
#[primary_span]
span: Span,
name: Symbol,
ty: Ty<'tcx>,
},
- #[diag(codegen_ssa_invalid_monomorphization_vector_argument, code = E0511)]
- VectorArgument {
- #[primary_span]
- span: Span,
- name: Symbol,
- in_ty: Ty<'tcx>,
- in_elem: Ty<'tcx>,
- },
-
#[diag(codegen_ssa_invalid_monomorphization_cannot_return, code = E0511)]
CannotReturn {
#[primary_span]
@@ -1077,15 +1067,6 @@ pub enum InvalidMonomorphization<'tcx> {
mutability: ExpectedPointerMutability,
},
- #[diag(codegen_ssa_invalid_monomorphization_third_arg_element_type, code = E0511)]
- ThirdArgElementType {
- #[primary_span]
- span: Span,
- name: Symbol,
- expected_element: Ty<'tcx>,
- third_arg: Ty<'tcx>,
- },
-
#[diag(codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size, code = E0511)]
UnsupportedSymbolOfSize {
#[primary_span]
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 153935f..5b2ed69 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -2,7 +2,6 @@
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(assert_matches)]
diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs
index 2b74c84..b600b89 100644
--- a/compiler/rustc_const_eval/src/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/check_consts/check.rs
@@ -34,7 +34,7 @@
use crate::errors;
type QualifResults<'mir, 'tcx, Q> =
- rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'mir, 'tcx, Q>>;
+ rustc_mir_dataflow::ResultsCursor<'mir, 'tcx, FlowSensitiveAnalysis<'mir, 'tcx, Q>>;
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum ConstConditionsHold {
diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs
index 8cee282..9f7fcc5 100644
--- a/compiler/rustc_const_eval/src/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs
@@ -22,17 +22,17 @@
/// qualified immediately after it is borrowed or its address escapes. The borrow must allow for
/// mutation, which includes shared borrows of places with interior mutability. The type of
/// borrowed place must contain the qualif.
-struct TransferFunction<'a, 'mir, 'tcx, Q> {
- ccx: &'a ConstCx<'mir, 'tcx>,
- state: &'a mut State,
+struct TransferFunction<'mir, 'tcx, Q> {
+ ccx: &'mir ConstCx<'mir, 'tcx>,
+ state: &'mir mut State,
_qualif: PhantomData<Q>,
}
-impl<'a, 'mir, 'tcx, Q> TransferFunction<'a, 'mir, 'tcx, Q>
+impl<'mir, 'tcx, Q> TransferFunction<'mir, 'tcx, Q>
where
Q: Qualif,
{
- fn new(ccx: &'a ConstCx<'mir, 'tcx>, state: &'a mut State) -> Self {
+ fn new(ccx: &'mir ConstCx<'mir, 'tcx>, state: &'mir mut State) -> Self {
TransferFunction { ccx, state, _qualif: PhantomData }
}
@@ -124,7 +124,7 @@ fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool {
}
}
-impl<'tcx, Q> Visitor<'tcx> for TransferFunction<'_, '_, 'tcx, Q>
+impl<'tcx, Q> Visitor<'tcx> for TransferFunction<'_, 'tcx, Q>
where
Q: Qualif,
{
@@ -228,20 +228,20 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Loc
}
/// The dataflow analysis used to propagate qualifs on arbitrary CFGs.
-pub(super) struct FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q> {
- ccx: &'a ConstCx<'mir, 'tcx>,
+pub(super) struct FlowSensitiveAnalysis<'mir, 'tcx, Q> {
+ ccx: &'mir ConstCx<'mir, 'tcx>,
_qualif: PhantomData<Q>,
}
-impl<'a, 'mir, 'tcx, Q> FlowSensitiveAnalysis<'a, 'mir, 'tcx, Q>
+impl<'mir, 'tcx, Q> FlowSensitiveAnalysis<'mir, 'tcx, Q>
where
Q: Qualif,
{
- pub(super) fn new(_: Q, ccx: &'a ConstCx<'mir, 'tcx>) -> Self {
+ pub(super) fn new(_: Q, ccx: &'mir ConstCx<'mir, 'tcx>) -> Self {
FlowSensitiveAnalysis { ccx, _qualif: PhantomData }
}
- fn transfer_function(&self, state: &'a mut State) -> TransferFunction<'a, 'mir, 'tcx, Q> {
+ fn transfer_function(&self, state: &'mir mut State) -> TransferFunction<'mir, 'tcx, Q> {
TransferFunction::<Q>::new(self.ccx, state)
}
}
@@ -313,7 +313,7 @@ fn join(&mut self, other: &Self) -> bool {
}
}
-impl<'tcx, Q> Analysis<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q>
+impl<'tcx, Q> Analysis<'tcx> for FlowSensitiveAnalysis<'_, 'tcx, Q>
where
Q: Qualif,
{
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index e2675e2..6472aaa 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -6,7 +6,7 @@
use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagArgValue, DiagCtxtHandle, DiagMessage, Diagnostic, EmissionGuarantee, Level,
- MultiSpan, SubdiagMessageOp, Subdiagnostic,
+ MultiSpan, Subdiagnostic,
};
use rustc_hir::ConstContext;
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@@ -290,11 +290,7 @@ pub struct FrameNote {
}
impl Subdiagnostic for FrameNote {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("times", self.times);
diag.arg("where_", self.where_);
diag.arg("instance", self.instance);
@@ -302,7 +298,7 @@ fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
if self.has_label && !self.span.is_dummy() {
span.push_span_label(self.span, fluent::const_eval_frame_note_last);
}
- let msg = f(diag, fluent::const_eval_frame_note.into());
+ let msg = diag.eagerly_translate(fluent::const_eval_frame_note);
diag.span_note(span, msg);
}
}
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index c1948e9..b69bc09 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -268,7 +268,7 @@ pub fn load_mir(
/// Call this on things you got out of the MIR (so it is as generic as the current
/// stack frame), to bring it into the proper environment for this interpreter.
- pub(super) fn instantiate_from_current_frame_and_normalize_erasing_regions<
+ pub fn instantiate_from_current_frame_and_normalize_erasing_regions<
T: TypeFoldable<TyCtxt<'tcx>>,
>(
&self,
@@ -279,9 +279,7 @@ pub(super) fn instantiate_from_current_frame_and_normalize_erasing_regions<
/// Call this on things you got out of the MIR (so it is as generic as the provided
/// stack frame), to bring it into the proper environment for this interpreter.
- pub(super) fn instantiate_from_frame_and_normalize_erasing_regions<
- T: TypeFoldable<TyCtxt<'tcx>>,
- >(
+ pub fn instantiate_from_frame_and_normalize_erasing_regions<T: TypeFoldable<TyCtxt<'tcx>>>(
&self,
frame: &Frame<'tcx, M::Provenance, M::FrameExtra>,
value: T,
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index e4b2fe5..8f0cb19 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -30,6 +30,7 @@
AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, err_ub, interp_ok,
};
use crate::const_eval;
+use crate::const_eval::DummyMachine;
use crate::errors::NestedStaticInThreadLocal;
pub trait CompileTimeMachine<'tcx, T> = Machine<
@@ -323,14 +324,17 @@ pub fn intern_const_alloc_for_constprop<'tcx, T, M: CompileTimeMachine<'tcx, T>>
interp_ok(())
}
-impl<'tcx, M: super::intern::CompileTimeMachine<'tcx, !>> InterpCx<'tcx, M> {
+impl<'tcx> InterpCx<'tcx, DummyMachine> {
/// A helper function that allocates memory for the layout given and gives you access to mutate
/// it. Once your own mutation code is done, the backing `Allocation` is removed from the
/// current `Memory` and interned as read-only into the global memory.
pub fn intern_with_temp_alloc(
&mut self,
layout: TyAndLayout<'tcx>,
- f: impl FnOnce(&mut InterpCx<'tcx, M>, &PlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx, ()>,
+ f: impl FnOnce(
+ &mut InterpCx<'tcx, DummyMachine>,
+ &PlaceTy<'tcx, CtfeProvenance>,
+ ) -> InterpResult<'tcx, ()>,
) -> InterpResult<'tcx, AllocId> {
// `allocate` picks a fresh AllocId that we will associate with its data below.
let dest = self.allocate(layout, MemoryKind::Stack)?;
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index d077900..9d81306 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -872,8 +872,21 @@ pub fn get_alloc_info(&self, id: AllocId) -> AllocInfo {
// # Function pointers
// (both global from `alloc_map` and local from `extra_fn_ptr_map`)
- if self.get_fn_alloc(id).is_some() {
- return AllocInfo::new(Size::ZERO, Align::ONE, AllocKind::Function, Mutability::Not);
+ if let Some(fn_val) = self.get_fn_alloc(id) {
+ let align = match fn_val {
+ FnVal::Instance(instance) => {
+ // Function alignment can be set globally with the `-Zmin-function-alignment=<n>` flag;
+ // the alignment from a `#[repr(align(<n>))]` is used if it specifies a higher alignment.
+ let fn_align = self.tcx.codegen_fn_attrs(instance.def_id()).alignment;
+ let global_align = self.tcx.sess.opts.unstable_opts.min_function_alignment;
+
+ Ord::max(global_align, fn_align).unwrap_or(Align::ONE)
+ }
+ // Machine-specific extra functions currently do not support alignment restrictions.
+ FnVal::Other(_) => Align::ONE,
+ };
+
+ return AllocInfo::new(Size::ZERO, align, AllocKind::Function, Mutability::Not);
}
// # Global allocations
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index e03849c..da52d60 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -1,7 +1,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(rust_logo)]
#![feature(assert_matches)]
#![feature(box_patterns)]
diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs
index 744ae9b..5f07cfe 100644
--- a/compiler/rustc_data_structures/src/marker.rs
+++ b/compiler/rustc_data_structures/src/marker.rs
@@ -1,13 +1,13 @@
use std::alloc::Allocator;
-#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \
+#[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSend`. \
Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`")]
// This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()`
// is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a
// `Send` type in `IntoDynSyncSend` will create a `DynSend` type.
pub unsafe auto trait DynSend {}
-#[rustc_on_unimplemented(message = "`{Self}` doesn't implement `DynSync`. \
+#[diagnostic::on_unimplemented(message = "`{Self}` doesn't implement `DynSync`. \
Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Sync`")]
// This is an auto trait for types which can be shared across threads if `sync::is_dyn_thread_safe()`
// is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index 381309f..a03834c 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -3,7 +3,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(rust_logo)]
#![feature(rustdoc_internals)]
// tidy-alphabetical-end
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index de64335..c823d11 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -4,6 +4,7 @@
edition = "2024"
[dependencies]
+jiff = { version = "0.2.5", default-features = false, features = ["std"] }
# tidy-alphabetical-start
rustc_abi = { path = "../rustc_abi" }
rustc_ast = { path = "../rustc_ast" }
@@ -50,7 +51,6 @@
rustc_ty_utils = { path = "../rustc_ty_utils" }
serde_json = "1.0.59"
shlex = "1.0"
-time = { version = "0.3.36", default-features = false, features = ["alloc", "formatting", "macros"] }
tracing = { version = "0.1.35" }
# tidy-alphabetical-end
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 7d9560a..40cc827 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -7,7 +7,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(decl_macro)]
@@ -30,7 +29,7 @@
use std::process::{self, Command, Stdio};
use std::sync::OnceLock;
use std::sync::atomic::{AtomicBool, Ordering};
-use std::time::{Instant, SystemTime};
+use std::time::Instant;
use std::{env, str};
use rustc_ast as ast;
@@ -66,8 +65,6 @@
use rustc_span::def_id::LOCAL_CRATE;
use rustc_target::json::ToJson;
use rustc_target::spec::{Target, TargetTuple};
-use time::OffsetDateTime;
-use time::macros::format_description;
use tracing::trace;
#[allow(unused_macros)]
@@ -1301,13 +1298,8 @@ fn ice_path_with_config(config: Option<&UnstableOptions>) -> &'static Option<Pat
.or_else(|| std::env::current_dir().ok())
.unwrap_or_default(),
};
- let now: OffsetDateTime = SystemTime::now().into();
- let file_now = now
- .format(
- // Don't use a standard datetime format because Windows doesn't support `:` in paths
- &format_description!("[year]-[month]-[day]T[hour]_[minute]_[second]"),
- )
- .unwrap_or_default();
+ // Don't use a standard datetime format because Windows doesn't support `:` in paths
+ let file_now = jiff::Zoned::now().strftime("%Y-%m-%dT%H_%M_%S");
let pid = std::process::id();
path.push(format!("rustc-ice-{file_now}-{pid}.txt"));
Some(path)
diff --git a/compiler/rustc_error_codes/src/error_codes/E0736.md b/compiler/rustc_error_codes/src/error_codes/E0736.md
index cb7633b..66d5fbb 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0736.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0736.md
@@ -11,7 +11,7 @@
```compile_fail,E0736
#[inline]
-#[naked]
+#[unsafe(naked)]
fn foo() {}
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0755.md b/compiler/rustc_error_codes/src/error_codes/E0755.md
index 88b7f48..b67f078 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0755.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0755.md
@@ -5,7 +5,7 @@
```compile_fail,E0755
#![feature(ffi_pure)]
-#[ffi_pure] // error!
+#[unsafe(ffi_pure)] // error!
pub fn foo() {}
# fn main() {}
```
@@ -17,7 +17,7 @@
#![feature(ffi_pure)]
extern "C" {
- #[ffi_pure] // ok!
+ #[unsafe(ffi_pure)] // ok!
pub fn strlen(s: *const i8) -> isize;
}
# fn main() {}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0756.md b/compiler/rustc_error_codes/src/error_codes/E0756.md
index ffdc421..aadde03 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0756.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0756.md
@@ -6,7 +6,7 @@
```compile_fail,E0756
#![feature(ffi_const)]
-#[ffi_const] // error!
+#[unsafe(ffi_const)] // error!
pub fn foo() {}
# fn main() {}
```
@@ -18,7 +18,7 @@
#![feature(ffi_const)]
extern "C" {
- #[ffi_const] // ok!
+ #[unsafe(ffi_const)] // ok!
pub fn strlen(s: *const i8) -> i32;
}
# fn main() {}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0757.md b/compiler/rustc_error_codes/src/error_codes/E0757.md
index 41b06b2..fb75b02 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0757.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0757.md
@@ -6,8 +6,9 @@
#![feature(ffi_const, ffi_pure)]
extern "C" {
- #[ffi_const]
- #[ffi_pure] // error: `#[ffi_const]` function cannot be `#[ffi_pure]`
+ #[unsafe(ffi_const)]
+ #[unsafe(ffi_pure)]
+ //~^ ERROR `#[ffi_const]` function cannot be `#[ffi_pure]`
pub fn square(num: i32) -> i32;
}
```
@@ -19,7 +20,7 @@
#![feature(ffi_const)]
extern "C" {
- #[ffi_const]
+ #[unsafe(ffi_const)]
pub fn square(num: i32) -> i32;
}
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0787.md b/compiler/rustc_error_codes/src/error_codes/E0787.md
index f5c5faa..b7f92c8 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0787.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0787.md
@@ -3,9 +3,7 @@
Erroneous code example:
```compile_fail,E0787
-#![feature(naked_functions)]
-
-#[naked]
+#[unsafe(naked)]
pub extern "C" fn f() -> u32 {
42
}
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index bd13c41..539ecfb 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -181,22 +181,9 @@ pub trait Subdiagnostic
Self: Sized,
{
/// Add a subdiagnostic to an existing diagnostic.
- fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
- self.add_to_diag_with(diag, &|_, m| m);
- }
-
- /// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used
- /// (to optionally perform eager translation).
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- f: &F,
- );
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>);
}
-pub trait SubdiagMessageOp<G: EmissionGuarantee> =
- Fn(&mut Diag<'_, G>, SubdiagMessage) -> SubdiagMessage;
-
/// Trait implemented by lint types. This should not be implemented manually. Instead, use
/// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic].
#[rustc_diagnostic_item = "LintDiagnostic"]
@@ -1227,15 +1214,21 @@ pub fn tool_only_span_suggestion(
/// interpolated variables).
#[rustc_lint_diagnostics]
pub fn subdiagnostic(&mut self, subdiagnostic: impl Subdiagnostic) -> &mut Self {
- let dcx = self.dcx;
- subdiagnostic.add_to_diag_with(self, &|diag, msg| {
- let args = diag.args.iter();
- let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
- dcx.eagerly_translate(msg, args)
- });
+ subdiagnostic.add_to_diag(self);
self
}
+ /// Fluent variables are not namespaced from each other, so when
+ /// `Diagnostic`s and `Subdiagnostic`s use the same variable name,
+ /// one value will clobber the other. Eagerly translating the
+ /// diagnostic uses the variables defined right then, before the
+ /// clobbering occurs.
+ pub fn eagerly_translate(&self, msg: impl Into<SubdiagMessage>) -> SubdiagMessage {
+ let args = self.args.iter();
+ let msg = self.subdiagnostic_message_to_diagnostic_message(msg.into());
+ self.dcx.eagerly_translate(msg, args)
+ }
+
with_fn! { with_span,
/// Add a span.
#[rustc_lint_diagnostics]
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index cb2e176..8b59ba9 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -19,7 +19,7 @@
use crate::diagnostic::DiagLocation;
use crate::{
Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, ErrCode, IntoDiagArg, Level,
- SubdiagMessageOp, Subdiagnostic, fluent_generated as fluent,
+ Subdiagnostic, fluent_generated as fluent,
};
pub struct DiagArgFromDisplay<'a>(pub &'a dyn fmt::Display);
@@ -384,11 +384,7 @@ pub struct SingleLabelManySpans {
pub label: &'static str,
}
impl Subdiagnostic for SingleLabelManySpans {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.span_labels(self.spans, self.label);
}
}
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 75bb0e8..c0c5dba 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -47,7 +47,7 @@
pub use diagnostic::{
BugAbort, Diag, DiagArg, DiagArgMap, DiagArgName, DiagArgValue, DiagInner, DiagStyledString,
Diagnostic, EmissionGuarantee, FatalAbort, IntoDiagArg, LintDiagnostic, StringPart, Subdiag,
- SubdiagMessageOp, Subdiagnostic,
+ Subdiagnostic,
};
pub use diagnostic_impls::{
DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 49f6d58..f5eaf7d 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -824,10 +824,10 @@ fn collapse_debuginfo_by_name(
return Err(item.span);
}
- match item.name_or_empty() {
- sym::no => Ok(CollapseMacroDebuginfo::No),
- sym::external => Ok(CollapseMacroDebuginfo::External),
- sym::yes => Ok(CollapseMacroDebuginfo::Yes),
+ match item.name() {
+ Some(sym::no) => Ok(CollapseMacroDebuginfo::No),
+ Some(sym::external) => Ok(CollapseMacroDebuginfo::External),
+ Some(sym::yes) => Ok(CollapseMacroDebuginfo::Yes),
_ => Err(item.path.span),
}
}
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index bcc2703..d2e45d7 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -237,22 +237,7 @@ fn can_skip(stream: &AttrTokenStream) -> bool {
inner = self.configure_tokens(&inner);
Some(AttrTokenTree::Delimited(sp, spacing, delim, inner))
}
- AttrTokenTree::Token(
- Token {
- kind:
- TokenKind::NtIdent(..)
- | TokenKind::NtLifetime(..)
- | TokenKind::Interpolated(..),
- ..
- },
- _,
- ) => {
- panic!("Nonterminal should have been flattened: {:?}", tree);
- }
- AttrTokenTree::Token(
- Token { kind: TokenKind::OpenDelim(_) | TokenKind::CloseDelim(_), .. },
- _,
- ) => {
+ AttrTokenTree::Token(Token { kind, .. }, _) if kind.is_delim() => {
panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tree);
}
AttrTokenTree::Token(token, spacing) => Some(AttrTokenTree::Token(token, spacing)),
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 1b53947..1f430b0 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -7,13 +7,12 @@
use rustc_ast as ast;
use rustc_ast::mut_visit::*;
use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter};
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::visit::{self, AssocCtxt, Visitor, VisitorResult, try_visit, walk_list};
use rustc_ast::{
AssocItemKind, AstNodeWrapper, AttrArgs, AttrStyle, AttrVec, ExprKind, ForeignItemKind,
HasAttrs, HasNodeId, Inline, ItemKind, MacStmtStyle, MetaItemInner, MetaItemKind, ModKind,
- NodeId, PatKind, StmtKind, TyKind,
+ NodeId, PatKind, StmtKind, TyKind, token,
};
use rustc_ast_pretty::pprust;
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
@@ -1004,7 +1003,7 @@ pub fn parse_ast_fragment<'a>(
AstFragmentKind::Stmts => {
let mut stmts = SmallVec::new();
// Won't make progress on a `}`.
- while this.token != token::Eof && this.token != token::CloseDelim(Delimiter::Brace) {
+ while this.token != token::Eof && this.token != token::CloseBrace {
if let Some(stmt) = this.parse_full_stmt(AttemptLocalParseRecovery::Yes)? {
stmts.push(stmt);
}
@@ -2053,8 +2052,8 @@ fn flat_map_node<Node: InvocationCollectorNode<OutputTy: Default>>(
) -> Node::OutputTy {
loop {
return match self.take_first_attr(&mut node) {
- Some((attr, pos, derives)) => match attr.name_or_empty() {
- sym::cfg => {
+ Some((attr, pos, derives)) => match attr.name() {
+ Some(sym::cfg) => {
let (res, meta_item) = self.expand_cfg_true(&mut node, attr, pos);
if res {
continue;
@@ -2071,7 +2070,7 @@ fn flat_map_node<Node: InvocationCollectorNode<OutputTy: Default>>(
}
Default::default()
}
- sym::cfg_attr => {
+ Some(sym::cfg_attr) => {
self.expand_cfg_attr(&mut node, &attr, pos);
continue;
}
@@ -2144,8 +2143,8 @@ fn visit_node<Node: InvocationCollectorNode<OutputTy = Node> + DummyAstNode>(
) {
loop {
return match self.take_first_attr(node) {
- Some((attr, pos, derives)) => match attr.name_or_empty() {
- sym::cfg => {
+ Some((attr, pos, derives)) => match attr.name() {
+ Some(sym::cfg) => {
let span = attr.span;
if self.expand_cfg_true(node, attr, pos).0 {
continue;
@@ -2154,7 +2153,7 @@ fn visit_node<Node: InvocationCollectorNode<OutputTy = Node> + DummyAstNode>(
node.expand_cfg_false(self, pos, span);
continue;
}
- sym::cfg_attr => {
+ Some(sym::cfg_attr) => {
self.expand_cfg_attr(node, &attr, pos);
continue;
}
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index e60a9e8..698492f 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -1,6 +1,6 @@
use std::borrow::Cow;
-use rustc_ast::token::{self, Delimiter, Token, TokenKind};
+use rustc_ast::token::{self, Token};
use rustc_ast::tokenstream::TokenStream;
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, DiagMessage};
use rustc_macros::Subdiagnostic;
@@ -66,10 +66,8 @@ pub(super) fn failed_to_match_macro(
}
if let MatcherLoc::Token { token: expected_token } = &remaining_matcher
- && (matches!(expected_token.kind, TokenKind::Interpolated(_))
- || matches!(token.kind, TokenKind::Interpolated(_))
- || matches!(expected_token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_)))
- || matches!(token.kind, TokenKind::OpenDelim(Delimiter::Invisible(_))))
+ && (matches!(expected_token.kind, token::OpenInvisible(_))
+ || matches!(token.kind, token::OpenInvisible(_)))
{
err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
@@ -162,7 +160,7 @@ fn after_arm(&mut self, result: &NamedParseResult<Self::Failure>) {
.is_none_or(|failure| failure.is_better_position(*approx_position))
{
self.best_failure = Some(BestFailure {
- token: token.clone(),
+ token: *token,
position_in_tokenstream: *approx_position,
msg,
remaining_matcher: self
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index d709fd7..c78beb4 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -179,11 +179,11 @@ fn inner(
for tt in tts {
match tt {
TokenTree::Token(token) => {
- locs.push(MatcherLoc::Token { token: token.clone() });
+ locs.push(MatcherLoc::Token { token: *token });
}
TokenTree::Delimited(span, _, delimited) => {
- let open_token = Token::new(token::OpenDelim(delimited.delim), span.open);
- let close_token = Token::new(token::CloseDelim(delimited.delim), span.close);
+ let open_token = Token::new(delimited.delim.as_open_token_kind(), span.open);
+ let close_token = Token::new(delimited.delim.as_close_token_kind(), span.close);
locs.push(MatcherLoc::Delimited);
locs.push(MatcherLoc::Token { token: open_token });
@@ -648,7 +648,7 @@ pub(super) fn parse_tt<'matcher, T: Tracker<'matcher>>(
// There are no possible next positions AND we aren't waiting for the black-box
// parser: syntax error.
return Failure(T::build_failure(
- parser.token.clone(),
+ parser.token,
parser.approx_token_stream_pos(),
"no rules expected this token in macro call",
));
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 77ec598..93604a1 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -6,13 +6,13 @@
use ast::token::IdentIsRaw;
use rustc_ast::token::NtPatKind::*;
use rustc_ast::token::TokenKind::*;
-use rustc_ast::token::{self, Delimiter, NonterminalKind, Token, TokenKind};
+use rustc_ast::token::{self, NonterminalKind, Token, TokenKind};
use rustc_ast::tokenstream::{DelimSpan, TokenStream};
use rustc_ast::{self as ast, DUMMY_NODE_ID, NodeId};
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::{AttributeKind, find_attr};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
-use rustc_errors::{Applicability, ErrorGuaranteed};
+use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
use rustc_feature::Features;
use rustc_hir as hir;
use rustc_lint_defs::BuiltinLintDiag;
@@ -27,19 +27,18 @@
use rustc_span::{Ident, MacroRulesNormalizedIdent, Span, kw, sym};
use tracing::{debug, instrument, trace, trace_span};
-use super::diagnostics;
use super::macro_parser::{NamedMatches, NamedParseResult};
+use super::{SequenceRepetition, diagnostics};
use crate::base::{
DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult, SyntaxExtension,
SyntaxExtensionKind, TTMacroExpander,
};
use crate::expand::{AstFragment, AstFragmentKind, ensure_complete_parse, parse_ast_fragment};
-use crate::mbe;
use crate::mbe::diagnostics::{annotate_doc_comment, parse_failure_msg};
-use crate::mbe::macro_check;
use crate::mbe::macro_parser::NamedMatch::*;
use crate::mbe::macro_parser::{Error, ErrorReported, Failure, MatcherLoc, Success, TtParser};
use crate::mbe::transcribe::transcribe;
+use crate::mbe::{self, KleeneOp, macro_check};
pub(crate) struct ParserAnyMacro<'a> {
parser: Parser<'a>,
@@ -640,6 +639,37 @@ fn is_empty_token_tree(sess: &Session, seq: &mbe::SequenceRepetition) -> bool {
}
}
+/// Checks if a `vis` nonterminal fragment is unnecessarily wrapped in an optional repetition.
+///
+/// When a `vis` fragment (which can already be empty) is wrapped in `$(...)?`,
+/// this suggests removing the redundant repetition syntax since it provides no additional benefit.
+fn check_redundant_vis_repetition(
+ err: &mut Diag<'_>,
+ sess: &Session,
+ seq: &SequenceRepetition,
+ span: &DelimSpan,
+) {
+ let is_zero_or_one: bool = seq.kleene.op == KleeneOp::ZeroOrOne;
+ let is_vis = seq.tts.first().map_or(false, |tt| {
+ matches!(tt, mbe::TokenTree::MetaVarDecl(_, _, Some(NonterminalKind::Vis)))
+ });
+
+ if is_vis && is_zero_or_one {
+ err.note("a `vis` fragment can already be empty");
+ err.multipart_suggestion(
+ "remove the `$(` and `)?`",
+ vec![
+ (
+ sess.source_map().span_extend_to_prev_char_before(span.open, '$', true),
+ "".to_string(),
+ ),
+ (span.close.with_hi(seq.kleene.span.hi()), "".to_string()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+}
+
/// Checks that the lhs contains no repetition which could match an empty token
/// tree, because then the matcher would hang indefinitely.
fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(), ErrorGuaranteed> {
@@ -654,8 +684,10 @@ fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(),
TokenTree::Sequence(span, seq) => {
if is_empty_token_tree(sess, seq) {
let sp = span.entire();
- let guar = sess.dcx().span_err(sp, "repetition matches empty token tree");
- return Err(guar);
+ let mut err =
+ sess.dcx().struct_span_err(sp, "repetition matches empty token tree");
+ check_redundant_vis_repetition(&mut err, sess, seq, span);
+ return Err(err.emit());
}
check_lhs_no_empty_seq(sess, &seq.tts)?
}
@@ -752,7 +784,7 @@ fn build_recur<'tt>(sets: &mut FirstSets<'tt>, tts: &'tt [TokenTree]) -> TokenSe
TokenTree::Delimited(span, _, delimited) => {
build_recur(sets, &delimited.tts);
first.replace_with(TtHandle::from_token_kind(
- token::OpenDelim(delimited.delim),
+ delimited.delim.as_open_token_kind(),
span.open,
));
}
@@ -778,7 +810,7 @@ fn build_recur<'tt>(sets: &mut FirstSets<'tt>, tts: &'tt [TokenTree]) -> TokenSe
// token could be the separator token itself.
if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) {
- first.add_one_maybe(TtHandle::from_token(sep.clone()));
+ first.add_one_maybe(TtHandle::from_token(*sep));
}
// Reverse scan: Sequence comes before `first`.
@@ -820,7 +852,7 @@ fn first(&self, tts: &'tt [mbe::TokenTree]) -> TokenSet<'tt> {
}
TokenTree::Delimited(span, _, delimited) => {
first.add_one(TtHandle::from_token_kind(
- token::OpenDelim(delimited.delim),
+ delimited.delim.as_open_token_kind(),
span.open,
));
return first;
@@ -841,7 +873,7 @@ fn first(&self, tts: &'tt [mbe::TokenTree]) -> TokenSet<'tt> {
// If the sequence contents can be empty, then the first
// token could be the separator token itself.
if let (Some(sep), true) = (&seq_rep.separator, subfirst.maybe_empty) {
- first.add_one_maybe(TtHandle::from_token(sep.clone()));
+ first.add_one_maybe(TtHandle::from_token(*sep));
}
assert!(first.maybe_empty);
@@ -917,7 +949,7 @@ fn clone(&self) -> Self {
// This variant *must* contain a `mbe::TokenTree::Token`, and not
// any other variant of `mbe::TokenTree`.
TtHandle::Token(mbe::TokenTree::Token(tok)) => {
- TtHandle::Token(mbe::TokenTree::Token(tok.clone()))
+ TtHandle::Token(mbe::TokenTree::Token(*tok))
}
_ => unreachable!(),
@@ -1067,7 +1099,7 @@ fn check_matcher_core<'tt>(
}
TokenTree::Delimited(span, _, d) => {
let my_suffix = TokenSet::singleton(TtHandle::from_token_kind(
- token::CloseDelim(d.delim),
+ d.delim.as_close_token_kind(),
span.close,
));
check_matcher_core(sess, node_id, first_sets, &d.tts, &my_suffix)?;
@@ -1093,7 +1125,7 @@ fn check_matcher_core<'tt>(
let mut new;
let my_suffix = if let Some(sep) = &seq_rep.separator {
new = suffix_first.clone();
- new.add_one_maybe(TtHandle::from_token(sep.clone()));
+ new.add_one_maybe(TtHandle::from_token(*sep));
&new
} else {
&suffix_first
@@ -1267,7 +1299,9 @@ enum IsInFollow {
fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
use mbe::TokenTree;
- if let TokenTree::Token(Token { kind: token::CloseDelim(_), .. }) = *tok {
+ if let TokenTree::Token(Token { kind, .. }) = tok
+ && kind.close_delim().is_some()
+ {
// closing a token tree can never be matched by any fragment;
// iow, we always require that `(` and `)` match, etc.
IsInFollow::Yes
@@ -1326,16 +1360,8 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow {
];
match tok {
TokenTree::Token(token) => match token.kind {
- OpenDelim(Delimiter::Brace)
- | OpenDelim(Delimiter::Bracket)
- | Comma
- | FatArrow
- | Colon
- | Eq
- | Gt
- | Shr
- | Semi
- | Or => IsInFollow::Yes,
+ OpenBrace | OpenBracket | Comma | FatArrow | Colon | Eq | Gt | Shr
+ | Semi | Or => IsInFollow::Yes,
Ident(name, IdentIsRaw::No) if name == kw::As || name == kw::Where => {
IsInFollow::Yes
}
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 0ea5362..0c2362f 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -181,7 +181,10 @@ fn parse_tree<'a>(
if delim != Delimiter::Parenthesis {
span_dollar_dollar_or_metavar_in_the_lhs_err(
sess,
- &Token { kind: token::OpenDelim(delim), span: delim_span.entire() },
+ &Token {
+ kind: delim.as_open_token_kind(),
+ span: delim_span.entire(),
+ },
);
}
} else {
@@ -217,7 +220,8 @@ fn parse_tree<'a>(
}
Delimiter::Parenthesis => {}
_ => {
- let token = pprust::token_kind_to_string(&token::OpenDelim(delim));
+ let token =
+ pprust::token_kind_to_string(&delim.as_open_token_kind());
sess.dcx().emit_err(errors::ExpectedParenOrBrace {
span: delim_span.entire(),
token,
@@ -283,7 +287,7 @@ fn parse_tree<'a>(
}
// `tree` is an arbitrary token. Keep it.
- tokenstream::TokenTree::Token(token, _) => TokenTree::Token(token.clone()),
+ tokenstream::TokenTree::Token(token, _) => TokenTree::Token(*token),
// `tree` is the beginning of a delimited set of tokens (e.g., `(` or `{`). We need to
// descend into the delimited set and further parse it.
@@ -321,7 +325,7 @@ fn parse_kleene_op(
match iter.next() {
Some(tokenstream::TokenTree::Token(token, _)) => match kleene_op(token) {
Some(op) => Ok(Ok((op, token.span))),
- None => Ok(Err(token.clone())),
+ None => Ok(Err(*token)),
},
tree => Err(tree.map_or(span, tokenstream::TokenTree::span)),
}
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 6e47ed6..3918631 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -1,5 +1,4 @@
use std::mem;
-use std::sync::Arc;
use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_ast::token::{
@@ -165,7 +164,7 @@ pub(super) fn transcribe<'a>(
if repeat_idx < repeat_len {
frame.idx = 0;
if let Some(sep) = sep {
- result.push(TokenTree::Token(sep.clone(), Spacing::Alone));
+ result.push(TokenTree::Token(*sep, Spacing::Alone));
}
continue;
}
@@ -307,7 +306,9 @@ pub(super) fn transcribe<'a>(
let tt = match cur_matched {
MatchedSingle(ParseNtResult::Tt(tt)) => {
// `tt`s are emitted into the output stream directly as "raw tokens",
- // without wrapping them into groups.
+ // without wrapping them into groups. Other variables are emitted into
+ // the output stream as groups with `Delimiter::Invisible` to maintain
+ // parsing priorities.
maybe_use_metavar_location(psess, &stack, sp, tt, &mut marker)
}
MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => {
@@ -325,6 +326,11 @@ pub(super) fn transcribe<'a>(
MatchedSingle(ParseNtResult::Item(item)) => {
mk_delimited(item.span, MetaVarKind::Item, TokenStream::from_ast(item))
}
+ MatchedSingle(ParseNtResult::Block(block)) => mk_delimited(
+ block.span,
+ MetaVarKind::Block,
+ TokenStream::from_ast(block),
+ ),
MatchedSingle(ParseNtResult::Stmt(stmt)) => {
let stream = if let StmtKind::Empty = stmt.kind {
// FIXME: Properly collect tokens for empty statements.
@@ -385,15 +391,6 @@ pub(super) fn transcribe<'a>(
MatchedSingle(ParseNtResult::Vis(vis)) => {
mk_delimited(vis.span, MetaVarKind::Vis, TokenStream::from_ast(vis))
}
- MatchedSingle(ParseNtResult::Nt(nt)) => {
- // Other variables are emitted into the output stream as groups with
- // `Delimiter::Invisible` to maintain parsing priorities.
- // `Interpolated` is currently used for such groups in rustc parser.
- marker.visit_span(&mut sp);
- let use_span = nt.use_span();
- with_metavar_spans(|mspans| mspans.insert(use_span, sp));
- TokenTree::token_alone(token::Interpolated(Arc::clone(nt)), sp)
- }
MatchedSeq(..) => {
// We were unable to descend far enough. This is an error.
return Err(dcx.create_err(VarStillRepeating { span: sp, ident }));
@@ -441,7 +438,7 @@ pub(super) fn transcribe<'a>(
// Nothing much to do here. Just push the token to the result, being careful to
// preserve syntax context.
mbe::TokenTree::Token(token) => {
- let mut token = token.clone();
+ let mut token = *token;
mut_visit::visit_token(&mut marker, &mut token);
let tt = TokenTree::Token(token, Spacing::Alone);
result.push(tt);
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index ee6306e..f00201a 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -1,5 +1,4 @@
use std::ops::{Bound, Range};
-use std::sync::Arc;
use ast::token::IdentIsRaw;
use pm::bridge::{
@@ -18,7 +17,7 @@
use rustc_parse::{exp, new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal};
use rustc_session::parse::ParseSess;
use rustc_span::def_id::CrateNum;
-use rustc_span::{BytePos, FileName, Pos, SourceFile, Span, Symbol, sym};
+use rustc_span::{BytePos, FileName, Pos, Span, Symbol, sym};
use smallvec::{SmallVec, smallvec};
use crate::base::ExtCtxt;
@@ -309,17 +308,8 @@ fn from_internal((stream, rustc): (TokenStream, &mut Rustc<'_, '_>)) -> Self {
}));
}
- Interpolated(nt) => {
- let stream = TokenStream::from_nonterminal_ast(&nt);
- trees.push(TokenTree::Group(Group {
- delimiter: pm::Delimiter::None,
- stream: Some(stream),
- span: DelimSpan::from_single(span),
- }))
- }
-
- OpenDelim(..) | CloseDelim(..) => unreachable!(),
- Eof => unreachable!(),
+ OpenParen | CloseParen | OpenBrace | CloseBrace | OpenBracket | CloseBracket
+ | OpenInvisible(_) | CloseInvisible(_) | Eof => unreachable!(),
}
}
trees
@@ -467,7 +457,6 @@ fn psess(&self) -> &ParseSess {
impl server::Types for Rustc<'_, '_> {
type FreeFunctions = FreeFunctions;
type TokenStream = TokenStream;
- type SourceFile = Arc<SourceFile>;
type Span = Span;
type Symbol = Symbol;
}
@@ -673,28 +662,6 @@ fn into_trees(
}
}
-impl server::SourceFile for Rustc<'_, '_> {
- fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
- Arc::ptr_eq(file1, file2)
- }
-
- fn path(&mut self, file: &Self::SourceFile) -> String {
- match &file.name {
- FileName::Real(name) => name
- .local_path()
- .expect("attempting to get a file path in an imported file in `proc_macro::SourceFile::path`")
- .to_str()
- .expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
- .to_string(),
- _ => file.name.prefer_local().to_string(),
- }
- }
-
- fn is_real(&mut self, file: &Self::SourceFile) -> bool {
- file.is_real_file()
- }
-}
-
impl server::Span for Rustc<'_, '_> {
fn debug(&mut self, span: Self::Span) -> String {
if self.ecx.ecfg.span_debug {
@@ -704,8 +671,29 @@ fn debug(&mut self, span: Self::Span) -> String {
}
}
- fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
- self.psess().source_map().lookup_char_pos(span.lo()).file
+ fn file(&mut self, span: Self::Span) -> String {
+ self.psess()
+ .source_map()
+ .lookup_char_pos(span.lo())
+ .file
+ .name
+ .prefer_remapped_unconditionaly()
+ .to_string()
+ }
+
+ fn local_file(&mut self, span: Self::Span) -> Option<String> {
+ self.psess()
+ .source_map()
+ .lookup_char_pos(span.lo())
+ .file
+ .name
+ .clone()
+ .into_local_path()
+ .map(|p| {
+ p.to_str()
+ .expect("non-UTF8 file path in `proc_macro::SourceFile::path`")
+ .to_string()
+ })
}
fn parent(&mut self, span: Self::Span) -> Option<Self::Span> {
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 8968c17..e3e4eef 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -95,6 +95,8 @@ macro_rules! declare_features {
(accepted, c_unwind, "1.81.0", Some(74990)),
/// Allows `#[cfg_attr(predicate, multiple, attributes, here)]`.
(accepted, cfg_attr_multi, "1.33.0", Some(54881)),
+ /// Allows the use of `#[cfg(<true/false>)]`.
+ (accepted, cfg_boolean_literals, "CURRENT_RUSTC_VERSION", Some(131204)),
/// Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests.
(accepted, cfg_doctest, "1.40.0", Some(62210)),
/// Enables `#[cfg(panic = "...")]` config key.
@@ -298,6 +300,8 @@ macro_rules! declare_features {
/// Allows patterns with concurrent by-move and by-ref bindings.
/// For example, you can write `Foo(a, ref b)` where `a` is by-move and `b` is by-ref.
(accepted, move_ref_pattern, "1.49.0", Some(68354)),
+ /// Allows using `#[naked]` on functions.
+ (accepted, naked_functions, "CURRENT_RUSTC_VERSION", Some(90957)),
/// Allows specifying modifiers in the link attribute: `#[link(modifiers = "...")]`
(accepted, native_link_modifiers, "1.61.0", Some(81490)),
/// Allows specifying the bundle link modifier
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 1e33e2e..76270ca 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -6,6 +6,7 @@
use AttributeGate::*;
use AttributeType::*;
use rustc_data_structures::fx::FxHashMap;
+use rustc_span::edition::Edition;
use rustc_span::{Symbol, sym};
use crate::{Features, Stability};
@@ -65,9 +66,12 @@ pub enum AttributeSafety {
/// Normal attribute that does not need `#[unsafe(...)]`
Normal,
- /// Unsafe attribute that requires safety obligations
- /// to be discharged
- Unsafe,
+ /// Unsafe attribute that requires safety obligations to be discharged.
+ ///
+ /// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition
+ /// is less than the one stored in `unsafe_since`. This handles attributes that were safe in
+ /// earlier editions, but become unsafe in later ones.
+ Unsafe { unsafe_since: Option<Edition> },
}
#[derive(Clone, Copy)]
@@ -187,12 +191,23 @@ macro_rules! template {
}
macro_rules! ungated {
+ (unsafe($edition:ident) $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
+ BuiltinAttribute {
+ name: sym::$attr,
+ encode_cross_crate: $encode_cross_crate,
+ type_: $typ,
+ safety: AttributeSafety::Unsafe { unsafe_since: Some(Edition::$edition) },
+ template: $tpl,
+ gate: Ungated,
+ duplicates: $duplicates,
+ }
+ };
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
- safety: AttributeSafety::Unsafe,
+ safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl,
gate: Ungated,
duplicates: $duplicates,
@@ -217,7 +232,7 @@ macro_rules! gated {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
- safety: AttributeSafety::Unsafe,
+ safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl,
duplicates: $duplicates,
gate: Gated(Stability::Unstable, sym::$gate, $msg, Features::$gate),
@@ -228,7 +243,7 @@ macro_rules! gated {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
- safety: AttributeSafety::Unsafe,
+ safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl,
duplicates: $duplicates,
gate: Gated(Stability::Unstable, sym::$attr, $msg, Features::$attr),
@@ -423,11 +438,12 @@ pub struct BuiltinAttribute {
),
ungated!(no_link, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
ungated!(repr, Normal, template!(List: "C"), DuplicatesOk, EncodeCrossCrate::No),
- ungated!(unsafe export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
- ungated!(unsafe link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
- ungated!(unsafe no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
+ ungated!(unsafe(Edition2024) export_name, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
+ ungated!(unsafe(Edition2024) link_section, Normal, template!(NameValueStr: "name"), FutureWarnPreceding, EncodeCrossCrate::No),
+ ungated!(unsafe(Edition2024) no_mangle, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
ungated!(used, Normal, template!(Word, List: "compiler|linker"), WarnFollowing, EncodeCrossCrate::No),
ungated!(link_ordinal, Normal, template!(List: "ordinal"), ErrorPreceding, EncodeCrossCrate::Yes),
+ ungated!(unsafe naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No),
// Limits:
ungated!(
@@ -500,12 +516,6 @@ pub struct BuiltinAttribute {
// Unstable attributes:
// ==========================================================================
- // Linking:
- gated!(
- naked, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
- naked_functions, experimental!(naked)
- ),
-
// Testing:
gated!(
test_runner, CrateLevel, template!(List: "path"), ErrorFollowing,
@@ -661,14 +671,6 @@ pub struct BuiltinAttribute {
"`rustc_never_type_options` is used to experiment with never type fallback and work on \
never type stabilization, and will never be stable"
),
- rustc_attr!(
- rustc_macro_edition_2021,
- Normal,
- template!(Word),
- ErrorFollowing,
- EncodeCrossCrate::No,
- "makes spans in this macro edition 2021"
- ),
// ==========================================================================
// Internal attributes: Runtime related:
@@ -752,7 +754,7 @@ pub struct BuiltinAttribute {
),
rustc_attr!(
rustc_macro_transparency, Normal,
- template!(NameValueStr: "transparent|semitransparent|opaque"), ErrorFollowing,
+ template!(NameValueStr: "transparent|semiopaque|opaque"), ErrorFollowing,
EncodeCrossCrate::Yes, "used internally for testing macro hygiene",
),
rustc_attr!(
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 98213af..cbc121e 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -391,8 +391,6 @@ pub fn internal(&self, feature: Symbol) -> bool {
(unstable, async_trait_bounds, "1.85.0", Some(62290)),
/// Allows using C-variadics.
(unstable, c_variadic, "1.34.0", Some(44930)),
- /// Allows the use of `#[cfg(<true/false>)]`.
- (unstable, cfg_boolean_literals, "1.83.0", Some(131204)),
/// Allows the use of `#[cfg(contract_checks)` to check if contract checks are enabled.
(unstable, cfg_contract_checks, "1.86.0", Some(128044)),
/// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
@@ -477,6 +475,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
(incomplete, ergonomic_clones, "1.87.0", Some(132290)),
/// Allows exhaustive pattern matching on types that contain uninhabited types.
(unstable, exhaustive_patterns, "1.13.0", Some(51085)),
+ /// Disallows `extern` without an explicit ABI.
+ (unstable, explicit_extern_abis, "CURRENT_RUSTC_VERSION", Some(134986)),
/// Allows explicit tail calls via `become` expression.
(incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
/// Allows using `aapcs`, `efiapi`, `sysv64` and `win64` as calling conventions
@@ -563,8 +563,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
(unstable, must_not_suspend, "1.57.0", Some(83310)),
/// Allows `mut ref` and `mut ref mut` identifier patterns.
(incomplete, mut_ref, "1.79.0", Some(123076)),
- /// Allows using `#[naked]` on functions.
- (unstable, naked_functions, "1.9.0", Some(90957)),
+ /// Allows using `#[naked]` on `extern "Rust"` functions.
+ (unstable, naked_functions_rustic_abi, "CURRENT_RUSTC_VERSION", Some(138997)),
/// Allows using `#[target_feature(enable = "...")]` on `#[naked]` on functions.
(unstable, naked_functions_target_feature, "1.86.0", Some(138568)),
/// Allows specifying the as-needed link modifier
diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs
index b04fd1b..c96bb48 100644
--- a/compiler/rustc_fluent_macro/src/fluent.rs
+++ b/compiler/rustc_fluent_macro/src/fluent.rs
@@ -25,7 +25,10 @@ fn invocation_relative_path_to_absolute(span: Span, path: &str) -> PathBuf {
path.to_path_buf()
} else {
// `/a/b/c/foo/bar.rs` contains the current macro invocation
+ #[cfg(bootstrap)]
let mut source_file_path = span.source_file().path();
+ #[cfg(not(bootstrap))]
+ let mut source_file_path = span.local_file().unwrap();
// `/a/b/c/foo/`
source_file_path.pop();
// `/a/b/c/foo/../locales/en-US/example.ftl`
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 34f3c16..bf7b1ee 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -47,12 +47,9 @@ fn allocate(&mut self, key: DefKey, def_path_hash: DefPathHash) -> DefIndex {
debug_assert_eq!(self.stable_crate_id, def_path_hash.stable_crate_id());
let local_hash = def_path_hash.local_hash();
- let index = {
- let index = DefIndex::from(self.index_to_key.len());
- debug!("DefPathTable::insert() - {:?} <-> {:?}", key, index);
- self.index_to_key.push(key);
- index
- };
+ let index = self.index_to_key.push(key);
+ debug!("DefPathTable::insert() - {key:?} <-> {index:?}");
+
self.def_path_hashes.push(local_hash);
debug_assert!(self.def_path_hashes.len() == self.index_to_key.len());
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index c9c4936..d02c767 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -42,7 +42,7 @@ pub enum IsAnonInPath {
}
/// A lifetime. The valid field combinations are non-obvious. The following
-/// example shows some of them. See also the comments on `LifetimeName`.
+/// example shows some of them. See also the comments on `LifetimeKind`.
/// ```
/// #[repr(C)]
/// struct S<'a>(&'a u32); // res=Param, name='a, IsAnonInPath::No
@@ -84,7 +84,7 @@ pub struct Lifetime {
pub ident: Ident,
/// Semantics of this lifetime.
- pub res: LifetimeName,
+ pub kind: LifetimeKind,
/// Is the lifetime anonymous and in a path? Used only for error
/// suggestions. See `Lifetime::suggestion` for example use.
@@ -130,7 +130,7 @@ pub fn ident(&self) -> Ident {
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
-pub enum LifetimeName {
+pub enum LifetimeKind {
/// User-given names or fresh (synthetic) names.
Param(LocalDefId),
@@ -160,16 +160,16 @@ pub enum LifetimeName {
Static,
}
-impl LifetimeName {
+impl LifetimeKind {
fn is_elided(&self) -> bool {
match self {
- LifetimeName::ImplicitObjectLifetimeDefault | LifetimeName::Infer => true,
+ LifetimeKind::ImplicitObjectLifetimeDefault | LifetimeKind::Infer => true,
// It might seem surprising that `Fresh` counts as not *elided*
// -- but this is because, as far as the code in the compiler is
// concerned -- `Fresh` variants act equivalently to "some fresh name".
// They correspond to early-bound regions on an impl, in other words.
- LifetimeName::Error | LifetimeName::Param(..) | LifetimeName::Static => false,
+ LifetimeKind::Error | LifetimeKind::Param(..) | LifetimeKind::Static => false,
}
}
}
@@ -184,10 +184,10 @@ impl Lifetime {
pub fn new(
hir_id: HirId,
ident: Ident,
- res: LifetimeName,
+ kind: LifetimeKind,
is_anon_in_path: IsAnonInPath,
) -> Lifetime {
- let lifetime = Lifetime { hir_id, ident, res, is_anon_in_path };
+ let lifetime = Lifetime { hir_id, ident, kind, is_anon_in_path };
// Sanity check: elided lifetimes form a strict subset of anonymous lifetimes.
#[cfg(debug_assertions)]
@@ -202,7 +202,7 @@ pub fn new(
}
pub fn is_elided(&self) -> bool {
- self.res.is_elided()
+ self.kind.is_elided()
}
pub fn is_anonymous(&self) -> bool {
@@ -1014,7 +1014,7 @@ pub struct WhereRegionPredicate<'hir> {
impl<'hir> WhereRegionPredicate<'hir> {
/// Returns `true` if `param_def_id` matches the `lifetime` of this predicate.
fn is_param_bound(&self, param_def_id: LocalDefId) -> bool {
- self.lifetime.res == LifetimeName::Param(param_def_id)
+ self.lifetime.kind == LifetimeKind::Param(param_def_id)
}
}
@@ -1237,7 +1237,7 @@ fn doc_str_and_comment_kind(&self) -> Option<(Symbol, CommentKind)> {
Attribute::Parsed(AttributeKind::DocComment { kind, comment, .. }) => {
Some((*comment, *kind))
}
- Attribute::Unparsed(_) if self.name_or_empty() == sym::doc => {
+ Attribute::Unparsed(_) if self.has_name(sym::doc) => {
self.value_str().map(|s| (s, CommentKind::Line))
}
_ => None,
@@ -1262,8 +1262,8 @@ pub fn id(&self) -> AttrId {
}
#[inline]
- pub fn name_or_empty(&self) -> Symbol {
- AttributeExt::name_or_empty(self)
+ pub fn name(&self) -> Option<Symbol> {
+ AttributeExt::name(self)
}
#[inline]
@@ -1302,6 +1302,11 @@ pub fn has_name(&self, name: Symbol) -> bool {
}
#[inline]
+ pub fn has_any_name(&self, names: &[Symbol]) -> bool {
+ AttributeExt::has_any_name(self, names)
+ }
+
+ #[inline]
pub fn span(&self) -> Span {
AttributeExt::span(self)
}
@@ -1756,7 +1761,7 @@ pub enum PatKind<'hir> {
Never,
/// A tuple pattern (e.g., `(a, b)`).
- /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
+ /// If the `..` pattern fragment is present, then `DotDotPos` denotes its position.
/// `0 <= position <= subpats.len()`
Tuple(&'hir [Pat<'hir>], DotDotPos),
diff --git a/compiler/rustc_hir/src/hir/tests.rs b/compiler/rustc_hir/src/hir/tests.rs
index 62ef02d..fcd0eaf 100644
--- a/compiler/rustc_hir/src/hir/tests.rs
+++ b/compiler/rustc_hir/src/hir/tests.rs
@@ -57,7 +57,7 @@ fn trait_object_roundtrips_impl(syntax: TraitObjectSyntax) {
Lifetime {
hir_id: HirId::INVALID,
ident: Ident::new(sym::name, DUMMY_SP),
- res: LifetimeName::Static,
+ kind: LifetimeKind::Static,
is_anon_in_path: IsAnonInPath::No,
}
},
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 93d20df..3c2897e 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -6,7 +6,7 @@
//! 1. **Shallow visit**: Get a simple callback for every item (or item-like thing) in the HIR.
//! - Example: find all items with a `#[foo]` attribute on them.
//! - How: Use the `hir_crate_items` or `hir_module_items` query to traverse over item-like ids
-//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir().item*(id)` to filter and
+//! (ItemId, TraitItemId, etc.) and use tcx.def_kind and `tcx.hir_item*(id)` to filter and
//! access actual item-like thing, respectively.
//! - Pro: Efficient; just walks the lists of item ids and gives users control whether to access
//! the hir_owners themselves or not.
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 90fab01..b9f4a8c 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -182,6 +182,7 @@ pub fn extract(attrs: &[impl AttributeExt]) -> Option<(Symbol, Span)> {
DynMetadata, sym::dyn_metadata, dyn_metadata, Target::Struct, GenericRequirement::None;
Freeze, sym::freeze, freeze_trait, Target::Trait, GenericRequirement::Exact(0);
+ UnsafeUnpin, sym::unsafe_unpin, unsafe_unpin_trait, Target::Trait, GenericRequirement::Exact(0);
FnPtrTrait, sym::fn_ptr_trait, fn_ptr_trait, Target::Trait, GenericRequirement::Exact(0);
FnPtrAddr, sym::fn_ptr_addr, fn_ptr_addr, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
@@ -235,6 +236,8 @@ pub fn extract(attrs: &[impl AttributeExt]) -> Option<(Symbol, Span)> {
IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);
UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
+ UnsafePinned, sym::unsafe_pinned, unsafe_pinned_type, Target::Struct, GenericRequirement::None;
+
VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;
Deref, sym::deref, deref_trait, Target::Trait, GenericRequirement::Exact(0);
@@ -439,6 +442,8 @@ pub fn extract(attrs: &[impl AttributeExt]) -> Option<(Symbol, Span)> {
DefaultTrait3, sym::default_trait3, default_trait3_trait, Target::Trait, GenericRequirement::None;
DefaultTrait2, sym::default_trait2, default_trait2_trait, Target::Trait, GenericRequirement::None;
DefaultTrait1, sym::default_trait1, default_trait1_trait, Target::Trait, GenericRequirement::None;
+
+ ContractCheckEnsures, sym::contract_check_ensures, contract_check_ensures_fn, Target::Fn, GenericRequirement::None;
}
/// The requirement imposed on the generics of a lang item
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 6bc0f79..a84857e 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -4,7 +4,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(associated_type_defaults)]
#![feature(box_patterns)]
#![feature(closure_track_caller)]
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index b3eade8..99e495d 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -2,8 +2,8 @@
use rustc_infer::traits::PredicateObligations;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
use rustc_session::Limit;
-use rustc_span::Span;
use rustc_span::def_id::{LOCAL_CRATE, LocalDefId};
+use rustc_span::{ErrorGuaranteed, Span};
use rustc_trait_selection::traits::ObligationCtxt;
use tracing::{debug, instrument};
@@ -259,7 +259,11 @@ pub fn silence_errors(mut self) -> Self {
}
}
-pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
+pub fn report_autoderef_recursion_limit_error<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ span: Span,
+ ty: Ty<'tcx>,
+) -> ErrorGuaranteed {
// We've reached the recursion limit, error gracefully.
let suggested_limit = match tcx.recursion_limit() {
Limit(0) => Limit(2),
@@ -270,5 +274,5 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa
ty,
suggested_limit,
crate_name: tcx.crate_name(LOCAL_CRATE),
- });
+ })
}
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index f50746d..4f338c6 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -443,13 +443,13 @@ fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) -> Self::Resu
let impl_def_id = tcx.local_parent(parent);
for assoc in tcx.associated_items(impl_def_id).in_definition_order() {
match assoc.kind {
- ty::AssocKind::Const | ty::AssocKind::Fn => {
+ ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => {
if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local())
{
return Some(span);
}
}
- ty::AssocKind::Type => {}
+ ty::AssocKind::Type { .. } => {}
}
}
@@ -740,7 +740,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
for &assoc_item in assoc_items.in_definition_order() {
match assoc_item.kind {
- ty::AssocKind::Type if assoc_item.defaultness(tcx).has_value() => {
+ ty::AssocKind::Type { .. } if assoc_item.defaultness(tcx).has_value() => {
let trait_args = GenericArgs::identity_for_item(tcx, def_id);
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
tcx,
@@ -942,7 +942,7 @@ fn check_impl_items_against_trait<'tcx>(
if res.is_ok() {
match ty_impl_item.kind {
- ty::AssocKind::Fn => {
+ ty::AssocKind::Fn { .. } => {
compare_impl_item::refine::check_refining_return_position_impl_trait_in_trait(
tcx,
ty_impl_item,
@@ -952,8 +952,8 @@ fn check_impl_items_against_trait<'tcx>(
.instantiate_identity(),
);
}
- ty::AssocKind::Const => {}
- ty::AssocKind::Type => {}
+ ty::AssocKind::Const { .. } => {}
+ ty::AssocKind::Type { .. } => {}
}
}
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 29a9931..06a7b1f 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -43,9 +43,11 @@ pub(super) fn compare_impl_item(
debug!(?impl_trait_ref);
match impl_item.kind {
- ty::AssocKind::Fn => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref),
- ty::AssocKind::Type => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref),
- ty::AssocKind::Const => compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref),
+ ty::AssocKind::Fn { .. } => compare_impl_method(tcx, impl_item, trait_item, impl_trait_ref),
+ ty::AssocKind::Type { .. } => compare_impl_ty(tcx, impl_item, trait_item, impl_trait_ref),
+ ty::AssocKind::Const { .. } => {
+ compare_impl_const(tcx, impl_item, trait_item, impl_trait_ref)
+ }
}
}
@@ -606,7 +608,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
// with placeholders, which imply nothing about outlives bounds, and then
// prove below that the hidden types are well formed.
let universe = infcx.create_next_universe();
- let mut idx = 0;
+ let mut idx = ty::BoundVar::ZERO;
let mapping: FxIndexMap<_, _> = collector
.types
.iter()
@@ -623,10 +625,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
tcx,
ty::Placeholder {
universe,
- bound: ty::BoundTy {
- var: ty::BoundVar::from_usize(idx),
- kind: ty::BoundTyKind::Anon,
- },
+ bound: ty::BoundTy { var: idx, kind: ty::BoundTyKind::Anon },
},
),
)
@@ -654,7 +653,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
cause.span,
E0053,
"method `{}` has an incompatible return type for trait",
- trait_m.name
+ trait_m.name()
);
infcx.err_ctxt().note_type_err(
&mut diag,
@@ -1032,11 +1031,11 @@ fn report_trait_method_mismatch<'tcx>(
impl_err_span,
E0053,
"method `{}` has an incompatible type for trait",
- trait_m.name
+ trait_m.name()
);
match &terr {
TypeError::ArgumentMutability(0) | TypeError::ArgumentSorts(_, 0)
- if trait_m.fn_has_self_parameter =>
+ if trait_m.is_method() =>
{
let ty = trait_sig.inputs()[0];
let sugg = get_self_string(ty, |ty| ty == impl_trait_ref.self_ty());
@@ -1255,7 +1254,7 @@ fn compare_self_type<'tcx>(
get_self_string(self_arg_ty, can_eq_self)
};
- match (trait_m.fn_has_self_parameter, impl_m.fn_has_self_parameter) {
+ match (trait_m.is_method(), impl_m.is_method()) {
(false, false) | (true, true) => {}
(false, true) => {
@@ -1266,14 +1265,14 @@ fn compare_self_type<'tcx>(
impl_m_span,
E0185,
"method `{}` has a `{}` declaration in the impl, but not in the trait",
- trait_m.name,
+ trait_m.name(),
self_descr
);
err.span_label(impl_m_span, format!("`{self_descr}` used in impl"));
if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {
err.span_label(span, format!("trait method declared without `{self_descr}`"));
} else {
- err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
+ err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
}
return Err(err.emit_unless(delay));
}
@@ -1286,14 +1285,14 @@ fn compare_self_type<'tcx>(
impl_m_span,
E0186,
"method `{}` has a `{}` declaration in the trait, but not in the impl",
- trait_m.name,
+ trait_m.name(),
self_descr
);
err.span_label(impl_m_span, format!("expected `{self_descr}` in impl"));
if let Some(span) = tcx.hir_span_if_local(trait_m.def_id) {
err.span_label(span, format!("`{self_descr}` used in trait"));
} else {
- err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
+ err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
}
return Err(err.emit_unless(delay));
@@ -1363,7 +1362,7 @@ fn compare_number_of_generics<'tcx>(
let mut err_occurred = None;
for (kind, trait_count, impl_count) in matchings {
if impl_count != trait_count {
- let arg_spans = |kind: ty::AssocKind, generics: &hir::Generics<'_>| {
+ let arg_spans = |item: &ty::AssocItem, generics: &hir::Generics<'_>| {
let mut spans = generics
.params
.iter()
@@ -1373,7 +1372,7 @@ fn compare_number_of_generics<'tcx>(
} => {
// A fn can have an arbitrary number of extra elided lifetimes for the
// same signature.
- !matches!(kind, ty::AssocKind::Fn)
+ !item.is_fn()
}
_ => true,
})
@@ -1386,7 +1385,7 @@ fn compare_number_of_generics<'tcx>(
};
let (trait_spans, impl_trait_spans) = if let Some(def_id) = trait_.def_id.as_local() {
let trait_item = tcx.hir_expect_trait_item(def_id);
- let arg_spans: Vec<Span> = arg_spans(trait_.kind, trait_item.generics);
+ let arg_spans: Vec<Span> = arg_spans(&trait_, trait_item.generics);
let impl_trait_spans: Vec<Span> = trait_item
.generics
.params
@@ -1412,7 +1411,7 @@ fn compare_number_of_generics<'tcx>(
_ => None,
})
.collect();
- let spans = arg_spans(impl_.kind, impl_item.generics);
+ let spans = arg_spans(&impl_, impl_item.generics);
let span = spans.first().copied();
let mut err = tcx.dcx().struct_span_err(
@@ -1421,7 +1420,7 @@ fn compare_number_of_generics<'tcx>(
"{} `{}` has {} {kind} parameter{} but its trait \
declaration has {} {kind} parameter{}",
item_kind,
- trait_.name,
+ trait_.name(),
impl_count,
pluralize!(impl_count),
trait_count,
@@ -1512,7 +1511,7 @@ fn compare_number_of_method_arguments<'tcx>(
impl_span,
E0050,
"method `{}` has {} but the declaration in trait `{}` has {}",
- trait_m.name,
+ trait_m.name(),
potentially_plural_count(impl_number_args, "parameter"),
tcx.def_path_str(trait_m.def_id),
trait_number_args
@@ -1527,7 +1526,7 @@ fn compare_number_of_method_arguments<'tcx>(
),
);
} else {
- err.note_trait_signature(trait_m.name, trait_m.signature(tcx));
+ err.note_trait_signature(trait_m.name(), trait_m.signature(tcx));
}
err.span_label(
@@ -1581,7 +1580,7 @@ fn compare_synthetic_generics<'tcx>(
impl_span,
E0643,
"method `{}` has incompatible signature for trait",
- trait_m.name
+ trait_m.name()
);
err.span_label(trait_span, "declaration in trait here");
if impl_synthetic {
@@ -1703,7 +1702,7 @@ fn compare_generic_param_kinds<'tcx>(
trait_item: ty::AssocItem,
delay: bool,
) -> Result<(), ErrorGuaranteed> {
- assert_eq!(impl_item.kind, trait_item.kind);
+ assert_eq!(impl_item.as_tag(), trait_item.as_tag());
let ty_const_params_of = |def_id| {
tcx.generics_of(def_id).own_params.iter().filter(|param| {
@@ -1741,7 +1740,7 @@ fn compare_generic_param_kinds<'tcx>(
E0053,
"{} `{}` has an incompatible generic parameter for trait `{}`",
impl_item.descr(),
- trait_item.name,
+ trait_item.name(),
&tcx.def_path_str(tcx.parent(trait_item.def_id))
);
@@ -1877,7 +1876,7 @@ fn compare_const_predicate_entailment<'tcx>(
cause.span,
E0326,
"implemented const `{}` has an incompatible type for trait",
- trait_ct.name
+ trait_ct.name()
);
let trait_c_span = trait_ct.def_id.as_local().map(|trait_ct_def_id| {
@@ -2235,16 +2234,19 @@ fn param_env_with_gat_bounds<'tcx>(
// of the RPITITs associated with the same body. This is because checking
// the item bounds of RPITITs often involves nested RPITITs having to prove
// bounds about themselves.
- let impl_tys_to_install = match impl_ty.opt_rpitit_info {
- None => vec![impl_ty],
- Some(
- ty::ImplTraitInTraitData::Impl { fn_def_id }
- | ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
- ) => tcx
+ let impl_tys_to_install = match impl_ty.kind {
+ ty::AssocKind::Type {
+ data:
+ ty::AssocTypeData::Rpitit(
+ ty::ImplTraitInTraitData::Impl { fn_def_id }
+ | ty::ImplTraitInTraitData::Trait { fn_def_id, .. },
+ ),
+ } => tcx
.associated_types_for_impl_traits_in_associated_fn(fn_def_id)
.iter()
.map(|def_id| tcx.associated_item(*def_id))
.collect(),
+ _ => vec![impl_ty],
};
for impl_ty in impl_tys_to_install {
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index ed8ca27..692784b 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -2,8 +2,7 @@
use rustc_abi::ExternAbi;
use rustc_errors::DiagMessage;
-use rustc_hir::{self as hir};
-use rustc_middle::bug;
+use rustc_hir::{self as hir, LangItem};
use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::LocalDefId;
@@ -173,23 +172,22 @@ pub(crate) fn check_intrinsic_type(
ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv),
]);
let mk_va_list_ty = |mutbl| {
- tcx.lang_items().va_list().map(|did| {
- let region = ty::Region::new_bound(
- tcx,
- ty::INNERMOST,
- ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon },
- );
- let env_region = ty::Region::new_bound(
- tcx,
- ty::INNERMOST,
- ty::BoundRegion {
- var: ty::BoundVar::from_u32(2),
- kind: ty::BoundRegionKind::ClosureEnv,
- },
- );
- let va_list_ty = tcx.type_of(did).instantiate(tcx, &[region.into()]);
- (Ty::new_ref(tcx, env_region, va_list_ty, mutbl), va_list_ty)
- })
+ let did = tcx.require_lang_item(LangItem::VaList, Some(span));
+ let region = ty::Region::new_bound(
+ tcx,
+ ty::INNERMOST,
+ ty::BoundRegion { var: ty::BoundVar::ZERO, kind: ty::BoundRegionKind::Anon },
+ );
+ let env_region = ty::Region::new_bound(
+ tcx,
+ ty::INNERMOST,
+ ty::BoundRegion {
+ var: ty::BoundVar::from_u32(2),
+ kind: ty::BoundRegionKind::ClosureEnv,
+ },
+ );
+ let va_list_ty = tcx.type_of(did).instantiate(tcx, &[region.into()]);
+ (Ty::new_ref(tcx, env_region, va_list_ty, mutbl), va_list_ty)
};
let (n_tps, n_lts, n_cts, inputs, output, safety) = if name_str.starts_with("atomic_") {
@@ -217,15 +215,11 @@ pub(crate) fn check_intrinsic_type(
};
(n_tps, 0, 0, inputs, output, hir::Safety::Unsafe)
} else if intrinsic_name == sym::contract_check_ensures {
- // contract_check_ensures::<'a, Ret, C>(&'a Ret, C)
- // where C: impl Fn(&'a Ret) -> bool,
+ // contract_check_ensures::<Ret, C>(Ret, C) -> Ret
+ // where C: for<'a> Fn(&'a Ret) -> bool,
//
- // so: two type params, one lifetime param, 0 const params, two inputs, no return
-
- let p = generics.param_at(0, tcx);
- let r = ty::Region::new_early_param(tcx, p.to_early_bound_region_data());
- let ref_ret = Ty::new_imm_ref(tcx, r, param(1));
- (2, 1, 0, vec![ref_ret, param(2)], tcx.types.unit, hir::Safety::Safe)
+ // so: two type params, 0 lifetime param, 0 const params, two inputs, no return
+ (2, 0, 0, vec![param(0), param(1)], param(1), hir::Safety::Safe)
} else {
let safety = intrinsic_operation_unsafety(tcx, intrinsic_id);
let (n_tps, n_cts, inputs, output) = match intrinsic_name {
@@ -552,23 +546,17 @@ pub(crate) fn check_intrinsic_type(
)
}
- sym::va_start | sym::va_end => match mk_va_list_ty(hir::Mutability::Mut) {
- Some((va_list_ref_ty, _)) => (0, 0, vec![va_list_ref_ty], tcx.types.unit),
- None => bug!("`va_list` lang item needed for C-variadic intrinsics"),
- },
+ sym::va_start | sym::va_end => {
+ (0, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], tcx.types.unit)
+ }
- sym::va_copy => match mk_va_list_ty(hir::Mutability::Not) {
- Some((va_list_ref_ty, va_list_ty)) => {
- let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty);
- (0, 0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.types.unit)
- }
- None => bug!("`va_list` lang item needed for C-variadic intrinsics"),
- },
+ sym::va_copy => {
+ let (va_list_ref_ty, va_list_ty) = mk_va_list_ty(hir::Mutability::Not);
+ let va_list_ptr_ty = Ty::new_mut_ptr(tcx, va_list_ty);
+ (0, 0, vec![va_list_ptr_ty, va_list_ref_ty], tcx.types.unit)
+ }
- sym::va_arg => match mk_va_list_ty(hir::Mutability::Mut) {
- Some((va_list_ref_ty, _)) => (1, 0, vec![va_list_ref_ty], param(0)),
- None => bug!("`va_list` lang item needed for C-variadic intrinsics"),
- },
+ sym::va_arg => (1, 0, vec![mk_va_list_ty(hir::Mutability::Mut).0], param(0)),
sym::nontemporal_store => {
(1, 0, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], tcx.types.unit)
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 30921b6..5fbd771 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -205,7 +205,7 @@ fn missing_items_err(
let missing_items_msg = missing_items
.clone()
- .map(|trait_item| trait_item.name.to_string())
+ .map(|trait_item| trait_item.name().to_string())
.collect::<Vec<_>>()
.join("`, `");
@@ -236,7 +236,7 @@ fn missing_items_err(
let code = format!("{padding}{snippet}\n{padding}");
if let Some(span) = tcx.hir_span_if_local(trait_item.def_id) {
missing_trait_item_label
- .push(errors::MissingTraitItemLabel { span, item: trait_item.name });
+ .push(errors::MissingTraitItemLabel { span, item: trait_item.name() });
missing_trait_item.push(errors::MissingTraitItemSuggestion {
span: sugg_sp,
code,
@@ -407,14 +407,14 @@ fn fn_sig_suggestion<'tcx>(
.enumerate()
.map(|(i, ty)| {
Some(match ty.kind() {
- ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(),
+ ty::Param(_) if assoc.is_method() && i == 0 => "self".to_string(),
ty::Ref(reg, ref_ty, mutability) if i == 0 => {
let reg = format!("{reg} ");
let reg = match ®[..] {
"'_ " | " " => "",
reg => reg,
};
- if assoc.fn_has_self_parameter {
+ if assoc.is_method() {
match ref_ty.kind() {
ty::Param(param) if param.name == kw::SelfUpper => {
format!("&{}{}self", reg, mutability.prefix_str())
@@ -427,7 +427,7 @@ fn fn_sig_suggestion<'tcx>(
}
}
_ => {
- if assoc.fn_has_self_parameter && i == 0 {
+ if assoc.is_method() && i == 0 {
format!("self: {ty}")
} else {
format!("_: {ty}")
@@ -489,7 +489,7 @@ fn suggestion_signature<'tcx>(
);
match assoc.kind {
- ty::AssocKind::Fn => fn_sig_suggestion(
+ ty::AssocKind::Fn { .. } => fn_sig_suggestion(
tcx,
tcx.liberate_late_bound_regions(
assoc.def_id,
@@ -499,14 +499,14 @@ fn suggestion_signature<'tcx>(
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
assoc,
),
- ty::AssocKind::Type => {
+ ty::AssocKind::Type { .. } => {
let (generics, where_clauses) = bounds_from_generic_predicates(
tcx,
tcx.predicates_of(assoc.def_id).instantiate_own(tcx, args),
);
- format!("type {}{generics} = /* Type */{where_clauses};", assoc.name)
+ format!("type {}{generics} = /* Type */{where_clauses};", assoc.name())
}
- ty::AssocKind::Const => {
+ ty::AssocKind::Const { name } => {
let ty = tcx.type_of(assoc.def_id).instantiate_identity();
let val = tcx
.infer_ctxt()
@@ -514,7 +514,7 @@ fn suggestion_signature<'tcx>(
.err_ctxt()
.ty_kind_suggestion(tcx.param_env(assoc.def_id), ty)
.unwrap_or_else(|| "value".to_string());
- format!("const {}: {} = {};", assoc.name, ty, val)
+ format!("const {}: {} = {};", name, ty, val)
}
}
}
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 6292d03..33d5a86 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -408,7 +408,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
let gat_def_id = gat_item.def_id.expect_local();
let gat_item = tcx.associated_item(gat_def_id);
// If this item is not an assoc ty, or has no args, then it's not a GAT
- if gat_item.kind != ty::AssocKind::Type {
+ if !gat_item.is_type() {
continue;
}
let gat_generics = tcx.generics_of(gat_def_id);
@@ -432,7 +432,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
let item_required_bounds = match tcx.associated_item(item_def_id).kind {
// In our example, this corresponds to `into_iter` method
- ty::AssocKind::Fn => {
+ ty::AssocKind::Fn { .. } => {
// For methods, we check the function signature's return type for any GATs
// to constrain. In the `into_iter` case, we see that the return type
// `Self::Iter<'a>` is a GAT we want to gather any potential missing bounds from.
@@ -453,7 +453,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
)
}
// In our example, this corresponds to the `Iter` and `Item` associated types
- ty::AssocKind::Type => {
+ ty::AssocKind::Type { .. } => {
// If our associated item is a GAT with missing bounds, add them to
// the param-env here. This allows this GAT to propagate missing bounds
// to other GATs.
@@ -474,7 +474,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
gat_generics,
)
}
- ty::AssocKind::Const => None,
+ ty::AssocKind::Const { .. } => None,
};
if let Some(item_required_bounds) = item_required_bounds {
@@ -1076,7 +1076,7 @@ fn check_associated_item(
};
match item.kind {
- ty::AssocKind::Const => {
+ ty::AssocKind::Const { .. } => {
let ty = tcx.type_of(item.def_id).instantiate_identity();
let ty = wfcx.normalize(span, Some(WellFormedLoc::Ty(item_id)), ty);
wfcx.register_wf_obligation(span, loc, ty.into());
@@ -1089,7 +1089,7 @@ fn check_associated_item(
);
Ok(())
}
- ty::AssocKind::Fn => {
+ ty::AssocKind::Fn { .. } => {
let sig = tcx.fn_sig(item.def_id).instantiate_identity();
let hir_sig = sig_if_method.expect("bad signature for method");
check_fn_or_method(
@@ -1101,7 +1101,7 @@ fn check_associated_item(
);
check_method_receiver(wfcx, hir_sig, item, self_ty)
}
- ty::AssocKind::Type => {
+ ty::AssocKind::Type { .. } => {
if let ty::AssocItemContainer::Trait = item.container {
check_associated_type_bounds(wfcx, item, span)
}
@@ -1716,7 +1716,7 @@ fn check_method_receiver<'tcx>(
) -> Result<(), ErrorGuaranteed> {
let tcx = wfcx.tcx();
- if !method.fn_has_self_parameter {
+ if !method.is_method() {
return Ok(());
}
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 8ad9d80..52656fc 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -750,7 +750,7 @@ fn visit_implementation_of_pointer_like(checker: &Checker<'_>) -> Result<(), Err
ObligationCause::misc(impl_span, checker.impl_def_id),
param_env,
nontrivial_field_ty,
- tcx.lang_items().pointer_like().unwrap(),
+ tcx.require_lang_item(LangItem::PointerLike, Some(impl_span)),
);
// FIXME(dyn-star): We should regionck this implementation.
if ocx.select_all_or_error().is_empty() {
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index dc61657..2426391 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
@@ -51,7 +51,7 @@ fn impls_have_common_items(
for &item1 in impl_items1.in_definition_order() {
let collision = impl_items2
- .filter_by_name_unhygienic(item1.name)
+ .filter_by_name_unhygienic(item1.name())
.any(|&item2| self.compare_hygienically(item1, item2));
if collision {
@@ -64,7 +64,7 @@ fn impls_have_common_items(
fn compare_hygienically(&self, item1: ty::AssocItem, item2: ty::AssocItem) -> bool {
// Symbols and namespace match, compare hygienically.
- item1.kind.namespace() == item2.kind.namespace()
+ item1.namespace() == item2.namespace()
&& item1.ident(self.tcx).normalize_to_macros_2_0()
== item2.ident(self.tcx).normalize_to_macros_2_0()
}
@@ -113,7 +113,7 @@ fn check_for_common_items_in_impls(
let mut res = Ok(());
for &item1 in impl_items1.in_definition_order() {
let collision = impl_items2
- .filter_by_name_unhygienic(item1.name)
+ .filter_by_name_unhygienic(item1.name())
.find(|&&item2| self.compare_hygienically(item1, item2));
if let Some(item2) = collision {
@@ -230,11 +230,11 @@ struct ConnectedRegion {
let mut ids = impl_items
.in_definition_order()
.filter_map(|item| {
- let entry = connected_region_ids.entry(item.name);
+ let entry = connected_region_ids.entry(item.name());
if let IndexEntry::Occupied(e) = &entry {
Some(*e.get())
} else {
- idents_to_add.push(item.name);
+ idents_to_add.push(item.name());
None
}
})
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index deded69..4520fbe 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -44,7 +44,7 @@
use tracing::{debug, instrument};
use crate::errors;
-use crate::hir_ty_lowering::errors::assoc_kind_str;
+use crate::hir_ty_lowering::errors::assoc_tag_str;
use crate::hir_ty_lowering::{FeedConstTy, HirTyLowerer, RegionInferReason};
pub(crate) mod dump;
@@ -450,7 +450,7 @@ fn lower_assoc_shared(
item_def_id: DefId,
item_segment: &rustc_hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
- kind: ty::AssocKind,
+ assoc_tag: ty::AssocTag,
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
let item_args = self.lowerer().lower_generic_args_of_assoc_item(
@@ -525,7 +525,7 @@ fn lower_assoc_shared(
inferred_sugg,
bound,
mpart_sugg,
- what: assoc_kind_str(kind),
+ what: assoc_tag_str(assoc_tag),
}))
}
}
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 9bcda35..59ab36d 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -16,7 +16,7 @@
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{self, InferKind, Visitor, VisitorExt};
use rustc_hir::{
- self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeName, Node,
+ self as hir, AmbigArg, GenericArg, GenericParam, GenericParamKind, HirId, LifetimeKind, Node,
};
use rustc_macros::extension;
use rustc_middle::hir::nested_filter;
@@ -646,14 +646,14 @@ fn visit_precise_capturing_arg(
arg: &'tcx hir::PreciseCapturingArg<'tcx>,
) -> Self::Result {
match *arg {
- hir::PreciseCapturingArg::Lifetime(lt) => match lt.res {
- LifetimeName::Param(def_id) => {
+ hir::PreciseCapturingArg::Lifetime(lt) => match lt.kind {
+ LifetimeKind::Param(def_id) => {
self.resolve_lifetime_ref(def_id, lt);
}
- LifetimeName::Error => {}
- LifetimeName::ImplicitObjectLifetimeDefault
- | LifetimeName::Infer
- | LifetimeName::Static => {
+ LifetimeKind::Error => {}
+ LifetimeKind::ImplicitObjectLifetimeDefault
+ | LifetimeKind::Infer
+ | LifetimeKind::Static => {
self.tcx.dcx().emit_err(errors::BadPreciseCapture {
span: lt.ident.span,
kind: "lifetime",
@@ -774,26 +774,26 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, AmbigArg>) {
);
}
});
- match lifetime.res {
- LifetimeName::ImplicitObjectLifetimeDefault => {
+ match lifetime.kind {
+ LifetimeKind::ImplicitObjectLifetimeDefault => {
// If the user does not write *anything*, we
// use the object lifetime defaulting
// rules. So e.g., `Box<dyn Debug>` becomes
// `Box<dyn Debug + 'static>`.
self.resolve_object_lifetime_default(&*lifetime)
}
- LifetimeName::Infer => {
+ LifetimeKind::Infer => {
// If the user writes `'_`, we use the *ordinary* elision
// rules. So the `'_` in e.g., `Box<dyn Debug + '_>` will be
// resolved the same as the `'_` in `&'_ Foo`.
//
// cc #48468
}
- LifetimeName::Param(..) | LifetimeName::Static => {
+ LifetimeKind::Param(..) | LifetimeKind::Static => {
// If the user wrote an explicit name, use that.
self.visit_lifetime(&*lifetime);
}
- LifetimeName::Error => {}
+ LifetimeKind::Error => {}
}
}
hir::TyKind::Ref(lifetime_ref, ref mt) => {
@@ -873,17 +873,17 @@ fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
#[instrument(level = "debug", skip(self))]
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
- match lifetime_ref.res {
- hir::LifetimeName::Static => {
+ match lifetime_ref.kind {
+ hir::LifetimeKind::Static => {
self.insert_lifetime(lifetime_ref, ResolvedArg::StaticLifetime)
}
- hir::LifetimeName::Param(param_def_id) => {
+ hir::LifetimeKind::Param(param_def_id) => {
self.resolve_lifetime_ref(param_def_id, lifetime_ref)
}
// If we've already reported an error, just ignore `lifetime_ref`.
- hir::LifetimeName::Error => {}
+ hir::LifetimeKind::Error => {}
// Those will be resolved by typechecking.
- hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Infer => {}
+ hir::LifetimeKind::ImplicitObjectLifetimeDefault | hir::LifetimeKind::Infer => {}
}
}
@@ -1063,15 +1063,15 @@ fn object_lifetime_default(tcx: TyCtxt<'_>, param_def_id: LocalDefId) -> ObjectL
for bound in bound.bounds {
if let hir::GenericBound::Outlives(lifetime) = bound {
- set.insert(lifetime.res);
+ set.insert(lifetime.kind);
}
}
}
match set {
Set1::Empty => ObjectLifetimeDefault::Empty,
- Set1::One(hir::LifetimeName::Static) => ObjectLifetimeDefault::Static,
- Set1::One(hir::LifetimeName::Param(param_def_id)) => {
+ Set1::One(hir::LifetimeKind::Static) => ObjectLifetimeDefault::Static,
+ Set1::One(hir::LifetimeKind::Param(param_def_id)) => {
ObjectLifetimeDefault::Param(param_def_id.to_def_id())
}
_ => ObjectLifetimeDefault::Ambiguous,
@@ -1241,7 +1241,7 @@ fn resolve_lifetime_ref(
// Fresh lifetimes in APIT used to be allowed in async fns and forbidden in
// regular fns.
if let Some(hir::PredicateOrigin::ImplTrait) = where_bound_origin
- && let hir::LifetimeName::Param(param_id) = lifetime_ref.res
+ && let hir::LifetimeKind::Param(param_id) = lifetime_ref.kind
&& let Some(generics) =
self.tcx.hir_get_generics(self.tcx.local_parent(param_id))
&& let Some(param) = generics.params.iter().find(|p| p.def_id == param_id)
@@ -1811,7 +1811,7 @@ fn visit_segment_args(
self.tcx,
type_def_id,
constraint.ident,
- ty::AssocKind::Fn,
+ ty::AssocTag::Fn,
) {
bound_vars.extend(
self.tcx
@@ -1843,7 +1843,7 @@ fn visit_segment_args(
self.tcx,
type_def_id,
constraint.ident,
- ty::AssocKind::Type,
+ ty::AssocTag::Type,
)
.map(|(bound_vars, _)| bound_vars);
self.with(scope, |this| {
@@ -1875,13 +1875,13 @@ fn supertrait_hrtb_vars(
tcx: TyCtxt<'tcx>,
def_id: DefId,
assoc_ident: Ident,
- assoc_kind: ty::AssocKind,
+ assoc_tag: ty::AssocTag,
) -> Option<(Vec<ty::BoundVariableKind>, &'tcx ty::AssocItem)> {
let trait_defines_associated_item_named = |trait_def_id: DefId| {
tcx.associated_items(trait_def_id).find_by_ident_and_kind(
tcx,
assoc_ident,
- assoc_kind,
+ assoc_tag,
trait_def_id,
)
};
@@ -1894,8 +1894,8 @@ fn supertrait_hrtb_vars(
let Some((def_id, bound_vars)) = stack.pop() else {
break None;
};
- // See issue #83753. If someone writes an associated type on a non-trait, just treat it as
- // there being no supertrait HRTBs.
+ // See issue #83753. If someone writes an associated type on a non-trait, just treat it
+ // as there being no supertrait HRTBs.
match tcx.def_kind(def_id) {
DefKind::Trait | DefKind::TraitAlias | DefKind::Impl { .. } => {}
_ => break None,
@@ -2067,7 +2067,7 @@ fn try_append_return_type_notation_params(
self.tcx,
trait_def_id,
item_segment.ident,
- ty::AssocKind::Fn,
+ ty::AssocTag::Fn,
)
});
@@ -2112,7 +2112,7 @@ fn try_append_return_type_notation_params(
self.tcx,
trait_def_id,
item_segment.ident,
- ty::AssocKind::Fn,
+ ty::AssocTag::Fn,
) else {
return;
};
@@ -2440,7 +2440,7 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
}
fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) {
- if let hir::LifetimeName::Param(def_id) = lifetime_ref.res {
+ if let hir::LifetimeKind::Param(def_id) = lifetime_ref.kind {
self.regions.insert(def_id);
}
}
@@ -2453,7 +2453,7 @@ struct AllCollector {
impl<'tcx> Visitor<'tcx> for AllCollector {
fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) {
- if let hir::LifetimeName::Param(def_id) = lifetime_ref.res {
+ if let hir::LifetimeKind::Param(def_id) = lifetime_ref.kind {
self.regions.insert(def_id);
}
}
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index 772197a..50e20a1 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -32,9 +32,11 @@ pub(super) fn find_opaque_ty_constraints_for_impl_trait_in_assoc_type(
for &assoc_id in tcx.associated_item_def_ids(impl_def_id) {
let assoc = tcx.associated_item(assoc_id);
match assoc.kind {
- ty::AssocKind::Const | ty::AssocKind::Fn => locator.check(assoc_id.expect_local()),
+ ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => {
+ locator.check(assoc_id.expect_local())
+ }
// Associated types don't have bodies, so they can't constrain hidden types
- ty::AssocKind::Type => {}
+ ty::AssocKind::Type { .. } => {}
}
}
diff --git a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
index 610b293..a3c8ce6 100644
--- a/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/errors/wrong_number_of_generic_args.rs
@@ -4,7 +4,7 @@
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, Diagnostic, EmissionGuarantee, MultiSpan, pluralize};
use rustc_hir as hir;
-use rustc_middle::ty::{self as ty, AssocItems, AssocKind, TyCtxt};
+use rustc_middle::ty::{self as ty, AssocItems, TyCtxt};
use rustc_span::def_id::DefId;
use tracing::debug;
@@ -486,15 +486,15 @@ fn get_unbound_associated_types(&self) -> Vec<String> {
let items: &AssocItems = self.tcx.associated_items(self.def_id);
items
.in_definition_order()
- .filter(|item| item.kind == AssocKind::Type)
.filter(|item| {
- !self
- .gen_args
- .constraints
- .iter()
- .any(|constraint| constraint.ident.name == item.name)
+ item.is_type()
+ && !item.is_impl_trait_in_trait()
+ && !self
+ .gen_args
+ .constraints
+ .iter()
+ .any(|constraint| constraint.ident.name == item.name())
})
- .filter(|item| !item.is_impl_trait_in_trait())
.map(|item| self.tcx.item_ident(item.def_id).to_string())
.collect()
} else {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 24d05b4..bf91eb1 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -431,16 +431,16 @@ pub(super) fn lower_assoc_item_constraint(
) -> Result<(), ErrorGuaranteed> {
let tcx = self.tcx();
- let assoc_kind = if constraint.gen_args.parenthesized
+ let assoc_tag = if constraint.gen_args.parenthesized
== hir::GenericArgsParentheses::ReturnTypeNotation
{
- ty::AssocKind::Fn
+ ty::AssocTag::Fn
} else if let hir::AssocItemConstraintKind::Equality { term: hir::Term::Const(_) } =
constraint.kind
{
- ty::AssocKind::Const
+ ty::AssocTag::Const
} else {
- ty::AssocKind::Type
+ ty::AssocTag::Type
};
// Given something like `U: Trait<T = X>`, we want to produce a predicate like
@@ -453,7 +453,7 @@ pub(super) fn lower_assoc_item_constraint(
// trait SuperTrait<A> { type T; }
let candidate = if self.probe_trait_that_defines_assoc_item(
trait_ref.def_id(),
- assoc_kind,
+ assoc_tag,
constraint.ident,
) {
// Simple case: The assoc item is defined in the current trait.
@@ -464,7 +464,7 @@ pub(super) fn lower_assoc_item_constraint(
self.probe_single_bound_for_assoc_item(
|| traits::supertraits(tcx, trait_ref),
AssocItemQSelf::Trait(trait_ref.def_id()),
- assoc_kind,
+ assoc_tag,
constraint.ident,
path_span,
Some(constraint),
@@ -474,7 +474,7 @@ pub(super) fn lower_assoc_item_constraint(
let assoc_item = self
.probe_assoc_item(
constraint.ident,
- assoc_kind,
+ assoc_tag,
hir_ref_id,
constraint.span,
candidate.def_id(),
@@ -493,7 +493,7 @@ pub(super) fn lower_assoc_item_constraint(
})
.or_insert(constraint.span);
- let projection_term = if let ty::AssocKind::Fn = assoc_kind {
+ let projection_term = if let ty::AssocTag::Fn = assoc_tag {
let bound_vars = tcx.late_bound_vars(constraint.hir_id);
ty::Binder::bind_with_vars(
self.lower_return_type_notation_ty(candidate, assoc_item.def_id, path_span)?.into(),
@@ -542,7 +542,7 @@ pub(super) fn lower_assoc_item_constraint(
};
match constraint.kind {
- hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocKind::Fn = assoc_kind => {
+ hir::AssocItemConstraintKind::Equality { .. } if let ty::AssocTag::Fn = assoc_tag => {
return Err(self.dcx().emit_err(crate::errors::ReturnTypeNotationEqualityBound {
span: constraint.span,
}));
@@ -679,7 +679,7 @@ pub fn lower_ty_maybe_return_type_notation(&self, hir_ty: &hir::Ty<'tcx>) -> Ty<
trait_def_id,
hir_ty.span,
item_segment,
- ty::AssocKind::Type,
+ ty::AssocTag::Type,
);
return Ty::new_error(tcx, guar);
};
@@ -771,7 +771,7 @@ fn resolve_type_relative_return_type_notation(
)
},
AssocItemQSelf::SelfTyAlias,
- ty::AssocKind::Fn,
+ ty::AssocTag::Fn,
assoc_ident,
span,
None,
@@ -783,7 +783,7 @@ fn resolve_type_relative_return_type_notation(
) => self.probe_single_ty_param_bound_for_assoc_item(
param_did.expect_local(),
qself.span,
- ty::AssocKind::Fn,
+ ty::AssocTag::Fn,
assoc_ident,
span,
)?,
@@ -823,7 +823,7 @@ fn resolve_type_relative_return_type_notation(
let trait_def_id = bound.def_id();
let assoc_ty = self
- .probe_assoc_item(assoc_ident, ty::AssocKind::Fn, qpath_hir_id, span, trait_def_id)
+ .probe_assoc_item(assoc_ident, ty::AssocTag::Fn, qpath_hir_id, span, trait_def_id)
.expect("failed to find associated type");
Ok((bound, assoc_ty.def_id))
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
index e64cd8e..88f7458 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/dyn_compatibility.rs
@@ -201,7 +201,7 @@ pub(super) fn lower_trait_object_ty(
tcx.associated_items(pred.trait_ref.def_id)
.in_definition_order()
// We only care about associated types.
- .filter(|item| item.kind == ty::AssocKind::Type)
+ .filter(|item| item.is_type())
// No RPITITs -- they're not dyn-compatible for now.
.filter(|item| !item.is_impl_trait_in_trait())
// If the associated type has a `where Self: Sized` bound,
@@ -415,7 +415,7 @@ pub(super) fn lower_trait_object_ty(
self.lower_lifetime(lifetime, RegionInferReason::ExplicitObjectLifetime)
} else {
let reason =
- if let hir::LifetimeName::ImplicitObjectLifetimeDefault = lifetime.res {
+ if let hir::LifetimeKind::ImplicitObjectLifetimeDefault = lifetime.kind {
if let hir::Node::Ty(hir::Ty {
kind: hir::TyKind::Ref(parent_lifetime, _),
..
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 5a0524d..3759a22 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -116,7 +116,7 @@ pub(super) fn complain_about_assoc_item_not_found<I>(
&self,
all_candidates: impl Fn() -> I,
qself: AssocItemQSelf,
- assoc_kind: ty::AssocKind,
+ assoc_tag: ty::AssocTag,
assoc_ident: Ident,
span: Span,
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
@@ -134,14 +134,14 @@ pub(super) fn complain_about_assoc_item_not_found<I>(
}) {
return self.complain_about_assoc_kind_mismatch(
assoc_item,
- assoc_kind,
+ assoc_tag,
assoc_ident,
span,
constraint,
);
}
- let assoc_kind_str = assoc_kind_str(assoc_kind);
+ let assoc_kind_str = assoc_tag_str(assoc_tag);
let qself_str = qself.to_string(tcx);
// The fallback span is needed because `assoc_name` might be an `Fn()`'s `Output` without a
@@ -168,7 +168,11 @@ pub(super) fn complain_about_assoc_item_not_found<I>(
let all_candidate_names: Vec<_> = all_candidates()
.flat_map(|r| tcx.associated_items(r.def_id()).in_definition_order())
.filter_map(|item| {
- (!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
+ if !item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag {
+ item.opt_name()
+ } else {
+ None
+ }
})
.collect();
@@ -200,7 +204,7 @@ pub(super) fn complain_about_assoc_item_not_found<I>(
.iter()
.flat_map(|trait_def_id| tcx.associated_items(*trait_def_id).in_definition_order())
.filter_map(|item| {
- (!item.is_impl_trait_in_trait() && item.kind == assoc_kind).then_some(item.name)
+ (!item.is_impl_trait_in_trait() && item.as_tag() == assoc_tag).then(|| item.name())
})
.collect();
@@ -213,7 +217,7 @@ pub(super) fn complain_about_assoc_item_not_found<I>(
.filter(|trait_def_id| {
tcx.associated_items(trait_def_id)
.filter_by_name_unhygienic(suggested_name)
- .any(|item| item.kind == assoc_kind)
+ .any(|item| item.as_tag() == assoc_tag)
})
.collect::<Vec<_>>()[..]
{
@@ -330,14 +334,14 @@ pub(super) fn complain_about_assoc_item_not_found<I>(
fn complain_about_assoc_kind_mismatch(
&self,
assoc_item: &ty::AssocItem,
- assoc_kind: ty::AssocKind,
+ assoc_tag: ty::AssocTag,
ident: Ident,
span: Span,
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
) -> ErrorGuaranteed {
let tcx = self.tcx();
- let bound_on_assoc_const_label = if let ty::AssocKind::Const = assoc_item.kind
+ let bound_on_assoc_const_label = if let ty::AssocKind::Const { .. } = assoc_item.kind
&& let Some(constraint) = constraint
&& let hir::AssocItemConstraintKind::Bound { .. } = constraint.kind
{
@@ -375,17 +379,17 @@ fn complain_about_assoc_kind_mismatch(
hir::Term::Ty(ty) => ty.span,
hir::Term::Const(ct) => ct.span(),
};
- (span, Some(ident.span), assoc_item.kind, assoc_kind)
+ (span, Some(ident.span), assoc_item.as_tag(), assoc_tag)
} else {
- (ident.span, None, assoc_kind, assoc_item.kind)
+ (ident.span, None, assoc_tag, assoc_item.as_tag())
};
self.dcx().emit_err(errors::AssocKindMismatch {
span,
- expected: assoc_kind_str(expected),
- got: assoc_kind_str(got),
+ expected: assoc_tag_str(expected),
+ got: assoc_tag_str(got),
expected_because_label,
- assoc_kind: assoc_kind_str(assoc_item.kind),
+ assoc_kind: assoc_tag_str(assoc_item.as_tag()),
def_span: tcx.def_span(assoc_item.def_id),
bound_on_assoc_const_label,
wrap_in_braces_sugg,
@@ -398,9 +402,9 @@ pub(super) fn report_ambiguous_assoc(
types: &[String],
traits: &[String],
name: Symbol,
- kind: ty::AssocKind,
+ assoc_tag: ty::AssocTag,
) -> ErrorGuaranteed {
- let kind_str = assoc_kind_str(kind);
+ let kind_str = assoc_tag_str(assoc_tag);
let mut err =
struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated {kind_str}");
if self
@@ -569,7 +573,7 @@ pub(crate) fn complain_about_inherent_assoc_not_found(
candidates: Vec<(DefId, (DefId, DefId))>,
fulfillment_errors: Vec<FulfillmentError<'tcx>>,
span: Span,
- kind: ty::AssocKind,
+ assoc_tag: ty::AssocTag,
) -> ErrorGuaranteed {
// FIXME(fmease): This was copied in parts from an old version of `rustc_hir_typeck::method::suggest`.
// Either
@@ -579,14 +583,14 @@ pub(crate) fn complain_about_inherent_assoc_not_found(
let tcx = self.tcx();
- let kind_str = assoc_kind_str(kind);
+ let assoc_tag_str = assoc_tag_str(assoc_tag);
let adt_did = self_ty.ty_adt_def().map(|def| def.did());
let add_def_label = |err: &mut Diag<'_>| {
if let Some(did) = adt_did {
err.span_label(
tcx.def_span(did),
format!(
- "associated {kind_str} `{name}` not found for this {}",
+ "associated {assoc_tag_str} `{name}` not found for this {}",
tcx.def_descr(did)
),
);
@@ -615,11 +619,11 @@ pub(crate) fn complain_about_inherent_assoc_not_found(
self.dcx(),
name.span,
E0220,
- "associated {kind_str} `{name}` not found for `{self_ty}` in the current scope"
+ "associated {assoc_tag_str} `{name}` not found for `{self_ty}` in the current scope"
);
err.span_label(name.span, format!("associated item not found in `{self_ty}`"));
err.note(format!(
- "the associated {kind_str} was found for\n{type_candidates}{additional_types}",
+ "the associated {assoc_tag_str} was found for\n{type_candidates}{additional_types}",
));
add_def_label(&mut err);
return err.emit();
@@ -700,7 +704,7 @@ pub(crate) fn complain_about_inherent_assoc_not_found(
let mut err = self.dcx().struct_span_err(
name.span,
- format!("the associated {kind_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
+ format!("the associated {assoc_tag_str} `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
);
if !bounds.is_empty() {
err.note(format!(
@@ -710,7 +714,7 @@ pub(crate) fn complain_about_inherent_assoc_not_found(
}
err.span_label(
name.span,
- format!("associated {kind_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
+ format!("associated {assoc_tag_str} cannot be referenced on `{self_ty}` due to unsatisfied trait bounds")
);
for (span, mut bounds) in bound_spans {
@@ -761,7 +765,7 @@ pub(crate) fn check_for_required_assoc_tys(
// `issue-22560.rs`.
let mut dyn_compatibility_violations = Ok(());
for (assoc_item, trait_ref) in &missing_assoc_types {
- names.entry(trait_ref).or_default().push(assoc_item.name);
+ names.entry(trait_ref).or_default().push(assoc_item.name());
names_len += 1;
let violations =
@@ -812,7 +816,7 @@ pub(crate) fn check_for_required_assoc_tys(
let assoc_item = tcx.associated_items(trait_def).find_by_ident_and_kind(
tcx,
ident,
- ty::AssocKind::Type,
+ ty::AssocTag::Type,
trait_def,
);
@@ -852,16 +856,17 @@ pub(crate) fn check_for_required_assoc_tys(
let mut names: UnordMap<_, usize> = Default::default();
for (item, _) in &missing_assoc_types {
types_count += 1;
- *names.entry(item.name).or_insert(0) += 1;
+ *names.entry(item.name()).or_insert(0) += 1;
}
let mut dupes = false;
let mut shadows = false;
for (item, trait_ref) in &missing_assoc_types {
- let prefix = if names[&item.name] > 1 {
+ let name = item.name();
+ let prefix = if names[&name] > 1 {
let trait_def_id = trait_ref.def_id();
dupes = true;
format!("{}::", tcx.def_path_str(trait_def_id))
- } else if bound_names.get(&item.name).is_some_and(|x| *x != item) {
+ } else if bound_names.get(&name).is_some_and(|x| *x != item) {
let trait_def_id = trait_ref.def_id();
shadows = true;
format!("{}::", tcx.def_path_str(trait_def_id))
@@ -871,7 +876,7 @@ pub(crate) fn check_for_required_assoc_tys(
let mut is_shadowed = false;
- if let Some(assoc_item) = bound_names.get(&item.name)
+ if let Some(assoc_item) = bound_names.get(&name)
&& *assoc_item != item
{
is_shadowed = true;
@@ -880,17 +885,14 @@ pub(crate) fn check_for_required_assoc_tys(
if assoc_item.def_id.is_local() { ", consider renaming it" } else { "" };
err.span_label(
tcx.def_span(assoc_item.def_id),
- format!("`{}{}` shadowed here{}", prefix, item.name, rename_message),
+ format!("`{}{}` shadowed here{}", prefix, name, rename_message),
);
}
let rename_message = if is_shadowed { ", consider renaming it" } else { "" };
if let Some(sp) = tcx.hir_span_if_local(item.def_id) {
- err.span_label(
- sp,
- format!("`{}{}` defined here{}", prefix, item.name, rename_message),
- );
+ err.span_label(sp, format!("`{}{}` defined here{}", prefix, name, rename_message));
}
}
if potential_assoc_types.len() == missing_assoc_types.len() {
@@ -903,7 +905,7 @@ pub(crate) fn check_for_required_assoc_tys(
{
let types: Vec<_> = missing_assoc_types
.iter()
- .map(|(item, _)| format!("{} = Type", item.name))
+ .map(|(item, _)| format!("{} = Type", item.name()))
.collect();
let code = if let Some(snippet) = snippet.strip_suffix('>') {
// The user wrote `Trait<'a>` or similar and we don't have a type we can
@@ -938,16 +940,17 @@ pub(crate) fn check_for_required_assoc_tys(
let mut names: FxIndexMap<_, usize> = FxIndexMap::default();
for (item, _) in &missing_assoc_types {
types_count += 1;
- *names.entry(item.name).or_insert(0) += 1;
+ *names.entry(item.name()).or_insert(0) += 1;
}
let mut label = vec![];
for (item, trait_ref) in &missing_assoc_types {
- let postfix = if names[&item.name] > 1 {
+ let name = item.name();
+ let postfix = if names[&name] > 1 {
format!(" (from trait `{}`)", trait_ref.print_trait_sugared())
} else {
String::new()
};
- label.push(format!("`{}`{}", item.name, postfix));
+ label.push(format!("`{}`{}", name, postfix));
}
if !label.is_empty() {
err.span_label(
@@ -1022,12 +1025,13 @@ pub(crate) fn maybe_report_similar_assoc_fn(
.map(|simple_ty| tcx.incoherent_impls(simple_ty))
})
&& let name = Symbol::intern(&format!("{ident2}_{ident3}"))
- && let Some(ty::AssocItem { kind: ty::AssocKind::Fn, .. }) = inherent_impls
+ && let Some(item) = inherent_impls
.iter()
.flat_map(|inherent_impl| {
tcx.associated_items(inherent_impl).filter_by_name_unhygienic(name)
})
.next()
+ && item.is_fn()
{
Err(struct_span_code_err!(self.dcx(), span, E0223, "ambiguous associated type")
.with_span_suggestion_verbose(
@@ -1629,10 +1633,10 @@ fn generics_args_err_extend<'a>(
}
}
-pub(crate) fn assoc_kind_str(kind: ty::AssocKind) -> &'static str {
- match kind {
- ty::AssocKind::Fn => "function",
- ty::AssocKind::Const => "constant",
- ty::AssocKind::Type => "type",
+pub(crate) fn assoc_tag_str(assoc_tag: ty::AssocTag) -> &'static str {
+ match assoc_tag {
+ ty::AssocTag::Fn => "function",
+ ty::AssocTag::Const => "constant",
+ ty::AssocTag::Type => "type",
}
}
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index 8e62dce..483b61a 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -501,8 +501,8 @@ fn maybe_suggest_typoed_method(
let names: Vec<_> = tcx
.associated_items(trait_def_id)
.in_definition_order()
- .filter(|assoc| assoc.kind.namespace() == Namespace::ValueNS)
- .map(|cand| cand.name)
+ .filter(|assoc| assoc.namespace() == Namespace::ValueNS)
+ .map(|cand| cand.name())
.collect();
if let Some(typo) = find_best_match_for_name(&names, segment.ident.name, None) {
diag.span_suggestion_verbose(
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index 83aa0d9..22162b8 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -29,7 +29,7 @@
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, FatalError, struct_span_code_err,
};
-use rustc_hir::def::{CtorKind, CtorOf, DefKind, Namespace, Res};
+use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self as hir, AnonConst, GenericArg, GenericArgs, HirId};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
@@ -38,8 +38,8 @@
use rustc_middle::mir::interpret::LitToConstInput;
use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
use rustc_middle::ty::{
- self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
- TypeVisitableExt, TypingMode, Upcast, fold_regions,
+ self, AssocTag, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty,
+ TyCtxt, TypeVisitableExt, TypingMode, Upcast, fold_regions,
};
use rustc_middle::{bug, span_bug};
use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
@@ -51,7 +51,7 @@
use rustc_trait_selection::traits::{self, ObligationCtxt};
use tracing::{debug, instrument};
-use self::errors::assoc_kind_str;
+use self::errors::assoc_tag_str;
use crate::check::check_abi_fn_ptr;
use crate::errors::{AmbiguousLifetimeBound, BadReturnTypeNotation, NoVariantNamed};
use crate::hir_ty_lowering::errors::{GenericsArgsErrExtend, prohibit_assoc_item_constraint};
@@ -168,7 +168,7 @@ fn lower_assoc_shared(
item_def_id: DefId,
item_segment: &hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
- kind: ty::AssocKind,
+ assoc_tag: ty::AssocTag,
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed>;
fn lower_fn_sig(
@@ -251,10 +251,10 @@ enum LowerAssocMode {
}
impl LowerAssocMode {
- fn kind(self) -> ty::AssocKind {
+ fn assoc_tag(self) -> ty::AssocTag {
match self {
- LowerAssocMode::Type { .. } => ty::AssocKind::Type,
- LowerAssocMode::Const => ty::AssocKind::Const,
+ LowerAssocMode::Type { .. } => ty::AssocTag::Type,
+ LowerAssocMode::Const => ty::AssocTag::Const,
}
}
@@ -268,7 +268,8 @@ fn def_kind(self) -> DefKind {
fn permit_variants(self) -> bool {
match self {
LowerAssocMode::Type { permit_variants } => permit_variants,
- // FIXME(mgca): Support paths like `Option::<T>::None` or `Option::<T>::Some` which resolve to const ctors/fn items respectively
+ // FIXME(mgca): Support paths like `Option::<T>::None` or `Option::<T>::Some` which
+ // resolve to const ctors/fn items respectively.
LowerAssocMode::Const => false,
}
}
@@ -932,12 +933,12 @@ fn lower_mono_trait_ref(
fn probe_trait_that_defines_assoc_item(
&self,
trait_def_id: DefId,
- assoc_kind: ty::AssocKind,
+ assoc_tag: AssocTag,
assoc_ident: Ident,
) -> bool {
self.tcx()
.associated_items(trait_def_id)
- .find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_kind, trait_def_id)
+ .find_by_ident_and_kind(self.tcx(), assoc_ident, assoc_tag, trait_def_id)
.is_some()
}
@@ -975,7 +976,7 @@ fn probe_single_ty_param_bound_for_assoc_item(
&self,
ty_param_def_id: LocalDefId,
ty_param_span: Span,
- kind: ty::AssocKind,
+ assoc_tag: AssocTag,
assoc_ident: Ident,
span: Span,
) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
@@ -993,7 +994,7 @@ fn probe_single_ty_param_bound_for_assoc_item(
traits::transitive_bounds_that_define_assoc_item(tcx, trait_refs, assoc_ident)
},
AssocItemQSelf::TyParam(ty_param_def_id, ty_param_span),
- kind,
+ assoc_tag,
assoc_ident,
span,
None,
@@ -1010,7 +1011,7 @@ fn probe_single_bound_for_assoc_item<I>(
&self,
all_candidates: impl Fn() -> I,
qself: AssocItemQSelf,
- assoc_kind: ty::AssocKind,
+ assoc_tag: AssocTag,
assoc_ident: Ident,
span: Span,
constraint: Option<&hir::AssocItemConstraint<'tcx>>,
@@ -1021,14 +1022,14 @@ fn probe_single_bound_for_assoc_item<I>(
let tcx = self.tcx();
let mut matching_candidates = all_candidates().filter(|r| {
- self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_kind, assoc_ident)
+ self.probe_trait_that_defines_assoc_item(r.def_id(), assoc_tag, assoc_ident)
});
let Some(bound) = matching_candidates.next() else {
let reported = self.complain_about_assoc_item_not_found(
all_candidates,
qself,
- assoc_kind,
+ assoc_tag,
assoc_ident,
span,
constraint,
@@ -1040,7 +1041,7 @@ fn probe_single_bound_for_assoc_item<I>(
if let Some(bound2) = matching_candidates.next() {
debug!(?bound2);
- let assoc_kind_str = errors::assoc_kind_str(assoc_kind);
+ let assoc_kind_str = errors::assoc_tag_str(assoc_tag);
let qself_str = qself.to_string(tcx);
let mut err = self.dcx().create_err(crate::errors::AmbiguousAssocItem {
span,
@@ -1059,14 +1060,15 @@ fn probe_single_bound_for_assoc_item<I>(
},
);
- // FIXME(#97583): Print associated item bindings properly (i.e., not as equality predicates!).
+ // FIXME(#97583): Print associated item bindings properly (i.e., not as equality
+ // predicates!).
// FIXME: Turn this into a structured, translateable & more actionable suggestion.
let mut where_bounds = vec![];
for bound in [bound, bound2].into_iter().chain(matching_candidates) {
let bound_id = bound.def_id();
let bound_span = tcx
.associated_items(bound_id)
- .find_by_ident_and_kind(tcx, assoc_ident, assoc_kind, bound_id)
+ .find_by_ident_and_kind(tcx, assoc_ident, assoc_tag, bound_id)
.and_then(|item| tcx.hir_span_if_local(item.def_id));
if let Some(bound_span) = bound_span {
@@ -1265,7 +1267,7 @@ fn lower_assoc_path_shared(
qself_ty,
hir_ref_id,
span,
- mode.kind(),
+ mode.assoc_tag(),
)? {
return Ok(LoweredAssoc::Term(did, args));
}
@@ -1296,7 +1298,7 @@ fn lower_assoc_path_shared(
)
},
AssocItemQSelf::SelfTyAlias,
- mode.kind(),
+ mode.assoc_tag(),
assoc_ident,
span,
None,
@@ -1308,12 +1310,12 @@ fn lower_assoc_path_shared(
) => self.probe_single_ty_param_bound_for_assoc_item(
param_did.expect_local(),
qself.span,
- mode.kind(),
+ mode.assoc_tag(),
assoc_ident,
span,
)?,
_ => {
- let kind_str = assoc_kind_str(mode.kind());
+ let kind_str = assoc_tag_str(mode.assoc_tag());
let reported = if variant_resolution.is_some() {
// Variant in type position
let msg = format!("expected {kind_str}, found variant `{assoc_ident}`");
@@ -1420,7 +1422,7 @@ fn lower_assoc_path_shared(
&[qself_ty.to_string()],
&traits,
assoc_ident.name,
- mode.kind(),
+ mode.assoc_tag(),
)
};
return Err(reported);
@@ -1429,10 +1431,15 @@ fn lower_assoc_path_shared(
let trait_did = bound.def_id();
let assoc_item = self
- .probe_assoc_item(assoc_ident, mode.kind(), hir_ref_id, span, trait_did)
+ .probe_assoc_item(assoc_ident, mode.assoc_tag(), hir_ref_id, span, trait_did)
.expect("failed to find associated item");
- let (def_id, args) =
- self.lower_assoc_shared(span, assoc_item.def_id, assoc_segment, bound, mode.kind())?;
+ let (def_id, args) = self.lower_assoc_shared(
+ span,
+ assoc_item.def_id,
+ assoc_segment,
+ bound,
+ mode.assoc_tag(),
+ )?;
let result = LoweredAssoc::Term(def_id, args);
if let Some(variant_def_id) = variant_resolution {
@@ -1469,20 +1476,21 @@ fn probe_inherent_assoc_shared(
self_ty: Ty<'tcx>,
block: HirId,
span: Span,
- kind: ty::AssocKind,
+ assoc_tag: ty::AssocTag,
) -> Result<Option<(DefId, GenericArgsRef<'tcx>)>, ErrorGuaranteed> {
let tcx = self.tcx();
if !tcx.features().inherent_associated_types() {
- match kind {
- // Don't attempt to look up inherent associated types when the feature is not enabled.
- // Theoretically it'd be fine to do so since we feature-gate their definition site.
- // However, due to current limitations of the implementation (caused by us performing
- // selection during HIR ty lowering instead of in the trait solver), IATs can lead to cycle
- // errors (#108491) which mask the feature-gate error, needlessly confusing users
- // who use IATs by accident (#113265).
- ty::AssocKind::Type => return Ok(None),
- ty::AssocKind::Const => {
+ match assoc_tag {
+ // Don't attempt to look up inherent associated types when the feature is not
+ // enabled. Theoretically it'd be fine to do so since we feature-gate their
+ // definition site. However, due to current limitations of the implementation
+ // (caused by us performing selection during HIR ty lowering instead of in the
+ // trait solver), IATs can lead to cycle errors (#108491) which mask the
+ // feature-gate error, needlessly confusing users who use IATs by accident
+ // (#113265).
+ ty::AssocTag::Type => return Ok(None),
+ ty::AssocTag::Const => {
// We also gate the mgca codepath for type-level uses of inherent consts
// with the inherent_associated_types feature gate since it relies on the
// same machinery and has similar rough edges.
@@ -1494,7 +1502,7 @@ fn probe_inherent_assoc_shared(
)
.emit());
}
- ty::AssocKind::Fn => unreachable!(),
+ ty::AssocTag::Fn => unreachable!(),
}
}
@@ -1503,7 +1511,8 @@ fn probe_inherent_assoc_shared(
.inherent_impls(adt_did)
.iter()
.filter_map(|&impl_| {
- let (item, scope) = self.probe_assoc_item_unchecked(name, kind, block, impl_)?;
+ let (item, scope) =
+ self.probe_assoc_item_unchecked(name, assoc_tag, block, impl_)?;
Some((impl_, (item.def_id, scope)))
})
.collect();
@@ -1542,7 +1551,7 @@ fn probe_inherent_assoc_shared(
self_ty,
|self_ty| {
self.select_inherent_assoc_candidates(
- infcx, name, span, self_ty, param_env, candidates, kind,
+ infcx, name, span, self_ty, param_env, candidates, assoc_tag,
)
},
)?;
@@ -1570,7 +1579,7 @@ fn select_inherent_assoc_candidates(
self_ty: Ty<'tcx>,
param_env: ParamEnv<'tcx>,
candidates: Vec<(DefId, (DefId, DefId))>,
- kind: ty::AssocKind,
+ assoc_tag: ty::AssocTag,
) -> Result<(DefId, (DefId, DefId)), ErrorGuaranteed> {
let tcx = self.tcx();
let mut fulfillment_errors = Vec::new();
@@ -1621,7 +1630,7 @@ fn select_inherent_assoc_candidates(
candidates,
fulfillment_errors,
span,
- kind,
+ assoc_tag,
)),
&[applicable_candidate] => Ok(applicable_candidate),
@@ -1640,12 +1649,12 @@ fn select_inherent_assoc_candidates(
fn probe_assoc_item(
&self,
ident: Ident,
- kind: ty::AssocKind,
+ assoc_tag: ty::AssocTag,
block: HirId,
span: Span,
scope: DefId,
) -> Option<ty::AssocItem> {
- let (item, scope) = self.probe_assoc_item_unchecked(ident, kind, block, scope)?;
+ let (item, scope) = self.probe_assoc_item_unchecked(ident, assoc_tag, block, scope)?;
self.check_assoc_item(item.def_id, ident, scope, block, span);
Some(item)
}
@@ -1657,7 +1666,7 @@ fn probe_assoc_item(
fn probe_assoc_item_unchecked(
&self,
ident: Ident,
- kind: ty::AssocKind,
+ assoc_tag: ty::AssocTag,
block: HirId,
scope: DefId,
) -> Option<(ty::AssocItem, /*scope*/ DefId)> {
@@ -1670,7 +1679,7 @@ fn probe_assoc_item_unchecked(
let item = tcx
.associated_items(scope)
.filter_by_name_unhygienic(ident.name)
- .find(|i| i.kind == kind && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
+ .find(|i| i.as_tag() == assoc_tag && i.ident(tcx).normalize_to_macros_2_0() == ident)?;
Some((*item, def_scope))
}
@@ -1722,9 +1731,9 @@ fn probe_traits_that_match_assoc_ty(
tcx.associated_items(*trait_def_id)
.in_definition_order()
.any(|i| {
- i.kind.namespace() == Namespace::TypeNS
+ i.is_type()
+ && !i.is_impl_trait_in_trait()
&& i.ident(tcx).normalize_to_macros_2_0() == assoc_ident
- && matches!(i.kind, ty::AssocKind::Type)
})
// Consider only accessible traits
&& tcx.visibility(*trait_def_id)
@@ -1770,7 +1779,7 @@ fn lower_qpath_ty(
item_def_id,
trait_segment,
item_segment,
- ty::AssocKind::Type,
+ ty::AssocTag::Type,
) {
Ok((item_def_id, item_args)) => {
Ty::new_projection_from_args(self.tcx(), item_def_id, item_args)
@@ -1795,7 +1804,7 @@ fn lower_qpath_const(
item_def_id,
trait_segment,
item_segment,
- ty::AssocKind::Const,
+ ty::AssocTag::Const,
) {
Ok((item_def_id, item_args)) => {
let uv = ty::UnevaluatedConst::new(item_def_id, item_args);
@@ -1813,7 +1822,7 @@ fn lower_qpath_shared(
item_def_id: DefId,
trait_segment: &hir::PathSegment<'tcx>,
item_segment: &hir::PathSegment<'tcx>,
- kind: ty::AssocKind,
+ assoc_tag: ty::AssocTag,
) -> Result<(DefId, GenericArgsRef<'tcx>), ErrorGuaranteed> {
let tcx = self.tcx();
@@ -1821,7 +1830,12 @@ fn lower_qpath_shared(
debug!(?trait_def_id);
let Some(self_ty) = opt_self_ty else {
- return Err(self.error_missing_qpath_self_ty(trait_def_id, span, item_segment, kind));
+ return Err(self.error_missing_qpath_self_ty(
+ trait_def_id,
+ span,
+ item_segment,
+ assoc_tag,
+ ));
};
debug!(?self_ty);
@@ -1840,7 +1854,7 @@ fn error_missing_qpath_self_ty(
trait_def_id: DefId,
span: Span,
item_segment: &hir::PathSegment<'tcx>,
- kind: ty::AssocKind,
+ assoc_tag: ty::AssocTag,
) -> ErrorGuaranteed {
let tcx = self.tcx();
let path_str = tcx.def_path_str(trait_def_id);
@@ -1877,7 +1891,13 @@ fn error_missing_qpath_self_ty(
// FIXME: also look at `tcx.generics_of(self.item_def_id()).params` any that
// references the trait. Relevant for the first case in
// `src/test/ui/associated-types/associated-types-in-ambiguous-context.rs`
- self.report_ambiguous_assoc(span, &type_names, &[path_str], item_segment.ident.name, kind)
+ self.report_ambiguous_assoc(
+ span,
+ &type_names,
+ &[path_str],
+ item_segment.ident.name,
+ assoc_tag,
+ )
}
pub fn prohibit_generic_args<'a>(
@@ -2862,7 +2882,7 @@ pub(super) fn suggest_trait_fn_ty_for_impl_fn_infer(
let assoc = tcx.associated_items(trait_ref.def_id).find_by_ident_and_kind(
tcx,
*ident,
- ty::AssocKind::Fn,
+ ty::AssocTag::Fn,
trait_ref.def_id,
)?;
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index c30b39d..cbdc501 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -112,14 +112,14 @@ pub(crate) fn enforce_impl_lifetime_params_are_constrained(
.flat_map(|def_id| {
let item = tcx.associated_item(def_id);
match item.kind {
- ty::AssocKind::Type => {
+ ty::AssocKind::Type { .. } => {
if item.defaultness(tcx).has_value() {
cgp::parameters_for(tcx, tcx.type_of(def_id).instantiate_identity(), true)
} else {
vec![]
}
}
- ty::AssocKind::Fn | ty::AssocKind::Const => vec![],
+ ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => vec![],
}
})
.collect();
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index e7ecd72..e1ad812 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -59,7 +59,6 @@
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(assert_matches)]
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index e5ab317..ff4385c 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1871,10 +1871,11 @@ fn print_ty_pat(&mut self, pat: &hir::TyPat<'_>) {
fn print_pat(&mut self, pat: &hir::Pat<'_>) {
self.maybe_print_comment(pat.span.lo());
self.ann.pre(self, AnnNode::Pat(pat));
- // Pat isn't normalized, but the beauty of it
- // is that it doesn't matter
+ // Pat isn't normalized, but the beauty of it is that it doesn't matter.
match pat.kind {
- PatKind::Missing => unreachable!(),
+ // Printing `_` isn't ideal for a missing pattern, but it's easy and good enough.
+ // E.g. `fn(u32)` gets printed as `fn(_: u32)`.
+ PatKind::Missing => self.word("_"),
PatKind::Wild => self.word("_"),
PatKind::Never => self.word("!"),
PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => {
@@ -2164,7 +2165,9 @@ fn print_fn(
s.end();
});
if decl.c_variadic {
- self.word(", ");
+ if !decl.inputs.is_empty() {
+ self.word(", ");
+ }
print_arg(self, None);
self.word("...");
}
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 02fd736..d770937 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -37,7 +37,7 @@ pub(crate) fn check_legal_trait_for_method_call(
body_id: DefId,
) -> Result<(), ErrorGuaranteed> {
if tcx.is_lang_item(trait_id, LangItem::Drop)
- && tcx.lang_items().fallback_surface_drop_fn() != Some(body_id)
+ && !tcx.is_lang_item(body_id, LangItem::FallbackSurfaceDrop)
{
let sugg = if let Some(receiver) = receiver.filter(|s| !s.is_empty()) {
errors::ExplicitDestructorCallSugg::Snippet {
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 8f5fddd..b19d9ef 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -1042,30 +1042,31 @@ fn check_ref_cast(
m_cast: ty::TypeAndMut<'tcx>,
) -> Result<CastKind, CastError<'tcx>> {
// array-ptr-cast: allow mut-to-mut, mut-to-const, const-to-const
- if m_expr.mutbl >= m_cast.mutbl {
- if let ty::Array(ety, _) = m_expr.ty.kind() {
- // Due to the limitations of LLVM global constants,
- // region pointers end up pointing at copies of
- // vector elements instead of the original values.
- // To allow raw pointers to work correctly, we
- // need to special-case obtaining a raw pointer
- // from a region pointer to a vector.
+ if m_expr.mutbl >= m_cast.mutbl
+ && let ty::Array(ety, _) = m_expr.ty.kind()
+ && fcx.can_eq(fcx.param_env, *ety, m_cast.ty)
+ {
+ // Due to the limitations of LLVM global constants,
+ // region pointers end up pointing at copies of
+ // vector elements instead of the original values.
+ // To allow raw pointers to work correctly, we
+ // need to special-case obtaining a raw pointer
+ // from a region pointer to a vector.
- // Coerce to a raw pointer so that we generate RawPtr in MIR.
- let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl);
- fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
- .unwrap_or_else(|_| {
- bug!(
+ // Coerce to a raw pointer so that we generate RawPtr in MIR.
+ let array_ptr_type = Ty::new_ptr(fcx.tcx, m_expr.ty, m_expr.mutbl);
+ fcx.coerce(self.expr, self.expr_ty, array_ptr_type, AllowTwoPhase::No, None)
+ .unwrap_or_else(|_| {
+ bug!(
"could not cast from reference to array to pointer to array ({:?} to {:?})",
self.expr_ty,
array_ptr_type,
)
- });
+ });
- // this will report a type mismatch if needed
- fcx.demand_eqtype(self.span, *ety, m_cast.ty);
- return Ok(CastKind::ArrayPtrCast);
- }
+ // this will report a type mismatch if needed
+ fcx.demand_eqtype(self.span, *ety, m_cast.ty);
+ return Ok(CastKind::ArrayPtrCast);
}
Err(CastError::IllegalCast)
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index b8968b5..8fd5999 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -163,7 +163,15 @@ pub(crate) fn check_expr_closure(
// Resume type defaults to `()` if the coroutine has no argument.
let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit);
- let interior = self.next_ty_var(expr_span);
+ // In the new solver, we can just instantiate this eagerly
+ // with the witness. This will ensure that goals that don't need
+ // to stall on interior types will get processed eagerly.
+ let interior = if self.next_trait_solver() {
+ Ty::new_coroutine_witness(tcx, expr_def_id.to_def_id(), parent_args)
+ } else {
+ self.next_ty_var(expr_span)
+ };
+
self.deferred_coroutine_interiors.borrow_mut().push((expr_def_id, interior));
// Coroutines that come from coroutine closures have not yet determined
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index f1571cf4..fd89942 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -103,15 +103,6 @@ fn coerce_mutbls<'tcx>(
if from_mutbl >= to_mutbl { Ok(()) } else { Err(TypeError::Mutability) }
}
-/// Do not require any adjustments, i.e. coerce `x -> x`.
-fn identity(_: Ty<'_>) -> Vec<Adjustment<'_>> {
- vec![]
-}
-
-fn simple<'tcx>(kind: Adjust) -> impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>> {
- move |target| vec![Adjustment { kind, target }]
-}
-
/// This always returns `Ok(...)`.
fn success<'tcx>(
adj: Vec<Adjustment<'tcx>>,
@@ -131,7 +122,7 @@ fn new(
Coerce { fcx, cause, allow_two_phase, use_lub: false, coerce_never }
}
- fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
+ fn unify_raw(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
debug!("unify(a: {:?}, b: {:?}, use_lub: {})", a, b, self.use_lub);
self.commit_if_ok(|_| {
let at = self.at(&self.cause, self.fcx.param_env);
@@ -161,13 +152,30 @@ fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> InferResult<'tcx, Ty<'tcx>> {
})
}
+ /// Unify two types (using sub or lub).
+ fn unify(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
+ self.unify_raw(a, b)
+ .and_then(|InferOk { value: ty, obligations }| success(vec![], ty, obligations))
+ }
+
/// Unify two types (using sub or lub) and produce a specific coercion.
- fn unify_and<F>(&self, a: Ty<'tcx>, b: Ty<'tcx>, f: F) -> CoerceResult<'tcx>
- where
- F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
- {
- self.unify(a, b)
- .and_then(|InferOk { value: ty, obligations }| success(f(ty), ty, obligations))
+ fn unify_and(
+ &self,
+ a: Ty<'tcx>,
+ b: Ty<'tcx>,
+ adjustments: impl IntoIterator<Item = Adjustment<'tcx>>,
+ final_adjustment: Adjust,
+ ) -> CoerceResult<'tcx> {
+ self.unify_raw(a, b).and_then(|InferOk { value: ty, obligations }| {
+ success(
+ adjustments
+ .into_iter()
+ .chain(std::iter::once(Adjustment { target: ty, kind: final_adjustment }))
+ .collect(),
+ ty,
+ obligations,
+ )
+ })
}
#[instrument(skip(self))]
@@ -180,10 +188,14 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
// Coercing from `!` to any type is allowed:
if a.is_never() {
if self.coerce_never {
- return success(simple(Adjust::NeverToAny)(b), b, PredicateObligations::new());
+ return success(
+ vec![Adjustment { kind: Adjust::NeverToAny, target: b }],
+ b,
+ PredicateObligations::new(),
+ );
} else {
// Otherwise the only coercion we can do is unification.
- return self.unify_and(a, b, identity);
+ return self.unify(a, b);
}
}
@@ -191,7 +203,7 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
// we have no information about the source type. This will always
// ultimately fall back to some form of subtyping.
if a.is_ty_var() {
- return self.coerce_from_inference_variable(a, b, identity);
+ return self.coerce_from_inference_variable(a, b);
}
// Consider coercing the subtype to a DST
@@ -247,7 +259,7 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
ty::FnPtr(a_sig_tys, a_hdr) => {
// We permit coercion of fn pointers to drop the
// unsafe qualifier.
- self.coerce_from_fn_pointer(a, a_sig_tys.with(a_hdr), b)
+ self.coerce_from_fn_pointer(a_sig_tys.with(a_hdr), b)
}
ty::Closure(closure_def_id_a, args_a) => {
// Non-capturing closures are coercible to
@@ -257,7 +269,7 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
}
_ => {
// Otherwise, just use unification rules.
- self.unify_and(a, b, identity)
+ self.unify(a, b)
}
}
}
@@ -265,12 +277,7 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
/// Coercing *from* an inference variable. In this case, we have no information
/// about the source type, so we can't really do a true coercion and we always
/// fall back to subtyping (`unify_and`).
- fn coerce_from_inference_variable(
- &self,
- a: Ty<'tcx>,
- b: Ty<'tcx>,
- make_adjustments: impl FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
- ) -> CoerceResult<'tcx> {
+ fn coerce_from_inference_variable(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
debug!("coerce_from_inference_variable(a={:?}, b={:?})", a, b);
assert!(a.is_ty_var() && self.shallow_resolve(a) == a);
assert!(self.shallow_resolve(b) == b);
@@ -298,12 +305,11 @@ fn coerce_from_inference_variable(
"coerce_from_inference_variable: two inference variables, target_ty={:?}, obligations={:?}",
target_ty, obligations
);
- let adjustments = make_adjustments(target_ty);
- InferResult::Ok(InferOk { value: (adjustments, target_ty), obligations })
+ success(vec![], target_ty, obligations)
} else {
// One unresolved type variable: just apply subtyping, we may be able
// to do something useful.
- self.unify_and(a, b, make_adjustments)
+ self.unify(a, b)
}
}
@@ -331,7 +337,7 @@ fn coerce_borrowed_pointer(
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
(r_a, mt_a)
}
- _ => return self.unify_and(a, b, identity),
+ _ => return self.unify(a, b),
};
let span = self.cause.span;
@@ -437,7 +443,7 @@ fn coerce_borrowed_pointer(
referent_ty,
mutbl_b, // [1] above
);
- match self.unify(derefd_ty_a, b) {
+ match self.unify_raw(derefd_ty_a, b) {
Ok(ok) => {
found = Some(ok);
break;
@@ -579,13 +585,13 @@ fn coerce_unsized(&self, mut source: Ty<'tcx>, mut target: Ty<'tcx>) -> CoerceRe
// We only have the latter, so we use an inference variable
// for the former and let type inference do the rest.
let coerce_target = self.next_ty_var(self.cause.span);
- let mut coercion = self.unify_and(coerce_target, target, |target| {
- let unsize = Adjustment { kind: Adjust::Pointer(PointerCoercion::Unsize), target };
- match reborrow {
- None => vec![unsize],
- Some((ref deref, ref autoref)) => vec![deref.clone(), autoref.clone(), unsize],
- }
- })?;
+
+ let mut coercion = self.unify_and(
+ coerce_target,
+ target,
+ reborrow.into_iter().flat_map(|(deref, autoref)| [deref, autoref]),
+ Adjust::Pointer(PointerCoercion::Unsize),
+ )?;
let mut selcx = traits::SelectionContext::new(self);
@@ -708,7 +714,7 @@ fn coerce_dyn_star(
&& let ty::Dynamic(b_data, _, ty::DynStar) = b.kind()
&& a_data.principal_def_id() == b_data.principal_def_id()
{
- return self.unify_and(a, b, |_| vec![]);
+ return self.unify(a, b);
}
// Check the obligations of the cast -- for example, when casting
@@ -808,23 +814,15 @@ fn coerce_pin_ref(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
// To complete the reborrow, we need to make sure we can unify the inner types, and if so we
// add the adjustments.
- self.unify_and(a, b, |_inner_ty| {
- vec![Adjustment { kind: Adjust::ReborrowPin(mut_b), target: b }]
- })
+ self.unify_and(a, b, [], Adjust::ReborrowPin(mut_b))
}
- fn coerce_from_safe_fn<F, G>(
+ fn coerce_from_safe_fn(
&self,
- a: Ty<'tcx>,
fn_ty_a: ty::PolyFnSig<'tcx>,
b: Ty<'tcx>,
- to_unsafe: F,
- normal: G,
- ) -> CoerceResult<'tcx>
- where
- F: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
- G: FnOnce(Ty<'tcx>) -> Vec<Adjustment<'tcx>>,
- {
+ adjustment: Option<Adjust>,
+ ) -> CoerceResult<'tcx> {
self.commit_if_ok(|snapshot| {
let outer_universe = self.infcx.universe();
@@ -833,9 +831,19 @@ fn coerce_from_safe_fn<F, G>(
&& hdr_b.safety.is_unsafe()
{
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
- self.unify_and(unsafe_a, b, to_unsafe)
+ self.unify_and(
+ unsafe_a,
+ b,
+ adjustment
+ .map(|kind| Adjustment { kind, target: Ty::new_fn_ptr(self.tcx, fn_ty_a) }),
+ Adjust::Pointer(PointerCoercion::UnsafeFnPointer),
+ )
} else {
- self.unify_and(a, b, normal)
+ let a = Ty::new_fn_ptr(self.tcx, fn_ty_a);
+ match adjustment {
+ Some(adjust) => self.unify_and(a, b, [], adjust),
+ None => self.unify(a, b),
+ }
};
// FIXME(#73154): This is a hack. Currently LUB can generate
@@ -852,7 +860,6 @@ fn coerce_from_safe_fn<F, G>(
fn coerce_from_fn_pointer(
&self,
- a: Ty<'tcx>,
fn_ty_a: ty::PolyFnSig<'tcx>,
b: Ty<'tcx>,
) -> CoerceResult<'tcx> {
@@ -861,15 +868,9 @@ fn coerce_from_fn_pointer(
//!
let b = self.shallow_resolve(b);
- debug!("coerce_from_fn_pointer(a={:?}, b={:?})", a, b);
+ debug!(?fn_ty_a, ?b, "coerce_from_fn_pointer");
- self.coerce_from_safe_fn(
- a,
- fn_ty_a,
- b,
- simple(Adjust::Pointer(PointerCoercion::UnsafeFnPointer)),
- identity,
- )
+ self.coerce_from_safe_fn(fn_ty_a, b, None)
}
fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
@@ -916,30 +917,16 @@ fn coerce_from_fn_item(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
self.at(&self.cause, self.param_env).normalize(a_sig);
obligations.extend(o1);
- let a_fn_pointer = Ty::new_fn_ptr(self.tcx, a_sig);
let InferOk { value, obligations: o2 } = self.coerce_from_safe_fn(
- a_fn_pointer,
a_sig,
b,
- |unsafe_ty| {
- vec![
- Adjustment {
- kind: Adjust::Pointer(PointerCoercion::ReifyFnPointer),
- target: a_fn_pointer,
- },
- Adjustment {
- kind: Adjust::Pointer(PointerCoercion::UnsafeFnPointer),
- target: unsafe_ty,
- },
- ]
- },
- simple(Adjust::Pointer(PointerCoercion::ReifyFnPointer)),
+ Some(Adjust::Pointer(PointerCoercion::ReifyFnPointer)),
)?;
obligations.extend(o2);
Ok(InferOk { value, obligations })
}
- _ => self.unify_and(a, b, identity),
+ _ => self.unify(a, b),
}
}
@@ -983,10 +970,11 @@ fn coerce_closure_to_fn(
self.unify_and(
pointer_ty,
b,
- simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety))),
+ [],
+ Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety)),
)
}
- _ => self.unify_and(a, b, identity),
+ _ => self.unify(a, b),
}
}
@@ -1001,7 +989,7 @@ fn coerce_raw_ptr(
let (is_ref, mt_a) = match *a.kind() {
ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }),
ty::RawPtr(ty, mutbl) => (false, ty::TypeAndMut { ty, mutbl }),
- _ => return self.unify_and(a, b, identity),
+ _ => return self.unify(a, b),
};
coerce_mutbls(mt_a.mutbl, mutbl_b)?;
@@ -1011,16 +999,16 @@ fn coerce_raw_ptr(
// representation, we still register an Adjust::DerefRef so that
// regionck knows that the region for `a` must be valid here.
if is_ref {
- self.unify_and(a_raw, b, |target| {
- vec![
- Adjustment { kind: Adjust::Deref(None), target: mt_a.ty },
- Adjustment { kind: Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)), target },
- ]
- })
+ self.unify_and(
+ a_raw,
+ b,
+ [Adjustment { kind: Adjust::Deref(None), target: mt_a.ty }],
+ Adjust::Borrow(AutoBorrow::RawPtr(mutbl_b)),
+ )
} else if mt_a.mutbl != mutbl_b {
- self.unify_and(a_raw, b, simple(Adjust::Pointer(PointerCoercion::MutToConstPointer)))
+ self.unify_and(a_raw, b, [], Adjust::Pointer(PointerCoercion::MutToConstPointer))
} else {
- self.unify_and(a_raw, b, identity)
+ self.unify(a_raw, b)
}
}
}
@@ -1118,9 +1106,9 @@ pub(crate) fn deref_steps_for_suggestion(
let cause = self.cause(DUMMY_SP, ObligationCauseCode::ExprAssignable);
// We don't ever need two-phase here since we throw out the result of the coercion.
let coerce = Coerce::new(self, cause, AllowTwoPhase::No, true);
- coerce
- .autoderef(DUMMY_SP, expr_ty)
- .find_map(|(ty, steps)| self.probe(|_| coerce.unify(ty, target)).ok().map(|_| steps))
+ coerce.autoderef(DUMMY_SP, expr_ty).find_map(|(ty, steps)| {
+ self.probe(|_| coerce.unify_raw(ty, target)).ok().map(|_| steps)
+ })
}
/// Given a type, this function will calculate and return the type given
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index fec4599..d1bc54e 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -1089,14 +1089,8 @@ pub(crate) fn get_conversion_methods_for_diagnostic(
/// This function checks whether the method is not static and does not accept other parameters than `self`.
fn has_only_self_parameter(&self, method: &AssocItem) -> bool {
- match method.kind {
- ty::AssocKind::Fn => {
- method.fn_has_self_parameter
- && self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len()
- == 1
- }
- _ => false,
- }
+ method.is_method()
+ && self.tcx.fn_sig(method.def_id).skip_binder().inputs().skip_binder().len() == 1
}
/// If the given `HirId` corresponds to a block with a trailing expression, return that expression
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index dfaa374..9e73054 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -5,7 +5,7 @@
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagArgValue, DiagSymbolList, EmissionGuarantee, IntoDiagArg, MultiSpan,
- SubdiagMessageOp, Subdiagnostic,
+ Subdiagnostic,
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{self, Ty};
@@ -270,11 +270,7 @@ pub(crate) struct SuggestAnnotations {
pub suggestions: Vec<SuggestAnnotation>,
}
impl Subdiagnostic for SuggestAnnotations {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
if self.suggestions.is_empty() {
return;
}
@@ -337,11 +333,7 @@ pub(crate) struct TypeMismatchFruTypo {
}
impl Subdiagnostic for TypeMismatchFruTypo {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("expr", self.expr.as_deref().unwrap_or("NONE"));
// Only explain that `a ..b` is a range if it's split up
@@ -599,11 +591,7 @@ pub(crate) struct RemoveSemiForCoerce {
}
impl Subdiagnostic for RemoveSemiForCoerce {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut multispan: MultiSpan = self.semi.into();
multispan.push_span_label(self.expr, fluent::hir_typeck_remove_semi_for_coerce_expr);
multispan.push_span_label(self.ret, fluent::hir_typeck_remove_semi_for_coerce_ret);
@@ -778,20 +766,16 @@ pub(crate) enum CastUnknownPointerSub {
}
impl rustc_errors::Subdiagnostic for CastUnknownPointerSub {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
match self {
CastUnknownPointerSub::To(span) => {
- let msg = f(diag, crate::fluent_generated::hir_typeck_label_to);
+ let msg = diag.eagerly_translate(fluent::hir_typeck_label_to);
diag.span_label(span, msg);
- let msg = f(diag, crate::fluent_generated::hir_typeck_note);
+ let msg = diag.eagerly_translate(fluent::hir_typeck_note);
diag.note(msg);
}
CastUnknownPointerSub::From(span) => {
- let msg = f(diag, crate::fluent_generated::hir_typeck_label_from);
+ let msg = diag.eagerly_translate(fluent::hir_typeck_label_from);
diag.span_label(span, msg);
}
}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index de2f039..9c6d4ee 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1600,11 +1600,7 @@ fn check_expr_method_call(
Ok(method)
}
Err(error) => {
- if segment.ident.name == kw::Empty {
- span_bug!(rcvr.span, "empty method name")
- } else {
- Err(self.report_method_error(expr.hir_id, rcvr_t, error, expected, false))
- }
+ Err(self.report_method_error(expr.hir_id, rcvr_t, error, expected, false))
}
};
@@ -2588,9 +2584,7 @@ fn report_private_fields(
.into_iter()
.flat_map(|i| self.tcx.associated_items(i).in_definition_order())
// Only assoc fn with no receivers.
- .filter(|item| {
- matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter
- })
+ .filter(|item| item.is_fn() && !item.is_method())
.filter_map(|item| {
// Only assoc fns that return `Self`
let fn_sig = self.tcx.fn_sig(item.def_id).skip_binder();
@@ -2603,8 +2597,9 @@ fn report_private_fields(
return None;
}
let input_len = fn_sig.inputs().skip_binder().len();
- let order = !item.name.as_str().starts_with("new");
- Some((order, item.name, input_len))
+ let name = item.name();
+ let order = !name.as_str().starts_with("new");
+ Some((order, name, input_len))
})
.collect::<Vec<_>>();
items.sort_by_key(|(order, _, _)| *order);
@@ -2942,9 +2937,7 @@ fn check_expr_field(
return Ty::new_error(self.tcx(), guar);
}
- let guar = if field.name == kw::Empty {
- self.dcx().span_bug(field.span, "field name with no name")
- } else if self.method_exists_for_diagnostic(
+ let guar = if self.method_exists_for_diagnostic(
field,
base_ty,
expr.hir_id,
@@ -3296,8 +3289,8 @@ fn suggest_first_deref_field(&self, err: &mut Diag<'_>, base: &hir::Expr<'_>, fi
err.multipart_suggestion(
format!("{val} is a raw pointer; try dereferencing it"),
vec![
- (base.span.shrink_to_lo(), "(*".to_string()),
- (base.span.shrink_to_hi(), ")".to_string()),
+ (base.span.shrink_to_lo(), "(*".into()),
+ (base.span.between(field.span), format!(").")),
],
Applicability::MaybeIncorrect,
);
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 27df8f0..f5e0f01 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -1000,6 +1000,8 @@ fn walk_pat(
// determines whether to borrow *at the level of the deref pattern* rather than
// borrowing the bound place (since that inner place is inside the temporary that
// stores the result of calling `deref()`/`deref_mut()` so can't be captured).
+ // HACK: this could be a fake pattern corresponding to a deref inserted by match
+ // ergonomics, in which case `pat.hir_id` will be the id of the subpattern.
let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpattern);
let mutability =
if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
@@ -1227,9 +1229,9 @@ fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> Result<Ty<'tcx>, Cx::Error> {
// actually this is somewhat "disjoint" from the code below
// that aims to account for `ref x`.
if let Some(vec) = self.cx.typeck_results().pat_adjustments().get(pat.hir_id) {
- if let Some(first_ty) = vec.first() {
- debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty);
- return Ok(*first_ty);
+ if let Some(first_adjust) = vec.first() {
+ debug!("pat_ty(pat={:?}) found adjustment `{:?}`", pat, first_adjust);
+ return Ok(first_adjust.source);
}
} else if let PatKind::Ref(subpat, _) = pat.kind
&& self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id)
@@ -1502,16 +1504,21 @@ fn cat_projection(
let mut projections = base_place.place.projections;
let node_ty = self.cx.typeck_results().node_type(node);
- // Opaque types can't have field projections, but we can instead convert
- // the current place in-place (heh) to the hidden type, and then apply all
- // follow up projections on that.
- if node_ty != place_ty
- && self
- .cx
- .try_structurally_resolve_type(self.cx.tcx().hir_span(base_place.hir_id), place_ty)
- .is_impl_trait()
- {
- projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
+ if !self.cx.tcx().next_trait_solver_globally() {
+ // Opaque types can't have field projections, but we can instead convert
+ // the current place in-place (heh) to the hidden type, and then apply all
+ // follow up projections on that.
+ if node_ty != place_ty
+ && self
+ .cx
+ .try_structurally_resolve_type(
+ self.cx.tcx().hir_span(base_place.hir_id),
+ place_ty,
+ )
+ .is_impl_trait()
+ {
+ projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
+ }
}
projections.push(Projection { kind, ty });
PlaceWithHirId::new(node, base_place.place.base_ty, base_place.place.base, projections)
@@ -1675,12 +1682,31 @@ fn cat_pattern<F>(
// Then we see that to get the same result, we must start with
// `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
// and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
- for _ in
- 0..self.cx.typeck_results().pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len())
- {
+ let typeck_results = self.cx.typeck_results();
+ let adjustments: &[adjustment::PatAdjustment<'tcx>] =
+ typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
+ let mut adjusts = adjustments.iter().peekable();
+ while let Some(adjust) = adjusts.next() {
debug!("applying adjustment to place_with_id={:?}", place_with_id);
- place_with_id = self.cat_deref(pat.hir_id, place_with_id)?;
+ place_with_id = match adjust.kind {
+ adjustment::PatAdjust::BuiltinDeref => self.cat_deref(pat.hir_id, place_with_id)?,
+ adjustment::PatAdjust::OverloadedDeref => {
+ // This adjustment corresponds to an overloaded deref; it borrows the scrutinee to
+ // call `Deref::deref` or `DerefMut::deref_mut`. Invoke the callback before setting
+ // `place_with_id` to the temporary storing the result of the deref.
+ // HACK(dianne): giving the callback a fake deref pattern makes sure it behaves the
+ // same as it would if this were an explicit deref pattern.
+ op(&place_with_id, &hir::Pat { kind: PatKind::Deref(pat), ..*pat })?;
+ let target_ty = match adjusts.peek() {
+ Some(&&next_adjust) => next_adjust.source,
+ // At the end of the deref chain, we get `pat`'s scrutinee.
+ None => self.pat_ty_unadjusted(pat)?,
+ };
+ self.pat_deref_temp(pat.hir_id, pat, target_ty)?
+ }
+ };
}
+ drop(typeck_results); // explicitly release borrow of typeck results, just in case.
let place_with_id = place_with_id; // lose mutability
debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id);
@@ -1783,14 +1809,8 @@ fn cat_pattern<F>(
self.cat_pattern(subplace, subpat, op)?;
}
PatKind::Deref(subpat) => {
- let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpat);
- let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
- let re_erased = self.cx.tcx().lifetimes.re_erased;
let ty = self.pat_ty_adjusted(subpat)?;
- let ty = Ty::new_ref(self.cx.tcx(), re_erased, ty, mutability);
- // A deref pattern generates a temporary.
- let base = self.cat_rvalue(pat.hir_id, ty);
- let place = self.cat_deref(pat.hir_id, base)?;
+ let place = self.pat_deref_temp(pat.hir_id, subpat, ty)?;
self.cat_pattern(place, subpat, op)?;
}
@@ -1843,6 +1863,23 @@ fn cat_pattern<F>(
Ok(())
}
+ /// Represents the place of the temp that stores the scrutinee of a deref pattern's interior.
+ fn pat_deref_temp(
+ &self,
+ hir_id: HirId,
+ inner: &hir::Pat<'_>,
+ target_ty: Ty<'tcx>,
+ ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
+ let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(inner);
+ let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
+ let re_erased = self.cx.tcx().lifetimes.re_erased;
+ let ty = Ty::new_ref(self.cx.tcx(), re_erased, target_ty, mutability);
+ // A deref pattern stores the result of `Deref::deref` or `DerefMut::deref_mut` ...
+ let base = self.cat_rvalue(hir_id, ty);
+ // ... and the inner pattern matches on the place behind that reference.
+ self.cat_deref(hir_id, base)
+ }
+
fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool {
if let ty::Adt(def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() {
// Note that if a non-exhaustive SingleVariant is defined in another crate, we need
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 91190a3..cac8237 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -27,9 +27,9 @@
};
use rustc_middle::{bug, span_bug};
use rustc_session::lint;
+use rustc_span::Span;
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
-use rustc_span::{Span, kw};
use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded;
use rustc_trait_selection::traits::{
self, NormalizeExt, ObligationCauseCode, StructurallyNormalizeExt,
@@ -635,34 +635,39 @@ pub(crate) fn resolve_coroutine_interiors(&self) {
let mut obligations = vec![];
- for &(coroutine_def_id, interior) in coroutines.iter() {
- debug!(?coroutine_def_id);
+ if !self.next_trait_solver() {
+ for &(coroutine_def_id, interior) in coroutines.iter() {
+ debug!(?coroutine_def_id);
- // Create the `CoroutineWitness` type that we will unify with `interior`.
- let args = ty::GenericArgs::identity_for_item(
- self.tcx,
- self.tcx.typeck_root_def_id(coroutine_def_id.to_def_id()),
- );
- let witness = Ty::new_coroutine_witness(self.tcx, coroutine_def_id.to_def_id(), args);
+ // Create the `CoroutineWitness` type that we will unify with `interior`.
+ let args = ty::GenericArgs::identity_for_item(
+ self.tcx,
+ self.tcx.typeck_root_def_id(coroutine_def_id.to_def_id()),
+ );
+ let witness =
+ Ty::new_coroutine_witness(self.tcx, coroutine_def_id.to_def_id(), args);
- // Unify `interior` with `witness` and collect all the resulting obligations.
- let span = self.tcx.hir_body_owned_by(coroutine_def_id).value.span;
- let ty::Infer(ty::InferTy::TyVar(_)) = interior.kind() else {
- span_bug!(span, "coroutine interior witness not infer: {:?}", interior.kind())
- };
- let ok = self
- .at(&self.misc(span), self.param_env)
- // Will never define opaque types, as all we do is instantiate a type variable.
- .eq(DefineOpaqueTypes::Yes, interior, witness)
- .expect("Failed to unify coroutine interior type");
+ // Unify `interior` with `witness` and collect all the resulting obligations.
+ let span = self.tcx.hir_body_owned_by(coroutine_def_id).value.span;
+ let ty::Infer(ty::InferTy::TyVar(_)) = interior.kind() else {
+ span_bug!(span, "coroutine interior witness not infer: {:?}", interior.kind())
+ };
+ let ok = self
+ .at(&self.misc(span), self.param_env)
+ // Will never define opaque types, as all we do is instantiate a type variable.
+ .eq(DefineOpaqueTypes::Yes, interior, witness)
+ .expect("Failed to unify coroutine interior type");
- obligations.extend(ok.obligations);
+ obligations.extend(ok.obligations);
+ }
}
- // FIXME: Use a real visitor for unstalled obligations in the new solver.
if !coroutines.is_empty() {
- obligations
- .extend(self.fulfillment_cx.borrow_mut().drain_unstalled_obligations(&self.infcx));
+ obligations.extend(
+ self.fulfillment_cx
+ .borrow_mut()
+ .drain_stalled_obligations_for_coroutines(&self.infcx),
+ );
}
self.typeck_results
@@ -833,7 +838,6 @@ pub(crate) fn resolve_ty_and_res_fully_qualified_call(
let trait_missing_method =
matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait();
- assert_ne!(item_name.name, kw::Empty);
self.report_method_error(
hir_id,
ty.normalized,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 81eb851..8b2d9ab 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -616,7 +616,7 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
if let Some((DefKind::AssocFn, def_id)) =
self.typeck_results.borrow().type_dependent_def(call_expr.hir_id)
&& let Some(assoc) = tcx.opt_associated_item(def_id)
- && assoc.fn_has_self_parameter
+ && assoc.is_method()
{
Some(*receiver)
} else {
@@ -642,8 +642,7 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
TraitsInScope,
|mut ctxt| ctxt.probe_for_similar_candidate(),
)
- && let ty::AssocKind::Fn = assoc.kind
- && assoc.fn_has_self_parameter
+ && assoc.is_method()
{
let args = self.infcx.fresh_args_for_item(call_name.span, assoc.def_id);
let fn_sig = tcx.fn_sig(assoc.def_id).instantiate(tcx, args);
@@ -684,10 +683,11 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
.all(|(expected, found)| self.may_coerce(*expected, *found))
&& fn_sig.inputs()[1..].len() == input_types.len()
{
+ let assoc_name = assoc.name();
err.span_suggestion_verbose(
call_name.span,
- format!("you might have meant to use `{}`", assoc.name),
- assoc.name,
+ format!("you might have meant to use `{}`", assoc_name),
+ assoc_name,
Applicability::MaybeIncorrect,
);
return;
@@ -707,7 +707,7 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
tcx.def_span(assoc.def_id),
format!(
"there's is a method with similar name `{}`, but the arguments don't match",
- assoc.name,
+ assoc.name(),
),
);
return;
@@ -719,7 +719,7 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
format!(
"there's is a method with similar name `{}`, but their argument count \
doesn't match",
- assoc.name,
+ assoc.name(),
),
);
return;
@@ -925,7 +925,7 @@ fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool {
let detect_dotdot = |err: &mut Diag<'_>, ty: Ty<'_>, expr: &hir::Expr<'_>| {
if let ty::Adt(adt, _) = ty.kind()
- && self.tcx().lang_items().get(hir::LangItem::RangeFull) == Some(adt.did())
+ && self.tcx().is_lang_item(adt.did(), hir::LangItem::RangeFull)
&& let hir::ExprKind::Struct(
hir::QPath::LangItem(hir::LangItem::RangeFull, _),
[],
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index e14f152..934820e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -314,7 +314,7 @@ fn lower_assoc_shared(
item_def_id: DefId,
item_segment: &rustc_hir::PathSegment<'tcx>,
poly_trait_ref: ty::PolyTraitRef<'tcx>,
- _kind: ty::AssocKind,
+ _assoc_tag: ty::AssocTag,
) -> Result<(DefId, ty::GenericArgsRef<'tcx>), ErrorGuaranteed> {
let trait_ref = self.instantiate_binder_with_fresh_vars(
span,
@@ -488,7 +488,7 @@ fn parse_never_type_options_attr(
item.span(),
format!(
"unknown or duplicate never type option: `{}` (supported: `fallback`, `diverging_block_default`)",
- item.name_or_empty()
+ item.name().unwrap()
),
);
}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 912098c..91eb198 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -381,9 +381,10 @@ pub(crate) fn suggest_deref_ref_or_into(
let mut suggestions = methods
.iter()
.filter_map(|conversion_method| {
+ let conversion_method_name = conversion_method.name();
let receiver_method_ident = expr.method_ident();
if let Some(method_ident) = receiver_method_ident
- && method_ident.name == conversion_method.name
+ && method_ident.name == conversion_method_name
{
return None; // do not suggest code that is already there (#53348)
}
@@ -391,20 +392,20 @@ pub(crate) fn suggest_deref_ref_or_into(
let method_call_list = [sym::to_vec, sym::to_string];
let mut sugg = if let ExprKind::MethodCall(receiver_method, ..) = expr.kind
&& receiver_method.ident.name == sym::clone
- && method_call_list.contains(&conversion_method.name)
+ && method_call_list.contains(&conversion_method_name)
// If receiver is `.clone()` and found type has one of those methods,
// we guess that the user wants to convert from a slice type (`&[]` or `&str`)
// to an owned type (`Vec` or `String`). These conversions clone internally,
// so we remove the user's `clone` call.
{
- vec![(receiver_method.ident.span, conversion_method.name.to_string())]
+ vec![(receiver_method.ident.span, conversion_method_name.to_string())]
} else if expr.precedence() < ExprPrecedence::Unambiguous {
vec![
(expr.span.shrink_to_lo(), "(".to_string()),
- (expr.span.shrink_to_hi(), format!(").{}()", conversion_method.name)),
+ (expr.span.shrink_to_hi(), format!(").{}()", conversion_method_name)),
]
} else {
- vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method.name))]
+ vec![(expr.span.shrink_to_hi(), format!(".{}()", conversion_method_name))]
};
let struct_pat_shorthand_field =
self.tcx.hir_maybe_get_struct_pattern_shorthand_field(expr);
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 1d86ff1..af8ec37 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -1,7 +1,6 @@
// tidy-alphabetical-start
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(array_windows)]
#![feature(box_patterns)]
#![feature(if_let_guard)]
@@ -266,7 +265,7 @@ fn infer_type_if_missing<'tcx>(fcx: &FnCtxt<'_, 'tcx>, node: Node<'tcx>) -> Opti
let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer(()), span, .. }) = node.ty()
{
if let Some(item) = tcx.opt_associated_item(def_id.into())
- && let ty::AssocKind::Const = item.kind
+ && let ty::AssocKind::Const { .. } = item.kind
&& let ty::AssocItemContainer::Impl = item.container
&& let Some(trait_item_def_id) = item.trait_item_def_id
{
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index ddfd27c..1b67e23 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -379,7 +379,7 @@ pub(super) fn lookup_method_in_trait(
};
let def_id = method_item.def_id;
- if method_item.kind != ty::AssocKind::Fn {
+ if !method_item.is_fn() {
span_bug!(tcx.def_span(def_id), "expected `{m_name}` to be an associated function");
}
@@ -529,7 +529,7 @@ pub(crate) fn resolve_fully_qualified_call(
}
}
- let def_kind = pick.item.kind.as_def_kind();
+ let def_kind = pick.item.as_def_kind();
tcx.check_stability(pick.item.def_id, Some(expr_id), span, Some(method_name.span));
Ok((def_kind, pick.item.def_id))
}
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 0a01ec8..1d3a081 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -992,7 +992,7 @@ fn assemble_extension_candidates_for_all_traits(&mut self) {
fn matches_return_type(&self, method: ty::AssocItem, expected: Ty<'tcx>) -> bool {
match method.kind {
- ty::AssocKind::Fn => self.probe(|_| {
+ ty::AssocKind::Fn { .. } => self.probe(|_| {
let args = self.fresh_args_for_item(self.span, method.def_id);
let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args);
let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty);
@@ -1583,7 +1583,7 @@ fn pick_method(
},
None,
) {
- self.private_candidate.set(Some((pick.item.kind.as_def_kind(), pick.item.def_id)));
+ self.private_candidate.set(Some((pick.item.as_def_kind(), pick.item.def_id)));
}
}
None
@@ -1671,16 +1671,7 @@ impl<'tcx> Pick<'tcx> {
/// Do not use for type checking.
pub(crate) fn differs_from(&self, other: &Self) -> bool {
let Self {
- item:
- AssocItem {
- def_id,
- name: _,
- kind: _,
- container: _,
- trait_item_def_id: _,
- fn_has_self_parameter: _,
- opt_rpitit_info: _,
- },
+ item: AssocItem { def_id, kind: _, container: _, trait_item_def_id: _ },
kind: _,
import_ids: _,
autoderefs: _,
@@ -1703,7 +1694,7 @@ pub(crate) fn maybe_emit_unstable_name_collision_hint(
if self.unstable_candidates.is_empty() {
return;
}
- let def_kind = self.item.kind.as_def_kind();
+ let def_kind = self.item.as_def_kind();
tcx.node_span_lint(lint::builtin::UNSTABLE_NAME_COLLISIONS, scope_expr_id, span, |lint| {
lint.primary_message(format!(
"{} {} with this name may be added to the standard library in the future",
@@ -1712,7 +1703,7 @@ pub(crate) fn maybe_emit_unstable_name_collision_hint(
));
match (self.item.kind, self.item.container) {
- (ty::AssocKind::Fn, _) => {
+ (ty::AssocKind::Fn { .. }, _) => {
// FIXME: This should be a `span_suggestion` instead of `help`
// However `self.span` only
// highlights the method name, so we can't use it. Also consider reusing
@@ -1723,17 +1714,12 @@ pub(crate) fn maybe_emit_unstable_name_collision_hint(
tcx.def_path_str(self.item.def_id),
));
}
- (ty::AssocKind::Const, ty::AssocItemContainer::Trait) => {
+ (ty::AssocKind::Const { name }, ty::AssocItemContainer::Trait) => {
let def_id = self.item.container_id(tcx);
lint.span_suggestion(
span,
"use the fully qualified path to the associated const",
- format!(
- "<{} as {}>::{}",
- self.self_ty,
- tcx.def_path_str(def_id),
- self.item.name
- ),
+ format!("<{} as {}>::{}", self.self_ty, tcx.def_path_str(def_id), name),
Applicability::MachineApplicable,
);
}
@@ -2222,7 +2208,7 @@ pub(crate) fn probe_for_similar_candidate(
let best_name = {
let names = applicable_close_candidates
.iter()
- .map(|cand| cand.name)
+ .map(|cand| cand.name())
.collect::<Vec<Symbol>>();
find_best_match_for_name_with_substrings(
&names,
@@ -2234,10 +2220,12 @@ pub(crate) fn probe_for_similar_candidate(
applicable_close_candidates
.iter()
.find(|cand| self.matches_by_doc_alias(cand.def_id))
- .map(|cand| cand.name)
+ .map(|cand| cand.name())
});
Ok(best_name.and_then(|best_name| {
- applicable_close_candidates.into_iter().find(|method| method.name == best_name)
+ applicable_close_candidates
+ .into_iter()
+ .find(|method| method.name() == best_name)
}))
}
})
@@ -2252,10 +2240,10 @@ fn has_applicable_self(&self, item: &ty::AssocItem) -> bool {
// In Path mode (i.e., resolving a value like `T::next`), consider any
// associated value (i.e., methods, constants) but not types.
match self.mode {
- Mode::MethodCall => item.fn_has_self_parameter,
+ Mode::MethodCall => item.is_method(),
Mode::Path => match item.kind {
- ty::AssocKind::Type => false,
- ty::AssocKind::Fn | ty::AssocKind::Const => true,
+ ty::AssocKind::Type { .. } => false,
+ ty::AssocKind::Fn { .. } | ty::AssocKind::Const { .. } => true,
},
}
// FIXME -- check for types that deref to `Self`,
@@ -2277,7 +2265,7 @@ fn xform_self_ty(
impl_ty: Ty<'tcx>,
args: GenericArgsRef<'tcx>,
) -> (Ty<'tcx>, Option<Ty<'tcx>>) {
- if item.kind == ty::AssocKind::Fn && self.mode == Mode::MethodCall {
+ if item.is_fn() && self.mode == Mode::MethodCall {
let sig = self.xform_method_sig(item.def_id, args);
(sig.inputs()[0], Some(sig.output()))
} else {
@@ -2328,8 +2316,8 @@ fn xform_method_sig(&self, method: DefId, args: GenericArgsRef<'tcx>) -> ty::FnS
/// Determine if the given associated item type is relevant in the current context.
fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool {
match (self.mode, kind) {
- (Mode::MethodCall, ty::AssocKind::Fn) => true,
- (Mode::Path, ty::AssocKind::Const | ty::AssocKind::Fn) => true,
+ (Mode::MethodCall, ty::AssocKind::Fn { .. }) => true,
+ (Mode::Path, ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. }) => true,
_ => false,
}
}
@@ -2346,8 +2334,9 @@ fn matches_by_doc_alias(&self, def_id: DefId) -> bool {
let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id);
let attrs = self.fcx.tcx.hir_attrs(hir_id);
for attr in attrs {
- if sym::doc == attr.name_or_empty() {
- } else if sym::rustc_confusables == attr.name_or_empty() {
+ if attr.has_name(sym::doc) {
+ // do nothing
+ } else if attr.has_name(sym::rustc_confusables) {
let Some(confusables) = attr.meta_item_list() else {
continue;
};
@@ -2367,7 +2356,7 @@ fn matches_by_doc_alias(&self, def_id: DefId) -> bool {
continue;
};
for v in values {
- if v.name_or_empty() != sym::alias {
+ if !v.has_name(sym::alias) {
continue;
}
if let Some(nested) = v.meta_item_list() {
@@ -2411,7 +2400,7 @@ fn matches_by_doc_alias(&self, def_id: DefId) -> bool {
}
match edit_distance_with_substrings(
name.as_str(),
- x.name.as_str(),
+ x.name().as_str(),
max_dist,
) {
Some(d) => d > 0,
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 68f13d6..6a9fd7c 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -713,7 +713,7 @@ fn report_no_match_method_error(
&& let Some(candidate) = tcx.associated_items(impl_def_id).find_by_ident_and_kind(
self.tcx,
item_ident,
- ty::AssocKind::Type,
+ ty::AssocTag::Type,
impl_def_id,
)
&& let Some(adt_def) = tcx.type_of(candidate.def_id).skip_binder().ty_adt_def()
@@ -1442,7 +1442,7 @@ fn report_no_match_method_error(
if let Some(assoc) = self.associated_value(*def_id, item_ident) {
// Check for both mode is the same so we avoid suggesting
// incorrect associated item.
- match (mode, assoc.fn_has_self_parameter, source) {
+ match (mode, assoc.is_method(), source) {
(Mode::MethodCall, true, SelfSource::MethodCall(_)) => {
// We check that the suggest type is actually
// different from the received one
@@ -1722,7 +1722,7 @@ fn report_no_match_method_error(
// that had unsatisfied trait bounds
if unsatisfied_predicates.is_empty()
// ...or if we already suggested that name because of `rustc_confusable` annotation.
- && Some(similar_candidate.name) != confusable_suggested
+ && Some(similar_candidate.name()) != confusable_suggested
{
self.find_likely_intended_associated_item(
&mut err,
@@ -1819,12 +1819,13 @@ fn find_likely_intended_associated_item(
mode: Mode,
) {
let tcx = self.tcx;
- let def_kind = similar_candidate.kind.as_def_kind();
+ let def_kind = similar_candidate.as_def_kind();
let an = self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id);
+ let similar_candidate_name = similar_candidate.name();
let msg = format!(
"there is {an} {} `{}` with a similar name",
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id),
- similar_candidate.name,
+ similar_candidate_name,
);
// Methods are defined within the context of a struct and their first parameter
// is always `self`, which represents the instance of the struct the method is
@@ -1834,7 +1835,7 @@ fn find_likely_intended_associated_item(
let ty_args = self.infcx.fresh_args_for_item(span, similar_candidate.def_id);
let fn_sig = tcx.fn_sig(similar_candidate.def_id).instantiate(tcx, ty_args);
let fn_sig = self.instantiate_binder_with_fresh_vars(span, infer::FnCall, fn_sig);
- if similar_candidate.fn_has_self_parameter {
+ if similar_candidate.is_method() {
if let Some(args) = args
&& fn_sig.inputs()[1..].len() == args.len()
{
@@ -1843,7 +1844,7 @@ fn find_likely_intended_associated_item(
err.span_suggestion_verbose(
span,
msg,
- similar_candidate.name,
+ similar_candidate_name,
Applicability::MaybeIncorrect,
);
} else {
@@ -1865,7 +1866,7 @@ fn find_likely_intended_associated_item(
err.span_suggestion_verbose(
span,
msg,
- similar_candidate.name,
+ similar_candidate_name,
Applicability::MaybeIncorrect,
);
} else {
@@ -1878,7 +1879,7 @@ fn find_likely_intended_associated_item(
err.span_suggestion_verbose(
span,
msg,
- similar_candidate.name,
+ similar_candidate_name,
Applicability::MaybeIncorrect,
);
} else {
@@ -1902,7 +1903,7 @@ pub(crate) fn confusable_method_name(
{
if let Some(candidates) = find_attr!(self.tcx.get_all_attrs(inherent_method.def_id), AttributeKind::Confusables{symbols, ..} => symbols)
&& candidates.contains(&item_name.name)
- && let ty::AssocKind::Fn = inherent_method.kind
+ && inherent_method.is_fn()
{
let args =
ty::GenericArgs::identity_for_item(self.tcx, inherent_method.def_id)
@@ -1918,6 +1919,7 @@ pub(crate) fn confusable_method_name(
infer::FnCall,
fn_sig,
);
+ let name = inherent_method.name();
if let Some(ref args) = call_args
&& fn_sig.inputs()[1..]
.iter()
@@ -1927,20 +1929,17 @@ pub(crate) fn confusable_method_name(
{
err.span_suggestion_verbose(
item_name.span,
- format!("you might have meant to use `{}`", inherent_method.name),
- inherent_method.name,
+ format!("you might have meant to use `{}`", name),
+ name,
Applicability::MaybeIncorrect,
);
- return Some(inherent_method.name);
+ return Some(name);
} else if let None = call_args {
err.span_note(
self.tcx.def_span(inherent_method.def_id),
- format!(
- "you might have meant to use method `{}`",
- inherent_method.name,
- ),
+ format!("you might have meant to use method `{}`", name),
);
- return Some(inherent_method.name);
+ return Some(name);
}
}
}
@@ -2116,8 +2115,7 @@ fn find_builder_fn(&self, err: &mut Diag<'_>, rcvr_ty: Ty<'tcx>, expr_id: hir::H
// Only assoc fn with no receivers and only if
// they are resolvable
.filter(|item| {
- matches!(item.kind, ty::AssocKind::Fn)
- && !item.fn_has_self_parameter
+ matches!(item.kind, ty::AssocKind::Fn { has_self: false, .. })
&& self
.probe_for_name(
Mode::Path,
@@ -2261,7 +2259,7 @@ fn suggest_associated_call_syntax(
};
let assoc = self.associated_value(assoc_did, item_name)?;
- if assoc.kind != ty::AssocKind::Fn {
+ if !assoc.is_fn() {
return None;
}
@@ -3208,7 +3206,7 @@ fn note_derefed_ty_has_method(
// If this method receives `&self`, then the provided
// argument _should_ coerce, so it's valid to suggest
// just changing the path.
- && pick.item.fn_has_self_parameter
+ && pick.item.is_method()
&& let Some(self_ty) =
self.tcx.fn_sig(pick.item.def_id).instantiate_identity().inputs().skip_binder().get(0)
&& self_ty.is_ref()
@@ -3560,7 +3558,7 @@ fn suggest_traits_to_import(
|| (("Pin::new" == *pre)
&& ((sym::as_ref == item_name.name) || !unpin))
|| inputs_len.is_some_and(|inputs_len| {
- pick.item.kind == ty::AssocKind::Fn
+ pick.item.is_fn()
&& self
.tcx
.fn_sig(pick.item.def_id)
@@ -3618,7 +3616,7 @@ fn suggest_traits_to_import(
&& pick.autoderefs == 0
// Check that the method of the same name that was found on the new `Pin<T>`
// receiver has the same number of arguments that appear in the user's code.
- && inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len)
+ && inputs_len.is_some_and(|inputs_len| pick.item.is_fn() && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() == inputs_len)
{
let indent = self
.tcx
@@ -3756,7 +3754,7 @@ fn suggest_traits_to_import(
&& self
.associated_value(info.def_id, item_name)
.filter(|item| {
- if let ty::AssocKind::Fn = item.kind {
+ if item.is_fn() {
let id = item
.def_id
.as_local()
@@ -4279,17 +4277,17 @@ fn print_disambiguation_help<'tcx>(
item: ty::AssocItem,
) -> Option<String> {
let trait_impl_type = trait_ref.self_ty().peel_refs();
- let trait_ref = if item.fn_has_self_parameter {
+ let trait_ref = if item.is_method() {
trait_ref.print_only_trait_name().to_string()
} else {
format!("<{} as {}>", trait_ref.args[0], trait_ref.print_only_trait_name())
};
Some(
- if matches!(item.kind, ty::AssocKind::Fn)
+ if item.is_fn()
&& let SelfSource::MethodCall(receiver) = source
&& let Some(args) = args
{
- let def_kind_descr = tcx.def_kind_descr(item.kind.as_def_kind(), item.def_id);
+ let def_kind_descr = tcx.def_kind_descr(item.as_def_kind(), item.def_id);
let item_name = item.ident(tcx);
let first_input =
tcx.fn_sig(item.def_id).instantiate_identity().skip_binder().inputs().get(0);
@@ -4304,7 +4302,7 @@ fn print_disambiguation_help<'tcx>(
let args = if let Some(first_arg_type) = first_arg_type
&& (first_arg_type == tcx.types.self_param
|| first_arg_type == trait_impl_type
- || item.fn_has_self_parameter)
+ || item.is_method())
{
Some(receiver)
} else {
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 93f77b8..b86991f 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -234,7 +234,6 @@ fn check_overloaded_binop(
// us do better coercions than we would be able to do otherwise,
// particularly for things like `String + &String`.
let rhs_ty_var = self.next_ty_var(rhs_expr.span);
-
let result = self.lookup_op_method(
(lhs_expr, lhs_ty),
Some((rhs_expr, rhs_ty_var)),
@@ -372,7 +371,7 @@ fn check_overloaded_binop(
.associated_item_def_ids(def_id)
.iter()
.find(|item_def_id| {
- self.tcx.associated_item(*item_def_id).name == sym::Output
+ self.tcx.associated_item(*item_def_id).name() == sym::Output
})
.cloned()
});
@@ -698,6 +697,57 @@ fn check_overloaded_binop(
}
}
+ let lhs_name_str = match lhs_expr.kind {
+ hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => {
+ path.segments.last().map_or("_".to_string(), |s| s.ident.to_string())
+ }
+ _ => self
+ .tcx
+ .sess
+ .source_map()
+ .span_to_snippet(lhs_expr.span)
+ .unwrap_or("_".to_string()),
+ };
+
+ if op.span().can_be_used_for_suggestions() {
+ match op {
+ Op::AssignOp(Spanned { node: hir::AssignOpKind::AddAssign, .. })
+ if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() =>
+ {
+ err.multipart_suggestion(
+ "consider using `add` or `wrapping_add` to do pointer arithmetic",
+ vec![
+ (lhs_expr.span.shrink_to_lo(), format!("{} = ", lhs_name_str)),
+ (
+ lhs_expr.span.between(rhs_expr.span),
+ ".wrapping_add(".to_owned(),
+ ),
+ (rhs_expr.span.shrink_to_hi(), ")".to_owned()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ Op::AssignOp(Spanned { node: hir::AssignOpKind::SubAssign, .. }) => {
+ if lhs_ty.is_raw_ptr() && rhs_ty.is_integral() {
+ err.multipart_suggestion(
+ "consider using `sub` or `wrapping_sub` to do pointer arithmetic",
+ vec![
+ (lhs_expr.span.shrink_to_lo(), format!("{} = ", lhs_name_str)),
+ (
+ lhs_expr.span.between(rhs_expr.span),
+ ".wrapping_sub(".to_owned(),
+
+ ),
+ (rhs_expr.span.shrink_to_hi(), ")".to_owned()),
+ ],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ _ => {}
+ }
+ }
+
let reported = err.emit();
Ty::new_error(self.tcx, reported)
}
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index fbc783c..7e7079f 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -9,11 +9,13 @@
Applicability, Diag, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err,
};
use rustc_hir::def::{CtorKind, DefKind, Res};
+use rustc_hir::def_id::DefId;
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::{
self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatExpr,
PatExprKind, PatKind, expr_needs_parens,
};
+use rustc_hir_analysis::autoderef::report_autoderef_recursion_limit_error;
use rustc_infer::infer;
use rustc_middle::traits::PatternOriginExpr;
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
@@ -29,11 +31,12 @@
use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
use tracing::{debug, instrument, trace};
use ty::VariantDef;
+use ty::adjustment::{PatAdjust, PatAdjustment};
use super::report_unexpected_variant_res;
use crate::expectation::Expectation;
use crate::gather_locals::DeclOrigin;
-use crate::{FnCtxt, LoweredTy, errors};
+use crate::{FnCtxt, errors};
const CANNOT_IMPLICITLY_DEREF_POINTER_TRAIT_OBJ: &str = "\
This error indicates that a pointer to a trait type cannot be implicitly dereferenced by a \
@@ -161,12 +164,35 @@ fn demand_eqtype_pat(
/// Mode for adjusting the expected type and binding mode.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum AdjustMode {
- /// Peel off all immediate reference types.
- Peel,
+ /// Peel off all immediate reference types. If the `deref_patterns` feature is enabled, this
+ /// also peels smart pointer ADTs.
+ Peel { kind: PeelKind },
/// Pass on the input binding mode and expected type.
Pass,
}
+/// Restrictions on what types to peel when adjusting the expected type and binding mode.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum PeelKind {
+ /// Only peel reference types. This is used for explicit `deref!(_)` patterns, which dereference
+ /// any number of `&`/`&mut` references, plus a single smart pointer.
+ ExplicitDerefPat,
+ /// Implicitly peel any number of references, and if `deref_patterns` is enabled, smart pointer
+ /// ADTs. In order to peel only as much as necessary for the pattern to match, the `until_adt`
+ /// field contains the ADT def that the pattern is a constructor for, if applicable, so that we
+ /// don't peel it. See [`ResolvedPat`] for more information.
+ Implicit { until_adt: Option<DefId> },
+}
+
+impl AdjustMode {
+ const fn peel_until_adt(opt_adt_def: Option<DefId>) -> AdjustMode {
+ AdjustMode::Peel { kind: PeelKind::Implicit { until_adt: opt_adt_def } }
+ }
+ const fn peel_all() -> AdjustMode {
+ AdjustMode::peel_until_adt(None)
+ }
+}
+
/// `ref mut` bindings (explicit or match-ergonomics) are not allowed behind an `&` reference.
/// Normally, the borrow checker enforces this, but for (currently experimental) match ergonomics,
/// we track this when typing patterns for two purposes:
@@ -242,6 +268,47 @@ enum InheritedRefMatchRule {
},
}
+/// When checking patterns containing paths, we need to know the path's resolution to determine
+/// whether to apply match ergonomics and implicitly dereference the scrutinee. For instance, when
+/// the `deref_patterns` feature is enabled and we're matching against a scrutinee of type
+/// `Cow<'a, Option<u8>>`, we insert an implicit dereference to allow the pattern `Some(_)` to type,
+/// but we must not dereference it when checking the pattern `Cow::Borrowed(_)`.
+///
+/// `ResolvedPat` contains the information from resolution needed to determine match ergonomics
+/// adjustments, and to finish checking the pattern once we know its adjusted type.
+#[derive(Clone, Copy, Debug)]
+struct ResolvedPat<'tcx> {
+ /// The type of the pattern, to be checked against the type of the scrutinee after peeling. This
+ /// is also used to avoid peeling the scrutinee's constructors (see the `Cow` example above).
+ ty: Ty<'tcx>,
+ kind: ResolvedPatKind<'tcx>,
+}
+
+#[derive(Clone, Copy, Debug)]
+enum ResolvedPatKind<'tcx> {
+ Path { res: Res, pat_res: Res, segments: &'tcx [hir::PathSegment<'tcx>] },
+ Struct { variant: &'tcx VariantDef },
+ TupleStruct { res: Res, variant: &'tcx VariantDef },
+}
+
+impl<'tcx> ResolvedPat<'tcx> {
+ fn adjust_mode(&self) -> AdjustMode {
+ if let ResolvedPatKind::Path { res, .. } = self.kind
+ && matches!(res, Res::Def(DefKind::Const | DefKind::AssocConst, _))
+ {
+ // These constants can be of a reference type, e.g. `const X: &u8 = &0;`.
+ // Peeling the reference types too early will cause type checking failures.
+ // Although it would be possible to *also* peel the types of the constants too.
+ AdjustMode::Pass
+ } else {
+ // The remaining possible resolutions for path, struct, and tuple struct patterns are
+ // ADT constructors. As such, we may peel references freely, but we must not peel the
+ // ADT itself from the scrutinee if it's a smart pointer.
+ AdjustMode::peel_until_adt(self.ty.ty_adt_def().map(|adt| adt.did()))
+ }
+ }
+}
+
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Experimental pattern feature: after matching against a shared reference, do we limit the
/// default binding mode in subpatterns to be `ref` when it would otherwise be `ref mut`?
@@ -318,16 +385,35 @@ pub(crate) fn check_pat_top(
/// Conversely, inside this module, `check_pat_top` should never be used.
#[instrument(level = "debug", skip(self, pat_info))]
fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx>) {
+ // For patterns containing paths, we need the path's resolution to determine whether to
+ // implicitly dereference the scrutinee before matching.
let opt_path_res = match pat.kind {
PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
- Some(self.resolve_ty_and_res_fully_qualified_call(qpath, *hir_id, *span))
+ Some(self.resolve_pat_path(*hir_id, *span, qpath))
}
+ PatKind::Struct(ref qpath, ..) => Some(self.resolve_pat_struct(pat, qpath)),
+ PatKind::TupleStruct(ref qpath, ..) => Some(self.resolve_pat_tuple_struct(pat, qpath)),
_ => None,
};
- let adjust_mode = self.calc_adjust_mode(pat, opt_path_res.map(|(res, ..)| res));
+ let adjust_mode = self.calc_adjust_mode(pat, opt_path_res);
let ty = self.check_pat_inner(pat, opt_path_res, adjust_mode, expected, pat_info);
self.write_ty(pat.hir_id, ty);
+ // If we implicitly inserted overloaded dereferences before matching, check the pattern to
+ // see if the dereferenced types need `DerefMut` bounds.
+ if let Some(derefed_tys) = self.typeck_results.borrow().pat_adjustments().get(pat.hir_id)
+ && derefed_tys.iter().any(|adjust| adjust.kind == PatAdjust::OverloadedDeref)
+ {
+ self.register_deref_mut_bounds_if_needed(
+ pat.span,
+ pat,
+ derefed_tys.iter().filter_map(|adjust| match adjust.kind {
+ PatAdjust::OverloadedDeref => Some(adjust.source),
+ PatAdjust::BuiltinDeref => None,
+ }),
+ );
+ }
+
// (note_1): In most of the cases where (note_1) is referenced
// (literals and constants being the exception), we relate types
// using strict equality, even though subtyping would be sufficient.
@@ -375,7 +461,7 @@ fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<
fn check_pat_inner(
&self,
pat: &'tcx Pat<'tcx>,
- opt_path_res: Option<(Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>])>,
+ opt_path_res: Option<Result<ResolvedPat<'tcx>, ErrorGuaranteed>>,
adjust_mode: AdjustMode,
expected: Ty<'tcx>,
pat_info: PatInfo<'tcx>,
@@ -389,7 +475,7 @@ fn check_pat_inner(
}
// Resolve type if needed.
- let expected = if let AdjustMode::Peel = adjust_mode
+ let expected = if let AdjustMode::Peel { .. } = adjust_mode
&& pat.default_binding_modes
{
self.try_structurally_resolve_type(pat.span, expected)
@@ -402,7 +488,7 @@ fn check_pat_inner(
match pat.kind {
// Peel off a `&` or `&mut` from the scrutinee type. See the examples in
// `tests/ui/rfcs/rfc-2005-default-binding-mode`.
- _ if let AdjustMode::Peel = adjust_mode
+ _ if let AdjustMode::Peel { .. } = adjust_mode
&& pat.default_binding_modes
&& let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() =>
{
@@ -415,7 +501,7 @@ fn check_pat_inner(
.pat_adjustments_mut()
.entry(pat.hir_id)
.or_default()
- .push(expected);
+ .push(PatAdjustment { kind: PatAdjust::BuiltinDeref, source: expected });
let mut binding_mode = ByRef::Yes(match pat_info.binding_mode {
// If default binding mode is by value, make it `ref` or `ref mut`
@@ -442,19 +528,68 @@ fn check_pat_inner(
// Recurse with the new expected type.
self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, new_pat_info)
}
+ // If `deref_patterns` is enabled, peel a smart pointer from the scrutinee type. See the
+ // examples in `tests/ui/pattern/deref_patterns/`.
+ _ if self.tcx.features().deref_patterns()
+ && let AdjustMode::Peel { kind: PeelKind::Implicit { until_adt } } = adjust_mode
+ && pat.default_binding_modes
+ // For simplicity, only apply overloaded derefs if `expected` is a known ADT.
+ // FIXME(deref_patterns): we'll get better diagnostics for users trying to
+ // implicitly deref generics if we allow them here, but primitives, tuples, and
+ // inference vars definitely should be stopped. Figure out what makes most sense.
+ && let ty::Adt(scrutinee_adt, _) = *expected.kind()
+ // Don't peel if the pattern type already matches the scrutinee. E.g., stop here if
+ // matching on a `Cow<'a, T>` scrutinee with a `Cow::Owned(_)` pattern.
+ && until_adt != Some(scrutinee_adt.did())
+ // At this point, the pattern isn't able to match `expected` without peeling. Check
+ // that it implements `Deref` before assuming it's a smart pointer, to get a normal
+ // type error instead of a missing impl error if not. This only checks for `Deref`,
+ // not `DerefPure`: we require that too, but we want a trait error if it's missing.
+ && let Some(deref_trait) = self.tcx.lang_items().deref_trait()
+ && self
+ .type_implements_trait(deref_trait, [expected], self.param_env)
+ .may_apply() =>
+ {
+ debug!("scrutinee ty {expected:?} is a smart pointer, inserting overloaded deref");
+ // The scrutinee is a smart pointer; implicitly dereference it. This adds a
+ // requirement that `expected: DerefPure`.
+ let mut inner_ty = self.deref_pat_target(pat.span, expected);
+ // Once we've checked `pat`, we'll add a `DerefMut` bound if it contains any
+ // `ref mut` bindings. See `Self::register_deref_mut_bounds_if_needed`.
+
+ let mut typeck_results = self.typeck_results.borrow_mut();
+ let mut pat_adjustments_table = typeck_results.pat_adjustments_mut();
+ let pat_adjustments = pat_adjustments_table.entry(pat.hir_id).or_default();
+ // We may reach the recursion limit if a user matches on a type `T` satisfying
+ // `T: Deref<Target = T>`; error gracefully in this case.
+ // FIXME(deref_patterns): If `deref_patterns` stabilizes, it may make sense to move
+ // this check out of this branch. Alternatively, this loop could be implemented with
+ // autoderef and this check removed. For now though, don't break code compiling on
+ // stable with lots of `&`s and a low recursion limit, if anyone's done that.
+ if self.tcx.recursion_limit().value_within_limit(pat_adjustments.len()) {
+ // Preserve the smart pointer type for THIR lowering and closure upvar analysis.
+ pat_adjustments
+ .push(PatAdjustment { kind: PatAdjust::OverloadedDeref, source: expected });
+ } else {
+ let guar = report_autoderef_recursion_limit_error(self.tcx, pat.span, expected);
+ inner_ty = Ty::new_error(self.tcx, guar);
+ }
+ drop(typeck_results);
+
+ // Recurse, using the old pat info to keep `current_depth` to its old value.
+ // Peeling smart pointers does not update the default binding mode.
+ self.check_pat_inner(pat, opt_path_res, adjust_mode, inner_ty, old_pat_info)
+ }
PatKind::Missing | PatKind::Wild | PatKind::Err(_) => expected,
// We allow any type here; we ensure that the type is uninhabited during match checking.
PatKind::Never => expected,
- PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
- let ty = self.check_pat_path(
- *hir_id,
- pat.hir_id,
- *span,
- qpath,
- opt_path_res.unwrap(),
- expected,
- &pat_info.top_info,
- );
+ PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), hir_id, .. }) => {
+ let ty = match opt_path_res.unwrap() {
+ Ok(ref pr) => {
+ self.check_pat_path(pat.hir_id, pat.span, pr, expected, &pat_info.top_info)
+ }
+ Err(guar) => Ty::new_error(self.tcx, guar),
+ };
self.write_ty(*hir_id, ty);
ty
}
@@ -465,12 +600,32 @@ fn check_pat_inner(
PatKind::Binding(ba, var_id, ident, sub) => {
self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info)
}
- PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
- self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
- }
- PatKind::Struct(ref qpath, fields, has_rest_pat) => {
- self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
- }
+ PatKind::TupleStruct(ref qpath, subpats, ddpos) => match opt_path_res.unwrap() {
+ Ok(ResolvedPat { ty, kind: ResolvedPatKind::TupleStruct { res, variant } }) => self
+ .check_pat_tuple_struct(
+ pat, qpath, subpats, ddpos, res, ty, variant, expected, pat_info,
+ ),
+ Err(guar) => {
+ let ty_err = Ty::new_error(self.tcx, guar);
+ for subpat in subpats {
+ self.check_pat(subpat, ty_err, pat_info);
+ }
+ ty_err
+ }
+ Ok(pr) => span_bug!(pat.span, "tuple struct pattern resolved to {pr:?}"),
+ },
+ PatKind::Struct(_, fields, has_rest_pat) => match opt_path_res.unwrap() {
+ Ok(ResolvedPat { ty, kind: ResolvedPatKind::Struct { variant } }) => self
+ .check_pat_struct(pat, fields, has_rest_pat, ty, variant, expected, pat_info),
+ Err(guar) => {
+ let ty_err = Ty::new_error(self.tcx, guar);
+ for field in fields {
+ self.check_pat(field.pat, ty_err, pat_info);
+ }
+ ty_err
+ }
+ Ok(pr) => span_bug!(pat.span, "struct pattern resolved to {pr:?}"),
+ },
PatKind::Guard(pat, cond) => {
self.check_pat(pat, expected, pat_info);
self.check_expr_has_type_or_error(cond, self.tcx.types.bool, |_| {});
@@ -496,31 +651,32 @@ fn check_pat_inner(
/// How should the binding mode and expected type be adjusted?
///
- /// When the pattern is a path pattern, `opt_path_res` must be `Some(res)`.
- fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res>) -> AdjustMode {
+ /// When the pattern contains a path, `opt_path_res` must be `Some(path_res)`.
+ fn calc_adjust_mode(
+ &self,
+ pat: &'tcx Pat<'tcx>,
+ opt_path_res: Option<Result<ResolvedPat<'tcx>, ErrorGuaranteed>>,
+ ) -> AdjustMode {
match &pat.kind {
// Type checking these product-like types successfully always require
// that the expected type be of those types and not reference types.
+ PatKind::Tuple(..)
+ | PatKind::Range(..)
+ | PatKind::Slice(..) => AdjustMode::peel_all(),
+ // When checking an explicit deref pattern, only peel reference types.
+ // FIXME(deref_patterns): If box patterns and deref patterns need to coexist, box
+ // patterns may want `PeelKind::Implicit`, stopping on encountering a box.
+ | PatKind::Box(_)
+ | PatKind::Deref(_) => AdjustMode::Peel { kind: PeelKind::ExplicitDerefPat },
+ // A never pattern behaves somewhat like a literal or unit variant.
+ PatKind::Never => AdjustMode::peel_all(),
+ // For patterns with paths, how we peel the scrutinee depends on the path's resolution.
PatKind::Struct(..)
| PatKind::TupleStruct(..)
- | PatKind::Tuple(..)
- | PatKind::Box(_)
- | PatKind::Deref(_)
- | PatKind::Range(..)
- | PatKind::Slice(..) => AdjustMode::Peel,
- // A never pattern behaves somewhat like a literal or unit variant.
- PatKind::Never => AdjustMode::Peel,
- PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), .. }) => match opt_path_res.unwrap() {
- // These constants can be of a reference type, e.g. `const X: &u8 = &0;`.
- // Peeling the reference types too early will cause type checking failures.
- // Although it would be possible to *also* peel the types of the constants too.
- Res::Def(DefKind::Const | DefKind::AssocConst, _) => AdjustMode::Pass,
- // In the `ValueNS`, we have `SelfCtor(..) | Ctor(_, Const), _)` remaining which
- // could successfully compile. The former being `Self` requires a unit struct.
- // In either case, and unlike constants, the pattern itself cannot be
- // a reference type wherefore peeling doesn't give up any expressiveness.
- _ => AdjustMode::Peel,
- },
+ | PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), .. }) => {
+ // If there was an error resolving the path, default to peeling everything.
+ opt_path_res.unwrap().map_or(AdjustMode::peel_all(), |pr| pr.adjust_mode())
+ }
// String and byte-string literals result in types `&str` and `&[u8]` respectively.
// All other literals result in non-reference types.
@@ -529,7 +685,17 @@ fn calc_adjust_mode(&self, pat: &'tcx Pat<'tcx>, opt_path_res: Option<Res>) -> A
// Call `resolve_vars_if_possible` here for inline const blocks.
PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
ty::Ref(..) => AdjustMode::Pass,
- _ => AdjustMode::Peel,
+ _ => {
+ // Path patterns have already been handled, and inline const blocks currently
+ // aren't possible to write, so any handling for them would be untested.
+ if cfg!(debug_assertions)
+ && self.tcx.features().deref_patterns()
+ && !matches!(lt.kind, PatExprKind::Lit { .. })
+ {
+ span_bug!(lt.span, "FIXME(deref_patterns): adjust mode unimplemented for {:?}", lt.kind);
+ }
+ AdjustMode::peel_all()
+ }
},
// Ref patterns are complicated, we handle them in `check_pat_ref`.
@@ -1112,27 +1278,26 @@ fn check_dereferenceable(
Ok(())
}
- fn check_pat_struct(
+ fn resolve_pat_struct(
&self,
pat: &'tcx Pat<'tcx>,
qpath: &hir::QPath<'tcx>,
+ ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
+ // Resolve the path and check the definition for errors.
+ let (variant, pat_ty) = self.check_struct_path(qpath, pat.hir_id)?;
+ Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Struct { variant } })
+ }
+
+ fn check_pat_struct(
+ &self,
+ pat: &'tcx Pat<'tcx>,
fields: &'tcx [hir::PatField<'tcx>],
has_rest_pat: bool,
+ pat_ty: Ty<'tcx>,
+ variant: &'tcx VariantDef,
expected: Ty<'tcx>,
pat_info: PatInfo<'tcx>,
) -> Ty<'tcx> {
- // Resolve the path and check the definition for errors.
- let (variant, pat_ty) = match self.check_struct_path(qpath, pat.hir_id) {
- Ok(data) => data,
- Err(guar) => {
- let err = Ty::new_error(self.tcx, guar);
- for field in fields {
- self.check_pat(field.pat, err, pat_info);
- }
- return err;
- }
- };
-
// Type-check the path.
let _ = self.demand_eqtype_pat(pat.span, expected, pat_ty, &pat_info.top_info);
@@ -1143,31 +1308,27 @@ fn check_pat_struct(
}
}
- fn check_pat_path(
+ fn resolve_pat_path(
&self,
path_id: HirId,
- pat_id_for_diag: HirId,
span: Span,
- qpath: &hir::QPath<'_>,
- path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
- expected: Ty<'tcx>,
- ti: &TopInfo<'tcx>,
- ) -> Ty<'tcx> {
+ qpath: &'tcx hir::QPath<'_>,
+ ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
let tcx = self.tcx;
- // We have already resolved the path.
- let (res, opt_ty, segments) = path_resolution;
+ let (res, opt_ty, segments) =
+ self.resolve_ty_and_res_fully_qualified_call(qpath, path_id, span);
match res {
Res::Err => {
let e =
self.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted");
self.set_tainted_by_errors(e);
- return Ty::new_error(tcx, e);
+ return Err(e);
}
Res::Def(DefKind::AssocFn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::Variant, _) => {
let expected = "unit struct, unit variant or constant";
let e = report_unexpected_variant_res(tcx, res, None, qpath, span, E0533, expected);
- return Ty::new_error(tcx, e);
+ return Err(e);
}
Res::SelfCtor(def_id) => {
if let ty::Adt(adt_def, _) = *tcx.type_of(def_id).skip_binder().kind()
@@ -1185,7 +1346,7 @@ fn check_pat_path(
E0533,
"unit struct",
);
- return Ty::new_error(tcx, e);
+ return Err(e);
}
}
Res::Def(
@@ -1198,15 +1359,26 @@ fn check_pat_path(
_ => bug!("unexpected pattern resolution: {:?}", res),
}
- // Type-check the path.
+ // Find the type of the path pattern, for later checking.
let (pat_ty, pat_res) =
self.instantiate_value_path(segments, opt_ty, res, span, span, path_id);
+ Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::Path { res, pat_res, segments } })
+ }
+
+ fn check_pat_path(
+ &self,
+ pat_id_for_diag: HirId,
+ span: Span,
+ resolved: &ResolvedPat<'tcx>,
+ expected: Ty<'tcx>,
+ ti: &TopInfo<'tcx>,
+ ) -> Ty<'tcx> {
if let Err(err) =
- self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, pat_ty)
+ self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, resolved.ty)
{
- self.emit_bad_pat_path(err, pat_id_for_diag, span, res, pat_res, pat_ty, segments);
+ self.emit_bad_pat_path(err, pat_id_for_diag, span, resolved);
}
- pat_ty
+ resolved.ty
}
fn maybe_suggest_range_literal(
@@ -1249,11 +1421,12 @@ fn emit_bad_pat_path(
mut e: Diag<'_>,
hir_id: HirId,
pat_span: Span,
- res: Res,
- pat_res: Res,
- pat_ty: Ty<'tcx>,
- segments: &'tcx [hir::PathSegment<'tcx>],
+ resolved_pat: &ResolvedPat<'tcx>,
) {
+ let ResolvedPatKind::Path { res, pat_res, segments } = resolved_pat.kind else {
+ span_bug!(pat_span, "unexpected resolution for path pattern: {resolved_pat:?}");
+ };
+
if let Some(span) = self.tcx.hir_res_span(pat_res) {
e.span_label(span, format!("{} defined here", res.descr()));
if let [hir::PathSegment { ident, .. }] = &*segments {
@@ -1276,7 +1449,7 @@ fn emit_bad_pat_path(
);
}
_ => {
- let (type_def_id, item_def_id) = match pat_ty.kind() {
+ let (type_def_id, item_def_id) = match resolved_pat.ty.kind() {
ty::Adt(def, _) => match res {
Res::Def(DefKind::Const, def_id) => (Some(def.did()), Some(def_id)),
_ => (None, None),
@@ -1284,15 +1457,18 @@ fn emit_bad_pat_path(
_ => (None, None),
};
- let ranges = &[
- self.tcx.lang_items().range_struct(),
- self.tcx.lang_items().range_from_struct(),
- self.tcx.lang_items().range_to_struct(),
- self.tcx.lang_items().range_full_struct(),
- self.tcx.lang_items().range_inclusive_struct(),
- self.tcx.lang_items().range_to_inclusive_struct(),
- ];
- if type_def_id != None && ranges.contains(&type_def_id) {
+ let is_range = match type_def_id.and_then(|id| self.tcx.as_lang_item(id)) {
+ Some(
+ LangItem::Range
+ | LangItem::RangeFrom
+ | LangItem::RangeTo
+ | LangItem::RangeFull
+ | LangItem::RangeInclusiveStruct
+ | LangItem::RangeToInclusive,
+ ) => true,
+ _ => false,
+ };
+ if is_range {
if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) {
let msg = "constants only support matching by type, \
if you meant to match against a range of values, \
@@ -1316,12 +1492,61 @@ fn emit_bad_pat_path(
e.emit();
}
+ fn resolve_pat_tuple_struct(
+ &self,
+ pat: &'tcx Pat<'tcx>,
+ qpath: &'tcx hir::QPath<'tcx>,
+ ) -> Result<ResolvedPat<'tcx>, ErrorGuaranteed> {
+ let tcx = self.tcx;
+ let report_unexpected_res = |res: Res| {
+ let expected = "tuple struct or tuple variant";
+ let e = report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0164, expected);
+ Err(e)
+ };
+
+ // Resolve the path and check the definition for errors.
+ let (res, opt_ty, segments) =
+ self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span);
+ if res == Res::Err {
+ let e = self.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted");
+ self.set_tainted_by_errors(e);
+ return Err(e);
+ }
+
+ // Type-check the path.
+ let (pat_ty, res) =
+ self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id);
+ if !pat_ty.is_fn() {
+ return report_unexpected_res(res);
+ }
+
+ let variant = match res {
+ Res::Err => {
+ self.dcx().span_bug(pat.span, "`Res::Err` but no error emitted");
+ }
+ Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
+ return report_unexpected_res(res);
+ }
+ Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
+ _ => bug!("unexpected pattern resolution: {:?}", res),
+ };
+
+ // Replace constructor type with constructed type for tuple struct patterns.
+ let pat_ty = pat_ty.fn_sig(tcx).output();
+ let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
+
+ Ok(ResolvedPat { ty: pat_ty, kind: ResolvedPatKind::TupleStruct { res, variant } })
+ }
+
fn check_pat_tuple_struct(
&self,
pat: &'tcx Pat<'tcx>,
qpath: &'tcx hir::QPath<'tcx>,
subpats: &'tcx [Pat<'tcx>],
ddpos: hir::DotDotPos,
+ res: Res,
+ pat_ty: Ty<'tcx>,
+ variant: &'tcx VariantDef,
expected: Ty<'tcx>,
pat_info: PatInfo<'tcx>,
) -> Ty<'tcx> {
@@ -1331,46 +1556,6 @@ fn check_pat_tuple_struct(
self.check_pat(pat, Ty::new_error(tcx, e), pat_info);
}
};
- let report_unexpected_res = |res: Res| {
- let expected = "tuple struct or tuple variant";
- let e = report_unexpected_variant_res(tcx, res, None, qpath, pat.span, E0164, expected);
- on_error(e);
- e
- };
-
- // Resolve the path and check the definition for errors.
- let (res, opt_ty, segments) =
- self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span);
- if res == Res::Err {
- let e = self.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted");
- self.set_tainted_by_errors(e);
- on_error(e);
- return Ty::new_error(tcx, e);
- }
-
- // Type-check the path.
- let (pat_ty, res) =
- self.instantiate_value_path(segments, opt_ty, res, pat.span, pat.span, pat.hir_id);
- if !pat_ty.is_fn() {
- let e = report_unexpected_res(res);
- return Ty::new_error(tcx, e);
- }
-
- let variant = match res {
- Res::Err => {
- self.dcx().span_bug(pat.span, "`Res::Err` but no error emitted");
- }
- Res::Def(DefKind::AssocConst | DefKind::AssocFn, _) => {
- let e = report_unexpected_res(res);
- return Ty::new_error(tcx, e);
- }
- Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) => tcx.expect_variant_res(res),
- _ => bug!("unexpected pattern resolution: {:?}", res),
- };
-
- // Replace constructor type with constructed type for tuple struct patterns.
- let pat_ty = pat_ty.fn_sig(tcx).output();
- let pat_ty = pat_ty.no_bound_vars().expect("expected fn type");
// Type-check the tuple struct pattern against the expected type.
let diag = self.demand_eqtype_pat_diag(pat.span, expected, pat_ty, &pat_info.top_info);
@@ -2255,36 +2440,49 @@ fn check_pat_deref(
expected: Ty<'tcx>,
pat_info: PatInfo<'tcx>,
) -> Ty<'tcx> {
- let tcx = self.tcx;
+ let target_ty = self.deref_pat_target(span, expected);
+ self.check_pat(inner, target_ty, pat_info);
+ self.register_deref_mut_bounds_if_needed(span, inner, [expected]);
+ expected
+ }
+
+ fn deref_pat_target(&self, span: Span, source_ty: Ty<'tcx>) -> Ty<'tcx> {
// Register a `DerefPure` bound, which is required by all `deref!()` pats.
+ let tcx = self.tcx;
self.register_bound(
- expected,
+ source_ty,
tcx.require_lang_item(hir::LangItem::DerefPure, Some(span)),
self.misc(span),
);
- // <expected as Deref>::Target
- let ty = Ty::new_projection(
+ // The expected type for the deref pat's inner pattern is `<expected as Deref>::Target`.
+ let target_ty = Ty::new_projection(
tcx,
tcx.require_lang_item(hir::LangItem::DerefTarget, Some(span)),
- [expected],
+ [source_ty],
);
- let ty = self.normalize(span, ty);
- let ty = self.try_structurally_resolve_type(span, ty);
- self.check_pat(inner, ty, pat_info);
+ let target_ty = self.normalize(span, target_ty);
+ self.try_structurally_resolve_type(span, target_ty)
+ }
- // Check if the pattern has any `ref mut` bindings, which would require
- // `DerefMut` to be emitted in MIR building instead of just `Deref`.
- // We do this *after* checking the inner pattern, since we want to make
- // sure to apply any match-ergonomics adjustments.
+ /// Check if the interior of a deref pattern (either explicit or implicit) has any `ref mut`
+ /// bindings, which would require `DerefMut` to be emitted in MIR building instead of just
+ /// `Deref`. We do this *after* checking the inner pattern, since we want to make sure to
+ /// account for `ref mut` binding modes inherited from implicitly dereferencing `&mut` refs.
+ fn register_deref_mut_bounds_if_needed(
+ &self,
+ span: Span,
+ inner: &'tcx Pat<'tcx>,
+ derefed_tys: impl IntoIterator<Item = Ty<'tcx>>,
+ ) {
if self.typeck_results.borrow().pat_has_ref_mut_binding(inner) {
- self.register_bound(
- expected,
- tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)),
- self.misc(span),
- );
+ for mutably_derefed_ty in derefed_tys {
+ self.register_bound(
+ mutably_derefed_ty,
+ self.tcx.require_lang_item(hir::LangItem::DerefMut, Some(span)),
+ self.misc(span),
+ );
+ }
}
-
- expected
}
// Precondition: Pat is Ref(inner)
diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
index 5b4fc51..56859ee 100644
--- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
+++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
@@ -2,9 +2,8 @@
use std::ops::Deref;
use rustc_data_structures::unord::{UnordMap, UnordSet};
-use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
-use rustc_hir::{HirId, HirIdMap};
+use rustc_hir::{self as hir, HirId, HirIdMap, LangItem};
use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
use rustc_middle::span_bug;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode};
@@ -84,7 +83,7 @@ pub(crate) fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner;
let infcx =
- tcx.infer_ctxt().ignoring_regions().build(TypingMode::analysis_in_body(tcx, def_id));
+ tcx.infer_ctxt().ignoring_regions().build(TypingMode::typeck_for_body(tcx, def_id));
let typeck_results = RefCell::new(ty::TypeckResults::new(hir_owner));
TypeckRootCtxt {
@@ -137,7 +136,7 @@ fn update_infer_var_info(&self, obligation: &PredicateObligation<'tcx>) {
obligation.predicate.kind().skip_binder()
&& let Some(ty) =
self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t))
- && self.tcx.lang_items().sized_trait().is_some_and(|st| st != tpred.trait_ref.def_id)
+ && !self.tcx.is_lang_item(tpred.trait_ref.def_id, LangItem::Sized)
{
let new_self_ty = self.tcx.types.unit;
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 6ba7435..3caaa7f 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -8,6 +8,7 @@
use rustc_errors::ErrorGuaranteed;
use rustc_hir::intravisit::{self, InferKind, Visitor};
use rustc_hir::{self as hir, AmbigArg, HirId};
+use rustc_infer::traits::solve::Goal;
use rustc_middle::span_bug;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
@@ -763,7 +764,32 @@ fn resolve<T>(&mut self, value: T, span: &dyn Locatable) -> T
T: TypeFoldable<TyCtxt<'tcx>>,
{
let value = self.fcx.resolve_vars_if_possible(value);
- let value = value.fold_with(&mut Resolver::new(self.fcx, span, self.body, true));
+
+ let mut goals = vec![];
+ let value =
+ value.fold_with(&mut Resolver::new(self.fcx, span, self.body, true, &mut goals));
+
+ // Ensure that we resolve goals we get from normalizing coroutine interiors,
+ // but we shouldn't expect those goals to need normalizing (or else we'd get
+ // into a somewhat awkward fixpoint situation, and we don't need it anyways).
+ let mut unexpected_goals = vec![];
+ self.typeck_results.coroutine_stalled_predicates.extend(
+ goals
+ .into_iter()
+ .map(|pred| {
+ self.fcx.resolve_vars_if_possible(pred).fold_with(&mut Resolver::new(
+ self.fcx,
+ span,
+ self.body,
+ false,
+ &mut unexpected_goals,
+ ))
+ })
+ // FIXME: throwing away the param-env :(
+ .map(|goal| (goal.predicate, self.fcx.misc(span.to_span(self.fcx.tcx)))),
+ );
+ assert_eq!(unexpected_goals, vec![]);
+
assert!(!value.has_infer());
// We may have introduced e.g. `ty::Error`, if inference failed, make sure
@@ -781,7 +807,12 @@ fn resolve_coroutine_predicate<T>(&mut self, value: T, span: &dyn Locatable) ->
T: TypeFoldable<TyCtxt<'tcx>>,
{
let value = self.fcx.resolve_vars_if_possible(value);
- let value = value.fold_with(&mut Resolver::new(self.fcx, span, self.body, false));
+
+ let mut goals = vec![];
+ let value =
+ value.fold_with(&mut Resolver::new(self.fcx, span, self.body, false, &mut goals));
+ assert_eq!(goals, vec![]);
+
assert!(!value.has_infer());
// We may have introduced e.g. `ty::Error`, if inference failed, make sure
@@ -818,6 +849,7 @@ struct Resolver<'cx, 'tcx> {
/// Whether we should normalize using the new solver, disabled
/// both when using the old solver and when resolving predicates.
should_normalize: bool,
+ nested_goals: &'cx mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
}
impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
@@ -826,8 +858,9 @@ fn new(
span: &'cx dyn Locatable,
body: &'tcx hir::Body<'tcx>,
should_normalize: bool,
+ nested_goals: &'cx mut Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
) -> Resolver<'cx, 'tcx> {
- Resolver { fcx, span, body, should_normalize }
+ Resolver { fcx, span, body, nested_goals, should_normalize }
}
fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) -> ErrorGuaranteed {
@@ -864,12 +897,18 @@ fn handle_term<T>(
let cause = ObligationCause::misc(self.span.to_span(tcx), body_id);
let at = self.fcx.at(&cause, self.fcx.param_env);
let universes = vec![None; outer_exclusive_binder(value).as_usize()];
- solve::deeply_normalize_with_skipped_universes(at, value, universes).unwrap_or_else(
- |errors| {
+ match solve::deeply_normalize_with_skipped_universes_and_ambiguous_goals(
+ at, value, universes,
+ ) {
+ Ok((value, goals)) => {
+ self.nested_goals.extend(goals);
+ value
+ }
+ Err(errors) => {
let guar = self.fcx.err_ctxt().report_fulfillment_errors(errors);
new_err(tcx, guar)
- },
- )
+ }
+ }
} else {
value
};
diff --git a/compiler/rustc_incremental/messages.ftl b/compiler/rustc_incremental/messages.ftl
index 2a65101..bbc1fab 100644
--- a/compiler/rustc_incremental/messages.ftl
+++ b/compiler/rustc_incremental/messages.ftl
@@ -93,7 +93,7 @@
incremental_undefined_clean_dirty_assertions_item =
clean/dirty auto-assertions not yet defined for Node::Item.node={$kind}
-incremental_unknown_item = unknown item `{$name}`
+incremental_unknown_rustc_clean_argument = unknown `rustc_clean` argument
incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name}
diff --git a/compiler/rustc_incremental/src/errors.rs b/compiler/rustc_incremental/src/errors.rs
index b4a2073..dbc72d0 100644
--- a/compiler/rustc_incremental/src/errors.rs
+++ b/compiler/rustc_incremental/src/errors.rs
@@ -107,11 +107,10 @@ pub(crate) struct NotLoaded<'a> {
}
#[derive(Diagnostic)]
-#[diag(incremental_unknown_item)]
-pub(crate) struct UnknownItem {
+#[diag(incremental_unknown_rustc_clean_argument)]
+pub(crate) struct UnknownRustcCleanArgument {
#[primary_span]
pub span: Span,
- pub name: Symbol,
}
#[derive(Diagnostic)]
diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs
index dabfb6a..299ee48 100644
--- a/compiler/rustc_incremental/src/lib.rs
+++ b/compiler/rustc_incremental/src/lib.rs
@@ -2,7 +2,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![deny(missing_docs)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index d40a0d5..6416625 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -405,8 +405,7 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool {
debug!("check_config: searching for cfg {:?}", value);
cfg = Some(config.contains(&(value, None)));
} else if !(item.has_name(EXCEPT) || item.has_name(LOADED_FROM_DISK)) {
- tcx.dcx()
- .emit_err(errors::UnknownItem { span: attr.span(), name: item.name_or_empty() });
+ tcx.dcx().emit_err(errors::UnknownRustcCleanArgument { span: item.span() });
}
}
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 76a1ff3..f0d24d2 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -290,7 +290,7 @@ pub(crate) fn prepare_session_directory(sess: &Session, crate_name: Symbol) {
// Try to remove the session directory we just allocated. We don't
// know if there's any garbage in it from the failed copy action.
- if let Err(err) = safe_remove_dir_all(&session_dir) {
+ if let Err(err) = std_fs::remove_dir_all(&session_dir) {
sess.dcx().emit_warn(errors::DeletePartial { path: &session_dir, err });
}
@@ -324,7 +324,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option<Svh>) {
incr_comp_session_dir.display()
);
- if let Err(err) = safe_remove_dir_all(&*incr_comp_session_dir) {
+ if let Err(err) = std_fs::remove_dir_all(&*incr_comp_session_dir) {
sess.dcx().emit_warn(errors::DeleteFull { path: &incr_comp_session_dir, err });
}
@@ -715,7 +715,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result<
for directory_name in session_directories {
if !lock_file_to_session_dir.items().any(|(_, dir)| *dir == directory_name) {
let path = crate_directory.join(directory_name);
- if let Err(err) = safe_remove_dir_all(&path) {
+ if let Err(err) = std_fs::remove_dir_all(&path) {
sess.dcx().emit_warn(errors::InvalidGcFailed { path: &path, err });
}
}
@@ -821,7 +821,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result<
all_except_most_recent(deletion_candidates).into_items().all(|(path, lock)| {
debug!("garbage_collect_session_directories() - deleting `{}`", path.display());
- if let Err(err) = safe_remove_dir_all(&path) {
+ if let Err(err) = std_fs::remove_dir_all(&path) {
sess.dcx().emit_warn(errors::FinalizedGcFailed { path: &path, err });
} else {
delete_session_dir_lock_file(sess, &lock_file_path(&path));
@@ -839,7 +839,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result<
fn delete_old(sess: &Session, path: &Path) {
debug!("garbage_collect_session_directories() - deleting `{}`", path.display());
- if let Err(err) = safe_remove_dir_all(path) {
+ if let Err(err) = std_fs::remove_dir_all(path) {
sess.dcx().emit_warn(errors::SessionGcFailed { path, err });
} else {
delete_session_dir_lock_file(sess, &lock_file_path(path));
@@ -862,30 +862,8 @@ fn all_except_most_recent(
}
}
-/// Since paths of artifacts within session directories can get quite long, we
-/// need to support deleting files with very long paths. The regular
-/// WinApi functions only support paths up to 260 characters, however. In order
-/// to circumvent this limitation, we canonicalize the path of the directory
-/// before passing it to std::fs::remove_dir_all(). This will convert the path
-/// into the '\\?\' format, which supports much longer paths.
-fn safe_remove_dir_all(p: &Path) -> io::Result<()> {
- let canonicalized = match try_canonicalize(p) {
- Ok(canonicalized) => canonicalized,
- Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
- Err(err) => return Err(err),
- };
-
- std_fs::remove_dir_all(canonicalized)
-}
-
fn safe_remove_file(p: &Path) -> io::Result<()> {
- let canonicalized = match try_canonicalize(p) {
- Ok(canonicalized) => canonicalized,
- Err(err) if err.kind() == io::ErrorKind::NotFound => return Ok(()),
- Err(err) => return Err(err),
- };
-
- match std_fs::remove_file(canonicalized) {
+ match std_fs::remove_file(p) {
Err(err) if err.kind() == io::ErrorKind::NotFound => Ok(()),
result => result,
}
diff --git a/compiler/rustc_index/src/slice.rs b/compiler/rustc_index/src/slice.rs
index 67ac805..d2702bd 100644
--- a/compiler/rustc_index/src/slice.rs
+++ b/compiler/rustc_index/src/slice.rs
@@ -1,6 +1,6 @@
use std::fmt;
use std::marker::PhantomData;
-use std::ops::{Index, IndexMut};
+use std::ops::{Index, IndexMut, RangeBounds};
use std::slice::GetDisjointMutError::*;
use std::slice::{self, SliceIndex};
@@ -105,6 +105,17 @@ pub fn swap(&mut self, a: I, b: I) {
}
#[inline]
+ pub fn copy_within(
+ &mut self,
+ src: impl IntoSliceIdx<I, [T], Output: RangeBounds<usize>>,
+ dest: I,
+ ) where
+ T: Copy,
+ {
+ self.raw.copy_within(src.into_slice_idx(), dest.index());
+ }
+
+ #[inline]
pub fn get<R: IntoSliceIdx<I, [T]>>(
&self,
index: R,
diff --git a/compiler/rustc_index_macros/src/newtype.rs b/compiler/rustc_index_macros/src/newtype.rs
index f0b58ea..eedbe63 100644
--- a/compiler/rustc_index_macros/src/newtype.rs
+++ b/compiler/rustc_index_macros/src/newtype.rs
@@ -257,6 +257,13 @@ fn add(self, other: usize) -> Self {
}
}
+ impl std::ops::AddAssign<usize> for #name {
+ #[inline]
+ fn add_assign(&mut self, other: usize) {
+ *self = *self + other;
+ }
+ }
+
impl rustc_index::Idx for #name {
#[inline]
fn new(value: usize) -> Self {
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 529e996..c4698e5 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -967,7 +967,9 @@ pub fn clone_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
pub fn can_define_opaque_ty(&self, id: impl Into<DefId>) -> bool {
debug_assert!(!self.next_trait_solver());
match self.typing_mode() {
- TypingMode::Analysis { defining_opaque_types }
+ TypingMode::Analysis {
+ defining_opaque_types_and_generators: defining_opaque_types,
+ }
| TypingMode::Borrowck { defining_opaque_types } => {
id.into().as_local().is_some_and(|def_id| defining_opaque_types.contains(&def_id))
}
@@ -1262,7 +1264,7 @@ pub fn typing_env(&self, param_env: ty::ParamEnv<'tcx>) -> ty::TypingEnv<'tcx> {
// to handle them without proper canonicalization. This means we may cause cycle
// errors and fail to reveal opaques while inside of bodies. We should rename this
// function and require explicit comments on all use-sites in the future.
- ty::TypingMode::Analysis { defining_opaque_types: _ }
+ ty::TypingMode::Analysis { defining_opaque_types_and_generators: _ }
| ty::TypingMode::Borrowck { defining_opaque_types: _ } => {
TypingMode::non_body_analysis()
}
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 8366aa6..40e2e65 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -618,9 +618,7 @@ pub fn vars_since_snapshot(
RegionVid::from(value_count)..RegionVid::from(self.storage.unification_table.len());
(
range.clone(),
- (range.start.index()..range.end.index())
- .map(|index| self.storage.var_infos[ty::RegionVid::from(index)].origin)
- .collect(),
+ (range.start..range.end).map(|index| self.storage.var_infos[index].origin).collect(),
)
}
diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
index b5d3c26..39c8c40 100644
--- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
@@ -30,11 +30,12 @@ fn const_vars_since_snapshot<'tcx>(
snapshot_var_len: usize,
) -> (Range<ConstVid>, Vec<ConstVariableOrigin>) {
let range = vars_since_snapshot(table, snapshot_var_len);
+ let range = range.start.vid..range.end.vid;
(
- range.start.vid..range.end.vid,
- (range.start.index()..range.end.index())
- .map(|index| match table.probe_value(ConstVid::from_u32(index)) {
+ range.clone(),
+ range
+ .map(|index| match table.probe_value(index) {
ConstVariableValue::Known { value: _ } => {
ConstVariableOrigin { param_def_id: None, span: rustc_span::DUMMY_SP }
}
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index 1eae106..9e51a53 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -94,7 +94,7 @@ fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
/// Among all pending obligations, collect those are stalled on a inference variable which has
/// changed since the last call to `select_where_possible`. Those obligations are marked as
/// successful and returned.
- fn drain_unstalled_obligations(
+ fn drain_stalled_obligations_for_coroutines(
&mut self,
infcx: &InferCtxt<'tcx>,
) -> PredicateObligations<'tcx>;
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index b537750..6d5ad96 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -12,6 +12,7 @@
use hir::def_id::LocalDefId;
use rustc_hir as hir;
+use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::traits::query::NoSolution;
use rustc_middle::traits::solve::Certainty;
pub use rustc_middle::traits::*;
@@ -35,9 +36,11 @@
/// either identifying an `impl` (e.g., `impl Eq for i32`) that
/// satisfies the obligation, or else finding a bound that is in
/// scope. The eventual result is usually a `Selection` (defined below).
-#[derive(Clone)]
+#[derive(Clone, TypeFoldable, TypeVisitable)]
pub struct Obligation<'tcx, T> {
/// The reason we have to prove this thing.
+ #[type_foldable(identity)]
+ #[type_visitable(ignore)]
pub cause: ObligationCause<'tcx>,
/// The environment in which we should prove this thing.
@@ -51,6 +54,8 @@ pub struct Obligation<'tcx, T> {
/// If this goes over a certain threshold, we abort compilation --
/// in such cases, we can not say whether or not the predicate
/// holds for certain. Stupid halting problem; such a drag.
+ #[type_foldable(identity)]
+ #[type_visitable(ignore)]
pub recursion_depth: usize,
}
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index 4335073..03661eb 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -1,8 +1,6 @@
use std::fmt;
-use rustc_middle::ty::{
- self, FallibleTypeFolder, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitor, try_visit,
-};
+use rustc_middle::ty;
use crate::traits;
use crate::traits::project::Normalized;
@@ -34,31 +32,3 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "MismatchedProjectionTypes({:?})", self.err)
}
}
-
-///////////////////////////////////////////////////////////////////////////
-// TypeFoldable implementations.
-
-impl<'tcx, O: TypeFoldable<TyCtxt<'tcx>>> TypeFoldable<TyCtxt<'tcx>>
- for traits::Obligation<'tcx, O>
-{
- fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
- self,
- folder: &mut F,
- ) -> Result<Self, F::Error> {
- Ok(traits::Obligation {
- cause: self.cause,
- recursion_depth: self.recursion_depth,
- predicate: self.predicate.try_fold_with(folder)?,
- param_env: self.param_env.try_fold_with(folder)?,
- })
- }
-}
-
-impl<'tcx, O: TypeVisitable<TyCtxt<'tcx>>> TypeVisitable<TyCtxt<'tcx>>
- for traits::Obligation<'tcx, O>
-{
- fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
- try_visit!(self.predicate.visit_with(visitor));
- self.param_env.visit_with(visitor)
- }
-}
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 75a1b61..5c8c51c 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -614,6 +614,7 @@ macro_rules! tracked {
tracked!(control_flow_guard, CFGuard::Checks);
tracked!(debug_assertions, Some(true));
tracked!(debuginfo, DebugInfo::Limited);
+ tracked!(dwarf_version, Some(5));
tracked!(embed_bitcode, false);
tracked!(force_frame_pointers, FramePointer::Always);
tracked!(force_unwind_tables, Some(true));
@@ -817,8 +818,8 @@ macro_rules! tracked {
tracked!(min_function_alignment, Some(Align::EIGHT));
tracked!(mir_emit_retag, true);
tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]);
- tracked!(mir_keep_place_mention, true);
tracked!(mir_opt_level, Some(4));
+ tracked!(mir_preserve_ub, true);
tracked!(move_size_limit, Some(4096));
tracked!(mutable_noalias, false);
tracked!(next_solver, NextSolverConfig { coherence: true, globally: true });
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 782d328..60c183b 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -271,7 +271,7 @@
lint_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition
.suggestion = convert it to a `use`
-lint_extern_without_abi = extern declarations without an explicit ABI are deprecated
+lint_extern_without_abi = `extern` declarations without an explicit ABI are deprecated
.label = ABI should be specified here
.suggestion = explicitly specify the {$default_abi} ABI
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 16c9e08..3660bb3 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -83,11 +83,6 @@ enum TargetLint {
Ignored,
}
-pub enum FindLintError {
- NotFound,
- Removed,
-}
-
struct LintAlias {
name: &'static str,
/// Whether deprecation warnings should be suppressed for this alias.
@@ -231,13 +226,24 @@ pub fn register_lints(&mut self, lints: &[&'static Lint]) {
}
}
- pub fn register_group_alias(&mut self, lint_name: &'static str, alias: &'static str) {
- self.lint_groups.insert(
+ fn insert_group(&mut self, name: &'static str, group: LintGroup) {
+ let previous = self.lint_groups.insert(name, group);
+ if previous.is_some() {
+ bug!("group {name:?} already exists");
+ }
+ }
+
+ pub fn register_group_alias(&mut self, group_name: &'static str, alias: &'static str) {
+ let Some(LintGroup { lint_ids, .. }) = self.lint_groups.get(group_name) else {
+ bug!("group alias {alias:?} points to unregistered group {group_name:?}")
+ };
+
+ self.insert_group(
alias,
LintGroup {
- lint_ids: vec![],
+ lint_ids: lint_ids.clone(),
is_externally_loaded: false,
- depr: Some(LintAlias { name: lint_name, silent: true }),
+ depr: Some(LintAlias { name: group_name, silent: true }),
},
);
}
@@ -249,24 +255,17 @@ pub fn register_group(
deprecated_name: Option<&'static str>,
to: Vec<LintId>,
) {
- let new = self
- .lint_groups
- .insert(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None })
- .is_none();
if let Some(deprecated) = deprecated_name {
- self.lint_groups.insert(
+ self.insert_group(
deprecated,
LintGroup {
- lint_ids: vec![],
+ lint_ids: to.clone(),
is_externally_loaded,
depr: Some(LintAlias { name, silent: false }),
},
);
}
-
- if !new {
- bug!("duplicate specification of lint group {}", name);
- }
+ self.insert_group(name, LintGroup { lint_ids: to, is_externally_loaded, depr: None });
}
/// This lint should give no warning and have no effect.
@@ -292,23 +291,15 @@ pub fn register_removed(&mut self, name: &str, reason: &str) {
self.by_name.insert(name.into(), Removed(reason.into()));
}
- pub fn find_lints(&self, mut lint_name: &str) -> Result<Vec<LintId>, FindLintError> {
+ pub fn find_lints(&self, lint_name: &str) -> Option<&[LintId]> {
match self.by_name.get(lint_name) {
- Some(&Id(lint_id)) => Ok(vec![lint_id]),
- Some(&Renamed(_, lint_id)) => Ok(vec![lint_id]),
- Some(&Removed(_)) => Err(FindLintError::Removed),
- Some(&Ignored) => Ok(vec![]),
- None => loop {
- return match self.lint_groups.get(lint_name) {
- Some(LintGroup { lint_ids, depr, .. }) => {
- if let Some(LintAlias { name, .. }) = depr {
- lint_name = name;
- continue;
- }
- Ok(lint_ids.clone())
- }
- None => Err(FindLintError::Removed),
- };
+ Some(Id(lint_id)) => Some(slice::from_ref(lint_id)),
+ Some(Renamed(_, lint_id)) => Some(slice::from_ref(lint_id)),
+ Some(Removed(_)) => None,
+ Some(Ignored) => Some(&[]),
+ None => match self.lint_groups.get(lint_name) {
+ Some(LintGroup { lint_ids, .. }) => Some(lint_ids),
+ None => None,
},
}
}
@@ -374,8 +365,12 @@ pub fn check_lint_name(
CheckLintNameResult::MissingTool
};
}
- Some(LintGroup { lint_ids, .. }) => {
- return CheckLintNameResult::Tool(lint_ids, None);
+ Some(LintGroup { lint_ids, depr, .. }) => {
+ return if let &Some(LintAlias { name, silent: false }) = depr {
+ CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
+ } else {
+ CheckLintNameResult::Tool(lint_ids, None)
+ };
}
},
Some(Id(id)) => return CheckLintNameResult::Tool(slice::from_ref(id), None),
@@ -393,15 +388,11 @@ pub fn check_lint_name(
None => self.check_tool_name_for_backwards_compat(&complete_name, "clippy"),
Some(LintGroup { lint_ids, depr, .. }) => {
// Check if the lint group name is deprecated
- if let Some(LintAlias { name, silent }) = depr {
- let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
- return if *silent {
- CheckLintNameResult::Ok(lint_ids)
- } else {
- CheckLintNameResult::Tool(lint_ids, Some((*name).to_string()))
- };
+ if let &Some(LintAlias { name, silent: false }) = depr {
+ CheckLintNameResult::Tool(lint_ids, Some(name.to_string()))
+ } else {
+ CheckLintNameResult::Ok(lint_ids)
}
- CheckLintNameResult::Ok(lint_ids)
}
},
Some(Id(id)) => CheckLintNameResult::Ok(slice::from_ref(id)),
@@ -412,7 +403,7 @@ pub fn check_lint_name(
fn no_lint_suggestion(&self, lint_name: &str, tool_name: &str) -> CheckLintNameResult<'_> {
let name_lower = lint_name.to_lowercase();
- if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_ok() {
+ if lint_name.chars().any(char::is_uppercase) && self.find_lints(&name_lower).is_some() {
// First check if the lint name is (partly) in upper case instead of lower case...
return CheckLintNameResult::NoLint(Some((Symbol::intern(&name_lower), false)));
}
@@ -455,18 +446,8 @@ fn check_tool_name_for_backwards_compat(
None => match self.lint_groups.get(&*complete_name) {
// Now we are sure, that this lint exists nowhere
None => self.no_lint_suggestion(lint_name, tool_name),
- Some(LintGroup { lint_ids, depr, .. }) => {
- // Reaching this would be weird, but let's cover this case anyway
- if let Some(LintAlias { name, silent }) = depr {
- let LintGroup { lint_ids, .. } = self.lint_groups.get(name).unwrap();
- if *silent {
- CheckLintNameResult::Tool(lint_ids, Some(complete_name))
- } else {
- CheckLintNameResult::Tool(lint_ids, Some((*name).to_string()))
- }
- } else {
- CheckLintNameResult::Tool(lint_ids, Some(complete_name))
- }
+ Some(LintGroup { lint_ids, .. }) => {
+ CheckLintNameResult::Tool(lint_ids, Some(complete_name))
}
},
Some(Id(id)) => CheckLintNameResult::Tool(slice::from_ref(id), Some(complete_name)),
@@ -855,11 +836,11 @@ pub fn get_associated_type(
&self,
self_ty: Ty<'tcx>,
trait_id: DefId,
- name: &str,
+ name: Symbol,
) -> Option<Ty<'tcx>> {
let tcx = self.tcx;
tcx.associated_items(trait_id)
- .find_by_ident_and_kind(tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
+ .find_by_ident_and_kind(tcx, Ident::with_dummy_span(name), ty::AssocTag::Type, trait_id)
.and_then(|assoc| {
let proj = Ty::new_projection(tcx, assoc.def_id, [self_ty]);
tcx.try_normalize_erasing_regions(self.typing_env(), proj).ok()
diff --git a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
index ec8f844..5989ef9 100644
--- a/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
+++ b/compiler/rustc_lint/src/deref_into_dyn_supertrait.rs
@@ -69,7 +69,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
&& let ty::Dynamic(data, _, ty::Dyn) = self_ty.kind()
&& let Some(self_principal) = data.principal()
// `<T as Deref>::Target` is `dyn target_principal`
- && let Some(target) = cx.get_associated_type(self_ty, did, "Target")
+ && let Some(target) = cx.get_associated_type(self_ty, did, sym::Target)
&& let ty::Dynamic(data, _, ty::Dyn) = target.kind()
&& let Some(target_principal) = data.principal()
// `target_principal` is a supertrait of `t_principal`
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
index d109a5c..586e55c 100644
--- a/compiler/rustc_lint/src/errors.rs
+++ b/compiler/rustc_lint/src/errors.rs
@@ -1,5 +1,5 @@
use rustc_errors::codes::*;
-use rustc_errors::{Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
+use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_session::lint::Level;
use rustc_span::{Span, Symbol};
@@ -26,11 +26,7 @@ pub(crate) enum OverruledAttributeSub {
}
impl Subdiagnostic for OverruledAttributeSub {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
match self {
OverruledAttributeSub::DefaultSource { id } => {
diag.note(fluent::lint_default_source);
diff --git a/compiler/rustc_lint/src/if_let_rescope.rs b/compiler/rustc_lint/src/if_let_rescope.rs
index 39ea8d8..a9b0451 100644
--- a/compiler/rustc_lint/src/if_let_rescope.rs
+++ b/compiler/rustc_lint/src/if_let_rescope.rs
@@ -3,9 +3,7 @@
use hir::intravisit::{self, Visitor};
use rustc_ast::Recovered;
-use rustc_errors::{
- Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic, SuggestionStyle,
-};
+use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic, SuggestionStyle};
use rustc_hir::{self as hir, HirIdSet};
use rustc_macros::{LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::adjustment::Adjust;
@@ -327,11 +325,7 @@ struct IfLetRescopeRewrite {
}
impl Subdiagnostic for IfLetRescopeRewrite {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut suggestions = vec![];
for match_head in self.match_heads {
match match_head {
@@ -360,7 +354,7 @@ fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
.chain(repeat('}').take(closing_brackets.count))
.collect(),
));
- let msg = f(diag, crate::fluent_generated::lint_suggestion);
+ let msg = diag.eagerly_translate(crate::fluent_generated::lint_suggestion);
diag.multipart_suggestion_with_style(
msg,
suggestions,
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index d0b1e7b..0077564 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -517,11 +517,11 @@ fn add_command_line(&mut self) {
let lint_flag_val = Symbol::intern(lint_name);
- let Ok(ids) = self.store.find_lints(lint_name) else {
+ let Some(ids) = self.store.find_lints(lint_name) else {
// errors already handled above
continue;
};
- for id in ids {
+ for &id in ids {
// ForceWarn and Forbid cannot be overridden
if let Some(LevelAndSource { level: Level::ForceWarn | Level::Forbid, .. }) =
self.current_specs().get(&id)
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 9b5c564..daddd45 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -21,7 +21,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(array_windows)]
@@ -125,9 +124,7 @@
#[rustfmt::skip]
pub use builtin::{MissingDoc, SoftLints};
-pub use context::{
- CheckLintNameResult, EarlyContext, FindLintError, LateContext, LintContext, LintStore,
-};
+pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore};
pub use early::{EarlyCheckNode, check_ast_node};
pub use late::{check_crate, late_lint_mod, unerased_lint_store};
pub use levels::LintLevelsBuilder;
@@ -606,6 +603,16 @@ macro_rules! add_lint_group {
"converted into hard error, see issue #127323 \
<https://github.com/rust-lang/rust/issues/127323> for more information",
);
+ store.register_removed(
+ "undefined_naked_function_abi",
+ "converted into hard error, see PR #139001 \
+ <https://github.com/rust-lang/rust/issues/139001> for more information",
+ );
+ store.register_removed(
+ "abi_unsupported_vector_types",
+ "converted into hard error, \
+ see <https://github.com/rust-lang/rust/issues/116558> for more information",
+ );
}
fn register_internals(store: &mut LintStore) {
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 51214c8..8ab64fb 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -6,7 +6,7 @@
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString, ElidedLifetimeInPathSubdiag,
- EmissionGuarantee, LintDiagnostic, MultiSpan, SubdiagMessageOp, Subdiagnostic, SuggestionStyle,
+ EmissionGuarantee, LintDiagnostic, MultiSpan, Subdiagnostic, SuggestionStyle,
};
use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId;
@@ -449,11 +449,7 @@ pub(crate) struct BuiltinUnpermittedTypeInitSub {
}
impl Subdiagnostic for BuiltinUnpermittedTypeInitSub {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut err = self.err;
loop {
if let Some(span) = err.span {
@@ -504,11 +500,7 @@ pub(crate) struct BuiltinClashingExternSub<'a> {
}
impl Subdiagnostic for BuiltinClashingExternSub<'_> {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut expected_str = DiagStyledString::new();
expected_str.push(self.expected.fn_sig(self.tcx).to_string(), false);
let mut found_str = DiagStyledString::new();
@@ -824,11 +816,7 @@ pub(crate) struct HiddenUnicodeCodepointsDiagLabels {
}
impl Subdiagnostic for HiddenUnicodeCodepointsDiagLabels {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
for (c, span) in self.spans {
diag.span_label(span, format!("{c:?}"));
}
@@ -842,11 +830,7 @@ pub(crate) enum HiddenUnicodeCodepointsDiagSub {
// Used because of multiple multipart_suggestion and note
impl Subdiagnostic for HiddenUnicodeCodepointsDiagSub {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
match self {
HiddenUnicodeCodepointsDiagSub::Escape { spans } => {
diag.multipart_suggestion_with_style(
@@ -1015,11 +999,7 @@ pub(crate) struct NonBindingLetSub {
}
impl Subdiagnostic for NonBindingLetSub {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let can_suggest_binding = self.drop_fn_start_end.is_some() || !self.is_assign_desugar;
if can_suggest_binding {
@@ -1303,11 +1283,7 @@ pub(crate) enum NonSnakeCaseDiagSub {
}
impl Subdiagnostic for NonSnakeCaseDiagSub {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
match self {
NonSnakeCaseDiagSub::Label { span } => {
diag.span_label(span, fluent::lint_label);
@@ -1629,11 +1605,7 @@ pub(crate) enum OverflowingBinHexSign {
}
impl Subdiagnostic for OverflowingBinHexSign {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
match self {
OverflowingBinHexSign::Positive => {
diag.note(fluent::lint_positive_note);
diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs
index 571cab9..00fa049 100644
--- a/compiler/rustc_lint/src/shadowed_into_iter.rs
+++ b/compiler/rustc_lint/src/shadowed_into_iter.rs
@@ -1,4 +1,4 @@
-use rustc_hir as hir;
+use rustc_hir::{self as hir, LangItem};
use rustc_middle::ty::{self, Ty};
use rustc_session::lint::FutureIncompatibilityReason;
use rustc_session::{declare_lint, impl_lint_pass};
@@ -81,7 +81,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else {
return;
};
- if Some(method_def_id) != cx.tcx.lang_items().into_iter_fn() {
+ if !cx.tcx.is_lang_item(method_def_id, LangItem::IntoIterIntoIter) {
return;
}
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index a6c82f5..a084dac 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -864,8 +864,8 @@ fn ty_is_known_nonnull<'tcx>(
return true;
}
- // `UnsafeCell` has its niche hidden.
- if def.is_unsafe_cell() {
+ // `UnsafeCell` and `UnsafePinned` have their niche hidden.
+ if def.is_unsafe_cell() || def.is_unsafe_pinned() {
return false;
}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 8a761a0..a49eb76 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -16,7 +16,6 @@
/// that are used by other parts of the compiler.
HardwiredLints => [
// tidy-alphabetical-start
- ABI_UNSUPPORTED_VECTOR_TYPES,
ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
AMBIGUOUS_ASSOCIATED_ITEMS,
AMBIGUOUS_GLOB_IMPORTS,
@@ -110,7 +109,6 @@
UNCONDITIONAL_PANIC,
UNCONDITIONAL_RECURSION,
UNCOVERED_PARAM_IN_PROJECTION,
- UNDEFINED_NAKED_FUNCTION_ABI,
UNEXPECTED_CFGS,
UNFULFILLED_LINT_EXPECTATIONS,
UNINHABITED_STATIC,
@@ -2831,39 +2829,6 @@
}
declare_lint! {
- /// The `undefined_naked_function_abi` lint detects naked function definitions that
- /// either do not specify an ABI or specify the Rust ABI.
- ///
- /// ### Example
- ///
- /// ```rust
- /// #![feature(asm_experimental_arch, naked_functions)]
- ///
- /// use std::arch::naked_asm;
- ///
- /// #[naked]
- /// pub fn default_abi() -> u32 {
- /// unsafe { naked_asm!(""); }
- /// }
- ///
- /// #[naked]
- /// pub extern "Rust" fn rust_abi() -> u32 {
- /// unsafe { naked_asm!(""); }
- /// }
- /// ```
- ///
- /// {{produces}}
- ///
- /// ### Explanation
- ///
- /// The Rust ABI is currently undefined. Therefore, naked functions should
- /// specify a non-Rust ABI.
- pub UNDEFINED_NAKED_FUNCTION_ABI,
- Warn,
- "undefined naked function ABI"
-}
-
-declare_lint! {
/// The `ineffective_unstable_trait_impl` lint detects `#[unstable]` attributes which are not used.
///
/// ### Example
@@ -5062,74 +5027,6 @@
}
declare_lint! {
- /// The `abi_unsupported_vector_types` lint detects function definitions and calls
- /// whose ABI depends on enabling certain target features, but those features are not enabled.
- ///
- /// ### Example
- ///
- /// ```rust,ignore (fails on non-x86_64)
- /// extern "C" fn missing_target_feature(_: std::arch::x86_64::__m256) {
- /// todo!()
- /// }
- ///
- /// #[target_feature(enable = "avx")]
- /// unsafe extern "C" fn with_target_feature(_: std::arch::x86_64::__m256) {
- /// todo!()
- /// }
- ///
- /// fn main() {
- /// let v = unsafe { std::mem::zeroed() };
- /// unsafe { with_target_feature(v); }
- /// }
- /// ```
- ///
- /// This will produce:
- ///
- /// ```text
- /// warning: ABI error: this function call uses a avx vector type, which is not enabled in the caller
- /// --> lint_example.rs:18:12
- /// |
- /// | unsafe { with_target_feature(v); }
- /// | ^^^^^^^^^^^^^^^^^^^^^^ function called here
- /// |
- /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- /// = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- /// = help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")])
- /// = note: `#[warn(abi_unsupported_vector_types)]` on by default
- ///
- ///
- /// warning: ABI error: this function definition uses a avx vector type, which is not enabled
- /// --> lint_example.rs:3:1
- /// |
- /// | pub extern "C" fn with_target_feature(_: std::arch::x86_64::__m256) {
- /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- /// |
- /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- /// = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- /// = help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")])
- /// ```
- ///
- ///
- ///
- /// ### Explanation
- ///
- /// The C ABI for `__m256` requires the value to be passed in an AVX register,
- /// which is only possible when the `avx` target feature is enabled.
- /// Therefore, `missing_target_feature` cannot be compiled without that target feature.
- /// A similar (but complementary) message is triggered when `with_target_feature` is called
- /// by a function that does not enable the `avx` target feature.
- ///
- /// Note that this lint is very similar to the `-Wpsabi` warning in `gcc`/`clang`.
- pub ABI_UNSUPPORTED_VECTOR_TYPES,
- Warn,
- "this function call or definition uses a vector type which is not enabled",
- @future_incompatible = FutureIncompatibleInfo {
- reason: FutureIncompatibilityReason::FutureReleaseErrorReportInDeps,
- reference: "issue #116558 <https://github.com/rust-lang/rust/issues/116558>",
- };
-}
-
-declare_lint! {
/// The `wasm_c_abi` lint detects usage of the `extern "C"` ABI of wasm that is affected
/// by a planned ABI change that has the goal of aligning Rust with the standard C ABI
/// of this target.
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 7fdbae3..b4069b3 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -249,7 +249,7 @@ pub fn from_str(x: &str) -> Option<Self> {
/// Converts an `Attribute` to a level.
pub fn from_attr(attr: &impl AttributeExt) -> Option<(Self, Option<LintExpectationId>)> {
- Self::from_symbol(attr.name_or_empty(), || Some(attr.id()))
+ attr.name().and_then(|name| Self::from_symbol(name, || Some(attr.id())))
}
/// Converts a `Symbol` to a level.
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 909083d..bc9516b 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -20,14 +20,12 @@
/// The central struct for constructing the `add_to_diag` method from an annotated struct.
pub(crate) struct SubdiagnosticDerive {
diag: syn::Ident,
- f: syn::Ident,
}
impl SubdiagnosticDerive {
pub(crate) fn new() -> Self {
let diag = format_ident!("diag");
- let f = format_ident!("f");
- Self { diag, f }
+ Self { diag }
}
pub(crate) fn into_tokens(self, mut structure: Structure<'_>) -> TokenStream {
@@ -86,19 +84,16 @@ pub(crate) fn into_tokens(self, mut structure: Structure<'_>) -> TokenStream {
};
let diag = &self.diag;
- let f = &self.f;
// FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here?
#[allow(keyword_idents_2024)]
let ret = structure.gen_impl(quote! {
gen impl rustc_errors::Subdiagnostic for @Self {
- fn add_to_diag_with<__G, __F>(
+ fn add_to_diag<__G>(
self,
#diag: &mut rustc_errors::Diag<'_, __G>,
- #f: &__F
) where
__G: rustc_errors::EmissionGuarantee,
- __F: rustc_errors::SubdiagMessageOp<__G>,
{
#implementation
}
@@ -384,11 +379,10 @@ fn generate_field_code_inner_path(
Ok(quote! {})
}
"subdiagnostic" => {
- let f = &self.parent.f;
let diag = &self.parent.diag;
let binding = &info.binding;
self.has_subdiagnostic = true;
- Ok(quote! { #binding.add_to_diag_with(#diag, #f); })
+ Ok(quote! { #binding.add_to_diag(#diag); })
}
_ => {
let mut span_attrs = vec![];
@@ -531,12 +525,11 @@ pub(crate) fn into_tokens(&mut self) -> Result<TokenStream, DiagnosticDeriveErro
let span_field = self.span_field.value_ref();
let diag = &self.parent.diag;
- let f = &self.parent.f;
let mut calls = TokenStream::new();
for (kind, slug, no_span) in kind_slugs {
let message = format_ident!("__message");
calls.extend(
- quote! { let #message = #f(#diag, crate::fluent_generated::#slug.into()); },
+ quote! { let #message = #diag.eagerly_translate(crate::fluent_generated::#slug); },
);
let name = format_ident!(
diff --git a/compiler/rustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs
index c4f584d..8505131 100644
--- a/compiler/rustc_macros/src/type_foldable.rs
+++ b/compiler/rustc_macros/src/type_foldable.rs
@@ -14,31 +14,33 @@ pub(super) fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_m
s.add_bounds(synstructure::AddBounds::Generics);
s.bind_with(|_| synstructure::BindStyle::Move);
+ let try_body_fold = s.each_variant(|vi| {
+ let bindings = vi.bindings();
+ vi.construct(|_, index| {
+ let bind = &bindings[index];
+
+ // retain value of fields with #[type_foldable(identity)]
+ if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") {
+ bind.to_token_stream()
+ } else {
+ quote! {
+ ::rustc_middle::ty::TypeFoldable::try_fold_with(#bind, __folder)?
+ }
+ }
+ })
+ });
+
let body_fold = s.each_variant(|vi| {
let bindings = vi.bindings();
vi.construct(|_, index| {
let bind = &bindings[index];
- let mut fixed = false;
-
// retain value of fields with #[type_foldable(identity)]
- bind.ast().attrs.iter().for_each(|x| {
- if !x.path().is_ident("type_foldable") {
- return;
- }
- let _ = x.parse_nested_meta(|nested| {
- if nested.path.is_ident("identity") {
- fixed = true;
- }
- Ok(())
- });
- });
-
- if fixed {
+ if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") {
bind.to_token_stream()
} else {
quote! {
- ::rustc_middle::ty::TypeFoldable::try_fold_with(#bind, __folder)?
+ ::rustc_middle::ty::TypeFoldable::fold_with(#bind, __folder)
}
}
})
@@ -51,8 +53,32 @@ fn try_fold_with<__F: ::rustc_middle::ty::FallibleTypeFolder<::rustc_middle::ty:
self,
__folder: &mut __F
) -> Result<Self, __F::Error> {
- Ok(match self { #body_fold })
+ Ok(match self { #try_body_fold })
+ }
+
+ fn fold_with<__F: ::rustc_middle::ty::TypeFolder<::rustc_middle::ty::TyCtxt<'tcx>>>(
+ self,
+ __folder: &mut __F
+ ) -> Self {
+ match self { #body_fold }
}
},
)
}
+
+fn has_ignore_attr(attrs: &[syn::Attribute], name: &'static str, meta: &'static str) -> bool {
+ let mut ignored = false;
+ attrs.iter().for_each(|attr| {
+ if !attr.path().is_ident(name) {
+ return;
+ }
+ let _ = attr.parse_nested_meta(|nested| {
+ if nested.path.is_ident(meta) {
+ ignored = true;
+ }
+ Ok(())
+ });
+ });
+
+ ignored
+}
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 028d5c8..3b44c44 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -1,6 +1,5 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(coroutines)]
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index 112954e..f0a898d 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -427,12 +427,21 @@ fn find_library_crate(
let (rlibs, rmetas, dylibs) =
candidates.entry(hash.to_string()).or_default();
- let path =
- try_canonicalize(&spf.path).unwrap_or_else(|_| spf.path.to_path_buf());
- if seen_paths.contains(&path) {
- continue;
- };
- seen_paths.insert(path.clone());
+ {
+ // As a perforamnce optimisation we canonicalize the path and skip
+ // ones we've already seeen. This allows us to ignore crates
+ // we know are exactual equal to ones we've already found.
+ // Going to the same crate through different symlinks does not change the result.
+ let path = try_canonicalize(&spf.path)
+ .unwrap_or_else(|_| spf.path.to_path_buf());
+ if seen_paths.contains(&path) {
+ continue;
+ };
+ seen_paths.insert(path);
+ }
+ // Use the original path (potentially with unresolved symlinks),
+ // filesystem code should not care, but this is nicer for diagnostics.
+ let path = spf.path.to_path_buf();
match kind {
CrateFlavor::Rlib => rlibs.insert(path, search_path.kind),
CrateFlavor::Rmeta => rmetas.insert(path, search_path.kind),
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index cfb0de8..cee9cff 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -226,8 +226,8 @@ fn process_module(&mut self, module: &ForeignModule) {
let mut wasm_import_module = None;
let mut import_name_type = None;
for item in items.iter() {
- match item.name_or_empty() {
- sym::name => {
+ match item.name() {
+ Some(sym::name) => {
if name.is_some() {
sess.dcx().emit_err(errors::MultipleNamesInLink { span: item.span() });
continue;
@@ -242,7 +242,7 @@ fn process_module(&mut self, module: &ForeignModule) {
}
name = Some((link_name, span));
}
- sym::kind => {
+ Some(sym::kind) => {
if kind.is_some() {
sess.dcx().emit_err(errors::MultipleKindsInLink { span: item.span() });
continue;
@@ -304,7 +304,7 @@ fn process_module(&mut self, module: &ForeignModule) {
};
kind = Some(link_kind);
}
- sym::modifiers => {
+ Some(sym::modifiers) => {
if modifiers.is_some() {
sess.dcx()
.emit_err(errors::MultipleLinkModifiers { span: item.span() });
@@ -316,7 +316,7 @@ fn process_module(&mut self, module: &ForeignModule) {
};
modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap()));
}
- sym::cfg => {
+ Some(sym::cfg) => {
if cfg.is_some() {
sess.dcx().emit_err(errors::MultipleCfgs { span: item.span() });
continue;
@@ -346,7 +346,7 @@ fn process_module(&mut self, module: &ForeignModule) {
}
cfg = Some(link_cfg.clone());
}
- sym::wasm_import_module => {
+ Some(sym::wasm_import_module) => {
if wasm_import_module.is_some() {
sess.dcx().emit_err(errors::MultipleWasmImport { span: item.span() });
continue;
@@ -357,7 +357,7 @@ fn process_module(&mut self, module: &ForeignModule) {
};
wasm_import_module = Some((link_wasm_import_module, item.span()));
}
- sym::import_name_type => {
+ Some(sym::import_name_type) => {
if import_name_type.is_some() {
sess.dcx()
.emit_err(errors::MultipleImportNameType { span: item.span() });
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 4cc12ca..3c22453 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -1332,29 +1332,30 @@ fn get_associated_item_or_field_def_ids(self, id: DefIndex) -> impl Iterator<Ite
}
fn get_associated_item(self, id: DefIndex, sess: &'a Session) -> ty::AssocItem {
- let name = if self.root.tables.opt_rpitit_info.get(self, id).is_some() {
- kw::Empty
- } else {
- self.item_name(id)
- };
- let (kind, has_self) = match self.def_kind(id) {
- DefKind::AssocConst => (ty::AssocKind::Const, false),
- DefKind::AssocFn => (ty::AssocKind::Fn, self.get_fn_has_self_parameter(id, sess)),
- DefKind::AssocTy => (ty::AssocKind::Type, false),
+ let kind = match self.def_kind(id) {
+ DefKind::AssocConst => ty::AssocKind::Const { name: self.item_name(id) },
+ DefKind::AssocFn => ty::AssocKind::Fn {
+ name: self.item_name(id),
+ has_self: self.get_fn_has_self_parameter(id, sess),
+ },
+ DefKind::AssocTy => {
+ let data = if let Some(rpitit_info) = self.root.tables.opt_rpitit_info.get(self, id)
+ {
+ ty::AssocTypeData::Rpitit(rpitit_info.decode(self))
+ } else {
+ ty::AssocTypeData::Normal(self.item_name(id))
+ };
+ ty::AssocKind::Type { data }
+ }
_ => bug!("cannot get associated-item of `{:?}`", self.def_key(id)),
};
let container = self.root.tables.assoc_container.get(self, id).unwrap();
- let opt_rpitit_info =
- self.root.tables.opt_rpitit_info.get(self, id).map(|d| d.decode(self));
ty::AssocItem {
- name,
kind,
def_id: self.local_def_id(id),
trait_item_def_id: self.get_trait_item_def_id(id),
container,
- fn_has_self_parameter: has_self,
- opt_rpitit_info,
}
}
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 5c8e288..3ea61d1 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -821,7 +821,9 @@ struct AnalyzeAttrState<'a> {
#[inline]
fn analyze_attr(attr: &impl AttributeExt, state: &mut AnalyzeAttrState<'_>) -> bool {
let mut should_encode = false;
- if !rustc_feature::encode_cross_crate(attr.name_or_empty()) {
+ if let Some(name) = attr.name()
+ && !rustc_feature::encode_cross_crate(name)
+ {
// Attributes not marked encode-cross-crate don't need to be encoded for downstream crates.
} else if attr.doc_str().is_some() {
// We keep all doc comments reachable to rustdoc because they might be "imported" into
@@ -1338,7 +1340,7 @@ fn should_encode_const(def_kind: DefKind) -> bool {
fn should_encode_fn_impl_trait_in_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool {
if let Some(assoc_item) = tcx.opt_associated_item(def_id)
&& assoc_item.container == ty::AssocItemContainer::Trait
- && assoc_item.kind == ty::AssocKind::Fn
+ && assoc_item.is_fn()
{
true
} else {
@@ -1691,7 +1693,7 @@ fn encode_info_for_assoc_item(&mut self, def_id: DefId) {
match item.container {
AssocItemContainer::Trait => {
- if let ty::AssocKind::Type = item.kind {
+ if item.is_type() {
self.encode_explicit_item_bounds(def_id);
self.encode_explicit_item_self_bounds(def_id);
if tcx.is_conditionally_const(def_id) {
@@ -1706,7 +1708,7 @@ fn encode_info_for_assoc_item(&mut self, def_id: DefId) {
}
}
}
- if let Some(rpitit_info) = item.opt_rpitit_info {
+ if let ty::AssocKind::Type { data: ty::AssocTypeData::Rpitit(rpitit_info) } = item.kind {
record!(self.tables.opt_rpitit_info[def_id] <- rpitit_info);
if matches!(rpitit_info, ty::ImplTraitInTraitData::Trait { .. }) {
record_array!(
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 2f27e5f..5aa81f4 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -36,9 +36,7 @@
use rustc_session::config::{SymbolManglingVersion, TargetModifier};
use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
use rustc_span::edition::Edition;
-use rustc_span::hygiene::{
- ExpnIndex, MacroKind, SyntaxContextDataNonRecursive as SyntaxContextData,
-};
+use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextKey};
use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Ident, Span, Symbol};
use rustc_target::spec::{PanicStrategy, TargetTuple};
use table::TableBuilder;
@@ -195,7 +193,7 @@ enum LazyState {
Previous(NonZero<usize>),
}
-type SyntaxContextTable = LazyTable<u32, Option<LazyValue<SyntaxContextData>>>;
+type SyntaxContextTable = LazyTable<u32, Option<LazyValue<SyntaxContextKey>>>;
type ExpnDataTable = LazyTable<ExpnIndex, Option<LazyValue<ExpnData>>>;
type ExpnHashTable = LazyTable<ExpnIndex, Option<LazyValue<ExpnHash>>>;
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 98273a0..d1bbb05 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -89,7 +89,6 @@ macro_rules! arena_types {
[] name_set: rustc_data_structures::unord::UnordSet<rustc_span::Symbol>,
[] autodiff_item: rustc_ast::expand::autodiff_attrs::AutoDiffItem,
[] ordered_name_set: rustc_data_structures::fx::FxIndexSet<rustc_span::Symbol>,
- [] pats: rustc_middle::ty::PatternKind<'tcx>,
[] valtree: rustc_middle::ty::ValTreeKind<'tcx>,
// Note that this deliberately duplicates items in the `rustc_hir::arena`,
diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs
index daf9542..fee707f 100644
--- a/compiler/rustc_middle/src/hir/map.rs
+++ b/compiler/rustc_middle/src/hir/map.rs
@@ -1,3 +1,7 @@
+//! This module used to contain a type called `Map`. That type has since been
+//! eliminated, and all its methods are now on `TyCtxt`. But the module name
+//! stays as `map` because there isn't an obviously better name for it.
+
use rustc_abi::ExternAbi;
use rustc_ast::visit::{VisitorResult, walk_list};
use rustc_data_structures::fingerprint::Fingerprint;
@@ -18,16 +22,6 @@
use crate::query::LocalCrate;
use crate::ty::TyCtxt;
-// FIXME: the structure was necessary in the past but now it
-// only serves as "namespace" for HIR-related methods, and can be
-// removed if all the methods are reasonably renamed and moved to tcx
-// (https://github.com/rust-lang/rust/pull/118256#issuecomment-1826442834).
-#[allow(unused)] // FIXME: temporary
-#[derive(Copy, Clone)]
-pub struct Map<'hir> {
- pub(super) tcx: TyCtxt<'hir>,
-}
-
/// An iterator that walks up the ancestor tree of a given `HirId`.
/// Constructed using `tcx.hir_parent_iter(hir_id)`.
struct ParentHirIterator<'tcx> {
@@ -335,7 +329,7 @@ pub fn hir_body_const_context(self, def_id: impl Into<DefId>) -> Option<ConstCon
/// Returns an iterator of the `DefId`s for all body-owners in this
/// crate. If you would prefer to iterate over the bodies
- /// themselves, you can do `self.hir().krate().body_ids.iter()`.
+ /// themselves, you can do `self.hir_crate(()).body_ids.iter()`.
#[inline]
pub fn hir_body_owners(self) -> impl Iterator<Item = LocalDefId> {
self.hir_crate_items(()).body_owners.iter().copied()
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 640ac70..a28dcb0 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -116,11 +116,6 @@ pub fn par_opaques(
}
impl<'tcx> TyCtxt<'tcx> {
- #[inline(always)]
- pub fn hir(self) -> map::Map<'tcx> {
- map::Map { tcx: self }
- }
-
pub fn parent_module(self, id: HirId) -> LocalModDefId {
if !id.is_owner() && self.def_kind(id.owner) == DefKind::Mod {
LocalModDefId::new_unchecked(id.owner.def_id)
diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs
index 60ce854..c3d1061 100644
--- a/compiler/rustc_middle/src/hir/place.rs
+++ b/compiler/rustc_middle/src/hir/place.rs
@@ -40,6 +40,8 @@ pub enum ProjectionKind {
/// A conversion from an opaque type to its hidden type so we can
/// do further projections on it.
+ ///
+ /// This is unused if `-Znext-solver` is enabled.
OpaqueCast,
}
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index 3cd148c..5b86037 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -39,15 +39,6 @@
pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues<TyCtxt<'tcx>>;
pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
-impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
- fn try_fold_with<F: ty::FallibleTypeFolder<TyCtxt<'tcx>>>(
- self,
- folder: &mut F,
- ) -> Result<Self, F::Error> {
- ty::util::fold_list(self, folder, |tcx, v| tcx.mk_canonical_var_infos(v))
- }
-}
-
/// When we canonicalize a value to form a query, we wind up replacing
/// various parts of it with canonical variables. This struct stores
/// those replaced bits to remember for when we process the query
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 1e61781..8fe2cc7 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -29,7 +29,6 @@
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::potential_query_instability)]
#![allow(rustc::untranslatable_diagnostic)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(allocator_api)]
diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs
index 7a91bfa..0f92c19 100644
--- a/compiler/rustc_middle/src/middle/lang_items.rs
+++ b/compiler/rustc_middle/src/middle/lang_items.rs
@@ -35,11 +35,10 @@ pub fn as_lang_item(self, def_id: DefId) -> Option<LangItem> {
/// returns a corresponding [`ty::ClosureKind`].
/// For any other [`DefId`] return `None`.
pub fn fn_trait_kind_from_def_id(self, id: DefId) -> Option<ty::ClosureKind> {
- let items = self.lang_items();
- match Some(id) {
- x if x == items.fn_trait() => Some(ty::ClosureKind::Fn),
- x if x == items.fn_mut_trait() => Some(ty::ClosureKind::FnMut),
- x if x == items.fn_once_trait() => Some(ty::ClosureKind::FnOnce),
+ match self.as_lang_item(id)? {
+ LangItem::Fn => Some(ty::ClosureKind::Fn),
+ LangItem::FnMut => Some(ty::ClosureKind::FnMut),
+ LangItem::FnOnce => Some(ty::ClosureKind::FnOnce),
_ => None,
}
}
@@ -48,11 +47,10 @@ pub fn fn_trait_kind_from_def_id(self, id: DefId) -> Option<ty::ClosureKind> {
/// returns a corresponding [`ty::ClosureKind`].
/// For any other [`DefId`] return `None`.
pub fn async_fn_trait_kind_from_def_id(self, id: DefId) -> Option<ty::ClosureKind> {
- let items = self.lang_items();
- match Some(id) {
- x if x == items.async_fn_trait() => Some(ty::ClosureKind::Fn),
- x if x == items.async_fn_mut_trait() => Some(ty::ClosureKind::FnMut),
- x if x == items.async_fn_once_trait() => Some(ty::ClosureKind::FnOnce),
+ match self.as_lang_item(id)? {
+ LangItem::AsyncFn => Some(ty::ClosureKind::Fn),
+ LangItem::AsyncFnMut => Some(ty::ClosureKind::FnMut),
+ LangItem::AsyncFnOnce => Some(ty::ClosureKind::FnOnce),
_ => None,
}
}
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 4dfb362..db19c85 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -1636,8 +1636,8 @@ pub fn find_self_call<'tcx>(
&body[block].terminator
&& let Operand::Constant(box ConstOperand { const_, .. }) = func
&& let ty::FnDef(def_id, fn_args) = *const_.ty().kind()
- && let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
- tcx.opt_associated_item(def_id)
+ && let Some(item) = tcx.opt_associated_item(def_id)
+ && item.is_method()
&& let [Spanned { node: Operand::Move(self_place) | Operand::Copy(self_place), .. }, ..] =
**args
{
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 5a038b2..d57019f 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -531,12 +531,12 @@ fn write_mir_intro<'tcx>(
// construct a scope tree and write it out
let mut scope_tree: FxHashMap<SourceScope, Vec<SourceScope>> = Default::default();
- for (index, scope_data) in body.source_scopes.iter().enumerate() {
+ for (index, scope_data) in body.source_scopes.iter_enumerated() {
if let Some(parent) = scope_data.parent_scope {
- scope_tree.entry(parent).or_default().push(SourceScope::new(index));
+ scope_tree.entry(parent).or_default().push(index);
} else {
// Only the argument scope has no parent, because it's the root.
- assert_eq!(index, OUTERMOST_SOURCE_SCOPE.index());
+ assert_eq!(index, OUTERMOST_SOURCE_SCOPE);
}
}
@@ -859,7 +859,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
BackwardIncompatibleDropHint { ref place, reason: _ } => {
// For now, we don't record the reason because there is only one use case,
// which is to report breaking change in drop order by Edition 2024
- write!(fmt, "backward incompatible drop({place:?})")
+ write!(fmt, "BackwardIncompatibleDropHint({place:?})")
}
}
}
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index ff9d32e..304b3ca 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -931,6 +931,8 @@ pub enum TerminatorKind<'tcx> {
asm_macro: InlineAsmMacro,
/// The template for the inline assembly, with placeholders.
+ #[type_foldable(identity)]
+ #[type_visitable(ignore)]
template: &'tcx [InlineAsmTemplatePiece],
/// The operands for the inline assembly, as `Operand`s or `Place`s.
@@ -941,6 +943,8 @@ pub enum TerminatorKind<'tcx> {
/// Source spans for each line of the inline assembly code. These are
/// used to map assembler errors back to the line in the source code.
+ #[type_foldable(identity)]
+ #[type_visitable(ignore)]
line_spans: &'tcx [Span],
/// Valid targets for the inline assembly.
@@ -1238,6 +1242,8 @@ pub enum ProjectionElem<V, T> {
/// Like an explicit cast from an opaque type to a concrete type, but without
/// requiring an intermediate variable.
+ ///
+ /// This is unused with `-Znext-solver`.
OpaqueCast(T),
/// A transmute from an unsafe binder to the type that it wraps. This is a projection
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index 3c83d96..de4d514 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -457,9 +457,15 @@ fn super_statement(
}
}
}
+ StatementKind::BackwardIncompatibleDropHint { place, .. } => {
+ self.visit_place(
+ place,
+ PlaceContext::NonUse(NonUseContext::BackwardIncompatibleDropHint),
+ location
+ );
+ }
StatementKind::ConstEvalCounter => {}
StatementKind::Nop => {}
- StatementKind::BackwardIncompatibleDropHint { .. } => {}
}
}
@@ -1348,6 +1354,8 @@ pub enum NonUseContext {
AscribeUserTy(ty::Variance),
/// The data of a user variable, for debug info.
VarDebugInfo,
+ /// A `BackwardIncompatibleDropHint` statement, meant for edition 2024 lints.
+ BackwardIncompatibleDropHint,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -1422,7 +1430,9 @@ pub fn ambient_variance(self) -> ty::Variance {
use NonUseContext::*;
match self {
PlaceContext::MutatingUse(_) => ty::Invariant,
- PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant,
+ PlaceContext::NonUse(
+ StorageDead | StorageLive | VarDebugInfo | BackwardIncompatibleDropHint,
+ ) => ty::Invariant,
PlaceContext::NonMutatingUse(
Inspect | Copy | Move | PlaceMention | SharedBorrow | FakeBorrow | RawBorrow
| Projection,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 28a59d3..3432648 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -161,11 +161,11 @@
/// Represents crate as a whole (as distinct from the top-level crate module).
///
- /// If you call `hir_crate` (e.g., indirectly by calling `tcx.hir_crate()`),
- /// we will have to assume that any change means that you need to be recompiled.
- /// This is because the `hir_crate` query gives you access to all other items.
- /// To avoid this fate, do not call `tcx.hir_crate()`; instead,
- /// prefer wrappers like [`TyCtxt::hir_visit_all_item_likes_in_crate`].
+ /// If you call `tcx.hir_crate(())` we will have to assume that any change
+ /// means that you need to be recompiled. This is because the `hir_crate`
+ /// query gives you access to all other items. To avoid this fate, do not
+ /// call `tcx.hir_crate(())`; instead, prefer wrappers like
+ /// [`TyCtxt::hir_visit_all_item_likes_in_crate`].
query hir_crate(key: ()) -> &'tcx Crate<'tcx> {
arena_cache
eval_always
@@ -197,7 +197,7 @@
/// Gives access to the HIR node's parent for the HIR owner `key`.
///
- /// This can be conveniently accessed by methods on `tcx.hir()`.
+ /// This can be conveniently accessed by `tcx.hir_*` methods.
/// Avoid calling this query directly.
query hir_owner_parent(key: hir::OwnerId) -> hir::HirId {
desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key) }
@@ -205,7 +205,7 @@
/// Gives access to the HIR nodes and bodies inside `key` if it's a HIR owner.
///
- /// This can be conveniently accessed by methods on `tcx.hir()`.
+ /// This can be conveniently accessed by `tcx.hir_*` methods.
/// Avoid calling this query directly.
query opt_hir_owner_nodes(key: LocalDefId) -> Option<&'tcx hir::OwnerNodes<'tcx>> {
desc { |tcx| "getting HIR owner items in `{}`", tcx.def_path_str(key) }
@@ -214,7 +214,7 @@
/// Gives access to the HIR attributes inside the HIR owner `key`.
///
- /// This can be conveniently accessed by methods on `tcx.hir()`.
+ /// This can be conveniently accessed by `tcx.hir_*` methods.
/// Avoid calling this query directly.
query hir_attr_map(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> {
desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key) }
@@ -387,6 +387,15 @@
}
}
+ query stalled_generators_within(
+ key: LocalDefId
+ ) -> &'tcx ty::List<LocalDefId> {
+ desc {
+ |tcx| "computing the coroutines defined within `{}`",
+ tcx.def_path_str(key.to_def_id())
+ }
+ }
+
/// Returns the explicitly user-written *bounds* on the associated or opaque type given by `DefId`
/// that must be proven true at definition site (and which can be assumed at usage sites).
///
diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index f78398c..5431097 100644
--- a/compiler/rustc_middle/src/query/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -16,8 +16,7 @@
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_session::Session;
use rustc_span::hygiene::{
- ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext,
- SyntaxContextDataNonRecursive as SyntaxContextData,
+ ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextKey,
};
use rustc_span::source_map::Spanned;
use rustc_span::{
@@ -567,7 +566,7 @@ fn decode_syntax_context(&mut self) -> SyntaxContext {
// We look up the position of the associated `SyntaxData` and decode it.
let pos = syntax_contexts.get(&id).unwrap();
this.with_position(pos.to_usize(), |decoder| {
- let data: SyntaxContextData = decode_tagged(decoder, TAG_SYNTAX_CONTEXT);
+ let data: SyntaxContextKey = decode_tagged(decoder, TAG_SYNTAX_CONTEXT);
data
})
})
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index a099f77..69b6f88 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -366,7 +366,7 @@ pub fn provided_to_erased<'tcx>(
pub type Storage<'tcx> = <$($K)* as keys::Key>::Cache<Erase<$V>>;
- // Ensure that keys grow no larger than 80 bytes by accident.
+ // Ensure that keys grow no larger than 88 bytes by accident.
// Increase this limit if necessary, but do try to keep the size low if possible
#[cfg(target_pointer_width = "64")]
const _: () = {
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index f8ab555..a61a6c5 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -5,7 +5,7 @@
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
use rustc_span::Span;
-use crate::ty::{self, Ty, TyCtxt};
+use crate::ty::{Ty, TyCtxt};
#[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
pub enum PointerCoercion {
@@ -133,7 +133,7 @@ pub fn method_call<'tcx>(&self, tcx: TyCtxt<'tcx>) -> DefId {
};
tcx.associated_items(trait_def_id)
.in_definition_order()
- .find(|m| m.kind == ty::AssocKind::Fn)
+ .find(|item| item.is_fn())
.unwrap()
.def_id
}
@@ -214,3 +214,25 @@ pub enum CustomCoerceUnsized {
/// Records the index of the field being coerced.
Struct(FieldIdx),
}
+
+/// Represents an implicit coercion applied to the scrutinee of a match before testing a pattern
+/// against it. Currently, this is used only for implicit dereferences.
+#[derive(Clone, Copy, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
+pub struct PatAdjustment<'tcx> {
+ pub kind: PatAdjust,
+ /// The type of the scrutinee before the adjustment is applied, or the "adjusted type" of the
+ /// pattern.
+ pub source: Ty<'tcx>,
+}
+
+/// Represents implicit coercions of patterns' types, rather than values' types.
+#[derive(Clone, Copy, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
+#[derive(TypeFoldable, TypeVisitable)]
+pub enum PatAdjust {
+ /// An implicit dereference before matching, such as when matching the pattern `0` against a
+ /// scrutinee of type `&u8` or `&mut u8`.
+ BuiltinDeref,
+ /// An implicit call to `Deref(Mut)::deref(_mut)` before matching, such as when matching the
+ /// pattern `[..]` against a scrutinee of type `Vec<T>`.
+ OverloadedDeref,
+}
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 00fe5cb..d92b4f9 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -53,6 +53,8 @@ impl AdtFlags: u16 {
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 8;
/// Indicates whether the type is `UnsafeCell`.
const IS_UNSAFE_CELL = 1 << 9;
+ /// Indicates whether the type is `UnsafePinned`.
+ const IS_UNSAFE_PINNED = 1 << 10;
}
}
rustc_data_structures::external_bitflags_debug! { AdtFlags }
@@ -302,6 +304,9 @@ pub(super) fn new(
if tcx.is_lang_item(did, LangItem::UnsafeCell) {
flags |= AdtFlags::IS_UNSAFE_CELL;
}
+ if tcx.is_lang_item(did, LangItem::UnsafePinned) {
+ flags |= AdtFlags::IS_UNSAFE_PINNED;
+ }
AdtDefData { did, variants, flags, repr }
}
@@ -405,6 +410,12 @@ pub fn is_unsafe_cell(self) -> bool {
self.flags().contains(AdtFlags::IS_UNSAFE_CELL)
}
+ /// Returns `true` if this is `UnsafePinned<T>`.
+ #[inline]
+ pub fn is_unsafe_pinned(self) -> bool {
+ self.flags().contains(AdtFlags::IS_UNSAFE_PINNED)
+ }
+
/// Returns `true` if this is `ManuallyDrop<T>`.
#[inline]
pub fn is_manually_drop(self) -> bool {
diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs
index bbaf735..78b2e26 100644
--- a/compiler/rustc_middle/src/ty/assoc.rs
+++ b/compiler/rustc_middle/src/ty/assoc.rs
@@ -18,27 +18,33 @@ pub enum AssocItemContainer {
#[derive(Copy, Clone, Debug, PartialEq, HashStable, Eq, Hash, Encodable, Decodable)]
pub struct AssocItem {
pub def_id: DefId,
- pub name: Symbol,
pub kind: AssocKind,
pub container: AssocItemContainer,
/// If this is an item in an impl of a trait then this is the `DefId` of
/// the associated item on the trait that this implements.
pub trait_item_def_id: Option<DefId>,
-
- /// Whether this is a method with an explicit self
- /// as its first parameter, allowing method calls.
- pub fn_has_self_parameter: bool,
-
- /// `Some` if the associated item (an associated type) comes from the
- /// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData`
- /// provides additional information about its source.
- pub opt_rpitit_info: Option<ty::ImplTraitInTraitData>,
}
impl AssocItem {
+ // Gets the identifier, if it has one.
+ pub fn opt_name(&self) -> Option<Symbol> {
+ match self.kind {
+ ty::AssocKind::Type { data: AssocTypeData::Normal(name) } => Some(name),
+ ty::AssocKind::Type { data: AssocTypeData::Rpitit(_) } => None,
+ ty::AssocKind::Const { name } => Some(name),
+ ty::AssocKind::Fn { name, .. } => Some(name),
+ }
+ }
+
+ // Gets the identifier name. Aborts if it lacks one, i.e. is an RPITIT
+ // associated type.
+ pub fn name(&self) -> Symbol {
+ self.opt_name().expect("name of non-Rpitit assoc item")
+ }
+
pub fn ident(&self, tcx: TyCtxt<'_>) -> Ident {
- Ident::new(self.name, tcx.def_ident_span(self.def_id).unwrap())
+ Ident::new(self.name(), tcx.def_ident_span(self.def_id).unwrap())
}
/// Gets the defaultness of the associated item.
@@ -78,35 +84,65 @@ pub fn impl_container(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
pub fn signature(&self, tcx: TyCtxt<'_>) -> String {
match self.kind {
- ty::AssocKind::Fn => {
+ ty::AssocKind::Fn { .. } => {
// We skip the binder here because the binder would deanonymize all
// late-bound regions, and we don't want method signatures to show up
// `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound
// regions just fine, showing `fn(&MyType)`.
tcx.fn_sig(self.def_id).instantiate_identity().skip_binder().to_string()
}
- ty::AssocKind::Type => format!("type {};", self.name),
- ty::AssocKind::Const => {
- format!(
- "const {}: {:?};",
- self.name,
- tcx.type_of(self.def_id).instantiate_identity()
- )
+ ty::AssocKind::Type { .. } => format!("type {};", self.name()),
+ ty::AssocKind::Const { name } => {
+ format!("const {}: {:?};", name, tcx.type_of(self.def_id).instantiate_identity())
}
}
}
pub fn descr(&self) -> &'static str {
match self.kind {
- ty::AssocKind::Const => "associated const",
- ty::AssocKind::Fn if self.fn_has_self_parameter => "method",
- ty::AssocKind::Fn => "associated function",
- ty::AssocKind::Type => "associated type",
+ ty::AssocKind::Const { .. } => "associated const",
+ ty::AssocKind::Fn { has_self: true, .. } => "method",
+ ty::AssocKind::Fn { has_self: false, .. } => "associated function",
+ ty::AssocKind::Type { .. } => "associated type",
+ }
+ }
+
+ pub fn namespace(&self) -> Namespace {
+ match self.kind {
+ ty::AssocKind::Type { .. } => Namespace::TypeNS,
+ ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
+ }
+ }
+
+ pub fn as_def_kind(&self) -> DefKind {
+ match self.kind {
+ AssocKind::Const { .. } => DefKind::AssocConst,
+ AssocKind::Fn { .. } => DefKind::AssocFn,
+ AssocKind::Type { .. } => DefKind::AssocTy,
+ }
+ }
+ pub fn is_type(&self) -> bool {
+ matches!(self.kind, ty::AssocKind::Type { .. })
+ }
+
+ pub fn is_fn(&self) -> bool {
+ matches!(self.kind, ty::AssocKind::Fn { .. })
+ }
+
+ pub fn is_method(&self) -> bool {
+ matches!(self.kind, ty::AssocKind::Fn { has_self: true, .. })
+ }
+
+ pub fn as_tag(&self) -> AssocTag {
+ match self.kind {
+ AssocKind::Const { .. } => AssocTag::Const,
+ AssocKind::Fn { .. } => AssocTag::Fn,
+ AssocKind::Type { .. } => AssocTag::Type,
}
}
pub fn is_impl_trait_in_trait(&self) -> bool {
- self.opt_rpitit_info.is_some()
+ matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
}
/// Returns true if:
@@ -114,7 +150,7 @@ pub fn is_impl_trait_in_trait(&self) -> bool {
/// - If it is in a trait impl, the item from the original trait has this attribute, or
/// - It is an inherent assoc const.
pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool {
- if self.kind != ty::AssocKind::Const {
+ if !matches!(self.kind, ty::AssocKind::Const { .. }) {
return false;
}
@@ -129,25 +165,34 @@ pub fn is_type_const_capable(&self, tcx: TyCtxt<'_>) -> bool {
}
#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
+pub enum AssocTypeData {
+ Normal(Symbol),
+ /// The associated type comes from an RPITIT. It has no name, and the
+ /// `ImplTraitInTraitData` provides additional information about its
+ /// source.
+ Rpitit(ty::ImplTraitInTraitData),
+}
+
+#[derive(Copy, Clone, PartialEq, Debug, HashStable, Eq, Hash, Encodable, Decodable)]
pub enum AssocKind {
- Const,
- Fn,
- Type,
+ Const { name: Symbol },
+ Fn { name: Symbol, has_self: bool },
+ Type { data: AssocTypeData },
}
impl AssocKind {
pub fn namespace(&self) -> Namespace {
match *self {
- ty::AssocKind::Type => Namespace::TypeNS,
- ty::AssocKind::Const | ty::AssocKind::Fn => Namespace::ValueNS,
+ ty::AssocKind::Type { .. } => Namespace::TypeNS,
+ ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => Namespace::ValueNS,
}
}
pub fn as_def_kind(&self) -> DefKind {
match self {
- AssocKind::Const => DefKind::AssocConst,
- AssocKind::Fn => DefKind::AssocFn,
- AssocKind::Type => DefKind::AssocTy,
+ AssocKind::Const { .. } => DefKind::AssocConst,
+ AssocKind::Fn { .. } => DefKind::AssocFn,
+ AssocKind::Type { .. } => DefKind::AssocTy,
}
}
}
@@ -155,15 +200,22 @@ pub fn as_def_kind(&self) -> DefKind {
impl std::fmt::Display for AssocKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
- // FIXME: fails to distinguish between "associated function" and
- // "method" because `has_self` isn't known here.
- AssocKind::Fn => write!(f, "method"),
- AssocKind::Const => write!(f, "associated const"),
- AssocKind::Type => write!(f, "associated type"),
+ AssocKind::Fn { has_self: true, .. } => write!(f, "method"),
+ AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"),
+ AssocKind::Const { .. } => write!(f, "associated const"),
+ AssocKind::Type { .. } => write!(f, "associated type"),
}
}
}
+// Like `AssocKind`, but just the tag, no fields. Used in various kinds of matching.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub enum AssocTag {
+ Const,
+ Fn,
+ Type,
+}
+
/// A list of `ty::AssocItem`s in definition order that allows for efficient lookup by name.
///
/// When doing lookup by name, we try to postpone hygienic comparison for as long as possible since
@@ -171,17 +223,17 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
/// done only on items with the same name.
#[derive(Debug, Clone, PartialEq, HashStable)]
pub struct AssocItems {
- items: SortedIndexMultiMap<u32, Symbol, ty::AssocItem>,
+ items: SortedIndexMultiMap<u32, Option<Symbol>, ty::AssocItem>,
}
impl AssocItems {
/// Constructs an `AssociatedItems` map from a series of `ty::AssocItem`s in definition order.
pub fn new(items_in_def_order: impl IntoIterator<Item = ty::AssocItem>) -> Self {
- let items = items_in_def_order.into_iter().map(|item| (item.name, item)).collect();
+ let items = items_in_def_order.into_iter().map(|item| (item.opt_name(), item)).collect();
AssocItems { items }
}
- /// Returns a slice of associated items in the order they were defined.
+ /// Returns an iterator over associated items in the order they were defined.
///
/// New code should avoid relying on definition order. If you need a particular associated item
/// for a known trait, make that trait a lang item instead of indexing this array.
@@ -194,11 +246,14 @@ pub fn len(&self) -> usize {
}
/// Returns an iterator over all associated items with the given name, ignoring hygiene.
+ ///
+ /// Panics if `name.is_empty()` returns `true`.
pub fn filter_by_name_unhygienic(
&self,
name: Symbol,
) -> impl '_ + Iterator<Item = &ty::AssocItem> {
- self.items.get_by_key(name)
+ assert!(!name.is_empty());
+ self.items.get_by_key(Some(name))
}
/// Returns the associated item with the given identifier and `AssocKind`, if one exists.
@@ -207,27 +262,14 @@ pub fn find_by_ident_and_kind(
&self,
tcx: TyCtxt<'_>,
ident: Ident,
- kind: AssocKind,
+ assoc_tag: AssocTag,
parent_def_id: DefId,
) -> Option<&ty::AssocItem> {
self.filter_by_name_unhygienic(ident.name)
- .filter(|item| item.kind == kind)
+ .filter(|item| item.as_tag() == assoc_tag)
.find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
}
- /// Returns the associated item with the given identifier and any of `AssocKind`, if one
- /// exists. The identifier is matched hygienically.
- pub fn find_by_ident_and_kinds(
- &self,
- tcx: TyCtxt<'_>,
- ident: Ident,
- // Sorted in order of what kinds to look at
- kinds: &[AssocKind],
- parent_def_id: DefId,
- ) -> Option<&ty::AssocItem> {
- kinds.iter().find_map(|kind| self.find_by_ident_and_kind(tcx, ident, *kind, parent_def_id))
- }
-
/// Returns the associated item with the given identifier in the given `Namespace`, if one
/// exists. The identifier is matched hygienically.
pub fn find_by_ident_and_namespace(
@@ -238,7 +280,7 @@ pub fn find_by_ident_and_namespace(
parent_def_id: DefId,
) -> Option<&ty::AssocItem> {
self.filter_by_name_unhygienic(ident.name)
- .filter(|item| item.kind.namespace() == ns)
+ .filter(|item| item.namespace() == ns)
.find(|item| tcx.hygienic_eq(ident, item.ident(tcx), parent_def_id))
}
}
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index ae1c6c6..dc5fe2d 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -3,6 +3,7 @@
use rustc_data_structures::intern::Interned;
use rustc_error_messages::MultiSpan;
use rustc_macros::HashStable;
+use rustc_type_ir::walk::TypeWalker;
use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
use crate::ty::{self, Ty, TyCtxt};
@@ -243,4 +244,18 @@ pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
pub fn is_ct_infer(self) -> bool {
matches!(self.kind(), ty::ConstKind::Infer(_))
}
+
+ /// Iterator that walks `self` and any types reachable from
+ /// `self`, in depth-first order. Note that just walks the types
+ /// that appear in `self`, it does not descend into the fields of
+ /// structs or variants. For example:
+ ///
+ /// ```text
+ /// isize => { isize }
+ /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
+ /// [isize] => { [isize], isize }
+ /// ```
+ pub fn walk(self) -> TypeWalker<TyCtxt<'tcx>> {
+ TypeWalker::new(self.into())
+ }
}
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index abf6cbb..98057a2 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -106,7 +106,7 @@ fn mk_predefined_opaques_in_body(
) -> Self::PredefinedOpaques {
self.mk_predefined_opaques_in_body(data)
}
- type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>;
+ type LocalDefIds = &'tcx ty::List<LocalDefId>;
type CanonicalVars = CanonicalVarInfos<'tcx>;
fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
self.mk_canonical_var_infos(infos)
@@ -464,7 +464,7 @@ fn as_lang_item(self, def_id: DefId) -> Option<TraitSolverLangItem> {
fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator<Item = DefId> {
self.associated_items(def_id)
.in_definition_order()
- .filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type))
+ .filter(|assoc_item| assoc_item.is_type())
.map(|assoc_item| assoc_item.def_id)
}
@@ -674,9 +674,24 @@ fn anonymize_bound_vars<T: TypeFoldable<TyCtxt<'tcx>>>(
self.anonymize_bound_vars(binder)
}
- fn opaque_types_defined_by(self, defining_anchor: LocalDefId) -> Self::DefiningOpaqueTypes {
+ fn opaque_types_defined_by(self, defining_anchor: LocalDefId) -> Self::LocalDefIds {
self.opaque_types_defined_by(defining_anchor)
}
+
+ fn opaque_types_and_generators_defined_by(
+ self,
+ defining_anchor: Self::LocalDefId,
+ ) -> Self::LocalDefIds {
+ if self.next_trait_solver_globally() {
+ self.mk_local_def_ids_from_iter(
+ self.opaque_types_defined_by(defining_anchor)
+ .iter()
+ .chain(self.stalled_generators_within(defining_anchor)),
+ )
+ } else {
+ self.opaque_types_defined_by(defining_anchor)
+ }
+ }
}
macro_rules! bidirectional_lang_item_map {
@@ -870,7 +885,7 @@ fn intern_ty(&self, kind: TyKind<'tcx>, sess: &Session, untracked: &Untracked) -
Ty(Interned::new_unchecked(
self.type_
.intern(kind, |kind| {
- let flags = super::flags::FlagComputation::for_kind(&kind);
+ let flags = ty::FlagComputation::<TyCtxt<'tcx>>::for_kind(&kind);
let stable_hash = self.stable_hash(&flags, sess, untracked, &kind);
InternedInSet(self.arena.alloc(WithCachedTypeInfo {
@@ -896,7 +911,7 @@ fn intern_const(
Const(Interned::new_unchecked(
self.const_
.intern(kind, |kind: ty::ConstKind<'_>| {
- let flags = super::flags::FlagComputation::for_const_kind(&kind);
+ let flags = ty::FlagComputation::<TyCtxt<'tcx>>::for_const_kind(&kind);
let stable_hash = self.stable_hash(&flags, sess, untracked, &kind);
InternedInSet(self.arena.alloc(WithCachedTypeInfo {
@@ -912,7 +927,7 @@ fn intern_const(
fn stable_hash<'a, T: HashStable<StableHashingContext<'a>>>(
&self,
- flags: &ty::flags::FlagComputation,
+ flags: &ty::FlagComputation<TyCtxt<'tcx>>,
sess: &'a Session,
untracked: &'a Untracked,
val: &T,
@@ -940,7 +955,7 @@ fn intern_predicate(
Predicate(Interned::new_unchecked(
self.predicate
.intern(kind, |kind| {
- let flags = super::flags::FlagComputation::for_predicate(kind);
+ let flags = ty::FlagComputation::<TyCtxt<'tcx>>::for_predicate(kind);
let stable_hash = self.stable_hash(&flags, sess, untracked, &kind);
@@ -961,7 +976,7 @@ fn intern_clauses(&self, clauses: &[Clause<'tcx>]) -> Clauses<'tcx> {
} else {
self.clauses
.intern_ref(clauses, || {
- let flags = super::flags::FlagComputation::for_clauses(clauses);
+ let flags = ty::FlagComputation::<TyCtxt<'tcx>>::for_clauses(clauses);
InternedInSet(ListWithCachedTypeInfo::from_arena(
&*self.arena,
@@ -2147,7 +2162,7 @@ pub fn return_type_impl_or_dyn_traits(
return vec![];
};
- let mut v = TraitObjectVisitor(vec![], self.hir());
+ let mut v = TraitObjectVisitor(vec![]);
v.visit_ty_unambig(hir_output);
v.0
}
@@ -2160,7 +2175,7 @@ pub fn return_type_impl_or_dyn_traits_with_type_alias(
scope_def_id: LocalDefId,
) -> Option<(Vec<&'tcx hir::Ty<'tcx>>, Span, Option<Span>)> {
let hir_id = self.local_def_id_to_hir_id(scope_def_id);
- let mut v = TraitObjectVisitor(vec![], self.hir());
+ let mut v = TraitObjectVisitor(vec![]);
// when the return type is a type alias
if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir_fn_decl_by_hir_id(hir_id)
&& let hir::TyKind::Path(hir::QPath::Resolved(
@@ -2906,11 +2921,11 @@ pub fn mk_clauses(self, clauses: &[Clause<'tcx>]) -> Clauses<'tcx> {
self.interners.intern_clauses(clauses)
}
- pub fn mk_local_def_ids(self, clauses: &[LocalDefId]) -> &'tcx List<LocalDefId> {
+ pub fn mk_local_def_ids(self, def_ids: &[LocalDefId]) -> &'tcx List<LocalDefId> {
// FIXME consider asking the input slice to be sorted to avoid
// re-interning permutations, in which case that would be asserted
// here.
- self.intern_local_def_ids(clauses)
+ self.intern_local_def_ids(def_ids)
}
pub fn mk_local_def_ids_from_iter<I, T>(self, iter: I) -> T::Output
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index d3abb3d..fbb57b8 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -571,15 +571,15 @@ pub fn suggest_constraining_type_params<'a>(
}
/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
-pub struct TraitObjectVisitor<'tcx>(pub Vec<&'tcx hir::Ty<'tcx>>, pub crate::hir::map::Map<'tcx>);
+pub(crate) struct TraitObjectVisitor<'tcx>(pub(crate) Vec<&'tcx hir::Ty<'tcx>>);
impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
match ty.kind {
hir::TyKind::TraitObject(_, tagged_ptr)
if let hir::Lifetime {
- res:
- hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static,
+ kind:
+ hir::LifetimeKind::ImplicitObjectLifetimeDefault | hir::LifetimeKind::Static,
..
} = tagged_ptr.pointer() =>
{
@@ -592,18 +592,6 @@ fn visit_ty(&mut self, ty: &'v hir::Ty<'v, AmbigArg>) {
}
}
-/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for.
-pub struct StaticLifetimeVisitor<'tcx>(pub Vec<Span>, pub crate::hir::map::Map<'tcx>);
-
-impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> {
- fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) {
- if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static = lt.res
- {
- self.0.push(lt.ident.span);
- }
- }
-}
-
pub struct IsSuggestableVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
infer_suggestable: bool,
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
deleted file mode 100644
index 2424923..0000000
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ /dev/null
@@ -1,359 +0,0 @@
-use std::slice;
-
-use crate::ty::{self, GenericArg, GenericArgKind, InferConst, Ty, TypeFlags};
-
-#[derive(Debug)]
-pub struct FlagComputation {
- pub flags: TypeFlags,
-
- /// see `Ty::outer_exclusive_binder` for details
- pub outer_exclusive_binder: ty::DebruijnIndex,
-}
-
-impl FlagComputation {
- fn new() -> FlagComputation {
- FlagComputation { flags: TypeFlags::empty(), outer_exclusive_binder: ty::INNERMOST }
- }
-
- #[allow(rustc::usage_of_ty_tykind)]
- pub fn for_kind(kind: &ty::TyKind<'_>) -> FlagComputation {
- let mut result = FlagComputation::new();
- result.add_kind(kind);
- result
- }
-
- pub fn for_predicate(binder: ty::Binder<'_, ty::PredicateKind<'_>>) -> FlagComputation {
- let mut result = FlagComputation::new();
- result.add_predicate(binder);
- result
- }
-
- pub fn for_const_kind(kind: &ty::ConstKind<'_>) -> FlagComputation {
- let mut result = FlagComputation::new();
- result.add_const_kind(kind);
- result
- }
-
- pub fn for_clauses(clauses: &[ty::Clause<'_>]) -> FlagComputation {
- let mut result = FlagComputation::new();
- for c in clauses {
- result.add_flags(c.as_predicate().flags());
- result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder());
- }
- result
- }
-
- fn add_flags(&mut self, flags: TypeFlags) {
- self.flags = self.flags | flags;
- }
-
- /// indicates that `self` refers to something at binding level `binder`
- fn add_bound_var(&mut self, binder: ty::DebruijnIndex) {
- let exclusive_binder = binder.shifted_in(1);
- self.add_exclusive_binder(exclusive_binder);
- }
-
- /// indicates that `self` refers to something *inside* binding
- /// level `binder` -- not bound by `binder`, but bound by the next
- /// binder internal to it
- fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) {
- self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder);
- }
-
- /// Adds the flags/depth from a set of types that appear within the current type, but within a
- /// region binder.
- fn bound_computation<T, F>(&mut self, value: ty::Binder<'_, T>, f: F)
- where
- F: FnOnce(&mut Self, T),
- {
- let mut computation = FlagComputation::new();
-
- if !value.bound_vars().is_empty() {
- computation.add_flags(TypeFlags::HAS_BINDER_VARS);
- }
-
- f(&mut computation, value.skip_binder());
-
- self.add_flags(computation.flags);
-
- // The types that contributed to `computation` occurred within
- // a region binder, so subtract one from the region depth
- // within when adding the depth to `self`.
- let outer_exclusive_binder = computation.outer_exclusive_binder;
- if outer_exclusive_binder > ty::INNERMOST {
- self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1));
- } // otherwise, this binder captures nothing
- }
-
- #[allow(rustc::usage_of_ty_tykind)]
- fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
- match kind {
- &ty::Bool
- | &ty::Char
- | &ty::Int(_)
- | &ty::Float(_)
- | &ty::Uint(_)
- | &ty::Never
- | &ty::Str
- | &ty::Foreign(..) => {}
-
- &ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
-
- &ty::Param(_) => {
- self.add_flags(TypeFlags::HAS_TY_PARAM);
- }
-
- &ty::Closure(_, args)
- | &ty::Coroutine(_, args)
- | &ty::CoroutineClosure(_, args)
- | &ty::CoroutineWitness(_, args) => {
- self.add_args(args);
- }
-
- &ty::Bound(debruijn, _) => {
- self.add_bound_var(debruijn);
- self.add_flags(TypeFlags::HAS_TY_BOUND);
- }
-
- &ty::Placeholder(..) => {
- self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER);
- }
-
- &ty::Infer(infer) => match infer {
- ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
- self.add_flags(TypeFlags::HAS_TY_FRESH)
- }
-
- ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
- self.add_flags(TypeFlags::HAS_TY_INFER)
- }
- },
-
- &ty::Adt(_, args) => {
- self.add_args(args);
- }
-
- &ty::Alias(kind, data) => {
- self.add_flags(match kind {
- ty::Projection => TypeFlags::HAS_TY_PROJECTION,
- ty::Weak => TypeFlags::HAS_TY_WEAK,
- ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
- ty::Inherent => TypeFlags::HAS_TY_INHERENT,
- });
-
- self.add_alias_ty(data);
- }
-
- &ty::Dynamic(obj, r, _) => {
- for predicate in obj.iter() {
- self.bound_computation(predicate, |computation, predicate| match predicate {
- ty::ExistentialPredicate::Trait(tr) => computation.add_args(tr.args),
- ty::ExistentialPredicate::Projection(p) => {
- computation.add_existential_projection(&p);
- }
- ty::ExistentialPredicate::AutoTrait(_) => {}
- });
- }
-
- self.add_region(r);
- }
-
- &ty::Array(tt, len) => {
- self.add_ty(tt);
- self.add_const(len);
- }
-
- &ty::Pat(ty, pat) => {
- self.add_ty(ty);
- match *pat {
- ty::PatternKind::Range { start, end } => {
- self.add_const(start);
- self.add_const(end);
- }
- }
- }
-
- &ty::Slice(tt) => self.add_ty(tt),
-
- &ty::RawPtr(ty, _) => {
- self.add_ty(ty);
- }
-
- &ty::Ref(r, ty, _) => {
- self.add_region(r);
- self.add_ty(ty);
- }
-
- &ty::Tuple(types) => {
- self.add_tys(types);
- }
-
- &ty::FnDef(_, args) => {
- self.add_args(args);
- }
-
- &ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| {
- computation.add_tys(sig_tys.inputs_and_output);
- }),
-
- &ty::UnsafeBinder(bound_ty) => {
- self.bound_computation(bound_ty.into(), |computation, ty| {
- computation.add_ty(ty);
- })
- }
- }
- }
-
- fn add_predicate(&mut self, binder: ty::Binder<'_, ty::PredicateKind<'_>>) {
- self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom));
- }
-
- fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) {
- match atom {
- ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
- self.add_args(trait_pred.trait_ref.args);
- }
- ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
- trait_ref,
- constness: _,
- })) => {
- self.add_args(trait_ref.args);
- }
- ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
- a,
- b,
- ))) => {
- self.add_region(a);
- self.add_region(b);
- }
- ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
- ty,
- region,
- ))) => {
- self.add_ty(ty);
- self.add_region(region);
- }
- ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
- self.add_const(ct);
- self.add_ty(ty);
- }
- ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
- self.add_ty(a);
- self.add_ty(b);
- }
- ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
- self.add_ty(a);
- self.add_ty(b);
- }
- ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
- projection_term,
- term,
- })) => {
- self.add_alias_term(projection_term);
- self.add_term(term);
- }
- ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
- self.add_args(slice::from_ref(&arg));
- }
- ty::PredicateKind::DynCompatible(_def_id) => {}
- ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
- self.add_const(uv);
- }
- ty::PredicateKind::ConstEquate(expected, found) => {
- self.add_const(expected);
- self.add_const(found);
- }
- ty::PredicateKind::Ambiguous => {}
- ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => {
- self.add_alias_term(alias);
- self.add_term(term);
- }
- ty::PredicateKind::AliasRelate(t1, t2, _) => {
- self.add_term(t1);
- self.add_term(t2);
- }
- }
- }
-
- fn add_ty(&mut self, ty: Ty<'_>) {
- self.add_flags(ty.flags());
- self.add_exclusive_binder(ty.outer_exclusive_binder());
- }
-
- fn add_tys(&mut self, tys: &[Ty<'_>]) {
- for &ty in tys {
- self.add_ty(ty);
- }
- }
-
- fn add_region(&mut self, r: ty::Region<'_>) {
- self.add_flags(r.type_flags());
- if let ty::ReBound(debruijn, _) = r.kind() {
- self.add_bound_var(debruijn);
- }
- }
-
- fn add_const(&mut self, c: ty::Const<'_>) {
- self.add_flags(c.flags());
- self.add_exclusive_binder(c.outer_exclusive_binder());
- }
-
- fn add_const_kind(&mut self, c: &ty::ConstKind<'_>) {
- match *c {
- ty::ConstKind::Unevaluated(uv) => {
- self.add_args(uv.args);
- self.add_flags(TypeFlags::HAS_CT_PROJECTION);
- }
- ty::ConstKind::Infer(infer) => match infer {
- InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
- InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
- },
- ty::ConstKind::Bound(debruijn, _) => {
- self.add_bound_var(debruijn);
- self.add_flags(TypeFlags::HAS_CT_BOUND);
- }
- ty::ConstKind::Param(_) => {
- self.add_flags(TypeFlags::HAS_CT_PARAM);
- }
- ty::ConstKind::Placeholder(_) => {
- self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER);
- }
- ty::ConstKind::Value(cv) => self.add_ty(cv.ty),
- ty::ConstKind::Expr(e) => self.add_args(e.args()),
- ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
- }
- }
-
- fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
- self.add_args(projection.args);
- match projection.term.unpack() {
- ty::TermKind::Ty(ty) => self.add_ty(ty),
- ty::TermKind::Const(ct) => self.add_const(ct),
- }
- }
-
- fn add_alias_ty(&mut self, alias_ty: ty::AliasTy<'_>) {
- self.add_args(alias_ty.args);
- }
-
- fn add_alias_term(&mut self, alias_term: ty::AliasTerm<'_>) {
- self.add_args(alias_term.args);
- }
-
- fn add_args(&mut self, args: &[GenericArg<'_>]) {
- for kind in args {
- match kind.unpack() {
- GenericArgKind::Type(ty) => self.add_ty(ty),
- GenericArgKind::Lifetime(lt) => self.add_region(lt),
- GenericArgKind::Const(ct) => self.add_const(ct),
- }
- }
- }
-
- fn add_term(&mut self, term: ty::Term<'_>) {
- match term.unpack() {
- ty::TermKind::Ty(ty) => self.add_ty(ty),
- ty::TermKind::Const(ct) => self.add_const(ct),
- }
- }
-}
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 8dc73e4..8d6871d 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -278,7 +278,7 @@ pub fn shift_bound_var_indices<T>(self, bound_vars: usize, value: T) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
- let shift_bv = |bv: ty::BoundVar| ty::BoundVar::from_usize(bv.as_usize() + bound_vars);
+ let shift_bv = |bv: ty::BoundVar| bv + bound_vars;
self.replace_escaping_bound_vars_uncached(
value,
FnMutDelegate {
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index 9c1ff13..8de64b3 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -11,12 +11,13 @@
use rustc_macros::{HashStable, TyDecodable, TyEncodable, extension};
use rustc_serialize::{Decodable, Encodable};
use rustc_type_ir::WithCachedTypeInfo;
+use rustc_type_ir::walk::TypeWalker;
use smallvec::SmallVec;
use crate::ty::codec::{TyDecoder, TyEncoder};
use crate::ty::{
self, ClosureArgs, CoroutineArgs, CoroutineClosureArgs, FallibleTypeFolder, InlineConstArgs,
- Lift, List, Ty, TyCtxt, TypeFoldable, TypeVisitable, TypeVisitor, VisitorResult,
+ Lift, List, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, VisitorResult,
walk_visitable_list,
};
@@ -297,6 +298,20 @@ pub fn is_non_region_infer(self) -> bool {
GenericArgKind::Const(ct) => ct.is_ct_infer(),
}
}
+
+ /// Iterator that walks `self` and any types reachable from
+ /// `self`, in depth-first order. Note that just walks the types
+ /// that appear in `self`, it does not descend into the fields of
+ /// structs or variants. For example:
+ ///
+ /// ```text
+ /// isize => { isize }
+ /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
+ /// [isize] => { [isize], isize }
+ /// ```
+ pub fn walk(self) -> TypeWalker<TyCtxt<'tcx>> {
+ TypeWalker::new(self)
+ }
}
impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for GenericArg<'a> {
@@ -322,6 +337,14 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
GenericArgKind::Const(ct) => ct.try_fold_with(folder).map(Into::into),
}
}
+
+ fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
+ match self.unpack() {
+ GenericArgKind::Lifetime(lt) => lt.fold_with(folder).into(),
+ GenericArgKind::Type(ty) => ty.fold_with(folder).into(),
+ GenericArgKind::Const(ct) => ct.fold_with(folder).into(),
+ }
+ }
}
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for GenericArg<'tcx> {
@@ -591,6 +614,27 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
}
}
0 => Ok(self),
+ _ => ty::util::try_fold_list(self, folder, |tcx, v| tcx.mk_args(v)),
+ }
+ }
+
+ fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
+ // See justification for this behavior in `try_fold_with`.
+ match self.len() {
+ 1 => {
+ let param0 = self[0].fold_with(folder);
+ if param0 == self[0] { self } else { folder.cx().mk_args(&[param0]) }
+ }
+ 2 => {
+ let param0 = self[0].fold_with(folder);
+ let param1 = self[1].fold_with(folder);
+ if param0 == self[0] && param1 == self[1] {
+ self
+ } else {
+ folder.cx().mk_args(&[param0, param1])
+ }
+ }
+ 0 => self,
_ => ty::util::fold_list(self, folder, |tcx, v| tcx.mk_args(v)),
}
}
@@ -626,6 +670,22 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
Ok(folder.cx().mk_type_list(&[param0, param1]))
}
}
+ _ => ty::util::try_fold_list(self, folder, |tcx, v| tcx.mk_type_list(v)),
+ }
+ }
+
+ fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
+ // See comment justifying behavior in `try_fold_with`.
+ match self.len() {
+ 2 => {
+ let param0 = self[0].fold_with(folder);
+ let param1 = self[1].fold_with(folder);
+ if param0 == self[0] && param1 == self[1] {
+ self
+ } else {
+ folder.cx().mk_type_list(&[param0, param1])
+ }
+ }
_ => ty::util::fold_list(self, folder, |tcx, v| tcx.mk_type_list(v)),
}
}
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index 07f2a60..faad0a8 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -746,7 +746,7 @@ pub fn fn_once_adapter_instance(
let call_once = tcx
.associated_items(fn_once)
.in_definition_order()
- .find(|it| it.kind == ty::AssocKind::Fn)
+ .find(|it| it.is_fn())
.unwrap()
.def_id;
let track_caller =
diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs
index 0fd370a..0cf58209 100644
--- a/compiler/rustc_middle/src/ty/list.rs
+++ b/compiler/rustc_middle/src/ty/list.rs
@@ -7,9 +7,9 @@
use rustc_data_structures::aligned::{Aligned, align_of};
use rustc_data_structures::sync::DynSync;
use rustc_serialize::{Encodable, Encoder};
+use rustc_type_ir::FlagComputation;
-use super::flags::FlagComputation;
-use super::{DebruijnIndex, TypeFlags};
+use super::{DebruijnIndex, TyCtxt, TypeFlags};
use crate::arena::Arena;
/// `List<T>` is a bit like `&[T]`, but with some critical differences.
@@ -299,8 +299,8 @@ const fn empty() -> Self {
}
}
-impl From<FlagComputation> for TypeInfo {
- fn from(computation: FlagComputation) -> TypeInfo {
+impl<'tcx> From<FlagComputation<TyCtxt<'tcx>>> for TypeInfo {
+ fn from(computation: FlagComputation<TyCtxt<'tcx>>) -> TypeInfo {
TypeInfo {
flags: computation.flags,
outer_exclusive_binder: computation.outer_exclusive_binder,
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index a2b3aca..3698cfb 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -117,7 +117,6 @@
pub mod codec;
pub mod error;
pub mod fast_reject;
-pub mod flags;
pub mod inhabitedness;
pub mod layout;
pub mod normalize_erasing_regions;
@@ -128,7 +127,6 @@
pub mod trait_def;
pub mod util;
pub mod vtable;
-pub mod walk;
mod adt;
mod assoc;
@@ -539,6 +537,13 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
ty::TermKind::Const(ct) => ct.try_fold_with(folder).map(Into::into),
}
}
+
+ fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
+ match self.unpack() {
+ ty::TermKind::Ty(ty) => ty.fold_with(folder).into(),
+ ty::TermKind::Const(ct) => ct.fold_with(folder).into(),
+ }
+ }
}
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for Term<'tcx> {
@@ -1464,7 +1469,7 @@ pub fn typeck_body(self, body: hir::BodyId) -> &'tcx TypeckResults<'tcx> {
pub fn provided_trait_methods(self, id: DefId) -> impl 'tcx + Iterator<Item = &'tcx AssocItem> {
self.associated_items(id)
.in_definition_order()
- .filter(move |item| item.kind == AssocKind::Fn && item.defaultness(self).has_value())
+ .filter(move |item| item.is_fn() && item.defaultness(self).has_value())
}
pub fn repr_options_of_def(self, did: LocalDefId) -> ReprOptions {
@@ -1610,8 +1615,11 @@ pub fn opt_associated_item(self, def_id: DefId) -> Option<AssocItem> {
/// return-position `impl Trait` from a trait, then provide the source info
/// about where that RPITIT came from.
pub fn opt_rpitit_info(self, def_id: DefId) -> Option<ImplTraitInTraitData> {
- if let DefKind::AssocTy = self.def_kind(def_id) {
- self.associated_item(def_id).opt_rpitit_info
+ if let DefKind::AssocTy = self.def_kind(def_id)
+ && let AssocKind::Type { data: AssocTypeData::Rpitit(rpitit_info) } =
+ self.associated_item(def_id).kind
+ {
+ Some(rpitit_info)
} else {
None
}
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index b56e086..ecd6132 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -113,7 +113,7 @@ impl $crate::ty::ParameterizedOverTcx for $ty {
rustc_span::Span,
rustc_span::Symbol,
rustc_span::def_id::DefPathHash,
- rustc_span::hygiene::SyntaxContextDataNonRecursive,
+ rustc_span::hygiene::SyntaxContextKey,
rustc_span::Ident,
rustc_type_ir::Variance,
rustc_hir::Attribute,
diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs
index 4cad1ab..758adc4 100644
--- a/compiler/rustc_middle/src/ty/pattern.rs
+++ b/compiler/rustc_middle/src/ty/pattern.rs
@@ -1,14 +1,40 @@
use std::fmt;
use rustc_data_structures::intern::Interned;
-use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
+use rustc_macros::HashStable;
+use rustc_type_ir::ir_print::IrPrint;
+use rustc_type_ir::{
+ FlagComputation, Flags, {self as ir},
+};
+use super::TyCtxt;
use crate::ty;
+pub type PatternKind<'tcx> = ir::PatternKind<TyCtxt<'tcx>>;
+
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable)]
#[rustc_pass_by_value]
pub struct Pattern<'tcx>(pub Interned<'tcx, PatternKind<'tcx>>);
+impl<'tcx> Flags for Pattern<'tcx> {
+ fn flags(&self) -> rustc_type_ir::TypeFlags {
+ match &**self {
+ ty::PatternKind::Range { start, end } => {
+ FlagComputation::for_const_kind(&start.kind()).flags
+ | FlagComputation::for_const_kind(&end.kind()).flags
+ }
+ }
+ }
+
+ fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
+ match &**self {
+ ty::PatternKind::Range { start, end } => {
+ start.outer_exclusive_binder().max(end.outer_exclusive_binder())
+ }
+ }
+ }
+}
+
impl<'tcx> std::ops::Deref for Pattern<'tcx> {
type Target = PatternKind<'tcx>;
@@ -23,9 +49,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
-impl<'tcx> fmt::Debug for PatternKind<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self {
+impl<'tcx> IrPrint<PatternKind<'tcx>> for TyCtxt<'tcx> {
+ fn print(t: &PatternKind<'tcx>, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *t {
PatternKind::Range { start, end } => {
write!(f, "{start}")?;
@@ -53,10 +79,15 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
}
+
+ fn print_debug(t: &PatternKind<'tcx>, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ Self::print(t, fmt)
+ }
}
-#[derive(Clone, PartialEq, Eq, Hash)]
-#[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
-pub enum PatternKind<'tcx> {
- Range { start: ty::Const<'tcx>, end: ty::Const<'tcx> },
+impl<'tcx> rustc_type_ir::inherent::IntoKind for Pattern<'tcx> {
+ type Kind = PatternKind<'tcx>;
+ fn kind(self) -> Self::Kind {
+ *self
+ }
}
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 2f93197..d739218 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1214,7 +1214,7 @@ fn pretty_print_opaque_impl_type(
&& assoc
.trait_container(tcx)
.is_some_and(|def_id| tcx.is_lang_item(def_id, LangItem::Coroutine))
- && assoc.name == rustc_span::sym::Return
+ && assoc.opt_name() == Some(rustc_span::sym::Return)
{
if let ty::Coroutine(_, args) = args.type_at(0).kind() {
let return_ty = args.as_coroutine().return_ty();
@@ -1237,7 +1237,7 @@ fn pretty_print_opaque_impl_type(
p!(", ");
}
- p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name));
+ p!(write("{} = ", tcx.associated_item(assoc_item_def_id).name()));
match term.unpack() {
TermKind::Ty(ty) => p!(print(ty)),
@@ -3291,7 +3291,7 @@ macro_rules! define_print_and_forward_display {
}
ty::ExistentialProjection<'tcx> {
- let name = cx.tcx().associated_item(self.def_id).name;
+ let name = cx.tcx().associated_item(self.def_id).name();
// The args don't contain the self ty (as it has been erased) but the corresp.
// generics do as the trait always has a self ty param. We need to offset.
let args = &self.args[cx.tcx().generics_of(self.def_id).parent_count - 1..];
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 798ef35..2686166 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -6,20 +6,19 @@
use std::fmt::{self, Debug};
use rustc_abi::TyAndLayout;
-use rustc_ast::InlineAsmTemplatePiece;
use rustc_hir::def::Namespace;
use rustc_hir::def_id::LocalDefId;
-use rustc_span::Span;
use rustc_span::source_map::Spanned;
-use rustc_type_ir::{ConstKind, VisitorResult, try_visit};
+use rustc_type_ir::{ConstKind, TypeFolder, VisitorResult, try_visit};
use super::print::PrettyPrinter;
use super::{GenericArg, GenericArgKind, Pattern, Region};
+use crate::infer::canonical::CanonicalVarInfos;
use crate::mir::PlaceElem;
use crate::ty::print::{FmtPrinter, Printer, with_no_trimmed_paths};
use crate::ty::{
- self, FallibleTypeFolder, InferConst, Lift, Term, TermKind, Ty, TyCtxt, TypeFoldable,
- TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+ self, FallibleTypeFolder, Lift, Term, TermKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable,
+ TypeSuperVisitable, TypeVisitable, TypeVisitor,
};
impl fmt::Debug for ty::TraitDef {
@@ -61,6 +60,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
+impl<'tcx> fmt::Debug for ty::adjustment::PatAdjustment<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{} -> {:?}", self.source, self.kind)
+ }
+}
+
impl fmt::Debug for ty::BoundRegionKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
@@ -271,6 +276,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
crate::ty::AssocKind,
crate::ty::BoundRegion,
crate::ty::BoundVar,
+ crate::ty::InferConst,
crate::ty::Placeholder<crate::ty::BoundRegion>,
crate::ty::Placeholder<crate::ty::BoundTy>,
crate::ty::Placeholder<ty::BoundVar>,
@@ -337,24 +343,6 @@ fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, _visitor: &mut V) -> V::Resul
}
}
-impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
- fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
- self,
- folder: &mut F,
- ) -> Result<Self, F::Error> {
- ty::util::fold_list(self, folder, |tcx, v| tcx.mk_poly_existential_predicates(v))
- }
-}
-
-impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Const<'tcx>> {
- fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
- self,
- folder: &mut F,
- ) -> Result<Self, F::Error> {
- ty::util::fold_list(self, folder, |tcx, v| tcx.mk_const_list(v))
- }
-}
-
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Pattern<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
@@ -363,6 +351,11 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
let pat = (*self).clone().try_fold_with(folder)?;
Ok(if pat == *self { self } else { folder.cx().mk_pat(pat) })
}
+
+ fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
+ let pat = (*self).clone().fold_with(folder);
+ if pat == *self { self } else { folder.cx().mk_pat(pat) }
+ }
}
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for Pattern<'tcx> {
@@ -378,6 +371,10 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
) -> Result<Self, F::Error> {
folder.try_fold_ty(self)
}
+
+ fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
+ folder.fold_ty(self)
+ }
}
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for Ty<'tcx> {
@@ -436,6 +433,45 @@ fn try_super_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
Ok(if *self.kind() == kind { self } else { folder.cx().mk_ty_from_kind(kind) })
}
+
+ fn super_fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
+ let kind = match *self.kind() {
+ ty::RawPtr(ty, mutbl) => ty::RawPtr(ty.fold_with(folder), mutbl),
+ ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)),
+ ty::Slice(typ) => ty::Slice(typ.fold_with(folder)),
+ ty::Adt(tid, args) => ty::Adt(tid, args.fold_with(folder)),
+ ty::Dynamic(trait_ty, region, representation) => {
+ ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder), representation)
+ }
+ ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)),
+ ty::FnDef(def_id, args) => ty::FnDef(def_id, args.fold_with(folder)),
+ ty::FnPtr(sig_tys, hdr) => ty::FnPtr(sig_tys.fold_with(folder), hdr),
+ ty::UnsafeBinder(f) => ty::UnsafeBinder(f.fold_with(folder)),
+ ty::Ref(r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl),
+ ty::Coroutine(did, args) => ty::Coroutine(did, args.fold_with(folder)),
+ ty::CoroutineWitness(did, args) => ty::CoroutineWitness(did, args.fold_with(folder)),
+ ty::Closure(did, args) => ty::Closure(did, args.fold_with(folder)),
+ ty::CoroutineClosure(did, args) => ty::CoroutineClosure(did, args.fold_with(folder)),
+ ty::Alias(kind, data) => ty::Alias(kind, data.fold_with(folder)),
+ ty::Pat(ty, pat) => ty::Pat(ty.fold_with(folder), pat.fold_with(folder)),
+
+ ty::Bool
+ | ty::Char
+ | ty::Str
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Error(_)
+ | ty::Infer(_)
+ | ty::Param(..)
+ | ty::Bound(..)
+ | ty::Placeholder(..)
+ | ty::Never
+ | ty::Foreign(..) => return self,
+ };
+
+ if *self.kind() == kind { self } else { folder.cx().mk_ty_from_kind(kind) }
+ }
}
impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for Ty<'tcx> {
@@ -496,6 +532,10 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
) -> Result<Self, F::Error> {
folder.try_fold_region(self)
}
+
+ fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
+ folder.fold_region(self)
+ }
}
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::Region<'tcx> {
@@ -511,6 +551,10 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
) -> Result<Self, F::Error> {
folder.try_fold_predicate(self)
}
+
+ fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
+ folder.fold_predicate(self)
+ }
}
// FIXME(clause): This is wonky
@@ -521,6 +565,10 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
) -> Result<Self, F::Error> {
Ok(folder.try_fold_predicate(self.as_predicate())?.expect_clause())
}
+
+ fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
+ folder.fold_predicate(self.as_predicate()).expect_clause()
+ }
}
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::Predicate<'tcx> {
@@ -543,6 +591,11 @@ fn try_super_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
let new = self.kind().try_fold_with(folder)?;
Ok(folder.cx().reuse_or_mk_predicate(self, new))
}
+
+ fn super_fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
+ let new = self.kind().fold_with(folder);
+ folder.cx().reuse_or_mk_predicate(self, new)
+ }
}
impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Predicate<'tcx> {
@@ -563,15 +616,6 @@ fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::
}
}
-impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Clauses<'tcx> {
- fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
- self,
- folder: &mut F,
- ) -> Result<Self, F::Error> {
- ty::util::fold_list(self, folder, |tcx, v| tcx.mk_clauses(v))
- }
-}
-
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Const<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
@@ -579,6 +623,10 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
) -> Result<Self, F::Error> {
folder.try_fold_const(self)
}
+
+ fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
+ folder.fold_const(self)
+ }
}
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> {
@@ -606,6 +654,20 @@ fn try_super_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
};
if kind != self.kind() { Ok(folder.cx().mk_ct_from_kind(kind)) } else { Ok(self) }
}
+
+ fn super_fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
+ let kind = match self.kind() {
+ ConstKind::Param(p) => ConstKind::Param(p.fold_with(folder)),
+ ConstKind::Infer(i) => ConstKind::Infer(i.fold_with(folder)),
+ ConstKind::Bound(d, b) => ConstKind::Bound(d.fold_with(folder), b.fold_with(folder)),
+ ConstKind::Placeholder(p) => ConstKind::Placeholder(p.fold_with(folder)),
+ ConstKind::Unevaluated(uv) => ConstKind::Unevaluated(uv.fold_with(folder)),
+ ConstKind::Value(v) => ConstKind::Value(v.fold_with(folder)),
+ ConstKind::Error(e) => ConstKind::Error(e.fold_with(folder)),
+ ConstKind::Expr(e) => ConstKind::Expr(e.fold_with(folder)),
+ };
+ if kind != self.kind() { folder.cx().mk_ct_from_kind(kind) } else { self }
+ }
}
impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Const<'tcx> {
@@ -639,20 +701,9 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
) -> Result<Self, F::Error> {
Ok(self)
}
-}
-impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for InferConst {
- fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
- self,
- _folder: &mut F,
- ) -> Result<Self, F::Error> {
- Ok(self)
- }
-}
-
-impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for InferConst {
- fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, _visitor: &mut V) -> V::Result {
- V::Result::output()
+ fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, _folder: &mut F) -> Self {
+ self
}
}
@@ -683,23 +734,9 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
span: self.span.try_fold_with(folder)?,
})
}
-}
-impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx [InlineAsmTemplatePiece] {
- fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
- self,
- _folder: &mut F,
- ) -> Result<Self, F::Error> {
- Ok(self)
- }
-}
-
-impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx [Span] {
- fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
- self,
- _folder: &mut F,
- ) -> Result<Self, F::Error> {
- Ok(self)
+ fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
+ Spanned { node: self.node.fold_with(folder), span: self.span.fold_with(folder) }
}
}
@@ -710,13 +747,37 @@ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
) -> Result<Self, F::Error> {
Ok(self)
}
+
+ fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, _folder: &mut F) -> Self {
+ self
+ }
}
-impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<PlaceElem<'tcx>> {
- fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
- self,
- folder: &mut F,
- ) -> Result<Self, F::Error> {
- ty::util::fold_list(self, folder, |tcx, v| tcx.mk_place_elems(v))
+macro_rules! list_fold {
+ ($($ty:ty : $mk:ident),+ $(,)?) => {
+ $(
+ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for $ty {
+ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ ty::util::try_fold_list(self, folder, |tcx, v| tcx.$mk(v))
+ }
+
+ fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(
+ self,
+ folder: &mut F,
+ ) -> Self {
+ ty::util::fold_list(self, folder, |tcx, v| tcx.$mk(v))
+ }
+ }
+ )*
}
}
+
+list_fold! {
+ ty::Clauses<'tcx> : mk_clauses,
+ &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> : mk_poly_existential_predicates,
+ &'tcx ty::List<PlaceElem<'tcx>> : mk_place_elems,
+ CanonicalVarInfos<'tcx> : mk_canonical_var_infos,
+}
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 27ee363..affb7b3 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -16,6 +16,7 @@
use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, extension};
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
use rustc_type_ir::TyKind::*;
+use rustc_type_ir::walk::TypeWalker;
use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind, TypeVisitableExt, elaborate};
use tracing::instrument;
use ty::util::{AsyncDropGlueMorphology, IntTypeExt};
@@ -734,7 +735,7 @@ pub fn new_dynamic(
.map(|principal| {
tcx.associated_items(principal.def_id())
.in_definition_order()
- .filter(|item| item.kind == ty::AssocKind::Type)
+ .filter(|item| item.is_type())
.filter(|item| !item.is_impl_trait_in_trait())
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
.count()
@@ -1773,9 +1774,7 @@ pub fn pointee_metadata_ty_or_projection(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
match pointee_ty.ptr_metadata_ty_or_tail(tcx, |x| x) {
Ok(metadata_ty) => metadata_ty,
Err(tail_ty) => {
- let Some(metadata_def_id) = tcx.lang_items().metadata_type() else {
- bug!("No metadata_type lang item while looking at {self:?}")
- };
+ let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None);
Ty::new_projection(tcx, metadata_def_id, [tail_ty])
}
}
@@ -1872,14 +1871,14 @@ pub fn from_coroutine_closure_kind(tcx: TyCtxt<'tcx>, kind: ty::ClosureKind) ->
/// Fast path helper for testing if a type is `Sized`.
///
- /// Returning true means the type is known to be sized. Returning
- /// `false` means nothing -- could be sized, might not be.
+ /// Returning true means the type is known to implement `Sized`. Returning `false` means
+ /// nothing -- could be sized, might not be.
///
- /// Note that we could never rely on the fact that a type such as `[_]` is
- /// trivially `!Sized` because we could be in a type environment with a
- /// bound such as `[_]: Copy`. A function with such a bound obviously never
- /// can be called, but that doesn't mean it shouldn't typecheck. This is why
- /// this method doesn't return `Option<bool>`.
+ /// Note that we could never rely on the fact that a type such as `[_]` is trivially `!Sized`
+ /// because we could be in a type environment with a bound such as `[_]: Copy`. A function with
+ /// such a bound obviously never can be called, but that doesn't mean it shouldn't typecheck.
+ /// This is why this method doesn't return `Option<bool>`.
+ #[instrument(skip(tcx), level = "debug")]
pub fn is_trivially_sized(self, tcx: TyCtxt<'tcx>) -> bool {
match self.kind() {
ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
@@ -2029,6 +2028,20 @@ pub fn is_c_void(self, tcx: TyCtxt<'_>) -> bool {
pub fn is_known_rigid(self) -> bool {
self.kind().is_known_rigid()
}
+
+ /// Iterator that walks `self` and any types reachable from
+ /// `self`, in depth-first order. Note that just walks the types
+ /// that appear in `self`, it does not descend into the fields of
+ /// structs or variants. For example:
+ ///
+ /// ```text
+ /// isize => { isize }
+ /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
+ /// [isize] => { [isize], isize }
+ /// ```
+ pub fn walk(self) -> TypeWalker<TyCtxt<'tcx>> {
+ TypeWalker::new(self.into())
+ }
}
impl<'tcx> rustc_type_ir::inherent::Tys<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> {
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 90c6ef6..4c5c669 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -77,8 +77,8 @@ pub struct TypeckResults<'tcx> {
/// to a form valid in all Editions, either as a lint diagnostic or hard error.
rust_2024_migration_desugared_pats: ItemLocalMap<Rust2024IncompatiblePatInfo>,
- /// Stores the types which were implicitly dereferenced in pattern binding modes
- /// for later usage in THIR lowering. For example,
+ /// Stores the types which were implicitly dereferenced in pattern binding modes or deref
+ /// patterns for later usage in THIR lowering. For example,
///
/// ```
/// match &&Some(5i32) {
@@ -86,11 +86,20 @@ pub struct TypeckResults<'tcx> {
/// _ => {},
/// }
/// ```
- /// leads to a `vec![&&Option<i32>, &Option<i32>]`. Empty vectors are not stored.
+ /// leads to a `vec![&&Option<i32>, &Option<i32>]` and
+ ///
+ /// ```
+ /// #![feature(deref_patterns)]
+ /// match &Box::new(Some(5i32)) {
+ /// Some(n) => {},
+ /// _ => {},
+ /// }
+ /// ```
+ /// leads to a `vec![&Box<Option<i32>>, Box<Option<i32>>]`. Empty vectors are not stored.
///
/// See:
/// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
- pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
+ pat_adjustments: ItemLocalMap<Vec<ty::adjustment::PatAdjustment<'tcx>>>,
/// Set of reference patterns that match against a match-ergonomics inserted reference
/// (as opposed to against a reference in the scrutinee type).
@@ -403,11 +412,15 @@ pub fn pat_binding_modes_mut(&mut self) -> LocalTableInContextMut<'_, BindingMod
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes }
}
- pub fn pat_adjustments(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
+ pub fn pat_adjustments(
+ &self,
+ ) -> LocalTableInContext<'_, Vec<ty::adjustment::PatAdjustment<'tcx>>> {
LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_adjustments }
}
- pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
+ pub fn pat_adjustments_mut(
+ &mut self,
+ ) -> LocalTableInContextMut<'_, Vec<ty::adjustment::PatAdjustment<'tcx>>> {
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
}
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index 857b462..08cee11 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -819,7 +819,7 @@ pub fn def_descr(self, def_id: DefId) -> &'static str {
/// Get an English description for the item's kind.
pub fn def_kind_descr(self, def_kind: DefKind, def_id: DefId) -> &'static str {
match def_kind {
- DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "method",
+ DefKind::AssocFn if self.associated_item(def_id).is_method() => "method",
DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
match coroutine_kind {
hir::CoroutineKind::Desugared(
@@ -873,7 +873,7 @@ pub fn def_descr_article(self, def_id: DefId) -> &'static str {
/// Gets an English article for the [`TyCtxt::def_kind_descr`].
pub fn def_kind_descr_article(self, def_kind: DefKind, def_id: DefId) -> &'static str {
match def_kind {
- DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "a",
+ DefKind::AssocFn if self.associated_item(def_id).is_method() => "a",
DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => {
match coroutine_kind {
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, ..) => "an",
@@ -1647,6 +1647,42 @@ pub fn fold_list<'tcx, F, L, T>(
list: L,
folder: &mut F,
intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> L,
+) -> L
+where
+ F: TypeFolder<TyCtxt<'tcx>>,
+ L: AsRef<[T]>,
+ T: TypeFoldable<TyCtxt<'tcx>> + PartialEq + Copy,
+{
+ let slice = list.as_ref();
+ let mut iter = slice.iter().copied();
+ // Look for the first element that changed
+ match iter.by_ref().enumerate().find_map(|(i, t)| {
+ let new_t = t.fold_with(folder);
+ if new_t != t { Some((i, new_t)) } else { None }
+ }) {
+ Some((i, new_t)) => {
+ // An element changed, prepare to intern the resulting list
+ let mut new_list = SmallVec::<[_; 8]>::with_capacity(slice.len());
+ new_list.extend_from_slice(&slice[..i]);
+ new_list.push(new_t);
+ for t in iter {
+ new_list.push(t.fold_with(folder))
+ }
+ intern(folder.cx(), &new_list)
+ }
+ None => list,
+ }
+}
+
+/// Does the equivalent of
+/// ```ignore (illustrative)
+/// let v = self.iter().map(|p| p.try_fold_with(folder)).collect::<SmallVec<[_; 8]>>();
+/// folder.tcx().intern_*(&v)
+/// ```
+pub fn try_fold_list<'tcx, F, L, T>(
+ list: L,
+ folder: &mut F,
+ intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> L,
) -> Result<L, F::Error>
where
F: FallibleTypeFolder<TyCtxt<'tcx>>,
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index b341b30..44c7b6a 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -231,9 +231,7 @@ pub fn max_universe(self) -> ty::UniverseIndex {
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxUniverse {
fn visit_ty(&mut self, t: Ty<'tcx>) {
if let ty::Placeholder(placeholder) = t.kind() {
- self.max_universe = ty::UniverseIndex::from_u32(
- self.max_universe.as_u32().max(placeholder.universe.as_u32()),
- );
+ self.max_universe = self.max_universe.max(placeholder.universe);
}
t.super_visit_with(self)
@@ -241,9 +239,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
fn visit_const(&mut self, c: ty::consts::Const<'tcx>) {
if let ty::ConstKind::Placeholder(placeholder) = c.kind() {
- self.max_universe = ty::UniverseIndex::from_u32(
- self.max_universe.as_u32().max(placeholder.universe.as_u32()),
- );
+ self.max_universe = self.max_universe.max(placeholder.universe);
}
c.super_visit_with(self)
@@ -251,9 +247,7 @@ fn visit_const(&mut self, c: ty::consts::Const<'tcx>) {
fn visit_region(&mut self, r: ty::Region<'tcx>) {
if let ty::RePlaceholder(placeholder) = r.kind() {
- self.max_universe = ty::UniverseIndex::from_u32(
- self.max_universe.as_u32().max(placeholder.universe.as_u32()),
- );
+ self.max_universe = self.max_universe.max(placeholder.universe);
}
}
}
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
deleted file mode 100644
index a23316a..0000000
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ /dev/null
@@ -1,217 +0,0 @@
-//! An iterator over the type substructure.
-//! WARNING: this does not keep track of the region depth.
-
-use rustc_data_structures::sso::SsoHashSet;
-use smallvec::{SmallVec, smallvec};
-use tracing::debug;
-
-use crate::ty::{self, GenericArg, GenericArgKind, Ty};
-
-// The TypeWalker's stack is hot enough that it's worth going to some effort to
-// avoid heap allocations.
-type TypeWalkerStack<'tcx> = SmallVec<[GenericArg<'tcx>; 8]>;
-
-pub struct TypeWalker<'tcx> {
- stack: TypeWalkerStack<'tcx>,
- last_subtree: usize,
- pub visited: SsoHashSet<GenericArg<'tcx>>,
-}
-
-/// An iterator for walking the type tree.
-///
-/// It's very easy to produce a deeply
-/// nested type tree with a lot of
-/// identical subtrees. In order to work efficiently
-/// in this situation walker only visits each type once.
-/// It maintains a set of visited types and
-/// skips any types that are already there.
-impl<'tcx> TypeWalker<'tcx> {
- pub fn new(root: GenericArg<'tcx>) -> Self {
- Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() }
- }
-
- /// Skips the subtree corresponding to the last type
- /// returned by `next()`.
- ///
- /// Example: Imagine you are walking `Foo<Bar<i32>, usize>`.
- ///
- /// ```ignore (illustrative)
- /// let mut iter: TypeWalker = ...;
- /// iter.next(); // yields Foo
- /// iter.next(); // yields Bar<i32>
- /// iter.skip_current_subtree(); // skips i32
- /// iter.next(); // yields usize
- /// ```
- pub fn skip_current_subtree(&mut self) {
- self.stack.truncate(self.last_subtree);
- }
-}
-
-impl<'tcx> Iterator for TypeWalker<'tcx> {
- type Item = GenericArg<'tcx>;
-
- fn next(&mut self) -> Option<GenericArg<'tcx>> {
- debug!("next(): stack={:?}", self.stack);
- loop {
- let next = self.stack.pop()?;
- self.last_subtree = self.stack.len();
- if self.visited.insert(next) {
- push_inner(&mut self.stack, next);
- debug!("next: stack={:?}", self.stack);
- return Some(next);
- }
- }
- }
-}
-
-impl<'tcx> GenericArg<'tcx> {
- /// Iterator that walks `self` and any types reachable from
- /// `self`, in depth-first order. Note that just walks the types
- /// that appear in `self`, it does not descend into the fields of
- /// structs or variants. For example:
- ///
- /// ```text
- /// isize => { isize }
- /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
- /// [isize] => { [isize], isize }
- /// ```
- pub fn walk(self) -> TypeWalker<'tcx> {
- TypeWalker::new(self)
- }
-}
-
-impl<'tcx> Ty<'tcx> {
- /// Iterator that walks `self` and any types reachable from
- /// `self`, in depth-first order. Note that just walks the types
- /// that appear in `self`, it does not descend into the fields of
- /// structs or variants. For example:
- ///
- /// ```text
- /// isize => { isize }
- /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
- /// [isize] => { [isize], isize }
- /// ```
- pub fn walk(self) -> TypeWalker<'tcx> {
- TypeWalker::new(self.into())
- }
-}
-
-impl<'tcx> ty::Const<'tcx> {
- /// Iterator that walks `self` and any types reachable from
- /// `self`, in depth-first order. Note that just walks the types
- /// that appear in `self`, it does not descend into the fields of
- /// structs or variants. For example:
- ///
- /// ```text
- /// isize => { isize }
- /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
- /// [isize] => { [isize], isize }
- /// ```
- pub fn walk(self) -> TypeWalker<'tcx> {
- TypeWalker::new(self.into())
- }
-}
-
-/// We push `GenericArg`s on the stack in reverse order so as to
-/// maintain a pre-order traversal. As of the time of this
-/// writing, the fact that the traversal is pre-order is not
-/// known to be significant to any code, but it seems like the
-/// natural order one would expect (basically, the order of the
-/// types as they are written).
-fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) {
- match parent.unpack() {
- GenericArgKind::Type(parent_ty) => match *parent_ty.kind() {
- ty::Bool
- | ty::Char
- | ty::Int(_)
- | ty::Uint(_)
- | ty::Float(_)
- | ty::Str
- | ty::Infer(_)
- | ty::Param(_)
- | ty::Never
- | ty::Error(_)
- | ty::Placeholder(..)
- | ty::Bound(..)
- | ty::Foreign(..) => {}
-
- ty::Pat(ty, pat) => {
- match *pat {
- ty::PatternKind::Range { start, end } => {
- stack.push(end.into());
- stack.push(start.into());
- }
- }
- stack.push(ty.into());
- }
- ty::Array(ty, len) => {
- stack.push(len.into());
- stack.push(ty.into());
- }
- ty::Slice(ty) => {
- stack.push(ty.into());
- }
- ty::RawPtr(ty, _) => {
- stack.push(ty.into());
- }
- ty::Ref(lt, ty, _) => {
- stack.push(ty.into());
- stack.push(lt.into());
- }
- ty::Alias(_, data) => {
- stack.extend(data.args.iter().rev());
- }
- ty::Dynamic(obj, lt, _) => {
- stack.push(lt.into());
- stack.extend(obj.iter().rev().flat_map(|predicate| {
- let (args, opt_ty) = match predicate.skip_binder() {
- ty::ExistentialPredicate::Trait(tr) => (tr.args, None),
- ty::ExistentialPredicate::Projection(p) => (p.args, Some(p.term)),
- ty::ExistentialPredicate::AutoTrait(_) =>
- // Empty iterator
- {
- (ty::GenericArgs::empty(), None)
- }
- };
-
- args.iter().rev().chain(opt_ty.map(|term| match term.unpack() {
- ty::TermKind::Ty(ty) => ty.into(),
- ty::TermKind::Const(ct) => ct.into(),
- }))
- }));
- }
- ty::Adt(_, args)
- | ty::Closure(_, args)
- | ty::CoroutineClosure(_, args)
- | ty::Coroutine(_, args)
- | ty::CoroutineWitness(_, args)
- | ty::FnDef(_, args) => {
- stack.extend(args.iter().rev());
- }
- ty::Tuple(ts) => stack.extend(ts.iter().rev().map(GenericArg::from)),
- ty::FnPtr(sig_tys, _hdr) => {
- stack.extend(
- sig_tys.skip_binder().inputs_and_output.iter().rev().map(|ty| ty.into()),
- );
- }
- ty::UnsafeBinder(bound_ty) => {
- stack.push(bound_ty.skip_binder().into());
- }
- },
- GenericArgKind::Lifetime(_) => {}
- GenericArgKind::Const(parent_ct) => match parent_ct.kind() {
- ty::ConstKind::Infer(_)
- | ty::ConstKind::Param(_)
- | ty::ConstKind::Placeholder(_)
- | ty::ConstKind::Bound(..)
- | ty::ConstKind::Error(_) => {}
-
- ty::ConstKind::Value(cv) => stack.push(cv.ty.into()),
-
- ty::ConstKind::Expr(expr) => stack.extend(expr.args().iter().rev()),
- ty::ConstKind::Unevaluated(ct) => {
- stack.extend(ct.args.iter().rev());
- }
- },
- }
-}
diff --git a/compiler/rustc_mir_build/src/builder/custom/mod.rs b/compiler/rustc_mir_build/src/builder/custom/mod.rs
index bfc1681..902a6e7 100644
--- a/compiler/rustc_mir_build/src/builder/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/custom/mod.rs
@@ -103,8 +103,9 @@ fn parse_attribute(attr: &Attribute) -> MirPhase {
let mut dialect: Option<String> = None;
let mut phase: Option<String> = None;
+ // Not handling errors properly for this internal attribute; will just abort on errors.
for nested in meta_items {
- let name = nested.name_or_empty();
+ let name = nested.name().unwrap();
let value = nested.value_str().unwrap().as_str().to_string();
match name.as_str() {
"dialect" => {
diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
index 9670c17..d66b38c 100644
--- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs
@@ -101,18 +101,21 @@ pub(super) fn for_pattern(
place_builder = resolved;
}
- // Only add the OpaqueCast projection if the given place is an opaque type and the
- // expected type from the pattern is not.
- let may_need_cast = match place_builder.base() {
- PlaceBase::Local(local) => {
- let ty =
- Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx).ty;
- ty != pattern.ty && ty.has_opaque_types()
+ if !cx.tcx.next_trait_solver_globally() {
+ // Only add the OpaqueCast projection if the given place is an opaque type and the
+ // expected type from the pattern is not.
+ let may_need_cast = match place_builder.base() {
+ PlaceBase::Local(local) => {
+ let ty =
+ Place::ty_from(local, place_builder.projection(), &cx.local_decls, cx.tcx)
+ .ty;
+ ty != pattern.ty && ty.has_opaque_types()
+ }
+ _ => true,
+ };
+ if may_need_cast {
+ place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
}
- _ => true,
- };
- if may_need_cast {
- place_builder = place_builder.project(ProjectionElem::OpaqueCast(pattern.ty));
}
let place = place_builder.try_to_place(cx);
diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs
index d1f9d4c..73cc3c8 100644
--- a/compiler/rustc_mir_build/src/builder/matches/test.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/test.rs
@@ -140,8 +140,8 @@ pub(super) fn perform_test(
let success_block = target_block(TestBranch::Success);
let fail_block = target_block(TestBranch::Failure);
- let expect_ty = value.ty();
- let expect = self.literal_operand(test.span, value);
+ let mut expect_ty = value.ty();
+ let mut expect = self.literal_operand(test.span, value);
let mut place = place;
let mut block = block;
@@ -174,6 +174,31 @@ pub(super) fn perform_test(
place = ref_str;
ty = ref_str_ty;
}
+ &ty::Pat(base, _) => {
+ assert_eq!(ty, value.ty());
+ assert!(base.is_trivially_pure_clone_copy());
+
+ let transmuted_place = self.temp(base, test.span);
+ self.cfg.push_assign(
+ block,
+ self.source_info(scrutinee_span),
+ transmuted_place,
+ Rvalue::Cast(CastKind::Transmute, Operand::Copy(place), base),
+ );
+
+ let transmuted_expect = self.temp(base, test.span);
+ self.cfg.push_assign(
+ block,
+ self.source_info(test.span),
+ transmuted_expect,
+ Rvalue::Cast(CastKind::Transmute, expect, base),
+ );
+
+ place = transmuted_place;
+ expect = Operand::Copy(transmuted_expect);
+ ty = base;
+ expect_ty = base;
+ }
_ => {}
}
@@ -715,7 +740,7 @@ fn trait_method<'tcx>(
let item = tcx
.associated_items(trait_def_id)
.filter_by_name_unhygienic(method_name)
- .find(|item| item.kind == ty::AssocKind::Fn)
+ .find(|item| item.is_fn())
.expect("trait method not found");
let method_ty = Ty::new_fn_def(tcx, item.def_id, args);
diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs
index 8ca9ab5..59a52ae 100644
--- a/compiler/rustc_mir_build/src/builder/mod.rs
+++ b/compiler/rustc_mir_build/src/builder/mod.rs
@@ -485,7 +485,7 @@ fn construct_fn<'tcx>(
};
if let Some(custom_mir_attr) =
- tcx.hir_attrs(fn_id).iter().find(|attr| attr.name_or_empty() == sym::custom_mir)
+ tcx.hir_attrs(fn_id).iter().find(|attr| attr.has_name(sym::custom_mir))
{
return custom::build_custom_mir(
tcx,
diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs
index e42336a..4e4b11b 100644
--- a/compiler/rustc_mir_build/src/builder/scope.rs
+++ b/compiler/rustc_mir_build/src/builder/scope.rs
@@ -1530,7 +1530,7 @@ fn build_scope_drops<'tcx>(
// path, then don't generate the drop. (We only take this into
// account for non-unwind paths so as not to disturb the
// caching mechanism.)
- if scope.moved_locals.iter().any(|&o| o == local) {
+ if scope.moved_locals.contains(&local) {
continue;
}
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index b6a856a..adfce99 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -564,13 +564,17 @@ fn visit_expr(&mut self, expr: &'a Expr<'tcx>) {
}
}
ExprKind::InlineAsm(box InlineAsmExpr {
- asm_macro: AsmMacro::Asm | AsmMacro::NakedAsm,
+ asm_macro: asm_macro @ (AsmMacro::Asm | AsmMacro::NakedAsm),
ref operands,
template: _,
options: _,
line_spans: _,
}) => {
- self.requires_unsafe(expr.span, UseOfInlineAssembly);
+ // The `naked` attribute and the `naked_asm!` block form one atomic unit of
+ // unsafety, and `naked_asm!` does not itself need to be wrapped in an unsafe block.
+ if let AsmMacro::Asm = asm_macro {
+ self.requires_unsafe(expr.span, UseOfInlineAssembly);
+ }
// For inline asm, do not use `walk_expr`, since we want to handle the label block
// specially.
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 0e16f87..ae09db5 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -2,7 +2,7 @@
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level,
- MultiSpan, SubdiagMessageOp, Subdiagnostic, pluralize,
+ MultiSpan, Subdiagnostic, pluralize,
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{self, Ty};
@@ -546,11 +546,7 @@ pub(crate) struct UnsafeNotInheritedLintNote {
}
impl Subdiagnostic for UnsafeNotInheritedLintNote {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.span_note(self.signature_span, fluent::mir_build_unsafe_fn_safe_body);
let body_start = self.body_span.shrink_to_lo();
let body_end = self.body_span.shrink_to_hi();
@@ -1031,11 +1027,7 @@ pub(crate) struct Variant {
}
impl<'tcx> Subdiagnostic for AdtDefinedHere<'tcx> {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("ty", self.ty);
let mut spans = MultiSpan::from(self.adt_def_span);
@@ -1117,11 +1109,7 @@ pub(crate) struct Rust2024IncompatiblePatSugg {
}
impl Subdiagnostic for Rust2024IncompatiblePatSugg {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
// Format and emit explanatory notes about default binding modes. Reversing the spans' order
// means if we have nested spans, the innermost ones will be visited first.
for (span, def_br_mutbl) in self.default_mode_labels.into_iter().rev() {
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index a25697b..8e96d46 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -3,7 +3,6 @@
// tidy-alphabetical-start
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(if_let_guard)]
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 31e22e6..fde2341 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -191,7 +191,7 @@ fn apply_adjustment(
let pointer_target = ExprKind::Field {
lhs: self.thir.exprs.push(expr),
variant_index: FIRST_VARIANT,
- name: FieldIdx::from(0u32),
+ name: FieldIdx::ZERO,
};
let arg = Expr { temp_lifetime, ty: pin_ty, span, kind: pointer_target };
let arg = self.thir.exprs.push(arg);
@@ -226,7 +226,7 @@ fn apply_adjustment(
adt_def: self.tcx.adt_def(pin_did),
variant_index: FIRST_VARIANT,
args,
- fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]),
+ fields: Box::new([FieldExpr { name: FieldIdx::ZERO, expr }]),
user_ty: None,
base: AdtExprBase::None,
}));
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index b3daed8..2f593b9 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -113,7 +113,7 @@ fn new(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Self {
apply_adjustments: tcx
.hir_attrs(hir_id)
.iter()
- .all(|attr| attr.name_or_empty() != rustc_span::sym::custom_mir),
+ .all(|attr| !attr.has_name(rustc_span::sym::custom_mir)),
}
}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/migration.rs b/compiler/rustc_mir_build/src/thir/pattern/migration.rs
index bd7787b..12c457f 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/migration.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/migration.rs
@@ -4,8 +4,7 @@
use rustc_errors::MultiSpan;
use rustc_hir::{BindingMode, ByRef, HirId, Mutability};
use rustc_lint as lint;
-use rustc_middle::span_bug;
-use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, Ty, TyCtxt};
+use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, TyCtxt};
use rustc_span::{Ident, Span};
use crate::errors::{Rust2024IncompatiblePat, Rust2024IncompatiblePatSugg};
@@ -87,19 +86,18 @@ pub(super) fn emit<'tcx>(self, tcx: TyCtxt<'tcx>, pat_id: HirId) {
}
/// Tracks when we're lowering a pattern that implicitly dereferences the scrutinee.
- /// This should only be called when the pattern type adjustments list `adjustments` is
- /// non-empty. Returns the prior default binding mode; this should be followed by a call to
- /// [`PatMigration::leave_ref`] to restore it when we leave the pattern.
+ /// This should only be called when the pattern type adjustments list `adjustments` contains an
+ /// implicit deref of a reference type. Returns the prior default binding mode; this should be
+ /// followed by a call to [`PatMigration::leave_ref`] to restore it when we leave the pattern.
pub(super) fn visit_implicit_derefs<'tcx>(
&mut self,
pat_span: Span,
- adjustments: &[Ty<'tcx>],
+ adjustments: &[ty::adjustment::PatAdjustment<'tcx>],
) -> Option<(Span, Mutability)> {
- let implicit_deref_mutbls = adjustments.iter().map(|ref_ty| {
- let &ty::Ref(_, _, mutbl) = ref_ty.kind() else {
- span_bug!(pat_span, "pattern implicitly dereferences a non-ref type");
- };
- mutbl
+ // Implicitly dereferencing references changes the default binding mode, but implicit derefs
+ // of smart pointers do not. Thus, we only consider implicit derefs of reference types.
+ let implicit_deref_mutbls = adjustments.iter().filter_map(|adjust| {
+ if let &ty::Ref(_, _, mutbl) = adjust.source.kind() { Some(mutbl) } else { None }
});
if !self.info.suggest_eliding_modes {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 73d60cf..8f058ef 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -18,6 +18,7 @@
use rustc_middle::thir::{
Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
};
+use rustc_middle::ty::adjustment::{PatAdjust, PatAdjustment};
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypingMode};
use rustc_middle::{bug, span_bug};
@@ -63,13 +64,15 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
- let adjustments: &[Ty<'tcx>] =
+ let adjustments: &[PatAdjustment<'tcx>] =
self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
// Track the default binding mode for the Rust 2024 migration suggestion.
+ // Implicitly dereferencing references changes the default binding mode, but implicit deref
+ // patterns do not. Only track binding mode changes if a ref type is in the adjustments.
let mut opt_old_mode_span = None;
if let Some(s) = &mut self.rust_2024_migration
- && !adjustments.is_empty()
+ && adjustments.iter().any(|adjust| adjust.kind == PatAdjust::BuiltinDeref)
{
opt_old_mode_span = s.visit_implicit_derefs(pat.span, adjustments);
}
@@ -102,17 +105,23 @@ fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
_ => self.lower_pattern_unadjusted(pat),
};
- let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, ref_ty| {
- debug!("{:?}: wrapping pattern with type {:?}", thir_pat, ref_ty);
- Box::new(Pat {
- span: thir_pat.span,
- ty: *ref_ty,
- kind: PatKind::Deref { subpattern: thir_pat },
- })
+ let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, adjust| {
+ debug!("{:?}: wrapping pattern with adjustment {:?}", thir_pat, adjust);
+ let span = thir_pat.span;
+ let kind = match adjust.kind {
+ PatAdjust::BuiltinDeref => PatKind::Deref { subpattern: thir_pat },
+ PatAdjust::OverloadedDeref => {
+ let mutable = self.typeck_results.pat_has_ref_mut_binding(pat);
+ let mutability =
+ if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
+ PatKind::DerefPattern { subpattern: thir_pat, mutability }
+ }
+ };
+ Box::new(Pat { span, ty: adjust.source, kind })
});
if let Some(s) = &mut self.rust_2024_migration
- && !adjustments.is_empty()
+ && adjustments.iter().any(|adjust| adjust.kind == PatAdjust::BuiltinDeref)
{
s.leave_ref(opt_old_mode_span);
}
diff --git a/compiler/rustc_mir_dataflow/src/framework/cursor.rs b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
index c46ae97..d500576 100644
--- a/compiler/rustc_mir_dataflow/src/framework/cursor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/cursor.rs
@@ -114,26 +114,11 @@ pub(crate) fn allow_unreachable(&mut self) {
self.reachable_blocks.insert_all()
}
- /// Returns the underlying `Results`.
- pub fn results(&self) -> &Results<'tcx, A> {
- &self.results
- }
-
- /// Returns the underlying `Results`.
- pub fn mut_results(&mut self) -> &mut Results<'tcx, A> {
- &mut self.results
- }
-
/// Returns the `Analysis` used to generate the underlying `Results`.
pub fn analysis(&self) -> &A {
&self.results.analysis
}
- /// Returns the `Analysis` used to generate the underlying `Results`.
- pub fn mut_analysis(&mut self) -> &mut A {
- &mut self.results.analysis
- }
-
/// Resets the cursor to hold the entry set for the given basic block.
///
/// For forward dataflow analyses, this is the dataflow state prior to the first statement.
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index 3d7f9e2..b8c26da 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -43,7 +43,7 @@ fn visit_results_in_block<'mir, 'tcx, A>(
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
results: &mut Results<'tcx, A>,
- vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
+ vis: &mut impl ResultsVisitor<'tcx, A>,
) where
A: Analysis<'tcx>;
}
@@ -212,7 +212,7 @@ fn visit_results_in_block<'mir, 'tcx, A>(
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
results: &mut Results<'tcx, A>,
- vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
+ vis: &mut impl ResultsVisitor<'tcx, A>,
) where
A: Analysis<'tcx>,
{
@@ -394,7 +394,7 @@ fn visit_results_in_block<'mir, 'tcx, A>(
block: BasicBlock,
block_data: &'mir mir::BasicBlockData<'tcx>,
results: &mut Results<'tcx, A>,
- vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
+ vis: &mut impl ResultsVisitor<'tcx, A>,
) where
A: Analysis<'tcx>,
{
diff --git a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
index 448fad2..b5e9a0b 100644
--- a/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/graphviz.rs
@@ -109,27 +109,29 @@ fn parse(tcx: TyCtxt<'_>, def_id: DefId) -> Result<Self, ()> {
.flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));
for attr in rustc_mir_attrs {
- let attr_result = if attr.has_name(sym::borrowck_graphviz_postflow) {
- Self::set_field(&mut ret.basename_and_suffix, tcx, &attr, |s| {
- let path = PathBuf::from(s.to_string());
- match path.file_name() {
- Some(_) => Ok(path),
- None => {
- tcx.dcx().emit_err(PathMustEndInFilename { span: attr.span() });
+ let attr_result = match attr.name() {
+ Some(name @ sym::borrowck_graphviz_postflow) => {
+ Self::set_field(&mut ret.basename_and_suffix, tcx, name, &attr, |s| {
+ let path = PathBuf::from(s.to_string());
+ match path.file_name() {
+ Some(_) => Ok(path),
+ None => {
+ tcx.dcx().emit_err(PathMustEndInFilename { span: attr.span() });
+ Err(())
+ }
+ }
+ })
+ }
+ Some(name @ sym::borrowck_graphviz_format) => {
+ Self::set_field(&mut ret.formatter, tcx, name, &attr, |s| match s {
+ sym::two_phase => Ok(s),
+ _ => {
+ tcx.dcx().emit_err(UnknownFormatter { span: attr.span() });
Err(())
}
- }
- })
- } else if attr.has_name(sym::borrowck_graphviz_format) {
- Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s {
- sym::gen_kill | sym::two_phase => Ok(s),
- _ => {
- tcx.dcx().emit_err(UnknownFormatter { span: attr.span() });
- Err(())
- }
- })
- } else {
- Ok(())
+ })
+ }
+ _ => Ok(()),
};
result = result.and(attr_result);
@@ -141,12 +143,12 @@ fn parse(tcx: TyCtxt<'_>, def_id: DefId) -> Result<Self, ()> {
fn set_field<T>(
field: &mut Option<T>,
tcx: TyCtxt<'_>,
+ name: Symbol,
attr: &ast::MetaItemInner,
mapper: impl FnOnce(Symbol) -> Result<T, ()>,
) -> Result<(), ()> {
if field.is_some() {
- tcx.dcx()
- .emit_err(DuplicateValuesFor { span: attr.span(), name: attr.name_or_empty() });
+ tcx.dcx().emit_err(DuplicateValuesFor { span: attr.span(), name });
return Err(());
}
@@ -156,7 +158,7 @@ fn set_field<T>(
Ok(())
} else {
tcx.dcx()
- .emit_err(RequiresAnArgument { span: attr.span(), name: attr.name_or_empty() });
+ .emit_err(RequiresAnArgument { span: attr.span(), name: attr.name().unwrap() });
Err(())
}
}
@@ -199,11 +201,12 @@ struct Formatter<'mir, 'tcx, A>
where
A: Analysis<'tcx>,
{
+ body: &'mir Body<'tcx>,
// The `RefCell` is used because `<Formatter as Labeller>::node_label`
- // takes `&self`, but it needs to modify the cursor. This is also the
+ // takes `&self`, but it needs to modify the results. This is also the
// reason for the `Formatter`/`BlockFormatter` split; `BlockFormatter` has
// the operations that involve the mutation, i.e. within the `borrow_mut`.
- cursor: RefCell<ResultsCursor<'mir, 'tcx, A>>,
+ results: RefCell<&'mir mut Results<'tcx, A>>,
style: OutputStyle,
reachable: DenseBitSet<BasicBlock>,
}
@@ -218,11 +221,7 @@ fn new(
style: OutputStyle,
) -> Self {
let reachable = traversal::reachable_as_bitset(body);
- Formatter { cursor: results.as_results_cursor(body).into(), style, reachable }
- }
-
- fn body(&self) -> &'mir Body<'tcx> {
- self.cursor.borrow().body()
+ Formatter { body, results: results.into(), style, reachable }
}
}
@@ -251,7 +250,7 @@ impl<'tcx, A> dot::Labeller<'_> for Formatter<'_, 'tcx, A>
type Edge = CfgEdge;
fn graph_id(&self) -> dot::Id<'_> {
- let name = graphviz_safe_def_name(self.body().source.def_id());
+ let name = graphviz_safe_def_name(self.body.source.def_id());
dot::Id::new(format!("graph_for_def_id_{name}")).unwrap()
}
@@ -260,10 +259,16 @@ fn node_id(&self, n: &Self::Node) -> dot::Id<'_> {
}
fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> {
- let mut cursor = self.cursor.borrow_mut();
- let mut fmt =
- BlockFormatter { cursor: &mut cursor, style: self.style, bg: Background::Light };
- let label = fmt.write_node_label(*block).unwrap();
+ let mut results = self.results.borrow_mut();
+
+ let diffs = StateDiffCollector::run(self.body, *block, *results, self.style);
+
+ let mut fmt = BlockFormatter {
+ cursor: results.as_results_cursor(self.body),
+ style: self.style,
+ bg: Background::Light,
+ };
+ let label = fmt.write_node_label(*block, diffs).unwrap();
dot::LabelText::html(String::from_utf8(label).unwrap())
}
@@ -273,7 +278,7 @@ fn node_shape(&self, _n: &Self::Node) -> Option<dot::LabelText<'_>> {
}
fn edge_label(&self, e: &Self::Edge) -> dot::LabelText<'_> {
- let label = &self.body()[e.source].terminator().kind.fmt_successor_labels()[e.index];
+ let label = &self.body[e.source].terminator().kind.fmt_successor_labels()[e.index];
dot::LabelText::label(label.clone())
}
}
@@ -286,7 +291,7 @@ impl<'tcx, A> dot::GraphWalk<'_> for Formatter<'_, 'tcx, A>
type Edge = CfgEdge;
fn nodes(&self) -> dot::Nodes<'_, Self::Node> {
- self.body()
+ self.body
.basic_blocks
.indices()
.filter(|&idx| self.reachable.contains(idx))
@@ -295,10 +300,10 @@ fn nodes(&self) -> dot::Nodes<'_, Self::Node> {
}
fn edges(&self) -> dot::Edges<'_, Self::Edge> {
- let body = self.body();
- body.basic_blocks
+ self.body
+ .basic_blocks
.indices()
- .flat_map(|bb| dataflow_successors(body, bb))
+ .flat_map(|bb| dataflow_successors(self.body, bb))
.collect::<Vec<_>>()
.into()
}
@@ -308,20 +313,20 @@ fn source(&self, edge: &Self::Edge) -> Self::Node {
}
fn target(&self, edge: &Self::Edge) -> Self::Node {
- self.body()[edge.source].terminator().successors().nth(edge.index).unwrap()
+ self.body[edge.source].terminator().successors().nth(edge.index).unwrap()
}
}
-struct BlockFormatter<'a, 'mir, 'tcx, A>
+struct BlockFormatter<'mir, 'tcx, A>
where
A: Analysis<'tcx>,
{
- cursor: &'a mut ResultsCursor<'mir, 'tcx, A>,
+ cursor: ResultsCursor<'mir, 'tcx, A>,
bg: Background,
style: OutputStyle,
}
-impl<'tcx, A> BlockFormatter<'_, '_, 'tcx, A>
+impl<'tcx, A> BlockFormatter<'_, 'tcx, A>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>,
@@ -334,7 +339,11 @@ fn toggle_background(&mut self) -> Background {
bg
}
- fn write_node_label(&mut self, block: BasicBlock) -> io::Result<Vec<u8>> {
+ fn write_node_label(
+ &mut self,
+ block: BasicBlock,
+ diffs: StateDiffCollector<A::Domain>,
+ ) -> io::Result<Vec<u8>> {
use std::io::Write;
// Sample output:
@@ -390,7 +399,7 @@ fn write_node_label(&mut self, block: BasicBlock) -> io::Result<Vec<u8>> {
self.write_row_with_full_state(w, "", "(on start)")?;
// D + E: Statement and terminator transfer functions
- self.write_statements_and_terminator(w, block)?;
+ self.write_statements_and_terminator(w, block, diffs)?;
// F: State at end of block
@@ -573,14 +582,8 @@ fn write_statements_and_terminator(
&mut self,
w: &mut impl io::Write,
block: BasicBlock,
+ diffs: StateDiffCollector<A::Domain>,
) -> io::Result<()> {
- let diffs = StateDiffCollector::run(
- self.cursor.body(),
- block,
- self.cursor.mut_results(),
- self.style,
- );
-
let mut diffs_before = diffs.before.map(|v| v.into_iter());
let mut diffs_after = diffs.after.into_iter();
@@ -707,7 +710,7 @@ fn run<'tcx, A>(
}
}
-impl<'tcx, A> ResultsVisitor<'_, 'tcx, A> for StateDiffCollector<A::Domain>
+impl<'tcx, A> ResultsVisitor<'tcx, A> for StateDiffCollector<A::Domain>
where
A: Analysis<'tcx>,
A::Domain: DebugWithContext<A>,
diff --git a/compiler/rustc_mir_dataflow/src/framework/results.rs b/compiler/rustc_mir_dataflow/src/framework/results.rs
index 8e2c3af..93dfc06 100644
--- a/compiler/rustc_mir_dataflow/src/framework/results.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/results.rs
@@ -47,7 +47,7 @@ pub fn visit_with<'mir>(
&mut self,
body: &'mir Body<'tcx>,
blocks: impl IntoIterator<Item = BasicBlock>,
- vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
+ vis: &mut impl ResultsVisitor<'tcx, A>,
) {
visit_results(body, blocks, self, vis)
}
@@ -55,7 +55,7 @@ pub fn visit_with<'mir>(
pub fn visit_reachable_with<'mir>(
&mut self,
body: &'mir Body<'tcx>,
- vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
+ vis: &mut impl ResultsVisitor<'tcx, A>,
) {
let blocks = traversal::reachable(body);
visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
diff --git a/compiler/rustc_mir_dataflow/src/framework/visitor.rs b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
index a03aece..c9fdf46 100644
--- a/compiler/rustc_mir_dataflow/src/framework/visitor.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/visitor.rs
@@ -8,7 +8,7 @@ pub fn visit_results<'mir, 'tcx, A>(
body: &'mir mir::Body<'tcx>,
blocks: impl IntoIterator<Item = BasicBlock>,
results: &mut Results<'tcx, A>,
- vis: &mut impl ResultsVisitor<'mir, 'tcx, A>,
+ vis: &mut impl ResultsVisitor<'tcx, A>,
) where
A: Analysis<'tcx>,
{
@@ -29,7 +29,7 @@ pub fn visit_results<'mir, 'tcx, A>(
/// A visitor over the results of an `Analysis`. Use this when you want to inspect domain values in
/// many or all locations; use `ResultsCursor` if you want to inspect domain values only in certain
/// locations.
-pub trait ResultsVisitor<'mir, 'tcx, A>
+pub trait ResultsVisitor<'tcx, A>
where
A: Analysis<'tcx>,
{
@@ -40,7 +40,7 @@ fn visit_after_early_statement_effect(
&mut self,
_results: &mut Results<'tcx, A>,
_state: &A::Domain,
- _statement: &'mir mir::Statement<'tcx>,
+ _statement: &mir::Statement<'tcx>,
_location: Location,
) {
}
@@ -50,7 +50,7 @@ fn visit_after_primary_statement_effect(
&mut self,
_results: &mut Results<'tcx, A>,
_state: &A::Domain,
- _statement: &'mir mir::Statement<'tcx>,
+ _statement: &mir::Statement<'tcx>,
_location: Location,
) {
}
@@ -60,7 +60,7 @@ fn visit_after_early_terminator_effect(
&mut self,
_results: &mut Results<'tcx, A>,
_state: &A::Domain,
- _terminator: &'mir mir::Terminator<'tcx>,
+ _terminator: &mir::Terminator<'tcx>,
_location: Location,
) {
}
@@ -72,7 +72,7 @@ fn visit_after_primary_terminator_effect(
&mut self,
_results: &mut Results<'tcx, A>,
_state: &A::Domain,
- _terminator: &'mir mir::Terminator<'tcx>,
+ _terminator: &mir::Terminator<'tcx>,
_location: Location,
) {
}
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index 82c57ef..a0efc62 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -1,5 +1,4 @@
// tidy-alphabetical-start
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(assert_matches)]
#![feature(associated_type_defaults)]
#![feature(box_patterns)]
diff --git a/compiler/rustc_mir_dataflow/src/points.rs b/compiler/rustc_mir_dataflow/src/points.rs
index 5d2a78a..21590ff 100644
--- a/compiler/rustc_mir_dataflow/src/points.rs
+++ b/compiler/rustc_mir_dataflow/src/points.rs
@@ -120,12 +120,12 @@ struct Visitor<'a, N: Idx> {
values: SparseIntervalMatrix<N, PointIndex>,
}
-impl<'mir, 'tcx, A, N> ResultsVisitor<'mir, 'tcx, A> for Visitor<'_, N>
+impl<'tcx, A, N> ResultsVisitor<'tcx, A> for Visitor<'_, N>
where
A: Analysis<'tcx, Domain = DenseBitSet<N>>,
N: Idx,
{
- fn visit_after_primary_statement_effect(
+ fn visit_after_primary_statement_effect<'mir>(
&mut self,
_results: &mut Results<'tcx, A>,
state: &A::Domain,
@@ -139,7 +139,7 @@ fn visit_after_primary_statement_effect(
});
}
- fn visit_after_primary_terminator_effect(
+ fn visit_after_primary_terminator_effect<'mir>(
&mut self,
_results: &mut Results<'tcx, A>,
state: &A::Domain,
diff --git a/compiler/rustc_mir_transform/src/check_call_recursion.rs b/compiler/rustc_mir_transform/src/check_call_recursion.rs
index e49723a..cace4cd 100644
--- a/compiler/rustc_mir_transform/src/check_call_recursion.rs
+++ b/compiler/rustc_mir_transform/src/check_call_recursion.rs
@@ -3,6 +3,7 @@
use rustc_data_structures::graph::iterate::{
NodeStatus, TriColorDepthFirstSearch, TriColorVisitor,
};
+use rustc_hir::LangItem;
use rustc_hir::def::DefKind;
use rustc_middle::mir::{self, BasicBlock, BasicBlocks, Body, Terminator, TerminatorKind};
use rustc_middle::ty::{self, GenericArg, GenericArgs, Instance, Ty, TyCtxt};
@@ -44,8 +45,7 @@ fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
if let DefKind::AssocFn = tcx.def_kind(def_id)
&& let Some(trait_ref) =
tcx.impl_of_method(def_id.to_def_id()).and_then(|def_id| tcx.impl_trait_ref(def_id))
- && let Some(drop_trait) = tcx.lang_items().drop_trait()
- && drop_trait == trait_ref.instantiate_identity().def_id
+ && tcx.is_lang_item(trait_ref.instantiate_identity().def_id, LangItem::Drop)
// avoid erroneous `Drop` impls from causing ICEs below
&& let sig = tcx.fn_sig(def_id).instantiate_identity()
&& sig.inputs().skip_binder().len() == 1
diff --git a/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs
index ed3b1ae..daddb5d 100644
--- a/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs
+++ b/compiler/rustc_mir_transform/src/check_undefined_transmutes.rs
@@ -42,7 +42,7 @@ fn is_ptr_to_int_in_const(&self, function: &Operand<'tcx>) -> bool {
if self.tcx.is_const_fn(def_id)
|| matches!(
self.tcx.opt_associated_item(def_id),
- Some(AssocItem { kind: AssocKind::Const, .. })
+ Some(AssocItem { kind: AssocKind::Const { .. }, .. })
)
{
let fn_sig = function.ty(self.body, self.tcx).fn_sig(self.tcx).skip_binder();
diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
index cb84401..4be67b8 100644
--- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
@@ -35,7 +35,8 @@ fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// MIR building, and are not needed after InstrumentCoverage.
CoverageKind::BlockMarker { .. } | CoverageKind::SpanMarker { .. },
)
- | StatementKind::FakeRead(..) => statement.make_nop(),
+ | StatementKind::FakeRead(..)
+ | StatementKind::BackwardIncompatibleDropHint { .. } => statement.make_nop(),
StatementKind::Assign(box (
_,
Rvalue::Cast(
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 04d96f1..0eed46c 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -203,7 +203,7 @@ struct TransformVisitor<'tcx> {
impl<'tcx> TransformVisitor<'tcx> {
fn insert_none_ret_block(&self, body: &mut Body<'tcx>) -> BasicBlock {
- let block = BasicBlock::new(body.basic_blocks.len());
+ let block = body.basic_blocks.next_index();
let source_info = SourceInfo::outermost(body.span);
let none_value = match self.coroutine_kind {
@@ -547,7 +547,7 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let get_context_def_id = tcx.require_lang_item(LangItem::GetContext, None);
- for bb in START_BLOCK..body.basic_blocks.next_index() {
+ for bb in body.basic_blocks.indices() {
let bb_data = &body[bb];
if bb_data.is_cleanup {
continue;
@@ -556,11 +556,11 @@ fn transform_async_context<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
match &bb_data.terminator().kind {
TerminatorKind::Call { func, .. } => {
let func_ty = func.ty(body, tcx);
- if let ty::FnDef(def_id, _) = *func_ty.kind() {
- if def_id == get_context_def_id {
- let local = eliminate_get_context_call(&mut body[bb]);
- replace_resume_ty_local(tcx, body, local, context_mut_ref);
- }
+ if let ty::FnDef(def_id, _) = *func_ty.kind()
+ && def_id == get_context_def_id
+ {
+ let local = eliminate_get_context_call(&mut body[bb]);
+ replace_resume_ty_local(tcx, body, local, context_mut_ref);
}
}
TerminatorKind::Yield { resume_arg, .. } => {
@@ -875,14 +875,14 @@ struct StorageConflictVisitor<'a, 'tcx> {
eligible_storage_live: DenseBitSet<Local>,
}
-impl<'a, 'tcx> ResultsVisitor<'a, 'tcx, MaybeRequiresStorage<'a, 'tcx>>
+impl<'a, 'tcx> ResultsVisitor<'tcx, MaybeRequiresStorage<'a, 'tcx>>
for StorageConflictVisitor<'a, 'tcx>
{
fn visit_after_early_statement_effect(
&mut self,
_results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
state: &DenseBitSet<Local>,
- _statement: &'a Statement<'tcx>,
+ _statement: &Statement<'tcx>,
loc: Location,
) {
self.apply_state(state, loc);
@@ -892,7 +892,7 @@ fn visit_after_early_terminator_effect(
&mut self,
_results: &mut Results<'tcx, MaybeRequiresStorage<'a, 'tcx>>,
state: &DenseBitSet<Local>,
- _terminator: &'a Terminator<'tcx>,
+ _terminator: &Terminator<'tcx>,
loc: Location,
) {
self.apply_state(state, loc);
@@ -1057,7 +1057,7 @@ fn insert_switch<'tcx>(
let blocks = body.basic_blocks_mut().iter_mut();
for target in blocks.flat_map(|b| b.terminator_mut().successors_mut()) {
- *target = BasicBlock::new(target.index() + 1);
+ *target += 1;
}
}
@@ -1169,6 +1169,13 @@ fn create_coroutine_drop_shim<'tcx>(
dump_mir(tcx, false, "coroutine_drop", &0, &body, |_, _| Ok(()));
body.source.instance = drop_instance;
+ // Creating a coroutine drop shim happens on `Analysis(PostCleanup) -> Runtime(Initial)`
+ // but the pass manager doesn't update the phase of the coroutine drop shim. Update the
+ // phase of the drop shim so that later on when we run the pass manager on the shim, in
+ // the `mir_shims` query, we don't ICE on the intra-pass validation before we've updated
+ // the phase of the body from analysis.
+ body.phase = MirPhase::Runtime(RuntimePhase::Initial);
+
body
}
@@ -1186,7 +1193,7 @@ fn insert_panic_block<'tcx>(
body: &mut Body<'tcx>,
message: AssertMessage<'tcx>,
) -> BasicBlock {
- let assert_block = BasicBlock::new(body.basic_blocks.len());
+ let assert_block = body.basic_blocks.next_index();
let kind = TerminatorKind::Assert {
cond: Operand::Constant(Box::new(ConstOperand {
span: body.span,
@@ -1209,14 +1216,8 @@ fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, typing_env: ty::Typing
}
// If there's a return terminator the function may return.
- for block in body.basic_blocks.iter() {
- if let TerminatorKind::Return = block.terminator().kind {
- return true;
- }
- }
-
+ body.basic_blocks.iter().any(|block| matches!(block.terminator().kind, TerminatorKind::Return))
// Otherwise the function can't return.
- false
}
fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
@@ -1293,12 +1294,12 @@ fn create_coroutine_resume_function<'tcx>(
kind: TerminatorKind::Goto { target: poison_block },
};
}
- } else if !block.is_cleanup {
+ } else if !block.is_cleanup
// Any terminators that *can* unwind but don't have an unwind target set are also
// pointed at our poisoning block (unless they're part of the cleanup path).
- if let Some(unwind @ UnwindAction::Continue) = block.terminator_mut().unwind_mut() {
- *unwind = UnwindAction::Cleanup(poison_block);
- }
+ && let Some(unwind @ UnwindAction::Continue) = block.terminator_mut().unwind_mut()
+ {
+ *unwind = UnwindAction::Cleanup(poison_block);
}
}
}
@@ -1340,12 +1341,14 @@ fn create_coroutine_resume_function<'tcx>(
make_coroutine_state_argument_indirect(tcx, body);
match transform.coroutine_kind {
+ CoroutineKind::Coroutine(_)
+ | CoroutineKind::Desugared(CoroutineDesugaring::Async | CoroutineDesugaring::AsyncGen, _) =>
+ {
+ make_coroutine_state_argument_pinned(tcx, body);
+ }
// Iterator::next doesn't accept a pinned argument,
// unlike for all other coroutine kinds.
CoroutineKind::Desugared(CoroutineDesugaring::Gen, _) => {}
- _ => {
- make_coroutine_state_argument_pinned(tcx, body);
- }
}
// Make sure we remove dead blocks to remove
@@ -1408,8 +1411,7 @@ fn create_cases<'tcx>(
let mut statements = Vec::new();
// Create StorageLive instructions for locals with live storage
- for i in 0..(body.local_decls.len()) {
- let l = Local::new(i);
+ for l in body.local_decls.indices() {
let needs_storage_live = point.storage_liveness.contains(l)
&& !transform.remap.contains(l)
&& !transform.always_live_locals.contains(l);
@@ -1535,15 +1537,10 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let coroutine_kind = body.coroutine_kind().unwrap();
// Get the discriminant type and args which typeck computed
- let (discr_ty, movable) = match *coroutine_ty.kind() {
- ty::Coroutine(_, args) => {
- let args = args.as_coroutine();
- (args.discr_ty(tcx), coroutine_kind.movability() == hir::Movability::Movable)
- }
- _ => {
- tcx.dcx().span_bug(body.span, format!("unexpected coroutine type {coroutine_ty}"));
- }
+ let ty::Coroutine(_, args) = coroutine_ty.kind() else {
+ tcx.dcx().span_bug(body.span, format!("unexpected coroutine type {coroutine_ty}"));
};
+ let discr_ty = args.as_coroutine().discr_ty(tcx);
let new_ret_ty = match coroutine_kind {
CoroutineKind::Desugared(CoroutineDesugaring::Async, _) => {
@@ -1610,6 +1607,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let always_live_locals = always_storage_live_locals(body);
+ let movable = coroutine_kind.movability() == hir::Movability::Movable;
let liveness_info =
locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index 90173da..a2103a0 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -958,13 +958,13 @@ fn try_write_constant<'tcx>(
interp_ok(())
}
-impl<'mir, 'tcx> ResultsVisitor<'mir, 'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> {
+impl<'tcx> ResultsVisitor<'tcx, ConstAnalysis<'_, 'tcx>> for Collector<'_, 'tcx> {
#[instrument(level = "trace", skip(self, results, statement))]
fn visit_after_early_statement_effect(
&mut self,
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
state: &State<FlatSet<Scalar>>,
- statement: &'mir Statement<'tcx>,
+ statement: &Statement<'tcx>,
location: Location,
) {
match &statement.kind {
@@ -986,7 +986,7 @@ fn visit_after_primary_statement_effect(
&mut self,
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
state: &State<FlatSet<Scalar>>,
- statement: &'mir Statement<'tcx>,
+ statement: &Statement<'tcx>,
location: Location,
) {
match statement.kind {
@@ -1011,7 +1011,7 @@ fn visit_after_early_terminator_effect(
&mut self,
results: &mut Results<'tcx, ConstAnalysis<'_, 'tcx>>,
state: &State<FlatSet<Scalar>>,
- terminator: &'mir Terminator<'tcx>,
+ terminator: &Terminator<'tcx>,
location: Location,
) {
OperandCollector {
diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
index 57f7893..c7feb9e 100644
--- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
+++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs
@@ -103,9 +103,8 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let mut should_cleanup = false;
// Also consider newly generated bbs in the same pass
- for i in 0..body.basic_blocks.len() {
+ for parent in body.basic_blocks.indices() {
let bbs = &*body.basic_blocks;
- let parent = BasicBlock::from_usize(i);
let Some(opt_data) = evaluate_candidate(tcx, body, parent) else { continue };
trace!("SUCCESS: found optimization possibility to apply: {opt_data:?}");
@@ -224,7 +223,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// Since this optimization adds new basic blocks and invalidates others,
// clean up the cfg to make it nicer for other passes
if should_cleanup {
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
diff --git a/compiler/rustc_mir_transform/src/elaborate_drop.rs b/compiler/rustc_mir_transform/src/elaborate_drop.rs
index 0d8cf52..e3057a2 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drop.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drop.rs
@@ -258,31 +258,27 @@ fn move_paths_for_fields(
) -> Vec<(Place<'tcx>, Option<D::Path>)> {
variant
.fields
- .iter()
- .enumerate()
- .map(|(i, f)| {
- let field = FieldIdx::new(i);
- let subpath = self.elaborator.field_subpath(variant_path, field);
+ .iter_enumerated()
+ .map(|(field_idx, field)| {
+ let subpath = self.elaborator.field_subpath(variant_path, field_idx);
let tcx = self.tcx();
assert_eq!(self.elaborator.typing_env().typing_mode, ty::TypingMode::PostAnalysis);
- // The type error for normalization may have been in dropck: see
- // `compute_drop_data` in rustc_borrowck, in which case we wouldn't have
- // deleted the MIR body and could have an error here as well.
- let field_ty = match tcx
- .try_normalize_erasing_regions(self.elaborator.typing_env(), f.ty(tcx, args))
- {
+ let field_ty = match tcx.try_normalize_erasing_regions(
+ self.elaborator.typing_env(),
+ field.ty(tcx, args),
+ ) {
Ok(t) => t,
Err(_) => Ty::new_error(
self.tcx(),
- self.elaborator
- .body()
- .tainted_by_errors
- .expect("Error in drop elaboration not found by dropck."),
+ self.tcx().dcx().span_delayed_bug(
+ self.elaborator.body().span,
+ "Error normalizing in drop elaboration.",
+ ),
),
};
- (tcx.mk_place_field(base_place, field, field_ty), subpath)
+ (tcx.mk_place_field(base_place, field_idx, field_ty), subpath)
})
.collect()
}
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 0ab24e4..c573219 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -63,7 +63,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let _guard = span.enter();
if inline::<NormalInliner<'tcx>>(tcx, body) {
debug!("running simplify cfg on {:?}", body.source);
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
deref_finder(tcx, body);
}
}
@@ -99,7 +99,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let _guard = span.enter();
if inline::<ForceInliner<'tcx>>(tcx, body) {
debug!("running simplify cfg on {:?}", body.source);
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
deref_finder(tcx, body);
}
}
@@ -903,9 +903,9 @@ fn dest_needs_borrow(place: Place<'_>) -> bool {
let mut integrator = Integrator {
args: &args,
- new_locals: Local::new(caller_body.local_decls.len())..,
- new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
- new_blocks: BasicBlock::new(caller_body.basic_blocks.len())..,
+ new_locals: caller_body.local_decls.next_index()..,
+ new_scopes: caller_body.source_scopes.next_index()..,
+ new_blocks: caller_body.basic_blocks.next_index()..,
destination: destination_local,
callsite_scope: caller_body.source_scopes[callsite.source_info.scope].clone(),
callsite,
@@ -1169,7 +1169,7 @@ fn map_local(&self, local: Local) -> Local {
if idx < self.args.len() {
self.args[idx]
} else {
- Local::new(self.new_locals.start.index() + (idx - self.args.len()))
+ self.new_locals.start + (idx - self.args.len())
}
};
trace!("mapping local `{:?}` to `{:?}`", local, new);
@@ -1177,13 +1177,13 @@ fn map_local(&self, local: Local) -> Local {
}
fn map_scope(&self, scope: SourceScope) -> SourceScope {
- let new = SourceScope::new(self.new_scopes.start.index() + scope.index());
+ let new = self.new_scopes.start + scope.index();
trace!("mapping scope `{:?}` to `{:?}`", scope, new);
new
}
fn map_block(&self, block: BasicBlock) -> BasicBlock {
- let new = BasicBlock::new(self.new_blocks.start.index() + block.index());
+ let new = self.new_blocks.start + block.index();
trace!("mapping block `{:?}` to `{:?}`", block, new);
new
}
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index a8d6aaa..5f0c55d 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -10,7 +10,6 @@
use rustc_span::{DUMMY_SP, Symbol, sym};
use crate::simplify::simplify_duplicate_switch_targets;
-use crate::take_array;
pub(super) enum InstSimplify {
BeforeInline,
@@ -214,7 +213,9 @@ fn simplify_primitive_clone(
terminator: &mut Terminator<'tcx>,
statements: &mut Vec<Statement<'tcx>>,
) {
- let TerminatorKind::Call { func, args, destination, target, .. } = &mut terminator.kind
+ let TerminatorKind::Call {
+ func, args, destination, target: Some(destination_block), ..
+ } = &terminator.kind
else {
return;
};
@@ -222,15 +223,8 @@ fn simplify_primitive_clone(
// It's definitely not a clone if there are multiple arguments
let [arg] = &args[..] else { return };
- let Some(destination_block) = *target else { return };
-
// Only bother looking more if it's easy to know what we're calling
- let Some((fn_def_id, fn_args)) = func.const_fn_def() else { return };
-
- // Clone needs one arg, so we can cheaply rule out other stuff
- if fn_args.len() != 1 {
- return;
- }
+ let Some((fn_def_id, ..)) = func.const_fn_def() else { return };
// These types are easily available from locals, so check that before
// doing DefId lookups to figure out what we're actually calling.
@@ -238,15 +232,12 @@ fn simplify_primitive_clone(
let ty::Ref(_region, inner_ty, Mutability::Not) = *arg_ty.kind() else { return };
- if !inner_ty.is_trivially_pure_clone_copy() {
+ if !self.tcx.is_lang_item(fn_def_id, LangItem::CloneFn)
+ || !inner_ty.is_trivially_pure_clone_copy()
+ {
return;
}
- if !self.tcx.is_lang_item(fn_def_id, LangItem::CloneFn) {
- return;
- }
-
- let Ok([arg]) = take_array(args) else { return };
let Some(arg_place) = arg.node.place() else { return };
statements.push(Statement {
@@ -258,7 +249,7 @@ fn simplify_primitive_clone(
)),
))),
});
- terminator.kind = TerminatorKind::Goto { target: destination_block };
+ terminator.kind = TerminatorKind::Goto { target: *destination_block };
}
fn simplify_nounwind_call(&self, terminator: &mut Terminator<'tcx>) {
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index 0a72a9d..9732225 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -150,14 +150,6 @@ impl Condition {
fn matches(&self, value: ScalarInt) -> bool {
(self.value == value) == (self.polarity == Polarity::Eq)
}
-
- fn inv(mut self) -> Self {
- self.polarity = match self.polarity {
- Polarity::Eq => Polarity::Ne,
- Polarity::Ne => Polarity::Eq,
- };
- self
- }
}
#[derive(Copy, Clone, Debug)]
@@ -180,8 +172,21 @@ fn iter_matches(self, value: ScalarInt) -> impl Iterator<Item = Condition> {
self.iter().filter(move |c| c.matches(value))
}
- fn map(self, arena: &'a DroplessArena, f: impl Fn(Condition) -> Condition) -> ConditionSet<'a> {
- ConditionSet(arena.alloc_from_iter(self.iter().map(f)))
+ fn map(
+ self,
+ arena: &'a DroplessArena,
+ f: impl Fn(Condition) -> Option<Condition>,
+ ) -> Option<ConditionSet<'a>> {
+ let mut all_ok = true;
+ let set = arena.alloc_from_iter(self.iter().map_while(|c| {
+ if let Some(c) = f(c) {
+ Some(c)
+ } else {
+ all_ok = false;
+ None
+ }
+ }));
+ all_ok.then_some(ConditionSet(set))
}
}
@@ -202,9 +207,7 @@ fn start_from_switch(&mut self, bb: BasicBlock) {
debug!(?discr, ?bb);
let discr_ty = discr.ty(self.body, self.tcx).ty;
- let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else {
- return;
- };
+ let Ok(discr_layout) = self.ecx.layout_of(discr_ty) else { return };
let Some(discr) = self.map.find(discr.as_ref()) else { return };
debug!(?discr);
@@ -227,7 +230,7 @@ fn start_from_switch(&mut self, bb: BasicBlock) {
let conds = ConditionSet(conds);
state.insert_value_idx(discr, conds, &self.map);
- self.find_opportunity(bb, state, cost, 0);
+ self.find_opportunity(bb, state, cost, 0)
}
/// Recursively walk statements backwards from this bb's terminator to find threading
@@ -495,19 +498,22 @@ fn process_assign(
}
}
}
- // Transfer the conditions on the copy rhs, after inversing polarity.
+ // Transfer the conditions on the copy rhs, after inverting the value of the condition.
Rvalue::UnaryOp(UnOp::Not, Operand::Move(place) | Operand::Copy(place)) => {
- if !place.ty(self.body, self.tcx).ty.is_bool() {
- // Constructing the conditions by inverting the polarity
- // of equality is only correct for bools. That is to say,
- // `!a == b` is not `a != b` for integers greater than 1 bit.
- return;
- }
+ let layout = self.ecx.layout_of(place.ty(self.body, self.tcx).ty).unwrap();
let Some(conditions) = state.try_get_idx(lhs, &self.map) else { return };
let Some(place) = self.map.find(place.as_ref()) else { return };
- // FIXME: I think This could be generalized to not bool if we
- // actually perform a logical not on the condition's value.
- let conds = conditions.map(self.arena, Condition::inv);
+ let Some(conds) = conditions.map(self.arena, |mut cond| {
+ cond.value = self
+ .ecx
+ .unary_op(UnOp::Not, &ImmTy::from_scalar_int(cond.value, layout))
+ .discard_err()?
+ .to_scalar_int()
+ .discard_err()?;
+ Some(cond)
+ }) else {
+ return;
+ };
state.insert_value_idx(place, conds, &self.map);
}
// We expect `lhs ?= A`. We found `lhs = Eq(rhs, B)`.
@@ -535,11 +541,15 @@ fn process_assign(
else {
return;
};
- let conds = conditions.map(self.arena, |c| Condition {
- value,
- polarity: if c.matches(equals) { Polarity::Eq } else { Polarity::Ne },
- ..c
- });
+ let Some(conds) = conditions.map(self.arena, |c| {
+ Some(Condition {
+ value,
+ polarity: if c.matches(equals) { Polarity::Eq } else { Polarity::Ne },
+ ..c
+ })
+ }) else {
+ return;
+ };
state.insert_value_idx(place, conds, &self.map);
}
@@ -576,17 +586,17 @@ fn process_statement(
else {
return;
};
- self.process_immediate(bb, discr_target, discr, state);
+ self.process_immediate(bb, discr_target, discr, state)
}
// If we expect `lhs ?= true`, we have an opportunity if we assume `lhs == true`.
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(
Operand::Copy(place) | Operand::Move(place),
)) => {
let Some(conditions) = state.try_get(place.as_ref(), &self.map) else { return };
- conditions.iter_matches(ScalarInt::TRUE).for_each(register_opportunity);
+ conditions.iter_matches(ScalarInt::TRUE).for_each(register_opportunity)
}
StatementKind::Assign(box (lhs_place, rhs)) => {
- self.process_assign(bb, lhs_place, rhs, state);
+ self.process_assign(bb, lhs_place, rhs, state)
}
_ => {}
}
@@ -632,7 +642,7 @@ fn recurse_through_terminator(
if let Some(place_to_flood) = place_to_flood {
state.flood_with(place_to_flood.as_ref(), &self.map, ConditionSet::BOTTOM);
}
- self.find_opportunity(bb, state, cost.clone(), depth + 1);
+ self.find_opportunity(bb, state, cost.clone(), depth + 1)
}
#[instrument(level = "trace", skip(self))]
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index dfd07f0..4d74ecd 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -1,5 +1,4 @@
// tidy-alphabetical-start
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(array_windows)]
#![feature(assert_matches)]
#![feature(box_patterns)]
diff --git a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
index 29a9133..537f152 100644
--- a/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
+++ b/compiler/rustc_mir_transform/src/lint_tail_expr_drop_order.rs
@@ -512,23 +512,17 @@ struct LocalLabel<'a> {
/// A custom `Subdiagnostic` implementation so that the notes are delivered in a specific order
impl Subdiagnostic for LocalLabel<'_> {
- fn add_to_diag_with<
- G: rustc_errors::EmissionGuarantee,
- F: rustc_errors::SubdiagMessageOp<G>,
- >(
- self,
- diag: &mut rustc_errors::Diag<'_, G>,
- f: &F,
- ) {
+ fn add_to_diag<G: rustc_errors::EmissionGuarantee>(self, diag: &mut rustc_errors::Diag<'_, G>) {
diag.arg("name", self.name);
diag.arg("is_generated_name", self.is_generated_name);
diag.arg("is_dropped_first_edition_2024", self.is_dropped_first_edition_2024);
- let msg = f(diag, crate::fluent_generated::mir_transform_tail_expr_local.into());
+ let msg = diag.eagerly_translate(crate::fluent_generated::mir_transform_tail_expr_local);
diag.span_label(self.span, msg);
for dtor in self.destructors {
- dtor.add_to_diag_with(diag, f);
+ dtor.add_to_diag(diag);
}
- let msg = f(diag, crate::fluent_generated::mir_transform_label_local_epilogue);
+ let msg =
+ diag.eagerly_translate(crate::fluent_generated::mir_transform_label_local_epilogue);
diag.span_label(self.span, msg);
}
}
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index 0d9d036..b372411 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -20,13 +20,11 @@ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let typing_env = body.typing_env(tcx);
let mut should_cleanup = false;
- for i in 0..body.basic_blocks.len() {
- let bbs = &*body.basic_blocks;
- let bb_idx = BasicBlock::from_usize(i);
- match bbs[bb_idx].terminator().kind {
+ for bb_idx in body.basic_blocks.indices() {
+ match &body.basic_blocks[bb_idx].terminator().kind {
TerminatorKind::SwitchInt {
- discr: ref _discr @ (Operand::Copy(_) | Operand::Move(_)),
- ref targets,
+ discr: Operand::Copy(_) | Operand::Move(_),
+ targets,
..
// We require that the possible target blocks don't contain this block.
} if !targets.all_targets().contains(&bb_idx) => {}
@@ -45,7 +43,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
}
if should_cleanup {
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
@@ -66,9 +64,10 @@ fn simplify(
typing_env: ty::TypingEnv<'tcx>,
) -> Option<()> {
let bbs = &body.basic_blocks;
- let (discr, targets) = match bbs[switch_bb_idx].terminator().kind {
- TerminatorKind::SwitchInt { ref discr, ref targets, .. } => (discr, targets),
- _ => unreachable!(),
+ let TerminatorKind::SwitchInt { discr, targets, .. } =
+ &bbs[switch_bb_idx].terminator().kind
+ else {
+ unreachable!();
};
let discr_ty = discr.ty(body.local_decls(), tcx);
diff --git a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
index c63bfdc..f59b849 100644
--- a/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
+++ b/compiler/rustc_mir_transform/src/multiple_return_terminators.rs
@@ -18,19 +18,17 @@ fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// find basic blocks with no statement and a return terminator
let mut bbs_simple_returns = DenseBitSet::new_empty(body.basic_blocks.len());
let bbs = body.basic_blocks_mut();
- for idx in bbs.indices() {
- if bbs[idx].statements.is_empty()
- && bbs[idx].terminator().kind == TerminatorKind::Return
- {
+ for (idx, bb) in bbs.iter_enumerated() {
+ if bb.statements.is_empty() && bb.terminator().kind == TerminatorKind::Return {
bbs_simple_returns.insert(idx);
}
}
for bb in bbs {
- if let TerminatorKind::Goto { target } = bb.terminator().kind {
- if bbs_simple_returns.contains(target) {
- bb.terminator_mut().kind = TerminatorKind::Return;
- }
+ if let TerminatorKind::Goto { target } = bb.terminator().kind
+ && bbs_simple_returns.contains(target)
+ {
+ bb.terminator_mut().kind = TerminatorKind::Return;
}
}
diff --git a/compiler/rustc_mir_transform/src/patch.rs b/compiler/rustc_mir_transform/src/patch.rs
index 6a177fa..12ace04 100644
--- a/compiler/rustc_mir_transform/src/patch.rs
+++ b/compiler/rustc_mir_transform/src/patch.rs
@@ -181,7 +181,7 @@ pub(crate) fn local_ty(&self, local: Local) -> Ty<'tcx> {
/// Queues the addition of a new basic block.
pub(crate) fn new_block(&mut self, data: BasicBlockData<'tcx>) -> BasicBlock {
- let block = BasicBlock::new(self.term_patch_map.len());
+ let block = self.term_patch_map.next_index();
debug!("MirPatch: new_block: {:?}: {:?}", block, data);
self.new_blocks.push(data);
self.term_patch_map.push(None);
diff --git a/compiler/rustc_mir_transform/src/post_analysis_normalize.rs b/compiler/rustc_mir_transform/src/post_analysis_normalize.rs
index 76c2f08..5599dee 100644
--- a/compiler/rustc_mir_transform/src/post_analysis_normalize.rs
+++ b/compiler/rustc_mir_transform/src/post_analysis_normalize.rs
@@ -39,20 +39,22 @@ fn visit_place(
_context: PlaceContext,
_location: Location,
) {
- // Performance optimization: don't reintern if there is no `OpaqueCast` to remove.
- if place.projection.iter().all(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_))) {
- return;
+ if !self.tcx.next_trait_solver_globally() {
+ // `OpaqueCast` projections are only needed if there are opaque types on which projections
+ // are performed. After the `PostAnalysisNormalize` pass, all opaque types are replaced with their
+ // hidden types, so we don't need these projections anymore.
+ //
+ // Performance optimization: don't reintern if there is no `OpaqueCast` to remove.
+ if place.projection.iter().any(|elem| matches!(elem, ProjectionElem::OpaqueCast(_))) {
+ place.projection = self.tcx.mk_place_elems(
+ &place
+ .projection
+ .into_iter()
+ .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_)))
+ .collect::<Vec<_>>(),
+ );
+ };
}
- // `OpaqueCast` projections are only needed if there are opaque types on which projections
- // are performed. After the `PostAnalysisNormalize` pass, all opaque types are replaced with their
- // hidden types, so we don't need these projections anymore.
- place.projection = self.tcx.mk_place_elems(
- &place
- .projection
- .into_iter()
- .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(_)))
- .collect::<Vec<_>>(),
- );
self.super_place(place, _context, _location);
}
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index c8d8dc1..47d4383 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -18,7 +18,7 @@
use rustc_const_eval::check_consts::{ConstCx, qualifs};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
-use rustc_index::{Idx, IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::{self, GenericArgs, List, Ty, TyCtxt, TypeVisitableExt};
@@ -864,17 +864,21 @@ fn promote_temp(&mut self, temp: Local) -> Local {
new_temp
}
- fn promote_candidate(mut self, candidate: Candidate, next_promoted_id: usize) -> Body<'tcx> {
+ fn promote_candidate(
+ mut self,
+ candidate: Candidate,
+ next_promoted_index: Promoted,
+ ) -> Body<'tcx> {
let def = self.source.source.def_id();
let (mut rvalue, promoted_op) = {
let promoted = &mut self.promoted;
- let promoted_id = Promoted::new(next_promoted_id);
let tcx = self.tcx;
let mut promoted_operand = |ty, span| {
promoted.span = span;
promoted.local_decls[RETURN_PLACE] = LocalDecl::new(ty, span);
let args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, def));
- let uneval = mir::UnevaluatedConst { def, args, promoted: Some(promoted_id) };
+ let uneval =
+ mir::UnevaluatedConst { def, args, promoted: Some(next_promoted_index) };
ConstOperand { span, user_ty: None, const_: Const::Unevaluated(uneval, ty) }
};
@@ -1034,7 +1038,7 @@ fn promote_candidates<'tcx>(
required_consts: Vec::new(),
};
- let mut promoted = promoter.promote_candidate(candidate, promotions.len());
+ let mut promoted = promoter.promote_candidate(candidate, promotions.next_index());
promoted.source.promoted = Some(promotions.next_index());
promotions.push(promoted);
}
diff --git a/compiler/rustc_mir_transform/src/remove_place_mention.rs b/compiler/rustc_mir_transform/src/remove_place_mention.rs
index 15fe77d..cb598ce 100644
--- a/compiler/rustc_mir_transform/src/remove_place_mention.rs
+++ b/compiler/rustc_mir_transform/src/remove_place_mention.rs
@@ -8,7 +8,7 @@
impl<'tcx> crate::MirPass<'tcx> for RemovePlaceMention {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
- !sess.opts.unstable_opts.mir_keep_place_mention
+ !sess.opts.unstable_opts.mir_preserve_ub
}
fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
diff --git a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
index 8a8cdaf..43f8050 100644
--- a/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir_transform/src/remove_unneeded_drops.rs
@@ -35,7 +35,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// if we applied optimizations, we potentially have some cfg to cleanup to
// make it easier for further passes
if should_simplify {
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
}
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index c977146..c13ffae 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -66,7 +66,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<
let call_mut = tcx
.associated_items(fn_mut)
.in_definition_order()
- .find(|it| it.kind == ty::AssocKind::Fn)
+ .find(|it| it.is_fn())
.unwrap()
.def_id;
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index 84905f4..4f2cce8 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -26,6 +26,13 @@
//! Here the block (`{ return; }`) has the return type `char`, rather than `()`, but the MIR we
//! naively generate still contains the `_a = ()` write in the unreachable block "after" the
//! return.
+//!
+//! **WARNING**: This is one of the few optimizations that runs on built and analysis MIR, and
+//! so its effects may affect the type-checking, borrow-checking, and other analysis of MIR.
+//! We must be extremely careful to only apply optimizations that preserve UB and all
+//! non-determinism, since changes here can affect which programs compile in an insta-stable way.
+//! The normal logic that a program with UB can be changed to do anything does not apply to
+//! pre-"runtime" MIR!
use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
@@ -66,8 +73,8 @@ fn name(&self) -> &'static str {
}
}
-pub(super) fn simplify_cfg(body: &mut Body<'_>) {
- CfgSimplifier::new(body).simplify();
+pub(super) fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ CfgSimplifier::new(tcx, body).simplify();
remove_dead_blocks(body);
// FIXME: Should probably be moved into some kind of pass manager
@@ -79,9 +86,9 @@ fn name(&self) -> &'static str {
self.name()
}
- fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
debug!("SimplifyCfg({:?}) - simplifying {:?}", self.name(), body.source);
- simplify_cfg(body);
+ simplify_cfg(tcx, body);
}
fn is_required(&self) -> bool {
@@ -90,12 +97,13 @@ fn is_required(&self) -> bool {
}
struct CfgSimplifier<'a, 'tcx> {
+ preserve_switch_reads: bool,
basic_blocks: &'a mut IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
pred_count: IndexVec<BasicBlock, u32>,
}
impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
- fn new(body: &'a mut Body<'tcx>) -> Self {
+ fn new(tcx: TyCtxt<'tcx>, body: &'a mut Body<'tcx>) -> Self {
let mut pred_count = IndexVec::from_elem(0u32, &body.basic_blocks);
// we can't use mir.predecessors() here because that counts
@@ -110,9 +118,12 @@ fn new(body: &'a mut Body<'tcx>) -> Self {
}
}
+ // Preserve `SwitchInt` reads on built and analysis MIR, or if `-Zmir-preserve-ub`.
+ let preserve_switch_reads = matches!(body.phase, MirPhase::Built | MirPhase::Analysis(_))
+ || tcx.sess.opts.unstable_opts.mir_preserve_ub;
let basic_blocks = body.basic_blocks_mut();
- CfgSimplifier { basic_blocks, pred_count }
+ CfgSimplifier { preserve_switch_reads, basic_blocks, pred_count }
}
fn simplify(mut self) {
@@ -253,9 +264,15 @@ fn merge_successor(
// turn a branch with all successors identical to a goto
fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
- match terminator.kind {
- TerminatorKind::SwitchInt { .. } => {}
- _ => return false,
+ // Removing a `SwitchInt` terminator may remove reads that result in UB,
+ // so we must not apply this optimization before borrowck or when
+ // `-Zmir-preserve-ub` is set.
+ if self.preserve_switch_reads {
+ return false;
+ }
+
+ let TerminatorKind::SwitchInt { .. } = terminator.kind else {
+ return false;
};
let first_succ = {
@@ -597,20 +614,6 @@ fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}
- fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
- if let StatementKind::BackwardIncompatibleDropHint { place, reason: _ } =
- &mut statement.kind
- {
- self.visit_local(
- &mut place.local,
- PlaceContext::MutatingUse(MutatingUseContext::Store),
- location,
- );
- } else {
- self.super_statement(statement, location);
- }
- }
-
fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) {
*l = self.map[*l].unwrap();
}
diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs
index e7930f0..66fe3ef 100644
--- a/compiler/rustc_mir_transform/src/validate.rs
+++ b/compiler/rustc_mir_transform/src/validate.rs
@@ -221,12 +221,11 @@ fn check_cleanup_control_flow(&self) {
// Check for cycles
let mut stack = FxHashSet::default();
- for i in 0..parent.len() {
- let mut bb = BasicBlock::from_usize(i);
+ for (mut bb, parent) in parent.iter_enumerated_mut() {
stack.clear();
stack.insert(bb);
loop {
- let Some(parent) = parent[bb].take() else { break };
+ let Some(parent) = parent.take() else { break };
let no_cycle = stack.insert(parent);
if !no_cycle {
self.fail(
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 1dbb35f..d1d0f7c 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -688,7 +688,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
let target_ty = self.monomorphize(target_ty);
let source_ty = self.monomorphize(source_ty);
let (source_ty, target_ty) =
- find_vtable_types_for_unsizing(self.tcx.at(span), source_ty, target_ty);
+ find_tails_for_unsizing(self.tcx.at(span), source_ty, target_ty);
// This could also be a different Unsize instruction, like
// from a fixed sized array to a slice. But we are only
// interested in things that produce a vtable.
@@ -1037,36 +1037,35 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) ->
///
/// Finally, there is also the case of custom unsizing coercions, e.g., for
/// smart pointers such as `Rc` and `Arc`.
-fn find_vtable_types_for_unsizing<'tcx>(
+fn find_tails_for_unsizing<'tcx>(
tcx: TyCtxtAt<'tcx>,
source_ty: Ty<'tcx>,
target_ty: Ty<'tcx>,
) -> (Ty<'tcx>, Ty<'tcx>) {
- let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
- let typing_env = ty::TypingEnv::fully_monomorphized();
- if tcx.type_has_metadata(inner_source, typing_env) {
- (inner_source, inner_target)
- } else {
- tcx.struct_lockstep_tails_for_codegen(inner_source, inner_target, typing_env)
- }
- };
+ let typing_env = ty::TypingEnv::fully_monomorphized();
+ debug_assert!(!source_ty.has_param(), "{source_ty} should be fully monomorphic");
+ debug_assert!(!target_ty.has_param(), "{target_ty} should be fully monomorphic");
match (source_ty.kind(), target_ty.kind()) {
- (&ty::Ref(_, a, _), &ty::Ref(_, b, _) | &ty::RawPtr(b, _))
- | (&ty::RawPtr(a, _), &ty::RawPtr(b, _)) => ptr_vtable(a, b),
+ (
+ &ty::Ref(_, source_pointee, _),
+ &ty::Ref(_, target_pointee, _) | &ty::RawPtr(target_pointee, _),
+ )
+ | (&ty::RawPtr(source_pointee, _), &ty::RawPtr(target_pointee, _)) => {
+ tcx.struct_lockstep_tails_for_codegen(source_pointee, target_pointee, typing_env)
+ }
+
+ // `Box<T>` could go through the ADT code below, b/c it'll unpeel to `Unique<T>`,
+ // and eventually bottom out in a raw ref, but we can micro-optimize it here.
(_, _)
if let Some(source_boxed) = source_ty.boxed_ty()
&& let Some(target_boxed) = target_ty.boxed_ty() =>
{
- ptr_vtable(source_boxed, target_boxed)
+ tcx.struct_lockstep_tails_for_codegen(source_boxed, target_boxed, typing_env)
}
- // T as dyn* Trait
- (_, &ty::Dynamic(_, _, ty::DynStar)) => ptr_vtable(source_ty, target_ty),
-
(&ty::Adt(source_adt_def, source_args), &ty::Adt(target_adt_def, target_args)) => {
assert_eq!(source_adt_def, target_adt_def);
-
let CustomCoerceUnsized::Struct(coerce_index) =
match crate::custom_coerce_unsize_info(tcx, source_ty, target_ty) {
Ok(ccu) => ccu,
@@ -1075,21 +1074,23 @@ fn find_vtable_types_for_unsizing<'tcx>(
return (e, e);
}
};
-
- let source_fields = &source_adt_def.non_enum_variant().fields;
- let target_fields = &target_adt_def.non_enum_variant().fields;
-
- assert!(
- coerce_index.index() < source_fields.len()
- && source_fields.len() == target_fields.len()
- );
-
- find_vtable_types_for_unsizing(
- tcx,
- source_fields[coerce_index].ty(*tcx, source_args),
- target_fields[coerce_index].ty(*tcx, target_args),
- )
+ let coerce_field = &source_adt_def.non_enum_variant().fields[coerce_index];
+ // We're getting a possibly unnormalized type, so normalize it.
+ let source_field =
+ tcx.normalize_erasing_regions(typing_env, coerce_field.ty(*tcx, source_args));
+ let target_field =
+ tcx.normalize_erasing_regions(typing_env, coerce_field.ty(*tcx, target_args));
+ find_tails_for_unsizing(tcx, source_field, target_field)
}
+
+ // `T` as `dyn* Trait` unsizes *directly*.
+ //
+ // FIXME(dyn_star): This case is a bit awkward, b/c we're not really computing
+ // a tail here. We probably should handle this separately in the *caller* of
+ // this function, rather than returning something that is semantically different
+ // than what we return above.
+ (_, &ty::Dynamic(_, _, ty::DynStar)) => (source_ty, target_ty),
+
_ => bug!(
"find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}",
source_ty,
@@ -1308,7 +1309,7 @@ fn visit_mentioned_item<'tcx>(
}
MentionedItem::UnsizeCast { source_ty, target_ty } => {
let (source_ty, target_ty) =
- find_vtable_types_for_unsizing(tcx.at(span), source_ty, target_ty);
+ find_tails_for_unsizing(tcx.at(span), source_ty, target_ty);
// This could also be a different Unsize instruction, like
// from a fixed sized array to a slice. But we are only
// interested in things that produce a vtable.
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index adfe096..0dd20bb 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -70,10 +70,11 @@ pub(crate) struct UnknownCguCollectionMode<'a> {
pub mode: &'a str,
}
-#[derive(LintDiagnostic)]
+#[derive(Diagnostic)]
#[diag(monomorphize_abi_error_disabled_vector_type)]
#[help]
pub(crate) struct AbiErrorDisabledVectorType<'a> {
+ #[primary_span]
#[label]
pub span: Span,
pub required_feature: &'a str,
@@ -82,9 +83,10 @@ pub(crate) struct AbiErrorDisabledVectorType<'a> {
pub is_call: bool,
}
-#[derive(LintDiagnostic)]
+#[derive(Diagnostic)]
#[diag(monomorphize_abi_error_unsupported_vector_type)]
pub(crate) struct AbiErrorUnsupportedVectorType<'a> {
+ #[primary_span]
#[label]
pub span: Span,
pub ty: Ty<'a>,
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index 5dbae50..8f6914f 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -1,5 +1,4 @@
// tidy-alphabetical-start
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(array_windows)]
#![feature(file_buffered)]
#![feature(if_let_guard)]
diff --git a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
index 0f5bdc8..2ef23d7 100644
--- a/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
+++ b/compiler/rustc_monomorphize/src/mono_checks/abi_check.rs
@@ -5,7 +5,7 @@
use rustc_middle::mir::{self, Location, traversal};
use rustc_middle::ty::layout::LayoutCx;
use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt, TypingEnv};
-use rustc_session::lint::builtin::{ABI_UNSUPPORTED_VECTOR_TYPES, WASM_C_ABI};
+use rustc_session::lint::builtin::WASM_C_ABI;
use rustc_span::def_id::DefId;
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
use rustc_target::callconv::{ArgAbi, Conv, FnAbi, PassMode};
@@ -50,34 +50,24 @@ fn do_check_simd_vector_abi<'tcx>(
let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) {
Some((_, feature)) => feature,
None => {
- let (span, hir_id) = loc();
- tcx.emit_node_span_lint(
- ABI_UNSUPPORTED_VECTOR_TYPES,
- hir_id,
+ let (span, _hir_id) = loc();
+ tcx.dcx().emit_err(errors::AbiErrorUnsupportedVectorType {
span,
- errors::AbiErrorUnsupportedVectorType {
- span,
- ty: arg_abi.layout.ty,
- is_call,
- },
- );
+ ty: arg_abi.layout.ty,
+ is_call,
+ });
continue;
}
};
if !have_feature(Symbol::intern(feature)) {
// Emit error.
- let (span, hir_id) = loc();
- tcx.emit_node_span_lint(
- ABI_UNSUPPORTED_VECTOR_TYPES,
- hir_id,
+ let (span, _hir_id) = loc();
+ tcx.dcx().emit_err(errors::AbiErrorDisabledVectorType {
span,
- errors::AbiErrorDisabledVectorType {
- span,
- required_feature: feature,
- ty: arg_abi.layout.ty,
- is_call,
- },
- );
+ required_feature: feature,
+ ty: arg_abi.layout.ty,
+ is_call,
+ });
}
}
}
@@ -111,6 +101,11 @@ fn wasm_abi_safe<'tcx>(tcx: TyCtxt<'tcx>, arg: &ArgAbi<'tcx, Ty<'tcx>>) -> bool
}
}
+ // Zero-sized types are dropped in both ABIs, so they're safe
+ if arg.layout.is_zst() {
+ return true;
+ }
+
false
}
diff --git a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs
index 55d52d5..7251ef4 100644
--- a/compiler/rustc_monomorphize/src/mono_checks/move_check.rs
+++ b/compiler/rustc_monomorphize/src/mono_checks/move_check.rs
@@ -3,7 +3,7 @@
use rustc_hir::def_id::DefId;
use rustc_middle::mir::visit::Visitor as MirVisitor;
use rustc_middle::mir::{self, Location, traversal};
-use rustc_middle::ty::{self, AssocKind, Instance, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, AssocTag, Instance, Ty, TyCtxt, TypeFoldable};
use rustc_session::Limit;
use rustc_session::lint::builtin::LARGE_ASSIGNMENTS;
use rustc_span::source_map::Spanned;
@@ -194,7 +194,7 @@ fn assoc_fn_of_type<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, fn_ident: Ident) ->
if let Some(new) = tcx.associated_items(impl_def_id).find_by_ident_and_kind(
tcx,
fn_ident,
- AssocKind::Fn,
+ AssocTag::Fn,
def_id,
) {
return Some(new.def_id);
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index b1b6f10..6bc8a0f 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -223,7 +223,7 @@ fn place_mono_items<'tcx, I>(cx: &PartitioningCx<'_, 'tcx>, mono_items: I) -> Pl
match mono_item.instantiation_mode(cx.tcx) {
InstantiationMode::GloballyShared { .. } => {}
InstantiationMode::LocalCopy => {
- if Some(mono_item.def_id()) != cx.tcx.lang_items().start_fn() {
+ if !cx.tcx.is_lang_item(mono_item.def_id(), LangItem::Start) {
continue;
}
}
@@ -254,8 +254,9 @@ fn place_mono_items<'tcx, I>(cx: &PartitioningCx<'_, 'tcx>, mono_items: I) -> Pl
always_export_generics,
);
- // We can't differentiate something that got inlined.
+ // We can't differentiate a function that got inlined.
let autodiff_active = cfg!(llvm_enzyme)
+ && matches!(mono_item, MonoItem::Fn(_))
&& cx
.tcx
.codegen_fn_attrs(mono_item.def_id())
diff --git a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs
index ebe0b25..22d593b 100644
--- a/compiler/rustc_monomorphize/src/partitioning/autodiff.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/autodiff.rs
@@ -2,7 +2,7 @@
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_middle::bug;
use rustc_middle::mir::mono::MonoItem;
-use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
+use rustc_middle::ty::{self, Instance, PseudoCanonicalInput, Ty, TyCtxt, TypingEnv};
use rustc_symbol_mangling::symbol_name_for_instance_in_crate;
use tracing::{debug, trace};
@@ -22,23 +22,51 @@ fn adjust_activity_to_abi<'tcx>(tcx: TyCtxt<'tcx>, fn_ty: Ty<'tcx>, da: &mut Vec
for (i, ty) in sig.inputs().iter().enumerate() {
if let Some(inner_ty) = ty.builtin_deref(true) {
if inner_ty.is_slice() {
+ // Now we need to figure out the size of each slice element in memory to allow
+ // safety checks and usability improvements in the backend.
+ let sty = match inner_ty.builtin_index() {
+ Some(sty) => sty,
+ None => {
+ panic!("slice element type unknown");
+ }
+ };
+ let pci = PseudoCanonicalInput {
+ typing_env: TypingEnv::fully_monomorphized(),
+ value: sty,
+ };
+
+ let layout = tcx.layout_of(pci);
+ let elem_size = match layout {
+ Ok(layout) => layout.size,
+ Err(_) => {
+ bug!("autodiff failed to compute slice element size");
+ }
+ };
+ let elem_size: u32 = elem_size.bytes() as u32;
+
// We know that the length will be passed as extra arg.
if !da.is_empty() {
// We are looking at a slice. The length of that slice will become an
// extra integer on llvm level. Integers are always const.
// However, if the slice get's duplicated, we want to know to later check the
// size. So we mark the new size argument as FakeActivitySize.
+ // There is one FakeActivitySize per slice, so for convenience we store the
+ // slice element size in bytes in it. We will use the size in the backend.
let activity = match da[i] {
DiffActivity::DualOnly
| DiffActivity::Dual
+ | DiffActivity::Dualv
| DiffActivity::DuplicatedOnly
- | DiffActivity::Duplicated => DiffActivity::FakeActivitySize,
+ | DiffActivity::Duplicated => {
+ DiffActivity::FakeActivitySize(Some(elem_size))
+ }
DiffActivity::Const => DiffActivity::Const,
_ => bug!("unexpected activity for ptr/ref"),
};
new_activities.push(activity);
new_positions.push(i + 1);
}
+
continue;
}
}
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index 384a304..ecb57cc 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -92,16 +92,20 @@ fn probe_and_consider_object_bound_candidate(
let ty::Dynamic(bounds, _, _) = goal.predicate.self_ty().kind() else {
panic!("expected object type in `probe_and_consider_object_bound_candidate`");
};
- ecx.add_goals(
- GoalSource::ImplWhereBound,
- structural_traits::predicates_for_object_candidate(
- ecx,
- goal.param_env,
- goal.predicate.trait_ref(cx),
- bounds,
- ),
- );
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ match structural_traits::predicates_for_object_candidate(
+ ecx,
+ goal.param_env,
+ goal.predicate.trait_ref(cx),
+ bounds,
+ ) {
+ Ok(requirements) => {
+ ecx.add_goals(GoalSource::ImplWhereBound, requirements);
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ }
+ Err(_) => {
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+ }
+ }
})
}
@@ -284,6 +288,21 @@ fn consider_structural_builtin_unsize_candidates(
) -> Vec<Candidate<I>>;
}
+/// Allows callers of `assemble_and_evaluate_candidates` to choose whether to limit
+/// candidate assembly to param-env and alias-bound candidates.
+///
+/// On top of being a micro-optimization, as it avoids doing unnecessary work when
+/// a param-env trait bound candidate shadows impls for normalization, this is also
+/// required to prevent query cycles due to RPITIT inference. See the issue at:
+/// <https://github.com/rust-lang/trait-system-refactor-initiative/issues/173>.
+pub(super) enum AssembleCandidatesFrom {
+ All,
+ /// Only assemble candidates from the environment and alias bounds, ignoring
+ /// user-written and built-in impls. We only expect `ParamEnv` and `AliasBound`
+ /// candidates to be assembled.
+ EnvAndBounds,
+}
+
impl<D, I> EvalCtxt<'_, D>
where
D: SolverDelegate<Interner = I>,
@@ -292,6 +311,7 @@ impl<D, I> EvalCtxt<'_, D>
pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>(
&mut self,
goal: Goal<I, G>,
+ assemble_from: AssembleCandidatesFrom,
) -> Vec<Candidate<I>> {
let Ok(normalized_self_ty) =
self.structurally_normalize_ty(goal.param_env, goal.predicate.self_ty())
@@ -318,16 +338,18 @@ pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<D>>(
}
}
- self.assemble_impl_candidates(goal, &mut candidates);
-
- self.assemble_builtin_impl_candidates(goal, &mut candidates);
-
self.assemble_alias_bound_candidates(goal, &mut candidates);
-
- self.assemble_object_bound_candidates(goal, &mut candidates);
-
self.assemble_param_env_candidates(goal, &mut candidates);
+ match assemble_from {
+ AssembleCandidatesFrom::All => {
+ self.assemble_impl_candidates(goal, &mut candidates);
+ self.assemble_builtin_impl_candidates(goal, &mut candidates);
+ self.assemble_object_bound_candidates(goal, &mut candidates);
+ }
+ AssembleCandidatesFrom::EnvAndBounds => {}
+ }
+
candidates
}
@@ -750,6 +772,9 @@ fn consider_coherence_unknowable_candidate<G: GoalKind<D>>(
})
}
+ /// Assemble and merge candidates for goals which are related to an underlying trait
+ /// goal. Right now, this is normalizes-to and host effect goals.
+ ///
/// We sadly can't simply take all possible candidates for normalization goals
/// and check whether they result in the same constraints. We want to make sure
/// that trying to normalize an alias doesn't result in constraints which aren't
@@ -778,54 +803,63 @@ fn consider_coherence_unknowable_candidate<G: GoalKind<D>>(
///
/// See trait-system-refactor-initiative#124 for more details.
#[instrument(level = "debug", skip(self, inject_normalize_to_rigid_candidate), ret)]
- pub(super) fn merge_candidates(
+ pub(super) fn assemble_and_merge_candidates<G: GoalKind<D>>(
&mut self,
proven_via: Option<TraitGoalProvenVia>,
- candidates: Vec<Candidate<I>>,
+ goal: Goal<I, G>,
inject_normalize_to_rigid_candidate: impl FnOnce(&mut EvalCtxt<'_, D>) -> QueryResult<I>,
) -> QueryResult<I> {
let Some(proven_via) = proven_via else {
// We don't care about overflow. If proving the trait goal overflowed, then
// it's enough to report an overflow error for that, we don't also have to
// overflow during normalization.
- return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Ambiguity));
+ //
+ // We use `forced_ambiguity` here over `make_ambiguous_response_no_constraints`
+ // because the former will also record a built-in candidate in the inspector.
+ return self.forced_ambiguity(MaybeCause::Ambiguity).map(|cand| cand.result);
};
match proven_via {
- // Even when a trait bound has been proven using a where-bound, we
- // still need to consider alias-bounds for normalization, see
- // tests/ui/next-solver/alias-bound-shadowed-by-env.rs.
- //
- // FIXME(const_trait_impl): should this behavior also be used by
- // constness checking. Doing so is *at least theoretically* breaking,
- // see github.com/rust-lang/rust/issues/133044#issuecomment-2500709754
TraitGoalProvenVia::ParamEnv | TraitGoalProvenVia::AliasBound => {
- let mut candidates_from_env_and_bounds: Vec<_> = candidates
+ // Even when a trait bound has been proven using a where-bound, we
+ // still need to consider alias-bounds for normalization, see
+ // `tests/ui/next-solver/alias-bound-shadowed-by-env.rs`.
+ let candidates_from_env_and_bounds: Vec<_> = self
+ .assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::EnvAndBounds);
+
+ // We still need to prefer where-bounds over alias-bounds however.
+ // See `tests/ui/winnowing/norm-where-bound-gt-alias-bound.rs`.
+ let mut considered_candidates: Vec<_> = if candidates_from_env_and_bounds
.iter()
- .filter(|c| {
- matches!(
- c.source,
- CandidateSource::AliasBound | CandidateSource::ParamEnv(_)
- )
- })
- .map(|c| c.result)
- .collect();
+ .any(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
+ {
+ candidates_from_env_and_bounds
+ .into_iter()
+ .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
+ .map(|c| c.result)
+ .collect()
+ } else {
+ candidates_from_env_and_bounds.into_iter().map(|c| c.result).collect()
+ };
// If the trait goal has been proven by using the environment, we want to treat
// aliases as rigid if there are no applicable projection bounds in the environment.
- if candidates_from_env_and_bounds.is_empty() {
+ if considered_candidates.is_empty() {
if let Ok(response) = inject_normalize_to_rigid_candidate(self) {
- candidates_from_env_and_bounds.push(response);
+ considered_candidates.push(response);
}
}
- if let Some(response) = self.try_merge_responses(&candidates_from_env_and_bounds) {
+ if let Some(response) = self.try_merge_responses(&considered_candidates) {
Ok(response)
} else {
- self.flounder(&candidates_from_env_and_bounds)
+ self.flounder(&considered_candidates)
}
}
TraitGoalProvenVia::Misc => {
+ let candidates =
+ self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
+
// Prefer "orphaned" param-env normalization predicates, which are used
// (for example, and ideally only) when proving item bounds for an impl.
let candidates_from_env: Vec<_> = candidates
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
index c2fb592..1526049 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs
@@ -5,9 +5,10 @@
use rustc_type_ir::data_structures::HashMap;
use rustc_type_ir::inherent::*;
use rustc_type_ir::lang_items::TraitSolverLangItem;
+use rustc_type_ir::solve::inspect::ProbeKind;
use rustc_type_ir::{
- self as ty, Interner, Movability, Mutability, TypeFoldable, TypeFolder, TypeSuperFoldable,
- Upcast as _, elaborate,
+ self as ty, FallibleTypeFolder, Interner, Movability, Mutability, TypeFoldable,
+ TypeSuperFoldable, Upcast as _, elaborate,
};
use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
use tracing::instrument;
@@ -822,22 +823,16 @@ pub(in crate::solve) fn const_conditions_for_destruct<I: Interner>(
/// impl Baz for dyn Foo<Item = Ty> {}
/// ```
///
-/// However, in order to make such impls well-formed, we need to do an
+/// However, in order to make such impls non-cyclical, we need to do an
/// additional step of eagerly folding the associated types in the where
/// clauses of the impl. In this example, that means replacing
/// `<Self as Foo>::Bar` with `Ty` in the first impl.
-///
-// FIXME: This is only necessary as `<Self as Trait>::Assoc: ItemBound`
-// bounds in impls are trivially proven using the item bound candidates.
-// This is unsound in general and once that is fixed, we don't need to
-// normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9
-// for more details.
pub(in crate::solve) fn predicates_for_object_candidate<D, I>(
- ecx: &EvalCtxt<'_, D>,
+ ecx: &mut EvalCtxt<'_, D>,
param_env: I::ParamEnv,
trait_ref: ty::TraitRef<I>,
object_bounds: I::BoundExistentialPredicates,
-) -> Vec<Goal<I, I::Predicate>>
+) -> Result<Vec<Goal<I, I::Predicate>>, Ambiguous>
where
D: SolverDelegate<Interner = I>,
I: Interner,
@@ -871,72 +866,130 @@ pub(in crate::solve) fn predicates_for_object_candidate<D, I>(
.extend(cx.item_bounds(associated_type_def_id).iter_instantiated(cx, trait_ref.args));
}
- let mut replace_projection_with = HashMap::default();
+ let mut replace_projection_with: HashMap<_, Vec<_>> = HashMap::default();
for bound in object_bounds.iter() {
if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() {
+ // FIXME: We *probably* should replace this with a dummy placeholder,
+ // b/c don't want to replace literal instances of this dyn type that
+ // show up in the bounds, but just ones that come from substituting
+ // `Self` with the dyn type.
let proj = proj.with_self_ty(cx, trait_ref.self_ty());
- let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj));
- assert_eq!(
- old_ty,
- None,
- "{:?} has two generic parameters: {:?} and {:?}",
- proj.projection_term,
- proj.term,
- old_ty.unwrap()
- );
+ replace_projection_with.entry(proj.def_id()).or_default().push(bound.rebind(proj));
}
}
- let mut folder =
- ReplaceProjectionWith { ecx, param_env, mapping: replace_projection_with, nested: vec![] };
- let folded_requirements = requirements.fold_with(&mut folder);
+ let mut folder = ReplaceProjectionWith {
+ ecx,
+ param_env,
+ self_ty: trait_ref.self_ty(),
+ mapping: &replace_projection_with,
+ nested: vec![],
+ };
- folder
+ let requirements = requirements.try_fold_with(&mut folder)?;
+ Ok(folder
.nested
.into_iter()
- .chain(folded_requirements.into_iter().map(|clause| Goal::new(cx, param_env, clause)))
- .collect()
+ .chain(requirements.into_iter().map(|clause| Goal::new(cx, param_env, clause)))
+ .collect())
}
-struct ReplaceProjectionWith<'a, D: SolverDelegate<Interner = I>, I: Interner> {
- ecx: &'a EvalCtxt<'a, D>,
+struct ReplaceProjectionWith<'a, 'b, I: Interner, D: SolverDelegate<Interner = I>> {
+ ecx: &'a mut EvalCtxt<'b, D>,
param_env: I::ParamEnv,
- mapping: HashMap<I::DefId, ty::Binder<I, ty::ProjectionPredicate<I>>>,
+ self_ty: I::Ty,
+ mapping: &'a HashMap<I::DefId, Vec<ty::Binder<I, ty::ProjectionPredicate<I>>>>,
nested: Vec<Goal<I, I::Predicate>>,
}
-impl<D: SolverDelegate<Interner = I>, I: Interner> TypeFolder<I>
- for ReplaceProjectionWith<'_, D, I>
+impl<D, I> ReplaceProjectionWith<'_, '_, I, D>
+where
+ D: SolverDelegate<Interner = I>,
+ I: Interner,
{
+ fn projection_may_match(
+ &mut self,
+ source_projection: ty::Binder<I, ty::ProjectionPredicate<I>>,
+ target_projection: ty::AliasTerm<I>,
+ ) -> bool {
+ source_projection.item_def_id() == target_projection.def_id
+ && self
+ .ecx
+ .probe(|_| ProbeKind::ProjectionCompatibility)
+ .enter(|ecx| -> Result<_, NoSolution> {
+ let source_projection = ecx.instantiate_binder_with_infer(source_projection);
+ ecx.eq(self.param_env, source_projection.projection_term, target_projection)?;
+ ecx.try_evaluate_added_goals()
+ })
+ .is_ok()
+ }
+
+ /// Try to replace an alias with the term present in the projection bounds of the self type.
+ /// Returns `Ok<None>` if this alias is not eligible to be replaced, or bail with
+ /// `Err(Ambiguous)` if it's uncertain which projection bound to replace the term with due
+ /// to multiple bounds applying.
+ fn try_eagerly_replace_alias(
+ &mut self,
+ alias_term: ty::AliasTerm<I>,
+ ) -> Result<Option<I::Term>, Ambiguous> {
+ if alias_term.self_ty() != self.self_ty {
+ return Ok(None);
+ }
+
+ let Some(replacements) = self.mapping.get(&alias_term.def_id) else {
+ return Ok(None);
+ };
+
+ // This is quite similar to the `projection_may_match` we use in unsizing,
+ // but here we want to unify a projection predicate against an alias term
+ // so we can replace it with the the projection predicate's term.
+ let mut matching_projections = replacements
+ .iter()
+ .filter(|source_projection| self.projection_may_match(**source_projection, alias_term));
+ let Some(replacement) = matching_projections.next() else {
+ // This shouldn't happen.
+ panic!("could not replace {alias_term:?} with term from from {:?}", self.self_ty);
+ };
+ // FIXME: This *may* have issues with duplicated projections.
+ if matching_projections.next().is_some() {
+ // If there's more than one projection that we can unify here, then we
+ // need to stall until inference constrains things so that there's only
+ // one choice.
+ return Err(Ambiguous);
+ }
+
+ let replacement = self.ecx.instantiate_binder_with_infer(*replacement);
+ self.nested.extend(
+ self.ecx
+ .eq_and_get_goals(self.param_env, alias_term, replacement.projection_term)
+ .expect("expected to be able to unify goal projection with dyn's projection"),
+ );
+
+ Ok(Some(replacement.term))
+ }
+}
+
+/// Marker for bailing with ambiguity.
+pub(crate) struct Ambiguous;
+
+impl<D, I> FallibleTypeFolder<I> for ReplaceProjectionWith<'_, '_, I, D>
+where
+ D: SolverDelegate<Interner = I>,
+ I: Interner,
+{
+ type Error = Ambiguous;
+
fn cx(&self) -> I {
self.ecx.cx()
}
- fn fold_ty(&mut self, ty: I::Ty) -> I::Ty {
+ fn try_fold_ty(&mut self, ty: I::Ty) -> Result<I::Ty, Ambiguous> {
if let ty::Alias(ty::Projection, alias_ty) = ty.kind() {
- if let Some(replacement) = self.mapping.get(&alias_ty.def_id) {
- // We may have a case where our object type's projection bound is higher-ranked,
- // but the where clauses we instantiated are not. We can solve this by instantiating
- // the binder at the usage site.
- let proj = self.ecx.instantiate_binder_with_infer(*replacement);
- // FIXME: Technically this equate could be fallible...
- self.nested.extend(
- self.ecx
- .eq_and_get_goals(
- self.param_env,
- alias_ty,
- proj.projection_term.expect_ty(self.ecx.cx()),
- )
- .expect(
- "expected to be able to unify goal projection with dyn's projection",
- ),
- );
- proj.term.expect_ty()
- } else {
- ty.super_fold_with(self)
+ if let Some(term) = self.try_eagerly_replace_alias(alias_ty.into())? {
+ return Ok(term.expect_ty());
}
- } else {
- ty.super_fold_with(self)
}
+
+ ty.try_super_fold_with(self)
}
}
diff --git a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
index 0b61c36..7752a70 100644
--- a/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/effect_goals.rs
@@ -399,12 +399,11 @@ pub(super) fn compute_host_effect_goal(
&mut self,
goal: Goal<I, ty::HostEffectPredicate<I>>,
) -> QueryResult<I> {
- let candidates = self.assemble_and_evaluate_candidates(goal);
let (_, proven_via) = self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
let trait_goal: Goal<I, ty::TraitPredicate<I>> =
goal.with(ecx.cx(), goal.predicate.trait_ref);
ecx.compute_trait_goal(trait_goal)
})?;
- self.merge_candidates(proven_via, candidates, |_ecx| Err(NoSolution))
+ self.assemble_and_merge_candidates(proven_via, goal, |_ecx| Err(NoSolution))
}
}
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
index 4edc293..d56b0e5 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/canonical.rs
@@ -355,7 +355,7 @@ fn compute_query_response_instantiation_values<T: ResponseT<I>>(
// exist at all (see the FIXME at the start of this method), we have to deal with
// them for now.
delegate.instantiate_canonical_var_with_infer(info, span, |idx| {
- ty::UniverseIndex::from(prev_universe.index() + idx.index())
+ prev_universe + idx.index()
})
} else if info.is_existential() {
// As an optimization we sometimes avoid creating a new inference variable here.
diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
index 148ba02..9994c85 100644
--- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs
@@ -286,18 +286,23 @@ pub(super) fn step_kind_for_source(&self, source: GoalSource) -> PathKind {
// fixing it may cause inference breakage or introduce ambiguity.
GoalSource::Misc => PathKind::Unknown,
GoalSource::NormalizeGoal(path_kind) => path_kind,
- GoalSource::ImplWhereBound => {
+ GoalSource::ImplWhereBound => match self.current_goal_kind {
// We currently only consider a cycle coinductive if it steps
// into a where-clause of a coinductive trait.
+ CurrentGoalKind::CoinductiveTrait => PathKind::Coinductive,
+ // While normalizing via an impl does step into a where-clause of
+ // an impl, accessing the associated item immediately steps out of
+ // it again. This means cycles/recursive calls are not guarded
+ // by impls used for normalization.
//
+ // See tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.rs
+ // for how this can go wrong.
+ CurrentGoalKind::NormalizesTo => PathKind::Inductive,
// We probably want to make all traits coinductive in the future,
- // so we treat cycles involving their where-clauses as ambiguous.
- if let CurrentGoalKind::CoinductiveTrait = self.current_goal_kind {
- PathKind::Coinductive
- } else {
- PathKind::Unknown
- }
- }
+ // so we treat cycles involving where-clauses of not-yet coinductive
+ // traits as ambiguous for now.
+ CurrentGoalKind::Misc => PathKind::Unknown,
+ },
// Relating types is always unproductive. If we were to map proof trees to
// corecursive functions as explained in #136824, relating types never
// introduces a constructor which could cause the recursion to be guarded.
diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs
index 7641e9a..0695c5a 100644
--- a/compiler/rustc_next_trait_solver/src/solve/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs
@@ -329,7 +329,7 @@ fn opaque_type_is_rigid(&self, def_id: I::DefId) -> bool {
TypingMode::Coherence | TypingMode::PostAnalysis => false,
// During analysis, opaques are rigid unless they may be defined by
// the current body.
- TypingMode::Analysis { defining_opaque_types: non_rigid_opaques }
+ TypingMode::Analysis { defining_opaque_types_and_generators: non_rigid_opaques }
| TypingMode::Borrowck { defining_opaque_types: non_rigid_opaques }
| TypingMode::PostBorrowckAnalysis { defined_opaque_types: non_rigid_opaques } => {
!def_id.as_local().is_some_and(|def_id| non_rigid_opaques.contains(&def_id))
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
index 2d027f1..9466901 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs
@@ -32,20 +32,18 @@ pub(super) fn compute_normalizes_to_goal(
let cx = self.cx();
match goal.predicate.alias.kind(cx) {
ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
- let candidates = self.assemble_and_evaluate_candidates(goal);
let trait_ref = goal.predicate.alias.trait_ref(cx);
let (_, proven_via) =
self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
let trait_goal: Goal<I, ty::TraitPredicate<I>> = goal.with(cx, trait_ref);
ecx.compute_trait_goal(trait_goal)
})?;
- self.merge_candidates(proven_via, candidates, |ecx| {
+ self.assemble_and_merge_candidates(proven_via, goal, |ecx| {
ecx.probe(|&result| ProbeKind::RigidAlias { result }).enter(|this| {
this.structurally_instantiate_normalizes_to_term(
goal,
goal.predicate.alias,
);
- this.add_goal(GoalSource::AliasWellFormed, goal.with(cx, trait_ref));
this.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
})
diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
index aa89e77..ee439f1 100644
--- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs
@@ -33,11 +33,11 @@ pub(super) fn normalize_opaque_type(
);
self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
}
- TypingMode::Analysis { defining_opaque_types } => {
+ TypingMode::Analysis { defining_opaque_types_and_generators } => {
let Some(def_id) = opaque_ty
.def_id
.as_local()
- .filter(|&def_id| defining_opaque_types.contains(&def_id))
+ .filter(|&def_id| defining_opaque_types_and_generators.contains(&def_id))
else {
self.structurally_instantiate_normalizes_to_term(goal, goal.predicate.alias);
return self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
index d42c998..827853b 100644
--- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs
@@ -13,7 +13,7 @@
use crate::delegate::SolverDelegate;
use crate::solve::assembly::structural_traits::{self, AsyncCallableRelevantTypes};
-use crate::solve::assembly::{self, Candidate};
+use crate::solve::assembly::{self, AssembleCandidatesFrom, Candidate};
use crate::solve::inspect::ProbeKind;
use crate::solve::{
BuiltinImplSource, CandidateSource, Certainty, EvalCtxt, Goal, GoalSource, MaybeCause,
@@ -164,6 +164,7 @@ fn consider_auto_trait_candidate(
ecx: &mut EvalCtxt<'_, D>,
goal: Goal<I, Self>,
) -> Result<Candidate<I>, NoSolution> {
+ let cx = ecx.cx();
if goal.predicate.polarity != ty::PredicatePolarity::Positive {
return Err(NoSolution);
}
@@ -174,20 +175,42 @@ fn consider_auto_trait_candidate(
// Only consider auto impls of unsafe traits when there are no unsafe
// fields.
- if ecx.cx().trait_is_unsafe(goal.predicate.def_id())
+ if cx.trait_is_unsafe(goal.predicate.def_id())
&& goal.predicate.self_ty().has_unsafe_fields()
{
return Err(NoSolution);
}
- // We only look into opaque types during analysis for opaque types
- // outside of their defining scope. Doing so for opaques in the
- // defining scope may require calling `typeck` on the same item we're
- // currently type checking, which will result in a fatal cycle that
- // ideally we want to avoid, since we can make progress on this goal
- // via an alias bound or a locally-inferred hidden type instead.
+ // We leak the implemented auto traits of opaques outside of their defining scope.
+ // This depends on `typeck` of the defining scope of that opaque, which may result in
+ // fatal query cycles.
+ //
+ // We only get to this point if we're outside of the defining scope as we'd otherwise
+ // be able to normalize the opaque type. We may also cycle in case `typeck` of a defining
+ // scope relies on the current context, e.g. either because it also leaks auto trait
+ // bounds of opaques defined in the current context or by evaluating the current item.
+ //
+ // To avoid this we don't try to leak auto trait bounds if they can also be proven via
+ // item bounds of the opaque. These bounds are always applicable as auto traits must not
+ // have any generic parameters. They would also get preferred over the impl candidate
+ // when merging candidates anyways.
+ //
+ // See tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs.
if let ty::Alias(ty::Opaque, opaque_ty) = goal.predicate.self_ty().kind() {
debug_assert!(ecx.opaque_type_is_rigid(opaque_ty.def_id));
+ for item_bound in cx.item_self_bounds(opaque_ty.def_id).skip_binder() {
+ if item_bound
+ .as_trait_clause()
+ .is_some_and(|b| b.def_id() == goal.predicate.def_id())
+ {
+ return Err(NoSolution);
+ }
+ }
+ }
+
+ // We need to make sure to stall any coroutines we are inferring to avoid query cycles.
+ if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) {
+ return cand;
}
ecx.probe_and_evaluate_goal_for_constituent_tys(
@@ -241,6 +264,11 @@ fn consider_builtin_copy_clone_candidate(
return Err(NoSolution);
}
+ // We need to make sure to stall any coroutines we are inferring to avoid query cycles.
+ if let Some(cand) = ecx.try_stall_coroutine_witness(goal.predicate.self_ty()) {
+ return cand;
+ }
+
ecx.probe_and_evaluate_goal_for_constituent_tys(
CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
goal,
@@ -926,7 +954,7 @@ fn consider_builtin_upcast_to_principal(
target_projection: ty::Binder<I, ty::ExistentialProjection<I>>| {
source_projection.item_def_id() == target_projection.item_def_id()
&& ecx
- .probe(|_| ProbeKind::UpcastProjectionCompatibility)
+ .probe(|_| ProbeKind::ProjectionCompatibility)
.enter(|ecx| -> Result<_, NoSolution> {
ecx.enter_forall(target_projection, |ecx, target_projection| {
let source_projection =
@@ -1238,10 +1266,11 @@ impl<D, I> EvalCtxt<'_, D>
D: SolverDelegate<Interner = I>,
I: Interner,
{
+ #[instrument(level = "debug", skip(self, goal), ret)]
pub(super) fn merge_trait_candidates(
&mut self,
goal: Goal<I, TraitPredicate<I>>,
- candidates: Vec<Candidate<I>>,
+ mut candidates: Vec<Candidate<I>>,
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
if let TypingMode::Coherence = self.typing_mode() {
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
@@ -1323,13 +1352,16 @@ pub(super) fn merge_trait_candidates(
// If there are *only* global where bounds, then make sure to return that this
// is still reported as being proven-via the param-env so that rigid projections
- // operate correctly.
+ // operate correctly. Otherwise, drop all global where-bounds before merging the
+ // remaining candidates.
let proven_via =
if candidates.iter().all(|c| matches!(c.source, CandidateSource::ParamEnv(_))) {
TraitGoalProvenVia::ParamEnv
} else {
+ candidates.retain(|c| !matches!(c.source, CandidateSource::ParamEnv(_)));
TraitGoalProvenVia::Misc
};
+
let all_candidates: Vec<_> = candidates.into_iter().map(|c| c.result).collect();
if let Some(response) = self.try_merge_responses(&all_candidates) {
Ok((response, Some(proven_via)))
@@ -1343,7 +1375,31 @@ pub(super) fn compute_trait_goal(
&mut self,
goal: Goal<I, TraitPredicate<I>>,
) -> Result<(CanonicalResponse<I>, Option<TraitGoalProvenVia>), NoSolution> {
- let candidates = self.assemble_and_evaluate_candidates(goal);
+ let candidates = self.assemble_and_evaluate_candidates(goal, AssembleCandidatesFrom::All);
self.merge_trait_candidates(goal, candidates)
}
+
+ fn try_stall_coroutine_witness(
+ &mut self,
+ self_ty: I::Ty,
+ ) -> Option<Result<Candidate<I>, NoSolution>> {
+ if let ty::CoroutineWitness(def_id, _) = self_ty.kind() {
+ match self.typing_mode() {
+ TypingMode::Analysis {
+ defining_opaque_types_and_generators: stalled_generators,
+ } => {
+ if def_id.as_local().is_some_and(|def_id| stalled_generators.contains(&def_id))
+ {
+ return Some(self.forced_ambiguity(MaybeCause::Ambiguity));
+ }
+ }
+ TypingMode::Coherence
+ | TypingMode::PostAnalysis
+ | TypingMode::Borrowck { defining_opaque_types: _ }
+ | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ } => {}
+ }
+ }
+
+ None
+ }
}
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 93fa89b..ae91434 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -246,9 +246,9 @@
parse_expected_trait_in_trait_impl_found_type = expected a trait, found type
-parse_expr_rarrow_call = `->` used for field access or method call
+parse_expr_rarrow_call = `->` is not valid syntax for field accesses and method calls
.suggestion = try using `.` instead
- .help = the `.` operator will dereference the value if needed
+ .help = the `.` operator will automatically dereference the value, except if the value is a raw pointer
parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements
.label = dash-separated idents are not valid
@@ -543,7 +543,7 @@
.suggestion = types that don't start with an identifier need to be surrounded with angle brackets in qualified paths
parse_maybe_recover_from_bad_type_plus =
- expected a path on the left-hand side of `+`, not `{$ty}`
+ expected a path on the left-hand side of `+`
parse_maybe_report_ambiguous_plus =
ambiguous `+` in a type
@@ -642,7 +642,9 @@
.suggestion = add `mut` to each binding
parse_mut_on_non_ident_pattern = `mut` must be followed by a named binding
.suggestion = remove the `mut` prefix
-parse_need_plus_after_trait_object_lifetime = lifetime in trait object type must be followed by `+`
+
+parse_need_plus_after_trait_object_lifetime = lifetimes must be followed by `+` to form a trait object type
+ .suggestion = consider adding a trait bound after the potential lifetime bound
parse_nested_adt = `{$kw_str}` definition cannot be nested inside `{$keyword}`
.suggestion = consider creating a new `{$kw_str}` definition instead of nesting
@@ -806,9 +808,6 @@
parse_transpose_dyn_or_impl = `for<...>` expected after `{$kw}`, not before
.suggestion = move `{$kw}` before the `for<...>`
-parse_type_ascription_removed =
- if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
-
parse_unclosed_unicode_escape = unterminated unicode escape
.label = missing a closing `{"}"}`
.terminate = terminate the unicode escape
@@ -894,6 +893,7 @@
.label = unknown prefix
.note = prefixed identifiers and literals are reserved since Rust 2021
.suggestion_br = use `br` for a raw byte string
+ .suggestion_cr = use `cr` for a raw C-string
.suggestion_str = if you meant to write a string literal, use double quotes
.suggestion_whitespace = consider inserting whitespace here
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index dfdef01..35cf4c1 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -7,8 +7,7 @@
use rustc_ast::{Path, Visibility};
use rustc_errors::codes::*;
use rustc_errors::{
- Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, SubdiagMessageOp,
- Subdiagnostic,
+ Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, Subdiagnostic,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_session::errors::ExprParenthesesNeeded;
@@ -30,7 +29,6 @@ pub(crate) struct AmbiguousPlus {
#[derive(Diagnostic)]
#[diag(parse_maybe_recover_from_bad_type_plus, code = E0178)]
pub(crate) struct BadTypePlus {
- pub ty: String,
#[primary_span]
pub span: Span,
#[subdiagnostic]
@@ -1551,11 +1549,7 @@ pub(crate) struct FnTraitMissingParen {
}
impl Subdiagnostic for FnTraitMissingParen {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.span_label(self.span, crate::fluent_generated::parse_fn_trait_missing_paren);
diag.span_suggestion_short(
self.span.shrink_to_hi(),
@@ -1598,9 +1592,6 @@ pub(crate) struct PathSingleColon {
#[suggestion(applicability = "machine-applicable", code = ":", style = "verbose")]
pub suggestion: Span,
-
- #[note(parse_type_ascription_removed)]
- pub type_ascription: bool,
}
#[derive(Diagnostic)]
@@ -1617,9 +1608,6 @@ pub(crate) struct ColonAsSemi {
#[primary_span]
#[suggestion(applicability = "machine-applicable", code = ";", style = "verbose")]
pub span: Span,
-
- #[note(parse_type_ascription_removed)]
- pub type_ascription: bool,
}
#[derive(Diagnostic)]
@@ -2153,6 +2141,13 @@ pub(crate) enum UnknownPrefixSugg {
)]
UseBr(#[primary_span] Span),
#[suggestion(
+ parse_suggestion_cr,
+ code = "cr",
+ applicability = "maybe-incorrect",
+ style = "verbose"
+ )]
+ UseCr(#[primary_span] Span),
+ #[suggestion(
parse_suggestion_whitespace,
code = " ",
applicability = "maybe-incorrect",
@@ -2806,6 +2801,8 @@ pub(crate) struct ReturnTypesUseThinArrow {
pub(crate) struct NeedPlusAfterTraitObjectLifetime {
#[primary_span]
pub span: Span,
+ #[suggestion(code = " + /* Trait */", applicability = "has-placeholders")]
+ pub suggestion: Span,
}
#[derive(Diagnostic)]
diff --git a/compiler/rustc_parse/src/lexer/diagnostics.rs b/compiler/rustc_parse/src/lexer/diagnostics.rs
index e1f19be..0b97d4e 100644
--- a/compiler/rustc_parse/src/lexer/diagnostics.rs
+++ b/compiler/rustc_parse/src/lexer/diagnostics.rs
@@ -1,14 +1,17 @@
use rustc_ast::token::Delimiter;
use rustc_errors::Diag;
+use rustc_session::parse::ParseSess;
use rustc_span::Span;
use rustc_span::source_map::SourceMap;
use super::UnmatchedDelim;
+use crate::errors::MismatchedClosingDelimiter;
+use crate::pprust;
#[derive(Default)]
pub(super) struct TokenTreeDiagInfo {
/// Stack of open delimiters and their spans. Used for error message.
- pub open_braces: Vec<(Delimiter, Span)>,
+ pub open_delimiters: Vec<(Delimiter, Span)>,
pub unmatched_delims: Vec<UnmatchedDelim>,
/// Used only for error recovery when arriving to EOF with mismatched braces.
@@ -108,7 +111,7 @@ pub(super) fn report_suspicious_mismatch_block(
} else {
// If there is no suspicious span, give the last properly closed block may help
if let Some(parent) = diag_info.matching_block_spans.last()
- && diag_info.open_braces.last().is_none()
+ && diag_info.open_delimiters.last().is_none()
&& diag_info.empty_block_spans.iter().all(|&sp| sp != parent.0.to(parent.1))
{
err.span_label(parent.0, "this opening brace...");
@@ -116,3 +119,24 @@ pub(super) fn report_suspicious_mismatch_block(
}
}
}
+
+pub(crate) fn make_unclosed_delims_error(
+ unmatched: UnmatchedDelim,
+ psess: &ParseSess,
+) -> Option<Diag<'_>> {
+ // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to
+ // `unmatched_delims` only for error recovery in the `Parser`.
+ let found_delim = unmatched.found_delim?;
+ let mut spans = vec![unmatched.found_span];
+ if let Some(sp) = unmatched.unclosed_span {
+ spans.push(sp);
+ };
+ let err = psess.dcx().create_err(MismatchedClosingDelimiter {
+ spans,
+ delimiter: pprust::token_kind_to_string(&found_delim.as_close_token_kind()).to_string(),
+ unmatched: unmatched.found_span,
+ opening_candidate: unmatched.candidate_span,
+ unclosed: unmatched.unclosed_span,
+ });
+ Some(err)
+}
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 4935fc0..e8a5cae 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -1,5 +1,6 @@
use std::ops::Range;
+use diagnostics::make_unclosed_delims_error;
use rustc_ast::ast::{self, AttrStyle};
use rustc_ast::token::{self, CommentKind, Delimiter, IdentIsRaw, Token, TokenKind};
use rustc_ast::tokenstream::TokenStream;
@@ -17,9 +18,9 @@
use rustc_span::{BytePos, Pos, Span, Symbol};
use tracing::debug;
+use crate::errors;
use crate::lexer::diagnostics::TokenTreeDiagInfo;
use crate::lexer::unicode_chars::UNICODE_ARRAY;
-use crate::{errors, make_unclosed_delims_error};
mod diagnostics;
mod tokentrees;
@@ -256,7 +257,6 @@ fn next_token_from_cursor(&mut self) -> (Token, bool) {
let lit_start = start + BytePos(prefix_len);
self.pos = lit_start;
self.cursor = Cursor::new(&str_before[prefix_len as usize..]);
-
self.report_unknown_prefix(start);
let prefix_span = self.mk_sp(start, lit_start);
return (Token::new(self.ident(start), prefix_span), preceded_by_whitespace);
@@ -371,12 +371,12 @@ fn next_token_from_cursor(&mut self) -> (Token, bool) {
rustc_lexer::TokenKind::Semi => token::Semi,
rustc_lexer::TokenKind::Comma => token::Comma,
rustc_lexer::TokenKind::Dot => token::Dot,
- rustc_lexer::TokenKind::OpenParen => token::OpenDelim(Delimiter::Parenthesis),
- rustc_lexer::TokenKind::CloseParen => token::CloseDelim(Delimiter::Parenthesis),
- rustc_lexer::TokenKind::OpenBrace => token::OpenDelim(Delimiter::Brace),
- rustc_lexer::TokenKind::CloseBrace => token::CloseDelim(Delimiter::Brace),
- rustc_lexer::TokenKind::OpenBracket => token::OpenDelim(Delimiter::Bracket),
- rustc_lexer::TokenKind::CloseBracket => token::CloseDelim(Delimiter::Bracket),
+ rustc_lexer::TokenKind::OpenParen => token::OpenParen,
+ rustc_lexer::TokenKind::CloseParen => token::CloseParen,
+ rustc_lexer::TokenKind::OpenBrace => token::OpenBrace,
+ rustc_lexer::TokenKind::CloseBrace => token::CloseBrace,
+ rustc_lexer::TokenKind::OpenBracket => token::OpenBracket,
+ rustc_lexer::TokenKind::CloseBracket => token::CloseBracket,
rustc_lexer::TokenKind::At => token::At,
rustc_lexer::TokenKind::Pound => token::Pound,
rustc_lexer::TokenKind::Tilde => token::Tilde,
@@ -789,13 +789,14 @@ fn report_unterminated_block_comment(&self, start: BytePos, doc_style: Option<Do
fn report_unknown_prefix(&self, start: BytePos) {
let prefix_span = self.mk_sp(start, self.pos);
let prefix = self.str_from_to(start, self.pos);
-
let expn_data = prefix_span.ctxt().outer_expn_data();
if expn_data.edition.at_least_rust_2021() {
// In Rust 2021, this is a hard error.
let sugg = if prefix == "rb" {
Some(errors::UnknownPrefixSugg::UseBr(prefix_span))
+ } else if prefix == "rc" {
+ Some(errors::UnknownPrefixSugg::UseCr(prefix_span))
} else if expn_data.is_root() {
if self.cursor.first() == '\''
&& let Some(start) = self.last_lifetime
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index b3f83a3..fbea958 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -18,38 +18,33 @@ pub(super) fn lex_token_trees(
let mut buf = Vec::new();
loop {
- match self.token.kind {
- token::OpenDelim(delim) => {
- // Invisible delimiters cannot occur here because `TokenTreesReader` parses
- // code directly from strings, with no macro expansion involved.
- debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
- buf.push(match self.lex_token_tree_open_delim(delim) {
- Ok(val) => val,
- Err(errs) => return Err(errs),
- })
- }
- token::CloseDelim(delim) => {
- // Invisible delimiters cannot occur here because `TokenTreesReader` parses
- // code directly from strings, with no macro expansion involved.
- debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
- return if is_delimited {
- Ok((open_spacing, TokenStream::new(buf)))
- } else {
- Err(vec![self.close_delim_err(delim)])
- };
- }
- token::Eof => {
- return if is_delimited {
- Err(vec![self.eof_err()])
- } else {
- Ok((open_spacing, TokenStream::new(buf)))
- };
- }
- _ => {
- // Get the next normal token.
- let (this_tok, this_spacing) = self.bump();
- buf.push(TokenTree::Token(this_tok, this_spacing));
- }
+ if let Some(delim) = self.token.kind.open_delim() {
+ // Invisible delimiters cannot occur here because `TokenTreesReader` parses
+ // code directly from strings, with no macro expansion involved.
+ debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
+ buf.push(match self.lex_token_tree_open_delim(delim) {
+ Ok(val) => val,
+ Err(errs) => return Err(errs),
+ })
+ } else if let Some(delim) = self.token.kind.close_delim() {
+ // Invisible delimiters cannot occur here because `TokenTreesReader` parses
+ // code directly from strings, with no macro expansion involved.
+ debug_assert!(!matches!(delim, Delimiter::Invisible(_)));
+ return if is_delimited {
+ Ok((open_spacing, TokenStream::new(buf)))
+ } else {
+ Err(vec![self.close_delim_err(delim)])
+ };
+ } else if self.token.kind == token::Eof {
+ return if is_delimited {
+ Err(vec![self.eof_err()])
+ } else {
+ Ok((open_spacing, TokenStream::new(buf)))
+ };
+ } else {
+ // Get the next normal token.
+ let (this_tok, this_spacing) = self.bump();
+ buf.push(TokenTree::Token(this_tok, this_spacing));
}
}
}
@@ -59,8 +54,8 @@ fn eof_err(&mut self) -> Diag<'psess> {
let mut err = self.dcx().struct_span_err(self.token.span, msg);
let unclosed_delimiter_show_limit = 5;
- let len = usize::min(unclosed_delimiter_show_limit, self.diag_info.open_braces.len());
- for &(_, span) in &self.diag_info.open_braces[..len] {
+ let len = usize::min(unclosed_delimiter_show_limit, self.diag_info.open_delimiters.len());
+ for &(_, span) in &self.diag_info.open_delimiters[..len] {
err.span_label(span, "unclosed delimiter");
self.diag_info.unmatched_delims.push(UnmatchedDelim {
found_delim: None,
@@ -70,19 +65,19 @@ fn eof_err(&mut self) -> Diag<'psess> {
});
}
- if let Some((_, span)) = self.diag_info.open_braces.get(unclosed_delimiter_show_limit)
- && self.diag_info.open_braces.len() >= unclosed_delimiter_show_limit + 2
+ if let Some((_, span)) = self.diag_info.open_delimiters.get(unclosed_delimiter_show_limit)
+ && self.diag_info.open_delimiters.len() >= unclosed_delimiter_show_limit + 2
{
err.span_label(
*span,
format!(
"another {} unclosed delimiters begin from here",
- self.diag_info.open_braces.len() - unclosed_delimiter_show_limit
+ self.diag_info.open_delimiters.len() - unclosed_delimiter_show_limit
),
);
}
- if let Some((delim, _)) = self.diag_info.open_braces.last() {
+ if let Some((delim, _)) = self.diag_info.open_delimiters.last() {
report_suspicious_mismatch_block(
&mut err,
&self.diag_info,
@@ -100,7 +95,7 @@ fn lex_token_tree_open_delim(
// The span for beginning of the delimited section.
let pre_span = self.token.span;
- self.diag_info.open_braces.push((open_delim, self.token.span));
+ self.diag_info.open_delimiters.push((open_delim, self.token.span));
// Lex the token trees within the delimiters.
// We stop at any delimiter so we can try to recover if the user
@@ -111,14 +106,15 @@ fn lex_token_tree_open_delim(
let delim_span = DelimSpan::from_pair(pre_span, self.token.span);
let sm = self.psess.source_map();
- let close_spacing = match self.token.kind {
- // Correct delimiter.
- token::CloseDelim(close_delim) if close_delim == open_delim => {
- let (open_brace, open_brace_span) = self.diag_info.open_braces.pop().unwrap();
- let close_brace_span = self.token.span;
+ let close_spacing = if let Some(close_delim) = self.token.kind.close_delim() {
+ if close_delim == open_delim {
+ // Correct delimiter.
+ let (open_delimiter, open_delimiter_span) =
+ self.diag_info.open_delimiters.pop().unwrap();
+ let close_delimiter_span = self.token.span;
if tts.is_empty() && close_delim == Delimiter::Brace {
- let empty_block_span = open_brace_span.to(close_brace_span);
+ let empty_block_span = open_delimiter_span.to(close_delimiter_span);
if !sm.is_multiline(empty_block_span) {
// Only track if the block is in the form of `{}`, otherwise it is
// likely that it was written on purpose.
@@ -127,16 +123,17 @@ fn lex_token_tree_open_delim(
}
// only add braces
- if let (Delimiter::Brace, Delimiter::Brace) = (open_brace, open_delim) {
+ if let (Delimiter::Brace, Delimiter::Brace) = (open_delimiter, open_delim) {
// Add all the matching spans, we will sort by span later
- self.diag_info.matching_block_spans.push((open_brace_span, close_brace_span));
+ self.diag_info
+ .matching_block_spans
+ .push((open_delimiter_span, close_delimiter_span));
}
// Move past the closing delimiter.
self.bump_minimal()
- }
- // Incorrect delimiter.
- token::CloseDelim(close_delim) => {
+ } else {
+ // Incorrect delimiter.
let mut unclosed_delimiter = None;
let mut candidate = None;
@@ -146,18 +143,18 @@ fn lex_token_tree_open_delim(
// This is a conservative error: only report the last unclosed
// delimiter. The previous unclosed delimiters could actually be
// closed! The lexer just hasn't gotten to them yet.
- if let Some(&(_, sp)) = self.diag_info.open_braces.last() {
+ if let Some(&(_, sp)) = self.diag_info.open_delimiters.last() {
unclosed_delimiter = Some(sp);
};
- for (brace, brace_span) in &self.diag_info.open_braces {
- if same_indentation_level(sm, self.token.span, *brace_span)
- && brace == &close_delim
+ for (delimiter, delimiter_span) in &self.diag_info.open_delimiters {
+ if same_indentation_level(sm, self.token.span, *delimiter_span)
+ && delimiter == &close_delim
{
// high likelihood of these two corresponding
- candidate = Some(*brace_span);
+ candidate = Some(*delimiter_span);
}
}
- let (_, _) = self.diag_info.open_braces.pop().unwrap();
+ let (_, _) = self.diag_info.open_delimiters.pop().unwrap();
self.diag_info.unmatched_delims.push(UnmatchedDelim {
found_delim: Some(close_delim),
found_span: self.token.span,
@@ -165,7 +162,7 @@ fn lex_token_tree_open_delim(
candidate_span: candidate,
});
} else {
- self.diag_info.open_braces.pop();
+ self.diag_info.open_delimiters.pop();
}
// If the incorrect delimiter matches an earlier opening
@@ -175,21 +172,20 @@ fn lex_token_tree_open_delim(
// fn foo() {
// bar(baz(
// } // Incorrect delimiter but matches the earlier `{`
- if !self.diag_info.open_braces.iter().any(|&(b, _)| b == close_delim) {
+ if !self.diag_info.open_delimiters.iter().any(|&(d, _)| d == close_delim) {
self.bump_minimal()
} else {
// The choice of value here doesn't matter.
Spacing::Alone
}
}
- token::Eof => {
- // Silently recover, the EOF token will be seen again
- // and an error emitted then. Thus we don't pop from
- // self.open_braces here. The choice of spacing value here
- // doesn't matter.
- Spacing::Alone
- }
- _ => unreachable!(),
+ } else {
+ assert_eq!(self.token.kind, token::Eof);
+ // Silently recover, the EOF token will be seen again
+ // and an error emitted then. Thus we don't pop from
+ // self.open_delimiters here. The choice of spacing value here
+ // doesn't matter.
+ Spacing::Alone
};
let spacing = DelimSpacing::new(open_spacing, close_spacing);
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index ff03b42..751d13a 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -5,7 +5,7 @@
use super::Lexer;
use crate::errors::TokenSubstitution;
-use crate::token::{self, Delimiter};
+use crate::token;
#[rustfmt::skip] // for line breaks
pub(super) static UNICODE_ARRAY: &[(char, &str, &str)] = &[
@@ -315,12 +315,12 @@
("!", "Exclamation Mark", Some(token::Bang)),
("?", "Question Mark", Some(token::Question)),
(".", "Period", Some(token::Dot)),
- ("(", "Left Parenthesis", Some(token::OpenDelim(Delimiter::Parenthesis))),
- (")", "Right Parenthesis", Some(token::CloseDelim(Delimiter::Parenthesis))),
- ("[", "Left Square Bracket", Some(token::OpenDelim(Delimiter::Bracket))),
- ("]", "Right Square Bracket", Some(token::CloseDelim(Delimiter::Bracket))),
- ("{", "Left Curly Brace", Some(token::OpenDelim(Delimiter::Brace))),
- ("}", "Right Curly Brace", Some(token::CloseDelim(Delimiter::Brace))),
+ ("(", "Left Parenthesis", Some(token::OpenParen)),
+ (")", "Right Parenthesis", Some(token::CloseParen)),
+ ("[", "Left Square Bracket", Some(token::OpenBracket)),
+ ("]", "Right Square Bracket", Some(token::CloseBracket)),
+ ("{", "Left Curly Brace", Some(token::OpenBrace)),
+ ("}", "Right Curly Brace", Some(token::CloseBrace)),
("*", "Asterisk", Some(token::Star)),
("/", "Slash", Some(token::Slash)),
("\\", "Backslash", None),
@@ -376,7 +376,7 @@ pub(super) fn check_for_substitution(
ascii_name,
})
};
- (token.clone(), sugg)
+ (*token, sugg)
}
/// Extract string if found at current position with given delimiters
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 79939aa..896e348 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -4,7 +4,6 @@
#![allow(internal_features)]
#![allow(rustc::diagnostic_outside_of_impl)]
#![allow(rustc::untranslatable_diagnostic)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(array_windows)]
#![feature(assert_matches)]
#![feature(box_patterns)]
@@ -33,7 +32,7 @@
#[macro_use]
pub mod parser;
-use parser::{Parser, make_unclosed_delims_error};
+use parser::Parser;
pub mod lexer;
pub mod validate_attr;
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index cff998f..6061c9c 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -1,7 +1,7 @@
use std::borrow::Cow;
use std::{iter, mem};
-use rustc_ast::token::{Delimiter, Token, TokenKind};
+use rustc_ast::token::{Delimiter, Token};
use rustc_ast::tokenstream::{
AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing, DelimSpan, LazyAttrTokenStream,
Spacing, ToAttrTokenStream,
@@ -120,7 +120,7 @@ fn to_attr_token_stream(&self) -> AttrTokenStream {
// produce an empty `TokenStream` if no calls were made, and omit the
// final token otherwise.
let mut cursor_snapshot = self.cursor_snapshot.clone();
- let tokens = iter::once(FlatToken::Token(self.start_token.clone()))
+ let tokens = iter::once(FlatToken::Token(self.start_token))
.chain(iter::repeat_with(|| FlatToken::Token(cursor_snapshot.next())))
.take(self.num_calls as usize);
@@ -186,7 +186,7 @@ fn to_attr_token_stream(&self) -> AttrTokenStream {
impl<'a> Parser<'a> {
pub(super) fn collect_pos(&self) -> CollectPos {
CollectPos {
- start_token: (self.token.clone(), self.token_spacing),
+ start_token: (self.token, self.token_spacing),
cursor_snapshot: self.token_cursor.clone(),
start_pos: self.num_bump_calls,
}
@@ -501,27 +501,27 @@ struct FrameData {
let mut stack_rest = vec![];
for flat_token in iter {
match flat_token {
- FlatToken::Token((Token { kind: TokenKind::OpenDelim(delim), span }, spacing)) => {
- stack_rest.push(mem::replace(
- &mut stack_top,
- FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] },
- ));
- }
- FlatToken::Token((Token { kind: TokenKind::CloseDelim(delim), span }, spacing)) => {
- let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap());
- let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap();
- assert!(
- open_delim.eq_ignoring_invisible_origin(&delim),
- "Mismatched open/close delims: open={open_delim:?} close={span:?}"
- );
- let dspan = DelimSpan::from_pair(open_sp, span);
- let dspacing = DelimSpacing::new(open_spacing, spacing);
- let stream = AttrTokenStream::new(frame_data.inner);
- let delimited = AttrTokenTree::Delimited(dspan, dspacing, delim, stream);
- stack_top.inner.push(delimited);
- }
- FlatToken::Token((token, spacing)) => {
- stack_top.inner.push(AttrTokenTree::Token(token, spacing))
+ FlatToken::Token((token @ Token { kind, span }, spacing)) => {
+ if let Some(delim) = kind.open_delim() {
+ stack_rest.push(mem::replace(
+ &mut stack_top,
+ FrameData { open_delim_sp: Some((delim, span, spacing)), inner: vec![] },
+ ));
+ } else if let Some(delim) = kind.close_delim() {
+ let frame_data = mem::replace(&mut stack_top, stack_rest.pop().unwrap());
+ let (open_delim, open_sp, open_spacing) = frame_data.open_delim_sp.unwrap();
+ assert!(
+ open_delim.eq_ignoring_invisible_origin(&delim),
+ "Mismatched open/close delims: open={open_delim:?} close={span:?}"
+ );
+ let dspan = DelimSpan::from_pair(open_sp, span);
+ let dspacing = DelimSpacing::new(open_spacing, spacing);
+ let stream = AttrTokenStream::new(frame_data.inner);
+ let delimited = AttrTokenTree::Delimited(dspan, dspacing, delim, stream);
+ stack_top.inner.push(delimited);
+ } else {
+ stack_top.inner.push(AttrTokenTree::Token(token, spacing))
+ }
}
FlatToken::AttrsTarget(target) => {
stack_top.inner.push(AttrTokenTree::AttrsTarget(target))
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index ef044fe..23c8db7 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -4,7 +4,7 @@
use ast::token::IdentIsRaw;
use rustc_ast as ast;
use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind};
+use rustc_ast::token::{self, Lit, LitKind, Token, TokenKind};
use rustc_ast::util::parser::AssocOp;
use rustc_ast::{
AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block,
@@ -304,10 +304,10 @@ pub(super) fn expected_ident_found(
TokenKind::Comma,
TokenKind::Semi,
TokenKind::PathSep,
- TokenKind::OpenDelim(Delimiter::Brace),
- TokenKind::OpenDelim(Delimiter::Parenthesis),
- TokenKind::CloseDelim(Delimiter::Brace),
- TokenKind::CloseDelim(Delimiter::Parenthesis),
+ TokenKind::OpenBrace,
+ TokenKind::OpenParen,
+ TokenKind::CloseBrace,
+ TokenKind::CloseParen,
];
if let TokenKind::DocComment(..) = self.prev_token.kind
&& valid_follow.contains(&self.token.kind)
@@ -322,7 +322,7 @@ pub(super) fn expected_ident_found(
let mut recovered_ident = None;
// we take this here so that the correct original token is retained in
// the diagnostic, regardless of eager recovery.
- let bad_token = self.token.clone();
+ let bad_token = self.token;
// suggest prepending a keyword in identifier position with `r#`
let suggest_raw = if let Some((ident, IdentIsRaw::No)) = self.token.ident()
@@ -382,7 +382,7 @@ pub(super) fn expected_ident_found(
// if the previous token is a valid keyword
// that might use a generic, then suggest a correct
// generic placement (later on)
- let maybe_keyword = self.prev_token.clone();
+ let maybe_keyword = self.prev_token;
if valid_prev_keywords.into_iter().any(|x| maybe_keyword.is_keyword(x)) {
// if we have a valid keyword, attempt to parse generics
// also obtain the keywords symbol
@@ -507,7 +507,7 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
} else if !sm.is_multiline(self.prev_token.span.until(self.token.span)) {
// The current token is in the same line as the prior token, not recoverable.
} else if [token::Comma, token::Colon].contains(&self.token.kind)
- && self.prev_token == token::CloseDelim(Delimiter::Parenthesis)
+ && self.prev_token == token::CloseParen
{
// Likely typo: The current token is on a new line and is expected to be
// `.`, `;`, `?`, or an operator after a close delimiter token.
@@ -518,8 +518,7 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
// ^
// https://github.com/rust-lang/rust/issues/72253
} else if self.look_ahead(1, |t| {
- t == &token::CloseDelim(Delimiter::Brace)
- || t.can_begin_expr() && *t != token::Colon
+ t == &token::CloseBrace || t.can_begin_expr() && *t != token::Colon
}) && [token::Comma, token::Colon].contains(&self.token.kind)
{
// Likely typo: `,` → `;` or `:` → `;`. This is triggered if the current token is
@@ -530,14 +529,14 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
// let y = 42;
let guar = self.dcx().emit_err(ExpectedSemi {
span: self.token.span,
- token: self.token.clone(),
+ token: self.token,
unexpected_token_label: None,
sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span),
});
self.bump();
return Ok(guar);
} else if self.look_ahead(0, |t| {
- t == &token::CloseDelim(Delimiter::Brace)
+ t == &token::CloseBrace
|| ((t.can_begin_expr() || t.can_begin_item())
&& t != &token::Semi
&& t != &token::Pound)
@@ -555,7 +554,7 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
let span = self.prev_token.span.shrink_to_hi();
let guar = self.dcx().emit_err(ExpectedSemi {
span,
- token: self.token.clone(),
+ token: self.token,
unexpected_token_label: Some(self.token.span),
sugg: ExpectedSemiSugg::AddSemi(span),
});
@@ -609,6 +608,8 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
// FIXME: translation requires list formatting (for `expect`)
let mut err = self.dcx().struct_span_err(self.token.span, msg_exp);
+ self.label_expected_raw_ref(&mut err);
+
// Look for usages of '=>' where '>=' was probably intended
if self.token == token::FatArrow
&& expected.iter().any(|tok| matches!(tok, TokenType::Operator | TokenType::Le))
@@ -673,8 +674,7 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
// `pub` may be used for an item or `pub(crate)`
if self.prev_token.is_ident_named(sym::public)
- && (self.token.can_begin_item()
- || self.token == TokenKind::OpenDelim(Delimiter::Parenthesis))
+ && (self.token.can_begin_item() || self.token == TokenKind::OpenParen)
{
err.span_suggestion_short(
self.prev_token.span,
@@ -750,6 +750,25 @@ fn tokens_to_string(tokens: &[TokenType]) -> String {
Err(err)
}
+ /// Adds a label when `&raw EXPR` was written instead of `&raw const EXPR`/`&raw mut EXPR`.
+ ///
+ /// Given that not all parser diagnostics flow through `expected_one_of_not_found`, this
+ /// label may need added to other diagnostics emission paths as needed.
+ pub(super) fn label_expected_raw_ref(&mut self, err: &mut Diag<'_>) {
+ if self.prev_token.is_keyword(kw::Raw)
+ && self.expected_token_types.contains(TokenType::KwMut)
+ && self.expected_token_types.contains(TokenType::KwConst)
+ && self.token.can_begin_expr()
+ {
+ err.span_suggestions(
+ self.prev_token.span.shrink_to_hi(),
+ "`&raw` must be followed by `const` or `mut` to be a raw reference expression",
+ [" const".to_string(), " mut".to_string()],
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+
/// Checks if the current token or the previous token are misspelled keywords
/// and adds a helpful suggestion.
fn check_for_misspelled_kw(&self, err: &mut Diag<'_>, expected: &[TokenType]) {
@@ -801,7 +820,7 @@ pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) -> ErrorGuaranteed {
let span = self.prev_token.span.shrink_to_hi();
let mut err = self.dcx().create_err(ExpectedSemi {
span,
- token: self.token.clone(),
+ token: self.token,
unexpected_token_label: Some(self.token.span),
sugg: ExpectedSemiSugg::AddSemi(span),
});
@@ -822,9 +841,7 @@ pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) -> ErrorGuaranteed {
if expr.attrs.len() == 1 { "this attribute" } else { "these attributes" },
),
);
- if self.token == token::Pound
- && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Bracket))
- {
+ if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) {
// We have
// #[attr]
// expr
@@ -1016,9 +1033,7 @@ pub(super) fn recover_closure_body(
) -> PResult<'a, P<Expr>> {
err.span_label(lo.to(decl_hi), "while parsing the body of this closure");
let guar = match before.kind {
- token::OpenDelim(Delimiter::Brace)
- if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) =>
- {
+ token::OpenBrace if token.kind != token::OpenBrace => {
// `{ || () }` should have been `|| { () }`
err.multipart_suggestion(
"you might have meant to open the body of the closure, instead of enclosing \
@@ -1033,9 +1048,7 @@ pub(super) fn recover_closure_body(
self.eat_to_tokens(&[exp!(CloseBrace)]);
guar
}
- token::OpenDelim(Delimiter::Parenthesis)
- if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) =>
- {
+ token::OpenParen if token.kind != token::OpenBrace => {
// We are within a function call or tuple, we can emit the error
// and recover.
self.eat_to_tokens(&[exp!(CloseParen), exp!(Comma)]);
@@ -1050,7 +1063,7 @@ pub(super) fn recover_closure_body(
);
err.emit()
}
- _ if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => {
+ _ if token.kind != token::OpenBrace => {
// We don't have a heuristic to correctly identify where the block
// should be closed.
err.multipart_suggestion_verbose(
@@ -1204,7 +1217,7 @@ pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut Pa
trailing_span = trailing_span.to(self.token.span);
self.bump();
}
- if self.token == token::OpenDelim(Delimiter::Parenthesis) {
+ if self.token == token::OpenParen {
// Recover from bad turbofish: `foo.collect::Vec<_>()`.
segment.args = Some(AngleBracketedArgs { args, span }.into());
@@ -1449,9 +1462,7 @@ pub(super) fn check_no_chained_comparison(
let modifiers = [(token::Lt, 1), (token::Gt, -1), (token::Shr, -2)];
self.consume_tts(1, &modifiers);
- if !&[token::OpenDelim(Delimiter::Parenthesis), token::PathSep]
- .contains(&self.token.kind)
- {
+ if !matches!(self.token.kind, token::OpenParen | token::PathSep) {
// We don't have `foo< bar >(` or `foo< bar >::`, so we rewind the
// parser and bail out.
self.restore_snapshot(snapshot);
@@ -1489,7 +1500,7 @@ pub(super) fn check_no_chained_comparison(
Err(self.dcx().create_err(err))
}
}
- } else if self.token == token::OpenDelim(Delimiter::Parenthesis) {
+ } else if self.token == token::OpenParen {
// We have high certainty that this was a bad turbofish at this point.
// `foo< bar >(`
if let ExprKind::Binary(o, ..) = inner_op.kind
@@ -1549,10 +1560,7 @@ fn consume_fn_args(&mut self) -> Result<(), ()> {
self.bump(); // `(`
// Consume the fn call arguments.
- let modifiers = [
- (token::OpenDelim(Delimiter::Parenthesis), 1),
- (token::CloseDelim(Delimiter::Parenthesis), -1),
- ];
+ let modifiers = [(token::OpenParen, 1), (token::CloseParen, -1)];
self.consume_tts(1, &modifiers);
if self.token == token::Eof {
@@ -1636,19 +1644,19 @@ pub(super) fn maybe_recover_from_bad_type_plus(&mut self, ty: &Ty) -> PResult<'a
self.bump(); // `+`
let _bounds = self.parse_generic_bounds()?;
- let sum_span = ty.span.to(self.prev_token.span);
-
let sub = match &ty.kind {
TyKind::Ref(_lifetime, mut_ty) => {
let lo = mut_ty.ty.span.shrink_to_lo();
let hi = self.prev_token.span.shrink_to_hi();
BadTypePlusSub::AddParen { suggestion: AddParen { lo, hi } }
}
- TyKind::Ptr(..) | TyKind::BareFn(..) => BadTypePlusSub::ForgotParen { span: sum_span },
- _ => BadTypePlusSub::ExpectPath { span: sum_span },
+ TyKind::Ptr(..) | TyKind::BareFn(..) => {
+ BadTypePlusSub::ForgotParen { span: ty.span.to(self.prev_token.span) }
+ }
+ _ => BadTypePlusSub::ExpectPath { span: ty.span },
};
- self.dcx().emit_err(BadTypePlus { ty: pprust::ty_to_string(ty), span: sum_span, sub });
+ self.dcx().emit_err(BadTypePlus { span: ty.span, sub });
Ok(())
}
@@ -1922,10 +1930,7 @@ pub(super) fn recover_colon_as_semi(&mut self) -> bool {
&& self.token == token::Colon
&& self.look_ahead(1, |next| line_idx(self.token.span) < line_idx(next.span))
{
- self.dcx().emit_err(ColonAsSemi {
- span: self.token.span,
- type_ascription: self.psess.unstable_features.is_nightly_build(),
- });
+ self.dcx().emit_err(ColonAsSemi { span: self.token.span });
self.bump();
return true;
}
@@ -1960,7 +1965,7 @@ fn recover_await_macro(&mut self) -> PResult<'a, (Span, P<Expr>, bool)> {
fn recover_await_prefix(&mut self, await_sp: Span) -> PResult<'a, (Span, P<Expr>, bool)> {
let is_question = self.eat(exp!(Question)); // Handle `await? <expr>`.
- let expr = if self.token == token::OpenDelim(Delimiter::Brace) {
+ let expr = if self.token == token::OpenBrace {
// Handle `await { <expr> }`.
// This needs to be handled separately from the next arm to avoid
// interpreting `await { <expr> }?` as `<expr>?.await`.
@@ -1996,9 +2001,7 @@ fn error_on_incorrect_await(
/// If encountering `future.await()`, consumes and emits an error.
pub(super) fn recover_from_await_method_call(&mut self) {
- if self.token == token::OpenDelim(Delimiter::Parenthesis)
- && self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis))
- {
+ if self.token == token::OpenParen && self.look_ahead(1, |t| t == &token::CloseParen) {
// future.await()
let lo = self.token.span;
self.bump(); // (
@@ -2011,9 +2014,7 @@ pub(super) fn recover_from_await_method_call(&mut self) {
///
/// If encountering `x.use()`, consumes and emits an error.
pub(super) fn recover_from_use(&mut self) {
- if self.token == token::OpenDelim(Delimiter::Parenthesis)
- && self.look_ahead(1, |t| t == &token::CloseDelim(Delimiter::Parenthesis))
- {
+ if self.token == token::OpenParen && self.look_ahead(1, |t| t == &token::CloseParen) {
// var.use()
let lo = self.token.span;
self.bump(); // (
@@ -2027,7 +2028,7 @@ pub(super) fn recover_from_use(&mut self) {
pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P<Expr>> {
let is_try = self.token.is_keyword(kw::Try);
let is_questionmark = self.look_ahead(1, |t| t == &token::Bang); //check for !
- let is_open = self.look_ahead(2, |t| t == &token::OpenDelim(Delimiter::Parenthesis)); //check for (
+ let is_open = self.look_ahead(2, |t| t == &token::OpenParen); //check for (
if is_try && is_questionmark && is_open {
let lo = self.token.span;
@@ -2035,7 +2036,7 @@ pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P<Expr>> {
self.bump(); //remove !
let try_span = lo.to(self.token.span); //we take the try!( span
self.bump(); //remove (
- let is_empty = self.token == token::CloseDelim(Delimiter::Parenthesis); //check if the block is empty
+ let is_empty = self.token == token::CloseParen; //check if the block is empty
self.consume_block(exp!(OpenParen), exp!(CloseParen), ConsumeClosingDelim::No); //eat the block
let hi = self.token.span;
self.bump(); //remove )
@@ -2130,7 +2131,7 @@ pub(super) fn recover_stmt_(
loop {
debug!("recover_stmt_ loop {:?}", self.token);
match self.token.kind {
- token::OpenDelim(Delimiter::Brace) => {
+ token::OpenBrace => {
brace_depth += 1;
self.bump();
if break_on_block == BlockMode::Break && brace_depth == 1 && bracket_depth == 0
@@ -2138,11 +2139,11 @@ pub(super) fn recover_stmt_(
in_block = true;
}
}
- token::OpenDelim(Delimiter::Bracket) => {
+ token::OpenBracket => {
bracket_depth += 1;
self.bump();
}
- token::CloseDelim(Delimiter::Brace) => {
+ token::CloseBrace => {
if brace_depth == 0 {
debug!("recover_stmt_ return - close delim {:?}", self.token);
break;
@@ -2154,7 +2155,7 @@ pub(super) fn recover_stmt_(
break;
}
}
- token::CloseDelim(Delimiter::Bracket) => {
+ token::CloseBracket => {
bracket_depth -= 1;
if bracket_depth < 0 {
bracket_depth = 0;
@@ -2201,12 +2202,10 @@ pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) {
if let token::DocComment(..) = self.token.kind {
self.dcx().emit_err(DocCommentOnParamType { span: self.token.span });
self.bump();
- } else if self.token == token::Pound
- && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Bracket))
- {
+ } else if self.token == token::Pound && self.look_ahead(1, |t| *t == token::OpenBracket) {
let lo = self.token.span;
// Skip every token until next possible arg.
- while self.token != token::CloseDelim(Delimiter::Bracket) {
+ while self.token != token::CloseBracket {
self.bump();
}
let sp = lo.to(self.token.span);
@@ -2225,9 +2224,7 @@ pub(super) fn parameter_without_type(
// If we find a pattern followed by an identifier, it could be an (incorrect)
// C-style parameter declaration.
if self.check_ident()
- && self.look_ahead(1, |t| {
- *t == token::Comma || *t == token::CloseDelim(Delimiter::Parenthesis)
- })
+ && self.look_ahead(1, |t| *t == token::Comma || *t == token::CloseParen)
{
// `fn foo(String s) {}`
let ident = self.parse_ident().unwrap();
@@ -2243,7 +2240,7 @@ pub(super) fn parameter_without_type(
} else if require_name
&& (self.token == token::Comma
|| self.token == token::Lt
- || self.token == token::CloseDelim(Delimiter::Parenthesis))
+ || self.token == token::CloseParen)
{
let rfc_note = "anonymous parameters are removed in the 2018 edition (see RFC 1685)";
@@ -2854,7 +2851,7 @@ pub(crate) fn maybe_recover_unexpected_block_label(
// Check for `'a : {`
if !(self.check_lifetime()
&& self.look_ahead(1, |t| *t == token::Colon)
- && self.look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace)))
+ && self.look_ahead(2, |t| *t == token::OpenBrace))
{
return false;
}
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index d52e36f..370eb3f 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -26,6 +26,7 @@
use rustc_session::errors::{ExprParenthesesNeeded, report_lit_error};
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
+use rustc_span::edition::Edition;
use rustc_span::source_map::{self, Spanned};
use rustc_span::{BytePos, ErrorGuaranteed, Ident, Pos, Span, Symbol, kw, sym};
use thin_vec::{ThinVec, thin_vec};
@@ -344,7 +345,7 @@ fn should_continue_as_assoc_expr(&mut self, lhs: &Expr) -> bool {
fn error_found_expr_would_be_stmt(&self, lhs: &Expr) {
self.dcx().emit_err(errors::FoundExprWouldBeStmt {
span: self.token.span,
- token: self.token.clone(),
+ token: self.token,
suggestion: ExprParenthesesNeeded::surrounding(lhs.span),
});
}
@@ -417,7 +418,7 @@ fn parse_expr_range(
cur_op_span: Span,
) -> PResult<'a, P<Expr>> {
let rhs = if self.is_at_start_of_range_notation_rhs() {
- let maybe_lt = self.token.clone();
+ let maybe_lt = self.token;
let attrs = self.parse_outer_attributes()?;
Some(
self.parse_expr_assoc_with(Bound::Excluded(prec), attrs)
@@ -436,7 +437,7 @@ fn parse_expr_range(
fn is_at_start_of_range_notation_rhs(&self) -> bool {
if self.token.can_begin_expr() {
// Parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`.
- if self.token == token::OpenDelim(Delimiter::Brace) {
+ if self.token == token::OpenBrace {
return !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL);
}
true
@@ -542,8 +543,8 @@ macro_rules! make_it {
}
// Recover from `++x`:
token::Plus if this.look_ahead(1, |t| *t == token::Plus) => {
- let starts_stmt = this.prev_token == token::Semi
- || this.prev_token == token::CloseDelim(Delimiter::Brace);
+ let starts_stmt =
+ this.prev_token == token::Semi || this.prev_token == token::CloseBrace;
let pre_span = this.token.span.to(this.look_ahead(1, |t| t.span));
// Eat both `+`s.
this.bump();
@@ -611,7 +612,7 @@ fn is_mistaken_not_ident_negation(&self) -> bool {
/// Recover on `not expr` in favor of `!expr`.
fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
- let negated_token = self.look_ahead(1, |t| t.clone());
+ let negated_token = self.look_ahead(1, |t| *t);
let sub_diag = if negated_token.is_numeric_lit() {
errors::NotAsNegationOperatorSub::SuggestNotBitwise
@@ -637,10 +638,8 @@ fn recover_not_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
/// Returns the span of expr if it was not interpolated, or the span of the interpolated token.
fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {
match self.prev_token.kind {
- TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) | TokenKind::Interpolated(..) => {
- self.prev_token.span
- }
- TokenKind::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => {
+ token::NtIdent(..) | token::NtLifetime(..) => self.prev_token.span,
+ token::CloseInvisible(InvisibleOrigin::MetaVar(_)) => {
// `expr.span` is the interpolated span, because invisible open
// and close delims both get marked with the same span, one
// that covers the entire thing between them. (See
@@ -829,6 +828,18 @@ fn parse_expr_borrow(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
if let Some(lt) = lifetime {
self.error_remove_borrow_lifetime(span, lt.ident.span.until(expr.span));
}
+
+ // Add expected tokens if we parsed `&raw` as an expression.
+ // This will make sure we see "expected `const`, `mut`", and
+ // guides recovery in case we write `&raw expr`.
+ if borrow_kind == ast::BorrowKind::Ref
+ && mutbl == ast::Mutability::Not
+ && matches!(&expr.kind, ExprKind::Path(None, p) if p.is_ident(kw::Raw))
+ {
+ self.expected_token_types.insert(TokenType::KwMut);
+ self.expected_token_types.insert(TokenType::KwConst);
+ }
+
Ok((span, ExprKind::AddrOf(borrow_kind, mutbl, expr)))
}
@@ -902,8 +913,8 @@ pub(super) fn parse_expr_dot_or_call_with(
return Ok(e);
}
e = match self.token.kind {
- token::OpenDelim(Delimiter::Parenthesis) => self.parse_expr_fn_call(lo, e),
- token::OpenDelim(Delimiter::Bracket) => self.parse_expr_index(lo, e)?,
+ token::OpenParen => self.parse_expr_fn_call(lo, e),
+ token::OpenBracket => self.parse_expr_index(lo, e)?,
_ => return Ok(e),
}
}
@@ -992,7 +1003,7 @@ fn error_unexpected_after_dot(&self) {
(token::Eof, Some(_)) if let Ok(snippet) = sm.span_to_snippet(sm.next_point(span)) => {
(span.shrink_to_hi(), format!("`{}`", snippet))
}
- (token::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))), _) => {
+ (token::CloseInvisible(InvisibleOrigin::MetaVar(_)), _) => {
// No need to report an error. This case will only occur when parsing a pasted
// metavariable, and we should have emitted an error when parsing the macro call in
// the first place. E.g. in this code:
@@ -1192,7 +1203,7 @@ fn parse_floating_field_access(&mut self) -> PResult<'a, P<[Ident]>> {
}
}
- if matches!(self.token.kind, token::CloseDelim(..) | token::Comma) {
+ if self.token.kind.close_delim().is_some() || self.token.kind == token::Comma {
break;
} else if trailing_dot.is_none() {
// This loop should only repeat if there is a trailing dot.
@@ -1222,7 +1233,7 @@ fn mk_expr_tuple_field_access(
/// Parse a function call expression, `expr(...)`.
fn parse_expr_fn_call(&mut self, lo: Span, fun: P<Expr>) -> P<Expr> {
- let snapshot = if self.token == token::OpenDelim(Delimiter::Parenthesis) {
+ let snapshot = if self.token == token::OpenParen {
Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))
} else {
None
@@ -1386,15 +1397,7 @@ fn parse_expr_bottom(&mut self) -> PResult<'a, P<Expr>> {
maybe_recover_from_interpolated_ty_qpath!(self, true);
let span = self.token.span;
- if let token::Interpolated(nt) = &self.token.kind {
- match &**nt {
- token::NtBlock(block) => {
- let block = block.clone();
- self.bump();
- return Ok(self.mk_expr(self.prev_token.span, ExprKind::Block(block, None)));
- }
- };
- } else if let Some(expr) = self.eat_metavar_seq_with_matcher(
+ if let Some(expr) = self.eat_metavar_seq_with_matcher(
|mv_kind| matches!(mv_kind, MetaVarKind::Expr { .. }),
|this| {
// Force collection (as opposed to just `parse_expr`) is required to avoid the
@@ -1415,9 +1418,13 @@ fn parse_expr_bottom(&mut self) -> PResult<'a, P<Expr>> {
self.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
{
return Ok(lit);
- } else if let Some(path) = self.eat_metavar_seq(MetaVarKind::Path, |this| {
- this.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))
- }) {
+ } else if let Some(block) =
+ self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block())
+ {
+ return Ok(self.mk_expr(span, ExprKind::Block(block, None)));
+ } else if let Some(path) =
+ self.eat_metavar_seq(MetaVarKind::Path, |this| this.parse_path(PathStyle::Type))
+ {
return Ok(self.mk_expr(span, ExprKind::Path(None, path)));
}
@@ -1612,7 +1619,7 @@ fn parse_expr_array_or_repeat(&mut self, close: ExpTokenPair<'_>) -> PResult<'a,
}
fn parse_expr_path_start(&mut self) -> PResult<'a, P<Expr>> {
- let maybe_eq_tok = self.prev_token.clone();
+ let maybe_eq_tok = self.prev_token;
let (qself, path) = if self.eat_lt() {
let lt_span = self.prev_token.span;
let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| {
@@ -1670,14 +1677,11 @@ pub(super) fn parse_expr_labeled(
self.parse_expr_for(label, lo)
} else if self.eat_keyword(exp!(Loop)) {
self.parse_expr_loop(label, lo)
- } else if self.check_noexpect(&token::OpenDelim(Delimiter::Brace))
- || self.token.is_whole_block()
- {
+ } else if self.check_noexpect(&token::OpenBrace) || self.token.is_metavar_block() {
self.parse_expr_block(label, lo, BlockCheckMode::Default)
} else if !ate_colon
&& self.may_recover()
- && (matches!(self.token.kind, token::CloseDelim(_) | token::Comma)
- || self.token.is_punct())
+ && (self.token.kind.close_delim().is_some() || self.token.is_punct())
&& could_be_unclosed_char_literal(label_.ident)
{
let (lit, _) =
@@ -1872,19 +1876,21 @@ fn parse_expr_break(&mut self) -> PResult<'a, P<Expr>> {
},
});
Some(lexpr)
- } else if self.token != token::OpenDelim(Delimiter::Brace)
+ } else if self.token != token::OpenBrace
|| !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
{
let mut expr = self.parse_expr_opt()?;
if let Some(expr) = &mut expr {
if label.is_some()
- && matches!(
- expr.kind,
+ && match &expr.kind {
ExprKind::While(_, _, None)
- | ExprKind::ForLoop { label: None, .. }
- | ExprKind::Loop(_, None, _)
- | ExprKind::Block(_, None)
- )
+ | ExprKind::ForLoop { label: None, .. }
+ | ExprKind::Loop(_, None, _) => true,
+ ExprKind::Block(block, None) => {
+ matches!(block.rules, BlockCheckMode::Default)
+ }
+ _ => false,
+ }
{
self.psess.buffer_lint(
BREAK_WITH_LABEL_AND_LOOP,
@@ -2008,7 +2014,7 @@ pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P<Expr>>
// Eat tokens until the macro call ends.
if self.may_recover() {
- while !matches!(self.token.kind, token::CloseDelim(..) | token::Eof) {
+ while !self.token.kind.is_close_delim_or_eof() {
self.bump();
}
}
@@ -2073,7 +2079,7 @@ fn handle_missing_lit<L>(
&mut self,
mk_lit_char: impl FnOnce(Symbol, Span) -> L,
) -> PResult<'a, L> {
- let token = self.token.clone();
+ let token = self.token;
let err = |self_: &Self| {
let msg = format!("unexpected token: {}", super::token_descr(&token));
self_.dcx().struct_span_err(token.span, msg)
@@ -2140,6 +2146,17 @@ fn recover_after_dot(&mut self) {
/// Keep this in sync with `Token::can_begin_literal_maybe_minus` and
/// `Lit::from_token` (excluding unary negation).
fn eat_token_lit(&mut self) -> Option<token::Lit> {
+ let check_expr = |expr: P<Expr>| {
+ if let ast::ExprKind::Lit(token_lit) = expr.kind {
+ Some(token_lit)
+ } else if let ast::ExprKind::Unary(UnOp::Neg, inner) = &expr.kind
+ && let ast::Expr { kind: ast::ExprKind::Lit(_), .. } = **inner
+ {
+ None
+ } else {
+ panic!("unexpected reparsed expr/literal: {:?}", expr.kind);
+ }
+ };
match self.token.uninterpolate().kind {
token::Ident(name, IdentIsRaw::No) if name.is_bool_lit() => {
self.bump();
@@ -2149,32 +2166,19 @@ fn eat_token_lit(&mut self) -> Option<token::Lit> {
self.bump();
Some(token_lit)
}
- token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
- MetaVarKind::Literal,
- ))) => {
+ token::OpenInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Literal)) => {
let lit = self
.eat_metavar_seq(MetaVarKind::Literal, |this| this.parse_literal_maybe_minus())
.expect("metavar seq literal");
- let ast::ExprKind::Lit(token_lit) = lit.kind else {
- panic!("didn't reparse a literal");
- };
- Some(token_lit)
+ check_expr(lit)
}
- token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
+ token::OpenInvisible(InvisibleOrigin::MetaVar(
mv_kind @ MetaVarKind::Expr { can_begin_literal_maybe_minus: true, .. },
- ))) => {
+ )) => {
let expr = self
.eat_metavar_seq(mv_kind, |this| this.parse_expr())
.expect("metavar seq expr");
- if let ast::ExprKind::Lit(token_lit) = expr.kind {
- Some(token_lit)
- } else if let ast::ExprKind::Unary(UnOp::Neg, inner) = &expr.kind
- && let ast::Expr { kind: ast::ExprKind::Lit(_), .. } = **inner
- {
- None
- } else {
- panic!("unexpected reparsed expr: {:?}", expr.kind);
- }
+ check_expr(expr)
}
_ => None,
}
@@ -2267,7 +2271,7 @@ pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
}
fn is_array_like_block(&mut self) -> bool {
- matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace))
+ self.token.kind == TokenKind::OpenBrace
&& self
.look_ahead(1, |t| matches!(t.kind, TokenKind::Ident(..) | TokenKind::Literal(_)))
&& self.look_ahead(2, |t| t == &token::Comma)
@@ -2320,8 +2324,8 @@ fn suggest_missing_semicolon_before_array(
|p| p.parse_expr(),
) {
Ok(_)
- // When the close delim is `)`, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`,
- // but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`.
+ // When the close delim is `)`, `token.kind` is expected to be `token::CloseParen`,
+ // but the actual `token.kind` is `token::CloseBracket`.
// This is because the `token.kind` of the close delim is treated as the same as
// that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
// Therefore, `token.kind` should not be compared here.
@@ -2354,7 +2358,7 @@ pub(super) fn parse_expr_block(
}
}
- if self.token.is_whole_block() {
+ if self.token.is_metavar_block() {
self.dcx().emit_err(errors::InvalidBlockMacroSegment {
span: self.token.span,
context: lo.to(self.token.span),
@@ -2379,7 +2383,7 @@ fn parse_simple_block(&mut self) -> PResult<'a, P<Expr>> {
fn parse_expr_closure(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.token.span;
- let before = self.prev_token.clone();
+ let before = self.prev_token;
let binder = if self.check_keyword(exp!(For)) {
let lo = self.token.span;
let (lifetime_defs, _) = self.parse_late_bound_lifetime_defs()?;
@@ -2411,8 +2415,8 @@ fn parse_expr_closure(&mut self) -> PResult<'a, P<Expr>> {
FnRetTy::Default(_) => {
let restrictions =
self.restrictions - Restrictions::STMT_EXPR - Restrictions::ALLOW_LET;
- let prev = self.prev_token.clone();
- let token = self.token.clone();
+ let prev = self.prev_token;
+ let token = self.token;
let attrs = self.parse_outer_attributes()?;
match self.parse_expr_res(restrictions, attrs) {
Ok((expr, _)) => expr,
@@ -2476,8 +2480,8 @@ fn parse_expr_closure(&mut self) -> PResult<'a, P<Expr>> {
fn parse_closure_block_body(&mut self, ret_span: Span) -> PResult<'a, P<Expr>> {
if self.may_recover()
&& self.token.can_begin_expr()
- && !matches!(self.token.kind, TokenKind::OpenDelim(Delimiter::Brace))
- && !self.token.is_whole_block()
+ && self.token.kind != TokenKind::OpenBrace
+ && !self.token.is_metavar_block()
{
let snapshot = self.create_snapshot_for_diagnostic();
let restrictions =
@@ -2599,7 +2603,10 @@ fn parse_fn_block_param(&mut self) -> PResult<'a, Param> {
/// Parses an `if` expression (`if` token already eaten).
fn parse_expr_if(&mut self) -> PResult<'a, P<Expr>> {
let lo = self.prev_token.span;
- let cond = self.parse_expr_cond()?;
+ // Scoping code checks the top level edition of the `if`; let's match it here.
+ // The `CondChecker` also checks the edition of the `let` itself, just to make sure.
+ let let_chains_policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
+ let cond = self.parse_expr_cond(let_chains_policy)?;
self.parse_if_after_cond(lo, cond)
}
@@ -2659,7 +2666,7 @@ fn parse_if_after_cond(&mut self, lo: Span, mut cond: P<Expr>) -> PResult<'a, P<
}
} else {
let attrs = self.parse_outer_attributes()?; // For recovery.
- let maybe_fatarrow = self.token.clone();
+ let maybe_fatarrow = self.token;
let block = if self.check(exp!(OpenBrace)) {
self.parse_block()?
} else if let Some(block) = recover_block_from_condition(self) {
@@ -2708,18 +2715,17 @@ fn parse_if_after_cond(&mut self, lo: Span, mut cond: P<Expr>) -> PResult<'a, P<
}
/// Parses the condition of a `if` or `while` expression.
+ ///
+ /// The specified `edition` in `let_chains_policy` should be that of the whole `if` construct,
+ /// i.e. the same span we use to later decide whether the drop behaviour should be that of
+ /// edition `..=2021` or that of `2024..`.
// Public because it is used in rustfmt forks such as https://github.com/tucant/rustfmt/blob/30c83df9e1db10007bdd16dafce8a86b404329b2/src/parse/macros/html.rs#L57 for custom if expressions.
- pub fn parse_expr_cond(&mut self) -> PResult<'a, P<Expr>> {
+ pub fn parse_expr_cond(&mut self, let_chains_policy: LetChainsPolicy) -> PResult<'a, P<Expr>> {
let attrs = self.parse_outer_attributes()?;
let (mut cond, _) =
self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL | Restrictions::ALLOW_LET, attrs)?;
- CondChecker::new(self).visit_expr(&mut cond);
-
- if let ExprKind::Let(_, _, _, Recovered::No) = cond.kind {
- // Remove the last feature gating of a `let` expression since it's stable.
- self.psess.gated_spans.ungate_last(sym::let_chains, cond.span);
- }
+ CondChecker::new(self, let_chains_policy).visit_expr(&mut cond);
Ok(cond)
}
@@ -2879,7 +2885,7 @@ fn error_on_extra_if(&mut self, cond: &P<Expr>) -> PResult<'a, ()> {
}
fn parse_for_head(&mut self) -> PResult<'a, (P<Pat>, P<Expr>)> {
- let begin_paren = if self.token == token::OpenDelim(Delimiter::Parenthesis) {
+ let begin_paren = if self.token == token::OpenParen {
// Record whether we are about to parse `for (`.
// This is used below for recovery in case of `for ( $stuff ) $block`
// in which case we will suggest `for $stuff $block`.
@@ -2913,7 +2919,7 @@ fn parse_for_head(&mut self) -> PResult<'a, (P<Pat>, P<Expr>)> {
return Err(err);
}
};
- return if self.token == token::CloseDelim(Delimiter::Parenthesis) {
+ return if self.token == token::CloseParen {
// We know for sure we have seen `for ($SOMETHING in $EXPR)`, so we recover the
// parser state and emit a targeted suggestion.
let span = vec![start_span, self.token.span];
@@ -2957,7 +2963,7 @@ fn parse_expr_for(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a,
let (pat, expr) = self.parse_for_head()?;
// Recover from missing expression in `for` loop
if matches!(expr.kind, ExprKind::Block(..))
- && !matches!(self.token.kind, token::OpenDelim(Delimiter::Brace))
+ && self.token.kind != token::OpenBrace
&& self.may_recover()
{
let guar = self
@@ -3014,7 +3020,8 @@ fn error_missing_in_for_loop(&mut self) {
/// Parses a `while` or `while let` expression (`while` token already eaten).
fn parse_expr_while(&mut self, opt_label: Option<Label>, lo: Span) -> PResult<'a, P<Expr>> {
- let cond = self.parse_expr_cond().map_err(|mut err| {
+ let policy = LetChainsPolicy::EditionDependent { current_edition: lo.edition() };
+ let cond = self.parse_expr_cond(policy).map_err(|mut err| {
err.span_label(lo, "while parsing the condition of this `while` expression");
err
})?;
@@ -3106,7 +3113,7 @@ fn parse_match_block(
let attrs = self.parse_inner_attributes()?;
let mut arms = ThinVec::new();
- while self.token != token::CloseDelim(Delimiter::Brace) {
+ while self.token != token::CloseBrace {
match self.parse_arm() {
Ok(arm) => arms.push(arm),
Err(e) => {
@@ -3114,7 +3121,7 @@ fn parse_match_block(
let guar = e.emit();
self.recover_stmt();
let span = lo.to(self.token.span);
- if self.token == token::CloseDelim(Delimiter::Brace) {
+ if self.token == token::CloseBrace {
self.bump();
}
// Always push at least one arm to make the match non-empty
@@ -3175,7 +3182,7 @@ fn parse_arm_body_missing_braces(
// We might have either a `,` -> `;` typo, or a block without braces. We need
// a more subtle parsing strategy.
loop {
- if self.token == token::CloseDelim(Delimiter::Brace) {
+ if self.token == token::CloseBrace {
// We have reached the closing brace of the `match` expression.
return Some(err(self, stmts));
}
@@ -3234,7 +3241,7 @@ pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
// this avoids the compiler saying that a `,` or `}` was expected even though
// the pattern isn't a never pattern (and thus an arm body is required)
let armless = (!is_fat_arrow && !is_almost_fat_arrow && pat.could_be_never_pattern())
- || matches!(this.token.kind, token::Comma | token::CloseDelim(Delimiter::Brace));
+ || matches!(this.token.kind, token::Comma | token::CloseBrace);
let mut result = if armless {
// A pattern without a body, allowed for never patterns.
@@ -3282,8 +3289,8 @@ pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
err
})?;
- let require_comma = !classify::expr_is_complete(&expr)
- && this.token != token::CloseDelim(Delimiter::Brace);
+ let require_comma =
+ !classify::expr_is_complete(&expr) && this.token != token::CloseBrace;
if !require_comma {
arm_body = Some(expr);
@@ -3398,17 +3405,17 @@ pub(super) fn parse_arm(&mut self) -> PResult<'a, Arm> {
}
fn parse_match_arm_guard(&mut self) -> PResult<'a, Option<P<Expr>>> {
- // Used to check the `let_chains` and `if_let_guard` features mostly by scanning
+ // Used to check the `if_let_guard` feature mostly by scanning
// `&&` tokens.
- fn check_let_expr(expr: &Expr) -> (bool, bool) {
+ fn has_let_expr(expr: &Expr) -> bool {
match &expr.kind {
ExprKind::Binary(BinOp { node: BinOpKind::And, .. }, lhs, rhs) => {
- let lhs_rslt = check_let_expr(lhs);
- let rhs_rslt = check_let_expr(rhs);
- (lhs_rslt.0 || rhs_rslt.0, false)
+ let lhs_rslt = has_let_expr(lhs);
+ let rhs_rslt = has_let_expr(rhs);
+ lhs_rslt || rhs_rslt
}
- ExprKind::Let(..) => (true, true),
- _ => (false, true),
+ ExprKind::Let(..) => true,
+ _ => false,
}
}
if !self.eat_keyword(exp!(If)) {
@@ -3419,14 +3426,9 @@ fn check_let_expr(expr: &Expr) -> (bool, bool) {
let if_span = self.prev_token.span;
let mut cond = self.parse_match_guard_condition()?;
- CondChecker::new(self).visit_expr(&mut cond);
+ CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
- let (has_let_expr, does_not_have_bin_op) = check_let_expr(&cond);
- if has_let_expr {
- if does_not_have_bin_op {
- // Remove the last feature gating of a `let` expression since it's stable.
- self.psess.gated_spans.ungate_last(sym::let_chains, cond.span);
- }
+ if has_let_expr(&cond) {
let span = if_span.to(cond.span);
self.psess.gated_spans.gate(sym::if_let_guard, span);
}
@@ -3434,7 +3436,7 @@ fn check_let_expr(expr: &Expr) -> (bool, bool) {
}
fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (P<Pat>, Option<P<Expr>>)> {
- if self.token == token::OpenDelim(Delimiter::Parenthesis) {
+ if self.token == token::OpenParen {
let left = self.token.span;
let pat = self.parse_pat_no_top_guard(
None,
@@ -3453,7 +3455,7 @@ fn parse_match_arm_pat_and_guard(&mut self) -> PResult<'a, (P<Pat>, Option<P<Exp
unreachable!()
};
self.psess.gated_spans.ungate_last(sym::guard_patterns, cond.span);
- CondChecker::new(self).visit_expr(&mut cond);
+ CondChecker::new(self, LetChainsPolicy::AlwaysAllowed).visit_expr(&mut cond);
let right = self.prev_token.span;
self.dcx().emit_err(errors::ParenthesesInMatchPat {
span: vec![left, right],
@@ -3480,7 +3482,7 @@ fn parse_match_guard_condition(&mut self) -> PResult<'a, P<Expr>> {
match self.parse_expr_res(Restrictions::ALLOW_LET | Restrictions::IN_IF_GUARD, attrs) {
Ok((expr, _)) => Ok(expr),
Err(mut err) => {
- if self.prev_token == token::OpenDelim(Delimiter::Brace) {
+ if self.prev_token == token::OpenBrace {
let sugg_sp = self.prev_token.span.shrink_to_lo();
// Consume everything within the braces, let's avoid further parse
// errors.
@@ -3523,8 +3525,7 @@ fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
fn is_do_catch_block(&self) -> bool {
self.token.is_keyword(kw::Do)
&& self.is_keyword_ahead(1, &[kw::Catch])
- && self
- .look_ahead(2, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
+ && self.look_ahead(2, |t| *t == token::OpenBrace || t.is_metavar_block())
&& !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
}
@@ -3534,8 +3535,7 @@ fn is_do_yeet(&self) -> bool {
fn is_try_block(&self) -> bool {
self.token.is_keyword(kw::Try)
- && self
- .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
+ && self.look_ahead(1, |t| *t == token::OpenBrace || t.is_metavar_block())
&& self.token_uninterpolated_span().at_least_rust_2018()
}
@@ -3569,13 +3569,11 @@ fn is_gen_block(&self, kw: Symbol, lookahead: usize) -> bool {
// `async move {`
self.is_keyword_ahead(lookahead + 1, &[kw::Move, kw::Use])
&& self.look_ahead(lookahead + 2, |t| {
- *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()
+ *t == token::OpenBrace || t.is_metavar_block()
})
) || (
// `async {`
- self.look_ahead(lookahead + 1, |t| {
- *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block()
- })
+ self.look_ahead(lookahead + 1, |t| *t == token::OpenBrace || t.is_metavar_block())
))
}
@@ -3699,11 +3697,7 @@ pub(super) fn parse_struct_fields(
AssocOp::from_token(t).is_some()
|| matches!(
t.kind,
- token::OpenDelim(
- Delimiter::Parenthesis
- | Delimiter::Bracket
- | Delimiter::Brace
- )
+ token::OpenParen | token::OpenBracket | token::OpenBrace
)
|| *t == token::Dot
})
@@ -3860,14 +3854,14 @@ fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
t == &token::Colon
|| t == &token::Eq
|| t == &token::Comma
- || t == &token::CloseDelim(Delimiter::Brace)
- || t == &token::CloseDelim(Delimiter::Parenthesis)
+ || t == &token::CloseBrace
+ || t == &token::CloseParen
});
if is_wrong {
return Err(this.dcx().create_err(errors::ExpectedStructField {
span: this.look_ahead(1, |t| t.span),
ident_span: this.token.span,
- token: this.look_ahead(1, |t| t.clone()),
+ token: this.look_ahead(1, |t| *t),
}));
}
let (ident, expr) = if is_shorthand {
@@ -4032,7 +4026,14 @@ pub(crate) enum ForbiddenLetReason {
NotSupportedParentheses(#[primary_span] Span),
}
-/// Visitor to check for invalid/unstable use of `ExprKind::Let` that can't
+/// Whether let chains are allowed on all editions, or it's edition dependent (allowed only on
+/// 2024 and later). In case of edition dependence, specify the currently present edition.
+pub enum LetChainsPolicy {
+ AlwaysAllowed,
+ EditionDependent { current_edition: Edition },
+}
+
+/// Visitor to check for invalid use of `ExprKind::Let` that can't
/// easily be caught in parsing. For example:
///
/// ```rust,ignore (example)
@@ -4043,19 +4044,29 @@ pub(crate) enum ForbiddenLetReason {
/// ```
struct CondChecker<'a> {
parser: &'a Parser<'a>,
+ let_chains_policy: LetChainsPolicy,
+ depth: u32,
forbid_let_reason: Option<ForbiddenLetReason>,
missing_let: Option<errors::MaybeMissingLet>,
comparison: Option<errors::MaybeComparison>,
}
impl<'a> CondChecker<'a> {
- fn new(parser: &'a Parser<'a>) -> Self {
- CondChecker { parser, forbid_let_reason: None, missing_let: None, comparison: None }
+ fn new(parser: &'a Parser<'a>, let_chains_policy: LetChainsPolicy) -> Self {
+ CondChecker {
+ parser,
+ forbid_let_reason: None,
+ missing_let: None,
+ comparison: None,
+ let_chains_policy,
+ depth: 0,
+ }
}
}
impl MutVisitor for CondChecker<'_> {
fn visit_expr(&mut self, e: &mut P<Expr>) {
+ self.depth += 1;
use ForbiddenLetReason::*;
let span = e.span;
@@ -4070,8 +4081,16 @@ fn visit_expr(&mut self, e: &mut P<Expr>) {
comparison: self.comparison,
},
));
- } else {
- self.parser.psess.gated_spans.gate(sym::let_chains, span);
+ } else if self.depth > 1 {
+ // Top level `let` is always allowed; only gate chains
+ match self.let_chains_policy {
+ LetChainsPolicy::AlwaysAllowed => (),
+ LetChainsPolicy::EditionDependent { current_edition } => {
+ if !current_edition.at_least_rust_2024() || !span.at_least_rust_2024() {
+ self.parser.psess.gated_spans.gate(sym::let_chains, span);
+ }
+ }
+ }
}
}
ExprKind::Binary(Spanned { node: BinOpKind::And, .. }, _, _) => {
@@ -4173,5 +4192,6 @@ fn visit_expr(&mut self, e: &mut P<Expr>) {
// These would forbid any let expressions they contain already.
}
}
+ self.depth -= 1;
}
}
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index c3f71dd..c05479f 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -1,4 +1,3 @@
-use ast::token::Delimiter;
use rustc_ast::{
self as ast, AttrVec, DUMMY_NODE_ID, GenericBounds, GenericParam, GenericParamKind, TyKind,
WhereClause, token,
@@ -437,7 +436,7 @@ fn parse_ty_where_predicate_kind_or_recover_tuple_struct_body(
if let Some(struct_) = struct_
&& self.may_recover()
- && self.token == token::OpenDelim(Delimiter::Parenthesis)
+ && self.token == token::OpenParen
{
snapshot = Some((struct_, self.create_snapshot_for_diagnostic()));
};
@@ -548,7 +547,7 @@ pub(super) fn choose_generics_over_qpath(&self, start: usize) -> bool {
matches!(t.kind, token::Gt | token::Comma | token::Colon | token::Eq)
// Recovery-only branch -- this could be removed,
// since it only affects diagnostics currently.
- || matches!(t.kind, token::Question)
+ || t.kind == token::Question
})
|| self.is_keyword_ahead(start + 1, &[kw::Const]))
}
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 0650181..39251f1 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -399,14 +399,9 @@ fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> {
let insert_span = ident_span.shrink_to_lo();
let ident = if self.token.is_ident()
- && (!is_const || self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Parenthesis)))
+ && (!is_const || self.look_ahead(1, |t| *t == token::OpenParen))
&& self.look_ahead(1, |t| {
- [
- token::Lt,
- token::OpenDelim(Delimiter::Brace),
- token::OpenDelim(Delimiter::Parenthesis),
- ]
- .contains(&t.kind)
+ matches!(t.kind, token::Lt | token::OpenBrace | token::OpenParen)
}) {
self.parse_ident().unwrap()
} else {
@@ -422,7 +417,7 @@ fn recover_missing_kw_before_item(&mut self) -> PResult<'a, ()> {
let err = if self.check(exp!(OpenBrace)) {
// possible struct or enum definition where `struct` or `enum` was forgotten
- if self.look_ahead(1, |t| *t == token::CloseDelim(Delimiter::Brace)) {
+ if self.look_ahead(1, |t| *t == token::CloseBrace) {
// `S {}` could be unit enum or struct
Some(errors::MissingKeywordForItemDefinition::EnumOrStruct { span })
} else if self.look_ahead(2, |t| *t == token::Colon)
@@ -764,11 +759,12 @@ fn parse_item_list<T>(
match parse_item(self) {
Ok(None) => {
let mut is_unnecessary_semicolon = !items.is_empty()
- // When the close delim is `)` in a case like the following, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`,
- // but the actual `token.kind` is `token::CloseDelim(Delimiter::Brace)`.
- // This is because the `token.kind` of the close delim is treated as the same as
- // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different.
- // Therefore, `token.kind` should not be compared here.
+ // When the close delim is `)` in a case like the following, `token.kind`
+ // is expected to be `token::CloseParen`, but the actual `token.kind` is
+ // `token::CloseBrace`. This is because the `token.kind` of the close delim
+ // is treated as the same as that of the open delim in
+ // `TokenTreesReader::parse_token_tree`, even if the delimiters of them are
+ // different. Therefore, `token.kind` should not be compared here.
//
// issue-60075.rs
// ```
@@ -787,8 +783,8 @@ fn parse_item_list<T>(
let mut semicolon_span = self.token.span;
if !is_unnecessary_semicolon {
// #105369, Detect spurious `;` before assoc fn body
- is_unnecessary_semicolon = self.token == token::OpenDelim(Delimiter::Brace)
- && self.prev_token == token::Semi;
+ is_unnecessary_semicolon =
+ self.token == token::OpenBrace && self.prev_token == token::Semi;
semicolon_span = self.prev_token.span;
}
// We have to bail or we'll potentially never make progress.
@@ -840,7 +836,7 @@ fn parse_item_list<T>(
/// Recover on a doc comment before `}`.
fn recover_doc_comment_before_brace(&mut self) -> bool {
if let token::DocComment(..) = self.token.kind {
- if self.look_ahead(1, |tok| tok == &token::CloseDelim(Delimiter::Brace)) {
+ if self.look_ahead(1, |tok| tok == &token::CloseBrace) {
// FIXME: merge with `DocCommentDoesNotDocumentAnything` (E0585)
struct_span_code_err!(
self.dcx(),
@@ -1206,7 +1202,7 @@ fn parse_item_foreign_mod(
// FIXME: This recovery should be tested better.
if safety == Safety::Default
&& self.token.is_keyword(kw::Unsafe)
- && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace))
+ && self.look_ahead(1, |t| *t == token::OpenBrace)
{
self.expect(exp!(OpenBrace)).unwrap_err().emit();
safety = Safety::Unsafe(self.token.span);
@@ -1718,7 +1714,7 @@ fn parse_item_struct(&mut self) -> PResult<'a, ItemKind> {
} else if self.eat(exp!(Semi)) {
VariantData::Unit(DUMMY_NODE_ID)
// Record-style struct definition
- } else if self.token == token::OpenDelim(Delimiter::Brace) {
+ } else if self.token == token::OpenBrace {
let (fields, recovered) = self.parse_record_struct_body(
"struct",
ident.span,
@@ -1726,14 +1722,13 @@ fn parse_item_struct(&mut self) -> PResult<'a, ItemKind> {
)?;
VariantData::Struct { fields, recovered }
// Tuple-style struct definition with optional where-clause.
- } else if self.token == token::OpenDelim(Delimiter::Parenthesis) {
+ } else if self.token == token::OpenParen {
let body = VariantData::Tuple(self.parse_tuple_struct_body()?, DUMMY_NODE_ID);
generics.where_clause = self.parse_where_clause()?;
self.expect_semi()?;
body
} else {
- let err =
- errors::UnexpectedTokenAfterStructName::new(self.token.span, self.token.clone());
+ let err = errors::UnexpectedTokenAfterStructName::new(self.token.span, self.token);
return Err(self.dcx().create_err(err));
};
@@ -1754,7 +1749,7 @@ fn parse_item_union(&mut self) -> PResult<'a, ItemKind> {
generics.where_clause.has_where_token,
)?;
VariantData::Struct { fields, recovered }
- } else if self.token == token::OpenDelim(Delimiter::Brace) {
+ } else if self.token == token::OpenBrace {
let (fields, recovered) = self.parse_record_struct_body(
"union",
ident.span,
@@ -1785,7 +1780,7 @@ pub(crate) fn parse_record_struct_body(
let mut fields = ThinVec::new();
let mut recovered = Recovered::No;
if self.eat(exp!(OpenBrace)) {
- while self.token != token::CloseDelim(Delimiter::Brace) {
+ while self.token != token::CloseBrace {
match self.parse_field_def(adt_ty) {
Ok(field) => {
fields.push(field);
@@ -1942,7 +1937,7 @@ fn parse_single_struct_field(
token::Comma => {
self.bump();
}
- token::CloseDelim(Delimiter::Brace) => {}
+ token::CloseBrace => {}
token::DocComment(..) => {
let previous_span = self.prev_token.span;
let mut err = errors::DocCommentDoesNotDocumentAnything {
@@ -1956,7 +1951,7 @@ fn parse_single_struct_field(
if !seen_comma && comma_after_doc_seen {
seen_comma = true;
}
- if comma_after_doc_seen || self.token == token::CloseDelim(Delimiter::Brace) {
+ if comma_after_doc_seen || self.token == token::CloseBrace {
self.dcx().emit_err(err);
} else {
if !seen_comma {
@@ -1994,7 +1989,7 @@ fn parse_single_struct_field(
if self.token.is_ident()
|| (self.token == TokenKind::Pound
- && (self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Bracket))))
+ && (self.look_ahead(1, |t| t == &token::OpenBracket)))
{
// This is likely another field, TokenKind::Pound is used for `#[..]`
// attribute for next field. Emit the diagnostic and continue parsing.
@@ -2303,7 +2298,7 @@ fn recover_nested_adt_item(&mut self, keyword: Symbol) -> PResult<'a, bool> {
|| self.token.is_keyword(kw::Union))
&& self.look_ahead(1, |t| t.is_ident())
{
- let kw_token = self.token.clone();
+ let kw_token = self.token;
let kw_str = pprust::token_to_string(&kw_token);
let item = self.parse_item(ForceCollect::No)?;
let mut item = item.unwrap().span;
@@ -2448,7 +2443,7 @@ fn error_fn_body_not_found(
match self.expected_one_of_not_found(&[], expected) {
Ok(error_guaranteed) => Ok(error_guaranteed),
Err(mut err) => {
- if self.token == token::CloseDelim(Delimiter::Brace) {
+ if self.token == token::CloseBrace {
// The enclosing `mod`, `trait` or `impl` is being closed, so keep the `fn` in
// the AST for typechecking.
err.span_label(ident_span, "while parsing this `fn`");
@@ -2536,7 +2531,7 @@ fn parse_fn_body(
self.expect_semi()?;
*sig_hi = self.prev_token.span;
(AttrVec::new(), None)
- } else if self.check(exp!(OpenBrace)) || self.token.is_whole_block() {
+ } else if self.check(exp!(OpenBrace)) || self.token.is_metavar_block() {
self.parse_block_common(self.token.span, BlockCheckMode::Default, None)
.map(|(attrs, body)| (attrs, Some(body)))?
} else if self.token == token::Eq {
@@ -2875,7 +2870,7 @@ pub(super) fn parse_fn_decl(
pub(super) fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, ThinVec<Param>> {
let mut first_param = true;
// Parse the arguments, starting out with `self` being allowed...
- if self.token != TokenKind::OpenDelim(Delimiter::Parenthesis)
+ if self.token != TokenKind::OpenParen
// might be typo'd trait impl, handled elsewhere
&& !self.token.is_keyword(kw::For)
{
@@ -2893,7 +2888,7 @@ pub(super) fn parse_fn_params(&mut self, req_name: ReqName) -> PResult<'a, ThinV
// When parsing a param failed, we should check to make the span of the param
// not contain '(' before it.
// For example when parsing `*mut Self` in function `fn oof(*mut Self)`.
- let lo = if let TokenKind::OpenDelim(Delimiter::Parenthesis) = p.prev_token.kind {
+ let lo = if let TokenKind::OpenParen = p.prev_token.kind {
p.prev_token.span.shrink_to_hi()
} else {
p.prev_token.span
@@ -2970,9 +2965,7 @@ fn parse_param_general(&mut self, req_name: ReqName, first_param: bool) -> PResu
}
}
- if this.token != token::Comma
- && this.token != token::CloseDelim(Delimiter::Parenthesis)
- {
+ if this.token != token::Comma && this.token != token::CloseParen {
// This wasn't actually a type, but a pattern looking like a type,
// so we are going to rollback and re-parse for recovery.
ty = this.unexpected_any();
@@ -3154,7 +3147,7 @@ fn parse_self_param(&mut self) -> PResult<'a, Option<Param>> {
fn is_named_param(&self) -> bool {
let offset = match &self.token.kind {
- token::OpenDelim(Delimiter::Invisible(origin)) => match origin {
+ token::OpenInvisible(origin) => match origin {
InvisibleOrigin::MetaVar(MetaVarKind::Pat(_)) => {
return self.check_noexpect_past_close_delim(&token::Colon);
}
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index fafd1b1..48df8b5 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -13,7 +13,6 @@
use std::assert_matches::debug_assert_matches;
use std::ops::Range;
-use std::sync::Arc;
use std::{fmt, mem, slice};
use attr_wrapper::{AttrWrapper, UsePreAttrPos};
@@ -24,8 +23,7 @@
use path::PathStyle;
use rustc_ast::ptr::P;
use rustc_ast::token::{
- self, Delimiter, IdentIsRaw, InvisibleOrigin, MetaVarKind, Nonterminal, NtExprKind, NtPatKind,
- Token, TokenKind,
+ self, IdentIsRaw, InvisibleOrigin, MetaVarKind, NtExprKind, NtPatKind, Token, TokenKind,
};
use rustc_ast::tokenstream::{AttrsTarget, Spacing, TokenStream, TokenTree};
use rustc_ast::util::case::Case;
@@ -45,11 +43,8 @@
pub use token_type::{ExpKeywordPair, ExpTokenPair, TokenType};
use tracing::debug;
-use crate::errors::{
- self, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral,
-};
+use crate::errors::{self, IncorrectVisibilityRestriction, NonStringAbiLiteral};
use crate::exp;
-use crate::lexer::UnmatchedDelim;
#[cfg(test)]
mod tests;
@@ -98,21 +93,6 @@ pub enum ForceCollect {
No,
}
-#[macro_export]
-macro_rules! maybe_whole {
- ($p:expr, $constructor:ident, |$x:ident| $e:expr) => {
- #[allow(irrefutable_let_patterns)] // FIXME: temporary
- if let token::Interpolated(nt) = &$p.token.kind
- && let token::$constructor(x) = &**nt
- {
- #[allow(unused_mut)]
- let mut $x = x.clone();
- $p.bump();
- return Ok($e);
- }
- };
-}
-
/// If the next tokens are ill-formed `$ty::` recover them as `<$ty>::`.
#[macro_export]
macro_rules! maybe_recover_from_interpolated_ty_qpath {
@@ -342,12 +322,9 @@ fn inlined_next(&mut self) -> (Token, Spacing) {
// below can be removed.
if let Some(tree) = self.curr.curr() {
match tree {
- &TokenTree::Token(ref token, spacing) => {
- debug_assert!(!matches!(
- token.kind,
- token::OpenDelim(_) | token::CloseDelim(_)
- ));
- let res = (token.clone(), spacing);
+ &TokenTree::Token(token, spacing) => {
+ debug_assert!(!token.kind.is_delim());
+ let res = (token, spacing);
self.curr.bump();
return res;
}
@@ -355,7 +332,7 @@ fn inlined_next(&mut self) -> (Token, Spacing) {
let trees = TokenTreeCursor::new(tts.clone());
self.stack.push(mem::replace(&mut self.curr, trees));
if !delim.skip() {
- return (Token::new(token::OpenDelim(delim), sp.open), spacing.open);
+ return (Token::new(delim.as_open_token_kind(), sp.open), spacing.open);
}
// No open delimiter to return; continue on to the next iteration.
}
@@ -368,7 +345,7 @@ fn inlined_next(&mut self) -> (Token, Spacing) {
self.curr = parent;
self.curr.bump(); // move past the `Delimited`
if !delim.skip() {
- return (Token::new(token::CloseDelim(delim), span.close), spacing.close);
+ return (Token::new(delim.as_close_token_kind(), span.close), spacing.close);
}
// No close delimiter to return; continue on to the next iteration.
} else {
@@ -439,7 +416,7 @@ pub(super) fn from_token(token: &Token) -> Option<Self> {
_ if token.is_used_keyword() => Some(TokenDescription::Keyword),
_ if token.is_unused_keyword() => Some(TokenDescription::ReservedKeyword),
token::DocComment(..) => Some(TokenDescription::DocComment),
- token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => {
+ token::OpenInvisible(InvisibleOrigin::MetaVar(kind)) => {
Some(TokenDescription::MetaVar(kind))
}
_ => None,
@@ -459,7 +436,6 @@ pub fn token_descr(token: &Token) -> String {
(Some(TokenDescription::MetaVar(kind)), _) => format!("`{kind}` metavariable"),
(None, TokenKind::NtIdent(..)) => format!("identifier `{s}`"),
(None, TokenKind::NtLifetime(..)) => format!("lifetime `{s}`"),
- (None, TokenKind::Interpolated(node)) => format!("{} `{s}`", node.descr()),
(None, _) => format!("`{s}`"),
}
}
@@ -637,9 +613,8 @@ fn check_noexpect(&self, tok: &TokenKind) -> bool {
// past the entire `TokenTree::Delimited` in a single step, avoiding the
// need for unbounded token lookahead.
//
- // Primarily used when `self.token` matches
- // `OpenDelim(Delimiter::Invisible(_))`, to look ahead through the current
- // metavar expansion.
+ // Primarily used when `self.token` matches `OpenInvisible(_))`, to look
+ // ahead through the current metavar expansion.
fn check_noexpect_past_close_delim(&self, tok: &TokenKind) -> bool {
let mut tree_cursor = self.token_cursor.stack.last().unwrap().clone();
tree_cursor.bump();
@@ -773,8 +748,7 @@ fn eat_metavar_seq_with_matcher<T>(
match_mv_kind: impl Fn(MetaVarKind) -> bool,
mut f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
) -> Option<T> {
- if let token::OpenDelim(delim) = self.token.kind
- && let Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)) = delim
+ if let token::OpenInvisible(InvisibleOrigin::MetaVar(mv_kind)) = self.token.kind
&& match_mv_kind(mv_kind)
{
self.bump();
@@ -793,8 +767,7 @@ fn eat_metavar_seq_with_matcher<T>(
}
};
- if let token::CloseDelim(delim) = self.token.kind
- && let Delimiter::Invisible(InvisibleOrigin::MetaVar(mv_kind)) = delim
+ if let token::CloseInvisible(InvisibleOrigin::MetaVar(mv_kind)) = self.token.kind
&& match_mv_kind(mv_kind)
{
self.bump();
@@ -855,8 +828,8 @@ fn check_const_closure(&self) -> bool {
fn check_inline_const(&self, dist: usize) -> bool {
self.is_keyword_ahead(dist, &[kw::Const])
&& self.look_ahead(dist + 1, |t| match &t.kind {
- token::Interpolated(nt) => matches!(&**nt, token::NtBlock(..)),
- token::OpenDelim(Delimiter::Brace) => true,
+ token::OpenBrace => true,
+ token::OpenInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Block)) => true,
_ => false,
})
}
@@ -975,7 +948,7 @@ fn parse_seq_to_before_tokens<T>(
let mut v = ThinVec::new();
while !self.expect_any_with_type(closes_expected, closes_not_expected) {
- if let token::CloseDelim(..) | token::Eof = self.token.kind {
+ if self.token.kind.is_close_delim_or_eof() {
break;
}
if let Some(exp) = sep.sep {
@@ -1259,7 +1232,7 @@ pub fn bump(&mut self) {
}
debug_assert!(!matches!(
next.0.kind,
- token::OpenDelim(delim) | token::CloseDelim(delim) if delim.skip()
+ token::OpenInvisible(origin) | token::CloseInvisible(origin) if origin.skip()
));
self.inlined_bump_with(next)
}
@@ -1284,7 +1257,7 @@ pub fn look_ahead<R>(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R
TokenTree::Token(token, _) => return looker(token),
&TokenTree::Delimited(dspan, _, delim, _) => {
if !delim.skip() {
- return looker(&Token::new(token::OpenDelim(delim), dspan.open));
+ return looker(&Token::new(delim.as_open_token_kind(), dspan.open));
}
}
}
@@ -1298,7 +1271,7 @@ pub fn look_ahead<R>(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R
{
// We are not in the outermost token stream, so we have
// delimiters. Also, those delimiters are not skipped.
- return looker(&Token::new(token::CloseDelim(delim), span.close));
+ return looker(&Token::new(delim.as_close_token_kind(), span.close));
}
}
}
@@ -1313,7 +1286,7 @@ pub fn look_ahead<R>(&self, dist: usize, looker: impl FnOnce(&Token) -> R) -> R
token = cursor.next().0;
if matches!(
token.kind,
- token::OpenDelim(delim) | token::CloseDelim(delim) if delim.skip()
+ token::OpenInvisible(origin) | token::CloseInvisible(origin) if origin.skip()
) {
continue;
}
@@ -1401,8 +1374,7 @@ fn parse_closure_constness(&mut self) -> Const {
fn parse_constness_(&mut self, case: Case, is_closure: bool) -> Const {
// Avoid const blocks and const closures to be parsed as const items
if (self.check_const_closure() == is_closure)
- && !self
- .look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Brace) || t.is_whole_block())
+ && !self.look_ahead(1, |t| *t == token::OpenBrace || t.is_metavar_block())
&& self.eat_keyword_case(exp!(Const), case)
{
Const::Yes(self.prev_token_uninterpolated_span())
@@ -1501,48 +1473,46 @@ fn parse_delim_args_inner(&mut self) -> Option<DelimArgs> {
/// Parses a single token tree from the input.
pub fn parse_token_tree(&mut self) -> TokenTree {
- match self.token.kind {
- token::OpenDelim(..) => {
- // Clone the `TokenTree::Delimited` that we are currently
- // within. That's what we are going to return.
- let tree = self.token_cursor.stack.last().unwrap().curr().unwrap().clone();
- debug_assert_matches!(tree, TokenTree::Delimited(..));
+ if self.token.kind.open_delim().is_some() {
+ // Clone the `TokenTree::Delimited` that we are currently
+ // within. That's what we are going to return.
+ let tree = self.token_cursor.stack.last().unwrap().curr().unwrap().clone();
+ debug_assert_matches!(tree, TokenTree::Delimited(..));
- // Advance the token cursor through the entire delimited
- // sequence. After getting the `OpenDelim` we are *within* the
- // delimited sequence, i.e. at depth `d`. After getting the
- // matching `CloseDelim` we are *after* the delimited sequence,
- // i.e. at depth `d - 1`.
- let target_depth = self.token_cursor.stack.len() - 1;
- loop {
- // Advance one token at a time, so `TokenCursor::next()`
- // can capture these tokens if necessary.
- self.bump();
- if self.token_cursor.stack.len() == target_depth {
- debug_assert_matches!(self.token.kind, token::CloseDelim(_));
- break;
- }
+ // Advance the token cursor through the entire delimited
+ // sequence. After getting the `OpenDelim` we are *within* the
+ // delimited sequence, i.e. at depth `d`. After getting the
+ // matching `CloseDelim` we are *after* the delimited sequence,
+ // i.e. at depth `d - 1`.
+ let target_depth = self.token_cursor.stack.len() - 1;
+ loop {
+ // Advance one token at a time, so `TokenCursor::next()`
+ // can capture these tokens if necessary.
+ self.bump();
+ if self.token_cursor.stack.len() == target_depth {
+ debug_assert!(self.token.kind.close_delim().is_some());
+ break;
}
+ }
- // Consume close delimiter
- self.bump();
- tree
- }
- token::CloseDelim(_) | token::Eof => unreachable!(),
- _ => {
- let prev_spacing = self.token_spacing;
- self.bump();
- TokenTree::Token(self.prev_token.clone(), prev_spacing)
- }
+ // Consume close delimiter
+ self.bump();
+ tree
+ } else {
+ assert!(!self.token.kind.is_close_delim_or_eof());
+ let prev_spacing = self.token_spacing;
+ self.bump();
+ TokenTree::Token(self.prev_token, prev_spacing)
}
}
pub fn parse_tokens(&mut self) -> TokenStream {
let mut result = Vec::new();
loop {
- match self.token.kind {
- token::Eof | token::CloseDelim(..) => break,
- _ => result.push(self.parse_token_tree()),
+ if self.token.kind.is_close_delim_or_eof() {
+ break;
+ } else {
+ result.push(self.parse_token_tree());
}
}
TokenStream::new(result)
@@ -1605,7 +1575,7 @@ pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibilit
kind: vis,
tokens: None,
});
- } else if self.look_ahead(2, |t| t == &token::CloseDelim(Delimiter::Parenthesis))
+ } else if self.look_ahead(2, |t| t == &token::CloseParen)
&& self.is_keyword_ahead(1, &[kw::Crate, kw::Super, kw::SelfLower])
{
// Parse `pub(crate)`, `pub(self)`, or `pub(super)`.
@@ -1702,9 +1672,7 @@ fn check_path_sep_and_look_ahead(&mut self, looker: impl Fn(&Token) -> bool) ->
/// `::{` or `::*`
fn is_import_coupler(&mut self) -> bool {
- self.check_path_sep_and_look_ahead(|t| {
- matches!(t.kind, token::OpenDelim(Delimiter::Brace) | token::Star)
- })
+ self.check_path_sep_and_look_ahead(|t| matches!(t.kind, token::OpenBrace | token::Star))
}
// Debug view of the parser's token stream, up to `{lookahead}` tokens.
@@ -1718,7 +1686,7 @@ pub(crate) fn debug_lookahead(&self, lookahead: usize) -> impl fmt::Debug {
dbg_fmt.field("prev_token", &self.prev_token);
let mut tokens = vec![];
for i in 0..lookahead {
- let tok = self.look_ahead(i, |tok| tok.kind.clone());
+ let tok = self.look_ahead(i, |tok| tok.kind);
let is_eof = tok == TokenKind::Eof;
tokens.push(tok);
if is_eof {
@@ -1759,10 +1727,7 @@ pub fn approx_token_stream_pos(&self) -> u32 {
pub fn token_uninterpolated_span(&self) -> Span {
match &self.token.kind {
token::NtIdent(ident, _) | token::NtLifetime(ident, _) => ident.span,
- token::Interpolated(nt) => nt.use_span(),
- token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => {
- self.look_ahead(1, |t| t.span)
- }
+ token::OpenInvisible(InvisibleOrigin::MetaVar(_)) => self.look_ahead(1, |t| t.span),
_ => self.token.span,
}
}
@@ -1771,36 +1736,12 @@ pub fn token_uninterpolated_span(&self) -> Span {
pub fn prev_token_uninterpolated_span(&self) -> Span {
match &self.prev_token.kind {
token::NtIdent(ident, _) | token::NtLifetime(ident, _) => ident.span,
- token::Interpolated(nt) => nt.use_span(),
- token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => {
- self.look_ahead(0, |t| t.span)
- }
+ token::OpenInvisible(InvisibleOrigin::MetaVar(_)) => self.look_ahead(0, |t| t.span),
_ => self.prev_token.span,
}
}
}
-pub(crate) fn make_unclosed_delims_error(
- unmatched: UnmatchedDelim,
- psess: &ParseSess,
-) -> Option<Diag<'_>> {
- // `None` here means an `Eof` was found. We already emit those errors elsewhere, we add them to
- // `unmatched_delims` only for error recovery in the `Parser`.
- let found_delim = unmatched.found_delim?;
- let mut spans = vec![unmatched.found_span];
- if let Some(sp) = unmatched.unclosed_span {
- spans.push(sp);
- };
- let err = psess.dcx().create_err(MismatchedClosingDelimiter {
- spans,
- delimiter: pprust::token_kind_to_string(&token::CloseDelim(found_delim)).to_string(),
- unmatched: unmatched.found_span,
- opening_candidate: unmatched.candidate_span,
- unclosed: unmatched.unclosed_span,
- });
- Some(err)
-}
-
/// A helper struct used when building an `AttrTokenStream` from
/// a `LazyAttrTokenStream`. Both delimiter and non-delimited tokens
/// are stored as `FlatToken::Token`. A vector of `FlatToken`s
@@ -1828,6 +1769,7 @@ pub enum ParseNtResult {
Ident(Ident, IdentIsRaw),
Lifetime(Ident, IdentIsRaw),
Item(P<ast::Item>),
+ Block(P<ast::Block>),
Stmt(P<ast::Stmt>),
Pat(P<ast::Pat>, NtPatKind),
Expr(P<ast::Expr>, NtExprKind),
@@ -1836,7 +1778,4 @@ pub enum ParseNtResult {
Meta(P<ast::AttrItem>),
Path(P<ast::Path>),
Vis(P<ast::Visibility>),
-
- /// This variant will eventually be removed, along with `Token::Interpolate`.
- Nt(Arc<Nonterminal>),
}
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index b4e540d..7c83e96 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -1,14 +1,7 @@
-use std::sync::Arc;
-
-use rustc_ast::HasTokens;
use rustc_ast::ptr::P;
-use rustc_ast::token::Nonterminal::*;
use rustc_ast::token::NtExprKind::*;
use rustc_ast::token::NtPatKind::*;
-use rustc_ast::token::{
- self, Delimiter, InvisibleOrigin, MetaVarKind, Nonterminal, NonterminalKind, Token,
-};
-use rustc_ast_pretty::pprust;
+use rustc_ast::token::{self, InvisibleOrigin, MetaVarKind, NonterminalKind, Token};
use rustc_errors::PResult;
use rustc_span::{Ident, kw};
@@ -45,13 +38,6 @@ fn may_be_ident(kind: MetaVarKind) -> bool {
}
}
- /// Old variant of `may_be_ident`. Being phased out.
- fn nt_may_be_ident(nt: &Nonterminal) -> bool {
- match nt {
- NtBlock(_) => false,
- }
- }
-
match kind {
// `expr_2021` and earlier
NonterminalKind::Expr(Expr2021 { .. }) => {
@@ -83,17 +69,13 @@ fn nt_may_be_ident(nt: &Nonterminal) -> bool {
| token::Ident(..)
| token::NtIdent(..)
| token::NtLifetime(..)
- | token::Interpolated(_)
- | token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(_))) => true,
+ | token::OpenInvisible(InvisibleOrigin::MetaVar(_)) => true,
_ => token.can_begin_type(),
},
NonterminalKind::Block => match &token.kind {
- token::OpenDelim(Delimiter::Brace) => true,
+ token::OpenBrace => true,
token::NtLifetime(..) => true,
- token::Interpolated(nt) => match &**nt {
- NtBlock(_) => true,
- },
- token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(k))) => match k {
+ token::OpenInvisible(InvisibleOrigin::MetaVar(k)) => match k {
MetaVarKind::Block
| MetaVarKind::Stmt
| MetaVarKind::Expr { .. }
@@ -112,10 +94,7 @@ fn nt_may_be_ident(nt: &Nonterminal) -> bool {
},
NonterminalKind::Path | NonterminalKind::Meta => match &token.kind {
token::PathSep | token::Ident(..) | token::NtIdent(..) => true,
- token::Interpolated(nt) => nt_may_be_ident(nt),
- token::OpenDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(kind))) => {
- may_be_ident(*kind)
- }
+ token::OpenInvisible(InvisibleOrigin::MetaVar(kind)) => may_be_ident(*kind),
_ => false,
},
NonterminalKind::Pat(pat_kind) => token.can_begin_pattern(pat_kind),
@@ -124,7 +103,7 @@ fn nt_may_be_ident(nt: &Nonterminal) -> bool {
_ => false,
},
NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => {
- !matches!(token.kind, token::CloseDelim(_))
+ token.kind.close_delim().is_none()
}
}
}
@@ -136,110 +115,85 @@ pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseN
// A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
// which requires having captured tokens available. Since we cannot determine
// in advance whether or not a proc-macro will be (transitively) invoked,
- // we always capture tokens for any `Nonterminal` which needs them.
- let mut nt = match kind {
+ // we always capture tokens for any nonterminal that needs them.
+ match kind {
// Note that TT is treated differently to all the others.
- NonterminalKind::TT => return Ok(ParseNtResult::Tt(self.parse_token_tree())),
+ NonterminalKind::TT => Ok(ParseNtResult::Tt(self.parse_token_tree())),
NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? {
- Some(item) => return Ok(ParseNtResult::Item(item)),
- None => {
- return Err(self
- .dcx()
- .create_err(UnexpectedNonterminal::Item(self.token.span)));
- }
+ Some(item) => Ok(ParseNtResult::Item(item)),
+ None => Err(self.dcx().create_err(UnexpectedNonterminal::Item(self.token.span))),
},
NonterminalKind::Block => {
// While a block *expression* may have attributes (e.g. `#[my_attr] { ... }`),
// the ':block' matcher does not support them
- NtBlock(self.collect_tokens_no_attrs(|this| this.parse_block())?)
+ Ok(ParseNtResult::Block(self.collect_tokens_no_attrs(|this| this.parse_block())?))
}
NonterminalKind::Stmt => match self.parse_stmt(ForceCollect::Yes)? {
- Some(stmt) => return Ok(ParseNtResult::Stmt(P(stmt))),
+ Some(stmt) => Ok(ParseNtResult::Stmt(P(stmt))),
None => {
- return Err(self
- .dcx()
- .create_err(UnexpectedNonterminal::Statement(self.token.span)));
+ Err(self.dcx().create_err(UnexpectedNonterminal::Statement(self.token.span)))
}
},
- NonterminalKind::Pat(pat_kind) => {
- return Ok(ParseNtResult::Pat(
- self.collect_tokens_no_attrs(|this| match pat_kind {
- PatParam { .. } => this.parse_pat_no_top_alt(None, None),
- PatWithOr => this.parse_pat_no_top_guard(
- None,
- RecoverComma::No,
- RecoverColon::No,
- CommaRecoveryMode::EitherTupleOrPipe,
- ),
- })?,
- pat_kind,
- ));
- }
+ NonterminalKind::Pat(pat_kind) => Ok(ParseNtResult::Pat(
+ self.collect_tokens_no_attrs(|this| match pat_kind {
+ PatParam { .. } => this.parse_pat_no_top_alt(None, None),
+ PatWithOr => this.parse_pat_no_top_guard(
+ None,
+ RecoverComma::No,
+ RecoverColon::No,
+ CommaRecoveryMode::EitherTupleOrPipe,
+ ),
+ })?,
+ pat_kind,
+ )),
NonterminalKind::Expr(expr_kind) => {
- return Ok(ParseNtResult::Expr(self.parse_expr_force_collect()?, expr_kind));
+ Ok(ParseNtResult::Expr(self.parse_expr_force_collect()?, expr_kind))
}
NonterminalKind::Literal => {
// The `:literal` matcher does not support attributes.
- return Ok(ParseNtResult::Literal(
+ Ok(ParseNtResult::Literal(
self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?,
- ));
+ ))
}
- NonterminalKind::Ty => {
- return Ok(ParseNtResult::Ty(
- self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?,
- ));
- }
- // this could be handled like a token, since it is one
+ NonterminalKind::Ty => Ok(ParseNtResult::Ty(
+ self.collect_tokens_no_attrs(|this| this.parse_ty_no_question_mark_recover())?,
+ )),
+ // This could be handled like a token, since it is one.
NonterminalKind::Ident => {
- return if let Some((ident, is_raw)) = get_macro_ident(&self.token) {
+ if let Some((ident, is_raw)) = get_macro_ident(&self.token) {
self.bump();
Ok(ParseNtResult::Ident(ident, is_raw))
} else {
Err(self.dcx().create_err(UnexpectedNonterminal::Ident {
span: self.token.span,
- token: self.token.clone(),
+ token: self.token,
}))
- };
+ }
}
- NonterminalKind::Path => {
- return Ok(ParseNtResult::Path(P(
- self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?
- )));
- }
+ NonterminalKind::Path => Ok(ParseNtResult::Path(P(
+ self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?
+ ))),
NonterminalKind::Meta => {
- return Ok(ParseNtResult::Meta(P(self.parse_attr_item(ForceCollect::Yes)?)));
+ Ok(ParseNtResult::Meta(P(self.parse_attr_item(ForceCollect::Yes)?)))
}
NonterminalKind::Vis => {
- return Ok(ParseNtResult::Vis(P(self.collect_tokens_no_attrs(|this| {
- this.parse_visibility(FollowedByType::Yes)
- })?)));
+ Ok(ParseNtResult::Vis(P(self
+ .collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?)))
}
NonterminalKind::Lifetime => {
// We want to keep `'keyword` parsing, just like `keyword` is still
// an ident for nonterminal purposes.
- return if let Some((ident, is_raw)) = self.token.lifetime() {
+ if let Some((ident, is_raw)) = self.token.lifetime() {
self.bump();
Ok(ParseNtResult::Lifetime(ident, is_raw))
} else {
Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime {
span: self.token.span,
- token: self.token.clone(),
+ token: self.token,
}))
- };
+ }
}
- };
-
- // If tokens are supported at all, they should be collected.
- if matches!(nt.tokens_mut(), Some(None)) {
- panic!(
- "Missing tokens for nt {:?} at {:?}: {:?}",
- nt,
- nt.use_span(),
- pprust::nonterminal_to_string(&nt)
- );
}
-
- Ok(ParseNtResult::Nt(Arc::new(nt)))
}
}
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 9612f71..d6ff80b 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -3,7 +3,7 @@
use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_ast::ptr::P;
use rustc_ast::token::NtPatKind::*;
-use rustc_ast::token::{self, Delimiter, IdentIsRaw, MetaVarKind, Token};
+use rustc_ast::token::{self, IdentIsRaw, MetaVarKind, Token};
use rustc_ast::util::parser::ExprPrecedence;
use rustc_ast::visit::{self, Visitor};
use rustc_ast::{
@@ -323,7 +323,7 @@ pub(super) fn parse_fn_param_pat_colon(&mut self) -> PResult<'a, (P<Pat>, bool)>
fn eat_or_separator(&mut self, lo: Option<Span>) -> EatOrResult {
if self.recover_trailing_vert(lo) {
EatOrResult::TrailingVert
- } else if matches!(self.token.kind, token::OrOr) {
+ } else if self.token.kind == token::OrOr {
// Found `||`; Recover and pretend we parsed `|`.
self.dcx().emit_err(UnexpectedVertVertInPattern { span: self.token.span, start: lo });
self.bump();
@@ -352,9 +352,9 @@ fn recover_trailing_vert(&mut self, lo: Option<Span>) -> bool {
| token::Semi // e.g. `let a |;`.
| token::Colon // e.g. `let a | :`.
| token::Comma // e.g. `let (a |,)`.
- | token::CloseDelim(Delimiter::Bracket) // e.g. `let [a | ]`.
- | token::CloseDelim(Delimiter::Parenthesis) // e.g. `let (a | )`.
- | token::CloseDelim(Delimiter::Brace) // e.g. `let A { f: a | }`.
+ | token::CloseBracket // e.g. `let [a | ]`.
+ | token::CloseParen // e.g. `let (a | )`.
+ | token::CloseBrace // e.g. `let A { f: a | }`.
)
});
match (is_end_ahead, &self.token.kind) {
@@ -363,8 +363,8 @@ fn recover_trailing_vert(&mut self, lo: Option<Span>) -> bool {
self.dcx().emit_err(TrailingVertNotAllowed {
span: self.token.span,
start: lo,
- token: self.token.clone(),
- note_double_vert: matches!(self.token.kind, token::OrOr),
+ token: self.token,
+ note_double_vert: self.token.kind == token::OrOr,
});
self.bump();
true
@@ -438,8 +438,8 @@ fn maybe_recover_trailing_expr(
| token::Caret | token::And | token::Shl | token::Shr // excludes `Or`
)
|| self.token == token::Question
- || (self.token == token::OpenDelim(Delimiter::Bracket)
- && self.look_ahead(1, |t| *t != token::CloseDelim(Delimiter::Bracket))) // excludes `[]`
+ || (self.token == token::OpenBracket
+ && self.look_ahead(1, |t| *t != token::CloseBracket)) // excludes `[]`
|| self.token.is_keyword(kw::As);
if !has_dot_expr && !has_trailing_operator {
@@ -481,7 +481,7 @@ fn maybe_recover_trailing_expr(
let is_bound = is_end_bound
// is_start_bound: either `..` or `)..`
|| self.token.is_range_separator()
- || self.token == token::CloseDelim(Delimiter::Parenthesis)
+ || self.token == token::CloseParen
&& self.look_ahead(1, Token::is_range_separator);
let span = expr.span;
@@ -835,7 +835,7 @@ fn parse_pat_with_range_pat(
// because we never have `'a: label {}` in a pattern position anyways, but it does
// keep us from suggesting something like `let 'a: Ty = ..` => `let 'a': Ty = ..`
&& could_be_unclosed_char_literal(lt)
- && !self.look_ahead(1, |token| matches!(token.kind, token::Colon))
+ && !self.look_ahead(1, |token| token.kind == token::Colon)
{
// Recover a `'a` as a `'a'` literal
let lt = self.expect_lifetime();
@@ -1255,8 +1255,8 @@ fn is_pat_range_end_start(&self, dist: usize) -> bool {
|| t.is_metavar_expr()
|| t.is_lifetime() // recover `'a` instead of `'a'`
|| (self.may_recover() // recover leading `(`
- && *t == token::OpenDelim(Delimiter::Parenthesis)
- && self.look_ahead(dist + 1, |t| *t != token::OpenDelim(Delimiter::Parenthesis))
+ && *t == token::OpenParen
+ && self.look_ahead(dist + 1, |t| *t != token::OpenParen)
&& self.is_pat_range_end_start(dist + 1))
})
}
@@ -1264,9 +1264,8 @@ fn is_pat_range_end_start(&self, dist: usize) -> bool {
/// Parse a range pattern end bound
fn parse_pat_range_end(&mut self) -> PResult<'a, P<Expr>> {
// recover leading `(`
- let open_paren = (self.may_recover()
- && self.eat_noexpect(&token::OpenDelim(Delimiter::Parenthesis)))
- .then_some(self.prev_token.span);
+ let open_paren = (self.may_recover() && self.eat_noexpect(&token::OpenParen))
+ .then_some(self.prev_token.span);
let bound = if self.check_inline_const(0) {
self.parse_const_block(self.token.span, true)
@@ -1322,8 +1321,8 @@ fn can_be_ident_pat(&mut self) -> bool {
// Avoid `in`. Due to recovery in the list parser this messes with `for ( $pat in $expr )`.
&& !self.token.is_keyword(kw::In)
// Try to do something more complex?
- && self.look_ahead(1, |t| !matches!(t.kind, token::OpenDelim(Delimiter::Parenthesis) // A tuple struct pattern.
- | token::OpenDelim(Delimiter::Brace) // A struct pattern.
+ && self.look_ahead(1, |t| !matches!(t.kind, token::OpenParen // A tuple struct pattern.
+ | token::OpenBrace // A struct pattern.
| token::DotDotDot | token::DotDotEq | token::DotDot // A range pattern.
| token::PathSep // A tuple / struct variant pattern.
| token::Bang)) // A macro expanding to a pattern.
@@ -1361,7 +1360,7 @@ fn parse_pat_ident(
// This shortly leads to a parse error. Note that if there is no explicit
// binding mode then we do not end up here, because the lookahead
// will direct us over to `parse_enum_variant()`.
- if self.token == token::OpenDelim(Delimiter::Parenthesis) {
+ if self.token == token::OpenParen {
return Err(self
.dcx()
.create_err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span }));
@@ -1429,9 +1428,9 @@ fn isnt_pattern_start(&self) -> bool {
token::Comma,
token::Semi,
token::At,
- token::OpenDelim(Delimiter::Brace),
- token::CloseDelim(Delimiter::Brace),
- token::CloseDelim(Delimiter::Parenthesis),
+ token::OpenBrace,
+ token::CloseBrace,
+ token::CloseParen,
]
.contains(&self.token.kind)
}
@@ -1489,7 +1488,7 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (ThinVec<PatField>, PatFieldsRest)
let mut first_etc_and_maybe_comma_span = None;
let mut last_non_comma_dotdot_span = None;
- while self.token != token::CloseDelim(Delimiter::Brace) {
+ while self.token != token::CloseBrace {
// check that a comma comes after every field
if !ate_comma {
let err = if self.token == token::At {
@@ -1519,8 +1518,8 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (ThinVec<PatField>, PatFieldsRest)
etc = PatFieldsRest::Rest;
let mut etc_sp = self.token.span;
if first_etc_and_maybe_comma_span.is_none() {
- if let Some(comma_tok) = self
- .look_ahead(1, |t| if *t == token::Comma { Some(t.clone()) } else { None })
+ if let Some(comma_tok) =
+ self.look_ahead(1, |&t| if t == token::Comma { Some(t) } else { None })
{
let nw_span = self
.psess
@@ -1538,7 +1537,7 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (ThinVec<PatField>, PatFieldsRest)
self.recover_bad_dot_dot();
self.bump(); // `..` || `...` || `_`
- if self.token == token::CloseDelim(Delimiter::Brace) {
+ if self.token == token::CloseBrace {
break;
}
let token_str = super::token_descr(&self.token);
@@ -1561,7 +1560,7 @@ fn parse_pat_fields(&mut self) -> PResult<'a, (ThinVec<PatField>, PatFieldsRest)
ate_comma = true;
}
- if self.token == token::CloseDelim(Delimiter::Brace) {
+ if self.token == token::CloseBrace {
// If the struct looks otherwise well formed, recover and continue.
if let Some(sp) = comma_sp {
err.span_suggestion_short(
@@ -1681,7 +1680,7 @@ fn recover_misplaced_pattern_modifiers(&self, fields: &ThinVec<PatField>, err: &
// We found `ref mut? ident:`, try to parse a `name,` or `name }`.
&& let Some(name_span) = self.look_ahead(1, |t| t.is_ident().then(|| t.span))
&& self.look_ahead(2, |t| {
- t == &token::Comma || t == &token::CloseDelim(Delimiter::Brace)
+ t == &token::Comma || t == &token::CloseBrace
})
{
let span = last.pat.span.with_hi(ident.span.lo());
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 9c6830c..1a02d45 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -2,7 +2,7 @@
use ast::token::IdentIsRaw;
use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, MetaVarKind, Token, TokenKind};
+use rustc_ast::token::{self, MetaVarKind, Token, TokenKind};
use rustc_ast::{
self as ast, AngleBracketedArg, AngleBracketedArgs, AnonConst, AssocItemConstraint,
AssocItemConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
@@ -273,7 +273,6 @@ pub(super) fn parse_path_segments(
self.dcx().emit_err(PathSingleColon {
span: self.prev_token.span,
suggestion: self.prev_token.span.shrink_to_hi(),
- type_ascription: self.psess.unstable_features.is_nightly_build(),
});
}
continue;
@@ -303,10 +302,7 @@ pub(super) fn parse_path_segment(
) -> PResult<'a, PathSegment> {
let ident = self.parse_path_segment_ident()?;
let is_args_start = |token: &Token| {
- matches!(
- token.kind,
- token::Lt | token::Shl | token::OpenDelim(Delimiter::Parenthesis) | token::LArrow
- )
+ matches!(token.kind, token::Lt | token::Shl | token::OpenParen | token::LArrow)
};
let check_args_start = |this: &mut Self| {
this.expected_token_types.insert(TokenType::Lt);
@@ -348,7 +344,6 @@ pub(super) fn parse_path_segment(
err = self.dcx().create_err(PathSingleColon {
span: self.token.span,
suggestion: self.prev_token.span.shrink_to_hi(),
- type_ascription: self.psess.unstable_features.is_nightly_build(),
});
}
// Attempt to find places where a missing `>` might belong.
@@ -368,7 +363,7 @@ pub(super) fn parse_path_segment(
})?;
let span = lo.to(self.prev_token.span);
AngleBracketedArgs { args, span }.into()
- } else if self.token == token::OpenDelim(Delimiter::Parenthesis)
+ } else if self.token == token::OpenParen
// FIXME(return_type_notation): Could also recover `...` here.
&& self.look_ahead(1, |t| *t == token::DotDot)
{
@@ -393,8 +388,8 @@ pub(super) fn parse_path_segment(
} else {
// `(T, U) -> R`
- let prev_token_before_parsing = self.prev_token.clone();
- let token_before_parsing = self.token.clone();
+ let prev_token_before_parsing = self.prev_token;
+ let token_before_parsing = self.token;
let mut snapshot = None;
if self.may_recover()
&& prev_token_before_parsing == token::PathSep
@@ -854,7 +849,7 @@ pub(super) fn expr_is_valid_const_arg(&self, expr: &P<rustc_ast::Expr>) -> bool
/// the caller.
pub(super) fn parse_const_arg(&mut self) -> PResult<'a, AnonConst> {
// Parse const argument.
- let value = if let token::OpenDelim(Delimiter::Brace) = self.token.kind {
+ let value = if self.token.kind == token::OpenBrace {
self.parse_expr_block(None, self.token.span, BlockCheckMode::Default)?
} else {
self.handle_unambiguous_unbraced_const_arg()?
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index e00fd40..885a65d 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -23,8 +23,8 @@
AttrWrapper, BlockMode, FnParseMode, ForceCollect, Parser, Restrictions, SemiColonMode,
Trailing, UsePreAttrPos,
};
-use crate::errors::MalformedLoopLabel;
-use crate::{errors, exp, maybe_whole};
+use crate::errors::{self, MalformedLoopLabel};
+use crate::exp;
impl<'a> Parser<'a> {
/// Parses a statement. This stops just before trailing semicolons on everything but items.
@@ -162,7 +162,7 @@ pub fn parse_stmt_without_recovery(
// Do not attempt to parse an expression if we're done here.
self.error_outer_attrs(attrs);
self.mk_stmt(lo, StmtKind::Empty)
- } else if self.token != token::CloseDelim(Delimiter::Brace) {
+ } else if self.token != token::CloseBrace {
// Remainder are line-expr stmts. This is similar to the `parse_stmt_path_start` case
// above.
let restrictions =
@@ -254,9 +254,7 @@ fn parse_stmt_mac(&mut self, lo: Span, attrs: AttrVec, path: ast::Path) -> PResu
self.token.kind,
token::Semi
| token::Eof
- | token::CloseDelim(Delimiter::Invisible(InvisibleOrigin::MetaVar(
- MetaVarKind::Stmt
- )))
+ | token::CloseInvisible(InvisibleOrigin::MetaVar(MetaVarKind::Stmt))
) {
StmtKind::MacCall(P(MacCallStmt { mac, style, attrs, tokens: None }))
} else {
@@ -518,7 +516,11 @@ fn error_block_no_opening_brace_msg(&mut self, msg: Cow<'static, str>) -> Diag<'
let prev = self.prev_token.span;
let sp = self.token.span;
let mut e = self.dcx().struct_span_err(sp, msg);
- let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon;
+ self.label_expected_raw_ref(&mut e);
+
+ let do_not_suggest_help = self.token.is_keyword(kw::In)
+ || self.token == token::Colon
+ || self.prev_token.is_keyword(kw::Raw);
// Check to see if the user has written something like
//
@@ -543,7 +545,7 @@ fn error_block_no_opening_brace_msg(&mut self, msg: Cow<'static, str>) -> Diag<'
// + +
Ok(Some(_))
if (!self.token.is_keyword(kw::Else)
- && self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace)))
+ && self.look_ahead(1, |t| t == &token::OpenBrace))
|| do_not_suggest_help => {}
// Do not suggest `if foo println!("") {;}` (as would be seen in test for #46836).
Ok(Some(Stmt { kind: StmtKind::Empty, .. })) => {}
@@ -580,9 +582,7 @@ fn suggest_fixes_misparsed_for_loop_head(
stmt_kind: &StmtKind,
) {
match (&self.token.kind, &stmt_kind) {
- (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
- if let ExprKind::Call(..) = expr.kind =>
- {
+ (token::OpenBrace, StmtKind::Expr(expr)) if let ExprKind::Call(..) = expr.kind => {
// for _ in x y() {}
e.span_suggestion_verbose(
between,
@@ -591,9 +591,7 @@ fn suggest_fixes_misparsed_for_loop_head(
Applicability::MaybeIncorrect,
);
}
- (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
- if let ExprKind::Field(..) = expr.kind =>
- {
+ (token::OpenBrace, StmtKind::Expr(expr)) if let ExprKind::Field(..) = expr.kind => {
// for _ in x y.z {}
e.span_suggestion_verbose(
between,
@@ -602,7 +600,7 @@ fn suggest_fixes_misparsed_for_loop_head(
Applicability::MaybeIncorrect,
);
}
- (token::CloseDelim(Delimiter::Brace), StmtKind::Expr(expr))
+ (token::CloseBrace, StmtKind::Expr(expr))
if let ExprKind::Struct(expr) = &expr.kind
&& let None = expr.qself
&& expr.path.segments.len() == 1 =>
@@ -617,7 +615,7 @@ fn suggest_fixes_misparsed_for_loop_head(
Applicability::MaybeIncorrect,
);
}
- (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
+ (token::OpenBrace, StmtKind::Expr(expr))
if let ExprKind::Lit(lit) = expr.kind
&& let None = lit.suffix
&& let token::LitKind::Integer | token::LitKind::Float = lit.kind =>
@@ -631,7 +629,7 @@ fn suggest_fixes_misparsed_for_loop_head(
Applicability::MaybeIncorrect,
);
}
- (token::OpenDelim(Delimiter::Brace), StmtKind::Expr(expr))
+ (token::OpenBrace, StmtKind::Expr(expr))
if let ExprKind::Loop(..)
| ExprKind::If(..)
| ExprKind::While(..)
@@ -654,7 +652,7 @@ fn suggest_fixes_misparsed_for_loop_head(
Applicability::MaybeIncorrect,
);
}
- (token::OpenDelim(Delimiter::Brace), _) => {}
+ (token::OpenBrace, _) => {}
(_, _) => {
e.multipart_suggestion(
"you might have meant to write this as part of a block",
@@ -696,9 +694,11 @@ pub(super) fn parse_block_common(
blk_mode: BlockCheckMode,
loop_header: Option<Span>,
) -> PResult<'a, (AttrVec, P<Block>)> {
- maybe_whole!(self, NtBlock, |block| (AttrVec::new(), block));
+ if let Some(block) = self.eat_metavar_seq(MetaVarKind::Block, |this| this.parse_block()) {
+ return Ok((AttrVec::new(), block));
+ }
- let maybe_ident = self.prev_token.clone();
+ let maybe_ident = self.prev_token;
self.maybe_recover_unexpected_block_label(loop_header);
if !self.eat(exp!(OpenBrace)) {
return self.error_block_no_opening_brace();
@@ -765,10 +765,6 @@ pub(crate) fn parse_block_tail(
Applicability::MaybeIncorrect,
);
}
- if self.psess.unstable_features.is_nightly_build() {
- // FIXME(Nilstrieb): Remove this again after a few months.
- err.note("type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>");
- }
}
}
@@ -807,7 +803,7 @@ fn recover_missing_dot(&mut self, err: &mut Diag<'_>) {
// Likely `foo bar`
} else if self.prev_token.kind == token::Question {
// `foo? bar`
- } else if self.prev_token.kind == token::CloseDelim(Delimiter::Parenthesis) {
+ } else if self.prev_token.kind == token::CloseParen {
// `foo() bar`
} else {
return;
@@ -824,7 +820,7 @@ fn recover_missing_dot(&mut self, err: &mut Diag<'_>) {
Applicability::MaybeIncorrect,
);
}
- if self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Parenthesis)) {
+ if self.look_ahead(1, |t| t.kind == token::OpenParen) {
err.span_suggestion_verbose(
self.prev_token.span.between(self.token.span),
"you might have meant to write a method call",
@@ -868,8 +864,7 @@ pub fn parse_full_stmt(
StmtKind::Expr(expr)
if classify::expr_requires_semi_to_be_stmt(expr)
&& !expr.attrs.is_empty()
- && ![token::Eof, token::Semi, token::CloseDelim(Delimiter::Brace)]
- .contains(&self.token.kind) =>
+ && !matches!(self.token.kind, token::Eof | token::Semi | token::CloseBrace) =>
{
// The user has written `#[attr] expr` which is unsupported. (#106020)
let guar = self.attr_on_non_tail_expr(&expr);
@@ -911,13 +906,13 @@ pub fn parse_full_stmt(
{
if self.token == token::Colon
&& self.look_ahead(1, |token| {
- token.is_whole_block()
+ token.is_metavar_block()
|| matches!(
token.kind,
token::Ident(
kw::For | kw::Loop | kw::While,
token::IdentIsRaw::No
- ) | token::OpenDelim(Delimiter::Brace)
+ ) | token::OpenBrace
)
})
{
diff --git a/compiler/rustc_parse/src/parser/tests.rs b/compiler/rustc_parse/src/parser/tests.rs
index 49ae6cb..8285070 100644
--- a/compiler/rustc_parse/src/parser/tests.rs
+++ b/compiler/rustc_parse/src/parser/tests.rs
@@ -2554,7 +2554,7 @@ fn look(p: &Parser<'_>, dist: usize, kind: rustc_ast::token::TokenKind) {
// Do the `assert_eq` outside the closure so that `track_caller` works.
// (`#![feature(closure_track_caller)]` + `#[track_caller]` on the closure
// doesn't give the line number in the test below if the assertion fails.)
- let tok = p.look_ahead(dist, |tok| tok.clone());
+ let tok = p.look_ahead(dist, |tok| *tok);
assert_eq!(kind, tok.kind);
}
@@ -2573,14 +2573,14 @@ fn look_ahead() {
// Current position is the `fn`.
look(&p, 0, token::Ident(kw::Fn, raw_no));
look(&p, 1, token::Ident(sym_f, raw_no));
- look(&p, 2, token::OpenDelim(Delimiter::Parenthesis));
+ look(&p, 2, token::OpenParen);
look(&p, 3, token::Ident(sym_x, raw_no));
look(&p, 4, token::Colon);
look(&p, 5, token::Ident(sym::u32, raw_no));
- look(&p, 6, token::CloseDelim(Delimiter::Parenthesis));
- look(&p, 7, token::OpenDelim(Delimiter::Brace));
+ look(&p, 6, token::CloseParen);
+ look(&p, 7, token::OpenBrace);
look(&p, 8, token::Ident(sym_x, raw_no));
- look(&p, 9, token::CloseDelim(Delimiter::Brace));
+ look(&p, 9, token::CloseBrace);
look(&p, 10, token::Ident(kw::Struct, raw_no));
look(&p, 11, token::Ident(sym_S, raw_no));
look(&p, 12, token::Semi);
@@ -2597,10 +2597,10 @@ fn look_ahead() {
look(&p, 0, token::Ident(sym_x, raw_no));
look(&p, 1, token::Colon);
look(&p, 2, token::Ident(sym::u32, raw_no));
- look(&p, 3, token::CloseDelim(Delimiter::Parenthesis));
- look(&p, 4, token::OpenDelim(Delimiter::Brace));
+ look(&p, 3, token::CloseParen);
+ look(&p, 4, token::OpenBrace);
look(&p, 5, token::Ident(sym_x, raw_no));
- look(&p, 6, token::CloseDelim(Delimiter::Brace));
+ look(&p, 6, token::CloseBrace);
look(&p, 7, token::Ident(kw::Struct, raw_no));
look(&p, 8, token::Ident(sym_S, raw_no));
look(&p, 9, token::Semi);
@@ -2652,18 +2652,18 @@ fn look_ahead_non_outermost_stream() {
}
look(&p, 0, token::Ident(kw::Fn, raw_no));
look(&p, 1, token::Ident(sym_f, raw_no));
- look(&p, 2, token::OpenDelim(Delimiter::Parenthesis));
+ look(&p, 2, token::OpenParen);
look(&p, 3, token::Ident(sym_x, raw_no));
look(&p, 4, token::Colon);
look(&p, 5, token::Ident(sym::u32, raw_no));
- look(&p, 6, token::CloseDelim(Delimiter::Parenthesis));
- look(&p, 7, token::OpenDelim(Delimiter::Brace));
+ look(&p, 6, token::CloseParen);
+ look(&p, 7, token::OpenBrace);
look(&p, 8, token::Ident(sym_x, raw_no));
- look(&p, 9, token::CloseDelim(Delimiter::Brace));
+ look(&p, 9, token::CloseBrace);
look(&p, 10, token::Ident(kw::Struct, raw_no));
look(&p, 11, token::Ident(sym_S, raw_no));
look(&p, 12, token::Semi);
- look(&p, 13, token::CloseDelim(Delimiter::Brace));
+ look(&p, 13, token::CloseBrace);
// Any lookahead past the end of the token stream returns `Eof`.
look(&p, 14, token::Eof);
look(&p, 15, token::Eof);
@@ -2723,9 +2723,7 @@ fn debug_lookahead() {
\"f\",
No,
),
- OpenDelim(
- Parenthesis,
- ),
+ OpenParen,
Ident(
\"x\",
No,
@@ -2735,9 +2733,7 @@ fn debug_lookahead() {
\"u32\",
No,
),
- CloseDelim(
- Parenthesis,
- ),
+ CloseParen,
],
approx_token_stream_pos: 0,
..
@@ -2768,9 +2764,7 @@ fn debug_lookahead() {
\"f\",
No,
),
- OpenDelim(
- Parenthesis,
- ),
+ OpenParen,
Ident(
\"x\",
No,
@@ -2780,19 +2774,13 @@ fn debug_lookahead() {
\"u32\",
No,
),
- CloseDelim(
- Parenthesis,
- ),
- OpenDelim(
- Brace,
- ),
+ CloseParen,
+ OpenBrace,
Ident(
\"x\",
No,
),
- CloseDelim(
- Brace,
- ),
+ CloseBrace,
Ident(
\"struct\",
No,
@@ -2817,9 +2805,7 @@ fn debug_lookahead() {
&format!("{:#?}", p.debug_lookahead(1)),
"Parser {
prev_token: Token {
- kind: OpenDelim(
- Brace,
- ),
+ kind: OpenBrace,
span: Span {
lo: BytePos(
13,
@@ -2844,9 +2830,7 @@ fn debug_lookahead() {
&format!("{:#?}", p.debug_lookahead(4)),
"Parser {
prev_token: Token {
- kind: OpenDelim(
- Brace,
- ),
+ kind: OpenBrace,
span: Span {
lo: BytePos(
13,
@@ -2862,9 +2846,7 @@ fn debug_lookahead() {
\"x\",
No,
),
- CloseDelim(
- Brace,
- ),
+ CloseBrace,
Ident(
\"struct\",
No,
diff --git a/compiler/rustc_parse/src/parser/token_type.rs b/compiler/rustc_parse/src/parser/token_type.rs
index add3c97..b915481 100644
--- a/compiler/rustc_parse/src/parser/token_type.rs
+++ b/compiler/rustc_parse/src/parser/token_type.rs
@@ -448,18 +448,6 @@ macro_rules! exp {
token_type: $crate::parser::token_type::TokenType::$tok
}
};
- (@open, $delim:ident, $token_type:ident) => {
- $crate::parser::token_type::ExpTokenPair {
- tok: &rustc_ast::token::OpenDelim(rustc_ast::token::Delimiter::$delim),
- token_type: $crate::parser::token_type::TokenType::$token_type,
- }
- };
- (@close, $delim:ident, $token_type:ident) => {
- $crate::parser::token_type::ExpTokenPair {
- tok: &rustc_ast::token::CloseDelim(rustc_ast::token::Delimiter::$delim),
- token_type: $crate::parser::token_type::TokenType::$token_type,
- }
- };
// `ExpKeywordPair` helper rules.
(@kw, $kw:ident, $token_type:ident) => {
@@ -504,12 +492,12 @@ macro_rules! exp {
(Question) => { exp!(@tok, Question) };
(Eof) => { exp!(@tok, Eof) };
- (OpenParen) => { exp!(@open, Parenthesis, OpenParen) };
- (OpenBrace) => { exp!(@open, Brace, OpenBrace) };
- (OpenBracket) => { exp!(@open, Bracket, OpenBracket) };
- (CloseParen) => { exp!(@close, Parenthesis, CloseParen) };
- (CloseBrace) => { exp!(@close, Brace, CloseBrace) };
- (CloseBracket) => { exp!(@close, Bracket, CloseBracket) };
+ (OpenParen) => { exp!(@tok, OpenParen) };
+ (OpenBrace) => { exp!(@tok, OpenBrace) };
+ (OpenBracket) => { exp!(@tok, OpenBracket) };
+ (CloseParen) => { exp!(@tok, CloseParen) };
+ (CloseBrace) => { exp!(@tok, CloseBrace) };
+ (CloseBracket) => { exp!(@tok, CloseBracket) };
(As) => { exp!(@kw, As, KwAs) };
(Async) => { exp!(@kw, Async, KwAsync) };
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 93705da..1748173 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -1,5 +1,5 @@
use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, IdentIsRaw, MetaVarKind, Token, TokenKind};
+use rustc_ast::token::{self, IdentIsRaw, MetaVarKind, Token, TokenKind};
use rustc_ast::util::case::Case;
use rustc_ast::{
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy,
@@ -7,7 +7,7 @@
Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty,
TyKind, UnsafeBinderTy,
};
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::{Applicability, Diag, PResult};
use rustc_span::{ErrorGuaranteed, Ident, Span, kw, sym};
use thin_vec::{ThinVec, thin_vec};
@@ -98,7 +98,7 @@ fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool {
|| t.is_lifetime()
|| t == &TokenKind::Question
|| t.is_keyword(kw::For)
- || t == &TokenKind::OpenDelim(Delimiter::Parenthesis)
+ || t == &TokenKind::OpenParen
}
impl<'a> Parser<'a> {
@@ -355,7 +355,7 @@ fn parse_ty_common(
}
}
} else if self.check_keyword(exp!(Unsafe))
- && self.look_ahead(1, |tok| matches!(tok.kind, token::Lt))
+ && self.look_ahead(1, |tok| tok.kind == token::Lt)
{
self.parse_unsafe_binder_ty()?
} else {
@@ -411,6 +411,9 @@ fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: AllowPlus) -> PResu
TyKind::Path(None, path) if maybe_bounds => {
self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true)
}
+ // For `('a) + …`, we know that `'a` in type position already lead to an error being
+ // emitted. To reduce output, let's indirectly suppress E0178 (bad `+` in type) and
+ // other irrelevant consequential errors.
TyKind::TraitObject(bounds, TraitObjectSyntax::None)
if maybe_bounds && bounds.len() == 1 && !trailing_plus =>
{
@@ -425,12 +428,60 @@ fn parse_ty_tuple_or_parens(&mut self, lo: Span, allow_plus: AllowPlus) -> PResu
}
fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
- let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus());
- let bounds = self.parse_generic_bounds_common(allow_plus)?;
- if lt_no_plus {
- self.dcx().emit_err(NeedPlusAfterTraitObjectLifetime { span: lo });
+ // A lifetime only begins a bare trait object type if it is followed by `+`!
+ if self.token.is_lifetime() && !self.look_ahead(1, |t| t.is_like_plus()) {
+ // In Rust 2021 and beyond, we assume that the user didn't intend to write a bare trait
+ // object type with a leading lifetime bound since that seems very unlikely given the
+ // fact that `dyn`-less trait objects are *semantically* invalid.
+ if self.psess.edition.at_least_rust_2021() {
+ let lt = self.expect_lifetime();
+ let mut err = self.dcx().struct_span_err(lo, "expected type, found lifetime");
+ err.span_label(lo, "expected type");
+ return Ok(match self.maybe_recover_ref_ty_no_leading_ampersand(lt, lo, err) {
+ Ok(ref_ty) => ref_ty,
+ Err(err) => TyKind::Err(err.emit()),
+ });
+ }
+
+ self.dcx().emit_err(NeedPlusAfterTraitObjectLifetime {
+ span: lo,
+ suggestion: lo.shrink_to_hi(),
+ });
}
- Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
+ Ok(TyKind::TraitObject(
+ self.parse_generic_bounds_common(allow_plus)?,
+ TraitObjectSyntax::None,
+ ))
+ }
+
+ fn maybe_recover_ref_ty_no_leading_ampersand<'cx>(
+ &mut self,
+ lt: Lifetime,
+ lo: Span,
+ mut err: Diag<'cx>,
+ ) -> Result<TyKind, Diag<'cx>> {
+ if !self.may_recover() {
+ return Err(err);
+ }
+ let snapshot = self.create_snapshot_for_diagnostic();
+ let mutbl = self.parse_mutability();
+ match self.parse_ty_no_plus() {
+ Ok(ty) => {
+ err.span_suggestion_verbose(
+ lo.shrink_to_lo(),
+ "you might have meant to write a reference type here",
+ "&",
+ Applicability::MaybeIncorrect,
+ );
+ err.emit();
+ Ok(TyKind::Ref(Some(lt), MutTy { ty, mutbl }))
+ }
+ Err(diag) => {
+ diag.cancel();
+ self.restore_snapshot(snapshot);
+ Err(err)
+ }
+ }
}
fn parse_remaining_bounds_path(
@@ -483,7 +534,7 @@ fn parse_array_or_slice_ty(&mut self) -> PResult<'a, TyKind> {
let elt_ty = match self.parse_ty() {
Ok(ty) => ty,
Err(err)
- if self.look_ahead(1, |t| *t == token::CloseDelim(Delimiter::Bracket))
+ if self.look_ahead(1, |t| *t == token::CloseBracket)
| self.look_ahead(1, |t| *t == token::Semi) =>
{
// Recover from `[LIT; EXPR]` and `[LIT]`
@@ -547,7 +598,7 @@ fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
// Recovery
mutbl = Mutability::Mut;
- let (dyn_tok, dyn_tok_sp) = (self.token.clone(), self.token_spacing);
+ let (dyn_tok, dyn_tok_sp) = (self.token, self.token_spacing);
self.bump();
self.bump_with((dyn_tok, dyn_tok_sp));
}
@@ -886,7 +937,7 @@ fn can_begin_bound(&mut self) -> bool {
/// ```
fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
let lo = self.token.span;
- let leading_token = self.prev_token.clone();
+ let leading_token = self.prev_token;
let has_parens = self.eat(exp!(OpenParen));
let bound = if self.token.is_lifetime() {
@@ -1103,7 +1154,7 @@ fn parse_generic_ty_bound(
}
let mut path = if self.token.is_keyword(kw::Fn)
- && self.look_ahead(1, |t| *t == TokenKind::OpenDelim(Delimiter::Parenthesis))
+ && self.look_ahead(1, |t| *t == TokenKind::OpenParen)
&& let Some(path) = self.recover_path_from_fn()
{
path
@@ -1157,7 +1208,7 @@ fn parse_generic_ty_bound(
self.parse_path(PathStyle::Type)?
};
- if self.may_recover() && self.token == TokenKind::OpenDelim(Delimiter::Parenthesis) {
+ if self.may_recover() && self.token == TokenKind::OpenParen {
self.recover_fn_trait_with_lifetime_params(&mut path, &mut lifetime_defs)?;
}
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 6bbd650..6a1c2af 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -157,7 +157,7 @@ fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaIte
pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr: &Attribute) {
let attr_item = attr.get_normal_item();
- if safety == AttributeSafety::Unsafe {
+ if let AttributeSafety::Unsafe { unsafe_since } = safety {
if let ast::Safety::Default = attr_item.unsafety {
let path_span = attr_item.path.span;
@@ -167,7 +167,13 @@ pub fn check_attribute_safety(psess: &ParseSess, safety: AttributeSafety, attr:
// square bracket respectively.
let diag_span = attr_item.span();
- if attr.span.at_least_rust_2024() {
+ // Attributes can be safe in earlier editions, and become unsafe in later ones.
+ let emit_error = match unsafe_since {
+ None => true,
+ Some(unsafe_since) => attr.span.edition() >= unsafe_since,
+ };
+
+ if emit_error {
psess.dcx().emit_err(errors::UnsafeAttrOutsideUnsafe {
span: path_span,
suggestion: errors::UnsafeAttrOutsideUnsafeSuggestion {
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index bea8680..413726d 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -404,7 +404,7 @@
passes_invalid_attr_at_crate_level_item =
the inner attribute doesn't annotate this {$kind}
-passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument
+passes_invalid_macro_export_arguments = invalid `#[macro_export]` argument
passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
@@ -508,7 +508,7 @@
`#[must_use]` has no effect when applied to {$article} {$target}
passes_naked_asm_outside_naked_fn =
- the `naked_asm!` macro can only be used in functions marked with `#[naked]`
+ the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
passes_naked_functions_asm_block =
naked functions must contain a single `naked_asm!` invocation
@@ -516,9 +516,9 @@
.label_non_asm = not allowed in naked functions
passes_naked_functions_incompatible_attribute =
- attribute incompatible with `#[naked]`
- .label = the `{$attr}` attribute is incompatible with `#[naked]`
- .naked_attribute = function marked with `#[naked]` here
+ attribute incompatible with `#[unsafe(naked)]`
+ .label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`
+ .naked_attribute = function marked with `#[unsafe(naked)]` here
passes_naked_functions_must_naked_asm =
the `asm!` macro is not allowed in naked functions
@@ -742,9 +742,6 @@
passes_transparent_incompatible =
transparent {$target} cannot have other repr hints
-passes_undefined_naked_function_abi =
- Rust ABI is unsupported in naked functions
-
passes_unknown_external_lang_item =
unknown external lang item: `{$lang_item}`
@@ -774,8 +771,8 @@
.label_orig = any code following this expression is unreachable
.note = this expression has type `{$ty}`, which is uninhabited
-passes_unrecognized_field =
- unrecognized field name `{$name}`
+passes_unrecognized_argument =
+ unrecognized argument
passes_unstable_attr_for_already_stable_feature =
can't mark as unstable using an already stable feature
diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs
index 671b7d7..b139ed6 100644
--- a/compiler/rustc_passes/src/abi_test.rs
+++ b/compiler/rustc_passes/src/abi_test.rs
@@ -9,7 +9,7 @@
use rustc_target::callconv::FnAbi;
use super::layout_test::ensure_wf;
-use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedField};
+use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedArgument};
pub fn test_abi(tcx: TyCtxt<'_>) {
if !tcx.features().rustc_attrs() {
@@ -77,8 +77,8 @@ fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
// The `..` are the names of fields to dump.
let meta_items = attr.meta_item_list().unwrap_or_default();
for meta_item in meta_items {
- match meta_item.name_or_empty() {
- sym::debug => {
+ match meta_item.name() {
+ Some(sym::debug) => {
let fn_name = tcx.item_name(item_def_id.into());
tcx.dcx().emit_err(AbiOf {
span: tcx.def_span(item_def_id),
@@ -88,8 +88,8 @@ fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
});
}
- name => {
- tcx.dcx().emit_err(UnrecognizedField { span: meta_item.span(), name });
+ _ => {
+ tcx.dcx().emit_err(UnrecognizedArgument { span: meta_item.span() });
}
}
}
@@ -118,8 +118,8 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
}
let meta_items = attr.meta_item_list().unwrap_or_default();
for meta_item in meta_items {
- match meta_item.name_or_empty() {
- sym::debug => {
+ match meta_item.name() {
+ Some(sym::debug) => {
let ty::FnPtr(sig_tys, hdr) = ty.kind() else {
span_bug!(
meta_item.span(),
@@ -138,7 +138,7 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
let fn_name = tcx.item_name(item_def_id.into());
tcx.dcx().emit_err(AbiOf { span, fn_name, fn_abi: format!("{:#?}", abi) });
}
- sym::assert_eq => {
+ Some(sym::assert_eq) => {
let ty::Tuple(fields) = ty.kind() else {
span_bug!(
meta_item.span(),
@@ -188,8 +188,8 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
});
}
}
- name => {
- tcx.dcx().emit_err(UnrecognizedField { span: meta_item.span(), name });
+ _ => {
+ tcx.dcx().emit_err(UnrecognizedArgument { span: meta_item.span() });
}
}
}
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 9161b23..cfc71a4 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -523,9 +523,9 @@ fn check_optimize(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Ta
fn check_no_sanitize(&self, attr: &Attribute, span: Span, target: Target) {
if let Some(list) = attr.meta_item_list() {
for item in list.iter() {
- let sym = item.name_or_empty();
+ let sym = item.name();
match sym {
- sym::address | sym::hwaddress => {
+ Some(s @ sym::address | s @ sym::hwaddress) => {
let is_valid =
matches!(target, Target::Fn | Target::Method(..) | Target::Static);
if !is_valid {
@@ -533,7 +533,7 @@ fn check_no_sanitize(&self, attr: &Attribute, span: Span, target: Target) {
attr_span: item.span(),
defn_span: span,
accepted_kind: "a function or static",
- attr_str: sym.as_str(),
+ attr_str: s.as_str(),
});
}
}
@@ -544,7 +544,10 @@ fn check_no_sanitize(&self, attr: &Attribute, span: Span, target: Target) {
attr_span: item.span(),
defn_span: span,
accepted_kind: "a function",
- attr_str: sym.as_str(),
+ attr_str: &match sym {
+ Some(name) => name.to_string(),
+ None => "...".to_string(),
+ },
});
}
}
@@ -561,12 +564,15 @@ fn check_generic_attr(
allowed_target: Target,
) {
if target != allowed_target {
+ let path = attr.path();
+ let path: Vec<_> = path.iter().map(|s| s.as_str()).collect();
+ let attr_name = path.join("::");
self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span(),
errors::OnlyHasEffectOn {
- attr_name: attr.name_or_empty(),
+ attr_name,
target_name: allowed_target.name().replace(' ', "_"),
},
);
@@ -589,7 +595,8 @@ fn check_naked(
// * `#[track_caller]`
// * `#[test]`, `#[ignore]`, `#[should_panic]`
//
- // NOTE: when making changes to this list, check that `error_codes/E0736.md` remains accurate
+ // NOTE: when making changes to this list, check that `error_codes/E0736.md` remains
+ // accurate.
const ALLOW_LIST: &[rustc_span::Symbol] = &[
// conditional compilation
sym::cfg_trace,
@@ -624,6 +631,21 @@ fn check_naked(
match target {
Target::Fn
| Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {
+ let fn_sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
+ let abi = fn_sig.header.abi;
+ if abi.is_rustic_abi() && !self.tcx.features().naked_functions_rustic_abi() {
+ feature_err(
+ &self.tcx.sess,
+ sym::naked_functions_rustic_abi,
+ fn_sig.span,
+ format!(
+ "`#[naked]` is currently unstable on `extern \"{}\"` functions",
+ abi.as_str()
+ ),
+ )
+ .emit();
+ }
+
for other_attr in attrs {
// this covers "sugared doc comments" of the form `/// ...`
// it does not cover `#[doc = "..."]`, which is handled below
@@ -657,24 +679,17 @@ fn check_naked(
}
}
- if !ALLOW_LIST.iter().any(|name| other_attr.has_name(*name)) {
+ if !other_attr.has_any_name(ALLOW_LIST) {
self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute {
span: other_attr.span(),
naked_span: attr.span(),
- attr: other_attr.name_or_empty(),
+ attr: other_attr.name().unwrap(),
});
return;
}
}
}
- // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
- // `#[naked]` attribute with just a lint, because we previously
- // erroneously allowed it and some crates used it accidentally, to be compatible
- // with crates depending on them, we can't throw an error here.
- Target::Field | Target::Arm | Target::MacroDef => {
- self.inline_attr_str_error_with_macro_def(hir_id, attr, "naked")
- }
_ => {
self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
attr_span: attr.span(),
@@ -1109,6 +1124,7 @@ fn check_doc_search_unbox(&self, meta: &MetaItemInner, hir_id: HirId) {
ItemKind::Trait(_, _, _, generics, _, items)
if generics.params.len() != 0
|| items.iter().any(|item| matches!(item.kind, AssocItemKind::Type)) => {}
+ ItemKind::TyAlias(_, _, generics) if generics.params.len() != 0 => {}
_ => {
self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() });
}
@@ -1134,7 +1150,7 @@ fn check_doc_inline(
) {
match target {
Target::Use | Target::ExternCrate => {
- let do_inline = meta.name_or_empty() == sym::inline;
+ let do_inline = meta.has_name(sym::inline);
if let Some((prev_inline, prev_span)) = *specified_inline {
if do_inline != prev_inline {
let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]);
@@ -1244,8 +1260,8 @@ fn check_attr_crate_level(
fn check_test_attr(&self, meta: &MetaItemInner, hir_id: HirId) {
if let Some(metas) = meta.meta_item_list() {
for i_meta in metas {
- match (i_meta.name_or_empty(), i_meta.meta_item()) {
- (sym::attr | sym::no_crate_inject, _) => {}
+ match (i_meta.name(), i_meta.meta_item()) {
+ (Some(sym::attr | sym::no_crate_inject), _) => {}
(_, Some(m)) => {
self.tcx.emit_node_span_lint(
INVALID_DOC_ATTRIBUTES,
@@ -1306,61 +1322,63 @@ fn check_doc_attrs(
if let Some(list) = attr.meta_item_list() {
for meta in &list {
if let Some(i_meta) = meta.meta_item() {
- match i_meta.name_or_empty() {
- sym::alias => {
+ match i_meta.name() {
+ Some(sym::alias) => {
if self.check_attr_not_crate_level(meta, hir_id, "alias") {
self.check_doc_alias(meta, hir_id, target, aliases);
}
}
- sym::keyword => {
+ Some(sym::keyword) => {
if self.check_attr_not_crate_level(meta, hir_id, "keyword") {
self.check_doc_keyword(meta, hir_id);
}
}
- sym::fake_variadic => {
+ Some(sym::fake_variadic) => {
if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") {
self.check_doc_fake_variadic(meta, hir_id);
}
}
- sym::search_unbox => {
+ Some(sym::search_unbox) => {
if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") {
self.check_doc_search_unbox(meta, hir_id);
}
}
- sym::test => {
+ Some(sym::test) => {
if self.check_attr_crate_level(attr, meta, hir_id) {
self.check_test_attr(meta, hir_id);
}
}
- sym::html_favicon_url
- | sym::html_logo_url
- | sym::html_playground_url
- | sym::issue_tracker_base_url
- | sym::html_root_url
- | sym::html_no_source => {
+ Some(
+ sym::html_favicon_url
+ | sym::html_logo_url
+ | sym::html_playground_url
+ | sym::issue_tracker_base_url
+ | sym::html_root_url
+ | sym::html_no_source,
+ ) => {
self.check_attr_crate_level(attr, meta, hir_id);
}
- sym::cfg_hide => {
+ Some(sym::cfg_hide) => {
if self.check_attr_crate_level(attr, meta, hir_id) {
self.check_doc_cfg_hide(meta, hir_id);
}
}
- sym::inline | sym::no_inline => {
+ Some(sym::inline | sym::no_inline) => {
self.check_doc_inline(attr, meta, hir_id, target, specified_inline)
}
- sym::masked => self.check_doc_masked(attr, meta, hir_id, target),
+ Some(sym::masked) => self.check_doc_masked(attr, meta, hir_id, target),
- sym::cfg | sym::hidden | sym::notable_trait => {}
+ Some(sym::cfg | sym::hidden | sym::notable_trait) => {}
- sym::rust_logo => {
+ Some(sym::rust_logo) => {
if self.check_attr_crate_level(attr, meta, hir_id)
&& !self.tcx.features().rustdoc_internals()
{
@@ -2283,7 +2301,7 @@ fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target:
}
fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
- let name = attr.name_or_empty();
+ let name = attr.name().unwrap();
match target {
Target::ExternCrate | Target::Mod => {}
_ => {
@@ -2315,12 +2333,12 @@ fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) {
attr.span(),
errors::MacroExport::TooManyItems,
);
- } else if meta_item_list[0].name_or_empty() != sym::local_inner_macros {
+ } else if !meta_item_list[0].has_name(sym::local_inner_macros) {
self.tcx.emit_node_span_lint(
INVALID_MACRO_EXPORT_ARGUMENTS,
hir_id,
meta_item_list[0].span(),
- errors::MacroExport::UnknownItem { name: meta_item_list[0].name_or_empty() },
+ errors::MacroExport::InvalidArgument,
);
}
} else {
@@ -2365,33 +2383,28 @@ fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
}
// Warn on useless empty attributes.
- let note = if (matches!(
- attr.name_or_empty(),
- sym::macro_use
- | sym::allow
- | sym::expect
- | sym::warn
- | sym::deny
- | sym::forbid
- | sym::feature
- | sym::target_feature
- ) && attr.meta_item_list().is_some_and(|list| list.is_empty()))
+ let note = if attr.has_any_name(&[
+ sym::macro_use,
+ sym::allow,
+ sym::expect,
+ sym::warn,
+ sym::deny,
+ sym::forbid,
+ sym::feature,
+ sym::target_feature,
+ ]) && attr.meta_item_list().is_some_and(|list| list.is_empty())
{
- errors::UnusedNote::EmptyList { name: attr.name_or_empty() }
- } else if matches!(
- attr.name_or_empty(),
- sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
- ) && let Some(meta) = attr.meta_item_list()
+ errors::UnusedNote::EmptyList { name: attr.name().unwrap() }
+ } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect])
+ && let Some(meta) = attr.meta_item_list()
&& let [meta] = meta.as_slice()
&& let Some(item) = meta.meta_item()
&& let MetaItemKind::NameValue(_) = &item.kind
&& item.path == sym::reason
{
- errors::UnusedNote::NoLints { name: attr.name_or_empty() }
- } else if matches!(
- attr.name_or_empty(),
- sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
- ) && let Some(meta) = attr.meta_item_list()
+ errors::UnusedNote::NoLints { name: attr.name().unwrap() }
+ } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect])
+ && let Some(meta) = attr.meta_item_list()
&& meta.iter().any(|meta| {
meta.meta_item().map_or(false, |item| item.path == sym::linker_messages)
})
@@ -2424,7 +2437,7 @@ fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
return;
}
}
- } else if attr.name_or_empty() == sym::default_method_body_is_const {
+ } else if attr.has_name(sym::default_method_body_is_const) {
errors::UnusedNote::DefaultMethodBodyConst
} else {
return;
@@ -2881,10 +2894,11 @@ fn check_duplicates(
if matches!(duplicates, WarnFollowingWordOnly) && !attr.is_word() {
return;
}
+ let attr_name = attr.name().unwrap();
match duplicates {
DuplicatesOk => {}
WarnFollowing | FutureWarnFollowing | WarnFollowingWordOnly | FutureWarnPreceding => {
- match seen.entry(attr.name_or_empty()) {
+ match seen.entry(attr_name) {
Entry::Occupied(mut entry) => {
let (this, other) = if matches!(duplicates, FutureWarnPreceding) {
let to_remove = entry.insert(attr.span());
@@ -2911,7 +2925,7 @@ fn check_duplicates(
}
}
}
- ErrorFollowing | ErrorPreceding => match seen.entry(attr.name_or_empty()) {
+ ErrorFollowing | ErrorPreceding => match seen.entry(attr_name) {
Entry::Occupied(mut entry) => {
let (this, other) = if matches!(duplicates, ErrorPreceding) {
let to_remove = entry.insert(attr.span());
@@ -2919,11 +2933,7 @@ fn check_duplicates(
} else {
(attr.span(), *entry.get())
};
- tcx.dcx().emit_err(errors::UnusedMultiple {
- this,
- other,
- name: attr.name_or_empty(),
- });
+ tcx.dcx().emit_err(errors::UnusedMultiple { this, other, name: attr_name });
}
Entry::Vacant(entry) => {
entry.insert(attr.span());
diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index 062d56a..7a7a817 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -28,17 +28,17 @@ fn check_for_debugger_visualizer(&mut self, attr: &Attribute) {
return;
};
- let (visualizer_type, visualizer_path) =
- match (meta_item.name_or_empty(), meta_item.value_str()) {
- (sym::natvis_file, Some(value)) => (DebuggerVisualizerType::Natvis, value),
- (sym::gdb_script_file, Some(value)) => {
- (DebuggerVisualizerType::GdbPrettyPrinter, value)
- }
- (_, _) => {
- self.sess.dcx().emit_err(DebugVisualizerInvalid { span: meta_item.span });
- return;
- }
- };
+ let (visualizer_type, visualizer_path) = match (meta_item.name(), meta_item.value_str())
+ {
+ (Some(sym::natvis_file), Some(value)) => (DebuggerVisualizerType::Natvis, value),
+ (Some(sym::gdb_script_file), Some(value)) => {
+ (DebuggerVisualizerType::GdbPrettyPrinter, value)
+ }
+ (_, _) => {
+ self.sess.dcx().emit_err(DebugVisualizerInvalid { span: meta_item.span });
+ return;
+ }
+ };
let file = match resolve_path(&self.sess, visualizer_path.as_str(), attr.span) {
Ok(file) => file,
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 4e3e032..4052264 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -5,7 +5,7 @@
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, Level,
- MultiSpan, SubdiagMessageOp, Subdiagnostic,
+ MultiSpan, Subdiagnostic,
};
use rustc_hir::{self as hir, ExprKind, Target};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@@ -756,7 +756,7 @@ pub(crate) enum MacroExport {
OnDeclMacro,
#[diag(passes_invalid_macro_export_arguments)]
- UnknownItem { name: Symbol },
+ InvalidArgument,
#[diag(passes_invalid_macro_export_arguments_too_many_items)]
TooManyItems,
@@ -1045,11 +1045,10 @@ pub(crate) struct AbiInvalidAttribute {
}
#[derive(Diagnostic)]
-#[diag(passes_unrecognized_field)]
-pub(crate) struct UnrecognizedField {
+#[diag(passes_unrecognized_argument)]
+pub(crate) struct UnrecognizedArgument {
#[primary_span]
pub span: Span,
- pub name: Symbol,
}
#[derive(Diagnostic)]
@@ -1197,10 +1196,6 @@ pub(crate) struct UnlabeledCfInWhileCondition<'a> {
pub cf_type: &'a str,
}
-#[derive(LintDiagnostic)]
-#[diag(passes_undefined_naked_function_abi)]
-pub(crate) struct UndefinedNakedFunctionAbi;
-
#[derive(Diagnostic)]
#[diag(passes_no_patterns)]
pub(crate) struct NoPatterns {
@@ -1437,7 +1432,7 @@ pub(crate) struct UselessAssignment<'a> {
#[derive(LintDiagnostic)]
#[diag(passes_only_has_effect_on)]
pub(crate) struct OnlyHasEffectOn {
- pub attr_name: Symbol,
+ pub attr_name: String,
pub target_name: String,
}
@@ -1856,11 +1851,7 @@ pub(crate) struct UnusedVariableStringInterp {
}
impl Subdiagnostic for UnusedVariableStringInterp {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.span_label(self.lit, crate::fluent_generated::passes_maybe_string_interpolation);
diag.multipart_suggestion(
crate::fluent_generated::passes_string_interpolation_only_works,
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index d4512c9..a19faf0 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -13,7 +13,7 @@
use crate::errors::{
LayoutAbi, LayoutAlign, LayoutHomogeneousAggregate, LayoutInvalidAttribute, LayoutOf,
- LayoutSize, UnrecognizedField,
+ LayoutSize, UnrecognizedArgument,
};
pub fn test_layout(tcx: TyCtxt<'_>) {
@@ -79,28 +79,28 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
// The `..` are the names of fields to dump.
let meta_items = attr.meta_item_list().unwrap_or_default();
for meta_item in meta_items {
- match meta_item.name_or_empty() {
+ match meta_item.name() {
// FIXME: this never was about ABI and now this dump arg is confusing
- sym::abi => {
+ Some(sym::abi) => {
tcx.dcx().emit_err(LayoutAbi {
span,
abi: format!("{:?}", ty_layout.backend_repr),
});
}
- sym::align => {
+ Some(sym::align) => {
tcx.dcx().emit_err(LayoutAlign {
span,
align: format!("{:?}", ty_layout.align),
});
}
- sym::size => {
+ Some(sym::size) => {
tcx.dcx()
.emit_err(LayoutSize { span, size: format!("{:?}", ty_layout.size) });
}
- sym::homogeneous_aggregate => {
+ Some(sym::homogeneous_aggregate) => {
tcx.dcx().emit_err(LayoutHomogeneousAggregate {
span,
homogeneous_aggregate: format!(
@@ -111,15 +111,15 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
});
}
- sym::debug => {
+ Some(sym::debug) => {
let normalized_ty = tcx.normalize_erasing_regions(typing_env, ty);
// FIXME: using the `Debug` impl here isn't ideal.
let ty_layout = format!("{:#?}", *ty_layout);
tcx.dcx().emit_err(LayoutOf { span, normalized_ty, ty_layout });
}
- name => {
- tcx.dcx().emit_err(UnrecognizedField { span: meta_item.span(), name });
+ _ => {
+ tcx.dcx().emit_err(UnrecognizedArgument { span: meta_item.span() });
}
}
}
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index 6f6115a..93ff0f6 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -6,7 +6,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(let_chains)]
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index 06eb76c..4e9b7fd 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -578,8 +578,7 @@ fn write_vars<F>(&self, wr: &mut dyn Write, mut test: F) -> io::Result<()>
where
F: FnMut(Variable) -> bool,
{
- for var_idx in 0..self.ir.var_kinds.len() {
- let var = Variable::from(var_idx);
+ for var in self.ir.var_kinds.indices() {
if test(var) {
write!(wr, " {var:?}")?;
}
@@ -609,8 +608,8 @@ fn log_liveness(&self, entry_ln: LiveNode, hir_id: HirId) {
debug!(
"^^ liveness computation results for body {} (entry={:?})",
{
- for ln_idx in 0..self.ir.lnks.len() {
- debug!("{:?}", self.ln_str(LiveNode::from(ln_idx)));
+ for ln_idx in self.ir.lnks.indices() {
+ debug!("{:?}", self.ln_str(ln_idx));
}
hir_id
},
@@ -1021,7 +1020,10 @@ fn propagate_through_expr(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNod
}
hir::ExprKind::Call(ref f, args) => {
- let succ = self.check_is_ty_uninhabited(expr, succ);
+ let is_ctor = |f: &Expr<'_>| matches!(f.kind, hir::ExprKind::Path(hir::QPath::Resolved(_, path)) if matches!(path.res, rustc_hir::def::Res::Def(rustc_hir::def::DefKind::Ctor(_, _), _)));
+ let succ =
+ if !is_ctor(f) { self.check_is_ty_uninhabited(expr, succ) } else { succ };
+
let succ = self.propagate_through_exprs(args, succ);
self.propagate_through_expr(f, succ)
}
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index d35aedf..3c9f8b7 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -1,6 +1,5 @@
//! Checks validity of naked functions.
-use rustc_abi::ExternAbi;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{LocalDefId, LocalModDefId};
@@ -10,12 +9,11 @@
use rustc_middle::query::Providers;
use rustc_middle::span_bug;
use rustc_middle::ty::TyCtxt;
-use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
use rustc_span::{Span, sym};
use crate::errors::{
NakedAsmOutsideNakedFn, NakedFunctionsAsmBlock, NakedFunctionsMustNakedAsm, NoPatterns,
- ParamsNotAllowed, UndefinedNakedFunctionAbi,
+ ParamsNotAllowed,
};
pub(crate) fn provide(providers: &mut Providers) {
@@ -29,26 +27,21 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
continue;
}
- let (fn_header, body_id) = match tcx.hir_node_by_def_id(def_id) {
+ let body = match tcx.hir_node_by_def_id(def_id) {
hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Fn { sig, body: body_id, .. },
- ..
+ kind: hir::ItemKind::Fn { body: body_id, .. }, ..
})
| hir::Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Fn(sig, hir::TraitFn::Provided(body_id)),
+ kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body_id)),
..
})
| hir::Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::Fn(sig, body_id),
- ..
- }) => (sig.header, *body_id),
+ kind: hir::ImplItemKind::Fn(_, body_id), ..
+ }) => tcx.hir_body(*body_id),
_ => continue,
};
- let body = tcx.hir_body(body_id);
-
if tcx.has_attr(def_id, sym::naked) {
- check_abi(tcx, def_id, fn_header.abi);
check_no_patterns(tcx, body.params);
check_no_parameters_use(tcx, body);
check_asm(tcx, def_id, body);
@@ -60,20 +53,6 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
}
}
-/// Checks that function uses non-Rust ABI.
-fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: ExternAbi) {
- if abi == ExternAbi::Rust {
- let hir_id = tcx.local_def_id_to_hir_id(def_id);
- let span = tcx.def_span(def_id);
- tcx.emit_node_span_lint(
- UNDEFINED_NAKED_FUNCTION_ABI,
- hir_id,
- span,
- UndefinedNakedFunctionAbi,
- );
- }
-}
-
/// Checks that parameters don't use patterns. Mirrors the checks for function declarations.
fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
for param in params {
diff --git a/compiler/rustc_pattern_analysis/src/errors.rs b/compiler/rustc_pattern_analysis/src/errors.rs
index 1f7852e..e60930d 100644
--- a/compiler/rustc_pattern_analysis/src/errors.rs
+++ b/compiler/rustc_pattern_analysis/src/errors.rs
@@ -1,4 +1,4 @@
-use rustc_errors::{Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic};
+use rustc_errors::{Diag, EmissionGuarantee, Subdiagnostic};
use rustc_macros::{LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::Span;
@@ -55,11 +55,7 @@ pub struct Overlap {
}
impl Subdiagnostic for Overlap {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let Overlap { span, range } = self;
// FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]`
@@ -103,11 +99,7 @@ pub struct GappedRange {
}
impl Subdiagnostic for GappedRange {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let GappedRange { span, gap, first_range } = self;
// FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]`
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index 643b82f..c7bab82 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -1,6 +1,5 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(associated_type_defaults)]
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 30a9e71..3c329dd 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -3,7 +3,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(unused_parens)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(min_specialization)]
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 56fd3a6..0d56db1 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -1174,8 +1174,7 @@ pub(super) struct CurrentDepGraph<D: Deps> {
/// ID from the previous session. In order to side-step this problem, we make
/// sure that anonymous `NodeId`s allocated in different sessions don't overlap.
/// This is implemented by mixing a session-key into the ID fingerprint of
- /// each anon node. The session-key is just a random number generated when
- /// the `DepGraph` is created.
+ /// each anon node. The session-key is a hash of the number of previous sessions.
anon_id_seed: Fingerprint,
/// These are simple counters that are for profiling and
@@ -1193,12 +1192,8 @@ fn new(
record_stats: bool,
previous: Arc<SerializedDepGraph>,
) -> Self {
- use std::time::{SystemTime, UNIX_EPOCH};
-
- let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
- let nanos = duration.as_nanos();
let mut stable_hasher = StableHasher::new();
- nanos.hash(&mut stable_hasher);
+ previous.session_count().hash(&mut stable_hasher);
let anon_id_seed = stable_hasher.finish();
#[cfg(debug_assertions)]
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 7556a24..ac246284 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -92,6 +92,9 @@ pub struct SerializedDepGraph {
/// Stores a map from fingerprints to nodes per dep node kind.
/// This is the reciprocal of `nodes`.
index: Vec<UnhashMap<PackedFingerprint, SerializedDepNodeIndex>>,
+ /// The number of previous compilation sessions. This is used to generate
+ /// unique anon dep nodes per session.
+ session_count: u64,
}
impl SerializedDepGraph {
@@ -146,6 +149,11 @@ pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fi
pub fn node_count(&self) -> usize {
self.nodes.len()
}
+
+ #[inline]
+ pub fn session_count(&self) -> u64 {
+ self.session_count
+ }
}
/// A packed representation of an edge's start index and byte width.
@@ -226,12 +234,12 @@ pub fn decode<D: Deps>(d: &mut MemDecoder<'_>, deps: &D) -> Arc<SerializedDepGra
// If the length of this node's edge list is small, the length is stored in the header.
// If it is not, we fall back to another decoder call.
- let num_edges = node_header.len().unwrap_or_else(|| d.read_usize());
+ let num_edges = node_header.len().unwrap_or_else(|| d.read_u32());
// The edges index list uses the same varint strategy as rmeta tables; we select the
// number of byte elements per-array not per-element. This lets us read the whole edge
// list for a node with one decoder call and also use the on-disk format in memory.
- let edges_len_bytes = node_header.bytes_per_index() * num_edges;
+ let edges_len_bytes = node_header.bytes_per_index() * (num_edges as usize);
// The in-memory structure for the edges list stores the byte width of the edges on
// this node with the offset into the global edge data array.
let edges_header = node_header.edges_header(&edge_list_data);
@@ -252,6 +260,8 @@ pub fn decode<D: Deps>(d: &mut MemDecoder<'_>, deps: &D) -> Arc<SerializedDepGra
.map(|_| UnhashMap::with_capacity_and_hasher(d.read_u32() as usize, Default::default()))
.collect();
+ let session_count = d.read_u64();
+
for (idx, node) in nodes.iter_enumerated() {
if index[node.kind.as_usize()].insert(node.hash, idx).is_some() {
// Side effect nodes can have duplicates
@@ -273,6 +283,7 @@ pub fn decode<D: Deps>(d: &mut MemDecoder<'_>, deps: &D) -> Arc<SerializedDepGra
edge_list_indices,
edge_list_data,
index,
+ session_count,
})
}
}
@@ -296,7 +307,7 @@ struct SerializedNodeHeader<D> {
// The fields of a `SerializedNodeHeader`, this struct is an implementation detail and exists only
// to make the implementation of `SerializedNodeHeader` simpler.
struct Unpacked {
- len: Option<usize>,
+ len: Option<u32>,
bytes_per_index: usize,
kind: DepKind,
hash: PackedFingerprint,
@@ -352,7 +363,7 @@ fn new(
assert_eq!(fingerprint, res.fingerprint());
assert_eq!(node, res.node());
if let Some(len) = res.len() {
- assert_eq!(edge_count, len);
+ assert_eq!(edge_count, len as usize);
}
}
Self { bytes, _marker: PhantomData }
@@ -366,7 +377,7 @@ fn unpack(&self) -> Unpacked {
let kind = head & mask(Self::KIND_BITS) as u16;
let bytes_per_index = (head >> Self::KIND_BITS) & mask(Self::WIDTH_BITS) as u16;
- let len = (head as usize) >> (Self::WIDTH_BITS + Self::KIND_BITS);
+ let len = (head as u32) >> (Self::WIDTH_BITS + Self::KIND_BITS);
Unpacked {
len: len.checked_sub(1),
@@ -378,7 +389,7 @@ fn unpack(&self) -> Unpacked {
}
#[inline]
- fn len(&self) -> Option<usize> {
+ fn len(&self) -> Option<u32> {
self.unpack().len
}
@@ -421,7 +432,8 @@ fn encode<D: Deps>(&self, e: &mut FileEncoder) {
e.write_array(header.bytes);
if header.len().is_none() {
- e.emit_usize(edges.len());
+ // The edges are all unique and the number of unique indices is less than u32::MAX.
+ e.emit_u32(edges.len().try_into().unwrap());
}
let bytes_per_index = header.bytes_per_index();
@@ -456,7 +468,8 @@ fn encode_promoted<D: Deps>(
e.write_array(header.bytes);
if header.len().is_none() {
- e.emit_usize(edge_count);
+ // The edges are all unique and the number of unique indices is less than u32::MAX.
+ e.emit_u32(edge_count.try_into().unwrap());
}
let bytes_per_index = header.bytes_per_index();
@@ -601,7 +614,7 @@ fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult {
stats: _,
kind_stats,
marker: _,
- previous: _,
+ previous,
} = self;
let node_count = total_node_count.try_into().unwrap();
@@ -612,6 +625,8 @@ fn finish(self, profiler: &SelfProfilerRef) -> FileEncodeResult {
count.encode(&mut encoder);
}
+ previous.session_count.checked_add(1).unwrap().encode(&mut encoder);
+
debug!(?node_count, ?edge_count);
debug!("position: {:?}", encoder.position());
IntEncodedWithFixedSize(node_count).encode(&mut encoder);
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 3f3b455..762e08b 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -1012,7 +1012,7 @@ fn finalize_import(&mut self, import: Import<'ra>) -> Option<UnresolvedImportErr
// HACK(eddyb) `lint_if_path_starts_with_module` needs at least
// 2 segments, so the `resolve_path` above won't trigger it.
let mut full_path = import.module_path.clone();
- full_path.push(Segment::from_ident(Ident::empty()));
+ full_path.push(Segment::from_ident(Ident::dummy()));
self.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
}
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index a7170ed..bae2fde 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1948,7 +1948,7 @@ fn resolve_elided_lifetime(&mut self, anchor_id: NodeId, span: Span) {
self.record_lifetime_res(
anchor_id,
- LifetimeRes::ElidedAnchor { start: id, end: NodeId::from_u32(id.as_u32() + 1) },
+ LifetimeRes::ElidedAnchor { start: id, end: id + 1 },
LifetimeElisionCandidate::Ignore,
);
self.resolve_anonymous_lifetime(<, anchor_id, true);
@@ -4606,6 +4606,11 @@ fn resolve_qpath(
}
};
+ // Fix up partial res of segment from `resolve_path` call.
+ if let Some(id) = path[0].id {
+ self.r.partial_res_map.insert(id, PartialRes::new(Res::PrimTy(prim)));
+ }
+
PartialRes::with_unresolved_segments(Res::PrimTy(prim), path.len() - 1)
}
PathResult::Module(ModuleOrUniformRoot::Module(module)) => {
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index c2761bd..d4fe446 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1994,7 +1994,7 @@ fn suggest_alternative_construction_methods(
.iter()
.flat_map(|i| self.r.tcx.associated_items(i).in_definition_order())
// Only assoc fn with no receivers.
- .filter(|item| matches!(item.kind, ty::AssocKind::Fn) && !item.fn_has_self_parameter)
+ .filter(|item| item.is_fn() && !item.is_method())
.filter_map(|item| {
// Only assoc fns that return `Self`
let fn_sig = self.r.tcx.fn_sig(item.def_id).skip_binder();
@@ -2007,8 +2007,9 @@ fn suggest_alternative_construction_methods(
if def.did() != def_id {
return None;
}
- let order = !item.name.as_str().starts_with("new");
- Some((order, item.name, input_len))
+ let name = item.name();
+ let order = !name.as_str().starts_with("new");
+ Some((order, name, input_len))
})
.collect::<Vec<_>>();
items.sort_by_key(|(order, _, _)| *order);
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index a92912c..b121755 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -2007,16 +2007,16 @@ fn resolve_crate_root(&mut self, ident: Ident) -> Module<'ra> {
result,
result.map(|r| r.expn_data())
);
- // Then find the last semi-transparent mark from the end if it exists.
+ // Then find the last semi-opaque mark from the end if it exists.
for (mark, transparency) in iter {
- if transparency == Transparency::SemiTransparent {
+ if transparency == Transparency::SemiOpaque {
result = Some(mark);
} else {
break;
}
}
debug!(
- "resolve_crate_root: found semi-transparent mark {:?} {:?}",
+ "resolve_crate_root: found semi-opaque mark {:?} {:?}",
result,
result.map(|r| r.expn_data())
);
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 749b7f2..c58f848 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -8,7 +8,7 @@
use rustc_ast::expand::StrippedCfgItem;
use rustc_ast::{self as ast, Crate, NodeId, attr};
use rustc_ast_pretty::pprust;
-use rustc_attr_parsing::{AttributeKind, StabilityLevel, find_attr};
+use rustc_attr_parsing::StabilityLevel;
use rustc_data_structures::intern::Interned;
use rustc_errors::{Applicability, DiagCtxtHandle, StashKey};
use rustc_expand::base::{
@@ -1128,13 +1128,6 @@ pub(crate) fn compile_macro(
edition,
);
- // The #[rustc_macro_edition_2021] attribute is used by the pin!() macro
- // as a temporary workaround for a regression in expressiveness in Rust 2024.
- // See https://github.com/rust-lang/rust/issues/138718.
- if find_attr!(attrs.iter(), AttributeKind::RustcMacroEdition2021) {
- ext.edition = Edition::Edition2021;
- }
-
if let Some(builtin_name) = ext.builtin_name {
// The macro was marked with `#[rustc_builtin_macro]`.
if let Some(builtin_ext_kind) = self.builtin_macros.get(&builtin_name) {
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
index 129a32c..d291747 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
@@ -240,7 +240,7 @@ fn trait_object_ty<'tcx>(tcx: TyCtxt<'tcx>, poly_trait_ref: ty::PolyTraitRef<'tc
.flat_map(|super_poly_trait_ref| {
tcx.associated_items(super_poly_trait_ref.def_id())
.in_definition_order()
- .filter(|item| item.kind == ty::AssocKind::Type)
+ .filter(|item| item.is_type())
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
.map(move |assoc_ty| {
super_poly_trait_ref.map_bound(|super_trait_ref| {
@@ -446,7 +446,7 @@ pub(crate) fn transform_instance<'tcx>(
let call = tcx
.associated_items(trait_id)
.in_definition_order()
- .find(|it| it.kind == ty::AssocKind::Fn)
+ .find(|it| it.is_fn())
.expect("No call-family function on closure-like Fn trait?")
.def_id;
diff --git a/compiler/rustc_sanitizers/src/lib.rs b/compiler/rustc_sanitizers/src/lib.rs
index c4a9cab..e479256 100644
--- a/compiler/rustc_sanitizers/src/lib.rs
+++ b/compiler/rustc_sanitizers/src/lib.rs
@@ -4,7 +4,6 @@
//! compiler.
// tidy-alphabetical-start
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(let_chains)]
// tidy-alphabetical-end
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index 81f6266..0a55504 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -19,7 +19,7 @@
pub const MAGIC_END_BYTES: &[u8] = b"rust-end-file";
/// The size of the buffer in `FileEncoder`.
-const BUF_SIZE: usize = 8192;
+const BUF_SIZE: usize = 64 * 1024;
/// `FileEncoder` encodes data to file via fixed-size buffer.
///
diff --git a/compiler/rustc_session/src/code_stats.rs b/compiler/rustc_session/src/code_stats.rs
index b4597ae..80603b4 100644
--- a/compiler/rustc_session/src/code_stats.rs
+++ b/compiler/rustc_session/src/code_stats.rs
@@ -72,7 +72,9 @@ pub struct TypeSizeInfo {
#[derive(Default)]
pub struct CodeStats {
- type_sizes: Lock<FxHashSet<TypeSizeInfo>>,
+ /// The hash set that actually holds all the type size information.
+ /// The field is public for use in external tools. See #139876.
+ pub type_sizes: Lock<FxHashSet<TypeSizeInfo>>,
}
impl CodeStats {
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index bdd54a1..bc92b95 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -14,6 +14,7 @@
use std::sync::LazyLock;
use std::{cmp, fmt, fs, iter};
+use externs::{ExternOpt, split_extern_opt};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
use rustc_errors::emitter::HumanReadableErrorType;
@@ -39,6 +40,7 @@
use crate::{EarlyDiagCtxt, HashStableContext, Session, filesearch, lint};
mod cfg;
+mod externs;
mod native_libs;
pub mod sigpipe;
@@ -566,122 +568,203 @@ fn from_str(s: &str) -> Result<Self, ()> {
}
}
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
-#[derive(Encodable, Decodable)]
-pub enum OutputType {
- /// This is the optimized bitcode, which could be either pre-LTO or non-LTO bitcode,
- /// depending on the specific request type.
- Bitcode,
- /// This is the summary or index data part of the ThinLTO bitcode.
- ThinLinkBitcode,
- Assembly,
- LlvmAssembly,
- Mir,
- Metadata,
- Object,
- Exe,
- DepInfo,
-}
+macro_rules! define_output_types {
+ (
+ $(
+ $(#[doc = $doc:expr])*
+ $Variant:ident => {
+ shorthand: $shorthand:expr,
+ extension: $extension:expr,
+ description: $description:expr,
+ default_filename: $default_filename:expr,
+ is_text: $is_text:expr,
+ compatible_with_cgus_and_single_output: $compatible:expr
+ }
+ ),* $(,)?
+ ) => {
+ #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, PartialOrd, Ord, HashStable_Generic)]
+ #[derive(Encodable, Decodable)]
+ pub enum OutputType {
+ $(
+ $(#[doc = $doc])*
+ $Variant,
+ )*
+ }
-impl StableOrd for OutputType {
- const CAN_USE_UNSTABLE_SORT: bool = true;
- // Trivial C-Style enums have a stable sort order across compilation sessions.
- const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
-}
+ impl StableOrd for OutputType {
+ const CAN_USE_UNSTABLE_SORT: bool = true;
-impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
- type KeyType = Self;
+ // Trivial C-Style enums have a stable sort order across compilation sessions.
+ const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
+ }
- fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
- *self
+ impl<HCX: HashStableContext> ToStableHashKey<HCX> for OutputType {
+ type KeyType = Self;
+
+ fn to_stable_hash_key(&self, _: &HCX) -> Self::KeyType {
+ *self
+ }
+ }
+
+
+ impl OutputType {
+ pub fn iter_all() -> impl Iterator<Item = OutputType> {
+ static ALL_VARIANTS: &[OutputType] = &[
+ $(
+ OutputType::$Variant,
+ )*
+ ];
+ ALL_VARIANTS.iter().copied()
+ }
+
+ fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
+ match *self {
+ $(
+ OutputType::$Variant => $compatible,
+ )*
+ }
+ }
+
+ pub fn shorthand(&self) -> &'static str {
+ match *self {
+ $(
+ OutputType::$Variant => $shorthand,
+ )*
+ }
+ }
+
+ fn from_shorthand(shorthand: &str) -> Option<Self> {
+ match shorthand {
+ $(
+ s if s == $shorthand => Some(OutputType::$Variant),
+ )*
+ _ => None,
+ }
+ }
+
+ fn shorthands_display() -> String {
+ let shorthands = vec![
+ $(
+ format!("`{}`", $shorthand),
+ )*
+ ];
+ shorthands.join(", ")
+ }
+
+ pub fn extension(&self) -> &'static str {
+ match *self {
+ $(
+ OutputType::$Variant => $extension,
+ )*
+ }
+ }
+
+ pub fn is_text_output(&self) -> bool {
+ match *self {
+ $(
+ OutputType::$Variant => $is_text,
+ )*
+ }
+ }
+
+ pub fn description(&self) -> &'static str {
+ match *self {
+ $(
+ OutputType::$Variant => $description,
+ )*
+ }
+ }
+
+ pub fn default_filename(&self) -> &'static str {
+ match *self {
+ $(
+ OutputType::$Variant => $default_filename,
+ )*
+ }
+ }
+
+
+ }
}
}
-impl OutputType {
- fn is_compatible_with_codegen_units_and_single_output_file(&self) -> bool {
- match *self {
- OutputType::Exe | OutputType::DepInfo | OutputType::Metadata => true,
- OutputType::Bitcode
- | OutputType::ThinLinkBitcode
- | OutputType::Assembly
- | OutputType::LlvmAssembly
- | OutputType::Mir
- | OutputType::Object => false,
- }
- }
-
- pub fn shorthand(&self) -> &'static str {
- match *self {
- OutputType::Bitcode => "llvm-bc",
- OutputType::ThinLinkBitcode => "thin-link-bitcode",
- OutputType::Assembly => "asm",
- OutputType::LlvmAssembly => "llvm-ir",
- OutputType::Mir => "mir",
- OutputType::Object => "obj",
- OutputType::Metadata => "metadata",
- OutputType::Exe => "link",
- OutputType::DepInfo => "dep-info",
- }
- }
-
- fn from_shorthand(shorthand: &str) -> Option<Self> {
- Some(match shorthand {
- "asm" => OutputType::Assembly,
- "llvm-ir" => OutputType::LlvmAssembly,
- "mir" => OutputType::Mir,
- "llvm-bc" => OutputType::Bitcode,
- "thin-link-bitcode" => OutputType::ThinLinkBitcode,
- "obj" => OutputType::Object,
- "metadata" => OutputType::Metadata,
- "link" => OutputType::Exe,
- "dep-info" => OutputType::DepInfo,
- _ => return None,
- })
- }
-
- fn shorthands_display() -> String {
- format!(
- "`{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`, `{}`",
- OutputType::Bitcode.shorthand(),
- OutputType::ThinLinkBitcode.shorthand(),
- OutputType::Assembly.shorthand(),
- OutputType::LlvmAssembly.shorthand(),
- OutputType::Mir.shorthand(),
- OutputType::Object.shorthand(),
- OutputType::Metadata.shorthand(),
- OutputType::Exe.shorthand(),
- OutputType::DepInfo.shorthand(),
- )
- }
-
- pub fn extension(&self) -> &'static str {
- match *self {
- OutputType::Bitcode => "bc",
- OutputType::ThinLinkBitcode => "indexing.o",
- OutputType::Assembly => "s",
- OutputType::LlvmAssembly => "ll",
- OutputType::Mir => "mir",
- OutputType::Object => "o",
- OutputType::Metadata => "rmeta",
- OutputType::DepInfo => "d",
- OutputType::Exe => "",
- }
- }
-
- pub fn is_text_output(&self) -> bool {
- match *self {
- OutputType::Assembly
- | OutputType::LlvmAssembly
- | OutputType::Mir
- | OutputType::DepInfo => true,
- OutputType::Bitcode
- | OutputType::ThinLinkBitcode
- | OutputType::Object
- | OutputType::Metadata
- | OutputType::Exe => false,
- }
- }
+define_output_types! {
+ Assembly => {
+ shorthand: "asm",
+ extension: "s",
+ description: "Generates a file with the crate's assembly code",
+ default_filename: "CRATE_NAME.s",
+ is_text: true,
+ compatible_with_cgus_and_single_output: false
+ },
+ #[doc = "This is the optimized bitcode, which could be either pre-LTO or non-LTO bitcode,"]
+ #[doc = "depending on the specific request type."]
+ Bitcode => {
+ shorthand: "llvm-bc",
+ extension: "bc",
+ description: "Generates a binary file containing the LLVM bitcode",
+ default_filename: "CRATE_NAME.bc",
+ is_text: false,
+ compatible_with_cgus_and_single_output: false
+ },
+ DepInfo => {
+ shorthand: "dep-info",
+ extension: "d",
+ description: "Generates a file with Makefile syntax that indicates all the source files that were loaded to generate the crate",
+ default_filename: "CRATE_NAME.d",
+ is_text: true,
+ compatible_with_cgus_and_single_output: true
+ },
+ Exe => {
+ shorthand: "link",
+ extension: "",
+ description: "Generates the crates specified by --crate-type. This is the default if --emit is not specified",
+ default_filename: "(platform and crate-type dependent)",
+ is_text: false,
+ compatible_with_cgus_and_single_output: true
+ },
+ LlvmAssembly => {
+ shorthand: "llvm-ir",
+ extension: "ll",
+ description: "Generates a file containing LLVM IR",
+ default_filename: "CRATE_NAME.ll",
+ is_text: true,
+ compatible_with_cgus_and_single_output: false
+ },
+ Metadata => {
+ shorthand: "metadata",
+ extension: "rmeta",
+ description: "Generates a file containing metadata about the crate",
+ default_filename: "libCRATE_NAME.rmeta",
+ is_text: false,
+ compatible_with_cgus_and_single_output: true
+ },
+ Mir => {
+ shorthand: "mir",
+ extension: "mir",
+ description: "Generates a file containing rustc's mid-level intermediate representation",
+ default_filename: "CRATE_NAME.mir",
+ is_text: true,
+ compatible_with_cgus_and_single_output: false
+ },
+ Object => {
+ shorthand: "obj",
+ extension: "o",
+ description: "Generates a native object file",
+ default_filename: "CRATE_NAME.o",
+ is_text: false,
+ compatible_with_cgus_and_single_output: false
+ },
+ #[doc = "This is the summary or index data part of the ThinLTO bitcode."]
+ ThinLinkBitcode => {
+ shorthand: "thin-link-bitcode",
+ extension: "indexing.o",
+ description: "Generates the ThinLTO summary as bitcode",
+ default_filename: "CRATE_NAME.indexing.o",
+ is_text: false,
+ compatible_with_cgus_and_single_output: false
+ },
}
/// The type of diagnostics output to generate.
@@ -1560,13 +1643,26 @@ pub fn make_opt(
)
});
-static PRINT_KINDS_STRING: LazyLock<String> = LazyLock::new(|| {
+static PRINT_HELP: LazyLock<String> = LazyLock::new(|| {
format!(
- "[{}]",
+ "Compiler information to print on stdout (or to a file)\n\
+ INFO may be one of ({}).",
PRINT_KINDS.iter().map(|(name, _)| format!("{name}")).collect::<Vec<_>>().join("|")
)
});
+static EMIT_HELP: LazyLock<String> = LazyLock::new(|| {
+ let mut result =
+ String::from("Comma separated list of types of output for the compiler to emit.\n");
+ result.push_str("Each TYPE has the default FILE name:\n");
+
+ for output in OutputType::iter_all() {
+ result.push_str(&format!("* {} - {}\n", output.shorthand(), output.default_filename()));
+ }
+
+ result
+});
+
/// Returns all rustc command line options, including metadata for
/// each option, such as whether the option is stable.
pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
@@ -1613,22 +1709,8 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
make_crate_type_option(),
opt(Stable, Opt, "", "crate-name", "Specify the name of the crate being built", "NAME"),
opt(Stable, Opt, "", "edition", &EDITION_STRING, EDITION_NAME_LIST),
- opt(
- Stable,
- Multi,
- "",
- "emit",
- "Comma separated list of types of output for the compiler to emit",
- "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]",
- ),
- opt(
- Stable,
- Multi,
- "",
- "print",
- "Compiler information to print on stdout",
- &PRINT_KINDS_STRING,
- ),
+ opt(Stable, Multi, "", "emit", &EMIT_HELP, "TYPE[=FILE]"),
+ opt(Stable, Multi, "", "print", &PRINT_HELP, "INFO[=FILE]"),
opt(Stable, FlagMulti, "g", "", "Equivalent to -C debuginfo=2", ""),
opt(Stable, FlagMulti, "O", "", "Equivalent to -C opt-level=3", ""),
opt(Stable, Opt, "o", "", "Write output to <filename>", "FILENAME"),
@@ -2069,7 +2151,8 @@ fn collect_print_requests(
check_print_request_stability(early_dcx, unstable_opts, (print_name, *print_kind));
*print_kind
} else {
- emit_unknown_print_request_help(early_dcx, req)
+ let is_nightly = nightly_options::match_is_nightly_build(matches);
+ emit_unknown_print_request_help(early_dcx, req, is_nightly)
};
let out = out.unwrap_or(OutFileName::Stdout);
@@ -2093,25 +2176,37 @@ fn check_print_request_stability(
unstable_opts: &UnstableOptions,
(print_name, print_kind): (&str, PrintKind),
) {
+ if !is_print_request_stable(print_kind) && !unstable_opts.unstable_options {
+ early_dcx.early_fatal(format!(
+ "the `-Z unstable-options` flag must also be passed to enable the `{print_name}` \
+ print option"
+ ));
+ }
+}
+
+fn is_print_request_stable(print_kind: PrintKind) -> bool {
match print_kind {
PrintKind::AllTargetSpecsJson
| PrintKind::CheckCfg
| PrintKind::CrateRootLintLevels
| PrintKind::SupportedCrateTypes
- | PrintKind::TargetSpecJson
- if !unstable_opts.unstable_options =>
- {
- early_dcx.early_fatal(format!(
- "the `-Z unstable-options` flag must also be passed to enable the `{print_name}` \
- print option"
- ));
- }
- _ => {}
+ | PrintKind::TargetSpecJson => false,
+ _ => true,
}
}
-fn emit_unknown_print_request_help(early_dcx: &EarlyDiagCtxt, req: &str) -> ! {
- let prints = PRINT_KINDS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
+fn emit_unknown_print_request_help(early_dcx: &EarlyDiagCtxt, req: &str, is_nightly: bool) -> ! {
+ let prints = PRINT_KINDS
+ .iter()
+ .filter_map(|(name, kind)| {
+ // If we're not on nightly, we don't want to print unstable options
+ if !is_nightly && !is_print_request_stable(*kind) {
+ None
+ } else {
+ Some(format!("`{name}`"))
+ }
+ })
+ .collect::<Vec<_>>();
let prints = prints.join(", ");
let mut diag = early_dcx.early_struct_fatal(format!("unknown print request: `{req}`"));
@@ -2211,44 +2306,13 @@ pub fn parse_externs(
matches: &getopts::Matches,
unstable_opts: &UnstableOptions,
) -> Externs {
- fn is_ascii_ident(string: &str) -> bool {
- let mut chars = string.chars();
- if let Some(start) = chars.next()
- && (start.is_ascii_alphabetic() || start == '_')
- {
- chars.all(|char| char.is_ascii_alphanumeric() || char == '_')
- } else {
- false
- }
- }
-
let is_unstable_enabled = unstable_opts.unstable_options;
let mut externs: BTreeMap<String, ExternEntry> = BTreeMap::new();
for arg in matches.opt_strs("extern") {
- let (name, path) = match arg.split_once('=') {
- None => (arg, None),
- Some((name, path)) => (name.to_string(), Some(Path::new(path))),
- };
- let (options, name) = match name.split_once(':') {
- None => (None, name),
- Some((opts, name)) => (Some(opts), name.to_string()),
- };
+ let ExternOpt { crate_name: name, path, options } =
+ split_extern_opt(early_dcx, unstable_opts, &arg).unwrap_or_else(|e| e.emit());
- if !is_ascii_ident(&name) {
- let mut error = early_dcx.early_struct_fatal(format!(
- "crate name `{name}` passed to `--extern` is not a valid ASCII identifier"
- ));
- let adjusted_name = name.replace('-', "_");
- if is_ascii_ident(&adjusted_name) {
- #[allow(rustc::diagnostic_outside_of_impl)] // FIXME
- error.help(format!(
- "consider replacing the dashes with underscores: `{adjusted_name}`"
- ));
- }
- error.emit();
- }
-
- let path = path.map(|p| CanonicalizedPath::new(p));
+ let path = path.map(|p| CanonicalizedPath::new(p.as_path()));
let entry = externs.entry(name.to_owned());
diff --git a/compiler/rustc_session/src/config/externs.rs b/compiler/rustc_session/src/config/externs.rs
new file mode 100644
index 0000000..1420ee3
--- /dev/null
+++ b/compiler/rustc_session/src/config/externs.rs
@@ -0,0 +1,79 @@
+//! This module contains code to help parse and manipulate `--extern` arguments.
+
+use std::path::PathBuf;
+
+use rustc_errors::{Diag, FatalAbort};
+
+use super::UnstableOptions;
+use crate::EarlyDiagCtxt;
+
+#[cfg(test)]
+mod tests;
+
+/// Represents the pieces of an `--extern` argument.
+pub(crate) struct ExternOpt {
+ pub(crate) crate_name: String,
+ pub(crate) path: Option<PathBuf>,
+ pub(crate) options: Option<String>,
+}
+
+/// Breaks out the major components of an `--extern` argument.
+///
+/// The options field will be a string containing comma-separated options that will need further
+/// parsing and processing.
+pub(crate) fn split_extern_opt<'a>(
+ early_dcx: &'a EarlyDiagCtxt,
+ unstable_opts: &UnstableOptions,
+ extern_opt: &str,
+) -> Result<ExternOpt, Diag<'a, FatalAbort>> {
+ let (name, path) = match extern_opt.split_once('=') {
+ None => (extern_opt.to_string(), None),
+ Some((name, path)) => (name.to_string(), Some(PathBuf::from(path))),
+ };
+ let (options, crate_name) = match name.split_once(':') {
+ None => (None, name),
+ Some((opts, crate_name)) => {
+ if unstable_opts.namespaced_crates && crate_name.starts_with(':') {
+ // If the name starts with `:`, we know this was actually something like `foo::bar` and
+ // not a set of options. We can just use the original name as the crate name.
+ (None, name)
+ } else {
+ (Some(opts.to_string()), crate_name.to_string())
+ }
+ }
+ };
+
+ if !valid_crate_name(&crate_name, unstable_opts) {
+ let mut error = early_dcx.early_struct_fatal(format!(
+ "crate name `{crate_name}` passed to `--extern` is not a valid ASCII identifier"
+ ));
+ let adjusted_name = crate_name.replace('-', "_");
+ if is_ascii_ident(&adjusted_name) {
+ #[allow(rustc::diagnostic_outside_of_impl)] // FIXME
+ error
+ .help(format!("consider replacing the dashes with underscores: `{adjusted_name}`"));
+ }
+ return Err(error);
+ }
+
+ Ok(ExternOpt { crate_name, path, options })
+}
+
+fn valid_crate_name(name: &str, unstable_opts: &UnstableOptions) -> bool {
+ match name.split_once("::") {
+ Some((a, b)) if unstable_opts.namespaced_crates => is_ascii_ident(a) && is_ascii_ident(b),
+ Some(_) => false,
+ None => is_ascii_ident(name),
+ }
+}
+
+fn is_ascii_ident(string: &str) -> bool {
+ let mut chars = string.chars();
+ if let Some(start) = chars.next()
+ && (start.is_ascii_alphabetic() || start == '_')
+ {
+ chars.all(|char| char.is_ascii_alphanumeric() || char == '_')
+ } else {
+ false
+ }
+}
diff --git a/compiler/rustc_session/src/config/externs/tests.rs b/compiler/rustc_session/src/config/externs/tests.rs
new file mode 100644
index 0000000..6544886
--- /dev/null
+++ b/compiler/rustc_session/src/config/externs/tests.rs
@@ -0,0 +1,92 @@
+use std::path::PathBuf;
+
+use super::split_extern_opt;
+use crate::EarlyDiagCtxt;
+use crate::config::UnstableOptions;
+
+/// Verifies split_extern_opt handles the supported cases.
+#[test]
+fn test_split_extern_opt() {
+ let early_dcx = EarlyDiagCtxt::new(<_>::default());
+ let unstable_opts = &UnstableOptions::default();
+
+ let extern_opt =
+ split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo=libbar.rlib").unwrap();
+ assert_eq!(extern_opt.crate_name, "foo");
+ assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib")));
+ assert_eq!(extern_opt.options, Some("priv,noprelude".to_string()));
+
+ let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo").unwrap();
+ assert_eq!(extern_opt.crate_name, "foo");
+ assert_eq!(extern_opt.path, None);
+ assert_eq!(extern_opt.options, Some("priv,noprelude".to_string()));
+
+ let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo=libbar.rlib").unwrap();
+ assert_eq!(extern_opt.crate_name, "foo");
+ assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib")));
+ assert_eq!(extern_opt.options, None);
+
+ let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo").unwrap();
+ assert_eq!(extern_opt.crate_name, "foo");
+ assert_eq!(extern_opt.path, None);
+ assert_eq!(extern_opt.options, None);
+}
+
+/// Tests some invalid cases for split_extern_opt.
+#[test]
+fn test_split_extern_opt_invalid() {
+ let early_dcx = EarlyDiagCtxt::new(<_>::default());
+ let unstable_opts = &UnstableOptions::default();
+
+ // too many `:`s
+ let result = split_extern_opt(&early_dcx, unstable_opts, "priv:noprelude:foo=libbar.rlib");
+ assert!(result.is_err());
+ let _ = result.map_err(|e| e.cancel());
+
+ // can't nest externs without the unstable flag
+ let result = split_extern_opt(&early_dcx, unstable_opts, "noprelude:foo::bar=libbar.rlib");
+ assert!(result.is_err());
+ let _ = result.map_err(|e| e.cancel());
+}
+
+/// Tests some cases for split_extern_opt with nested crates like `foo::bar`.
+#[test]
+fn test_split_extern_opt_nested() {
+ let early_dcx = EarlyDiagCtxt::new(<_>::default());
+ let unstable_opts = &UnstableOptions { namespaced_crates: true, ..Default::default() };
+
+ let extern_opt =
+ split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo::bar=libbar.rlib").unwrap();
+ assert_eq!(extern_opt.crate_name, "foo::bar");
+ assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib")));
+ assert_eq!(extern_opt.options, Some("priv,noprelude".to_string()));
+
+ let extern_opt =
+ split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo::bar").unwrap();
+ assert_eq!(extern_opt.crate_name, "foo::bar");
+ assert_eq!(extern_opt.path, None);
+ assert_eq!(extern_opt.options, Some("priv,noprelude".to_string()));
+
+ let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo::bar=libbar.rlib").unwrap();
+ assert_eq!(extern_opt.crate_name, "foo::bar");
+ assert_eq!(extern_opt.path, Some(PathBuf::from("libbar.rlib")));
+ assert_eq!(extern_opt.options, None);
+
+ let extern_opt = split_extern_opt(&early_dcx, unstable_opts, "foo::bar").unwrap();
+ assert_eq!(extern_opt.crate_name, "foo::bar");
+ assert_eq!(extern_opt.path, None);
+ assert_eq!(extern_opt.options, None);
+}
+
+/// Tests some invalid cases for split_extern_opt with nested crates like `foo::bar`.
+#[test]
+fn test_split_extern_opt_nested_invalid() {
+ let early_dcx = EarlyDiagCtxt::new(<_>::default());
+ let unstable_opts = &UnstableOptions { namespaced_crates: true, ..Default::default() };
+
+ // crates can only be nested one deep.
+ let result =
+ split_extern_opt(&early_dcx, unstable_opts, "priv,noprelude:foo::bar::baz=libbar.rlib");
+ assert!(result.is_err());
+ let _ = result.map_err(|e| e.cancel());
+}
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index c70f150..36eee5f 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1956,6 +1956,9 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
"allow the linker to link its default libraries (default: no)"),
dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
"import library generation tool (ignored except when targeting windows-gnu)"),
+ #[rustc_lint_opt_deny_field_access("use `Session::dwarf_version` instead of this field")]
+ dwarf_version: Option<u32> = (None, parse_opt_number, [TRACKED],
+ "version of DWARF debug information to emit (default: 2 or 4, depending on platform)"),
embed_bitcode: bool = (true, parse_bool, [TRACKED],
"emit bitcode in rlibs (default: yes)"),
extra_filename: String = (String::new(), parse_string, [UNTRACKED],
@@ -2319,18 +2322,20 @@ pub(crate) fn parse_align(slot: &mut Option<Align>, v: Option<&str>) -> bool {
mir_include_spans: MirIncludeSpans = (MirIncludeSpans::default(), parse_mir_include_spans, [UNTRACKED],
"include extra comments in mir pretty printing, like line numbers and statement indices, \
details about types, etc. (boolean for all passes, 'nll' to enable in NLL MIR only, default: 'nll')"),
- mir_keep_place_mention: bool = (false, parse_bool, [TRACKED],
- "keep place mention MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
- (default: no)"),
#[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
"MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
+ mir_preserve_ub: bool = (false, parse_bool, [TRACKED],
+ "keep place mention statements and reads in trivial SwitchInt terminators, which are interpreted \
+ e.g., by miri; implies -Zmir-opt-level=0 (default: no)"),
mir_strip_debuginfo: MirStripDebugInfo = (MirStripDebugInfo::None, parse_mir_strip_debuginfo, [TRACKED],
"Whether to remove some of the MIR debug info from methods. Default: None"),
move_size_limit: Option<usize> = (None, parse_opt_number, [TRACKED],
"the size at which the `large_assignments` lint starts to be emitted"),
mutable_noalias: bool = (true, parse_bool, [TRACKED],
"emit noalias metadata for mutable references (default: yes)"),
+ namespaced_crates: bool = (false, parse_bool, [TRACKED],
+ "allow crates to be namespaced by other crates (default: no)"),
next_solver: NextSolverConfig = (NextSolverConfig::default(), parse_next_solver_config, [TRACKED],
"enable and configure the next generation trait solver used by rustc"),
nll_facts: bool = (false, parse_bool, [UNTRACKED],
diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs
index a24919e..46dae91 100644
--- a/compiler/rustc_session/src/output.rs
+++ b/compiler/rustc_session/src/output.rs
@@ -177,6 +177,13 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<C
// If we're generating a test executable, then ignore all other output
// styles at all other locations
if session.opts.test {
+ if !session.target.executables {
+ session.dcx().emit_warn(errors::UnsupportedCrateTypeForTarget {
+ crate_type: CrateType::Executable,
+ target_triple: &session.opts.target_triple,
+ });
+ return Vec::new();
+ }
return vec![CrateType::Executable];
}
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 1359f7e..010ae42 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -764,7 +764,11 @@ pub fn split_debuginfo(&self) -> SplitDebuginfo {
/// Returns the DWARF version passed on the CLI or the default for the target.
pub fn dwarf_version(&self) -> u32 {
- self.opts.unstable_opts.dwarf_version.unwrap_or(self.target.default_dwarf_version)
+ self.opts
+ .cg
+ .dwarf_version
+ .or(self.opts.unstable_opts.dwarf_version)
+ .unwrap_or(self.target.default_dwarf_version)
}
pub fn stack_protector(&self) -> StackProtector {
@@ -1327,7 +1331,9 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
sess.dcx().emit_err(errors::BranchProtectionRequiresAArch64);
}
- if let Some(dwarf_version) = sess.opts.unstable_opts.dwarf_version {
+ if let Some(dwarf_version) =
+ sess.opts.cg.dwarf_version.or(sess.opts.unstable_opts.dwarf_version)
+ {
// DWARF 1 is not supported by LLVM and DWARF 6 is not yet finalized.
if dwarf_version < 2 || dwarf_version > 5 {
sess.dcx().emit_err(errors::UnsupportedDwarfVersion { dwarf_version });
diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs
index 5d465bc..77e5f34 100644
--- a/compiler/rustc_smir/src/lib.rs
+++ b/compiler/rustc_smir/src/lib.rs
@@ -9,7 +9,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
#![allow(rustc::usage_of_ty_tykind)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(
html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/",
test(attr(allow(unused_variables), deny(warnings)))
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index a546a44..146ba17 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -244,6 +244,7 @@ pub fn run<F, T>(tcx: TyCtxt<'_>, f: F) -> Result<T, Error>
/// ```ignore(needs-extern-crate)
/// # extern crate rustc_driver;
/// # extern crate rustc_interface;
+/// # extern crate rustc_middle;
/// # #[macro_use]
/// # extern crate rustc_smir;
/// # extern crate stable_mir;
@@ -264,6 +265,7 @@ pub fn run<F, T>(tcx: TyCtxt<'_>, f: F) -> Result<T, Error>
/// ```ignore(needs-extern-crate)
/// # extern crate rustc_driver;
/// # extern crate rustc_interface;
+/// # extern crate rustc_middle;
/// # #[macro_use]
/// # extern crate rustc_smir;
/// # extern crate stable_mir;
@@ -328,6 +330,7 @@ macro_rules! run_driver {
use rustc_driver::{Callbacks, Compilation, run_compiler};
use rustc_middle::ty::TyCtxt;
use rustc_interface::interface;
+ use rustc_smir::rustc_internal;
use stable_mir::CompilerError;
use std::ops::ControlFlow;
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index 28fc68d..a757329 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -894,12 +894,21 @@ fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
impl<'tcx> Stable<'tcx> for ty::AssocKind {
type T = stable_mir::ty::AssocKind;
- fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
- use stable_mir::ty::AssocKind;
- match self {
- ty::AssocKind::Const => AssocKind::Const,
- ty::AssocKind::Fn => AssocKind::Fn,
- ty::AssocKind::Type => AssocKind::Type,
+ fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+ use stable_mir::ty::{AssocKind, AssocTypeData};
+ match *self {
+ ty::AssocKind::Const { name } => AssocKind::Const { name: name.to_string() },
+ ty::AssocKind::Fn { name, has_self } => {
+ AssocKind::Fn { name: name.to_string(), has_self }
+ }
+ ty::AssocKind::Type { data } => AssocKind::Type {
+ data: match data {
+ ty::AssocTypeData::Normal(name) => AssocTypeData::Normal(name.to_string()),
+ ty::AssocTypeData::Rpitit(rpitit) => {
+ AssocTypeData::Rpitit(rpitit.stable(tables))
+ }
+ },
+ },
}
}
}
@@ -922,12 +931,9 @@ impl<'tcx> Stable<'tcx> for ty::AssocItem {
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
stable_mir::ty::AssocItem {
def_id: tables.assoc_def(self.def_id),
- name: self.name.to_string(),
kind: self.kind.stable(tables),
container: self.container.stable(tables),
trait_item_def_id: self.trait_item_def_id.map(|did| tables.assoc_def(did)),
- fn_has_self_parameter: self.fn_has_self_parameter,
- opt_rpitit_info: self.opt_rpitit_info.map(|rpitit| rpitit.stable(tables)),
}
}
}
diff --git a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs
index 439ebe9..8a6be0c 100644
--- a/compiler/rustc_smir/src/stable_mir/mir/pretty.rs
+++ b/compiler/rustc_smir/src/stable_mir/mir/pretty.rs
@@ -22,9 +22,10 @@ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
impl Display for AssocKind {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
- AssocKind::Fn => write!(f, "method"),
- AssocKind::Const => write!(f, "associated const"),
- AssocKind::Type => write!(f, "associated type"),
+ AssocKind::Fn { has_self: true, .. } => write!(f, "method"),
+ AssocKind::Fn { has_self: false, .. } => write!(f, "associated function"),
+ AssocKind::Const { .. } => write!(f, "associated const"),
+ AssocKind::Type { .. } => write!(f, "associated type"),
}
}
}
diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs
index 3fcbbb0..4b15300 100644
--- a/compiler/rustc_smir/src/stable_mir/ty.rs
+++ b/compiler/rustc_smir/src/stable_mir/ty.rs
@@ -1578,29 +1578,28 @@ fn to_index(&self) -> usize {
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct AssocItem {
pub def_id: AssocDef,
- pub name: Symbol,
pub kind: AssocKind,
pub container: AssocItemContainer,
/// If this is an item in an impl of a trait then this is the `DefId` of
/// the associated item on the trait that this implements.
pub trait_item_def_id: Option<AssocDef>,
+}
- /// Whether this is a method with an explicit self
- /// as its first parameter, allowing method calls.
- pub fn_has_self_parameter: bool,
-
- /// `Some` if the associated item (an associated type) comes from the
- /// return-position `impl Trait` in trait desugaring. The `ImplTraitInTraitData`
- /// provides additional information about its source.
- pub opt_rpitit_info: Option<ImplTraitInTraitData>,
+#[derive(Clone, PartialEq, Debug, Eq, Serialize)]
+pub enum AssocTypeData {
+ Normal(Symbol),
+ /// The associated type comes from an RPITIT. It has no name, and the
+ /// `ImplTraitInTraitData` provides additional information about its
+ /// source.
+ Rpitit(ImplTraitInTraitData),
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum AssocKind {
- Const,
- Fn,
- Type,
+ Const { name: Symbol },
+ Fn { name: Symbol, has_self: bool },
+ Type { data: AssocTypeData },
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
@@ -1617,6 +1616,6 @@ pub enum ImplTraitInTraitData {
impl AssocItem {
pub fn is_impl_trait_in_trait(&self) -> bool {
- self.opt_rpitit_info.is_some()
+ matches!(self.kind, AssocKind::Type { data: AssocTypeData::Rpitit(_) })
}
}
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 9be16f8..5390891 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -56,44 +56,33 @@ impl !PartialOrd for SyntaxContext {}
/// If this part of two syntax contexts is equal, then the whole syntax contexts should be equal.
/// The other fields are only for caching.
-type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency);
+pub type SyntaxContextKey = (SyntaxContext, ExpnId, Transparency);
#[derive(Clone, Copy, Debug)]
struct SyntaxContextData {
outer_expn: ExpnId,
outer_transparency: Transparency,
parent: SyntaxContext,
- /// This context, but with all transparent and semi-transparent expansions filtered away.
+ /// This context, but with all transparent and semi-opaque expansions filtered away.
opaque: SyntaxContext,
/// This context, but with all transparent expansions filtered away.
- opaque_and_semitransparent: SyntaxContext,
+ opaque_and_semiopaque: SyntaxContext,
/// Name of the crate to which `$crate` with this context would resolve.
dollar_crate_name: Symbol,
}
-/// Same as `SyntaxContextData`, but `opaque(_and_semitransparent)` cannot be recursive
-/// and use `None` if they need to refer to self. Used for encoding and decoding metadata.
-#[derive(Encodable, Decodable)]
-pub struct SyntaxContextDataNonRecursive {
- outer_expn: ExpnId,
- outer_transparency: Transparency,
- parent: SyntaxContext,
- opaque: Option<SyntaxContext>,
- opaque_and_semitransparent: Option<SyntaxContext>,
-}
-
impl SyntaxContextData {
fn new(
(parent, outer_expn, outer_transparency): SyntaxContextKey,
opaque: SyntaxContext,
- opaque_and_semitransparent: SyntaxContext,
+ opaque_and_semiopaque: SyntaxContext,
) -> SyntaxContextData {
SyntaxContextData {
outer_expn,
outer_transparency,
parent,
opaque,
- opaque_and_semitransparent,
+ opaque_and_semiopaque,
dollar_crate_name: kw::DollarCrate,
}
}
@@ -104,7 +93,7 @@ fn root() -> SyntaxContextData {
outer_transparency: Transparency::Opaque,
parent: SyntaxContext::root(),
opaque: SyntaxContext::root(),
- opaque_and_semitransparent: SyntaxContext::root(),
+ opaque_and_semiopaque: SyntaxContext::root(),
dollar_crate_name: kw::DollarCrate,
}
}
@@ -122,19 +111,6 @@ fn key(&self) -> SyntaxContextKey {
}
}
-impl SyntaxContextDataNonRecursive {
- fn recursive(&self, ctxt: SyntaxContext) -> SyntaxContextData {
- SyntaxContextData {
- outer_expn: self.outer_expn,
- outer_transparency: self.outer_transparency,
- parent: self.parent,
- opaque: self.opaque.unwrap_or(ctxt),
- opaque_and_semitransparent: self.opaque_and_semitransparent.unwrap_or(ctxt),
- dollar_crate_name: kw::DollarCrate,
- }
- }
-}
-
rustc_index::newtype_index! {
/// A unique ID associated with a macro invocation and expansion.
#[orderable]
@@ -228,13 +204,13 @@ pub enum Transparency {
/// Identifier produced by a transparent expansion is always resolved at call-site.
/// Call-site spans in procedural macros, hygiene opt-out in `macro` should use this.
Transparent,
- /// Identifier produced by a semi-transparent expansion may be resolved
+ /// Identifier produced by a semi-opaque expansion may be resolved
/// either at call-site or at definition-site.
/// If it's a local variable, label or `$crate` then it's resolved at def-site.
/// Otherwise it's resolved at call-site.
/// `macro_rules` macros behave like this, built-in macros currently behave like this too,
/// but that's an implementation detail.
- SemiTransparent,
+ SemiOpaque,
/// Identifier produced by an opaque expansion is always resolved at definition-site.
/// Def-site spans in procedural macros, identifiers from `macro` by default use this.
Opaque,
@@ -242,7 +218,7 @@ pub enum Transparency {
impl Transparency {
pub fn fallback(macro_rules: bool) -> Self {
- if macro_rules { Transparency::SemiTransparent } else { Transparency::Opaque }
+ if macro_rules { Transparency::SemiOpaque } else { Transparency::Opaque }
}
}
@@ -490,7 +466,7 @@ fn normalize_to_macros_2_0(&self, ctxt: SyntaxContext) -> SyntaxContext {
fn normalize_to_macro_rules(&self, ctxt: SyntaxContext) -> SyntaxContext {
debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
- self.syntax_context_data[ctxt.0 as usize].opaque_and_semitransparent
+ self.syntax_context_data[ctxt.0 as usize].opaque_and_semiopaque
}
fn outer_expn(&self, ctxt: SyntaxContext) -> ExpnId {
@@ -583,7 +559,7 @@ fn apply_mark(
}
let call_site_ctxt = self.expn_data(expn_id).call_site.ctxt();
- let mut call_site_ctxt = if transparency == Transparency::SemiTransparent {
+ let mut call_site_ctxt = if transparency == Transparency::SemiOpaque {
self.normalize_to_macros_2_0(call_site_ctxt)
} else {
self.normalize_to_macro_rules(call_site_ctxt)
@@ -629,48 +605,34 @@ fn alloc_ctxt(
self.syntax_context_data.push(SyntaxContextData::decode_placeholder());
self.syntax_context_map.insert(key, ctxt);
- // Opaque and semi-transparent versions of the parent. Note that they may be equal to the
+ // Opaque and semi-opaque versions of the parent. Note that they may be equal to the
// parent itself. E.g. `parent_opaque` == `parent` if the expn chain contains only opaques,
- // and `parent_opaque_and_semitransparent` == `parent` if the expn contains only opaques
- // and semi-transparents.
+ // and `parent_opaque_and_semiopaque` == `parent` if the expn contains only (semi-)opaques.
let parent_opaque = self.syntax_context_data[parent.0 as usize].opaque;
- let parent_opaque_and_semitransparent =
- self.syntax_context_data[parent.0 as usize].opaque_and_semitransparent;
+ let parent_opaque_and_semiopaque =
+ self.syntax_context_data[parent.0 as usize].opaque_and_semiopaque;
- // Evaluate opaque and semi-transparent versions of the new syntax context.
- let (opaque, opaque_and_semitransparent) = match transparency {
- Transparency::Transparent => (parent_opaque, parent_opaque_and_semitransparent),
- Transparency::SemiTransparent => (
+ // Evaluate opaque and semi-opaque versions of the new syntax context.
+ let (opaque, opaque_and_semiopaque) = match transparency {
+ Transparency::Transparent => (parent_opaque, parent_opaque_and_semiopaque),
+ Transparency::SemiOpaque => (
parent_opaque,
- // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents.
- self.alloc_ctxt(parent_opaque_and_semitransparent, expn_id, transparency),
+ // Will be the same as `ctxt` if the expn chain contains only (semi-)opaques.
+ self.alloc_ctxt(parent_opaque_and_semiopaque, expn_id, transparency),
),
Transparency::Opaque => (
// Will be the same as `ctxt` if the expn chain contains only opaques.
self.alloc_ctxt(parent_opaque, expn_id, transparency),
- // Will be the same as `ctxt` if the expn chain contains only opaques and semi-transparents.
- self.alloc_ctxt(parent_opaque_and_semitransparent, expn_id, transparency),
+ // Will be the same as `ctxt` if the expn chain contains only (semi-)opaques.
+ self.alloc_ctxt(parent_opaque_and_semiopaque, expn_id, transparency),
),
};
// Fill the full data, now that we have it.
self.syntax_context_data[ctxt.as_u32() as usize] =
- SyntaxContextData::new(key, opaque, opaque_and_semitransparent);
+ SyntaxContextData::new(key, opaque, opaque_and_semiopaque);
ctxt
}
-
- fn non_recursive_ctxt(&self, ctxt: SyntaxContext) -> SyntaxContextDataNonRecursive {
- debug_assert!(!self.syntax_context_data[ctxt.0 as usize].is_decode_placeholder());
- let data = &self.syntax_context_data[ctxt.0 as usize];
- SyntaxContextDataNonRecursive {
- outer_expn: data.outer_expn,
- outer_transparency: data.outer_transparency,
- parent: data.parent,
- opaque: (data.opaque != ctxt).then_some(data.opaque),
- opaque_and_semitransparent: (data.opaque_and_semitransparent != ctxt)
- .then_some(data.opaque_and_semitransparent),
- }
- }
}
pub fn walk_chain(span: Span, to: SyntaxContext) -> Span {
@@ -1270,6 +1232,25 @@ pub fn descr(self) -> &'static str {
DesugaringKind::PatTyRange => "pattern type",
}
}
+
+ /// For use with `rustc_unimplemented` to support conditions
+ /// like `from_desugaring = "QuestionMark"`
+ pub fn matches(&self, value: &str) -> bool {
+ match self {
+ DesugaringKind::CondTemporary => value == "CondTemporary",
+ DesugaringKind::Async => value == "Async",
+ DesugaringKind::Await => value == "Await",
+ DesugaringKind::QuestionMark => value == "QuestionMark",
+ DesugaringKind::TryBlock => value == "TryBlock",
+ DesugaringKind::YeetExpr => value == "YeetExpr",
+ DesugaringKind::OpaqueTy => value == "OpaqueTy",
+ DesugaringKind::ForLoop => value == "ForLoop",
+ DesugaringKind::WhileLoop => value == "WhileLoop",
+ DesugaringKind::BoundModifier => value == "BoundModifier",
+ DesugaringKind::Contract => value == "Contract",
+ DesugaringKind::PatTyRange => value == "PatTyRange",
+ }
+ }
}
#[derive(Default)]
@@ -1300,7 +1281,7 @@ pub fn schedule_expn_data_for_encoding(&self, expn: ExpnId) {
pub fn encode<T>(
&self,
encoder: &mut T,
- mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextDataNonRecursive),
+ mut encode_ctxt: impl FnMut(&mut T, u32, &SyntaxContextKey),
mut encode_expn: impl FnMut(&mut T, ExpnId, &ExpnData, ExpnHash),
) {
// When we serialize a `SyntaxContextData`, we may end up serializing
@@ -1425,10 +1406,7 @@ pub fn decode_expn_id(
// to track which `SyntaxContext`s we have already decoded.
// The provided closure will be invoked to deserialize a `SyntaxContextData`
// if we haven't already seen the id of the `SyntaxContext` we are deserializing.
-pub fn decode_syntax_context<
- D: Decoder,
- F: FnOnce(&mut D, u32) -> SyntaxContextDataNonRecursive,
->(
+pub fn decode_syntax_context<D: Decoder, F: FnOnce(&mut D, u32) -> SyntaxContextKey>(
d: &mut D,
context: &HygieneDecodeContext,
decode_data: F,
@@ -1450,16 +1428,9 @@ pub fn decode_syntax_context<
// Don't try to decode data while holding the lock, since we need to
// be able to recursively decode a SyntaxContext
- let ctxt_data = decode_data(d, raw_id);
-
- let ctxt = HygieneData::with(|hygiene_data| {
- let ctxt_key = (ctxt_data.parent, ctxt_data.outer_expn, ctxt_data.outer_transparency);
- *hygiene_data.syntax_context_map.entry(ctxt_key).or_insert_with(|| {
- let ctxt = SyntaxContext::from_usize(hygiene_data.syntax_context_data.len());
- hygiene_data.syntax_context_data.push(ctxt_data.recursive(ctxt));
- ctxt
- })
- });
+ let (parent, expn_id, transparency) = decode_data(d, raw_id);
+ let ctxt =
+ HygieneData::with(|hygiene_data| hygiene_data.alloc_ctxt(parent, expn_id, transparency));
let mut inner = context.inner.lock();
let new_len = raw_id as usize + 1;
@@ -1471,12 +1442,21 @@ pub fn decode_syntax_context<
ctxt
}
-fn for_all_ctxts_in<F: FnMut(u32, SyntaxContext, &SyntaxContextDataNonRecursive)>(
+fn for_all_ctxts_in<F: FnMut(u32, SyntaxContext, &SyntaxContextKey)>(
ctxts: impl Iterator<Item = SyntaxContext>,
mut f: F,
) {
- let all_data: Vec<_> =
- HygieneData::with(|data| ctxts.map(|ctxt| (ctxt, data.non_recursive_ctxt(ctxt))).collect());
+ let all_data: Vec<_> = HygieneData::with(|data| {
+ ctxts
+ .map(|ctxt| {
+ (ctxt, {
+ let item = data.syntax_context_data[ctxt.0 as usize];
+ debug_assert!(!item.is_decode_placeholder());
+ item.key()
+ })
+ })
+ .collect()
+ });
for (ctxt, data) in all_data.into_iter() {
f(ctxt.0, ctxt, &data);
}
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index c95c03b..f788fd4 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -1117,7 +1117,7 @@ pub fn with_call_site_ctxt(self, expn_id: ExpnId) -> Span {
/// Equivalent of `Span::mixed_site` from the proc macro API,
/// except that the location is taken from the `self` span.
pub fn with_mixed_site_ctxt(self, expn_id: ExpnId) -> Span {
- self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent)
+ self.with_ctxt_from_mark(expn_id, Transparency::SemiOpaque)
}
/// Produces a span with the same location as `self` and context produced by a macro with the
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 6fdf8e4..0273bb0 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -633,6 +633,24 @@ pub fn span_extend_to_prev_char(&self, sp: Span, c: char, accept_newlines: bool)
sp
}
+ /// Extends the given `Span` to just before the previous occurrence of `c`. Return the same span
+ /// if an error occurred while retrieving the code snippet.
+ pub fn span_extend_to_prev_char_before(
+ &self,
+ sp: Span,
+ c: char,
+ accept_newlines: bool,
+ ) -> Span {
+ if let Ok(prev_source) = self.span_to_prev_source(sp) {
+ let prev_source = prev_source.rsplit(c).next().unwrap_or("");
+ if accept_newlines || !prev_source.contains('\n') {
+ return sp.with_lo(BytePos(sp.lo().0 - prev_source.len() as u32 - 1_u32));
+ }
+ }
+
+ sp
+ }
+
/// Extends the given `Span` to just after the previous occurrence of `pat` when surrounded by
/// whitespace. Returns None if the pattern could not be found or if an error occurred while
/// retrieving the code snippet.
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 986370f..32a5aff 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -372,6 +372,7 @@
SyncUnsafeCell,
T,
Target,
+ This,
ToOwned,
ToString,
TokenStream,
@@ -916,6 +917,7 @@
expf16,
expf32,
expf64,
+ explicit_extern_abis,
explicit_generic_args_with_impl_trait,
explicit_tail_calls,
export_name,
@@ -1068,7 +1070,6 @@
ge,
gen_blocks,
gen_future,
- gen_kill,
generator_clone,
generators,
generic_arg_infer,
@@ -1186,6 +1187,7 @@
instruction_set,
integer_: "integer", // underscore to avoid clashing with the function `sym::integer` below
integral,
+ internal_features,
into_async_iter_into_iter,
into_future,
into_iter,
@@ -1400,6 +1402,7 @@
naked,
naked_asm,
naked_functions,
+ naked_functions_rustic_abi,
naked_functions_target_feature,
name,
names,
@@ -1821,7 +1824,6 @@
rustc_lint_opt_ty,
rustc_lint_query_instability,
rustc_lint_untracked_query_information,
- rustc_macro_edition_2021,
rustc_macro_transparency,
rustc_main,
rustc_mir,
@@ -1882,6 +1884,7 @@
select_unpredictable,
self_in_typedefs,
self_struct_ctor,
+ semiopaque,
semitransparent,
sha2,
sha3,
@@ -2214,7 +2217,8 @@
unsafe_extern_blocks,
unsafe_fields,
unsafe_no_drop_flag,
- unsafe_pin_internals,
+ unsafe_pinned,
+ unsafe_unpin,
unsize,
unsized_const_param_ty,
unsized_const_params,
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index c9b1515..cc33974 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -89,7 +89,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(let_chains)]
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index d28f10b..f310aa6 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -615,7 +615,7 @@ fn print_dyn_existential(
cx.print_def_path(trait_ref.def_id, trait_ref.args)?;
}
ty::ExistentialPredicate::Projection(projection) => {
- let name = cx.tcx.associated_item(projection.def_id).name;
+ let name = cx.tcx.associated_item(projection.def_id).name();
cx.push("p");
cx.push_ident(name.as_str());
match projection.term.unpack() {
@@ -776,7 +776,7 @@ fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> {
self.push_disambiguator(
disambiguated_field.disambiguator as u64,
);
- self.push_ident(field_name.unwrap_or(kw::Empty).as_str());
+ self.push_ident(field_name.unwrap().as_str());
field.print(self)?;
}
diff --git a/compiler/rustc_target/src/spec/base/linux_musl.rs b/compiler/rustc_target/src/spec/base/linux_musl.rs
index 1a854fe..1bef602 100644
--- a/compiler/rustc_target/src/spec/base/linux_musl.rs
+++ b/compiler/rustc_target/src/spec/base/linux_musl.rs
@@ -1,12 +1,11 @@
use crate::spec::{LinkSelfContainedDefault, TargetOptions, base, crt_objects};
pub(crate) fn opts() -> TargetOptions {
- let mut base = base::linux::opts();
-
- base.env = "musl".into();
- base.pre_link_objects_self_contained = crt_objects::pre_musl_self_contained();
- base.post_link_objects_self_contained = crt_objects::post_musl_self_contained();
- base.link_self_contained = LinkSelfContainedDefault::InferredForMusl;
-
- base
+ TargetOptions {
+ env: "musl".into(),
+ pre_link_objects_self_contained: crt_objects::pre_musl_self_contained(),
+ post_link_objects_self_contained: crt_objects::post_musl_self_contained(),
+ link_self_contained: LinkSelfContainedDefault::InferredForMusl,
+ ..base::linux::opts()
+ }
}
diff --git a/compiler/rustc_target/src/spec/base/linux_ohos.rs b/compiler/rustc_target/src/spec/base/linux_ohos.rs
index 6f4d69a..1b7f1e1 100644
--- a/compiler/rustc_target/src/spec/base/linux_ohos.rs
+++ b/compiler/rustc_target/src/spec/base/linux_ohos.rs
@@ -1,12 +1,11 @@
use crate::spec::{TargetOptions, TlsModel, base};
pub(crate) fn opts() -> TargetOptions {
- let mut base = base::linux::opts();
-
- base.env = "ohos".into();
- base.crt_static_default = false;
- base.tls_model = TlsModel::Emulated;
- base.has_thread_local = false;
-
- base
+ TargetOptions {
+ env: "ohos".into(),
+ crt_static_default: false,
+ tls_model: TlsModel::Emulated,
+ has_thread_local: false,
+ ..base::linux::opts()
+ }
}
diff --git a/compiler/rustc_target/src/spec/base/lynxos178.rs b/compiler/rustc_target/src/spec/base/lynxos178.rs
new file mode 100644
index 0000000..b9434ff
--- /dev/null
+++ b/compiler/rustc_target/src/spec/base/lynxos178.rs
@@ -0,0 +1,31 @@
+use std::borrow::Cow;
+
+use crate::spec::{
+ PanicStrategy, RelocModel, RelroLevel, SplitDebuginfo, StackProbeType, TargetOptions, cvs,
+};
+
+pub(crate) fn opts() -> TargetOptions {
+ TargetOptions {
+ os: "lynxos178".into(),
+ dynamic_linking: false,
+ families: cvs!["unix"],
+ position_independent_executables: false,
+ static_position_independent_executables: false,
+ relro_level: RelroLevel::Full,
+ has_thread_local: false,
+ crt_static_respected: true,
+ panic_strategy: PanicStrategy::Abort,
+ linker: Some(Cow::Borrowed("x86_64-lynx-lynxos178-gcc")),
+ no_default_libraries: false,
+ eh_frame_header: false, // GNU ld (GNU Binutils) 2.37.50 does not support --eh-frame-hdr
+ max_atomic_width: Some(64),
+ supported_split_debuginfo: Cow::Borrowed(&[
+ SplitDebuginfo::Packed,
+ SplitDebuginfo::Unpacked,
+ SplitDebuginfo::Off,
+ ]),
+ relocation_model: RelocModel::Static,
+ stack_probes: StackProbeType::Inline,
+ ..Default::default()
+ }
+}
diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs
index 71b6528..b368d93 100644
--- a/compiler/rustc_target/src/spec/base/mod.rs
+++ b/compiler/rustc_target/src/spec/base/mod.rs
@@ -19,6 +19,7 @@
pub(crate) mod linux_ohos;
pub(crate) mod linux_uclibc;
pub(crate) mod linux_wasm;
+pub(crate) mod lynxos178;
pub(crate) mod msvc;
pub(crate) mod netbsd;
pub(crate) mod nto_qnx;
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 64171fc..3c769da 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -2078,6 +2078,7 @@ fn $module() {
("riscv32imafc-unknown-nuttx-elf", riscv32imafc_unknown_nuttx_elf),
("riscv64imac-unknown-nuttx-elf", riscv64imac_unknown_nuttx_elf),
("riscv64gc-unknown-nuttx-elf", riscv64gc_unknown_nuttx_elf),
+ ("x86_64-lynx-lynxos178", x86_64_lynx_lynxos178),
("x86_64-pc-cygwin", x86_64_pc_cygwin),
}
diff --git a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs
index 233a1c4..91ab311 100644
--- a/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_win7_windows_msvc.rs
@@ -7,6 +7,12 @@ pub(crate) fn target() -> Target {
base.cpu = "pentium4".into();
base.max_atomic_width = Some(64);
base.supported_sanitizers = SanitizerSet::ADDRESS;
+ // On Windows 7 32-bit, the alignment characteristic of the TLS Directory
+ // don't appear to be respected by the PE Loader, leading to crashes. As
+ // a result, let's disable has_thread_local to make sure TLS goes through
+ // the emulation layer.
+ // See https://github.com/rust-lang/rust/issues/138903
+ base.has_thread_local = false;
base.add_pre_link_args(
LinkerFlavor::Msvc(Lld::No),
diff --git a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs
index 9f02ed4..b9176c9 100644
--- a/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs
+++ b/compiler/rustc_target/src/spec/targets/riscv64_linux_android.rs
@@ -19,7 +19,7 @@ pub(crate) fn target() -> Target {
options: TargetOptions {
code_model: Some(CodeModel::Medium),
cpu: "generic-rv64".into(),
- features: "+m,+a,+f,+d,+c,+zicsr,+zifencei,+zba,+zbb,+zbs,+v".into(),
+ features: "+m,+a,+f,+d,+c,+b,+v,+zicsr,+zifencei".into(),
llvm_abiname: "lp64d".into(),
supported_sanitizers: SanitizerSet::ADDRESS,
max_atomic_width: Some(64),
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_lynx_lynxos178.rs b/compiler/rustc_target/src/spec/targets/x86_64_lynx_lynxos178.rs
new file mode 100644
index 0000000..654ae7c
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/x86_64_lynx_lynxos178.rs
@@ -0,0 +1,34 @@
+use crate::spec::{SanitizerSet, StackProbeType, Target, base};
+
+pub(crate) fn target() -> Target {
+ let mut base = base::lynxos178::opts();
+ base.cpu = "x86-64".into();
+ base.plt_by_default = false;
+ base.max_atomic_width = Some(64);
+ base.stack_probes = StackProbeType::Inline;
+ base.static_position_independent_executables = false;
+ base.supported_sanitizers = SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
+ | SanitizerSet::KCFI
+ | SanitizerSet::DATAFLOW
+ | SanitizerSet::LEAK
+ | SanitizerSet::MEMORY
+ | SanitizerSet::SAFESTACK
+ | SanitizerSet::THREAD;
+ base.supports_xray = true;
+
+ Target {
+ llvm_target: "x86_64-unknown-unknown-gnu".into(),
+ metadata: crate::spec::TargetMetadata {
+ description: Some("LynxOS-178".into()),
+ tier: Some(3),
+ host_tools: Some(false),
+ std: Some(false),
+ },
+ pointer_width: 64,
+ data_layout:
+ "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(),
+ arch: "x86_64".into(),
+ options: base,
+ }
+}
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index b4ec187..0700521 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -491,7 +491,8 @@ pub fn toggle_allowed(&self) -> Result<(), &'static str> {
static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
// tidy-alphabetical-start
("a", Stable, &["zaamo", "zalrsc"]),
- ("c", Stable, &[]),
+ ("b", Unstable(sym::riscv_target_feature), &["zba", "zbb", "zbs"]),
+ ("c", Stable, &["zca"]),
("d", Unstable(sym::riscv_target_feature), &["f"]),
("e", Unstable(sym::riscv_target_feature), &[]),
("f", Unstable(sym::riscv_target_feature), &["zicsr"]),
@@ -520,17 +521,25 @@ pub fn toggle_allowed(&self) -> Result<(), &'static str> {
("zbkc", Stable, &[]),
("zbkx", Stable, &[]),
("zbs", Stable, &[]),
+ ("zca", Unstable(sym::riscv_target_feature), &[]),
+ ("zcb", Unstable(sym::riscv_target_feature), &["zca"]),
+ ("zcmop", Unstable(sym::riscv_target_feature), &["zca"]),
("zdinx", Unstable(sym::riscv_target_feature), &["zfinx"]),
+ ("zfa", Unstable(sym::riscv_target_feature), &["f"]),
("zfh", Unstable(sym::riscv_target_feature), &["zfhmin"]),
("zfhmin", Unstable(sym::riscv_target_feature), &["f"]),
("zfinx", Unstable(sym::riscv_target_feature), &["zicsr"]),
("zhinx", Unstable(sym::riscv_target_feature), &["zhinxmin"]),
("zhinxmin", Unstable(sym::riscv_target_feature), &["zfinx"]),
+ ("zicboz", Unstable(sym::riscv_target_feature), &[]),
("zicntr", Unstable(sym::riscv_target_feature), &["zicsr"]),
+ ("zicond", Unstable(sym::riscv_target_feature), &[]),
("zicsr", Unstable(sym::riscv_target_feature), &[]),
("zifencei", Unstable(sym::riscv_target_feature), &[]),
+ ("zihintntl", Unstable(sym::riscv_target_feature), &[]),
("zihintpause", Unstable(sym::riscv_target_feature), &[]),
("zihpm", Unstable(sym::riscv_target_feature), &["zicsr"]),
+ ("zimop", Unstable(sym::riscv_target_feature), &[]),
("zk", Stable, &["zkn", "zkr", "zkt"]),
("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]),
("zknd", Stable, &[]),
@@ -541,6 +550,7 @@ pub fn toggle_allowed(&self) -> Result<(), &'static str> {
("zksed", Stable, &[]),
("zksh", Stable, &[]),
("zkt", Stable, &[]),
+ ("ztso", Unstable(sym::riscv_target_feature), &[]),
("zvbb", Unstable(sym::riscv_target_feature), &["zvkb"]),
("zvbc", Unstable(sym::riscv_target_feature), &["zve64x"]),
("zve32f", Unstable(sym::riscv_target_feature), &["zve32x", "f"]),
@@ -765,7 +775,7 @@ pub fn all_rust_features() -> impl Iterator<Item = (&'static str, Stability)> {
(32768, "zvl32768b"),
(65536, "zvl65536b"),
];
-// Always warn on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
+// Always error on SPARC, as the necessary target features cannot be enabled in Rust at the moment.
const SPARC_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] = &[/*(64, "vis")*/];
const HEXAGON_FEATURES_FOR_CORRECT_VECTOR_ABI: &'static [(u64, &'static str)] =
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 05bbb42..74e38f5 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -268,8 +268,8 @@
trait_selection_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds
.label = opaque type defined here
trait_selection_opaque_type_non_generic_param =
- expected generic {$kind} parameter, found `{$ty}`
- .label = {STREQ($ty, "'static") ->
+ expected generic {$kind} parameter, found `{$arg}`
+ .label = {STREQ($arg, "'static") ->
[true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
*[other] this generic parameter must be used with a generic {$kind} parameter
}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 40f8af1..fdd5474 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -2334,13 +2334,13 @@ fn as_failure_code_diag(
subdiags: Vec<TypeErrorAdditionalDiags>,
) -> ObligationCauseFailureCode {
match self.code() {
- ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => {
+ ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => {
ObligationCauseFailureCode::MethodCompat { span, subdiags }
}
- ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => {
+ ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => {
ObligationCauseFailureCode::TypeCompat { span, subdiags }
}
- ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
+ ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => {
ObligationCauseFailureCode::ConstCompat { span, subdiags }
}
ObligationCauseCode::BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => {
@@ -2398,13 +2398,13 @@ fn as_failure_code_diag(
fn as_requirement_str(&self) -> &'static str {
match self.code() {
- ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => {
+ ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => {
"method type is compatible with trait"
}
- ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => {
+ ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => {
"associated type is compatible with trait"
}
- ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
+ ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => {
"const is compatible with trait"
}
ObligationCauseCode::MainFunctionType => "`main` function has the correct type",
@@ -2422,9 +2422,13 @@ fn as_requirement_str(&self) -> &'static str {
impl IntoDiagArg for ObligationCauseAsDiagArg<'_> {
fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
let kind = match self.0.code() {
- ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => "method_compat",
- ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => "type_compat",
- ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
+ ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn { .. }, .. } => {
+ "method_compat"
+ }
+ ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type { .. }, .. } => {
+ "type_compat"
+ }
+ ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const { .. }, .. } => {
"const_compat"
}
ObligationCauseCode::MainFunctionType => "fn_main_correct_type",
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
index 3559c66..eaa06d8 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
@@ -6,7 +6,7 @@
use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty};
use rustc_hir::{
self as hir, AmbigArg, GenericBound, GenericParam, GenericParamKind, Item, ItemKind, Lifetime,
- LifetimeName, LifetimeParamKind, MissingLifetimeKind, Node, TyKind,
+ LifetimeKind, LifetimeParamKind, MissingLifetimeKind, Node, TyKind,
};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
use rustc_span::def_id::LocalDefId;
@@ -165,7 +165,7 @@ pub fn suggest_new_region_bound(
if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg {
GenericBound::Outlives(Lifetime {
- res: LifetimeName::Static, ident, ..
+ kind: LifetimeKind::Static, ident, ..
}) => Some(ident.span),
_ => None,
}) {
@@ -253,7 +253,7 @@ pub fn suggest_new_region_bound(
}
}
TyKind::TraitObject(_, lt) => {
- if let LifetimeName::ImplicitObjectLifetimeDefault = lt.res {
+ if let LifetimeKind::ImplicitObjectLifetimeDefault = lt.kind {
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
format!("{declare} the trait object {captures}, {explicit}",),
@@ -414,7 +414,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) {
impl<'a, 'tcx> Visitor<'tcx> for HirTraitObjectVisitor<'a> {
fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx, AmbigArg>) {
if let TyKind::TraitObject(poly_trait_refs, lifetime_ptr) = t.kind
- && let Lifetime { res: LifetimeName::ImplicitObjectLifetimeDefault, .. } =
+ && let Lifetime { kind: LifetimeKind::ImplicitObjectLifetimeDefault, .. } =
lifetime_ptr.pointer()
{
for ptr in poly_trait_refs {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
index 7420592..b66bd2c 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
@@ -98,7 +98,7 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) {
let assoc_item = self.tcx().associated_item(trait_item_def_id);
let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
match assoc_item.kind {
- ty::AssocKind::Fn => {
+ ty::AssocKind::Fn { .. } => {
if let Some(hir_id) =
assoc_item.def_id.as_local().map(|id| self.tcx().local_def_id_to_hir_id(id))
{
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs
index fd2d2fa..4a71ab4 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs
@@ -158,6 +158,6 @@ pub(super) fn is_self_anon(&self, is_first: bool, scope_def_id: LocalDefId) -> b
&& self
.tcx()
.opt_associated_item(scope_def_id.to_def_id())
- .is_some_and(|i| i.fn_has_self_parameter)
+ .is_some_and(|i| i.is_method())
}
}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index 5583ded..be508c8 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -782,8 +782,8 @@ fn point_at_methods_that_satisfy_associated_type(
let methods: Vec<(Span, String)> = items
.in_definition_order()
.filter(|item| {
- ty::AssocKind::Fn == item.kind
- && Some(item.name) != current_method_ident
+ item.is_fn()
+ && Some(item.name()) != current_method_ident
&& !tcx.is_doc_hidden(item.def_id)
})
.filter_map(|item| {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
index 49c6ace..1cf1ac5 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -850,14 +850,14 @@ pub fn suggest_name_region(
add_lt_suggs: &mut Vec<(Span, String)>,
) -> String {
struct LifetimeReplaceVisitor<'a> {
- needle: hir::LifetimeName,
+ needle: hir::LifetimeKind,
new_lt: &'a str,
add_lt_suggs: &'a mut Vec<(Span, String)>,
}
impl<'hir> hir::intravisit::Visitor<'hir> for LifetimeReplaceVisitor<'_> {
fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) {
- if lt.res == self.needle {
+ if lt.kind == self.needle {
self.add_lt_suggs.push(lt.suggestion(self.new_lt));
}
}
@@ -894,7 +894,7 @@ fn visit_lifetime(&mut self, lt: &'hir hir::Lifetime) {
};
let mut visitor = LifetimeReplaceVisitor {
- needle: hir::LifetimeName::Param(lifetime_def_id),
+ needle: hir::LifetimeKind::Param(lifetime_def_id),
add_lt_suggs,
new_lt: &new_lt,
};
@@ -1017,7 +1017,7 @@ fn report_inference_failure(&self, var_origin: RegionVariableOrigin) -> Diag<'_>
infer::BoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!(
" for lifetime parameter {}in trait containing associated type `{}`",
br_string(br),
- self.tcx.associated_item(def_id).name
+ self.tcx.associated_item(def_id).name()
),
infer::RegionParameterDefinition(_, name) => {
format!(" for lifetime parameter `{name}`")
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
index 59c93db..54b5085 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -348,11 +348,11 @@ pub(super) fn maybe_report_ambiguity(
&& let None = self.tainted_by_errors()
{
let (verb, noun) = match self.tcx.associated_item(item_id).kind {
- ty::AssocKind::Const => ("refer to the", "constant"),
- ty::AssocKind::Fn => ("call", "function"),
+ ty::AssocKind::Const { .. } => ("refer to the", "constant"),
+ ty::AssocKind::Fn { .. } => ("call", "function"),
// This is already covered by E0223, but this following single match
// arm doesn't hurt here.
- ty::AssocKind::Type => ("refer to the", "type"),
+ ty::AssocKind::Type { .. } => ("refer to the", "type"),
};
// Replace the more general E0283 with a more specific error
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs
index 1c3e570..d8b405e 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/call_kind.rs
@@ -81,9 +81,7 @@ pub fn call_kind<'tcx>(
}
});
- let fn_call = parent.and_then(|p| {
- lang_items::FN_TRAITS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p)
- });
+ let fn_call = parent.filter(|&p| tcx.fn_trait_kind_from_def_id(p).is_some());
let operator = if !from_hir_call && let Some(p) = parent {
lang_items::OPERATORS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p)
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 5648021..df6e8fc 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -146,7 +146,7 @@ pub fn report_selection_error(
&& leaf_trait_predicate.def_id() != root_pred.def_id()
// The root trait is not `Unsize`, as to avoid talking about it in
// `tests/ui/coercion/coerce-issue-49593-box-never.rs`.
- && Some(root_pred.def_id()) != self.tcx.lang_items().unsize_trait()
+ && !self.tcx.is_lang_item(root_pred.def_id(), LangItem::Unsize)
{
(
self.resolve_vars_if_possible(
@@ -2274,10 +2274,7 @@ fn report_similar_impl_candidates_for_root_obligation(
// auto-traits or fundamental traits that might not be exactly what
// the user might expect to be presented with. Instead this is
// useful for less general traits.
- if peeled
- && !self.tcx.trait_is_auto(def_id)
- && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
- {
+ if peeled && !self.tcx.trait_is_auto(def_id) && self.tcx.as_lang_item(def_id).is_none() {
let impl_candidates = self.find_similar_impl_candidates(trait_pred);
self.report_similar_impl_candidates(
&impl_candidates,
@@ -3013,8 +3010,7 @@ fn report_signature_mismatch_error(
// This shouldn't be common unless manually implementing one of the
// traits manually, but don't make it more confusing when it does
// happen.
- if Some(expected_trait_ref.def_id) != self.tcx.lang_items().coroutine_trait() && not_tupled
- {
+ if !self.tcx.is_lang_item(expected_trait_ref.def_id, LangItem::Coroutine) && not_tupled {
return Ok(self.report_and_explain_type_error(
TypeTrace::trait_refs(&obligation.cause, expected_trait_ref, found_trait_ref),
obligation.param_env,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index 8ff7030..78f9287 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -2,6 +2,8 @@
pub mod call_kind;
mod fulfillment_errors;
pub mod on_unimplemented;
+pub mod on_unimplemented_condition;
+pub mod on_unimplemented_format;
mod overflow;
pub mod suggestions;
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index f0c6e51..4c44912 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -1,44 +1,31 @@
use std::iter;
use std::path::PathBuf;
-use rustc_ast::MetaItemInner;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_ast::{LitKind, MetaItem, MetaItemInner, MetaItemKind, MetaItemLit};
use rustc_errors::codes::*;
use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{AttrArgs, Attribute};
use rustc_macros::LintDiagnostic;
use rustc_middle::bug;
-use rustc_middle::ty::print::PrintTraitRefExt as _;
-use rustc_middle::ty::{self, GenericArgsRef, GenericParamDefKind, TyCtxt};
-use rustc_parse_format::{ParseMode, Parser, Piece, Position};
+use rustc_middle::ty::print::PrintTraitRefExt;
+use rustc_middle::ty::{self, GenericArgsRef, GenericParamDef, GenericParamDefKind, TyCtxt};
use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
-use rustc_span::{Ident, Span, Symbol, kw, sym};
+use rustc_span::{Span, Symbol, sym};
use tracing::{debug, info};
use {rustc_attr_parsing as attr, rustc_hir as hir};
use super::{ObligationCauseCode, PredicateObligation};
use crate::error_reporting::TypeErrCtxt;
+use crate::error_reporting::traits::on_unimplemented_condition::{Condition, ConditionOptions};
+use crate::error_reporting::traits::on_unimplemented_format::{
+ Ctx, FormatArgs, FormatString, FormatWarning,
+};
use crate::errors::{
EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
};
use crate::infer::InferCtxtExt;
-/// The symbols which are always allowed in a format string
-static ALLOWED_FORMAT_SYMBOLS: &[Symbol] = &[
- kw::SelfUpper,
- sym::ItemContext,
- sym::from_desugaring,
- sym::direct,
- sym::cause,
- sym::integral,
- sym::integer_,
- sym::float,
- sym::_Self,
- sym::crate_local,
- sym::Trait,
-];
-
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
fn impl_similar_to(
&self,
@@ -121,86 +108,78 @@ pub fn on_unimplemented_note(
.unwrap_or_else(|| (trait_pred.def_id(), trait_pred.skip_binder().trait_ref.args));
let trait_pred = trait_pred.skip_binder();
- let mut flags = vec![];
+ let mut self_types = vec![];
+ let mut generic_args: Vec<(Symbol, String)> = vec![];
+ let mut crate_local = false;
// FIXME(-Zlower-impl-trait-in-trait-to-assoc-ty): HIR is not present for RPITITs,
// but I guess we could synthesize one here. We don't see any errors that rely on
// that yet, though.
- let enclosure = self.describe_enclosure(obligation.cause.body_id).map(|t| t.to_owned());
- flags.push((sym::ItemContext, enclosure));
+ let item_context = self.describe_enclosure(obligation.cause.body_id).unwrap_or("");
- match obligation.cause.code() {
+ let direct = match obligation.cause.code() {
ObligationCauseCode::BuiltinDerived(..)
| ObligationCauseCode::ImplDerived(..)
- | ObligationCauseCode::WellFormedDerived(..) => {}
+ | ObligationCauseCode::WellFormedDerived(..) => false,
_ => {
// this is a "direct", user-specified, rather than derived,
// obligation.
- flags.push((sym::direct, None));
+ true
}
- }
+ };
- if let Some(k) = obligation.cause.span.desugaring_kind() {
- flags.push((sym::from_desugaring, None));
- flags.push((sym::from_desugaring, Some(format!("{k:?}"))));
- }
+ let from_desugaring = obligation.cause.span.desugaring_kind();
- if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
- flags.push((sym::cause, Some("MainFunctionType".to_string())));
- }
-
- flags.push((sym::Trait, Some(trait_pred.trait_ref.print_trait_sugared().to_string())));
+ let cause = if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
+ Some("MainFunctionType".to_string())
+ } else {
+ None
+ };
// Add all types without trimmed paths or visible paths, ensuring they end up with
// their "canonical" def path.
ty::print::with_no_trimmed_paths!(ty::print::with_no_visible_paths!({
let generics = self.tcx.generics_of(def_id);
let self_ty = trait_pred.self_ty();
- // This is also included through the generics list as `Self`,
- // but the parser won't allow you to use it
- flags.push((sym::_Self, Some(self_ty.to_string())));
+ self_types.push(self_ty.to_string());
if let Some(def) = self_ty.ty_adt_def() {
// We also want to be able to select self's original
// signature with no type arguments resolved
- flags.push((
- sym::_Self,
- Some(self.tcx.type_of(def.did()).instantiate_identity().to_string()),
- ));
+ self_types.push(self.tcx.type_of(def.did()).instantiate_identity().to_string());
}
- for param in generics.own_params.iter() {
- let value = match param.kind {
+ for GenericParamDef { name, kind, index, .. } in generics.own_params.iter() {
+ let value = match kind {
GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
- args[param.index as usize].to_string()
+ args[*index as usize].to_string()
}
GenericParamDefKind::Lifetime => continue,
};
- let name = param.name;
- flags.push((name, Some(value)));
+ generic_args.push((*name, value));
- if let GenericParamDefKind::Type { .. } = param.kind {
- let param_ty = args[param.index as usize].expect_ty();
+ if let GenericParamDefKind::Type { .. } = kind {
+ let param_ty = args[*index as usize].expect_ty();
if let Some(def) = param_ty.ty_adt_def() {
// We also want to be able to select the parameter's
// original signature with no type arguments resolved
- flags.push((
- name,
- Some(self.tcx.type_of(def.did()).instantiate_identity().to_string()),
+ generic_args.push((
+ *name,
+ self.tcx.type_of(def.did()).instantiate_identity().to_string(),
));
}
}
}
if let Some(true) = self_ty.ty_adt_def().map(|def| def.did().is_local()) {
- flags.push((sym::crate_local, None));
+ crate_local = true;
}
// Allow targeting all integers using `{integral}`, even if the exact type was resolved
if self_ty.is_integral() {
- flags.push((sym::_Self, Some("{integral}".to_owned())));
+ self_types.push("{integral}".to_owned());
}
if self_ty.is_array_slice() {
- flags.push((sym::_Self, Some("&[]".to_owned())));
+ self_types.push("&[]".to_owned());
}
if self_ty.is_fn() {
@@ -215,53 +194,51 @@ pub fn on_unimplemented_note(
hir::Safety::Unsafe => "unsafe fn",
}
};
- flags.push((sym::_Self, Some(shortname.to_owned())));
+ self_types.push(shortname.to_owned());
}
// Slices give us `[]`, `[{ty}]`
if let ty::Slice(aty) = self_ty.kind() {
- flags.push((sym::_Self, Some("[]".to_string())));
+ self_types.push("[]".to_owned());
if let Some(def) = aty.ty_adt_def() {
// We also want to be able to select the slice's type's original
// signature with no type arguments resolved
- flags.push((
- sym::_Self,
- Some(format!("[{}]", self.tcx.type_of(def.did()).instantiate_identity())),
- ));
+ self_types
+ .push(format!("[{}]", self.tcx.type_of(def.did()).instantiate_identity()));
}
if aty.is_integral() {
- flags.push((sym::_Self, Some("[{integral}]".to_string())));
+ self_types.push("[{integral}]".to_string());
}
}
// Arrays give us `[]`, `[{ty}; _]` and `[{ty}; N]`
if let ty::Array(aty, len) = self_ty.kind() {
- flags.push((sym::_Self, Some("[]".to_string())));
+ self_types.push("[]".to_string());
let len = len.try_to_target_usize(self.tcx);
- flags.push((sym::_Self, Some(format!("[{aty}; _]"))));
+ self_types.push(format!("[{aty}; _]"));
if let Some(n) = len {
- flags.push((sym::_Self, Some(format!("[{aty}; {n}]"))));
+ self_types.push(format!("[{aty}; {n}]"));
}
if let Some(def) = aty.ty_adt_def() {
// We also want to be able to select the array's type's original
// signature with no type arguments resolved
let def_ty = self.tcx.type_of(def.did()).instantiate_identity();
- flags.push((sym::_Self, Some(format!("[{def_ty}; _]"))));
+ self_types.push(format!("[{def_ty}; _]"));
if let Some(n) = len {
- flags.push((sym::_Self, Some(format!("[{def_ty}; {n}]"))));
+ self_types.push(format!("[{def_ty}; {n}]"));
}
}
if aty.is_integral() {
- flags.push((sym::_Self, Some("[{integral}; _]".to_string())));
+ self_types.push("[{integral}; _]".to_string());
if let Some(n) = len {
- flags.push((sym::_Self, Some(format!("[{{integral}}; {n}]"))));
+ self_types.push(format!("[{{integral}}; {n}]"));
}
}
}
if let ty::Dynamic(traits, _, _) = self_ty.kind() {
for t in traits.iter() {
if let ty::ExistentialPredicate::Trait(trait_ref) = t.skip_binder() {
- flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id))))
+ self_types.push(self.tcx.def_path_str(trait_ref.def_id));
}
}
}
@@ -271,31 +248,76 @@ pub fn on_unimplemented_note(
&& let ty::Slice(sty) = ref_ty.kind()
&& sty.is_integral()
{
- flags.push((sym::_Self, Some("&[{integral}]".to_owned())));
+ self_types.push("&[{integral}]".to_owned());
}
}));
+ let this = self.tcx.def_path_str(trait_pred.trait_ref.def_id);
+ let trait_sugared = trait_pred.trait_ref.print_trait_sugared();
+
+ let condition_options = ConditionOptions {
+ self_types,
+ from_desugaring,
+ cause,
+ crate_local,
+ direct,
+ generic_args,
+ };
+
+ // Unlike the generic_args earlier,
+ // this one is *not* collected under `with_no_trimmed_paths!`
+ // for printing the type to the user
+ //
+ // This includes `Self`, as it is the first parameter in `own_params`.
+ let generic_args = self
+ .tcx
+ .generics_of(trait_pred.trait_ref.def_id)
+ .own_params
+ .iter()
+ .filter_map(|param| {
+ let value = match param.kind {
+ GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+ if let Some(ty) = trait_pred.trait_ref.args[param.index as usize].as_type()
+ {
+ self.tcx.short_string(ty, long_ty_file)
+ } else {
+ trait_pred.trait_ref.args[param.index as usize].to_string()
+ }
+ }
+ GenericParamDefKind::Lifetime => return None,
+ };
+ let name = param.name;
+ Some((name, value))
+ })
+ .collect();
+
+ let format_args = FormatArgs { this, trait_sugared, generic_args, item_context };
+
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
- command.evaluate(self.tcx, trait_pred.trait_ref, &flags, long_ty_file)
+ command.evaluate(self.tcx, trait_pred.trait_ref, &condition_options, &format_args)
} else {
OnUnimplementedNote::default()
}
}
}
+/// Represents a format string in a on_unimplemented attribute,
+/// like the "content" in `#[diagnostic::on_unimplemented(message = "content")]`
#[derive(Clone, Debug)]
pub struct OnUnimplementedFormatString {
- symbol: Symbol,
- span: Span,
- is_diagnostic_namespace_variant: bool,
+ /// Symbol of the format string, i.e. `"content"`
+ pub symbol: Symbol,
+ ///The span of the format string, i.e. `"content"`
+ pub span: Span,
+ pub is_diagnostic_namespace_variant: bool,
}
#[derive(Debug)]
pub struct OnUnimplementedDirective {
- pub condition: Option<MetaItemInner>,
+ pub condition: Option<Condition>,
pub subcommands: Vec<OnUnimplementedDirective>,
- pub message: Option<OnUnimplementedFormatString>,
- pub label: Option<OnUnimplementedFormatString>,
+ pub message: Option<(Span, OnUnimplementedFormatString)>,
+ pub label: Option<(Span, OnUnimplementedFormatString)>,
pub notes: Vec<OnUnimplementedFormatString>,
pub parent_label: Option<OnUnimplementedFormatString>,
pub append_const_msg: Option<AppendConstMessage>,
@@ -329,7 +351,7 @@ pub struct MalformedOnUnimplementedAttrLint {
}
impl MalformedOnUnimplementedAttrLint {
- fn new(span: Span) -> Self {
+ pub fn new(span: Span) -> Self {
Self { span }
}
}
@@ -350,7 +372,7 @@ pub struct IgnoredDiagnosticOption {
}
impl IgnoredDiagnosticOption {
- fn maybe_emit_warning<'tcx>(
+ pub fn maybe_emit_warning<'tcx>(
tcx: TyCtxt<'tcx>,
item_def_id: DefId,
new: Option<Span>,
@@ -371,28 +393,10 @@ fn maybe_emit_warning<'tcx>(
}
#[derive(LintDiagnostic)]
-#[diag(trait_selection_unknown_format_parameter_for_on_unimplemented_attr)]
-#[help]
-pub struct UnknownFormatParameterForOnUnimplementedAttr {
- argument_name: Symbol,
- trait_name: Ident,
-}
-
-#[derive(LintDiagnostic)]
-#[diag(trait_selection_disallowed_positional_argument)]
-#[help]
-pub struct DisallowedPositionalArgument;
-
-#[derive(LintDiagnostic)]
-#[diag(trait_selection_invalid_format_specifier)]
-#[help]
-pub struct InvalidFormatSpecifier;
-
-#[derive(LintDiagnostic)]
#[diag(trait_selection_wrapped_parser_error)]
pub struct WrappedParserError {
- description: String,
- label: String,
+ pub description: String,
+ pub label: String,
}
impl<'tcx> OnUnimplementedDirective {
@@ -407,12 +411,12 @@ fn parse(
let mut errored = None;
let mut item_iter = items.iter();
- let parse_value = |value_str, value_span| {
+ let parse_value = |value_str, span| {
OnUnimplementedFormatString::try_parse(
tcx,
item_def_id,
value_str,
- value_span,
+ span,
is_diagnostic_namespace_variant,
)
.map(Some)
@@ -434,7 +438,7 @@ fn parse(
}
true
});
- Some(cond.clone())
+ Some(Condition { inner: cond.clone() })
};
let mut message = None;
@@ -444,24 +448,36 @@ fn parse(
let mut subcommands = vec![];
let mut append_const_msg = None;
+ let get_value_and_span = |item: &_, key| {
+ if let MetaItemInner::MetaItem(MetaItem {
+ path,
+ kind: MetaItemKind::NameValue(MetaItemLit { span, kind: LitKind::Str(s, _), .. }),
+ ..
+ }) = item
+ && *path == key
+ {
+ Some((*s, *span))
+ } else {
+ None
+ }
+ };
+
for item in item_iter {
- if item.has_name(sym::message) && message.is_none() {
- if let Some(message_) = item.value_str() {
- message = parse_value(message_, item.span())?;
+ if let Some((message_, span)) = get_value_and_span(item, sym::message)
+ && message.is_none()
+ {
+ message = parse_value(message_, span)?.map(|l| (item.span(), l));
+ continue;
+ } else if let Some((label_, span)) = get_value_and_span(item, sym::label)
+ && label.is_none()
+ {
+ label = parse_value(label_, span)?.map(|l| (item.span(), l));
+ continue;
+ } else if let Some((note_, span)) = get_value_and_span(item, sym::note) {
+ if let Some(note) = parse_value(note_, span)? {
+ notes.push(note);
continue;
}
- } else if item.has_name(sym::label) && label.is_none() {
- if let Some(label_) = item.value_str() {
- label = parse_value(label_, item.span())?;
- continue;
- }
- } else if item.has_name(sym::note) {
- if let Some(note_) = item.value_str() {
- if let Some(note) = parse_value(note_, item.span())? {
- notes.push(note);
- continue;
- }
- }
} else if item.has_name(sym::parent_label)
&& parent_label.is_none()
&& !is_diagnostic_namespace_variant
@@ -539,6 +555,13 @@ fn parse(
}
pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
+ if !tcx.is_trait(item_def_id) {
+ // It could be a trait_alias (`trait MyTrait = SomeOtherTrait`)
+ // or an implementation (`impl MyTrait for Foo {}`)
+ //
+ // We don't support those.
+ return Ok(None);
+ }
if let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) {
return Self::parse_attribute(attr, false, tcx, item_def_id);
} else {
@@ -554,15 +577,15 @@ pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, Er
IgnoredDiagnosticOption::maybe_emit_warning(
tcx,
item_def_id,
- directive.message.as_ref().map(|f| f.span),
- aggr.message.as_ref().map(|f| f.span),
+ directive.message.as_ref().map(|f| f.0),
+ aggr.message.as_ref().map(|f| f.0),
"message",
);
IgnoredDiagnosticOption::maybe_emit_warning(
tcx,
item_def_id,
- directive.label.as_ref().map(|f| f.span),
- aggr.label.as_ref().map(|f| f.span),
+ directive.label.as_ref().map(|f| f.0),
+ aggr.label.as_ref().map(|f| f.0),
"label",
);
IgnoredDiagnosticOption::maybe_emit_warning(
@@ -636,13 +659,16 @@ fn parse_attribute(
condition: None,
message: None,
subcommands: vec![],
- label: Some(OnUnimplementedFormatString::try_parse(
- tcx,
- item_def_id,
- value,
+ label: Some((
attr.span(),
- is_diagnostic_namespace_variant,
- )?),
+ OnUnimplementedFormatString::try_parse(
+ tcx,
+ item_def_id,
+ value,
+ attr.value_span().unwrap_or(attr.span()),
+ is_diagnostic_namespace_variant,
+ )?,
+ )),
notes: Vec::new(),
parent_label: None,
append_const_msg: None,
@@ -702,43 +728,23 @@ pub fn evaluate(
&self,
tcx: TyCtxt<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
- options: &[(Symbol, Option<String>)],
- long_ty_file: &mut Option<PathBuf>,
+ condition_options: &ConditionOptions,
+ args: &FormatArgs<'tcx>,
) -> OnUnimplementedNote {
let mut message = None;
let mut label = None;
let mut notes = Vec::new();
let mut parent_label = None;
let mut append_const_msg = None;
- info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
-
- let options_map: FxHashMap<Symbol, String> =
- options.iter().filter_map(|(k, v)| v.clone().map(|v| (*k, v))).collect();
+ info!(
+ "evaluate({:?}, trait_ref={:?}, options={:?}, args ={:?})",
+ self, trait_ref, condition_options, args
+ );
for command in self.subcommands.iter().chain(Some(self)).rev() {
debug!(?command);
if let Some(ref condition) = command.condition
- && !attr::eval_condition(condition, &tcx.sess, Some(tcx.features()), &mut |cfg| {
- let value = cfg.value.map(|v| {
- // `with_no_visible_paths` is also used when generating the options,
- // so we need to match it here.
- ty::print::with_no_visible_paths!(
- OnUnimplementedFormatString {
- symbol: v,
- span: cfg.span,
- is_diagnostic_namespace_variant: false
- }
- .format(
- tcx,
- trait_ref,
- &options_map,
- long_ty_file
- )
- )
- });
-
- options.contains(&(cfg.name, value))
- })
+ && !condition.matches_predicate(tcx, condition_options)
{
debug!("evaluate: skipping {:?} due to condition", command);
continue;
@@ -762,14 +768,10 @@ pub fn evaluate(
}
OnUnimplementedNote {
- label: label.map(|l| l.format(tcx, trait_ref, &options_map, long_ty_file)),
- message: message.map(|m| m.format(tcx, trait_ref, &options_map, long_ty_file)),
- notes: notes
- .into_iter()
- .map(|n| n.format(tcx, trait_ref, &options_map, long_ty_file))
- .collect(),
- parent_label: parent_label
- .map(|e_s| e_s.format(tcx, trait_ref, &options_map, long_ty_file)),
+ label: label.map(|l| l.1.format(tcx, trait_ref, args)),
+ message: message.map(|m| m.1.format(tcx, trait_ref, args)),
+ notes: notes.into_iter().map(|n| n.format(tcx, trait_ref, args)).collect(),
+ parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, args)),
append_const_msg,
}
}
@@ -780,142 +782,95 @@ fn try_parse(
tcx: TyCtxt<'tcx>,
item_def_id: DefId,
from: Symbol,
- value_span: Span,
+ span: Span,
is_diagnostic_namespace_variant: bool,
) -> Result<Self, ErrorGuaranteed> {
- let result = OnUnimplementedFormatString {
- symbol: from,
- span: value_span,
- is_diagnostic_namespace_variant,
- };
+ let result =
+ OnUnimplementedFormatString { symbol: from, span, is_diagnostic_namespace_variant };
result.verify(tcx, item_def_id)?;
Ok(result)
}
- fn verify(&self, tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<(), ErrorGuaranteed> {
- let trait_def_id = if tcx.is_trait(item_def_id) {
- item_def_id
- } else {
- tcx.trait_id_of_impl(item_def_id)
- .expect("expected `on_unimplemented` to correspond to a trait")
+ fn verify(&self, tcx: TyCtxt<'tcx>, trait_def_id: DefId) -> Result<(), ErrorGuaranteed> {
+ if !tcx.is_trait(trait_def_id) {
+ return Ok(());
};
- let trait_name = tcx.item_ident(trait_def_id);
- let generics = tcx.generics_of(item_def_id);
- let s = self.symbol.as_str();
- let mut parser = Parser::new(s, None, None, false, ParseMode::Format);
+
+ let ctx = if self.is_diagnostic_namespace_variant {
+ Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }
+ } else {
+ Ctx::RustcOnUnimplemented { tcx, trait_def_id }
+ };
+
let mut result = Ok(());
- for token in &mut parser {
- match token {
- Piece::Lit(_) => (), // Normal string, no need to check it
- Piece::NextArgument(a) => {
- let format_spec = a.format;
- if self.is_diagnostic_namespace_variant
- && (format_spec.ty_span.is_some()
- || format_spec.width_span.is_some()
- || format_spec.precision_span.is_some()
- || format_spec.fill_span.is_some())
- {
- if let Some(item_def_id) = item_def_id.as_local() {
- tcx.emit_node_span_lint(
- UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- tcx.local_def_id_to_hir_id(item_def_id),
- self.span,
- InvalidFormatSpecifier,
- );
- }
+
+ match FormatString::parse(self.symbol, self.span, &ctx) {
+ // Warnings about format specifiers, deprecated parameters, wrong parameters etc.
+ // In other words we'd like to let the author know, but we can still try to format the string later
+ Ok(FormatString { warnings, .. }) => {
+ if self.is_diagnostic_namespace_variant {
+ for w in warnings {
+ w.emit_warning(tcx, trait_def_id)
}
- match a.position {
- Position::ArgumentNamed(s) => {
- match Symbol::intern(s) {
- // `{ThisTraitsName}` is allowed
- s if s == trait_name.name
- && !self.is_diagnostic_namespace_variant =>
- {
- ()
- }
- s if ALLOWED_FORMAT_SYMBOLS.contains(&s)
- && !self.is_diagnostic_namespace_variant =>
- {
- ()
- }
- // So is `{A}` if A is a type parameter
- s if generics.own_params.iter().any(|param| param.name == s) => (),
- s => {
- if self.is_diagnostic_namespace_variant {
- if let Some(item_def_id) = item_def_id.as_local() {
- tcx.emit_node_span_lint(
- UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- tcx.local_def_id_to_hir_id(item_def_id),
- self.span,
- UnknownFormatParameterForOnUnimplementedAttr {
- argument_name: s,
- trait_name,
- },
- );
- }
- } else {
- result = Err(struct_span_code_err!(
- tcx.dcx(),
- self.span,
- E0230,
- "there is no parameter `{}` on {}",
- s,
- if trait_def_id == item_def_id {
- format!("trait `{trait_name}`")
- } else {
- "impl".to_string()
- }
- )
- .emit());
- }
- }
- }
- }
- // `{:1}` and `{}` are not to be used
- Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => {
- if self.is_diagnostic_namespace_variant {
- if let Some(item_def_id) = item_def_id.as_local() {
- tcx.emit_node_span_lint(
- UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- tcx.local_def_id_to_hir_id(item_def_id),
- self.span,
- DisallowedPositionalArgument,
- );
- }
- } else {
+ } else {
+ for w in warnings {
+ match w {
+ FormatWarning::UnknownParam { argument_name, span } => {
let reported = struct_span_code_err!(
tcx.dcx(),
- self.span,
- E0231,
- "only named generic parameters are allowed"
+ span,
+ E0230,
+ "cannot find parameter {} on this trait",
+ argument_name,
)
.emit();
result = Err(reported);
}
+ FormatWarning::PositionalArgument { span, .. } => {
+ let reported = struct_span_code_err!(
+ tcx.dcx(),
+ span,
+ E0231,
+ "positional format arguments are not allowed here"
+ )
+ .emit();
+ result = Err(reported);
+ }
+ FormatWarning::InvalidSpecifier { .. }
+ | FormatWarning::FutureIncompat { .. } => {}
}
}
}
}
- }
- // we cannot return errors from processing the format string as hard error here
- // as the diagnostic namespace guarantees that malformed input cannot cause an error
- //
- // if we encounter any error while processing we nevertheless want to show it as warning
- // so that users are aware that something is not correct
- for e in parser.errors {
- if self.is_diagnostic_namespace_variant {
- if let Some(item_def_id) = item_def_id.as_local() {
- tcx.emit_node_span_lint(
- UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
- tcx.local_def_id_to_hir_id(item_def_id),
- self.span,
- WrappedParserError { description: e.description, label: e.label },
- );
+ // Errors from the underlying `rustc_parse_format::Parser`
+ Err(errors) => {
+ // we cannot return errors from processing the format string as hard error here
+ // as the diagnostic namespace guarantees that malformed input cannot cause an error
+ //
+ // if we encounter any error while processing we nevertheless want to show it as warning
+ // so that users are aware that something is not correct
+ for e in errors {
+ if self.is_diagnostic_namespace_variant {
+ if let Some(trait_def_id) = trait_def_id.as_local() {
+ tcx.emit_node_span_lint(
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ tcx.local_def_id_to_hir_id(trait_def_id),
+ self.span,
+ WrappedParserError { description: e.description, label: e.label },
+ );
+ }
+ } else {
+ let reported = struct_span_code_err!(
+ tcx.dcx(),
+ self.span,
+ E0231,
+ "{}",
+ e.description,
+ )
+ .emit();
+ result = Err(reported);
+ }
}
- } else {
- let reported =
- struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,).emit();
- result = Err(reported);
}
}
@@ -926,98 +881,28 @@ pub fn format(
&self,
tcx: TyCtxt<'tcx>,
trait_ref: ty::TraitRef<'tcx>,
- options: &FxHashMap<Symbol, String>,
- long_ty_file: &mut Option<PathBuf>,
+ args: &FormatArgs<'tcx>,
) -> String {
- let name = tcx.item_name(trait_ref.def_id);
- let trait_str = tcx.def_path_str(trait_ref.def_id);
- let generics = tcx.generics_of(trait_ref.def_id);
- let generic_map = generics
- .own_params
- .iter()
- .filter_map(|param| {
- let value = match param.kind {
- GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
- if let Some(ty) = trait_ref.args[param.index as usize].as_type() {
- tcx.short_string(ty, long_ty_file)
- } else {
- trait_ref.args[param.index as usize].to_string()
- }
- }
- GenericParamDefKind::Lifetime => return None,
- };
- let name = param.name;
- Some((name, value))
- })
- .collect::<FxHashMap<Symbol, String>>();
- let empty_string = String::new();
-
- let s = self.symbol.as_str();
- let mut parser = Parser::new(s, None, None, false, ParseMode::Format);
- let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string);
- let constructed_message = (&mut parser)
- .map(|p| match p {
- Piece::Lit(s) => s.to_owned(),
- Piece::NextArgument(a) => match a.position {
- Position::ArgumentNamed(arg) => {
- let s = Symbol::intern(arg);
- match generic_map.get(&s) {
- Some(val) => val.to_string(),
- None if self.is_diagnostic_namespace_variant => {
- format!("{{{arg}}}")
- }
- None if s == name => trait_str.clone(),
- None => {
- if let Some(val) = options.get(&s) {
- val.clone()
- } else if s == sym::from_desugaring {
- // don't break messages using these two arguments incorrectly
- String::new()
- } else if s == sym::ItemContext
- && !self.is_diagnostic_namespace_variant
- {
- item_context.clone()
- } else if s == sym::integral {
- String::from("{integral}")
- } else if s == sym::integer_ {
- String::from("{integer}")
- } else if s == sym::float {
- String::from("{float}")
- } else {
- bug!(
- "broken on_unimplemented {:?} for {:?}: \
- no argument matching {:?}",
- self.symbol,
- trait_ref,
- s
- )
- }
- }
- }
- }
- Position::ArgumentImplicitlyIs(_) if self.is_diagnostic_namespace_variant => {
- String::from("{}")
- }
- Position::ArgumentIs(idx) if self.is_diagnostic_namespace_variant => {
- format!("{{{idx}}}")
- }
- _ => bug!("broken on_unimplemented {:?} - bad format arg", self.symbol),
- },
- })
- .collect();
- // we cannot return errors from processing the format string as hard error here
- // as the diagnostic namespace guarantees that malformed input cannot cause an error
- //
- // if we encounter any error while processing the format string
- // we don't want to show the potentially half assembled formatted string,
- // therefore we fall back to just showing the input string in this case
- //
- // The actual parser errors are emitted earlier
- // as lint warnings in OnUnimplementedFormatString::verify
- if self.is_diagnostic_namespace_variant && !parser.errors.is_empty() {
- String::from(s)
+ let trait_def_id = trait_ref.def_id;
+ let ctx = if self.is_diagnostic_namespace_variant {
+ Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }
} else {
- constructed_message
+ Ctx::RustcOnUnimplemented { tcx, trait_def_id }
+ };
+
+ if let Ok(s) = FormatString::parse(self.symbol, self.span, &ctx) {
+ s.format(args)
+ } else {
+ // we cannot return errors from processing the format string as hard error here
+ // as the diagnostic namespace guarantees that malformed input cannot cause an error
+ //
+ // if we encounter any error while processing the format string
+ // we don't want to show the potentially half assembled formatted string,
+ // therefore we fall back to just showing the input string in this case
+ //
+ // The actual parser errors are emitted earlier
+ // as lint warnings in OnUnimplementedFormatString::verify
+ self.symbol.as_str().into()
}
}
}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs
new file mode 100644
index 0000000..116cfb0
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_condition.rs
@@ -0,0 +1,120 @@
+use rustc_ast::MetaItemInner;
+use rustc_attr_parsing as attr;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_parse_format::{ParseMode, Parser, Piece, Position};
+use rustc_span::{DesugaringKind, Span, Symbol, kw, sym};
+
+/// A predicate in an attribute using on, all, any,
+/// similar to a cfg predicate.
+#[derive(Debug)]
+pub struct Condition {
+ pub inner: MetaItemInner,
+}
+
+impl Condition {
+ pub fn span(&self) -> Span {
+ self.inner.span()
+ }
+
+ pub fn matches_predicate<'tcx>(&self, tcx: TyCtxt<'tcx>, options: &ConditionOptions) -> bool {
+ attr::eval_condition(&self.inner, tcx.sess, Some(tcx.features()), &mut |cfg| {
+ let value = cfg.value.map(|v| {
+ // `with_no_visible_paths` is also used when generating the options,
+ // so we need to match it here.
+ ty::print::with_no_visible_paths!({
+ Parser::new(v.as_str(), None, None, false, ParseMode::Format)
+ .map(|p| match p {
+ Piece::Lit(s) => s.to_owned(),
+ Piece::NextArgument(a) => match a.position {
+ Position::ArgumentNamed(arg) => {
+ let s = Symbol::intern(arg);
+ match options.generic_args.iter().find(|(k, _)| *k == s) {
+ Some((_, val)) => val.to_string(),
+ None => format!("{{{arg}}}"),
+ }
+ }
+ Position::ArgumentImplicitlyIs(_) => String::from("{}"),
+ Position::ArgumentIs(idx) => format!("{{{idx}}}"),
+ },
+ })
+ .collect()
+ })
+ });
+
+ options.contains(cfg.name, &value)
+ })
+ }
+}
+
+/// Used with `Condition::matches_predicate` to test whether the condition applies
+///
+/// For example, given a
+/// ```rust,ignore (just an example)
+/// #[rustc_on_unimplemented(
+/// on(all(from_desugaring = "QuestionMark"),
+/// message = "the `?` operator can only be used in {ItemContext} \
+/// that returns `Result` or `Option` \
+/// (or another type that implements `{FromResidual}`)",
+/// label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
+/// parent_label = "this function should return `Result` or `Option` to accept `?`"
+/// ),
+/// )]
+/// pub trait FromResidual<R = <Self as Try>::Residual> {
+/// ...
+/// }
+///
+/// async fn an_async_function() -> u32 {
+/// let x: Option<u32> = None;
+/// x?; //~ ERROR the `?` operator
+/// 22
+/// }
+/// ```
+/// it will look like this:
+///
+/// ```rust,ignore (just an example)
+/// ConditionOptions {
+/// self_types: ["u32", "{integral}"],
+/// from_desugaring: Some("QuestionMark"),
+/// cause: None,
+/// crate_local: false,
+/// direct: true,
+/// generic_args: [("Self","u32"),
+/// ("R", "core::option::Option<core::convert::Infallible>"),
+/// ("R", "core::option::Option<T>" ),
+/// ],
+/// }
+/// ```
+#[derive(Debug)]
+pub struct ConditionOptions {
+ /// All the self types that may apply.
+ /// for example
+ pub self_types: Vec<String>,
+ // The kind of compiler desugaring.
+ pub from_desugaring: Option<DesugaringKind>,
+ /// Match on a variant of [rustc_infer::traits::ObligationCauseCode]
+ pub cause: Option<String>,
+ pub crate_local: bool,
+ /// Is the obligation "directly" user-specified, rather than derived?
+ pub direct: bool,
+ // A list of the generic arguments and their reified types
+ pub generic_args: Vec<(Symbol, String)>,
+}
+
+impl ConditionOptions {
+ pub fn contains(&self, key: Symbol, value: &Option<String>) -> bool {
+ match (key, value) {
+ (sym::_Self | kw::SelfUpper, Some(value)) => self.self_types.contains(&value),
+ // from_desugaring as a flag
+ (sym::from_desugaring, None) => self.from_desugaring.is_some(),
+ // from_desugaring as key == value
+ (sym::from_desugaring, Some(v)) if let Some(ds) = self.from_desugaring => ds.matches(v),
+ (sym::cause, Some(value)) => self.cause.as_deref() == Some(value),
+ (sym::crate_local, None) => self.crate_local,
+ (sym::direct, None) => self.direct,
+ (other, Some(value)) => {
+ self.generic_args.iter().any(|(k, v)| *k == other && v == value)
+ }
+ _ => false,
+ }
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs
new file mode 100644
index 0000000..f835406
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented_format.rs
@@ -0,0 +1,414 @@
+use std::fmt;
+
+use errors::*;
+use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::print::TraitRefPrintSugared;
+use rustc_parse_format::{
+ Alignment, Argument, Count, FormatSpec, InnerSpan, ParseError, ParseMode, Parser,
+ Piece as RpfPiece, Position,
+};
+use rustc_session::lint::builtin::UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES;
+use rustc_span::def_id::DefId;
+use rustc_span::{BytePos, Pos, Span, Symbol, kw, sym};
+
+/// Like [std::fmt::Arguments] this is a string that has been parsed into "pieces",
+/// either as string pieces or dynamic arguments.
+#[derive(Debug)]
+pub struct FormatString {
+ #[allow(dead_code, reason = "Debug impl")]
+ input: Symbol,
+ span: Span,
+ pieces: Vec<Piece>,
+ /// The formatting string was parsed succesfully but with warnings
+ pub warnings: Vec<FormatWarning>,
+}
+
+#[derive(Debug)]
+enum Piece {
+ Lit(String),
+ Arg(FormatArg),
+}
+
+#[derive(Debug)]
+enum FormatArg {
+ // A generic parameter, like `{T}` if we're on the `From<T>` trait.
+ GenericParam {
+ generic_param: Symbol,
+ },
+ // `{Self}`
+ SelfUpper,
+ /// `{This}` or `{TraitName}`
+ This,
+ /// The sugared form of the trait
+ Trait,
+ /// what we're in, like a function, method, closure etc.
+ ItemContext,
+ /// What the user typed, if it doesn't match anything we can use.
+ AsIs(String),
+}
+
+pub enum Ctx<'tcx> {
+ // `#[rustc_on_unimplemented]`
+ RustcOnUnimplemented { tcx: TyCtxt<'tcx>, trait_def_id: DefId },
+ // `#[diagnostic::...]`
+ DiagnosticOnUnimplemented { tcx: TyCtxt<'tcx>, trait_def_id: DefId },
+}
+
+#[derive(Debug)]
+pub enum FormatWarning {
+ UnknownParam { argument_name: Symbol, span: Span },
+ PositionalArgument { span: Span, help: String },
+ InvalidSpecifier { name: String, span: Span },
+ FutureIncompat { span: Span, help: String },
+}
+
+impl FormatWarning {
+ pub fn emit_warning<'tcx>(&self, tcx: TyCtxt<'tcx>, item_def_id: DefId) {
+ match *self {
+ FormatWarning::UnknownParam { argument_name, span } => {
+ let this = tcx.item_ident(item_def_id);
+ if let Some(item_def_id) = item_def_id.as_local() {
+ tcx.emit_node_span_lint(
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ tcx.local_def_id_to_hir_id(item_def_id),
+ span,
+ UnknownFormatParameterForOnUnimplementedAttr {
+ argument_name,
+ trait_name: this,
+ },
+ );
+ }
+ }
+ FormatWarning::PositionalArgument { span, .. } => {
+ if let Some(item_def_id) = item_def_id.as_local() {
+ tcx.emit_node_span_lint(
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ tcx.local_def_id_to_hir_id(item_def_id),
+ span,
+ DisallowedPositionalArgument,
+ );
+ }
+ }
+ FormatWarning::InvalidSpecifier { span, .. } => {
+ if let Some(item_def_id) = item_def_id.as_local() {
+ tcx.emit_node_span_lint(
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ tcx.local_def_id_to_hir_id(item_def_id),
+ span,
+ InvalidFormatSpecifier,
+ );
+ }
+ }
+ FormatWarning::FutureIncompat { .. } => {
+ // We've never deprecated anything in diagnostic namespace format strings
+ // but if we do we will emit a warning here
+
+ // FIXME(mejrs) in a couple releases, start emitting warnings for
+ // #[rustc_on_unimplemented] deprecated args
+ }
+ }
+ }
+}
+
+/// Arguments to fill a [FormatString] with.
+///
+/// For example, given a
+/// ```rust,ignore (just an example)
+///
+/// #[rustc_on_unimplemented(
+/// on(all(from_desugaring = "QuestionMark"),
+/// message = "the `?` operator can only be used in {ItemContext} \
+/// that returns `Result` or `Option` \
+/// (or another type that implements `{FromResidual}`)",
+/// label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`",
+/// parent_label = "this function should return `Result` or `Option` to accept `?`"
+/// ),
+/// )]
+/// pub trait FromResidual<R = <Self as Try>::Residual> {
+/// ...
+/// }
+///
+/// async fn an_async_function() -> u32 {
+/// let x: Option<u32> = None;
+/// x?; //~ ERROR the `?` operator
+/// 22
+/// }
+/// ```
+/// it will look like this:
+///
+/// ```rust,ignore (just an example)
+/// FormatArgs {
+/// this: "FromResidual",
+/// trait_sugared: "FromResidual<Option<Infallible>>",
+/// item_context: "an async function",
+/// generic_args: [("Self", "u32"), ("R", "Option<Infallible>")],
+/// }
+/// ```
+#[derive(Debug)]
+pub struct FormatArgs<'tcx> {
+ pub this: String,
+ pub trait_sugared: TraitRefPrintSugared<'tcx>,
+ pub item_context: &'static str,
+ pub generic_args: Vec<(Symbol, String)>,
+}
+
+impl FormatString {
+ pub fn span(&self) -> Span {
+ self.span
+ }
+
+ pub fn parse<'tcx>(
+ input: Symbol,
+ span: Span,
+ ctx: &Ctx<'tcx>,
+ ) -> Result<Self, Vec<ParseError>> {
+ let s = input.as_str();
+ let mut parser = Parser::new(s, None, None, false, ParseMode::Format);
+ let mut pieces = Vec::new();
+ let mut warnings = Vec::new();
+
+ for piece in &mut parser {
+ match piece {
+ RpfPiece::Lit(lit) => {
+ pieces.push(Piece::Lit(lit.into()));
+ }
+ RpfPiece::NextArgument(arg) => {
+ warn_on_format_spec(arg.format, &mut warnings, span);
+ let arg = parse_arg(&arg, ctx, &mut warnings, span);
+ pieces.push(Piece::Arg(arg));
+ }
+ }
+ }
+
+ if parser.errors.is_empty() {
+ Ok(FormatString { input, pieces, span, warnings })
+ } else {
+ Err(parser.errors)
+ }
+ }
+
+ pub fn format(&self, args: &FormatArgs<'_>) -> String {
+ let mut ret = String::new();
+ for piece in &self.pieces {
+ match piece {
+ Piece::Lit(s) | Piece::Arg(FormatArg::AsIs(s)) => ret.push_str(&s),
+
+ // `A` if we have `trait Trait<A> {}` and `note = "i'm the actual type of {A}"`
+ Piece::Arg(FormatArg::GenericParam { generic_param }) => {
+ // Should always be some but we can't raise errors here
+ let value = match args.generic_args.iter().find(|(p, _)| p == generic_param) {
+ Some((_, val)) => val.to_string(),
+ None => generic_param.to_string(),
+ };
+ ret.push_str(&value);
+ }
+ // `{Self}`
+ Piece::Arg(FormatArg::SelfUpper) => {
+ let slf = match args.generic_args.iter().find(|(p, _)| *p == kw::SelfUpper) {
+ Some((_, val)) => val.to_string(),
+ None => "Self".to_string(),
+ };
+ ret.push_str(&slf);
+ }
+
+ // It's only `rustc_onunimplemented` from here
+ Piece::Arg(FormatArg::This) => ret.push_str(&args.this),
+ Piece::Arg(FormatArg::Trait) => {
+ let _ = fmt::write(&mut ret, format_args!("{}", &args.trait_sugared));
+ }
+ Piece::Arg(FormatArg::ItemContext) => ret.push_str(args.item_context),
+ }
+ }
+ ret
+ }
+}
+
+fn parse_arg<'tcx>(
+ arg: &Argument<'_>,
+ ctx: &Ctx<'tcx>,
+ warnings: &mut Vec<FormatWarning>,
+ input_span: Span,
+) -> FormatArg {
+ let (Ctx::RustcOnUnimplemented { tcx, trait_def_id }
+ | Ctx::DiagnosticOnUnimplemented { tcx, trait_def_id }) = ctx;
+ let trait_name = tcx.item_ident(*trait_def_id);
+ let generics = tcx.generics_of(trait_def_id);
+ let span = slice_span(input_span, arg.position_span);
+
+ match arg.position {
+ // Something like "hello {name}"
+ Position::ArgumentNamed(name) => match (ctx, Symbol::intern(name)) {
+ // accepted, but deprecated
+ (Ctx::RustcOnUnimplemented { .. }, sym::_Self) => {
+ warnings
+ .push(FormatWarning::FutureIncompat { span, help: String::from("use {Self}") });
+ FormatArg::SelfUpper
+ }
+ (
+ Ctx::RustcOnUnimplemented { .. },
+ sym::from_desugaring
+ | sym::crate_local
+ | sym::direct
+ | sym::cause
+ | sym::float
+ | sym::integer_
+ | sym::integral,
+ ) => {
+ warnings.push(FormatWarning::FutureIncompat {
+ span,
+ help: String::from("don't use this in a format string"),
+ });
+ FormatArg::AsIs(String::new())
+ }
+
+ // Only `#[rustc_on_unimplemented]` can use these
+ (Ctx::RustcOnUnimplemented { .. }, sym::ItemContext) => FormatArg::ItemContext,
+ (Ctx::RustcOnUnimplemented { .. }, sym::This) => FormatArg::This,
+ (Ctx::RustcOnUnimplemented { .. }, sym::Trait) => FormatArg::Trait,
+ // `{ThisTraitsName}`. Some attrs in std use this, but I'd like to change it to the more general `{This}`
+ // because that'll be simpler to parse and extend in the future
+ (Ctx::RustcOnUnimplemented { .. }, name) if name == trait_name.name => {
+ warnings
+ .push(FormatWarning::FutureIncompat { span, help: String::from("use {This}") });
+ FormatArg::This
+ }
+
+ // Any attribute can use these
+ (
+ Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. },
+ kw::SelfUpper,
+ ) => FormatArg::SelfUpper,
+ (
+ Ctx::RustcOnUnimplemented { .. } | Ctx::DiagnosticOnUnimplemented { .. },
+ generic_param,
+ ) if generics.own_params.iter().any(|param| param.name == generic_param) => {
+ FormatArg::GenericParam { generic_param }
+ }
+
+ (_, argument_name) => {
+ warnings.push(FormatWarning::UnknownParam { argument_name, span });
+ FormatArg::AsIs(format!("{{{}}}", argument_name.as_str()))
+ }
+ },
+
+ // `{:1}` and `{}` are ignored
+ Position::ArgumentIs(idx) => {
+ warnings.push(FormatWarning::PositionalArgument {
+ span,
+ help: format!("use `{{{idx}}}` to print a number in braces"),
+ });
+ FormatArg::AsIs(format!("{{{idx}}}"))
+ }
+ Position::ArgumentImplicitlyIs(_) => {
+ warnings.push(FormatWarning::PositionalArgument {
+ span,
+ help: String::from("use `{{}}` to print empty braces"),
+ });
+ FormatArg::AsIs(String::from("{}"))
+ }
+ }
+}
+
+/// `#[rustc_on_unimplemented]` and `#[diagnostic::...]` don't actually do anything
+/// with specifiers, so emit a warning if they are used.
+fn warn_on_format_spec(spec: FormatSpec<'_>, warnings: &mut Vec<FormatWarning>, input_span: Span) {
+ if !matches!(
+ spec,
+ FormatSpec {
+ fill: None,
+ fill_span: None,
+ align: Alignment::AlignUnknown,
+ sign: None,
+ alternate: false,
+ zero_pad: false,
+ debug_hex: None,
+ precision: Count::CountImplied,
+ precision_span: None,
+ width: Count::CountImplied,
+ width_span: None,
+ ty: _,
+ ty_span: _,
+ },
+ ) {
+ let span = spec.ty_span.map(|inner| slice_span(input_span, inner)).unwrap_or(input_span);
+ warnings.push(FormatWarning::InvalidSpecifier { span, name: spec.ty.into() })
+ }
+}
+
+/// Helper function because `Span` and `rustc_parse_format::InnerSpan` don't know about each other
+fn slice_span(input: Span, inner: InnerSpan) -> Span {
+ let InnerSpan { start, end } = inner;
+ let span = input.data();
+
+ Span::new(
+ span.lo + BytePos::from_usize(start),
+ span.lo + BytePos::from_usize(end),
+ span.ctxt,
+ span.parent,
+ )
+}
+
+pub mod errors {
+ use rustc_macros::LintDiagnostic;
+ use rustc_span::Ident;
+
+ use super::*;
+
+ #[derive(LintDiagnostic)]
+ #[diag(trait_selection_unknown_format_parameter_for_on_unimplemented_attr)]
+ #[help]
+ pub struct UnknownFormatParameterForOnUnimplementedAttr {
+ pub argument_name: Symbol,
+ pub trait_name: Ident,
+ }
+
+ #[derive(LintDiagnostic)]
+ #[diag(trait_selection_disallowed_positional_argument)]
+ #[help]
+ pub struct DisallowedPositionalArgument;
+
+ #[derive(LintDiagnostic)]
+ #[diag(trait_selection_invalid_format_specifier)]
+ #[help]
+ pub struct InvalidFormatSpecifier;
+
+ #[derive(LintDiagnostic)]
+ #[diag(trait_selection_missing_options_for_on_unimplemented_attr)]
+ #[help]
+ pub struct MissingOptionsForOnUnimplementedAttr;
+
+ #[derive(LintDiagnostic)]
+ #[diag(trait_selection_ignored_diagnostic_option)]
+ pub struct IgnoredDiagnosticOption {
+ pub option_name: &'static str,
+ #[label]
+ pub span: Span,
+ #[label(trait_selection_other_label)]
+ pub prev_span: Span,
+ }
+
+ impl IgnoredDiagnosticOption {
+ pub fn maybe_emit_warning<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ item_def_id: DefId,
+ new: Option<Span>,
+ old: Option<Span>,
+ option_name: &'static str,
+ ) {
+ if let (Some(new_item), Some(old_item)) = (new, old) {
+ if let Some(item_def_id) = item_def_id.as_local() {
+ tcx.emit_node_span_lint(
+ UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+ tcx.local_def_id_to_hir_id(item_def_id),
+ new_item,
+ IgnoredDiagnosticOption {
+ span: new_item,
+ prev_span: old_item,
+ option_name,
+ },
+ );
+ }
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index b963e4a..de251ae 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -2112,16 +2112,20 @@ pub(super) fn suggest_fully_qualified_path(
trait_ref: DefId,
) {
if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id) {
- if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind {
+ if let ty::AssocKind::Const { .. } | ty::AssocKind::Type { .. } = assoc_item.kind {
err.note(format!(
"{}s cannot be accessed directly on a `trait`, they can only be \
accessed through a specific `impl`",
- self.tcx.def_kind_descr(assoc_item.kind.as_def_kind(), item_def_id)
+ self.tcx.def_kind_descr(assoc_item.as_def_kind(), item_def_id)
));
err.span_suggestion(
span,
"use the fully qualified path to an implementation",
- format!("<Type as {}>::{}", self.tcx.def_path_str(trait_ref), assoc_item.name),
+ format!(
+ "<Type as {}>::{}",
+ self.tcx.def_path_str(trait_ref),
+ assoc_item.name()
+ ),
Applicability::HasPlaceholders,
);
}
@@ -3840,12 +3844,7 @@ fn note_function_argument_obligation<G: EmissionGuarantee>(
);
if let ty::PredicateKind::Clause(clause) = failed_pred.kind().skip_binder()
&& let ty::ClauseKind::Trait(pred) = clause
- && [
- tcx.lang_items().fn_once_trait(),
- tcx.lang_items().fn_mut_trait(),
- tcx.lang_items().fn_trait(),
- ]
- .contains(&Some(pred.def_id()))
+ && tcx.fn_trait_kind_from_def_id(pred.def_id()).is_some()
{
if let [stmt, ..] = block.stmts
&& let hir::StmtKind::Semi(value) = stmt.kind
@@ -5411,7 +5410,7 @@ fn point_at_assoc_type_restriction<G: EmissionGuarantee>(
tcx.associated_items(data.impl_or_alias_def_id).find_by_ident_and_kind(
tcx,
Ident::with_dummy_span(name),
- ty::AssocKind::Type,
+ ty::AssocTag::Type,
data.impl_or_alias_def_id,
)
{
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index bb4aba9..756d9a5 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -4,7 +4,7 @@
use rustc_errors::codes::*;
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, DiagMessage, DiagStyledString, Diagnostic,
- EmissionGuarantee, IntoDiagArg, Level, MultiSpan, SubdiagMessageOp, Subdiagnostic,
+ EmissionGuarantee, IntoDiagArg, Level, MultiSpan, Subdiagnostic,
};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -107,11 +107,7 @@ pub enum AdjustSignatureBorrow {
}
impl Subdiagnostic for AdjustSignatureBorrow {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
match self {
AdjustSignatureBorrow::Borrow { to_borrow } => {
diag.arg("len", to_borrow.len());
@@ -381,11 +377,7 @@ pub enum RegionOriginNote<'a> {
}
impl Subdiagnostic for RegionOriginNote<'_> {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut label_or_note = |span, msg: DiagMessage| {
let sub_count = diag.children.iter().filter(|d| d.span.is_dummy()).count();
let expanded_sub_count = diag.children.iter().filter(|d| !d.span.is_dummy()).count();
@@ -446,11 +438,7 @@ pub enum LifetimeMismatchLabels {
}
impl Subdiagnostic for LifetimeMismatchLabels {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
match self {
LifetimeMismatchLabels::InRet { param_span, ret_span, span, label_var1 } => {
diag.span_label(param_span, fluent::trait_selection_declared_different);
@@ -495,11 +483,7 @@ pub struct AddLifetimeParamsSuggestion<'a> {
}
impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut mk_suggestion = || {
let Some(anon_reg) = self.tcx.is_suitable_region(self.generic_param_scope, self.sub)
else {
@@ -689,11 +673,7 @@ pub struct IntroducesStaticBecauseUnmetLifetimeReq {
}
impl Subdiagnostic for IntroducesStaticBecauseUnmetLifetimeReq {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- mut self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(mut self, diag: &mut Diag<'_, G>) {
self.unmet_requirements
.push_span_label(self.binding_span, fluent::trait_selection_msl_introduces_static);
diag.span_note(self.unmet_requirements, fluent::trait_selection_msl_unmet_req);
@@ -1008,17 +988,13 @@ pub struct ConsiderBorrowingParamHelp {
}
impl Subdiagnostic for ConsiderBorrowingParamHelp {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut type_param_span: MultiSpan = self.spans.clone().into();
for &span in &self.spans {
// Seems like we can't call f() here as Into<DiagMessage> is required
type_param_span.push_span_label(span, fluent::trait_selection_tid_consider_borrowing);
}
- let msg = f(diag, fluent::trait_selection_tid_param_help.into());
+ let msg = diag.eagerly_translate(fluent::trait_selection_tid_param_help);
diag.span_help(type_param_span, msg);
}
}
@@ -1053,18 +1029,14 @@ pub struct DynTraitConstraintSuggestion {
}
impl Subdiagnostic for DynTraitConstraintSuggestion {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let mut multi_span: MultiSpan = vec![self.span].into();
multi_span.push_span_label(self.span, fluent::trait_selection_dtcs_has_lifetime_req_label);
multi_span
.push_span_label(self.ident.span, fluent::trait_selection_dtcs_introduces_requirement);
- let msg = f(diag, fluent::trait_selection_dtcs_has_req_note.into());
+ let msg = diag.eagerly_translate(fluent::trait_selection_dtcs_has_req_note);
diag.span_note(multi_span, msg);
- let msg = f(diag, fluent::trait_selection_dtcs_suggestion.into());
+ let msg = diag.eagerly_translate(fluent::trait_selection_dtcs_suggestion);
diag.span_suggestion_verbose(
self.span.shrink_to_hi(),
msg,
@@ -1101,11 +1073,7 @@ pub struct ReqIntroducedLocations {
}
impl Subdiagnostic for ReqIntroducedLocations {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- mut self,
- diag: &mut Diag<'_, G>,
- f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(mut self, diag: &mut Diag<'_, G>) {
for sp in self.spans {
self.span.push_span_label(sp, fluent::trait_selection_ril_introduced_here);
}
@@ -1114,7 +1082,7 @@ fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self.span.push_span_label(self.fn_decl_span, fluent::trait_selection_ril_introduced_by);
}
self.span.push_span_label(self.cause_span, fluent::trait_selection_ril_because_of);
- let msg = f(diag, fluent::trait_selection_ril_static_introduced_by.into());
+ let msg = diag.eagerly_translate(fluent::trait_selection_ril_static_introduced_by);
diag.span_note(self.span, msg);
}
}
@@ -1513,13 +1481,9 @@ pub struct SuggestTuplePatternMany {
}
impl Subdiagnostic for SuggestTuplePatternMany {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("path", self.path);
- let message = f(diag, crate::fluent_generated::trait_selection_stp_wrap_many.into());
+ let message = diag.eagerly_translate(fluent::trait_selection_stp_wrap_many);
diag.multipart_suggestions(
message,
self.compatible_variants.into_iter().map(|variant| {
@@ -1752,11 +1716,7 @@ pub struct AddPreciseCapturingAndParams {
}
impl Subdiagnostic for AddPreciseCapturingAndParams {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("new_lifetime", self.new_lifetime);
diag.multipart_suggestion_verbose(
fluent::trait_selection_precise_capturing_new_but_apit,
@@ -1896,11 +1856,7 @@ pub struct AddPreciseCapturingForOvercapture {
}
impl Subdiagnostic for AddPreciseCapturingForOvercapture {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- _f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
let applicability = if self.apit_spans.is_empty() {
Applicability::MachineApplicable
} else {
@@ -1926,7 +1882,7 @@ fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
#[derive(Diagnostic)]
#[diag(trait_selection_opaque_type_non_generic_param, code = E0792)]
pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
- pub ty: GenericArg<'tcx>,
+ pub arg: GenericArg<'tcx>,
pub kind: &'a str,
#[primary_span]
pub span: Span,
diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
index e4ab78b..84e7686 100644
--- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
@@ -1,4 +1,4 @@
-use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, SubdiagMessageOp, Subdiagnostic};
+use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, Subdiagnostic};
use rustc_hir::def_id::LocalDefId;
use rustc_middle::bug;
use rustc_middle::ty::{self, TyCtxt};
@@ -162,17 +162,13 @@ pub fn new<'tcx>(
}
impl Subdiagnostic for RegionExplanation<'_> {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
- self,
- diag: &mut Diag<'_, G>,
- f: &F,
- ) {
+ fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
diag.arg("pref_kind", self.prefix);
diag.arg("suff_kind", self.suffix);
diag.arg("desc_kind", self.desc.kind);
diag.arg("desc_arg", self.desc.arg);
- let msg = f(diag, fluent::trait_selection_region_explanation.into());
+ let msg = diag.eagerly_translate(fluent::trait_selection_region_explanation);
if let Some(span) = self.desc.span {
diag.span_note(span, msg);
} else {
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 84ac229..0dab3ad 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -34,7 +34,7 @@ fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx
// FIXME(#132279): This should be removed as it causes us to incorrectly
// handle opaques in their defining scope.
- if !(param_env, ty).has_infer() {
+ if !self.next_trait_solver() && !(param_env, ty).has_infer() {
return self.tcx.type_is_copy_modulo_regions(self.typing_env(param_env), ty);
}
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 309bf4d..cce67b0 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -70,7 +70,7 @@ pub fn check_opaque_type_parameter_valid<'tcx>(
opaque_env.param_is_error(i)?;
return Err(infcx.dcx().emit_err(NonGenericOpaqueTypeParam {
- ty: arg,
+ arg,
kind,
span,
param_span: tcx.def_span(opaque_param.def_id),
diff --git a/compiler/rustc_trait_selection/src/solve.rs b/compiler/rustc_trait_selection/src/solve.rs
index d425ab5..0c2451a 100644
--- a/compiler/rustc_trait_selection/src/solve.rs
+++ b/compiler/rustc_trait_selection/src/solve.rs
@@ -9,5 +9,8 @@
pub(crate) use delegate::SolverDelegate;
pub use fulfill::{FulfillmentCtxt, NextSolverError};
pub(crate) use normalize::deeply_normalize_for_diagnostics;
-pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes};
+pub use normalize::{
+ deeply_normalize, deeply_normalize_with_skipped_universes,
+ deeply_normalize_with_skipped_universes_and_ambiguous_goals,
+};
pub use select::InferCtxtSelectExt;
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 192e632..848d064 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -1,18 +1,26 @@
use std::marker::PhantomData;
use std::mem;
+use std::ops::ControlFlow;
use rustc_data_structures::thinvec::ExtractIf;
+use rustc_hir::def_id::LocalDefId;
use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::{
FromSolverError, PredicateObligation, PredicateObligations, TraitEngine,
};
+use rustc_middle::ty::{
+ self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, TypingMode,
+};
use rustc_next_trait_solver::solve::{GenerateProofTree, HasChanged, SolverDelegateEvalExt as _};
+use rustc_span::Span;
+use rustc_type_ir::data_structures::DelayedSet;
use tracing::instrument;
use self::derive_errors::*;
use super::Certainty;
use super::delegate::SolverDelegate;
+use super::inspect::{self, ProofTreeInferCtxtExt};
use crate::traits::{FulfillmentError, ScrubbedTraitError};
mod derive_errors;
@@ -39,7 +47,7 @@ pub struct FulfillmentCtxt<'tcx, E: 'tcx> {
_errors: PhantomData<E>,
}
-#[derive(Default)]
+#[derive(Default, Debug)]
struct ObligationStorage<'tcx> {
/// Obligations which resulted in an overflow in fulfillment itself.
///
@@ -55,20 +63,23 @@ fn register(&mut self, obligation: PredicateObligation<'tcx>) {
self.pending.push(obligation);
}
+ fn has_pending_obligations(&self) -> bool {
+ !self.pending.is_empty() || !self.overflowed.is_empty()
+ }
+
fn clone_pending(&self) -> PredicateObligations<'tcx> {
let mut obligations = self.pending.clone();
obligations.extend(self.overflowed.iter().cloned());
obligations
}
- fn take_pending(&mut self) -> PredicateObligations<'tcx> {
- let mut obligations = mem::take(&mut self.pending);
- obligations.append(&mut self.overflowed);
- obligations
- }
-
- fn unstalled_for_select(&mut self) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'tcx {
- mem::take(&mut self.pending).into_iter()
+ fn drain_pending(
+ &mut self,
+ cond: impl Fn(&PredicateObligation<'tcx>) -> bool,
+ ) -> PredicateObligations<'tcx> {
+ let (unstalled, pending) = mem::take(&mut self.pending).into_iter().partition(cond);
+ self.pending = pending;
+ unstalled
}
fn on_fulfillment_overflow(&mut self, infcx: &InferCtxt<'tcx>) {
@@ -160,7 +171,7 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
}
let mut has_changed = false;
- for obligation in self.obligations.unstalled_for_select() {
+ for obligation in self.obligations.drain_pending(|_| true) {
let goal = obligation.as_goal();
let result = <&SolverDelegate<'tcx>>::from(infcx)
.evaluate_root_goal(goal, GenerateProofTree::No, obligation.cause.span)
@@ -196,15 +207,95 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
}
fn has_pending_obligations(&self) -> bool {
- !self.obligations.pending.is_empty() || !self.obligations.overflowed.is_empty()
+ self.obligations.has_pending_obligations()
}
fn pending_obligations(&self) -> PredicateObligations<'tcx> {
self.obligations.clone_pending()
}
- fn drain_unstalled_obligations(&mut self, _: &InferCtxt<'tcx>) -> PredicateObligations<'tcx> {
- self.obligations.take_pending()
+ fn drain_stalled_obligations_for_coroutines(
+ &mut self,
+ infcx: &InferCtxt<'tcx>,
+ ) -> PredicateObligations<'tcx> {
+ let stalled_generators = match infcx.typing_mode() {
+ TypingMode::Analysis { defining_opaque_types_and_generators } => {
+ defining_opaque_types_and_generators
+ }
+ TypingMode::Coherence
+ | TypingMode::Borrowck { defining_opaque_types: _ }
+ | TypingMode::PostBorrowckAnalysis { defined_opaque_types: _ }
+ | TypingMode::PostAnalysis => return Default::default(),
+ };
+
+ if stalled_generators.is_empty() {
+ return Default::default();
+ }
+
+ self.obligations.drain_pending(|obl| {
+ infcx.probe(|_| {
+ infcx
+ .visit_proof_tree(
+ obl.as_goal(),
+ &mut StalledOnCoroutines {
+ stalled_generators,
+ span: obl.cause.span,
+ cache: Default::default(),
+ },
+ )
+ .is_break()
+ })
+ })
+ }
+}
+
+/// Detect if a goal is stalled on a coroutine that is owned by the current typeck root.
+///
+/// This function can (erroneously) fail to detect a predicate, i.e. it doesn't need to
+/// be complete. However, this will lead to ambiguity errors, so we want to make it
+/// accurate.
+///
+/// This function can be also return false positives, which will lead to poor diagnostics
+/// so we want to keep this visitor *precise* too.
+struct StalledOnCoroutines<'tcx> {
+ stalled_generators: &'tcx ty::List<LocalDefId>,
+ span: Span,
+ cache: DelayedSet<Ty<'tcx>>,
+}
+
+impl<'tcx> inspect::ProofTreeVisitor<'tcx> for StalledOnCoroutines<'tcx> {
+ type Result = ControlFlow<()>;
+
+ fn span(&self) -> rustc_span::Span {
+ self.span
+ }
+
+ fn visit_goal(&mut self, inspect_goal: &super::inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
+ inspect_goal.goal().predicate.visit_with(self)?;
+
+ if let Some(candidate) = inspect_goal.unique_applicable_candidate() {
+ candidate.visit_nested_no_probe(self)
+ } else {
+ ControlFlow::Continue(())
+ }
+ }
+}
+
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for StalledOnCoroutines<'tcx> {
+ type Result = ControlFlow<()>;
+
+ fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
+ if !self.cache.insert(ty) {
+ return ControlFlow::Continue(());
+ }
+
+ if let ty::CoroutineWitness(def_id, _) = *ty.kind()
+ && def_id.as_local().is_some_and(|def_id| self.stalled_generators.contains(&def_id))
+ {
+ return ControlFlow::Break(());
+ }
+
+ ty.super_visit_with(self)
}
}
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
index d8dcd12..f6c650c 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
@@ -1,5 +1,6 @@
use std::ops::ControlFlow;
+use rustc_hir::LangItem;
use rustc_infer::infer::InferCtxt;
use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause};
use rustc_infer::traits::{
@@ -109,10 +110,16 @@ pub(super) fn fulfillment_error_for_stalled<'tcx>(
false,
),
Ok((_, Certainty::Yes)) => {
- bug!("did not expect successful goal when collecting ambiguity errors")
+ bug!(
+ "did not expect successful goal when collecting ambiguity errors for `{:?}`",
+ infcx.resolve_vars_if_possible(root_obligation.predicate),
+ )
}
Err(_) => {
- bug!("did not expect selection error when collecting ambiguity errors")
+ bug!(
+ "did not expect selection error when collecting ambiguity errors for `{:?}`",
+ infcx.resolve_vars_if_possible(root_obligation.predicate),
+ )
}
}
});
@@ -452,9 +459,8 @@ fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result
// We do this as a separate loop so that we do not choose to tell the user about some nested
// goal before we encounter a `T: FnPtr` nested goal.
for nested_goal in &nested_goals {
- if let Some(fn_ptr_trait) = tcx.lang_items().fn_ptr_trait()
- && let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause()
- && poly_trait_pred.def_id() == fn_ptr_trait
+ if let Some(poly_trait_pred) = nested_goal.goal().predicate.as_trait_clause()
+ && tcx.is_lang_item(poly_trait_pred.def_id(), LangItem::FnPtrTrait)
&& let Err(NoSolution) = nested_goal.result()
{
return ControlFlow::Break(self.obligation.clone());
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index 48a05ad..24b8700 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -292,7 +292,7 @@ fn candidates_recur(
inspect::ProbeStep::NestedProbe(ref probe) => {
match probe.kind {
// These never assemble candidates for the goal we're trying to solve.
- inspect::ProbeKind::UpcastProjectionCompatibility
+ inspect::ProbeKind::ProjectionCompatibility
| inspect::ProbeKind::ShadowedEnvProbing => continue,
inspect::ProbeKind::NormalizedSelfTyAssembly
@@ -314,8 +314,10 @@ fn candidates_recur(
}
match probe.kind {
- inspect::ProbeKind::UpcastProjectionCompatibility
- | inspect::ProbeKind::ShadowedEnvProbing => bug!(),
+ inspect::ProbeKind::ProjectionCompatibility
+ | inspect::ProbeKind::ShadowedEnvProbing => {
+ bug!()
+ }
inspect::ProbeKind::NormalizedSelfTyAssembly | inspect::ProbeKind::UnsizeAssembly => {}
diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
index 79fb044..5f1e63a 100644
--- a/compiler/rustc_trait_selection/src/solve/normalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -1,10 +1,10 @@
use std::assert_matches::assert_matches;
use std::fmt::Debug;
-use std::marker::PhantomData;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_infer::infer::InferCtxt;
use rustc_infer::infer::at::At;
+use rustc_infer::traits::solve::Goal;
use rustc_infer::traits::{FromSolverError, Obligation, TraitEngine};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{
@@ -45,11 +45,37 @@ pub fn deeply_normalize_with_skipped_universes<'tcx, T, E>(
T: TypeFoldable<TyCtxt<'tcx>>,
E: FromSolverError<'tcx, NextSolverError<'tcx>>,
{
+ let (value, goals) =
+ deeply_normalize_with_skipped_universes_and_ambiguous_goals(at, value, universes)?;
+ assert_eq!(goals, vec![]);
+
+ Ok(value)
+}
+
+/// Deeply normalize all aliases in `value`. This does not handle inference and expects
+/// its input to be already fully resolved.
+///
+/// Additionally takes a list of universes which represents the binders which have been
+/// entered before passing `value` to the function. This is currently needed for
+/// `normalize_erasing_regions`, which skips binders as it walks through a type.
+///
+/// This returns a set of stalled obligations if the typing mode of the underlying infcx
+/// has any stalled coroutine def ids.
+pub fn deeply_normalize_with_skipped_universes_and_ambiguous_goals<'tcx, T, E>(
+ at: At<'_, 'tcx>,
+ value: T,
+ universes: Vec<Option<UniverseIndex>>,
+) -> Result<(T, Vec<Goal<'tcx, ty::Predicate<'tcx>>>), Vec<E>>
+where
+ T: TypeFoldable<TyCtxt<'tcx>>,
+ E: FromSolverError<'tcx, NextSolverError<'tcx>>,
+{
let fulfill_cx = FulfillmentCtxt::new(at.infcx);
let mut folder =
- NormalizationFolder { at, fulfill_cx, depth: 0, universes, _errors: PhantomData };
-
- value.try_fold_with(&mut folder)
+ NormalizationFolder { at, fulfill_cx, depth: 0, universes, stalled_goals: vec![] };
+ let value = value.try_fold_with(&mut folder)?;
+ let errors = folder.fulfill_cx.select_all_or_error(at.infcx);
+ if errors.is_empty() { Ok((value, folder.stalled_goals)) } else { Err(errors) }
}
struct NormalizationFolder<'me, 'tcx, E> {
@@ -57,7 +83,7 @@ struct NormalizationFolder<'me, 'tcx, E> {
fulfill_cx: FulfillmentCtxt<'tcx, E>,
depth: usize,
universes: Vec<Option<UniverseIndex>>,
- _errors: PhantomData<E>,
+ stalled_goals: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
}
impl<'tcx, E> NormalizationFolder<'_, 'tcx, E>
@@ -98,10 +124,7 @@ fn normalize_alias_ty(&mut self, alias_ty: Ty<'tcx>) -> Result<Ty<'tcx>, Vec<E>>
);
self.fulfill_cx.register_predicate_obligation(infcx, obligation);
- let errors = self.fulfill_cx.select_all_or_error(infcx);
- if !errors.is_empty() {
- return Err(errors);
- }
+ self.select_all_and_stall_coroutine_predicates()?;
// Alias is guaranteed to be fully structurally resolved,
// so we can super fold here.
@@ -139,7 +162,7 @@ fn normalize_unevaluated_const(
let result = if infcx.predicate_may_hold(&obligation) {
self.fulfill_cx.register_predicate_obligation(infcx, obligation);
- let errors = self.fulfill_cx.select_all_or_error(infcx);
+ let errors = self.fulfill_cx.select_where_possible(infcx);
if !errors.is_empty() {
return Err(errors);
}
@@ -152,6 +175,27 @@ fn normalize_unevaluated_const(
self.depth -= 1;
Ok(result)
}
+
+ fn select_all_and_stall_coroutine_predicates(&mut self) -> Result<(), Vec<E>> {
+ let errors = self.fulfill_cx.select_where_possible(self.at.infcx);
+ if !errors.is_empty() {
+ return Err(errors);
+ }
+
+ self.stalled_goals.extend(
+ self.fulfill_cx
+ .drain_stalled_obligations_for_coroutines(self.at.infcx)
+ .into_iter()
+ .map(|obl| obl.as_goal()),
+ );
+
+ let errors = self.fulfill_cx.collect_remaining_errors(self.at.infcx);
+ if !errors.is_empty() {
+ return Err(errors);
+ }
+
+ Ok(())
+ }
}
impl<'tcx, E> FallibleTypeFolder<TyCtxt<'tcx>> for NormalizationFolder<'_, 'tcx, E>
@@ -254,27 +298,31 @@ fn cx(&self) -> TyCtxt<'tcx> {
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
let infcx = self.at.infcx;
- infcx
- .commit_if_ok(|_| {
- deeply_normalize_with_skipped_universes(
- self.at,
- ty,
- vec![None; ty.outer_exclusive_binder().as_usize()],
- )
- })
- .unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ty.super_fold_with(self))
+ let result =
+ infcx.commit_if_ok(|_| {
+ deeply_normalize_with_skipped_universes_and_ambiguous_goals::<
+ _,
+ ScrubbedTraitError<'tcx>,
+ >(self.at, ty, vec![None; ty.outer_exclusive_binder().as_usize()])
+ });
+ match result {
+ Ok((ty, _)) => ty,
+ Err(_) => ty.super_fold_with(self),
+ }
}
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
let infcx = self.at.infcx;
- infcx
- .commit_if_ok(|_| {
- deeply_normalize_with_skipped_universes(
- self.at,
- ct,
- vec![None; ct.outer_exclusive_binder().as_usize()],
- )
- })
- .unwrap_or_else(|_: Vec<ScrubbedTraitError<'tcx>>| ct.super_fold_with(self))
+ let result =
+ infcx.commit_if_ok(|_| {
+ deeply_normalize_with_skipped_universes_and_ambiguous_goals::<
+ _,
+ ScrubbedTraitError<'tcx>,
+ >(self.at, ct, vec![None; ct.outer_exclusive_binder().as_usize()])
+ });
+ match result {
+ Ok((ct, _)) => ct,
+ Err(_) => ct.super_fold_with(self),
+ }
}
}
diff --git a/compiler/rustc_trait_selection/src/solve/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs
index 4437fc5..4fdaf74 100644
--- a/compiler/rustc_trait_selection/src/solve/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/select.rs
@@ -177,7 +177,7 @@ fn to_selection<'tcx>(
},
ProbeKind::NormalizedSelfTyAssembly
| ProbeKind::UnsizeAssembly
- | ProbeKind::UpcastProjectionCompatibility
+ | ProbeKind::ProjectionCompatibility
| ProbeKind::OpaqueTypeStorageLookup { result: _ }
| ProbeKind::Root { result: _ }
| ProbeKind::ShadowedEnvProbing
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index bf9fcb0..5193946 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -188,7 +188,7 @@ fn predicates_reference_self(
tcx.associated_items(trait_def_id)
.in_definition_order()
// We're only looking at associated type bounds
- .filter(|item| item.kind == ty::AssocKind::Type)
+ .filter(|item| item.is_type())
// Ignore GATs with `Self: Sized`
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
.flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied())
@@ -298,31 +298,33 @@ pub fn dyn_compatibility_violations_for_assoc_item(
match item.kind {
// Associated consts are never dyn-compatible, as they can't have `where` bounds yet at all,
// and associated const bounds in trait objects aren't a thing yet either.
- ty::AssocKind::Const => {
- vec![DynCompatibilityViolation::AssocConst(item.name, item.ident(tcx).span)]
+ ty::AssocKind::Const { name } => {
+ vec![DynCompatibilityViolation::AssocConst(name, item.ident(tcx).span)]
}
- ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item)
- .into_iter()
- .map(|v| {
- let node = tcx.hir_get_if_local(item.def_id);
- // Get an accurate span depending on the violation.
- let span = match (&v, node) {
- (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
- (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
- (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
- (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
- node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
- }
- _ => item.ident(tcx).span,
- };
+ ty::AssocKind::Fn { name, .. } => {
+ virtual_call_violations_for_method(tcx, trait_def_id, item)
+ .into_iter()
+ .map(|v| {
+ let node = tcx.hir_get_if_local(item.def_id);
+ // Get an accurate span depending on the violation.
+ let span = match (&v, node) {
+ (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
+ (MethodViolationCode::UndispatchableReceiver(Some(span)), _) => *span,
+ (MethodViolationCode::ReferencesImplTraitInTrait(span), _) => *span,
+ (MethodViolationCode::ReferencesSelfOutput, Some(node)) => {
+ node.fn_decl().map_or(item.ident(tcx).span, |decl| decl.output.span())
+ }
+ _ => item.ident(tcx).span,
+ };
- DynCompatibilityViolation::Method(item.name, v, span)
- })
- .collect(),
+ DynCompatibilityViolation::Method(name, v, span)
+ })
+ .collect()
+ }
// Associated types can only be dyn-compatible if they have `Self: Sized` bounds.
- ty::AssocKind::Type => {
+ ty::AssocKind::Type { .. } => {
if !tcx.generics_of(item.def_id).is_own_empty() && !item.is_impl_trait_in_trait() {
- vec![DynCompatibilityViolation::GAT(item.name, item.ident(tcx).span)]
+ vec![DynCompatibilityViolation::GAT(item.name(), item.ident(tcx).span)]
} else {
// We will permit associated types if they are explicitly mentioned in the trait object.
// We can't check this here, as here we only check if it is guaranteed to not be possible.
@@ -344,7 +346,7 @@ fn virtual_call_violations_for_method<'tcx>(
let sig = tcx.fn_sig(method.def_id).instantiate_identity();
// The method's first parameter must be named `self`
- if !method.fn_has_self_parameter {
+ if !method.is_method() {
let sugg = if let Some(hir::Node::TraitItem(hir::TraitItem {
generics,
kind: hir::TraitItemKind::Fn(sig, _),
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index e98a240..a11f8d3 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -24,10 +24,10 @@
};
use crate::error_reporting::InferCtxtErrorExt;
use crate::infer::{InferCtxt, TyOrConstInferVar};
-use crate::traits::EvaluateConstErr;
use crate::traits::normalize::normalize_with_depth_to;
use crate::traits::project::{PolyProjectionObligation, ProjectionCacheKeyExt as _};
use crate::traits::query::evaluate_obligation::InferCtxtExt;
+use crate::traits::{EvaluateConstErr, sizedness_fast_path};
pub(crate) type PendingPredicateObligations<'tcx> = ThinVec<PendingPredicateObligation<'tcx>>;
@@ -162,7 +162,7 @@ fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> {
self.select(selcx)
}
- fn drain_unstalled_obligations(
+ fn drain_stalled_obligations_for_coroutines(
&mut self,
infcx: &InferCtxt<'tcx>,
) -> PredicateObligations<'tcx> {
@@ -335,6 +335,10 @@ fn process_obligation(
let infcx = self.selcx.infcx;
+ if sizedness_fast_path(infcx.tcx, obligation.predicate) {
+ return ProcessResult::Changed(thin_vec::thin_vec![]);
+ }
+
if obligation.predicate.has_aliases() {
let mut obligations = PredicateObligations::new();
let predicate = normalize_with_depth_to(
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index de33771..0987c5b 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -65,8 +65,8 @@
pub use self::structural_normalize::StructurallyNormalizeExt;
pub use self::util::{
BoundVarReplacer, PlaceholderReplacer, elaborate, expand_trait_aliases, impl_item_is_final,
- supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item, upcast_choices,
- with_replaced_escaping_bound_vars,
+ sizedness_fast_path, supertrait_def_ids, supertraits, transitive_bounds_that_define_assoc_item,
+ upcast_choices, with_replaced_escaping_bound_vars,
};
use crate::error_reporting::InferCtxtErrorExt;
use crate::infer::outlives::env::OutlivesEnvironment;
@@ -643,7 +643,7 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>(
) -> GenericArgsRef<'tcx> {
struct ReplaceParamAndInferWithPlaceholder<'tcx> {
tcx: TyCtxt<'tcx>,
- idx: u32,
+ idx: ty::BoundVar,
}
impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceParamAndInferWithPlaceholder<'tcx> {
@@ -653,19 +653,13 @@ fn cx(&self) -> TyCtxt<'tcx> {
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
if let ty::Infer(_) = t.kind() {
- let idx = {
- let idx = self.idx;
- self.idx += 1;
- idx
- };
+ let idx = self.idx;
+ self.idx += 1;
Ty::new_placeholder(
self.tcx,
ty::PlaceholderType {
universe: ty::UniverseIndex::ROOT,
- bound: ty::BoundTy {
- var: ty::BoundVar::from_u32(idx),
- kind: ty::BoundTyKind::Anon,
- },
+ bound: ty::BoundTy { var: idx, kind: ty::BoundTyKind::Anon },
},
)
} else {
@@ -675,16 +669,11 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
if let ty::ConstKind::Infer(_) = c.kind() {
+ let idx = self.idx;
+ self.idx += 1;
ty::Const::new_placeholder(
self.tcx,
- ty::PlaceholderConst {
- universe: ty::UniverseIndex::ROOT,
- bound: ty::BoundVar::from_u32({
- let idx = self.idx;
- self.idx += 1;
- idx
- }),
- },
+ ty::PlaceholderConst { universe: ty::UniverseIndex::ROOT, bound: idx },
)
} else {
c.super_fold_with(self)
@@ -692,7 +681,7 @@ fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
}
}
- args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: 0 })
+ args.fold_with(&mut ReplaceParamAndInferWithPlaceholder { tcx, idx: ty::BoundVar::ZERO })
}
/// Normalizes the predicates and checks whether they hold in an empty environment. If this
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index 4ac4517..7551ac5 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -77,7 +77,15 @@ fn deeply_normalize<T, E>(
.into_value_registering_obligations(self.infcx, &mut *fulfill_cx);
let errors = fulfill_cx.select_all_or_error(self.infcx);
let value = self.infcx.resolve_vars_if_possible(value);
- if errors.is_empty() { Ok(value) } else { Err(errors) }
+ if errors.is_empty() {
+ Ok(value)
+ } else {
+ // Drop pending obligations, since deep normalization may happen
+ // in a loop and we don't want to trigger the assertion on the next
+ // iteration due to pending ambiguous obligations we've left over.
+ let _ = fulfill_cx.collect_remaining_errors(self.infcx);
+ Err(errors)
+ }
}
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 8359121..99fa791 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -965,36 +965,38 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
let tcx = selcx.tcx();
- let lang_items = selcx.tcx().lang_items();
- if [
- lang_items.coroutine_trait(),
- lang_items.future_trait(),
- lang_items.iterator_trait(),
- lang_items.async_iterator_trait(),
- lang_items.fn_trait(),
- lang_items.fn_mut_trait(),
- lang_items.fn_once_trait(),
- lang_items.async_fn_trait(),
- lang_items.async_fn_mut_trait(),
- lang_items.async_fn_once_trait(),
- ]
- .contains(&Some(trait_ref.def_id))
- {
- true
- } else if tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncFnKindHelper) {
- // FIXME(async_closures): Validity constraints here could be cleaned up.
- if obligation.predicate.args.type_at(0).is_ty_var()
- || obligation.predicate.args.type_at(4).is_ty_var()
- || obligation.predicate.args.type_at(5).is_ty_var()
- {
- candidate_set.mark_ambiguous();
- true
- } else {
- obligation.predicate.args.type_at(0).to_opt_closure_kind().is_some()
- && obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some()
+ match selcx.tcx().as_lang_item(trait_ref.def_id) {
+ Some(
+ LangItem::Coroutine
+ | LangItem::Future
+ | LangItem::Iterator
+ | LangItem::AsyncIterator
+ | LangItem::Fn
+ | LangItem::FnMut
+ | LangItem::FnOnce
+ | LangItem::AsyncFn
+ | LangItem::AsyncFnMut
+ | LangItem::AsyncFnOnce,
+ ) => true,
+ Some(LangItem::AsyncFnKindHelper) => {
+ // FIXME(async_closures): Validity constraints here could be cleaned up.
+ if obligation.predicate.args.type_at(0).is_ty_var()
+ || obligation.predicate.args.type_at(4).is_ty_var()
+ || obligation.predicate.args.type_at(5).is_ty_var()
+ {
+ candidate_set.mark_ambiguous();
+ true
+ } else {
+ obligation.predicate.args.type_at(0).to_opt_closure_kind().is_some()
+ && obligation
+ .predicate
+ .args
+ .type_at(1)
+ .to_opt_closure_kind()
+ .is_some()
+ }
}
- } else if tcx.is_lang_item(trait_ref.def_id, LangItem::DiscriminantKind) {
- match self_ty.kind() {
+ Some(LangItem::DiscriminantKind) => match self_ty.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
@@ -1031,9 +1033,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Placeholder(..)
| ty::Infer(..)
| ty::Error(_) => false,
- }
- } else if tcx.is_lang_item(trait_ref.def_id, LangItem::AsyncDestruct) {
- match self_ty.kind() {
+ },
+ Some(LangItem::AsyncDestruct) => match self_ty.kind() {
ty::Bool
| ty::Char
| ty::Int(_)
@@ -1068,101 +1069,104 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
| ty::Placeholder(..)
| ty::Infer(_)
| ty::Error(_) => false,
- }
- } else if tcx.is_lang_item(trait_ref.def_id, LangItem::PointeeTrait) {
- let tail = selcx.tcx().struct_tail_raw(
- self_ty,
- |ty| {
- // We throw away any obligations we get from this, since we normalize
- // and confirm these obligations once again during confirmation
- normalize_with_depth(
- selcx,
- obligation.param_env,
- obligation.cause.clone(),
- obligation.recursion_depth + 1,
- ty,
- )
- .value
- },
- || {},
- );
+ },
+ Some(LangItem::PointeeTrait) => {
+ let tail = selcx.tcx().struct_tail_raw(
+ self_ty,
+ |ty| {
+ // We throw away any obligations we get from this, since we normalize
+ // and confirm these obligations once again during confirmation
+ normalize_with_depth(
+ selcx,
+ obligation.param_env,
+ obligation.cause.clone(),
+ obligation.recursion_depth + 1,
+ ty,
+ )
+ .value
+ },
+ || {},
+ );
- match tail.kind() {
- ty::Bool
- | ty::Char
- | ty::Int(_)
- | ty::Uint(_)
- | ty::Float(_)
- | ty::Str
- | ty::Array(..)
- | ty::Pat(..)
- | ty::Slice(_)
- | ty::RawPtr(..)
- | ty::Ref(..)
- | ty::FnDef(..)
- | ty::FnPtr(..)
- | ty::Dynamic(..)
- | ty::Closure(..)
- | ty::CoroutineClosure(..)
- | ty::Coroutine(..)
- | ty::CoroutineWitness(..)
- | ty::Never
- // Extern types have unit metadata, according to RFC 2850
- | ty::Foreign(_)
- // If returned by `struct_tail` this is a unit struct
- // without any fields, or not a struct, and therefore is Sized.
- | ty::Adt(..)
- // If returned by `struct_tail` this is the empty tuple.
- | ty::Tuple(..)
- // Integers and floats are always Sized, and so have unit type metadata.
- | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..))
- // This happens if we reach the recursion limit when finding the struct tail.
- | ty::Error(..) => true,
+ match tail.kind() {
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Str
+ | ty::Array(..)
+ | ty::Pat(..)
+ | ty::Slice(_)
+ | ty::RawPtr(..)
+ | ty::Ref(..)
+ | ty::FnDef(..)
+ | ty::FnPtr(..)
+ | ty::Dynamic(..)
+ | ty::Closure(..)
+ | ty::CoroutineClosure(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
+ | ty::Never
+ // Extern types have unit metadata, according to RFC 2850
+ | ty::Foreign(_)
+ // If returned by `struct_tail` this is a unit struct
+ // without any fields, or not a struct, and therefore is Sized.
+ | ty::Adt(..)
+ // If returned by `struct_tail` this is the empty tuple.
+ | ty::Tuple(..)
+ // Integers and floats are always Sized, and so have unit type metadata.
+ | ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(..))
+ // This happens if we reach the recursion limit when finding the struct tail.
+ | ty::Error(..) => true,
- // We normalize from `Wrapper<Tail>::Metadata` to `Tail::Metadata` if able.
- // Otherwise, type parameters, opaques, and unnormalized projections have
- // unit metadata if they're known (e.g. by the param_env) to be sized.
- ty::Param(_) | ty::Alias(..)
- if self_ty != tail
- || selcx.infcx.predicate_must_hold_modulo_regions(
- &obligation.with(
- selcx.tcx(),
- ty::TraitRef::new(
+ // We normalize from `Wrapper<Tail>::Metadata` to `Tail::Metadata` if able.
+ // Otherwise, type parameters, opaques, and unnormalized projections have
+ // unit metadata if they're known (e.g. by the param_env) to be sized.
+ ty::Param(_) | ty::Alias(..)
+ if self_ty != tail
+ || selcx.infcx.predicate_must_hold_modulo_regions(
+ &obligation.with(
selcx.tcx(),
- selcx.tcx().require_lang_item(
- LangItem::Sized,
- Some(obligation.cause.span),
+ ty::TraitRef::new(
+ selcx.tcx(),
+ selcx.tcx().require_lang_item(
+ LangItem::Sized,
+ Some(obligation.cause.span),
+ ),
+ [self_ty],
),
- [self_ty],
),
- ),
- ) =>
- {
- true
- }
-
- ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
-
- // FIXME(compiler-errors): are Bound and Placeholder types ever known sized?
- ty::Param(_)
- | ty::Alias(..)
- | ty::Bound(..)
- | ty::Placeholder(..)
- | ty::Infer(..) => {
- if tail.has_infer_types() {
- candidate_set.mark_ambiguous();
+ ) =>
+ {
+ true
}
- false
+
+ ty::UnsafeBinder(_) => todo!("FIXME(unsafe_binder)"),
+
+ // FIXME(compiler-errors): are Bound and Placeholder types ever known sized?
+ ty::Param(_)
+ | ty::Alias(..)
+ | ty::Bound(..)
+ | ty::Placeholder(..)
+ | ty::Infer(..) => {
+ if tail.has_infer_types() {
+ candidate_set.mark_ambiguous();
+ }
+ false
+ }
}
}
- } else if tcx.trait_is_auto(trait_ref.def_id) {
- tcx.dcx().span_delayed_bug(
- tcx.def_span(obligation.predicate.def_id),
- "associated types not allowed on auto traits",
- );
- false
- } else {
- bug!("unexpected builtin trait with associated type: {trait_ref:?}")
+ _ if tcx.trait_is_auto(trait_ref.def_id) => {
+ tcx.dcx().span_delayed_bug(
+ tcx.def_span(obligation.predicate.def_id),
+ "associated types not allowed on auto traits",
+ );
+ false
+ }
+ _ => {
+ bug!("unexpected builtin trait with associated type: {trait_ref:?}")
+ }
}
}
ImplSource::Param(..) => {
@@ -1393,7 +1397,7 @@ fn confirm_future_candidate<'cx, 'tcx>(
coroutine_sig,
);
- debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output);
+ debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Output);
let predicate = ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args(
@@ -1439,7 +1443,7 @@ fn confirm_iterator_candidate<'cx, 'tcx>(
gen_sig,
);
- debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item);
+ debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Item);
let predicate = ty::ProjectionPredicate {
projection_term: ty::AliasTerm::new_from_args(
@@ -1485,7 +1489,7 @@ fn confirm_async_iterator_candidate<'cx, 'tcx>(
gen_sig,
);
- debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item);
+ debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name(), sym::Item);
let ty::Adt(_poll_adt, args) = *yield_ty.kind() else {
bug!();
@@ -2005,7 +2009,8 @@ fn confirm_impl_candidate<'cx, 'tcx>(
if !assoc_ty.item.defaultness(tcx).has_value() {
debug!(
"confirm_impl_candidate: no associated type {:?} for {:?}",
- assoc_ty.item.name, obligation.predicate
+ assoc_ty.item.name(),
+ obligation.predicate
);
if tcx.impl_self_is_guaranteed_unsized(impl_def_id) {
// We treat this projection as rigid here, which is represented via
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
index 4f9e2e79..87fc532 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
@@ -1,4 +1,3 @@
-use rustc_hir::LangItem;
use rustc_infer::traits::Obligation;
use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::query::NoSolution;
@@ -7,7 +6,7 @@
use rustc_span::Span;
use crate::infer::canonical::{CanonicalQueryInput, CanonicalQueryResponse};
-use crate::traits::ObligationCtxt;
+use crate::traits::{ObligationCtxt, sizedness_fast_path};
impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
type QueryResponse = ();
@@ -16,15 +15,7 @@ fn try_fast_path(
tcx: TyCtxt<'tcx>,
key: &ParamEnvAnd<'tcx, Self>,
) -> Option<Self::QueryResponse> {
- // Proving Sized, very often on "obviously sized" types like
- // `&T`, accounts for about 60% percentage of the predicates
- // we have to prove. No need to canonicalize and all that for
- // such cases.
- if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) =
- key.value.predicate.kind().skip_binder()
- && tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized)
- && trait_ref.self_ty().is_trivially_sized(tcx)
- {
+ if sizedness_fast_path(tcx, key.value.predicate) {
return Some(());
}
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 69e7b2a..d71d1e9 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -594,9 +594,7 @@ fn confirm_object_candidate(
// Associated types that require `Self: Sized` do not show up in the built-in
// implementation of `Trait for dyn Trait`, and can be dropped here.
.filter(|item| !tcx.generics_require_sized_self(item.def_id))
- .filter_map(
- |item| if item.kind == ty::AssocKind::Type { Some(item.def_id) } else { None },
- )
+ .filter_map(|item| if item.is_type() { Some(item.def_id) } else { None })
.collect();
for assoc_type in assoc_types {
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 56ff46e..c7ce13c 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -49,7 +49,9 @@
use crate::solve::InferCtxtSelectExt as _;
use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
use crate::traits::project::{ProjectAndUnifyResult, ProjectionCacheKeyExt};
-use crate::traits::{EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects};
+use crate::traits::{
+ EvaluateConstErr, ProjectionCacheKey, Unimplemented, effects, sizedness_fast_path,
+};
mod _match;
mod candidate_assembly;
@@ -603,6 +605,10 @@ fn evaluate_predicate_recursively<'o>(
None => self.check_recursion_limit(&obligation, &obligation)?,
}
+ if sizedness_fast_path(self.tcx(), obligation.predicate) {
+ return Ok(EvaluatedToOk);
+ }
+
ensure_sufficient_stack(|| {
let bound_predicate = obligation.predicate.kind();
match bound_predicate.skip_binder() {
@@ -1492,7 +1498,9 @@ fn can_use_global_caches(
// However, if we disqualify *all* goals from being cached, perf suffers.
// This is likely fixed by better caching in general in the new solver.
// See: <https://github.com/rust-lang/rust/issues/132064>.
- TypingMode::Analysis { defining_opaque_types }
+ TypingMode::Analysis {
+ defining_opaque_types_and_generators: defining_opaque_types,
+ }
| TypingMode::Borrowck { defining_opaque_types } => {
defining_opaque_types.is_empty() || !pred.has_opaque_types()
}
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 9f20cd7..035fd38 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -1,6 +1,7 @@
use std::collections::{BTreeMap, VecDeque};
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
+use rustc_hir::LangItem;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::InferCtxt;
pub use rustc_infer::traits::util::*;
@@ -504,3 +505,21 @@ fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
}
}
}
+
+pub fn sizedness_fast_path<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tcx>) -> bool {
+ // Proving `Sized` very often on "obviously sized" types like `&T`, accounts for about 60%
+ // percentage of the predicates we have to prove. No need to canonicalize and all that for
+ // such cases.
+ if let ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_ref)) =
+ predicate.kind().skip_binder()
+ {
+ if tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized)
+ && trait_ref.self_ty().is_trivially_sized(tcx)
+ {
+ debug!("fast path -- trivial sizedness");
+ return true;
+ }
+ }
+
+ false
+}
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index 165174c..3565c11 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -197,10 +197,8 @@ fn own_existential_vtable_entries_iter(
tcx: TyCtxt<'_>,
trait_def_id: DefId,
) -> impl Iterator<Item = DefId> {
- let trait_methods = tcx
- .associated_items(trait_def_id)
- .in_definition_order()
- .filter(|item| item.kind == ty::AssocKind::Fn);
+ let trait_methods =
+ tcx.associated_items(trait_def_id).in_definition_order().filter(|item| item.is_fn());
// Now list each method's DefId (for within its trait).
let own_entries = trait_methods.filter_map(move |&trait_method| {
diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs
index 4a889ab..88f02d1 100644
--- a/compiler/rustc_traits/src/codegen.rs
+++ b/compiler/rustc_traits/src/codegen.rs
@@ -6,11 +6,11 @@
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::bug;
use rustc_middle::traits::CodegenObligationError;
-use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, PseudoCanonicalInput, TyCtxt, TypeVisitableExt, Upcast};
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
use rustc_trait_selection::traits::{
ImplSource, Obligation, ObligationCause, ObligationCtxt, ScrubbedTraitError, SelectionContext,
- Unimplemented,
+ Unimplemented, sizedness_fast_path,
};
use tracing::debug;
@@ -34,6 +34,13 @@ pub(crate) fn codegen_select_candidate<'tcx>(
let (infcx, param_env) = tcx.infer_ctxt().ignoring_regions().build_with_typing_env(typing_env);
let mut selcx = SelectionContext::new(&infcx);
+ if sizedness_fast_path(tcx, trait_ref.upcast(tcx)) {
+ return Ok(&*tcx.arena.alloc(ImplSource::Builtin(
+ ty::solve::BuiltinImplSource::Trivial,
+ Default::default(),
+ )));
+ }
+
let obligation_cause = ObligationCause::dummy();
let obligation = Obligation::new(tcx, obligation_cause, param_env, trait_ref);
diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs
index c9ad096..7771db8 100644
--- a/compiler/rustc_traits/src/evaluate_obligation.rs
+++ b/compiler/rustc_traits/src/evaluate_obligation.rs
@@ -5,6 +5,7 @@
use rustc_trait_selection::traits::query::CanonicalPredicateGoal;
use rustc_trait_selection::traits::{
EvaluationResult, Obligation, ObligationCause, OverflowError, SelectionContext, TraitQueryMode,
+ sizedness_fast_path,
};
use tracing::debug;
@@ -23,6 +24,10 @@ fn evaluate_obligation<'tcx>(
debug!("evaluate_obligation: goal={:#?}", goal);
let ParamEnvAnd { param_env, value: predicate } = goal;
+ if sizedness_fast_path(tcx, predicate) {
+ return Ok(EvaluationResult::EvaluatedToOk);
+ }
+
let mut selcx = SelectionContext::with_query_mode(infcx, TraitQueryMode::Canonical);
let obligation = Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate);
diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs
index af56817..bb909c5 100644
--- a/compiler/rustc_transmute/src/layout/dfa.rs
+++ b/compiler/rustc_transmute/src/layout/dfa.rs
@@ -1,19 +1,18 @@
use std::fmt;
use std::sync::atomic::{AtomicU32, Ordering};
-use tracing::instrument;
-
-use super::{Byte, Nfa, Ref, nfa};
+use super::{Byte, Ref, Tree, Uninhabited};
use crate::Map;
-#[derive(PartialEq, Clone, Debug)]
+#[derive(PartialEq)]
+#[cfg_attr(test, derive(Clone))]
pub(crate) struct Dfa<R>
where
R: Ref,
{
pub(crate) transitions: Map<State, Transitions<R>>,
pub(crate) start: State,
- pub(crate) accepting: State,
+ pub(crate) accept: State,
}
#[derive(PartialEq, Clone, Debug)]
@@ -34,35 +33,15 @@ fn default() -> Self {
}
}
-impl<R> Transitions<R>
-where
- R: Ref,
-{
- #[cfg(test)]
- fn insert(&mut self, transition: Transition<R>, state: State) {
- match transition {
- Transition::Byte(b) => {
- self.byte_transitions.insert(b, state);
- }
- Transition::Ref(r) => {
- self.ref_transitions.insert(r, state);
- }
- }
- }
-}
-
-/// The states in a `Nfa` represent byte offsets.
+/// The states in a [`Dfa`] represent byte offsets.
#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
-pub(crate) struct State(u32);
+pub(crate) struct State(pub(crate) u32);
-#[cfg(test)]
-#[derive(Hash, Eq, PartialEq, Clone, Copy)]
-pub(crate) enum Transition<R>
-where
- R: Ref,
-{
- Byte(Byte),
- Ref(R),
+impl State {
+ pub(crate) fn new() -> Self {
+ static COUNTER: AtomicU32 = AtomicU32::new(0);
+ Self(COUNTER.fetch_add(1, Ordering::SeqCst))
+ }
}
impl fmt::Debug for State {
@@ -71,19 +50,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
-#[cfg(test)]
-impl<R> fmt::Debug for Transition<R>
-where
- R: Ref,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match &self {
- Self::Byte(b) => b.fmt(f),
- Self::Ref(r) => r.fmt(f),
- }
- }
-}
-
impl<R> Dfa<R>
where
R: Ref,
@@ -92,60 +58,167 @@ impl<R> Dfa<R>
pub(crate) fn bool() -> Self {
let mut transitions: Map<State, Transitions<R>> = Map::default();
let start = State::new();
- let accepting = State::new();
+ let accept = State::new();
- transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x00)), accepting);
+ transitions.entry(start).or_default().byte_transitions.insert(Byte::Init(0x00), accept);
- transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x01)), accepting);
+ transitions.entry(start).or_default().byte_transitions.insert(Byte::Init(0x01), accept);
- Self { transitions, start, accepting }
+ Self { transitions, start, accept }
}
- #[instrument(level = "debug")]
- pub(crate) fn from_nfa(nfa: Nfa<R>) -> Self {
- let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa;
+ pub(crate) fn unit() -> Self {
+ let transitions: Map<State, Transitions<R>> = Map::default();
+ let start = State::new();
+ let accept = start;
- let mut dfa_transitions: Map<State, Transitions<R>> = Map::default();
- let mut nfa_to_dfa: Map<nfa::State, State> = Map::default();
- let dfa_start = State::new();
- nfa_to_dfa.insert(nfa_start, dfa_start);
+ Self { transitions, start, accept }
+ }
- let mut queue = vec![(nfa_start, dfa_start)];
+ pub(crate) fn from_byte(byte: Byte) -> Self {
+ let mut transitions: Map<State, Transitions<R>> = Map::default();
+ let start = State::new();
+ let accept = State::new();
- while let Some((nfa_state, dfa_state)) = queue.pop() {
- if nfa_state == nfa_accepting {
- continue;
+ transitions.entry(start).or_default().byte_transitions.insert(byte, accept);
+
+ Self { transitions, start, accept }
+ }
+
+ pub(crate) fn from_ref(r: R) -> Self {
+ let mut transitions: Map<State, Transitions<R>> = Map::default();
+ let start = State::new();
+ let accept = State::new();
+
+ transitions.entry(start).or_default().ref_transitions.insert(r, accept);
+
+ Self { transitions, start, accept }
+ }
+
+ pub(crate) fn from_tree(tree: Tree<!, R>) -> Result<Self, Uninhabited> {
+ Ok(match tree {
+ Tree::Byte(b) => Self::from_byte(b),
+ Tree::Ref(r) => Self::from_ref(r),
+ Tree::Alt(alts) => {
+ // Convert and filter the inhabited alternatives.
+ let mut alts = alts.into_iter().map(Self::from_tree).filter_map(Result::ok);
+ // If there are no alternatives, return `Uninhabited`.
+ let dfa = alts.next().ok_or(Uninhabited)?;
+ // Combine the remaining alternatives with `dfa`.
+ alts.fold(dfa, |dfa, alt| dfa.union(alt, State::new))
+ }
+ Tree::Seq(elts) => {
+ let mut dfa = Self::unit();
+ for elt in elts.into_iter().map(Self::from_tree) {
+ dfa = dfa.concat(elt?);
+ }
+ dfa
+ }
+ })
+ }
+
+ /// Concatenate two `Dfa`s.
+ pub(crate) fn concat(self, other: Self) -> Self {
+ if self.start == self.accept {
+ return other;
+ } else if other.start == other.accept {
+ return self;
+ }
+
+ let start = self.start;
+ let accept = other.accept;
+
+ let mut transitions: Map<State, Transitions<R>> = self.transitions;
+
+ for (source, transition) in other.transitions {
+ let fix_state = |state| if state == other.start { self.accept } else { state };
+ let entry = transitions.entry(fix_state(source)).or_default();
+ for (edge, destination) in transition.byte_transitions {
+ entry.byte_transitions.insert(edge, fix_state(destination));
+ }
+ for (edge, destination) in transition.ref_transitions {
+ entry.ref_transitions.insert(edge, fix_state(destination));
+ }
+ }
+
+ Self { transitions, start, accept }
+ }
+
+ /// Compute the union of two `Dfa`s.
+ pub(crate) fn union(self, other: Self, mut new_state: impl FnMut() -> State) -> Self {
+ // We implement `union` by lazily initializing a set of states
+ // corresponding to the product of states in `self` and `other`, and
+ // then add transitions between these states that correspond to where
+ // they exist between `self` and `other`.
+
+ let a = self;
+ let b = other;
+
+ let accept = new_state();
+
+ let mut mapping: Map<(Option<State>, Option<State>), State> = Map::default();
+
+ let mut mapped = |(a_state, b_state)| {
+ if Some(a.accept) == a_state || Some(b.accept) == b_state {
+ // If either `a_state` or `b_state` are accepting, map to a
+ // common `accept` state.
+ accept
+ } else {
+ *mapping.entry((a_state, b_state)).or_insert_with(&mut new_state)
+ }
+ };
+
+ let start = mapped((Some(a.start), Some(b.start)));
+ let mut transitions: Map<State, Transitions<R>> = Map::default();
+ let mut queue = vec![(Some(a.start), Some(b.start))];
+ let empty_transitions = Transitions::default();
+
+ while let Some((a_src, b_src)) = queue.pop() {
+ let a_transitions =
+ a_src.and_then(|a_src| a.transitions.get(&a_src)).unwrap_or(&empty_transitions);
+ let b_transitions =
+ b_src.and_then(|b_src| b.transitions.get(&b_src)).unwrap_or(&empty_transitions);
+
+ let byte_transitions =
+ a_transitions.byte_transitions.keys().chain(b_transitions.byte_transitions.keys());
+
+ for byte_transition in byte_transitions {
+ let a_dst = a_transitions.byte_transitions.get(byte_transition).copied();
+ let b_dst = b_transitions.byte_transitions.get(byte_transition).copied();
+
+ assert!(a_dst.is_some() || b_dst.is_some());
+
+ let src = mapped((a_src, b_src));
+ let dst = mapped((a_dst, b_dst));
+
+ transitions.entry(src).or_default().byte_transitions.insert(*byte_transition, dst);
+
+ if !transitions.contains_key(&dst) {
+ queue.push((a_dst, b_dst))
+ }
}
- for (nfa_transition, next_nfa_states) in nfa_transitions[&nfa_state].iter() {
- let dfa_transitions =
- dfa_transitions.entry(dfa_state).or_insert_with(Default::default);
+ let ref_transitions =
+ a_transitions.ref_transitions.keys().chain(b_transitions.ref_transitions.keys());
- let mapped_state = next_nfa_states.iter().find_map(|x| nfa_to_dfa.get(x).copied());
+ for ref_transition in ref_transitions {
+ let a_dst = a_transitions.ref_transitions.get(ref_transition).copied();
+ let b_dst = b_transitions.ref_transitions.get(ref_transition).copied();
- let next_dfa_state = match nfa_transition {
- &nfa::Transition::Byte(b) => *dfa_transitions
- .byte_transitions
- .entry(b)
- .or_insert_with(|| mapped_state.unwrap_or_else(State::new)),
- &nfa::Transition::Ref(r) => *dfa_transitions
- .ref_transitions
- .entry(r)
- .or_insert_with(|| mapped_state.unwrap_or_else(State::new)),
- };
+ assert!(a_dst.is_some() || b_dst.is_some());
- for &next_nfa_state in next_nfa_states {
- nfa_to_dfa.entry(next_nfa_state).or_insert_with(|| {
- queue.push((next_nfa_state, next_dfa_state));
- next_dfa_state
- });
+ let src = mapped((a_src, b_src));
+ let dst = mapped((a_dst, b_dst));
+
+ transitions.entry(src).or_default().ref_transitions.insert(*ref_transition, dst);
+
+ if !transitions.contains_key(&dst) {
+ queue.push((a_dst, b_dst))
}
}
}
- let dfa_accepting = nfa_to_dfa[&nfa_accepting];
-
- Self { transitions: dfa_transitions, start: dfa_start, accepting: dfa_accepting }
+ Self { transitions, start, accept }
}
pub(crate) fn bytes_from(&self, start: State) -> Option<&Map<Byte, State>> {
@@ -159,24 +232,48 @@ pub(crate) fn byte_from(&self, start: State, byte: Byte) -> Option<State> {
pub(crate) fn refs_from(&self, start: State) -> Option<&Map<R, State>> {
Some(&self.transitions.get(&start)?.ref_transitions)
}
-}
-impl State {
- pub(crate) fn new() -> Self {
- static COUNTER: AtomicU32 = AtomicU32::new(0);
- Self(COUNTER.fetch_add(1, Ordering::SeqCst))
+ #[cfg(test)]
+ pub(crate) fn from_edges<B: Copy + Into<Byte>>(
+ start: u32,
+ accept: u32,
+ edges: &[(u32, B, u32)],
+ ) -> Self {
+ let start = State(start);
+ let accept = State(accept);
+ let mut transitions: Map<State, Transitions<R>> = Map::default();
+
+ for &(src, edge, dst) in edges {
+ let src = State(src);
+ let dst = State(dst);
+ let old = transitions.entry(src).or_default().byte_transitions.insert(edge.into(), dst);
+ assert!(old.is_none());
+ }
+
+ Self { start, accept, transitions }
}
}
-#[cfg(test)]
-impl<R> From<nfa::Transition<R>> for Transition<R>
+/// Serialize the DFA using the Graphviz DOT format.
+impl<R> fmt::Debug for Dfa<R>
where
R: Ref,
{
- fn from(nfa_transition: nfa::Transition<R>) -> Self {
- match nfa_transition {
- nfa::Transition::Byte(byte) => Transition::Byte(byte),
- nfa::Transition::Ref(r) => Transition::Ref(r),
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ writeln!(f, "digraph {{")?;
+ writeln!(f, " {:?} [shape = doublecircle]", self.start)?;
+ writeln!(f, " {:?} [shape = doublecircle]", self.accept)?;
+
+ for (src, transitions) in self.transitions.iter() {
+ for (t, dst) in transitions.byte_transitions.iter() {
+ writeln!(f, " {src:?} -> {dst:?} [label=\"{t:?}\"]")?;
+ }
+
+ for (t, dst) in transitions.ref_transitions.iter() {
+ writeln!(f, " {src:?} -> {dst:?} [label=\"{t:?}\"]")?;
+ }
}
+
+ writeln!(f, "}}")
}
}
diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs
index c4c01a8..c940f7c 100644
--- a/compiler/rustc_transmute/src/layout/mod.rs
+++ b/compiler/rustc_transmute/src/layout/mod.rs
@@ -4,9 +4,6 @@
pub(crate) mod tree;
pub(crate) use tree::Tree;
-pub(crate) mod nfa;
-pub(crate) use nfa::Nfa;
-
pub(crate) mod dfa;
pub(crate) use dfa::Dfa;
@@ -29,6 +26,13 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
+#[cfg(test)]
+impl From<u8> for Byte {
+ fn from(src: u8) -> Self {
+ Self::Init(src)
+ }
+}
+
pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone {
fn has_safety_invariants(&self) -> bool;
}
diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs
deleted file mode 100644
index 9c21fd9..0000000
--- a/compiler/rustc_transmute/src/layout/nfa.rs
+++ /dev/null
@@ -1,169 +0,0 @@
-use std::fmt;
-use std::sync::atomic::{AtomicU32, Ordering};
-
-use super::{Byte, Ref, Tree, Uninhabited};
-use crate::{Map, Set};
-
-/// A non-deterministic finite automaton (NFA) that represents the layout of a type.
-/// The transmutability of two given types is computed by comparing their `Nfa`s.
-#[derive(PartialEq, Debug)]
-pub(crate) struct Nfa<R>
-where
- R: Ref,
-{
- pub(crate) transitions: Map<State, Map<Transition<R>, Set<State>>>,
- pub(crate) start: State,
- pub(crate) accepting: State,
-}
-
-/// The states in a `Nfa` represent byte offsets.
-#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
-pub(crate) struct State(u32);
-
-/// The transitions between states in a `Nfa` reflect bit validity.
-#[derive(Hash, Eq, PartialEq, Clone, Copy)]
-pub(crate) enum Transition<R>
-where
- R: Ref,
-{
- Byte(Byte),
- Ref(R),
-}
-
-impl fmt::Debug for State {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "S_{}", self.0)
- }
-}
-
-impl<R> fmt::Debug for Transition<R>
-where
- R: Ref,
-{
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match &self {
- Self::Byte(b) => b.fmt(f),
- Self::Ref(r) => r.fmt(f),
- }
- }
-}
-
-impl<R> Nfa<R>
-where
- R: Ref,
-{
- pub(crate) fn unit() -> Self {
- let transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
- let start = State::new();
- let accepting = start;
-
- Nfa { transitions, start, accepting }
- }
-
- pub(crate) fn from_byte(byte: Byte) -> Self {
- let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
- let start = State::new();
- let accepting = State::new();
-
- let source = transitions.entry(start).or_default();
- let edge = source.entry(Transition::Byte(byte)).or_default();
- edge.insert(accepting);
-
- Nfa { transitions, start, accepting }
- }
-
- pub(crate) fn from_ref(r: R) -> Self {
- let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
- let start = State::new();
- let accepting = State::new();
-
- let source = transitions.entry(start).or_default();
- let edge = source.entry(Transition::Ref(r)).or_default();
- edge.insert(accepting);
-
- Nfa { transitions, start, accepting }
- }
-
- pub(crate) fn from_tree(tree: Tree<!, R>) -> Result<Self, Uninhabited> {
- Ok(match tree {
- Tree::Byte(b) => Self::from_byte(b),
- Tree::Ref(r) => Self::from_ref(r),
- Tree::Alt(alts) => {
- let mut alts = alts.into_iter().map(Self::from_tree);
- let mut nfa = alts.next().ok_or(Uninhabited)??;
- for alt in alts {
- nfa = nfa.union(alt?);
- }
- nfa
- }
- Tree::Seq(elts) => {
- let mut nfa = Self::unit();
- for elt in elts.into_iter().map(Self::from_tree) {
- nfa = nfa.concat(elt?);
- }
- nfa
- }
- })
- }
-
- /// Concatenate two `Nfa`s.
- pub(crate) fn concat(self, other: Self) -> Self {
- if self.start == self.accepting {
- return other;
- } else if other.start == other.accepting {
- return self;
- }
-
- let start = self.start;
- let accepting = other.accepting;
-
- let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions;
-
- for (source, transition) in other.transitions {
- let fix_state = |state| if state == other.start { self.accepting } else { state };
- let entry = transitions.entry(fix_state(source)).or_default();
- for (edge, destinations) in transition {
- let entry = entry.entry(edge).or_default();
- for destination in destinations {
- entry.insert(fix_state(destination));
- }
- }
- }
-
- Self { transitions, start, accepting }
- }
-
- /// Compute the union of two `Nfa`s.
- pub(crate) fn union(self, other: Self) -> Self {
- let start = self.start;
- let accepting = self.accepting;
-
- let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions.clone();
-
- for (&(mut source), transition) in other.transitions.iter() {
- // if source is starting state of `other`, replace with starting state of `self`
- if source == other.start {
- source = self.start;
- }
- let entry = transitions.entry(source).or_default();
- for (edge, destinations) in transition {
- let entry = entry.entry(*edge).or_default();
- for &(mut destination) in destinations {
- // if dest is accepting state of `other`, replace with accepting state of `self`
- if destination == other.accepting {
- destination = self.accepting;
- }
- entry.insert(destination);
- }
- }
- }
- Self { transitions, start, accepting }
- }
-}
-
-impl State {
- pub(crate) fn new() -> Self {
- static COUNTER: AtomicU32 = AtomicU32::new(0);
- Self(COUNTER.fetch_add(1, Ordering::SeqCst))
- }
-}
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index a21be5d..70ecc75 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -514,7 +514,7 @@ fn ty_field<'tcx>(
}
}
ty::Tuple(fields) => fields[i.as_usize()],
- kind @ _ => unimplemented!(
+ kind => unimplemented!(
"only a subset of `Ty::ty_and_layout_field`'s functionality is implemented. implementation needed for {:?}",
kind
),
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index 7d800e4..76fa6ce 100644
--- a/compiler/rustc_transmute/src/lib.rs
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -1,9 +1,8 @@
// tidy-alphabetical-start
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![feature(never_type)]
// tidy-alphabetical-end
-pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set};
+pub(crate) use rustc_data_structures::fx::FxIndexMap as Map;
pub mod layout;
mod maybe_transmutable;
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
index 63fabc9..db0e1ab 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs
@@ -4,7 +4,7 @@
#[cfg(test)]
mod tests;
-use crate::layout::{self, Byte, Def, Dfa, Nfa, Ref, Tree, Uninhabited, dfa};
+use crate::layout::{self, Byte, Def, Dfa, Ref, Tree, Uninhabited, dfa};
use crate::maybe_transmutable::query_context::QueryContext;
use crate::{Answer, Condition, Map, Reason};
@@ -73,7 +73,7 @@ impl<C> MaybeTransmutableQuery<Tree<<C as QueryContext>::Def, <C as QueryContext
/// Answers whether a `Tree` is transmutable into another `Tree`.
///
/// This method begins by de-def'ing `src` and `dst`, and prunes private paths from `dst`,
- /// then converts `src` and `dst` to `Nfa`s, and computes an answer using those NFAs.
+ /// then converts `src` and `dst` to `Dfa`s, and computes an answer using those DFAs.
#[inline(always)]
#[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
@@ -105,22 +105,22 @@ pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
trace!(?dst, "pruned dst");
- // Convert `src` from a tree-based representation to an NFA-based
+ // Convert `src` from a tree-based representation to an DFA-based
// representation. If the conversion fails because `src` is uninhabited,
// conclude that the transmutation is acceptable, because instances of
// the `src` type do not exist.
- let src = match Nfa::from_tree(src) {
+ let src = match Dfa::from_tree(src) {
Ok(src) => src,
Err(Uninhabited) => return Answer::Yes,
};
- // Convert `dst` from a tree-based representation to an NFA-based
+ // Convert `dst` from a tree-based representation to an DFA-based
// representation. If the conversion fails because `src` is uninhabited,
// conclude that the transmutation is unacceptable. Valid instances of
// the `dst` type do not exist, either because it's genuinely
// uninhabited, or because there are no branches of the tree that are
// free of safety invariants.
- let dst = match Nfa::from_tree(dst) {
+ let dst = match Dfa::from_tree(dst) {
Ok(dst) => dst,
Err(Uninhabited) => return Answer::No(Reason::DstMayHaveSafetyInvariants),
};
@@ -129,23 +129,6 @@ pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
}
}
-impl<C> MaybeTransmutableQuery<Nfa<<C as QueryContext>::Ref>, C>
-where
- C: QueryContext,
-{
- /// Answers whether a `Nfa` is transmutable into another `Nfa`.
- ///
- /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs.
- #[inline(always)]
- #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
- pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
- let Self { src, dst, assume, context } = self;
- let src = Dfa::from_nfa(src);
- let dst = Dfa::from_nfa(dst);
- MaybeTransmutableQuery { src, dst, assume, context }.answer()
- }
-}
-
impl<C> MaybeTransmutableQuery<Dfa<<C as QueryContext>::Ref>, C>
where
C: QueryContext,
@@ -173,7 +156,7 @@ fn answer_memo(
src_transitions_len = self.src.transitions.len(),
dst_transitions_len = self.dst.transitions.len()
);
- let answer = if dst_state == self.dst.accepting {
+ let answer = if dst_state == self.dst.accept {
// truncation: `size_of(Src) >= size_of(Dst)`
//
// Why is truncation OK to do? Because even though the Src is bigger, all we care about
@@ -190,7 +173,7 @@ fn answer_memo(
// that none of the actually-used data can introduce an invalid state for Dst's type, we
// are able to safely transmute, even with truncation.
Answer::Yes
- } else if src_state == self.src.accepting {
+ } else if src_state == self.src.accept {
// extension: `size_of(Src) >= size_of(Dst)`
if let Some(dst_state_prime) = self.dst.byte_from(dst_state, Byte::Uninit) {
self.answer_memo(cache, src_state, dst_state_prime)
diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
index 4d81382..cc6a4dc 100644
--- a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
+++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs
@@ -1,93 +1,115 @@
use itertools::Itertools;
use super::query_context::test::{Def, UltraMinimal};
-use crate::maybe_transmutable::MaybeTransmutableQuery;
-use crate::{Reason, layout};
+use crate::{Answer, Assume, Reason, layout};
+
+type Tree = layout::Tree<Def, !>;
+type Dfa = layout::Dfa<!>;
+
+trait Representation {
+ fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!>;
+}
+
+impl Representation for Tree {
+ fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!> {
+ crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, UltraMinimal)
+ .answer()
+ }
+}
+
+impl Representation for Dfa {
+ fn is_transmutable(src: Self, dst: Self, assume: Assume) -> Answer<!> {
+ crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, UltraMinimal)
+ .answer()
+ }
+}
+
+fn is_transmutable<R: Representation + Clone>(
+ src: &R,
+ dst: &R,
+ assume: Assume,
+) -> crate::Answer<!> {
+ let src = src.clone();
+ let dst = dst.clone();
+ // The only dimension of the transmutability analysis we want to test
+ // here is the safety analysis. To ensure this, we disable all other
+ // toggleable aspects of the transmutability analysis.
+ R::is_transmutable(src, dst, assume)
+}
mod safety {
use super::*;
use crate::Answer;
- type Tree = layout::Tree<Def, !>;
-
const DST_HAS_SAFETY_INVARIANTS: Answer<!> =
Answer::No(crate::Reason::DstMayHaveSafetyInvariants);
- fn is_transmutable(src: &Tree, dst: &Tree, assume_safety: bool) -> crate::Answer<!> {
- let src = src.clone();
- let dst = dst.clone();
- // The only dimension of the transmutability analysis we want to test
- // here is the safety analysis. To ensure this, we disable all other
- // toggleable aspects of the transmutability analysis.
- let assume = crate::Assume {
- alignment: true,
- lifetimes: true,
- validity: true,
- safety: assume_safety,
- };
- crate::maybe_transmutable::MaybeTransmutableQuery::new(src, dst, assume, UltraMinimal)
- .answer()
- }
-
#[test]
fn src_safe_dst_safe() {
let src = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8());
let dst = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8());
- assert_eq!(is_transmutable(&src, &dst, false), Answer::Yes);
- assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes);
+ assert_eq!(is_transmutable(&src, &dst, Assume::default()), Answer::Yes);
+ assert_eq!(
+ is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }),
+ Answer::Yes
+ );
}
#[test]
fn src_safe_dst_unsafe() {
let src = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8());
let dst = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8());
- assert_eq!(is_transmutable(&src, &dst, false), DST_HAS_SAFETY_INVARIANTS);
- assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes);
+ assert_eq!(is_transmutable(&src, &dst, Assume::default()), DST_HAS_SAFETY_INVARIANTS);
+ assert_eq!(
+ is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }),
+ Answer::Yes
+ );
}
#[test]
fn src_unsafe_dst_safe() {
let src = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8());
let dst = Tree::Def(Def::NoSafetyInvariants).then(Tree::u8());
- assert_eq!(is_transmutable(&src, &dst, false), Answer::Yes);
- assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes);
+ assert_eq!(is_transmutable(&src, &dst, Assume::default()), Answer::Yes);
+ assert_eq!(
+ is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }),
+ Answer::Yes
+ );
}
#[test]
fn src_unsafe_dst_unsafe() {
let src = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8());
let dst = Tree::Def(Def::HasSafetyInvariants).then(Tree::u8());
- assert_eq!(is_transmutable(&src, &dst, false), DST_HAS_SAFETY_INVARIANTS);
- assert_eq!(is_transmutable(&src, &dst, true), Answer::Yes);
+ assert_eq!(is_transmutable(&src, &dst, Assume::default()), DST_HAS_SAFETY_INVARIANTS);
+ assert_eq!(
+ is_transmutable(&src, &dst, Assume { safety: true, ..Assume::default() }),
+ Answer::Yes
+ );
}
}
mod bool {
use super::*;
- use crate::Answer;
#[test]
fn should_permit_identity_transmutation_tree() {
- let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new(
- layout::Tree::<Def, !>::bool(),
- layout::Tree::<Def, !>::bool(),
- crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false },
- UltraMinimal,
- )
- .answer();
- assert_eq!(answer, Answer::Yes);
+ let src = Tree::bool();
+ assert_eq!(is_transmutable(&src, &src, Assume::default()), Answer::Yes);
+ assert_eq!(
+ is_transmutable(&src, &src, Assume { validity: true, ..Assume::default() }),
+ Answer::Yes
+ );
}
#[test]
fn should_permit_identity_transmutation_dfa() {
- let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new(
- layout::Dfa::<!>::bool(),
- layout::Dfa::<!>::bool(),
- crate::Assume { alignment: false, lifetimes: false, validity: true, safety: false },
- UltraMinimal,
- )
- .answer();
- assert_eq!(answer, Answer::Yes);
+ let src = Dfa::bool();
+ assert_eq!(is_transmutable(&src, &src, Assume::default()), Answer::Yes);
+ assert_eq!(
+ is_transmutable(&src, &src, Assume { validity: true, ..Assume::default() }),
+ Answer::Yes
+ );
}
#[test]
@@ -104,7 +126,7 @@ fn should_permit_validity_expansion_and_reject_contraction() {
let into_set = |alts: Vec<_>| {
#[cfg(feature = "rustc")]
- let mut set = crate::Set::default();
+ let mut set = rustc_data_structures::fx::FxIndexSet::default();
#[cfg(not(feature = "rustc"))]
let mut set = std::collections::HashSet::new();
set.extend(alts);
@@ -122,13 +144,7 @@ fn should_permit_validity_expansion_and_reject_contraction() {
if src_set.is_subset(&dst_set) {
assert_eq!(
Answer::Yes,
- MaybeTransmutableQuery::new(
- src_layout.clone(),
- dst_layout.clone(),
- crate::Assume { validity: false, ..crate::Assume::default() },
- UltraMinimal,
- )
- .answer(),
+ is_transmutable(&src_layout, &dst_layout, Assume::default()),
"{:?} SHOULD be transmutable into {:?}",
src_layout,
dst_layout
@@ -136,13 +152,11 @@ fn should_permit_validity_expansion_and_reject_contraction() {
} else if !src_set.is_disjoint(&dst_set) {
assert_eq!(
Answer::Yes,
- MaybeTransmutableQuery::new(
- src_layout.clone(),
- dst_layout.clone(),
- crate::Assume { validity: true, ..crate::Assume::default() },
- UltraMinimal,
- )
- .answer(),
+ is_transmutable(
+ &src_layout,
+ &dst_layout,
+ Assume { validity: true, ..Assume::default() }
+ ),
"{:?} SHOULD be transmutable (assuming validity) into {:?}",
src_layout,
dst_layout
@@ -150,13 +164,7 @@ fn should_permit_validity_expansion_and_reject_contraction() {
} else {
assert_eq!(
Answer::No(Reason::DstIsBitIncompatible),
- MaybeTransmutableQuery::new(
- src_layout.clone(),
- dst_layout.clone(),
- crate::Assume { validity: false, ..crate::Assume::default() },
- UltraMinimal,
- )
- .answer(),
+ is_transmutable(&src_layout, &dst_layout, Assume::default()),
"{:?} should NOT be transmutable into {:?}",
src_layout,
dst_layout
@@ -166,3 +174,32 @@ fn should_permit_validity_expansion_and_reject_contraction() {
}
}
}
+
+mod union {
+ use super::*;
+
+ #[test]
+ fn union() {
+ let [a, b, c, d] = [0, 1, 2, 3];
+ let s = Dfa::from_edges(a, d, &[(a, 0, b), (b, 0, d), (a, 1, c), (c, 1, d)]);
+
+ let t = Dfa::from_edges(a, c, &[(a, 1, b), (b, 0, c)]);
+
+ let mut ctr = 0;
+ let new_state = || {
+ let state = crate::layout::dfa::State(ctr);
+ ctr += 1;
+ state
+ };
+
+ let u = s.clone().union(t.clone(), new_state);
+
+ let expected_u =
+ Dfa::from_edges(b, a, &[(b, 0, c), (b, 1, d), (d, 1, a), (d, 0, a), (c, 0, a)]);
+
+ assert_eq!(u, expected_u);
+
+ assert_eq!(is_transmutable(&s, &u, Assume::default()), Answer::Yes);
+ assert_eq!(is_transmutable(&t, &u, Assume::default()), Answer::Yes);
+ }
+}
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index 9520d94..6cb9fdc 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -6,7 +6,6 @@
use rustc_middle::query::Providers;
use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
use rustc_middle::{bug, span_bug};
-use rustc_span::kw;
pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers {
@@ -129,39 +128,35 @@ fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem {
fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
let owner_id = trait_item_ref.id.owner_id;
- let (kind, has_self) = match trait_item_ref.kind {
- hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
- hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
- hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
+ let name = trait_item_ref.ident.name;
+ let kind = match trait_item_ref.kind {
+ hir::AssocItemKind::Const => ty::AssocKind::Const { name },
+ hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self },
+ hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) },
};
ty::AssocItem {
- name: trait_item_ref.ident.name,
kind,
def_id: owner_id.to_def_id(),
trait_item_def_id: Some(owner_id.to_def_id()),
container: ty::AssocItemContainer::Trait,
- fn_has_self_parameter: has_self,
- opt_rpitit_info: None,
}
}
fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
let def_id = impl_item_ref.id.owner_id;
- let (kind, has_self) = match impl_item_ref.kind {
- hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
- hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
- hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
+ let name = impl_item_ref.ident.name;
+ let kind = match impl_item_ref.kind {
+ hir::AssocItemKind::Const => ty::AssocKind::Const { name },
+ hir::AssocItemKind::Fn { has_self } => ty::AssocKind::Fn { name, has_self },
+ hir::AssocItemKind::Type => ty::AssocKind::Type { data: ty::AssocTypeData::Normal(name) },
};
ty::AssocItem {
- name: impl_item_ref.ident.name,
kind,
def_id: def_id.to_def_id(),
trait_item_def_id: impl_item_ref.trait_item_def_id,
container: ty::AssocItemContainer::Impl,
- fn_has_self_parameter: has_self,
- opt_rpitit_info: None,
}
}
@@ -264,16 +259,15 @@ fn associated_type_for_impl_trait_in_trait(
trait_assoc_ty.def_ident_span(Some(span));
trait_assoc_ty.associated_item(ty::AssocItem {
- name: kw::Empty,
- kind: ty::AssocKind::Type,
+ kind: ty::AssocKind::Type {
+ data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Trait {
+ fn_def_id: fn_def_id.to_def_id(),
+ opaque_def_id: opaque_ty_def_id.to_def_id(),
+ }),
+ },
def_id,
trait_item_def_id: None,
container: ty::AssocItemContainer::Trait,
- fn_has_self_parameter: false,
- opt_rpitit_info: Some(ImplTraitInTraitData::Trait {
- fn_def_id: fn_def_id.to_def_id(),
- opaque_def_id: opaque_ty_def_id.to_def_id(),
- }),
});
// Copy visility of the containing function.
@@ -317,13 +311,14 @@ fn associated_type_for_impl_trait_in_impl(
impl_assoc_ty.def_ident_span(Some(span));
impl_assoc_ty.associated_item(ty::AssocItem {
- name: kw::Empty,
- kind: ty::AssocKind::Type,
+ kind: ty::AssocKind::Type {
+ data: ty::AssocTypeData::Rpitit(ImplTraitInTraitData::Impl {
+ fn_def_id: impl_fn_def_id.to_def_id(),
+ }),
+ },
def_id,
trait_item_def_id: Some(trait_assoc_def_id),
container: ty::AssocItemContainer::Impl,
- fn_has_self_parameter: false,
- opt_rpitit_info: Some(ImplTraitInTraitData::Impl { fn_def_id: impl_fn_def_id.to_def_id() }),
});
// Copy visility of the containing function.
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 0017186..1915ba6 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -514,6 +514,9 @@ fn layout_of_uncached<'tcx>(
return map_layout(cx.calc.layout_of_union(&def.repr(), &variants));
}
+ // UnsafeCell and UnsafePinned both disable niche optimizations
+ let is_special_no_niche = def.is_unsafe_cell() || def.is_unsafe_pinned();
+
let get_discriminant_type =
|min, max| abi::Integer::repr_discr(tcx, ty, &def.repr(), min, max);
@@ -542,7 +545,7 @@ fn layout_of_uncached<'tcx>(
&def.repr(),
&variants,
def.is_enum(),
- def.is_unsafe_cell(),
+ is_special_no_niche,
tcx.layout_scalar_valid_range(def.did()),
get_discriminant_type,
discriminants_iter(),
@@ -568,7 +571,7 @@ fn layout_of_uncached<'tcx>(
&def.repr(),
&variants,
def.is_enum(),
- def.is_unsafe_cell(),
+ is_special_no_niche,
tcx.layout_scalar_valid_range(def.did()),
get_discriminant_type,
discriminants_iter(),
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 143b7d5..57051e0 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -6,7 +6,6 @@
// tidy-alphabetical-start
#![allow(internal_features)]
-#![cfg_attr(doc, recursion_limit = "256")] // FIXME(nnethercote): will be removed by #124141
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![doc(rust_logo)]
#![feature(assert_matches)]
@@ -33,6 +32,7 @@
mod opaque_types;
mod representability;
pub mod sig_types;
+mod stalled_generators;
mod structural_match;
mod ty;
@@ -51,4 +51,5 @@ pub fn provide(providers: &mut Providers) {
ty::provide(providers);
instance::provide(providers);
structural_match::provide(providers);
+ stalled_generators::provide(providers);
}
diff --git a/compiler/rustc_ty_utils/src/stalled_generators.rs b/compiler/rustc_ty_utils/src/stalled_generators.rs
new file mode 100644
index 0000000..8b45e8b
--- /dev/null
+++ b/compiler/rustc_ty_utils/src/stalled_generators.rs
@@ -0,0 +1,54 @@
+use rustc_hir as hir;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::intravisit;
+use rustc_hir::intravisit::Visitor;
+use rustc_middle::query::Providers;
+use rustc_middle::ty::{self, TyCtxt};
+
+fn stalled_generators_within<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ item: LocalDefId,
+) -> &'tcx ty::List<LocalDefId> {
+ if !tcx.next_trait_solver_globally() {
+ return ty::List::empty();
+ }
+
+ let body = tcx.hir_body_owned_by(item);
+ let mut collector =
+ StalledGeneratorVisitor { tcx, root_def_id: item.to_def_id(), stalled_coroutines: vec![] };
+ collector.visit_body(body);
+ tcx.mk_local_def_ids(&collector.stalled_coroutines)
+}
+
+struct StalledGeneratorVisitor<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ root_def_id: DefId,
+ stalled_coroutines: Vec<LocalDefId>,
+}
+
+impl<'tcx> Visitor<'tcx> for StalledGeneratorVisitor<'tcx> {
+ fn visit_nested_body(&mut self, id: hir::BodyId) {
+ if self.tcx.typeck_root_def_id(self.tcx.hir_body_owner_def_id(id).to_def_id())
+ == self.root_def_id
+ {
+ let body = self.tcx.hir_body(id);
+ self.visit_body(body);
+ }
+ }
+
+ fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) {
+ if let hir::ExprKind::Closure(&hir::Closure {
+ def_id,
+ kind: hir::ClosureKind::Coroutine(_),
+ ..
+ }) = ex.kind
+ {
+ self.stalled_coroutines.push(def_id);
+ }
+ intravisit::walk_expr(self, ex);
+ }
+}
+
+pub(super) fn provide(providers: &mut Providers) {
+ *providers = Providers { stalled_generators_within, ..*providers };
+}
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index e905594..27ea4e2 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -122,6 +122,10 @@ impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Binder<I, T> {
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
folder.try_fold_binder(self)
}
+
+ fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
+ folder.fold_binder(self)
+ }
}
impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Binder<I, T> {
@@ -135,7 +139,11 @@ fn try_super_fold_with<F: FallibleTypeFolder<I>>(
self,
folder: &mut F,
) -> Result<Self, F::Error> {
- self.try_map_bound(|ty| ty.try_fold_with(folder))
+ self.try_map_bound(|t| t.try_fold_with(folder))
+ }
+
+ fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
+ self.map_bound(|t| t.fold_with(folder))
}
}
diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs
index 6a24982..e9d3a14 100644
--- a/compiler/rustc_type_ir/src/flags.rs
+++ b/compiler/rustc_type_ir/src/flags.rs
@@ -1,3 +1,9 @@
+use std::slice;
+
+use crate::inherent::*;
+use crate::visit::Flags;
+use crate::{self as ty, Interner};
+
bitflags::bitflags! {
/// Flags that we track on types. These flags are propagated upwards
/// through the type during type construction, so that we can quickly check
@@ -128,3 +134,362 @@ pub struct TypeFlags: u32 {
const HAS_BINDER_VARS = 1 << 23;
}
}
+
+#[derive(Debug)]
+pub struct FlagComputation<I> {
+ pub flags: TypeFlags,
+
+ /// see `Ty::outer_exclusive_binder` for details
+ pub outer_exclusive_binder: ty::DebruijnIndex,
+
+ interner: std::marker::PhantomData<I>,
+}
+
+impl<I: Interner> FlagComputation<I> {
+ fn new() -> FlagComputation<I> {
+ FlagComputation {
+ flags: TypeFlags::empty(),
+ outer_exclusive_binder: ty::INNERMOST,
+ interner: std::marker::PhantomData,
+ }
+ }
+
+ #[allow(rustc::usage_of_ty_tykind)]
+ pub fn for_kind(kind: &ty::TyKind<I>) -> FlagComputation<I> {
+ let mut result = FlagComputation::new();
+ result.add_kind(kind);
+ result
+ }
+
+ pub fn for_predicate(binder: ty::Binder<I, ty::PredicateKind<I>>) -> FlagComputation<I> {
+ let mut result = FlagComputation::new();
+ result.add_predicate(binder);
+ result
+ }
+
+ pub fn for_const_kind(kind: &ty::ConstKind<I>) -> FlagComputation<I> {
+ let mut result = FlagComputation::new();
+ result.add_const_kind(kind);
+ result
+ }
+
+ pub fn for_clauses(clauses: &[I::Clause]) -> FlagComputation<I> {
+ let mut result = FlagComputation::new();
+ for c in clauses {
+ result.add_flags(c.as_predicate().flags());
+ result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder());
+ }
+ result
+ }
+
+ fn add_flags(&mut self, flags: TypeFlags) {
+ self.flags = self.flags | flags;
+ }
+
+ /// indicates that `self` refers to something at binding level `binder`
+ fn add_bound_var(&mut self, binder: ty::DebruijnIndex) {
+ let exclusive_binder = binder.shifted_in(1);
+ self.add_exclusive_binder(exclusive_binder);
+ }
+
+ /// indicates that `self` refers to something *inside* binding
+ /// level `binder` -- not bound by `binder`, but bound by the next
+ /// binder internal to it
+ fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) {
+ self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder);
+ }
+
+ /// Adds the flags/depth from a set of types that appear within the current type, but within a
+ /// region binder.
+ fn bound_computation<T, F>(&mut self, value: ty::Binder<I, T>, f: F)
+ where
+ F: FnOnce(&mut Self, T),
+ {
+ let mut computation = FlagComputation::new();
+
+ if !value.bound_vars().is_empty() {
+ computation.add_flags(TypeFlags::HAS_BINDER_VARS);
+ }
+
+ f(&mut computation, value.skip_binder());
+
+ self.add_flags(computation.flags);
+
+ // The types that contributed to `computation` occurred within
+ // a region binder, so subtract one from the region depth
+ // within when adding the depth to `self`.
+ let outer_exclusive_binder = computation.outer_exclusive_binder;
+ if outer_exclusive_binder > ty::INNERMOST {
+ self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1));
+ } // otherwise, this binder captures nothing
+ }
+
+ #[allow(rustc::usage_of_ty_tykind)]
+ fn add_kind(&mut self, kind: &ty::TyKind<I>) {
+ match *kind {
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Float(_)
+ | ty::Uint(_)
+ | ty::Never
+ | ty::Str
+ | ty::Foreign(..) => {}
+
+ ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
+
+ ty::Param(_) => {
+ self.add_flags(TypeFlags::HAS_TY_PARAM);
+ }
+
+ ty::Closure(_, args)
+ | ty::Coroutine(_, args)
+ | ty::CoroutineClosure(_, args)
+ | ty::CoroutineWitness(_, args) => {
+ self.add_args(args.as_slice());
+ }
+
+ ty::Bound(debruijn, _) => {
+ self.add_bound_var(debruijn);
+ self.add_flags(TypeFlags::HAS_TY_BOUND);
+ }
+
+ ty::Placeholder(..) => {
+ self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER);
+ }
+
+ ty::Infer(infer) => match infer {
+ ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
+ self.add_flags(TypeFlags::HAS_TY_FRESH)
+ }
+
+ ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
+ self.add_flags(TypeFlags::HAS_TY_INFER)
+ }
+ },
+
+ ty::Adt(_, args) => {
+ self.add_args(args.as_slice());
+ }
+
+ ty::Alias(kind, data) => {
+ self.add_flags(match kind {
+ ty::Projection => TypeFlags::HAS_TY_PROJECTION,
+ ty::Weak => TypeFlags::HAS_TY_WEAK,
+ ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
+ ty::Inherent => TypeFlags::HAS_TY_INHERENT,
+ });
+
+ self.add_alias_ty(data);
+ }
+
+ ty::Dynamic(obj, r, _) => {
+ for predicate in obj.iter() {
+ self.bound_computation(predicate, |computation, predicate| match predicate {
+ ty::ExistentialPredicate::Trait(tr) => {
+ computation.add_args(tr.args.as_slice())
+ }
+ ty::ExistentialPredicate::Projection(p) => {
+ computation.add_existential_projection(&p);
+ }
+ ty::ExistentialPredicate::AutoTrait(_) => {}
+ });
+ }
+
+ self.add_region(r);
+ }
+
+ ty::Array(tt, len) => {
+ self.add_ty(tt);
+ self.add_const(len);
+ }
+
+ ty::Pat(ty, pat) => {
+ self.add_ty(ty);
+ self.add_flags(pat.flags());
+ }
+
+ ty::Slice(tt) => self.add_ty(tt),
+
+ ty::RawPtr(ty, _) => {
+ self.add_ty(ty);
+ }
+
+ ty::Ref(r, ty, _) => {
+ self.add_region(r);
+ self.add_ty(ty);
+ }
+
+ ty::Tuple(types) => {
+ self.add_tys(types);
+ }
+
+ ty::FnDef(_, args) => {
+ self.add_args(args.as_slice());
+ }
+
+ ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| {
+ computation.add_tys(sig_tys.inputs_and_output);
+ }),
+
+ ty::UnsafeBinder(bound_ty) => {
+ self.bound_computation(bound_ty.into(), |computation, ty| {
+ computation.add_ty(ty);
+ })
+ }
+ }
+ }
+
+ fn add_predicate(&mut self, binder: ty::Binder<I, ty::PredicateKind<I>>) {
+ self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom));
+ }
+
+ fn add_predicate_atom(&mut self, atom: ty::PredicateKind<I>) {
+ match atom {
+ ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
+ self.add_args(trait_pred.trait_ref.args.as_slice());
+ }
+ ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
+ trait_ref,
+ constness: _,
+ })) => {
+ self.add_args(trait_ref.args.as_slice());
+ }
+ ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
+ a,
+ b,
+ ))) => {
+ self.add_region(a);
+ self.add_region(b);
+ }
+ ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
+ ty,
+ region,
+ ))) => {
+ self.add_ty(ty);
+ self.add_region(region);
+ }
+ ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
+ self.add_const(ct);
+ self.add_ty(ty);
+ }
+ ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
+ self.add_ty(a);
+ self.add_ty(b);
+ }
+ ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
+ self.add_ty(a);
+ self.add_ty(b);
+ }
+ ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
+ projection_term,
+ term,
+ })) => {
+ self.add_alias_term(projection_term);
+ self.add_term(term);
+ }
+ ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
+ self.add_args(slice::from_ref(&arg));
+ }
+ ty::PredicateKind::DynCompatible(_def_id) => {}
+ ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
+ self.add_const(uv);
+ }
+ ty::PredicateKind::ConstEquate(expected, found) => {
+ self.add_const(expected);
+ self.add_const(found);
+ }
+ ty::PredicateKind::Ambiguous => {}
+ ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => {
+ self.add_alias_term(alias);
+ self.add_term(term);
+ }
+ ty::PredicateKind::AliasRelate(t1, t2, _) => {
+ self.add_term(t1);
+ self.add_term(t2);
+ }
+ }
+ }
+
+ fn add_ty(&mut self, ty: I::Ty) {
+ self.add_flags(ty.flags());
+ self.add_exclusive_binder(ty.outer_exclusive_binder());
+ }
+
+ fn add_tys(&mut self, tys: I::Tys) {
+ for ty in tys.iter() {
+ self.add_ty(ty);
+ }
+ }
+
+ fn add_region(&mut self, r: I::Region) {
+ self.add_flags(r.flags());
+ if let ty::ReBound(debruijn, _) = r.kind() {
+ self.add_bound_var(debruijn);
+ }
+ }
+
+ fn add_const(&mut self, c: I::Const) {
+ self.add_flags(c.flags());
+ self.add_exclusive_binder(c.outer_exclusive_binder());
+ }
+
+ fn add_const_kind(&mut self, c: &ty::ConstKind<I>) {
+ match *c {
+ ty::ConstKind::Unevaluated(uv) => {
+ self.add_args(uv.args.as_slice());
+ self.add_flags(TypeFlags::HAS_CT_PROJECTION);
+ }
+ ty::ConstKind::Infer(infer) => match infer {
+ ty::InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
+ ty::InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
+ },
+ ty::ConstKind::Bound(debruijn, _) => {
+ self.add_bound_var(debruijn);
+ self.add_flags(TypeFlags::HAS_CT_BOUND);
+ }
+ ty::ConstKind::Param(_) => {
+ self.add_flags(TypeFlags::HAS_CT_PARAM);
+ }
+ ty::ConstKind::Placeholder(_) => {
+ self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER);
+ }
+ ty::ConstKind::Value(cv) => self.add_ty(cv.ty()),
+ ty::ConstKind::Expr(e) => self.add_args(e.args().as_slice()),
+ ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
+ }
+ }
+
+ fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<I>) {
+ self.add_args(projection.args.as_slice());
+ match projection.term.kind() {
+ ty::TermKind::Ty(ty) => self.add_ty(ty),
+ ty::TermKind::Const(ct) => self.add_const(ct),
+ }
+ }
+
+ fn add_alias_ty(&mut self, alias_ty: ty::AliasTy<I>) {
+ self.add_args(alias_ty.args.as_slice());
+ }
+
+ fn add_alias_term(&mut self, alias_term: ty::AliasTerm<I>) {
+ self.add_args(alias_term.args.as_slice());
+ }
+
+ fn add_args(&mut self, args: &[I::GenericArg]) {
+ for kind in args {
+ match kind.kind() {
+ ty::GenericArgKind::Type(ty) => self.add_ty(ty),
+ ty::GenericArgKind::Lifetime(lt) => self.add_region(lt),
+ ty::GenericArgKind::Const(ct) => self.add_const(ct),
+ }
+ }
+ }
+
+ fn add_term(&mut self, term: I::Term) {
+ match term.kind() {
+ ty::TermKind::Ty(ty) => self.add_ty(ty),
+ ty::TermKind::Const(ct) => self.add_const(ct),
+ }
+ }
+}
diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs
index e58f25f..ce11880 100644
--- a/compiler/rustc_type_ir/src/fold.rs
+++ b/compiler/rustc_type_ir/src/fold.rs
@@ -45,6 +45,7 @@
//! - u.fold_with(folder)
//! ```
+use std::convert::Infallible;
use std::mem;
use std::sync::Arc;
@@ -56,12 +57,6 @@
use crate::visit::{TypeVisitable, TypeVisitableExt as _};
use crate::{self as ty, Interner, TypeFlags};
-#[cfg(feature = "nightly")]
-type Never = !;
-
-#[cfg(not(feature = "nightly"))]
-type Never = std::convert::Infallible;
-
/// This trait is implemented for every type that can be folded,
/// providing the skeleton of the traversal.
///
@@ -82,18 +77,24 @@ pub trait TypeFoldable<I: Interner>: TypeVisitable<I> + Clone {
///
/// For types of interest (such as `Ty`), the implementation of this method
/// calls a folder method specifically for that type (such as
- /// `F::try_fold_ty`). This is where control transfers from `TypeFoldable`
- /// to `TypeFolder`.
+ /// `F::try_fold_ty`). This is where control transfers from [`TypeFoldable`]
+ /// to [`FallibleTypeFolder`].
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error>;
- /// A convenient alternative to `try_fold_with` for use with infallible
- /// folders. Do not override this method, to ensure coherence with
- /// `try_fold_with`.
- fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
- match self.try_fold_with(folder) {
- Ok(t) => t,
- }
- }
+ /// The entry point for folding. To fold a value `t` with a folder `f`
+ /// call: `t.fold_with(f)`.
+ ///
+ /// For most types, this just traverses the value, calling `fold_with`
+ /// on each field/element.
+ ///
+ /// For types of interest (such as `Ty`), the implementation of this method
+ /// calls a folder method specifically for that type (such as
+ /// `F::fold_ty`). This is where control transfers from `TypeFoldable`
+ /// to `TypeFolder`.
+ ///
+ /// Same as [`TypeFoldable::try_fold_with`], but not fallible. Make sure to keep
+ /// the behavior in sync across functions.
+ fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self;
}
// This trait is implemented for types of interest.
@@ -112,11 +113,7 @@ fn try_super_fold_with<F: FallibleTypeFolder<I>>(
/// A convenient alternative to `try_super_fold_with` for use with
/// infallible folders. Do not override this method, to ensure coherence
/// with `try_super_fold_with`.
- fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
- match self.try_super_fold_with(folder) {
- Ok(t) => t,
- }
- }
+ fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self;
}
/// This trait is implemented for every infallible folding traversal. There is
@@ -128,7 +125,7 @@ fn super_fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
/// A blanket implementation of [`FallibleTypeFolder`] will defer to
/// the infallible methods of this trait to ensure that the two APIs
/// are coherent.
-pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = Never> {
+pub trait TypeFolder<I: Interner>: Sized {
fn cx(&self) -> I;
fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
@@ -195,42 +192,6 @@ fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Self::
}
}
-// This blanket implementation of the fallible trait for infallible folders
-// delegates to infallible methods to ensure coherence.
-impl<I: Interner, F> FallibleTypeFolder<I> for F
-where
- F: TypeFolder<I>,
-{
- type Error = Never;
-
- fn cx(&self) -> I {
- TypeFolder::cx(self)
- }
-
- fn try_fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> Result<ty::Binder<I, T>, Never>
- where
- T: TypeFoldable<I>,
- {
- Ok(self.fold_binder(t))
- }
-
- fn try_fold_ty(&mut self, t: I::Ty) -> Result<I::Ty, Never> {
- Ok(self.fold_ty(t))
- }
-
- fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Never> {
- Ok(self.fold_region(r))
- }
-
- fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Never> {
- Ok(self.fold_const(c))
- }
-
- fn try_fold_predicate(&mut self, p: I::Predicate) -> Result<I::Predicate, Never> {
- Ok(self.fold_predicate(p))
- }
-}
-
///////////////////////////////////////////////////////////////////////////
// Traversal implementations.
@@ -238,6 +199,10 @@ impl<I: Interner, T: TypeFoldable<I>, U: TypeFoldable<I>> TypeFoldable<I> for (T
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<(T, U), F::Error> {
Ok((self.0.try_fold_with(folder)?, self.1.try_fold_with(folder)?))
}
+
+ fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
+ (self.0.fold_with(folder), self.1.fold_with(folder))
+ }
}
impl<I: Interner, A: TypeFoldable<I>, B: TypeFoldable<I>, C: TypeFoldable<I>> TypeFoldable<I>
@@ -253,6 +218,10 @@ fn try_fold_with<F: FallibleTypeFolder<I>>(
self.2.try_fold_with(folder)?,
))
}
+
+ fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
+ (self.0.fold_with(folder), self.1.fold_with(folder), self.2.fold_with(folder))
+ }
}
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Option<T> {
@@ -262,6 +231,10 @@ fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self,
None => None,
})
}
+
+ fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
+ Some(self?.fold_with(folder))
+ }
}
impl<I: Interner, T: TypeFoldable<I>, E: TypeFoldable<I>> TypeFoldable<I> for Result<T, E> {
@@ -271,41 +244,61 @@ fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self,
Err(e) => Err(e.try_fold_with(folder)?),
})
}
+
+ fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
+ match self {
+ Ok(v) => Ok(v.fold_with(folder)),
+ Err(e) => Err(e.fold_with(folder)),
+ }
+ }
+}
+
+fn fold_arc<T: Clone, E>(
+ mut arc: Arc<T>,
+ fold: impl FnOnce(T) -> Result<T, E>,
+) -> Result<Arc<T>, E> {
+ // We merely want to replace the contained `T`, if at all possible,
+ // so that we don't needlessly allocate a new `Arc` or indeed clone
+ // the contained type.
+ unsafe {
+ // First step is to ensure that we have a unique reference to
+ // the contained type, which `Arc::make_mut` will accomplish (by
+ // allocating a new `Arc` and cloning the `T` only if required).
+ // This is done *before* casting to `Arc<ManuallyDrop<T>>` so that
+ // panicking during `make_mut` does not leak the `T`.
+ Arc::make_mut(&mut arc);
+
+ // Casting to `Arc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
+ // is `repr(transparent)`.
+ let ptr = Arc::into_raw(arc).cast::<mem::ManuallyDrop<T>>();
+ let mut unique = Arc::from_raw(ptr);
+
+ // Call to `Arc::make_mut` above guarantees that `unique` is the
+ // sole reference to the contained value, so we can avoid doing
+ // a checked `get_mut` here.
+ let slot = Arc::get_mut(&mut unique).unwrap_unchecked();
+
+ // Semantically move the contained type out from `unique`, fold
+ // it, then move the folded value back into `unique`. Should
+ // folding fail, `ManuallyDrop` ensures that the "moved-out"
+ // value is not re-dropped.
+ let owned = mem::ManuallyDrop::take(slot);
+ let folded = fold(owned)?;
+ *slot = mem::ManuallyDrop::new(folded);
+
+ // Cast back to `Arc<T>`.
+ Ok(Arc::from_raw(Arc::into_raw(unique).cast()))
+ }
}
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Arc<T> {
- fn try_fold_with<F: FallibleTypeFolder<I>>(mut self, folder: &mut F) -> Result<Self, F::Error> {
- // We merely want to replace the contained `T`, if at all possible,
- // so that we don't needlessly allocate a new `Arc` or indeed clone
- // the contained type.
- unsafe {
- // First step is to ensure that we have a unique reference to
- // the contained type, which `Arc::make_mut` will accomplish (by
- // allocating a new `Arc` and cloning the `T` only if required).
- // This is done *before* casting to `Arc<ManuallyDrop<T>>` so that
- // panicking during `make_mut` does not leak the `T`.
- Arc::make_mut(&mut self);
+ fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ fold_arc(self, |t| t.try_fold_with(folder))
+ }
- // Casting to `Arc<ManuallyDrop<T>>` is safe because `ManuallyDrop`
- // is `repr(transparent)`.
- let ptr = Arc::into_raw(self).cast::<mem::ManuallyDrop<T>>();
- let mut unique = Arc::from_raw(ptr);
-
- // Call to `Arc::make_mut` above guarantees that `unique` is the
- // sole reference to the contained value, so we can avoid doing
- // a checked `get_mut` here.
- let slot = Arc::get_mut(&mut unique).unwrap_unchecked();
-
- // Semantically move the contained type out from `unique`, fold
- // it, then move the folded value back into `unique`. Should
- // folding fail, `ManuallyDrop` ensures that the "moved-out"
- // value is not re-dropped.
- let owned = mem::ManuallyDrop::take(slot);
- let folded = owned.try_fold_with(folder)?;
- *slot = mem::ManuallyDrop::new(folded);
-
- // Cast back to `Arc<T>`.
- Ok(Arc::from_raw(Arc::into_raw(unique).cast()))
+ fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
+ match fold_arc::<T, Infallible>(self, |t| Ok(t.fold_with(folder))) {
+ Ok(t) => t,
}
}
}
@@ -315,30 +308,51 @@ fn try_fold_with<F: FallibleTypeFolder<I>>(mut self, folder: &mut F) -> Result<S
*self = (*self).try_fold_with(folder)?;
Ok(self)
}
+
+ fn fold_with<F: TypeFolder<I>>(mut self, folder: &mut F) -> Self {
+ *self = (*self).fold_with(folder);
+ self
+ }
}
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Vec<T> {
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.into_iter().map(|t| t.try_fold_with(folder)).collect()
}
+
+ fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
+ self.into_iter().map(|t| t.fold_with(folder)).collect()
+ }
}
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for ThinVec<T> {
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.into_iter().map(|t| t.try_fold_with(folder)).collect()
}
+
+ fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
+ self.into_iter().map(|t| t.fold_with(folder)).collect()
+ }
}
impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<[T]> {
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
Vec::from(self).try_fold_with(folder).map(Vec::into_boxed_slice)
}
+
+ fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
+ Vec::into_boxed_slice(Vec::from(self).fold_with(folder))
+ }
}
impl<I: Interner, T: TypeFoldable<I>, Ix: Idx> TypeFoldable<I> for IndexVec<Ix, T> {
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.raw.try_fold_with(folder).map(IndexVec::from_raw)
}
+
+ fn fold_with<F: TypeFolder<I>>(self, folder: &mut F) -> Self {
+ IndexVec::from_raw(self.raw.fold_with(folder))
+ }
}
///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs
index fec6e24..8fa56c3 100644
--- a/compiler/rustc_type_ir/src/infer_ctxt.rs
+++ b/compiler/rustc_type_ir/src/infer_ctxt.rs
@@ -65,7 +65,7 @@ pub enum TypingMode<I: Interner> {
/// let x: <() as Assoc>::Output = true;
/// }
/// ```
- Analysis { defining_opaque_types: I::DefiningOpaqueTypes },
+ Analysis { defining_opaque_types_and_generators: I::LocalDefIds },
/// The behavior during MIR borrowck is identical to `TypingMode::Analysis`
/// except that the initial value for opaque types is the type computed during
/// HIR typeck with unique unconstrained region inference variables.
@@ -73,13 +73,13 @@ pub enum TypingMode<I: Interner> {
/// This is currently only used with by the new solver as it results in new
/// non-universal defining uses of opaque types, which is a breaking change.
/// See tests/ui/impl-trait/non-defining-use/as-projection-term.rs.
- Borrowck { defining_opaque_types: I::DefiningOpaqueTypes },
+ Borrowck { defining_opaque_types: I::LocalDefIds },
/// Any analysis after borrowck for a given body should be able to use all the
/// hidden types defined by borrowck, without being able to define any new ones.
///
/// This is currently only used by the new solver, but should be implemented in
/// the old solver as well.
- PostBorrowckAnalysis { defined_opaque_types: I::DefiningOpaqueTypes },
+ PostBorrowckAnalysis { defined_opaque_types: I::LocalDefIds },
/// After analysis, mostly during codegen and MIR optimizations, we're able to
/// reveal all opaque types. As the concrete type should *never* be observable
/// directly by the user, this should not be used by checks which may expose
@@ -94,13 +94,25 @@ pub enum TypingMode<I: Interner> {
impl<I: Interner> TypingMode<I> {
/// Analysis outside of a body does not define any opaque types.
pub fn non_body_analysis() -> TypingMode<I> {
- TypingMode::Analysis { defining_opaque_types: Default::default() }
+ TypingMode::Analysis { defining_opaque_types_and_generators: Default::default() }
+ }
+
+ pub fn typeck_for_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
+ TypingMode::Analysis {
+ defining_opaque_types_and_generators: cx
+ .opaque_types_and_generators_defined_by(body_def_id),
+ }
}
/// While typechecking a body, we need to be able to define the opaque
/// types defined by that body.
+ ///
+ /// FIXME: This will be removed because it's generally not correct to define
+ /// opaques outside of HIR typeck.
pub fn analysis_in_body(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
- TypingMode::Analysis { defining_opaque_types: cx.opaque_types_defined_by(body_def_id) }
+ TypingMode::Analysis {
+ defining_opaque_types_and_generators: cx.opaque_types_defined_by(body_def_id),
+ }
}
pub fn borrowck(cx: I, body_def_id: I::LocalDefId) -> TypingMode<I> {
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
index 6e6c405..417803e 100644
--- a/compiler/rustc_type_ir/src/inherent.rs
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -583,7 +583,7 @@ pub trait Span<I: Interner>: Copy + Debug + Hash + Eq + TypeFoldable<I> {
pub trait SliceLike: Sized + Copy {
type Item: Copy;
- type IntoIter: Iterator<Item = Self::Item>;
+ type IntoIter: Iterator<Item = Self::Item> + DoubleEndedIterator;
fn iter(self) -> Self::IntoIter;
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index a9e6764..ab38556 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -31,6 +31,7 @@ pub trait Interner:
+ IrPrint<ty::SubtypePredicate<Self>>
+ IrPrint<ty::CoercePredicate<Self>>
+ IrPrint<ty::FnSig<Self>>
+ + IrPrint<ty::PatternKind<Self>>
{
type DefId: DefId<Self>;
type LocalDefId: Copy + Debug + Hash + Eq + Into<Self::DefId> + TypeFoldable<Self>;
@@ -55,7 +56,7 @@ fn mk_predefined_opaques_in_body(
data: PredefinedOpaquesData<Self>,
) -> Self::PredefinedOpaques;
- type DefiningOpaqueTypes: Copy
+ type LocalDefIds: Copy
+ Debug
+ Hash
+ Default
@@ -104,7 +105,14 @@ fn mk_tracked<T: Debug + Clone>(
type ErrorGuaranteed: Copy + Debug + Hash + Eq;
type BoundExistentialPredicates: BoundExistentialPredicates<Self>;
type AllocId: Copy + Debug + Hash + Eq;
- type Pat: Copy + Debug + Hash + Eq + Debug + Relate<Self>;
+ type Pat: Copy
+ + Debug
+ + Hash
+ + Eq
+ + Debug
+ + Relate<Self>
+ + Flags
+ + IntoKind<Kind = ty::PatternKind<Self>>;
type Safety: Safety<Self>;
type Abi: Abi<Self>;
@@ -322,10 +330,12 @@ fn anonymize_bound_vars<T: TypeFoldable<Self>>(
binder: ty::Binder<Self, T>,
) -> ty::Binder<Self, T>;
- fn opaque_types_defined_by(
+ fn opaque_types_defined_by(self, defining_anchor: Self::LocalDefId) -> Self::LocalDefIds;
+
+ fn opaque_types_and_generators_defined_by(
self,
defining_anchor: Self::LocalDefId,
- ) -> Self::DefiningOpaqueTypes;
+ ) -> Self::LocalDefIds;
}
/// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs
index 0c71f3a..388ad09 100644
--- a/compiler/rustc_type_ir/src/ir_print.rs
+++ b/compiler/rustc_type_ir/src/ir_print.rs
@@ -2,8 +2,8 @@
use crate::{
AliasTerm, AliasTy, Binder, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
- HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate,
- SubtypePredicate, TraitPredicate, TraitRef,
+ HostEffectPredicate, Interner, NormalizesTo, OutlivesPredicate, PatternKind,
+ ProjectionPredicate, SubtypePredicate, TraitPredicate, TraitRef,
};
pub trait IrPrint<T> {
@@ -57,9 +57,10 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
AliasTy,
AliasTerm,
FnSig,
+ PatternKind,
);
-define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection);
+define_debug_via_print!(TraitRef, ExistentialTraitRef, PatternKind);
impl<I: Interner, T> fmt::Display for OutlivesPredicate<I, T>
where
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index bdc61e95..792090e 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -31,6 +31,7 @@
pub mod relate;
pub mod search_graph;
pub mod solve;
+pub mod walk;
// These modules are not `pub` since they are glob-imported.
#[macro_use]
@@ -44,6 +45,7 @@
mod infer_ctxt;
mod interner;
mod opaque_ty;
+mod pattern;
mod predicate;
mod predicate_kind;
mod region_kind;
@@ -67,6 +69,7 @@
pub use infer_ctxt::*;
pub use interner::*;
pub use opaque_ty::*;
+pub use pattern::*;
pub use predicate::*;
pub use predicate_kind::*;
pub use region_kind::*;
diff --git a/compiler/rustc_type_ir/src/pattern.rs b/compiler/rustc_type_ir/src/pattern.rs
new file mode 100644
index 0000000..d74a82d
--- /dev/null
+++ b/compiler/rustc_type_ir/src/pattern.rs
@@ -0,0 +1,16 @@
+use derive_where::derive_where;
+#[cfg(feature = "nightly")]
+use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContext};
+use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
+
+use crate::Interner;
+
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(
+ feature = "nightly",
+ derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext)
+)]
+pub enum PatternKind<I: Interner> {
+ Range { start: I::Const, end: I::Const },
+}
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
index 22d0fa2..8e10636 100644
--- a/compiler/rustc_type_ir/src/predicate.rs
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -374,7 +374,7 @@ pub fn with_self_ty(&self, cx: I, self_ty: I::Ty) -> ty::Binder<I, TraitRef<I>>
}
/// A `ProjectionPredicate` for an `ExistentialTraitRef`.
-#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)]
+#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)]
#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
#[cfg_attr(
feature = "nightly",
diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs
index 18fb71d..b10641b 100644
--- a/compiler/rustc_type_ir/src/solve/inspect.rs
+++ b/compiler/rustc_type_ir/src/solve/inspect.rs
@@ -118,10 +118,12 @@ pub enum ProbeKind<I: Interner> {
/// Used in the probe that wraps normalizing the non-self type for the unsize
/// trait, which is also structurally matched on.
UnsizeAssembly,
- /// During upcasting from some source object to target object type, used to
- /// do a probe to find out what projection type(s) may be used to prove that
- /// the source type upholds all of the target type's object bounds.
- UpcastProjectionCompatibility,
+ /// Used to do a probe to find out what projection type(s) match a given
+ /// alias bound or projection predicate. For trait upcasting, this is used
+ /// to prove that the source type upholds all of the target type's object
+ /// bounds. For object type bounds, this is used when eagerly replacing
+ /// supertrait aliases.
+ ProjectionCompatibility,
/// Looking for param-env candidates that satisfy the trait ref for a projection.
ShadowedEnvProbing,
/// Try to unify an opaque type with an existing key in the storage.
diff --git a/compiler/rustc_type_ir/src/walk.rs b/compiler/rustc_type_ir/src/walk.rs
new file mode 100644
index 0000000..5683e1f
--- /dev/null
+++ b/compiler/rustc_type_ir/src/walk.rs
@@ -0,0 +1,173 @@
+//! An iterator over the type substructure.
+//! WARNING: this does not keep track of the region depth.
+
+use smallvec::{SmallVec, smallvec};
+use tracing::debug;
+
+use crate::data_structures::SsoHashSet;
+use crate::inherent::*;
+use crate::{self as ty, Interner};
+
+// The TypeWalker's stack is hot enough that it's worth going to some effort to
+// avoid heap allocations.
+type TypeWalkerStack<I> = SmallVec<[<I as Interner>::GenericArg; 8]>;
+
+pub struct TypeWalker<I: Interner> {
+ stack: TypeWalkerStack<I>,
+ last_subtree: usize,
+ pub visited: SsoHashSet<I::GenericArg>,
+}
+
+/// An iterator for walking the type tree.
+///
+/// It's very easy to produce a deeply
+/// nested type tree with a lot of
+/// identical subtrees. In order to work efficiently
+/// in this situation walker only visits each type once.
+/// It maintains a set of visited types and
+/// skips any types that are already there.
+impl<I: Interner> TypeWalker<I> {
+ pub fn new(root: I::GenericArg) -> Self {
+ Self { stack: smallvec![root], last_subtree: 1, visited: SsoHashSet::new() }
+ }
+
+ /// Skips the subtree corresponding to the last type
+ /// returned by `next()`.
+ ///
+ /// Example: Imagine you are walking `Foo<Bar<i32>, usize>`.
+ ///
+ /// ```ignore (illustrative)
+ /// let mut iter: TypeWalker = ...;
+ /// iter.next(); // yields Foo
+ /// iter.next(); // yields Bar<i32>
+ /// iter.skip_current_subtree(); // skips i32
+ /// iter.next(); // yields usize
+ /// ```
+ pub fn skip_current_subtree(&mut self) {
+ self.stack.truncate(self.last_subtree);
+ }
+}
+
+impl<I: Interner> Iterator for TypeWalker<I> {
+ type Item = I::GenericArg;
+
+ fn next(&mut self) -> Option<I::GenericArg> {
+ debug!("next(): stack={:?}", self.stack);
+ loop {
+ let next = self.stack.pop()?;
+ self.last_subtree = self.stack.len();
+ if self.visited.insert(next) {
+ push_inner::<I>(&mut self.stack, next);
+ debug!("next: stack={:?}", self.stack);
+ return Some(next);
+ }
+ }
+ }
+}
+
+/// We push `GenericArg`s on the stack in reverse order so as to
+/// maintain a pre-order traversal. As of the time of this
+/// writing, the fact that the traversal is pre-order is not
+/// known to be significant to any code, but it seems like the
+/// natural order one would expect (basically, the order of the
+/// types as they are written).
+fn push_inner<I: Interner>(stack: &mut TypeWalkerStack<I>, parent: I::GenericArg) {
+ match parent.kind() {
+ ty::GenericArgKind::Type(parent_ty) => match parent_ty.kind() {
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Str
+ | ty::Infer(_)
+ | ty::Param(_)
+ | ty::Never
+ | ty::Error(_)
+ | ty::Placeholder(..)
+ | ty::Bound(..)
+ | ty::Foreign(..) => {}
+
+ ty::Pat(ty, pat) => {
+ match pat.kind() {
+ ty::PatternKind::Range { start, end } => {
+ stack.push(end.into());
+ stack.push(start.into());
+ }
+ }
+ stack.push(ty.into());
+ }
+ ty::Array(ty, len) => {
+ stack.push(len.into());
+ stack.push(ty.into());
+ }
+ ty::Slice(ty) => {
+ stack.push(ty.into());
+ }
+ ty::RawPtr(ty, _) => {
+ stack.push(ty.into());
+ }
+ ty::Ref(lt, ty, _) => {
+ stack.push(ty.into());
+ stack.push(lt.into());
+ }
+ ty::Alias(_, data) => {
+ stack.extend(data.args.iter().rev());
+ }
+ ty::Dynamic(obj, lt, _) => {
+ stack.push(lt.into());
+ stack.extend(
+ obj.iter()
+ .rev()
+ .filter_map(|predicate| {
+ let (args, opt_ty) = match predicate.skip_binder() {
+ ty::ExistentialPredicate::Trait(tr) => (tr.args, None),
+ ty::ExistentialPredicate::Projection(p) => (p.args, Some(p.term)),
+ ty::ExistentialPredicate::AutoTrait(_) => {
+ return None;
+ }
+ };
+
+ Some(args.iter().rev().chain(opt_ty.map(|term| match term.kind() {
+ ty::TermKind::Ty(ty) => ty.into(),
+ ty::TermKind::Const(ct) => ct.into(),
+ })))
+ })
+ .flatten(),
+ );
+ }
+ ty::Adt(_, args)
+ | ty::Closure(_, args)
+ | ty::CoroutineClosure(_, args)
+ | ty::Coroutine(_, args)
+ | ty::CoroutineWitness(_, args)
+ | ty::FnDef(_, args) => {
+ stack.extend(args.iter().rev());
+ }
+ ty::Tuple(ts) => stack.extend(ts.iter().rev().map(|ty| ty.into())),
+ ty::FnPtr(sig_tys, _hdr) => {
+ stack.extend(
+ sig_tys.skip_binder().inputs_and_output.iter().rev().map(|ty| ty.into()),
+ );
+ }
+ ty::UnsafeBinder(bound_ty) => {
+ stack.push(bound_ty.skip_binder().into());
+ }
+ },
+ ty::GenericArgKind::Lifetime(_) => {}
+ ty::GenericArgKind::Const(parent_ct) => match parent_ct.kind() {
+ ty::ConstKind::Infer(_)
+ | ty::ConstKind::Param(_)
+ | ty::ConstKind::Placeholder(_)
+ | ty::ConstKind::Bound(..)
+ | ty::ConstKind::Error(_) => {}
+
+ ty::ConstKind::Value(cv) => stack.push(cv.ty().into()),
+
+ ty::ConstKind::Expr(expr) => stack.extend(expr.args().iter().rev()),
+ ty::ConstKind::Unevaluated(ct) => {
+ stack.extend(ct.args.iter().rev());
+ }
+ },
+ }
+}
diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs
index 8eefecd..3a10d0d 100644
--- a/compiler/rustc_type_ir_macros/src/lib.rs
+++ b/compiler/rustc_type_ir_macros/src/lib.rs
@@ -83,7 +83,7 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
s.add_where_predicate(parse_quote! { I: Interner });
s.add_bounds(synstructure::AddBounds::Fields);
s.bind_with(|_| synstructure::BindStyle::Move);
- let body_fold = s.each_variant(|vi| {
+ let body_try_fold = s.each_variant(|vi| {
let bindings = vi.bindings();
vi.construct(|_, index| {
let bind = &bindings[index];
@@ -99,6 +99,22 @@ fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::Toke
})
});
+ let body_fold = s.each_variant(|vi| {
+ let bindings = vi.bindings();
+ vi.construct(|_, index| {
+ let bind = &bindings[index];
+
+ // retain value of fields with #[type_foldable(identity)]
+ if has_ignore_attr(&bind.ast().attrs, "type_foldable", "identity") {
+ bind.to_token_stream()
+ } else {
+ quote! {
+ ::rustc_type_ir::TypeFoldable::fold_with(#bind, __folder)
+ }
+ }
+ })
+ });
+
// We filter fields which get ignored and don't require them to implement
// `TypeFoldable`. We do so after generating `body_fold` as we still need
// to generate code for them.
@@ -111,7 +127,14 @@ fn try_fold_with<__F: ::rustc_type_ir::FallibleTypeFolder<I>>(
self,
__folder: &mut __F
) -> Result<Self, __F::Error> {
- Ok(match self { #body_fold })
+ Ok(match self { #body_try_fold })
+ }
+
+ fn fold_with<__F: ::rustc_type_ir::TypeFolder<I>>(
+ self,
+ __folder: &mut __F
+ ) -> Self {
+ match self { #body_fold }
}
},
)
diff --git a/library/Cargo.lock b/library/Cargo.lock
index d035ca6..f7f09a1 100644
--- a/library/Cargo.lock
+++ b/library/Cargo.lock
@@ -67,9 +67,9 @@
[[package]]
name = "compiler_builtins"
-version = "0.1.153"
+version = "0.1.156"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "926ef6a360c15a911023352fd6969c51605d70495406f735beb1ca0257448e59"
+checksum = "c1ffbd2789fe5bb95b96a2e22cbe3128239dc46ff0374e0d38e9f102062d7055"
dependencies = [
"cc",
"rustc-std-workspace-core",
@@ -157,9 +157,9 @@
[[package]]
name = "libc"
-version = "0.2.171"
+version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
+checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
dependencies = [
"rustc-std-workspace-core",
]
@@ -176,9 +176,9 @@
[[package]]
name = "miniz_oxide"
-version = "0.8.7"
+version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
+checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [
"adler2",
"compiler_builtins",
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index ee8cb9d..994221d 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -16,7 +16,7 @@
[dependencies]
core = { path = "../core", public = true }
-compiler_builtins = { version = "=0.1.153", features = ['rustc-dep-of-std'] }
+compiler_builtins = { version = "=0.1.156", features = ['rustc-dep-of-std'] }
[features]
compiler-builtins-mem = ['compiler_builtins/mem']
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index f6743c6..d5b1947 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -574,7 +574,7 @@ pub fn as_bytes_with_nul(&self) -> &[u8] {
#[stable(feature = "as_c_str", since = "1.20.0")]
#[rustc_diagnostic_item = "cstring_as_c_str"]
pub fn as_c_str(&self) -> &CStr {
- &*self
+ unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
}
/// Converts this `CString` into a boxed [`CStr`].
@@ -705,14 +705,14 @@ impl ops::Deref for CString {
#[inline]
fn deref(&self) -> &CStr {
- unsafe { CStr::from_bytes_with_nul_unchecked(self.as_bytes_with_nul()) }
+ self.as_c_str()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for CString {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Debug::fmt(&**self, f)
+ fmt::Debug::fmt(self.as_c_str(), f)
}
}
@@ -1116,7 +1116,7 @@ impl CStr {
/// with the corresponding <code>&[str]</code> slice. Otherwise, it will
/// replace any invalid UTF-8 sequences with
/// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
- /// <code>[Cow]::[Owned]\(&[str])</code> with the result.
+ /// <code>[Cow]::[Owned]\([String])</code> with the result.
///
/// [str]: prim@str "str"
/// [Borrowed]: Cow::Borrowed
diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs
index e40de13..30f4205 100644
--- a/library/alloc/src/fmt.rs
+++ b/library/alloc/src/fmt.rs
@@ -109,7 +109,7 @@
//! parameters (corresponding to `format_spec` in [the syntax](#syntax)). These
//! parameters affect the string representation of what's being formatted.
//!
-//! The colon `:` in format syntax divides indentifier of the input data and
+//! The colon `:` in format syntax divides identifier of the input data and
//! the formatting options, the colon itself does not change anything, only
//! introduces the options.
//!
diff --git a/library/alloctests/tests/c_str2.rs b/library/alloctests/tests/c_str2.rs
index 0f4c27f..fe7686b 100644
--- a/library/alloctests/tests/c_str2.rs
+++ b/library/alloctests/tests/c_str2.rs
@@ -34,12 +34,6 @@ fn build_with_zero2() {
}
#[test]
-fn formatted() {
- let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap();
- assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
-}
-
-#[test]
fn borrowed() {
unsafe {
let s = CStr::from_ptr(b"12\0".as_ptr() as *const _);
diff --git a/library/core/src/any.rs b/library/core/src/any.rs
index 10f2a11..7aa3f3c 100644
--- a/library/core/src/any.rs
+++ b/library/core/src/any.rs
@@ -772,8 +772,8 @@ fn hash<H: hash::Hasher>(&self, state: &mut H) {
// (especially given the previous point about the lower 64 bits being
// high quality on their own).
// - It is correct to do so -- only hashing a subset of `self` is still
- // with an `Eq` implementation that considers the entire value, as
- // ours does.
+ // compatible with an `Eq` implementation that considers the entire
+ // value, as ours does.
self.t.1.hash(state);
}
}
diff --git a/library/core/src/arch.rs b/library/core/src/arch.rs
index 81d828a..f19fde2 100644
--- a/library/core/src/arch.rs
+++ b/library/core/src/arch.rs
@@ -32,7 +32,7 @@
///
/// [Rust By Example]: https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html
/// [reference]: https://doc.rust-lang.org/nightly/reference/inline-assembly.html
-#[unstable(feature = "naked_functions", issue = "90957")]
+#[stable(feature = "naked_functions", since = "CURRENT_RUSTC_VERSION")]
#[rustc_builtin_macro]
pub macro naked_asm("assembly template", $(operands,)* $(options($(option),*))?) {
/* compiler built-in */
diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs
index d525ab4..2016ece 100644
--- a/library/core/src/bool.rs
+++ b/library/core/src/bool.rs
@@ -61,52 +61,4 @@ pub fn then_some<T>(self, t: T) -> Option<T> {
pub fn then<T, F: FnOnce() -> T>(self, f: F) -> Option<T> {
if self { Some(f()) } else { None }
}
-
- /// Returns either `true_val` or `false_val` depending on the value of
- /// `self`, with a hint to the compiler that `self` is unlikely
- /// to be correctly predicted by a CPU’s branch predictor.
- ///
- /// This method is functionally equivalent to
- /// ```ignore (this is just for illustrative purposes)
- /// fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
- /// if b { true_val } else { false_val }
- /// }
- /// ```
- /// but might generate different assembly. In particular, on platforms with
- /// a conditional move or select instruction (like `cmov` on x86 or `csel`
- /// on ARM) the optimizer might use these instructions to avoid branches,
- /// which can benefit performance if the branch predictor is struggling
- /// with predicting `condition`, such as in an implementation of binary
- /// search.
- ///
- /// Note however that this lowering is not guaranteed (on any platform) and
- /// should not be relied upon when trying to write constant-time code. Also
- /// be aware that this lowering might *decrease* performance if `condition`
- /// is well-predictable. It is advisable to perform benchmarks to tell if
- /// this function is useful.
- ///
- /// # Examples
- ///
- /// Distribute values evenly between two buckets:
- /// ```
- /// #![feature(select_unpredictable)]
- ///
- /// use std::hash::BuildHasher;
- ///
- /// fn append<H: BuildHasher>(hasher: &H, v: i32, bucket_one: &mut Vec<i32>, bucket_two: &mut Vec<i32>) {
- /// let hash = hasher.hash_one(&v);
- /// let bucket = (hash % 2 == 0).select_unpredictable(bucket_one, bucket_two);
- /// bucket.push(v);
- /// }
- /// # let hasher = std::collections::hash_map::RandomState::new();
- /// # let mut bucket_one = Vec::new();
- /// # let mut bucket_two = Vec::new();
- /// # append(&hasher, 42, &mut bucket_one, &mut bucket_two);
- /// # assert_eq!(bucket_one.len() + bucket_two.len(), 1);
- /// ```
- #[inline(always)]
- #[unstable(feature = "select_unpredictable", issue = "133962")]
- pub fn select_unpredictable<T>(self, true_val: T, false_val: T) -> T {
- crate::intrinsics::select_unpredictable(self, true_val, false_val)
- }
}
diff --git a/library/core/src/bstr/mod.rs b/library/core/src/bstr/mod.rs
index c8d0c70..13127d6 100644
--- a/library/core/src/bstr/mod.rs
+++ b/library/core/src/bstr/mod.rs
@@ -36,8 +36,7 @@
/// presented as hex escape sequences.
///
/// The `Display` implementation behaves as if the `ByteStr` were first lossily converted to a
-/// `str`, with invalid UTF-8 presented as the Unicode replacement character: �
-///
+/// `str`, with invalid UTF-8 presented as the Unicode replacement character (�).
#[unstable(feature = "bstr", issue = "134915")]
#[repr(transparent)]
#[doc(alias = "BStr")]
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 17231df..c765735 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -549,8 +549,6 @@ pub const fn get(&self) -> T {
/// # Examples
///
/// ```
- /// #![feature(cell_update)]
- ///
/// use std::cell::Cell;
///
/// let c = Cell::new(5);
@@ -558,7 +556,7 @@ pub const fn get(&self) -> T {
/// assert_eq!(c.get(), 6);
/// ```
#[inline]
- #[unstable(feature = "cell_update", issue = "50186")]
+ #[stable(feature = "cell_update", since = "CURRENT_RUSTC_VERSION")]
pub fn update(&self, f: impl FnOnce(T) -> T) {
let old = self.get();
self.set(f(old));
diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs
index 0dc2cc7..c315131 100644
--- a/library/core/src/cmp.rs
+++ b/library/core/src/cmp.rs
@@ -2053,6 +2053,22 @@ fn gt(&self, other: &&B) -> bool {
fn ge(&self, other: &&B) -> bool {
PartialOrd::ge(*self, *other)
}
+ #[inline]
+ fn __chaining_lt(&self, other: &&B) -> ControlFlow<bool> {
+ PartialOrd::__chaining_lt(*self, *other)
+ }
+ #[inline]
+ fn __chaining_le(&self, other: &&B) -> ControlFlow<bool> {
+ PartialOrd::__chaining_le(*self, *other)
+ }
+ #[inline]
+ fn __chaining_gt(&self, other: &&B) -> ControlFlow<bool> {
+ PartialOrd::__chaining_gt(*self, *other)
+ }
+ #[inline]
+ fn __chaining_ge(&self, other: &&B) -> ControlFlow<bool> {
+ PartialOrd::__chaining_ge(*self, *other)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: ?Sized> Ord for &A
@@ -2108,6 +2124,22 @@ fn gt(&self, other: &&mut B) -> bool {
fn ge(&self, other: &&mut B) -> bool {
PartialOrd::ge(*self, *other)
}
+ #[inline]
+ fn __chaining_lt(&self, other: &&mut B) -> ControlFlow<bool> {
+ PartialOrd::__chaining_lt(*self, *other)
+ }
+ #[inline]
+ fn __chaining_le(&self, other: &&mut B) -> ControlFlow<bool> {
+ PartialOrd::__chaining_le(*self, *other)
+ }
+ #[inline]
+ fn __chaining_gt(&self, other: &&mut B) -> ControlFlow<bool> {
+ PartialOrd::__chaining_gt(*self, *other)
+ }
+ #[inline]
+ fn __chaining_ge(&self, other: &&mut B) -> ControlFlow<bool> {
+ PartialOrd::__chaining_ge(*self, *other)
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<A: ?Sized> Ord for &mut A
diff --git a/library/core/src/contracts.rs b/library/core/src/contracts.rs
index 8b79a3a..495f84b 100644
--- a/library/core/src/contracts.rs
+++ b/library/core/src/contracts.rs
@@ -2,19 +2,23 @@
pub use crate::macros::builtin::{contracts_ensures as ensures, contracts_requires as requires};
-/// Emitted by rustc as a desugaring of `#[ensures(PRED)] fn foo() -> R { ... [return R;] ... }`
-/// into: `fn foo() { let _check = build_check_ensures(|ret| PRED) ... [return _check(R);] ... }`
-/// (including the implicit return of the tail expression, if any).
+/// This is an identity function used as part of the desugaring of the `#[ensures]` attribute.
+///
+/// This is an existing hack to allow users to omit the type of the return value in their ensures
+/// attribute.
+///
+/// Ideally, rustc should be able to generate the type annotation.
+/// The existing lowering logic makes it rather hard to add the explicit type annotation,
+/// while the function call is fairly straight forward.
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
+// Similar to `contract_check_requires`, we need to use the user-facing
+// `contracts` feature rather than the perma-unstable `contracts_internals`.
+// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion.
+#[rustc_const_unstable(feature = "contracts", issue = "128044")]
#[lang = "contract_build_check_ensures"]
-#[track_caller]
-pub fn build_check_ensures<Ret, C>(cond: C) -> impl (Fn(Ret) -> Ret) + Copy
+pub const fn build_check_ensures<Ret, C>(cond: C) -> C
where
- C: for<'a> Fn(&'a Ret) -> bool + Copy + 'static,
+ C: Fn(&Ret) -> bool + Copy + 'static,
{
- #[track_caller]
- move |ret| {
- crate::intrinsics::contract_check_ensures(&ret, cond);
- ret
- }
+ cond
}
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 080c0ce..85e8744 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -150,7 +150,6 @@ fn description(&self) -> &str {
/// within the slice.
///
/// This error is created by the [`CStr::from_bytes_until_nul`] method.
-///
#[derive(Clone, PartialEq, Eq, Debug)]
#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")]
pub struct FromBytesUntilNulError(());
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index 7ca3909..580f95e 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -7,7 +7,7 @@
use crate::marker::PhantomData;
use crate::num::fmt as numfmt;
use crate::ops::Deref;
-use crate::{iter, mem, result, str};
+use crate::{iter, result, str};
mod builders;
#[cfg(not(no_fp_fmt_parse))]
diff --git a/library/core/src/fmt/rt.rs b/library/core/src/fmt/rt.rs
index 0459674..adcfdd3 100644
--- a/library/core/src/fmt/rt.rs
+++ b/library/core/src/fmt/rt.rs
@@ -65,61 +65,92 @@ pub struct Argument<'a> {
ty: ArgumentType<'a>,
}
-#[rustc_diagnostic_item = "ArgumentMethods"]
-impl Argument<'_> {
- #[inline]
- const fn new<'a, T>(x: &'a T, f: fn(&T, &mut Formatter<'_>) -> Result) -> Argument<'a> {
+macro_rules! argument_new {
+ ($t:ty, $x:expr, $f:expr) => {
Argument {
// INVARIANT: this creates an `ArgumentType<'a>` from a `&'a T` and
// a `fn(&T, ...)`, so the invariant is maintained.
ty: ArgumentType::Placeholder {
- value: NonNull::from_ref(x).cast(),
- // SAFETY: function pointers always have the same layout.
- formatter: unsafe { mem::transmute(f) },
+ value: NonNull::<$t>::from_ref($x).cast(),
+ // The Rust ABI considers all pointers to be equivalent, so transmuting a fn(&T) to
+ // fn(NonNull<()>) and calling it with a NonNull<()> that points at a T is allowed.
+ // However, the CFI sanitizer does not allow this, and triggers a crash when it
+ // happens.
+ //
+ // To avoid this crash, we use a helper function when CFI is enabled. To avoid the
+ // cost of this helper function (mainly code-size) when it is not needed, we
+ // transmute the function pointer otherwise.
+ //
+ // This is similar to what the Rust compiler does internally with vtables when KCFI
+ // is enabled, where it generates trampoline functions that only serve to adjust the
+ // expected type of the argument. `ArgumentType::Placeholder` is a bit like a
+ // manually constructed trait object, so it is not surprising that the same approach
+ // has to be applied here as well.
+ //
+ // It is still considered problematic (from the Rust side) that CFI rejects entirely
+ // legal Rust programs, so we do not consider anything done here a stable guarantee,
+ // but meanwhile we carry this work-around to keep Rust compatible with CFI and
+ // KCFI.
+ #[cfg(not(any(sanitize = "cfi", sanitize = "kcfi")))]
+ formatter: {
+ let f: fn(&$t, &mut Formatter<'_>) -> Result = $f;
+ // SAFETY: This is only called with `value`, which has the right type.
+ unsafe { core::mem::transmute(f) }
+ },
+ #[cfg(any(sanitize = "cfi", sanitize = "kcfi"))]
+ formatter: |ptr: NonNull<()>, fmt: &mut Formatter<'_>| {
+ let func = $f;
+ // SAFETY: This is the same type as the `value` field.
+ let r = unsafe { ptr.cast::<$t>().as_ref() };
+ (func)(r, fmt)
+ },
_lifetime: PhantomData,
},
}
- }
+ };
+}
+#[rustc_diagnostic_item = "ArgumentMethods"]
+impl Argument<'_> {
#[inline]
pub fn new_display<T: Display>(x: &T) -> Argument<'_> {
- Self::new(x, Display::fmt)
+ argument_new!(T, x, <T as Display>::fmt)
}
#[inline]
pub fn new_debug<T: Debug>(x: &T) -> Argument<'_> {
- Self::new(x, Debug::fmt)
+ argument_new!(T, x, <T as Debug>::fmt)
}
#[inline]
pub fn new_debug_noop<T: Debug>(x: &T) -> Argument<'_> {
- Self::new(x, |_, _| Ok(()))
+ argument_new!(T, x, |_: &T, _| Ok(()))
}
#[inline]
pub fn new_octal<T: Octal>(x: &T) -> Argument<'_> {
- Self::new(x, Octal::fmt)
+ argument_new!(T, x, <T as Octal>::fmt)
}
#[inline]
pub fn new_lower_hex<T: LowerHex>(x: &T) -> Argument<'_> {
- Self::new(x, LowerHex::fmt)
+ argument_new!(T, x, <T as LowerHex>::fmt)
}
#[inline]
pub fn new_upper_hex<T: UpperHex>(x: &T) -> Argument<'_> {
- Self::new(x, UpperHex::fmt)
+ argument_new!(T, x, <T as UpperHex>::fmt)
}
#[inline]
pub fn new_pointer<T: Pointer>(x: &T) -> Argument<'_> {
- Self::new(x, Pointer::fmt)
+ argument_new!(T, x, <T as Pointer>::fmt)
}
#[inline]
pub fn new_binary<T: Binary>(x: &T) -> Argument<'_> {
- Self::new(x, Binary::fmt)
+ argument_new!(T, x, <T as Binary>::fmt)
}
#[inline]
pub fn new_lower_exp<T: LowerExp>(x: &T) -> Argument<'_> {
- Self::new(x, LowerExp::fmt)
+ argument_new!(T, x, <T as LowerExp>::fmt)
}
#[inline]
pub fn new_upper_exp<T: UpperExp>(x: &T) -> Argument<'_> {
- Self::new(x, UpperExp::fmt)
+ argument_new!(T, x, <T as UpperExp>::fmt)
}
#[inline]
#[track_caller]
@@ -135,11 +166,6 @@ pub const fn from_usize(x: &usize) -> Argument<'_> {
/// # Safety
///
/// This argument must actually be a placeholder argument.
- ///
- // FIXME: Transmuting formatter in new and indirectly branching to/calling
- // it here is an explicit CFI violation.
- #[allow(inline_no_sanitize)]
- #[no_sanitize(cfi, kcfi)]
#[inline]
pub(super) unsafe fn fmt(&self, f: &mut Formatter<'_>) -> Result {
match self.ty {
diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs
index 5ce282b..1ca23ab 100644
--- a/library/core/src/hint.rs
+++ b/library/core/src/hint.rs
@@ -4,6 +4,7 @@
//!
//! Hints may be compile time or runtime.
+use crate::mem::MaybeUninit;
use crate::{intrinsics, ub_checks};
/// Informs the compiler that the site which is calling this function is not
@@ -734,3 +735,63 @@ pub const fn unlikely(b: bool) -> bool {
pub const fn cold_path() {
crate::intrinsics::cold_path()
}
+
+/// Returns either `true_val` or `false_val` depending on the value of
+/// `condition`, with a hint to the compiler that `condition` is unlikely to be
+/// correctly predicted by a CPU’s branch predictor.
+///
+/// This method is functionally equivalent to
+/// ```ignore (this is just for illustrative purposes)
+/// fn select_unpredictable<T>(b: bool, true_val: T, false_val: T) -> T {
+/// if b { true_val } else { false_val }
+/// }
+/// ```
+/// but might generate different assembly. In particular, on platforms with
+/// a conditional move or select instruction (like `cmov` on x86 or `csel`
+/// on ARM) the optimizer might use these instructions to avoid branches,
+/// which can benefit performance if the branch predictor is struggling
+/// with predicting `condition`, such as in an implementation of binary
+/// search.
+///
+/// Note however that this lowering is not guaranteed (on any platform) and
+/// should not be relied upon when trying to write cryptographic constant-time
+/// code. Also be aware that this lowering might *decrease* performance if
+/// `condition` is well-predictable. It is advisable to perform benchmarks to
+/// tell if this function is useful.
+///
+/// # Examples
+///
+/// Distribute values evenly between two buckets:
+/// ```
+/// #![feature(select_unpredictable)]
+///
+/// use std::hash::BuildHasher;
+/// use std::hint;
+///
+/// fn append<H: BuildHasher>(hasher: &H, v: i32, bucket_one: &mut Vec<i32>, bucket_two: &mut Vec<i32>) {
+/// let hash = hasher.hash_one(&v);
+/// let bucket = hint::select_unpredictable(hash % 2 == 0, bucket_one, bucket_two);
+/// bucket.push(v);
+/// }
+/// # let hasher = std::collections::hash_map::RandomState::new();
+/// # let mut bucket_one = Vec::new();
+/// # let mut bucket_two = Vec::new();
+/// # append(&hasher, 42, &mut bucket_one, &mut bucket_two);
+/// # assert_eq!(bucket_one.len() + bucket_two.len(), 1);
+/// ```
+#[inline(always)]
+#[unstable(feature = "select_unpredictable", issue = "133962")]
+pub fn select_unpredictable<T>(condition: bool, true_val: T, false_val: T) -> T {
+ // FIXME(https://github.com/rust-lang/unsafe-code-guidelines/issues/245):
+ // Change this to use ManuallyDrop instead.
+ let mut true_val = MaybeUninit::new(true_val);
+ let mut false_val = MaybeUninit::new(false_val);
+ // SAFETY: The value that is not selected is dropped, and the selected one
+ // is returned. This is necessary because the intrinsic doesn't drop the
+ // value that is not selected.
+ unsafe {
+ crate::intrinsics::select_unpredictable(!condition, &mut true_val, &mut false_val)
+ .assume_init_drop();
+ crate::intrinsics::select_unpredictable(condition, true_val, false_val).assume_init()
+ }
+}
diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs
index e99776a..a01efb2 100644
--- a/library/core/src/intrinsics/mod.rs
+++ b/library/core/src/intrinsics/mod.rs
@@ -1326,7 +1326,9 @@ pub const fn unlikely(b: bool) -> bool {
/// Therefore, implementations must not require the user to uphold
/// any safety invariants.
///
-/// The public form of this instrinsic is [`bool::select_unpredictable`].
+/// The public form of this instrinsic is [`core::hint::select_unpredictable`].
+/// However unlike the public form, the intrinsic will not drop the value that
+/// is not selected.
#[unstable(feature = "core_intrinsics", issue = "none")]
#[rustc_intrinsic]
#[rustc_nounwind]
@@ -2737,6 +2739,7 @@ pub const fn carrying_mul_add<T: ~const fallback::CarryingMulAdd<Unsigned = U>,
/// `x % y != 0` or `y == 0` or `x == T::MIN && y == -1`
///
/// This intrinsic does not have a stable counterpart.
+#[rustc_intrinsic_const_stable_indirect]
#[rustc_nounwind]
#[rustc_intrinsic]
pub const unsafe fn exact_div<T: Copy>(x: T, y: T) -> T;
@@ -3401,20 +3404,62 @@ pub const fn contract_checks() -> bool {
///
/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
/// returns false.
-#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
+///
+/// Note that this function is a no-op during constant evaluation.
+#[unstable(feature = "contracts_internals", issue = "128044")]
+// Calls to this function get inserted by an AST expansion pass, which uses the equivalent of
+// `#[allow_internal_unstable]` to allow using `contracts_internals` functions. Const-checking
+// doesn't honor `#[allow_internal_unstable]`, so for the const feature gate we use the user-facing
+// `contracts` feature rather than the perma-unstable `contracts_internals`
+#[rustc_const_unstable(feature = "contracts", issue = "128044")]
#[lang = "contract_check_requires"]
#[rustc_intrinsic]
-pub fn contract_check_requires<C: Fn() -> bool>(cond: C) {
- if contract_checks() && !cond() {
- // Emit no unwind panic in case this was a safety requirement.
- crate::panicking::panic_nounwind("failed requires check");
- }
+pub const fn contract_check_requires<C: Fn() -> bool + Copy>(cond: C) {
+ const_eval_select!(
+ @capture[C: Fn() -> bool + Copy] { cond: C } :
+ if const {
+ // Do nothing
+ } else {
+ if contract_checks() && !cond() {
+ // Emit no unwind panic in case this was a safety requirement.
+ crate::panicking::panic_nounwind("failed requires check");
+ }
+ }
+ )
}
/// Check if the post-condition `cond` has been met.
///
/// By default, if `contract_checks` is enabled, this will panic with no unwind if the condition
/// returns false.
+///
+/// Note that this function is a no-op during constant evaluation.
+#[cfg(not(bootstrap))]
+#[unstable(feature = "contracts_internals", issue = "128044")]
+// Similar to `contract_check_requires`, we need to use the user-facing
+// `contracts` feature rather than the perma-unstable `contracts_internals`.
+// Const-checking doesn't honor allow_internal_unstable logic used by contract expansion.
+#[rustc_const_unstable(feature = "contracts", issue = "128044")]
+#[lang = "contract_check_ensures"]
+#[rustc_intrinsic]
+pub const fn contract_check_ensures<C: Fn(&Ret) -> bool + Copy, Ret>(cond: C, ret: Ret) -> Ret {
+ const_eval_select!(
+ @capture[C: Fn(&Ret) -> bool + Copy, Ret] { cond: C, ret: Ret } -> Ret :
+ if const {
+ // Do nothing
+ ret
+ } else {
+ if contract_checks() && !cond(&ret) {
+ // Emit no unwind panic in case this was a safety requirement.
+ crate::panicking::panic_nounwind("failed ensures check");
+ }
+ ret
+ }
+ )
+}
+
+/// This is the old version of contract_check_ensures kept here for bootstrap only.
+#[cfg(bootstrap)]
#[unstable(feature = "contracts_internals", issue = "128044" /* compiler-team#759 */)]
#[rustc_intrinsic]
pub fn contract_check_ensures<'a, Ret, C: Fn(&'a Ret) -> bool>(ret: &'a Ret, cond: C) {
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs
index 9ac6ee8..6afe924 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd.rs
@@ -304,7 +304,7 @@ pub unsafe fn simd_extract_dyn<T, U>(x: T, idx: u32) -> U {
///
/// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`.
///
-/// `V` must be a vector of signed integers with the same length as `T` (but any element size).
+/// `V` must be a vector of integers with the same length as `T` (but any element size).
///
/// For each pointer in `ptr`, if the corresponding value in `mask` is `!0`, read the pointer.
/// Otherwise if the corresponding value in `mask` is `0`, return the corresponding value from
@@ -325,7 +325,7 @@ pub unsafe fn simd_extract_dyn<T, U>(x: T, idx: u32) -> U {
///
/// `U` must be a vector of pointers to the element type of `T`, with the same length as `T`.
///
-/// `V` must be a vector of signed integers with the same length as `T` (but any element size).
+/// `V` must be a vector of integers with the same length as `T` (but any element size).
///
/// For each pointer in `ptr`, if the corresponding value in `mask` is `!0`, write the
/// corresponding value in `val` to the pointer.
@@ -349,7 +349,7 @@ pub unsafe fn simd_extract_dyn<T, U>(x: T, idx: u32) -> U {
///
/// `U` must be a pointer to the element type of `T`
///
-/// `V` must be a vector of signed integers with the same length as `T` (but any element size).
+/// `V` must be a vector of integers with the same length as `T` (but any element size).
///
/// For each element, if the corresponding value in `mask` is `!0`, read the corresponding
/// pointer offset from `ptr`.
@@ -372,7 +372,7 @@ pub unsafe fn simd_extract_dyn<T, U>(x: T, idx: u32) -> U {
///
/// `U` must be a pointer to the element type of `T`
///
-/// `V` must be a vector of signed integers with the same length as `T` (but any element size).
+/// `V` must be a vector of integers with the same length as `T` (but any element size).
///
/// For each element, if the corresponding value in `mask` is `!0`, write the corresponding
/// value in `val` to the pointer offset from `ptr`.
@@ -556,7 +556,7 @@ pub unsafe fn simd_extract_dyn<T, U>(x: T, idx: u32) -> U {
///
/// `T` must be a vector.
///
-/// `M` must be a signed integer vector with the same length as `T` (but any element size).
+/// `M` must be an integer vector with the same length as `T` (but any element size).
///
/// For each element, if the corresponding value in `mask` is `!0`, select the element from
/// `if_true`. If the corresponding value in `mask` is `0`, select the element from
diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs
index aea6d64..72d7462 100644
--- a/library/core/src/iter/adapters/cloned.rs
+++ b/library/core/src/iter/adapters/cloned.rs
@@ -1,5 +1,6 @@
use core::num::NonZero;
+use crate::cmp::Ordering;
use crate::iter::adapters::zip::try_get_unchecked;
use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen, UncheckedIterator};
@@ -41,13 +42,31 @@ fn next(&mut self) -> Option<T> {
self.it.next().cloned()
}
+ #[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}
+ #[inline]
+ fn count(self) -> usize {
+ self.it.count()
+ }
+
+ fn last(self) -> Option<T> {
+ self.it.last().cloned()
+ }
+
+ #[inline]
+ fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+ self.it.advance_by(n)
+ }
+
+ fn nth(&mut self, n: usize) -> Option<T> {
+ self.it.nth(n).cloned()
+ }
+
fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
where
- Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
@@ -61,6 +80,58 @@ fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
self.it.map(T::clone).fold(init, f)
}
+ fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
+ where
+ P: FnMut(&Self::Item) -> bool,
+ {
+ self.it.find(move |x| predicate(&x)).cloned()
+ }
+
+ fn max_by<F>(self, mut compare: F) -> Option<Self::Item>
+ where
+ F: FnMut(&Self::Item, &Self::Item) -> Ordering,
+ {
+ self.it.max_by(move |&x, &y| compare(x, y)).cloned()
+ }
+
+ fn min_by<F>(self, mut compare: F) -> Option<Self::Item>
+ where
+ F: FnMut(&Self::Item, &Self::Item) -> Ordering,
+ {
+ self.it.min_by(move |&x, &y| compare(x, y)).cloned()
+ }
+
+ fn cmp<O>(self, other: O) -> Ordering
+ where
+ O: IntoIterator<Item = Self::Item>,
+ Self::Item: Ord,
+ {
+ self.it.cmp_by(other, |x, y| x.cmp(&y))
+ }
+
+ fn partial_cmp<O>(self, other: O) -> Option<Ordering>
+ where
+ O: IntoIterator,
+ Self::Item: PartialOrd<O::Item>,
+ {
+ self.it.partial_cmp_by(other, |x, y| x.partial_cmp(&y))
+ }
+
+ fn eq<O>(self, other: O) -> bool
+ where
+ O: IntoIterator,
+ Self::Item: PartialEq<O::Item>,
+ {
+ self.it.eq_by(other, |x, y| x == &y)
+ }
+
+ fn is_sorted_by<F>(self, mut compare: F) -> bool
+ where
+ F: FnMut(&Self::Item, &Self::Item) -> bool,
+ {
+ self.it.is_sorted_by(move |&x, &y| compare(x, y))
+ }
+
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
where
Self: TrustedRandomAccessNoCoerce,
@@ -81,9 +152,13 @@ fn next_back(&mut self) -> Option<T> {
self.it.next_back().cloned()
}
+ #[inline]
+ fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+ self.it.advance_back_by(n)
+ }
+
fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
where
- Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
@@ -96,6 +171,13 @@ fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
{
self.it.map(T::clone).rfold(init, f)
}
+
+ fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item>
+ where
+ P: FnMut(&Self::Item) -> bool,
+ {
+ self.it.rfind(move |x| predicate(&x)).cloned()
+ }
}
#[stable(feature = "iter_cloned", since = "1.1.0")]
@@ -104,10 +186,12 @@ impl<'a, I, T: 'a> ExactSizeIterator for Cloned<I>
I: ExactSizeIterator<Item = &'a T>,
T: Clone,
{
+ #[inline]
fn len(&self) -> usize {
self.it.len()
}
+ #[inline]
fn is_empty(&self) -> bool {
self.it.is_empty()
}
diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs
index 23e4e25..73913aa 100644
--- a/library/core/src/iter/adapters/copied.rs
+++ b/library/core/src/iter/adapters/copied.rs
@@ -1,3 +1,4 @@
+use crate::cmp::Ordering;
use crate::iter::adapters::zip::try_get_unchecked;
use crate::iter::adapters::{SourceIter, TrustedRandomAccess, TrustedRandomAccessNoCoerce};
use crate::iter::{FusedIterator, InPlaceIterable, TrustedLen};
@@ -48,20 +49,35 @@ fn next(&mut self) -> Option<T> {
fn next_chunk<const N: usize>(
&mut self,
- ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>>
- where
- Self: Sized,
- {
+ ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>> {
<I as SpecNextChunk<'_, N, T>>::spec_next_chunk(&mut self.it)
}
+ #[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.it.size_hint()
}
+ #[inline]
+ fn count(self) -> usize {
+ self.it.count()
+ }
+
+ fn last(self) -> Option<T> {
+ self.it.last().copied()
+ }
+
+ #[inline]
+ fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+ self.it.advance_by(n)
+ }
+
+ fn nth(&mut self, n: usize) -> Option<T> {
+ self.it.nth(n).copied()
+ }
+
fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R
where
- Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
@@ -75,21 +91,56 @@ fn fold<Acc, F>(self, init: Acc, f: F) -> Acc
self.it.fold(init, copy_fold(f))
}
- fn nth(&mut self, n: usize) -> Option<T> {
- self.it.nth(n).copied()
+ fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
+ where
+ P: FnMut(&Self::Item) -> bool,
+ {
+ self.it.find(move |x| predicate(&x)).copied()
}
- fn last(self) -> Option<T> {
- self.it.last().copied()
+ fn max_by<F>(self, mut compare: F) -> Option<Self::Item>
+ where
+ F: FnMut(&Self::Item, &Self::Item) -> Ordering,
+ {
+ self.it.max_by(move |&x, &y| compare(x, y)).copied()
}
- fn count(self) -> usize {
- self.it.count()
+ fn min_by<F>(self, mut compare: F) -> Option<Self::Item>
+ where
+ F: FnMut(&Self::Item, &Self::Item) -> Ordering,
+ {
+ self.it.min_by(move |&x, &y| compare(x, y)).copied()
}
- #[inline]
- fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
- self.it.advance_by(n)
+ fn cmp<O>(self, other: O) -> Ordering
+ where
+ O: IntoIterator<Item = Self::Item>,
+ Self::Item: Ord,
+ {
+ self.it.cmp_by(other, |x, y| x.cmp(&y))
+ }
+
+ fn partial_cmp<O>(self, other: O) -> Option<Ordering>
+ where
+ O: IntoIterator,
+ Self::Item: PartialOrd<O::Item>,
+ {
+ self.it.partial_cmp_by(other, |x, y| x.partial_cmp(&y))
+ }
+
+ fn eq<O>(self, other: O) -> bool
+ where
+ O: IntoIterator,
+ Self::Item: PartialEq<O::Item>,
+ {
+ self.it.eq_by(other, |x, y| x == &y)
+ }
+
+ fn is_sorted_by<F>(self, mut compare: F) -> bool
+ where
+ F: FnMut(&Self::Item, &Self::Item) -> bool,
+ {
+ self.it.is_sorted_by(move |&x, &y| compare(x, y))
}
unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> T
@@ -112,9 +163,13 @@ fn next_back(&mut self) -> Option<T> {
self.it.next_back().copied()
}
+ #[inline]
+ fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
+ self.it.advance_back_by(n)
+ }
+
fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R
where
- Self: Sized,
F: FnMut(B, Self::Item) -> R,
R: Try<Output = B>,
{
@@ -128,9 +183,11 @@ fn rfold<Acc, F>(self, init: Acc, f: F) -> Acc
self.it.rfold(init, copy_fold(f))
}
- #[inline]
- fn advance_back_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
- self.it.advance_back_by(n)
+ fn rfind<P>(&mut self, mut predicate: P) -> Option<Self::Item>
+ where
+ P: FnMut(&Self::Item) -> bool,
+ {
+ self.it.rfind(move |x| predicate(&x)).copied()
}
}
@@ -140,10 +197,12 @@ impl<'a, I, T: 'a> ExactSizeIterator for Copied<I>
I: ExactSizeIterator<Item = &'a T>,
T: Copy,
{
+ #[inline]
fn len(&self) -> usize {
self.it.len()
}
+ #[inline]
fn is_empty(&self) -> bool {
self.it.is_empty()
}
diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs
index bd093e2..f7b9f0b 100644
--- a/library/core/src/iter/adapters/enumerate.rs
+++ b/library/core/src/iter/adapters/enumerate.rs
@@ -23,6 +23,39 @@ impl<I> Enumerate<I> {
pub(in crate::iter) fn new(iter: I) -> Enumerate<I> {
Enumerate { iter, count: 0 }
}
+
+ /// Retrieve the current position of the iterator.
+ ///
+ /// If the iterator has not advanced, the position returned will be 0.
+ ///
+ /// The position may also exceed the bounds of the iterator to allow for calculating
+ /// the displacement of the iterator from following calls to [`Iterator::next`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(next_index)]
+ ///
+ /// let arr = ['a', 'b'];
+ ///
+ /// let mut iter = arr.iter().enumerate();
+ ///
+ /// assert_eq!(iter.next_index(), 0);
+ /// assert_eq!(iter.next(), Some((0, &'a')));
+ ///
+ /// assert_eq!(iter.next_index(), 1);
+ /// assert_eq!(iter.next_index(), 1);
+ /// assert_eq!(iter.next(), Some((1, &'b')));
+ ///
+ /// assert_eq!(iter.next_index(), 2);
+ /// assert_eq!(iter.next(), None);
+ /// assert_eq!(iter.next_index(), 2);
+ /// ```
+ #[inline]
+ #[unstable(feature = "next_index", issue = "130711")]
+ pub fn next_index(&self) -> usize {
+ self.count
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index dc06aa4..9625475 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -101,7 +101,6 @@
#![feature(bstr)]
#![feature(bstr_internals)]
#![feature(cfg_match)]
-#![feature(closure_track_caller)]
#![feature(const_carrying_mul_add)]
#![feature(const_eval_select)]
#![feature(core_intrinsics)]
@@ -127,6 +126,7 @@
#![feature(ub_checks)]
#![feature(unchecked_neg)]
#![feature(unchecked_shifts)]
+#![feature(unsafe_pinned)]
#![feature(utf16_extra)]
#![feature(variant_count)]
// tidy-alphabetical-end
@@ -169,7 +169,6 @@
#![feature(negative_impls)]
#![feature(never_type)]
#![feature(no_core)]
-#![feature(no_sanitize)]
#![feature(optimize_attribute)]
#![feature(prelude_import)]
#![feature(repr_simd)]
diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs
index 6801131..9dc20be 100644
--- a/library/core/src/marker.rs
+++ b/library/core/src/marker.rs
@@ -17,6 +17,7 @@
use crate::cmp;
use crate::fmt::Debug;
use crate::hash::{Hash, Hasher};
+use crate::pin::UnsafePinned;
/// Implements a given marker trait for multiple types at the same time.
///
@@ -878,6 +879,23 @@ impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
{T: ?Sized} &mut T,
}
+/// Used to determine whether a type contains any `UnsafePinned` (or `PhantomPinned`) internally,
+/// but not through an indirection. This affects, for example, whether we emit `noalias` metadata
+/// for `&mut T` or not.
+///
+/// This is part of [RFC 3467](https://rust-lang.github.io/rfcs/3467-unsafe-pinned.html), and is
+/// tracked by [#125735](https://github.com/rust-lang/rust/issues/125735).
+#[cfg_attr(not(bootstrap), lang = "unsafe_unpin")]
+#[cfg_attr(bootstrap, allow(dead_code))]
+pub(crate) unsafe auto trait UnsafeUnpin {}
+
+impl<T: ?Sized> !UnsafeUnpin for UnsafePinned<T> {}
+unsafe impl<T: ?Sized> UnsafeUnpin for PhantomData<T> {}
+unsafe impl<T: ?Sized> UnsafeUnpin for *const T {}
+unsafe impl<T: ?Sized> UnsafeUnpin for *mut T {}
+unsafe impl<T: ?Sized> UnsafeUnpin for &T {}
+unsafe impl<T: ?Sized> UnsafeUnpin for &mut T {}
+
/// Types that do not require any pinning guarantees.
///
/// For information on what "pinning" is, see the [`pin` module] documentation.
@@ -953,6 +971,11 @@ impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
/// A marker type which does not implement `Unpin`.
///
/// If a type contains a `PhantomPinned`, it will not implement `Unpin` by default.
+//
+// FIXME(unsafe_pinned): This is *not* a stable guarantee we want to make, at least not yet.
+// Note that for backwards compatibility with the new [`UnsafePinned`] wrapper type, placing this
+// marker in your struct acts as if you wrapped the entire struct in an `UnsafePinned`. This type
+// will likely eventually be deprecated, and all new code should be using `UnsafePinned` instead.
#[stable(feature = "pin", since = "1.33.0")]
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct PhantomPinned;
@@ -960,6 +983,12 @@ impl<T: ?Sized> !Freeze for UnsafeCell<T> {}
#[stable(feature = "pin", since = "1.33.0")]
impl !Unpin for PhantomPinned {}
+// This is a small hack to allow existing code which uses PhantomPinned to opt-out of noalias to
+// continue working. Ideally PhantomPinned could just wrap an `UnsafePinned<()>` to get the same
+// effect, but we can't add a new field to an already stable unit struct -- that would be a breaking
+// change.
+impl !UnsafeUnpin for PhantomPinned {}
+
marker_impls! {
#[stable(feature = "pin", since = "1.33.0")]
Unpin for
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 08c34e8..2ee2596 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -145,6 +145,9 @@ impl f128 {
pub const RADIX: u32 = 2;
/// Number of significant digits in base 2.
+ ///
+ /// Note that the size of the mantissa in the bitwise representation is one
+ /// smaller than this since the leading 1 is not stored explicitly.
#[unstable(feature = "f128", issue = "116909")]
pub const MANTISSA_DIGITS: u32 = 113;
@@ -224,14 +227,16 @@ impl f128 {
/// Not a Number (NaN).
///
- /// Note that IEEE 754 doesn't define just a single NaN value;
- /// a plethora of bit patterns are considered to be NaN.
- /// Furthermore, the standard makes a difference
- /// between a "signaling" and a "quiet" NaN,
- /// and allows inspecting its "payload" (the unspecified bits in the bit pattern).
- /// This constant isn't guaranteed to equal to any specific NaN bitpattern,
- /// and the stability of its representation over Rust versions
- /// and target platforms isn't guaranteed.
+ /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are
+ /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and
+ /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern)
+ /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more
+ /// info.
+ ///
+ /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions
+ /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is
+ /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary.
+ /// The concrete bit pattern may change across Rust versions and target platforms.
#[allow(clippy::eq_op)]
#[rustc_diagnostic_item = "f128_nan"]
#[unstable(feature = "f128", issue = "116909")]
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index a33e5f5..69882d1 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -140,6 +140,9 @@ impl f16 {
pub const RADIX: u32 = 2;
/// Number of significant digits in base 2.
+ ///
+ /// Note that the size of the mantissa in the bitwise representation is one
+ /// smaller than this since the leading 1 is not stored explicitly.
#[unstable(feature = "f16", issue = "116909")]
pub const MANTISSA_DIGITS: u32 = 11;
@@ -219,14 +222,16 @@ impl f16 {
/// Not a Number (NaN).
///
- /// Note that IEEE 754 doesn't define just a single NaN value;
- /// a plethora of bit patterns are considered to be NaN.
- /// Furthermore, the standard makes a difference
- /// between a "signaling" and a "quiet" NaN,
- /// and allows inspecting its "payload" (the unspecified bits in the bit pattern).
- /// This constant isn't guaranteed to equal to any specific NaN bitpattern,
- /// and the stability of its representation over Rust versions
- /// and target platforms isn't guaranteed.
+ /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are
+ /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and
+ /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern)
+ /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more
+ /// info.
+ ///
+ /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions
+ /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is
+ /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary.
+ /// The concrete bit pattern may change across Rust versions and target platforms.
#[allow(clippy::eq_op)]
#[rustc_diagnostic_item = "f16_nan"]
#[unstable(feature = "f16", issue = "116909")]
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index e473fac0..7e056a6 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -390,6 +390,9 @@ impl f32 {
pub const RADIX: u32 = 2;
/// Number of significant digits in base 2.
+ ///
+ /// Note that the size of the mantissa in the bitwise representation is one
+ /// smaller than this since the leading 1 is not stored explicitly.
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
pub const MANTISSA_DIGITS: u32 = 24;
@@ -470,14 +473,16 @@ impl f32 {
/// Not a Number (NaN).
///
- /// Note that IEEE 754 doesn't define just a single NaN value;
- /// a plethora of bit patterns are considered to be NaN.
- /// Furthermore, the standard makes a difference
- /// between a "signaling" and a "quiet" NaN,
- /// and allows inspecting its "payload" (the unspecified bits in the bit pattern).
- /// This constant isn't guaranteed to equal to any specific NaN bitpattern,
- /// and the stability of its representation over Rust versions
- /// and target platforms isn't guaranteed.
+ /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are
+ /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and
+ /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern)
+ /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more
+ /// info.
+ ///
+ /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions
+ /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is
+ /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary.
+ /// The concrete bit pattern may change across Rust versions and target platforms.
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
#[rustc_diagnostic_item = "f32_nan"]
#[allow(clippy::eq_op)]
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 6522a80..b9ebbb1 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -390,6 +390,9 @@ impl f64 {
pub const RADIX: u32 = 2;
/// Number of significant digits in base 2.
+ ///
+ /// Note that the size of the mantissa in the bitwise representation is one
+ /// smaller than this since the leading 1 is not stored explicitly.
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
pub const MANTISSA_DIGITS: u32 = 53;
/// Approximate number of significant digits in base 10.
@@ -469,14 +472,16 @@ impl f64 {
/// Not a Number (NaN).
///
- /// Note that IEEE 754 doesn't define just a single NaN value;
- /// a plethora of bit patterns are considered to be NaN.
- /// Furthermore, the standard makes a difference
- /// between a "signaling" and a "quiet" NaN,
- /// and allows inspecting its "payload" (the unspecified bits in the bit pattern).
- /// This constant isn't guaranteed to equal to any specific NaN bitpattern,
- /// and the stability of its representation over Rust versions
- /// and target platforms isn't guaranteed.
+ /// Note that IEEE 754 doesn't define just a single NaN value; a plethora of bit patterns are
+ /// considered to be NaN. Furthermore, the standard makes a difference between a "signaling" and
+ /// a "quiet" NaN, and allows inspecting its "payload" (the unspecified bits in the bit pattern)
+ /// and its sign. See the [specification of NaN bit patterns](f32#nan-bit-patterns) for more
+ /// info.
+ ///
+ /// This constant is guaranteed to be a quiet NaN (on targets that follow the Rust assumptions
+ /// that the quiet/signaling bit being set to 1 indicates a quiet NaN). Beyond that, nothing is
+ /// guaranteed about the specific bit pattern chosen here: both payload and sign are arbitrary.
+ /// The concrete bit pattern may change across Rust versions and target platforms.
#[rustc_diagnostic_item = "f64_nan"]
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
#[allow(clippy::eq_op)]
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 1b2acdc..3678bb0 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -3343,7 +3343,7 @@ pub const fn is_multiple_of(self, rhs: Self) -> bool {
}
}
- /// Returns `true` if and only if `self == 2^k` for some `k`.
+ /// Returns `true` if and only if `self == 2^k` for some unsigned integer `k`.
///
/// # Examples
///
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 2ef1bbf..9e6acf0 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -931,6 +931,11 @@
};
use crate::{cmp, fmt};
+mod unsafe_pinned;
+
+#[unstable(feature = "unsafe_pinned", issue = "125735")]
+pub use self::unsafe_pinned::UnsafePinned;
+
/// A pointer which pins its pointee in place.
///
/// [`Pin`] is a wrapper around some kind of pointer `Ptr` which makes that pointer "pin" its
@@ -1087,24 +1092,15 @@
#[rustc_pub_transparent]
#[derive(Copy, Clone)]
pub struct Pin<Ptr> {
- // FIXME(#93176): this field is made `#[unstable] #[doc(hidden)] pub` to:
- // - deter downstream users from accessing it (which would be unsound!),
- // - let the `pin!` macro access it (such a macro requires using struct
- // literal syntax in order to benefit from lifetime extension).
- //
- // However, if the `Deref` impl exposes a field with the same name as this
- // field, then the two will collide, resulting in a confusing error when the
- // user attempts to access the field through a `Pin<Ptr>`. Therefore, the
- // name `__pointer` is designed to be unlikely to collide with any other
- // field. Long-term, macro hygiene is expected to offer a more robust
- // alternative, alongside `unsafe` fields.
- #[unstable(feature = "unsafe_pin_internals", issue = "none")]
- #[doc(hidden)]
- pub __pointer: Ptr,
+ /// Only public for bootstrap.
+ #[cfg(bootstrap)]
+ pub pointer: Ptr,
+ #[cfg(not(bootstrap))]
+ pointer: Ptr,
}
// The following implementations aren't derived in order to avoid soundness
-// issues. `&self.__pointer` should not be accessible to untrusted trait
+// issues. `&self.pointer` should not be accessible to untrusted trait
// implementations.
//
// See <https://internals.rust-lang.org/t/unsoundness-in-pin/11311/73> for more details.
@@ -1218,7 +1214,7 @@ pub const fn new(pointer: Ptr) -> Pin<Ptr> {
#[rustc_const_stable(feature = "const_pin", since = "1.84.0")]
#[stable(feature = "pin_into_inner", since = "1.39.0")]
pub const fn into_inner(pin: Pin<Ptr>) -> Ptr {
- pin.__pointer
+ pin.pointer
}
}
@@ -1355,7 +1351,7 @@ impl<Ptr: Deref> Pin<Ptr> {
#[rustc_const_stable(feature = "const_pin", since = "1.84.0")]
#[stable(feature = "pin", since = "1.33.0")]
pub const unsafe fn new_unchecked(pointer: Ptr) -> Pin<Ptr> {
- Pin { __pointer: pointer }
+ Pin { pointer }
}
/// Gets a shared reference to the pinned value this [`Pin`] points to.
@@ -1369,7 +1365,7 @@ impl<Ptr: Deref> Pin<Ptr> {
#[inline(always)]
pub fn as_ref(&self) -> Pin<&Ptr::Target> {
// SAFETY: see documentation on this function
- unsafe { Pin::new_unchecked(&*self.__pointer) }
+ unsafe { Pin::new_unchecked(&*self.pointer) }
}
}
@@ -1413,7 +1409,7 @@ impl<Ptr: DerefMut> Pin<Ptr> {
#[inline(always)]
pub fn as_mut(&mut self) -> Pin<&mut Ptr::Target> {
// SAFETY: see documentation on this function
- unsafe { Pin::new_unchecked(&mut *self.__pointer) }
+ unsafe { Pin::new_unchecked(&mut *self.pointer) }
}
/// Gets `Pin<&mut T>` to the underlying pinned value from this nested `Pin`-pointer.
@@ -1480,7 +1476,7 @@ pub fn set(&mut self, value: Ptr::Target)
where
Ptr::Target: Sized,
{
- *(self.__pointer) = value;
+ *(self.pointer) = value;
}
}
@@ -1508,7 +1504,7 @@ impl<Ptr: Deref> Pin<Ptr> {
#[rustc_const_stable(feature = "const_pin", since = "1.84.0")]
#[stable(feature = "pin_into_inner", since = "1.39.0")]
pub const unsafe fn into_inner_unchecked(pin: Pin<Ptr>) -> Ptr {
- pin.__pointer
+ pin.pointer
}
}
@@ -1534,7 +1530,7 @@ pub unsafe fn map_unchecked<U, F>(self, func: F) -> Pin<&'a U>
U: ?Sized,
F: FnOnce(&T) -> &U,
{
- let pointer = &*self.__pointer;
+ let pointer = &*self.pointer;
let new_pointer = func(pointer);
// SAFETY: the safety contract for `new_unchecked` must be
@@ -1564,7 +1560,7 @@ pub unsafe fn map_unchecked<U, F>(self, func: F) -> Pin<&'a U>
#[rustc_const_stable(feature = "const_pin", since = "1.84.0")]
#[stable(feature = "pin", since = "1.33.0")]
pub const fn get_ref(self) -> &'a T {
- self.__pointer
+ self.pointer
}
}
@@ -1575,7 +1571,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> {
#[rustc_const_stable(feature = "const_pin", since = "1.84.0")]
#[stable(feature = "pin", since = "1.33.0")]
pub const fn into_ref(self) -> Pin<&'a T> {
- Pin { __pointer: self.__pointer }
+ Pin { pointer: self.pointer }
}
/// Gets a mutable reference to the data inside of this `Pin`.
@@ -1595,7 +1591,7 @@ pub const fn get_mut(self) -> &'a mut T
where
T: Unpin,
{
- self.__pointer
+ self.pointer
}
/// Gets a mutable reference to the data inside of this `Pin`.
@@ -1613,7 +1609,7 @@ pub const fn get_mut(self) -> &'a mut T
#[stable(feature = "pin", since = "1.33.0")]
#[rustc_const_stable(feature = "const_pin", since = "1.84.0")]
pub const unsafe fn get_unchecked_mut(self) -> &'a mut T {
- self.__pointer
+ self.pointer
}
/// Constructs a new pin by mapping the interior value.
@@ -1700,21 +1696,21 @@ impl<Ptr: LegacyReceiver> LegacyReceiver for Pin<Ptr> {}
#[stable(feature = "pin", since = "1.33.0")]
impl<Ptr: fmt::Debug> fmt::Debug for Pin<Ptr> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Debug::fmt(&self.__pointer, f)
+ fmt::Debug::fmt(&self.pointer, f)
}
}
#[stable(feature = "pin", since = "1.33.0")]
impl<Ptr: fmt::Display> fmt::Display for Pin<Ptr> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Display::fmt(&self.__pointer, f)
+ fmt::Display::fmt(&self.pointer, f)
}
}
#[stable(feature = "pin", since = "1.33.0")]
impl<Ptr: fmt::Pointer> fmt::Pointer for Pin<Ptr> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Pointer::fmt(&self.__pointer, f)
+ fmt::Pointer::fmt(&self.pointer, f)
}
}
@@ -1940,80 +1936,22 @@ unsafe impl<T: ?Sized> PinCoerceUnsized for *mut T {}
/// constructor.
///
/// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin
+#[cfg(not(bootstrap))]
#[stable(feature = "pin_macro", since = "1.68.0")]
#[rustc_macro_transparency = "semitransparent"]
-#[allow_internal_unstable(unsafe_pin_internals)]
-#[rustc_macro_edition_2021]
+#[allow_internal_unstable(super_let)]
pub macro pin($value:expr $(,)?) {
- // This is `Pin::new_unchecked(&mut { $value })`, so, for starters, let's
- // review such a hypothetical macro (that any user-code could define):
- //
- // ```rust
- // macro_rules! pin {( $value:expr ) => (
- // match &mut { $value } { at_value => unsafe { // Do not wrap `$value` in an `unsafe` block.
- // $crate::pin::Pin::<&mut _>::new_unchecked(at_value)
- // }}
- // )}
- // ```
- //
- // Safety:
- // - `type P = &mut _`. There are thus no pathological `Deref{,Mut}` impls
- // that would break `Pin`'s invariants.
- // - `{ $value }` is braced, making it a _block expression_, thus **moving**
- // the given `$value`, and making it _become an **anonymous** temporary_.
- // By virtue of being anonymous, it can no longer be accessed, thus
- // preventing any attempts to `mem::replace` it or `mem::forget` it, _etc._
- //
- // This gives us a `pin!` definition that is sound, and which works, but only
- // in certain scenarios:
- // - If the `pin!(value)` expression is _directly_ fed to a function call:
- // `let poll = pin!(fut).poll(cx);`
- // - If the `pin!(value)` expression is part of a scrutinee:
- // ```rust
- // match pin!(fut) { pinned_fut => {
- // pinned_fut.as_mut().poll(...);
- // pinned_fut.as_mut().poll(...);
- // }} // <- `fut` is dropped here.
- // ```
- // Alas, it doesn't work for the more straight-forward use-case: `let` bindings.
- // ```rust
- // let pinned_fut = pin!(fut); // <- temporary value is freed at the end of this statement
- // pinned_fut.poll(...) // error[E0716]: temporary value dropped while borrowed
- // // note: consider using a `let` binding to create a longer lived value
- // ```
- // - Issues such as this one are the ones motivating https://github.com/rust-lang/rfcs/pull/66
- //
- // This makes such a macro incredibly unergonomic in practice, and the reason most macros
- // out there had to take the path of being a statement/binding macro (_e.g._, `pin!(future);`)
- // instead of featuring the more intuitive ergonomics of an expression macro.
- //
- // Luckily, there is a way to avoid the problem. Indeed, the problem stems from the fact that a
- // temporary is dropped at the end of its enclosing statement when it is part of the parameters
- // given to function call, which has precisely been the case with our `Pin::new_unchecked()`!
- // For instance,
- // ```rust
- // let p = Pin::new_unchecked(&mut <temporary>);
- // ```
- // becomes:
- // ```rust
- // let p = { let mut anon = <temporary>; &mut anon };
- // ```
- //
- // However, when using a literal braced struct to construct the value, references to temporaries
- // can then be taken. This makes Rust change the lifespan of such temporaries so that they are,
- // instead, dropped _at the end of the enscoping block_.
- // For instance,
- // ```rust
- // let p = Pin { __pointer: &mut <temporary> };
- // ```
- // becomes:
- // ```rust
- // let mut anon = <temporary>;
- // let p = Pin { __pointer: &mut anon };
- // ```
- // which is *exactly* what we want.
- //
- // See https://doc.rust-lang.org/1.58.1/reference/destructors.html#temporary-lifetime-extension
- // for more info.
- $crate::pin::Pin::<&mut _> { __pointer: &mut { $value } }
+ {
+ super let mut pinned = $value;
+ // SAFETY: The value is pinned: it is the local above which cannot be named outside this macro.
+ unsafe { $crate::pin::Pin::new_unchecked(&mut pinned) }
+ }
+}
+
+/// Only for bootstrap.
+#[cfg(bootstrap)]
+#[stable(feature = "pin_macro", since = "1.68.0")]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro pin($value:expr $(,)?) {
+ $crate::pin::Pin::<&mut _> { pointer: &mut { $value } }
}
diff --git a/library/core/src/pin/unsafe_pinned.rs b/library/core/src/pin/unsafe_pinned.rs
new file mode 100644
index 0000000..5fb628c
--- /dev/null
+++ b/library/core/src/pin/unsafe_pinned.rs
@@ -0,0 +1,197 @@
+use crate::marker::{PointerLike, Unpin};
+use crate::ops::{CoerceUnsized, DispatchFromDyn};
+use crate::pin::Pin;
+use crate::{fmt, ptr};
+
+/// This type provides a way to opt-out of typical aliasing rules;
+/// specifically, `&mut UnsafePinned<T>` is not guaranteed to be a unique pointer.
+///
+/// However, even if you define your type like `pub struct Wrapper(UnsafePinned<...>)`, it is still
+/// very risky to have an `&mut Wrapper` that aliases anything else. Many functions that work
+/// generically on `&mut T` assume that the memory that stores `T` is uniquely owned (such as
+/// `mem::swap`). In other words, while having aliasing with `&mut Wrapper` is not immediate
+/// Undefined Behavior, it is still unsound to expose such a mutable reference to code you do not
+/// control! Techniques such as pinning via [`Pin`] are needed to ensure soundness.
+///
+/// Similar to [`UnsafeCell`](crate::cell::UnsafeCell), `UnsafePinned` will not usually show up in
+/// the public API of a library. It is an internal implementation detail of libraries that need to
+/// support aliasing mutable references.
+///
+/// Further note that this does *not* lift the requirement that shared references must be read-only!
+/// Use `UnsafeCell` for that.
+///
+/// This type blocks niches the same way `UnsafeCell` does.
+#[cfg_attr(not(bootstrap), lang = "unsafe_pinned")]
+#[repr(transparent)]
+#[unstable(feature = "unsafe_pinned", issue = "125735")]
+pub struct UnsafePinned<T: ?Sized> {
+ value: T,
+}
+
+/// When this type is used, that almost certainly means safe APIs need to use pinning to avoid the
+/// aliases from becoming invalidated. Therefore let's mark this as `!Unpin`. You can always opt
+/// back in to `Unpin` with an `impl` block, provided your API is still sound while unpinned.
+#[unstable(feature = "unsafe_pinned", issue = "125735")]
+impl<T: ?Sized> !Unpin for UnsafePinned<T> {}
+
+/// The type is `Copy` when `T` is to avoid people assuming that `Copy` implies there is no
+/// `UnsafePinned` anywhere. (This is an issue with `UnsafeCell`: people use `Copy` bounds to mean
+/// `Freeze`.) Given that there is no `unsafe impl Copy for ...`, this is also the option that
+/// leaves the user more choices (as they can always wrap this in a `!Copy` type).
+// FIXME(unsafe_pinned): this may be unsound or a footgun?
+#[unstable(feature = "unsafe_pinned", issue = "125735")]
+impl<T: Copy> Copy for UnsafePinned<T> {}
+
+#[unstable(feature = "unsafe_pinned", issue = "125735")]
+impl<T: Copy> Clone for UnsafePinned<T> {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+// `Send` and `Sync` are inherited from `T`. This is similar to `SyncUnsafeCell`, since
+// we eventually concluded that `UnsafeCell` implicitly making things `!Sync` is sometimes
+// unergonomic. A type that needs to be `!Send`/`!Sync` should really have an explicit
+// opt-out itself, e.g. via an `PhantomData<*mut T>` or (one day) via `impl !Send`/`impl !Sync`.
+
+impl<T> UnsafePinned<T> {
+ /// Constructs a new instance of `UnsafePinned` which will wrap the specified value.
+ ///
+ /// All access to the inner value through `&UnsafePinned<T>` or `&mut UnsafePinned<T>` or
+ /// `Pin<&mut UnsafePinned<T>>` requires `unsafe` code.
+ #[inline(always)]
+ #[must_use]
+ #[unstable(feature = "unsafe_pinned", issue = "125735")]
+ pub const fn new(value: T) -> Self {
+ UnsafePinned { value }
+ }
+
+ /// Unwraps the value, consuming this `UnsafePinned`.
+ #[inline(always)]
+ #[must_use]
+ #[unstable(feature = "unsafe_pinned", issue = "125735")]
+ #[rustc_allow_const_fn_unstable(const_precise_live_drops)]
+ pub const fn into_inner(self) -> T {
+ self.value
+ }
+}
+
+impl<T: ?Sized> UnsafePinned<T> {
+ /// Get read-write access to the contents of a pinned `UnsafePinned`.
+ #[inline(always)]
+ #[must_use]
+ #[unstable(feature = "unsafe_pinned", issue = "125735")]
+ pub const fn get_mut_pinned(self: Pin<&mut Self>) -> *mut T {
+ // SAFETY: we're not using `get_unchecked_mut` to unpin anything
+ unsafe { self.get_unchecked_mut() }.get_mut_unchecked()
+ }
+
+ /// Get read-write access to the contents of an `UnsafePinned`.
+ ///
+ /// You should usually be using `get_mut_pinned` instead to explicitly track the fact that this
+ /// memory is "pinned" due to there being aliases.
+ #[inline(always)]
+ #[must_use]
+ #[unstable(feature = "unsafe_pinned", issue = "125735")]
+ pub const fn get_mut_unchecked(&mut self) -> *mut T {
+ ptr::from_mut(self) as *mut T
+ }
+
+ /// Get read-only access to the contents of a shared `UnsafePinned`.
+ ///
+ /// Note that `&UnsafePinned<T>` is read-only if `&T` is read-only. This means that if there is
+ /// mutation of the `T`, future reads from the `*const T` returned here are UB! Use
+ /// [`UnsafeCell`] if you also need interior mutability.
+ ///
+ /// [`UnsafeCell`]: crate::cell::UnsafeCell
+ ///
+ /// ```rust,no_run
+ /// #![feature(unsafe_pinned)]
+ /// use std::pin::UnsafePinned;
+ ///
+ /// unsafe {
+ /// let mut x = UnsafePinned::new(0);
+ /// let ptr = x.get(); // read-only pointer, assumes immutability
+ /// x.get_mut_unchecked().write(1);
+ /// ptr.read(); // UB!
+ /// }
+ /// ```
+ #[inline(always)]
+ #[must_use]
+ #[unstable(feature = "unsafe_pinned", issue = "125735")]
+ pub const fn get(&self) -> *const T {
+ ptr::from_ref(self) as *const T
+ }
+
+ /// Gets an immutable pointer to the wrapped value.
+ ///
+ /// The difference from [`get`] is that this function accepts a raw pointer, which is useful to
+ /// avoid the creation of temporary references.
+ ///
+ /// [`get`]: UnsafePinned::get
+ #[inline(always)]
+ #[must_use]
+ #[unstable(feature = "unsafe_pinned", issue = "125735")]
+ pub const fn raw_get(this: *const Self) -> *const T {
+ this as *const T
+ }
+
+ /// Gets a mutable pointer to the wrapped value.
+ ///
+ /// The difference from [`get_mut_pinned`] and [`get_mut_unchecked`] is that this function
+ /// accepts a raw pointer, which is useful to avoid the creation of temporary references.
+ ///
+ /// [`get_mut_pinned`]: UnsafePinned::get_mut_pinned
+ /// [`get_mut_unchecked`]: UnsafePinned::get_mut_unchecked
+ #[inline(always)]
+ #[must_use]
+ #[unstable(feature = "unsafe_pinned", issue = "125735")]
+ pub const fn raw_get_mut(this: *mut Self) -> *mut T {
+ this as *mut T
+ }
+}
+
+#[unstable(feature = "unsafe_pinned", issue = "125735")]
+impl<T: Default> Default for UnsafePinned<T> {
+ /// Creates an `UnsafePinned`, with the `Default` value for T.
+ fn default() -> Self {
+ UnsafePinned::new(T::default())
+ }
+}
+
+#[unstable(feature = "unsafe_pinned", issue = "125735")]
+impl<T> From<T> for UnsafePinned<T> {
+ /// Creates a new `UnsafePinned<T>` containing the given value.
+ fn from(value: T) -> Self {
+ UnsafePinned::new(value)
+ }
+}
+
+#[unstable(feature = "unsafe_pinned", issue = "125735")]
+impl<T: ?Sized> fmt::Debug for UnsafePinned<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("UnsafePinned").finish_non_exhaustive()
+ }
+}
+
+#[unstable(feature = "coerce_unsized", issue = "18598")]
+// #[unstable(feature = "unsafe_pinned", issue = "125735")]
+impl<T: CoerceUnsized<U>, U> CoerceUnsized<UnsafePinned<U>> for UnsafePinned<T> {}
+
+// Allow types that wrap `UnsafePinned` to also implement `DispatchFromDyn`
+// and become dyn-compatible method receivers.
+// Note that currently `UnsafePinned` itself cannot be a method receiver
+// because it does not implement Deref.
+// In other words:
+// `self: UnsafePinned<&Self>` won't work
+// `self: UnsafePinned<Self>` becomes possible
+// FIXME(unsafe_pinned) this logic is copied from UnsafeCell, is it still sound?
+#[unstable(feature = "dispatch_from_dyn", issue = "none")]
+// #[unstable(feature = "unsafe_pinned", issue = "125735")]
+impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<UnsafePinned<U>> for UnsafePinned<T> {}
+
+#[unstable(feature = "pointer_like_trait", issue = "none")]
+// #[unstable(feature = "unsafe_pinned", issue = "125735")]
+impl<T: PointerLike> PointerLike for UnsafePinned<T> {}
+
+// FIXME(unsafe_pinned): impl PinCoerceUnsized for UnsafePinned<T>?
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 369bf18..17c4b48 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1307,10 +1307,12 @@ mod prim_f16 {}
// FIXME: Is there a better place to put this?
///
/// | `target_arch` | Extra payloads possible on this platform |
-/// |---------------|---------|
-/// | `x86`, `x86_64`, `arm`, `aarch64`, `riscv32`, `riscv64` | None |
+/// |---------------|------------------------------------------|
+// Sorted alphabetically
+/// | `aarch64`, `arm`, `arm64ec`, `loongarch64`, `powerpc` (except when `target_abi = "spe"`), `powerpc64`, `riscv32`, `riscv64`, `s390x`, `x86`, `x86_64` | None |
+/// | `nvptx64` | All payloads |
/// | `sparc`, `sparc64` | The all-one payload |
-/// | `wasm32`, `wasm64` | If all input NaNs are quiet with all-zero payload: None.<br> Otherwise: all possible payloads. |
+/// | `wasm32`, `wasm64` | If all input NaNs are quiet with all-zero payload: None.<br> Otherwise: all payloads. |
///
/// For targets not in this table, all payloads are possible.
///
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 0854e31..2d86995 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -1739,3 +1739,11 @@ fn ge(&self, other: &*const T) -> bool {
*self >= *other
}
}
+
+#[stable(feature = "raw_ptr_default", since = "CURRENT_RUSTC_VERSION")]
+impl<T: ?Sized + Thin> Default for *const T {
+ /// Returns the default value of [`null()`][crate::ptr::null].
+ fn default() -> Self {
+ crate::ptr::null()
+ }
+}
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 2357ba2..445c789 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -278,7 +278,7 @@
//! ### Using Strict Provenance
//!
//! Most code needs no changes to conform to strict provenance, as the only really concerning
-//! operation is casts from usize to a pointer. For code which *does* cast a `usize` to a pointer,
+//! operation is casts from `usize` to a pointer. For code which *does* cast a `usize` to a pointer,
//! the scope of the change depends on exactly what you're doing.
//!
//! In general, you just need to make sure that if you want to convert a `usize` address to a
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index e297749..df49eed 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -2156,3 +2156,11 @@ fn ge(&self, other: &*mut T) -> bool {
*self >= *other
}
}
+
+#[stable(feature = "raw_ptr_default", since = "CURRENT_RUSTC_VERSION")]
+impl<T: ?Sized + Thin> Default for *mut T {
+ /// Returns the default value of [`null_mut()`][crate::ptr::null_mut].
+ fn default() -> Self {
+ crate::ptr::null_mut()
+ }
+}
diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs
index da85f42..5ce72b4 100644
--- a/library/core/src/slice/cmp.rs
+++ b/library/core/src/slice/cmp.rs
@@ -5,6 +5,7 @@
use crate::cmp::{self, BytewiseEq, Ordering};
use crate::intrinsics::compare_bytes;
use crate::num::NonZero;
+use crate::ops::ControlFlow;
#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U> PartialEq<[U]> for [T]
@@ -31,12 +32,64 @@ fn cmp(&self, other: &[T]) -> Ordering {
}
}
+#[inline]
+fn as_underlying(x: ControlFlow<bool>) -> u8 {
+ // SAFETY: This will only compile if `bool` and `ControlFlow<bool>` have the same
+ // size (which isn't guaranteed but this is libcore). Because they have the same
+ // size, it's a niched implementation, which in one byte means there can't be
+ // any uninitialized memory. The callers then only check for `0` or `1` from this,
+ // which must necessarily match the `Break` variant, and we're fine no matter
+ // what ends up getting picked as the value representing `Continue(())`.
+ unsafe { crate::mem::transmute(x) }
+}
+
/// Implements comparison of slices [lexicographically](Ord#lexicographical-comparison).
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PartialOrd> PartialOrd for [T] {
+ #[inline]
fn partial_cmp(&self, other: &[T]) -> Option<Ordering> {
SlicePartialOrd::partial_compare(self, other)
}
+ #[inline]
+ fn lt(&self, other: &Self) -> bool {
+ // This is certainly not the obvious way to implement these methods.
+ // Unfortunately, using anything that looks at the discriminant means that
+ // LLVM sees a check for `2` (aka `ControlFlow<bool>::Continue(())`) and
+ // gets very distracted by that, ending up generating extraneous code.
+ // This should be changed to something simpler once either LLVM is smarter,
+ // see <https://github.com/llvm/llvm-project/issues/132678>, or we generate
+ // niche discriminant checks in a way that doesn't trigger it.
+
+ as_underlying(self.__chaining_lt(other)) == 1
+ }
+ #[inline]
+ fn le(&self, other: &Self) -> bool {
+ as_underlying(self.__chaining_le(other)) != 0
+ }
+ #[inline]
+ fn gt(&self, other: &Self) -> bool {
+ as_underlying(self.__chaining_gt(other)) == 1
+ }
+ #[inline]
+ fn ge(&self, other: &Self) -> bool {
+ as_underlying(self.__chaining_ge(other)) != 0
+ }
+ #[inline]
+ fn __chaining_lt(&self, other: &Self) -> ControlFlow<bool> {
+ SliceChain::chaining_lt(self, other)
+ }
+ #[inline]
+ fn __chaining_le(&self, other: &Self) -> ControlFlow<bool> {
+ SliceChain::chaining_le(self, other)
+ }
+ #[inline]
+ fn __chaining_gt(&self, other: &Self) -> ControlFlow<bool> {
+ SliceChain::chaining_gt(self, other)
+ }
+ #[inline]
+ fn __chaining_ge(&self, other: &Self) -> ControlFlow<bool> {
+ SliceChain::chaining_ge(self, other)
+ }
}
#[doc(hidden)]
@@ -99,26 +152,65 @@ trait SlicePartialOrd: Sized {
fn partial_compare(left: &[Self], right: &[Self]) -> Option<Ordering>;
}
+#[doc(hidden)]
+// intermediate trait for specialization of slice's PartialOrd chaining methods
+trait SliceChain: Sized {
+ fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
+ fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
+ fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
+ fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
+}
+
+type AlwaysBreak<B> = ControlFlow<B, crate::convert::Infallible>;
+
impl<A: PartialOrd> SlicePartialOrd for A {
default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
- let l = cmp::min(left.len(), right.len());
-
- // Slice to the loop iteration range to enable bound check
- // elimination in the compiler
- let lhs = &left[..l];
- let rhs = &right[..l];
-
- for i in 0..l {
- match lhs[i].partial_cmp(&rhs[i]) {
- Some(Ordering::Equal) => (),
- non_eq => return non_eq,
- }
- }
-
- left.len().partial_cmp(&right.len())
+ let elem_chain = |a, b| match PartialOrd::partial_cmp(a, b) {
+ Some(Ordering::Equal) => ControlFlow::Continue(()),
+ non_eq => ControlFlow::Break(non_eq),
+ };
+ let len_chain = |a: &_, b: &_| ControlFlow::Break(usize::partial_cmp(a, b));
+ let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain);
+ b
}
}
+impl<A: PartialOrd> SliceChain for A {
+ default fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+ chaining_impl(left, right, PartialOrd::__chaining_lt, usize::__chaining_lt)
+ }
+ default fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+ chaining_impl(left, right, PartialOrd::__chaining_le, usize::__chaining_le)
+ }
+ default fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+ chaining_impl(left, right, PartialOrd::__chaining_gt, usize::__chaining_gt)
+ }
+ default fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+ chaining_impl(left, right, PartialOrd::__chaining_ge, usize::__chaining_ge)
+ }
+}
+
+#[inline]
+fn chaining_impl<'l, 'r, A: PartialOrd, B, C>(
+ left: &'l [A],
+ right: &'r [A],
+ elem_chain: impl Fn(&'l A, &'r A) -> ControlFlow<B>,
+ len_chain: impl for<'a> FnOnce(&'a usize, &'a usize) -> ControlFlow<B, C>,
+) -> ControlFlow<B, C> {
+ let l = cmp::min(left.len(), right.len());
+
+ // Slice to the loop iteration range to enable bound check
+ // elimination in the compiler
+ let lhs = &left[..l];
+ let rhs = &right[..l];
+
+ for i in 0..l {
+ elem_chain(&lhs[i], &rhs[i])?;
+ }
+
+ len_chain(&left.len(), &right.len())
+}
+
// This is the impl that we would like to have. Unfortunately it's not sound.
// See `partial_ord_slice.rs`.
/*
@@ -165,21 +257,13 @@ trait SliceOrd: Sized {
impl<A: Ord> SliceOrd for A {
default fn compare(left: &[Self], right: &[Self]) -> Ordering {
- let l = cmp::min(left.len(), right.len());
-
- // Slice to the loop iteration range to enable bound check
- // elimination in the compiler
- let lhs = &left[..l];
- let rhs = &right[..l];
-
- for i in 0..l {
- match lhs[i].cmp(&rhs[i]) {
- Ordering::Equal => (),
- non_eq => return non_eq,
- }
- }
-
- left.len().cmp(&right.len())
+ let elem_chain = |a, b| match Ord::cmp(a, b) {
+ Ordering::Equal => ControlFlow::Continue(()),
+ non_eq => ControlFlow::Break(non_eq),
+ };
+ let len_chain = |a: &_, b: &_| ControlFlow::Break(usize::cmp(a, b));
+ let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain);
+ b
}
}
@@ -191,7 +275,7 @@ impl<A: Ord> SliceOrd for A {
/// * For every `x` and `y` of this type, `Ord(x, y)` must return the same
/// value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`.
#[rustc_specialization_trait]
-unsafe trait UnsignedBytewiseOrd {}
+unsafe trait UnsignedBytewiseOrd: Ord {}
unsafe impl UnsignedBytewiseOrd for bool {}
unsafe impl UnsignedBytewiseOrd for u8 {}
@@ -225,6 +309,38 @@ fn compare(left: &[Self], right: &[Self]) -> Ordering {
}
}
+// Don't generate our own chaining loops for `memcmp`-able things either.
+impl<A: PartialOrd + UnsignedBytewiseOrd> SliceChain for A {
+ #[inline]
+ fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+ match SliceOrd::compare(left, right) {
+ Ordering::Equal => ControlFlow::Continue(()),
+ ne => ControlFlow::Break(ne.is_lt()),
+ }
+ }
+ #[inline]
+ fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+ match SliceOrd::compare(left, right) {
+ Ordering::Equal => ControlFlow::Continue(()),
+ ne => ControlFlow::Break(ne.is_le()),
+ }
+ }
+ #[inline]
+ fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+ match SliceOrd::compare(left, right) {
+ Ordering::Equal => ControlFlow::Continue(()),
+ ne => ControlFlow::Break(ne.is_gt()),
+ }
+ }
+ #[inline]
+ fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
+ match SliceOrd::compare(left, right) {
+ Ordering::Equal => ControlFlow::Continue(()),
+ ne => ControlFlow::Break(ne.is_ge()),
+ }
+ }
+}
+
pub(super) trait SliceContains: Sized {
fn slice_contains(&self, x: &[Self]) -> bool;
}
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index b906899..1ae0849 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -1287,7 +1287,6 @@ pub const fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_
/// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
- #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[must_use]
pub const unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] {
@@ -1333,7 +1332,6 @@ pub const fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_
/// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
- #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[track_caller]
#[must_use]
@@ -1368,7 +1366,6 @@ pub const fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_
/// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
- #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[track_caller]
#[must_use]
@@ -1448,7 +1445,6 @@ pub const fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N> {
/// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
- #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[must_use]
pub const unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] {
@@ -1489,7 +1485,6 @@ pub const fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N> {
/// assert_eq!(v, &[1, 1, 2, 2, 9]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
- #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[track_caller]
#[must_use]
@@ -1530,7 +1525,6 @@ pub const fn array_chunks<const N: usize>(&self) -> ArrayChunks<'_, T, N> {
/// assert_eq!(v, &[9, 1, 1, 2, 2]);
/// ```
#[unstable(feature = "slice_as_chunks", issue = "74985")]
- #[rustc_const_unstable(feature = "slice_as_chunks", issue = "74985")]
#[inline]
#[track_caller]
#[must_use]
@@ -2820,7 +2814,7 @@ pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
let half = size / 2;
let mid = base + half;
- // SAFETY: the call is made safe by the following inconstants:
+ // SAFETY: the call is made safe by the following invariants:
// - `mid >= 0`: by definition
// - `mid < size`: `mid = size / 2 + size / 4 + size / 8 ...`
let cmp = f(unsafe { self.get_unchecked(mid) });
@@ -2828,7 +2822,7 @@ pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize>
// Binary search interacts poorly with branch prediction, so force
// the compiler to use conditional moves if supported by the target
// architecture.
- base = (cmp == Greater).select_unpredictable(base, mid);
+ base = hint::select_unpredictable(cmp == Greater, base, mid);
// This is imprecise in the case where `size` is odd and the
// comparison returns Greater: the mid element still gets included
diff --git a/library/core/src/slice/sort/shared/smallsort.rs b/library/core/src/slice/sort/shared/smallsort.rs
index 95f196a..4280f75 100644
--- a/library/core/src/slice/sort/shared/smallsort.rs
+++ b/library/core/src/slice/sort/shared/smallsort.rs
@@ -2,7 +2,7 @@
use crate::mem::{self, ManuallyDrop, MaybeUninit};
use crate::slice::sort::shared::FreezeMarker;
-use crate::{intrinsics, ptr, slice};
+use crate::{hint, intrinsics, ptr, slice};
// It's important to differentiate between SMALL_SORT_THRESHOLD performance for
// small slices and small-sort performance sorting small sub-slices as part of
@@ -408,8 +408,8 @@ unsafe fn swap_if_less<T, F>(v_base: *mut T, a_pos: usize, b_pos: usize, is_less
// }
// The goal is to generate cmov instructions here.
- let v_a_swap = should_swap.select_unpredictable(v_b, v_a);
- let v_b_swap = should_swap.select_unpredictable(v_a, v_b);
+ let v_a_swap = hint::select_unpredictable(should_swap, v_b, v_a);
+ let v_b_swap = hint::select_unpredictable(should_swap, v_a, v_b);
let v_b_swap_tmp = ManuallyDrop::new(ptr::read(v_b_swap));
ptr::copy(v_a_swap, v_a, 1);
@@ -640,15 +640,15 @@ pub unsafe fn sort4_stable<T, F: FnMut(&T, &T) -> bool>(
// 1, 1 | c b a d
let c3 = is_less(&*c, &*a);
let c4 = is_less(&*d, &*b);
- let min = c3.select_unpredictable(c, a);
- let max = c4.select_unpredictable(b, d);
- let unknown_left = c3.select_unpredictable(a, c4.select_unpredictable(c, b));
- let unknown_right = c4.select_unpredictable(d, c3.select_unpredictable(b, c));
+ let min = hint::select_unpredictable(c3, c, a);
+ let max = hint::select_unpredictable(c4, b, d);
+ let unknown_left = hint::select_unpredictable(c3, a, hint::select_unpredictable(c4, c, b));
+ let unknown_right = hint::select_unpredictable(c4, d, hint::select_unpredictable(c3, b, c));
// Sort the last two unknown elements.
let c5 = is_less(&*unknown_right, &*unknown_left);
- let lo = c5.select_unpredictable(unknown_right, unknown_left);
- let hi = c5.select_unpredictable(unknown_left, unknown_right);
+ let lo = hint::select_unpredictable(c5, unknown_right, unknown_left);
+ let hi = hint::select_unpredictable(c5, unknown_left, unknown_right);
ptr::copy_nonoverlapping(min, dst, 1);
ptr::copy_nonoverlapping(lo, dst.add(1), 1);
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index d754bb9..02eb805 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -2,7 +2,7 @@
use crate::cmp::Ordering::{self, *};
use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy};
-use crate::ops::ControlFlow::{Break, Continue};
+use crate::ops::ControlFlow::{self, Break, Continue};
// Recursive macro for implementing n-ary tuple functions and operations
//
@@ -95,6 +95,22 @@ fn ge(&self, other: &($($T,)+)) -> bool {
fn gt(&self, other: &($($T,)+)) -> bool {
lexical_ord!(gt, __chaining_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
}
+ #[inline]
+ fn __chaining_lt(&self, other: &($($T,)+)) -> ControlFlow<bool> {
+ lexical_chain!(__chaining_lt, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
+ }
+ #[inline]
+ fn __chaining_le(&self, other: &($($T,)+)) -> ControlFlow<bool> {
+ lexical_chain!(__chaining_le, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
+ }
+ #[inline]
+ fn __chaining_gt(&self, other: &($($T,)+)) -> ControlFlow<bool> {
+ lexical_chain!(__chaining_gt, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
+ }
+ #[inline]
+ fn __chaining_ge(&self, other: &($($T,)+)) -> ControlFlow<bool> {
+ lexical_chain!(__chaining_ge, $( ${ignore($T)} self.${index()}, other.${index()} ),+)
+ }
}
}
@@ -187,6 +203,17 @@ macro_rules! lexical_ord {
};
}
+// Same parameter interleaving as `lexical_ord` above
+macro_rules! lexical_chain {
+ ($chain_rel: ident, $a:expr, $b:expr $(,$rest_a:expr, $rest_b:expr)*) => {{
+ PartialOrd::$chain_rel(&$a, &$b)?;
+ lexical_chain!($chain_rel $(,$rest_a, $rest_b)*)
+ }};
+ ($chain_rel: ident) => {
+ Continue(())
+ };
+}
+
macro_rules! lexical_partial_cmp {
($a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {
match ($a).partial_cmp(&$b) {
diff --git a/library/coretests/tests/ffi/cstr.rs b/library/coretests/tests/ffi/cstr.rs
index 9bf4c21..0d85b22 100644
--- a/library/coretests/tests/ffi/cstr.rs
+++ b/library/coretests/tests/ffi/cstr.rs
@@ -13,3 +13,9 @@ fn compares_as_u8s() {
assert_eq!(Ord::cmp(a, b), Ord::cmp(a_bytes, b_bytes));
assert_eq!(PartialOrd::partial_cmp(a, b), PartialOrd::partial_cmp(a_bytes, b_bytes));
}
+
+#[test]
+fn debug() {
+ let s = c"abc\x01\x02\n\xE2\x80\xA6\xFF";
+ assert_eq!(format!("{s:?}"), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#);
+}
diff --git a/library/coretests/tests/hint.rs b/library/coretests/tests/hint.rs
new file mode 100644
index 0000000..032bbc1
--- /dev/null
+++ b/library/coretests/tests/hint.rs
@@ -0,0 +1,23 @@
+#[test]
+fn select_unpredictable_drop() {
+ use core::cell::Cell;
+ struct X<'a>(&'a Cell<bool>);
+ impl Drop for X<'_> {
+ fn drop(&mut self) {
+ self.0.set(true);
+ }
+ }
+
+ let a_dropped = Cell::new(false);
+ let b_dropped = Cell::new(false);
+ let a = X(&a_dropped);
+ let b = X(&b_dropped);
+ assert!(!a_dropped.get());
+ assert!(!b_dropped.get());
+ let selected = core::hint::select_unpredictable(core::hint::black_box(true), a, b);
+ assert!(!a_dropped.get());
+ assert!(b_dropped.get());
+ drop(selected);
+ assert!(a_dropped.get());
+ assert!(b_dropped.get());
+}
diff --git a/library/coretests/tests/iter/adapters/enumerate.rs b/library/coretests/tests/iter/adapters/enumerate.rs
index b57d51c..2294f85 100644
--- a/library/coretests/tests/iter/adapters/enumerate.rs
+++ b/library/coretests/tests/iter/adapters/enumerate.rs
@@ -120,3 +120,13 @@ fn test_double_ended_enumerate() {
assert_eq!(it.next_back(), Some((2, 3)));
assert_eq!(it.next(), None);
}
+
+#[test]
+fn test_empty_iterator_enumerate_next_index() {
+ let mut it = empty::<i32>().enumerate();
+ assert_eq!(it.next_index(), 0);
+ assert_eq!(it.next_index(), 0);
+ assert_eq!(it.next(), None);
+ assert_eq!(it.next_index(), 0);
+ assert_eq!(it.next_index(), 0);
+}
diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs
index 7ad1547..ef54897 100644
--- a/library/coretests/tests/lib.rs
+++ b/library/coretests/tests/lib.rs
@@ -12,7 +12,6 @@
#![feature(async_iterator)]
#![feature(bigint_helper_methods)]
#![feature(bstr)]
-#![feature(cell_update)]
#![feature(char_max_len)]
#![feature(clone_to_uninit)]
#![feature(const_eval_select)]
@@ -63,11 +62,13 @@
#![feature(maybe_uninit_write_slice)]
#![feature(min_specialization)]
#![feature(never_type)]
+#![feature(next_index)]
#![feature(numfmt)]
#![feature(pattern)]
#![feature(pointer_is_aligned_to)]
#![feature(portable_simd)]
#![feature(ptr_metadata)]
+#![feature(select_unpredictable)]
#![feature(slice_from_ptr_range)]
#![feature(slice_internals)]
#![feature(slice_partition_dedup)]
@@ -147,6 +148,7 @@ fn $test() $block
mod fmt;
mod future;
mod hash;
+mod hint;
mod intrinsics;
mod io;
mod iter;
diff --git a/library/coretests/tests/pin_macro.rs b/library/coretests/tests/pin_macro.rs
index bfbfa8d..3174c91 100644
--- a/library/coretests/tests/pin_macro.rs
+++ b/library/coretests/tests/pin_macro.rs
@@ -38,6 +38,7 @@ fn rust_2024_expr() {
}
#[test]
+#[cfg(not(bootstrap))]
fn temp_lifetime() {
// Check that temporary lifetimes work as in Rust 2021.
// Regression test for https://github.com/rust-lang/rust/issues/138596
diff --git a/library/coretests/tests/ptr.rs b/library/coretests/tests/ptr.rs
index cc5f794..7d6e4ea 100644
--- a/library/coretests/tests/ptr.rs
+++ b/library/coretests/tests/ptr.rs
@@ -1020,3 +1020,20 @@ fn test_ptr_swap_nonoverlapping_is_untyped() {
ptr_swap_nonoverlapping_is_untyped_inner();
const { ptr_swap_nonoverlapping_is_untyped_inner() };
}
+
+#[test]
+fn test_ptr_default() {
+ #[derive(Default)]
+ struct PtrDefaultTest {
+ ptr: *const u64,
+ }
+ let default = PtrDefaultTest::default();
+ assert!(default.ptr.is_null());
+
+ #[derive(Default)]
+ struct PtrMutDefaultTest {
+ ptr: *mut u64,
+ }
+ let default = PtrMutDefaultTest::default();
+ assert!(default.ptr.is_null());
+}
diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs
index f6d4825..e7d5479 100644
--- a/library/proc_macro/src/bridge/client.rs
+++ b/library/proc_macro/src/bridge/client.rs
@@ -111,12 +111,6 @@ fn clone(&self) -> Self {
}
}
-impl Clone for SourceFile {
- fn clone(&self) -> Self {
- self.clone()
- }
-}
-
impl Span {
pub(crate) fn def_site() -> Span {
Bridge::with(|bridge| bridge.globals.def_site)
diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs
index 1b5c221..75d82d7 100644
--- a/library/proc_macro/src/bridge/mod.rs
+++ b/library/proc_macro/src/bridge/mod.rs
@@ -81,16 +81,8 @@ fn into_trees(
$self: $S::TokenStream
) -> Vec<TokenTree<$S::TokenStream, $S::Span, $S::Symbol>>;
},
- SourceFile {
- fn drop($self: $S::SourceFile);
- fn clone($self: &$S::SourceFile) -> $S::SourceFile;
- fn eq($self: &$S::SourceFile, other: &$S::SourceFile) -> bool;
- fn path($self: &$S::SourceFile) -> String;
- fn is_real($self: &$S::SourceFile) -> bool;
- },
Span {
fn debug($self: $S::Span) -> String;
- fn source_file($self: $S::Span) -> $S::SourceFile;
fn parent($self: $S::Span) -> Option<$S::Span>;
fn source($self: $S::Span) -> $S::Span;
fn byte_range($self: $S::Span) -> Range<usize>;
@@ -98,6 +90,8 @@ fn into_trees(
fn end($self: $S::Span) -> $S::Span;
fn line($self: $S::Span) -> usize;
fn column($self: $S::Span) -> usize;
+ fn file($self: $S::Span) -> String;
+ fn local_file($self: $S::Span) -> Option<String>;
fn join($self: $S::Span, other: $S::Span) -> Option<$S::Span>;
fn subspan($self: $S::Span, start: Bound<usize>, end: Bound<usize>) -> Option<$S::Span>;
fn resolved_at($self: $S::Span, at: $S::Span) -> $S::Span;
@@ -120,7 +114,6 @@ macro_rules! with_api_handle_types {
'owned:
FreeFunctions,
TokenStream,
- SourceFile,
'interned:
Span,
diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs
index 97e5a60..5beda7c 100644
--- a/library/proc_macro/src/bridge/server.rs
+++ b/library/proc_macro/src/bridge/server.rs
@@ -82,7 +82,6 @@ fn decode(r: &mut Reader<'_>, s: &mut HandleStore<MarkedTypes<S>>) -> Self {
pub trait Types {
type FreeFunctions: 'static;
type TokenStream: 'static + Clone;
- type SourceFile: 'static + Clone;
type Span: 'static + Copy + Eq + Hash;
type Symbol: 'static;
}
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index f1cf0c5..c46dceb 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -491,12 +491,6 @@ pub fn mixed_site() -> Span {
Span(bridge::client::Span::mixed_site())
}
- /// The original source file into which this span points.
- #[unstable(feature = "proc_macro_span", issue = "54725")]
- pub fn source_file(&self) -> SourceFile {
- SourceFile(self.0.source_file())
- }
-
/// The `Span` for the tokens in the previous macro expansion from which
/// `self` was generated from, if any.
#[unstable(feature = "proc_macro_span", issue = "54725")]
@@ -546,6 +540,25 @@ pub fn column(&self) -> usize {
self.0.column()
}
+ /// The path to the source file in which this span occurs, for display purposes.
+ ///
+ /// This might not correspond to a valid file system path.
+ /// It might be remapped, or might be an artificial path such as `"<macro expansion>"`.
+ #[unstable(feature = "proc_macro_span", issue = "54725")]
+ pub fn file(&self) -> String {
+ self.0.file()
+ }
+
+ /// The path to the source file in which this span occurs on disk.
+ ///
+ /// This is the actual path on disk. It is unaffected by path remapping.
+ ///
+ /// This path should not be embedded in the output of the macro; prefer `file()` instead.
+ #[unstable(feature = "proc_macro_span", issue = "54725")]
+ pub fn local_file(&self) -> Option<PathBuf> {
+ self.0.local_file().map(|s| PathBuf::from(s))
+ }
+
/// Creates a new span encompassing `self` and `other`.
///
/// Returns `None` if `self` and `other` are from different files.
@@ -614,58 +627,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
}
}
-/// The source file of a given `Span`.
-#[unstable(feature = "proc_macro_span", issue = "54725")]
-#[derive(Clone)]
-pub struct SourceFile(bridge::client::SourceFile);
-
-impl SourceFile {
- /// Gets the path to this source file.
- ///
- /// ### Note
- /// If the code span associated with this `SourceFile` was generated by an external macro, this
- /// macro, this might not be an actual path on the filesystem. Use [`is_real`] to check.
- ///
- /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on
- /// the command line, the path as given might not actually be valid.
- ///
- /// [`is_real`]: Self::is_real
- #[unstable(feature = "proc_macro_span", issue = "54725")]
- pub fn path(&self) -> PathBuf {
- PathBuf::from(self.0.path())
- }
-
- /// Returns `true` if this source file is a real source file, and not generated by an external
- /// macro's expansion.
- #[unstable(feature = "proc_macro_span", issue = "54725")]
- pub fn is_real(&self) -> bool {
- // This is a hack until intercrate spans are implemented and we can have real source files
- // for spans generated in external macros.
- // https://github.com/rust-lang/rust/pull/43604#issuecomment-333334368
- self.0.is_real()
- }
-}
-
-#[unstable(feature = "proc_macro_span", issue = "54725")]
-impl fmt::Debug for SourceFile {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("SourceFile")
- .field("path", &self.path())
- .field("is_real", &self.is_real())
- .finish()
- }
-}
-
-#[unstable(feature = "proc_macro_span", issue = "54725")]
-impl PartialEq for SourceFile {
- fn eq(&self, other: &Self) -> bool {
- self.0.eq(&other.0)
- }
-}
-
-#[unstable(feature = "proc_macro_span", issue = "54725")]
-impl Eq for SourceFile {}
-
/// A single token or a delimited sequence of token trees (e.g., `[1, (), ..]`).
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
#[derive(Clone)]
diff --git a/library/profiler_builtins/build.rs b/library/profiler_builtins/build.rs
index dd85239..fc1a9ec 100644
--- a/library/profiler_builtins/build.rs
+++ b/library/profiler_builtins/build.rs
@@ -9,8 +9,14 @@
fn main() {
if let Ok(rt) = tracked_env_var("LLVM_PROFILER_RT_LIB") {
- println!("cargo::rustc-link-lib=static:+verbatim={rt}");
- return;
+ let rt = PathBuf::from(rt);
+ if let Some(lib) = rt.file_name() {
+ if let Some(dir) = rt.parent() {
+ println!("cargo::rustc-link-search=native={}", dir.display());
+ }
+ println!("cargo::rustc-link-lib=static:+verbatim={}", lib.to_str().unwrap());
+ return;
+ }
}
let target_os = env::var("CARGO_CFG_TARGET_OS").expect("CARGO_CFG_TARGET_OS was not set");
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 6b70ff7..3536e84 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -18,7 +18,7 @@
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core", public = true }
-compiler_builtins = { version = "=0.1.153" }
+compiler_builtins = { version = "=0.1.156" }
unwind = { path = "../unwind" }
hashbrown = { version = "0.15", default-features = false, features = [
'rustc-dep-of-std',
@@ -35,7 +35,7 @@
addr2line = { version = "0.24.0", optional = true, default-features = false }
[target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
-libc = { version = "0.2.171", default-features = false, features = [
+libc = { version = "0.2.172", default-features = false, features = [
'rustc-dep-of-std',
], public = true }
diff --git a/library/std/build.rs b/library/std/build.rs
index d76d07a..40a56d4 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -12,11 +12,6 @@ fn main() {
.expect("CARGO_CFG_TARGET_POINTER_WIDTH was not set")
.parse()
.unwrap();
- let target_features: Vec<_> = env::var("CARGO_CFG_TARGET_FEATURE")
- .unwrap_or_default()
- .split(",")
- .map(ToOwned::to_owned)
- .collect();
let is_miri = env::var_os("CARGO_CFG_MIRI").is_some();
println!("cargo:rustc-check-cfg=cfg(netbsd10)");
@@ -108,8 +103,6 @@ fn main() {
("s390x", _) => false,
// Unsupported <https://github.com/llvm/llvm-project/issues/94434>
("arm64ec", _) => false,
- // LLVM crash <https://github.com/llvm/llvm-project/issues/129394>
- ("aarch64", _) if !target_features.iter().any(|f| f == "neon") => false,
// MinGW ABI bugs <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=115054>
("x86_64", "windows") if target_env == "gnu" && target_abi != "llvm" => false,
// Infinite recursion <https://github.com/llvm/llvm-project/issues/97981>
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index 0eef2bd..9ad26e5 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -973,6 +973,9 @@ pub fn get_key_value<Q: ?Sized>(&self, k: &Q) -> Option<(&K, &V)>
/// Returns an array of length `N` with the results of each query. For soundness, at most one
/// mutable reference will be returned to any value. `None` will be used if the key is missing.
///
+ /// This method performs a check to ensure there are no duplicate keys, which currently has a time-complexity of O(n^2),
+ /// so be careful when passing many keys.
+ ///
/// # Panics
///
/// Panics if any keys are overlapping.
diff --git a/library/std/src/env.rs b/library/std/src/env.rs
index 05bd434..c84a72c 100644
--- a/library/std/src/env.rs
+++ b/library/std/src/env.rs
@@ -950,7 +950,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// Constants associated with the current target
#[stable(feature = "env", since = "1.0.0")]
pub mod consts {
- use crate::sys::env::os;
+ use crate::sys::env_consts::os;
/// A string describing the architecture of the CPU that is currently in use.
/// An example value may be: `"x86"`, `"arm"` or `"riscv64"`.
diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs
index ede2196..217528f 100644
--- a/library/std/src/f128.rs
+++ b/library/std/src/f128.rs
@@ -666,7 +666,7 @@ pub fn log10(self) -> f128 {
#[unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn cbrt(self) -> f128 {
- unsafe { cmath::cbrtf128(self) }
+ cmath::cbrtf128(self)
}
/// Compute the distance between the origin and a point (`x`, `y`) on the
@@ -703,7 +703,7 @@ pub fn cbrt(self) -> f128 {
#[unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn hypot(self, other: f128) -> f128 {
- unsafe { cmath::hypotf128(self, other) }
+ cmath::hypotf128(self, other)
}
/// Computes the sine of a number (in radians).
@@ -789,7 +789,7 @@ pub fn cos(self) -> f128 {
#[unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn tan(self) -> f128 {
- unsafe { cmath::tanf128(self) }
+ cmath::tanf128(self)
}
/// Computes the arcsine of a number. Return value is in radians in
@@ -824,7 +824,7 @@ pub fn tan(self) -> f128 {
#[unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn asin(self) -> f128 {
- unsafe { cmath::asinf128(self) }
+ cmath::asinf128(self)
}
/// Computes the arccosine of a number. Return value is in radians in
@@ -859,7 +859,7 @@ pub fn asin(self) -> f128 {
#[unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn acos(self) -> f128 {
- unsafe { cmath::acosf128(self) }
+ cmath::acosf128(self)
}
/// Computes the arctangent of a number. Return value is in radians in the
@@ -893,7 +893,7 @@ pub fn acos(self) -> f128 {
#[unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn atan(self) -> f128 {
- unsafe { cmath::atanf128(self) }
+ cmath::atanf128(self)
}
/// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
@@ -939,7 +939,7 @@ pub fn atan(self) -> f128 {
#[unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn atan2(self, other: f128) -> f128 {
- unsafe { cmath::atan2f128(self, other) }
+ cmath::atan2f128(self, other)
}
/// Simultaneously computes the sine and cosine of the number, `x`. Returns
@@ -1008,7 +1008,7 @@ pub fn sin_cos(self) -> (f128, f128) {
#[unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn exp_m1(self) -> f128 {
- unsafe { cmath::expm1f128(self) }
+ cmath::expm1f128(self)
}
/// Returns `ln(1+n)` (natural logarithm) more accurately than if
@@ -1055,7 +1055,7 @@ pub fn exp_m1(self) -> f128 {
#[rustc_allow_incoherent_impl]
#[unstable(feature = "f128", issue = "116909")]
pub fn ln_1p(self) -> f128 {
- unsafe { cmath::log1pf128(self) }
+ cmath::log1pf128(self)
}
/// Hyperbolic sine function.
@@ -1090,7 +1090,7 @@ pub fn ln_1p(self) -> f128 {
#[unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn sinh(self) -> f128 {
- unsafe { cmath::sinhf128(self) }
+ cmath::sinhf128(self)
}
/// Hyperbolic cosine function.
@@ -1125,7 +1125,7 @@ pub fn sinh(self) -> f128 {
#[unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn cosh(self) -> f128 {
- unsafe { cmath::coshf128(self) }
+ cmath::coshf128(self)
}
/// Hyperbolic tangent function.
@@ -1160,7 +1160,7 @@ pub fn cosh(self) -> f128 {
#[unstable(feature = "f128", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn tanh(self) -> f128 {
- unsafe { cmath::tanhf128(self) }
+ cmath::tanhf128(self)
}
/// Inverse hyperbolic sine function.
@@ -1289,7 +1289,7 @@ pub fn atanh(self) -> f128 {
// #[unstable(feature = "float_gamma", issue = "99842")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn gamma(self) -> f128 {
- unsafe { cmath::tgammaf128(self) }
+ cmath::tgammaf128(self)
}
/// Natural logarithm of the absolute value of the gamma function
@@ -1325,7 +1325,7 @@ pub fn gamma(self) -> f128 {
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn ln_gamma(self) -> (f128, i32) {
let mut signgamp: i32 = 0;
- let x = unsafe { cmath::lgammaf128_r(self, &mut signgamp) };
+ let x = cmath::lgammaf128_r(self, &mut signgamp);
(x, signgamp)
}
@@ -1365,7 +1365,7 @@ pub fn ln_gamma(self) -> (f128, i32) {
// #[unstable(feature = "float_erf", issue = "136321")]
#[inline]
pub fn erf(self) -> f128 {
- unsafe { cmath::erff128(self) }
+ cmath::erff128(self)
}
/// Complementary error function.
@@ -1398,6 +1398,6 @@ pub fn erf(self) -> f128 {
// #[unstable(feature = "float_erf", issue = "136321")]
#[inline]
pub fn erfc(self) -> f128 {
- unsafe { cmath::erfcf128(self) }
+ cmath::erfcf128(self)
}
}
diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs
index 286993d..4dadcbb 100644
--- a/library/std/src/f16.rs
+++ b/library/std/src/f16.rs
@@ -665,7 +665,7 @@ pub fn log10(self) -> f16 {
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn cbrt(self) -> f16 {
- (unsafe { cmath::cbrtf(self as f32) }) as f16
+ cmath::cbrtf(self as f32) as f16
}
/// Compute the distance between the origin and a point (`x`, `y`) on the
@@ -701,7 +701,7 @@ pub fn cbrt(self) -> f16 {
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn hypot(self, other: f16) -> f16 {
- (unsafe { cmath::hypotf(self as f32, other as f32) }) as f16
+ cmath::hypotf(self as f32, other as f32) as f16
}
/// Computes the sine of a number (in radians).
@@ -787,7 +787,7 @@ pub fn cos(self) -> f16 {
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn tan(self) -> f16 {
- (unsafe { cmath::tanf(self as f32) }) as f16
+ cmath::tanf(self as f32) as f16
}
/// Computes the arcsine of a number. Return value is in radians in
@@ -822,7 +822,7 @@ pub fn tan(self) -> f16 {
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn asin(self) -> f16 {
- (unsafe { cmath::asinf(self as f32) }) as f16
+ cmath::asinf(self as f32) as f16
}
/// Computes the arccosine of a number. Return value is in radians in
@@ -857,7 +857,7 @@ pub fn asin(self) -> f16 {
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn acos(self) -> f16 {
- (unsafe { cmath::acosf(self as f32) }) as f16
+ cmath::acosf(self as f32) as f16
}
/// Computes the arctangent of a number. Return value is in radians in the
@@ -891,7 +891,7 @@ pub fn acos(self) -> f16 {
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn atan(self) -> f16 {
- (unsafe { cmath::atanf(self as f32) }) as f16
+ cmath::atanf(self as f32) as f16
}
/// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
@@ -937,7 +937,7 @@ pub fn atan(self) -> f16 {
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn atan2(self, other: f16) -> f16 {
- (unsafe { cmath::atan2f(self as f32, other as f32) }) as f16
+ cmath::atan2f(self as f32, other as f32) as f16
}
/// Simultaneously computes the sine and cosine of the number, `x`. Returns
@@ -1006,7 +1006,7 @@ pub fn sin_cos(self) -> (f16, f16) {
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn exp_m1(self) -> f16 {
- (unsafe { cmath::expm1f(self as f32) }) as f16
+ cmath::expm1f(self as f32) as f16
}
/// Returns `ln(1+n)` (natural logarithm) more accurately than if
@@ -1053,7 +1053,7 @@ pub fn exp_m1(self) -> f16 {
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn ln_1p(self) -> f16 {
- (unsafe { cmath::log1pf(self as f32) }) as f16
+ cmath::log1pf(self as f32) as f16
}
/// Hyperbolic sine function.
@@ -1088,7 +1088,7 @@ pub fn ln_1p(self) -> f16 {
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn sinh(self) -> f16 {
- (unsafe { cmath::sinhf(self as f32) }) as f16
+ cmath::sinhf(self as f32) as f16
}
/// Hyperbolic cosine function.
@@ -1123,7 +1123,7 @@ pub fn sinh(self) -> f16 {
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn cosh(self) -> f16 {
- (unsafe { cmath::coshf(self as f32) }) as f16
+ cmath::coshf(self as f32) as f16
}
/// Hyperbolic tangent function.
@@ -1158,7 +1158,7 @@ pub fn cosh(self) -> f16 {
#[unstable(feature = "f16", issue = "116909")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn tanh(self) -> f16 {
- (unsafe { cmath::tanhf(self as f32) }) as f16
+ cmath::tanhf(self as f32) as f16
}
/// Inverse hyperbolic sine function.
@@ -1287,7 +1287,7 @@ pub fn atanh(self) -> f16 {
// #[unstable(feature = "float_gamma", issue = "99842")]
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn gamma(self) -> f16 {
- (unsafe { cmath::tgammaf(self as f32) }) as f16
+ cmath::tgammaf(self as f32) as f16
}
/// Natural logarithm of the absolute value of the gamma function
@@ -1323,7 +1323,7 @@ pub fn gamma(self) -> f16 {
#[must_use = "method returns a new number and does not mutate the original value"]
pub fn ln_gamma(self) -> (f16, i32) {
let mut signgamp: i32 = 0;
- let x = (unsafe { cmath::lgammaf_r(self as f32, &mut signgamp) }) as f16;
+ let x = cmath::lgammaf_r(self as f32, &mut signgamp) as f16;
(x, signgamp)
}
@@ -1363,7 +1363,7 @@ pub fn ln_gamma(self) -> (f16, i32) {
// #[unstable(feature = "float_erf", issue = "136321")]
#[inline]
pub fn erf(self) -> f16 {
- (unsafe { cmath::erff(self as f32) }) as f16
+ cmath::erff(self as f32) as f16
}
/// Complementary error function.
@@ -1396,6 +1396,6 @@ pub fn erf(self) -> f16 {
// #[unstable(feature = "float_erf", issue = "136321")]
#[inline]
pub fn erfc(self) -> f16 {
- (unsafe { cmath::erfcf(self as f32) }) as f16
+ cmath::erfcf(self as f32) as f16
}
}
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index 980e7f7..baf7002 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -599,7 +599,7 @@ pub fn log10(self) -> f32 {
filing an issue describing your use-case too)."
)]
pub fn abs_sub(self, other: f32) -> f32 {
- unsafe { cmath::fdimf(self, other) }
+ cmath::fdimf(self, other)
}
/// Returns the cube root of a number.
@@ -626,7 +626,7 @@ pub fn abs_sub(self, other: f32) -> f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn cbrt(self) -> f32 {
- unsafe { cmath::cbrtf(self) }
+ cmath::cbrtf(self)
}
/// Compute the distance between the origin and a point (`x`, `y`) on the
@@ -657,7 +657,7 @@ pub fn cbrt(self) -> f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn hypot(self, other: f32) -> f32 {
- unsafe { cmath::hypotf(self, other) }
+ cmath::hypotf(self, other)
}
/// Computes the sine of a number (in radians).
@@ -730,7 +730,7 @@ pub fn cos(self) -> f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn tan(self) -> f32 {
- unsafe { cmath::tanf(self) }
+ cmath::tanf(self)
}
/// Computes the arcsine of a number. Return value is in radians in
@@ -760,7 +760,7 @@ pub fn tan(self) -> f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn asin(self) -> f32 {
- unsafe { cmath::asinf(self) }
+ cmath::asinf(self)
}
/// Computes the arccosine of a number. Return value is in radians in
@@ -790,7 +790,7 @@ pub fn asin(self) -> f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn acos(self) -> f32 {
- unsafe { cmath::acosf(self) }
+ cmath::acosf(self)
}
/// Computes the arctangent of a number. Return value is in radians in the
@@ -819,7 +819,7 @@ pub fn acos(self) -> f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn atan(self) -> f32 {
- unsafe { cmath::atanf(self) }
+ cmath::atanf(self)
}
/// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
@@ -860,7 +860,7 @@ pub fn atan(self) -> f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn atan2(self, other: f32) -> f32 {
- unsafe { cmath::atan2f(self, other) }
+ cmath::atan2f(self, other)
}
/// Simultaneously computes the sine and cosine of the number, `x`. Returns
@@ -919,7 +919,7 @@ pub fn sin_cos(self) -> (f32, f32) {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn exp_m1(self) -> f32 {
- unsafe { cmath::expm1f(self) }
+ cmath::expm1f(self)
}
/// Returns `ln(1+n)` (natural logarithm) more accurately than if
@@ -957,7 +957,7 @@ pub fn exp_m1(self) -> f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn ln_1p(self) -> f32 {
- unsafe { cmath::log1pf(self) }
+ cmath::log1pf(self)
}
/// Hyperbolic sine function.
@@ -987,7 +987,7 @@ pub fn ln_1p(self) -> f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn sinh(self) -> f32 {
- unsafe { cmath::sinhf(self) }
+ cmath::sinhf(self)
}
/// Hyperbolic cosine function.
@@ -1017,7 +1017,7 @@ pub fn sinh(self) -> f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn cosh(self) -> f32 {
- unsafe { cmath::coshf(self) }
+ cmath::coshf(self)
}
/// Hyperbolic tangent function.
@@ -1047,7 +1047,7 @@ pub fn cosh(self) -> f32 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn tanh(self) -> f32 {
- unsafe { cmath::tanhf(self) }
+ cmath::tanhf(self)
}
/// Inverse hyperbolic sine function.
@@ -1158,7 +1158,7 @@ pub fn atanh(self) -> f32 {
#[unstable(feature = "float_gamma", issue = "99842")]
#[inline]
pub fn gamma(self) -> f32 {
- unsafe { cmath::tgammaf(self) }
+ cmath::tgammaf(self)
}
/// Natural logarithm of the absolute value of the gamma function
@@ -1188,7 +1188,7 @@ pub fn gamma(self) -> f32 {
#[inline]
pub fn ln_gamma(self) -> (f32, i32) {
let mut signgamp: i32 = 0;
- let x = unsafe { cmath::lgammaf_r(self, &mut signgamp) };
+ let x = cmath::lgammaf_r(self, &mut signgamp);
(x, signgamp)
}
@@ -1224,7 +1224,7 @@ pub fn ln_gamma(self) -> (f32, i32) {
#[unstable(feature = "float_erf", issue = "136321")]
#[inline]
pub fn erf(self) -> f32 {
- unsafe { cmath::erff(self) }
+ cmath::erff(self)
}
/// Complementary error function.
@@ -1253,6 +1253,6 @@ pub fn erf(self) -> f32 {
#[unstable(feature = "float_erf", issue = "136321")]
#[inline]
pub fn erfc(self) -> f32 {
- unsafe { cmath::erfcf(self) }
+ cmath::erfcf(self)
}
}
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 2aaab3f..84fd9bf 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -599,7 +599,7 @@ pub fn log10(self) -> f64 {
filing an issue describing your use-case too)."
)]
pub fn abs_sub(self, other: f64) -> f64 {
- unsafe { cmath::fdim(self, other) }
+ cmath::fdim(self, other)
}
/// Returns the cube root of a number.
@@ -626,7 +626,7 @@ pub fn abs_sub(self, other: f64) -> f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn cbrt(self) -> f64 {
- unsafe { cmath::cbrt(self) }
+ cmath::cbrt(self)
}
/// Compute the distance between the origin and a point (`x`, `y`) on the
@@ -657,7 +657,7 @@ pub fn cbrt(self) -> f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn hypot(self, other: f64) -> f64 {
- unsafe { cmath::hypot(self, other) }
+ cmath::hypot(self, other)
}
/// Computes the sine of a number (in radians).
@@ -730,7 +730,7 @@ pub fn cos(self) -> f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn tan(self) -> f64 {
- unsafe { cmath::tan(self) }
+ cmath::tan(self)
}
/// Computes the arcsine of a number. Return value is in radians in
@@ -760,7 +760,7 @@ pub fn tan(self) -> f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn asin(self) -> f64 {
- unsafe { cmath::asin(self) }
+ cmath::asin(self)
}
/// Computes the arccosine of a number. Return value is in radians in
@@ -790,7 +790,7 @@ pub fn asin(self) -> f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn acos(self) -> f64 {
- unsafe { cmath::acos(self) }
+ cmath::acos(self)
}
/// Computes the arctangent of a number. Return value is in radians in the
@@ -819,7 +819,7 @@ pub fn acos(self) -> f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn atan(self) -> f64 {
- unsafe { cmath::atan(self) }
+ cmath::atan(self)
}
/// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`) in radians.
@@ -860,7 +860,7 @@ pub fn atan(self) -> f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn atan2(self, other: f64) -> f64 {
- unsafe { cmath::atan2(self, other) }
+ cmath::atan2(self, other)
}
/// Simultaneously computes the sine and cosine of the number, `x`. Returns
@@ -919,7 +919,7 @@ pub fn sin_cos(self) -> (f64, f64) {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn exp_m1(self) -> f64 {
- unsafe { cmath::expm1(self) }
+ cmath::expm1(self)
}
/// Returns `ln(1+n)` (natural logarithm) more accurately than if
@@ -957,7 +957,7 @@ pub fn exp_m1(self) -> f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn ln_1p(self) -> f64 {
- unsafe { cmath::log1p(self) }
+ cmath::log1p(self)
}
/// Hyperbolic sine function.
@@ -987,7 +987,7 @@ pub fn ln_1p(self) -> f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn sinh(self) -> f64 {
- unsafe { cmath::sinh(self) }
+ cmath::sinh(self)
}
/// Hyperbolic cosine function.
@@ -1017,7 +1017,7 @@ pub fn sinh(self) -> f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn cosh(self) -> f64 {
- unsafe { cmath::cosh(self) }
+ cmath::cosh(self)
}
/// Hyperbolic tangent function.
@@ -1047,7 +1047,7 @@ pub fn cosh(self) -> f64 {
#[stable(feature = "rust1", since = "1.0.0")]
#[inline]
pub fn tanh(self) -> f64 {
- unsafe { cmath::tanh(self) }
+ cmath::tanh(self)
}
/// Inverse hyperbolic sine function.
@@ -1158,7 +1158,7 @@ pub fn atanh(self) -> f64 {
#[unstable(feature = "float_gamma", issue = "99842")]
#[inline]
pub fn gamma(self) -> f64 {
- unsafe { cmath::tgamma(self) }
+ cmath::tgamma(self)
}
/// Natural logarithm of the absolute value of the gamma function
@@ -1188,7 +1188,7 @@ pub fn gamma(self) -> f64 {
#[inline]
pub fn ln_gamma(self) -> (f64, i32) {
let mut signgamp: i32 = 0;
- let x = unsafe { cmath::lgamma_r(self, &mut signgamp) };
+ let x = cmath::lgamma_r(self, &mut signgamp);
(x, signgamp)
}
@@ -1224,7 +1224,7 @@ pub fn ln_gamma(self) -> (f64, i32) {
#[unstable(feature = "float_erf", issue = "136321")]
#[inline]
pub fn erf(self) -> f64 {
- unsafe { cmath::erf(self) }
+ cmath::erf(self)
}
/// Complementary error function.
@@ -1253,6 +1253,6 @@ pub fn erf(self) -> f64 {
#[unstable(feature = "float_erf", issue = "136321")]
#[inline]
pub fn erfc(self) -> f64 {
- unsafe { cmath::erfc(self) }
+ cmath::erfc(self)
}
}
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 2498fb8..cf3778b 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -48,6 +48,7 @@
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(bootstrap), doc(search_unbox))]
pub type Result<T> = result::Result<T, Error>;
/// The error type for I/O operations of the [`Read`], [`Write`], [`Seek`], and
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index b6545ea..5242261 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -2658,6 +2658,10 @@ pub fn into_inner(self) -> (T, U) {
/// Gets references to the underlying readers in this `Chain`.
///
+ /// Care should be taken to avoid modifying the internal I/O state of the
+ /// underlying readers as doing so may corrupt the internal state of this
+ /// `Chain`.
+ ///
/// # Examples
///
/// ```no_run
@@ -2915,6 +2919,10 @@ pub fn into_inner(self) -> T {
/// Gets a reference to the underlying reader.
///
+ /// Care should be taken to avoid modifying the internal I/O state of the
+ /// underlying reader as doing so may corrupt the internal limit of this
+ /// `Take`.
+ ///
/// # Examples
///
/// ```no_run
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 5c38118..3a52b77 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -312,7 +312,6 @@
#![feature(needs_panic_runtime)]
#![feature(negative_impls)]
#![feature(never_type)]
-#![feature(no_sanitize)]
#![feature(optimize_attribute)]
#![feature(prelude_import)]
#![feature(rustc_attrs)]
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 980213b..7cd20c4 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -353,6 +353,15 @@ fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) {
}
}
+/// Checks whether the string is valid as a file extension, or panics otherwise.
+fn validate_extension(extension: &OsStr) {
+ for &b in extension.as_encoded_bytes() {
+ if is_sep_byte(b) {
+ panic!("extension cannot contain path separators: {extension:?}");
+ }
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// The core iterators
////////////////////////////////////////////////////////////////////////////////
@@ -1507,13 +1516,7 @@ pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
}
fn _set_extension(&mut self, extension: &OsStr) -> bool {
- for &b in extension.as_encoded_bytes() {
- if b < 128 {
- if is_separator(b as char) {
- panic!("extension cannot contain path separators: {:?}", extension);
- }
- }
- }
+ validate_extension(extension);
let file_stem = match self.file_stem() {
None => return false,
@@ -1541,6 +1544,11 @@ fn _set_extension(&mut self, extension: &OsStr) -> bool {
/// Returns `false` and does nothing if [`self.file_name`] is [`None`],
/// returns `true` and updates the extension otherwise.
///
+ /// # Panics
+ ///
+ /// Panics if the passed extension contains a path separator (see
+ /// [`is_separator`]).
+ ///
/// # Caveats
///
/// The appended `extension` may contain dots and will be used in its entirety,
@@ -1582,6 +1590,8 @@ pub fn add_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
}
fn _add_extension(&mut self, extension: &OsStr) -> bool {
+ validate_extension(extension);
+
let file_name = match self.file_name() {
None => return false,
Some(f) => f.as_encoded_bytes(),
@@ -3265,7 +3275,7 @@ fn hash<H: Hasher>(&self, h: &mut H) {
if !verbatim {
component_start += match tail {
[b'.'] => 1,
- [b'.', sep @ _, ..] if is_sep_byte(*sep) => 1,
+ [b'.', sep, ..] if is_sep_byte(*sep) => 1,
_ => 0,
};
}
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index da51801..76ce7bc 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -1286,6 +1286,40 @@ pub struct Output {
pub stderr: Vec<u8>,
}
+impl Output {
+ /// Returns an error if a nonzero exit status was received.
+ ///
+ /// If the [`Command`] exited successfully,
+ /// `self` is returned.
+ ///
+ /// This is equivalent to calling [`exit_ok`](ExitStatus::exit_ok)
+ /// on [`Output.status`](Output::status).
+ ///
+ /// Note that this will throw away the [`Output::stderr`] field in the error case.
+ /// If the child process outputs useful informantion to stderr, you can:
+ /// * Use `cmd.stderr(Stdio::inherit())` to forward the
+ /// stderr child process to the parent's stderr,
+ /// usually printing it to console where the user can see it.
+ /// This is usually correct for command-line applications.
+ /// * Capture `stderr` using a custom error type.
+ /// This is usually correct for libraries.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(exit_status_error)]
+ /// # #[cfg(unix)] {
+ /// use std::process::Command;
+ /// assert!(Command::new("false").output().unwrap().exit_ok().is_err());
+ /// # }
+ /// ```
+ #[unstable(feature = "exit_status_error", issue = "84908")]
+ pub fn exit_ok(self) -> Result<Self, ExitStatusError> {
+ self.status.exit_ok()?;
+ Ok(self)
+ }
+}
+
// If either stderr or stdout are valid utf8 strings it prints the valid
// strings, otherwise it prints the byte sequence instead
#[stable(feature = "process_output_debug", since = "1.7.0")]
diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs
index 3a22a16..9737b2f 100644
--- a/library/std/src/rt.rs
+++ b/library/std/src/rt.rs
@@ -46,7 +46,7 @@ macro_rules! rtprintpanic {
macro_rules! rtabort {
($($t:tt)*) => {
{
- rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*));
+ rtprintpanic!("fatal runtime error: {}, aborting\n", format_args!($($t)*));
crate::sys::abort_internal();
}
}
diff --git a/library/std/src/sync/mpmc/list.rs b/library/std/src/sync/mpmc/list.rs
index d88914f..1c6acb2 100644
--- a/library/std/src/sync/mpmc/list.rs
+++ b/library/std/src/sync/mpmc/list.rs
@@ -213,6 +213,11 @@ fn start_send(&self, token: &mut Token) -> bool {
.compare_exchange(block, new, Ordering::Release, Ordering::Relaxed)
.is_ok()
{
+ // This yield point leaves the channel in a half-initialized state where the
+ // tail.block pointer is set but the head.block is not. This is used to
+ // facilitate the test in src/tools/miri/tests/pass/issues/issue-139553.rs
+ #[cfg(miri)]
+ crate::thread::yield_now();
self.head.block.store(new, Ordering::Release);
block = new;
} else {
@@ -564,9 +569,15 @@ fn discard_all_messages(&self) {
// In that case, just wait until it gets initialized.
while block.is_null() {
backoff.spin_heavy();
- block = self.head.block.load(Ordering::Acquire);
+ block = self.head.block.swap(ptr::null_mut(), Ordering::AcqRel);
}
}
+ // After this point `head.block` is not modified again and it will be deallocated if it's
+ // non-null. The `Drop` code of the channel, which runs after this function, also attempts
+ // to deallocate `head.block` if it's non-null. Therefore this function must maintain the
+ // invariant that if a deallocation of head.block is attemped then it must also be set to
+ // NULL. Failing to do so will lead to the Drop code attempting a double free. For this
+ // reason both reads above do an atomic swap instead of a simple atomic load.
unsafe {
// Drop all messages between head and tail and deallocate the heap-allocated blocks.
diff --git a/library/std/src/sys/alloc/sgx.rs b/library/std/src/sys/alloc/sgx.rs
index f5c2768..7a846e2 100644
--- a/library/std/src/sys/alloc/sgx.rs
+++ b/library/std/src/sys/alloc/sgx.rs
@@ -10,8 +10,10 @@
// The current allocator here is the `dlmalloc` crate which we've got included
// in the rust-lang/rust repository as a submodule. The crate is a port of
// dlmalloc.c from C to Rust.
+//
+// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
#[cfg_attr(test, linkage = "available_externally")]
-#[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx5alloc8DLMALLOCE")]
+#[unsafe(export_name = "_ZN16__rust_internals3std3sys5alloc3sgx8DLMALLOCE")]
static DLMALLOC: SpinMutex<dlmalloc::Dlmalloc<Sgx>> =
SpinMutex::new(dlmalloc::Dlmalloc::new_with_allocator(Sgx {}));
diff --git a/library/std/src/sys/args/common.rs b/library/std/src/sys/args/common.rs
new file mode 100644
index 0000000..43ac5e9
--- /dev/null
+++ b/library/std/src/sys/args/common.rs
@@ -0,0 +1,43 @@
+use crate::ffi::OsString;
+use crate::{fmt, vec};
+
+pub struct Args {
+ iter: vec::IntoIter<OsString>,
+}
+
+impl !Send for Args {}
+impl !Sync for Args {}
+
+impl Args {
+ pub(super) fn new(args: Vec<OsString>) -> Self {
+ Args { iter: args.into_iter() }
+ }
+}
+
+impl fmt::Debug for Args {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.iter.as_slice().fmt(f)
+ }
+}
+
+impl Iterator for Args {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize {
+ self.iter.len()
+ }
+}
+
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> {
+ self.iter.next_back()
+ }
+}
diff --git a/library/std/src/sys/args/mod.rs b/library/std/src/sys/args/mod.rs
new file mode 100644
index 0000000..6a37b32
--- /dev/null
+++ b/library/std/src/sys/args/mod.rs
@@ -0,0 +1,34 @@
+//! Platform-dependent command line arguments abstraction.
+
+#![forbid(unsafe_op_in_unsafe_fn)]
+
+cfg_if::cfg_if! {
+ if #[cfg(any(
+ all(target_family = "unix", not(any(target_os = "espidf", target_os = "vita"))),
+ target_os = "hermit",
+ ))] {
+ mod unix;
+ pub use unix::*;
+ } else if #[cfg(target_family = "windows")] {
+ mod windows;
+ pub use windows::*;
+ } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
+ mod sgx;
+ pub use sgx::*;
+ } else if #[cfg(target_os = "uefi")] {
+ mod uefi;
+ pub use uefi::*;
+ } else if #[cfg(target_os = "wasi")] {
+ mod wasi;
+ pub use wasi::*;
+ } else if #[cfg(target_os = "xous")] {
+ mod xous;
+ pub use xous::*;
+ } else if #[cfg(target_os = "zkvm")] {
+ mod zkvm;
+ pub use zkvm::*;
+ } else {
+ mod unsupported;
+ pub use unsupported::*;
+ }
+}
diff --git a/library/std/src/sys/pal/sgx/args.rs b/library/std/src/sys/args/sgx.rs
similarity index 83%
rename from library/std/src/sys/pal/sgx/args.rs
rename to library/std/src/sys/args/sgx.rs
index e62bf38..0185a8a 100644
--- a/library/std/src/sys/pal/sgx/args.rs
+++ b/library/std/src/sys/args/sgx.rs
@@ -1,11 +1,14 @@
-use super::abi::usercalls::alloc;
-use super::abi::usercalls::raw::ByteBuffer;
+#![allow(fuzzy_provenance_casts)] // FIXME: this module systematically confuses pointers and integers
+
use crate::ffi::OsString;
use crate::sync::atomic::{AtomicUsize, Ordering};
use crate::sys::os_str::Buf;
+use crate::sys::pal::abi::usercalls::alloc;
+use crate::sys::pal::abi::usercalls::raw::ByteBuffer;
use crate::sys_common::FromInner;
use crate::{fmt, slice};
+// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
#[cfg_attr(test, linkage = "available_externally")]
#[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx4args4ARGSE")]
static ARGS: AtomicUsize = AtomicUsize::new(0);
diff --git a/library/std/src/sys/pal/uefi/args.rs b/library/std/src/sys/args/uefi.rs
similarity index 79%
rename from library/std/src/sys/pal/uefi/args.rs
rename to library/std/src/sys/args/uefi.rs
index 0c29caf..84406c7 100644
--- a/library/std/src/sys/pal/uefi/args.rs
+++ b/library/std/src/sys/args/uefi.rs
@@ -1,14 +1,13 @@
use r_efi::protocols::loaded_image;
-use super::helpers;
use crate::env::current_exe;
use crate::ffi::OsString;
use crate::iter::Iterator;
-use crate::{fmt, vec};
+use crate::sys::pal::helpers;
-pub struct Args {
- parsed_args_list: vec::IntoIter<OsString>,
-}
+#[path = "common.rs"]
+mod common;
+pub use common::Args;
pub fn args() -> Args {
let lazy_current_exe = || Vec::from([current_exe().map(Into::into).unwrap_or_default()]);
@@ -22,51 +21,17 @@ pub fn args() -> Args {
let lp_size = unsafe { (*protocol.as_ptr()).load_options_size } as usize;
// Break if we are sure that it cannot be UTF-16
if lp_size < size_of::<u16>() || lp_size % size_of::<u16>() != 0 {
- return Args { parsed_args_list: lazy_current_exe().into_iter() };
+ return Args::new(lazy_current_exe());
}
let lp_size = lp_size / size_of::<u16>();
let lp_cmd_line = unsafe { (*protocol.as_ptr()).load_options as *const u16 };
if !lp_cmd_line.is_aligned() {
- return Args { parsed_args_list: lazy_current_exe().into_iter() };
+ return Args::new(lazy_current_exe());
}
let lp_cmd_line = unsafe { crate::slice::from_raw_parts(lp_cmd_line, lp_size) };
- Args {
- parsed_args_list: parse_lp_cmd_line(lp_cmd_line)
- .unwrap_or_else(lazy_current_exe)
- .into_iter(),
- }
-}
-
-impl fmt::Debug for Args {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.parsed_args_list.as_slice().fmt(f)
- }
-}
-
-impl Iterator for Args {
- type Item = OsString;
-
- fn next(&mut self) -> Option<OsString> {
- self.parsed_args_list.next()
- }
-
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.parsed_args_list.size_hint()
- }
-}
-
-impl ExactSizeIterator for Args {
- fn len(&self) -> usize {
- self.parsed_args_list.len()
- }
-}
-
-impl DoubleEndedIterator for Args {
- fn next_back(&mut self) -> Option<OsString> {
- self.parsed_args_list.next_back()
- }
+ Args::new(parse_lp_cmd_line(lp_cmd_line).unwrap_or_else(lazy_current_exe))
}
/// Implements the UEFI command-line argument parsing algorithm.
diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/args/unix.rs
similarity index 84%
rename from library/std/src/sys/pal/unix/args.rs
rename to library/std/src/sys/args/unix.rs
index 0bb7b64..c087fd6 100644
--- a/library/std/src/sys/pal/unix/args.rs
+++ b/library/std/src/sys/args/unix.rs
@@ -5,13 +5,19 @@
#![allow(dead_code)] // runtime init functions not used during testing
-use crate::ffi::{CStr, OsString};
+use crate::ffi::CStr;
+#[cfg(target_os = "hermit")]
+use crate::os::hermit::ffi::OsStringExt;
+#[cfg(not(target_os = "hermit"))]
use crate::os::unix::ffi::OsStringExt;
-use crate::{fmt, vec};
+
+#[path = "common.rs"]
+mod common;
+pub use common::Args;
/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) {
- imp::init(argc, argv)
+ unsafe { imp::init(argc, argv) }
}
/// Returns the command line arguments
@@ -55,42 +61,7 @@ pub fn args() -> Args {
vec.push(OsStringExt::from_vec(cstr.to_bytes().to_vec()));
}
- Args { iter: vec.into_iter() }
-}
-
-pub struct Args {
- iter: vec::IntoIter<OsString>,
-}
-
-impl !Send for Args {}
-impl !Sync for Args {}
-
-impl fmt::Debug for Args {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.iter.as_slice().fmt(f)
- }
-}
-
-impl Iterator for Args {
- type Item = OsString;
- fn next(&mut self) -> Option<OsString> {
- self.iter.next()
- }
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-}
-
-impl ExactSizeIterator for Args {
- fn len(&self) -> usize {
- self.iter.len()
- }
-}
-
-impl DoubleEndedIterator for Args {
- fn next_back(&mut self) -> Option<OsString> {
- self.iter.next_back()
- }
+ Args::new(vec)
}
#[cfg(any(
@@ -105,6 +76,7 @@ fn next_back(&mut self) -> Option<OsString> {
target_os = "illumos",
target_os = "emscripten",
target_os = "haiku",
+ target_os = "hermit",
target_os = "l4re",
target_os = "fuchsia",
target_os = "redox",
@@ -132,7 +104,7 @@ mod imp {
unsafe fn really_init(argc: isize, argv: *const *const u8) {
// These don't need to be ordered with each other or other stores,
- // because they only hold the unmodified system-provide argv/argc.
+ // because they only hold the unmodified system-provided argv/argc.
ARGC.store(argc, Ordering::Relaxed);
ARGV.store(argv as *mut _, Ordering::Relaxed);
}
@@ -141,7 +113,7 @@ unsafe fn really_init(argc: isize, argv: *const *const u8) {
pub unsafe fn init(argc: isize, argv: *const *const u8) {
// on GNU/Linux if we are main then we will init argv and argc twice, it "duplicates work"
// BUT edge-cases are real: only using .init_array can break most emulators, dlopen, etc.
- really_init(argc, argv);
+ unsafe { really_init(argc, argv) };
}
/// glibc passes argc, argv, and envp to functions in .init_array, as a non-standard extension.
@@ -159,9 +131,7 @@ extern "C" fn init_wrapper(
argv: *const *const u8,
_envp: *const *const u8,
) {
- unsafe {
- really_init(argc as isize, argv);
- }
+ unsafe { really_init(argc as isize, argv) };
}
init_wrapper
};
@@ -228,16 +198,3 @@ pub fn argc_argv() -> (isize, *const *const c_char) {
(argc as isize, argv.cast())
}
}
-
-#[cfg(any(target_os = "espidf", target_os = "vita"))]
-mod imp {
- use crate::ffi::c_char;
- use crate::ptr;
-
- #[inline(always)]
- pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
-
- pub fn argc_argv() -> (isize, *const *const c_char) {
- (0, ptr::null())
- }
-}
diff --git a/library/std/src/sys/pal/unsupported/args.rs b/library/std/src/sys/args/unsupported.rs
similarity index 100%
rename from library/std/src/sys/pal/unsupported/args.rs
rename to library/std/src/sys/args/unsupported.rs
diff --git a/library/std/src/sys/args/wasi.rs b/library/std/src/sys/args/wasi.rs
new file mode 100644
index 0000000..4795789
--- /dev/null
+++ b/library/std/src/sys/args/wasi.rs
@@ -0,0 +1,29 @@
+#![forbid(unsafe_op_in_unsafe_fn)]
+
+use crate::ffi::{CStr, OsStr, OsString};
+use crate::os::wasi::ffi::OsStrExt;
+
+#[path = "common.rs"]
+mod common;
+pub use common::Args;
+
+/// Returns the command line arguments
+pub fn args() -> Args {
+ Args::new(maybe_args().unwrap_or(Vec::new()))
+}
+
+fn maybe_args() -> Option<Vec<OsString>> {
+ unsafe {
+ let (argc, buf_size) = wasi::args_sizes_get().ok()?;
+ let mut argv = Vec::with_capacity(argc);
+ let mut buf = Vec::with_capacity(buf_size);
+ wasi::args_get(argv.as_mut_ptr(), buf.as_mut_ptr()).ok()?;
+ argv.set_len(argc);
+ let mut ret = Vec::with_capacity(argc);
+ for ptr in argv {
+ let s = CStr::from_ptr(ptr.cast());
+ ret.push(OsStr::from_bytes(s.to_bytes()).to_owned());
+ }
+ Some(ret)
+ }
+}
diff --git a/library/std/src/sys/pal/windows/args.rs b/library/std/src/sys/args/windows.rs
similarity index 94%
rename from library/std/src/sys/pal/windows/args.rs
rename to library/std/src/sys/args/windows.rs
index d973743..47f0e5f 100644
--- a/library/std/src/sys/pal/windows/args.rs
+++ b/library/std/src/sys/args/windows.rs
@@ -6,17 +6,21 @@
#[cfg(test)]
mod tests;
-use super::ensure_no_nuls;
-use super::os::current_exe;
use crate::ffi::{OsStr, OsString};
use crate::num::NonZero;
use crate::os::windows::prelude::*;
use crate::path::{Path, PathBuf};
+use crate::sys::pal::os::current_exe;
+use crate::sys::pal::{ensure_no_nuls, fill_utf16_buf};
use crate::sys::path::get_long_path;
use crate::sys::{c, to_u16s};
use crate::sys_common::AsInner;
use crate::sys_common::wstr::WStrUnits;
-use crate::{fmt, io, iter, vec};
+use crate::{io, iter, ptr};
+
+#[path = "common.rs"]
+mod common;
+pub use common::Args;
pub fn args() -> Args {
// SAFETY: `GetCommandLineW` returns a pointer to a null terminated UTF-16
@@ -27,7 +31,7 @@ pub fn args() -> Args {
current_exe().map(PathBuf::into_os_string).unwrap_or_else(|_| OsString::new())
});
- Args { parsed_args_list: parsed_args_list.into_iter() }
+ Args::new(parsed_args_list)
}
}
@@ -153,38 +157,6 @@ fn parse_lp_cmd_line<'a, F: Fn() -> OsString>(
ret_val
}
-pub struct Args {
- parsed_args_list: vec::IntoIter<OsString>,
-}
-
-impl fmt::Debug for Args {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.parsed_args_list.as_slice().fmt(f)
- }
-}
-
-impl Iterator for Args {
- type Item = OsString;
- fn next(&mut self) -> Option<OsString> {
- self.parsed_args_list.next()
- }
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.parsed_args_list.size_hint()
- }
-}
-
-impl DoubleEndedIterator for Args {
- fn next_back(&mut self) -> Option<OsString> {
- self.parsed_args_list.next_back()
- }
-}
-
-impl ExactSizeIterator for Args {
- fn len(&self) -> usize {
- self.parsed_args_list.len()
- }
-}
-
#[derive(Debug)]
pub(crate) enum Arg {
/// Add quotes (if needed)
@@ -384,9 +356,6 @@ pub(crate) fn to_user_path(path: &Path) -> io::Result<Vec<u16>> {
from_wide_to_user_path(to_u16s(path)?)
}
pub(crate) fn from_wide_to_user_path(mut path: Vec<u16>) -> io::Result<Vec<u16>> {
- use super::fill_utf16_buf;
- use crate::ptr;
-
// UTF-16 encoded code points, used in parsing and building UTF-16 paths.
// All of these are in the ASCII range so they can be cast directly to `u16`.
const SEP: u16 = b'\\' as _;
diff --git a/library/std/src/sys/pal/windows/args/tests.rs b/library/std/src/sys/args/windows/tests.rs
similarity index 100%
rename from library/std/src/sys/pal/windows/args/tests.rs
rename to library/std/src/sys/args/windows/tests.rs
diff --git a/library/std/src/sys/args/xous.rs b/library/std/src/sys/args/xous.rs
new file mode 100644
index 0000000..09a4728
--- /dev/null
+++ b/library/std/src/sys/args/xous.rs
@@ -0,0 +1,23 @@
+use crate::sys::pal::os::get_application_parameters;
+use crate::sys::pal::os::params::ArgumentList;
+
+#[path = "common.rs"]
+mod common;
+pub use common::Args;
+
+pub fn args() -> Args {
+ let Some(params) = get_application_parameters() else {
+ return Args::new(vec![]);
+ };
+
+ for param in params {
+ if let Ok(args) = ArgumentList::try_from(¶m) {
+ let mut parsed_args = vec![];
+ for arg in args {
+ parsed_args.push(arg.into());
+ }
+ return Args::new(parsed_args);
+ }
+ }
+ Args::new(vec![])
+}
diff --git a/library/std/src/sys/pal/zkvm/args.rs b/library/std/src/sys/args/zkvm.rs
similarity index 97%
rename from library/std/src/sys/pal/zkvm/args.rs
rename to library/std/src/sys/args/zkvm.rs
index 47857f6..194ba71 100644
--- a/library/std/src/sys/pal/zkvm/args.rs
+++ b/library/std/src/sys/args/zkvm.rs
@@ -1,7 +1,7 @@
-use super::{WORD_SIZE, abi};
use crate::ffi::OsString;
use crate::fmt;
use crate::sys::os_str;
+use crate::sys::pal::{WORD_SIZE, abi};
use crate::sys_common::FromInner;
pub struct Args {
diff --git a/library/std/src/sys/cmath.rs b/library/std/src/sys/cmath.rs
index c9969b4..668fd92 100644
--- a/library/std/src/sys/cmath.rs
+++ b/library/std/src/sys/cmath.rs
@@ -3,70 +3,70 @@
// These symbols are all defined by `libm`,
// or by `compiler-builtins` on unsupported platforms.
unsafe extern "C" {
- pub fn acos(n: f64) -> f64;
- pub fn asin(n: f64) -> f64;
- pub fn atan(n: f64) -> f64;
- pub fn atan2(a: f64, b: f64) -> f64;
- pub fn cbrt(n: f64) -> f64;
- pub fn cbrtf(n: f32) -> f32;
- pub fn cosh(n: f64) -> f64;
- pub fn expm1(n: f64) -> f64;
- pub fn expm1f(n: f32) -> f32;
- pub fn fdim(a: f64, b: f64) -> f64;
- pub fn fdimf(a: f32, b: f32) -> f32;
+ pub safe fn acos(n: f64) -> f64;
+ pub safe fn asin(n: f64) -> f64;
+ pub safe fn atan(n: f64) -> f64;
+ pub safe fn atan2(a: f64, b: f64) -> f64;
+ pub safe fn cbrt(n: f64) -> f64;
+ pub safe fn cbrtf(n: f32) -> f32;
+ pub safe fn cosh(n: f64) -> f64;
+ pub safe fn expm1(n: f64) -> f64;
+ pub safe fn expm1f(n: f32) -> f32;
+ pub safe fn fdim(a: f64, b: f64) -> f64;
+ pub safe fn fdimf(a: f32, b: f32) -> f32;
#[cfg_attr(target_env = "msvc", link_name = "_hypot")]
- pub fn hypot(x: f64, y: f64) -> f64;
+ pub safe fn hypot(x: f64, y: f64) -> f64;
#[cfg_attr(target_env = "msvc", link_name = "_hypotf")]
- pub fn hypotf(x: f32, y: f32) -> f32;
- pub fn log1p(n: f64) -> f64;
- pub fn log1pf(n: f32) -> f32;
- pub fn sinh(n: f64) -> f64;
- pub fn tan(n: f64) -> f64;
- pub fn tanh(n: f64) -> f64;
- pub fn tgamma(n: f64) -> f64;
- pub fn tgammaf(n: f32) -> f32;
- pub fn lgamma_r(n: f64, s: &mut i32) -> f64;
+ pub safe fn hypotf(x: f32, y: f32) -> f32;
+ pub safe fn log1p(n: f64) -> f64;
+ pub safe fn log1pf(n: f32) -> f32;
+ pub safe fn sinh(n: f64) -> f64;
+ pub safe fn tan(n: f64) -> f64;
+ pub safe fn tanh(n: f64) -> f64;
+ pub safe fn tgamma(n: f64) -> f64;
+ pub safe fn tgammaf(n: f32) -> f32;
+ pub safe fn lgamma_r(n: f64, s: &mut i32) -> f64;
#[cfg(not(target_os = "aix"))]
- pub fn lgammaf_r(n: f32, s: &mut i32) -> f32;
- pub fn erf(n: f64) -> f64;
- pub fn erff(n: f32) -> f32;
- pub fn erfc(n: f64) -> f64;
- pub fn erfcf(n: f32) -> f32;
+ pub safe fn lgammaf_r(n: f32, s: &mut i32) -> f32;
+ pub safe fn erf(n: f64) -> f64;
+ pub safe fn erff(n: f32) -> f32;
+ pub safe fn erfc(n: f64) -> f64;
+ pub safe fn erfcf(n: f32) -> f32;
- pub fn acosf128(n: f128) -> f128;
- pub fn asinf128(n: f128) -> f128;
- pub fn atanf128(n: f128) -> f128;
- pub fn atan2f128(a: f128, b: f128) -> f128;
- pub fn cbrtf128(n: f128) -> f128;
- pub fn coshf128(n: f128) -> f128;
- pub fn expm1f128(n: f128) -> f128;
- pub fn hypotf128(x: f128, y: f128) -> f128;
- pub fn log1pf128(n: f128) -> f128;
- pub fn sinhf128(n: f128) -> f128;
- pub fn tanf128(n: f128) -> f128;
- pub fn tanhf128(n: f128) -> f128;
- pub fn tgammaf128(n: f128) -> f128;
- pub fn lgammaf128_r(n: f128, s: &mut i32) -> f128;
- pub fn erff128(n: f128) -> f128;
- pub fn erfcf128(n: f128) -> f128;
+ pub safe fn acosf128(n: f128) -> f128;
+ pub safe fn asinf128(n: f128) -> f128;
+ pub safe fn atanf128(n: f128) -> f128;
+ pub safe fn atan2f128(a: f128, b: f128) -> f128;
+ pub safe fn cbrtf128(n: f128) -> f128;
+ pub safe fn coshf128(n: f128) -> f128;
+ pub safe fn expm1f128(n: f128) -> f128;
+ pub safe fn hypotf128(x: f128, y: f128) -> f128;
+ pub safe fn log1pf128(n: f128) -> f128;
+ pub safe fn sinhf128(n: f128) -> f128;
+ pub safe fn tanf128(n: f128) -> f128;
+ pub safe fn tanhf128(n: f128) -> f128;
+ pub safe fn tgammaf128(n: f128) -> f128;
+ pub safe fn lgammaf128_r(n: f128, s: &mut i32) -> f128;
+ pub safe fn erff128(n: f128) -> f128;
+ pub safe fn erfcf128(n: f128) -> f128;
cfg_if::cfg_if! {
if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] {
- pub fn acosf(n: f32) -> f32;
- pub fn asinf(n: f32) -> f32;
- pub fn atan2f(a: f32, b: f32) -> f32;
- pub fn atanf(n: f32) -> f32;
- pub fn coshf(n: f32) -> f32;
- pub fn sinhf(n: f32) -> f32;
- pub fn tanf(n: f32) -> f32;
- pub fn tanhf(n: f32) -> f32;
+ pub safe fn acosf(n: f32) -> f32;
+ pub safe fn asinf(n: f32) -> f32;
+ pub safe fn atan2f(a: f32, b: f32) -> f32;
+ pub safe fn atanf(n: f32) -> f32;
+ pub safe fn coshf(n: f32) -> f32;
+ pub safe fn sinhf(n: f32) -> f32;
+ pub safe fn tanf(n: f32) -> f32;
+ pub safe fn tanhf(n: f32) -> f32;
}}
}
// On AIX, we don't have lgammaf_r only the f64 version, so we can
// use the f64 version lgamma_r
#[cfg(target_os = "aix")]
-pub unsafe fn lgammaf_r(n: f32, s: &mut i32) -> f32 {
+pub fn lgammaf_r(n: f32, s: &mut i32) -> f32 {
lgamma_r(n.into(), s) as f32
}
@@ -76,42 +76,42 @@ pub unsafe fn lgammaf_r(n: f32, s: &mut i32) -> f32 {
cfg_if::cfg_if! {
if #[cfg(all(target_os = "windows", target_env = "msvc", target_arch = "x86"))] {
#[inline]
- pub unsafe fn acosf(n: f32) -> f32 {
+ pub fn acosf(n: f32) -> f32 {
f64::acos(n as f64) as f32
}
#[inline]
- pub unsafe fn asinf(n: f32) -> f32 {
+ pub fn asinf(n: f32) -> f32 {
f64::asin(n as f64) as f32
}
#[inline]
- pub unsafe fn atan2f(n: f32, b: f32) -> f32 {
+ pub fn atan2f(n: f32, b: f32) -> f32 {
f64::atan2(n as f64, b as f64) as f32
}
#[inline]
- pub unsafe fn atanf(n: f32) -> f32 {
+ pub fn atanf(n: f32) -> f32 {
f64::atan(n as f64) as f32
}
#[inline]
- pub unsafe fn coshf(n: f32) -> f32 {
+ pub fn coshf(n: f32) -> f32 {
f64::cosh(n as f64) as f32
}
#[inline]
- pub unsafe fn sinhf(n: f32) -> f32 {
+ pub fn sinhf(n: f32) -> f32 {
f64::sinh(n as f64) as f32
}
#[inline]
- pub unsafe fn tanf(n: f32) -> f32 {
+ pub fn tanf(n: f32) -> f32 {
f64::tan(n as f64) as f32
}
#[inline]
- pub unsafe fn tanhf(n: f32) -> f32 {
+ pub fn tanhf(n: f32) -> f32 {
f64::tanh(n as f64) as f32
}
}}
diff --git a/library/std/src/sys/pal/unix/env.rs b/library/std/src/sys/env_consts.rs
similarity index 75%
rename from library/std/src/sys/pal/unix/env.rs
rename to library/std/src/sys/env_consts.rs
index c660929..018d795 100644
--- a/library/std/src/sys/pal/unix/env.rs
+++ b/library/std/src/sys/env_consts.rs
@@ -1,106 +1,35 @@
-#[cfg(target_os = "linux")]
+//! Constants associated with each target.
+
+// Replaces the #[else] gate with #[cfg(not(any(…)))] of all the other gates.
+// This ensures that they must be mutually exclusive and do not have precedence
+// like cfg_if!.
+macro cfg_unordered(
+ $(#[cfg($cfg:meta)] $os:item)*
+ #[else] $fallback:item
+) {
+ $(#[cfg($cfg)] $os)*
+ #[cfg(not(any($($cfg),*)))] $fallback
+}
+
+// Keep entries sorted alphabetically and mutually exclusive.
+
+cfg_unordered! {
+
+#[cfg(target_os = "aix")]
pub mod os {
pub const FAMILY: &str = "unix";
- pub const OS: &str = "linux";
+ pub const OS: &str = "aix";
pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".so";
- pub const DLL_EXTENSION: &str = "so";
+ pub const DLL_SUFFIX: &str = ".a";
+ pub const DLL_EXTENSION: &str = "a";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
-#[cfg(target_os = "macos")]
+#[cfg(target_os = "android")]
pub mod os {
pub const FAMILY: &str = "unix";
- pub const OS: &str = "macos";
- pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".dylib";
- pub const DLL_EXTENSION: &str = "dylib";
- pub const EXE_SUFFIX: &str = "";
- pub const EXE_EXTENSION: &str = "";
-}
-
-#[cfg(target_os = "ios")]
-pub mod os {
- pub const FAMILY: &str = "unix";
- pub const OS: &str = "ios";
- pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".dylib";
- pub const DLL_EXTENSION: &str = "dylib";
- pub const EXE_SUFFIX: &str = "";
- pub const EXE_EXTENSION: &str = "";
-}
-
-#[cfg(target_os = "tvos")]
-pub mod os {
- pub const FAMILY: &str = "unix";
- pub const OS: &str = "tvos";
- pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".dylib";
- pub const DLL_EXTENSION: &str = "dylib";
- pub const EXE_SUFFIX: &str = "";
- pub const EXE_EXTENSION: &str = "";
-}
-
-#[cfg(target_os = "watchos")]
-pub mod os {
- pub const FAMILY: &str = "unix";
- pub const OS: &str = "watchos";
- pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".dylib";
- pub const DLL_EXTENSION: &str = "dylib";
- pub const EXE_SUFFIX: &str = "";
- pub const EXE_EXTENSION: &str = "";
-}
-
-#[cfg(target_os = "visionos")]
-pub mod os {
- pub const FAMILY: &str = "unix";
- pub const OS: &str = "visionos";
- pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".dylib";
- pub const DLL_EXTENSION: &str = "dylib";
- pub const EXE_SUFFIX: &str = "";
- pub const EXE_EXTENSION: &str = "";
-}
-
-#[cfg(target_os = "freebsd")]
-pub mod os {
- pub const FAMILY: &str = "unix";
- pub const OS: &str = "freebsd";
- pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".so";
- pub const DLL_EXTENSION: &str = "so";
- pub const EXE_SUFFIX: &str = "";
- pub const EXE_EXTENSION: &str = "";
-}
-
-#[cfg(target_os = "dragonfly")]
-pub mod os {
- pub const FAMILY: &str = "unix";
- pub const OS: &str = "dragonfly";
- pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".so";
- pub const DLL_EXTENSION: &str = "so";
- pub const EXE_SUFFIX: &str = "";
- pub const EXE_EXTENSION: &str = "";
-}
-
-#[cfg(target_os = "netbsd")]
-pub mod os {
- pub const FAMILY: &str = "unix";
- pub const OS: &str = "netbsd";
- pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".so";
- pub const DLL_EXTENSION: &str = "so";
- pub const EXE_SUFFIX: &str = "";
- pub const EXE_EXTENSION: &str = "";
-}
-
-#[cfg(target_os = "openbsd")]
-pub mod os {
- pub const FAMILY: &str = "unix";
- pub const OS: &str = "openbsd";
+ pub const OS: &str = "android";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
@@ -119,10 +48,10 @@ pub mod os {
pub const EXE_EXTENSION: &str = "exe";
}
-#[cfg(target_os = "android")]
+#[cfg(target_os = "dragonfly")]
pub mod os {
pub const FAMILY: &str = "unix";
- pub const OS: &str = "android";
+ pub const OS: &str = "dragonfly";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
@@ -130,10 +59,21 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}
-#[cfg(target_os = "solaris")]
+#[cfg(target_os = "emscripten")]
pub mod os {
pub const FAMILY: &str = "unix";
- pub const OS: &str = "solaris";
+ pub const OS: &str = "emscripten";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = ".js";
+ pub const EXE_EXTENSION: &str = "js";
+}
+
+#[cfg(target_os = "espidf")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "espidf";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
@@ -141,10 +81,21 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}
-#[cfg(target_os = "illumos")]
+#[cfg(target_os = "freebsd")]
pub mod os {
pub const FAMILY: &str = "unix";
- pub const OS: &str = "illumos";
+ pub const OS: &str = "freebsd";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "fuchsia")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "fuchsia";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
@@ -163,6 +114,17 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}
+#[cfg(target_os = "hermit")]
+pub mod os {
+ pub const FAMILY: &str = "";
+ pub const OS: &str = "hermit";
+ pub const DLL_PREFIX: &str = "";
+ pub const DLL_SUFFIX: &str = "";
+ pub const DLL_EXTENSION: &str = "";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
#[cfg(target_os = "horizon")]
pub mod os {
pub const FAMILY: &str = "unix";
@@ -185,35 +147,24 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}
-#[cfg(target_os = "vita")]
+#[cfg(target_os = "illumos")]
pub mod os {
pub const FAMILY: &str = "unix";
- pub const OS: &str = "vita";
+ pub const OS: &str = "illumos";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
- pub const EXE_SUFFIX: &str = ".elf";
- pub const EXE_EXTENSION: &str = "elf";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
}
-#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))]
+#[cfg(target_os = "ios")]
pub mod os {
pub const FAMILY: &str = "unix";
- pub const OS: &str = "emscripten";
+ pub const OS: &str = "ios";
pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".so";
- pub const DLL_EXTENSION: &str = "so";
- pub const EXE_SUFFIX: &str = ".js";
- pub const EXE_EXTENSION: &str = "js";
-}
-
-#[cfg(target_os = "fuchsia")]
-pub mod os {
- pub const FAMILY: &str = "unix";
- pub const OS: &str = "fuchsia";
- pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".so";
- pub const DLL_EXTENSION: &str = "so";
+ pub const DLL_SUFFIX: &str = ".dylib";
+ pub const DLL_EXTENSION: &str = "dylib";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
@@ -229,6 +180,39 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}
+#[cfg(target_os = "linux")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "linux";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "macos")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "macos";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".dylib";
+ pub const DLL_EXTENSION: &str = "dylib";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "netbsd")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "netbsd";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
#[cfg(target_os = "nto")]
pub mod os {
pub const FAMILY: &str = "unix";
@@ -240,6 +224,28 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}
+#[cfg(target_os = "nuttx")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "nuttx";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "openbsd")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "openbsd";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
#[cfg(target_os = "redox")]
pub mod os {
pub const FAMILY: &str = "unix";
@@ -262,6 +268,83 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}
+#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
+pub mod os {
+ pub const FAMILY: &str = "";
+ pub const OS: &str = "";
+ pub const DLL_PREFIX: &str = "";
+ pub const DLL_SUFFIX: &str = ".sgxs";
+ pub const DLL_EXTENSION: &str = "sgxs";
+ pub const EXE_SUFFIX: &str = ".sgxs";
+ pub const EXE_EXTENSION: &str = "sgxs";
+}
+
+#[cfg(target_os = "solaris")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "solaris";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "solid_asp3")]
+pub mod os {
+ pub const FAMILY: &str = "itron";
+ pub const OS: &str = "solid";
+ pub const DLL_PREFIX: &str = "";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "tvos")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "tvos";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".dylib";
+ pub const DLL_EXTENSION: &str = "dylib";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "uefi")]
+pub mod os {
+ pub const FAMILY: &str = "";
+ pub const OS: &str = "uefi";
+ pub const DLL_PREFIX: &str = "";
+ pub const DLL_SUFFIX: &str = "";
+ pub const DLL_EXTENSION: &str = "";
+ pub const EXE_SUFFIX: &str = ".efi";
+ pub const EXE_EXTENSION: &str = "efi";
+}
+
+#[cfg(target_os = "visionos")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "visionos";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".dylib";
+ pub const DLL_EXTENSION: &str = "dylib";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
+#[cfg(target_os = "vita")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "vita";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = ".elf";
+ pub const EXE_EXTENSION: &str = "elf";
+}
+
#[cfg(target_os = "vxworks")]
pub mod os {
pub const FAMILY: &str = "unix";
@@ -273,35 +356,49 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}
-#[cfg(target_os = "espidf")]
+#[cfg(all(target_family = "wasm", not(any(target_os = "emscripten", target_os = "linux"))))]
+pub mod os {
+ pub const FAMILY: &str = "";
+ pub const OS: &str = "";
+ pub const DLL_PREFIX: &str = "";
+ pub const DLL_SUFFIX: &str = ".wasm";
+ pub const DLL_EXTENSION: &str = "wasm";
+ pub const EXE_SUFFIX: &str = ".wasm";
+ pub const EXE_EXTENSION: &str = "wasm";
+}
+
+#[cfg(target_os = "watchos")]
pub mod os {
pub const FAMILY: &str = "unix";
- pub const OS: &str = "espidf";
+ pub const OS: &str = "watchos";
pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".so";
- pub const DLL_EXTENSION: &str = "so";
+ pub const DLL_SUFFIX: &str = ".dylib";
+ pub const DLL_EXTENSION: &str = "dylib";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
-#[cfg(target_os = "aix")]
+#[cfg(target_os = "windows")]
pub mod os {
- pub const FAMILY: &str = "unix";
- pub const OS: &str = "aix";
- pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".a";
- pub const DLL_EXTENSION: &str = "a";
+ pub const FAMILY: &str = "windows";
+ pub const OS: &str = "windows";
+ pub const DLL_PREFIX: &str = "";
+ pub const DLL_SUFFIX: &str = ".dll";
+ pub const DLL_EXTENSION: &str = "dll";
+ pub const EXE_SUFFIX: &str = ".exe";
+ pub const EXE_EXTENSION: &str = "exe";
+}
+
+// The fallback when none of the other gates match.
+#[else]
+pub mod os {
+ pub const FAMILY: &str = "";
+ pub const OS: &str = "";
+ pub const DLL_PREFIX: &str = "";
+ pub const DLL_SUFFIX: &str = "";
+ pub const DLL_EXTENSION: &str = "";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
-#[cfg(target_os = "nuttx")]
-pub mod os {
- pub const FAMILY: &str = "unix";
- pub const OS: &str = "nuttx";
- pub const DLL_PREFIX: &str = "lib";
- pub const DLL_SUFFIX: &str = ".so";
- pub const DLL_EXTENSION: &str = "so";
- pub const EXE_SUFFIX: &str = "";
- pub const EXE_EXTENSION: &str = "";
}
diff --git a/library/std/src/sys/fd/unix.rs b/library/std/src/sys/fd/unix.rs
index 2042ea2..cdca73c 100644
--- a/library/std/src/sys/fd/unix.rs
+++ b/library/std/src/sys/fd/unix.rs
@@ -71,9 +71,11 @@ const fn max_iov() -> usize {
target_os = "android",
target_os = "dragonfly",
target_os = "emscripten",
+ target_os = "espidf",
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
+ target_os = "nuttx",
target_os = "nto",
target_os = "openbsd",
target_os = "horizon",
@@ -257,9 +259,6 @@ fn preadv(
}
#[cfg(all(target_os = "android", target_pointer_width = "32"))]
- // FIXME(#115199): Rust currently omits weak function definitions
- // and its metadata from LLVM IR.
- #[no_sanitize(cfi)]
pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
weak!(
fn preadv64(
diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs
index 2217950..d55e280 100644
--- a/library/std/src/sys/fs/mod.rs
+++ b/library/std/src/sys/fs/mod.rs
@@ -20,6 +20,7 @@
mod windows;
use windows as imp;
pub use windows::{symlink_inner, junction_point};
+ use crate::sys::path::with_native_path;
} else if #[cfg(target_os = "hermit")] {
mod hermit;
use hermit as imp;
@@ -39,7 +40,7 @@
}
// FIXME: Replace this with platform-specific path conversion functions.
-#[cfg(not(target_family = "unix"))]
+#[cfg(not(any(target_family = "unix", target_os = "windows")))]
#[inline]
pub fn with_native_path<T>(path: &Path, f: &dyn Fn(&Path) -> io::Result<T>) -> io::Result<T> {
f(path)
@@ -51,7 +52,7 @@ pub fn with_native_path<T>(path: &Path, f: &dyn Fn(&Path) -> io::Result<T>) -> i
};
pub fn read_dir(path: &Path) -> io::Result<ReadDir> {
- // FIXME: use with_native_path
+ // FIXME: use with_native_path on all platforms
imp::readdir(path)
}
@@ -68,8 +69,11 @@ pub fn remove_dir(path: &Path) -> io::Result<()> {
}
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
- // FIXME: use with_native_path
- imp::remove_dir_all(path)
+ // FIXME: use with_native_path on all platforms
+ #[cfg(not(windows))]
+ return imp::remove_dir_all(path);
+ #[cfg(windows)]
+ with_native_path(path, &imp::remove_dir_all)
}
pub fn read_link(path: &Path) -> io::Result<PathBuf> {
@@ -77,6 +81,10 @@ pub fn read_link(path: &Path) -> io::Result<PathBuf> {
}
pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
+ // FIXME: use with_native_path on all platforms
+ #[cfg(windows)]
+ return imp::symlink(original, link);
+ #[cfg(not(windows))]
with_native_path(original, &|original| {
with_native_path(link, &|link| imp::symlink(original, link))
})
@@ -105,11 +113,17 @@ pub fn canonicalize(path: &Path) -> io::Result<PathBuf> {
}
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
- // FIXME: use with_native_path
- imp::copy(from, to)
+ // FIXME: use with_native_path on all platforms
+ #[cfg(not(windows))]
+ return imp::copy(from, to);
+ #[cfg(windows)]
+ with_native_path(from, &|from| with_native_path(to, &|to| imp::copy(from, to)))
}
pub fn exists(path: &Path) -> io::Result<bool> {
- // FIXME: use with_native_path
- imp::exists(path)
+ // FIXME: use with_native_path on all platforms
+ #[cfg(not(windows))]
+ return imp::exists(path);
+ #[cfg(windows)]
+ with_native_path(path, &imp::exists)
}
diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs
index 018e7e9..351a9f9 100644
--- a/library/std/src/sys/fs/unix.rs
+++ b/library/std/src/sys/fs/unix.rs
@@ -12,10 +12,11 @@
all(target_os = "linux", not(target_env = "musl")),
target_os = "android",
target_os = "fuchsia",
- target_os = "hurd"
+ target_os = "hurd",
+ target_os = "illumos",
))]
use libc::dirfd;
-#[cfg(target_os = "fuchsia")]
+#[cfg(any(target_os = "fuchsia", target_os = "illumos"))]
use libc::fstatat as fstatat64;
#[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))]
use libc::fstatat64;
@@ -892,7 +893,8 @@ pub fn file_name(&self) -> OsString {
all(target_os = "linux", not(target_env = "musl")),
target_os = "android",
target_os = "fuchsia",
- target_os = "hurd"
+ target_os = "hurd",
+ target_os = "illumos",
),
not(miri) // no dirfd on Miri
))]
@@ -922,6 +924,7 @@ pub fn metadata(&self) -> io::Result<FileAttr> {
target_os = "android",
target_os = "fuchsia",
target_os = "hurd",
+ target_os = "illumos",
)),
miri
))]
@@ -1463,20 +1466,6 @@ pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
Ok(())
}
- // FIXME(#115199): Rust currently omits weak function definitions
- // and its metadata from LLVM IR.
- #[cfg_attr(
- any(
- target_os = "android",
- all(
- target_os = "linux",
- target_env = "gnu",
- target_pointer_width = "32",
- not(target_arch = "riscv32")
- )
- ),
- no_sanitize(cfi)
- )]
pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
#[cfg(not(any(
target_os = "redox",
diff --git a/library/std/src/sys/fs/windows.rs b/library/std/src/sys/fs/windows.rs
index 15727c9..9215f93 100644
--- a/library/std/src/sys/fs/windows.rs
+++ b/library/std/src/sys/fs/windows.rs
@@ -12,7 +12,7 @@
use crate::sys::handle::Handle;
use crate::sys::pal::api::{self, WinError, set_file_information_by_handle};
use crate::sys::pal::{IoResult, fill_utf16_buf, to_u16s, truncate_utf16_at_nul};
-use crate::sys::path::maybe_verbatim;
+use crate::sys::path::{WCStr, maybe_verbatim};
use crate::sys::time::SystemTime;
use crate::sys::{Align8, c, cvt};
use crate::sys_common::{AsInner, FromInner, IntoInner};
@@ -298,10 +298,12 @@ fn get_flags_and_attributes(&self) -> u32 {
impl File {
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
let path = maybe_verbatim(path)?;
+ // SAFETY: maybe_verbatim returns null-terminated strings
+ let path = unsafe { WCStr::from_wchars_with_null_unchecked(&path) };
Self::open_native(&path, opts)
}
- fn open_native(path: &[u16], opts: &OpenOptions) -> io::Result<File> {
+ fn open_native(path: &WCStr, opts: &OpenOptions) -> io::Result<File> {
let creation = opts.get_creation_mode()?;
let handle = unsafe {
c::CreateFileW(
@@ -1212,9 +1214,8 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
}
}
-pub fn unlink(p: &Path) -> io::Result<()> {
- let p_u16s = maybe_verbatim(p)?;
- if unsafe { c::DeleteFileW(p_u16s.as_ptr()) } == 0 {
+pub fn unlink(path: &WCStr) -> io::Result<()> {
+ if unsafe { c::DeleteFileW(path.as_ptr()) } == 0 {
let err = api::get_last_error();
// if `DeleteFileW` fails with ERROR_ACCESS_DENIED then try to remove
// the file while ignoring the readonly attribute.
@@ -1223,7 +1224,7 @@ pub fn unlink(p: &Path) -> io::Result<()> {
let mut opts = OpenOptions::new();
opts.access_mode(c::DELETE);
opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT);
- if let Ok(f) = File::open_native(&p_u16s, &opts) {
+ if let Ok(f) = File::open_native(&path, &opts) {
if f.posix_delete().is_ok() {
return Ok(());
}
@@ -1236,10 +1237,7 @@ pub fn unlink(p: &Path) -> io::Result<()> {
}
}
-pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
- let old = maybe_verbatim(old)?;
- let new = maybe_verbatim(new)?;
-
+pub fn rename(old: &WCStr, new: &WCStr) -> io::Result<()> {
if unsafe { c::MoveFileExW(old.as_ptr(), new.as_ptr(), c::MOVEFILE_REPLACE_EXISTING) } == 0 {
let err = api::get_last_error();
// if `MoveFileExW` fails with ERROR_ACCESS_DENIED then try to move
@@ -1253,7 +1251,8 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
// Calculate the layout of the `FILE_RENAME_INFO` we pass to `SetFileInformation`
// This is a dynamically sized struct so we need to get the position of the last field to calculate the actual size.
- let Ok(new_len_without_nul_in_bytes): Result<u32, _> = ((new.len() - 1) * 2).try_into()
+ let Ok(new_len_without_nul_in_bytes): Result<u32, _> =
+ ((new.count_bytes() - 1) * 2).try_into()
else {
return Err(err).io_result();
};
@@ -1282,7 +1281,7 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
new.as_ptr().copy_to_nonoverlapping(
(&raw mut (*file_rename_info).FileName).cast::<u16>(),
- new.len(),
+ new.count_bytes(),
);
}
@@ -1309,20 +1308,19 @@ pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
Ok(())
}
-pub fn rmdir(p: &Path) -> io::Result<()> {
- let p = maybe_verbatim(p)?;
+pub fn rmdir(p: &WCStr) -> io::Result<()> {
cvt(unsafe { c::RemoveDirectoryW(p.as_ptr()) })?;
Ok(())
}
-pub fn remove_dir_all(path: &Path) -> io::Result<()> {
+pub fn remove_dir_all(path: &WCStr) -> io::Result<()> {
// Open a file or directory without following symlinks.
let mut opts = OpenOptions::new();
opts.access_mode(c::FILE_LIST_DIRECTORY);
// `FILE_FLAG_BACKUP_SEMANTICS` allows opening directories.
// `FILE_FLAG_OPEN_REPARSE_POINT` opens a link instead of its target.
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT);
- let file = File::open(path, &opts)?;
+ let file = File::open_native(path, &opts)?;
// Test if the file is not a directory or a symlink to a directory.
if (file.basic_info()?.FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) == 0 {
@@ -1333,14 +1331,14 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> {
remove_dir_all_iterative(file).io_result()
}
-pub fn readlink(path: &Path) -> io::Result<PathBuf> {
+pub fn readlink(path: &WCStr) -> io::Result<PathBuf> {
// Open the link with no access mode, instead of generic read.
// By default FILE_LIST_DIRECTORY is denied for the junction "C:\Documents and Settings", so
// this is needed for a common case.
let mut opts = OpenOptions::new();
opts.access_mode(0);
opts.custom_flags(c::FILE_FLAG_OPEN_REPARSE_POINT | c::FILE_FLAG_BACKUP_SEMANTICS);
- let file = File::open(path, &opts)?;
+ let file = File::open_native(&path, &opts)?;
file.readlink()
}
@@ -1378,19 +1376,17 @@ pub fn symlink_inner(original: &Path, link: &Path, dir: bool) -> io::Result<()>
}
#[cfg(not(target_vendor = "uwp"))]
-pub fn link(original: &Path, link: &Path) -> io::Result<()> {
- let original = maybe_verbatim(original)?;
- let link = maybe_verbatim(link)?;
+pub fn link(original: &WCStr, link: &WCStr) -> io::Result<()> {
cvt(unsafe { c::CreateHardLinkW(link.as_ptr(), original.as_ptr(), ptr::null_mut()) })?;
Ok(())
}
#[cfg(target_vendor = "uwp")]
-pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
+pub fn link(_original: &WCStr, _link: &WCStr) -> io::Result<()> {
return Err(io::const_error!(io::ErrorKind::Unsupported, "hard link are not supported on UWP"));
}
-pub fn stat(path: &Path) -> io::Result<FileAttr> {
+pub fn stat(path: &WCStr) -> io::Result<FileAttr> {
match metadata(path, ReparsePoint::Follow) {
Err(err) if err.raw_os_error() == Some(c::ERROR_CANT_ACCESS_FILE as i32) => {
if let Ok(attrs) = lstat(path) {
@@ -1404,7 +1400,7 @@ pub fn stat(path: &Path) -> io::Result<FileAttr> {
}
}
-pub fn lstat(path: &Path) -> io::Result<FileAttr> {
+pub fn lstat(path: &WCStr) -> io::Result<FileAttr> {
metadata(path, ReparsePoint::Open)
}
@@ -1420,7 +1416,7 @@ fn as_flag(self) -> u32 {
}
}
-fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
+fn metadata(path: &WCStr, reparse: ReparsePoint) -> io::Result<FileAttr> {
let mut opts = OpenOptions::new();
// No read or write permissions are necessary
opts.access_mode(0);
@@ -1429,7 +1425,7 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
// Attempt to open the file normally.
// If that fails with `ERROR_SHARING_VIOLATION` then retry using `FindFirstFileExW`.
// If the fallback fails for any reason we return the original error.
- match File::open(path, &opts) {
+ match File::open_native(&path, &opts) {
Ok(file) => file.file_attr(),
Err(e)
if [Some(c::ERROR_SHARING_VIOLATION as _), Some(c::ERROR_ACCESS_DENIED as _)]
@@ -1442,8 +1438,6 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
// However, there are special system files, such as
// `C:\hiberfil.sys`, that are locked in a way that denies even that.
unsafe {
- let path = maybe_verbatim(path)?;
-
// `FindFirstFileExW` accepts wildcard file names.
// Fortunately wildcards are not valid file names and
// `ERROR_SHARING_VIOLATION` means the file exists (but is locked)
@@ -1482,8 +1476,7 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
}
}
-pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
- let p = maybe_verbatim(p)?;
+pub fn set_perm(p: &WCStr, perm: FilePermissions) -> io::Result<()> {
unsafe {
cvt(c::SetFileAttributesW(p.as_ptr(), perm.attrs))?;
Ok(())
@@ -1499,17 +1492,17 @@ fn get_path(f: &File) -> io::Result<PathBuf> {
)
}
-pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
+pub fn canonicalize(p: &WCStr) -> io::Result<PathBuf> {
let mut opts = OpenOptions::new();
// No read or write permissions are necessary
opts.access_mode(0);
// This flag is so we can open directories too
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
- let f = File::open(p, &opts)?;
+ let f = File::open_native(p, &opts)?;
get_path(&f)
}
-pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+pub fn copy(from: &WCStr, to: &WCStr) -> io::Result<u64> {
unsafe extern "system" fn callback(
_TotalFileSize: i64,
_TotalBytesTransferred: i64,
@@ -1528,13 +1521,11 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
c::PROGRESS_CONTINUE
}
}
- let pfrom = maybe_verbatim(from)?;
- let pto = maybe_verbatim(to)?;
let mut size = 0i64;
cvt(unsafe {
c::CopyFileExW(
- pfrom.as_ptr(),
- pto.as_ptr(),
+ from.as_ptr(),
+ to.as_ptr(),
Some(callback),
(&raw mut size) as *mut _,
ptr::null_mut(),
@@ -1624,14 +1615,14 @@ pub struct MountPointBuffer {
}
// Try to see if a file exists but, unlike `exists`, report I/O errors.
-pub fn exists(path: &Path) -> io::Result<bool> {
+pub fn exists(path: &WCStr) -> io::Result<bool> {
// Open the file to ensure any symlinks are followed to their target.
let mut opts = OpenOptions::new();
// No read, write, etc access rights are needed.
opts.access_mode(0);
// Backup semantics enables opening directories as well as files.
opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS);
- match File::open(path, &opts) {
+ match File::open_native(path, &opts) {
Err(e) => match e.kind() {
// The file definitely does not exist
io::ErrorKind::NotFound => Ok(false),
diff --git a/library/std/src/sys/fs/windows/remove_dir_all.rs b/library/std/src/sys/fs/windows/remove_dir_all.rs
index f51eced..b213c49 100644
--- a/library/std/src/sys/fs/windows/remove_dir_all.rs
+++ b/library/std/src/sys/fs/windows/remove_dir_all.rs
@@ -95,7 +95,7 @@ fn open_link_no_reparse(
ObjectName: &mut path_str,
RootDirectory: parent.as_raw_handle(),
Attributes: ATTRIBUTES.load(Ordering::Relaxed),
- ..c::OBJECT_ATTRIBUTES::default()
+ ..c::OBJECT_ATTRIBUTES::with_length()
};
let share = c::FILE_SHARE_DELETE | c::FILE_SHARE_READ | c::FILE_SHARE_WRITE;
let options = c::FILE_OPEN_REPARSE_POINT | options;
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index f8f220f..e7b6319 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -9,8 +9,10 @@
mod personality;
pub mod anonymous_pipe;
+pub mod args;
pub mod backtrace;
pub mod cmath;
+pub mod env_consts;
pub mod exit_guard;
pub mod fd;
pub mod fs;
diff --git a/library/std/src/sys/net/connection/socket/unix.rs b/library/std/src/sys/net/connection/socket/unix.rs
index bbe1e03..b35d5d2 100644
--- a/library/std/src/sys/net/connection/socket/unix.rs
+++ b/library/std/src/sys/net/connection/socket/unix.rs
@@ -1,5 +1,6 @@
use libc::{MSG_PEEK, c_int, c_void, size_t, sockaddr, socklen_t};
+#[cfg(not(any(target_os = "espidf", target_os = "nuttx")))]
use crate::ffi::CStr;
use crate::io::{self, BorrowedBuf, BorrowedCursor, IoSlice, IoSliceMut};
use crate::net::{Shutdown, SocketAddr};
diff --git a/library/std/src/sys/pal/hermit/args.rs b/library/std/src/sys/pal/hermit/args.rs
deleted file mode 100644
index 4402426..0000000
--- a/library/std/src/sys/pal/hermit/args.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-use crate::ffi::{CStr, OsString, c_char};
-use crate::os::hermit::ffi::OsStringExt;
-use crate::sync::atomic::Ordering::{Acquire, Relaxed, Release};
-use crate::sync::atomic::{AtomicIsize, AtomicPtr};
-use crate::{fmt, ptr, vec};
-
-static ARGC: AtomicIsize = AtomicIsize::new(0);
-static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut());
-
-/// One-time global initialization.
-pub unsafe fn init(argc: isize, argv: *const *const u8) {
- ARGC.store(argc, Relaxed);
- // Use release ordering here to broadcast writes by the OS.
- ARGV.store(argv as *mut *const u8, Release);
-}
-
-/// Returns the command line arguments
-pub fn args() -> Args {
- // Synchronize with the store above.
- let argv = ARGV.load(Acquire);
- // If argv has not been initialized yet, do not return any arguments.
- let argc = if argv.is_null() { 0 } else { ARGC.load(Relaxed) };
- let args: Vec<OsString> = (0..argc)
- .map(|i| unsafe {
- let cstr = CStr::from_ptr(*argv.offset(i) as *const c_char);
- OsStringExt::from_vec(cstr.to_bytes().to_vec())
- })
- .collect();
-
- Args { iter: args.into_iter() }
-}
-
-pub struct Args {
- iter: vec::IntoIter<OsString>,
-}
-
-impl fmt::Debug for Args {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.iter.as_slice().fmt(f)
- }
-}
-
-impl !Send for Args {}
-impl !Sync for Args {}
-
-impl Iterator for Args {
- type Item = OsString;
- fn next(&mut self) -> Option<OsString> {
- self.iter.next()
- }
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-}
-
-impl ExactSizeIterator for Args {
- fn len(&self) -> usize {
- self.iter.len()
- }
-}
-
-impl DoubleEndedIterator for Args {
- fn next_back(&mut self) -> Option<OsString> {
- self.iter.next_back()
- }
-}
diff --git a/library/std/src/sys/pal/hermit/env.rs b/library/std/src/sys/pal/hermit/env.rs
deleted file mode 100644
index 7a0fcb3..0000000
--- a/library/std/src/sys/pal/hermit/env.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-pub mod os {
- pub const FAMILY: &str = "";
- pub const OS: &str = "hermit";
- pub const DLL_PREFIX: &str = "";
- pub const DLL_SUFFIX: &str = "";
- pub const DLL_EXTENSION: &str = "";
- pub const EXE_SUFFIX: &str = "";
- pub const EXE_EXTENSION: &str = "";
-}
diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs
index 26211bc..7063676 100644
--- a/library/std/src/sys/pal/hermit/mod.rs
+++ b/library/std/src/sys/pal/hermit/mod.rs
@@ -18,8 +18,6 @@
use crate::os::raw::c_char;
-pub mod args;
-pub mod env;
pub mod futex;
pub mod os;
#[path = "../unsupported/pipe.rs"]
@@ -58,7 +56,7 @@ pub extern "C" fn __rust_abort() {
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
unsafe {
- args::init(argc, argv);
+ crate::sys::args::init(argc, argv);
}
}
diff --git a/library/std/src/sys/pal/sgx/abi/tls/mod.rs b/library/std/src/sys/pal/sgx/abi/tls/mod.rs
index 8e2b271..f082d94 100644
--- a/library/std/src/sys/pal/sgx/abi/tls/mod.rs
+++ b/library/std/src/sys/pal/sgx/abi/tls/mod.rs
@@ -11,15 +11,17 @@
const TLS_KEYS: usize = 128; // Same as POSIX minimum
const TLS_KEYS_BITSET_SIZE: usize = (TLS_KEYS + (USIZE_BITS - 1)) / USIZE_BITS;
+// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
#[cfg_attr(test, linkage = "available_externally")]
-#[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx3abi3tls14TLS_KEY_IN_USEE")]
+#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx3abi3tls14TLS_KEY_IN_USEE")]
static TLS_KEY_IN_USE: SyncBitset = SYNC_BITSET_INIT;
macro_rules! dup {
((* $($exp:tt)*) $($val:tt)*) => (dup!( ($($exp)*) $($val)* $($val)* ));
(() $($val:tt)*) => ([$($val),*])
}
+// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
#[cfg_attr(test, linkage = "available_externally")]
-#[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx3abi3tls14TLS_DESTRUCTORE")]
+#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx3abi3tls14TLS_DESTRUCTORE")]
static TLS_DESTRUCTOR: [AtomicUsize; TLS_KEYS] = dup!((* * * * * * *) (AtomicUsize::new(0)));
unsafe extern "C" {
diff --git a/library/std/src/sys/pal/sgx/env.rs b/library/std/src/sys/pal/sgx/env.rs
deleted file mode 100644
index 8043b7c..0000000
--- a/library/std/src/sys/pal/sgx/env.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-pub mod os {
- pub const FAMILY: &str = "";
- pub const OS: &str = "";
- pub const DLL_PREFIX: &str = "";
- pub const DLL_SUFFIX: &str = ".sgxs";
- pub const DLL_EXTENSION: &str = "sgxs";
- pub const EXE_SUFFIX: &str = ".sgxs";
- pub const EXE_EXTENSION: &str = "sgxs";
-}
diff --git a/library/std/src/sys/pal/sgx/mod.rs b/library/std/src/sys/pal/sgx/mod.rs
index 52684e1..9973594 100644
--- a/library/std/src/sys/pal/sgx/mod.rs
+++ b/library/std/src/sys/pal/sgx/mod.rs
@@ -9,8 +9,6 @@
use crate::sync::atomic::{AtomicBool, Ordering};
pub mod abi;
-pub mod args;
-pub mod env;
mod libunwind_integration;
pub mod os;
#[path = "../unsupported/pipe.rs"]
@@ -24,7 +22,7 @@
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
unsafe {
- args::init(argc, argv);
+ crate::sys::args::init(argc, argv);
}
}
diff --git a/library/std/src/sys/pal/sgx/os.rs b/library/std/src/sys/pal/sgx/os.rs
index b1ec2af..010634c 100644
--- a/library/std/src/sys/pal/sgx/os.rs
+++ b/library/std/src/sys/pal/sgx/os.rs
@@ -73,11 +73,13 @@ pub fn current_exe() -> io::Result<PathBuf> {
unsupported()
}
+// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
#[cfg_attr(test, linkage = "available_externally")]
-#[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx2os3ENVE")]
+#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os3ENVE")]
static ENV: AtomicUsize = AtomicUsize::new(0);
+// Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
#[cfg_attr(test, linkage = "available_externally")]
-#[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx2os8ENV_INITE")]
+#[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx2os8ENV_INITE")]
static ENV_INIT: Once = Once::new();
type EnvStore = Mutex<HashMap<OsString, OsString>>;
diff --git a/library/std/src/sys/pal/sgx/thread.rs b/library/std/src/sys/pal/sgx/thread.rs
index b6932df..219ef1b 100644
--- a/library/std/src/sys/pal/sgx/thread.rs
+++ b/library/std/src/sys/pal/sgx/thread.rs
@@ -45,8 +45,9 @@ pub(super) fn run(self) -> JoinNotifier {
}
}
+ // Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests
#[cfg_attr(test, linkage = "available_externally")]
- #[unsafe(export_name = "_ZN16__rust_internals3std3sys3sgx6thread10TASK_QUEUEE")]
+ #[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx6thread10TASK_QUEUEE")]
static TASK_QUEUE: Mutex<Vec<Task>> = Mutex::new(Vec::new());
pub(super) fn lock() -> MutexGuard<'static, Vec<Task>> {
diff --git a/library/std/src/sys/pal/solid/env.rs b/library/std/src/sys/pal/solid/env.rs
deleted file mode 100644
index 6855c11..0000000
--- a/library/std/src/sys/pal/solid/env.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-pub mod os {
- pub const FAMILY: &str = "itron";
- pub const OS: &str = "solid";
- pub const DLL_PREFIX: &str = "";
- pub const DLL_SUFFIX: &str = ".so";
- pub const DLL_EXTENSION: &str = "so";
- pub const EXE_SUFFIX: &str = "";
- pub const EXE_EXTENSION: &str = "";
-}
diff --git a/library/std/src/sys/pal/solid/mod.rs b/library/std/src/sys/pal/solid/mod.rs
index 22052a1..0011cf2 100644
--- a/library/std/src/sys/pal/solid/mod.rs
+++ b/library/std/src/sys/pal/solid/mod.rs
@@ -16,9 +16,6 @@ pub mod itron {
use super::unsupported;
}
-#[path = "../unsupported/args.rs"]
-pub mod args;
-pub mod env;
// `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as
// `crate::sys::error`
pub(crate) mod error;
diff --git a/library/std/src/sys/pal/teeos/mod.rs b/library/std/src/sys/pal/teeos/mod.rs
index c1921a2..c7b1777 100644
--- a/library/std/src/sys/pal/teeos/mod.rs
+++ b/library/std/src/sys/pal/teeos/mod.rs
@@ -6,11 +6,6 @@
#![allow(unused_variables)]
#![allow(dead_code)]
-#[path = "../unsupported/args.rs"]
-pub mod args;
-#[path = "../unsupported/env.rs"]
-pub mod env;
-//pub mod fd;
pub mod os;
#[path = "../unsupported/pipe.rs"]
pub mod pipe;
diff --git a/library/std/src/sys/pal/trusty/mod.rs b/library/std/src/sys/pal/trusty/mod.rs
index 5295d3f..275f606 100644
--- a/library/std/src/sys/pal/trusty/mod.rs
+++ b/library/std/src/sys/pal/trusty/mod.rs
@@ -1,12 +1,8 @@
//! System bindings for the Trusty OS.
-#[path = "../unsupported/args.rs"]
-pub mod args;
#[path = "../unsupported/common.rs"]
#[deny(unsafe_op_in_unsafe_fn)]
mod common;
-#[path = "../unsupported/env.rs"]
-pub mod env;
#[path = "../unsupported/os.rs"]
pub mod os;
#[path = "../unsupported/pipe.rs"]
diff --git a/library/std/src/sys/pal/uefi/env.rs b/library/std/src/sys/pal/uefi/env.rs
deleted file mode 100644
index c106d5f..0000000
--- a/library/std/src/sys/pal/uefi/env.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-pub mod os {
- pub const FAMILY: &str = "";
- pub const OS: &str = "uefi";
- pub const DLL_PREFIX: &str = "";
- pub const DLL_SUFFIX: &str = "";
- pub const DLL_EXTENSION: &str = "";
- pub const EXE_SUFFIX: &str = ".efi";
- pub const EXE_EXTENSION: &str = "efi";
-}
diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs
index 9760a23..bd6a360 100644
--- a/library/std/src/sys/pal/uefi/mod.rs
+++ b/library/std/src/sys/pal/uefi/mod.rs
@@ -13,8 +13,6 @@
//! [`OsString`]: crate::ffi::OsString
#![forbid(unsafe_op_in_unsafe_fn)]
-pub mod args;
-pub mod env;
pub mod helpers;
pub mod os;
#[path = "../unsupported/pipe.rs"]
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index d7106c3..a4702ae 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -6,8 +6,6 @@
#[macro_use]
pub mod weak;
-pub mod args;
-pub mod env;
#[cfg(target_os = "fuchsia")]
pub mod fuchsia;
pub mod futex;
@@ -27,6 +25,7 @@
pub fn init(_argc: isize, _argv: *const *const u8, _sigpipe: u8) {}
#[cfg(not(target_os = "espidf"))]
+#[cfg_attr(target_os = "vita", allow(unused_variables))]
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
// See `fn init()` in `library/std/src/rt.rs` for docs on `sigpipe`.
@@ -47,7 +46,8 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
reset_sigpipe(sigpipe);
stack_overflow::init();
- args::init(argc, argv);
+ #[cfg(not(target_os = "vita"))]
+ crate::sys::args::init(argc, argv);
// Normally, `thread::spawn` will call `Thread::set_name` but since this thread
// already exists, we have to call it ourselves. We only do this on Apple targets
@@ -273,6 +273,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
libc::ETXTBSY => ExecutableFileBusy,
libc::EXDEV => CrossesDevices,
libc::EINPROGRESS => InProgress,
+ libc::EOPNOTSUPP => Unsupported,
libc::EACCES | libc::EPERM => PermissionDenied,
diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs
index 9078dd1..4cdc2ea 100644
--- a/library/std/src/sys/pal/unix/thread.rs
+++ b/library/std/src/sys/pal/unix/thread.rs
@@ -8,14 +8,19 @@
use crate::sys::{os, stack_overflow};
use crate::time::Duration;
use crate::{cmp, io, ptr};
-#[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))]
+#[cfg(not(any(
+ target_os = "l4re",
+ target_os = "vxworks",
+ target_os = "espidf",
+ target_os = "nuttx"
+)))]
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
#[cfg(target_os = "l4re")]
pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024;
#[cfg(target_os = "vxworks")]
pub const DEFAULT_MIN_STACK_SIZE: usize = 256 * 1024;
-#[cfg(target_os = "espidf")]
-pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF menuconfig system should be used
+#[cfg(any(target_os = "espidf", target_os = "nuttx"))]
+pub const DEFAULT_MIN_STACK_SIZE: usize = 0; // 0 indicates that the stack size configured in the ESP-IDF/NuttX menuconfig system should be used
#[cfg(target_os = "fuchsia")]
mod zircon {
@@ -52,10 +57,10 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
let mut attr: mem::MaybeUninit<libc::pthread_attr_t> = mem::MaybeUninit::uninit();
assert_eq!(libc::pthread_attr_init(attr.as_mut_ptr()), 0);
- #[cfg(target_os = "espidf")]
+ #[cfg(any(target_os = "espidf", target_os = "nuttx"))]
if stack > 0 {
// Only set the stack if a non-zero value is passed
- // 0 is used as an indication that the default stack size configured in the ESP-IDF menuconfig system should be used
+ // 0 is used as an indication that the default stack size configured in the ESP-IDF/NuttX menuconfig system should be used
assert_eq!(
libc::pthread_attr_setstacksize(
attr.as_mut_ptr(),
@@ -65,7 +70,7 @@ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
);
}
- #[cfg(not(target_os = "espidf"))]
+ #[cfg(not(any(target_os = "espidf", target_os = "nuttx")))]
{
let stack_size = cmp::max(stack, min_stack_size(attr.as_ptr()));
@@ -189,9 +194,6 @@ pub fn set_name(name: &CStr) {
}
#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))]
- // FIXME(#115199): Rust currently omits weak function definitions
- // and its metadata from LLVM IR.
- #[no_sanitize(cfi)]
pub fn set_name(name: &CStr) {
weak!(
fn pthread_setname_np(
diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs
index b8469b1..0074d76 100644
--- a/library/std/src/sys/pal/unix/time.rs
+++ b/library/std/src/sys/pal/unix/time.rs
@@ -96,17 +96,6 @@ const fn new(tv_sec: i64, tv_nsec: i64) -> Result<Timespec, io::Error> {
}
}
- // FIXME(#115199): Rust currently omits weak function definitions
- // and its metadata from LLVM IR.
- #[cfg_attr(
- all(
- target_os = "linux",
- target_env = "gnu",
- target_pointer_width = "32",
- not(target_arch = "riscv32")
- ),
- no_sanitize(cfi)
- )]
pub fn now(clock: libc::clockid_t) -> Timespec {
use crate::mem::MaybeUninit;
use crate::sys::cvt;
diff --git a/library/std/src/sys/pal/unix/weak.rs b/library/std/src/sys/pal/unix/weak.rs
index e4c814f..a034995 100644
--- a/library/std/src/sys/pal/unix/weak.rs
+++ b/library/std/src/sys/pal/unix/weak.rs
@@ -155,9 +155,6 @@ unsafe fn fetch(name: &str) -> *mut libc::c_void {
#[cfg(not(any(target_os = "linux", target_os = "android")))]
pub(crate) macro syscall {
(fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => (
- // FIXME(#115199): Rust currently omits weak function definitions
- // and its metadata from LLVM IR.
- #[no_sanitize(cfi)]
unsafe fn $name($($param: $t),*) -> $ret {
weak!(fn $name($($param: $t),*) -> $ret;);
diff --git a/library/std/src/sys/pal/unsupported/env.rs b/library/std/src/sys/pal/unsupported/env.rs
deleted file mode 100644
index d2efec5..0000000
--- a/library/std/src/sys/pal/unsupported/env.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-pub mod os {
- pub const FAMILY: &str = "";
- pub const OS: &str = "";
- pub const DLL_PREFIX: &str = "";
- pub const DLL_SUFFIX: &str = "";
- pub const DLL_EXTENSION: &str = "";
- pub const EXE_SUFFIX: &str = "";
- pub const EXE_EXTENSION: &str = "";
-}
diff --git a/library/std/src/sys/pal/unsupported/mod.rs b/library/std/src/sys/pal/unsupported/mod.rs
index 38838b9..5e3295b 100644
--- a/library/std/src/sys/pal/unsupported/mod.rs
+++ b/library/std/src/sys/pal/unsupported/mod.rs
@@ -1,7 +1,5 @@
#![deny(unsafe_op_in_unsafe_fn)]
-pub mod args;
-pub mod env;
pub mod os;
pub mod pipe;
pub mod thread;
diff --git a/library/std/src/sys/pal/wasi/args.rs b/library/std/src/sys/pal/wasi/args.rs
deleted file mode 100644
index 52cfa20..0000000
--- a/library/std/src/sys/pal/wasi/args.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-#![forbid(unsafe_op_in_unsafe_fn)]
-
-use crate::ffi::{CStr, OsStr, OsString};
-use crate::os::wasi::ffi::OsStrExt;
-use crate::{fmt, vec};
-
-pub struct Args {
- iter: vec::IntoIter<OsString>,
-}
-
-impl !Send for Args {}
-impl !Sync for Args {}
-
-/// Returns the command line arguments
-pub fn args() -> Args {
- Args { iter: maybe_args().unwrap_or(Vec::new()).into_iter() }
-}
-
-fn maybe_args() -> Option<Vec<OsString>> {
- unsafe {
- let (argc, buf_size) = wasi::args_sizes_get().ok()?;
- let mut argv = Vec::with_capacity(argc);
- let mut buf = Vec::with_capacity(buf_size);
- wasi::args_get(argv.as_mut_ptr(), buf.as_mut_ptr()).ok()?;
- argv.set_len(argc);
- let mut ret = Vec::with_capacity(argc);
- for ptr in argv {
- let s = CStr::from_ptr(ptr.cast());
- ret.push(OsStr::from_bytes(s.to_bytes()).to_owned());
- }
- Some(ret)
- }
-}
-
-impl fmt::Debug for Args {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.iter.as_slice().fmt(f)
- }
-}
-
-impl Iterator for Args {
- type Item = OsString;
- fn next(&mut self) -> Option<OsString> {
- self.iter.next()
- }
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.iter.size_hint()
- }
-}
-
-impl ExactSizeIterator for Args {
- fn len(&self) -> usize {
- self.iter.len()
- }
-}
-
-impl DoubleEndedIterator for Args {
- fn next_back(&mut self) -> Option<OsString> {
- self.iter.next_back()
- }
-}
diff --git a/library/std/src/sys/pal/wasi/env.rs b/library/std/src/sys/pal/wasi/env.rs
deleted file mode 100644
index 8d44498..0000000
--- a/library/std/src/sys/pal/wasi/env.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![forbid(unsafe_op_in_unsafe_fn)]
-
-pub mod os {
- pub const FAMILY: &str = "";
- pub const OS: &str = "";
- pub const DLL_PREFIX: &str = "";
- pub const DLL_SUFFIX: &str = ".wasm";
- pub const DLL_EXTENSION: &str = "wasm";
- pub const EXE_SUFFIX: &str = ".wasm";
- pub const EXE_EXTENSION: &str = "wasm";
-}
diff --git a/library/std/src/sys/pal/wasi/mod.rs b/library/std/src/sys/pal/wasi/mod.rs
index 80853e7..61dd1c3 100644
--- a/library/std/src/sys/pal/wasi/mod.rs
+++ b/library/std/src/sys/pal/wasi/mod.rs
@@ -13,8 +13,6 @@
//! compiling for wasm. That way it's a compile time error for something that's
//! guaranteed to be a runtime error!
-pub mod args;
-pub mod env;
#[allow(unused)]
#[path = "../wasm/atomics/futex.rs"]
pub mod futex;
diff --git a/library/std/src/sys/pal/wasip2/mod.rs b/library/std/src/sys/pal/wasip2/mod.rs
index 504b947..47fe322 100644
--- a/library/std/src/sys/pal/wasip2/mod.rs
+++ b/library/std/src/sys/pal/wasip2/mod.rs
@@ -6,10 +6,6 @@
//! To begin with, this target mirrors the wasi target 1 to 1, but over
//! time this will change significantly.
-#[path = "../wasi/args.rs"]
-pub mod args;
-#[path = "../wasi/env.rs"]
-pub mod env;
#[allow(unused)]
#[path = "../wasm/atomics/futex.rs"]
pub mod futex;
diff --git a/library/std/src/sys/pal/wasm/env.rs b/library/std/src/sys/pal/wasm/env.rs
deleted file mode 100644
index 730e356..0000000
--- a/library/std/src/sys/pal/wasm/env.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-pub mod os {
- pub const FAMILY: &str = "";
- pub const OS: &str = "";
- pub const DLL_PREFIX: &str = "";
- pub const DLL_SUFFIX: &str = ".wasm";
- pub const DLL_EXTENSION: &str = "wasm";
- pub const EXE_SUFFIX: &str = ".wasm";
- pub const EXE_EXTENSION: &str = "wasm";
-}
diff --git a/library/std/src/sys/pal/wasm/mod.rs b/library/std/src/sys/pal/wasm/mod.rs
index 8d39b70..37cb46a 100644
--- a/library/std/src/sys/pal/wasm/mod.rs
+++ b/library/std/src/sys/pal/wasm/mod.rs
@@ -16,9 +16,6 @@
#![deny(unsafe_op_in_unsafe_fn)]
-#[path = "../unsupported/args.rs"]
-pub mod args;
-pub mod env;
#[path = "../unsupported/os.rs"]
pub mod os;
#[path = "../unsupported/pipe.rs"]
diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs
index 004cbee..ac1c5e9 100644
--- a/library/std/src/sys/pal/windows/c.rs
+++ b/library/std/src/sys/pal/windows/c.rs
@@ -44,8 +44,8 @@ pub fn from_ref(slice: &[u16]) -> Self {
}
}
-impl Default for OBJECT_ATTRIBUTES {
- fn default() -> Self {
+impl OBJECT_ATTRIBUTES {
+ pub fn with_length() -> Self {
Self {
Length: size_of::<Self>() as _,
RootDirectory: ptr::null_mut(),
diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt
index e2c2163..d5fbb45 100644
--- a/library/std/src/sys/pal/windows/c/bindings.txt
+++ b/library/std/src/sys/pal/windows/c/bindings.txt
@@ -1,7 +1,8 @@
--out windows_sys.rs
--flat
--sys
---no-core
+--no-deps
+--link windows_targets
--filter
!INVALID_HANDLE_VALUE
ABOVE_NORMAL_PRIORITY_CLASS
@@ -19,7 +20,6 @@
ARM64_NT_NEON128
BELOW_NORMAL_PRIORITY_CLASS
bind
-BOOL
BY_HANDLE_FILE_INFORMATION
CALLBACK_CHUNK_FINISHED
CALLBACK_STREAM_SWITCH
diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs
index 1d0e89f..eb2914b 100644
--- a/library/std/src/sys/pal/windows/c/windows_sys.rs
+++ b/library/std/src/sys/pal/windows/c/windows_sys.rs
@@ -1,4 +1,4 @@
-// Bindings generated by `windows-bindgen` 0.59.0
+// Bindings generated by `windows-bindgen` 0.61.0
#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
@@ -141,7 +141,7 @@
windows_targets::link!("ws2_32.dll" "system" fn shutdown(s : SOCKET, how : WINSOCK_SHUTDOWN_HOW) -> i32);
pub const ABOVE_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 32768u32;
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct ACL {
pub AclRevision: u8,
pub Sbz1: u8,
@@ -162,6 +162,11 @@ pub struct ADDRINFOA {
pub ai_addr: *mut SOCKADDR,
pub ai_next: *mut ADDRINFOA,
}
+impl Default for ADDRINFOA {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub const AF_INET: ADDRESS_FAMILY = 2u16;
pub const AF_INET6: ADDRESS_FAMILY = 23u16;
pub const AF_UNIX: u16 = 1u16;
@@ -176,8 +181,13 @@ pub union ARM64_NT_NEON128 {
pub H: [u16; 8],
pub B: [u8; 16],
}
+impl Default for ARM64_NT_NEON128 {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct ARM64_NT_NEON128_0 {
pub Low: u64,
pub High: i64,
@@ -185,7 +195,7 @@ pub struct ARM64_NT_NEON128_0 {
pub const BELOW_NORMAL_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 16384u32;
pub type BOOL = i32;
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct BY_HANDLE_FILE_INFORMATION {
pub dwFileAttributes: u32,
pub ftCreationTime: FILETIME,
@@ -206,9 +216,14 @@ pub struct BY_HANDLE_FILE_INFORMATION {
pub struct CONDITION_VARIABLE {
pub Ptr: *mut core::ffi::c_void,
}
+impl Default for CONDITION_VARIABLE {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub type CONSOLE_MODE = u32;
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct CONSOLE_READCONSOLE_CONTROL {
pub nLength: u32,
pub nInitialChars: u32,
@@ -245,6 +260,12 @@ pub struct CONTEXT {
pub SegSs: u32,
pub ExtendedRegisters: [u8; 512],
}
+#[cfg(target_arch = "x86")]
+impl Default for CONTEXT {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))]
#[derive(Clone, Copy)]
@@ -296,6 +317,12 @@ pub struct CONTEXT {
pub LastExceptionToRip: u64,
pub LastExceptionFromRip: u64,
}
+#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))]
+impl Default for CONTEXT {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))]
#[derive(Clone, Copy)]
@@ -303,6 +330,12 @@ pub union CONTEXT_0 {
pub FltSave: XSAVE_FORMAT,
pub Anonymous: CONTEXT_0_0,
}
+#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))]
+impl Default for CONTEXT_0 {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))]
#[derive(Clone, Copy)]
@@ -326,6 +359,12 @@ pub struct CONTEXT_0_0 {
pub Xmm14: M128A,
pub Xmm15: M128A,
}
+#[cfg(any(target_arch = "arm64ec", target_arch = "x86_64"))]
+impl Default for CONTEXT_0_0 {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[cfg(target_arch = "aarch64")]
#[derive(Clone, Copy)]
@@ -343,6 +382,12 @@ pub struct CONTEXT {
pub Wcr: [u32; 2],
pub Wvr: [u64; 2],
}
+#[cfg(target_arch = "aarch64")]
+impl Default for CONTEXT {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[cfg(target_arch = "aarch64")]
#[derive(Clone, Copy)]
@@ -350,9 +395,15 @@ pub union CONTEXT_0 {
pub Anonymous: CONTEXT_0_0,
pub X: [u64; 31],
}
+#[cfg(target_arch = "aarch64")]
+impl Default for CONTEXT_0 {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[cfg(target_arch = "aarch64")]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct CONTEXT_0_0 {
pub X0: u64,
pub X1: u64,
@@ -2305,6 +2356,11 @@ pub struct EXCEPTION_POINTERS {
pub ExceptionRecord: *mut EXCEPTION_RECORD,
pub ContextRecord: *mut CONTEXT,
}
+impl Default for EXCEPTION_POINTERS {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct EXCEPTION_RECORD {
@@ -2315,6 +2371,11 @@ pub struct EXCEPTION_RECORD {
pub NumberParameters: u32,
pub ExceptionInformation: [usize; 15],
}
+impl Default for EXCEPTION_RECORD {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub const EXCEPTION_STACK_OVERFLOW: NTSTATUS = 0xC00000FD_u32 as _;
pub const EXTENDED_STARTUPINFO_PRESENT: PROCESS_CREATION_FLAGS = 524288u32;
pub const E_NOTIMPL: HRESULT = 0x80004001_u32 as _;
@@ -2333,8 +2394,13 @@ pub struct FD_SET {
pub fd_count: u32,
pub fd_array: [SOCKET; 64],
}
+impl Default for FD_SET {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct FILETIME {
pub dwLowDateTime: u32,
pub dwHighDateTime: u32,
@@ -2343,7 +2409,7 @@ pub struct FILETIME {
pub const FILE_ADD_FILE: FILE_ACCESS_RIGHTS = 2u32;
pub const FILE_ADD_SUBDIRECTORY: FILE_ACCESS_RIGHTS = 4u32;
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct FILE_ALLOCATION_INFO {
pub AllocationSize: i64,
}
@@ -2369,7 +2435,7 @@ pub struct FILE_ALLOCATION_INFO {
pub const FILE_ATTRIBUTE_SPARSE_FILE: FILE_FLAGS_AND_ATTRIBUTES = 512u32;
pub const FILE_ATTRIBUTE_SYSTEM: FILE_FLAGS_AND_ATTRIBUTES = 4u32;
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct FILE_ATTRIBUTE_TAG_INFO {
pub FileAttributes: u32,
pub ReparseTag: u32,
@@ -2378,7 +2444,7 @@ pub struct FILE_ATTRIBUTE_TAG_INFO {
pub const FILE_ATTRIBUTE_UNPINNED: FILE_FLAGS_AND_ATTRIBUTES = 1048576u32;
pub const FILE_ATTRIBUTE_VIRTUAL: FILE_FLAGS_AND_ATTRIBUTES = 65536u32;
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct FILE_BASIC_INFO {
pub CreationTime: i64,
pub LastAccessTime: i64,
@@ -2405,19 +2471,19 @@ pub struct FILE_BASIC_INFO {
pub const FILE_DISPOSITION_FLAG_ON_CLOSE: FILE_DISPOSITION_INFO_EX_FLAGS = 8u32;
pub const FILE_DISPOSITION_FLAG_POSIX_SEMANTICS: FILE_DISPOSITION_INFO_EX_FLAGS = 2u32;
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct FILE_DISPOSITION_INFO {
pub DeleteFile: bool,
}
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct FILE_DISPOSITION_INFO_EX {
pub Flags: FILE_DISPOSITION_INFO_EX_FLAGS,
}
pub type FILE_DISPOSITION_INFO_EX_FLAGS = u32;
pub const FILE_END: SET_FILE_POINTER_MOVE_METHOD = 2u32;
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct FILE_END_OF_FILE_INFO {
pub EndOfFile: i64,
}
@@ -2457,9 +2523,14 @@ pub struct FILE_ID_BOTH_DIR_INFO {
pub FileId: i64,
pub FileName: [u16; 1],
}
+impl Default for FILE_ID_BOTH_DIR_INFO {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub type FILE_INFO_BY_HANDLE_CLASS = i32;
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct FILE_IO_PRIORITY_HINT_INFO {
pub PriorityHint: PRIORITY_HINT,
}
@@ -2494,12 +2565,22 @@ pub struct FILE_RENAME_INFO {
pub FileNameLength: u32,
pub FileName: [u16; 1],
}
+impl Default for FILE_RENAME_INFO {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[derive(Clone, Copy)]
pub union FILE_RENAME_INFO_0 {
pub ReplaceIfExists: bool,
pub Flags: u32,
}
+impl Default for FILE_RENAME_INFO_0 {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub const FILE_RESERVE_OPFILTER: NTCREATEFILE_CREATE_OPTIONS = 1048576u32;
pub const FILE_SEQUENTIAL_ONLY: NTCREATEFILE_CREATE_OPTIONS = 4u32;
pub const FILE_SESSION_AWARE: NTCREATEFILE_CREATE_OPTIONS = 262144u32;
@@ -2509,7 +2590,7 @@ pub union FILE_RENAME_INFO_0 {
pub const FILE_SHARE_READ: FILE_SHARE_MODE = 1u32;
pub const FILE_SHARE_WRITE: FILE_SHARE_MODE = 2u32;
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct FILE_STANDARD_INFO {
pub AllocationSize: i64,
pub EndOfFile: i64,
@@ -2549,6 +2630,12 @@ pub struct FLOATING_SAVE_AREA {
pub RegisterArea: [u8; 80],
pub Spare0: u32,
}
+#[cfg(target_arch = "x86")]
+impl Default for FLOATING_SAVE_AREA {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))]
#[derive(Clone, Copy)]
@@ -2563,6 +2650,12 @@ pub struct FLOATING_SAVE_AREA {
pub RegisterArea: [u8; 80],
pub Cr0NpxState: u32,
}
+#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))]
+impl Default for FLOATING_SAVE_AREA {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub const FORMAT_MESSAGE_ALLOCATE_BUFFER: FORMAT_MESSAGE_OPTIONS = 256u32;
pub const FORMAT_MESSAGE_ARGUMENT_ARRAY: FORMAT_MESSAGE_OPTIONS = 8192u32;
pub const FORMAT_MESSAGE_FROM_HMODULE: FORMAT_MESSAGE_OPTIONS = 2048u32;
@@ -2639,12 +2732,22 @@ pub const fn from_u128(uuid: u128) -> Self {
pub struct IN6_ADDR {
pub u: IN6_ADDR_0,
}
+impl Default for IN6_ADDR {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[derive(Clone, Copy)]
pub union IN6_ADDR_0 {
pub Byte: [u8; 16],
pub Word: [u16; 8],
}
+impl Default for IN6_ADDR_0 {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub const INFINITE: u32 = 4294967295u32;
pub const INHERIT_CALLER_PRIORITY: PROCESS_CREATION_FLAGS = 131072u32;
pub const INHERIT_PARENT_AFFINITY: PROCESS_CREATION_FLAGS = 65536u32;
@@ -2653,6 +2756,11 @@ pub union IN6_ADDR_0 {
pub union INIT_ONCE {
pub Ptr: *mut core::ffi::c_void,
}
+impl Default for INIT_ONCE {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub const INIT_ONCE_INIT_FAILED: u32 = 4u32;
pub const INVALID_FILE_ATTRIBUTES: u32 = 4294967295u32;
pub const INVALID_SOCKET: SOCKET = -1i32 as _;
@@ -2661,6 +2769,11 @@ pub union INIT_ONCE {
pub struct IN_ADDR {
pub S_un: IN_ADDR_0,
}
+impl Default for IN_ADDR {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[derive(Clone, Copy)]
pub union IN_ADDR_0 {
@@ -2668,8 +2781,13 @@ pub union IN_ADDR_0 {
pub S_un_w: IN_ADDR_0_1,
pub S_addr: u32,
}
+impl Default for IN_ADDR_0 {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct IN_ADDR_0_0 {
pub s_b1: u8,
pub s_b2: u8,
@@ -2677,7 +2795,7 @@ pub struct IN_ADDR_0_0 {
pub s_b4: u8,
}
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct IN_ADDR_0_1 {
pub s_w1: u16,
pub s_w2: u16,
@@ -2690,12 +2808,22 @@ pub struct IO_STATUS_BLOCK {
pub Anonymous: IO_STATUS_BLOCK_0,
pub Information: usize,
}
+impl Default for IO_STATUS_BLOCK {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[derive(Clone, Copy)]
pub union IO_STATUS_BLOCK_0 {
pub Status: NTSTATUS,
pub Pointer: *mut core::ffi::c_void,
}
+impl Default for IO_STATUS_BLOCK_0 {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub type IPPROTO = i32;
pub const IPPROTO_AH: IPPROTO = 51i32;
pub const IPPROTO_CBT: IPPROTO = 7i32;
@@ -2742,6 +2870,11 @@ pub struct IPV6_MREQ {
pub ipv6mr_multiaddr: IN6_ADDR,
pub ipv6mr_interface: u32,
}
+impl Default for IPV6_MREQ {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub const IPV6_MULTICAST_LOOP: i32 = 11i32;
pub const IPV6_V6ONLY: i32 = 27i32;
pub const IP_ADD_MEMBERSHIP: i32 = 12i32;
@@ -2752,11 +2885,16 @@ pub struct IP_MREQ {
pub imr_multiaddr: IN_ADDR,
pub imr_interface: IN_ADDR,
}
+impl Default for IP_MREQ {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub const IP_MULTICAST_LOOP: i32 = 11i32;
pub const IP_MULTICAST_TTL: i32 = 10i32;
pub const IP_TTL: i32 = 4i32;
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct LINGER {
pub l_onoff: u16,
pub l_linger: u16,
@@ -2797,7 +2935,7 @@ pub struct LINGER {
),
>;
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct M128A {
pub Low: u64,
pub High: i64,
@@ -2838,6 +2976,11 @@ pub struct OBJECT_ATTRIBUTES {
pub SecurityDescriptor: *const SECURITY_DESCRIPTOR,
pub SecurityQualityOfService: *const SECURITY_QUALITY_OF_SERVICE,
}
+impl Default for OBJECT_ATTRIBUTES {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub type OBJECT_ATTRIBUTE_FLAGS = u32;
pub const OBJ_DONT_REPARSE: OBJECT_ATTRIBUTE_FLAGS = 4096u32;
pub const OPEN_ALWAYS: FILE_CREATION_DISPOSITION = 4u32;
@@ -2850,14 +2993,24 @@ pub struct OVERLAPPED {
pub Anonymous: OVERLAPPED_0,
pub hEvent: HANDLE,
}
+impl Default for OVERLAPPED {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[derive(Clone, Copy)]
pub union OVERLAPPED_0 {
pub Anonymous: OVERLAPPED_0_0,
pub Pointer: *mut core::ffi::c_void,
}
+impl Default for OVERLAPPED_0 {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct OVERLAPPED_0_0 {
pub Offset: u32,
pub OffsetHigh: u32,
@@ -2895,6 +3048,11 @@ pub struct PROCESS_INFORMATION {
pub dwProcessId: u32,
pub dwThreadId: u32,
}
+impl Default for PROCESS_INFORMATION {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub const PROCESS_MODE_BACKGROUND_BEGIN: PROCESS_CREATION_FLAGS = 1048576u32;
pub const PROCESS_MODE_BACKGROUND_END: PROCESS_CREATION_FLAGS = 2097152u32;
pub const PROFILE_KERNEL: PROCESS_CREATION_FLAGS = 536870912u32;
@@ -2926,6 +3084,11 @@ pub struct SECURITY_ATTRIBUTES {
pub lpSecurityDescriptor: *mut core::ffi::c_void,
pub bInheritHandle: BOOL,
}
+impl Default for SECURITY_ATTRIBUTES {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub const SECURITY_CONTEXT_TRACKING: FILE_FLAGS_AND_ATTRIBUTES = 262144u32;
pub const SECURITY_DELEGATION: FILE_FLAGS_AND_ATTRIBUTES = 196608u32;
#[repr(C)]
@@ -2939,13 +3102,18 @@ pub struct SECURITY_DESCRIPTOR {
pub Sacl: *mut ACL,
pub Dacl: *mut ACL,
}
+impl Default for SECURITY_DESCRIPTOR {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub type SECURITY_DESCRIPTOR_CONTROL = u16;
pub const SECURITY_EFFECTIVE_ONLY: FILE_FLAGS_AND_ATTRIBUTES = 524288u32;
pub const SECURITY_IDENTIFICATION: FILE_FLAGS_AND_ATTRIBUTES = 65536u32;
pub const SECURITY_IMPERSONATION: FILE_FLAGS_AND_ATTRIBUTES = 131072u32;
pub type SECURITY_IMPERSONATION_LEVEL = i32;
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct SECURITY_QUALITY_OF_SERVICE {
pub Length: u32,
pub ImpersonationLevel: SECURITY_IMPERSONATION_LEVEL,
@@ -2962,6 +3130,11 @@ pub struct SOCKADDR {
pub sa_family: ADDRESS_FAMILY,
pub sa_data: [i8; 14],
}
+impl Default for SOCKADDR {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct SOCKADDR_STORAGE {
@@ -2970,12 +3143,22 @@ pub struct SOCKADDR_STORAGE {
pub __ss_align: i64,
pub __ss_pad2: [i8; 112],
}
+impl Default for SOCKADDR_STORAGE {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct SOCKADDR_UN {
pub sun_family: ADDRESS_FAMILY,
pub sun_path: [i8; 108],
}
+impl Default for SOCKADDR_UN {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub type SOCKET = usize;
pub const SOCKET_ERROR: i32 = -1i32;
pub const SOCK_DGRAM: WINSOCK_SOCKET_TYPE = 2i32;
@@ -2995,6 +3178,11 @@ pub struct SOCKADDR_UN {
pub struct SRWLOCK {
pub Ptr: *mut core::ffi::c_void,
}
+impl Default for SRWLOCK {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub const STACK_SIZE_PARAM_IS_A_RESERVATION: THREAD_CREATION_FLAGS = 65536u32;
pub const STANDARD_RIGHTS_ALL: FILE_ACCESS_RIGHTS = 2031616u32;
pub const STANDARD_RIGHTS_EXECUTE: FILE_ACCESS_RIGHTS = 131072u32;
@@ -3021,6 +3209,11 @@ pub struct STARTUPINFOEXW {
pub StartupInfo: STARTUPINFOW,
pub lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST,
}
+impl Default for STARTUPINFOEXW {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct STARTUPINFOW {
@@ -3043,6 +3236,11 @@ pub struct STARTUPINFOW {
pub hStdOutput: HANDLE,
pub hStdError: HANDLE,
}
+impl Default for STARTUPINFOW {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub type STARTUPINFOW_FLAGS = u32;
pub const STATUS_DELETE_PENDING: NTSTATUS = 0xC0000056_u32 as _;
pub const STATUS_DIRECTORY_NOT_EMPTY: NTSTATUS = 0xC0000101_u32 as _;
@@ -3078,14 +3276,24 @@ pub struct SYSTEM_INFO {
pub wProcessorLevel: u16,
pub wProcessorRevision: u16,
}
+impl Default for SYSTEM_INFO {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[derive(Clone, Copy)]
pub union SYSTEM_INFO_0 {
pub dwOemId: u32,
pub Anonymous: SYSTEM_INFO_0_0,
}
+impl Default for SYSTEM_INFO_0 {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct SYSTEM_INFO_0_0 {
pub wProcessorArchitecture: PROCESSOR_ARCHITECTURE,
pub wReserved: u16,
@@ -3097,7 +3305,7 @@ pub struct SYSTEM_INFO_0_0 {
pub const TIMER_ALL_ACCESS: SYNCHRONIZATION_ACCESS_RIGHTS = 2031619u32;
pub const TIMER_MODIFY_STATE: SYNCHRONIZATION_ACCESS_RIGHTS = 2u32;
#[repr(C)]
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Default)]
pub struct TIMEVAL {
pub tv_sec: i32,
pub tv_usec: i32,
@@ -3134,6 +3342,11 @@ pub struct UNICODE_STRING {
pub MaximumLength: u16,
pub Buffer: PWSTR,
}
+impl Default for UNICODE_STRING {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub const VOLUME_NAME_DOS: GETFINALPATHNAMEBYHANDLE_FLAGS = 0u32;
pub const VOLUME_NAME_GUID: GETFINALPATHNAMEBYHANDLE_FLAGS = 1u32;
pub const VOLUME_NAME_NONE: GETFINALPATHNAMEBYHANDLE_FLAGS = 4u32;
@@ -3160,6 +3373,11 @@ pub struct WIN32_FIND_DATAW {
pub cFileName: [u16; 260],
pub cAlternateFileName: [u16; 14],
}
+impl Default for WIN32_FIND_DATAW {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub type WINSOCK_SHUTDOWN_HOW = i32;
pub type WINSOCK_SOCKET_TYPE = i32;
pub const WRITE_DAC: FILE_ACCESS_RIGHTS = 262144u32;
@@ -3171,6 +3389,11 @@ pub struct WSABUF {
pub len: u32,
pub buf: PSTR,
}
+impl Default for WSABUF {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[cfg(target_arch = "x86")]
#[derive(Clone, Copy)]
@@ -3183,6 +3406,12 @@ pub struct WSADATA {
pub iMaxUdpDg: u16,
pub lpVendorInfo: PSTR,
}
+#[cfg(target_arch = "x86")]
+impl Default for WSADATA {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))]
#[derive(Clone, Copy)]
@@ -3195,6 +3424,12 @@ pub struct WSADATA {
pub szDescription: [i8; 257],
pub szSystemStatus: [i8; 129],
}
+#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))]
+impl Default for WSADATA {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub const WSAEACCES: WSA_ERROR = 10013i32;
pub const WSAEADDRINUSE: WSA_ERROR = 10048i32;
pub const WSAEADDRNOTAVAIL: WSA_ERROR = 10049i32;
@@ -3255,6 +3490,11 @@ pub struct WSAPROTOCOLCHAIN {
pub ChainLen: i32,
pub ChainEntries: [u32; 7],
}
+impl Default for WSAPROTOCOLCHAIN {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[derive(Clone, Copy)]
pub struct WSAPROTOCOL_INFOW {
@@ -3279,6 +3519,11 @@ pub struct WSAPROTOCOL_INFOW {
pub dwProviderReserved: u32,
pub szProtocol: [u16; 256],
}
+impl Default for WSAPROTOCOL_INFOW {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
pub const WSASERVICE_NOT_FOUND: WSA_ERROR = 10108i32;
pub const WSASYSCALLFAILURE: WSA_ERROR = 10107i32;
pub const WSASYSNOTREADY: WSA_ERROR = 10091i32;
@@ -3348,6 +3593,12 @@ pub struct XSAVE_FORMAT {
pub XmmRegisters: [M128A; 8],
pub Reserved4: [u8; 224],
}
+#[cfg(target_arch = "x86")]
+impl Default for XSAVE_FORMAT {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[repr(C)]
#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))]
#[derive(Clone, Copy)]
@@ -3369,6 +3620,12 @@ pub struct XSAVE_FORMAT {
pub XmmRegisters: [M128A; 16],
pub Reserved4: [u8; 96],
}
+#[cfg(any(target_arch = "aarch64", target_arch = "arm64ec", target_arch = "x86_64"))]
+impl Default for XSAVE_FORMAT {
+ fn default() -> Self {
+ unsafe { core::mem::zeroed() }
+ }
+}
#[cfg(target_arch = "arm")]
#[repr(C)]
diff --git a/library/std/src/sys/pal/windows/env.rs b/library/std/src/sys/pal/windows/env.rs
deleted file mode 100644
index f0a99d6..0000000
--- a/library/std/src/sys/pal/windows/env.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-pub mod os {
- pub const FAMILY: &str = "windows";
- pub const OS: &str = "windows";
- pub const DLL_PREFIX: &str = "";
- pub const DLL_SUFFIX: &str = ".dll";
- pub const DLL_EXTENSION: &str = "dll";
- pub const EXE_SUFFIX: &str = ".exe";
- pub const EXE_EXTENSION: &str = "exe";
-}
diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs
index bdf0cc2c..4f18c40 100644
--- a/library/std/src/sys/pal/windows/mod.rs
+++ b/library/std/src/sys/pal/windows/mod.rs
@@ -14,9 +14,7 @@
pub mod api;
-pub mod args;
pub mod c;
-pub mod env;
#[cfg(not(target_vendor = "win7"))]
pub mod futex;
pub mod handle;
diff --git a/library/std/src/sys/pal/xous/args.rs b/library/std/src/sys/pal/xous/args.rs
deleted file mode 100644
index 00c44ca..0000000
--- a/library/std/src/sys/pal/xous/args.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-use crate::ffi::OsString;
-use crate::sys::pal::xous::os::get_application_parameters;
-use crate::sys::pal::xous::os::params::ArgumentList;
-use crate::{fmt, vec};
-
-pub struct Args {
- parsed_args_list: vec::IntoIter<OsString>,
-}
-
-pub fn args() -> Args {
- let Some(params) = get_application_parameters() else {
- return Args { parsed_args_list: vec![].into_iter() };
- };
-
- for param in params {
- if let Ok(args) = ArgumentList::try_from(¶m) {
- let mut parsed_args = vec![];
- for arg in args {
- parsed_args.push(arg.into());
- }
- return Args { parsed_args_list: parsed_args.into_iter() };
- }
- }
- Args { parsed_args_list: vec![].into_iter() }
-}
-
-impl fmt::Debug for Args {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.parsed_args_list.as_slice().fmt(f)
- }
-}
-
-impl Iterator for Args {
- type Item = OsString;
- fn next(&mut self) -> Option<OsString> {
- self.parsed_args_list.next()
- }
- fn size_hint(&self) -> (usize, Option<usize>) {
- self.parsed_args_list.size_hint()
- }
-}
-
-impl DoubleEndedIterator for Args {
- fn next_back(&mut self) -> Option<OsString> {
- self.parsed_args_list.next_back()
- }
-}
-
-impl ExactSizeIterator for Args {
- fn len(&self) -> usize {
- self.parsed_args_list.len()
- }
-}
diff --git a/library/std/src/sys/pal/xous/mod.rs b/library/std/src/sys/pal/xous/mod.rs
index 58926e2..383d031 100644
--- a/library/std/src/sys/pal/xous/mod.rs
+++ b/library/std/src/sys/pal/xous/mod.rs
@@ -1,8 +1,5 @@
#![forbid(unsafe_op_in_unsafe_fn)]
-pub mod args;
-#[path = "../unsupported/env.rs"]
-pub mod env;
pub mod os;
#[path = "../unsupported/pipe.rs"]
pub mod pipe;
diff --git a/library/std/src/sys/pal/zkvm/mod.rs b/library/std/src/sys/pal/zkvm/mod.rs
index 4659dad..e1efa24 100644
--- a/library/std/src/sys/pal/zkvm/mod.rs
+++ b/library/std/src/sys/pal/zkvm/mod.rs
@@ -8,12 +8,9 @@
//! will likely change over time.
#![forbid(unsafe_op_in_unsafe_fn)]
-const WORD_SIZE: usize = size_of::<u32>();
+pub const WORD_SIZE: usize = size_of::<u32>();
pub mod abi;
-#[path = "../zkvm/args.rs"]
-pub mod args;
-pub mod env;
pub mod os;
#[path = "../unsupported/pipe.rs"]
pub mod pipe;
diff --git a/library/std/src/sys/path/windows.rs b/library/std/src/sys/path/windows.rs
index 6547ed9..e0e003f 100644
--- a/library/std/src/sys/path/windows.rs
+++ b/library/std/src/sys/path/windows.rs
@@ -10,6 +10,40 @@
pub const MAIN_SEP_STR: &str = "\\";
pub const MAIN_SEP: char = '\\';
+/// A null terminated wide string.
+#[repr(transparent)]
+pub struct WCStr([u16]);
+
+impl WCStr {
+ /// Convert a slice to a WCStr without checks.
+ ///
+ /// Though it is memory safe, the slice should also not contain interior nulls
+ /// as this may lead to unwanted truncation.
+ ///
+ /// # Safety
+ ///
+ /// The slice must end in a null.
+ pub unsafe fn from_wchars_with_null_unchecked(s: &[u16]) -> &Self {
+ unsafe { &*(s as *const [u16] as *const Self) }
+ }
+
+ pub fn as_ptr(&self) -> *const u16 {
+ self.0.as_ptr()
+ }
+
+ pub fn count_bytes(&self) -> usize {
+ self.0.len()
+ }
+}
+
+#[inline]
+pub fn with_native_path<T>(path: &Path, f: &dyn Fn(&WCStr) -> io::Result<T>) -> io::Result<T> {
+ let path = maybe_verbatim(path)?;
+ // SAFETY: maybe_verbatim returns null-terminated strings
+ let path = unsafe { WCStr::from_wchars_with_null_unchecked(&path) };
+ f(path)
+}
+
#[inline]
pub fn is_sep_byte(b: u8) -> bool {
b == b'/' || b == b'\\'
diff --git a/library/std/src/sys/process/uefi.rs b/library/std/src/sys/process/uefi.rs
index b46418a..5f92229 100644
--- a/library/std/src/sys/process/uefi.rs
+++ b/library/std/src/sys/process/uefi.rs
@@ -1,4 +1,4 @@
-use r_efi::protocols::simple_text_output;
+use r_efi::protocols::{simple_text_input, simple_text_output};
use crate::collections::BTreeMap;
pub use crate::ffi::OsString as EnvKey;
@@ -23,6 +23,7 @@ pub struct Command {
args: Vec<OsString>,
stdout: Option<Stdio>,
stderr: Option<Stdio>,
+ stdin: Option<Stdio>,
env: CommandEnv,
}
@@ -48,6 +49,7 @@ pub fn new(program: &OsStr) -> Command {
args: Vec::new(),
stdout: None,
stderr: None,
+ stdin: None,
env: Default::default(),
}
}
@@ -64,8 +66,8 @@ pub fn cwd(&mut self, _dir: &OsStr) {
panic!("unsupported")
}
- pub fn stdin(&mut self, _stdin: Stdio) {
- panic!("unsupported")
+ pub fn stdin(&mut self, stdin: Stdio) {
+ self.stdin = Some(stdin);
}
pub fn stdout(&mut self, stdout: Stdio) {
@@ -122,6 +124,22 @@ fn create_pipe(
}
}
+ fn create_stdin(
+ s: Stdio,
+ ) -> io::Result<Option<helpers::OwnedProtocol<uefi_command_internal::InputProtocol>>> {
+ match s {
+ Stdio::Null => unsafe {
+ helpers::OwnedProtocol::create(
+ uefi_command_internal::InputProtocol::null(),
+ simple_text_input::PROTOCOL_GUID,
+ )
+ }
+ .map(Some),
+ Stdio::Inherit => Ok(None),
+ Stdio::MakePipe => unsupported(),
+ }
+ }
+
pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?;
@@ -149,6 +167,15 @@ pub fn output(&mut self) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
cmd.stderr_inherit()
};
+ // Setup Stdin
+ let stdin = self.stdin.unwrap_or(Stdio::Null);
+ let stdin = Self::create_stdin(stdin)?;
+ if let Some(con) = stdin {
+ cmd.stdin_init(con)
+ } else {
+ cmd.stdin_inherit()
+ };
+
let env = env_changes(&self.env);
// Set any new vars
@@ -334,7 +361,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
#[allow(dead_code)]
mod uefi_command_internal {
- use r_efi::protocols::{loaded_image, simple_text_output};
+ use r_efi::protocols::{loaded_image, simple_text_input, simple_text_output};
use crate::ffi::{OsStr, OsString};
use crate::io::{self, const_error};
@@ -350,6 +377,7 @@ pub struct Image {
handle: NonNull<crate::ffi::c_void>,
stdout: Option<helpers::OwnedProtocol<PipeProtocol>>,
stderr: Option<helpers::OwnedProtocol<PipeProtocol>>,
+ stdin: Option<helpers::OwnedProtocol<InputProtocol>>,
st: OwnedTable<r_efi::efi::SystemTable>,
args: Option<(*mut u16, usize)>,
}
@@ -384,7 +412,14 @@ pub fn load_image(p: &OsStr) -> io::Result<Self> {
helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap();
let st = OwnedTable::from_table(unsafe { (*loaded_image.as_ptr()).system_table });
- Ok(Self { handle: child_handle, stdout: None, stderr: None, st, args: None })
+ Ok(Self {
+ handle: child_handle,
+ stdout: None,
+ stderr: None,
+ stdin: None,
+ st,
+ args: None,
+ })
}
}
@@ -445,6 +480,17 @@ fn set_stderr(
}
}
+ fn set_stdin(
+ &mut self,
+ handle: r_efi::efi::Handle,
+ protocol: *mut simple_text_input::Protocol,
+ ) {
+ unsafe {
+ (*self.st.as_mut_ptr()).console_in_handle = handle;
+ (*self.st.as_mut_ptr()).con_in = protocol;
+ }
+ }
+
pub fn stdout_init(&mut self, protocol: helpers::OwnedProtocol<PipeProtocol>) {
self.set_stdout(
protocol.handle().as_ptr(),
@@ -471,6 +517,19 @@ pub fn stderr_inherit(&mut self) {
unsafe { self.set_stderr((*st.as_ptr()).standard_error_handle, (*st.as_ptr()).std_err) }
}
+ pub(crate) fn stdin_init(&mut self, protocol: helpers::OwnedProtocol<InputProtocol>) {
+ self.set_stdin(
+ protocol.handle().as_ptr(),
+ protocol.as_ref() as *const InputProtocol as *mut simple_text_input::Protocol,
+ );
+ self.stdin = Some(protocol);
+ }
+
+ pub(crate) fn stdin_inherit(&mut self) {
+ let st: NonNull<r_efi::efi::SystemTable> = system_table().cast();
+ unsafe { self.set_stdin((*st.as_ptr()).console_in_handle, (*st.as_ptr()).con_in) }
+ }
+
pub fn stderr(&self) -> io::Result<Vec<u8>> {
match &self.stderr {
Some(stderr) => stderr.as_ref().utf8(),
@@ -722,6 +781,56 @@ fn drop(&mut self) {
}
}
+ #[repr(C)]
+ pub(crate) struct InputProtocol {
+ reset: simple_text_input::ProtocolReset,
+ read_key_stroke: simple_text_input::ProtocolReadKeyStroke,
+ wait_for_key: r_efi::efi::Event,
+ }
+
+ impl InputProtocol {
+ pub(crate) fn null() -> Self {
+ let evt = helpers::OwnedEvent::new(
+ r_efi::efi::EVT_NOTIFY_WAIT,
+ r_efi::efi::TPL_CALLBACK,
+ Some(Self::empty_notify),
+ None,
+ )
+ .unwrap();
+
+ Self {
+ reset: Self::null_reset,
+ read_key_stroke: Self::null_read_key,
+ wait_for_key: evt.into_raw(),
+ }
+ }
+
+ extern "efiapi" fn null_reset(
+ _: *mut simple_text_input::Protocol,
+ _: r_efi::efi::Boolean,
+ ) -> r_efi::efi::Status {
+ r_efi::efi::Status::SUCCESS
+ }
+
+ extern "efiapi" fn null_read_key(
+ _: *mut simple_text_input::Protocol,
+ _: *mut simple_text_input::InputKey,
+ ) -> r_efi::efi::Status {
+ r_efi::efi::Status::UNSUPPORTED
+ }
+
+ extern "efiapi" fn empty_notify(_: r_efi::efi::Event, _: *mut crate::ffi::c_void) {}
+ }
+
+ impl Drop for InputProtocol {
+ fn drop(&mut self) {
+ // Close wait_for_key
+ unsafe {
+ let _ = helpers::OwnedEvent::from_raw(self.wait_for_key);
+ }
+ }
+ }
+
pub fn create_args(prog: &OsStr, args: &[OsString]) -> Box<[u16]> {
const QUOTE: u16 = 0x0022;
const SPACE: u16 = 0x0020;
diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs
index 191a09c..92bb809 100644
--- a/library/std/src/sys/process/unix/unix.rs
+++ b/library/std/src/sys/process/unix/unix.rs
@@ -415,6 +415,7 @@ unsafe fn do_exec(
all(target_os = "linux", target_env = "musl"),
target_os = "nto",
target_vendor = "apple",
+ target_os = "cygwin",
)))]
fn posix_spawn(
&mut self,
@@ -433,10 +434,8 @@ fn posix_spawn(
all(target_os = "linux", target_env = "musl"),
target_os = "nto",
target_vendor = "apple",
+ target_os = "cygwin",
))]
- // FIXME(#115199): Rust currently omits weak function definitions
- // and its metadata from LLVM IR.
- #[cfg_attr(target_os = "linux", no_sanitize(cfi))]
fn posix_spawn(
&mut self,
stdio: &ChildPipes,
@@ -587,7 +586,7 @@ unsafe fn retrying_libc_posix_spawnp(
/// Some platforms can set a new working directory for a spawned process in the
/// `posix_spawn` path. This function looks up the function pointer for adding
/// such an action to a `posix_spawn_file_actions_t` struct.
- #[cfg(not(all(target_os = "linux", target_env = "musl")))]
+ #[cfg(not(any(all(target_os = "linux", target_env = "musl"), target_os = "cygwin")))]
fn get_posix_spawn_addchdir() -> Option<PosixSpawnAddChdirFn> {
use crate::sys::weak::weak;
@@ -621,7 +620,9 @@ fn posix_spawn_file_actions_addchdir(
/// Weak symbol lookup doesn't work with statically linked libcs, so in cases
/// where static linking is possible we need to either check for the presence
/// of the symbol at compile time or know about it upfront.
- #[cfg(all(target_os = "linux", target_env = "musl"))]
+ ///
+ /// Cygwin doesn't support weak symbol, so just link it.
+ #[cfg(any(all(target_os = "linux", target_env = "musl"), target_os = "cygwin"))]
fn get_posix_spawn_addchdir() -> Option<PosixSpawnAddChdirFn> {
// Our minimum required musl supports this function, so we can just use it.
Some(libc::posix_spawn_file_actions_addchdir_np)
diff --git a/library/std/src/sys/stdio/uefi.rs b/library/std/src/sys/stdio/uefi.rs
index 257e321..ccd6bf6 100644
--- a/library/std/src/sys/stdio/uefi.rs
+++ b/library/std/src/sys/stdio/uefi.rs
@@ -142,8 +142,12 @@ fn flush(&mut self) -> io::Result<()> {
// UTF-16 character should occupy 4 bytes at most in UTF-8
pub const STDIN_BUF_SIZE: usize = 4;
-pub fn is_ebadf(_err: &io::Error) -> bool {
- false
+pub fn is_ebadf(err: &io::Error) -> bool {
+ if let Some(x) = err.raw_os_error() {
+ r_efi::efi::Status::UNSUPPORTED.as_usize() == x
+ } else {
+ false
+ }
}
pub fn panic_output() -> Option<impl io::Write> {
diff --git a/library/std/src/sys/thread_local/destructors/linux_like.rs b/library/std/src/sys/thread_local/destructors/linux_like.rs
index 8179412..d7cbaeb 100644
--- a/library/std/src/sys/thread_local/destructors/linux_like.rs
+++ b/library/std/src/sys/thread_local/destructors/linux_like.rs
@@ -12,9 +12,6 @@
use crate::mem::transmute;
-// FIXME: The Rust compiler currently omits weakly function definitions (i.e.,
-// __cxa_thread_atexit_impl) and its metadata from LLVM IR.
-#[no_sanitize(cfi, kcfi)]
pub unsafe fn register(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
/// This is necessary because the __cxa_thread_atexit_impl implementation
/// std links to by default may be a C or C++ implementation that was not
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs
index d5a5d10..7cd4487 100644
--- a/library/std/src/thread/local.rs
+++ b/library/std/src/thread/local.rs
@@ -22,12 +22,16 @@
///
/// Initialization is dynamically performed on the first call to a setter (e.g.
/// [`with`]) within a thread, and values that implement [`Drop`] get
-/// destructed when a thread exits. Some caveats apply, which are explained below.
+/// destructed when a thread exits. Some platform-specific caveats apply, which
+/// are explained below.
+/// Note that, should the destructor panics, the whole process will be [aborted].
///
/// A `LocalKey`'s initializer cannot recursively depend on itself. Using a
/// `LocalKey` in this way may cause panics, aborts or infinite recursion on
/// the first call to `with`.
///
+/// [aborted]: crate::process::abort
+///
/// # Single-thread Synchronization
///
/// Though there is no potential race with other threads, it is still possible to
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 3f3ba02..2097f1e 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -1676,6 +1676,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
/// [`Result`]: crate::result::Result
/// [`std::panic::resume_unwind`]: crate::panic::resume_unwind
#[stable(feature = "rust1", since = "1.0.0")]
+#[cfg_attr(not(bootstrap), doc(search_unbox))]
pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>;
// This packet is used to communicate the return value between the spawned
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 5ab7141..03af35e 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -205,8 +205,8 @@
/// println!("{}", elapsed.as_secs());
/// }
/// Err(e) => {
-/// // an error occurred!
-/// println!("Error: {e:?}");
+/// // the system clock went backwards!
+/// println!("Great Scott! {e:?}");
/// }
/// }
/// }
@@ -245,6 +245,7 @@
/// > structure cannot represent the new point in time.
///
/// [`add`]: SystemTime::add
+/// [`UNIX_EPOCH`]: SystemTime::UNIX_EPOCH
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[stable(feature = "time2", since = "1.8.0")]
pub struct SystemTime(time::SystemTime);
diff --git a/library/std/tests/floats/f128.rs b/library/std/tests/floats/f128.rs
index df28e81..677738b 100644
--- a/library/std/tests/floats/f128.rs
+++ b/library/std/tests/floats/f128.rs
@@ -112,6 +112,8 @@ fn test_nan() {
assert!(!nan.is_sign_negative());
assert!(!nan.is_normal());
assert_eq!(Fp::Nan, nan.classify());
+ // Ensure the quiet bit is set.
+ assert!(nan.to_bits() & (1 << (f128::MANTISSA_DIGITS - 2)) != 0);
}
#[test]
diff --git a/library/std/tests/floats/f16.rs b/library/std/tests/floats/f16.rs
index 1a90f00..0fc4df8 100644
--- a/library/std/tests/floats/f16.rs
+++ b/library/std/tests/floats/f16.rs
@@ -95,6 +95,8 @@ fn test_nan() {
assert!(!nan.is_sign_negative());
assert!(!nan.is_normal());
assert_eq!(Fp::Nan, nan.classify());
+ // Ensure the quiet bit is set.
+ assert!(nan.to_bits() & (1 << (f16::MANTISSA_DIGITS - 2)) != 0);
}
#[test]
diff --git a/library/std/tests/floats/f32.rs b/library/std/tests/floats/f32.rs
index d99b03c..9af23af 100644
--- a/library/std/tests/floats/f32.rs
+++ b/library/std/tests/floats/f32.rs
@@ -72,6 +72,8 @@ fn test_nan() {
assert!(nan.is_sign_positive());
assert!(!nan.is_sign_negative());
assert_eq!(Fp::Nan, nan.classify());
+ // Ensure the quiet bit is set.
+ assert!(nan.to_bits() & (1 << (f32::MANTISSA_DIGITS - 2)) != 0);
}
#[test]
diff --git a/library/std/tests/floats/f64.rs b/library/std/tests/floats/f64.rs
index 6116707..de9c27e 100644
--- a/library/std/tests/floats/f64.rs
+++ b/library/std/tests/floats/f64.rs
@@ -60,6 +60,8 @@ fn test_nan() {
assert!(nan.is_sign_positive());
assert!(!nan.is_sign_negative());
assert_eq!(Fp::Nan, nan.classify());
+ // Ensure the quiet bit is set.
+ assert!(nan.to_bits() & (1 << (f64::MANTISSA_DIGITS - 2)) != 0);
}
#[test]
diff --git a/library/std/tests/sync/mpmc.rs b/library/std/tests/sync/mpmc.rs
index 81b9229..78abcb3 100644
--- a/library/std/tests/sync/mpmc.rs
+++ b/library/std/tests/sync/mpmc.rs
@@ -64,6 +64,24 @@ fn smoke_port_gone() {
}
#[test]
+fn smoke_receiver_clone() {
+ let (tx, rx) = channel::<i32>();
+ let rx2 = rx.clone();
+ drop(rx);
+ tx.send(1).unwrap();
+ assert_eq!(rx2.recv().unwrap(), 1);
+}
+
+#[test]
+fn smoke_receiver_clone_port_gone() {
+ let (tx, rx) = channel::<i32>();
+ let rx2 = rx.clone();
+ drop(rx);
+ drop(rx2);
+ assert!(tx.send(1).is_err());
+}
+
+#[test]
fn smoke_shared_port_gone() {
let (tx, rx) = channel::<i32>();
drop(rx);
@@ -125,6 +143,18 @@ fn chan_gone_concurrent() {
}
#[test]
+fn receiver_cloning() {
+ let (tx, rx) = channel::<i32>();
+ let rx2 = rx.clone();
+
+ tx.send(1).unwrap();
+ tx.send(2).unwrap();
+
+ assert_eq!(rx2.recv(), Ok(1));
+ assert_eq!(rx.recv(), Ok(2));
+}
+
+#[test]
fn stress() {
let count = if cfg!(miri) { 100 } else { 10000 };
let (tx, rx) = channel::<i32>();
diff --git a/library/stdarch b/library/stdarch
index 9426bb5..4666c73 160000
--- a/library/stdarch
+++ b/library/stdarch
@@ -1 +1 @@
-Subproject commit 9426bb56586c6ae4095a2dcbd66c570253e6fb32
+Subproject commit 4666c7376f25a265c74535585d622da3da6dfeb1
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index 7ada3f2..acaf026 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -666,10 +666,11 @@ fn run_test_in_process(
io::set_output_capture(None);
- let test_result = match result {
- Ok(()) => calc_result(&desc, Ok(()), time_opts.as_ref(), exec_time.as_ref()),
- Err(e) => calc_result(&desc, Err(e.as_ref()), time_opts.as_ref(), exec_time.as_ref()),
- };
+ // Determine whether the test passed or failed, by comparing its panic
+ // payload (if any) with its `ShouldPanic` value, and by checking for
+ // fatal timeout.
+ let test_result =
+ calc_result(&desc, result.err().as_deref(), time_opts.as_ref(), exec_time.as_ref());
let stdout = data.lock().unwrap_or_else(|e| e.into_inner()).to_vec();
let message = CompletedTest::new(id, desc, test_result, exec_time, stdout);
monitor_ch.send(message).unwrap();
@@ -741,10 +742,7 @@ fn spawn_test_subprocess(
fn run_test_in_spawned_subprocess(desc: TestDesc, runnable_test: RunnableTest) -> ! {
let builtin_panic_hook = panic::take_hook();
let record_result = Arc::new(move |panic_info: Option<&'_ PanicHookInfo<'_>>| {
- let test_result = match panic_info {
- Some(info) => calc_result(&desc, Err(info.payload()), None, None),
- None => calc_result(&desc, Ok(()), None, None),
- };
+ let test_result = calc_result(&desc, panic_info.map(|info| info.payload()), None, None);
// We don't support serializing TrFailedMsg, so just
// print the message out to stderr.
diff --git a/library/test/src/test_result.rs b/library/test/src/test_result.rs
index 73dcc2e..a312894 100644
--- a/library/test/src/test_result.rs
+++ b/library/test/src/test_result.rs
@@ -39,15 +39,18 @@ pub enum TestResult {
/// Creates a `TestResult` depending on the raw result of test execution
/// and associated data.
-pub(crate) fn calc_result<'a>(
+pub(crate) fn calc_result(
desc: &TestDesc,
- task_result: Result<(), &'a (dyn Any + 'static + Send)>,
+ panic_payload: Option<&(dyn Any + Send)>,
time_opts: Option<&time::TestTimeOptions>,
exec_time: Option<&time::TestExecTime>,
) -> TestResult {
- let result = match (&desc.should_panic, task_result) {
- (&ShouldPanic::No, Ok(())) | (&ShouldPanic::Yes, Err(_)) => TestResult::TrOk,
- (&ShouldPanic::YesWithMessage(msg), Err(err)) => {
+ let result = match (desc.should_panic, panic_payload) {
+ // The test did or didn't panic, as expected.
+ (ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestResult::TrOk,
+
+ // Check the actual panic message against the expected message.
+ (ShouldPanic::YesWithMessage(msg), Some(err)) => {
let maybe_panic_str = err
.downcast_ref::<String>()
.map(|e| &**e)
@@ -71,10 +74,19 @@ pub(crate) fn calc_result<'a>(
))
}
}
- (&ShouldPanic::Yes, Ok(())) | (&ShouldPanic::YesWithMessage(_), Ok(())) => {
- TestResult::TrFailedMsg("test did not panic as expected".to_string())
+
+ // The test should have panicked, but didn't panic.
+ (ShouldPanic::Yes, None) | (ShouldPanic::YesWithMessage(_), None) => {
+ let fn_location = if !desc.source_file.is_empty() {
+ &format!(" at {}:{}:{}", desc.source_file, desc.start_line, desc.start_col)
+ } else {
+ ""
+ };
+ TestResult::TrFailedMsg(format!("test did not panic as expected{}", fn_location))
}
- _ => TestResult::TrFailed,
+
+ // The test should not have panicked, but did panic.
+ (ShouldPanic::No, Some(_)) => TestResult::TrFailed,
};
// If test is already failed (or allowed to fail), do not change the result.
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 17ee4d6..d415668 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -56,6 +56,7 @@
"sha2",
"sysinfo",
"tar",
+ "tempfile",
"termcolor",
"toml",
"tracing",
@@ -225,22 +226,28 @@
[[package]]
name = "errno"
-version = "0.3.9"
+version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
+checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
dependencies = [
"libc",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
]
[[package]]
+name = "fastrand"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+
+[[package]]
name = "fd-lock"
version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947"
dependencies = [
"cfg-if",
- "rustix",
+ "rustix 0.38.40",
"windows-sys 0.52.0",
]
@@ -267,6 +274,18 @@
]
[[package]]
+name = "getrandom"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "r-efi",
+ "wasi",
+]
+
+[[package]]
name = "globset"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -334,9 +353,9 @@
[[package]]
name = "libc"
-version = "0.2.167"
+version = "0.2.171"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc"
+checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
[[package]]
name = "libredox"
@@ -356,6 +375,12 @@
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
[[package]]
+name = "linux-raw-sys"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
+
+[[package]]
name = "log"
version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -487,6 +512,12 @@
]
[[package]]
+name = "r-efi"
+version = "5.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
+
+[[package]]
name = "redox_syscall"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -548,11 +579,24 @@
"bitflags",
"errno",
"libc",
- "linux-raw-sys",
+ "linux-raw-sys 0.4.14",
"windows-sys 0.52.0",
]
[[package]]
+name = "rustix"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825"
+dependencies = [
+ "bitflags",
+ "errno",
+ "libc",
+ "linux-raw-sys 0.9.3",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -679,6 +723,19 @@
]
[[package]]
+name = "tempfile"
+version = "3.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488960f40a3fd53d72c2a29a58722561dee8afdd175bd88e3db4677d7b2ba600"
+dependencies = [
+ "fastrand",
+ "getrandom",
+ "once_cell",
+ "rustix 1.0.2",
+ "windows-sys 0.59.0",
+]
+
+[[package]]
name = "termcolor"
version = "1.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -825,6 +882,15 @@
]
[[package]]
+name = "wasi"
+version = "0.14.2+wasi-0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
+dependencies = [
+ "wit-bindgen-rt",
+]
+
+[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -991,14 +1057,23 @@
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
+name = "wit-bindgen-rt"
+version = "0.39.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
name = "xattr"
version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f"
dependencies = [
"libc",
- "linux-raw-sys",
- "rustix",
+ "linux-raw-sys 0.4.14",
+ "rustix 0.38.40",
]
[[package]]
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index 23aa87a..712a9b0 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -83,6 +83,7 @@
[dev-dependencies]
pretty_assertions = "1.4"
+tempfile = "3.15.0"
# We care a lot about bootstrap's compile times, so don't include debuginfo for
# dependencies, only bootstrap itself.
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 140f601..42ad14a 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -1331,7 +1331,7 @@
build.check_vendored_status()
if not os.path.exists(build.build_dir):
- os.makedirs(build.build_dir)
+ os.makedirs(os.path.realpath(build.build_dir))
# Fetch/build the bootstrap
build.download_toolchain()
diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp
index e157ff2..b70d452 100644
--- a/src/bootstrap/download-ci-llvm-stamp
+++ b/src/bootstrap/download-ci-llvm-stamp
@@ -1,4 +1,4 @@
Change this file to make users of the `download-ci-llvm` configuration download
a new version of LLVM from CI, even if the LLVM submodule hasn’t changed.
-Last change is for: https://github.com/rust-lang/rust/pull/138784
+Last change is for: https://github.com/rust-lang/rust/pull/139931
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index b191d0f..ae9511b 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -3,7 +3,7 @@
use crate::core::build_steps::compile::{
add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo, std_crates_for_run_make,
};
-use crate::core::build_steps::tool::{SourceType, prepare_tool_cargo};
+use crate::core::build_steps::tool::{COMPILETEST_ALLOW_FEATURES, SourceType, prepare_tool_cargo};
use crate::core::builder::{
self, Alias, Builder, Kind, RunConfig, ShouldRun, Step, crate_description,
};
@@ -416,7 +416,7 @@ fn run(self, builder: &Builder<'_>) {
&[],
);
- cargo.allow_features("test");
+ cargo.allow_features(COMPILETEST_ALLOW_FEATURES);
// For ./x.py clippy, don't run with --all-targets because
// linting tests and benchmarks can produce very noisy results
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index dab58fc..2e5865e 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -111,14 +111,10 @@ fn make_run(run: RunConfig<'_>) {
// the `rust.download-rustc=true` option.
let force_recompile = builder.rust_info().is_managed_git_subrepository()
&& builder.download_rustc()
- && builder.config.last_modified_commit(&["library"], "download-rustc", true).is_none();
+ && builder.config.has_changes_from_upstream(&["library"]);
trace!("is managed git repo: {}", builder.rust_info().is_managed_git_subrepository());
trace!("download_rustc: {}", builder.download_rustc());
- trace!(
- "last modified commit: {:?}",
- builder.config.last_modified_commit(&["library"], "download-rustc", true)
- );
trace!(force_recompile);
run.builder.ensure(Std {
@@ -155,7 +151,7 @@ fn run(self, builder: &Builder<'_>) {
// When using `download-rustc`, we already have artifacts for the host available. Don't
// recompile them.
- if builder.download_rustc() && builder.is_builder_target(target)
+ if builder.download_rustc() && builder.config.is_host_target(target)
// NOTE: the beta compiler may generate different artifacts than the downloaded compiler, so
// its artifacts can't be reused.
&& compiler.stage != 0
@@ -229,7 +225,7 @@ fn run(self, builder: &Builder<'_>) {
// The LLD wrappers and `rust-lld` are self-contained linking components that can be
// necessary to link the stdlib on some targets. We'll also need to copy these binaries to
// the `stage0-sysroot` to ensure the linker is found when bootstrapping on such a target.
- if compiler.stage == 0 && builder.is_builder_target(compiler.host) {
+ if compiler.stage == 0 && builder.config.is_host_target(compiler.host) {
trace!(
"(build == host) copying linking components to `stage0-sysroot` for bootstrapping"
);
@@ -1194,8 +1190,7 @@ pub fn rustc_cargo(
let enzyme_dir = builder.build.out.join(arch).join("enzyme").join("lib");
cargo.rustflag("-L").rustflag(enzyme_dir.to_str().expect("Invalid path"));
- if !builder.config.dry_run() {
- let llvm_config = builder.llvm_config(builder.config.build).unwrap();
+ if let Some(llvm_config) = builder.llvm_config(builder.config.build) {
let llvm_version_major = llvm::get_llvm_version_major(builder, &llvm_config);
cargo.rustflag("-l").rustflag(&format!("Enzyme-{llvm_version_major}"));
}
@@ -1374,7 +1369,7 @@ pub fn rustc_cargo_env(
/// Pass down configuration from the LLVM build into the build of
/// rustc_llvm and rustc_codegen_llvm.
fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) {
- if builder.is_rust_llvm(target) {
+ if builder.config.is_rust_llvm(target) {
cargo.env("LLVM_RUSTLLVM", "1");
}
if builder.config.llvm_enzyme {
@@ -2182,7 +2177,7 @@ fn run(self, builder: &Builder<'_>) -> Compiler {
debug!("copying codegen backends to sysroot");
copy_codegen_backends_to_sysroot(builder, build_compiler, target_compiler);
- if builder.config.lld_enabled {
+ if builder.config.lld_enabled && !builder.config.is_system_llvm(target_compiler.host) {
builder.ensure(crate::core::build_steps::tool::LldWrapper {
build_compiler,
target_compiler,
@@ -2532,7 +2527,9 @@ pub fn strip_debug(builder: &Builder<'_>, target: TargetSelection, path: &Path)
// FIXME: to make things simpler for now, limit this to the host and target where we know
// `strip -g` is both available and will fix the issue, i.e. on a x64 linux host that is not
// cross-compiling. Expand this to other appropriate targets in the future.
- if target != "x86_64-unknown-linux-gnu" || !builder.is_builder_target(target) || !path.exists()
+ if target != "x86_64-unknown-linux-gnu"
+ || !builder.config.is_host_target(target)
+ || !path.exists()
{
return;
}
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 83f71ae..ed90ede 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -612,7 +612,7 @@ fn run(self, builder: &Builder<'_>) {
fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
// The only true set of target libraries came from the build triple, so
// let's reduce redundant work by only producing archives from that host.
- if !builder.is_builder_target(compiler.host) {
+ if !builder.config.is_host_target(compiler.host) {
builder.info("\tskipping, not a build host");
true
} else {
@@ -671,7 +671,8 @@ fn copy_target_libs(
&self_contained_dst.join(path.file_name().unwrap()),
FileType::NativeLibrary,
);
- } else if dependency_type == DependencyType::Target || builder.is_builder_target(target) {
+ } else if dependency_type == DependencyType::Target || builder.config.is_host_target(target)
+ {
builder.copy_link(&path, &dst.join(path.file_name().unwrap()), FileType::NativeLibrary);
}
}
@@ -824,7 +825,7 @@ fn make_run(run: RunConfig<'_>) {
fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
let compiler = self.compiler;
let target = self.target;
- if !builder.is_builder_target(compiler.host) {
+ if !builder.config.is_host_target(compiler.host) {
return None;
}
@@ -2118,7 +2119,7 @@ fn maybe_install_llvm(
//
// If the LLVM is coming from ourselves (just from CI) though, we
// still want to install it, as it otherwise won't be available.
- if builder.is_system_llvm(target) {
+ if builder.config.is_system_llvm(target) {
trace!("system LLVM requested, no install");
return false;
}
diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs
index b1a97bd..9da8b27 100644
--- a/src/bootstrap/src/core/build_steps/format.rs
+++ b/src/bootstrap/src/core/build_steps/format.rs
@@ -81,14 +81,19 @@ fn update_rustfmt_version(build: &Builder<'_>) {
let Some((version, stamp_file)) = get_rustfmt_version(build) else {
return;
};
- t!(std::fs::write(stamp_file.path(), version))
+
+ t!(stamp_file.add_stamp(version).write());
}
-/// Returns the Rust files modified between the `merge-base` of HEAD and
-/// rust-lang/master and what is now on the disk. Does not include removed files.
+/// Returns the Rust files modified between the last merge commit and what is now on the disk.
+/// Does not include removed files.
///
/// Returns `None` if all files should be formatted.
fn get_modified_rs_files(build: &Builder<'_>) -> Result<Option<Vec<String>>, String> {
+ // In CI `get_git_modified_files` returns something different to normal environment.
+ // This shouldn't be called in CI anyway.
+ assert!(!build.config.is_running_on_ci);
+
if !verify_rustfmt_version(build) {
return Ok(None);
}
@@ -103,7 +108,7 @@ struct RustfmtConfig {
// Prints output describing a collection of paths, with lines such as "formatted modified file
// foo/bar/baz" or "skipped 20 untracked files".
-fn print_paths(build: &Builder<'_>, verb: &str, adjective: Option<&str>, paths: &[String]) {
+fn print_paths(verb: &str, adjective: Option<&str>, paths: &[String]) {
let len = paths.len();
let adjective =
if let Some(adjective) = adjective { format!("{adjective} ") } else { String::new() };
@@ -114,9 +119,6 @@ fn print_paths(build: &Builder<'_>, verb: &str, adjective: Option<&str>, paths:
} else {
println!("fmt: {verb} {len} {adjective}files");
}
- if len > 1000 && !build.config.is_running_on_ci {
- println!("hint: if this number seems too high, try running `git fetch origin master`");
- }
}
pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
@@ -189,7 +191,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
)
.map(|x| x.to_string())
.collect();
- print_paths(build, "skipped", Some("untracked"), &untracked_paths);
+ print_paths("skipped", Some("untracked"), &untracked_paths);
for untracked_path in untracked_paths {
// The leading `/` makes it an exact match against the
@@ -212,7 +214,13 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
override_builder.add(&format!("/{file}")).expect(&file);
}
}
- Ok(None) => {}
+ Ok(None) => {
+ // NOTE: `Ok(None)` signifies that we need to format all files.
+ // The tricky part here is that if `override_builder` isn't given any white
+ // list files (i.e. files to be formatted, added without leading `!`), it
+ // will instead look for *all* files. So, by doing nothing here, we are
+ // actually making it so we format all files.
+ }
Err(err) => {
eprintln!("fmt warning: Something went wrong running git commands:");
eprintln!("fmt warning: {err}");
@@ -318,7 +326,7 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
});
let mut paths = formatted_paths.into_inner().unwrap();
paths.sort();
- print_paths(build, if check { "checked" } else { "formatted" }, adjective, &paths);
+ print_paths(if check { "checked" } else { "formatted" }, adjective, &paths);
drop(tx);
@@ -328,7 +336,10 @@ pub fn format(build: &Builder<'_>, check: bool, all: bool, paths: &[PathBuf]) {
crate::exit!(1);
}
- if !check {
- update_rustfmt_version(build);
- }
+ // Update `build/.rustfmt-stamp`, allowing this code to ignore files which have not been changed
+ // since last merge.
+ //
+ // NOTE: Because of the exit above, this is only reachable if formatting / format checking
+ // succeeded. So we are not commiting the version if formatting was not good.
+ update_rustfmt_version(build);
}
diff --git a/src/bootstrap/src/core/build_steps/gcc.rs b/src/bootstrap/src/core/build_steps/gcc.rs
index 48bb5cb..ee8bd82 100644
--- a/src/bootstrap/src/core/build_steps/gcc.rs
+++ b/src/bootstrap/src/core/build_steps/gcc.rs
@@ -96,6 +96,8 @@ pub enum GccBuildStatus {
/// Returns a path to the libgccjit.so file.
#[cfg(not(test))]
fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option<PathBuf> {
+ use build_helper::git::PathFreshness;
+
// Try to download GCC from CI if configured and available
if !matches!(builder.config.gcc_ci_mode, crate::core::config::GccCiMode::DownloadFromCi) {
return None;
@@ -104,18 +106,40 @@ fn try_download_gcc(builder: &Builder<'_>, target: TargetSelection) -> Option<Pa
eprintln!("GCC CI download is only available for the `x86_64-unknown-linux-gnu` target");
return None;
}
- let sha =
- detect_gcc_sha(&builder.config, builder.config.rust_info.is_managed_git_subrepository());
- let root = ci_gcc_root(&builder.config);
- let gcc_stamp = BuildStamp::new(&root).with_prefix("gcc").add_stamp(&sha);
- if !gcc_stamp.is_up_to_date() && !builder.config.dry_run() {
- builder.config.download_ci_gcc(&sha, &root);
- t!(gcc_stamp.write());
- }
+ let source = detect_gcc_freshness(
+ &builder.config,
+ builder.config.rust_info.is_managed_git_subrepository(),
+ );
+ builder.verbose(|| {
+ eprintln!("GCC freshness: {source:?}");
+ });
+ match source {
+ PathFreshness::LastModifiedUpstream { upstream } => {
+ // Download from upstream CI
+ let root = ci_gcc_root(&builder.config);
+ let gcc_stamp = BuildStamp::new(&root).with_prefix("gcc").add_stamp(&upstream);
+ if !gcc_stamp.is_up_to_date() && !builder.config.dry_run() {
+ builder.config.download_ci_gcc(&upstream, &root);
+ t!(gcc_stamp.write());
+ }
- let libgccjit = root.join("lib").join("libgccjit.so");
- create_lib_alias(builder, &libgccjit);
- Some(libgccjit)
+ let libgccjit = root.join("lib").join("libgccjit.so");
+ create_lib_alias(builder, &libgccjit);
+ Some(libgccjit)
+ }
+ PathFreshness::HasLocalModifications { .. } => {
+ // We have local modifications, rebuild GCC.
+ eprintln!("Found local GCC modifications, GCC will *not* be downloaded");
+ None
+ }
+ PathFreshness::MissingUpstream => {
+ eprintln!("error: could not find commit hash for downloading GCC");
+ eprintln!("HELP: maybe your repository history is too shallow?");
+ eprintln!("HELP: consider disabling `download-ci-gcc`");
+ eprintln!("HELP: or fetch enough history to include one upstream commit");
+ None
+ }
+ }
}
#[cfg(test)]
@@ -264,31 +288,16 @@ fn ci_gcc_root(config: &crate::Config) -> PathBuf {
config.out.join(config.build).join("ci-gcc")
}
-/// This retrieves the GCC sha we *want* to use, according to git history.
+/// Detect whether GCC sources have been modified locally or not.
#[cfg(not(test))]
-fn detect_gcc_sha(config: &crate::Config, is_git: bool) -> String {
- use build_helper::git::get_closest_merge_commit;
+fn detect_gcc_freshness(config: &crate::Config, is_git: bool) -> build_helper::git::PathFreshness {
+ use build_helper::git::PathFreshness;
- let gcc_sha = if is_git {
- get_closest_merge_commit(
- Some(&config.src),
- &config.git_config(),
- &["src/gcc", "src/bootstrap/download-ci-gcc-stamp"],
- )
- .unwrap()
+ if is_git {
+ config.check_path_modifications(&["src/gcc", "src/bootstrap/download-ci-gcc-stamp"])
} else if let Some(info) = crate::utils::channel::read_commit_info_file(&config.src) {
- info.sha.trim().to_owned()
+ PathFreshness::LastModifiedUpstream { upstream: info.sha.trim().to_owned() }
} else {
- "".to_owned()
- };
-
- if gcc_sha.is_empty() {
- eprintln!("error: could not find commit hash for downloading GCC");
- eprintln!("HELP: maybe your repository history is too shallow?");
- eprintln!("HELP: consider disabling `download-ci-gcc`");
- eprintln!("HELP: or fetch enough history to include one upstream commit");
- panic!();
+ PathFreshness::MissingUpstream
}
-
- gcc_sha
}
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 69a8bd5..86af956 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -14,7 +14,7 @@
use std::sync::OnceLock;
use std::{env, fs};
-use build_helper::git::get_closest_merge_commit;
+use build_helper::git::PathFreshness;
#[cfg(feature = "tracing")]
use tracing::instrument;
@@ -181,26 +181,15 @@ pub fn prebuilt_llvm_config(
"src/version",
];
-/// This retrieves the LLVM sha we *want* to use, according to git history.
-pub(crate) fn detect_llvm_sha(config: &Config, is_git: bool) -> String {
- let llvm_sha = if is_git {
- get_closest_merge_commit(Some(&config.src), &config.git_config(), LLVM_INVALIDATION_PATHS)
- .unwrap()
+/// Detect whether LLVM sources have been modified locally or not.
+pub(crate) fn detect_llvm_freshness(config: &Config, is_git: bool) -> PathFreshness {
+ if is_git {
+ config.check_path_modifications(LLVM_INVALIDATION_PATHS)
} else if let Some(info) = crate::utils::channel::read_commit_info_file(&config.src) {
- info.sha.trim().to_owned()
+ PathFreshness::LastModifiedUpstream { upstream: info.sha.trim().to_owned() }
} else {
- "".to_owned()
- };
-
- if llvm_sha.is_empty() {
- eprintln!("error: could not find commit hash for downloading LLVM");
- eprintln!("HELP: maybe your repository history is too shallow?");
- eprintln!("HELP: consider disabling `download-ci-llvm`");
- eprintln!("HELP: or fetch enough history to include one upstream commit");
- panic!();
+ PathFreshness::MissingUpstream
}
-
- llvm_sha
}
/// Returns whether the CI-found LLVM is currently usable.
@@ -370,8 +359,8 @@ fn run(self, builder: &Builder<'_>) -> LlvmResult {
cfg.define("LLVM_PROFDATA_FILE", path);
}
- // Libraries for ELF section compression.
- if !target.is_windows() {
+ // Libraries for ELF section compression and profraw files merging.
+ if !target.is_msvc() {
cfg.define("LLVM_ENABLE_ZLIB", "ON");
} else {
cfg.define("LLVM_ENABLE_ZLIB", "OFF");
@@ -485,7 +474,7 @@ fn run(self, builder: &Builder<'_>) -> LlvmResult {
}
// https://llvm.org/docs/HowToCrossCompileLLVM.html
- if !builder.is_builder_target(target) {
+ if !builder.config.is_host_target(target) {
let LlvmResult { llvm_config, .. } =
builder.ensure(Llvm { target: builder.config.build });
if !builder.config.dry_run() {
@@ -637,7 +626,7 @@ fn configure_cmake(
}
cfg.target(&target.triple).host(&builder.config.build.triple);
- if !builder.is_builder_target(target) {
+ if !builder.config.is_host_target(target) {
cfg.define("CMAKE_CROSSCOMPILING", "True");
// NOTE: Ideally, we wouldn't have to do this, and `cmake-rs` would just handle it for us.
@@ -1098,7 +1087,7 @@ fn run(self, builder: &Builder<'_>) -> PathBuf {
.define("LLVM_CMAKE_DIR", llvm_cmake_dir)
.define("LLVM_INCLUDE_TESTS", "OFF");
- if !builder.is_builder_target(target) {
+ if !builder.config.is_host_target(target) {
// Use the host llvm-tblgen binary.
cfg.define(
"LLVM_TABLEGEN_EXE",
diff --git a/src/bootstrap/src/core/build_steps/setup.rs b/src/bootstrap/src/core/build_steps/setup.rs
index 80d9213..83083e1 100644
--- a/src/bootstrap/src/core/build_steps/setup.rs
+++ b/src/bootstrap/src/core/build_steps/setup.rs
@@ -584,6 +584,7 @@ fn hashes(&self) -> &'static [&'static str] {
"51068d4747a13732440d1a8b8f432603badb1864fa431d83d0fd4f8fa57039e0",
"d29af4d949bbe2371eac928a3c31cf9496b1701aa1c45f11cd6c759865ad5c45",
"b5dd299b93dca3ceeb9b335f929293cb3d4bf4977866fbe7ceeac2a8a9f99088",
+ "631c837b0e98ae35fd48b0e5f743b1ca60adadf2d0a2b23566ba25df372cf1a9",
],
EditorKind::Helix => &[
"2d3069b8cf1b977e5d4023965eb6199597755e6c96c185ed5f2854f98b83d233",
@@ -602,10 +603,12 @@ fn hashes(&self) -> &'static [&'static str] {
"4eecb58a2168b252077369da446c30ed0e658301efe69691979d1ef0443928f4",
"c394386e6133bbf29ffd32c8af0bb3d4aac354cba9ee051f29612aa9350f8f8d",
"e53e9129ca5ee5dcbd6ec8b68c2d87376474eb154992deba3c6d9ab1703e0717",
+ "f954316090936c7e590c253ca9d524008375882fa13c5b41d7e2547a896ff893",
],
EditorKind::Zed => &[
"bbce727c269d1bd0c98afef4d612eb4ce27aea3c3a8968c5f10b31affbc40b6c",
"a5380cf5dd9328731aecc5dfb240d16dac46ed272126b9728006151ef42f5909",
+ "2e96bf0d443852b12f016c8fc9840ab3d0a2b4fe0b0fb3a157e8d74d5e7e0e26",
],
}
}
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index e23c1ab..096f7de 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -15,7 +15,7 @@
use crate::core::build_steps::gcc::{Gcc, add_cg_gcc_cargo_flags};
use crate::core::build_steps::llvm::get_llvm_version;
use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
-use crate::core::build_steps::tool::{self, SourceType, Tool};
+use crate::core::build_steps::tool::{self, COMPILETEST_ALLOW_FEATURES, SourceType, Tool};
use crate::core::build_steps::toolstate::ToolState;
use crate::core::build_steps::{compile, dist, llvm};
use crate::core::builder::{
@@ -721,7 +721,7 @@ fn run(self, builder: &Builder<'_>) {
SourceType::InTree,
&[],
);
- cargo.allow_features("test");
+ cargo.allow_features(COMPILETEST_ALLOW_FEATURES);
run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder);
}
}
@@ -1894,7 +1894,7 @@ fn run(self, builder: &Builder<'_>) {
.arg(llvm_components.trim());
llvm_components_passed = true;
}
- if !builder.is_rust_llvm(target) {
+ if !builder.config.is_rust_llvm(target) {
cmd.arg("--system-llvm");
}
@@ -2668,7 +2668,7 @@ fn run(self, builder: &Builder<'_>) {
cargo
} else {
// Also prepare a sysroot for the target.
- if !builder.is_builder_target(target) {
+ if !builder.config.is_host_target(target) {
builder.ensure(compile::Std::new(compiler, target).force_recompile(true));
builder.ensure(RemoteCopyLibs { compiler, target });
}
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 1c61f0a..1549d47 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -150,10 +150,7 @@ fn run(mut self, builder: &Builder<'_>) -> ToolBuildResult {
// Rustc tools (miri, clippy, cargo, rustfmt, rust-analyzer)
// could use the additional optimizations.
- if self.mode == Mode::ToolRustc &&
- // rustdoc is performance sensitive, so apply LTO to it.
- is_lto_stage(&self.compiler)
- {
+ if self.mode == Mode::ToolRustc && is_lto_stage(&self.compiler) {
let lto = match builder.config.rust_lto {
RustcLto::Off => Some("off"),
RustcLto::Thin => Some("thin"),
@@ -447,7 +444,11 @@ fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
SourceType::InTree
},
extra_features: vec![],
- allow_features: concat!($($allow_features)*),
+ allow_features: {
+ let mut _value = "";
+ $( _value = $allow_features; )?
+ _value
+ },
cargo_args: vec![],
artifact_kind: if false $(|| $artifact_kind == ToolArtifactKind::Library)* {
ToolArtifactKind::Library
@@ -461,6 +462,8 @@ fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
}
}
+pub(crate) const COMPILETEST_ALLOW_FEATURES: &str = "test,internal_output_capture";
+
bootstrap_tool!(
// This is marked as an external tool because it includes dependencies
// from submodules. Trying to keep the lints in sync between all the repos
@@ -471,7 +474,7 @@ fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
Tidy, "src/tools/tidy", "tidy";
Linkchecker, "src/tools/linkchecker", "linkchecker";
CargoTest, "src/tools/cargotest", "cargotest";
- Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = "test";
+ Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES;
BuildManifest, "src/tools/build-manifest", "build-manifest";
RemoteTestClient, "src/tools/remote-test-client", "remote-test-client";
RustInstaller, "src/tools/rust-installer", "rust-installer";
@@ -486,7 +489,8 @@ fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
GenerateCopyright, "src/tools/generate-copyright", "generate-copyright";
SuggestTests, "src/tools/suggest-tests", "suggest-tests";
GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys";
- RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test";
+ // rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features.
+ RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES;
CoverageDump, "src/tools/coverage-dump", "coverage-dump";
WasmComponentLd, "src/tools/wasm-component-ld", "wasm-component-ld", is_unstable_tool = true, allow_features = "min_specialization";
UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator";
@@ -692,8 +696,7 @@ fn run(self, builder: &Builder<'_>) -> ToolBuildResult {
let files_to_track = &["src/librustdoc", "src/tools/rustdoc"];
// Check if unchanged
- if builder.config.last_modified_commit(files_to_track, "download-rustc", true).is_some()
- {
+ if !builder.config.has_changes_from_upstream(files_to_track) {
let precompiled_rustdoc = builder
.config
.ci_rustc_dir()
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index fd3b28e..8e2c6fc 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -1,11 +1,14 @@
+use std::env::VarError;
use std::{panic, thread};
+use build_helper::stage0_parser::parse_stage0_file;
use llvm::prebuilt_llvm_config;
use super::*;
use crate::Flags;
use crate::core::build_steps::doc::DocumentationFormat;
use crate::core::config::Config;
+use crate::utils::tests::git::{GitCtx, git_test};
static TEST_TRIPLE_1: &str = "i686-unknown-haiku";
static TEST_TRIPLE_2: &str = "i686-unknown-hurd-gnu";
@@ -239,42 +242,80 @@ fn alias_and_path_for_library() {
}
#[test]
-fn ci_rustc_if_unchanged_logic() {
- let config = Config::parse_inner(
+fn ci_rustc_if_unchanged_invalidate_on_compiler_changes() {
+ git_test(|ctx| {
+ prepare_rustc_checkout(ctx);
+ ctx.create_upstream_merge(&["compiler/bar"]);
+ // This change should invalidate download-ci-rustc
+ ctx.create_nonupstream_merge(&["compiler/foo"]);
+
+ let config = parse_config_download_rustc_at(ctx.get_path(), "if-unchanged", true);
+ assert_eq!(config.download_rustc_commit, None);
+ });
+}
+
+#[test]
+fn ci_rustc_if_unchanged_invalidate_on_library_changes_in_ci() {
+ git_test(|ctx| {
+ prepare_rustc_checkout(ctx);
+ ctx.create_upstream_merge(&["compiler/bar"]);
+ // This change should invalidate download-ci-rustc
+ ctx.create_nonupstream_merge(&["library/foo"]);
+
+ let config = parse_config_download_rustc_at(ctx.get_path(), "if-unchanged", true);
+ assert_eq!(config.download_rustc_commit, None);
+ });
+}
+
+#[test]
+fn ci_rustc_if_unchanged_do_not_invalidate_on_library_changes_outside_ci() {
+ git_test(|ctx| {
+ prepare_rustc_checkout(ctx);
+ let sha = ctx.create_upstream_merge(&["compiler/bar"]);
+ // This change should not invalidate download-ci-rustc
+ ctx.create_nonupstream_merge(&["library/foo"]);
+
+ let config = parse_config_download_rustc_at(ctx.get_path(), "if-unchanged", false);
+ assert_eq!(config.download_rustc_commit, Some(sha));
+ });
+}
+
+#[test]
+fn ci_rustc_if_unchanged_do_not_invalidate_on_tool_changes() {
+ git_test(|ctx| {
+ prepare_rustc_checkout(ctx);
+ let sha = ctx.create_upstream_merge(&["compiler/bar"]);
+ // This change should not invalidate download-ci-rustc
+ ctx.create_nonupstream_merge(&["src/tools/foo"]);
+
+ let config = parse_config_download_rustc_at(ctx.get_path(), "if-unchanged", true);
+ assert_eq!(config.download_rustc_commit, Some(sha));
+ });
+}
+
+/// Prepares the given directory so that it looks like a rustc checkout.
+/// Also configures `GitCtx` to use the correct merge bot e-mail for upstream merge commits.
+fn prepare_rustc_checkout(ctx: &mut GitCtx) {
+ ctx.merge_bot_email =
+ format!("Merge bot <{}>", parse_stage0_file().config.git_merge_commit_email);
+ ctx.write("src/ci/channel", "nightly");
+ ctx.commit();
+}
+
+/// Parses a Config directory from `path`, with the given value of `download_rustc`.
+fn parse_config_download_rustc_at(path: &Path, download_rustc: &str, ci: bool) -> Config {
+ Config::parse_inner(
Flags::parse(&[
"build".to_owned(),
"--dry-run".to_owned(),
- "--set=rust.download-rustc='if-unchanged'".to_owned(),
+ "--ci".to_owned(),
+ if ci { "true" } else { "false" }.to_owned(),
+ format!("--set=rust.download-rustc='{download_rustc}'"),
+ "--src".to_owned(),
+ path.to_str().unwrap().to_owned(),
]),
|&_| Ok(Default::default()),
- );
-
- let build = Build::new(config.clone());
- let builder = Builder::new(&build);
-
- if config.out.exists() {
- fs::remove_dir_all(&config.out).unwrap();
- }
-
- builder.run_step_descriptions(&Builder::get_step_descriptions(config.cmd.kind()), &[]);
-
- // Make sure "if-unchanged" logic doesn't try to use CI rustc while there are changes
- // in compiler and/or library.
- if config.download_rustc_commit.is_some() {
- let mut paths = vec!["compiler"];
-
- // Handle library tree the same way as in `Config::download_ci_rustc_commit`.
- if builder.config.is_running_on_ci {
- paths.push("library");
- }
-
- let has_changes = config.last_modified_commit(&paths, "download-rustc", true).is_none();
-
- assert!(
- !has_changes,
- "CI-rustc can't be used with 'if-unchanged' while there are changes in compiler and/or library."
- );
- }
+ )
}
mod defaults {
@@ -1107,8 +1148,8 @@ fn test_is_builder_target() {
let build = Build::new(config);
let builder = Builder::new(&build);
- assert!(builder.is_builder_target(target1));
- assert!(!builder.is_builder_target(target2));
+ assert!(builder.config.is_host_target(target1));
+ assert!(!builder.config.is_host_target(target2));
}
}
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 25ec64f..419976c 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -6,16 +6,17 @@
use std::cell::{Cell, RefCell};
use std::collections::{BTreeSet, HashMap, HashSet};
use std::fmt::{self, Display};
+use std::hash::Hash;
use std::io::IsTerminal;
use std::path::{Path, PathBuf, absolute};
use std::process::Command;
use std::str::FromStr;
-use std::sync::OnceLock;
+use std::sync::{Arc, Mutex, OnceLock};
use std::{cmp, env, fs};
use build_helper::ci::CiEnv;
use build_helper::exit;
-use build_helper::git::{GitConfig, get_closest_merge_commit, output_result};
+use build_helper::git::{GitConfig, PathFreshness, check_path_modifications, output_result};
use serde::{Deserialize, Deserializer};
use serde_derive::Deserialize;
#[cfg(feature = "tracing")]
@@ -421,6 +422,9 @@ pub struct Config {
pub compiletest_use_stage0_libtest: bool,
pub is_running_on_ci: bool,
+
+ /// Cache for determining path modifications
+ pub path_modification_cache: Arc<Mutex<HashMap<Vec<&'static str>, PathFreshness>>>,
}
#[derive(Clone, Debug, Default)]
@@ -701,6 +705,7 @@ pub(crate) struct TomlConfig {
target: Option<HashMap<String, TomlTarget>>,
dist: Option<Dist>,
profile: Option<String>,
+ include: Option<Vec<PathBuf>>,
}
/// This enum is used for deserializing change IDs from TOML, allowing both numeric values and the string `"ignore"`.
@@ -747,27 +752,35 @@ enum ReplaceOpt {
}
trait Merge {
- fn merge(&mut self, other: Self, replace: ReplaceOpt);
+ fn merge(
+ &mut self,
+ parent_config_path: Option<PathBuf>,
+ included_extensions: &mut HashSet<PathBuf>,
+ other: Self,
+ replace: ReplaceOpt,
+ );
}
impl Merge for TomlConfig {
fn merge(
&mut self,
- TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id }: Self,
+ parent_config_path: Option<PathBuf>,
+ included_extensions: &mut HashSet<PathBuf>,
+ TomlConfig { build, install, llvm, gcc, rust, dist, target, profile, change_id, include }: Self,
replace: ReplaceOpt,
) {
fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>, replace: ReplaceOpt) {
if let Some(new) = y {
if let Some(original) = x {
- original.merge(new, replace);
+ original.merge(None, &mut Default::default(), new, replace);
} else {
*x = Some(new);
}
}
}
- self.change_id.inner.merge(change_id.inner, replace);
- self.profile.merge(profile, replace);
+ self.change_id.inner.merge(None, &mut Default::default(), change_id.inner, replace);
+ self.profile.merge(None, &mut Default::default(), profile, replace);
do_merge(&mut self.build, build, replace);
do_merge(&mut self.install, install, replace);
@@ -782,13 +795,50 @@ fn do_merge<T: Merge>(x: &mut Option<T>, y: Option<T>, replace: ReplaceOpt) {
(Some(original_target), Some(new_target)) => {
for (triple, new) in new_target {
if let Some(original) = original_target.get_mut(&triple) {
- original.merge(new, replace);
+ original.merge(None, &mut Default::default(), new, replace);
} else {
original_target.insert(triple, new);
}
}
}
}
+
+ let parent_dir = parent_config_path
+ .as_ref()
+ .and_then(|p| p.parent().map(ToOwned::to_owned))
+ .unwrap_or_default();
+
+ // `include` handled later since we ignore duplicates using `ReplaceOpt::IgnoreDuplicate` to
+ // keep the upper-level configuration to take precedence.
+ for include_path in include.clone().unwrap_or_default().iter().rev() {
+ let include_path = parent_dir.join(include_path);
+ let include_path = include_path.canonicalize().unwrap_or_else(|e| {
+ eprintln!("ERROR: Failed to canonicalize '{}' path: {e}", include_path.display());
+ exit!(2);
+ });
+
+ let included_toml = Config::get_toml_inner(&include_path).unwrap_or_else(|e| {
+ eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display());
+ exit!(2);
+ });
+
+ assert!(
+ included_extensions.insert(include_path.clone()),
+ "Cyclic inclusion detected: '{}' is being included again before its previous inclusion was fully processed.",
+ include_path.display()
+ );
+
+ self.merge(
+ Some(include_path.clone()),
+ included_extensions,
+ included_toml,
+ // Ensures that parent configuration always takes precedence
+ // over child configurations.
+ ReplaceOpt::IgnoreDuplicate,
+ );
+
+ included_extensions.remove(&include_path);
+ }
}
}
@@ -803,7 +853,13 @@ struct $name {
}
impl Merge for $name {
- fn merge(&mut self, other: Self, replace: ReplaceOpt) {
+ fn merge(
+ &mut self,
+ _parent_config_path: Option<PathBuf>,
+ _included_extensions: &mut HashSet<PathBuf>,
+ other: Self,
+ replace: ReplaceOpt
+ ) {
$(
match replace {
ReplaceOpt::IgnoreDuplicate => {
@@ -903,7 +959,13 @@ fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
}
impl<T> Merge for Option<T> {
- fn merge(&mut self, other: Self, replace: ReplaceOpt) {
+ fn merge(
+ &mut self,
+ _parent_config_path: Option<PathBuf>,
+ _included_extensions: &mut HashSet<PathBuf>,
+ other: Self,
+ replace: ReplaceOpt,
+ ) {
match replace {
ReplaceOpt::IgnoreDuplicate => {
if self.is_none() {
@@ -1363,13 +1425,15 @@ pub(crate) fn get_builder_toml(&self, build_name: &str) -> Result<TomlConfig, to
Self::get_toml(&builder_config_path)
}
- #[cfg(test)]
- pub(crate) fn get_toml(_: &Path) -> Result<TomlConfig, toml::de::Error> {
- Ok(TomlConfig::default())
+ pub(crate) fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
+ #[cfg(test)]
+ return Ok(TomlConfig::default());
+
+ #[cfg(not(test))]
+ Self::get_toml_inner(file)
}
- #[cfg(not(test))]
- pub(crate) fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
+ fn get_toml_inner(file: &Path) -> Result<TomlConfig, toml::de::Error> {
let contents =
t!(fs::read_to_string(file), format!("config file {} not found", file.display()));
// Deserialize to Value and then TomlConfig to prevent the Deserialize impl of
@@ -1548,7 +1612,8 @@ pub(crate) fn parse_inner(
// but not if `bootstrap.toml` hasn't been created.
let mut toml = if !using_default_path || toml_path.exists() {
config.config = Some(if cfg!(not(test)) {
- toml_path.canonicalize().unwrap()
+ toml_path = toml_path.canonicalize().unwrap();
+ toml_path.clone()
} else {
toml_path.clone()
});
@@ -1576,6 +1641,26 @@ pub(crate) fn parse_inner(
toml.profile = Some("dist".into());
}
+ // Reverse the list to ensure the last added config extension remains the most dominant.
+ // For example, given ["a.toml", "b.toml"], "b.toml" should take precedence over "a.toml".
+ //
+ // This must be handled before applying the `profile` since `include`s should always take
+ // precedence over `profile`s.
+ for include_path in toml.include.clone().unwrap_or_default().iter().rev() {
+ let include_path = toml_path.parent().unwrap().join(include_path);
+
+ let included_toml = get_toml(&include_path).unwrap_or_else(|e| {
+ eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display());
+ exit!(2);
+ });
+ toml.merge(
+ Some(include_path),
+ &mut Default::default(),
+ included_toml,
+ ReplaceOpt::IgnoreDuplicate,
+ );
+ }
+
if let Some(include) = &toml.profile {
// Allows creating alias for profile names, allowing
// profiles to be renamed while maintaining back compatibility
@@ -1597,7 +1682,12 @@ pub(crate) fn parse_inner(
);
exit!(2);
});
- toml.merge(included_toml, ReplaceOpt::IgnoreDuplicate);
+ toml.merge(
+ Some(include_path),
+ &mut Default::default(),
+ included_toml,
+ ReplaceOpt::IgnoreDuplicate,
+ );
}
let mut override_toml = TomlConfig::default();
@@ -1608,7 +1698,12 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
let mut err = match get_table(option) {
Ok(v) => {
- override_toml.merge(v, ReplaceOpt::ErrorOnDuplicate);
+ override_toml.merge(
+ None,
+ &mut Default::default(),
+ v,
+ ReplaceOpt::ErrorOnDuplicate,
+ );
continue;
}
Err(e) => e,
@@ -1619,7 +1714,12 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
if !value.contains('"') {
match get_table(&format!(r#"{key}="{value}""#)) {
Ok(v) => {
- override_toml.merge(v, ReplaceOpt::ErrorOnDuplicate);
+ override_toml.merge(
+ None,
+ &mut Default::default(),
+ v,
+ ReplaceOpt::ErrorOnDuplicate,
+ );
continue;
}
Err(e) => err = e,
@@ -1629,7 +1729,7 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
eprintln!("failed to parse override `{option}`: `{err}");
exit!(2)
}
- toml.merge(override_toml, ReplaceOpt::Override);
+ toml.merge(None, &mut Default::default(), override_toml, ReplaceOpt::Override);
config.change_id = toml.change_id.inner;
@@ -2397,6 +2497,12 @@ fn get_table(option: &str) -> Result<TomlConfig, toml::de::Error> {
);
}
+ if config.lld_enabled && config.is_system_llvm(config.build) {
+ eprintln!(
+ "Warning: LLD is enabled when using external llvm-config. LLD will not be built and copied to the sysroot."
+ );
+ }
+
let default_std_features = BTreeSet::from([String::from("panic-unwind")]);
config.rust_std_features = std_features.unwrap_or(default_std_features);
@@ -2888,6 +2994,13 @@ pub(crate) fn update_submodule(&self, relative_path: &str) {
let absolute_path = self.src.join(relative_path);
+ // NOTE: This check is required because `jj git clone` doesn't create directories for
+ // submodules, they are completely ignored. The code below assumes this directory exists,
+ // so create it here.
+ if !absolute_path.exists() {
+ t!(fs::create_dir_all(&absolute_path));
+ }
+
// NOTE: The check for the empty directory is here because when running x.py the first time,
// the submodule won't be checked out. Check it out now so we can build it.
if !GitInfo::new(false, &absolute_path).is_managed_git_subrepository()
@@ -3083,19 +3196,30 @@ fn download_ci_rustc_commit(
let commit = if self.rust_info.is_managed_git_subrepository() {
// Look for a version to compare to based on the current commit.
// Only commits merged by bors will have CI artifacts.
- match self.last_modified_commit(&allowed_paths, "download-rustc", if_unchanged) {
- Some(commit) => commit,
- None => {
+ let freshness = self.check_path_modifications(&allowed_paths);
+ self.verbose(|| {
+ eprintln!("rustc freshness: {freshness:?}");
+ });
+ match freshness {
+ PathFreshness::LastModifiedUpstream { upstream } => upstream,
+ PathFreshness::HasLocalModifications { upstream } => {
if if_unchanged {
return None;
}
- println!("ERROR: could not find commit hash for downloading rustc");
- println!("HELP: maybe your repository history is too shallow?");
- println!(
- "HELP: consider setting `rust.download-rustc=false` in bootstrap.toml"
- );
- println!("HELP: or fetch enough history to include one upstream commit");
- crate::exit!(1);
+
+ if self.is_running_on_ci {
+ eprintln!("CI rustc commit matches with HEAD and we are in CI.");
+ eprintln!(
+ "`rustc.download-ci` functionality will be skipped as artifacts are not available."
+ );
+ return None;
+ }
+
+ upstream
+ }
+ PathFreshness::MissingUpstream => {
+ eprintln!("No upstream commit found");
+ return None;
}
}
} else {
@@ -3104,19 +3228,6 @@ fn download_ci_rustc_commit(
.expect("git-commit-info is missing in the project root")
};
- if self.is_running_on_ci && {
- let head_sha =
- output(helpers::git(Some(&self.src)).arg("rev-parse").arg("HEAD").as_command_mut());
- let head_sha = head_sha.trim();
- commit == head_sha
- } {
- eprintln!("CI rustc commit matches with HEAD and we are in CI.");
- eprintln!(
- "`rustc.download-ci` functionality will be skipped as artifacts are not available."
- );
- return None;
- }
-
if debug_assertions_requested {
eprintln!(
"WARN: `rust.debug-assertions = true` will prevent downloading CI rustc as alt CI \
@@ -3154,9 +3265,7 @@ fn parse_download_ci_llvm(
self.update_submodule("src/llvm-project");
// Check for untracked changes in `src/llvm-project` and other important places.
- let has_changes = self
- .last_modified_commit(LLVM_INVALIDATION_PATHS, "download-ci-llvm", true)
- .is_none();
+ let has_changes = self.has_changes_from_upstream(LLVM_INVALIDATION_PATHS);
// Return false if there are untracked changes, otherwise check if CI LLVM is available.
if has_changes { false } else { llvm::is_ci_llvm_available_for_target(self, asserts) }
@@ -3187,51 +3296,70 @@ fn parse_download_ci_llvm(
}
}
- /// Returns the last commit in which any of `modified_paths` were changed,
- /// or `None` if there are untracked changes in the working directory and `if_unchanged` is true.
- pub fn last_modified_commit(
- &self,
- modified_paths: &[&str],
- option_name: &str,
- if_unchanged: bool,
- ) -> Option<String> {
- assert!(
- self.rust_info.is_managed_git_subrepository(),
- "Can't run `Config::last_modified_commit` on a non-git source."
- );
-
- // Look for a version to compare to based on the current commit.
- // Only commits merged by bors will have CI artifacts.
- let commit = get_closest_merge_commit(Some(&self.src), &self.git_config(), &[]).unwrap();
- if commit.is_empty() {
- println!("error: could not find commit hash for downloading components from CI");
- println!("help: maybe your repository history is too shallow?");
- println!("help: consider disabling `{option_name}`");
- println!("help: or fetch enough history to include one upstream commit");
- crate::exit!(1);
+ /// Returns true if any of the `paths` have been modified locally.
+ pub fn has_changes_from_upstream(&self, paths: &[&'static str]) -> bool {
+ match self.check_path_modifications(paths) {
+ PathFreshness::LastModifiedUpstream { .. } => false,
+ PathFreshness::HasLocalModifications { .. } | PathFreshness::MissingUpstream => true,
}
+ }
- // Warn if there were changes to the compiler or standard library since the ancestor commit.
- let mut git = helpers::git(Some(&self.src));
- git.args(["diff-index", "--quiet", &commit, "--"]).args(modified_paths);
+ /// Checks whether any of the given paths have been modified w.r.t. upstream.
+ pub fn check_path_modifications(&self, paths: &[&'static str]) -> PathFreshness {
+ // Checking path modifications through git can be relatively expensive (>100ms).
+ // We do not assume that the sources would change during bootstrap's execution,
+ // so we can cache the results here.
+ // Note that we do not use a static variable for the cache, because it would cause problems
+ // in tests that create separate `Config` instsances.
+ self.path_modification_cache
+ .lock()
+ .unwrap()
+ .entry(paths.to_vec())
+ .or_insert_with(|| {
+ check_path_modifications(&self.src, &self.git_config(), paths, CiEnv::current())
+ .unwrap()
+ })
+ .clone()
+ }
- let has_changes = !t!(git.as_command_mut().status()).success();
- if has_changes {
- if if_unchanged {
- if self.is_verbose() {
- println!(
- "warning: saw changes to one of {modified_paths:?} since {commit}; \
- ignoring `{option_name}`"
- );
- }
- return None;
+ /// Checks if the given target is the same as the host target.
+ pub fn is_host_target(&self, target: TargetSelection) -> bool {
+ self.build == target
+ }
+
+ /// Returns `true` if this is an external version of LLVM not managed by bootstrap.
+ /// In particular, we expect llvm sources to be available when this is false.
+ ///
+ /// NOTE: this is not the same as `!is_rust_llvm` when `llvm_has_patches` is set.
+ pub fn is_system_llvm(&self, target: TargetSelection) -> bool {
+ match self.target_config.get(&target) {
+ Some(Target { llvm_config: Some(_), .. }) => {
+ let ci_llvm = self.llvm_from_ci && self.is_host_target(target);
+ !ci_llvm
}
- println!(
- "warning: `{option_name}` is enabled, but there are changes to one of {modified_paths:?}"
- );
+ // We're building from the in-tree src/llvm-project sources.
+ Some(Target { llvm_config: None, .. }) => false,
+ None => false,
}
+ }
- Some(commit.to_string())
+ /// Returns `true` if this is our custom, patched, version of LLVM.
+ ///
+ /// This does not necessarily imply that we're managing the `llvm-project` submodule.
+ pub fn is_rust_llvm(&self, target: TargetSelection) -> bool {
+ match self.target_config.get(&target) {
+ // We're using a user-controlled version of LLVM. The user has explicitly told us whether the version has our patches.
+ // (They might be wrong, but that's not a supported use-case.)
+ // In particular, this tries to support `submodules = false` and `patches = false`, for using a newer version of LLVM that's not through `rust-lang/llvm-project`.
+ Some(Target { llvm_has_rust_patches: Some(patched), .. }) => *patched,
+ // The user hasn't promised the patches match.
+ // This only has our patches if it's downloaded from CI or built from source.
+ _ => !self.is_system_llvm(target),
+ }
+ }
+
+ pub fn ci_env(&self) -> CiEnv {
+ if self.is_running_on_ci { CiEnv::GitHubActions } else { CiEnv::None }
}
}
diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs
index d8002ba..96ac8a6 100644
--- a/src/bootstrap/src/core/config/tests.rs
+++ b/src/bootstrap/src/core/config/tests.rs
@@ -1,10 +1,11 @@
use std::collections::BTreeSet;
-use std::env;
use std::fs::{File, remove_file};
use std::io::Write;
-use std::path::Path;
+use std::path::{Path, PathBuf};
+use std::{env, fs};
use build_helper::ci::CiEnv;
+use build_helper::git::PathFreshness;
use clap::CommandFactory;
use serde::Deserialize;
@@ -15,6 +16,7 @@
use crate::core::build_steps::llvm;
use crate::core::build_steps::llvm::LLVM_INVALIDATION_PATHS;
use crate::core::config::{LldMode, Target, TargetSelection, TomlConfig};
+use crate::utils::tests::git::git_test;
pub(crate) fn parse(config: &str) -> Config {
Config::parse_inner(
@@ -23,6 +25,27 @@ pub(crate) fn parse(config: &str) -> Config {
)
}
+fn get_toml(file: &Path) -> Result<TomlConfig, toml::de::Error> {
+ let contents = std::fs::read_to_string(file).unwrap();
+ toml::from_str(&contents).and_then(|table: toml::Value| TomlConfig::deserialize(table))
+}
+
+/// Helps with debugging by using consistent test-specific directories instead of
+/// random temporary directories.
+fn prepare_test_specific_dir() -> PathBuf {
+ let current = std::thread::current();
+ // Replace "::" with "_" to make it safe for directory names on Windows systems
+ let test_path = current.name().unwrap().replace("::", "_");
+
+ let testdir = parse("").tempdir().join(test_path);
+
+ // clean up any old test files
+ let _ = fs::remove_dir_all(&testdir);
+ let _ = fs::create_dir_all(&testdir);
+
+ testdir
+}
+
#[test]
fn download_ci_llvm() {
let config = parse("llvm.download-ci-llvm = false");
@@ -30,9 +53,7 @@ fn download_ci_llvm() {
let if_unchanged_config = parse("llvm.download-ci-llvm = \"if-unchanged\"");
if if_unchanged_config.llvm_from_ci && if_unchanged_config.is_running_on_ci {
- let has_changes = if_unchanged_config
- .last_modified_commit(LLVM_INVALIDATION_PATHS, "download-ci-llvm", true)
- .is_none();
+ let has_changes = if_unchanged_config.has_changes_from_upstream(LLVM_INVALIDATION_PATHS);
assert!(
!has_changes,
@@ -539,3 +560,428 @@ fn test_ci_flag() {
let config = Config::parse_inner(Flags::parse(&["check".into()]), |&_| toml::from_str(""));
assert_eq!(config.is_running_on_ci, CiEnv::is_ci());
}
+
+#[test]
+fn test_precedence_of_includes() {
+ let testdir = prepare_test_specific_dir();
+
+ let root_config = testdir.join("config.toml");
+ let root_config_content = br#"
+ include = ["./extension.toml"]
+
+ [llvm]
+ link-jobs = 2
+ "#;
+ File::create(&root_config).unwrap().write_all(root_config_content).unwrap();
+
+ let extension = testdir.join("extension.toml");
+ let extension_content = br#"
+ change-id=543
+ include = ["./extension2.toml"]
+ "#;
+ File::create(extension).unwrap().write_all(extension_content).unwrap();
+
+ let extension = testdir.join("extension2.toml");
+ let extension_content = br#"
+ change-id=742
+
+ [llvm]
+ link-jobs = 10
+
+ [build]
+ description = "Some creative description"
+ "#;
+ File::create(extension).unwrap().write_all(extension_content).unwrap();
+
+ let config = Config::parse_inner(
+ Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
+ get_toml,
+ );
+
+ assert_eq!(config.change_id.unwrap(), ChangeId::Id(543));
+ assert_eq!(config.llvm_link_jobs.unwrap(), 2);
+ assert_eq!(config.description.unwrap(), "Some creative description");
+}
+
+#[test]
+#[should_panic(expected = "Cyclic inclusion detected")]
+fn test_cyclic_include_direct() {
+ let testdir = prepare_test_specific_dir();
+
+ let root_config = testdir.join("config.toml");
+ let root_config_content = br#"
+ include = ["./extension.toml"]
+ "#;
+ File::create(&root_config).unwrap().write_all(root_config_content).unwrap();
+
+ let extension = testdir.join("extension.toml");
+ let extension_content = br#"
+ include = ["./config.toml"]
+ "#;
+ File::create(extension).unwrap().write_all(extension_content).unwrap();
+
+ let config = Config::parse_inner(
+ Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
+ get_toml,
+ );
+}
+
+#[test]
+#[should_panic(expected = "Cyclic inclusion detected")]
+fn test_cyclic_include_indirect() {
+ let testdir = prepare_test_specific_dir();
+
+ let root_config = testdir.join("config.toml");
+ let root_config_content = br#"
+ include = ["./extension.toml"]
+ "#;
+ File::create(&root_config).unwrap().write_all(root_config_content).unwrap();
+
+ let extension = testdir.join("extension.toml");
+ let extension_content = br#"
+ include = ["./extension2.toml"]
+ "#;
+ File::create(extension).unwrap().write_all(extension_content).unwrap();
+
+ let extension = testdir.join("extension2.toml");
+ let extension_content = br#"
+ include = ["./extension3.toml"]
+ "#;
+ File::create(extension).unwrap().write_all(extension_content).unwrap();
+
+ let extension = testdir.join("extension3.toml");
+ let extension_content = br#"
+ include = ["./extension.toml"]
+ "#;
+ File::create(extension).unwrap().write_all(extension_content).unwrap();
+
+ let config = Config::parse_inner(
+ Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
+ get_toml,
+ );
+}
+
+#[test]
+fn test_include_absolute_paths() {
+ let testdir = prepare_test_specific_dir();
+
+ let extension = testdir.join("extension.toml");
+ File::create(&extension).unwrap().write_all(&[]).unwrap();
+
+ let root_config = testdir.join("config.toml");
+ let extension_absolute_path =
+ extension.canonicalize().unwrap().to_str().unwrap().replace('\\', r"\\");
+ let root_config_content = format!(r#"include = ["{}"]"#, extension_absolute_path);
+ File::create(&root_config).unwrap().write_all(root_config_content.as_bytes()).unwrap();
+
+ let config = Config::parse_inner(
+ Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
+ get_toml,
+ );
+}
+
+#[test]
+fn test_include_relative_paths() {
+ let testdir = prepare_test_specific_dir();
+
+ let _ = fs::create_dir_all(&testdir.join("subdir/another_subdir"));
+
+ let root_config = testdir.join("config.toml");
+ let root_config_content = br#"
+ include = ["./subdir/extension.toml"]
+ "#;
+ File::create(&root_config).unwrap().write_all(root_config_content).unwrap();
+
+ let extension = testdir.join("subdir/extension.toml");
+ let extension_content = br#"
+ include = ["../extension2.toml"]
+ "#;
+ File::create(extension).unwrap().write_all(extension_content).unwrap();
+
+ let extension = testdir.join("extension2.toml");
+ let extension_content = br#"
+ include = ["./subdir/another_subdir/extension3.toml"]
+ "#;
+ File::create(extension).unwrap().write_all(extension_content).unwrap();
+
+ let extension = testdir.join("subdir/another_subdir/extension3.toml");
+ let extension_content = br#"
+ include = ["../../extension4.toml"]
+ "#;
+ File::create(extension).unwrap().write_all(extension_content).unwrap();
+
+ let extension = testdir.join("extension4.toml");
+ File::create(extension).unwrap().write_all(&[]).unwrap();
+
+ let config = Config::parse_inner(
+ Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
+ get_toml,
+ );
+}
+
+#[test]
+fn test_include_precedence_over_profile() {
+ let testdir = prepare_test_specific_dir();
+
+ let root_config = testdir.join("config.toml");
+ let root_config_content = br#"
+ profile = "dist"
+ include = ["./extension.toml"]
+ "#;
+ File::create(&root_config).unwrap().write_all(root_config_content).unwrap();
+
+ let extension = testdir.join("extension.toml");
+ let extension_content = br#"
+ [rust]
+ channel = "dev"
+ "#;
+ File::create(extension).unwrap().write_all(extension_content).unwrap();
+
+ let config = Config::parse_inner(
+ Flags::parse(&["check".to_owned(), format!("--config={}", root_config.to_str().unwrap())]),
+ get_toml,
+ );
+
+ // "dist" profile would normally set the channel to "auto-detect", but includes should
+ // override profile settings, so we expect this to be "dev" here.
+ assert_eq!(config.channel, "dev");
+}
+
+#[test]
+fn test_pr_ci_unchanged_anywhere() {
+ git_test(|ctx| {
+ let sha = ctx.create_upstream_merge(&["a"]);
+ ctx.create_nonupstream_merge(&["b"]);
+ let src = ctx.check_modifications(&["c"], CiEnv::GitHubActions);
+ assert_eq!(src, PathFreshness::LastModifiedUpstream { upstream: sha });
+ });
+}
+
+#[test]
+fn test_pr_ci_changed_in_pr() {
+ git_test(|ctx| {
+ let sha = ctx.create_upstream_merge(&["a"]);
+ ctx.create_nonupstream_merge(&["b"]);
+ let src = ctx.check_modifications(&["b"], CiEnv::GitHubActions);
+ assert_eq!(src, PathFreshness::HasLocalModifications { upstream: sha });
+ });
+}
+
+#[test]
+fn test_auto_ci_unchanged_anywhere_select_parent() {
+ git_test(|ctx| {
+ let sha = ctx.create_upstream_merge(&["a"]);
+ ctx.create_upstream_merge(&["b"]);
+ let src = ctx.check_modifications(&["c"], CiEnv::GitHubActions);
+ assert_eq!(src, PathFreshness::LastModifiedUpstream { upstream: sha });
+ });
+}
+
+#[test]
+fn test_auto_ci_changed_in_pr() {
+ git_test(|ctx| {
+ let sha = ctx.create_upstream_merge(&["a"]);
+ ctx.create_upstream_merge(&["b", "c"]);
+ let src = ctx.check_modifications(&["c", "d"], CiEnv::GitHubActions);
+ assert_eq!(src, PathFreshness::HasLocalModifications { upstream: sha });
+ });
+}
+
+#[test]
+fn test_local_uncommitted_modifications() {
+ git_test(|ctx| {
+ let sha = ctx.create_upstream_merge(&["a"]);
+ ctx.create_branch("feature");
+ ctx.modify("a");
+
+ assert_eq!(
+ ctx.check_modifications(&["a", "d"], CiEnv::None),
+ PathFreshness::HasLocalModifications { upstream: sha }
+ );
+ });
+}
+
+#[test]
+fn test_local_committed_modifications() {
+ git_test(|ctx| {
+ let sha = ctx.create_upstream_merge(&["a"]);
+ ctx.create_upstream_merge(&["b", "c"]);
+ ctx.create_branch("feature");
+ ctx.modify("x");
+ ctx.commit();
+ ctx.modify("a");
+ ctx.commit();
+
+ assert_eq!(
+ ctx.check_modifications(&["a", "d"], CiEnv::None),
+ PathFreshness::HasLocalModifications { upstream: sha }
+ );
+ });
+}
+
+#[test]
+fn test_local_committed_modifications_subdirectory() {
+ git_test(|ctx| {
+ let sha = ctx.create_upstream_merge(&["a/b/c"]);
+ ctx.create_upstream_merge(&["b", "c"]);
+ ctx.create_branch("feature");
+ ctx.modify("a/b/d");
+ ctx.commit();
+
+ assert_eq!(
+ ctx.check_modifications(&["a/b"], CiEnv::None),
+ PathFreshness::HasLocalModifications { upstream: sha }
+ );
+ });
+}
+
+#[test]
+fn test_local_changes_in_head_upstream() {
+ git_test(|ctx| {
+ // We want to resolve to the upstream commit that made modifications to a,
+ // even if it is currently HEAD
+ let sha = ctx.create_upstream_merge(&["a"]);
+ assert_eq!(
+ ctx.check_modifications(&["a", "d"], CiEnv::None),
+ PathFreshness::LastModifiedUpstream { upstream: sha }
+ );
+ });
+}
+
+#[test]
+fn test_local_changes_in_previous_upstream() {
+ git_test(|ctx| {
+ // We want to resolve to this commit, which modified a
+ let sha = ctx.create_upstream_merge(&["a", "e"]);
+ // Not to this commit, which is the latest upstream commit
+ ctx.create_upstream_merge(&["b", "c"]);
+ ctx.create_branch("feature");
+ ctx.modify("d");
+ ctx.commit();
+
+ assert_eq!(
+ ctx.check_modifications(&["a"], CiEnv::None),
+ PathFreshness::LastModifiedUpstream { upstream: sha }
+ );
+ });
+}
+
+#[test]
+fn test_local_no_upstream_commit_with_changes() {
+ git_test(|ctx| {
+ ctx.create_upstream_merge(&["a", "e"]);
+ ctx.create_upstream_merge(&["a", "e"]);
+ // We want to fall back to this commit, because there are no commits
+ // that modified `x`.
+ let sha = ctx.create_upstream_merge(&["a", "e"]);
+ ctx.create_branch("feature");
+ ctx.modify("d");
+ ctx.commit();
+ assert_eq!(
+ ctx.check_modifications(&["x"], CiEnv::None),
+ PathFreshness::LastModifiedUpstream { upstream: sha }
+ );
+ });
+}
+
+#[test]
+fn test_local_no_upstream_commit() {
+ git_test(|ctx| {
+ let src = ctx.check_modifications(&["c", "d"], CiEnv::None);
+ assert_eq!(src, PathFreshness::MissingUpstream);
+ });
+}
+
+#[test]
+fn test_local_changes_negative_path() {
+ git_test(|ctx| {
+ let upstream = ctx.create_upstream_merge(&["a"]);
+ ctx.create_branch("feature");
+ ctx.modify("b");
+ ctx.modify("d");
+ ctx.commit();
+
+ assert_eq!(
+ ctx.check_modifications(&[":!b", ":!d"], CiEnv::None),
+ PathFreshness::LastModifiedUpstream { upstream: upstream.clone() }
+ );
+ assert_eq!(
+ ctx.check_modifications(&[":!c"], CiEnv::None),
+ PathFreshness::HasLocalModifications { upstream: upstream.clone() }
+ );
+ assert_eq!(
+ ctx.check_modifications(&[":!d", ":!x"], CiEnv::None),
+ PathFreshness::HasLocalModifications { upstream }
+ );
+ });
+}
+
+#[test]
+fn test_local_changes_subtree_that_used_bors() {
+ // Here we simulate a very specific situation related to subtrees.
+ // When you have merge commits locally, we should ignore them w.r.t. the artifact download
+ // logic.
+ // The upstream search code currently uses a simple heuristic:
+ // - Find commits by bors (or in general an author with the merge commit e-mail)
+ // - Find the newest such commit
+ // This should make it work even for subtrees that:
+ // - Used bors in the past (so they have bors merge commits in their history).
+ // - Use Josh to merge rustc into the subtree, in a way that the rustc history is the second
+ // parent, not the first one.
+ //
+ // In addition, when searching for modified files, we cannot simply start from HEAD, because
+ // in this situation git wouldn't find the right commit.
+ //
+ // This test checks that this specific scenario will resolve to the right rustc commit, both
+ // when finding a modified file and when finding a non-existent file (which essentially means
+ // that we just lookup the most recent upstream commit).
+ //
+ // See https://github.com/rust-lang/rust/issues/101907#issuecomment-2697671282 for more details.
+ git_test(|ctx| {
+ ctx.create_upstream_merge(&["a"]);
+
+ // Start unrelated subtree history
+ ctx.run_git(&["switch", "--orphan", "subtree"]);
+ ctx.modify("bar");
+ ctx.commit();
+ // Now we need to emulate old bors commits in the subtree.
+ // Git only has a resolution of one second, which is a problem, since our git logic orders
+ // merge commits by their date.
+ // To avoid sleeping in the test, we modify the commit date to be forcefully in the past.
+ ctx.create_upstream_merge(&["subtree/a"]);
+ ctx.run_git(&["commit", "--amend", "--date", "Wed Feb 16 14:00 2011 +0100", "--no-edit"]);
+
+ // Merge the subtree history into rustc
+ ctx.switch_to_branch("main");
+ ctx.run_git(&["merge", "subtree", "--allow-unrelated"]);
+
+ // Create a rustc commit that modifies a path that we're interested in (`x`)
+ let upstream_1 = ctx.create_upstream_merge(&["x"]);
+ // Create another bors commit
+ let upstream_2 = ctx.create_upstream_merge(&["a"]);
+
+ ctx.switch_to_branch("subtree");
+
+ // Create a subtree branch
+ ctx.create_branch("subtree-pr");
+ ctx.modify("baz");
+ ctx.commit();
+ // We merge rustc into this branch (simulating a "subtree pull")
+ ctx.merge("main", "committer <committer@foo.bar>");
+
+ // And then merge that branch into the subtree (simulating a situation right before a
+ // "subtree push")
+ ctx.switch_to_branch("subtree");
+ ctx.merge("subtree-pr", "committer <committer@foo.bar>");
+
+ // And we want to check that we resolve to the right commits.
+ assert_eq!(
+ ctx.check_modifications(&["x"], CiEnv::None),
+ PathFreshness::LastModifiedUpstream { upstream: upstream_1 }
+ );
+ assert_eq!(
+ ctx.check_modifications(&["nonexistent"], CiEnv::None),
+ PathFreshness::LastModifiedUpstream { upstream: upstream_2 }
+ );
+ });
+}
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 5bd947f..b95d073 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -417,7 +417,7 @@ enum DownloadSource {
Dist,
}
-/// Functions that are only ever called once, but named for clarify and to avoid thousand-line functions.
+/// Functions that are only ever called once, but named for clarity and to avoid thousand-line functions.
impl Config {
pub(crate) fn download_clippy(&self) -> PathBuf {
self.verbose(|| println!("downloading stage0 clippy artifacts"));
@@ -720,8 +720,9 @@ pub(crate) fn maybe_download_ci_llvm(&self) {}
#[cfg(not(test))]
pub(crate) fn maybe_download_ci_llvm(&self) {
use build_helper::exit;
+ use build_helper::git::PathFreshness;
- use crate::core::build_steps::llvm::detect_llvm_sha;
+ use crate::core::build_steps::llvm::detect_llvm_freshness;
use crate::core::config::check_incompatible_options_for_ci_llvm;
if !self.llvm_from_ci {
@@ -729,7 +730,22 @@ pub(crate) fn maybe_download_ci_llvm(&self) {
}
let llvm_root = self.ci_llvm_root();
- let llvm_sha = detect_llvm_sha(self, self.rust_info.is_managed_git_subrepository());
+ let llvm_freshness =
+ detect_llvm_freshness(self, self.rust_info.is_managed_git_subrepository());
+ self.verbose(|| {
+ eprintln!("LLVM freshness: {llvm_freshness:?}");
+ });
+ let llvm_sha = match llvm_freshness {
+ PathFreshness::LastModifiedUpstream { upstream } => upstream,
+ PathFreshness::HasLocalModifications { upstream } => upstream,
+ PathFreshness::MissingUpstream => {
+ eprintln!("error: could not find commit hash for downloading LLVM");
+ eprintln!("HELP: maybe your repository history is too shallow?");
+ eprintln!("HELP: consider disabling `download-ci-llvm`");
+ eprintln!("HELP: or fetch enough history to include one upstream commit");
+ crate::exit!(1);
+ }
+ };
let stamp_key = format!("{}{}", llvm_sha, self.llvm_assertions);
let llvm_stamp = BuildStamp::new(&llvm_root).with_prefix("llvm").add_stamp(stamp_key);
if !llvm_stamp.is_up_to_date() && !self.dry_run() {
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 891340a..eb0bf1d 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -34,6 +34,7 @@ pub struct Finder {
// Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap).
const STAGE0_MISSING_TARGETS: &[&str] = &[
// just a dummy comment so the list doesn't get onelined
+ "x86_64-lynx-lynxos178",
];
/// Minimum version threshold for libstdc++ required when using prebuilt LLVM
@@ -325,7 +326,7 @@ pub fn check(build: &mut Build) {
if target.contains("musl") && !target.contains("unikraft") {
// If this is a native target (host is also musl) and no musl-root is given,
// fall back to the system toolchain in /usr before giving up
- if build.musl_root(*target).is_none() && build.is_builder_target(*target) {
+ if build.musl_root(*target).is_none() && build.config.is_host_target(*target) {
let target = build.config.target_config.entry(*target).or_default();
target.musl_root = Some("/usr".into());
}
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 1a513a2..88d1815 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -35,7 +35,7 @@
use crate::core::builder;
use crate::core::builder::Kind;
-use crate::core::config::{DryRun, LldMode, LlvmLibunwind, Target, TargetSelection, flags};
+use crate::core::config::{DryRun, LldMode, LlvmLibunwind, TargetSelection, flags};
use crate::utils::exec::{BehaviorOnFailure, BootstrapCommand, CommandOutput, OutputMode, command};
use crate::utils::helpers::{
self, dir_is_empty, exe, libdir, output, set_file_times, split_debuginfo, symlink_dir,
@@ -803,7 +803,7 @@ fn cargo_out(&self, compiler: Compiler, mode: Mode, target: TargetSelection) ->
/// Note that if LLVM is configured externally then the directory returned
/// will likely be empty.
fn llvm_out(&self, target: TargetSelection) -> PathBuf {
- if self.config.llvm_from_ci && self.is_builder_target(target) {
+ if self.config.llvm_from_ci && self.config.is_host_target(target) {
self.config.ci_llvm_root()
} else {
self.out.join(target).join("llvm")
@@ -851,37 +851,6 @@ fn vendored_crates_path(&self) -> Option<PathBuf> {
if self.config.vendor { Some(self.src.join(VENDOR_DIR)) } else { None }
}
- /// Returns `true` if this is an external version of LLVM not managed by bootstrap.
- /// In particular, we expect llvm sources to be available when this is false.
- ///
- /// NOTE: this is not the same as `!is_rust_llvm` when `llvm_has_patches` is set.
- fn is_system_llvm(&self, target: TargetSelection) -> bool {
- match self.config.target_config.get(&target) {
- Some(Target { llvm_config: Some(_), .. }) => {
- let ci_llvm = self.config.llvm_from_ci && self.is_builder_target(target);
- !ci_llvm
- }
- // We're building from the in-tree src/llvm-project sources.
- Some(Target { llvm_config: None, .. }) => false,
- None => false,
- }
- }
-
- /// Returns `true` if this is our custom, patched, version of LLVM.
- ///
- /// This does not necessarily imply that we're managing the `llvm-project` submodule.
- fn is_rust_llvm(&self, target: TargetSelection) -> bool {
- match self.config.target_config.get(&target) {
- // We're using a user-controlled version of LLVM. The user has explicitly told us whether the version has our patches.
- // (They might be wrong, but that's not a supported use-case.)
- // In particular, this tries to support `submodules = false` and `patches = false`, for using a newer version of LLVM that's not through `rust-lang/llvm-project`.
- Some(Target { llvm_has_rust_patches: Some(patched), .. }) => *patched,
- // The user hasn't promised the patches match.
- // This only has our patches if it's downloaded from CI or built from source.
- _ => !self.is_system_llvm(target),
- }
- }
-
/// Returns the path to `FileCheck` binary for the specified target
fn llvm_filecheck(&self, target: TargetSelection) -> PathBuf {
let target_config = self.config.target_config.get(&target);
@@ -1356,7 +1325,7 @@ fn linker(&self, target: TargetSelection) -> Option<PathBuf> {
// need to use CXX compiler as linker to resolve the exception functions
// that are only existed in CXX libraries
Some(self.cxx.borrow()[&target].path().into())
- } else if !self.is_builder_target(target)
+ } else if !self.config.is_host_target(target)
&& helpers::use_host_linker(target)
&& !target.is_msvc()
{
@@ -2025,11 +1994,6 @@ fn colored_stream_inner<R, F, C>(&self, constructor: C, is_tty: bool, f: F) -> R
stream.reset().unwrap();
result
}
-
- /// Checks if the given target is the same as the builder target.
- fn is_builder_target(&self, target: TargetSelection) -> bool {
- self.config.build == target
- }
}
#[cfg(unix)]
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 48b6f77..3f1885a 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -396,4 +396,9 @@ pub fn human_readable_changes(changes: &[ChangeInfo]) -> String {
severity: ChangeSeverity::Info,
summary: "Added a new option `build.compiletest-use-stage0-libtest` to force `compiletest` to use the stage 0 libtest.",
},
+ ChangeInfo {
+ change_id: 138934,
+ severity: ChangeSeverity::Info,
+ summary: "Added new option `include` to create config extensions.",
+ },
];
diff --git a/src/bootstrap/src/utils/mod.rs b/src/bootstrap/src/utils/mod.rs
index caef8ce..169fcec 100644
--- a/src/bootstrap/src/utils/mod.rs
+++ b/src/bootstrap/src/utils/mod.rs
@@ -20,4 +20,4 @@
pub(crate) mod metrics;
#[cfg(test)]
-mod tests;
+pub(crate) mod tests;
diff --git a/src/bootstrap/src/utils/proc_macro_deps.rs b/src/bootstrap/src/utils/proc_macro_deps.rs
index aa564b4..b61fa3b 100644
--- a/src/bootstrap/src/utils/proc_macro_deps.rs
+++ b/src/bootstrap/src/utils/proc_macro_deps.rs
@@ -28,18 +28,14 @@
"libc",
"log",
"memchr",
- "mime",
- "mime_guess",
"minimal-lexical",
"nom",
- "num-conv",
"once_cell",
"pest",
"pest_generator",
"pest_meta",
"proc-macro2",
"quote",
- "rinja_parser",
"rustc-hash",
"self_cell",
"serde",
@@ -50,7 +46,6 @@
"syn",
"synstructure",
"thiserror",
- "time-core",
"tinystr",
"type-map",
"typenum",
@@ -58,7 +53,6 @@
"unic-langid",
"unic-langid-impl",
"unic-langid-macros",
- "unicase",
"unicode-ident",
"unicode-width",
"version_check",
diff --git a/src/bootstrap/src/utils/tests/git.rs b/src/bootstrap/src/utils/tests/git.rs
new file mode 100644
index 0000000..99e0793
--- /dev/null
+++ b/src/bootstrap/src/utils/tests/git.rs
@@ -0,0 +1,152 @@
+use std::ffi::OsStr;
+use std::fs::OpenOptions;
+use std::path::Path;
+use std::process::Command;
+
+use build_helper::ci::CiEnv;
+use build_helper::git::{GitConfig, PathFreshness, check_path_modifications};
+
+pub struct GitCtx {
+ dir: tempfile::TempDir,
+ pub git_repo: String,
+ pub nightly_branch: String,
+ pub merge_bot_email: String,
+}
+
+impl GitCtx {
+ fn new() -> Self {
+ let dir = tempfile::TempDir::new().unwrap();
+ let ctx = Self {
+ dir,
+ git_repo: "rust-lang/rust".to_string(),
+ nightly_branch: "nightly".to_string(),
+ merge_bot_email: "Merge bot <merge-bot@rust-lang.org>".to_string(),
+ };
+ ctx.run_git(&["init"]);
+ ctx.run_git(&["config", "user.name", "Tester"]);
+ ctx.run_git(&["config", "user.email", "tester@rust-lang.org"]);
+ ctx.modify("README.md");
+ ctx.commit();
+ ctx.run_git(&["branch", "-m", "main"]);
+ ctx
+ }
+
+ pub fn get_path(&self) -> &Path {
+ self.dir.path()
+ }
+
+ pub fn check_modifications(&self, target_paths: &[&str], ci_env: CiEnv) -> PathFreshness {
+ check_path_modifications(self.dir.path(), &self.git_config(), target_paths, ci_env).unwrap()
+ }
+
+ pub fn create_upstream_merge(&self, modified_files: &[&str]) -> String {
+ self.create_branch_and_merge("previous-pr", modified_files, &self.merge_bot_email)
+ }
+
+ pub fn create_nonupstream_merge(&self, modified_files: &[&str]) -> String {
+ self.create_branch_and_merge("pr", modified_files, "Tester <tester@rust-lang.org>")
+ }
+
+ pub fn create_branch_and_merge(
+ &self,
+ branch: &str,
+ modified_files: &[&str],
+ author: &str,
+ ) -> String {
+ let current_branch = self.get_current_branch();
+
+ self.create_branch(branch);
+ for file in modified_files {
+ self.modify(file);
+ }
+ self.commit();
+ self.switch_to_branch(¤t_branch);
+ self.merge(branch, author);
+ self.run_git(&["branch", "-d", branch]);
+ self.get_current_commit()
+ }
+
+ pub fn get_current_commit(&self) -> String {
+ self.run_git(&["rev-parse", "HEAD"])
+ }
+
+ pub fn get_current_branch(&self) -> String {
+ self.run_git(&["rev-parse", "--abbrev-ref", "HEAD"])
+ }
+
+ pub fn merge(&self, branch: &str, author: &str) {
+ self.run_git(&["merge", "--no-commit", "--no-ff", branch]);
+ self.run_git(&[
+ "commit".to_string(),
+ "-m".to_string(),
+ format!("Merge of {branch} into {}", self.get_current_branch()),
+ "--author".to_string(),
+ author.to_string(),
+ ]);
+ }
+
+ pub fn modify(&self, path: &str) {
+ self.write(path, "line");
+ }
+
+ pub fn write(&self, path: &str, data: &str) {
+ use std::io::Write;
+
+ let path = self.dir.path().join(path);
+ std::fs::create_dir_all(&path.parent().unwrap()).unwrap();
+
+ let mut file = OpenOptions::new().create(true).append(true).open(path).unwrap();
+ writeln!(file, "{data}").unwrap();
+ }
+
+ pub fn commit(&self) -> String {
+ self.run_git(&["add", "."]);
+ self.run_git(&["commit", "-m", "commit message"]);
+ self.get_current_commit()
+ }
+
+ pub fn switch_to_branch(&self, name: &str) {
+ self.run_git(&["switch", name]);
+ }
+
+ /// Creates a branch and switches to it.
+ pub fn create_branch(&self, name: &str) {
+ self.run_git(&["checkout", "-b", name]);
+ }
+
+ pub fn run_git<S: AsRef<OsStr>>(&self, args: &[S]) -> String {
+ let mut cmd = self.git_cmd();
+ cmd.args(args);
+ eprintln!("Running {cmd:?}");
+ let output = cmd.output().unwrap();
+ let stdout = String::from_utf8(output.stdout).unwrap().trim().to_string();
+ let stderr = String::from_utf8(output.stderr).unwrap().trim().to_string();
+ if !output.status.success() {
+ panic!("Git command `{cmd:?}` failed\nStdout\n{stdout}\nStderr\n{stderr}");
+ }
+ stdout
+ }
+
+ fn git_cmd(&self) -> Command {
+ let mut cmd = Command::new("git");
+ cmd.current_dir(&self.dir);
+ cmd
+ }
+
+ fn git_config(&self) -> GitConfig<'_> {
+ GitConfig {
+ git_repository: &self.git_repo,
+ nightly_branch: &self.nightly_branch,
+ git_merge_commit_email: &self.merge_bot_email,
+ }
+ }
+}
+
+/// Run an end-to-end test that allows testing git logic.
+pub fn git_test<F>(test_fn: F)
+where
+ F: FnOnce(&mut GitCtx),
+{
+ let mut ctx = GitCtx::new();
+ test_fn(&mut ctx);
+}
diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs
index 0791f7a..73d55db 100644
--- a/src/bootstrap/src/utils/tests/mod.rs
+++ b/src/bootstrap/src/utils/tests/mod.rs
@@ -1 +1,2 @@
+pub mod git;
mod shared_helpers_tests;
diff --git a/src/build_helper/src/fs/mod.rs b/src/build_helper/src/fs/mod.rs
index 0202984..123df76 100644
--- a/src/build_helper/src/fs/mod.rs
+++ b/src/build_helper/src/fs/mod.rs
@@ -22,21 +22,27 @@ pub fn ignore_not_found<Op>(mut op: Op) -> io::Result<()>
/// A wrapper around [`std::fs::remove_dir_all`] that can also be used on *non-directory entries*,
/// including files and symbolic links.
///
-/// - This will produce an error if the target path is not found.
+/// - This will not produce an error if the target path is not found.
/// - Like [`std::fs::remove_dir_all`], this helper does not traverse symbolic links, will remove
/// symbolic link itself.
/// - This helper is **not** robust against races on the underlying filesystem, behavior is
/// unspecified if this helper is called concurrently.
/// - This helper is not robust against TOCTOU problems.
///
-/// FIXME: this implementation is insufficiently robust to replace bootstrap's clean `rm_rf`
-/// implementation:
-///
-/// - This implementation currently does not perform retries.
+/// FIXME: Audit whether this implementation is robust enough to replace bootstrap's clean `rm_rf`.
#[track_caller]
pub fn recursive_remove<P: AsRef<Path>>(path: P) -> io::Result<()> {
let path = path.as_ref();
- let metadata = fs::symlink_metadata(path)?;
+
+ // If the path doesn't exist, we treat it as a successful no-op.
+ // From the caller's perspective, the goal is simply "ensure this file/dir is gone" —
+ // if it's already not there, that's a success, not an error.
+ let metadata = match fs::symlink_metadata(path) {
+ Ok(m) => m,
+ Err(e) if e.kind() == io::ErrorKind::NotFound => return Ok(()),
+ Err(e) => return Err(e),
+ };
+
#[cfg(windows)]
let is_dir_like = |meta: &fs::Metadata| {
use std::os::windows::fs::FileTypeExt;
@@ -45,11 +51,35 @@ pub fn recursive_remove<P: AsRef<Path>>(path: P) -> io::Result<()> {
#[cfg(not(windows))]
let is_dir_like = fs::Metadata::is_dir;
- if is_dir_like(&metadata) {
- fs::remove_dir_all(path)
- } else {
- try_remove_op_set_perms(fs::remove_file, path, metadata)
+ const MAX_RETRIES: usize = 5;
+ const RETRY_DELAY_MS: u64 = 100;
+
+ let try_remove = || {
+ if is_dir_like(&metadata) {
+ fs::remove_dir_all(path)
+ } else {
+ try_remove_op_set_perms(fs::remove_file, path, metadata.clone())
+ }
+ };
+
+ // Retry deletion a few times to handle transient filesystem errors.
+ // This is unusual for local file operations, but it's a mitigation
+ // against unlikely events where malware scanners may be holding a
+ // file beyond our control, to give the malware scanners some opportunity
+ // to release their hold.
+ for attempt in 0..MAX_RETRIES {
+ match try_remove() {
+ Ok(()) => return Ok(()),
+ Err(e) if e.kind() == io::ErrorKind::NotFound => return Ok(()),
+ Err(_) if attempt < MAX_RETRIES - 1 => {
+ std::thread::sleep(std::time::Duration::from_millis(RETRY_DELAY_MS));
+ continue;
+ }
+ Err(e) => return Err(e),
+ }
}
+
+ Ok(())
}
fn try_remove_op_set_perms<'p, Op>(mut op: Op, path: &'p Path, metadata: Metadata) -> io::Result<()>
@@ -67,3 +97,9 @@ fn try_remove_op_set_perms<'p, Op>(mut op: Op, path: &'p Path, metadata: Metadat
Err(e) => Err(e),
}
}
+
+pub fn remove_and_create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
+ let path = path.as_ref();
+ recursive_remove(path)?;
+ fs::create_dir_all(path)
+}
diff --git a/src/build_helper/src/fs/tests.rs b/src/build_helper/src/fs/tests.rs
index 1e69439..7ce1d89 100644
--- a/src/build_helper/src/fs/tests.rs
+++ b/src/build_helper/src/fs/tests.rs
@@ -14,7 +14,7 @@ fn nonexistent_path() {
let tmpdir = env::temp_dir();
let path = tmpdir.join("__INTERNAL_BOOTSTRAP_nonexistent_path");
assert!(fs::symlink_metadata(&path).is_err_and(|e| e.kind() == io::ErrorKind::NotFound));
- assert!(recursive_remove(&path).is_err_and(|e| e.kind() == io::ErrorKind::NotFound));
+ assert!(recursive_remove(&path).is_ok());
}
#[test]
diff --git a/src/build_helper/src/git.rs b/src/build_helper/src/git.rs
index 693e0fc..8d53a83 100644
--- a/src/build_helper/src/git.rs
+++ b/src/build_helper/src/git.rs
@@ -3,6 +3,7 @@
use crate::ci::CiEnv;
+#[derive(Debug)]
pub struct GitConfig<'a> {
pub git_repository: &'a str,
pub nightly_branch: &'a str,
@@ -27,145 +28,234 @@ pub fn output_result(cmd: &mut Command) -> Result<String, String> {
String::from_utf8(output.stdout).map_err(|err| format!("{err:?}"))
}
-/// Finds the remote for rust-lang/rust.
-/// For example for these remotes it will return `upstream`.
-/// ```text
-/// origin https://github.com/pietroalbani/rust.git (fetch)
-/// origin https://github.com/pietroalbani/rust.git (push)
-/// upstream https://github.com/rust-lang/rust (fetch)
-/// upstream https://github.com/rust-lang/rust (push)
-/// ```
-pub fn get_rust_lang_rust_remote(
- config: &GitConfig<'_>,
- git_dir: Option<&Path>,
-) -> Result<String, String> {
- let mut git = Command::new("git");
- if let Some(git_dir) = git_dir {
- git.current_dir(git_dir);
- }
- git.args(["config", "--local", "--get-regex", "remote\\..*\\.url"]);
- let stdout = output_result(&mut git)?;
-
- let rust_lang_remote = stdout
- .lines()
- .find(|remote| remote.contains(config.git_repository))
- .ok_or_else(|| format!("{} remote not found", config.git_repository))?;
-
- let remote_name =
- rust_lang_remote.split('.').nth(1).ok_or_else(|| "remote name not found".to_owned())?;
- Ok(remote_name.into())
+/// Represents the result of checking whether a set of paths
+/// have been modified locally or not.
+#[derive(PartialEq, Debug, Clone)]
+pub enum PathFreshness {
+ /// Artifacts should be downloaded from this upstream commit,
+ /// there are no local modifications.
+ LastModifiedUpstream { upstream: String },
+ /// There are local modifications to a certain set of paths.
+ /// "Local" essentially means "not-upstream" here.
+ /// `upstream` is the latest upstream merge commit that made modifications to the
+ /// set of paths.
+ HasLocalModifications { upstream: String },
+ /// No upstream commit was found.
+ /// This should not happen in most reasonable circumstances, but one never knows.
+ MissingUpstream,
}
-pub fn rev_exists(rev: &str, git_dir: Option<&Path>) -> Result<bool, String> {
- let mut git = Command::new("git");
- if let Some(git_dir) = git_dir {
- git.current_dir(git_dir);
- }
- git.args(["rev-parse", rev]);
- let output = git.output().map_err(|err| format!("{err:?}"))?;
-
- match output.status.code() {
- Some(0) => Ok(true),
- Some(128) => Ok(false),
- None => Err(format!(
- "git didn't exit properly: {}",
- String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
- )),
- Some(code) => Err(format!(
- "git command exited with status code: {code}: {}",
- String::from_utf8(output.stderr).map_err(|err| format!("{err:?}"))?
- )),
- }
-}
-
-/// Returns the master branch from which we can take diffs to see changes.
-/// This will usually be rust-lang/rust master, but sometimes this might not exist.
-/// This could be because the user is updating their forked master branch using the GitHub UI
-/// and therefore doesn't need an upstream master branch checked out.
-/// We will then fall back to origin/master in the hope that at least this exists.
-pub fn updated_master_branch(
- config: &GitConfig<'_>,
- git_dir: Option<&Path>,
-) -> Result<String, String> {
- let upstream_remote = get_rust_lang_rust_remote(config, git_dir)?;
- let branch = config.nightly_branch;
- for upstream_master in [format!("{upstream_remote}/{branch}"), format!("origin/{branch}")] {
- if rev_exists(&upstream_master, git_dir)? {
- return Ok(upstream_master);
- }
- }
-
- Err("Cannot find any suitable upstream master branch".to_owned())
-}
-
-/// Finds the nearest merge commit by comparing the local `HEAD` with the upstream branch's state.
-/// To work correctly, the upstream remote must be properly configured using `git remote add <name> <url>`.
-/// In most cases `get_closest_merge_commit` is the function you are looking for as it doesn't require remote
-/// to be configured.
-fn git_upstream_merge_base(
- config: &GitConfig<'_>,
- git_dir: Option<&Path>,
-) -> Result<String, String> {
- let updated_master = updated_master_branch(config, git_dir)?;
- let mut git = Command::new("git");
- if let Some(git_dir) = git_dir {
- git.current_dir(git_dir);
- }
- Ok(output_result(git.arg("merge-base").arg(&updated_master).arg("HEAD"))?.trim().to_owned())
-}
-
-/// Searches for the nearest merge commit in the repository that also exists upstream.
+/// This function figures out if a set of paths was last modified upstream or
+/// if there are some local modifications made to them.
+/// It can be used to figure out if we should download artifacts from CI or rather
+/// build them locally.
///
-/// It looks for the most recent commit made by the merge bot by matching the author's email
-/// address with the merge bot's email.
-pub fn get_closest_merge_commit(
- git_dir: Option<&Path>,
+/// The function assumes that at least a single upstream bors merge commit is in the
+/// local git history.
+///
+/// `target_paths` should be a non-empty slice of paths (git `pathspec`s) relative to `git_dir`
+/// whose modifications would invalidate the artifact.
+/// Each pathspec can also be a negative match, i.e. `:!foo`. This matches changes outside
+/// the `foo` directory.
+/// See <https://git-scm.com/docs/gitglossary#Documentation/gitglossary.txt-aiddefpathspecapathspec>
+/// for how git `pathspec` works.
+///
+/// The function behaves differently in CI and outside CI.
+///
+/// - Outside CI, we want to find out if `target_paths` were modified in some local commit on
+/// top of the latest upstream commit that is available in local git history.
+/// If not, we try to find the most recent upstream commit (which we assume are commits
+/// made by bors) that modified `target_paths`.
+/// We don't want to simply take the latest master commit to avoid changing the output of
+/// this function frequently after rebasing on the latest master branch even if `target_paths`
+/// were not modified upstream in the meantime. In that case we would be redownloading CI
+/// artifacts unnecessarily.
+///
+/// - In CI, we use a shallow clone of depth 2, i.e., we fetch only a single parent commit
+/// (which will be the most recent bors merge commit) and do not have access
+/// to the full git history. Luckily, we only need to distinguish between two situations:
+/// 1) The current PR made modifications to `target_paths`.
+/// In that case, a build is typically necessary.
+/// 2) The current PR did not make modifications to `target_paths`.
+/// In that case we simply take the latest upstream commit, because on CI there is no need to avoid
+/// redownloading.
+pub fn check_path_modifications(
+ git_dir: &Path,
config: &GitConfig<'_>,
target_paths: &[&str],
-) -> Result<String, String> {
- let mut git = Command::new("git");
-
- if let Some(git_dir) = git_dir {
- git.current_dir(git_dir);
+ ci_env: CiEnv,
+) -> Result<PathFreshness, String> {
+ assert!(!target_paths.is_empty());
+ for path in target_paths {
+ assert!(Path::new(path.trim_start_matches(":!")).is_relative());
}
- let channel = include_str!("../../ci/channel").trim();
+ let upstream_sha = if matches!(ci_env, CiEnv::GitHubActions) {
+ // Here the situation is different for PR CI and try/auto CI.
+ // For PR CI, we have the following history:
+ // <merge commit made by GitHub>
+ // 1-N PR commits
+ // upstream merge commit made by bors
+ //
+ // For try/auto CI, we have the following history:
+ // <**non-upstream** merge commit made by bors>
+ // 1-N PR commits
+ // upstream merge commit made by bors
+ //
+ // But on both cases, HEAD should be a merge commit.
+ // So if HEAD contains modifications of `target_paths`, our PR has modified
+ // them. If not, we can use the only available upstream commit for downloading
+ // artifacts.
- let merge_base = {
- if CiEnv::is_ci() &&
- // FIXME: When running on rust-lang managed CI and it's not a nightly build,
- // `git_upstream_merge_base` fails with an error message similar to this:
- // ```
- // called `Result::unwrap()` on an `Err` value: "command did not execute successfully:
- // cd \"/checkout\" && \"git\" \"merge-base\" \"origin/master\" \"HEAD\"\nexpected success, got: exit status: 1\n"
- // ```
- // Investigate and resolve this issue instead of skipping it like this.
- (channel == "nightly" || !CiEnv::is_rust_lang_managed_ci_job())
- {
- git_upstream_merge_base(config, git_dir).unwrap()
- } else {
- // For non-CI environments, ignore rust-lang/rust upstream as it usually gets
- // outdated very quickly.
- "HEAD".to_string()
+ // Do not include HEAD, as it is never an upstream commit
+ // If we do not find an upstream commit in CI, something is seriously wrong.
+ Some(
+ get_closest_upstream_commit(Some(git_dir), config, ci_env)?
+ .expect("No upstream commit was found on CI"),
+ )
+ } else {
+ // Outside CI, we want to find the most recent upstream commit that
+ // modified the set of paths, to have an upstream reference that does not change
+ // unnecessarily often.
+ // However, if such commit is not found, we can fall back to the latest upstream commit
+ let upstream_with_modifications =
+ get_latest_upstream_commit_that_modified_files(git_dir, config, target_paths)?;
+ match upstream_with_modifications {
+ Some(sha) => Some(sha),
+ None => get_closest_upstream_commit(Some(git_dir), config, ci_env)?,
}
};
+ let Some(upstream_sha) = upstream_sha else {
+ return Ok(PathFreshness::MissingUpstream);
+ };
+
+ // For local environments, we want to find out if something has changed
+ // from the latest upstream commit.
+ // However, that should be equivalent to checking if something has changed
+ // from the latest upstream commit *that modified `target_paths`*, and
+ // with this approach we do not need to invoke git an additional time.
+ if has_changed_since(git_dir, &upstream_sha, target_paths) {
+ Ok(PathFreshness::HasLocalModifications { upstream: upstream_sha })
+ } else {
+ Ok(PathFreshness::LastModifiedUpstream { upstream: upstream_sha })
+ }
+}
+
+/// Returns true if any of the passed `paths` have changed since the `base` commit.
+pub fn has_changed_since(git_dir: &Path, base: &str, paths: &[&str]) -> bool {
+ let mut git = Command::new("git");
+ git.current_dir(git_dir);
+
+ git.args(["diff-index", "--quiet", base, "--"]).args(paths);
+
+ // Exit code 0 => no changes
+ // Exit code 1 => some changes were detected
+ !git.status().expect("cannot run git diff-index").success()
+}
+
+/// Returns the latest upstream commit that modified `target_paths`, or `None` if no such commit
+/// was found.
+fn get_latest_upstream_commit_that_modified_files(
+ git_dir: &Path,
+ git_config: &GitConfig<'_>,
+ target_paths: &[&str],
+) -> Result<Option<String>, String> {
+ let mut git = Command::new("git");
+ git.current_dir(git_dir);
+
+ // In theory, we could just use
+ // `git rev-list --first-parent HEAD --author=<merge-bot> -- <paths>`
+ // to find the latest upstream commit that modified `<paths>`.
+ // However, this does not work if you are in a subtree sync branch that contains merge commits
+ // which have the subtree history as their first parent, and the rustc history as second parent:
+ // `--first-parent` will just walk up the subtree history and never see a single rustc commit.
+ // We thus have to take a two-pronged approach. First lookup the most recent upstream commit
+ // by *date* (this should work even in a subtree sync branch), and then start the lookup for
+ // modified paths starting from that commit.
+ //
+ // See https://github.com/rust-lang/rust/pull/138591#discussion_r2037081858 for more details.
+ let upstream = get_closest_upstream_commit(Some(git_dir), git_config, CiEnv::None)?
+ .unwrap_or_else(|| "HEAD".to_string());
+
git.args([
"rev-list",
- &format!("--author={}", config.git_merge_commit_email),
- "-n1",
"--first-parent",
- &merge_base,
+ "-n1",
+ &upstream,
+ "--author",
+ git_config.git_merge_commit_email,
]);
if !target_paths.is_empty() {
git.arg("--").args(target_paths);
}
+ let output = output_result(&mut git)?.trim().to_owned();
+ if output.is_empty() { Ok(None) } else { Ok(Some(output)) }
+}
+
+/// Returns the most recent (ordered chronologically) commit found in the local history that
+/// should exist upstream. We identify upstream commits by the e-mail of the commit
+/// author.
+///
+/// If we are in CI, we simply return our first parent.
+fn get_closest_upstream_commit(
+ git_dir: Option<&Path>,
+ config: &GitConfig<'_>,
+ env: CiEnv,
+) -> Result<Option<String>, String> {
+ let base = match env {
+ CiEnv::None => "HEAD",
+ CiEnv::GitHubActions => {
+ // On CI, we should always have a non-upstream merge commit at the tip,
+ // and our first parent should be the most recently merged upstream commit.
+ // We thus simply return our first parent.
+ return resolve_commit_sha(git_dir, "HEAD^1").map(Some);
+ }
+ };
+
+ let mut git = Command::new("git");
+
+ if let Some(git_dir) = git_dir {
+ git.current_dir(git_dir);
+ }
+
+ // We do not use `--first-parent`, because we can be in a situation (outside CI) where we have
+ // a subtree merge that actually has the main rustc history as its second parent.
+ // Using `--first-parent` would recurse into the history of the subtree, which could have some
+ // old bors commits that are not relevant to us.
+ // With `--author-date-order`, git recurses into all parent subtrees, and returns the most
+ // chronologically recent bors commit.
+ // Here we assume that none of our subtrees use bors anymore, and that all their old bors
+ // commits are way older than recent rustc bors commits!
+ git.args([
+ "rev-list",
+ "--author-date-order",
+ &format!("--author={}", config.git_merge_commit_email),
+ "-n1",
+ &base,
+ ]);
+
+ let output = output_result(&mut git)?.trim().to_owned();
+ if output.is_empty() { Ok(None) } else { Ok(Some(output)) }
+}
+
+/// Resolve the commit SHA of `commit_ref`.
+fn resolve_commit_sha(git_dir: Option<&Path>, commit_ref: &str) -> Result<String, String> {
+ let mut git = Command::new("git");
+
+ if let Some(git_dir) = git_dir {
+ git.current_dir(git_dir);
+ }
+
+ git.args(["rev-parse", commit_ref]);
Ok(output_result(&mut git)?.trim().to_owned())
}
/// Returns the files that have been modified in the current branch compared to the master branch.
+/// This includes committed changes, uncommitted changes, and changes that are not even staged.
+///
/// The `extensions` parameter can be used to filter the files by their extension.
/// Does not include removed files.
/// If `extensions` is empty, all files will be returned.
@@ -174,7 +264,9 @@ pub fn get_git_modified_files(
git_dir: Option<&Path>,
extensions: &[&str],
) -> Result<Vec<String>, String> {
- let merge_base = get_closest_merge_commit(git_dir, config, &[])?;
+ let Some(merge_base) = get_closest_upstream_commit(git_dir, config, CiEnv::None)? else {
+ return Err("No upstream commit was found".to_string());
+ };
let mut git = Command::new("git");
if let Some(git_dir) = git_dir {
@@ -202,13 +294,7 @@ pub fn get_git_modified_files(
}
/// Returns the files that haven't been added to git yet.
-pub fn get_git_untracked_files(
- config: &GitConfig<'_>,
- git_dir: Option<&Path>,
-) -> Result<Option<Vec<String>>, String> {
- let Ok(_updated_master) = updated_master_branch(config, git_dir) else {
- return Ok(None);
- };
+pub fn get_git_untracked_files(git_dir: Option<&Path>) -> Result<Option<Vec<String>>, String> {
let mut git = Command::new("git");
if let Some(git_dir) = git_dir {
git.current_dir(git_dir);
diff --git a/src/ci/citool/Cargo.lock b/src/ci/citool/Cargo.lock
index 800eaae..43321d1 100644
--- a/src/ci/citool/Cargo.lock
+++ b/src/ci/citool/Cargo.lock
@@ -65,12 +65,63 @@
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
[[package]]
+name = "askama"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d4744ed2eef2645831b441d8f5459689ade2ab27c854488fbab1fbe94fce1a7"
+dependencies = [
+ "askama_derive",
+ "itoa",
+ "percent-encoding",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "askama_derive"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d661e0f57be36a5c14c48f78d09011e67e0cb618f269cca9f2fd8d15b68c46ac"
+dependencies = [
+ "askama_parser",
+ "basic-toml",
+ "memchr",
+ "proc-macro2",
+ "quote",
+ "rustc-hash",
+ "serde",
+ "serde_derive",
+ "syn",
+]
+
+[[package]]
+name = "askama_parser"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f"
+dependencies = [
+ "memchr",
+ "serde",
+ "serde_derive",
+ "winnow",
+]
+
+[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
+name = "basic-toml"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a"
+dependencies = [
+ "serde",
+]
+
+[[package]]
name = "build_helper"
version = "0.1.0"
dependencies = [
@@ -104,6 +155,7 @@
version = "0.1.0"
dependencies = [
"anyhow",
+ "askama",
"build_helper",
"clap",
"csv",
@@ -563,9 +615,9 @@
[[package]]
name = "miniz_oxide"
-version = "0.8.5"
+version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5"
+checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [
"adler2",
]
@@ -647,6 +699,12 @@
]
[[package]]
+name = "rustc-hash"
+version = "2.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
+
+[[package]]
name = "rustls"
version = "0.23.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1027,6 +1085,15 @@
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
+name = "winnow"
+version = "0.7.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
name = "write16"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/ci/citool/Cargo.toml b/src/ci/citool/Cargo.toml
index f18436a..0e2aba3 100644
--- a/src/ci/citool/Cargo.toml
+++ b/src/ci/citool/Cargo.toml
@@ -5,6 +5,7 @@
[dependencies]
anyhow = "1"
+askama = "0.13"
clap = { version = "4.5", features = ["derive"] }
csv = "1"
diff = "0.1"
diff --git a/src/ci/citool/src/analysis.rs b/src/ci/citool/src/analysis.rs
index 208a494..62974be 100644
--- a/src/ci/citool/src/analysis.rs
+++ b/src/ci/citool/src/analysis.rs
@@ -8,9 +8,9 @@
};
use crate::github::JobInfoResolver;
-use crate::metrics;
use crate::metrics::{JobMetrics, JobName, get_test_suites};
use crate::utils::{output_details, pluralize};
+use crate::{metrics, utils};
/// Outputs durations of individual bootstrap steps from the gathered bootstrap invocations,
/// and also a table with summarized information about executed tests.
@@ -394,18 +394,17 @@ fn aggregate_tests(metrics: &JsonRoot) -> TestSuiteData {
// Poor man's detection of doctests based on the "(line XYZ)" suffix
let is_doctest = matches!(suite.metadata, TestSuiteMetadata::CargoPackage { .. })
&& test.name.contains("(line");
- let test_entry = Test { name: generate_test_name(&test.name), stage, is_doctest };
+ let test_entry = Test {
+ name: utils::normalize_path_delimiters(&test.name).to_string(),
+ stage,
+ is_doctest,
+ };
tests.insert(test_entry, test.outcome.clone());
}
}
TestSuiteData { tests }
}
-/// Normalizes Windows-style path delimiters to Unix-style paths.
-fn generate_test_name(name: &str) -> String {
- name.replace('\\', "/")
-}
-
/// Prints test changes in Markdown format to stdout.
fn report_test_diffs(
diff: AggregatedTestDiffs,
@@ -520,23 +519,27 @@ fn format_job_group(group: u64) -> String {
}
if doctest_count > 0 {
+ let prefix =
+ if doctest_count < original_diff_count { "Additionally, " } else { "" };
println!(
- "\nAdditionally, {doctest_count} doctest {} were found. These are ignored, as they are noisy.",
+ "\n{prefix}{doctest_count} doctest {} were found. These are ignored, as they are noisy.",
pluralize("diff", doctest_count)
);
}
// Now print the job group index
- println!("\n**Job group index**\n");
- for (group, jobs) in job_index.into_iter().enumerate() {
- println!(
- "- {}: {}",
- format_job_group(group as u64),
- jobs.iter()
- .map(|j| format_job_link(job_info_resolver, job_metrics, j))
- .collect::<Vec<_>>()
- .join(", ")
- );
+ if !job_index.is_empty() {
+ println!("\n**Job group index**\n");
+ for (group, jobs) in job_index.into_iter().enumerate() {
+ println!(
+ "- {}: {}",
+ format_job_group(group as u64),
+ jobs.iter()
+ .map(|j| format_job_link(job_info_resolver, job_metrics, j))
+ .collect::<Vec<_>>()
+ .join(", ")
+ );
+ }
}
},
);
diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs
index a1956da..87ce09c 100644
--- a/src/ci/citool/src/main.rs
+++ b/src/ci/citool/src/main.rs
@@ -4,6 +4,7 @@
mod github;
mod jobs;
mod metrics;
+mod test_dashboard;
mod utils;
use std::collections::{BTreeMap, HashMap};
@@ -22,7 +23,8 @@
use crate::github::JobInfoResolver;
use crate::jobs::RunType;
use crate::metrics::{JobMetrics, download_auto_job_metrics, download_job_metrics, load_metrics};
-use crate::utils::load_env_var;
+use crate::test_dashboard::generate_test_dashboard;
+use crate::utils::{load_env_var, output_details};
const CI_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/..");
const DOCKER_DIRECTORY: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../docker");
@@ -180,12 +182,26 @@ fn postprocess_metrics(
}
fn post_merge_report(db: JobDatabase, current: String, parent: String) -> anyhow::Result<()> {
- let metrics = download_auto_job_metrics(&db, &parent, ¤t)?;
+ let metrics = download_auto_job_metrics(&db, Some(&parent), ¤t)?;
println!("\nComparing {parent} (parent) -> {current} (this PR)\n");
let mut job_info_resolver = JobInfoResolver::new();
output_test_diffs(&metrics, &mut job_info_resolver);
+
+ output_details("Test dashboard", || {
+ println!(
+ r#"Run
+
+```bash
+cargo run --manifest-path src/ci/citool/Cargo.toml -- \
+ test-dashboard {current} --output-dir test-dashboard
+```
+And then open `test-dashboard/index.html` in your browser to see an overview of all executed tests.
+"#
+ );
+ });
+
output_largest_duration_changes(&metrics, &mut job_info_resolver);
Ok(())
@@ -234,6 +250,14 @@ enum Args {
/// Current commit that will be compared to `parent`.
current: String,
},
+ /// Generate a directory containing a HTML dashboard of test results from a CI run.
+ TestDashboard {
+ /// Commit SHA that was tested on CI to analyze.
+ current: String,
+ /// Output path for the HTML directory.
+ #[clap(long)]
+ output_dir: PathBuf,
+ },
}
#[derive(clap::ValueEnum, Clone)]
@@ -275,7 +299,11 @@ fn main() -> anyhow::Result<()> {
postprocess_metrics(metrics_path, parent, job_name)?;
}
Args::PostMergeReport { current, parent } => {
- post_merge_report(load_db(default_jobs_file)?, current, parent)?;
+ post_merge_report(load_db(&default_jobs_file)?, current, parent)?;
+ }
+ Args::TestDashboard { current, output_dir } => {
+ let db = load_db(&default_jobs_file)?;
+ generate_test_dashboard(db, ¤t, &output_dir)?;
}
}
diff --git a/src/ci/citool/src/metrics.rs b/src/ci/citool/src/metrics.rs
index a816fb3..3d8b1ad 100644
--- a/src/ci/citool/src/metrics.rs
+++ b/src/ci/citool/src/metrics.rs
@@ -46,24 +46,25 @@ pub struct JobMetrics {
/// `parent` and `current` should be commit SHAs.
pub fn download_auto_job_metrics(
job_db: &JobDatabase,
- parent: &str,
+ parent: Option<&str>,
current: &str,
) -> anyhow::Result<HashMap<JobName, JobMetrics>> {
let mut jobs = HashMap::default();
for job in &job_db.auto_jobs {
eprintln!("Downloading metrics of job {}", job.name);
- let metrics_parent = match download_job_metrics(&job.name, parent) {
- Ok(metrics) => Some(metrics),
- Err(error) => {
- eprintln!(
- r#"Did not find metrics for job `{}` at `{parent}`: {error:?}.
+ let metrics_parent =
+ parent.and_then(|parent| match download_job_metrics(&job.name, parent) {
+ Ok(metrics) => Some(metrics),
+ Err(error) => {
+ eprintln!(
+ r#"Did not find metrics for job `{}` at `{parent}`: {error:?}.
Maybe it was newly added?"#,
- job.name
- );
- None
- }
- };
+ job.name
+ );
+ None
+ }
+ });
let metrics_current = download_job_metrics(&job.name, current)?;
jobs.insert(
job.name.clone(),
diff --git a/src/ci/citool/src/test_dashboard.rs b/src/ci/citool/src/test_dashboard.rs
new file mode 100644
index 0000000..8fbd0d3
--- /dev/null
+++ b/src/ci/citool/src/test_dashboard.rs
@@ -0,0 +1,216 @@
+use std::collections::{BTreeMap, HashMap};
+use std::fs::File;
+use std::io::BufWriter;
+use std::path::{Path, PathBuf};
+
+use askama::Template;
+use build_helper::metrics::{TestOutcome, TestSuiteMetadata};
+
+use crate::jobs::JobDatabase;
+use crate::metrics::{JobMetrics, JobName, download_auto_job_metrics, get_test_suites};
+use crate::utils::normalize_path_delimiters;
+
+/// Generate a set of HTML files into a directory that contain a dashboard of test results.
+pub fn generate_test_dashboard(
+ db: JobDatabase,
+ current: &str,
+ output_dir: &Path,
+) -> anyhow::Result<()> {
+ let metrics = download_auto_job_metrics(&db, None, current)?;
+ let suites = gather_test_suites(&metrics);
+
+ std::fs::create_dir_all(output_dir)?;
+
+ let test_count = suites.test_count();
+ write_page(output_dir, "index.html", &TestSuitesPage { suites, test_count })?;
+
+ Ok(())
+}
+
+fn write_page<T: Template>(dir: &Path, name: &str, template: &T) -> anyhow::Result<()> {
+ let mut file = BufWriter::new(File::create(dir.join(name))?);
+ Template::write_into(template, &mut file)?;
+ Ok(())
+}
+
+fn gather_test_suites(job_metrics: &HashMap<JobName, JobMetrics>) -> TestSuites {
+ struct CoarseTestSuite<'a> {
+ tests: BTreeMap<String, Test<'a>>,
+ }
+
+ let mut suites: HashMap<String, CoarseTestSuite> = HashMap::new();
+
+ // First, gather tests from all jobs, stages and targets, and aggregate them per suite
+ // Only work with compiletest suites.
+ for (job, metrics) in job_metrics {
+ let test_suites = get_test_suites(&metrics.current);
+ for suite in test_suites {
+ let (suite_name, stage, target) = match &suite.metadata {
+ TestSuiteMetadata::CargoPackage { .. } => {
+ continue;
+ }
+ TestSuiteMetadata::Compiletest { suite, stage, target, .. } => {
+ (suite.clone(), *stage, target)
+ }
+ };
+ let suite_entry = suites
+ .entry(suite_name.clone())
+ .or_insert_with(|| CoarseTestSuite { tests: Default::default() });
+ let test_metadata = TestMetadata { job, stage, target };
+
+ for test in &suite.tests {
+ let test_name = normalize_test_name(&test.name, &suite_name);
+ let (test_name, variant_name) = match test_name.rsplit_once('#') {
+ Some((name, variant)) => (name.to_string(), variant.to_string()),
+ None => (test_name, "".to_string()),
+ };
+ let test_entry = suite_entry
+ .tests
+ .entry(test_name.clone())
+ .or_insert_with(|| Test { revisions: Default::default() });
+ let variant_entry = test_entry
+ .revisions
+ .entry(variant_name)
+ .or_insert_with(|| TestResults { passed: vec![], ignored: vec![] });
+
+ match test.outcome {
+ TestOutcome::Passed => {
+ variant_entry.passed.push(test_metadata);
+ }
+ TestOutcome::Ignored { ignore_reason: _ } => {
+ variant_entry.ignored.push(test_metadata);
+ }
+ TestOutcome::Failed => {
+ eprintln!("Warning: failed test {test_name}");
+ }
+ }
+ }
+ }
+ }
+
+ // Then, split the suites per directory
+ let mut suites = suites.into_iter().collect::<Vec<_>>();
+ suites.sort_by(|a, b| a.0.cmp(&b.0));
+
+ let suites = suites
+ .into_iter()
+ .map(|(suite_name, suite)| TestSuite { group: build_test_group(&suite_name, suite.tests) })
+ .collect();
+
+ TestSuites { suites }
+}
+
+/// Recursively expand a test group based on filesystem hierarchy.
+fn build_test_group<'a>(name: &str, tests: BTreeMap<String, Test<'a>>) -> TestGroup<'a> {
+ let mut root_tests = vec![];
+ let mut subdirs: BTreeMap<String, BTreeMap<String, Test<'a>>> = Default::default();
+
+ // Split tests into root tests and tests located in subdirectories
+ for (name, test) in tests {
+ let mut components = Path::new(&name).components().peekable();
+ let subdir = components.next().unwrap();
+
+ if components.peek().is_none() {
+ // This is a root test
+ root_tests.push((name, test));
+ } else {
+ // This is a test in a nested directory
+ let subdir_tests =
+ subdirs.entry(subdir.as_os_str().to_str().unwrap().to_string()).or_default();
+ let test_name =
+ components.into_iter().collect::<PathBuf>().to_str().unwrap().to_string();
+ subdir_tests.insert(test_name, test);
+ }
+ }
+ let dirs = subdirs
+ .into_iter()
+ .map(|(name, tests)| {
+ let group = build_test_group(&name, tests);
+ (name, group)
+ })
+ .collect();
+
+ TestGroup { name: name.to_string(), root_tests, groups: dirs }
+}
+
+/// Compiletest tests start with `[suite] tests/[suite]/a/b/c...`.
+/// Remove the `[suite] tests/[suite]/` prefix so that we can find the filesystem path.
+/// Also normalizes path delimiters.
+fn normalize_test_name(name: &str, suite_name: &str) -> String {
+ let name = normalize_path_delimiters(name);
+ let name = name.as_ref();
+ let name = name.strip_prefix(&format!("[{suite_name}]")).unwrap_or(name).trim();
+ let name = name.strip_prefix("tests/").unwrap_or(name);
+ let name = name.strip_prefix(suite_name).unwrap_or(name);
+ name.trim_start_matches("/").to_string()
+}
+
+struct TestSuites<'a> {
+ suites: Vec<TestSuite<'a>>,
+}
+
+impl<'a> TestSuites<'a> {
+ fn test_count(&self) -> u64 {
+ self.suites.iter().map(|suite| suite.group.test_count()).sum::<u64>()
+ }
+}
+
+struct TestSuite<'a> {
+ group: TestGroup<'a>,
+}
+
+struct TestResults<'a> {
+ passed: Vec<TestMetadata<'a>>,
+ ignored: Vec<TestMetadata<'a>>,
+}
+
+struct Test<'a> {
+ revisions: BTreeMap<String, TestResults<'a>>,
+}
+
+impl<'a> Test<'a> {
+ /// If this is a test without revisions, it will have a single entry in `revisions` with
+ /// an empty string as the revision name.
+ fn single_test(&self) -> Option<&TestResults<'a>> {
+ if self.revisions.len() == 1 {
+ self.revisions.iter().next().take_if(|e| e.0.is_empty()).map(|e| e.1)
+ } else {
+ None
+ }
+ }
+}
+
+#[derive(Clone, Copy)]
+#[allow(dead_code)]
+struct TestMetadata<'a> {
+ job: &'a str,
+ stage: u32,
+ target: &'a str,
+}
+
+// We have to use a template for the TestGroup instead of a macro, because
+// macros cannot be recursive in askama at the moment.
+#[derive(Template)]
+#[template(path = "test_group.askama")]
+/// Represents a group of tests
+struct TestGroup<'a> {
+ name: String,
+ /// Tests located directly in this directory
+ root_tests: Vec<(String, Test<'a>)>,
+ /// Nested directories with additional tests
+ groups: Vec<(String, TestGroup<'a>)>,
+}
+
+impl<'a> TestGroup<'a> {
+ fn test_count(&self) -> u64 {
+ let root = self.root_tests.len() as u64;
+ self.groups.iter().map(|(_, group)| group.test_count()).sum::<u64>() + root
+ }
+}
+
+#[derive(Template)]
+#[template(path = "test_suites.askama")]
+struct TestSuitesPage<'a> {
+ suites: TestSuites<'a>,
+ test_count: u64,
+}
diff --git a/src/ci/citool/src/utils.rs b/src/ci/citool/src/utils.rs
index a4c6ff8..0367d34 100644
--- a/src/ci/citool/src/utils.rs
+++ b/src/ci/citool/src/utils.rs
@@ -1,3 +1,4 @@
+use std::borrow::Cow;
use std::path::Path;
use anyhow::Context;
@@ -28,3 +29,8 @@ pub fn output_details<F>(summary: &str, func: F)
func();
println!("</details>\n");
}
+
+/// Normalizes Windows-style path delimiters to Unix-style paths.
+pub fn normalize_path_delimiters(name: &str) -> Cow<str> {
+ if name.contains("\\") { name.replace('\\', "/").into() } else { name.into() }
+}
diff --git a/src/ci/citool/templates/layout.askama b/src/ci/citool/templates/layout.askama
new file mode 100644
index 0000000..3b3b6f2
--- /dev/null
+++ b/src/ci/citool/templates/layout.askama
@@ -0,0 +1,22 @@
+<html>
+<head>
+ <meta charset="UTF-8">
+ <title>Rust CI Test Dashboard</title>
+ <style>
+ body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
+ line-height: 1.6;
+ max-width: 1500px;
+ margin: 0 auto;
+ padding: 20px;
+ background: #F5F5F5;
+ }
+ {% block styles %}{% endblock %}
+ </style>
+</head>
+
+<body>
+{% block content %}{% endblock %}
+{% block scripts %}{% endblock %}
+</body>
+</html>
diff --git a/src/ci/citool/templates/test_group.askama b/src/ci/citool/templates/test_group.askama
new file mode 100644
index 0000000..9573110
--- /dev/null
+++ b/src/ci/citool/templates/test_group.askama
@@ -0,0 +1,42 @@
+{% macro test_result(r) -%}
+passed: {{ r.passed.len() }}, ignored: {{ r.ignored.len() }}
+{%- endmacro %}
+
+<li>
+<details>
+<summary>{{ name }} ({{ test_count() }} test{{ test_count() | pluralize }}{% if !root_tests.is_empty() && root_tests.len() as u64 != test_count() -%}
+ , {{ root_tests.len() }} root test{{ root_tests.len() | pluralize }}
+{%- endif %}{% if !groups.is_empty() -%}
+ , {{ groups.len() }} subdir{{ groups.len() | pluralize }}
+{%- endif %})
+</summary>
+
+{% if !groups.is_empty() %}
+<ul>
+ {% for (dir_name, subgroup) in groups %}
+ {{ subgroup|safe }}
+ {% endfor %}
+</ul>
+{% endif %}
+
+{% if !root_tests.is_empty() %}
+<ul>
+ {% for (name, test) in root_tests %}
+ <li>
+ {% if let Some(result) = test.single_test() %}
+ <b>{{ name }}</b> ({% call test_result(result) %})
+ {% else %}
+ <b>{{ name }}</b> ({{ test.revisions.len() }} revision{{ test.revisions.len() | pluralize }})
+ <ul>
+ {% for (revision, result) in test.revisions %}
+ <li>#<i>{{ revision }}</i> ({% call test_result(result) %})</li>
+ {% endfor %}
+ </ul>
+ {% endif %}
+ </li>
+ {% endfor %}
+</ul>
+{% endif %}
+
+</details>
+</li>
diff --git a/src/ci/citool/templates/test_suites.askama b/src/ci/citool/templates/test_suites.askama
new file mode 100644
index 0000000..4997f6a
--- /dev/null
+++ b/src/ci/citool/templates/test_suites.askama
@@ -0,0 +1,108 @@
+{% extends "layout.askama" %}
+
+{% block content %}
+<h1>Rust CI test dashboard</h1>
+<div>
+Here's how to interpret the "passed" and "ignored" counts:
+the count includes all combinations of "stage" x "target" x "CI job where the test was executed or ignored".
+</div>
+<div class="test-suites">
+ <div class="summary">
+ <div>
+ <div class="test-count">Total tests: {{ test_count }}</div>
+ <div>
+ To find tests that haven't been executed anywhere, click on "Open all" and search for "passed: 0".
+ </div>
+ </div>
+ <div>
+ <button onclick="openAll()">Open all</button>
+ <button onclick="closeAll()">Close all</button>
+ </div>
+ </div>
+
+ <ul>
+ {% for suite in suites.suites %}
+ {{ suite.group|safe }}
+ {% endfor %}
+ </ul>
+</div>
+{% endblock %}
+
+{% block styles %}
+h1 {
+ text-align: center;
+ color: #333333;
+ margin-bottom: 30px;
+}
+
+.summary {
+ display: flex;
+ justify-content: space-between;
+}
+
+.test-count {
+ font-size: 1.2em;
+}
+
+.test-suites {
+ background: white;
+ border-radius: 8px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ padding: 20px;
+}
+
+ul {
+ padding-left: 0;
+}
+
+li {
+ list-style: none;
+ padding-left: 20px;
+}
+summary {
+ margin-bottom: 5px;
+ padding: 6px;
+ background-color: #F4F4F4;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ cursor: pointer;
+}
+summary:hover {
+ background-color: #CFCFCF;
+}
+
+/* Style the disclosure triangles */
+details > summary {
+ list-style: none;
+ position: relative;
+}
+
+details > summary::before {
+ content: "▶";
+ position: absolute;
+ left: -15px;
+ transform: rotate(0);
+ transition: transform 0.2s;
+}
+
+details[open] > summary::before {
+ transform: rotate(90deg);
+}
+{% endblock %}
+
+{% block scripts %}
+<script type="text/javascript">
+function openAll() {
+ const details = document.getElementsByTagName("details");
+ for (const elem of details) {
+ elem.open = true;
+ }
+}
+function closeAll() {
+ const details = document.getElementsByTagName("details");
+ for (const elem of details) {
+ elem.open = false;
+ }
+}
+</script>
+{% endblock %}
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile
index be235f6..c09be04 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile
@@ -59,11 +59,10 @@
ARG SCRIPT_ARG
-COPY scripts/add_dummy_commit.sh /tmp/
COPY scripts/x86_64-gnu-llvm.sh /tmp/
COPY scripts/x86_64-gnu-llvm2.sh /tmp/
COPY scripts/x86_64-gnu-llvm3.sh /tmp/
COPY scripts/stage_2_test_set1.sh /tmp/
COPY scripts/stage_2_test_set2.sh /tmp/
-ENV SCRIPT "/tmp/add_dummy_commit.sh && /tmp/${SCRIPT_ARG}"
+ENV SCRIPT "/tmp/${SCRIPT_ARG}"
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile
new file mode 100644
index 0000000..83a3bfb
--- /dev/null
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-20/Dockerfile
@@ -0,0 +1,68 @@
+FROM ubuntu:25.04
+
+ARG DEBIAN_FRONTEND=noninteractive
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ bzip2 \
+ g++ \
+ gcc-multilib \
+ make \
+ ninja-build \
+ file \
+ curl \
+ ca-certificates \
+ python3 \
+ git \
+ cmake \
+ sudo \
+ gdb \
+ llvm-20-tools \
+ llvm-20-dev \
+ libedit-dev \
+ libssl-dev \
+ pkg-config \
+ zlib1g-dev \
+ xz-utils \
+ nodejs \
+ mingw-w64 \
+ # libgccjit dependencies
+ flex \
+ libmpfr-dev \
+ libgmp-dev \
+ libmpc3 \
+ libmpc-dev \
+ && rm -rf /var/lib/apt/lists/*
+
+# Install powershell (universal package) so we can test x.ps1 on Linux
+# FIXME: need a "universal" version that supports libicu74, but for now it still works to ignore that dep.
+RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \
+ dpkg --ignore-depends=libicu72 -i powershell.deb && \
+ rm -f powershell.deb
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+# We are disabling CI LLVM since this builder is intentionally using a host
+# LLVM, rather than the typical src/llvm-project LLVM.
+ENV NO_DOWNLOAD_CI_LLVM 1
+ENV EXTERNAL_LLVM 1
+
+# Using llvm-link-shared due to libffi issues -- see #34486
+ENV RUST_CONFIGURE_ARGS \
+ --build=x86_64-unknown-linux-gnu \
+ --llvm-root=/usr/lib/llvm-20 \
+ --enable-llvm-link-shared \
+ --set rust.randomize-layout=true \
+ --set rust.thin-lto-import-instr-limit=10
+
+COPY scripts/shared.sh /scripts/
+
+ARG SCRIPT_ARG
+
+COPY scripts/x86_64-gnu-llvm.sh /tmp/
+COPY scripts/x86_64-gnu-llvm2.sh /tmp/
+COPY scripts/x86_64-gnu-llvm3.sh /tmp/
+COPY scripts/stage_2_test_set1.sh /tmp/
+COPY scripts/stage_2_test_set2.sh /tmp/
+
+ENV SCRIPT "/tmp/${SCRIPT_ARG}"
diff --git a/src/ci/docker/scripts/add_dummy_commit.sh b/src/ci/docker/scripts/add_dummy_commit.sh
deleted file mode 100755
index 029e4ae..0000000
--- a/src/ci/docker/scripts/add_dummy_commit.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash
-
-set -ex
-
-if [ "$READ_ONLY_SRC" = "0" ]; then
- # `core::builder::tests::ci_rustc_if_unchanged_logic` bootstrap test ensures that
- # "download-rustc=if-unchanged" logic don't use CI rustc while there are changes on
- # compiler and/or library. Here we are adding a dummy commit on compiler and running
- # that test to make sure we never download CI rustc with a change on the compiler tree.
- echo "" >> ../compiler/rustc/src/main.rs
- git config --global user.email "dummy@dummy.com"
- git config --global user.name "dummy"
- git add ../compiler/rustc/src/main.rs
- git commit -m "test commit for rust.download-rustc=if-unchanged logic"
- DISABLE_CI_RUSTC_IF_INCOMPATIBLE=0 ../x.py test bootstrap \
- -- core::builder::tests::ci_rustc_if_unchanged_logic
- # Revert the dummy commit
- git reset --hard HEAD~1
-fi
diff --git a/src/ci/docker/scripts/x86_64-gnu-llvm3.sh b/src/ci/docker/scripts/x86_64-gnu-llvm3.sh
index d1bf2da..17eb2ce 100755
--- a/src/ci/docker/scripts/x86_64-gnu-llvm3.sh
+++ b/src/ci/docker/scripts/x86_64-gnu-llvm3.sh
@@ -2,8 +2,6 @@
set -ex
-/tmp/add_dummy_commit.sh
-
##### Test stage 1 #####
../x.py --stage 1 test --skip src/tools/tidy
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index fbda749..950a757 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -23,8 +23,8 @@
os: ubuntu-24.04-16core-64gb
<<: *base-job
- - &job-macos-xl
- os: macos-13 # We use the standard runner for now
+ - &job-macos
+ os: macos-13
<<: *base-job
- &job-macos-m1
@@ -108,8 +108,6 @@
- name: x86_64-gnu-llvm-19
env:
ENABLE_GCC_CODEGEN: "1"
- # We are adding (temporarily) a dummy commit on the compiler
- READ_ONLY_SRC: "0"
DOCKER_SCRIPT: x86_64-gnu-llvm.sh
<<: *job-linux-16c
- name: x86_64-gnu-tools
@@ -304,6 +302,31 @@
- name: x86_64-gnu-distcheck
<<: *job-linux-8c
+ # The x86_64-gnu-llvm-20 job is split into multiple jobs to run tests in parallel.
+ # x86_64-gnu-llvm-20-1 skips tests that run in x86_64-gnu-llvm-20-{2,3}.
+ - name: x86_64-gnu-llvm-20-1
+ env:
+ RUST_BACKTRACE: 1
+ IMAGE: x86_64-gnu-llvm-20
+ DOCKER_SCRIPT: stage_2_test_set1.sh
+ <<: *job-linux-4c
+
+ # Skip tests that run in x86_64-gnu-llvm-20-{1,3}
+ - name: x86_64-gnu-llvm-20-2
+ env:
+ RUST_BACKTRACE: 1
+ IMAGE: x86_64-gnu-llvm-20
+ DOCKER_SCRIPT: x86_64-gnu-llvm2.sh
+ <<: *job-linux-4c
+
+ # Skip tests that run in x86_64-gnu-llvm-20-{1,2}
+ - name: x86_64-gnu-llvm-20-3
+ env:
+ RUST_BACKTRACE: 1
+ IMAGE: x86_64-gnu-llvm-20
+ DOCKER_SCRIPT: x86_64-gnu-llvm3.sh
+ <<: *job-linux-4c
+
# The x86_64-gnu-llvm-19 job is split into multiple jobs to run tests in parallel.
# x86_64-gnu-llvm-19-1 skips tests that run in x86_64-gnu-llvm-19-{2,3}.
- name: x86_64-gnu-llvm-19-1
@@ -355,7 +378,7 @@
NO_OVERFLOW_CHECKS: 1
DIST_REQUIRE_ALL_TOOLS: 1
CODEGEN_BACKENDS: llvm,cranelift
- <<: *job-macos-xl
+ <<: *job-macos
- name: dist-apple-various
env:
@@ -372,18 +395,18 @@
NO_LLVM_ASSERTIONS: 1
NO_DEBUG_ASSERTIONS: 1
NO_OVERFLOW_CHECKS: 1
- <<: *job-macos-xl
+ <<: *job-macos
- name: x86_64-apple-1
env:
<<: *env-x86_64-apple-tests
- <<: *job-macos-xl
+ <<: *job-macos
- name: x86_64-apple-2
env:
SCRIPT: ./x.py --stage 2 test tests/ui tests/rustdoc
<<: *env-x86_64-apple-tests
- <<: *job-macos-xl
+ <<: *job-macos
- name: dist-aarch64-apple
env:
diff --git a/src/ci/scripts/setup-upstream-remote.sh b/src/ci/scripts/setup-upstream-remote.sh
deleted file mode 100755
index 52b4c98..0000000
--- a/src/ci/scripts/setup-upstream-remote.sh
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-# In CI environments, bootstrap is forced to use the remote upstream based
-# on "git_repository" and "nightly_branch" values from src/stage0 file.
-# This script configures the remote as it may not exist by default.
-
-set -euo pipefail
-IFS=$'\n\t'
-
-ci_dir=$(cd $(dirname $0) && pwd)/..
-source "$ci_dir/shared.sh"
-
-git_repository=$(parse_stage0_file_by_key "git_repository")
-nightly_branch=$(parse_stage0_file_by_key "nightly_branch")
-
-# Configure "rust-lang/rust" upstream remote only when it's not origin.
-if [ -z "$(git config remote.origin.url | grep $git_repository)" ]; then
- echo "Configuring https://github.com/$git_repository remote as upstream."
- git remote add upstream "https://github.com/$git_repository"
- REMOTE_NAME="upstream"
-else
- REMOTE_NAME="origin"
-fi
-
-git fetch $REMOTE_NAME $nightly_branch
diff --git a/src/doc/book b/src/doc/book
index 45f0536..d339163 160000
--- a/src/doc/book
+++ b/src/doc/book
@@ -1 +1 @@
-Subproject commit 45f05367360f033f89235eacbbb54e8d73ce6b70
+Subproject commit d33916341d480caede1d0ae57cbeae23aab23e88
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
index 1e27e5e..467f456 160000
--- a/src/doc/edition-guide
+++ b/src/doc/edition-guide
@@ -1 +1 @@
-Subproject commit 1e27e5e6d5133ae4612f5cc195c15fc8d51b1c9c
+Subproject commit 467f45637b73ec6aa70fb36bc3054bb50b8967ea
diff --git a/src/doc/nomicon b/src/doc/nomicon
index b4448fa..c76a20f 160000
--- a/src/doc/nomicon
+++ b/src/doc/nomicon
@@ -1 +1 @@
-Subproject commit b4448fa406a6dccde62d1e2f34f70fc51814cdcc
+Subproject commit c76a20f0d987145dcedf05c5c073ce8d91f2e82a
diff --git a/src/doc/reference b/src/doc/reference
index 46435cd..3bf3402 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit 46435cd4eba11b66acaa42c01da5c80ad88aee4b
+Subproject commit 3bf3402aea982b876eb56c87da17b0685c6461d5
diff --git a/src/doc/rustc-dev-guide/README.md b/src/doc/rustc-dev-guide/README.md
index 6a25a91..9f468b9 100644
--- a/src/doc/rustc-dev-guide/README.md
+++ b/src/doc/rustc-dev-guide/README.md
@@ -43,13 +43,13 @@
To build a local static HTML site, install [`mdbook`](https://github.com/rust-lang/mdBook) with:
```
-> cargo install mdbook mdbook-linkcheck2 mdbook-toc mdbook-mermaid
+cargo install mdbook mdbook-linkcheck2 mdbook-toc mdbook-mermaid
```
and execute the following command in the root of the repository:
```
-> mdbook build --open
+mdbook build --open
```
The build files are found in the `book/html` directory.
@@ -61,8 +61,8 @@
locally, set the environment variable `ENABLE_LINKCHECK=1` like in the
following example.
-```console
-$ ENABLE_LINKCHECK=1 mdbook serve
+```
+ENABLE_LINKCHECK=1 mdbook serve
```
### Table of Contents
@@ -86,14 +86,14 @@
1) Checkout a new branch that will be used to create a PR into `rust-lang/rustc-dev-guide`
2) Run the pull command
```
- $ cargo run --manifest-path josh-sync/Cargo.toml rustc-pull
+ cargo run --manifest-path josh-sync/Cargo.toml rustc-pull
```
3) Push the branch to your fork and create a PR into `rustc-dev-guide`
### Push changes from this repository into `rust-lang/rust`
1) Run the push command to create a branch named `<branch-name>` in a `rustc` fork under the `<gh-username>` account
```
- $ cargo run --manifest-path josh-sync/Cargo.toml rustc-push <branch-name> <gh-username>
+ cargo run --manifest-path josh-sync/Cargo.toml rustc-push <branch-name> <gh-username>
```
2) Create a PR from `<branch-name>` into `rust-lang/rust`
@@ -106,5 +106,5 @@
To minimize the likelihood of this happening, you may wish to keep a separate *minimal* git config that *only* has `[user]` entries from global git config, then repoint system git to use the minimal git config instead. E.g.
```
-$ GIT_CONFIG_GLOBAL=/path/to/minimal/gitconfig GIT_CONFIG_SYSTEM='' cargo +stable run --manifest-path josh-sync/Cargo.toml -- rustc-pull
+GIT_CONFIG_GLOBAL=/path/to/minimal/gitconfig GIT_CONFIG_SYSTEM='' cargo +stable run --manifest-path josh-sync/Cargo.toml -- rustc-pull
```
diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version
index a6f2951..dc52e09 100644
--- a/src/doc/rustc-dev-guide/rust-version
+++ b/src/doc/rustc-dev-guide/rust-version
@@ -1 +1 @@
-25a615bf829b9f6d6f22da537e3851043f92e5f2
+b8005bff3248cfc6e327faf4fa631ac49bb49ba9
diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md
index 95a3cd7..68112d0 100644
--- a/src/doc/rustc-dev-guide/src/SUMMARY.md
+++ b/src/doc/rustc-dev-guide/src/SUMMARY.md
@@ -10,9 +10,9 @@
- [How to build and run the compiler](./building/how-to-build-and-run.md)
- [Quickstart](./building/quickstart.md)
- [Prerequisites](./building/prerequisites.md)
- - [Suggested Workflows](./building/suggested.md)
+ - [Suggested workflows](./building/suggested.md)
- [Distribution artifacts](./building/build-install-distribution-artifacts.md)
- - [Building Documentation](./building/compiler-documenting.md)
+ - [Building documentation](./building/compiler-documenting.md)
- [Rustdoc overview](./rustdoc.md)
- [Adding a new target](./building/new-target.md)
- [Optimized build](./building/optimized-build.md)
@@ -42,11 +42,11 @@
- [with the linux perf tool](./profiling/with_perf.md)
- [with Windows Performance Analyzer](./profiling/wpa_profiling.md)
- [with the Rust benchmark suite](./profiling/with_rustc_perf.md)
-- [crates.io Dependencies](./crates-io.md)
+- [crates.io dependencies](./crates-io.md)
# Contributing to Rust
-- [Contribution Procedures](./contributing.md)
+- [Contribution procedures](./contributing.md)
- [About the compiler team](./compiler-team.md)
- [Using Git](./git.md)
- [Mastering @rustbot](./rustbot.md)
@@ -56,7 +56,7 @@
- [Stabilizing Features](./stabilization_guide.md)
- [Feature Gates](./feature-gates.md)
- [Coding conventions](./conventions.md)
-- [Procedures for Breaking Changes](./bug-fix-procedure.md)
+- [Procedures for breaking changes](./bug-fix-procedure.md)
- [Using external repositories](./external-repos.md)
- [Fuzzing](./fuzzing.md)
- [Notification groups](notification-groups/about.md)
@@ -81,6 +81,7 @@
- [How Bootstrap does it](./building/bootstrapping/how-bootstrap-does-it.md)
- [Writing tools in Bootstrap](./building/bootstrapping/writing-tools-in-bootstrap.md)
- [Debugging bootstrap](./building/bootstrapping/debugging-bootstrap.md)
+- [cfg(bootstrap) in dependencies](./building/bootstrapping/bootstrap-in-dependencies.md)
# High-level Compiler Architecture
@@ -88,29 +89,35 @@
- [Overview of the compiler](./overview.md)
- [The compiler source code](./compiler-src.md)
- [Queries: demand-driven compilation](./query.md)
- - [The Query Evaluation Model in Detail](./queries/query-evaluation-model-in-detail.md)
+ - [The Query Evaluation Model in detail](./queries/query-evaluation-model-in-detail.md)
- [Incremental compilation](./queries/incremental-compilation.md)
- - [Incremental compilation In Detail](./queries/incremental-compilation-in-detail.md)
- - [Debugging and Testing](./incrcomp-debugging.md)
+ - [Incremental compilation in detail](./queries/incremental-compilation-in-detail.md)
+ - [Debugging and testing](./incrcomp-debugging.md)
- [Salsa](./queries/salsa.md)
-- [Memory Management in Rustc](./memory.md)
-- [Serialization in Rustc](./serialization.md)
-- [Parallel Compilation](./parallel-rustc.md)
+- [Memory management in rustc](./memory.md)
+- [Serialization in rustc](./serialization.md)
+- [Parallel compilation](./parallel-rustc.md)
- [Rustdoc internals](./rustdoc-internals.md)
- [Search](./rustdoc-internals/search.md)
- [The `rustdoc` test suite](./rustdoc-internals/rustdoc-test-suite.md)
+- [Autodiff internals](./autodiff/internals.md)
+ - [Installation](./autodiff/installation.md)
+ - [How to debug](./autodiff/debugging.md)
+ - [Autodiff flags](./autodiff/flags.md)
+ - [Current limitations](./autodiff/limitations.md)
+
# Source Code Representation
- [Prologue](./part-3-intro.md)
- [Syntax and the AST](./syntax-intro.md)
- - [Lexing and Parsing](./the-parser.md)
+ - [Lexing and parsing](./the-parser.md)
- [Macro expansion](./macro-expansion.md)
- [Name resolution](./name-resolution.md)
- [Attributes](./attributes.md)
- - [`#[test]` Implementation](./test-implementation.md)
- - [Panic Implementation](./panic-implementation.md)
- - [AST Validation](./ast-validation.md)
- - [Feature Gate Checking](./feature-gate-ck.md)
+ - [`#[test]` implementation](./test-implementation.md)
+ - [Panic implementation](./panic-implementation.md)
+ - [AST validation](./ast-validation.md)
+ - [Feature gate checking](./feature-gate-ck.md)
- [Lang Items](./lang-items.md)
- [The HIR (High-level IR)](./hir.md)
- [Lowering AST to HIR](./ast-lowering.md)
@@ -129,7 +136,7 @@
- [Example: Type checking](./rustc-driver/interacting-with-the-ast.md)
- [Example: Getting diagnostics](./rustc-driver/getting-diagnostics.md)
- [Remarks on perma-unstable features](./rustc-driver/remarks-on-perma-unstable-features.md)
-- [Errors and Lints](diagnostics.md)
+- [Errors and lints](diagnostics.md)
- [Diagnostic and subdiagnostic structs](./diagnostics/diagnostic-structs.md)
- [Translation](./diagnostics/translation.md)
- [`LintStore`](./diagnostics/lintstore.md)
@@ -175,14 +182,14 @@
- [Type checking](./type-checking.md)
- [Method Lookup](./method-lookup.md)
- [Variance](./variance.md)
- - [Coherence Checking](./coherence.md)
- - [Opaque Types](./opaque-types-type-alias-impl-trait.md)
+ - [Coherence checking](./coherence.md)
+ - [Opaque types](./opaque-types-type-alias-impl-trait.md)
- [Inference details](./opaque-types-impl-trait-inference.md)
- [Return Position Impl Trait In Trait](./return-position-impl-trait-in-trait.md)
- [Region inference restrictions][opaque-infer]
- [Const condition checking](./effects.md)
- [Pattern and Exhaustiveness Checking](./pat-exhaustive-checking.md)
-- [Unsafety Checking](./unsafety-checking.md)
+- [Unsafety checking](./unsafety-checking.md)
- [MIR dataflow](./mir/dataflow.md)
- [Drop elaboration](./mir/drop-elaboration.md)
- [The borrow checker](./borrow_check.md)
diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md
index 781a5c5..057e4a4 100644
--- a/src/doc/rustc-dev-guide/src/about-this-guide.md
+++ b/src/doc/rustc-dev-guide/src/about-this-guide.md
@@ -3,33 +3,41 @@
This guide is meant to help document how rustc – the Rust compiler – works,
as well as to help new contributors get involved in rustc development.
-There are seven parts to this guide:
+There are several parts to this guide:
-1. [Building `rustc`][p1]:
+1. [Building and debugging `rustc`][p1]:
Contains information that should be useful no matter how you are contributing,
about building, debugging, profiling, etc.
-2. [Contributing to `rustc`][p2]:
+1. [Contributing to Rust][p2]:
Contains information that should be useful no matter how you are contributing,
about procedures for contribution, using git and Github, stabilizing features, etc.
-3. [High-Level Compiler Architecture][p3]:
+1. [Bootstrapping][p3]:
+ Describes how the Rust compiler builds itself using previous versions, including
+ an introduction to the bootstrap process and debugging methods.
+1. [High-level Compiler Architecture][p4]:
Discusses the high-level architecture of the compiler and stages of the compile process.
-4. [Source Code Representation][p4]:
+1. [Source Code Representation][p5]:
Describes the process of taking raw source code from the user
and transforming it into various forms that the compiler can work with easily.
-5. [Analysis][p5]:
- discusses the analyses that the compiler uses to check various properties of the code
+1. [Supporting Infrastructure][p6]:
+ Covers command-line argument conventions, compiler entry points like rustc_driver and
+ rustc_interface, and the design and implementation of errors and lints.
+1. [Analysis][p7]:
+ Discusses the analyses that the compiler uses to check various properties of the code
and inform later stages of the compile process (e.g., type checking).
-6. [From MIR to Binaries][p6]: How linked executable machine code is generated.
-7. [Appendices][p7] at the end with useful reference information.
+1. [MIR to Binaries][p8]: How linked executable machine code is generated.
+1. [Appendices][p9] at the end with useful reference information.
There are a few of these with different information, including a glossary.
[p1]: ./building/how-to-build-and-run.html
[p2]: ./contributing.md
-[p3]: ./part-2-intro.md
-[p4]: ./part-3-intro.md
-[p5]: ./part-4-intro.md
-[p6]: ./part-5-intro.md
-[p7]: ./appendix/background.md
+[p3]: ./building/bootstrapping/intro.md
+[p4]: ./part-2-intro.md
+[p5]: ./part-3-intro.md
+[p6]: ./cli.md
+[p7]: ./part-4-intro.md
+[p8]: ./part-5-intro.md
+[p9]: ./appendix/background.md
### Constant change
diff --git a/src/doc/rustc-dev-guide/src/appendix/glossary.md b/src/doc/rustc-dev-guide/src/appendix/glossary.md
index a7c3236..1837b59 100644
--- a/src/doc/rustc-dev-guide/src/appendix/glossary.md
+++ b/src/doc/rustc-dev-guide/src/appendix/glossary.md
@@ -31,7 +31,6 @@
<span id="generics">generics</span> | The list of generic parameters defined on an item. There are three kinds of generic parameters: Type, lifetime and const parameters.
<span id="hir">HIR</span> | The _high-level [IR](#ir)_, created by lowering and desugaring the AST. ([see more](../hir.md))
<span id="hir-id">`HirId`</span> | Identifies a particular node in the HIR by combining a def-id with an "intra-definition offset". See [the HIR chapter for more](../hir.md#identifiers-in-the-hir).
-<span id="hir-map">HIR map</span> | The HIR map, accessible via `tcx.hir()`, allows you to quickly navigate the HIR and convert between various forms of identifiers.
<span id="ice">ICE</span> | Short for _internal compiler error_, this is when the compiler crashes.
<span id="ich">ICH</span> | Short for _incremental compilation hash_, these are used as fingerprints for things such as HIR and crate metadata, to check if changes have been made. This is useful in incremental compilation to see if part of a crate has changed and should be recompiled.
<span id="infcx">`infcx`</span> | The type inference context (`InferCtxt`). (see `rustc_middle::infer`)
diff --git a/src/doc/rustc-dev-guide/src/ast-validation.md b/src/doc/rustc-dev-guide/src/ast-validation.md
index fa0f1d9..8f10bbe 100644
--- a/src/doc/rustc-dev-guide/src/ast-validation.md
+++ b/src/doc/rustc-dev-guide/src/ast-validation.md
@@ -1,4 +1,4 @@
-# AST Validation
+# AST validation
_AST validation_ is a separate AST pass that visits each
item in the tree and performs simple checks. This pass
diff --git a/src/doc/rustc-dev-guide/src/autodiff/debugging.md b/src/doc/rustc-dev-guide/src/autodiff/debugging.md
new file mode 100644
index 0000000..bd46a66
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/autodiff/debugging.md
@@ -0,0 +1,113 @@
+# Reporting backend crashes
+
+If after a compilation failure you are greeted by a large amount of llvm-ir code, then our enzyme backend likely failed to compile your code. These cases are harder to debug, so your help is highly appreciated. Please also keep in mind that release builds are usually much more likely to work at the moment.
+
+The final goal here is to reproduce your bug in the enzyme [compiler explorer](https://enzyme.mit.edu/explorer/), in order to create a bug report in the [Enzyme](https://github.com/enzymead/enzyme/issues) repository.
+
+We have an `autodiff` flag which you can pass to `rustflags` to help with this. it will print the whole llvm-ir module, along with some `__enzyme_fwddiff` or `__enzyme_autodiff` calls. A potential workflow on linux could look like:
+
+## Controlling llvm-ir generation
+
+Before generating the llvm-ir, keep in mind two techniques that can help ensure the relevant rust code is visible for debugging:
+
+- **`std::hint::black_box`**: wrap rust variables or expressions in `std::hint::black_box()` to prevent rust and llvm from optimizing them away. This is useful when you need to inspect or manually manipulate specific values in the llvm-ir.
+- **`extern "rust"` or `extern "c"`**: if you want to see how a specific function declaration is lowered to llvm-ir, you can declare it as `extern "rust"` or `extern "c"`. You can also look for existing `__enzyme_autodiff` or similar declarations within the generated module for examples.
+
+## 1) Generate an llvm-ir reproducer
+
+```sh
+rustflags="-z autodiff=enable,printmodbefore" cargo +enzyme build --release &> out.ll
+```
+
+This also captures a few warnings and info messages above and below your module. open out.ll and remove every line above `; moduleid = <somehash>`. Now look at the end of the file and remove everything that's not part of llvm-ir, i.e. remove errors and warnings. The last line of your llvm-ir should now start with `!<somenumber> = `, i.e. `!40831 = !{i32 0, i32 1037508, i32 1037538, i32 1037559}` or `!43760 = !dilocation(line: 297, column: 5, scope: !43746)`.
+
+The actual numbers will depend on your code.
+
+## 2) Check your llvm-ir reproducer
+
+To confirm that your previous step worked, we will use llvm's `opt` tool. find your path to the opt binary, with a path similar to `<some_dir>/rust/build/<x86/arm/...-target-tripple>/build/bin/opt`. also find `llvmenzyme-19.<so/dll/dylib>` path, similar to `/rust/build/target-tripple/enzyme/build/enzyme/llvmenzyme-19`. Please keep in mind that llvm frequently updates it's llvm backend, so the version number might be higher (20, 21, ...). Once you have both, run the following command:
+
+```sh
+<path/to/opt> out.ll -load-pass-plugin=/path/to/llvmenzyme-19.so -passes="enzyme" -s
+```
+
+If the previous step succeeded, you are going to see the same error that you saw when compiling your rust code with cargo.
+
+If you fail to get the same error, please open an issue in the rust repository. If you succeed, congrats! the file is still huge, so let's automatically minimize it.
+
+## 3) Minimize your llvm-ir reproducer
+
+First find your `llvm-extract` binary, it's in the same folder as your opt binary. then run:
+
+```sh
+<path/to/llvm-extract> -s --func=<name> --recursive --rfunc="enzyme_autodiff*" --rfunc="enzyme_fwddiff*" --rfunc=<fnc_called_by_enzyme> out.ll -o mwe.ll
+```
+
+This command creates `mwe.ll`, a minimal working example.
+
+Please adjust the name passed with the last `--func` flag. You can either apply the `#[no_mangle]` attribute to the function you differentiate, then you can replace it with the rust name. otherwise you will need to look up the mangled function name. To do that, open `out.ll` and search for `__enzyme_fwddiff` or `__enzyme_autodiff`. the first string in that function call is the name of your function. example:
+
+```llvm-ir
+define double @enzyme_opt_helper_0(ptr %0, i64 %1, double %2) {
+ %4 = call double (...) @__enzyme_fwddiff(ptr @_zn2ad3_f217h3b3b1800bd39fde3e, metadata !"enzyme_const", ptr %0, metadata !"enzyme_const", i64 %1, metadata !"enzyme_dup", double %2, double %2)
+ ret double %4
+}
+```
+
+Here, `_zn2ad3_f217h3b3b1800bd39fde3e` is the correct name. make sure to not copy the leading `@`. redo step 2) by running the `opt` command again, but this time passing `mwe.ll` as the input file instead of `out.ll`. Check if this minimized example still reproduces the crash.
+
+## 4) (Optional) Minimize your llvm-ir reproducer further.
+
+After the previous step you should have an `mwe.ll` file with ~5k loc. let's try to get it down to 50. find your `llvm-reduce` binary next to `opt` and `llvm-extract`. Copy the first line of your error message, an example could be:
+
+```sh
+opt: /home/manuel/prog/rust/src/llvm-project/llvm/lib/ir/instructions.cpp:686: void llvm::callinst::init(llvm::functiontype*, llvm::value*, llvm::arrayref<llvm::value*>, llvm::arrayref<llvm::operandbundledeft<llvm::value*> >, const llvm::twine&): assertion `(args.size() == fty->getnumparams() || (fty->isvararg() && args.size() > fty->getnumparams())) && "calling a function with bad signature!"' failed.
+```
+
+If you just get a `segfault` there is no sensible error message and not much to do automatically, so continue to 5).
+otherwise, create a `script.sh` file containing
+
+```sh
+#!/bin/bash
+<path/to/your/opt> $1 -load-pass-plugin=/path/to/llvmenzyme-19.so -passes="enzyme" \
+ |& grep "/some/path.cpp:686: void llvm::callinst::init"
+```
+
+Experiment a bit with which error message you pass to grep. it should be long enough to make sure that the error is unique. However, for longer errors including `(` or `)` you will need to escape them correctly which can become annoying. Run
+
+```sh
+<path/to/llvm-reduce> --test=script.sh mwe.ll
+```
+
+If you see `input isn't interesting! verify interesting-ness test`, you got the error message in script.sh wrong, you need to make sure that grep matches your actual error. If all works out, you will see a lot of iterations, ending with a new `reduced.ll` file. Verify with `opt` that you still get the same error.
+
+### Advanced debugging: manual llvm-ir investigation
+
+Once you have a minimized reproducer (`mwe.ll` or `reduced.ll`), you can delve deeper:
+
+- **manual editing:** try manually rewriting the llvm-ir. for certain issues, like those involving indirect calls, you might investigate enzyme-specific intrinsics like `__enzyme_virtualreverse`. Understanding how to use these might require consulting enzyme's documentation or source code.
+- **enzyme test cases:** look for relevant test cases within the [enzyme repository](https://github.com/enzymead/enzyme/tree/main/enzyme/test) that might demonstrate the correct usage of features or intrinsics related to your problem.
+
+## 5) Report your bug.
+
+Afterwards, you should be able to copy and paste your `mwe.ll` (or `reduced.ll`) example into our [compiler explorer](https://enzyme.mit.edu/explorer/).
+
+- Select `llvm ir` as language and `opt 20` as compiler.
+- Replace the field to the right of your compiler with `-passes="enzyme"`, if it is not already set.
+- Hopefully, you will see once again your now familiar error.
+- Please use the share button to copy links to them.
+- Please create an issue on [https://github.com/enzymead/enzyme/issues](https://github.com/enzymead/enzyme/issues) and share `mwe.ll` and (if you have it) `reduced.ll`, as well as links to the compiler explorer. Please feel free to also add your rust code or a link to it.
+
+#### Documenting findings
+
+some enzyme errors, like `"attempting to call an indirect active function whose runtime value is inactive"`, have historically caused confusion. If you investigate such an issue, even if you don't find a complete solution, please consider documenting your findings. If the insights are general to enzyme and not specific to its rust usage, contributing them to the main [enzyme documentation](https://github.com/enzymead/www) is often the best first step. You can also mention your findings in the relevant enzyme github issue or propose updates to these docs if appropriate. This helps prevent others from starting from scratch.
+
+With a clear reproducer and documentation, hopefully an enzyme developer will be able to fix your bug. Once that happens, the enzyme submodule inside the rust compiler will be updated, which should allow you to differentiate your rust code. Thanks for helping us to improve rust-ad.
+
+# Minimize rust code
+
+Beyond having a minimal llvm-ir reproducer, it is also helpful to have a minimal rust reproducer without dependencies. This allows us to add it as a test case to ci once we fix it, which avoids regressions for the future.
+
+There are a few solutions to help you with minimizing the rust reproducer. This is probably the most simple automated approach: [cargo-minimize](https://github.com/nilstrieb/cargo-minimize).
+
+Otherwise we have various alternatives, including [`treereduce`](https://github.com/langston-barrett/treereduce), [`halfempty`](https://github.com/googleprojectzero/halfempty), or [`picireny`](https://github.com/renatahodovan/picireny), potentially also [`creduce`](https://github.com/csmith-project/creduce).
diff --git a/src/doc/rustc-dev-guide/src/autodiff/flags.md b/src/doc/rustc-dev-guide/src/autodiff/flags.md
new file mode 100644
index 0000000..946ae1d
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/autodiff/flags.md
@@ -0,0 +1,42 @@
+# Supported `RUSTFLAGS`
+
+To support you while debugging or profiling, we have added support for an experimental `-Z autodiff` rustc flag (which can be passed to cargo via `RUSTFLAGS`), which allow changing the behaviour of Enzyme, without recompiling rustc. We currently support the following values for `autodiff`.
+
+### Debug Flags
+
+```text
+PrintTA // Print TypeAnalysis information
+PrintAA // Print ActivityAnalysis information
+Print // Print differentiated functions while they are being generated and optimized
+PrintPerf // Print AD related Performance warnings
+PrintModBefore // Print the whole LLVM-IR module directly before running AD
+PrintModAfter // Print the whole LLVM-IR module after running AD, before optimizations
+PrintModFinal // Print the whole LLVM-IR module after running optimizations and AD
+LooseTypes // Risk incorrect derivatives instead of aborting when missing Type Info
+```
+
+<div class="warning">
+`LooseTypes` is often helpful to get rid of Enzyme errors stating `Can not deduce type of <X>` and to be able to run some code. But please keep in mind that this flag absolutely has the chance to cause incorrect gradients. Even worse, the gradients might be correct for certain input values, but not for others. So please create issues about such bugs and only use this flag temporarily while you wait for your bug to be fixed.
+</div>
+
+### Benchmark flags
+
+For performance experiments and benchmarking we also support
+
+```text
+NoPostopt // We won't optimize the LLVM-IR Module after AD
+RuntimeActivity // Enables the runtime activity feature from Enzyme
+Inline // Instructs Enzyme to maximize inlining as far as possible, beyond LLVM's default
+```
+
+You can combine multiple `autodiff` values using a comma as separator:
+
+```bash
+RUSTFLAGS="-Z autodiff=Enable,LooseTypes,PrintPerf" cargo +enzyme build
+```
+
+Using `-Zautodiff=Enable` will allow using autodiff and update your normal rustc compilation pipeline:
+
+1. Run your selected compilation pipeline. If you selected a release build, we will disable vectorization and loop unrolling.
+2. Differentiate your functions.
+3. Run your selected compilation pipeline again on the whole module. This time we do not disable vectorization or loop unrolling.
diff --git a/src/doc/rustc-dev-guide/src/autodiff/installation.md b/src/doc/rustc-dev-guide/src/autodiff/installation.md
new file mode 100644
index 0000000..dbea9db
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/autodiff/installation.md
@@ -0,0 +1,86 @@
+# Installation
+
+In the near future, `std::autodiff` should become available in nightly builds for users. As a contribute however, you will still need to build rustc from source. Please be aware that the msvc target is not supported at the moment, all other tier 1 targets should work. Please open an issue if you encounter any problems on a supported tier 1 target, or if you succesfully build this project on a tier2/tier3 target.
+
+## Build instructions
+
+First you need to clone and configure the Rust repository:
+```bash
+git clone --depth=1 git@github.com:rust-lang/rust.git
+cd rust
+./configure --enable-llvm-link-shared --enable-llvm-plugins --enable-llvm-enzyme --release-channel=nightly --enable-llvm-assertions --enable-clang --enable-lld --enable-option-checking --enable-ninja --disable-docs
+```
+
+Afterwards you can build rustc using:
+```bash
+./x.py build --stage 1 library
+```
+
+Afterwards rustc toolchain link will allow you to use it through cargo:
+```
+rustup toolchain link enzyme build/host/stage1
+rustup toolchain install nightly # enables -Z unstable-options
+```
+
+You can then run our test cases:
+
+```bash
+./x.py test --stage 1 library tests/ui/autodiff
+./x.py test --stage 1 library tests/codegen/autodiff
+./x.py test --stage 1 library tests/pretty/autodiff*
+```
+
+Autodiff is still experimental, so if you want to use it in your own projects, you will need to add `lto="fat"` to your Cargo.toml
+and use `RUSTFLAGS="-Zautodiff=Enable" cargo +enzyme` instead of `cargo` or `cargo +nightly`.
+
+## Compiler Explorer and dist builds
+
+Our compiler explorer instance can be updated to a newer rustc in a similar way. First, prepare a docker instance.
+```bash
+docker run -it ubuntu:22.04
+export CC=clang CXX=clang++
+apt update
+apt install wget vim python3 git curl libssl-dev pkg-config lld ninja-build cmake clang build-essential
+```
+Then build rustc in a slightly altered way:
+```bash
+git clone --depth=1 https://github.com/EnzymeAD/rust.git
+cd rust
+./configure --enable-llvm-link-shared --enable-llvm-plugins --enable-llvm-enzyme --release-channel=nightly --enable-llvm-assertions --enable-clang --enable-lld --enable-option-checking --enable-ninja --disable-docs
+./x dist
+```
+We then copy the tarball to our host. The dockerid is the newest entry under `docker ps -a`.
+```bash
+docker cp <dockerid>:/rust/build/dist/rust-nightly-x86_64-unknown-linux-gnu.tar.gz rust-nightly-x86_64-unknown-linux-gnu.tar.gz
+```
+Afterwards we can create a new (pre-release) tag on the EnzymeAD/rust repository and make a PR against the EnzymeAD/enzyme-explorer repository to update the tag.
+Remember to ping `tgymnich` on the PR to run his update script.
+
+
+## Build instruction for Enzyme itself
+
+Following the Rust build instruction above will build LLVMEnzyme, LLDEnzyme, and ClangEnzyme along with the Rust compiler.
+We recommend that approach, if you just want to use any of them and have no experience with cmake.
+However, if you prefer to just build Enzyme without Rust, then these instructions might help.
+
+```bash
+git clone --depth=1 git@github.com:llvm/llvm-project.git
+cd llvm-project
+mkdir build
+cd build
+cmake -G Ninja ../llvm -DLLVM_TARGETS_TO_BUILD="host" -DLLVM_ENABLE_ASSERTIONS=ON -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_ENABLE_RUNTIMES="openmp" -DLLVM_ENABLE_PLUGINS=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=.
+ninja
+ninja install
+```
+This gives you a working LLVM build, now we can continue with building Enzyme.
+Leave the `llvm-project` folder, and execute the following commands:
+```bash
+git clone git@github.com:EnzymeAD/Enzyme.git
+cd Enzyme/enzyme
+mkdir build
+cd build
+cmake .. -G Ninja -DLLVM_DIR=<YourLocalPath>/llvm-project/build/lib/cmake/llvm/ -DLLVM_EXTERNAL_LIT=<YourLocalPath>/llvm-project/llvm/utils/lit/lit.py -DCMAKE_BUILD_TYPE=Release -DCMAKE_EXPORT_COMPILE_COMMANDS=YES -DBUILD_SHARED_LIBS=ON
+ninja
+```
+This will build Enzyme, and you can find it in `Enzyme/enzyme/build/lib/<LLD/Clang/LLVM>Enzyme.so`. (Endings might differ based on your OS).
+
diff --git a/src/doc/rustc-dev-guide/src/autodiff/internals.md b/src/doc/rustc-dev-guide/src/autodiff/internals.md
new file mode 100644
index 0000000..0093ef0
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/autodiff/internals.md
@@ -0,0 +1,27 @@
+The `std::autodiff` module in Rust allows differentiable programming:
+
+```rust
+#![feature(autodiff)]
+use std::autodiff::autodiff;
+
+// f(x) = x * x, f'(x) = 2.0 * x
+// bar therefore returns (x * x, 2.0 * x)
+#[autodiff(bar, Reverse, Active, Active)]
+fn foo(x: f32) -> f32 { x * x }
+
+fn main() {
+ assert_eq!(bar(3.0, 1.0), (9.0, 6.0));
+ assert_eq!(bar(4.0, 1.0), (16.0, 8.0));
+}
+```
+
+The detailed documentation for the `std::autodiff` module is available at [std::autodiff](https://doc.rust-lang.org/std/autodiff/index.html).
+
+Differentiable programing is used in various fields like numerical computing, [solid mechanics][ratel], [computational chemistry][molpipx], [fluid dynamics][waterlily] or for Neural Network training via Backpropagation, [ODE solver][diffsol], [differentiable rendering][libigl], [quantum computing][catalyst], and climate simulations.
+
+[ratel]: https://gitlab.com/micromorph/ratel
+[molpipx]: https://arxiv.org/abs/2411.17011v
+[waterlily]: https://github.com/WaterLily-jl/WaterLily.jl
+[diffsol]: https://github.com/martinjrobins/diffsol
+[libigl]: https://github.com/alecjacobson/libigl-enzyme-example?tab=readme-ov-file#run
+[catalyst]: https://github.com/PennyLaneAI/catalyst
diff --git a/src/doc/rustc-dev-guide/src/autodiff/limitations.md b/src/doc/rustc-dev-guide/src/autodiff/limitations.md
new file mode 100644
index 0000000..90afbd5
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/autodiff/limitations.md
@@ -0,0 +1,27 @@
+# Current limitations
+
+## Safety and Soundness
+
+Enzyme currently assumes that the user passes shadow arguments (`dx`, `dy`, ...) of appropriate size. Under Reverse Mode, we additionally assume that shadow arguments are mutable. In Reverse Mode we adjust the outermost pointer or reference to be mutable. Therefore `&f32` will receive the shadow type `&mut f32`. However, we do not check length for other types than slices (e.g. enums, Vec). We also do not enforce mutability of inner references, but will warn if we recognize them. We do intend to add additional checks over time.
+
+## ABI adjustments
+
+In some cases, a function parameter might get lowered in a way that we currently don't handle correctly, leading to a compile time type mismatch in the `rustc_codegen_llvm` backend. Here are some [examples](https://github.com/EnzymeAD/rust/issues/105).
+
+## Compile Times
+
+Enzyme will often achieve excellent runtime performance, but might increase your compile time by a large factor. For Rust, we already have made significant improvements and have a list of further improvements planed - please reach out if you have time to help here.
+
+### Type Analysis
+
+Most of the times, Type Analysis (TA) is the reason of large (>5x) compile time increases when using Enzyme. This poster explains why we need to run Type Analysis in the bottom left part: [Poster Link](https://c.wsmoses.com/posters/Enzyme-llvmdev.pdf).
+
+We intend to increase the number of locations where we pass down Type information based on Rust types, which in turn will reduce the number of locations where Enzyme has to run Type Analysis, which will help compile times.
+
+### Duplicated Optimizations
+
+The key reason for Enzyme offering often excellent performance is that Enzyme differentiates already optimized LLVM-IR. However, we also (have to) run LLVM's optimization pipeline after differentiating, to make sure that the code which Enzyme generates is optimized properly. As a result you should have excellent runtime performance (please fill an issue if not), but at a compile time cost for running optimizations twice.
+
+### Fat-LTO
+
+The usage of `#[autodiff(...)]` currently requires compiling your project with Fat-LTO. We technically only need LTO if the function being differentiated calls functions in other compilation units. Therefore, other solutions are possible, but this is the most simple one to get started.
diff --git a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md
index e6a16df6..8e6725c 100644
--- a/src/doc/rustc-dev-guide/src/bug-fix-procedure.md
+++ b/src/doc/rustc-dev-guide/src/bug-fix-procedure.md
@@ -1,4 +1,4 @@
-# Procedures for Breaking Changes
+# Procedures for breaking changes
<!-- toc -->
diff --git a/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md b/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md
new file mode 100644
index 0000000..68c5c23
--- /dev/null
+++ b/src/doc/rustc-dev-guide/src/building/bootstrapping/bootstrap-in-dependencies.md
@@ -0,0 +1,53 @@
+# `cfg(bootstrap)` in compiler dependencies
+
+The rust compiler uses some external crates that can run into cyclic dependencies with the compiler itself: the compiler needs an updated crate to build, but the crate needs an updated compiler. This page describes how `#[cfg(bootstrap)]` can be used to break this cycle.
+
+## Enabling `#[cfg(bootstrap)]`
+
+Usually the use of `#[cfg(bootstrap)]` in an external crate causes a warning:
+
+```
+warning: unexpected `cfg` condition name: `bootstrap`
+ --> src/main.rs:1:7
+ |
+1 | #[cfg(bootstrap)]
+ | ^^^^^^^^^
+ |
+ = help: expected names are: `docsrs`, `feature`, and `test` and 31 more
+ = help: consider using a Cargo feature instead
+ = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+ [lints.rust]
+ unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)'] }
+ = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(bootstrap)");` to the top of the `build.rs`
+ = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
+ = note: `#[warn(unexpected_cfgs)]` on by default
+```
+
+This warning can be silenced by adding these lines to the project's `Cargo.toml`:
+
+```toml
+[lints.rust]
+unexpected_cfgs = { level = "warn", check-cfg = ['cfg(bootstrap)'] }
+```
+
+Now `#[cfg(bootstrap)]` can be used in the crate just like it can be in the compiler: when the bootstrap compiler is used, code annotated with `#[cfg(bootstrap)]` is compiled, otherwise code annotated with `#[cfg(not(bootstrap))]` is compiled.
+
+## The update dance
+
+As a concrete example we'll use a change where the `#[naked]` attribute was made into an unsafe attribute, which caused a cyclic dependency with the `compiler-builtins` crate.
+
+### Step 1: accept the new behavior in the compiler ([#139797](https://github.com/rust-lang/rust/pull/139797))
+
+In this example it is possible to accept both the old and new behavior at the same time by disabling an error.
+
+### Step 2: update the crate ([#821](https://github.com/rust-lang/compiler-builtins/pull/821))
+
+Now in the crate, use `#[cfg(bootstrap)]` to use the old behavior, or `#[cfg(not(bootstrap))]` to use the new behavior.
+
+### Step 3: update the crate version used by the compiler ([#139934](https://github.com/rust-lang/rust/pull/139934))
+
+For `compiler-builtins` this meant a version bump, in other cases it may be a git submodule update.
+
+### Step 4: remove the old behavior from the compiler ([#139753](https://github.com/rust-lang/rust/pull/139753))
+
+The updated crate can now be used. In this example that meant that the old behavior could be removed.
diff --git a/src/doc/rustc-dev-guide/src/building/optimized-build.md b/src/doc/rustc-dev-guide/src/building/optimized-build.md
index 0849464..62dfaca 100644
--- a/src/doc/rustc-dev-guide/src/building/optimized-build.md
+++ b/src/doc/rustc-dev-guide/src/building/optimized-build.md
@@ -109,11 +109,16 @@
Here is an example of how can `opt-dist` be used locally (outside of CI):
-1. Build the tool with the following command:
+1. Enable metrics in your `bootstrap.toml` file, because `opt-dist` expects it to be enabled:
+ ```toml
+ [build]
+ metrics = true
+ ```
+2. Build the tool with the following command:
```bash
./x build tools/opt-dist
```
-2. Run the tool with the `local` mode and provide necessary parameters:
+3. Run the tool with the `local` mode and provide necessary parameters:
```bash
./build/host/stage0-tools-bin/opt-dist local \
--target-triple <target> \ # select target, e.g. "x86_64-unknown-linux-gnu"
diff --git a/src/doc/rustc-dev-guide/src/building/suggested.md b/src/doc/rustc-dev-guide/src/building/suggested.md
index 43ff2ba..f8a28b7f 100644
--- a/src/doc/rustc-dev-guide/src/building/suggested.md
+++ b/src/doc/rustc-dev-guide/src/building/suggested.md
@@ -1,4 +1,4 @@
-# Suggested Workflows
+# Suggested workflows
The full bootstrapping process takes quite a while. Here are some suggestions to
make your life easier.
@@ -20,6 +20,43 @@
You can also install the hook as a step of running `./x setup`!
+## Config extensions
+
+When working on different tasks, you might need to switch between different bootstrap configurations.
+Sometimes you may want to keep an old configuration for future use. But saving raw config values in
+random files and manually copying and pasting them can quickly become messy, especially if you have a
+long history of different configurations.
+
+To simplify managing multiple configurations, you can create config extensions.
+
+For example, you can create a simple config file named `cross.toml`:
+
+```toml
+[build]
+build = "x86_64-unknown-linux-gnu"
+host = ["i686-unknown-linux-gnu"]
+target = ["i686-unknown-linux-gnu"]
+
+
+[llvm]
+download-ci-llvm = false
+
+[target.x86_64-unknown-linux-gnu]
+llvm-config = "/path/to/llvm-19/bin/llvm-config"
+```
+
+Then, include this in your `bootstrap.toml`:
+
+```toml
+include = ["cross.toml"]
+```
+
+You can also include extensions within extensions recursively.
+
+**Note:** In the `include` field, the overriding logic follows a right-to-left order. For example,
+in `include = ["a.toml", "b.toml"]`, extension `b.toml` overrides `a.toml`. Also, parent extensions
+always overrides the inner ones.
+
## Configuring `rust-analyzer` for `rustc`
### Project-local rust-analyzer setup
diff --git a/src/doc/rustc-dev-guide/src/coherence.md b/src/doc/rustc-dev-guide/src/coherence.md
index b3af101..73f9213 100644
--- a/src/doc/rustc-dev-guide/src/coherence.md
+++ b/src/doc/rustc-dev-guide/src/coherence.md
@@ -1,4 +1,3 @@
-
# Coherence
> NOTE: this is based on [notes by @lcnr](https://github.com/rust-lang/rust/pull/121848)
diff --git a/src/doc/rustc-dev-guide/src/compiler-debugging.md b/src/doc/rustc-dev-guide/src/compiler-debugging.md
index 47f3976..102e202 100644
--- a/src/doc/rustc-dev-guide/src/compiler-debugging.md
+++ b/src/doc/rustc-dev-guide/src/compiler-debugging.md
@@ -301,7 +301,8 @@
Some compiler options for debugging specific features yield graphviz graphs -
e.g. the `#[rustc_mir(borrowck_graphviz_postflow="suffix.dot")]` attribute
-dumps various borrow-checker dataflow graphs.
+on a function dumps various borrow-checker dataflow graphs in conjunction with
+`-Zdump-mir-dataflow`.
These all produce `.dot` files. To view these files, install graphviz (e.g.
`apt-get install graphviz`) and then run the following commands:
diff --git a/src/doc/rustc-dev-guide/src/contributing.md b/src/doc/rustc-dev-guide/src/contributing.md
index 09a7f91..0575de6 100644
--- a/src/doc/rustc-dev-guide/src/contributing.md
+++ b/src/doc/rustc-dev-guide/src/contributing.md
@@ -1,4 +1,4 @@
-# Contribution Procedures
+# Contribution procedures
<!-- toc -->
@@ -150,6 +150,20 @@
[t-compiler]: https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler
[triagebot]: https://github.com/rust-lang/rust/blob/master/triagebot.toml
+### Keeping your branch up-to-date
+
+The CI in rust-lang/rust applies your patches directly against the current master,
+not against the commit your branch is based on. This can lead to unexpected failures
+if your branch is outdated, even when there are no explicit merge conflicts.
+
+Before submitting or updating a PR, make sure to update your branch
+as mentioned [here](git.md#keeping-things-up-to-date) if it's significantly
+behind the master branch (e.g., more than 100 commits behind).
+This fetches the latest master branch and rebases your changes on top of it,
+ensuring your PR is tested against the latest code.
+
+After rebasing, it's recommended to [run the relevant tests locally](tests/intro.md) to catch any issues before CI runs.
+
### r?
All pull requests are reviewed by another person. We have a bot,
@@ -346,7 +360,7 @@
[`src/doc`]: https://github.com/rust-lang/rust/tree/master/src/doc
[std-root]: https://github.com/rust-lang/rust/blob/master/library/std/src/lib.rs#L1
-To find documentation-related issues, sort by the [A-docs label].
+To find documentation-related issues, use the [A-docs label].
You can find documentation style guidelines in [RFC 1574].
@@ -373,7 +387,7 @@
There is no strict limit on line lengths; let the sentence or part of the sentence flow to its proper end on the same line.
- When contributing text to the guide, please contextualize the information with some time period
- and/or a reason so that the reader knows how much to trust or mistrust the information.
+ and/or a reason so that the reader knows how much to trust the information.
Aim to provide a reasonable amount of context, possibly including but not limited to:
- A reason for why the data may be out of date other than "change",
@@ -387,28 +401,28 @@
- jan 2021
- january 2021
- There is a CI action (in `~/.github/workflows/date-check.yml`)
- that generates a monthly showing those that are over 6 months old
+ There is a CI action (in `.github/workflows/date-check.yml`)
+ that generates a monthly report showing those that are over 6 months old
([example](https://github.com/rust-lang/rustc-dev-guide/issues/2052)).
For the action to pick the date,
add a special annotation before specifying the date:
```md
- <!-- date-check --> Sep 2024
+ <!-- date-check --> Apr 2025
```
Example:
```md
- As of <!-- date-check --> Sep 2024, the foo did the bar.
+ As of <!-- date-check --> Apr 2025, the foo did the bar.
```
For cases where the date should not be part of the visible rendered output,
use the following instead:
```md
- <!-- date-check: Sep 2024 -->
+ <!-- date-check: Apr 2025 -->
```
- A link to a relevant WG, tracking issue, `rustc` rustdoc page, or similar, that may provide
diff --git a/src/doc/rustc-dev-guide/src/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md
index 0e624a4..4356cf2 100644
--- a/src/doc/rustc-dev-guide/src/conventions.md
+++ b/src/doc/rustc-dev-guide/src/conventions.md
@@ -1,3 +1,5 @@
+# Coding conventions
+
This file offers some tips on the coding conventions for rustc. This
chapter covers [formatting](#formatting), [coding for correctness](#cc),
[using crates from crates.io](#cio), and some tips on
@@ -5,7 +7,7 @@
<a id="formatting"></a>
-# Formatting and the tidy script
+## Formatting and the tidy script
rustc is moving towards the [Rust standard coding style][fmt].
@@ -20,44 +22,42 @@
`./x test` and can be run in isolation with `./x fmt --check`.
If you want to use format-on-save in your editor, the pinned version of
-`rustfmt` is built under `build/<target>/stage0/bin/rustfmt`. You'll have to
-pass the <!-- date-check: nov 2022 --> `--edition=2021` argument yourself when calling
-`rustfmt` directly.
+`rustfmt` is built under `build/<target>/stage0/bin/rustfmt`.
[fmt]: https://github.com/rust-dev-tools/fmt-rfcs
-
[`rustfmt`]:https://github.com/rust-lang/rustfmt
-## Formatting C++ code
+### Formatting C++ code
The compiler contains some C++ code for interfacing with parts of LLVM that
don't have a stable C API.
When modifying that code, use this command to format it:
-```sh
-./x test tidy --extra-checks=cpp:fmt --bless
+```console
+./x test tidy --extra-checks cpp:fmt --bless
```
This uses a pinned version of `clang-format`, to avoid relying on the local
environment.
-## Formatting and linting Python code
+### Formatting and linting Python code
The Rust repository contains quite a lot of Python code. We try to keep
-it both linted and formatted by the [ruff][ruff] tool.
+it both linted and formatted by the [ruff] tool.
When modifying Python code, use this command to format it:
-```sh
-./x test tidy --extra-checks=py:fmt --bless
+
+```console
+./x test tidy --extra-checks py:fmt --bless
```
-and the following command to run lints:
-```sh
-./x test tidy --extra-checks=py:lint
+And, the following command to run lints:
+
+```console
+./x test tidy --extra-checks py:lint
```
-This uses a pinned version of `ruff`, to avoid relying on the local
-environment.
+These use a pinned version of `ruff`, to avoid relying on the local environment.
[ruff]: https://github.com/astral-sh/ruff
@@ -65,7 +65,7 @@
<!-- REUSE-IgnoreStart -->
<!-- Prevent REUSE from interpreting the heading as a copyright notice -->
-## Copyright notice
+### Copyright notice
<!-- REUSE-IgnoreEnd -->
In the past, files began with a copyright and license notice. Please **omit**
@@ -75,41 +75,42 @@
All of the copyright notices should be gone by now, but if you come across one
in the rust-lang/rust repo, feel free to open a PR to remove it.
-## Line length
+### Line length
Lines should be at most 100 characters. It's even better if you can
keep things to 80.
-**Ignoring the line length limit.** Sometimes – in particular for
-tests – it can be necessary to exempt yourself from this limit. In
-that case, you can add a comment towards the top of the file like so:
+Sometimes, and particularly for tests, it can be necessary to exempt yourself from this limit.
+In that case, you can add a comment towards the top of the file like so:
```rust
// ignore-tidy-linelength
```
-## Tabs vs spaces
+### Tabs vs spaces
-Prefer 4-space indent.
+Prefer 4-space indents.
<a id="cc"></a>
-# Coding for correctness
+## Coding for correctness
Beyond formatting, there are a few other tips that are worth
following.
-## Prefer exhaustive matches
+### Prefer exhaustive matches
Using `_` in a match is convenient, but it means that when new
variants are added to the enum, they may not get handled correctly.
Ask yourself: if a new variant were added to this enum, what's the
chance that it would want to use the `_` code, versus having some
other treatment? Unless the answer is "low", then prefer an
-exhaustive match. (The same advice applies to `if let` and `while
-let`, which are effectively tests for a single variant.)
+exhaustive match.
-## Use "TODO" comments for things you don't want to forget
+The same advice applies to `if let` and `while let`,
+which are effectively tests for a single variant.
+
+### Use "TODO" comments for things you don't want to forget
As a useful tool to yourself, you can insert a `// TODO` comment
for something that you want to get back to before you land your PR:
@@ -136,13 +137,13 @@
<a id="cio"></a>
-# Using crates from crates.io
+## Using crates from crates.io
See the [crates.io dependencies][crates] section.
<a id="er"></a>
-# How to structure your PR
+## How to structure your PR
How you prepare the commits in your PR can make a big difference for the
reviewer. Here are some tips.
@@ -172,7 +173,7 @@
expect to be able to bisect at a PR level. However, if you *can* make
individual commits build, that is always helpful.
-# Naming conventions
+## Naming conventions
Apart from normal Rust style/naming conventions, there are also some specific
to the compiler.
diff --git a/src/doc/rustc-dev-guide/src/crates-io.md b/src/doc/rustc-dev-guide/src/crates-io.md
index 403d61a..4431585 100644
--- a/src/doc/rustc-dev-guide/src/crates-io.md
+++ b/src/doc/rustc-dev-guide/src/crates-io.md
@@ -1,4 +1,4 @@
-# crates.io Dependencies
+# crates.io dependencies
The Rust compiler supports building with some dependencies from `crates.io`.
Examples are `log` and `env_logger`.
diff --git a/src/doc/rustc-dev-guide/src/diagnostics.md b/src/doc/rustc-dev-guide/src/diagnostics.md
index 6f72ea9..2f8f4b0 100644
--- a/src/doc/rustc-dev-guide/src/diagnostics.md
+++ b/src/doc/rustc-dev-guide/src/diagnostics.md
@@ -1,4 +1,4 @@
-# Errors and Lints
+# Errors and lints
<!-- toc -->
@@ -772,7 +772,7 @@
[`store.register_removed`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LintStore.html#method.register_removed
[`rustc_lint::register_builtins`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/fn.register_builtins.html
-### Lint Groups
+### Lint groups
Lints can be turned on in groups. These groups are declared in the
[`register_builtins`][rbuiltins] function in [`rustc_lint::lib`][builtin]. The
diff --git a/src/doc/rustc-dev-guide/src/feature-gates.md b/src/doc/rustc-dev-guide/src/feature-gates.md
index 24ce9bb..9806f73 100644
--- a/src/doc/rustc-dev-guide/src/feature-gates.md
+++ b/src/doc/rustc-dev-guide/src/feature-gates.md
@@ -1,4 +1,4 @@
-# Feature Gates
+# Feature gates
This chapter is intended to provide basic help for adding, removing, and
modifying feature gates.
diff --git a/src/doc/rustc-dev-guide/src/hir.md b/src/doc/rustc-dev-guide/src/hir.md
index 75f5a9e..0c1c994 100644
--- a/src/doc/rustc-dev-guide/src/hir.md
+++ b/src/doc/rustc-dev-guide/src/hir.md
@@ -100,7 +100,7 @@
a wrapper around a [`HirId`]. For more info about HIR bodies, please refer to the
[HIR chapter][hir-bodies].
-These identifiers can be converted into one another through the [HIR map][map].
+These identifiers can be converted into one another through the `TyCtxt`.
[`DefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefId.html
[`LocalDefId`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.LocalDefId.html
@@ -110,30 +110,24 @@
[`CrateNum`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.CrateNum.html
[`DefIndex`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/def_id/struct.DefIndex.html
[`Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Body.html
-[hir-map]: ./hir.md#the-hir-map
[hir-bodies]: ./hir.md#hir-bodies
-[map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html
-## The HIR Map
+## HIR Operations
Most of the time when you are working with the HIR, you will do so via
-the **HIR Map**, accessible in the tcx via [`tcx.hir()`] (and defined in
-the [`hir::map`] module). The [HIR map] contains a [number of methods] to
-convert between IDs of various kinds and to lookup data associated
-with a HIR node.
+`TyCtxt`. It contains a number of methods, defined in the `hir::map` module and
+mostly prefixed with `hir_`, to convert between IDs of various kinds and to
+lookup data associated with a HIR node.
-[`tcx.hir()`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir
-[`hir::map`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/index.html
-[HIR map]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html
-[number of methods]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#methods
+[`TyCtxt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html
For example, if you have a [`LocalDefId`], and you would like to convert it
-to a [`HirId`], you can use [`tcx.hir().local_def_id_to_hir_id(def_id)`][local_def_id_to_hir_id].
+to a [`HirId`], you can use [`tcx.local_def_id_to_hir_id(def_id)`][local_def_id_to_hir_id].
You need a `LocalDefId`, rather than a `DefId`, since only local items have HIR nodes.
-[local_def_id_to_hir_id]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.local_def_id_to_hir_id
+[local_def_id_to_hir_id]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.local_def_id_to_hir_id
-Similarly, you can use [`tcx.hir().find(n)`][find] to lookup the node for a
+Similarly, you can use [`tcx.hir_node(n)`][hir_node] to lookup the node for a
[`HirId`]. This returns a `Option<Node<'hir>>`, where [`Node`] is an enum
defined in the map. By matching on this, you can find out what sort of
node the `HirId` referred to and also get a pointer to the data
@@ -142,15 +136,16 @@
[`tcx.hir_expect_expr(n)`][expect_expr], which will extract and return the
[`&hir::Expr`][Expr], panicking if `n` is not in fact an expression.
-[find]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.find
+[hir_node]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_node
[`Node`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.Node.html
[expect_expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.expect_expr
[Expr]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Expr.html
-Finally, you can use the HIR map to find the parents of nodes, via
-calls like [`tcx.hir().get_parent(n)`][get_parent].
+Finally, you can find the parents of nodes, via
+calls like [`tcx.parent_hir_node(n)`][parent_hir_node].
-[get_parent]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.get_parent
+[parent_hir_node]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.parent_hir_node
+
## HIR Bodies
@@ -158,10 +153,10 @@
of a function/closure or the definition of a constant. Bodies are
associated with an **owner**, which is typically some kind of item
(e.g. an `fn()` or `const`), but could also be a closure expression
-(e.g. `|x, y| x + y`). You can use the HIR map to find the body
-associated with a given def-id ([`maybe_body_owned_by`]) or to find
-the owner of a body ([`body_owner_def_id`]).
+(e.g. `|x, y| x + y`). You can use the `TyCtxt` to find the body
+associated with a given def-id ([`hir_maybe_body_owned_by`]) or to find
+the owner of a body ([`hir_body_owner_def_id`]).
[`rustc_hir::Body`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/struct.Body.html
-[`maybe_body_owned_by`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.maybe_body_owned_by
-[`body_owner_def_id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/hir/map/struct.Map.html#method.body_owner_def_id
+[`hir_maybe_body_owned_by`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_maybe_body_owned_by
+[`hir_body_owner_def_id`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TyCtxt.html#method.hir_body_owner_def_id
diff --git a/src/doc/rustc-dev-guide/src/incrcomp-debugging.md b/src/doc/rustc-dev-guide/src/incrcomp-debugging.md
index 7045d3f..a548215 100644
--- a/src/doc/rustc-dev-guide/src/incrcomp-debugging.md
+++ b/src/doc/rustc-dev-guide/src/incrcomp-debugging.md
@@ -1,4 +1,4 @@
-# Debugging and Testing Dependencies
+# Debugging and testing dependencies
## Testing the dependency graph
diff --git a/src/doc/rustc-dev-guide/src/memory.md b/src/doc/rustc-dev-guide/src/memory.md
index 1e030ff..eeb4a81 100644
--- a/src/doc/rustc-dev-guide/src/memory.md
+++ b/src/doc/rustc-dev-guide/src/memory.md
@@ -1,4 +1,4 @@
-# Memory Management in Rustc
+# Memory management in rustc
Generally rustc tries to be pretty careful how it manages memory.
The compiler allocates _a lot_ of data structures throughout compilation,
diff --git a/src/doc/rustc-dev-guide/src/panic-implementation.md b/src/doc/rustc-dev-guide/src/panic-implementation.md
index f358742..468190f 100644
--- a/src/doc/rustc-dev-guide/src/panic-implementation.md
+++ b/src/doc/rustc-dev-guide/src/panic-implementation.md
@@ -1,4 +1,4 @@
-# Panicking in rust
+# Panicking in Rust
<!-- toc -->
diff --git a/src/doc/rustc-dev-guide/src/parallel-rustc.md b/src/doc/rustc-dev-guide/src/parallel-rustc.md
index 690fb19..ce69b66 100644
--- a/src/doc/rustc-dev-guide/src/parallel-rustc.md
+++ b/src/doc/rustc-dev-guide/src/parallel-rustc.md
@@ -1,4 +1,4 @@
-# Parallel Compilation
+# Parallel compilation
<div class="warning">
As of <!-- date-check --> November 2024,
@@ -28,7 +28,7 @@
[codegen]: backend/codegen.md
-## Code Generation
+## Code generation
During monomorphization the compiler splits up all the code to
be generated into smaller chunks called _codegen units_. These are then generated by
@@ -38,7 +38,7 @@
[`rustc_codegen_ssa::base`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_codegen_ssa/base/index.html
-## Data Structures
+## Data structures
The underlying thread-safe data-structures used in the parallel compiler
can be found in the [`rustc_data_structures::sync`] module. These data structures
@@ -83,7 +83,7 @@
[`rustc_data_structures::sync::worker_local`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/sync/worker_local/index.html
[`WorkerLocal`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_data_structures/sync/worker_local/struct.WorkerLocal.html
-## Parallel Iterator
+## Parallel iterator
The parallel iterators provided by the [`rayon`] crate are easy ways to
implement parallelism. In the current implementation of the parallel compiler
@@ -124,7 +124,7 @@
There are still many loops that have the potential to use parallel iterators.
-## Query System
+## Query system
The query model has some properties that make it actually feasible to evaluate
multiple queries in parallel without too much effort:
diff --git a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md
index 4133b19..03c822d 100644
--- a/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md
+++ b/src/doc/rustc-dev-guide/src/queries/incremental-compilation-in-detail.md
@@ -1,4 +1,4 @@
-# Incremental Compilation In Detail
+# Incremental Compilation in detail
<!-- toc -->
diff --git a/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md b/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md
index f7f204b..444e20b 100644
--- a/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md
+++ b/src/doc/rustc-dev-guide/src/queries/query-evaluation-model-in-detail.md
@@ -1,4 +1,4 @@
-# The Query Evaluation Model in Detail
+# The Query Evaluation Model in detail
<!-- toc -->
diff --git a/src/doc/rustc-dev-guide/src/serialization.md b/src/doc/rustc-dev-guide/src/serialization.md
index 0ff0499..670a37f 100644
--- a/src/doc/rustc-dev-guide/src/serialization.md
+++ b/src/doc/rustc-dev-guide/src/serialization.md
@@ -1,4 +1,4 @@
-# Serialization in Rustc
+# Serialization in rustc
rustc has to [serialize] and deserialize various data during compilation.
Specifically:
diff --git a/src/doc/rustc-dev-guide/src/test-implementation.md b/src/doc/rustc-dev-guide/src/test-implementation.md
index bee783c..e906dd2 100644
--- a/src/doc/rustc-dev-guide/src/test-implementation.md
+++ b/src/doc/rustc-dev-guide/src/test-implementation.md
@@ -83,7 +83,7 @@
technique prevents name collision during code generation and is the foundation
of Rust's [`macro`] hygiene.
-## Step 2: Harness Generation
+## Step 2: Harness generation
Now that our tests are accessible from the root of our crate, we need to do
something with them using [`rustc_ast`][ast] generates a module like so:
@@ -106,7 +106,7 @@
runtime for testing. [`test`][test]'s interface is unstable, so the only stable way
to interact with it is through the `#[test]` macro.
-## Step 3: Test Object Generation
+## Step 3: Test object generation
If you've written tests in Rust before, you may be familiar with some of the
optional attributes available on test functions. For example, a test can be
diff --git a/src/doc/rustc-dev-guide/src/tests/best-practices.md b/src/doc/rustc-dev-guide/src/tests/best-practices.md
index 6905ee1..2bdc7f3 100644
--- a/src/doc/rustc-dev-guide/src/tests/best-practices.md
+++ b/src/doc/rustc-dev-guide/src/tests/best-practices.md
@@ -175,6 +175,8 @@
- For `ignore-*`/`needs-*`/`only-*` directives, unless extremely obvious,
provide a brief remark on why the directive is needed. E.g. `"//@ ignore-wasi
(wasi codegens the main symbol differently)"`.
+- When using `//@ ignore-auxiliary`, specify the corresponding main test files,
+ e.g. ``//@ ignore-auxiliary (used by `./foo.rs`)``.
## FileCheck best practices
diff --git a/src/doc/rustc-dev-guide/src/tests/directives.md b/src/doc/rustc-dev-guide/src/tests/directives.md
index 4ec2909..dae659e 100644
--- a/src/doc/rustc-dev-guide/src/tests/directives.md
+++ b/src/doc/rustc-dev-guide/src/tests/directives.md
@@ -101,6 +101,7 @@
| `normalize-stdout` | Normalize actual stdout with a rule `"<raw>" -> "<normalized>"` before comparing against snapshot | `ui`, `incremental` | `"<RAW>" -> "<NORMALIZED>"`, `<RAW>`/`<NORMALIZED>` is regex capture and replace syntax |
| `dont-check-compiler-stderr` | Don't check actual compiler stderr vs stderr snapshot | `ui` | N/A |
| `dont-check-compiler-stdout` | Don't check actual compiler stdout vs stdout snapshot | `ui` | N/A |
+| `dont-require-annotations` | Don't require line annotations for the given diagnostic kind (`//~ KIND`) to be exhaustive | `ui`, `incremental` | `ERROR`, `WARN`, `NOTE`, `HELP`, `SUGGESTION` |
| `run-rustfix` | Apply all suggestions via `rustfix`, snapshot fixed output, and check fixed output builds | `ui` | N/A |
| `rustfix-only-machine-applicable` | `run-rustfix` but only machine-applicable suggestions | `ui` | N/A |
| `exec-env` | Env var to set when executing a test | `ui`, `crashes` | `<KEY>=<VALUE>` |
@@ -123,6 +124,9 @@
* `ignore-X` where `X` is a target detail or other criteria on which to ignore the test (see below)
* `only-X` is like `ignore-X`, but will *only* run the test on that target or
stage
+* `ignore-auxiliary` is intended for files that *participate* in one or more other
+ main test files but that `compiletest` should not try to build the file itself.
+ Please backlink to which main test is actually using the auxiliary file.
* `ignore-test` always ignores the test. This can be used to temporarily disable
a test if it is currently not working, but you want to keep it in tree to
re-enable it later.
diff --git a/src/doc/rustc-dev-guide/src/tests/ecosystem.md b/src/doc/rustc-dev-guide/src/tests/ecosystem.md
index f4b9349..eee07dd 100644
--- a/src/doc/rustc-dev-guide/src/tests/ecosystem.md
+++ b/src/doc/rustc-dev-guide/src/tests/ecosystem.md
@@ -15,9 +15,11 @@
`cargotest` is a small tool which runs `cargo test` on a few sample projects
(such as `servo`, `ripgrep`, `tokei`, etc.). This runs as part of CI and ensures
-there aren't any significant regressions.
+there aren't any significant regressions:
-> Example: `./x test src/tools/cargotest`
+```console
+./x test src/tools/cargotest
+```
### Large OSS Project builders
diff --git a/src/doc/rustc-dev-guide/src/tests/ui.md b/src/doc/rustc-dev-guide/src/tests/ui.md
index e862a07..6232c8b 100644
--- a/src/doc/rustc-dev-guide/src/tests/ui.md
+++ b/src/doc/rustc-dev-guide/src/tests/ui.md
@@ -303,8 +303,7 @@
### `error-pattern`
The `error-pattern` [directive](directives.md) can be used for runtime messages, which don't
-have a specific span, or for compile time messages if imprecise matching is required due to
-multi-line platform specific diagnostics.
+have a specific span, or in exceptional cases, for compile time messages.
Let's think about this test:
@@ -317,8 +316,8 @@
}
```
-We want to ensure this shows "index out of bounds" but we cannot use the `ERROR`
-annotation since the error doesn't have any span. Then it's time to use the
+We want to ensure this shows "index out of bounds", but we cannot use the `ERROR`
+annotation since the runtime error doesn't have any span. Then it's time to use the
`error-pattern` directive:
```rust,ignore
@@ -331,29 +330,52 @@
}
```
-But for strict testing, try to use the `ERROR` annotation as much as possible,
-including `//~?` annotations for diagnostics without span.
-For compile time diagnostics `error-pattern` should very rarely be necessary.
+Use of `error-pattern` is not recommended in general.
-Per-line annotations (`//~`) are still checked in tests using `error-pattern`.
-To opt out of these checks, use `//@ compile-flags: --error-format=human`.
-Do that only in exceptional cases.
+For strict testing of compile time output, try to use the line annotations `//~` as much as
+possible, including `//~?` annotations for diagnostics without spans.
-### Error levels
+If the compile time output is target dependent or too verbose, use directive
+`//@ dont-require-annotations: <diagnostic-kind>` to make the line annotation checking
+non-exhaustive.
+Some of the compiler messages can stay uncovered by annotations in this mode.
-The error levels that you can have are:
+For checking runtime output, `//@ check-run-results` may be preferable.
+
+Only use `error-pattern` if none of the above works.
+
+Line annotations `//~` are still checked in tests using `error-pattern`.
+In exceptional cases, use `//@ compile-flags: --error-format=human` to opt out of these checks.
+
+### Diagnostic kinds (error levels)
+
+The diagnostic kinds that you can have are:
- `ERROR`
-- `WARN` or `WARNING`
+- `WARN` (or `WARNING`)
- `NOTE`
-- `HELP` and `SUGGESTION`
+- `HELP`
+- `SUGGESTION`
-You are allowed to not include a level, but you should include it at least for
-the primary message.
-
-The `SUGGESTION` level is used for specifying what the expected replacement text
+The `SUGGESTION` kind is used for specifying what the expected replacement text
should be for a diagnostic suggestion.
+`ERROR` and `WARN` kinds are required to be exhaustively covered by line annotations
+`//~` by default.
+
+Other kinds only need to be line-annotated if at least one annotation of that kind appears
+in the test file. For example, one `//~ NOTE` will also require all other `//~ NOTE`s in the file
+to be written out explicitly.
+
+Use directive `//@ dont-require-annotations` to opt out of exhaustive annotations.
+E.g. use `//@ dont-require-annotations: NOTE` to annotate notes selectively.
+Avoid using this directive for `ERROR`s and `WARN`ings, unless there's a serious reason, like
+target-dependent compiler output.
+
+Missing diagnostic kinds (`//~ message`) are currently accepted, but are being phased away.
+They will match any compiler output kind, but will not force exhaustive annotations for that kind.
+Prefer explicit kind and `//@ dont-require-annotations` to achieve the same effect.
+
UI tests use the `-A unused` flag by default to ignore all unused warnings, as
unused warnings are usually not the focus of a test. However, simple code
samples often have unused warnings. If the test is specifically testing an
@@ -575,4 +597,27 @@
the term "UI" (*user* interface) and turns such UI tests from black-box tests
into white-box ones. Use them carefully and sparingly.
-[compiler debugging]: ../compiler-debugging.md#rustc_test-attributes
+[compiler debugging]: ../compiler-debugging.md#rustc_-test-attributes
+
+## UI test mode preset lint levels
+
+By default, test suites under UI test mode (`tests/ui`, `tests/ui-fulldeps`,
+but not `tests/rustdoc-ui`) will specify
+
+- `-A unused`
+- `-A internal_features`
+
+If:
+
+- The ui test's pass mode is below `run` (i.e. check or build).
+- No compare modes are specified.
+
+Since they can be very noisy in ui tests.
+
+You can override them with `compile-flags` lint level flags or
+in-source lint level attributes as required.
+
+Note that the `rustfix` version will *not* have `-A unused` passed,
+meaning that you may have to `#[allow(unused)]` to suppress `unused`
+lints on the rustfix'd file (because we might be testing rustfix
+on `unused` lints themselves).
diff --git a/src/doc/rustc-dev-guide/src/the-parser.md b/src/doc/rustc-dev-guide/src/the-parser.md
index 60a71ae..601a81e 100644
--- a/src/doc/rustc-dev-guide/src/the-parser.md
+++ b/src/doc/rustc-dev-guide/src/the-parser.md
@@ -1,4 +1,4 @@
-# Lexing and Parsing
+# Lexing and parsing
The very first thing the compiler does is take the program (in UTF-8 Unicode text)
and turn it into a data format the compiler can work with more conveniently than strings.
@@ -59,7 +59,7 @@
We set these aside to be expanded (see [Macro Expansion](./macro-expansion.md)).
Expansion itself may require parsing the output of a macro, which may reveal more macros to be expanded, and so on.
-## More on Lexical Analysis
+## More on lexical analysis
Code for lexical analysis is split between two crates:
diff --git a/src/doc/rustc-dev-guide/src/ty.md b/src/doc/rustc-dev-guide/src/ty.md
index b33d540..ce6cffe 100644
--- a/src/doc/rustc-dev-guide/src/ty.md
+++ b/src/doc/rustc-dev-guide/src/ty.md
@@ -61,11 +61,11 @@
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Describe the *syntax* of a type: what the user wrote (with some desugaring). | Describe the *semantics* of a type: the meaning of what the user wrote. |
| Each `rustc_hir::Ty` has its own spans corresponding to the appropriate place in the program. | Doesn’t correspond to a single place in the user’s program. |
-| `rustc_hir::Ty` has generics and lifetimes; however, some of those lifetimes are special markers like [`LifetimeName::Implicit`][implicit]. | `ty::Ty` has the full type, including generics and lifetimes, even if the user left them out |
+| `rustc_hir::Ty` has generics and lifetimes; however, some of those lifetimes are special markers like [`LifetimeKind::Implicit`][implicit]. | `ty::Ty` has the full type, including generics and lifetimes, even if the user left them out |
| `fn foo(x: u32) → u32 { }` - Two `rustc_hir::Ty` representing each usage of `u32`, each has its own `Span`s, and `rustc_hir::Ty` doesn’t tell us that both are the same type | `fn foo(x: u32) → u32 { }` - One `ty::Ty` for all instances of `u32` throughout the program, and `ty::Ty` tells us that both usages of `u32` mean the same type. |
-| `fn foo(x: &u32) -> &u32)` - Two `rustc_hir::Ty` again. Lifetimes for the references show up in the `rustc_hir::Ty`s using a special marker, [`LifetimeName::Implicit`][implicit]. | `fn foo(x: &u32) -> &u32)`- A single `ty::Ty`. The `ty::Ty` has the hidden lifetime param. |
+| `fn foo(x: &u32) -> &u32)` - Two `rustc_hir::Ty` again. Lifetimes for the references show up in the `rustc_hir::Ty`s using a special marker, [`LifetimeKind::Implicit`][implicit]. | `fn foo(x: &u32) -> &u32)`- A single `ty::Ty`. The `ty::Ty` has the hidden lifetime param. |
-[implicit]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.LifetimeName.html#variant.Implicit
+[implicit]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_hir/hir/enum.LifetimeKind.html#variant.Implicit
**Order**
@@ -323,4 +323,4 @@
- Generic parameters: `{name}/#{index}` e.g. `T/#0`, where `index` corresponds to its position in the list of generic parameters
- Inference variables: `?{id}` e.g. `?x`/`?0`, where `id` identifies the inference variable
- Variables from binders: `^{binder}_{index}` e.g. `^0_x`/`^0_2`, where `binder` and `index` identify which variable from which binder is being referred to
-- Placeholders: `!{id}` or `!{id}_{universe}` e.g. `!x`/`!0`/`!x_2`/`!0_2`, representing some unique type in the specified universe. The universe is often elided when it is `0`
\ No newline at end of file
+- Placeholders: `!{id}` or `!{id}_{universe}` e.g. `!x`/`!0`/`!x_2`/`!0_2`, representing some unique type in the specified universe. The universe is often elided when it is `0`
diff --git a/src/doc/rustc-dev-guide/src/unsafety-checking.md b/src/doc/rustc-dev-guide/src/unsafety-checking.md
index 1130878..fbc19d8 100644
--- a/src/doc/rustc-dev-guide/src/unsafety-checking.md
+++ b/src/doc/rustc-dev-guide/src/unsafety-checking.md
@@ -1,4 +1,4 @@
-# Unsafety Checking
+# Unsafety checking
Certain expressions in Rust can violate memory safety and as such need to be
inside an `unsafe` block or function. The compiler will also warn if an unsafe
diff --git a/src/doc/rustc-dev-guide/src/walkthrough.md b/src/doc/rustc-dev-guide/src/walkthrough.md
index 6e07ceb..48b3f8b 100644
--- a/src/doc/rustc-dev-guide/src/walkthrough.md
+++ b/src/doc/rustc-dev-guide/src/walkthrough.md
@@ -221,7 +221,7 @@
some merge conflicts with other PRs that happen to get merged first. You
should fix these merge conflicts using the normal git procedures.
-[crater]: ./tests/intro.html#crater
+[crater]: ./tests/crater.html
If you are not doing a new feature or something like that (e.g. if you are
fixing a bug), then that's it! Thanks for your contribution :)
diff --git a/src/doc/rustc-dev-guide/triagebot.toml b/src/doc/rustc-dev-guide/triagebot.toml
index 12aa0b7..6232dbf 100644
--- a/src/doc/rustc-dev-guide/triagebot.toml
+++ b/src/doc/rustc-dev-guide/triagebot.toml
@@ -7,5 +7,9 @@
"blocked",
]
+[no-mentions]
+
+[canonicalize-issue-links]
+
# Automatically close and reopen PRs made by bots to run CI on them
[bot-pull-requests]
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index 9bb64ad..cf41f5b8 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -78,6 +78,7 @@
- [illumos](platform-support/illumos.md)
- [loongarch\*-unknown-linux-\*](platform-support/loongarch-linux.md)
- [loongarch\*-unknown-none\*](platform-support/loongarch-none.md)
+ - [\*-lynxos178-\*](platform-support/lynxos178.md)
- [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md)
- [m68k-unknown-none-elf](platform-support/m68k-unknown-none-elf.md)
- [mips64-openwrt-linux-musl](platform-support/mips64-openwrt-linux-musl.md)
diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md
index 8c1769a..a3b70e7 100644
--- a/src/doc/rustc/src/codegen-options/index.md
+++ b/src/doc/rustc/src/codegen-options/index.md
@@ -110,6 +110,19 @@
If this flag is not specified, a dlltool executable will be inferred based on
the host environment and target.
+## dwarf-version
+
+This option controls the version of DWARF that the compiler emits, on platforms
+that use DWARF to encode debug information. It takes one of the following
+values:
+
+* `2`: DWARF version 2 (the default on certain platforms, like Android).
+* `3`: DWARF version 3 (the default on certain platforms, like AIX).
+* `4`: DWARF version 4 (the default on most platforms, like Linux & macOS).
+* `5`: DWARF version 5.
+
+DWARF version 1 is not supported.
+
## embed-bitcode
This flag controls whether or not the compiler embeds LLVM bitcode into object
diff --git a/src/doc/rustc/src/exploit-mitigations.md b/src/doc/rustc/src/exploit-mitigations.md
index d4e2fc5..f8bafe0 100644
--- a/src/doc/rustc/src/exploit-mitigations.md
+++ b/src/doc/rustc/src/exploit-mitigations.md
@@ -42,8 +42,7 @@
This section documents the exploit mitigations applicable to the Rust compiler
when building programs for the Linux operating system on the AMD64 architecture
-and equivalent.<sup id="fnref:1" role="doc-noteref"><a href="#fn:1"
-class="footnote">1</a></sup> All examples in this section were built using
+and equivalent.[^all-targets] All examples in this section were built using
nightly builds of the Rust compiler on Debian testing.
The Rust Programming Language currently has no specification. The Rust compiler
@@ -67,11 +66,8 @@
| Forward-edge control flow protection | Yes | Nightly |
| Backward-edge control flow protection (e.g., shadow and safe stack) | Yes | Nightly |
-<small id="fn:1">1\. See
-<https://github.com/rust-lang/rust/tree/master/compiler/rustc_target/src/spec>
-for a list of targets and their default options. <a href="#fnref:1"
-class="reversefootnote" role="doc-backlink">↩</a></small>
-
+[^all-targets]: See <https://github.com/rust-lang/rust/tree/master/compiler/rustc_target/src/spec>
+ for a list of targets and their default options.
### Position-independent executable
@@ -141,18 +137,15 @@
3), and disabled when debug assertions are disabled (see Fig. 4). To enable
integer overflow checks independently, use the option to control integer
overflow checks, scoped attributes, or explicit checking methods such as
-`checked_add`<sup id="fnref:2" role="doc-noteref"><a href="#fn:2"
-class="footnote">2</a></sup>.
+`checked_add`[^checked-methods].
It is recommended that explicit wrapping methods such as `wrapping_add` be used
when wrapping semantics are intended, and that explicit checking and wrapping
methods always be used when using Unsafe Rust.
-<small id="fn:2">2\. See [the `u32` docs](../std/primitive.u32.html) for more
-information on the checked, overflowing, saturating, and wrapping methods
-(using u32 as an example). <a href="#fnref:2" class="reversefootnote"
-role="doc-backlink">↩</a></small>
-
+[^checked-methods]: See [the `u32` docs](../std/primitive.u32.html) for more
+ information on the checked, overflowing, saturating, and wrapping methods
+ (using u32 as an example).
### Non-executable memory regions
@@ -180,17 +173,14 @@
The presence of an element of type `PT_GNU_STACK` in the program header table
with the `PF_X` (i.e., executable) flag unset indicates non-executable memory
-regions<sup id="fnref:3" role="doc-noteref"><a href="#fn:3"
-class="footnote">3</a></sup> are enabled for a given binary (see Fig. 5).
+regions[^other-regions] are enabled for a given binary (see Fig. 5).
Conversely, the presence of an element of type `PT_GNU_STACK` in the program
header table with the `PF_X` flag set or the absence of an element of type
`PT_GNU_STACK` in the program header table indicates non-executable memory
regions are not enabled for a given binary.
-<small id="fn:3">3\. See the Appendix section for more information on why it
-affects other memory regions besides the stack. <a href="#fnref:3"
-class="reversefootnote" role="doc-backlink">↩</a></small>
-
+[^other-regions]: See the [Appendix section](#appendix) for more information
+ on why it affects other memory regions besides the stack.
### Stack clashing protection
@@ -270,8 +260,7 @@
Fig. 10. Checking if immediate binding is enabled for a given binary.
The presence of an element with the `DT_BIND_NOW` tag and the `DF_BIND_NOW`
-flag<sup id="fnref:4" role="doc-noteref"><a href="#fn:4"
-class="footnote">4</a></sup> in the dynamic section indicates immediate binding
+flag[^bind-now] in the dynamic section indicates immediate binding
is enabled for a given binary (see Fig. 10). Conversely, the absence of an
element with the `DT_BIND_NOW` tag and the `DF_BIND_NOW` flag in the dynamic
section indicates immediate binding is not enabled for a given binary.
@@ -281,9 +270,7 @@
in the dynamic section indicates full RELRO is enabled for a given binary (see
Figs. 9–10).
-<small id="fn:4">4\. And the `DF_1_NOW` flag for some link editors. <a
-href="#fnref:4" class="reversefootnote" role="doc-backlink">↩</a></small>
-
+[^bind-now]: And the `DF_1_NOW` flag for some link editors.
### Heap corruption protection
@@ -303,8 +290,7 @@
[jemalloc](http://jemalloc.net/), and it has long been the cause of issues and
the subject of much discussion[32]–[38]. Consequently, it has been removed as
the default allocator in favor of the operating system’s standard C library
-default allocator<sup id="fnref:5" role="doc-noteref"><a href="#fn:5"
-class="footnote">5</a></sup> since version 1.32.0 (2019-01-17)[39].
+default allocator[^linx-allocator] since version 1.32.0 (2019-01-17)[39].
```rust,no_run
fn main() {
@@ -343,11 +329,9 @@
Heap corruption checks are performed when using the default allocator (i.e.,
the GNU Allocator) (see Figs. 12–13).
-<small id="fn:5">5\. Linux's standard C library default allocator is the GNU
-Allocator, which is derived from ptmalloc (pthreads malloc) by Wolfram Gloger,
-which in turn is derived from dlmalloc (Doug Lea malloc) by Doug Lea. <a
-href="#fnref:5" class="reversefootnote" role="doc-backlink">↩</a></small>
-
+[^linx-allocator]: Linux's standard C library default allocator is the GNU
+ Allocator, which is derived from ptmalloc (pthreads malloc) by Wolfram Gloger,
+ which in turn is derived from dlmalloc (Doug Lea malloc) by Doug Lea.
### Stack smashing protection
@@ -385,8 +369,7 @@
(RAP)](https://grsecurity.net/rap_faq).
The Rust compiler supports forward-edge control flow protection on nightly
-builds[41]-[42] <sup id="fnref:6" role="doc-noteref"><a href="#fn:6"
-class="footnote">6</a></sup>.
+builds[41]-[42] [^win-cfg].
```text
$ readelf -s -W target/release/hello-rust | grep "\.cfi"
@@ -401,10 +384,8 @@
`__cfi_check`) indicates that LLVM CFI is not enabled for a given binary (see
Fig. 15).
-<small id="fn:6">6\. It also supports Control Flow Guard (CFG) on Windows (see
-<https://github.com/rust-lang/rust/issues/68793>). <a href="#fnref:6"
-class="reversefootnote" role="doc-backlink">↩</a></small>
-
+[^win-cfg]: It also supports Control Flow Guard (CFG) on Windows (see
+ <https://github.com/rust-lang/rust/issues/68793>).
### Backward-edge control flow protection
@@ -431,8 +412,7 @@
protection, such as ARM Pointer Authentication, and Intel Shadow Stack as part
of Intel CET.
-The Rust compiler supports shadow stack for the AArch64 architecture<sup
-id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote">7</a></sup>on
+The Rust compiler supports shadow stack for the AArch64 architecture[^amd64-shadow] on
nightly builds[43]-[44], and also supports safe stack on nightly
builds[45]-[46].
@@ -447,9 +427,8 @@
symbol indicates that LLVM SafeStack is not enabled for a given binary (see
Fig. 16).
-<small id="fn:7">7\. The shadow stack implementation for the AMD64 architecture
-and equivalent in LLVM was removed due to performance and security issues. <a
-href="#fnref:7" class="reversefootnote" role="doc-backlink">↩</a></small>
+[^amd64-shadow]: The shadow stack implementation for the AMD64 architecture
+ and equivalent in LLVM was removed due to performance and security issues.
## Appendix
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 4149b4c..9870e50 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -407,6 +407,7 @@
[`wasm32-wali-linux-musl`](platform-support/wasm32-wali-linux.md) | ? | | WebAssembly with [WALI](https://github.com/arjunr2/WALI)
[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ✓ | | x86 64-bit tvOS
[`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator
+[`x86_64-lynx-lynxos178`](platform-support/lynxos178.md) | | | x86_64 LynxOS-178
[`x86_64-pc-cygwin`](platform-support/x86_64-pc-cygwin.md) | ✓ | | 64-bit x86 Cygwin |
[`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with default network stack (io-pkt) |
[`x86_64-pc-nto-qnx710_iosock`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS with new network stack (io-sock) |
diff --git a/src/doc/rustc/src/platform-support/TEMPLATE.md b/src/doc/rustc/src/platform-support/TEMPLATE.md
index 96c7997..f523237 100644
--- a/src/doc/rustc/src/platform-support/TEMPLATE.md
+++ b/src/doc/rustc/src/platform-support/TEMPLATE.md
@@ -6,7 +6,8 @@
## Target maintainers
-- Some Person, https://github.com/...
+[@Ghost](https://github.com/Ghost)
+[@octocat](https://github.com/octocat)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/aarch64-nintendo-switch-freestanding.md b/src/doc/rustc/src/platform-support/aarch64-nintendo-switch-freestanding.md
index 308e1fe..6951d7f 100644
--- a/src/doc/rustc/src/platform-support/aarch64-nintendo-switch-freestanding.md
+++ b/src/doc/rustc/src/platform-support/aarch64-nintendo-switch-freestanding.md
@@ -4,10 +4,10 @@
Nintendo Switch with pure-Rust toolchain.
-## Designated Developers
+## Target Maintainers
-* [@leo60228](https://github.com/leo60228)
-* [@jam1garner](https://github.com/jam1garner)
+[@leo60228](https://github.com/leo60228)
+[@jam1garner](https://github.com/jam1garner)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md b/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md
index e2f2379e..be11d0c 100644
--- a/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md
+++ b/src/doc/rustc/src/platform-support/aarch64-unknown-teeos.md
@@ -20,8 +20,8 @@
## Target maintainers
-- Petrochenkov Vadim
-- Sword-Destiny
+[@petrochenkov](https://github.com/petrochenkov)
+[@Sword-Destiny](https://github.com/Sword-Destiny)
## Setup
We use OpenHarmony SDK for TEEOS.
diff --git a/src/doc/rustc/src/platform-support/aix.md b/src/doc/rustc/src/platform-support/aix.md
index 5a19806..3002a5c 100644
--- a/src/doc/rustc/src/platform-support/aix.md
+++ b/src/doc/rustc/src/platform-support/aix.md
@@ -6,8 +6,8 @@
## Target maintainers
-- David Tenty `daltenty@ibm.com`, https://github.com/daltenty
-- Chris Cambly, `ccambly@ca.ibm.com`, https://github.com/gilamn5tr
+[@daltenty](https://github.com/daltenty)
+[@gilamn5tr](https://github.com/gilamn5tr)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md b/src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md
index 0b2f798..16152dd 100644
--- a/src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md
+++ b/src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md
@@ -6,7 +6,7 @@
## Target maintainers
-- [@Flakebi](https://github.com/Flakebi)
+[@Flakebi](https://github.com/Flakebi)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/android.md b/src/doc/rustc/src/platform-support/android.md
index 54e7ddc..a54288f 100644
--- a/src/doc/rustc/src/platform-support/android.md
+++ b/src/doc/rustc/src/platform-support/android.md
@@ -8,9 +8,9 @@
## Target maintainers
-- Chris Wailes ([@chriswailes](https://github.com/chriswailes))
-- Matthew Maurer ([@maurer](https://github.com/maurer))
-- Martin Geisler ([@mgeisler](https://github.com/mgeisler))
+[@chriswailes](https://github.com/chriswailes)
+[@maurer](https://github.com/maurer)
+[@mgeisler](https://github.com/mgeisler)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/apple-darwin.md b/src/doc/rustc/src/platform-support/apple-darwin.md
index 22c54d0..e41aee9 100644
--- a/src/doc/rustc/src/platform-support/apple-darwin.md
+++ b/src/doc/rustc/src/platform-support/apple-darwin.md
@@ -9,8 +9,8 @@
## Target maintainers
-- [@thomcc](https://github.com/thomcc)
-- [@madsmtm](https://github.com/madsmtm)
+[@thomcc](https://github.com/thomcc)
+[@madsmtm](https://github.com/madsmtm)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/apple-ios-macabi.md b/src/doc/rustc/src/platform-support/apple-ios-macabi.md
index 79966d9..d4b71db 100644
--- a/src/doc/rustc/src/platform-support/apple-ios-macabi.md
+++ b/src/doc/rustc/src/platform-support/apple-ios-macabi.md
@@ -9,9 +9,9 @@
## Target maintainers
-- [@badboy](https://github.com/badboy)
-- [@BlackHoleFox](https://github.com/BlackHoleFox)
-- [@madsmtm](https://github.com/madsmtm)
+[@badboy](https://github.com/badboy)
+[@BlackHoleFox](https://github.com/BlackHoleFox)
+[@madsmtm](https://github.com/madsmtm)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/apple-ios.md b/src/doc/rustc/src/platform-support/apple-ios.md
index 7f5dc36..6432555 100644
--- a/src/doc/rustc/src/platform-support/apple-ios.md
+++ b/src/doc/rustc/src/platform-support/apple-ios.md
@@ -15,9 +15,9 @@
## Target maintainers
-- [@badboy](https://github.com/badboy)
-- [@deg4uss3r](https://github.com/deg4uss3r)
-- [@madsmtm](https://github.com/madsmtm)
+[@badboy](https://github.com/badboy)
+[@deg4uss3r](https://github.com/deg4uss3r)
+[@madsmtm](https://github.com/madsmtm)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/apple-tvos.md b/src/doc/rustc/src/platform-support/apple-tvos.md
index fc46db2..193d646 100644
--- a/src/doc/rustc/src/platform-support/apple-tvos.md
+++ b/src/doc/rustc/src/platform-support/apple-tvos.md
@@ -10,8 +10,8 @@
## Target maintainers
-- [@thomcc](https://github.com/thomcc)
-- [@madsmtm](https://github.com/madsmtm)
+[@thomcc](https://github.com/thomcc)
+[@madsmtm](https://github.com/madsmtm)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/apple-visionos.md b/src/doc/rustc/src/platform-support/apple-visionos.md
index 7cf9549..ed96912 100644
--- a/src/doc/rustc/src/platform-support/apple-visionos.md
+++ b/src/doc/rustc/src/platform-support/apple-visionos.md
@@ -9,8 +9,8 @@
## Target maintainers
-- [@agg23](https://github.com/agg23)
-- [@madsmtm](https://github.com/madsmtm)
+[@agg23](https://github.com/agg23)
+[@madsmtm](https://github.com/madsmtm)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/apple-watchos.md b/src/doc/rustc/src/platform-support/apple-watchos.md
index 7b12d9e..6ac09d0 100644
--- a/src/doc/rustc/src/platform-support/apple-watchos.md
+++ b/src/doc/rustc/src/platform-support/apple-watchos.md
@@ -12,10 +12,10 @@
## Target maintainers
-- [@deg4uss3r](https://github.com/deg4uss3r)
-- [@vladimir-ea](https://github.com/vladimir-ea)
-- [@leohowell](https://github.com/leohowell)
-- [@madsmtm](https://github.com/madsmtm)
+[@deg4uss3r](https://github.com/deg4uss3r)
+[@vladimir-ea](https://github.com/vladimir-ea)
+[@leohowell](https://github.com/leohowell)
+[@madsmtm](https://github.com/madsmtm)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md b/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md
index 3200b7a..2043b34 100644
--- a/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md
+++ b/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md
@@ -6,7 +6,7 @@
## Target maintainers
-- Artyom Tetyukhin ([@arttet](https://github.com/arttet))
+[@arttet](https://github.com/arttet)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/arm64e-apple-ios.md b/src/doc/rustc/src/platform-support/arm64e-apple-ios.md
index aa99276..a2b09e0 100644
--- a/src/doc/rustc/src/platform-support/arm64e-apple-ios.md
+++ b/src/doc/rustc/src/platform-support/arm64e-apple-ios.md
@@ -6,7 +6,7 @@
## Target maintainers
-- Artyom Tetyukhin ([@arttet](https://github.com/arttet))
+[@arttet](https://github.com/arttet)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/arm64e-apple-tvos.md b/src/doc/rustc/src/platform-support/arm64e-apple-tvos.md
index 332ea75..36588c5 100644
--- a/src/doc/rustc/src/platform-support/arm64e-apple-tvos.md
+++ b/src/doc/rustc/src/platform-support/arm64e-apple-tvos.md
@@ -6,7 +6,7 @@
## Target maintainers
-- Artyom Tetyukhin ([@arttet](https://github.com/arttet))
+[@arttet](https://github.com/arttet)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md b/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md
index 67903ae..d02043b 100644
--- a/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md
+++ b/src/doc/rustc/src/platform-support/arm64ec-pc-windows-msvc.md
@@ -7,7 +7,7 @@
## Target maintainers
-- [@dpaoliello](https://github.com/dpaoliello)
+[@dpaoliello](https://github.com/dpaoliello)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md
index 3a5b5a3..7c1c5db 100644
--- a/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md
+++ b/src/doc/rustc/src/platform-support/armeb-unknown-linux-gnueabi.md
@@ -10,7 +10,8 @@
BE8 architecture is the default big-endian architecture for Arm since [Armv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en). It's predecessor, used for Armv4 and Armv5 devices was [BE32](https://developer.arm.com/documentation/dui0474/j/linker-command-line-options/--be32). On Armv6 architecture, endianness can be configured via [system registers](https://developer.arm.com/documentation/ddi0290/g/unaligned-and-mixed-endian-data-access-support/mixed-endian-access-support/interaction-between-the-bus-protocol-and-the-core-endianness). However, BE32 was withdrawn for [Armv7](https://developer.arm.com/documentation/ddi0406/cb/Appendixes/Deprecated-and-Obsolete-Features/Obsolete-features/Support-for-BE-32-endianness-model) onwards.
## Target Maintainers
-* [@WorksButNotTested](https://github.com/WorksButNotTested)
+
+[@WorksButNotTested](https://github.com/WorksButNotTested)
## Requirements
The target is cross-compiled. This target supports `std` in the normal way (indeed only nominal changes are required from the standard Arm configuration).
diff --git a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md
index 0c5129d..56f919e 100644
--- a/src/doc/rustc/src/platform-support/armv4t-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/armv4t-none-eabi.md
@@ -11,8 +11,8 @@
## Target Maintainers
-* [@Lokathor](https://github.com/lokathor)
-* [@corwinkuiper](https://github.com/corwinkuiper)
+[@Lokathor](https://github.com/lokathor)
+[@corwinkuiper](https://github.com/corwinkuiper)
## Testing
diff --git a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md
index 41621e0..2228797 100644
--- a/src/doc/rustc/src/platform-support/armv5te-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/armv5te-none-eabi.md
@@ -13,7 +13,7 @@
## Target Maintainers
-* [@QuinnPainter](https://github.com/QuinnPainter)
+[@QuinnPainter](https://github.com/QuinnPainter)
## Testing
diff --git a/src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md b/src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md
index a085aef..e4a0f75 100644
--- a/src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md
+++ b/src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md
@@ -13,9 +13,9 @@
This target is maintained by members of the [@rust3ds](https://github.com/rust3ds)
organization:
-- [@Meziu](https://github.com/Meziu)
-- [@AzureMarker](https://github.com/AzureMarker)
-- [@ian-h-chamberlain](https://github.com/ian-h-chamberlain)
+[@Meziu](https://github.com/Meziu)
+[@AzureMarker](https://github.com/AzureMarker)
+[@ian-h-chamberlain](https://github.com/ian-h-chamberlain)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/armv7-rtems-eabihf.md b/src/doc/rustc/src/platform-support/armv7-rtems-eabihf.md
index 2791c21..feac3c1 100644
--- a/src/doc/rustc/src/platform-support/armv7-rtems-eabihf.md
+++ b/src/doc/rustc/src/platform-support/armv7-rtems-eabihf.md
@@ -6,13 +6,13 @@
## Target maintainers
-- [@thesummer](https://github.com/thesummer)
+[@thesummer](https://github.com/thesummer)
## Requirements
The target does not support host tools. Only cross-compilation is possible.
The cross-compiler toolchain can be obtained by following the installation instructions
-of the [RTEMS Documentation](https://docs.rtems.org/branches/master/user/index.html). Additionally to the cross-compiler also a compiled BSP
+of the [RTEMS Documentation](https://docs.rtems.org/docs/main/user/index.html). Additionally to the cross-compiler also a compiled BSP
for a board fitting the architecture needs to be available on the host.
Currently tested has been the BSP `xilinx_zynq_a9_qemu` of RTEMS 6.
@@ -49,4 +49,4 @@
## Cross-compilation toolchains and C code
Compatible C-code can be built with the RTEMS cross-compiler toolchain `arm-rtems6-gcc`.
-For more information how to build the toolchain, RTEMS itself and RTEMS applications please have a look at the [RTEMS Documentation](https://docs.rtems.org/branches/master/user/index.html).
+For more information how to build the toolchain, RTEMS itself and RTEMS applications please have a look at the [RTEMS Documentation](https://docs.rtems.org/docs/main/user/index.html).
diff --git a/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md b/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md
index e1473bd..814f301 100644
--- a/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md
+++ b/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md
@@ -9,9 +9,9 @@
## Target maintainers
-* [@nikarh](https://github.com/nikarh)
-* [@pheki](https://github.com/pheki)
-* [@ZetaNumbers](https://github.com/ZetaNumbers)
+[@nikarh](https://github.com/nikarh)
+[@pheki](https://github.com/pheki)
+[@zetanumbers](https://github.com/zetanumbers)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md
index f22a208..e553c49 100644
--- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md
+++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabi.md
@@ -6,7 +6,7 @@
## Target maintainers
-* [@lancethepants](https://github.com/lancethepants)
+[@lancethepants](https://github.com/lancethepants)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md
index f687f6f..91f3ea8 100644
--- a/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md
+++ b/src/doc/rustc/src/platform-support/armv7-unknown-linux-uclibceabihf.md
@@ -4,9 +4,9 @@
This tier supports the Armv7-A processor running a Linux kernel and uClibc-ng standard library. It provides full support for rust and the rust standard library.
-## Designated Developers
+## Target Maintainers
-* [@skrap](https://github.com/skrap)
+[@skrap](https://github.com/skrap)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md
index 5f0dc6a..88b2689 100644
--- a/src/doc/rustc/src/platform-support/armv7r-none-eabi.md
+++ b/src/doc/rustc/src/platform-support/armv7r-none-eabi.md
@@ -16,7 +16,7 @@
## Target maintainers
-- [Chris Copeland](https://github.com/chrisnc), `chris@chrisnc.net`
+[@chrisnc](https://github.com/chrisnc)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md
index 6f80a06..569d880 100644
--- a/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md
+++ b/src/doc/rustc/src/platform-support/armv8r-none-eabihf.md
@@ -16,7 +16,7 @@
## Target maintainers
-- [Chris Copeland](https://github.com/chrisnc), `chris@chrisnc.net`
+[@chrisnc](https://github.com/chrisnc)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/avr-none.md b/src/doc/rustc/src/platform-support/avr-none.md
index 9c18362..5218f19 100644
--- a/src/doc/rustc/src/platform-support/avr-none.md
+++ b/src/doc/rustc/src/platform-support/avr-none.md
@@ -6,7 +6,7 @@
## Target maintainers
-- [Patryk Wychowaniec](https://github.com/Patryk27) <pwychowaniec@pm.me>
+[@Patryk27](https://github.com/Patryk27)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md
index f749b37..e69d606 100644
--- a/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md
+++ b/src/doc/rustc/src/platform-support/csky-unknown-linux-gnuabiv2.md
@@ -22,7 +22,7 @@
## Target maintainers
-* [@Dirreke](https://github.com/Dirreke)
+[@Dirreke](https://github.com/Dirreke)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/esp-idf.md b/src/doc/rustc/src/platform-support/esp-idf.md
index 91d7d66..baf42ab 100644
--- a/src/doc/rustc/src/platform-support/esp-idf.md
+++ b/src/doc/rustc/src/platform-support/esp-idf.md
@@ -6,9 +6,9 @@
## Target maintainers
-- Ivan Markov [@ivmarkov](https://github.com/ivmarkov)
-- Scott Mabin [@MabezDev](https://github.com/MabezDev)
-- Sergio Gasquez [@SergioGasquez](https://github.com/SergioGasquez)
+[@ivmarkov](https://github.com/ivmarkov)
+[@MabezDev](https://github.com/MabezDev)
+[@SergioGasquez](https://github.com/SergioGasquez)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/freebsd.md b/src/doc/rustc/src/platform-support/freebsd.md
index 9d34d36..9d7218b 100644
--- a/src/doc/rustc/src/platform-support/freebsd.md
+++ b/src/doc/rustc/src/platform-support/freebsd.md
@@ -6,8 +6,8 @@
## Target maintainers
-- Alan Somers `asomers@FreeBSD.org`, https://github.com/asomers
-- Mikael Urankar `mikael@FreeBSD.org`, https://github.com/MikaelUrankar
+[@asomers](https://github.com/asomers)
+[@MikaelUrankar](https://github.com/MikaelUrankar)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md
index bed5b81..e2befc5 100644
--- a/src/doc/rustc/src/platform-support/fuchsia.md
+++ b/src/doc/rustc/src/platform-support/fuchsia.md
@@ -7,9 +7,11 @@
## Target maintainers
-See [`fuchsia.toml`] in the `team` repository for current target maintainers.
+[@erickt](https://github.com/erickt)
+[@Nashenas88](https://github.com/Nashenas88)
-[`fuchsia.toml`]: https://github.com/rust-lang/team/blob/master/teams/fuchsia.toml
+The up-to-date list can be also found via the
+[fuchsia marker team](https://github.com/rust-lang/team/blob/master/teams/fuchsia.toml).
## Table of contents
diff --git a/src/doc/rustc/src/platform-support/hermit.md b/src/doc/rustc/src/platform-support/hermit.md
index df7bc49..069c253 100644
--- a/src/doc/rustc/src/platform-support/hermit.md
+++ b/src/doc/rustc/src/platform-support/hermit.md
@@ -14,8 +14,8 @@
## Target maintainers
-- Stefan Lankes ([@stlankes](https://github.com/stlankes))
-- Martin Kröning ([@mkroening](https://github.com/mkroening))
+[@stlankes](https://github.com/stlankes)
+[@mkroening](https://github.com/mkroening)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md
index cfd2b2b..be6e178 100644
--- a/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md
+++ b/src/doc/rustc/src/platform-support/hexagon-unknown-linux-musl.md
@@ -11,7 +11,7 @@
## Target maintainers
-- [Brian Cain](https://github.com/androm3da), `bcain@quicinc.com`
+[@androm3da](https://github.com/androm3da)
## Requirements
The target is cross-compiled. This target supports `std`. By default, code
diff --git a/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md b/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md
index c7726ea..b07b0bb 100644
--- a/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md
+++ b/src/doc/rustc/src/platform-support/hexagon-unknown-none-elf.md
@@ -10,7 +10,7 @@
## Target maintainers
-- [Brian Cain](https://github.com/androm3da), `bcain@quicinc.com`
+[@androm3da](https://github.com/androm3da)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/hurd.md b/src/doc/rustc/src/platform-support/hurd.md
index 2521f79..6ecde1d 100644
--- a/src/doc/rustc/src/platform-support/hurd.md
+++ b/src/doc/rustc/src/platform-support/hurd.md
@@ -6,7 +6,7 @@
## Target maintainers
-- Samuel Thibault, `samuel.thibault@ens-lyon.org`, https://github.com/sthibaul/
+[@sthibaul](https://github.com/sthibaul)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/i686-apple-darwin.md b/src/doc/rustc/src/platform-support/i686-apple-darwin.md
index abb64dc..5f18a5e 100644
--- a/src/doc/rustc/src/platform-support/i686-apple-darwin.md
+++ b/src/doc/rustc/src/platform-support/i686-apple-darwin.md
@@ -4,8 +4,8 @@
## Target maintainers
-- [@thomcc](https://github.com/thomcc)
-- [@madsmtm](https://github.com/madsmtm)
+[@thomcc](https://github.com/thomcc)
+[@madsmtm](https://github.com/madsmtm)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/illumos.md b/src/doc/rustc/src/platform-support/illumos.md
index dd2ae90..c032382 100644
--- a/src/doc/rustc/src/platform-support/illumos.md
+++ b/src/doc/rustc/src/platform-support/illumos.md
@@ -7,8 +7,8 @@
## Target maintainers
-- Joshua M. Clulow ([@jclulow](https://github.com/jclulow))
-- Patrick Mooney ([@pfmooney](https://github.com/pfmooney))
+[@jclulow](https://github.com/jclulow)
+[@pfmooney](https://github.com/pfmooney)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/kmc-solid.md b/src/doc/rustc/src/platform-support/kmc-solid.md
index 44f4792..838662a 100644
--- a/src/doc/rustc/src/platform-support/kmc-solid.md
+++ b/src/doc/rustc/src/platform-support/kmc-solid.md
@@ -14,9 +14,9 @@
| `armv7a-kmc-solid_asp3-eabi` | `arm` | `kmc` | `solid_asp3` |
| `armv7a-kmc-solid_asp3-eabihf` | `arm` | `kmc` | `solid_asp3` |
-## Designated Developers
+## Target Maintainers
-- [@kawadakk](https://github.com/kawadakk)
+[@kawadakk](https://github.com/kawadakk)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/loongarch-linux.md b/src/doc/rustc/src/platform-support/loongarch-linux.md
index 2c9f712..817d3a8 100644
--- a/src/doc/rustc/src/platform-support/loongarch-linux.md
+++ b/src/doc/rustc/src/platform-support/loongarch-linux.md
@@ -22,10 +22,10 @@
## Target maintainers
-- [WANG Rui](https://github.com/heiher) `wangrui@loongson.cn`
-- [ZHAI Xiang](https://github.com/xiangzhai) `zhaixiang@loongson.cn`
-- [ZHAI Xiaojuan](https://github.com/zhaixiaojuan) `zhaixiaojuan@loongson.cn`
-- [WANG Xuerui](https://github.com/xen0n) `git@xen0n.name`
+[@heiher](https://github.com/heiher)
+[@xiangzhai](https://github.com/xiangzhai)
+[@zhaixiaojuan](https://github.com/zhaixiaojuan)
+[@xen0n](https://github.com/xen0n)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/loongarch-none.md b/src/doc/rustc/src/platform-support/loongarch-none.md
index 6c5d866..a2bd6e5 100644
--- a/src/doc/rustc/src/platform-support/loongarch-none.md
+++ b/src/doc/rustc/src/platform-support/loongarch-none.md
@@ -11,8 +11,8 @@
## Target maintainers
-- [WANG Rui](https://github.com/heiher) `wangrui@loongson.cn`
-- [WANG Xuerui](https://github.com/xen0n) `git@xen0n.name`
+[@heiher](https://github.com/heiher)
+[@xen0n](https://github.com/xen0n)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/lynxos178.md b/src/doc/rustc/src/platform-support/lynxos178.md
new file mode 100644
index 0000000..6463f95
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/lynxos178.md
@@ -0,0 +1,77 @@
+# `*-lynxos178-*`
+
+**Tier: 3**
+
+Targets for the LynxOS-178 operating system.
+
+[LynxOS-178](https://www.lynx.com/products/lynxos-178-do-178c-certified-posix-rtos)
+is a commercial RTOS designed for safety-critical real-time systems. It is
+developed by Lynx Software Technologies as part of the
+[MOSA.ic](https://www.lynx.com/solutions/safe-and-secure-operating-environment)
+product suite.
+
+Target triples available:
+- `x86_64-lynx-lynxos178`
+
+## Target maintainers
+
+- Renat Fatykhov, https://github.com/rfatykhov-lynx
+
+## Requirements
+
+To build Rust programs for LynxOS-178, you must first have LYNX MOSA.ic
+installed on the build machine.
+
+This target supports only cross-compilation, from the same hosts supported by
+the Lynx CDK.
+
+Currently only `no_std` programs are supported. Work to support `std` is in
+progress.
+
+## Building the target
+
+You can build Rust with support for x86_64-lynx-lynxos178 by adding that
+to the `target` list in `config.toml`, and then running `./x build --target
+x86_64-lynx-lynxos178 compiler`.
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will need to build Rust with the target enabled (see "Building
+the target" above).
+
+Before executing `cargo`, you must configure the environment to build LynxOS-178
+binaries by running `source setup.sh` from the los178 directory.
+
+If your program/crates contain procedural macros, Rust must be able to build
+binaries for the host as well. The host gcc is hidden by sourcing setup.sh. To
+deal with this, add the following to your project's `.cargo/config.toml`:
+```toml
+[target.x86_64-unknown-linux-gnu]
+linker = "lynx-host-gcc"
+```
+(If necessary substitute your host target triple for x86_64-unknown-linux-gnu.)
+
+To point `cargo` at the correct rustc binary, set the RUSTC environment
+variable.
+
+The core library should be usable. You can try by building it as part of your
+project:
+```bash
+cargo +nightly build -Z build-std=core --target x86_64-lynx-lynxos178
+```
+
+## Testing
+
+Binaries built with rust can be provided to a LynxOS-178 instance on its file
+system, where they can be executed. Rust binaries tend to be large, so it may
+be necessary to strip them first.
+
+It is possible to run the Rust testsuite by providing a test runner that takes
+the test binary and executes it under LynxOS-178. Most (all?) tests won't run
+without std support though, which is not yet supported.
+
+## Cross-compilation toolchains and C code
+
+LYNX MOSA.ic comes with all the tools required to cross-compile C code for
+LynxOS-178.
diff --git a/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md
index b18a125..1efea86 100644
--- a/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md
+++ b/src/doc/rustc/src/platform-support/m68k-unknown-linux-gnu.md
@@ -4,10 +4,10 @@
Motorola 680x0 Linux
-## Designated Developers
+## Target Maintainers
-* [@glaubitz](https://github.com/glaubitz)
-* [@ricky26](https://github.com/ricky26)
+[@glaubitz](https://github.com/glaubitz)
+[@ricky26](https://github.com/ricky26)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md b/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md
index 92780cb..e390ba0 100644
--- a/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md
+++ b/src/doc/rustc/src/platform-support/m68k-unknown-none-elf.md
@@ -4,9 +4,9 @@
Bare metal Motorola 680x0
-## Designated Developers
+## Target Maintainers
-* [@knickish](https://github.com/knickish)
+[@knickish](https://github.com/knickish)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/mips-mti-none-elf.md b/src/doc/rustc/src/platform-support/mips-mti-none-elf.md
index 731f0a8..c060ebf 100644
--- a/src/doc/rustc/src/platform-support/mips-mti-none-elf.md
+++ b/src/doc/rustc/src/platform-support/mips-mti-none-elf.md
@@ -9,7 +9,7 @@
## Target maintainers
-- YunQiang Su, `syq@debian.org`, https://github.com/wzssyqa
+[@wzssyqa](https://github.com/wzssyqa)
## Background
diff --git a/src/doc/rustc/src/platform-support/mips-release-6.md b/src/doc/rustc/src/platform-support/mips-release-6.md
index b779477..77f4957 100644
--- a/src/doc/rustc/src/platform-support/mips-release-6.md
+++ b/src/doc/rustc/src/platform-support/mips-release-6.md
@@ -16,10 +16,10 @@
## Target Maintainers
-- [Xuan Chen](https://github.com/chenx97) <henry.chen@oss.cipunited.com>
-- [Walter Ji](https://github.com/709924470) <walter.ji@oss.cipunited.com>
-- [Xinhui Yang](https://github.com/Cyanoxygen) <cyan@oss.cipunited.com>
-- [Lain Yang](https://github.com/Fearyncess) <lain.yang@oss.cipunited.com>
+[@chenx97](https://github.com/chenx97)
+[@709924470](https://github.com/709924470)
+[@Cyanoxygen](https://github.com/Cyanoxygen)
+[@Fearyncess](https://github.com/Fearyncess)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/mips64-openwrt-linux-musl.md b/src/doc/rustc/src/platform-support/mips64-openwrt-linux-musl.md
index 07470ee..2ad33c9 100644
--- a/src/doc/rustc/src/platform-support/mips64-openwrt-linux-musl.md
+++ b/src/doc/rustc/src/platform-support/mips64-openwrt-linux-musl.md
@@ -2,7 +2,8 @@
**Tier: 3**
## Target maintainers
-- Donald Hoskins `grommish@gmail.com`, https://github.com/Itus-Shield
+
+[@Itus-Shield](https://github.com/Itus-Shield)
## Requirements
This target is cross-compiled. There is no support for `std`. There is no
diff --git a/src/doc/rustc/src/platform-support/mipsel-sony-psx.md b/src/doc/rustc/src/platform-support/mipsel-sony-psx.md
index 589100e..2343df2 100644
--- a/src/doc/rustc/src/platform-support/mipsel-sony-psx.md
+++ b/src/doc/rustc/src/platform-support/mipsel-sony-psx.md
@@ -6,7 +6,7 @@
## Designated Developer
-* [@ayrtonm](https://github.com/ayrtonm)
+[@ayrtonm](https://github.com/ayrtonm)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/mipsel-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/mipsel-unknown-linux-gnu.md
index b1ee872..eed0ce4 100644
--- a/src/doc/rustc/src/platform-support/mipsel-unknown-linux-gnu.md
+++ b/src/doc/rustc/src/platform-support/mipsel-unknown-linux-gnu.md
@@ -6,7 +6,7 @@
## Target maintainers
-- [@LukasWoodtli](https://github.com/LukasWoodtli)
+[@LukasWoodtli](https://github.com/LukasWoodtli)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/netbsd.md b/src/doc/rustc/src/platform-support/netbsd.md
index 5c2ce0e..9040ef6 100644
--- a/src/doc/rustc/src/platform-support/netbsd.md
+++ b/src/doc/rustc/src/platform-support/netbsd.md
@@ -31,9 +31,12 @@
are built for NetBSD 8.x but also work on newer OS versions).
-## Designated Developers
+## Target Maintainers
-- [@he32](https://github.com/he32), `he@NetBSD.org`
+[@he32](https://github.com/he32)
+
+Further contacts:
+
- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust185/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust
- [NetBSD's pkgsrc lang/rust](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust) for the "proper" package in pkgsrc.
- [NetBSD's pkgsrc lang/rust-bin](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust-bin) which re-uses the bootstrap kit as a binary distribution and therefore avoids the rather protracted native build time of rust itself
@@ -46,7 +49,7 @@
The `x86_64-unknown-netbsd` artifacts is being distributed by the
rust project.
-The other targets are built by the designated developers (see above),
+The other targets are built by the target maintainers (see above),
and the targets are initially cross-compiled, but many if not most
of them are also built natively as part of testing.
diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md
index e097d32..9f89608 100644
--- a/src/doc/rustc/src/platform-support/nto-qnx.md
+++ b/src/doc/rustc/src/platform-support/nto-qnx.md
@@ -13,10 +13,10 @@
## Target maintainers
-- Florian Bartels, `Florian.Bartels@elektrobit.com`, https://github.com/flba-eb
-- Tristan Roach, `TRoach@blackberry.com`, https://github.com/gh-tr
-- Jonathan Pallant `Jonathan.Pallant@ferrous-systems.com`, https://github.com/jonathanpallant
-- Jorge Aparicio `Jorge.Aparicio@ferrous-systems.com`, https://github.com/japaric
+[@flba-eb](https://github.com/flba-eb)
+[@gh-tr](https://github.com/gh-tr)
+[@jonathanpallant](https://github.com/jonathanpallant)
+[@japaric](https://github.com/japaric)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/nuttx.md b/src/doc/rustc/src/platform-support/nuttx.md
index f76fe08..df3f4e7 100644
--- a/src/doc/rustc/src/platform-support/nuttx.md
+++ b/src/doc/rustc/src/platform-support/nuttx.md
@@ -12,7 +12,7 @@
## Target maintainers
-- Qi Huang [@no1wudi](https://github.com/no1wudi)
+[@no1wudi](https://github.com/no1wudi)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md
index ab8641f..106ec56 100644
--- a/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md
+++ b/src/doc/rustc/src/platform-support/nvptx64-nvidia-cuda.md
@@ -7,8 +7,8 @@
## Target maintainers
-- Riccardo D'Ambrosio, https://github.com/RDambrosio016
-- Kjetil Kjeka, https://github.com/kjetilkjeka
+[@RDambrosio016](https://github.com/RDambrosio016)
+[@kjetilkjeka](https://github.com/kjetilkjeka)
<!-- FIXME: fill this out
diff --git a/src/doc/rustc/src/platform-support/openbsd.md b/src/doc/rustc/src/platform-support/openbsd.md
index 4ce8015..e6fb23c 100644
--- a/src/doc/rustc/src/platform-support/openbsd.md
+++ b/src/doc/rustc/src/platform-support/openbsd.md
@@ -20,9 +20,12 @@
Note that all OS versions are *major* even if using X.Y notation (`6.8` and `6.9` are different major versions) and could be binary incompatibles (with breaking changes).
-## Designated Developers
+## Target Maintainers
-- [@semarie](https://github.com/semarie), `semarie@openbsd.org`
+[@semarie](https://github.com/semarie)
+
+Further contacts:
+
- [lang/rust](https://cvsweb.openbsd.org/cgi-bin/cvsweb/ports/lang/rust/Makefile?rev=HEAD&content-type=text/x-cvsweb-markup) maintainer (see MAINTAINER variable)
Fallback to ports@openbsd.org, OpenBSD third parties public mailing-list (with openbsd developers readers)
diff --git a/src/doc/rustc/src/platform-support/openharmony.md b/src/doc/rustc/src/platform-support/openharmony.md
index ab50cbc..3acdc37 100644
--- a/src/doc/rustc/src/platform-support/openharmony.md
+++ b/src/doc/rustc/src/platform-support/openharmony.md
@@ -15,8 +15,8 @@
## Target maintainers
-- Amanieu d'Antras ([@Amanieu](https://github.com/Amanieu))
-- Lu Binglun ([@lubinglun](https://github.com/lubinglun))
+[@Amanieu](https://github.com/Amanieu)
+[@lubinglun](https://github.com/lubinglun)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/powerpc-unknown-linux-muslspe.md b/src/doc/rustc/src/platform-support/powerpc-unknown-linux-muslspe.md
index 6b62e9d..721e7bd 100644
--- a/src/doc/rustc/src/platform-support/powerpc-unknown-linux-muslspe.md
+++ b/src/doc/rustc/src/platform-support/powerpc-unknown-linux-muslspe.md
@@ -9,7 +9,7 @@
## Target maintainers
-- [@BKPepe](https://github.com/BKPepe)
+[@BKPepe](https://github.com/BKPepe)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md
index 0f78dcc..7213e54 100644
--- a/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md
+++ b/src/doc/rustc/src/platform-support/powerpc64-unknown-linux-musl.md
@@ -7,9 +7,9 @@
## Target maintainers
-- [@Gelbpunkt](https://github.com/Gelbpunkt)
-- [@famfo](https://github.com/famfo)
-- [@neuschaefer](https://github.com/neuschaefer)
+[@Gelbpunkt](https://github.com/Gelbpunkt)
+[@famfo](https://github.com/famfo)
+[@neuschaefer](https://github.com/neuschaefer)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-gnu.md
index 6cb34b2..78c3e68 100644
--- a/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-gnu.md
+++ b/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-gnu.md
@@ -6,8 +6,8 @@
## Target maintainers
-- David Tenty `daltenty@ibm.com`, https://github.com/daltenty
-- Chris Cambly, `ccambly@ca.ibm.com`, https://github.com/gilamn5tr
+[@daltenty](https://github.com/daltenty)
+[@gilamn5tr](https://github.com/gilamn5tr)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-musl.md
index e1e3d6d..0808840 100644
--- a/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-musl.md
+++ b/src/doc/rustc/src/platform-support/powerpc64le-unknown-linux-musl.md
@@ -6,9 +6,9 @@
## Target maintainers
-- [@Gelbpunkt](https://github.com/Gelbpunkt)
-- [@famfo](https://github.com/famfo)
-- [@neuschaefer](https://github.com/neuschaefer)
+[@Gelbpunkt](https://github.com/Gelbpunkt)
+[@famfo](https://github.com/famfo)
+[@neuschaefer](https://github.com/neuschaefer)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/redox.md b/src/doc/rustc/src/platform-support/redox.md
index c1a96f1..fc36a55 100644
--- a/src/doc/rustc/src/platform-support/redox.md
+++ b/src/doc/rustc/src/platform-support/redox.md
@@ -13,7 +13,7 @@
## Target maintainers
-- Jeremy Soller ([@jackpot51](https://github.com/jackpot51))
+[@jackpot51](https://github.com/jackpot51)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/riscv32e-unknown-none-elf.md b/src/doc/rustc/src/platform-support/riscv32e-unknown-none-elf.md
index 69f0877..d33bf37 100644
--- a/src/doc/rustc/src/platform-support/riscv32e-unknown-none-elf.md
+++ b/src/doc/rustc/src/platform-support/riscv32e-unknown-none-elf.md
@@ -6,7 +6,7 @@
## Target maintainers
-* Henri Lunnikivi, <henri.lunnikivi@gmail.com>, [@hegza](https://github.com/hegza)
+[@hegza](https://github.com/hegza)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md b/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md
index 79455b0..09b42da 100644
--- a/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md
+++ b/src/doc/rustc/src/platform-support/riscv32im-risc0-zkvm-elf.md
@@ -6,9 +6,9 @@
## Target maintainers
-- Frank Laub, `frank@risczero.com`, https://github.com/flaub
-- Jeremy Bruestle, `jeremy@risczero.com`, https://github.com/jbruestle
-- Erik Kaneda, `erik@risczero.com`, https://github.com/SchmErik
+[@flaub](https://github.com/flaub)
+[@jbruestle](https://github.com/jbruestle)
+[@SchmErik](https://github.com/SchmErik)
## Background
diff --git a/src/doc/rustc/src/platform-support/riscv32imac-unknown-xous-elf.md b/src/doc/rustc/src/platform-support/riscv32imac-unknown-xous-elf.md
index 12928ed..cbfb2e2 100644
--- a/src/doc/rustc/src/platform-support/riscv32imac-unknown-xous-elf.md
+++ b/src/doc/rustc/src/platform-support/riscv32imac-unknown-xous-elf.md
@@ -6,7 +6,7 @@
## Target maintainers
-- [@xobs](https://github.com/xobs)
+[@xobs](https://github.com/xobs)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md
index 1ab867f..d62a65b 100644
--- a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md
+++ b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-gnu.md
@@ -7,10 +7,10 @@
## Target maintainers
-- Kito Cheng, <kito.cheng@gmail.com>, [@kito-cheng](https://github.com/kito-cheng)
-- Michael Maitland, <michaeltmaitland@gmail.com>, [@michaelmaitland](https://github.com/michaelmaitland)
-- Robin Randhawa, <robin.randhawa@sifive.com>, [@robin-randhawa-sifive](https://github.com/robin-randhawa-sifive)
-- Craig Topper, <craig.topper@sifive.com>, [@topperc](https://github.com/topperc)
+[@kito-cheng](https://github.com/kito-cheng)
+[@michaelmaitland](https://github.com/michaelmaitland)
+[@robin-randhawa-sifive](https://github.com/robin-randhawa-sifive)
+[@topperc](https://github.com/topperc)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md
index 5e6275d..2e88b5a 100644
--- a/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md
+++ b/src/doc/rustc/src/platform-support/riscv64gc-unknown-linux-musl.md
@@ -6,8 +6,8 @@
## Target maintainers
-- [@Amanieu](https://github.com/Amanieu)
-- [@kraj](https://github.com/kraj)
+[@Amanieu](https://github.com/Amanieu)
+[@kraj](https://github.com/kraj)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md b/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md
index 1aa2704..77bdabf 100644
--- a/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md
+++ b/src/doc/rustc/src/platform-support/s390x-unknown-linux-gnu.md
@@ -6,8 +6,8 @@
## Target maintainers
-- Ulrich Weigand, <ulrich.weigand@de.ibm.com>, [@uweigand](https://github.com/uweigand)
-- Josh Stone, <jistone@redhat.com>, [@cuviper](https://github.com/cuviper)
+[@uweigand](https://github.com/uweigand)
+[@cuviper](https://github.com/cuviper)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md b/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md
index 3c33462..c604b48 100644
--- a/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md
+++ b/src/doc/rustc/src/platform-support/s390x-unknown-linux-musl.md
@@ -6,7 +6,7 @@
## Target maintainers
-- Ulrich Weigand, <ulrich.weigand@de.ibm.com>, [@uweigand](https://github.com/uweigand)
+[@uweigand](https://github.com/uweigand)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/solaris.md b/src/doc/rustc/src/platform-support/solaris.md
index 1e0a241..0452d76 100644
--- a/src/doc/rustc/src/platform-support/solaris.md
+++ b/src/doc/rustc/src/platform-support/solaris.md
@@ -7,7 +7,7 @@
## Target maintainers
-- Petr Sumbera `sumbera@volny.cz`, https://github.com/psumbera
+[@psumbera](https://github.com/psumbera)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/sparc-unknown-none-elf.md b/src/doc/rustc/src/platform-support/sparc-unknown-none-elf.md
index c19b7d7..f341914 100644
--- a/src/doc/rustc/src/platform-support/sparc-unknown-none-elf.md
+++ b/src/doc/rustc/src/platform-support/sparc-unknown-none-elf.md
@@ -10,7 +10,7 @@
## Target maintainers
-- Jonathan Pallant, <jonathan.pallant@ferrous-systems.com>, https://ferrous-systems.com
+[@jonathanpallant](https://github.com/jonathanpallant)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/trusty.md b/src/doc/rustc/src/platform-support/trusty.md
index 73fcbbd..2aa5995 100644
--- a/src/doc/rustc/src/platform-support/trusty.md
+++ b/src/doc/rustc/src/platform-support/trusty.md
@@ -7,10 +7,8 @@
## Target maintainers
-- Nicole LeGare (@randomPoison)
-- Andrei Homescu (@ahomescu)
-- Chris Wailes (chriswailes@google.com)
-- As a fallback trusty-dev-team@google.com can be contacted
+[@randomPoison](https://github.com/randomPoison)
+[@ahomescu](https://github.com/ahomescu)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/unikraft-linux-musl.md b/src/doc/rustc/src/platform-support/unikraft-linux-musl.md
index b40e998..4a4080e 100644
--- a/src/doc/rustc/src/platform-support/unikraft-linux-musl.md
+++ b/src/doc/rustc/src/platform-support/unikraft-linux-musl.md
@@ -12,7 +12,7 @@
## Target maintainers
-- Martin Kröning ([@mkroening](https://github.com/mkroening))
+[@mkroening](https://github.com/mkroening)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/unknown-uefi.md b/src/doc/rustc/src/platform-support/unknown-uefi.md
index e9979cc..9587590 100644
--- a/src/doc/rustc/src/platform-support/unknown-uefi.md
+++ b/src/doc/rustc/src/platform-support/unknown-uefi.md
@@ -13,8 +13,8 @@
## Target maintainers
-- David Rheinsberg ([@dvdhrm](https://github.com/dvdhrm))
-- Nicholas Bishop ([@nicholasbishop](https://github.com/nicholasbishop))
+[@dvdhrm](https://github.com/dvdhrm)
+[@nicholasbishop](https://github.com/nicholasbishop)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/uwp-windows-msvc.md b/src/doc/rustc/src/platform-support/uwp-windows-msvc.md
index ce2ebb6..7ee6b41 100644
--- a/src/doc/rustc/src/platform-support/uwp-windows-msvc.md
+++ b/src/doc/rustc/src/platform-support/uwp-windows-msvc.md
@@ -6,7 +6,7 @@
## Target maintainers
-- [@bdbai](https://github.com/bdbai)
+[@bdbai](https://github.com/bdbai)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/vxworks.md b/src/doc/rustc/src/platform-support/vxworks.md
index a2b91f3..3fccee8 100644
--- a/src/doc/rustc/src/platform-support/vxworks.md
+++ b/src/doc/rustc/src/platform-support/vxworks.md
@@ -19,7 +19,7 @@
## Target maintainers
-- B I Mohammed Abbas ([@biabbas](https://github.com/biabbas))
+[@biabbas](https://github.com/biabbas)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md b/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md
index 6949c65..a9ff1eb 100644
--- a/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md
+++ b/src/doc/rustc/src/platform-support/wasm32-unknown-emscripten.md
@@ -36,8 +36,8 @@
## Target maintainers
-- Hood Chatham, https://github.com/hoodmane
-- Juniper Tyree, https://github.com/juntyr
+[@hoodmane](https://github.com/hoodmane)
+[@juntyr](https://github.com/juntyr)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
index 150f69e..b67f49c 100644
--- a/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
+++ b/src/doc/rustc/src/platform-support/wasm32-unknown-unknown.md
@@ -34,7 +34,7 @@
exhaustive, and there are more interested parties in this target. That being
said, those interested in maintaining this target are:
-- Alex Crichton, https://github.com/alexcrichton
+[@alexcrichton](https://github.com/alexcrichton)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/wasm32-wali-linux.md b/src/doc/rustc/src/platform-support/wasm32-wali-linux.md
index 0c46ea2..3213e2b 100644
--- a/src/doc/rustc/src/platform-support/wasm32-wali-linux.md
+++ b/src/doc/rustc/src/platform-support/wasm32-wali-linux.md
@@ -10,7 +10,7 @@
## Target maintainers
-- Arjun Ramesh [@arjunr2](https://github.com/arjunr2)
+[@arjunr2](https://github.com/arjunr2)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md
index af20b62..6c8bf21 100644
--- a/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md
+++ b/src/doc/rustc/src/platform-support/wasm32-wasip1-threads.md
@@ -18,10 +18,10 @@
## Target maintainers
-- Georgii Rylov, https://github.com/g0djan
-- Alex Crichton, https://github.com/alexcrichton
-- Andrew Brown, https://github.com/abrown
-- Marcin Kolny, https://github.com/loganek
+[@g0djan](https://github.com/g0djan)
+[@alexcrichton](https://github.com/alexcrichton)
+[@abrown](https://github.com/abrown)
+[@loganek](https://github.com/loganek)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip1.md b/src/doc/rustc/src/platform-support/wasm32-wasip1.md
index e5e8d55..4f065a5 100644
--- a/src/doc/rustc/src/platform-support/wasm32-wasip1.md
+++ b/src/doc/rustc/src/platform-support/wasm32-wasip1.md
@@ -43,7 +43,7 @@
said since when this document was last updated those interested in maintaining
this target are:
-- Alex Crichton, https://github.com/alexcrichton
+[@alexcrichton](https://github.com/alexcrichton)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/wasm32-wasip2.md b/src/doc/rustc/src/platform-support/wasm32-wasip2.md
index 40049ec..dea33e6 100644
--- a/src/doc/rustc/src/platform-support/wasm32-wasip2.md
+++ b/src/doc/rustc/src/platform-support/wasm32-wasip2.md
@@ -13,8 +13,8 @@
## Target maintainers
-- Alex Crichton, https://github.com/alexcrichton
-- Ryan Levick, https://github.com/rylev
+[@alexcrichton](https://github.com/alexcrichton)
+[@rylev](https://github.com/rylev)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/wasm32v1-none.md b/src/doc/rustc/src/platform-support/wasm32v1-none.md
index 46f89c2..51b00de 100644
--- a/src/doc/rustc/src/platform-support/wasm32v1-none.md
+++ b/src/doc/rustc/src/platform-support/wasm32v1-none.md
@@ -19,8 +19,8 @@
## Target maintainers
-- Alex Crichton, https://github.com/alexcrichton
-- Graydon Hoare, https://github.com/graydon
+[@alexcrichton](https://github.com/alexcrichton)
+[@graydon](https://github.com/graydon)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md
index 157fff4..cc21da1 100644
--- a/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md
+++ b/src/doc/rustc/src/platform-support/wasm64-unknown-unknown.md
@@ -9,7 +9,7 @@
## Target maintainers
-- Alex Crichton, https://github.com/alexcrichton
+[@alexcrichton](https://github.com/alexcrichton)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/win7-windows-gnu.md b/src/doc/rustc/src/platform-support/win7-windows-gnu.md
index 3a819b0..1311117 100644
--- a/src/doc/rustc/src/platform-support/win7-windows-gnu.md
+++ b/src/doc/rustc/src/platform-support/win7-windows-gnu.md
@@ -10,7 +10,7 @@
## Target maintainers
-- @tbu-
+[@tbu-](https://github.com/tbu-)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/win7-windows-msvc.md b/src/doc/rustc/src/platform-support/win7-windows-msvc.md
index cbbb44b..56fe0f6 100644
--- a/src/doc/rustc/src/platform-support/win7-windows-msvc.md
+++ b/src/doc/rustc/src/platform-support/win7-windows-msvc.md
@@ -10,7 +10,7 @@
## Target maintainers
-- @roblabla
+[@roblabla](https://github.com/roblabla)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/windows-gnullvm.md b/src/doc/rustc/src/platform-support/windows-gnullvm.md
index 1ff559f..f3dc731 100644
--- a/src/doc/rustc/src/platform-support/windows-gnullvm.md
+++ b/src/doc/rustc/src/platform-support/windows-gnullvm.md
@@ -11,8 +11,8 @@
## Target maintainers
-- [@mati865](https://github.com/mati865)
-- [@thomcc](https://github.com/thomcc)
+[@mati865](https://github.com/mati865)
+[@thomcc](https://github.com/thomcc)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md b/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md
index 33e1c44..e52ad1c 100644
--- a/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md
+++ b/src/doc/rustc/src/platform-support/x86_64-fortanix-unknown-sgx.md
@@ -9,11 +9,13 @@
## Target maintainers
-The [EDP team](mailto:edp.maintainers@fortanix.com) at Fortanix.
+[@jethrogb](https://github.com/jethrogb)
+[@raoulstrackx](https://github.com/raoulstrackx)
+[@mzohreva](https://github.com/mzohreva)
-- Jethro Beekman [@jethrogb](https://github.com/jethrogb)
-- Raoul Strackx [@raoulstrackx](https://github.com/raoulstrackx)
-- Mohsen Zohrevandi [@mzohreva](https://github.com/mzohreva)
+Further contacts:
+
+The [EDP team](mailto:edp.maintainers@fortanix.com) at Fortanix.
## Requirements
diff --git a/src/doc/rustc/src/platform-support/x86_64-pc-cygwin.md b/src/doc/rustc/src/platform-support/x86_64-pc-cygwin.md
index a8fc4f1..60aaa37 100644
--- a/src/doc/rustc/src/platform-support/x86_64-pc-cygwin.md
+++ b/src/doc/rustc/src/platform-support/x86_64-pc-cygwin.md
@@ -10,7 +10,7 @@
## Target maintainers
-- [Berrysoft](https://github.com/Berrysoft)
+[@Berrysoft](https://github.com/Berrysoft)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/x86_64-unknown-linux-none.md b/src/doc/rustc/src/platform-support/x86_64-unknown-linux-none.md
index 965d6ae..ec16c18 100644
--- a/src/doc/rustc/src/platform-support/x86_64-unknown-linux-none.md
+++ b/src/doc/rustc/src/platform-support/x86_64-unknown-linux-none.md
@@ -6,7 +6,7 @@
## Target maintainers
-- [morr0ne](https://github.com/morr0ne/)
+[@morr0ne](https://github.com/morr0ne)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/x86_64-unknown-none.md b/src/doc/rustc/src/platform-support/x86_64-unknown-none.md
index 3b8aae3..c8db5dc 100644
--- a/src/doc/rustc/src/platform-support/x86_64-unknown-none.md
+++ b/src/doc/rustc/src/platform-support/x86_64-unknown-none.md
@@ -6,8 +6,8 @@
## Target maintainers
-- Harald Hoyer `harald@profian.com`, https://github.com/haraldh
-- Mike Leany, https://github.com/mikeleany
+[@haraldh](https://github.com/haraldh)
+[@mikeleany](https://github.com/mikeleany)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/x86_64h-apple-darwin.md b/src/doc/rustc/src/platform-support/x86_64h-apple-darwin.md
index 545fffb..4ffbe4b 100644
--- a/src/doc/rustc/src/platform-support/x86_64h-apple-darwin.md
+++ b/src/doc/rustc/src/platform-support/x86_64h-apple-darwin.md
@@ -8,7 +8,7 @@
## Target maintainers
-- Thom Chiovoloni `thom@shift.click` <https://github.com/thomcc>
+[@thomcc](https://github.com/thomcc)
## Requirements
diff --git a/src/doc/rustc/src/platform-support/xtensa.md b/src/doc/rustc/src/platform-support/xtensa.md
index 332b8ee..1189d27 100644
--- a/src/doc/rustc/src/platform-support/xtensa.md
+++ b/src/doc/rustc/src/platform-support/xtensa.md
@@ -6,8 +6,8 @@
## Target maintainers
-- Scott Mabin [@MabezDev](https://github.com/MabezDev)
-- Sergio Gasquez [@SergioGasquez](https://github.com/SergioGasquez)
+[@MabezDev](https://github.com/MabezDev)
+[@SergioGasquez](https://github.com/SergioGasquez)
## Requirements
diff --git a/src/doc/unstable-book/src/compiler-flags/allow-features.md b/src/doc/unstable-book/src/compiler-flags/allow-features.md
new file mode 100644
index 0000000..84fa465
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/allow-features.md
@@ -0,0 +1,14 @@
+# `allow-features`
+
+This feature is perma-unstable and has no tracking issue.
+
+----
+
+This flag allows limiting the features which can be enabled with `#![feature(...)]` attributes.
+By default, all features are allowed on nightly and no features are allowed on stable or beta (but see [`RUSTC_BOOTSTRAP`]).
+
+Features are comma-separated, for example `-Z allow-features=ffi_pure,f16`.
+If the flag is present, any feature listed will be allowed and any feature not listed will be disallowed.
+Any unrecognized feature is ignored.
+
+[`RUSTC_BOOTSTRAP`]: ./rustc-bootstrap.html
diff --git a/src/doc/unstable-book/src/compiler-flags/dwarf-version.md b/src/doc/unstable-book/src/compiler-flags/dwarf-version.md
deleted file mode 100644
index e88799d..0000000
--- a/src/doc/unstable-book/src/compiler-flags/dwarf-version.md
+++ /dev/null
@@ -1,13 +0,0 @@
-## `dwarf-version`
-
-The tracking issue for this feature is: <https://github.com/rust-lang/rust/issues/103057>
-
-----------------------------
-
-This option controls the version of DWARF that the compiler emits, on platforms
-that use DWARF to encode debug information. It takes one of the following
-values:
-
-* `2`: DWARF version 2 (the default on certain platforms, like macOS).
-* `4`: DWARF version 4 (the default on certain platforms, like Linux).
-* `5`: DWARF version 5.
diff --git a/src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md b/src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md
new file mode 100644
index 0000000..6895f23
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/rustc-bootstrap.md
@@ -0,0 +1,56 @@
+# `RUSTC_BOOTSTRAP`
+
+This feature is perma-unstable and has no tracking issue.
+
+----
+
+The `RUSTC_BOOTSTRAP` environment variable tells rustc to act as if it is a nightly compiler;
+in particular, it allows `#![feature(...)]` attributes and `-Z` flags even on the stable release channel.
+
+Setting `RUSTC_BOOTSTRAP=1` instructs rustc to enable this for all crates.
+Setting `RUSTC_BOOTSTRAP=crate_name` instructs rustc to only apply this to crates named `crate_name`.
+Setting `RUSTC_BOOTSTRAP=-1` instructs rustc to act as if it is a stable compiler, even on the nightly release channel.
+Cargo disallows setting `cargo::rustc-env=RUSTC_BOOTSTRAP` in build scripts.
+Build systems can limit the features they enable with [`-Z allow-features=feature1,feature2`][Z-allow-features].
+Crates can fully opt out of unstable features by using [`#![forbid(unstable_features)]`][unstable-features] at the crate root (or any other way of enabling lints, such as `-F unstable-features`).
+
+[Z-allow-features]: ./allow-features.html
+[unstable-features]: ../../rustc/lints/listing/allowed-by-default.html#unstable-features
+
+## Why does this environment variable exist?
+
+`RUSTC_BOOTSTRAP`, as the name suggests, is used for bootstrapping the compiler from an earlier version.
+In particular, nightly is built with beta, and beta is built with stable.
+Since the standard library and compiler both use unstable features, `RUSTC_BOOTSTRAP` is required so that we can use the previous version to build them.
+
+## Why is this environment variable so easy to use for people not in the rust project?
+
+Originally, `RUSTC_BOOTSTRAP` required passing in a hash of the previous compiler version, to discourage using it for any purpose other than bootstrapping.
+That constraint was later relaxed; see <https://github.com/rust-lang/rust/issues/36548> for the discussion that happened at that time.
+
+People have at various times proposed re-adding the technical constraints.
+However, doing so is extremely disruptive for several major projects that we very much want to keep using the latest stable toolchain version, such as Firefox, Rust for Linux, and Chromium.
+We continue to allow `RUSTC_BOOTSTRAP` until we can come up with an alternative that does not disrupt our largest constituents.
+
+## Stability policy
+
+Despite being usable on stable, this is an unstable feature.
+Like any other unstable feature, we reserve the right to change or remove this feature in the future, as well as any other unstable feature that it enables.
+Using this feature opts you out of the normal stability/backwards compatibility guarantee of stable.
+
+Although we do not take technical measures to prevent it from being used, we strongly discourage using this feature.
+If at all possible, please contribute to stabilizing the features you care about instead of bypassing the Rust project's stability policy.
+
+For library crates, we especially discourage the use of this feature.
+The crates depending on you do not know that you use this feature, have little recourse if it breaks, and can be used in contexts that are hard to predict.
+
+For libraries that do use this feature, please document the versions you support (including a *maximum* as well as minimum version), and a mechanism to disable it.
+If you do not have a mechanism to disable the use of `RUSTC_BOOTSTRAP`, consider removing its use altogether, such that people can only use your library if they are already using a nightly toolchain.
+This leaves the choice of whether to opt-out of Rust's stability guarantees up to the end user building their code.
+
+## History
+
+- [Allowed without a hash](https://github.com/rust-lang/rust/pull/37265) ([discussion](https://github.com/rust-lang/rust/issues/36548))
+- [Extended to crate names](https://github.com/rust-lang/rust/pull/77802) ([discussion](https://github.com/rust-lang/cargo/issues/7088))
+- [Disallowed for build scripts](https://github.com/rust-lang/cargo/pull/9181) ([discussion](https://github.com/rust-lang/compiler-team/issues/350))
+- [Extended to emulate stable](https://github.com/rust-lang/rust/pull/132993) ([discussion](https://github.com/rust-lang/rust/issues/123404))
diff --git a/src/doc/unstable-book/src/compiler-flags/rustc-override-version-string.md b/src/doc/unstable-book/src/compiler-flags/rustc-override-version-string.md
new file mode 100644
index 0000000..3d867b5
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/rustc-override-version-string.md
@@ -0,0 +1,39 @@
+# `RUSTC_OVERRIDE_VERSION_STRING`
+
+This feature is perma-unstable and has no tracking issue.
+
+----
+
+The `RUSTC_OVERRIDE_VERSION_STRING` environment variable overrides the version reported by `rustc --version`. For example:
+
+```console
+$ rustc --version
+rustc 1.87.0-nightly (43f0014ef 2025-03-25)
+$ env RUSTC_OVERRIDE_VERSION_STRING=1.81.0-nightly rustc --version
+rustc 1.81.0-nightly
+```
+
+Note that the version string is completely overwritten; i.e. rustc discards commit hash and commit date information unless it is explicitly included in the environment variable. The string only applies to the "release" part of the version; for example:
+```console
+$ RUSTC_OVERRIDE_VERSION_STRING="1.81.0-nightly (aaaaaaaaa 2025-03-22)" rustc -vV
+rustc 1.81.0-nightly (aaaaaaaaa 2025-03-22)
+binary: rustc
+commit-hash: 43f0014ef0f242418674f49052ed39b70f73bc1c
+commit-date: 2025-03-25
+host: x86_64-unknown-linux-gnu
+release: 1.81.0-nightly (aaaaaaaaa 2025-03-22)
+LLVM version: 20.1.1
+```
+
+Note here that `commit-hash` and `commit-date` do not match the values in the string, and `release` includes the fake hash and date.
+
+This variable has no effect on whether or not unstable features are allowed to be used. It only affects the output of `--version`.
+
+## Why does this environment variable exist?
+
+Various library crates have incomplete or incorrect feature detection.
+This environment variable allows bisecting crates that do incorrect detection with `version_check::supports_feature`.
+
+This is not intended to be used for any other case (and, except for bisection, is not particularly useful).
+
+See <https://github.com/rust-lang/rust/pull/124339> for further discussion.
diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
index 4679acf..2f9d4d2 100644
--- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md
+++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md
@@ -245,36 +245,31 @@
## Example 1: Redirecting control flow using an indirect branch/call to an invalid destination
```rust,ignore (making doc tests pass cross-platform is hard)
-#![feature(naked_functions)]
-
-use std::arch::asm;
+use std::arch::naked_asm;
use std::mem;
fn add_one(x: i32) -> i32 {
x + 1
}
-#[naked]
+#[unsafe(naked)]
pub extern "C" fn add_two(x: i32) {
// x + 2 preceded by a landing pad/nop block
- unsafe {
- asm!(
- "
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- nop
- lea eax, [rdi+2]
- ret
- ",
- options(noreturn)
- );
- }
+ naked_asm!(
+ "
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ lea eax, [rdi+2]
+ ret
+ "
+ );
}
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
diff --git a/src/doc/unstable-book/src/language-features/box-patterns.md b/src/doc/unstable-book/src/language-features/box-patterns.md
index a1ac096..c8a15b8 100644
--- a/src/doc/unstable-book/src/language-features/box-patterns.md
+++ b/src/doc/unstable-book/src/language-features/box-patterns.md
@@ -6,6 +6,8 @@
------------------------
+> **Note**: This feature will be superseded by [`deref_patterns`] in the future.
+
Box patterns let you match on `Box<T>`s:
@@ -28,3 +30,5 @@
}
}
```
+
+[`deref_patterns`]: ./deref-patterns.md
diff --git a/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md b/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md
deleted file mode 100644
index ad795ff..0000000
--- a/src/doc/unstable-book/src/language-features/cfg-boolean-literals.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# `cfg_boolean_literals`
-
-The tracking issue for this feature is: [#131204]
-
-[#131204]: https://github.com/rust-lang/rust/issues/131204
-
-------------------------
-
-The `cfg_boolean_literals` feature makes it possible to use the `true`/`false`
-literal as cfg predicate. They always evaluate to true/false respectively.
-
-## Examples
-
-```rust
-#![feature(cfg_boolean_literals)]
-
-#[cfg(true)]
-const A: i32 = 5;
-
-#[cfg(all(false))]
-const A: i32 = 58 * 89;
-```
diff --git a/src/doc/unstable-book/src/language-features/deref-patterns.md b/src/doc/unstable-book/src/language-features/deref-patterns.md
new file mode 100644
index 0000000..d0102a6
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/deref-patterns.md
@@ -0,0 +1,57 @@
+# `deref_patterns`
+
+The tracking issue for this feature is: [#87121]
+
+[#87121]: https://github.com/rust-lang/rust/issues/87121
+
+------------------------
+
+> **Note**: This feature is incomplete. In the future, it is meant to supersede
+> [`box_patterns`](./box-patterns.md) and [`string_deref_patterns`](./string-deref-patterns.md).
+
+This feature permits pattern matching on [smart pointers in the standard library] through their
+`Deref` target types, either implicitly or with explicit `deref!(_)` patterns (the syntax of which
+is currently a placeholder).
+
+```rust
+#![feature(deref_patterns)]
+#![allow(incomplete_features)]
+
+let mut v = vec![Box::new(Some(0))];
+
+// Implicit dereferences are inserted when a pattern can match against the
+// result of repeatedly dereferencing but can't match against a smart
+// pointer itself. This works alongside match ergonomics for references.
+if let [Some(x)] = &mut v {
+ *x += 1;
+}
+
+// Explicit `deref!(_)` patterns may instead be used when finer control is
+// needed, e.g. to dereference only a single smart pointer, or to bind the
+// the result of dereferencing to a variable.
+if let deref!([deref!(opt_x @ Some(1))]) = &mut v {
+ opt_x.as_mut().map(|x| *x += 1);
+}
+
+assert_eq!(v, [Box::new(Some(2))]);
+```
+
+Without this feature, it may be necessary to introduce temporaries to represent dereferenced places
+when matching on nested structures:
+
+```rust
+let mut v = vec![Box::new(Some(0))];
+if let [b] = &mut *v {
+ if let Some(x) = &mut **b {
+ *x += 1;
+ }
+}
+if let [b] = &mut *v {
+ if let opt_x @ Some(1) = &mut **b {
+ opt_x.as_mut().map(|x| *x += 1);
+ }
+}
+assert_eq!(v, [Box::new(Some(2))]);
+```
+
+[smart pointers in the standard library]: https://doc.rust-lang.org/std/ops/trait.DerefPure.html#implementors
diff --git a/src/doc/unstable-book/src/language-features/explicit-extern-abis.md b/src/doc/unstable-book/src/language-features/explicit-extern-abis.md
new file mode 100644
index 0000000..ba62246
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/explicit-extern-abis.md
@@ -0,0 +1,23 @@
+# `explicit_extern_abis`
+
+The tracking issue for this feature is: #134986
+
+------
+
+Disallow `extern` without an explicit ABI. We should write `extern "C"`
+(or another ABI) instead of just `extern`.
+
+By making the ABI explicit, it becomes much clearer that "C" is just one of the
+possible choices, rather than the "standard" way for external functions.
+Removing the default makes it easier to add a new ABI on equal footing as "C".
+
+```rust,editionfuture,compile_fail
+#![feature(explicit_extern_abis)]
+
+extern fn function1() {} // ERROR `extern` declarations without an explicit ABI
+ // are disallowed
+
+extern "C" fn function2() {} // compiles
+
+extern "aapcs" fn function3() {} // compiles
+```
diff --git a/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md b/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md
new file mode 100644
index 0000000..b6dbdb1
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/macro-metavar-expr-concat.md
@@ -0,0 +1,133 @@
+# `macro_metavar_expr_concat`
+
+The tracking issue for this feature is: [#124225]
+
+------------------------
+
+In stable Rust, there is no way to create new identifiers by joining identifiers to literals or other identifiers without using procedural macros such as [`paste`].
+ `#![feature(macro_metavar_expr_concat)]` introduces a way to do this, using the concat metavariable expression.
+
+> This feature uses the syntax from [`macro_metavar_expr`] but is otherwise
+> independent. It replaces the old unstable feature [`concat_idents`].
+
+> This is an experimental feature; it and its syntax will require a RFC before stabilization.
+
+
+### Overview
+
+`#![feature(macro_metavar_expr_concat)]` provides the `concat` metavariable expression for creating new identifiers:
+
+```rust
+#![feature(macro_metavar_expr_concat)]
+
+macro_rules! create_some_structs {
+ ($name:ident) => {
+ pub struct ${ concat(First, $name) };
+ pub struct ${ concat(Second, $name) };
+ pub struct ${ concat(Third, $name) };
+ }
+}
+
+create_some_structs!(Thing);
+```
+
+This macro invocation expands to:
+
+```rust
+pub struct FirstThing;
+pub struct SecondThing;
+pub struct ThirdThing;
+```
+
+### Syntax
+
+This feature builds upon the metavariable expression syntax `${ .. }` as specified in [RFC 3086] ([`macro_metavar_expr`]).
+ `concat` is available like `${ concat(items) }`, where `items` is a comma separated sequence of idents and/or literals.
+
+### Examples
+
+#### Create a function or method with a concatenated name
+
+```rust
+#![feature(macro_metavar_expr_concat)]
+
+macro_rules! make_getter {
+ ($name:ident, $field: ident, $ret:ty) => {
+ impl $name {
+ pub fn ${ concat(get_, $field) }(&self) -> &$ret {
+ &self.$field
+ }
+ }
+ }
+}
+
+pub struct Thing {
+ description: String,
+}
+
+make_getter!(Thing, description, String);
+```
+
+This expands to:
+
+```rust
+pub struct Thing {
+ description: String,
+}
+
+impl Thing {
+ pub fn get_description(&self) -> &String {
+ &self.description
+ }
+}
+```
+
+#### Create names for macro generated tests
+
+```rust
+#![feature(macro_metavar_expr_concat)]
+
+macro_rules! test_math {
+ ($integer:ident) => {
+ #[test]
+ fn ${ concat(test_, $integer, _, addition) } () {
+ let a: $integer = 73;
+ let b: $integer = 42;
+ assert_eq!(a + b, 115)
+ }
+
+ #[test]
+ fn ${ concat(test_, $integer, _, subtraction) } () {
+ let a: $integer = 73;
+ let b: $integer = 42;
+ assert_eq!(a - b, 31)
+ }
+ }
+}
+
+test_math!(i32);
+test_math!(u64);
+test_math!(u128);
+```
+
+Running this returns the following output:
+
+```text
+running 6 tests
+test test_i32_subtraction ... ok
+test test_i32_addition ... ok
+test test_u128_addition ... ok
+test test_u128_subtraction ... ok
+test test_u64_addition ... ok
+test test_u64_subtraction ... ok
+
+test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
+```
+
+[`paste`]: https://crates.io/crates/paste
+[RFC 3086]: https://rust-lang.github.io/rfcs/3086-macro-metavar-expr.html
+[`concat_idents!`]: https://doc.rust-lang.org/nightly/std/macro.concat_idents.html
+[`macro_metavar_expr`]: ../language-features/macro-metavar-expr.md
+[`concat_idents`]: ../library-features/concat-idents.md
+[#124225]: https://github.com/rust-lang/rust/issues/124225
+[declarative macros]: https://doc.rust-lang.org/stable/reference/macros-by-example.html
diff --git a/src/doc/unstable-book/src/language-features/macro-metavar-expr.md b/src/doc/unstable-book/src/language-features/macro-metavar-expr.md
new file mode 100644
index 0000000..7ce64c1
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/macro-metavar-expr.md
@@ -0,0 +1,10 @@
+# `macro_metavar_expr`
+
+The tracking issue for this feature is: [#83527]
+
+------------------------
+
+> This feature is not to be confused with [`macro_metavar_expr_concat`].
+
+[`macro_metavar_expr_concat`]: ./macro-metavar-expr-concat.md
+[#83527]: https://github.com/rust-lang/rust/issues/83527
diff --git a/src/doc/unstable-book/src/language-features/string-deref-patterns.md b/src/doc/unstable-book/src/language-features/string-deref-patterns.md
index 3723830..366bb15 100644
--- a/src/doc/unstable-book/src/language-features/string-deref-patterns.md
+++ b/src/doc/unstable-book/src/language-features/string-deref-patterns.md
@@ -6,6 +6,8 @@
------------------------
+> **Note**: This feature will be superseded by [`deref_patterns`] in the future.
+
This feature permits pattern matching `String` to `&str` through [its `Deref` implementation].
```rust
@@ -42,4 +44,5 @@
}
```
+[`deref_patterns`]: ./deref-patterns.md
[its `Deref` implementation]: https://doc.rust-lang.org/std/string/struct.String.html#impl-Deref-for-String
diff --git a/src/doc/unstable-book/src/library-features/concat-idents.md b/src/doc/unstable-book/src/library-features/concat-idents.md
index 73f6cfa..4366172 100644
--- a/src/doc/unstable-book/src/library-features/concat-idents.md
+++ b/src/doc/unstable-book/src/library-features/concat-idents.md
@@ -6,6 +6,8 @@
------------------------
+> This feature is expected to be superseded by [`macro_metavar_expr_concat`](../language-features/macro-metavar-expr-concat.md).
+
The `concat_idents` feature adds a macro for concatenating multiple identifiers
into one identifier.
diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis
index 8a441cf..8fe87a9 100644
--- a/src/etc/natvis/libcore.natvis
+++ b/src/etc/natvis/libcore.natvis
@@ -69,9 +69,9 @@
</Type>
<Type Name="core::pin::Pin<*>">
- <DisplayString>Pin({(void*)__pointer}: {__pointer})</DisplayString>
+ <DisplayString>Pin({(void*)pointer}: {pointer})</DisplayString>
<Expand>
- <ExpandedItem>__pointer</ExpandedItem>
+ <ExpandedItem>pointer</ExpandedItem>
</Expand>
</Type>
diff --git a/src/etc/rust_analyzer_eglot.el b/src/etc/rust_analyzer_eglot.el
index 6b40371..90bd38a 100644
--- a/src/etc/rust_analyzer_eglot.el
+++ b/src/etc/rust_analyzer_eglot.el
@@ -8,10 +8,11 @@
"check"
"--json-output"])
:linkedProjects ["Cargo.toml"
- "src/bootstrap/Cargo.toml"
- "src/tools/rust-analyzer/Cargo.toml"
"compiler/rustc_codegen_cranelift/Cargo.toml"
- "compiler/rustc_codegen_gcc/Cargo.toml"]
+ "compiler/rustc_codegen_gcc/Cargo.toml"
+ "library/Cargo.toml"
+ "src/bootstrap/Cargo.toml"
+ "src/tools/rust-analyzer/Cargo.toml"]
:rustfmt ( :overrideCommand ["build/host/rustfmt/bin/rustfmt"
"--edition=2021"])
:procMacro ( :server "build/host/stage0/libexec/rust-analyzer-proc-macro-srv"
diff --git a/src/etc/rust_analyzer_settings.json b/src/etc/rust_analyzer_settings.json
index da7d326..5ce886a 100644
--- a/src/etc/rust_analyzer_settings.json
+++ b/src/etc/rust_analyzer_settings.json
@@ -9,11 +9,11 @@
],
"rust-analyzer.linkedProjects": [
"Cargo.toml",
+ "compiler/rustc_codegen_cranelift/Cargo.toml",
+ "compiler/rustc_codegen_gcc/Cargo.toml",
"library/Cargo.toml",
"src/bootstrap/Cargo.toml",
- "src/tools/rust-analyzer/Cargo.toml",
- "compiler/rustc_codegen_cranelift/Cargo.toml",
- "compiler/rustc_codegen_gcc/Cargo.toml"
+ "src/tools/rust-analyzer/Cargo.toml"
],
"rust-analyzer.rustfmt.overrideCommand": [
"${workspaceFolder}/build/host/rustfmt/bin/rustfmt",
@@ -36,5 +36,10 @@
},
"rust-analyzer.server.extraEnv": {
"RUSTUP_TOOLCHAIN": "nightly"
+ },
+ "files.associations": {
+ "*.fixed": "rust",
+ "*.pp": "rust",
+ "*.mir": "rust"
}
}
diff --git a/src/etc/rust_analyzer_zed.json b/src/etc/rust_analyzer_zed.json
index abc6ddb..3461ff8 100644
--- a/src/etc/rust_analyzer_zed.json
+++ b/src/etc/rust_analyzer_zed.json
@@ -21,15 +21,15 @@
},
"linkedProjects": [
"Cargo.toml",
+ "compiler/rustc_codegen_cranelift/Cargo.toml",
+ "compiler/rustc_codegen_gcc/Cargo.toml",
"library/Cargo.toml",
"src/bootstrap/Cargo.toml",
- "src/tools/rust-analyzer/Cargo.toml",
- "compiler/rustc_codegen_cranelift/Cargo.toml",
- "compiler/rustc_codegen_gcc/Cargo.toml"
+ "src/tools/rust-analyzer/Cargo.toml"
],
"procMacro": {
- "enable": true,
- "server": "${workspaceFolder}/build/host/stage0/libexec/rust-analyzer-proc-macro-srv"
+ "enable": true,
+ "server": "${workspaceFolder}/build/host/stage0/libexec/rust-analyzer-proc-macro-srv"
},
"rustc": {
"source": "./Cargo.toml"
@@ -47,5 +47,8 @@
}
}
}
+ },
+ "file_types": {
+ "Rust": ["fixed", "pp", "mir"]
}
}
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 3a2b697..55a116a 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -67,9 +67,13 @@ pub(crate) fn try_inline(
record_extern_fqn(cx, did, ItemType::Trait);
cx.with_param_env(did, |cx| {
build_impls(cx, did, attrs_without_docs, &mut ret);
- clean::TraitItem(Box::new(build_external_trait(cx, did)))
+ clean::TraitItem(Box::new(build_trait(cx, did)))
})
}
+ Res::Def(DefKind::TraitAlias, did) => {
+ record_extern_fqn(cx, did, ItemType::TraitAlias);
+ cx.with_param_env(did, |cx| clean::TraitAliasItem(build_trait_alias(cx, did)))
+ }
Res::Def(DefKind::Fn, did) => {
record_extern_fqn(cx, did, ItemType::Function);
cx.with_param_env(did, |cx| {
@@ -251,7 +255,7 @@ pub(crate) fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemT
}
}
-pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait {
+pub(crate) fn build_trait(cx: &mut DocContext<'_>, did: DefId) -> clean::Trait {
let trait_items = cx
.tcx
.associated_items(did)
@@ -263,11 +267,18 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean
let predicates = cx.tcx.predicates_of(did);
let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
let generics = filter_non_trait_generics(did, generics);
- let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
+ let (generics, supertrait_bounds) = separate_self_bounds(generics);
clean::Trait { def_id: did, generics, items: trait_items, bounds: supertrait_bounds }
}
-pub(crate) fn build_function(cx: &mut DocContext<'_>, def_id: DefId) -> Box<clean::Function> {
+fn build_trait_alias(cx: &mut DocContext<'_>, did: DefId) -> clean::TraitAlias {
+ let predicates = cx.tcx.predicates_of(did);
+ let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
+ let (generics, bounds) = separate_self_bounds(generics);
+ clean::TraitAlias { generics, bounds }
+}
+
+pub(super) fn build_function(cx: &mut DocContext<'_>, def_id: DefId) -> Box<clean::Function> {
let sig = cx.tcx.fn_sig(def_id).instantiate_identity();
// The generics need to be cleaned before the signature.
let mut generics =
@@ -490,17 +501,17 @@ pub(crate) fn build_impl(
return true;
}
if let Some(associated_trait) = associated_trait {
- let assoc_kind = match item.kind {
- hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
- hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
- hir::ImplItemKind::Type(..) => ty::AssocKind::Type,
+ let assoc_tag = match item.kind {
+ hir::ImplItemKind::Const(..) => ty::AssocTag::Const,
+ hir::ImplItemKind::Fn(..) => ty::AssocTag::Fn,
+ hir::ImplItemKind::Type(..) => ty::AssocTag::Type,
};
let trait_item = tcx
.associated_items(associated_trait.def_id)
.find_by_ident_and_kind(
tcx,
item.ident,
- assoc_kind,
+ assoc_tag,
associated_trait.def_id,
)
.unwrap(); // SAFETY: For all impl items there exists trait item that has the same name.
@@ -527,7 +538,7 @@ pub(crate) fn build_impl(
.find_by_ident_and_kind(
tcx,
item.ident(tcx),
- item.kind,
+ item.as_tag(),
associated_trait.def_id,
)
.unwrap(); // corresponding associated item has to exist
@@ -788,12 +799,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean:
g
}
-/// Supertrait bounds for a trait are also listed in the generics coming from
-/// the metadata for a crate, so we want to separate those out and create a new
-/// list of explicit supertrait bounds to render nicely.
-fn separate_supertrait_bounds(
- mut g: clean::Generics,
-) -> (clean::Generics, Vec<clean::GenericBound>) {
+fn separate_self_bounds(mut g: clean::Generics) -> (clean::Generics, Vec<clean::GenericBound>) {
let mut ty_bounds = Vec::new();
g.where_predicates.retain(|pred| match *pred {
clean::WherePredicate::BoundPredicate { ty: clean::SelfTy, ref bounds, .. } => {
@@ -806,22 +812,17 @@ fn separate_supertrait_bounds(
}
pub(crate) fn record_extern_trait(cx: &mut DocContext<'_>, did: DefId) {
- if did.is_local() {
+ if did.is_local()
+ || cx.external_traits.contains_key(&did)
+ || cx.active_extern_traits.contains(&did)
+ {
return;
}
- {
- if cx.external_traits.contains_key(&did) || cx.active_extern_traits.contains(&did) {
- return;
- }
- }
-
- {
- cx.active_extern_traits.insert(did);
- }
+ cx.active_extern_traits.insert(did);
debug!("record_extern_trait: {did:?}");
- let trait_ = build_external_trait(cx, did);
+ let trait_ = build_trait(cx, did);
cx.external_traits.insert(did, trait_);
cx.active_extern_traits.remove(&did);
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 45a9157..6ecb67c 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -117,7 +117,14 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
hir::ItemKind::Use(path, kind) => {
let hir::UsePath { segments, span, .. } = *path;
let path = hir::Path { segments, res: *res, span };
- clean_use_statement_inner(import, name, &path, kind, cx, &mut Default::default())
+ clean_use_statement_inner(
+ import,
+ Some(name),
+ &path,
+ kind,
+ cx,
+ &mut Default::default(),
+ )
}
_ => unreachable!(),
}
@@ -125,8 +132,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<
items.extend(doc.items.values().flat_map(|(item, renamed, _)| {
// Now we actually lower the imports, skipping everything else.
if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
- let name = renamed.unwrap_or(kw::Empty); // using kw::Empty is a bit of a hack
- clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted)
+ clean_use_statement(item, *renamed, path, hir::UseKind::Glob, cx, &mut inserted)
} else {
// skip everything else
Vec::new()
@@ -521,7 +527,7 @@ fn projection_to_path_segment<'tcx>(
let item = cx.tcx.associated_item(def_id);
let generics = cx.tcx.generics_of(def_id);
PathSegment {
- name: item.name,
+ name: item.name(),
args: GenericArgs::AngleBracketed {
args: clean_middle_generic_args(
cx,
@@ -1046,7 +1052,7 @@ fn clean_fn_or_proc_macro<'tcx>(
match macro_kind {
Some(kind) => clean_proc_macro(item, name, kind, cx),
None => {
- let mut func = clean_function(cx, sig, generics, FunctionArgs::Body(body_id));
+ let mut func = clean_function(cx, sig, generics, ParamsSrc::Body(body_id));
clean_fn_decl_legacy_const_generics(&mut func, attrs);
FunctionItem(func)
}
@@ -1065,17 +1071,12 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[hir::Attrib
for (pos, literal) in meta_item_list.iter().filter_map(|meta| meta.lit()).enumerate() {
match literal.kind {
ast::LitKind::Int(a, _) => {
- let param = func.generics.params.remove(0);
- if let GenericParamDef {
- name,
- kind: GenericParamDefKind::Const { ty, .. },
- ..
- } = param
- {
- func.decl
- .inputs
- .values
- .insert(a.get() as _, Argument { name, type_: *ty, is_const: true });
+ let GenericParamDef { name, kind, .. } = func.generics.params.remove(0);
+ if let GenericParamDefKind::Const { ty, .. } = kind {
+ func.decl.inputs.insert(
+ a.get() as _,
+ Parameter { name: Some(name), type_: *ty, is_const: true },
+ );
} else {
panic!("unexpected non const in position {pos}");
}
@@ -1086,7 +1087,7 @@ fn clean_fn_decl_legacy_const_generics(func: &mut Function, attrs: &[hir::Attrib
}
}
-enum FunctionArgs<'tcx> {
+enum ParamsSrc<'tcx> {
Body(hir::BodyId),
Idents(&'tcx [Option<Ident>]),
}
@@ -1095,86 +1096,62 @@ fn clean_function<'tcx>(
cx: &mut DocContext<'tcx>,
sig: &hir::FnSig<'tcx>,
generics: &hir::Generics<'tcx>,
- args: FunctionArgs<'tcx>,
+ params: ParamsSrc<'tcx>,
) -> Box<Function> {
let (generics, decl) = enter_impl_trait(cx, |cx| {
- // NOTE: generics must be cleaned before args
+ // NOTE: Generics must be cleaned before params.
let generics = clean_generics(generics, cx);
- let args = match args {
- FunctionArgs::Body(body_id) => {
- clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id)
- }
- FunctionArgs::Idents(idents) => {
- clean_args_from_types_and_names(cx, sig.decl.inputs, idents)
- }
+ let params = match params {
+ ParamsSrc::Body(body_id) => clean_params_via_body(cx, sig.decl.inputs, body_id),
+ // Let's not perpetuate anon params from Rust 2015; use `_` for them.
+ ParamsSrc::Idents(idents) => clean_params(cx, sig.decl.inputs, idents, |ident| {
+ Some(ident.map_or(kw::Underscore, |ident| ident.name))
+ }),
};
- let decl = clean_fn_decl_with_args(cx, sig.decl, Some(&sig.header), args);
+ let decl = clean_fn_decl_with_params(cx, sig.decl, Some(&sig.header), params);
(generics, decl)
});
Box::new(Function { decl, generics })
}
-fn clean_args_from_types_and_names<'tcx>(
+fn clean_params<'tcx>(
cx: &mut DocContext<'tcx>,
types: &[hir::Ty<'tcx>],
idents: &[Option<Ident>],
-) -> Arguments {
- fn nonempty_name(ident: &Option<Ident>) -> Option<Symbol> {
- if let Some(ident) = ident
- && ident.name != kw::Underscore
- {
- Some(ident.name)
- } else {
- None
- }
- }
-
- // If at least one argument has a name, use `_` as the name of unnamed
- // arguments. Otherwise omit argument names.
- let default_name = if idents.iter().any(|ident| nonempty_name(ident).is_some()) {
- kw::Underscore
- } else {
- kw::Empty
- };
-
- Arguments {
- values: types
- .iter()
- .enumerate()
- .map(|(i, ty)| Argument {
- type_: clean_ty(ty, cx),
- name: idents.get(i).and_then(nonempty_name).unwrap_or(default_name),
- is_const: false,
- })
- .collect(),
- }
+ postprocess: impl Fn(Option<Ident>) -> Option<Symbol>,
+) -> Vec<Parameter> {
+ types
+ .iter()
+ .enumerate()
+ .map(|(i, ty)| Parameter {
+ name: postprocess(idents[i]),
+ type_: clean_ty(ty, cx),
+ is_const: false,
+ })
+ .collect()
}
-fn clean_args_from_types_and_body_id<'tcx>(
+fn clean_params_via_body<'tcx>(
cx: &mut DocContext<'tcx>,
types: &[hir::Ty<'tcx>],
body_id: hir::BodyId,
-) -> Arguments {
- let body = cx.tcx.hir_body(body_id);
-
- Arguments {
- values: types
- .iter()
- .zip(body.params)
- .map(|(ty, param)| Argument {
- name: name_from_pat(param.pat),
- type_: clean_ty(ty, cx),
- is_const: false,
- })
- .collect(),
- }
+) -> Vec<Parameter> {
+ types
+ .iter()
+ .zip(cx.tcx.hir_body(body_id).params)
+ .map(|(ty, param)| Parameter {
+ name: Some(name_from_pat(param.pat)),
+ type_: clean_ty(ty, cx),
+ is_const: false,
+ })
+ .collect()
}
-fn clean_fn_decl_with_args<'tcx>(
+fn clean_fn_decl_with_params<'tcx>(
cx: &mut DocContext<'tcx>,
decl: &hir::FnDecl<'tcx>,
header: Option<&hir::FnHeader>,
- args: Arguments,
+ params: Vec<Parameter>,
) -> FnDecl {
let mut output = match decl.output {
hir::FnRetTy::Return(typ) => clean_ty(typ, cx),
@@ -1185,7 +1162,7 @@ fn clean_fn_decl_with_args<'tcx>(
{
output = output.sugared_async_return_type();
}
- FnDecl { inputs: args, output, c_variadic: decl.c_variadic }
+ FnDecl { inputs: params, output, c_variadic: decl.c_variadic }
}
fn clean_poly_fn_sig<'tcx>(
@@ -1193,10 +1170,6 @@ fn clean_poly_fn_sig<'tcx>(
did: Option<DefId>,
sig: ty::PolyFnSig<'tcx>,
) -> FnDecl {
- let mut names = did.map_or(&[] as &[_], |did| cx.tcx.fn_arg_idents(did)).iter();
-
- // We assume all empty tuples are default return type. This theoretically can discard `-> ()`,
- // but shouldn't change any code meaning.
let mut output = clean_middle_ty(sig.output(), cx, None, None);
// If the return type isn't an `impl Trait`, we can safely assume that this
@@ -1209,25 +1182,25 @@ fn clean_poly_fn_sig<'tcx>(
output = output.sugared_async_return_type();
}
- FnDecl {
- output,
- c_variadic: sig.skip_binder().c_variadic,
- inputs: Arguments {
- values: sig
- .inputs()
- .iter()
- .map(|t| Argument {
- type_: clean_middle_ty(t.map_bound(|t| *t), cx, None, None),
- name: if let Some(Some(ident)) = names.next() {
- ident.name
- } else {
- kw::Underscore
- },
- is_const: false,
- })
- .collect(),
- },
- }
+ let mut idents = did.map(|did| cx.tcx.fn_arg_idents(did)).unwrap_or_default().iter().copied();
+
+ // If this comes from a fn item, let's not perpetuate anon params from Rust 2015; use `_` for them.
+ // If this comes from a fn ptr ty, we just keep params unnamed since it's more conventional stylistically.
+ // Since the param name is not part of the semantic type, these params never bear a name unlike
+ // in the HIR case, thus we can't peform any fancy fallback logic unlike `clean_bare_fn_ty`.
+ let fallback = did.map(|_| kw::Underscore);
+
+ let params = sig
+ .inputs()
+ .iter()
+ .map(|ty| Parameter {
+ name: idents.next().flatten().map(|ident| ident.name).or(fallback),
+ type_: clean_middle_ty(ty.map_bound(|ty| *ty), cx, None, None),
+ is_const: false,
+ })
+ .collect();
+
+ FnDecl { inputs: params, output, c_variadic: sig.skip_binder().c_variadic }
}
fn clean_trait_ref<'tcx>(trait_ref: &hir::TraitRef<'tcx>, cx: &mut DocContext<'tcx>) -> Path {
@@ -1267,11 +1240,11 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext
RequiredAssocConstItem(generics, Box::new(clean_ty(ty, cx)))
}
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
- let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body));
+ let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Body(body));
MethodItem(m, None)
}
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(idents)) => {
- let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Idents(idents));
+ let m = clean_function(cx, sig, trait_item.generics, ParamsSrc::Idents(idents));
RequiredMethodItem(m)
}
hir::TraitItemKind::Type(bounds, Some(default)) => {
@@ -1312,7 +1285,7 @@ pub(crate) fn clean_impl_item<'tcx>(
type_: clean_ty(ty, cx),
})),
hir::ImplItemKind::Fn(ref sig, body) => {
- let m = clean_function(cx, sig, impl_.generics, FunctionArgs::Body(body));
+ let m = clean_function(cx, sig, impl_.generics, ParamsSrc::Body(body));
let defaultness = cx.tcx.defaultness(impl_.owner_id);
MethodItem(m, Some(defaultness))
}
@@ -1340,7 +1313,7 @@ pub(crate) fn clean_impl_item<'tcx>(
pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocContext<'_>) -> Item {
let tcx = cx.tcx;
let kind = match assoc_item.kind {
- ty::AssocKind::Const => {
+ ty::AssocKind::Const { .. } => {
let ty = clean_middle_ty(
ty::Binder::dummy(tcx.type_of(assoc_item.def_id).instantiate_identity()),
cx,
@@ -1374,24 +1347,24 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
}
}
}
- ty::AssocKind::Fn => {
+ ty::AssocKind::Fn { has_self, .. } => {
let mut item = inline::build_function(cx, assoc_item.def_id);
- if assoc_item.fn_has_self_parameter {
+ if has_self {
let self_ty = match assoc_item.container {
ty::AssocItemContainer::Impl => {
tcx.type_of(assoc_item.container_id(tcx)).instantiate_identity()
}
ty::AssocItemContainer::Trait => tcx.types.self_param,
};
- let self_arg_ty =
+ let self_param_ty =
tcx.fn_sig(assoc_item.def_id).instantiate_identity().input(0).skip_binder();
- if self_arg_ty == self_ty {
- item.decl.inputs.values[0].type_ = SelfTy;
- } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind()
+ if self_param_ty == self_ty {
+ item.decl.inputs[0].type_ = SelfTy;
+ } else if let ty::Ref(_, ty, _) = *self_param_ty.kind()
&& ty == self_ty
{
- match item.decl.inputs.values[0].type_ {
+ match item.decl.inputs[0].type_ {
BorrowedRef { ref mut type_, .. } => **type_ = SelfTy,
_ => unreachable!(),
}
@@ -1412,8 +1385,8 @@ pub(crate) fn clean_middle_assoc_item(assoc_item: &ty::AssocItem, cx: &mut DocCo
RequiredMethodItem(item)
}
}
- ty::AssocKind::Type => {
- let my_name = assoc_item.name;
+ ty::AssocKind::Type { .. } => {
+ let my_name = assoc_item.name();
fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
match (¶m.kind, arg) {
@@ -1554,7 +1527,7 @@ fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool {
}
};
- Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx)
+ Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name()), kind, cx)
}
fn first_non_private_clean_path<'tcx>(
@@ -2223,7 +2196,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
Type::QPath(Box::new(QPathData {
assoc: PathSegment {
- name: cx.tcx.associated_item(def_id).name,
+ name: cx.tcx.associated_item(def_id).name(),
args: GenericArgs::AngleBracketed {
args: clean_middle_generic_args(
cx,
@@ -2605,15 +2578,25 @@ fn clean_bare_fn_ty<'tcx>(
cx: &mut DocContext<'tcx>,
) -> BareFunctionDecl {
let (generic_params, decl) = enter_impl_trait(cx, |cx| {
- // NOTE: generics must be cleaned before args
+ // NOTE: Generics must be cleaned before params.
let generic_params = bare_fn
.generic_params
.iter()
.filter(|p| !is_elided_lifetime(p))
.map(|x| clean_generic_param(cx, None, x))
.collect();
- let args = clean_args_from_types_and_names(cx, bare_fn.decl.inputs, bare_fn.param_idents);
- let decl = clean_fn_decl_with_args(cx, bare_fn.decl, None, args);
+ // Since it's more conventional stylistically, elide the name of all params called `_`
+ // unless there's at least one interestingly named param in which case don't elide any
+ // name since mixing named and unnamed params is less legible.
+ let filter = |ident: Option<Ident>| {
+ ident.map(|ident| ident.name).filter(|&ident| ident != kw::Underscore)
+ };
+ let fallback =
+ bare_fn.param_idents.iter().copied().find_map(filter).map(|_| kw::Underscore);
+ let params = clean_params(cx, bare_fn.decl.inputs, bare_fn.param_idents, |ident| {
+ filter(ident).or(fallback)
+ });
+ let decl = clean_fn_decl_with_params(cx, bare_fn.decl, None, params);
(generic_params, decl)
});
BareFunctionDecl { safety: bare_fn.safety, abi: bare_fn.abi, decl, generic_params }
@@ -2623,7 +2606,6 @@ fn clean_unsafe_binder_ty<'tcx>(
unsafe_binder_ty: &hir::UnsafeBinderTy<'tcx>,
cx: &mut DocContext<'tcx>,
) -> UnsafeBinderTy {
- // NOTE: generics must be cleaned before args
let generic_params = unsafe_binder_ty
.generic_params
.iter()
@@ -2791,13 +2773,35 @@ fn clean_maybe_renamed_item<'tcx>(
) -> Vec<Item> {
use hir::ItemKind;
- let def_id = item.owner_id.to_def_id();
- let mut name = renamed.unwrap_or_else(|| {
- // FIXME: using kw::Empty is a bit of a hack
- cx.tcx.hir_opt_name(item.hir_id()).unwrap_or(kw::Empty)
- });
+ fn get_name(
+ cx: &DocContext<'_>,
+ item: &hir::Item<'_>,
+ renamed: Option<Symbol>,
+ ) -> Option<Symbol> {
+ renamed.or_else(|| cx.tcx.hir_opt_name(item.hir_id()))
+ }
+ let def_id = item.owner_id.to_def_id();
cx.with_param_env(def_id, |cx| {
+ // These kinds of item either don't need a `name` or accept a `None` one so we handle them
+ // before.
+ match item.kind {
+ ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
+ ItemKind::Use(path, kind) => {
+ return clean_use_statement(
+ item,
+ get_name(cx, item, renamed),
+ path,
+ kind,
+ cx,
+ &mut FxHashSet::default(),
+ );
+ }
+ _ => {}
+ }
+
+ let mut name = get_name(cx, item, renamed).unwrap();
+
let kind = match item.kind {
ItemKind::Static(_, ty, mutability, body_id) => StaticItem(Static {
type_: Box::new(clean_ty(ty, cx)),
@@ -2859,7 +2863,6 @@ fn clean_maybe_renamed_item<'tcx>(
generics: clean_generics(generics, cx),
fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
}),
- ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
ItemKind::Macro(_, macro_def, MacroKind::Bang) => MacroItem(Macro {
source: display_macro_source(cx, name, macro_def),
macro_rules: macro_def.macro_rules,
@@ -2885,9 +2888,6 @@ fn clean_maybe_renamed_item<'tcx>(
ItemKind::ExternCrate(orig_name, _) => {
return clean_extern_crate(item, name, orig_name, cx);
}
- ItemKind::Use(path, kind) => {
- return clean_use_statement(item, name, path, kind, cx, &mut FxHashSet::default());
- }
_ => span_bug!(item.span, "not yet converted"),
};
@@ -3006,7 +3006,7 @@ fn clean_extern_crate<'tcx>(
fn clean_use_statement<'tcx>(
import: &hir::Item<'tcx>,
- name: Symbol,
+ name: Option<Symbol>,
path: &hir::UsePath<'tcx>,
kind: hir::UseKind,
cx: &mut DocContext<'tcx>,
@@ -3023,7 +3023,7 @@ fn clean_use_statement<'tcx>(
fn clean_use_statement_inner<'tcx>(
import: &hir::Item<'tcx>,
- name: Symbol,
+ name: Option<Symbol>,
path: &hir::Path<'tcx>,
kind: hir::UseKind,
cx: &mut DocContext<'tcx>,
@@ -3042,7 +3042,7 @@ fn clean_use_statement_inner<'tcx>(
let visibility = cx.tcx.visibility(import.owner_id);
let attrs = cx.tcx.hir_attrs(import.hir_id());
let inline_attr = hir_attr_lists(attrs, sym::doc).get_word_attr(sym::inline);
- let pub_underscore = visibility.is_public() && name == kw::Underscore;
+ let pub_underscore = visibility.is_public() && name == Some(kw::Underscore);
let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id);
let import_def_id = import.owner_id.def_id;
@@ -3108,6 +3108,7 @@ fn clean_use_statement_inner<'tcx>(
}
Import::new_glob(resolve_use_source(cx, path), true)
} else {
+ let name = name.unwrap();
if inline_attr.is_none()
&& let Res::Def(DefKind::Mod, did) = path.res
&& !did.is_local()
@@ -3149,7 +3150,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>(
cx.with_param_env(def_id, |cx| {
let kind = match item.kind {
hir::ForeignItemKind::Fn(sig, idents, generics) => ForeignFunctionItem(
- clean_function(cx, &sig, generics, FunctionArgs::Idents(idents)),
+ clean_function(cx, &sig, generics, ParamsSrc::Idents(idents)),
sig.header.safety(),
),
hir::ForeignItemKind::Static(ty, mutability, safety) => ForeignStaticItem(
diff --git a/src/librustdoc/clean/render_macro_matchers.rs b/src/librustdoc/clean/render_macro_matchers.rs
index 31f9c28..fc99dd0 100644
--- a/src/librustdoc/clean/render_macro_matchers.rs
+++ b/src/librustdoc/clean/render_macro_matchers.rs
@@ -96,7 +96,7 @@ fn print_tt(printer: &mut Printer<'_>, tt: &TokenTree) {
}
}
TokenTree::Delimited(_span, _spacing, delim, tts) => {
- let open_delim = printer.token_kind_to_string(&token::OpenDelim(*delim));
+ let open_delim = printer.token_kind_to_string(&delim.as_open_token_kind());
printer.word(open_delim);
if !tts.is_empty() {
if *delim == Delimiter::Brace {
@@ -107,7 +107,7 @@ fn print_tt(printer: &mut Printer<'_>, tt: &TokenTree) {
printer.space();
}
}
- let close_delim = printer.token_kind_to_string(&token::CloseDelim(*delim));
+ let close_delim = printer.token_kind_to_string(&delim.as_close_token_kind());
printer.word(close_delim);
}
}
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 06e75fe..bbe11bf 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -517,7 +517,7 @@ pub(crate) fn links(&self, cx: &Context<'_>) -> Vec<RenderedLink> {
Some(RenderedLink {
original_text: s.clone(),
new_text: link_text.clone(),
- tooltip: link_tooltip(*id, fragment, cx),
+ tooltip: link_tooltip(*id, fragment, cx).to_string(),
href,
})
} else {
@@ -788,7 +788,7 @@ pub(crate) fn attributes(&self, tcx: TyCtxt<'_>, cache: &Cache, is_json: bool) -
}
_ => Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)),
}
- } else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) {
+ } else if attr.has_any_name(ALLOWED_ATTRIBUTES) {
Some(
rustc_hir_pretty::attribute_to_string(&tcx, attr)
.replace("\\\n", "")
@@ -1407,34 +1407,30 @@ pub(crate) struct Function {
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub(crate) struct FnDecl {
- pub(crate) inputs: Arguments,
+ pub(crate) inputs: Vec<Parameter>,
pub(crate) output: Type,
pub(crate) c_variadic: bool,
}
impl FnDecl {
pub(crate) fn receiver_type(&self) -> Option<&Type> {
- self.inputs.values.first().and_then(|v| v.to_receiver())
+ self.inputs.first().and_then(|v| v.to_receiver())
}
}
+/// A function parameter.
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub(crate) struct Arguments {
- pub(crate) values: Vec<Argument>,
-}
-
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
-pub(crate) struct Argument {
+pub(crate) struct Parameter {
+ pub(crate) name: Option<Symbol>,
pub(crate) type_: Type,
- pub(crate) name: Symbol,
/// This field is used to represent "const" arguments from the `rustc_legacy_const_generics`
/// feature. More information in <https://github.com/rust-lang/rust/issues/83167>.
pub(crate) is_const: bool,
}
-impl Argument {
+impl Parameter {
pub(crate) fn to_receiver(&self) -> Option<&Type> {
- if self.name == kw::SelfLower { Some(&self.type_) } else { None }
+ if self.name == Some(kw::SelfLower) { Some(&self.type_) } else { None }
}
}
@@ -2504,7 +2500,7 @@ pub(crate) fn provided_trait_methods(&self, tcx: TyCtxt<'_>) -> FxIndexSet<Symbo
self.trait_
.as_ref()
.map(|t| t.def_id())
- .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name).collect())
+ .map(|did| tcx.provided_trait_methods(did).map(|meth| meth.name()).collect())
.unwrap_or_default()
}
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index afcca81..af7986d 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -234,7 +234,7 @@ pub(super) fn clean_middle_path<'tcx>(
args: ty::Binder<'tcx, GenericArgsRef<'tcx>>,
) -> Path {
let def_kind = cx.tcx.def_kind(did);
- let name = cx.tcx.opt_item_name(did).unwrap_or(kw::Empty);
+ let name = cx.tcx.opt_item_name(did).unwrap_or(sym::dummy);
Path {
res: Res::Def(def_kind, did),
segments: thin_vec![PathSegment {
@@ -303,13 +303,12 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
debug!("trying to get a name from pattern: {p:?}");
Symbol::intern(&match &p.kind {
- // FIXME(never_patterns): does this make sense?
- PatKind::Missing => unreachable!(),
- PatKind::Wild
- | PatKind::Err(_)
+ PatKind::Err(_)
+ | PatKind::Missing // Let's not perpetuate anon params from Rust 2015; use `_` for them.
| PatKind::Never
+ | PatKind::Range(..)
| PatKind::Struct(..)
- | PatKind::Range(..) => {
+ | PatKind::Wild => {
return kw::Underscore;
}
PatKind::Binding(_, _, ident, _) => return ident.name,
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index c4dea79..9d1c9ff 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -27,7 +27,7 @@
use rustc_span::symbol::sym;
use tracing::{debug, info};
-use crate::clean::inline::build_external_trait;
+use crate::clean::inline::build_trait;
use crate::clean::{self, ItemId};
use crate::config::{Options as RustdocOptions, OutputFormat, RenderOptions};
use crate::formats::cache::Cache;
@@ -385,7 +385,7 @@ pub(crate) fn run_global_ctxt(
//
// Note that in case of `#![no_core]`, the trait is not available.
if let Some(sized_trait_did) = ctxt.tcx.lang_items().sized_trait() {
- let sized_trait = build_external_trait(&mut ctxt, sized_trait_did);
+ let sized_trait = build_trait(&mut ctxt, sized_trait_did);
ctxt.external_traits.insert(sized_trait_did, sized_trait);
}
@@ -412,9 +412,7 @@ pub(crate) fn run_global_ctxt(
// Process all of the crate attributes, extracting plugin metadata along
// with the passes which we are supposed to run.
for attr in krate.module.attrs.lists(sym::doc) {
- let name = attr.name_or_empty();
-
- if attr.is_word() && name == sym::document_private_items {
+ if attr.is_word() && attr.has_name(sym::document_private_items) {
ctxt.render_options.document_private = true;
}
}
diff --git a/src/librustdoc/doctest/make.rs b/src/librustdoc/doctest/make.rs
index 4edd543..d5c965f 100644
--- a/src/librustdoc/doctest/make.rs
+++ b/src/librustdoc/doctest/make.rs
@@ -345,7 +345,7 @@ fn push_to_s(s: &mut String, source: &str, span: rustc_span::Span, prev_span_hi:
fn check_item(item: &ast::Item, info: &mut ParseSourceInfo, crate_name: &Option<&str>) -> bool {
let mut is_extern_crate = false;
if !info.has_global_allocator
- && item.attrs.iter().any(|attr| attr.name_or_empty() == sym::global_allocator)
+ && item.attrs.iter().any(|attr| attr.has_name(sym::global_allocator))
{
info.has_global_allocator = true;
}
@@ -377,7 +377,7 @@ fn check_item(item: &ast::Item, info: &mut ParseSourceInfo, crate_name: &Option<
}
let mut prev_span_hi = 0;
- let not_crate_attrs = [sym::forbid, sym::allow, sym::warn, sym::deny, sym::expect];
+ let not_crate_attrs = &[sym::forbid, sym::allow, sym::warn, sym::deny, sym::expect];
let parsed = parser.parse_item(rustc_parse::parser::ForceCollect::No);
let result = match parsed {
@@ -386,17 +386,13 @@ fn check_item(item: &ast::Item, info: &mut ParseSourceInfo, crate_name: &Option<
&& let Some(ref body) = fn_item.body =>
{
for attr in &item.attrs {
- let attr_name = attr.name_or_empty();
-
- if attr.style == AttrStyle::Outer || not_crate_attrs.contains(&attr_name) {
+ if attr.style == AttrStyle::Outer || attr.has_any_name(not_crate_attrs) {
// There is one exception to these attributes:
// `#![allow(internal_features)]`. If this attribute is used, we need to
// consider it only as a crate-level attribute.
- if attr_name == sym::allow
+ if attr.has_name(sym::allow)
&& let Some(list) = attr.meta_item_list()
- && list.iter().any(|sub_attr| {
- sub_attr.name_or_empty().as_str() == "internal_features"
- })
+ && list.iter().any(|sub_attr| sub_attr.has_name(sym::internal_features))
{
push_to_s(&mut info.crate_attrs, source, attr.span, &mut prev_span_hi);
} else {
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 41e9a5a..299fd6b 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -11,6 +11,7 @@
use std::cmp::Ordering;
use std::fmt::{self, Display, Write};
use std::iter::{self, once};
+use std::slice;
use itertools::Either;
use rustc_abi::ExternAbi;
@@ -650,33 +651,35 @@ pub(crate) fn href_relative_parts<'fqp>(
}
}
-pub(crate) fn link_tooltip(did: DefId, fragment: &Option<UrlFragment>, cx: &Context<'_>) -> String {
- let cache = cx.cache();
- let Some((fqp, shortty)) = cache.paths.get(&did).or_else(|| cache.external_paths.get(&did))
- else {
- return String::new();
- };
- let mut buf = String::new();
- let fqp = if *shortty == ItemType::Primitive {
- // primitives are documented in a crate, but not actually part of it
- &fqp[fqp.len() - 1..]
- } else {
- fqp
- };
- if let &Some(UrlFragment::Item(id)) = fragment {
- write_str(&mut buf, format_args!("{} ", cx.tcx().def_descr(id)));
- for component in fqp {
- write_str(&mut buf, format_args!("{component}::"));
+pub(crate) fn link_tooltip(
+ did: DefId,
+ fragment: &Option<UrlFragment>,
+ cx: &Context<'_>,
+) -> impl fmt::Display {
+ fmt::from_fn(move |f| {
+ let cache = cx.cache();
+ let Some((fqp, shortty)) = cache.paths.get(&did).or_else(|| cache.external_paths.get(&did))
+ else {
+ return Ok(());
+ };
+ let fqp = if *shortty == ItemType::Primitive {
+ // primitives are documented in a crate, but not actually part of it
+ slice::from_ref(fqp.last().unwrap())
+ } else {
+ fqp
+ };
+ if let &Some(UrlFragment::Item(id)) = fragment {
+ write!(f, "{} ", cx.tcx().def_descr(id))?;
+ for component in fqp {
+ write!(f, "{component}::")?;
+ }
+ write!(f, "{}", cx.tcx().item_name(id))?;
+ } else if !fqp.is_empty() {
+ write!(f, "{shortty} ")?;
+ fqp.iter().joined("::", f)?;
}
- write_str(&mut buf, format_args!("{}", cx.tcx().item_name(id)));
- } else if !fqp.is_empty() {
- let mut fqp_it = fqp.iter();
- write_str(&mut buf, format_args!("{shortty} {}", fqp_it.next().unwrap()));
- for component in fqp_it {
- write_str(&mut buf, format_args!("::{component}"));
- }
- }
- buf
+ Ok(())
+ })
}
/// Used to render a [`clean::Path`].
@@ -1183,8 +1186,8 @@ fn print_type(
{
primitive_link(f, PrimitiveType::Array, format_args!("[{name}; N]"), cx)?;
} else if let clean::BareFunction(bare_fn) = &type_
- && let [clean::Argument { type_: clean::Type::Generic(name), .. }] =
- &bare_fn.decl.inputs.values[..]
+ && let [clean::Parameter { type_: clean::Type::Generic(name), .. }] =
+ &bare_fn.decl.inputs[..]
&& (self.kind.is_fake_variadic() || self.kind.is_auto())
{
// Hardcoded anchor library/core/src/primitive_docs.rs
@@ -1231,22 +1234,20 @@ fn print_type(
}
}
-impl clean::Arguments {
- pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
- fmt::from_fn(move |f| {
- self.values
- .iter()
- .map(|input| {
- fmt::from_fn(|f| {
- if !input.name.is_empty() {
- write!(f, "{}: ", input.name)?;
- }
- input.type_.print(cx).fmt(f)
- })
+pub(crate) fn print_params(params: &[clean::Parameter], cx: &Context<'_>) -> impl Display {
+ fmt::from_fn(move |f| {
+ params
+ .iter()
+ .map(|param| {
+ fmt::from_fn(|f| {
+ if let Some(name) = param.name {
+ write!(f, "{}: ", name)?;
+ }
+ param.type_.print(cx).fmt(f)
})
- .joined(", ", f)
- })
- }
+ })
+ .joined(", ", f)
+ })
}
// Implements Write but only counts the bytes "written".
@@ -1278,16 +1279,16 @@ pub(crate) fn print(&self, cx: &Context<'_>) -> impl Display {
if f.alternate() {
write!(
f,
- "({args:#}{ellipsis}){arrow:#}",
- args = self.inputs.print(cx),
+ "({params:#}{ellipsis}){arrow:#}",
+ params = print_params(&self.inputs, cx),
ellipsis = ellipsis,
arrow = self.print_output(cx)
)
} else {
write!(
f,
- "({args}{ellipsis}){arrow}",
- args = self.inputs.print(cx),
+ "({params}{ellipsis}){arrow}",
+ params = print_params(&self.inputs, cx),
ellipsis = ellipsis,
arrow = self.print_output(cx)
)
@@ -1333,14 +1334,14 @@ fn inner_full_print(
write!(f, "(")?;
if let Some(n) = line_wrapping_indent
- && !self.inputs.values.is_empty()
+ && !self.inputs.is_empty()
{
write!(f, "\n{}", Indent(n + 4))?;
}
- let last_input_index = self.inputs.values.len().checked_sub(1);
- for (i, input) in self.inputs.values.iter().enumerate() {
- if let Some(selfty) = input.to_receiver() {
+ let last_input_index = self.inputs.len().checked_sub(1);
+ for (i, param) in self.inputs.iter().enumerate() {
+ if let Some(selfty) = param.to_receiver() {
match selfty {
clean::SelfTy => {
write!(f, "self")?;
@@ -1358,11 +1359,13 @@ fn inner_full_print(
}
}
} else {
- if input.is_const {
+ if param.is_const {
write!(f, "const ")?;
}
- write!(f, "{}: ", input.name)?;
- input.type_.print(cx).fmt(f)?;
+ if let Some(name) = param.name {
+ write!(f, "{}: ", name)?;
+ }
+ param.type_.print(cx).fmt(f)?;
}
match (line_wrapping_indent, last_input_index) {
(_, None) => (),
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index e2d1f58..f22935d 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -521,23 +521,23 @@ fn init(
// Crawl the crate attributes looking for attributes which control how we're
// going to emit HTML
for attr in krate.module.attrs.lists(sym::doc) {
- match (attr.name_or_empty(), attr.value_str()) {
- (sym::html_favicon_url, Some(s)) => {
+ match (attr.name(), attr.value_str()) {
+ (Some(sym::html_favicon_url), Some(s)) => {
layout.favicon = s.to_string();
}
- (sym::html_logo_url, Some(s)) => {
+ (Some(sym::html_logo_url), Some(s)) => {
layout.logo = s.to_string();
}
- (sym::html_playground_url, Some(s)) => {
+ (Some(sym::html_playground_url), Some(s)) => {
playground = Some(markdown::Playground {
crate_name: Some(krate.name(tcx)),
url: s.to_string(),
});
}
- (sym::issue_tracker_base_url, Some(s)) => {
+ (Some(sym::issue_tracker_base_url), Some(s)) => {
issue_tracker_base_url = Some(s.to_string());
}
- (sym::html_no_source, None) if attr.is_word() => {
+ (Some(sym::html_no_source), None) if attr.is_word() => {
include_sources = false;
}
_ => {}
@@ -650,15 +650,7 @@ fn after_krate(&mut self) -> Result<(), Error> {
bar.render_into(&mut sidebar).unwrap();
- let v = layout::render(
- &shared.layout,
- &page,
- sidebar,
- BufDisplay(|buf: &mut String| {
- all.print(buf);
- }),
- &shared.style_files,
- );
+ let v = layout::render(&shared.layout, &page, sidebar, all.print(), &shared.style_files);
shared.fs.write(final_file, v)?;
// if to avoid writing help, settings files to doc root unless we're on the final invocation
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 21c823f..7e17f09 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -40,6 +40,7 @@
mod type_layout;
mod write_shared;
+use std::borrow::Cow;
use std::collections::VecDeque;
use std::fmt::{self, Display as _, Write};
use std::iter::Peekable;
@@ -47,6 +48,7 @@
use std::{fs, str};
use askama::Template;
+use itertools::Either;
use rustc_attr_parsing::{
ConstStability, DeprecatedSince, Deprecation, RustcVersion, StabilityLevel, StableSince,
};
@@ -98,6 +100,19 @@ enum AssocItemRender<'a> {
DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool },
}
+impl AssocItemRender<'_> {
+ fn render_mode(&self) -> RenderMode {
+ match self {
+ Self::All => RenderMode::Normal,
+ &Self::DerefFor { deref_mut_, .. } => RenderMode::ForDeref { mut_: deref_mut_ },
+ }
+ }
+
+ fn class(&self) -> Option<&'static str> {
+ if let Self::DerefFor { .. } = self { Some("impl-items") } else { None }
+ }
+}
+
/// For different handling of associated items from the Deref target of a type rather than the type
/// itself.
#[derive(Copy, Clone, PartialEq)]
@@ -208,7 +223,7 @@ pub(crate) struct IndexItemFunctionType {
inputs: Vec<RenderType>,
output: Vec<RenderType>,
where_clause: Vec<Vec<RenderType>>,
- param_names: Vec<Symbol>,
+ param_names: Vec<Option<Symbol>>,
}
impl IndexItemFunctionType {
@@ -439,44 +454,49 @@ fn item_sections(&self) -> FxHashSet<ItemSection> {
sections
}
- fn print(&self, f: &mut String) {
- fn print_entries(f: &mut String, e: &FxIndexSet<ItemEntry>, kind: ItemSection) {
- if !e.is_empty() {
- let mut e: Vec<&ItemEntry> = e.iter().collect();
- e.sort();
- write_str(
- f,
- format_args!(
- "<h3 id=\"{id}\">{title}</h3><ul class=\"all-items\">",
- id = kind.id(),
- title = kind.name(),
- ),
- );
-
- for s in e.iter() {
- write_str(f, format_args!("<li>{}</li>", s.print()));
+ fn print(&self) -> impl fmt::Display {
+ fn print_entries(e: &FxIndexSet<ItemEntry>, kind: ItemSection) -> impl fmt::Display {
+ fmt::from_fn(move |f| {
+ if e.is_empty() {
+ return Ok(());
}
- f.push_str("</ul>");
- }
+ let mut e: Vec<&ItemEntry> = e.iter().collect();
+ e.sort();
+ write!(
+ f,
+ "<h3 id=\"{id}\">{title}</h3><ul class=\"all-items\">",
+ id = kind.id(),
+ title = kind.name(),
+ )?;
+
+ for s in e.iter() {
+ write!(f, "<li>{}</li>", s.print())?;
+ }
+
+ f.write_str("</ul>")
+ })
}
- f.push_str("<h1>List of all items</h1>");
- // Note: print_entries does not escape the title, because we know the current set of titles
- // doesn't require escaping.
- print_entries(f, &self.structs, ItemSection::Structs);
- print_entries(f, &self.enums, ItemSection::Enums);
- print_entries(f, &self.unions, ItemSection::Unions);
- print_entries(f, &self.primitives, ItemSection::PrimitiveTypes);
- print_entries(f, &self.traits, ItemSection::Traits);
- print_entries(f, &self.macros, ItemSection::Macros);
- print_entries(f, &self.attribute_macros, ItemSection::AttributeMacros);
- print_entries(f, &self.derive_macros, ItemSection::DeriveMacros);
- print_entries(f, &self.functions, ItemSection::Functions);
- print_entries(f, &self.type_aliases, ItemSection::TypeAliases);
- print_entries(f, &self.trait_aliases, ItemSection::TraitAliases);
- print_entries(f, &self.statics, ItemSection::Statics);
- print_entries(f, &self.constants, ItemSection::Constants);
+ fmt::from_fn(|f| {
+ f.write_str("<h1>List of all items</h1>")?;
+ // Note: print_entries does not escape the title, because we know the current set of titles
+ // doesn't require escaping.
+ print_entries(&self.structs, ItemSection::Structs).fmt(f)?;
+ print_entries(&self.enums, ItemSection::Enums).fmt(f)?;
+ print_entries(&self.unions, ItemSection::Unions).fmt(f)?;
+ print_entries(&self.primitives, ItemSection::PrimitiveTypes).fmt(f)?;
+ print_entries(&self.traits, ItemSection::Traits).fmt(f)?;
+ print_entries(&self.macros, ItemSection::Macros).fmt(f)?;
+ print_entries(&self.attribute_macros, ItemSection::AttributeMacros).fmt(f)?;
+ print_entries(&self.derive_macros, ItemSection::DeriveMacros).fmt(f)?;
+ print_entries(&self.functions, ItemSection::Functions).fmt(f)?;
+ print_entries(&self.type_aliases, ItemSection::TypeAliases).fmt(f)?;
+ print_entries(&self.trait_aliases, ItemSection::TraitAliases).fmt(f)?;
+ print_entries(&self.statics, ItemSection::Statics).fmt(f)?;
+ print_entries(&self.constants, ItemSection::Constants).fmt(f)?;
+ Ok(())
+ })
}
}
@@ -1205,7 +1225,7 @@ fn anchor(&self, id: &'a str) -> Self {
}
fn write_section_heading(
- title: &str,
+ title: impl fmt::Display,
id: &str,
extra_class: Option<&str>,
extra: impl fmt::Display,
@@ -1225,7 +1245,7 @@ fn write_section_heading(
})
}
-fn write_impl_section_heading(title: &str, id: &str) -> impl fmt::Display {
+fn write_impl_section_heading(title: impl fmt::Display, id: &str) -> impl fmt::Display {
write_section_heading(title, id, None, "")
}
@@ -1302,20 +1322,17 @@ fn render_assoc_items_inner(
let (mut non_trait, traits): (Vec<_>, _) =
v.iter().partition(|i| i.inner_impl().trait_.is_none());
if !non_trait.is_empty() {
- let mut close_tags = <Vec<&str>>::with_capacity(1);
- let mut tmp_buf = String::new();
- let (render_mode, id, class_html) = match what {
- AssocItemRender::All => {
- write_str(
- &mut tmp_buf,
- format_args!(
- "{}",
- write_impl_section_heading("Implementations", "implementations")
- ),
- );
- (RenderMode::Normal, "implementations-list".to_owned(), "")
- }
- AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => {
+ let render_mode = what.render_mode();
+ let class_html = what
+ .class()
+ .map(|class| fmt::from_fn(move |f| write!(f, r#" class="{class}""#)))
+ .maybe_display();
+ let (section_heading, id) = match what {
+ AssocItemRender::All => (
+ Either::Left(write_impl_section_heading("Implementations", "implementations")),
+ Cow::Borrowed("implementations-list"),
+ ),
+ AssocItemRender::DerefFor { trait_, type_, .. } => {
let id =
cx.derive_id(small_url_encode(format!("deref-methods-{:#}", type_.print(cx))));
// the `impls.get` above only looks at the outermost type,
@@ -1329,25 +1346,27 @@ fn render_assoc_items_inner(
type_.is_doc_subtype_of(&impl_.inner_impl().for_, &cx.shared.cache)
});
let derived_id = cx.derive_id(&id);
- close_tags.push("</details>");
- write_str(
- &mut tmp_buf,
- format_args!(
- "<details class=\"toggle big-toggle\" open><summary>{}</summary>",
- write_impl_section_heading(
- &format!(
- "<span>Methods from {trait_}<Target = {type_}></span>",
- trait_ = trait_.print(cx),
- type_ = type_.print(cx),
- ),
- &id,
- )
- ),
- );
if let Some(def_id) = type_.def_id(cx.cache()) {
- cx.deref_id_map.borrow_mut().insert(def_id, id);
+ cx.deref_id_map.borrow_mut().insert(def_id, id.clone());
}
- (RenderMode::ForDeref { mut_: deref_mut_ }, derived_id, r#" class="impl-items""#)
+ (
+ Either::Right(fmt::from_fn(move |f| {
+ write!(
+ f,
+ "<details class=\"toggle big-toggle\" open><summary>{}</summary>",
+ write_impl_section_heading(
+ fmt::from_fn(|f| write!(
+ f,
+ "<span>Methods from {trait_}<Target = {type_}></span>",
+ trait_ = trait_.print(cx),
+ type_ = type_.print(cx),
+ )),
+ &id,
+ )
+ )
+ })),
+ Cow::Owned(derived_id),
+ )
}
};
let mut impls_buf = String::new();
@@ -1375,10 +1394,14 @@ fn render_assoc_items_inner(
);
}
if !impls_buf.is_empty() {
- write!(w, "{tmp_buf}<div id=\"{id}\"{class_html}>{impls_buf}</div>").unwrap();
- for tag in close_tags.into_iter().rev() {
- w.write_str(tag).unwrap();
- }
+ write!(
+ w,
+ "{section_heading}<div id=\"{id}\"{class_html}>{impls_buf}</div>{}",
+ matches!(what, AssocItemRender::DerefFor { .. })
+ .then_some("</details>")
+ .maybe_display(),
+ )
+ .unwrap();
}
}
@@ -1639,8 +1662,8 @@ fn render_impl(
// `containing_item` is used for rendering stability info. If the parent is a trait impl,
// `containing_item` will the grandparent, since trait impls can't have stability attached.
fn doc_impl_item(
- boring: &mut String,
- interesting: &mut String,
+ boring: impl fmt::Write,
+ interesting: impl fmt::Write,
cx: &Context<'_>,
item: &clean::Item,
parent: &clean::Item,
@@ -1649,7 +1672,7 @@ fn doc_impl_item(
is_default_item: bool,
trait_: Option<&clean::Trait>,
rendering_params: ImplRenderingParameters,
- ) {
+ ) -> fmt::Result {
let item_type = item.type_();
let name = item.name.as_ref().unwrap();
@@ -1724,15 +1747,16 @@ fn doc_impl_item(
);
}
}
- let w = if short_documented && trait_.is_some() { interesting } else { boring };
+ let mut w = if short_documented && trait_.is_some() {
+ Either::Left(interesting)
+ } else {
+ Either::Right(boring)
+ };
let toggled = !doc_buffer.is_empty();
if toggled {
let method_toggle_class = if item_type.is_method() { " method-toggle" } else { "" };
- write_str(
- w,
- format_args!("<details class=\"toggle{method_toggle_class}\" open><summary>"),
- );
+ write!(w, "<details class=\"toggle{method_toggle_class}\" open><summary>")?;
}
match &item.kind {
clean::MethodItem(..) | clean::RequiredMethodItem(_) => {
@@ -1747,172 +1771,151 @@ fn doc_impl_item(
.find(|item| item.name.map(|n| n == *name).unwrap_or(false))
})
.map(|item| format!("{}.{name}", item.type_()));
- write_str(
+ write!(
w,
- format_args!(
- "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
+ "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
{}",
- render_rightside(cx, item, render_mode)
- ),
- );
+ render_rightside(cx, item, render_mode)
+ )?;
if trait_.is_some() {
// Anchors are only used on trait impls.
- write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
+ write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
}
- write_str(
+ write!(
w,
- format_args!(
- "<h4 class=\"code-header\">{}</h4></section>",
- render_assoc_item(
- item,
- link.anchor(source_id.as_ref().unwrap_or(&id)),
- ItemType::Impl,
- cx,
- render_mode,
- ),
+ "<h4 class=\"code-header\">{}</h4></section>",
+ render_assoc_item(
+ item,
+ link.anchor(source_id.as_ref().unwrap_or(&id)),
+ ItemType::Impl,
+ cx,
+ render_mode,
),
- );
+ )?;
}
}
clean::RequiredAssocConstItem(generics, ty) => {
let source_id = format!("{item_type}.{name}");
let id = cx.derive_id(&source_id);
- write_str(
+ write!(
w,
- format_args!(
- "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
+ "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
{}",
- render_rightside(cx, item, render_mode)
- ),
- );
+ render_rightside(cx, item, render_mode)
+ )?;
if trait_.is_some() {
// Anchors are only used on trait impls.
- write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
+ write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
}
- write_str(
+ write!(
w,
- format_args!(
- "<h4 class=\"code-header\">{}</h4></section>",
- assoc_const(
- item,
- generics,
- ty,
- AssocConstValue::None,
- link.anchor(if trait_.is_some() { &source_id } else { &id }),
- 0,
- cx,
- )
+ "<h4 class=\"code-header\">{}</h4></section>",
+ assoc_const(
+ item,
+ generics,
+ ty,
+ AssocConstValue::None,
+ link.anchor(if trait_.is_some() { &source_id } else { &id }),
+ 0,
+ cx,
),
- );
+ )?;
}
clean::ProvidedAssocConstItem(ci) | clean::ImplAssocConstItem(ci) => {
let source_id = format!("{item_type}.{name}");
let id = cx.derive_id(&source_id);
- write_str(
+ write!(
w,
- format_args!(
- "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
+ "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
{}",
- render_rightside(cx, item, render_mode)
- ),
- );
+ render_rightside(cx, item, render_mode),
+ )?;
if trait_.is_some() {
// Anchors are only used on trait impls.
- write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
+ write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
}
- write_str(
+ write!(
w,
- format_args!(
- "<h4 class=\"code-header\">{}</h4></section>",
- assoc_const(
- item,
- &ci.generics,
- &ci.type_,
- match item.kind {
- clean::ProvidedAssocConstItem(_) =>
- AssocConstValue::TraitDefault(&ci.kind),
- clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind),
- _ => unreachable!(),
- },
- link.anchor(if trait_.is_some() { &source_id } else { &id }),
- 0,
- cx,
- )
+ "<h4 class=\"code-header\">{}</h4></section>",
+ assoc_const(
+ item,
+ &ci.generics,
+ &ci.type_,
+ match item.kind {
+ clean::ProvidedAssocConstItem(_) =>
+ AssocConstValue::TraitDefault(&ci.kind),
+ clean::ImplAssocConstItem(_) => AssocConstValue::Impl(&ci.kind),
+ _ => unreachable!(),
+ },
+ link.anchor(if trait_.is_some() { &source_id } else { &id }),
+ 0,
+ cx,
),
- );
+ )?;
}
clean::RequiredAssocTypeItem(generics, bounds) => {
let source_id = format!("{item_type}.{name}");
let id = cx.derive_id(&source_id);
- write_str(
+ write!(
w,
- format_args!(
- "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
+ "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
{}",
- render_rightside(cx, item, render_mode)
- ),
- );
+ render_rightside(cx, item, render_mode),
+ )?;
if trait_.is_some() {
// Anchors are only used on trait impls.
- write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
+ write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
}
- write_str(
+ write!(
w,
- format_args!(
- "<h4 class=\"code-header\">{}</h4></section>",
- assoc_type(
- item,
- generics,
- bounds,
- None,
- link.anchor(if trait_.is_some() { &source_id } else { &id }),
- 0,
- cx,
- )
+ "<h4 class=\"code-header\">{}</h4></section>",
+ assoc_type(
+ item,
+ generics,
+ bounds,
+ None,
+ link.anchor(if trait_.is_some() { &source_id } else { &id }),
+ 0,
+ cx,
),
- );
+ )?;
}
clean::AssocTypeItem(tydef, _bounds) => {
let source_id = format!("{item_type}.{name}");
let id = cx.derive_id(&source_id);
- write_str(
+ write!(
w,
- format_args!(
- "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
+ "<section id=\"{id}\" class=\"{item_type}{in_trait_class}\">\
{}",
- render_rightside(cx, item, render_mode)
- ),
- );
+ render_rightside(cx, item, render_mode),
+ )?;
if trait_.is_some() {
// Anchors are only used on trait impls.
- write_str(w, format_args!("<a href=\"#{id}\" class=\"anchor\">§</a>"));
+ write!(w, "<a href=\"#{id}\" class=\"anchor\">§</a>")?;
}
- write_str(
+ write!(
w,
- format_args!(
- "<h4 class=\"code-header\">{}</h4></section>",
- assoc_type(
- item,
- &tydef.generics,
- &[], // intentionally leaving out bounds
- Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)),
- link.anchor(if trait_.is_some() { &source_id } else { &id }),
- 0,
- cx,
- )
+ "<h4 class=\"code-header\">{}</h4></section>",
+ assoc_type(
+ item,
+ &tydef.generics,
+ &[], // intentionally leaving out bounds
+ Some(tydef.item_type.as_ref().unwrap_or(&tydef.type_)),
+ link.anchor(if trait_.is_some() { &source_id } else { &id }),
+ 0,
+ cx,
),
- );
+ )?;
}
- clean::StrippedItem(..) => return,
+ clean::StrippedItem(..) => return Ok(()),
_ => panic!("can't make docs for trait item with name {:?}", item.name),
}
- w.push_str(&info_buffer);
+ w.write_str(&info_buffer)?;
if toggled {
- w.push_str("</summary>");
- w.push_str(&doc_buffer);
- w.push_str("</details>");
+ write!(w, "</summary>{doc_buffer}</details>")?;
}
+ Ok(())
}
let mut impl_items = String::new();
@@ -1955,7 +1958,7 @@ fn doc_impl_item(
false,
trait_,
rendering_params,
- );
+ )?;
}
_ => {}
}
@@ -1973,7 +1976,7 @@ fn doc_impl_item(
false,
trait_,
rendering_params,
- );
+ )?;
}
for method in methods {
doc_impl_item(
@@ -1987,20 +1990,20 @@ fn doc_impl_item(
false,
trait_,
rendering_params,
- );
+ )?;
}
}
fn render_default_items(
- boring: &mut String,
- interesting: &mut String,
+ mut boring: impl fmt::Write,
+ mut interesting: impl fmt::Write,
cx: &Context<'_>,
t: &clean::Trait,
i: &clean::Impl,
parent: &clean::Item,
render_mode: RenderMode,
rendering_params: ImplRenderingParameters,
- ) {
+ ) -> fmt::Result {
for trait_item in &t.items {
// Skip over any default trait items that are impossible to reference
// (e.g. if it has a `Self: Sized` bound on an unsized type).
@@ -2020,8 +2023,8 @@ fn render_default_items(
let assoc_link = AssocItemLink::GotoSource(did.into(), &provided_methods);
doc_impl_item(
- boring,
- interesting,
+ &mut boring,
+ &mut interesting,
cx,
trait_item,
parent,
@@ -2030,8 +2033,9 @@ fn render_default_items(
true,
Some(t),
rendering_params,
- );
+ )?;
}
+ Ok(())
}
// If we've implemented a trait, then also emit documentation for all
@@ -2051,7 +2055,7 @@ fn render_default_items(
&i.impl_item,
render_mode,
rendering_params,
- );
+ )?;
}
}
if render_mode == RenderMode::Normal {
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 96847f1..39a631b 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -11,7 +11,7 @@
use rustc_index::IndexVec;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::hygiene::MacroKind;
-use rustc_span::symbol::{Symbol, kw, sym};
+use rustc_span::symbol::{Symbol, sym};
use tracing::{debug, info};
use super::type_layout::document_type_layout;
@@ -347,9 +347,12 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, tcx: TyCtxt<'_>) -> Ordering {
// but we actually want stable items to come first
return is_stable2.cmp(&is_stable1);
}
- let lhs = i1.name.unwrap_or(kw::Empty);
- let rhs = i2.name.unwrap_or(kw::Empty);
- compare_names(lhs.as_str(), rhs.as_str())
+ match (i1.name, i2.name) {
+ (Some(name1), Some(name2)) => compare_names(name1.as_str(), name2.as_str()),
+ (Some(_), None) => Ordering::Greater,
+ (None, Some(_)) => Ordering::Less,
+ (None, None) => Ordering::Equal,
+ }
}
let tcx = cx.tcx();
@@ -1229,12 +1232,13 @@ fn item_trait_alias(
wrap_item(w, |w| {
write!(
w,
- "{attrs}trait {name}{generics}{where_b} = {bounds};",
+ "{attrs}trait {name}{generics} = {bounds}{where_clause};",
attrs = render_attributes_in_pre(it, "", cx),
name = it.name.unwrap(),
generics = t.generics.print(cx),
- where_b = print_where_clause(&t.generics, cx, 0, Ending::Newline).maybe_display(),
bounds = bounds(&t.bounds, true, cx),
+ where_clause =
+ print_where_clause(&t.generics, cx, 0, Ending::NoNewline).maybe_display(),
)
})?;
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index b39701f..aff8684 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -709,8 +709,11 @@ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
let mut result = Vec::new();
for (index, item) in self.items.iter().enumerate() {
if let Some(ty) = &item.search_type
- && let my =
- ty.param_names.iter().map(|sym| sym.as_str()).collect::<Vec<_>>()
+ && let my = ty
+ .param_names
+ .iter()
+ .filter_map(|sym| sym.map(|sym| sym.to_string()))
+ .collect::<Vec<_>>()
&& my != prev
{
result.push((index, my.join(",")));
@@ -1109,7 +1112,7 @@ fn simplify_fn_type<'a, 'tcx>(
}
Type::BareFunction(ref bf) => {
let mut ty_generics = Vec::new();
- for ty in bf.decl.inputs.values.iter().map(|arg| &arg.type_) {
+ for ty in bf.decl.inputs.iter().map(|arg| &arg.type_) {
simplify_fn_type(
self_,
generics,
@@ -1372,7 +1375,7 @@ fn simplify_fn_constraint<'a>(
/// Used to allow type-based search on constants and statics.
fn make_nullary_fn(
clean_type: &clean::Type,
-) -> (Vec<RenderType>, Vec<RenderType>, Vec<Symbol>, Vec<Vec<RenderType>>) {
+) -> (Vec<RenderType>, Vec<RenderType>, Vec<Option<Symbol>>, Vec<Vec<RenderType>>) {
let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
let output = get_index_type(clean_type, vec![], &mut rgen);
(vec![], vec![output], vec![], vec![])
@@ -1387,7 +1390,7 @@ fn get_fn_inputs_and_outputs(
tcx: TyCtxt<'_>,
impl_or_trait_generics: Option<&(clean::Type, clean::Generics)>,
cache: &Cache,
-) -> (Vec<RenderType>, Vec<RenderType>, Vec<Symbol>, Vec<Vec<RenderType>>) {
+) -> (Vec<RenderType>, Vec<RenderType>, Vec<Option<Symbol>>, Vec<Vec<RenderType>>) {
let decl = &func.decl;
let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
@@ -1415,15 +1418,15 @@ fn get_fn_inputs_and_outputs(
(None, &func.generics)
};
- let mut arg_types = Vec::new();
- for arg in decl.inputs.values.iter() {
+ let mut param_types = Vec::new();
+ for param in decl.inputs.iter() {
simplify_fn_type(
self_,
generics,
- &arg.type_,
+ ¶m.type_,
tcx,
0,
- &mut arg_types,
+ &mut param_types,
&mut rgen,
false,
cache,
@@ -1436,15 +1439,15 @@ fn get_fn_inputs_and_outputs(
let mut simplified_params = rgen.into_iter().collect::<Vec<_>>();
simplified_params.sort_by_key(|(_, (idx, _))| -idx);
(
- arg_types,
+ param_types,
ret_types,
simplified_params
.iter()
.map(|(name, (_idx, _traits))| match name {
- SimplifiedParam::Symbol(name) => *name,
- SimplifiedParam::Anonymous(_) => kw::Empty,
+ SimplifiedParam::Symbol(name) => Some(*name),
+ SimplifiedParam::Anonymous(_) => None,
SimplifiedParam::AssociatedType(def_id, name) => {
- Symbol::intern(&format!("{}::{}", tcx.item_name(*def_id), name))
+ Some(Symbol::intern(&format!("{}::{}", tcx.item_name(*def_id), name)))
}
})
.collect(),
diff --git a/src/librustdoc/html/render/tests.rs b/src/librustdoc/html/render/tests.rs
index 657cd3c..327a308 100644
--- a/src/librustdoc/html/render/tests.rs
+++ b/src/librustdoc/html/render/tests.rs
@@ -47,8 +47,7 @@ fn test_all_types_prints_header_once() {
// Regression test for #82477
let all_types = AllTypes::new();
- let mut buffer = String::new();
- all_types.print(&mut buffer);
+ let buffer = all_types.print().to_string();
assert_eq!(1, buffer.matches("List of all items").count());
}
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 74d23b3..a6dd06b 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -585,7 +585,7 @@
margin-left: -140px;
border-left: none;
}
-.sidebar-resizer.active:before {
+.sidebar-resizer.active::before {
border-left: solid 2px var(--sidebar-resizer-active);
display: block;
height: 100%;
@@ -2044,7 +2044,7 @@
text-decoration: none;
}
-#settings-menu > a:before {
+#settings-menu > a::before {
/* Wheel <https://www.svgrepo.com/svg/384069/settings-cog-gear> */
content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
@@ -2064,7 +2064,7 @@
filter: var(--settings-menu-filter);
}
-button#toggle-all-docs:before {
+button#toggle-all-docs::before {
/* Custom arrow icon */
content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
@@ -2074,14 +2074,14 @@
filter: var(--settings-menu-filter);
}
-button#toggle-all-docs.will-expand:before {
+button#toggle-all-docs.will-expand::before {
/* Custom arrow icon */
content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg">\
<path d="M2,5l4,-4l4,4M2,7l4,4l4,-4" stroke="black" fill="none" stroke-width="2px"/></svg>');
}
-#help-button > a:before {
+#help-button > a::before {
/* Question mark with circle */
content: url('data:image/svg+xml,<svg width="18" height="18" viewBox="0 0 12 12" \
enable-background="new 0 0 12 12" xmlns="http://www.w3.org/2000/svg" fill="none">\
@@ -2093,17 +2093,17 @@
filter: var(--settings-menu-filter);
}
-button#toggle-all-docs:before,
-#help-button > a:before,
-#settings-menu > a:before {
+button#toggle-all-docs::before,
+#help-button > a::before,
+#settings-menu > a::before {
filter: var(--settings-menu-filter);
margin: 8px;
}
@media not (pointer: coarse) {
- button#toggle-all-docs:hover:before,
- #help-button > a:hover:before,
- #settings-menu > a:hover:before {
+ button#toggle-all-docs:hover::before,
+ #help-button > a:hover::before,
+ #settings-menu > a:hover::before {
filter: var(--settings-menu-hover-filter);
}
}
@@ -2125,7 +2125,7 @@
padding-bottom: 4px;
}
-#sidebar-button > a:before {
+#sidebar-button > a::before {
/* sidebar resizer image */
content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" \
fill="none" stroke="black">\
@@ -2400,21 +2400,21 @@
/* sidebar button opens modal
use hamburger button */
-.src #sidebar-button > a:before, .sidebar-menu-toggle:before {
+.src #sidebar-button > a::before, .sidebar-menu-toggle::before {
/* hamburger button image */
content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
viewBox="0 0 22 22" fill="none" stroke="black">\
<path d="M3,5h16M3,11h16M3,17h16" stroke-width="2.75"/></svg>');
opacity: 0.75;
}
-.sidebar-menu-toggle:hover:before,
-.sidebar-menu-toggle:active:before,
-.sidebar-menu-toggle:focus:before {
+.sidebar-menu-toggle:hover::before,
+.sidebar-menu-toggle:active::before,
+.sidebar-menu-toggle:focus::before {
opacity: 1;
}
/* src sidebar button opens a folder view */
-.src #sidebar-button > a:before {
+.src #sidebar-button > a::before {
/* folder image */
content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
viewBox="0 0 22 22" fill="none" stroke="black">\
@@ -2599,7 +2599,7 @@
}
/* sidebar button becomes topbar button */
- #sidebar-button > a:before {
+ #sidebar-button > a::before {
content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" \
viewBox="0 0 22 22" fill="none" stroke="black">\
<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5" stroke="%23777"/>\
@@ -2608,7 +2608,7 @@
width: 22px;
height: 22px;
}
- .sidebar-menu-toggle:before {
+ .sidebar-menu-toggle::before {
filter: var(--mobile-sidebar-menu-filter);
}
.sidebar-menu-toggle:hover {
@@ -3287,7 +3287,7 @@
}
:root[data-theme="ayu"] #settings-menu > a img,
-:root[data-theme="ayu"] #sidebar-button > a:before {
+:root[data-theme="ayu"] #sidebar-button > a::before {
filter: invert(100);
}
/* End theme: ayu */
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 9d8eb70f..f446c9f 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -11,7 +11,7 @@
use rustc_hir::def_id::DefId;
use rustc_metadata::rendered_const;
use rustc_middle::{bug, ty};
-use rustc_span::{Pos, Symbol};
+use rustc_span::{Pos, Symbol, kw};
use rustdoc_json_types::*;
use crate::clean::{self, ItemId};
@@ -84,8 +84,8 @@ fn convert_span(&self, span: clean::Span) -> Option<Span> {
let lo = span.lo(self.sess());
Some(Span {
filename: local_path,
- begin: (lo.line, lo.col.to_usize()),
- end: (hi.line, hi.col.to_usize()),
+ begin: (lo.line, lo.col.to_usize() + 1),
+ end: (hi.line, hi.col.to_usize() + 1),
})
} else {
None
@@ -609,9 +609,13 @@ fn from_clean(decl: clean::FnDecl, renderer: &JsonRenderer<'_>) -> Self {
let clean::FnDecl { inputs, output, c_variadic } = decl;
FunctionSignature {
inputs: inputs
- .values
.into_iter()
- .map(|arg| (arg.name.to_string(), arg.type_.into_json(renderer)))
+ .map(|param| {
+ // `_` is the most sensible name for missing param names.
+ let name = param.name.unwrap_or(kw::Underscore).to_string();
+ let type_ = param.type_.into_json(renderer);
+ (name, type_)
+ })
.collect(),
output: if output.is_unit() { None } else { Some(output.into_json(renderer)) },
is_c_variadic: c_variadic,
diff --git a/src/librustdoc/json/mod.rs b/src/librustdoc/json/mod.rs
index ba27eed..131a12c 100644
--- a/src/librustdoc/json/mod.rs
+++ b/src/librustdoc/json/mod.rs
@@ -14,6 +14,7 @@
use std::path::PathBuf;
use std::rc::Rc;
+use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
@@ -123,6 +124,58 @@ fn serialize_and_write<T: Write>(
}
}
+fn target(sess: &rustc_session::Session) -> types::Target {
+ // Build a set of which features are enabled on this target
+ let globally_enabled_features: FxHashSet<&str> =
+ sess.unstable_target_features.iter().map(|name| name.as_str()).collect();
+
+ // Build a map of target feature stability by feature name
+ use rustc_target::target_features::Stability;
+ let feature_stability: FxHashMap<&str, Stability> = sess
+ .target
+ .rust_target_features()
+ .into_iter()
+ .copied()
+ .map(|(name, stability, _)| (name, stability))
+ .collect();
+
+ types::Target {
+ triple: sess.opts.target_triple.tuple().into(),
+ target_features: sess
+ .target
+ .rust_target_features()
+ .into_iter()
+ .copied()
+ .filter(|(_, stability, _)| {
+ // Describe only target features which the user can toggle
+ stability.toggle_allowed().is_ok()
+ })
+ .map(|(name, stability, implied_features)| {
+ types::TargetFeature {
+ name: name.into(),
+ unstable_feature_gate: match stability {
+ Stability::Unstable(feature_gate) => Some(feature_gate.as_str().into()),
+ _ => None,
+ },
+ implies_features: implied_features
+ .into_iter()
+ .copied()
+ .filter(|name| {
+ // Imply only target features which the user can toggle
+ feature_stability
+ .get(name)
+ .map(|stability| stability.toggle_allowed().is_ok())
+ .unwrap_or(false)
+ })
+ .map(String::from)
+ .collect(),
+ globally_enabled: globally_enabled_features.contains(name),
+ }
+ })
+ .collect(),
+ }
+}
+
impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
fn descr() -> &'static str {
"json"
@@ -248,6 +301,12 @@ fn after_krate(&mut self) -> Result<(), Error> {
let e = ExternalCrate { crate_num: LOCAL_CRATE };
let index = (*self.index).clone().into_inner();
+ // Note that tcx.rust_target_features is inappropriate here because rustdoc tries to run for
+ // multiple targets: https://github.com/rust-lang/rust/pull/137632
+ //
+ // We want to describe a single target, so pass tcx.sess rather than tcx.
+ let target = target(self.tcx.sess);
+
debug!("Constructing Output");
let output_crate = types::Crate {
root: self.id_from_item_default(e.def_id().into()),
@@ -288,6 +347,7 @@ fn after_krate(&mut self) -> Result<(), Error> {
)
})
.collect(),
+ target,
format_version: types::FORMAT_VERSION,
};
if let Some(ref out_dir) = self.out_dir {
diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs
index fdbb792..36f5889 100644
--- a/src/librustdoc/passes/collect_intra_doc_links.rs
+++ b/src/librustdoc/passes/collect_intra_doc_links.rs
@@ -59,8 +59,13 @@ fn filter_assoc_items_by_name_and_namespace(
ident: Ident,
ns: Namespace,
) -> impl Iterator<Item = &ty::AssocItem> {
- tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name).filter(move |item| {
- item.kind.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of)
+ let iter: Box<dyn Iterator<Item = &ty::AssocItem>> = if !ident.name.is_empty() {
+ Box::new(tcx.associated_items(assoc_items_of).filter_by_name_unhygienic(ident.name))
+ } else {
+ Box::new([].iter())
+ };
+ iter.filter(move |item| {
+ item.namespace() == ns && tcx.hygienic_eq(ident, item.ident(tcx), assoc_items_of)
})
}
@@ -743,7 +748,7 @@ fn resolve_associated_item(
ns,
)
.map(|item| {
- let res = Res::Def(item.kind.as_def_kind(), item.def_id);
+ let res = Res::Def(item.as_def_kind(), item.def_id);
(res, item.def_id)
})
.collect::<Vec<_>>(),
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index 137fe4c..64223b5 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -30,7 +30,7 @@
/// This integer is incremented with every breaking change to the API,
/// and is returned along with the JSON blob as [`Crate::format_version`].
/// Consuming code should assert that this value matches the format version(s) that it supports.
-pub const FORMAT_VERSION: u32 = 43;
+pub const FORMAT_VERSION: u32 = 45;
/// The root of the emitted JSON blob.
///
@@ -52,11 +52,67 @@ pub struct Crate {
pub paths: HashMap<Id, ItemSummary>,
/// Maps `crate_id` of items to a crate name and html_root_url if it exists.
pub external_crates: HashMap<u32, ExternalCrate>,
+ /// Information about the target for which this documentation was generated
+ pub target: Target,
/// A single version number to be used in the future when making backwards incompatible changes
/// to the JSON output.
pub format_version: u32,
}
+/// Information about a target
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
+pub struct Target {
+ /// The target triple for which this documentation was generated
+ pub triple: String,
+ /// A list of features valid for use in `#[target_feature]` attributes
+ /// for the target where this rustdoc JSON was generated.
+ pub target_features: Vec<TargetFeature>,
+}
+
+/// Information about a target feature.
+///
+/// Rust target features are used to influence code generation, especially around selecting
+/// instructions which are not universally supported by the target architecture.
+///
+/// Target features are commonly enabled by the [`#[target_feature]` attribute][1] to influence code
+/// generation for a particular function, and less commonly enabled by compiler options like
+/// `-Ctarget-feature` or `-Ctarget-cpu`. Targets themselves automatically enable certain target
+/// features by default, for example because the target's ABI specification requires saving specific
+/// registers which only exist in an architectural extension.
+///
+/// Target features can imply other target features: for example, x86-64 `avx2` implies `avx`, and
+/// aarch64 `sve2` implies `sve`, since both of these architectural extensions depend on their
+/// predecessors.
+///
+/// Target features can be probed at compile time by [`#[cfg(target_feature)]`][2] or `cfg!(…)`
+/// conditional compilation to determine whether a target feature is enabled in a particular
+/// context.
+///
+/// [1]: https://doc.rust-lang.org/stable/reference/attributes/codegen.html#the-target_feature-attribute
+/// [2]: https://doc.rust-lang.org/reference/conditional-compilation.html#target_feature
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
+pub struct TargetFeature {
+ /// The name of this target feature.
+ pub name: String,
+ /// Other target features which are implied by this target feature, if any.
+ pub implies_features: Vec<String>,
+ /// If this target feature is unstable, the name of the associated language feature gate.
+ pub unstable_feature_gate: Option<String>,
+ /// Whether this feature is globally enabled for this compilation session.
+ ///
+ /// Target features can be globally enabled implicitly as a result of the target's definition.
+ /// For example, x86-64 hardware floating point ABIs require saving x87 and SSE2 registers,
+ /// which in turn requires globally enabling the `x87` and `sse2` target features so that the
+ /// generated machine code conforms to the target's ABI.
+ ///
+ /// Target features can also be globally enabled explicitly as a result of compiler flags like
+ /// [`-Ctarget-feature`][1] or [`-Ctarget-cpu`][2].
+ ///
+ /// [1]: https://doc.rust-lang.org/beta/rustc/codegen-options/index.html#target-feature
+ /// [2]: https://doc.rust-lang.org/beta/rustc/codegen-options/index.html#target-cpu
+ pub globally_enabled: bool,
+}
+
/// Metadata of a crate, either the same crate on which `rustdoc` was invoked, or its dependency.
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ExternalCrate {
@@ -149,9 +205,9 @@ pub struct Item {
pub struct Span {
/// The path to the source file for this span relative to the path `rustdoc` was invoked with.
pub filename: PathBuf,
- /// Zero indexed Line and Column of the first character of the `Span`
+ /// One indexed Line and Column of the first character of the `Span`.
pub begin: (usize, usize),
- /// Zero indexed Line and Column of the last character of the `Span`
+ /// One indexed Line and Column of the last character of the `Span`.
pub end: (usize, usize),
}
diff --git a/src/stage0 b/src/stage0
index b3841d2..6e86501 100644
--- a/src/stage0
+++ b/src/stage0
@@ -476,4 +476,4 @@
dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=0ea7e17d7bb67d6a6c4b2f864aaffcd96512f15f17f0acc63751eb1df6c486a7
dist/2025-04-02/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=b73d37b704ab58921172cc561f5598db6a504dcd4d7980966f7c26caaf6d3594
dist/2025-04-02/rustc-nightly-x86_64-unknown-netbsd.tar.gz=986f6c594d37bcbd3833e053640ba8775f68d26a65c5618386654ef55d7b3542
-dist/2025-04-02/rustc-nightly-x86_64-unknown-netbsd.tar.xz=c0d9a88c30d2ab38ec3a11fabb5515ed9bc3ac1a8e35a438d68bf7ff82f6b843
\ No newline at end of file
+dist/2025-04-02/rustc-nightly-x86_64-unknown-netbsd.tar.xz=c0d9a88c30d2ab38ec3a11fabb5515ed9bc3ac1a8e35a438d68bf7ff82f6b843
diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs
index f510727..d679084 100644
--- a/src/tools/bump-stage0/src/main.rs
+++ b/src/tools/bump-stage0/src/main.rs
@@ -65,32 +65,33 @@ fn update_stage0_file(mut self) -> Result<(), Error> {
nightly_branch,
} = &self.config;
- file_content.push_str(&format!("dist_server={}", dist_server));
- file_content.push_str(&format!("\nartifacts_server={}", artifacts_server));
+ file_content.push_str(&format!("dist_server={}\n", dist_server));
+ file_content.push_str(&format!("artifacts_server={}\n", artifacts_server));
file_content.push_str(&format!(
- "\nartifacts_with_llvm_assertions_server={}",
+ "artifacts_with_llvm_assertions_server={}\n",
artifacts_with_llvm_assertions_server
));
- file_content.push_str(&format!("\ngit_merge_commit_email={}", git_merge_commit_email));
- file_content.push_str(&format!("\ngit_repository={}", git_repository));
- file_content.push_str(&format!("\nnightly_branch={}", nightly_branch));
+ file_content.push_str(&format!("git_merge_commit_email={}\n", git_merge_commit_email));
+ file_content.push_str(&format!("git_repository={}\n", git_repository));
+ file_content.push_str(&format!("nightly_branch={}\n", nightly_branch));
- file_content.push_str("\n\n");
+ file_content.push_str("\n");
file_content.push_str(COMMENTS);
+ file_content.push_str("\n");
let compiler = self.detect_compiler()?;
- file_content.push_str(&format!("\ncompiler_date={}", compiler.date));
- file_content.push_str(&format!("\ncompiler_version={}", compiler.version));
+ file_content.push_str(&format!("compiler_date={}\n", compiler.date));
+ file_content.push_str(&format!("compiler_version={}\n", compiler.version));
if let Some(rustfmt) = self.detect_rustfmt()? {
- file_content.push_str(&format!("\nrustfmt_date={}", rustfmt.date));
- file_content.push_str(&format!("\nrustfmt_version={}", rustfmt.version));
+ file_content.push_str(&format!("rustfmt_date={}\n", rustfmt.date));
+ file_content.push_str(&format!("rustfmt_version={}\n", rustfmt.version));
}
file_content.push_str("\n");
for (key, value) in self.checksums {
- file_content.push_str(&format!("\n{}={}", key, value));
+ file_content.push_str(&format!("{}={}\n", key, value));
}
std::fs::write(PATH, file_content)?;
diff --git a/src/tools/cargo b/src/tools/cargo
index 0e93c5b..d811228 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit 0e93c5bf6a1d5ee7bc2af63d1afb16cd28793601
+Subproject commit d811228b14ae2707323f37346aee3f4147e247e6
diff --git a/src/tools/clippy/.github/workflows/clippy_changelog.yml b/src/tools/clippy/.github/workflows/clippy_changelog.yml
index a2657bf..1e97154 100644
--- a/src/tools/clippy/.github/workflows/clippy_changelog.yml
+++ b/src/tools/clippy/.github/workflows/clippy_changelog.yml
@@ -24,7 +24,7 @@
- name: Check Changelog
if: ${{ github.event_name == 'pull_request' }}
run: |
- body=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -s "https://api.github.com/repos/rust-lang/rust-clippy/pulls/$PR_NUMBER" | \
+ body=$(curl -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -s "https://api.github.com/repos/${{ github.repository }}/pulls/$PR_NUMBER" | \
python -c "import sys, json; print(json.load(sys.stdin)['body'])")
output=$(awk '/^changelog:\s*\S/ && !/changelog: \[.*\]: your change/' <<< "$body" | sed "s/changelog:\s*//g")
if [ -z "$output" ]; then
diff --git a/src/tools/clippy/.github/workflows/clippy_mq.yml b/src/tools/clippy/.github/workflows/clippy_mq.yml
index 741e745..07d5a08 100644
--- a/src/tools/clippy/.github/workflows/clippy_mq.yml
+++ b/src/tools/clippy/.github/workflows/clippy_mq.yml
@@ -66,7 +66,7 @@
run: cargo test --features internal -- --skip dogfood
- name: Test clippy_lints
- run: cargo test --features internal
+ run: cargo test
working-directory: clippy_lints
- name: Test clippy_utils
diff --git a/src/tools/clippy/.github/workflows/clippy_pr.yml b/src/tools/clippy/.github/workflows/clippy_pr.yml
index 80523d9..880ebd6 100644
--- a/src/tools/clippy/.github/workflows/clippy_pr.yml
+++ b/src/tools/clippy/.github/workflows/clippy_pr.yml
@@ -42,7 +42,7 @@
run: cargo test --features internal
- name: Test clippy_lints
- run: cargo test --features internal
+ run: cargo test
working-directory: clippy_lints
- name: Test clippy_utils
diff --git a/src/tools/clippy/.github/workflows/deploy.yml b/src/tools/clippy/.github/workflows/deploy.yml
index b42f3e7..ede19c1 100644
--- a/src/tools/clippy/.github/workflows/deploy.yml
+++ b/src/tools/clippy/.github/workflows/deploy.yml
@@ -8,6 +8,10 @@
tags:
- rust-1.**
+concurrency:
+ group: ${{ github.workflow }}
+ cancel-in-progress: false
+
env:
TARGET_BRANCH: 'gh-pages'
SHA: '${{ github.sha }}'
diff --git a/src/tools/clippy/.github/workflows/lintcheck.yml b/src/tools/clippy/.github/workflows/lintcheck.yml
index d487c7d..70c8059 100644
--- a/src/tools/clippy/.github/workflows/lintcheck.yml
+++ b/src/tools/clippy/.github/workflows/lintcheck.yml
@@ -66,7 +66,7 @@
- name: Run lintcheck
if: steps.cache-json.outputs.cache-hit != 'true'
- run: ./target/debug/lintcheck --format json --all-lints --crates-toml ./lintcheck/ci_crates.toml
+ run: env CLIPPY_CONF_DIR="$PWD/lintcheck/ci-config" ./target/debug/lintcheck --format json --all-lints --crates-toml ./lintcheck/ci_crates.toml
- name: Upload base JSON
uses: actions/upload-artifact@v4
@@ -97,7 +97,7 @@
run: cargo build --manifest-path=lintcheck/Cargo.toml
- name: Run lintcheck
- run: ./target/debug/lintcheck --format json --all-lints --crates-toml ./lintcheck/ci_crates.toml
+ run: env CLIPPY_CONF_DIR="$PWD/lintcheck/ci-config" ./target/debug/lintcheck --format json --all-lints --crates-toml ./lintcheck/ci_crates.toml
- name: Upload head JSON
uses: actions/upload-artifact@v4
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 1bf4b51..2b62c9a 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,68 @@
## Unreleased / Beta / In Rust Nightly
-[609cd310...master](https://github.com/rust-lang/rust-clippy/compare/609cd310...master)
+[3e3715c3...master](https://github.com/rust-lang/rust-clippy/compare/3e3715c3...master)
+
+## Rust 1.86
+
+Current stable, released 2025-04-03
+
+[View all 108 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-12-27T15%3A11%3A38Z..2025-02-06T13%3A57%3A58Z+base%3Amaster)
+
+### New Lints
+
+* Added [`unneeded_struct_pattern`] to `style` [#13465](https://github.com/rust-lang/rust-clippy/pull/13465)
+* Added [`doc_overindented_list_items`] to `style` [#13711](https://github.com/rust-lang/rust-clippy/pull/13711)
+* Added [`manual_ok_err`] to `complexity` [#13740](https://github.com/rust-lang/rust-clippy/pull/13740)
+* Added [`non_std_lazy_statics`] to `pedantic` [#13770](https://github.com/rust-lang/rust-clippy/pull/13770)
+* Added [`manual_repeat_n`] to `style` [#13858](https://github.com/rust-lang/rust-clippy/pull/13858)
+* Added [`manual_option_as_slice`] to `complexity` [#13901](https://github.com/rust-lang/rust-clippy/pull/13901)
+* Added [`double_ended_iterator_last`] to `perf` [#13922](https://github.com/rust-lang/rust-clippy/pull/13922)
+* Added [`useless_nonzero_new_unchecked`] to `complexity` [#13993](https://github.com/rust-lang/rust-clippy/pull/13993)
+* Added [`sliced_string_as_bytes`] to `perf` [#14002](https://github.com/rust-lang/rust-clippy/pull/14002)
+* Added [`unnecessary_semicolon`] to `pedantic` [#14032](https://github.com/rust-lang/rust-clippy/pull/14032)
+* Added [`return_and_then`] to `restriction` [#14051](https://github.com/rust-lang/rust-clippy/pull/14051)
+* Added [`manual_slice_fill`] to `style` [#14082](https://github.com/rust-lang/rust-clippy/pull/14082)
+* Added [`precedence_bits`] to `restriction` [#14115](https://github.com/rust-lang/rust-clippy/pull/14115)
+
+### Moves and Deprecations
+
+* Moved [`redundant_locals`] to `suspicious` (from `correctness`, now warn-by-default)
+ [#13747](https://github.com/rust-lang/rust-clippy/pull/13747)
+* Moved [`format_push_string`] to `pedantic` (from `restriction`)
+ [#13894](https://github.com/rust-lang/rust-clippy/pull/13894)
+* Moved [`format_collect`] to `pedantic` (from `perf`, now allow-by-default)
+ [#13894](https://github.com/rust-lang/rust-clippy/pull/13894)
+* Moved [`mutex_integer`] to `restriction` (from `nursery`) [#14110](https://github.com/rust-lang/rust-clippy/pull/14110)
+
+### Enhancements
+
+* Add `lint-inconsistent-struct-field-initializers` configuration option to [`inconsistent_struct_constructor`]
+ [#13737](https://github.com/rust-lang/rust-clippy/pull/13737)
+* [`len_zero`] now also triggers if deref target implements `is_empty()`
+ [#13871](https://github.com/rust-lang/rust-clippy/pull/13871)
+* [`obfuscated_if_else`] now also triggers for the `.then(..).unwrap_or(..)` pattern
+ [#14021](https://github.com/rust-lang/rust-clippy/pull/14021)
+
+### False Positive Fixes
+
+* [`trailing_empty_array`] no longer triggers in tests [#13844](https://github.com/rust-lang/rust-clippy/pull/13844)
+* [`missing_const_for_fn`] no longer triggers in tests [#13945](https://github.com/rust-lang/rust-clippy/pull/13945)
+* [`significant_drop_in_scrutinee`]: do not falsely warn for temporaries created by `.await` expansion
+ [#13985](https://github.com/rust-lang/rust-clippy/pull/13985)
+
+### ICE Fixes
+
+* [`borrow_interior_mutable_const`] Fix an ICE that can occur when taking a reference to a tuple/`struct` field of an
+ interior mutable `const` [#13877](https://github.com/rust-lang/rust-clippy/pull/13877)
+
+### Others
+
+* Clippy now uses Rust edition 2024 [#13751](https://github.com/rust-lang/rust-clippy/pull/13751)
## Rust 1.85
-Current stable, released 2025-02-20
+Released 2025-02-20
[View all 72 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2024-11-15T19%3A31%3A08Z..2024-12-26T13%3A59%3A48Z+base%3Amaster)
@@ -5516,6 +5573,7 @@
[`cast_slice_different_sizes`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_different_sizes
[`cast_slice_from_raw_parts`]: https://rust-lang.github.io/rust-clippy/master/index.html#cast_slice_from_raw_parts
[`cfg_not_test`]: https://rust-lang.github.io/rust-clippy/master/index.html#cfg_not_test
+[`char_indices_as_byte_indices`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_indices_as_byte_indices
[`char_lit_as_u8`]: https://rust-lang.github.io/rust-clippy/master/index.html#char_lit_as_u8
[`chars_last_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_last_cmp
[`chars_next_cmp`]: https://rust-lang.github.io/rust-clippy/master/index.html#chars_next_cmp
@@ -5681,6 +5739,7 @@
[`if_same_then_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_same_then_else
[`if_then_some_else_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none
[`ifs_same_cond`]: https://rust-lang.github.io/rust-clippy/master/index.html#ifs_same_cond
+[`ignore_without_reason`]: https://rust-lang.github.io/rust-clippy/master/index.html#ignore_without_reason
[`ignored_unit_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ignored_unit_patterns
[`impl_hash_borrow_with_str_and_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_hash_borrow_with_str_and_bytes
[`impl_trait_in_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#impl_trait_in_params
@@ -5783,12 +5842,14 @@
[`macro_metavars_in_unsafe`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_metavars_in_unsafe
[`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
[`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
+[`manual_abs_diff`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_abs_diff
[`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert
[`manual_async_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_async_fn
[`manual_bits`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits
[`manual_c_str_literals`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals
[`manual_clamp`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp
[`manual_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_contains
+[`manual_dangling_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_dangling_ptr
[`manual_div_ceil`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_div_ceil
[`manual_filter`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter
[`manual_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_filter_map
@@ -6055,6 +6116,7 @@
[`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
[`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing
[`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes
+[`redundant_test_prefix`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_test_prefix
[`redundant_type_annotations`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_type_annotations
[`ref_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_as_ptr
[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference
@@ -6156,6 +6218,7 @@
[`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting
[`suspicious_xor_used_as_pow`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_xor_used_as_pow
[`swap_ptr_to_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#swap_ptr_to_ref
+[`swap_with_temporary`]: https://rust-lang.github.io/rust-clippy/master/index.html#swap_with_temporary
[`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments
[`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment
[`temporary_cstring_as_ptr`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_cstring_as_ptr
@@ -6346,6 +6409,7 @@
[`await-holding-invalid-types`]: https://doc.rust-lang.org/clippy/lint_configuration.html#await-holding-invalid-types
[`cargo-ignore-publish`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cargo-ignore-publish
[`check-incompatible-msrv-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-incompatible-msrv-in-tests
+[`check-inconsistent-struct-field-initializers`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-inconsistent-struct-field-initializers
[`check-private-items`]: https://doc.rust-lang.org/clippy/lint_configuration.html#check-private-items
[`cognitive-complexity-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#cognitive-complexity-threshold
[`disallowed-macros`]: https://doc.rust-lang.org/clippy/lint_configuration.html#disallowed-macros
@@ -6362,7 +6426,7 @@
[`future-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#future-size-threshold
[`ignore-interior-mutability`]: https://doc.rust-lang.org/clippy/lint_configuration.html#ignore-interior-mutability
[`large-error-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#large-error-threshold
-[`lint-inconsistent-struct-field-initializers`]: https://doc.rust-lang.org/clippy/lint_configuration.html#lint-inconsistent-struct-field-initializers
+[`lint-commented-code`]: https://doc.rust-lang.org/clippy/lint_configuration.html#lint-commented-code
[`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold
[`matches-for-let-else`]: https://doc.rust-lang.org/clippy/lint_configuration.html#matches-for-let-else
[`max-fn-params-bools`]: https://doc.rust-lang.org/clippy/lint_configuration.html#max-fn-params-bools
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index f5a8e3d..1cfc1c1 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "clippy"
# begin autogenerated version
-version = "0.1.87"
+version = "0.1.88"
# end autogenerated version
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
@@ -27,6 +27,7 @@
clippy_lints = { path = "clippy_lints" }
clippy_utils = { path = "clippy_utils" }
rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" }
+clippy_lints_internal = { path = "clippy_lints_internal", optional = true }
tempfile = { version = "3.3", optional = true }
termize = "0.1"
color-print = "0.3.4"
@@ -43,7 +44,7 @@
filetime = "0.2.9"
itertools = "0.12"
pulldown-cmark = { version = "0.11", default-features = false, features = ["html"] }
-rinja = { version = "0.3", default-features = false, features = ["config"] }
+askama = { version = "0.13", default-features = false, features = ["alloc", "config", "derive"] }
# UI test dependencies
clippy_utils = { path = "clippy_utils" }
@@ -58,8 +59,8 @@
rustc_tools_util = { path = "rustc_tools_util", version = "0.4.2" }
[features]
-integration = ["tempfile"]
-internal = ["clippy_lints/internal", "tempfile"]
+integration = ["dep:tempfile"]
+internal = ["dep:clippy_lints_internal", "dep:tempfile"]
[package.metadata.rust-analyzer]
# This package uses #[feature(rustc_private)]
diff --git a/src/tools/clippy/rinja.toml b/src/tools/clippy/askama.toml
similarity index 100%
rename from src/tools/clippy/rinja.toml
rename to src/tools/clippy/askama.toml
diff --git a/src/tools/clippy/book/src/SUMMARY.md b/src/tools/clippy/book/src/SUMMARY.md
index 19328fd..39fe735 100644
--- a/src/tools/clippy/book/src/SUMMARY.md
+++ b/src/tools/clippy/book/src/SUMMARY.md
@@ -30,6 +30,7 @@
- [Updating the Changelog](development/infrastructure/changelog_update.md)
- [Release a New Version](development/infrastructure/release.md)
- [The Clippy Book](development/infrastructure/book.md)
+ - [Benchmarking Clippy](development/infrastructure/benchmarking.md)
- [Proposals](development/proposals/README.md)
- [Roadmap 2021](development/proposals/roadmap-2021.md)
- [Syntax Tree Patterns](development/proposals/syntax-tree-patterns.md)
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index 0b9010f..e5e82ed 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -99,6 +99,7 @@
impl A {
pub fn fo(&self) {}
pub fn foo(&self) {}
+ //~^ foo_functions
pub fn food(&self) {}
}
@@ -106,12 +107,14 @@
trait B {
fn fo(&self) {}
fn foo(&self) {}
+ //~^ foo_functions
fn food(&self) {}
}
// Plain functions
fn fo() {}
fn foo() {}
+//~^ foo_functions
fn food() {}
fn main() {
@@ -122,17 +125,24 @@
}
```
-Now we can run the test with `TESTNAME=foo_functions cargo uibless`, currently
-this test is meaningless though.
+Note that we are adding comment annotations with the name of our lint to mark
+lines where we expect an error. Except for very specific situations
+(`//@check-pass`), at least one error marker must be present in a test file for
+it to be accepted.
+
+Once we have implemented our lint we can run `TESTNAME=foo_functions cargo
+uibless` to generate the `.stderr` file. If our lint makes use of structured
+suggestions then this command will also generate the corresponding `.fixed`
+file.
While we are working on implementing our lint, we can keep running the UI test.
That allows us to check if the output is turning into what we want by checking the
`.stderr` file that gets updated on every test run.
-Running `TESTNAME=foo_functions cargo uitest` should pass on its own. When we
-commit our lint, we need to commit the generated `.stderr` files, too. In
-general, you should only commit files changed by `cargo bless` for the
-specific lint you are creating/editing.
+Once we have implemented our lint running `TESTNAME=foo_functions cargo uitest`
+should pass on its own. When we commit our lint, we need to commit the generated
+ `.stderr` and if applicable `.fixed` files, too. In general, you should only
+ commit files changed by `cargo bless` for the specific lint you are creating/editing.
> _Note:_ you can run multiple test files by specifying a comma separated list:
> `TESTNAME=foo_functions,test2,test3`.
diff --git a/src/tools/clippy/book/src/development/basics.md b/src/tools/clippy/book/src/development/basics.md
index 931e5c3..4219724 100644
--- a/src/tools/clippy/book/src/development/basics.md
+++ b/src/tools/clippy/book/src/development/basics.md
@@ -147,7 +147,7 @@
First, take note of the toolchain
[override](https://rust-lang.github.io/rustup/overrides.html) in
-`/rust-toolchain`. We will use this override to install Clippy into the right
+`/rust-toolchain.toml`. We will use this override to install Clippy into the right
toolchain.
> Tip: You can view the active toolchain for the current directory with `rustup
diff --git a/src/tools/clippy/book/src/development/common_tools_writing_lints.md b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
index 051febc..2e39f27 100644
--- a/src/tools/clippy/book/src/development/common_tools_writing_lints.md
+++ b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
@@ -159,19 +159,21 @@
To check if our type defines a method called `some_method`:
```rust
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::return_ty;
+use clippy_utils::ty::is_type_lang_item;
+use clippy_utils::{sym, return_ty};
impl<'tcx> LateLintPass<'tcx> for MyTypeImpl {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx ImplItem<'_>) {
// Check if item is a method/function
if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
// Check the method is named `some_method`
- && impl_item.ident.name.as_str() == "some_method"
+ //
+ // Add `some_method` to `clippy_utils::sym` if it's not already there
+ && impl_item.ident.name == sym::some_method
// We can also check it has a parameter `self`
&& signature.decl.implicit_self.has_implicit_self()
// We can go further and even check if its return type is `String`
- && is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id), sym!(string_type))
+ && is_type_lang_item(cx, return_ty(cx, impl_item.hir_id), LangItem::String)
{
// ...
}
diff --git a/src/tools/clippy/book/src/development/defining_lints.md b/src/tools/clippy/book/src/development/defining_lints.md
index 169cecd..cb6d7b7 100644
--- a/src/tools/clippy/book/src/development/defining_lints.md
+++ b/src/tools/clippy/book/src/development/defining_lints.md
@@ -9,7 +9,7 @@
A lint type is the category of items and expressions in which your lint focuses on.
-As of the writing of this documentation update, there are 12 _types_ of lints
+As of the writing of this documentation update, there are 11 _types_ of lints
besides the numerous standalone lints living under `clippy_lints/src/`:
- `cargo`
@@ -23,7 +23,6 @@
- `transmute`
- `types`
- `unit_types`
-- `utils / internal` (Clippy internal lints)
These types group together lints that share some common behaviors. For instance,
`functions` groups together lints that deal with some aspects of functions in
diff --git a/src/tools/clippy/book/src/development/infrastructure/benchmarking.md b/src/tools/clippy/book/src/development/infrastructure/benchmarking.md
new file mode 100644
index 0000000..a3ebce9
--- /dev/null
+++ b/src/tools/clippy/book/src/development/infrastructure/benchmarking.md
@@ -0,0 +1,55 @@
+# Benchmarking Clippy
+
+Benchmarking Clippy is similar to using our Lintcheck tool, in fact, it even
+uses the same tool! Just by adding a `--perf` flag it will transform Lintcheck
+into a very simple but powerful benchmarking tool!
+
+It requires having the [`perf` tool][perf] installed, as `perf` is what's actually
+profiling Clippy under the hood.
+
+The lintcheck `--perf` tool generates a series of `perf.data` in the
+`target/lintcheck/sources/<package>-<version>` directories. Each `perf.data`
+corresponds to the package which is contained.
+
+Lintcheck uses the `-g` flag, meaning that you can get stack traces for richer
+analysis, including with tools such as [flamegraph][flamegraph-perf]
+(or [`flamegraph-rs`][flamegraph-rs]).
+
+Currently, we only measure instruction count, as it's the most reproducible metric
+and [rustc-perf][rustc-perf] also considers it the main number to focus on.
+
+## Benchmarking a PR
+
+Having a benchmarking tool directly implemented into lintcheck gives us the
+ability to benchmark any given PR just by making a before and after
+
+Here's the way you can get into any PR, benchmark it, and then benchmark
+`master`.
+
+The first `perf.data` will not have any numbers appended, but any subsequent
+benchmark will be written to `perf.data.number` with a number growing for 0.
+All benchmarks are compressed so that you can
+
+```bash
+git fetch upstream pull/<PR_NUMBER>/head:<BRANCH_NAME>
+git switch BRANCHNAME
+
+# Bench
+cargo lintcheck --perf
+
+# Get last common commit, checkout that
+LAST_COMMIT=$(git log BRANCHNAME..master --oneline | tail -1 | cut -c 1-11)
+git switch -c temporary $LAST_COMMIT
+
+# We're now on master
+
+# Bench
+cargo lintcheck --perf
+perf diff ./target/lintcheck/sources/CRATE/perf.data ./target/lintcheck/sources/CRATE/perf.data.0
+```
+
+
+[perf]: https://perfwiki.github.io/main/
+[flamegraph-perf]: https://github.com/brendangregg/FlameGraph
+[flamegraph-rs]: https://github.com/flamegraph-rs/flamegraph
+[rustc-perf]: https://github.com/rust-lang/rustc-perf
diff --git a/src/tools/clippy/book/src/development/infrastructure/release.md b/src/tools/clippy/book/src/development/infrastructure/release.md
index 8b080c0..a429e0d 100644
--- a/src/tools/clippy/book/src/development/infrastructure/release.md
+++ b/src/tools/clippy/book/src/development/infrastructure/release.md
@@ -88,9 +88,6 @@
After updating the `stable` branch, tag the HEAD commit and push it to the
Clippy repo.
-> Note: Only push the tag once the Deploy GitHub action of the `beta` branch is
-> finished. Otherwise the deploy for the tag might fail.
-
```bash
git tag rust-1.XX.0 # XX should be exchanged with the corresponding version
git push upstream rust-1.XX.0 # `upstream` is the `rust-lang/rust-clippy` remote
diff --git a/src/tools/clippy/book/src/development/infrastructure/sync.md b/src/tools/clippy/book/src/development/infrastructure/sync.md
index da1ad58..2bbdf47 100644
--- a/src/tools/clippy/book/src/development/infrastructure/sync.md
+++ b/src/tools/clippy/book/src/development/infrastructure/sync.md
@@ -86,7 +86,7 @@
4. Bump the nightly version in the Clippy repository by running these commands:
```bash
cargo dev sync update_nightly
- git commit -m "Bump nightly version -> YYYY-MM-DD" rust-toolchain clippy_utils/README.md
+ git commit -m "Bump nightly version -> YYYY-MM-DD" rust-toolchain.toml clippy_utils/README.md
```
5. Open a PR to `rust-lang/rust-clippy` and wait for it to get merged (to
accelerate the process ping the `@rust-lang/clippy` team in your PR and/or
diff --git a/src/tools/clippy/book/src/development/writing_tests.md b/src/tools/clippy/book/src/development/writing_tests.md
index d4cca2a..1da5432 100644
--- a/src/tools/clippy/book/src/development/writing_tests.md
+++ b/src/tools/clippy/book/src/development/writing_tests.md
@@ -41,20 +41,23 @@
struct A;
impl A {
pub fn fo(&self) {}
- pub fn foo(&self) {} //~ ERROR: function called "foo"
+ pub fn foo(&self) {}
+ //~^ foo_functions
pub fn food(&self) {}
}
// Default trait methods
trait B {
fn fo(&self) {}
- fn foo(&self) {} //~ ERROR: function called "foo"
+ fn foo(&self) {}
+ //~^ foo_functions
fn food(&self) {}
}
// Plain functions
fn fo() {}
-fn foo() {} //~ ERROR: function called "foo"
+fn foo() {}
+//~^ foo_functions
fn food() {}
fn main() {
@@ -66,19 +69,38 @@
```
Without actual lint logic to emit the lint when we see a `foo` function name,
-this test will just pass, because no lint will be emitted. However, we can now
-run the test with the following command:
+this test will fail, because we expect errors at lines marked with
+`//~^ foo_functions`. However, we can now run the test with the following command:
```sh
$ TESTNAME=foo_functions cargo uitest
```
-Clippy will compile and it will conclude with an `ok` for the tests:
+Clippy will compile and it will fail complaining it didn't receive any errors:
```
...Clippy warnings and test outputs...
-test compile_test ... ok
-test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.48s
+error: diagnostic code `clippy::foo_functions` not found on line 8
+ --> tests/ui/foo_functions.rs:9:10
+ |
+9 | //~^ foo_functions
+ | ^^^^^^^^^^^^^ expected because of this pattern
+ |
+
+error: diagnostic code `clippy::foo_functions` not found on line 16
+ --> tests/ui/foo_functions.rs:17:10
+ |
+17 | //~^ foo_functions
+ | ^^^^^^^^^^^^^ expected because of this pattern
+ |
+
+error: diagnostic code `clippy::foo_functions` not found on line 23
+ --> tests/ui/foo_functions.rs:24:6
+ |
+24 | //~^ foo_functions
+ | ^^^^^^^^^^^^^ expected because of this pattern
+ |
+
```
This is normal. After all, we wrote a bunch of Rust code but we haven't really
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index 3726d6e..2314d1b 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -425,6 +425,33 @@
* [`incompatible_msrv`](https://rust-lang.github.io/rust-clippy/master/index.html#incompatible_msrv)
+## `check-inconsistent-struct-field-initializers`
+Whether to suggest reordering constructor fields when initializers are present.
+
+Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the
+suggested code would compile, it can change semantics if the initializer expressions have side effects. The
+following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors:
+
+```rust
+struct MyStruct {
+ vector: Vec<u32>,
+ length: usize
+}
+fn main() {
+ let vector = vec![1,2,3];
+ MyStruct { length: vector.len(), vector};
+}
+```
+
+[from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924
+
+**Default Value:** `false`
+
+---
+**Affected lints:**
+* [`inconsistent_struct_constructor`](https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor)
+
+
## `check-private-items`
Whether to also run the listed lints on private items.
@@ -613,31 +640,15 @@
* [`result_large_err`](https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err)
-## `lint-inconsistent-struct-field-initializers`
-Whether to suggest reordering constructor fields when initializers are present.
-
-Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the
-suggested code would compile, it can change semantics if the initializer expressions have side effects. The
-following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors:
-
-```rust
-struct MyStruct {
- vector: Vec<u32>,
- length: usize
-}
-fn main() {
- let vector = vec![1,2,3];
- MyStruct { length: vector.len(), vector};
-}
-```
-
-[from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924
+## `lint-commented-code`
+Whether collapsible `if` chains are linted if they contain comments inside the parts
+that would be collapsed.
**Default Value:** `false`
---
**Affected lints:**
-* [`inconsistent_struct_constructor`](https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor)
+* [`collapsible_if`](https://rust-lang.github.io/rust-clippy/master/index.html#collapsible_if)
## `literal-representation-threshold`
@@ -786,6 +797,7 @@
* [`iter_kv_map`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map)
* [`legacy_numeric_constants`](https://rust-lang.github.io/rust-clippy/master/index.html#legacy_numeric_constants)
* [`lines_filter_map_ok`](https://rust-lang.github.io/rust-clippy/master/index.html#lines_filter_map_ok)
+* [`manual_abs_diff`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_abs_diff)
* [`manual_bits`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_bits)
* [`manual_c_str_literals`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_c_str_literals)
* [`manual_clamp`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_clamp)
@@ -793,6 +805,7 @@
* [`manual_flatten`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten)
* [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one)
* [`manual_is_ascii_check`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check)
+* [`manual_is_power_of_two`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_power_of_two)
* [`manual_let_else`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_let_else)
* [`manual_midpoint`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_midpoint)
* [`manual_non_exhaustive`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive)
@@ -1059,7 +1072,8 @@
## `warn-on-all-wildcard-imports`
-Whether to allow certain wildcard imports (prelude, super in tests).
+Whether to emit warnings on all wildcard imports, including those from `prelude`, from `super` in tests,
+or for `pub use` reexports.
**Default Value:** `false`
diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml
index f4789c9..0a7724b 100644
--- a/src/tools/clippy/clippy.toml
+++ b/src/tools/clippy/clippy.toml
@@ -1,15 +1,20 @@
avoid-breaking-exported-api = false
-lint-inconsistent-struct-field-initializers = true
+check-inconsistent-struct-field-initializers = true
+
+lint-commented-code = true
[[disallowed-methods]]
path = "rustc_lint::context::LintContext::lint"
reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead"
+allow-invalid = true
[[disallowed-methods]]
path = "rustc_lint::context::LintContext::span_lint"
reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead"
+allow-invalid = true
[[disallowed-methods]]
path = "rustc_middle::ty::context::TyCtxt::node_span_lint"
reason = "this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint_hir*` functions instead"
+allow-invalid = true
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
index 934725f..93fd2e3 100644
--- a/src/tools/clippy/clippy_config/Cargo.toml
+++ b/src/tools/clippy/clippy_config/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "clippy_config"
# begin autogenerated version
-version = "0.1.87"
+version = "0.1.88"
# end autogenerated version
edition = "2024"
publish = false
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 798f8b3..511cb84 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -120,12 +120,7 @@ fn spanned(
Self {
message: message.into(),
suggestion,
- span: Span::new(
- file.start_pos + BytePos::from_usize(span.start),
- file.start_pos + BytePos::from_usize(span.end),
- SyntaxContext::root(),
- None,
- ),
+ span: span_from_toml_range(file, span),
}
}
}
@@ -176,11 +171,61 @@ macro_rules! default_text {
};
}
+macro_rules! deserialize {
+ ($map:expr, $ty:ty, $errors:expr, $file:expr) => {{
+ let raw_value = $map.next_value::<toml::Spanned<toml::Value>>()?;
+ let value_span = raw_value.span();
+ let value = match <$ty>::deserialize(raw_value.into_inner()) {
+ Err(e) => {
+ $errors.push(ConfError::spanned(
+ $file,
+ e.to_string().replace('\n', " ").trim(),
+ None,
+ value_span,
+ ));
+ continue;
+ },
+ Ok(value) => value,
+ };
+ (value, value_span)
+ }};
+
+ ($map:expr, $ty:ty, $errors:expr, $file:expr, $replacements_allowed:expr) => {{
+ let array = $map.next_value::<Vec<toml::Spanned<toml::Value>>>()?;
+ let mut disallowed_paths_span = Range {
+ start: usize::MAX,
+ end: usize::MIN,
+ };
+ let mut disallowed_paths = Vec::new();
+ for raw_value in array {
+ let value_span = raw_value.span();
+ let mut disallowed_path = match DisallowedPath::<$replacements_allowed>::deserialize(raw_value.into_inner())
+ {
+ Err(e) => {
+ $errors.push(ConfError::spanned(
+ $file,
+ e.to_string().replace('\n', " ").trim(),
+ None,
+ value_span,
+ ));
+ continue;
+ },
+ Ok(disallowed_path) => disallowed_path,
+ };
+ disallowed_paths_span = union(&disallowed_paths_span, &value_span);
+ disallowed_path.set_span(span_from_toml_range($file, value_span));
+ disallowed_paths.push(disallowed_path);
+ }
+ (disallowed_paths, disallowed_paths_span)
+ }};
+}
+
macro_rules! define_Conf {
($(
$(#[doc = $doc:literal])+
$(#[conf_deprecated($dep:literal, $new_conf:ident)])?
$(#[default_text = $default_text:expr])?
+ $(#[disallowed_paths_allow_replacements = $replacements_allowed:expr])?
$(#[lints($($for_lints:ident),* $(,)?)])?
$name:ident: $ty:ty = $default:expr,
)*) => {
@@ -218,42 +263,46 @@ fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> where V: MapA
let mut value_spans = HashMap::new();
let mut errors = Vec::new();
let mut warnings = Vec::new();
+
+ // Declare a local variable for each field available to a configuration file.
$(let mut $name = None;)*
+
// could get `Field` here directly, but get `String` first for diagnostics
while let Some(name) = map.next_key::<toml::Spanned<String>>()? {
- match Field::deserialize(name.get_ref().as_str().into_deserializer()) {
+ let field = match Field::deserialize(name.get_ref().as_str().into_deserializer()) {
Err(e) => {
let e: FieldError = e;
errors.push(ConfError::spanned(self.0, e.error, e.suggestion, name.span()));
+ continue;
}
- $(Ok(Field::$name) => {
+ Ok(field) => field
+ };
+
+ match field {
+ $(Field::$name => {
+ // Is this a deprecated field, i.e., is `$dep` set? If so, push a warning.
$(warnings.push(ConfError::spanned(self.0, format!("deprecated field `{}`. {}", name.get_ref(), $dep), None, name.span()));)?
- let raw_value = map.next_value::<toml::Spanned<toml::Value>>()?;
- let value_span = raw_value.span();
- match <$ty>::deserialize(raw_value.into_inner()) {
- Err(e) => errors.push(ConfError::spanned(self.0, e.to_string().replace('\n', " ").trim(), None, value_span)),
- Ok(value) => match $name {
- Some(_) => {
- errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), None, name.span()));
- }
- None => {
- $name = Some(value);
- value_spans.insert(name.get_ref().as_str().to_string(), value_span);
- // $new_conf is the same as one of the defined `$name`s, so
- // this variable is defined in line 2 of this function.
- $(match $new_conf {
- Some(_) => errors.push(ConfError::spanned(self.0, concat!(
- "duplicate field `", stringify!($new_conf),
- "` (provided as `", stringify!($name), "`)"
- ), None, name.span())),
- None => $new_conf = $name.clone(),
- })?
- },
- }
+ let (value, value_span) =
+ deserialize!(map, $ty, errors, self.0 $(, $replacements_allowed)?);
+ // Was this field set previously?
+ if $name.is_some() {
+ errors.push(ConfError::spanned(self.0, format!("duplicate field `{}`", name.get_ref()), None, name.span()));
+ continue;
}
+ $name = Some(value);
+ value_spans.insert(name.get_ref().as_str().to_string(), value_span);
+ // If this is a deprecated field, was the new field (`$new_conf`) set previously?
+ // Note that `$new_conf` is one of the defined `$name`s.
+ $(match $new_conf {
+ Some(_) => errors.push(ConfError::spanned(self.0, concat!(
+ "duplicate field `", stringify!($new_conf),
+ "` (provided as `", stringify!($name), "`)"
+ ), None, name.span())),
+ None => $new_conf = $name.clone(),
+ })?
})*
// ignore contents of the third_party key
- Ok(Field::third_party) => drop(map.next_value::<IgnoredAny>())
+ Field::third_party => drop(map.next_value::<IgnoredAny>())
}
}
let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* };
@@ -275,6 +324,22 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
};
}
+fn union(x: &Range<usize>, y: &Range<usize>) -> Range<usize> {
+ Range {
+ start: cmp::min(x.start, y.start),
+ end: cmp::max(x.end, y.end),
+ }
+}
+
+fn span_from_toml_range(file: &SourceFile, span: Range<usize>) -> Span {
+ Span::new(
+ file.start_pos + BytePos::from_usize(span.start),
+ file.start_pos + BytePos::from_usize(span.end),
+ SyntaxContext::root(),
+ None,
+ )
+}
+
define_Conf! {
/// Which crates to allow absolute paths from
#[lints(absolute_paths)]
@@ -461,6 +526,7 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
)]
avoid_breaking_exported_api: bool = true,
/// The list of types which may not be held across an await point.
+ #[disallowed_paths_allow_replacements = false]
#[lints(await_holding_invalid_type)]
await_holding_invalid_types: Vec<DisallowedPathWithoutReplacement> = Vec::new(),
/// DEPRECATED LINT: BLACKLISTED_NAME.
@@ -474,6 +540,26 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// Whether to check MSRV compatibility in `#[test]` and `#[cfg(test)]` code.
#[lints(incompatible_msrv)]
check_incompatible_msrv_in_tests: bool = false,
+ /// Whether to suggest reordering constructor fields when initializers are present.
+ ///
+ /// Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the
+ /// suggested code would compile, it can change semantics if the initializer expressions have side effects. The
+ /// following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors:
+ ///
+ /// ```rust
+ /// struct MyStruct {
+ /// vector: Vec<u32>,
+ /// length: usize
+ /// }
+ /// fn main() {
+ /// let vector = vec![1,2,3];
+ /// MyStruct { length: vector.len(), vector};
+ /// }
+ /// ```
+ ///
+ /// [from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924
+ #[lints(inconsistent_struct_constructor)]
+ check_inconsistent_struct_field_initializers: bool = false,
/// Whether to also run the listed lints on private items.
#[lints(missing_errors_doc, missing_panics_doc, missing_safety_doc, unnecessary_safety_doc)]
check_private_items: bool = false,
@@ -486,9 +572,11 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
#[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)]
cyclomatic_complexity_threshold: u64 = 25,
/// The list of disallowed macros, written as fully qualified paths.
+ #[disallowed_paths_allow_replacements = true]
#[lints(disallowed_macros)]
disallowed_macros: Vec<DisallowedPath> = Vec::new(),
/// The list of disallowed methods, written as fully qualified paths.
+ #[disallowed_paths_allow_replacements = true]
#[lints(disallowed_methods)]
disallowed_methods: Vec<DisallowedPath> = Vec::new(),
/// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
@@ -497,6 +585,7 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
#[lints(disallowed_names)]
disallowed_names: Vec<String> = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect(),
/// The list of disallowed types, written as fully qualified paths.
+ #[disallowed_paths_allow_replacements = true]
#[lints(disallowed_types)]
disallowed_types: Vec<DisallowedPath> = Vec::new(),
/// The list of words this lint should not consider as identifiers needing ticks. The value
@@ -549,25 +638,15 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// The maximum size of the `Err`-variant in a `Result` returned from a function
#[lints(result_large_err)]
large_error_threshold: u64 = 128,
+ /// Whether collapsible `if` chains are linted if they contain comments inside the parts
+ /// that would be collapsed.
+ #[lints(collapsible_if)]
+ lint_commented_code: bool = false,
/// Whether to suggest reordering constructor fields when initializers are present.
+ /// DEPRECATED CONFIGURATION: lint-inconsistent-struct-field-initializers
///
- /// Warnings produced by this configuration aren't necessarily fixed by just reordering the fields. Even if the
- /// suggested code would compile, it can change semantics if the initializer expressions have side effects. The
- /// following example [from rust-clippy#11846] shows how the suggestion can run into borrow check errors:
- ///
- /// ```rust
- /// struct MyStruct {
- /// vector: Vec<u32>,
- /// length: usize
- /// }
- /// fn main() {
- /// let vector = vec![1,2,3];
- /// MyStruct { length: vector.len(), vector};
- /// }
- /// ```
- ///
- /// [from rust-clippy#11846]: https://github.com/rust-lang/rust-clippy/issues/11846#issuecomment-1820747924
- #[lints(inconsistent_struct_constructor)]
+ /// Use the `check-inconsistent-struct-field-initializers` configuration instead.
+ #[conf_deprecated("Please use `check-inconsistent-struct-field-initializers` instead", check_inconsistent_struct_field_initializers)]
lint_inconsistent_struct_field_initializers: bool = false,
/// The lower bound for linting decimal literals
#[lints(decimal_literal_representation)]
@@ -635,6 +714,7 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
iter_kv_map,
legacy_numeric_constants,
lines_filter_map_ok,
+ manual_abs_diff,
manual_bits,
manual_c_str_literals,
manual_clamp,
@@ -642,6 +722,7 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
manual_flatten,
manual_hash_one,
manual_is_ascii_check,
+ manual_is_power_of_two,
manual_let_else,
manual_midpoint,
manual_non_exhaustive,
@@ -760,7 +841,8 @@ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
/// The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
#[lints(verbose_bit_mask)]
verbose_bit_mask_threshold: u64 = 1,
- /// Whether to allow certain wildcard imports (prelude, super in tests).
+ /// Whether to emit warnings on all wildcard imports, including those from `prelude`, from `super` in tests,
+ /// or for `pub use` reexports.
#[lints(wildcard_imports)]
warn_on_all_wildcard_imports: bool = false,
/// Whether to also emit warnings for unsafe blocks with metavariable expansions in **private** macros.
@@ -981,7 +1063,23 @@ fn unknown_field(field: &str, expected: &'static [&'static str]) -> Self {
// set and allows it.
use fmt::Write;
- let mut expected = expected.to_vec();
+ let metadata = get_configuration_metadata();
+ let deprecated = metadata
+ .iter()
+ .filter_map(|conf| {
+ if conf.deprecation_reason.is_some() {
+ Some(conf.name.as_str())
+ } else {
+ None
+ }
+ })
+ .collect::<Vec<_>>();
+
+ let mut expected = expected
+ .iter()
+ .copied()
+ .filter(|name| !deprecated.contains(name))
+ .collect::<Vec<_>>();
expected.sort_unstable();
let (rows, column_widths) = calculate_dimensions(&expected);
@@ -1064,7 +1162,13 @@ mod tests {
fn configs_are_tested() {
let mut names: HashSet<String> = crate::get_configuration_metadata()
.into_iter()
- .map(|meta| meta.name.replace('_', "-"))
+ .filter_map(|meta| {
+ if meta.deprecation_reason.is_none() {
+ Some(meta.name.replace('_', "-"))
+ } else {
+ None
+ }
+ })
.collect();
let toml_files = WalkDir::new("../tests")
diff --git a/src/tools/clippy/clippy_config/src/lib.rs b/src/tools/clippy/clippy_config/src/lib.rs
index 5d6e8b8..c227b89 100644
--- a/src/tools/clippy/clippy_config/src/lib.rs
+++ b/src/tools/clippy/clippy_config/src/lib.rs
@@ -13,6 +13,7 @@
rustc::untranslatable_diagnostic
)]
+extern crate rustc_data_structures;
extern crate rustc_errors;
extern crate rustc_hir;
extern crate rustc_middle;
diff --git a/src/tools/clippy/clippy_config/src/types.rs b/src/tools/clippy/clippy_config/src/types.rs
index 8faac9e..5949eac 100644
--- a/src/tools/clippy/clippy_config/src/types.rs
+++ b/src/tools/clippy/clippy_config/src/types.rs
@@ -1,5 +1,7 @@
-use clippy_utils::def_path_def_ids;
+use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, Diag};
+use rustc_hir::PrimTy;
+use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefIdMap;
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;
@@ -21,6 +23,17 @@ pub struct DisallowedPath<const REPLACEMENT_ALLOWED: bool = true> {
path: String,
reason: Option<String>,
replacement: Option<String>,
+ /// Setting `allow_invalid` to true suppresses a warning if `path` does not refer to an existing
+ /// definition.
+ ///
+ /// This could be useful when conditional compilation is used, or when a clippy.toml file is
+ /// shared among multiple projects.
+ allow_invalid: bool,
+ /// The span of the `DisallowedPath`.
+ ///
+ /// Used for diagnostics.
+ #[serde(skip_serializing)]
+ span: Span,
}
impl<'de, const REPLACEMENT_ALLOWED: bool> Deserialize<'de> for DisallowedPath<REPLACEMENT_ALLOWED> {
@@ -36,6 +49,8 @@ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
path: enum_.path().to_owned(),
reason: enum_.reason().map(ToOwned::to_owned),
replacement: enum_.replacement().map(ToOwned::to_owned),
+ allow_invalid: enum_.allow_invalid(),
+ span: Span::default(),
})
}
}
@@ -50,6 +65,8 @@ enum DisallowedPathEnum {
path: String,
reason: Option<String>,
replacement: Option<String>,
+ #[serde(rename = "allow-invalid")]
+ allow_invalid: Option<bool>,
},
}
@@ -58,7 +75,7 @@ pub fn path(&self) -> &str {
&self.path
}
- pub fn diag_amendment(&self, span: Span) -> impl FnOnce(&mut Diag<'_, ()>) + use<'_, REPLACEMENT_ALLOWED> {
+ pub fn diag_amendment(&self, span: Span) -> impl FnOnce(&mut Diag<'_, ()>) {
move |diag| {
if let Some(replacement) = &self.replacement {
diag.span_suggestion(
@@ -72,6 +89,14 @@ pub fn diag_amendment(&self, span: Span) -> impl FnOnce(&mut Diag<'_, ()>) + use
}
}
}
+
+ pub fn span(&self) -> Span {
+ self.span
+ }
+
+ pub fn set_span(&mut self, span: Span) {
+ self.span = span;
+ }
}
impl DisallowedPathEnum {
@@ -94,20 +119,87 @@ fn replacement(&self) -> Option<&str> {
Self::Simple(_) => None,
}
}
+
+ fn allow_invalid(&self) -> bool {
+ match &self {
+ Self::WithReason { allow_invalid, .. } => allow_invalid.unwrap_or_default(),
+ Self::Simple(_) => false,
+ }
+ }
}
/// Creates a map of disallowed items to the reason they were disallowed.
+#[allow(clippy::type_complexity)]
pub fn create_disallowed_map<const REPLACEMENT_ALLOWED: bool>(
tcx: TyCtxt<'_>,
- disallowed: &'static [DisallowedPath<REPLACEMENT_ALLOWED>],
-) -> DefIdMap<(&'static str, &'static DisallowedPath<REPLACEMENT_ALLOWED>)> {
- disallowed
- .iter()
- .map(|x| (x.path(), x.path().split("::").collect::<Vec<_>>(), x))
- .flat_map(|(name, path, disallowed_path)| {
- def_path_def_ids(tcx, &path).map(move |id| (id, (name, disallowed_path)))
- })
- .collect()
+ disallowed_paths: &'static [DisallowedPath<REPLACEMENT_ALLOWED>],
+ def_kind_predicate: impl Fn(DefKind) -> bool,
+ predicate_description: &str,
+ allow_prim_tys: bool,
+) -> (
+ DefIdMap<(&'static str, &'static DisallowedPath<REPLACEMENT_ALLOWED>)>,
+ FxHashMap<PrimTy, (&'static str, &'static DisallowedPath<REPLACEMENT_ALLOWED>)>,
+) {
+ let mut def_ids: DefIdMap<(&'static str, &'static DisallowedPath<REPLACEMENT_ALLOWED>)> = DefIdMap::default();
+ let mut prim_tys: FxHashMap<PrimTy, (&'static str, &'static DisallowedPath<REPLACEMENT_ALLOWED>)> =
+ FxHashMap::default();
+ for disallowed_path in disallowed_paths {
+ let path = disallowed_path.path();
+ let mut resolutions = clippy_utils::def_path_res(tcx, &path.split("::").collect::<Vec<_>>());
+
+ let mut found_def_id = None;
+ let mut found_prim_ty = false;
+ resolutions.retain(|res| match res {
+ Res::Def(def_kind, def_id) => {
+ found_def_id = Some(*def_id);
+ def_kind_predicate(*def_kind)
+ },
+ Res::PrimTy(_) => {
+ found_prim_ty = true;
+ allow_prim_tys
+ },
+ _ => false,
+ });
+
+ if resolutions.is_empty() {
+ let span = disallowed_path.span();
+
+ if let Some(def_id) = found_def_id {
+ tcx.sess.dcx().span_warn(
+ span,
+ format!(
+ "expected a {predicate_description}, found {} {}",
+ tcx.def_descr_article(def_id),
+ tcx.def_descr(def_id)
+ ),
+ );
+ } else if found_prim_ty {
+ tcx.sess.dcx().span_warn(
+ span,
+ format!("expected a {predicate_description}, found a primitive type",),
+ );
+ } else if !disallowed_path.allow_invalid {
+ tcx.sess.dcx().span_warn(
+ span,
+ format!("`{path}` does not refer to an existing {predicate_description}"),
+ );
+ }
+ }
+
+ for res in resolutions {
+ match res {
+ Res::Def(_, def_id) => {
+ def_ids.insert(def_id, (path, disallowed_path));
+ },
+ Res::PrimTy(ty) => {
+ prim_tys.insert(ty, (path, disallowed_path));
+ },
+ _ => unreachable!(),
+ }
+ }
+ }
+
+ (def_ids, prim_tys)
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs
index 9280369..c1ffaf2 100644
--- a/src/tools/clippy/clippy_dev/src/lib.rs
+++ b/src/tools/clippy/clippy_dev/src/lib.rs
@@ -13,6 +13,7 @@
#[allow(unused_extern_crates)]
extern crate rustc_driver;
extern crate rustc_lexer;
+extern crate rustc_literal_escaper;
pub mod dogfood;
pub mod fmt;
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index 074dea4..83f8e66 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -170,7 +170,6 @@ enum DevCommand {
"restriction",
"cargo",
"nursery",
- "internal",
],
default_value = "nursery",
)]
@@ -334,7 +333,7 @@ struct SyncCommand {
#[derive(Subcommand)]
enum SyncSubcommand {
#[command(name = "update_nightly")]
- /// Update nightly version in rust-toolchain and `clippy_utils`
+ /// Update nightly version in `rust-toolchain.toml` and `clippy_utils`
UpdateNightly,
}
diff --git a/src/tools/clippy/clippy_dev/src/setup/toolchain.rs b/src/tools/clippy/clippy_dev/src/setup/toolchain.rs
index 2966629..ecd8021 100644
--- a/src/tools/clippy/clippy_dev/src/setup/toolchain.rs
+++ b/src/tools/clippy/clippy_dev/src/setup/toolchain.rs
@@ -62,7 +62,7 @@ pub fn create(standalone: bool, force: bool, release: bool, name: &str) {
println!("Created toolchain {name}, use it in other projects with e.g. `cargo +{name} clippy`");
if !standalone {
- println!("Note: This will need to be re-run whenever the Clippy `rust-toolchain` changes");
+ println!("Note: This will need to be re-run whenever the Clippy `rust-toolchain.toml` changes");
}
}
diff --git a/src/tools/clippy/clippy_dev/src/sync.rs b/src/tools/clippy/clippy_dev/src/sync.rs
index 3522d18..a6b65e5 100644
--- a/src/tools/clippy/clippy_dev/src/sync.rs
+++ b/src/tools/clippy/clippy_dev/src/sync.rs
@@ -10,7 +10,7 @@ pub fn update_nightly() {
let date = Utc::now().format("%Y-%m-%d").to_string();
replace_region_in_file(
UpdateMode::Change,
- Path::new("rust-toolchain"),
+ Path::new("rust-toolchain.toml"),
"# begin autogenerated nightly\n",
"# end autogenerated nightly",
|res| {
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index b80ee5a..d848a97 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -1,7 +1,8 @@
use crate::utils::{UpdateMode, clippy_project_root, exit_with_failure, replace_region_in_file};
use aho_corasick::AhoCorasickBuilder;
use itertools::Itertools;
-use rustc_lexer::{LiteralKind, TokenKind, tokenize, unescape};
+use rustc_lexer::{LiteralKind, TokenKind, tokenize};
+use rustc_literal_escaper::{Mode, unescape_unicode};
use std::collections::{HashMap, HashSet};
use std::ffi::OsStr;
use std::fmt::{self, Write};
@@ -37,9 +38,8 @@ fn generate_lint_files(
deprecated_lints: &[DeprecatedLint],
renamed_lints: &[RenamedLint],
) {
- let internal_lints = Lint::internal_lints(lints);
- let mut usable_lints = Lint::usable_lints(lints);
- usable_lints.sort_by_key(|lint| lint.name.clone());
+ let mut lints = lints.to_owned();
+ lints.sort_by_key(|lint| lint.name.clone());
replace_region_in_file(
update_mode,
@@ -47,7 +47,7 @@ fn generate_lint_files(
"[There are over ",
" lints included in this crate!]",
|res| {
- write!(res, "{}", round_to_fifty(usable_lints.len())).unwrap();
+ write!(res, "{}", round_to_fifty(lints.len())).unwrap();
},
);
@@ -57,7 +57,7 @@ fn generate_lint_files(
"[There are over ",
" lints included in this crate!]",
|res| {
- write!(res, "{}", round_to_fifty(usable_lints.len())).unwrap();
+ write!(res, "{}", round_to_fifty(lints.len())).unwrap();
},
);
@@ -67,7 +67,7 @@ fn generate_lint_files(
"<!-- begin autogenerated links to lint list -->\n",
"<!-- end autogenerated links to lint list -->",
|res| {
- for lint in usable_lints
+ for lint in lints
.iter()
.map(|l| &*l.name)
.chain(deprecated_lints.iter().filter_map(|l| l.name.strip_prefix("clippy::")))
@@ -86,7 +86,7 @@ fn generate_lint_files(
"// begin lints modules, do not remove this comment, it’s used in `update_lints`\n",
"// end lints modules, do not remove this comment, it’s used in `update_lints`",
|res| {
- for lint_mod in usable_lints.iter().map(|l| &l.module).unique().sorted() {
+ for lint_mod in lints.iter().map(|l| &l.module).unique().sorted() {
writeln!(res, "mod {lint_mod};").unwrap();
}
},
@@ -95,7 +95,7 @@ fn generate_lint_files(
process_file(
"clippy_lints/src/declared_lints.rs",
update_mode,
- &gen_declared_lints(internal_lints.iter(), usable_lints.iter()),
+ &gen_declared_lints(lints.iter()),
);
let content = gen_deprecated_lints_test(deprecated_lints);
@@ -106,10 +106,9 @@ fn generate_lint_files(
}
pub fn print_lints() {
- let (lint_list, _, _) = gather_all();
- let usable_lints = Lint::usable_lints(&lint_list);
- let usable_lint_count = usable_lints.len();
- let grouped_by_lint_group = Lint::by_lint_group(usable_lints.into_iter());
+ let (lints, _, _) = gather_all();
+ let lint_count = lints.len();
+ let grouped_by_lint_group = Lint::by_lint_group(lints.into_iter());
for (lint_group, mut lints) in grouped_by_lint_group {
println!("\n## {lint_group}");
@@ -121,7 +120,7 @@ pub fn print_lints() {
}
}
- println!("there are {usable_lint_count} lints");
+ println!("there are {lint_count} lints");
}
/// Runs the `rename_lint` command.
@@ -402,53 +401,53 @@ fn remove_impl_lint_pass(lint_name_upper: &str, content: &mut String) {
}
}
- if path.exists() {
- if let Some(lint) = lints.iter().find(|l| l.name == name) {
- if lint.module == name {
- // The lint name is the same as the file, we can just delete the entire file
- fs::remove_file(path)?;
- } else {
- // We can't delete the entire file, just remove the declaration
+ if path.exists()
+ && let Some(lint) = lints.iter().find(|l| l.name == name)
+ {
+ if lint.module == name {
+ // The lint name is the same as the file, we can just delete the entire file
+ fs::remove_file(path)?;
+ } else {
+ // We can't delete the entire file, just remove the declaration
- if let Some(Some("mod.rs")) = path.file_name().map(OsStr::to_str) {
- // Remove clippy_lints/src/some_mod/some_lint.rs
- let mut lint_mod_path = path.to_path_buf();
- lint_mod_path.set_file_name(name);
- lint_mod_path.set_extension("rs");
+ if let Some(Some("mod.rs")) = path.file_name().map(OsStr::to_str) {
+ // Remove clippy_lints/src/some_mod/some_lint.rs
+ let mut lint_mod_path = path.to_path_buf();
+ lint_mod_path.set_file_name(name);
+ lint_mod_path.set_extension("rs");
- let _ = fs::remove_file(lint_mod_path);
- }
-
- let mut content =
- fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy()));
-
- eprintln!(
- "warn: you will have to manually remove any code related to `{name}` from `{}`",
- path.display()
- );
-
- assert!(
- content[lint.declaration_range.clone()].contains(&name.to_uppercase()),
- "error: `{}` does not contain lint `{}`'s declaration",
- path.display(),
- lint.name
- );
-
- // Remove lint declaration (declare_clippy_lint!)
- content.replace_range(lint.declaration_range.clone(), "");
-
- // Remove the module declaration (mod xyz;)
- let mod_decl = format!("\nmod {name};");
- content = content.replacen(&mod_decl, "", 1);
-
- remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content);
- fs::write(path, content).unwrap_or_else(|_| panic!("failed to write to `{}`", path.to_string_lossy()));
+ let _ = fs::remove_file(lint_mod_path);
}
- remove_test_assets(name);
- remove_lint(name, lints);
- return Ok(true);
+ let mut content =
+ fs::read_to_string(path).unwrap_or_else(|_| panic!("failed to read `{}`", path.to_string_lossy()));
+
+ eprintln!(
+ "warn: you will have to manually remove any code related to `{name}` from `{}`",
+ path.display()
+ );
+
+ assert!(
+ content[lint.declaration_range.clone()].contains(&name.to_uppercase()),
+ "error: `{}` does not contain lint `{}`'s declaration",
+ path.display(),
+ lint.name
+ );
+
+ // Remove lint declaration (declare_clippy_lint!)
+ content.replace_range(lint.declaration_range.clone(), "");
+
+ // Remove the module declaration (mod xyz;)
+ let mod_decl = format!("\nmod {name};");
+ content = content.replacen(&mod_decl, "", 1);
+
+ remove_impl_lint_pass(&lint.name.to_uppercase(), &mut content);
+ fs::write(path, content).unwrap_or_else(|_| panic!("failed to write to `{}`", path.to_string_lossy()));
}
+
+ remove_test_assets(name);
+ remove_lint(name, lints);
+ return Ok(true);
}
Ok(false)
@@ -527,22 +526,6 @@ fn new(name: &str, group: &str, desc: &str, module: &str, declaration_range: Ran
}
}
- /// Returns all non-deprecated lints and non-internal lints
- #[must_use]
- fn usable_lints(lints: &[Self]) -> Vec<Self> {
- lints
- .iter()
- .filter(|l| !l.group.starts_with("internal"))
- .cloned()
- .collect()
- }
-
- /// Returns all internal lints
- #[must_use]
- fn internal_lints(lints: &[Self]) -> Vec<Self> {
- lints.iter().filter(|l| l.group == "internal").cloned().collect()
- }
-
/// Returns the lints in a `HashMap`, grouped by the different lint groups
#[must_use]
fn by_lint_group(lints: impl Iterator<Item = Self>) -> HashMap<String, Vec<Self>> {
@@ -579,23 +562,14 @@ fn new(old_name: &str, new_name: &str) -> Self {
/// Generates the code for registering lints
#[must_use]
-fn gen_declared_lints<'a>(
- internal_lints: impl Iterator<Item = &'a Lint>,
- usable_lints: impl Iterator<Item = &'a Lint>,
-) -> String {
- let mut details: Vec<_> = internal_lints
- .map(|l| (false, &l.module, l.name.to_uppercase()))
- .chain(usable_lints.map(|l| (true, &l.module, l.name.to_uppercase())))
- .collect();
+fn gen_declared_lints<'a>(lints: impl Iterator<Item = &'a Lint>) -> String {
+ let mut details: Vec<_> = lints.map(|l| (&l.module, l.name.to_uppercase())).collect();
details.sort_unstable();
let mut output = GENERATED_FILE_COMMENT.to_string();
output.push_str("pub static LINTS: &[&crate::LintInfo] = &[\n");
- for (is_public, module_name, lint_name) in details {
- if !is_public {
- output.push_str(" #[cfg(feature = \"internal\")]\n");
- }
+ for (module_name, lint_name) in details {
let _: fmt::Result = writeln!(output, " crate::{module_name}::{lint_name}_INFO,");
}
output.push_str("];\n");
@@ -830,7 +804,7 @@ fn remove_line_splices(s: &str) -> String {
.and_then(|s| s.strip_suffix('"'))
.unwrap_or_else(|| panic!("expected quoted string, found `{s}`"));
let mut res = String::with_capacity(s.len());
- unescape::unescape_unicode(s, unescape::Mode::Str, &mut |range, ch| {
+ unescape_unicode(s, Mode::Str, &mut |range, ch| {
if ch.is_ok() {
res.push_str(&s[range]);
}
@@ -937,41 +911,6 @@ fn test_parse_contents() {
}
#[test]
- fn test_usable_lints() {
- let lints = vec![
- Lint::new(
- "should_assert_eq2",
- "Not Deprecated",
- "\"abc\"",
- "module_name",
- Range::default(),
- ),
- Lint::new(
- "should_assert_eq2",
- "internal",
- "\"abc\"",
- "module_name",
- Range::default(),
- ),
- Lint::new(
- "should_assert_eq2",
- "internal_style",
- "\"abc\"",
- "module_name",
- Range::default(),
- ),
- ];
- let expected = vec![Lint::new(
- "should_assert_eq2",
- "Not Deprecated",
- "\"abc\"",
- "module_name",
- Range::default(),
- )];
- assert_eq!(expected, Lint::usable_lints(&lints));
- }
-
- #[test]
fn test_by_lint_group() {
let lints = vec![
Lint::new("should_assert_eq", "group1", "\"abc\"", "module_name", Range::default()),
diff --git a/src/tools/clippy/clippy_dev/src/utils.rs b/src/tools/clippy/clippy_dev/src/utils.rs
index b87fcca..2068163 100644
--- a/src/tools/clippy/clippy_dev/src/utils.rs
+++ b/src/tools/clippy/clippy_dev/src/utils.rs
@@ -30,10 +30,10 @@ pub fn clippy_project_root() -> PathBuf {
let current_dir = std::env::current_dir().unwrap();
for path in current_dir.ancestors() {
let result = fs::read_to_string(path.join("Cargo.toml"));
- if let Err(err) = &result {
- if err.kind() == io::ErrorKind::NotFound {
- continue;
- }
+ if let Err(err) = &result
+ && err.kind() == io::ErrorKind::NotFound
+ {
+ continue;
}
let content = result.unwrap();
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index 5434704..20951af 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "clippy_lints"
# begin autogenerated version
-version = "0.1.87"
+version = "0.1.88"
# end autogenerated version
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
@@ -19,10 +19,7 @@
quine-mc_cluskey = "0.2"
regex-syntax = "0.8"
serde = { version = "1.0", features = ["derive"] }
-serde_json = { version = "1.0", optional = true }
-tempfile = { version = "3.3.0", optional = true }
toml = "0.7.3"
-regex = { version = "1.5", optional = true }
unicode-normalization = "0.1"
unicode-script = { version = "0.5", default-features = false }
semver = "1.0"
@@ -31,10 +28,6 @@
[dev-dependencies]
walkdir = "2.3"
-[features]
-# build clippy with internal lints enabled, off by default
-internal = ["serde_json", "tempfile", "regex"]
-
[package.metadata.rust-analyzer]
# This crate uses #[feature(rustc_private)]
rustc_private = true
diff --git a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
index 57cabe4..2724444 100644
--- a/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
+++ b/src/tools/clippy/clippy_lints/src/arbitrary_source_item_ordering.rs
@@ -5,6 +5,7 @@
SourceItemOrderingWithinModuleItemGroupings,
};
use clippy_utils::diagnostics::span_lint_and_note;
+use clippy_utils::is_cfg_test;
use rustc_hir::{
AssocItemKind, FieldDef, HirId, ImplItemRef, IsAuto, Item, ItemKind, Mod, QPath, TraitItemRef, TyKind, Variant,
VariantData,
@@ -263,10 +264,11 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
continue;
}
- if let Some(cur_v) = cur_v {
- if cur_v.ident.name.as_str() > variant.ident.name.as_str() && cur_v.span != variant.span {
- Self::lint_member_name(cx, &variant.ident, &cur_v.ident);
- }
+ if let Some(cur_v) = cur_v
+ && cur_v.ident.name.as_str() > variant.ident.name.as_str()
+ && cur_v.span != variant.span
+ {
+ Self::lint_member_name(cx, &variant.ident, &cur_v.ident);
}
cur_v = Some(variant);
}
@@ -278,10 +280,11 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
continue;
}
- if let Some(cur_f) = cur_f {
- if cur_f.ident.name.as_str() > field.ident.name.as_str() && cur_f.span != field.span {
- Self::lint_member_name(cx, &field.ident, &cur_f.ident);
- }
+ if let Some(cur_f) = cur_f
+ && cur_f.ident.name.as_str() > field.ident.name.as_str()
+ && cur_f.span != field.span
+ {
+ Self::lint_member_name(cx, &field.ident, &cur_f.ident);
}
cur_f = Some(field);
}
@@ -342,7 +345,7 @@ fn check_mod(&mut self, cx: &LateContext<'tcx>, module: &'tcx Mod<'tcx>, _: HirI
struct CurItem<'a> {
item: &'a Item<'a>,
order: usize,
- name: String,
+ name: Option<String>,
}
let mut cur_t: Option<CurItem<'_>> = None;
@@ -359,32 +362,36 @@ struct CurItem<'a> {
// as no sorting by source map/line of code has to be applied.
//
for item in items {
+ if is_cfg_test(cx.tcx, item.hir_id()) {
+ continue;
+ }
+
if item.span.in_external_macro(cx.sess().source_map()) {
continue;
}
- let ident = if let Some(ident) = item.kind.ident() {
- ident
- } else if let ItemKind::Impl(_) = item.kind
- && !get_item_name(item).is_empty()
- {
- rustc_span::Ident::empty() // FIXME: a bit strange, is there a better way to do it?
- } else {
- continue;
- };
-
- if ident.name.as_str().starts_with('_') {
- // Filters out unnamed macro-like impls for various derives,
- // e.g. serde::Serialize or num_derive::FromPrimitive.
- continue;
- }
-
- if ident.name == rustc_span::sym::std && item.span.is_dummy() {
- if let ItemKind::ExternCrate(None, _) = item.kind {
- // Filters the auto-included Rust standard library.
+ if let Some(ident) = item.kind.ident() {
+ if ident.name.as_str().starts_with('_') {
+ // Filters out unnamed macro-like impls for various derives,
+ // e.g. serde::Serialize or num_derive::FromPrimitive.
continue;
}
- println!("Unknown item: {item:?}");
+
+ if ident.name == rustc_span::sym::std && item.span.is_dummy() {
+ if let ItemKind::ExternCrate(None, _) = item.kind {
+ // Filters the auto-included Rust standard library.
+ continue;
+ }
+ if cfg!(debug_assertions) {
+ rustc_middle::bug!("unknown item: {item:?}");
+ }
+ }
+ } else if let ItemKind::Impl(_) = item.kind
+ && get_item_name(item).is_some()
+ {
+ // keep going below
+ } else {
+ continue;
}
let item_kind = convert_module_item_kind(&item.kind);
@@ -493,7 +500,7 @@ fn convert_module_item_kind(value: &ItemKind<'_>) -> SourceItemOrderingModuleIte
/// further in the [Rust Reference, Paths Chapter][rust_ref].
///
/// [rust_ref]: https://doc.rust-lang.org/reference/paths.html#crate-1
-fn get_item_name(item: &Item<'_>) -> String {
+fn get_item_name(item: &Item<'_>) -> Option<String> {
match item.kind {
ItemKind::Impl(im) => {
if let TyKind::Path(path) = im.self_ty.kind {
@@ -513,27 +520,19 @@ fn get_item_name(item: &Item<'_>) -> String {
}
segs.push(String::new());
- segs.join("!!")
+ Some(segs.join("!!"))
},
QPath::TypeRelative(_, _path_seg) => {
// This case doesn't exist in the clippy tests codebase.
- String::new()
+ None
},
- QPath::LangItem(_, _) => String::new(),
+ QPath::LangItem(_, _) => None,
}
} else {
// Impls for anything that isn't a named type can be skipped.
- String::new()
+ None
}
},
- // FIXME: `Ident::empty` for anonymous items is a bit strange, is there
- // a better way to do it?
- _ => item
- .kind
- .ident()
- .unwrap_or(rustc_span::Ident::empty())
- .name
- .as_str()
- .to_owned(),
+ _ => item.kind.ident().map(|name| name.as_str().to_owned()),
}
}
diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs
index 7810277..27e304a 100644
--- a/src/tools/clippy/clippy_lints/src/as_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs
@@ -12,17 +12,17 @@
/// regardless of whether good alternatives exist or not. If you want more
/// precise lints for `as`, please consider using these separate lints:
///
- /// - clippy::cast_lossless
- /// - clippy::cast_possible_truncation
- /// - clippy::cast_possible_wrap
- /// - clippy::cast_precision_loss
- /// - clippy::cast_sign_loss
- /// - clippy::char_lit_as_u8
- /// - clippy::fn_to_numeric_cast
- /// - clippy::fn_to_numeric_cast_with_truncation
- /// - clippy::ptr_as_ptr
- /// - clippy::unnecessary_cast
- /// - invalid_reference_casting
+ /// - `clippy::cast_lossless`
+ /// - `clippy::cast_possible_truncation`
+ /// - `clippy::cast_possible_wrap`
+ /// - `clippy::cast_precision_loss`
+ /// - `clippy::cast_sign_loss`
+ /// - `clippy::char_lit_as_u8`
+ /// - `clippy::fn_to_numeric_cast`
+ /// - `clippy::fn_to_numeric_cast_with_truncation`
+ /// - `clippy::ptr_as_ptr`
+ /// - `clippy::unnecessary_cast`
+ /// - `invalid_reference_casting`
///
/// There is a good explanation the reason why this lint should work in this
/// way and how it is useful [in this
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index ab34af7..9acff67 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -111,8 +111,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
// Only suggest if `clone_from`/`clone_into` is explicitly implemented
&& resolved_assoc_items.in_definition_order().any(|assoc|
match which_trait {
- CloneTrait::Clone => assoc.name == sym::clone_from,
- CloneTrait::ToOwned => assoc.name.as_str() == "clone_into",
+ CloneTrait::Clone => assoc.name() == sym::clone_from,
+ CloneTrait::ToOwned => assoc.name().as_str() == "clone_into",
}
)
&& !clone_source_borrows_from_dest(cx, lhs, rhs.span)
@@ -243,7 +243,7 @@ fn build_sugg<'tcx>(
// `lhs = self_expr.clone();` -> `lhs.clone_from(self_expr)`
Sugg::hir_with_applicability(cx, lhs, "_", app)
}
- .maybe_par();
+ .maybe_paren();
// Determine whether we need to reference the argument to clone_from().
let clone_receiver_type = cx.typeck_results().expr_ty(fn_arg);
@@ -284,7 +284,7 @@ fn build_sugg<'tcx>(
let rhs_sugg = if let ExprKind::Unary(hir::UnOp::Deref, ref_expr) = lhs.kind {
// `*lhs = rhs.to_owned()` -> `rhs.clone_into(lhs)`
// `*lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, lhs)`
- let sugg = Sugg::hir_with_applicability(cx, ref_expr, "_", app).maybe_par();
+ let sugg = Sugg::hir_with_applicability(cx, ref_expr, "_", app).maybe_paren();
let inner_type = cx.typeck_results().expr_ty(ref_expr);
// If after unwrapping the dereference, the type is not a mutable reference, we add &mut to make it
// deref to a mutable reference.
@@ -296,7 +296,7 @@ fn build_sugg<'tcx>(
} else {
// `lhs = rhs.to_owned()` -> `rhs.clone_into(&mut lhs)`
// `lhs = ToOwned::to_owned(rhs)` -> `ToOwned::clone_into(rhs, &mut lhs)`
- Sugg::hir_with_applicability(cx, lhs, "_", app).maybe_par().mut_addr()
+ Sugg::hir_with_applicability(cx, lhs, "_", app).maybe_paren().mut_addr()
};
match call_kind {
diff --git a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs
index fecf316..457692e 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/blanket_clippy_restriction_lints.rs
@@ -8,17 +8,18 @@
pub(super) fn check(cx: &EarlyContext<'_>, name: Symbol, items: &[MetaItemInner]) {
for lint in items {
- if let Some(lint_name) = extract_clippy_lint(lint) {
- if lint_name.as_str() == "restriction" && name != sym::allow {
- span_lint_and_help(
- cx,
- BLANKET_CLIPPY_RESTRICTION_LINTS,
- lint.span(),
- "`clippy::restriction` is not meant to be enabled as a group",
- None,
- "enable the restriction lints you need individually",
- );
- }
+ if let Some(lint_name) = extract_clippy_lint(lint)
+ && lint_name.as_str() == "restriction"
+ && name != sym::allow
+ {
+ span_lint_and_help(
+ cx,
+ BLANKET_CLIPPY_RESTRICTION_LINTS,
+ lint.span(),
+ "`clippy::restriction` is not meant to be enabled as a group",
+ None,
+ "enable the restriction lints you need individually",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs
index d3153ec..50943b3 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/deprecated_semver.rs
@@ -6,10 +6,10 @@
use semver::Version;
pub(super) fn check(cx: &EarlyContext<'_>, span: Span, lit: &MetaItemLit) {
- if let LitKind::Str(is, _) = lit.kind {
- if is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok() {
- return;
- }
+ if let LitKind::Str(is, _) = lit.kind
+ && (is.as_str() == "TBD" || Version::parse(is.as_str()).is_ok())
+ {
+ return;
}
span_lint(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
index 4c84e61..a851daa 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
@@ -36,10 +36,7 @@ fn check_duplicated_attr(
}
let Some(ident) = attr.ident() else { return };
let name = ident.name;
- if name == sym::doc
- || name == sym::cfg_attr_trace
- || name == sym::rustc_on_unimplemented
- || name == sym::reason {
+ if name == sym::doc || name == sym::cfg_attr_trace || name == sym::rustc_on_unimplemented || name == sym::reason {
// FIXME: Would be nice to handle `cfg_attr` as well. Only problem is to check that cfg
// conditions are the same.
// `#[rustc_on_unimplemented]` contains duplicated subattributes, that's expected.
diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
index e04d2ad..f7f168c 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
@@ -14,8 +14,9 @@
mod utils;
use clippy_config::Conf;
+use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::msrvs::{self, Msrv, MsrvStack};
-use rustc_ast::{self as ast, Attribute, MetaItemInner, MetaItemKind};
+use rustc_ast::{self as ast, AttrArgs, AttrKind, Attribute, MetaItemInner, MetaItemKind};
use rustc_hir::{ImplItem, Item, ItemKind, TraitItem};
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
@@ -448,6 +449,31 @@
"duplicated attribute"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for ignored tests without messages.
+ ///
+ /// ### Why is this bad?
+ /// The reason for ignoring the test may not be obvious.
+ ///
+ /// ### Example
+ /// ```no_run
+ /// #[test]
+ /// #[ignore]
+ /// fn test() {}
+ /// ```
+ /// Use instead:
+ /// ```no_run
+ /// #[test]
+ /// #[ignore = "Some good reason"]
+ /// fn test() {}
+ /// ```
+ #[clippy::version = "1.85.0"]
+ pub IGNORE_WITHOUT_REASON,
+ pedantic,
+ "ignored tests without messages"
+}
+
pub struct Attributes {
msrv: Msrv,
}
@@ -532,6 +558,7 @@ pub fn new(conf: &'static Conf) -> Self {
ALLOW_ATTRIBUTES,
ALLOW_ATTRIBUTES_WITHOUT_REASON,
DEPRECATED_SEMVER,
+ IGNORE_WITHOUT_REASON,
USELESS_ATTRIBUTE,
BLANKET_CLIPPY_RESTRICTION_LINTS,
SHOULD_PANIC_WITHOUT_EXPECT,
@@ -546,28 +573,27 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) {
}
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
- if let Some(items) = &attr.meta_item_list() {
- if let Some(ident) = attr.ident() {
- if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) {
- allow_attributes::check(cx, attr);
- }
- if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION)
+ if let Some(items) = &attr.meta_item_list()
+ && let Some(ident) = attr.ident()
+ {
+ if matches!(ident.name, sym::allow) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) {
+ allow_attributes::check(cx, attr);
+ }
+ if matches!(ident.name, sym::allow | sym::expect) && self.msrv.meets(msrvs::LINT_REASONS_STABILIZATION) {
+ allow_attributes_without_reason::check(cx, ident.name, items, attr);
+ }
+ if is_lint_level(ident.name, attr.id) {
+ blanket_clippy_restriction_lints::check(cx, ident.name, items);
+ }
+ if items.is_empty() || !attr.has_name(sym::deprecated) {
+ return;
+ }
+ for item in items {
+ if let MetaItemInner::MetaItem(mi) = &item
+ && let MetaItemKind::NameValue(lit) = &mi.kind
+ && mi.has_name(sym::since)
{
- allow_attributes_without_reason::check(cx, ident.name, items, attr);
- }
- if is_lint_level(ident.name, attr.id) {
- blanket_clippy_restriction_lints::check(cx, ident.name, items);
- }
- if items.is_empty() || !attr.has_name(sym::deprecated) {
- return;
- }
- for item in items {
- if let MetaItemInner::MetaItem(mi) = &item
- && let MetaItemKind::NameValue(lit) = &mi.kind
- && mi.has_name(sym::since)
- {
- deprecated_semver::check(cx, item.span(), lit);
- }
+ deprecated_semver::check(cx, item.span(), lit);
}
}
}
@@ -575,6 +601,22 @@ fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) {
if attr.has_name(sym::should_panic) {
should_panic_without_expect::check(cx, attr);
}
+
+ if attr.has_name(sym::ignore)
+ && match &attr.kind {
+ AttrKind::Normal(normal_attr) => !matches!(normal_attr.item.args, AttrArgs::Eq { .. }),
+ AttrKind::DocComment(..) => true,
+ }
+ {
+ span_lint_and_help(
+ cx,
+ IGNORE_WITHOUT_REASON,
+ attr.span,
+ "`#[ignore]` without reason",
+ None,
+ "add a reason with `= \"..\"`",
+ );
+ }
}
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &'_ ast::Item) {
diff --git a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs
index e5cfbaf..df01c7f 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/repr_attributes.rs
@@ -30,7 +30,7 @@ pub(super) fn check(cx: &LateContext<'_>, item_span: Span, attrs: &[Attribute],
diag.warn(
"unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI",
)
- .help("qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`")
+ .help("qualify the desired ABI explicitly via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`")
.span_label(packed_span, "`packed` representation set here");
},
);
diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
index 1cb43ab..d75b732 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
@@ -14,75 +14,75 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
if attr.span.in_external_macro(cx.sess().source_map()) {
return;
}
- if let Some(lint_list) = &attr.meta_item_list() {
- if attr.ident().is_some_and(|ident| is_lint_level(ident.name, attr.id)) {
- for lint in lint_list {
- match item.kind {
- ItemKind::Use(..) => {
- let (namespace @ (Some(sym::clippy) | None), Some(name)) = namespace_and_lint(lint) else {
- return;
- };
+ if let Some(lint_list) = &attr.meta_item_list()
+ && attr.ident().is_some_and(|ident| is_lint_level(ident.name, attr.id))
+ {
+ for lint in lint_list {
+ match item.kind {
+ ItemKind::Use(..) => {
+ let (namespace @ (Some(sym::clippy) | None), Some(name)) = namespace_and_lint(lint) else {
+ return;
+ };
- if namespace.is_none()
- && matches!(
- name.as_str(),
- "ambiguous_glob_reexports"
- | "dead_code"
- | "deprecated"
- | "hidden_glob_reexports"
- | "unreachable_pub"
- | "unused"
- | "unused_braces"
- | "unused_import_braces"
- | "unused_imports"
- )
- {
- return;
- }
+ if namespace.is_none()
+ && matches!(
+ name.as_str(),
+ "ambiguous_glob_reexports"
+ | "dead_code"
+ | "deprecated"
+ | "hidden_glob_reexports"
+ | "unreachable_pub"
+ | "unused"
+ | "unused_braces"
+ | "unused_import_braces"
+ | "unused_imports"
+ )
+ {
+ return;
+ }
- if namespace == Some(sym::clippy)
- && matches!(
- name.as_str(),
- "wildcard_imports"
- | "enum_glob_use"
- | "redundant_pub_crate"
- | "macro_use_imports"
- | "unsafe_removed_from_name"
- | "module_name_repetitions"
- | "single_component_path_imports"
- | "disallowed_types"
- | "unused_trait_names"
- )
- {
- return;
- }
- },
- ItemKind::ExternCrate(..) => {
- if is_word(lint, sym::unused_imports) && skip_unused_imports {
- return;
- }
- if is_word(lint, sym::unused_extern_crates) {
- return;
- }
- },
- _ => {},
- }
+ if namespace == Some(sym::clippy)
+ && matches!(
+ name.as_str(),
+ "wildcard_imports"
+ | "enum_glob_use"
+ | "redundant_pub_crate"
+ | "macro_use_imports"
+ | "unsafe_removed_from_name"
+ | "module_name_repetitions"
+ | "single_component_path_imports"
+ | "disallowed_types"
+ | "unused_trait_names"
+ )
+ {
+ return;
+ }
+ },
+ ItemKind::ExternCrate(..) => {
+ if is_word(lint, sym::unused_imports) && skip_unused_imports {
+ return;
+ }
+ if is_word(lint, sym::unused_extern_crates) {
+ return;
+ }
+ },
+ _ => {},
}
- let line_span = first_line_of_span(cx, attr.span);
+ }
+ let line_span = first_line_of_span(cx, attr.span);
- if let Some(src) = line_span.get_source_text(cx) {
- if src.contains("#[") {
- #[expect(clippy::collapsible_span_lint_calls)]
- span_lint_and_then(cx, USELESS_ATTRIBUTE, line_span, "useless lint attribute", |diag| {
- diag.span_suggestion(
- line_span,
- "if you just forgot a `!`, use",
- src.replacen("#[", "#![", 1),
- Applicability::MaybeIncorrect,
- );
- });
- }
- }
+ if let Some(src) = line_span.get_source_text(cx)
+ && src.contains("#[")
+ {
+ #[expect(clippy::collapsible_span_lint_calls)]
+ span_lint_and_then(cx, USELESS_ATTRIBUTE, line_span, "useless lint attribute", |diag| {
+ diag.span_suggestion(
+ line_span,
+ "if you just forgot a `!`, use",
+ src.replacen("#[", "#![", 1),
+ Applicability::MaybeIncorrect,
+ );
+ });
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index 92a0c7f..52d1d5b 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -179,9 +179,14 @@ pub struct AwaitHolding {
impl AwaitHolding {
pub(crate) fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
- Self {
- def_ids: create_disallowed_map(tcx, &conf.await_holding_invalid_types),
- }
+ let (def_ids, _) = create_disallowed_map(
+ tcx,
+ &conf.await_holding_invalid_types,
+ crate::disallowed_types::def_kind_predicate,
+ "type",
+ false,
+ );
+ Self { def_ids }
}
}
@@ -192,10 +197,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
def_id,
..
}) = expr.kind
+ && let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(*def_id)
{
- if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(*def_id) {
- self.check_interior_types(cx, coroutine_layout);
- }
+ self.check_interior_types(cx, coroutine_layout);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
index ad18c70..4a876b8 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -56,7 +56,7 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -
cx.tcx.associated_items(trait_id).find_by_ident_and_kind(
cx.tcx,
Ident::from_str("Output"),
- ty::AssocKind::Type,
+ ty::AssocTag::Type,
trait_id,
)
})
diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
index 612712d..129e774 100644
--- a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
@@ -1,6 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::source::HasSession;
use clippy_utils::sugg::Sugg;
-use clippy_utils::{is_else_clause, is_in_const_context};
+use clippy_utils::{higher, is_else_clause, is_in_const_context, span_contains_comment};
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
@@ -46,18 +47,25 @@
impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- if let ExprKind::If(cond, then, Some(else_)) = expr.kind
- && matches!(cond.kind, ExprKind::DropTemps(_))
+ if !expr.span.from_expansion()
+ && let Some(higher::If {
+ cond,
+ then,
+ r#else: Some(r#else),
+ }) = higher::If::hir(expr)
&& let Some(then_lit) = as_int_bool_lit(then)
- && let Some(else_lit) = as_int_bool_lit(else_)
+ && let Some(else_lit) = as_int_bool_lit(r#else)
&& then_lit != else_lit
- && !expr.span.from_expansion()
&& !is_in_const_context(cx)
{
let ty = cx.typeck_results().expr_ty(then);
- let mut applicability = Applicability::MachineApplicable;
+ let mut applicability = if span_contains_comment(cx.sess().source_map(), expr.span) {
+ Applicability::MaybeIncorrect
+ } else {
+ Applicability::MachineApplicable
+ };
let snippet = {
- let mut sugg = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
+ let mut sugg = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "..", &mut applicability);
if !then_lit {
sugg = !sugg;
}
@@ -72,7 +80,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
s
};
- let into_snippet = snippet.clone().maybe_par();
+ let into_snippet = snippet.clone().maybe_paren();
let as_snippet = snippet.as_ty(ty);
span_lint_and_then(
@@ -91,10 +99,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
}
}
-fn as_int_bool_lit(e: &Expr<'_>) -> Option<bool> {
- if let ExprKind::Block(b, _) = e.kind
+fn as_int_bool_lit(expr: &Expr<'_>) -> Option<bool> {
+ if let ExprKind::Block(b, _) = expr.kind
&& b.stmts.is_empty()
&& let Some(e) = b.expr
+ && !e.span.from_expansion()
&& let ExprKind::Lit(lit) = e.kind
&& let LitKind::Int(x, _) = lit.node
{
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 7bb5dbe..bc6ba84 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -13,7 +13,7 @@
use rustc_lint::{LateContext, LateLintPass, Level};
use rustc_session::impl_lint_pass;
use rustc_span::def_id::LocalDefId;
-use rustc_span::{Span, sym};
+use rustc_span::{Span, SyntaxContext, sym};
declare_clippy_lint! {
/// ### What it does
@@ -242,11 +242,11 @@ struct Hir2Qmm<'a, 'tcx, 'v> {
impl<'v> Hir2Qmm<'_, '_, 'v> {
fn extract(&mut self, op: BinOpKind, a: &[&'v Expr<'_>], mut v: Vec<Bool>) -> Result<Vec<Bool>, String> {
for a in a {
- if let ExprKind::Binary(binop, lhs, rhs) = &a.kind {
- if binop.node == op {
- v = self.extract(op, &[lhs, rhs], v)?;
- continue;
- }
+ if let ExprKind::Binary(binop, lhs, rhs) = &a.kind
+ && binop.node == op
+ {
+ v = self.extract(op, &[lhs, rhs], v)?;
+ continue;
}
v.push(self.run(a)?);
}
@@ -349,9 +349,13 @@ fn recurse(&mut self, suggestion: &Bool) -> Option<()> {
if let Some(str) = simplify_not(self.cx, self.msrv, terminal) {
self.output.push_str(&str);
} else {
- self.output.push('!');
- self.output
- .push_str(&Sugg::hir_opt(self.cx, terminal)?.maybe_par().to_string());
+ let mut app = Applicability::MachineApplicable;
+ let snip = Sugg::hir_with_context(self.cx, terminal, SyntaxContext::root(), "", &mut app);
+ // Ignore the case If the expression is inside a macro expansion, or the default snippet is used
+ if app != Applicability::MachineApplicable {
+ return None;
+ }
+ self.output.push_str(&(!snip).to_string());
}
},
True | False | Not(_) => {
@@ -414,12 +418,12 @@ fn simplify_not(cx: &LateContext<'_>, curr_msrv: Msrv, expr: &Expr<'_>) -> Optio
let lhs_snippet = lhs.span.get_source_text(cx)?;
let rhs_snippet = rhs.span.get_source_text(cx)?;
- if !(lhs_snippet.starts_with('(') && lhs_snippet.ends_with(')')) {
- if let (ExprKind::Cast(..), BinOpKind::Ge) = (&lhs.kind, binop.node) {
- // e.g. `(a as u64) < b`. Without the parens the `<` is
- // interpreted as a start of generic arguments for `u64`
- return Some(format!("({lhs_snippet}){op}{rhs_snippet}"));
- }
+ if !(lhs_snippet.starts_with('(') && lhs_snippet.ends_with(')'))
+ && let (ExprKind::Cast(..), BinOpKind::Ge) = (&lhs.kind, binop.node)
+ {
+ // e.g. `(a as u64) < b`. Without the parens the `<` is
+ // interpreted as a start of generic arguments for `u64`
+ return Some(format!("({lhs_snippet}){op}{rhs_snippet}"));
}
Some(format!("{lhs_snippet}{op}{rhs_snippet}"))
diff --git a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
index 8892a9e..7cde007 100644
--- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
@@ -2,7 +2,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed};
+use clippy_utils::{get_parent_expr, is_from_proc_macro, is_lint_allowed, is_mutable};
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
@@ -73,6 +73,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
}
})
&& !is_from_proc_macro(cx, e)
+ && let e_ty = cx.typeck_results().expr_ty_adjusted(e)
+ // check if the reference is coercing to a mutable reference
+ && (!matches!(e_ty.kind(), ty::Ref(_, _, Mutability::Mut)) || is_mutable(cx, deref_target))
&& let Some(deref_text) = deref_target.span.get_source_text(cx)
{
span_lint_and_then(
@@ -90,10 +93,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
// has deref trait -> give 2 help
// doesn't have deref trait -> give 1 help
- if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait() {
- if !implements_trait(cx, *inner_ty, deref_trait_id, &[]) {
- return;
- }
+ if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait()
+ && !implements_trait(cx, *inner_ty, deref_trait_id, &[])
+ {
+ return;
}
diag.span_suggestion(
diff --git a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
index 64345c8..ad0a4f8 100644
--- a/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/borrow_as_ptr.rs
@@ -1,11 +1,12 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::msrvs::Msrv;
use clippy_utils::source::{snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::has_enclosing_paren;
-use clippy_utils::{is_expr_temporary_value, is_lint_allowed, msrvs, std_or_core};
+use clippy_utils::{get_parent_expr, is_expr_temporary_value, is_lint_allowed, msrvs, std_or_core};
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Ty, TyKind};
use rustc_lint::LateContext;
+use rustc_middle::ty::adjustment::{Adjust, AutoBorrow};
use rustc_span::BytePos;
use super::BORROW_AS_PTR;
@@ -29,10 +30,6 @@ pub(super) fn check<'tcx>(
}
let (suggestion, span) = if msrv.meets(cx, msrvs::RAW_REF_OP) {
- let operator_kind = match mutability {
- Mutability::Not => "const",
- Mutability::Mut => "mut",
- };
// Make sure that the span to be replaced doesn't include parentheses, that could break the
// suggestion.
let span = if has_enclosing_paren(snippet_with_applicability(cx, expr.span, "", &mut app)) {
@@ -42,7 +39,7 @@ pub(super) fn check<'tcx>(
} else {
expr.span
};
- (format!("&raw {operator_kind} {snip}"), span)
+ (format!("&raw {} {snip}", mutability.ptr_str()), span)
} else {
let Some(std_or_core) = std_or_core(cx) else {
return false;
@@ -59,3 +56,25 @@ pub(super) fn check<'tcx>(
}
false
}
+
+/// Check for an implicit cast from reference to raw pointer outside an explicit `as`.
+pub(super) fn check_implicit_cast(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if !expr.span.from_expansion()
+ && let ExprKind::AddrOf(BorrowKind::Ref, _, pointee) = expr.kind
+ && !matches!(get_parent_expr(cx, expr).map(|e| e.kind), Some(ExprKind::Cast(..)))
+ && let [deref, borrow] = cx.typeck_results().expr_adjustments(expr)
+ && matches!(deref.kind, Adjust::Deref(..))
+ && let Adjust::Borrow(AutoBorrow::RawPtr(mutability)) = borrow.kind
+ // Do not suggest taking a raw pointer to a temporary value
+ && !is_expr_temporary_value(cx, pointee)
+ {
+ span_lint_and_then(cx, BORROW_AS_PTR, expr.span, "implicit borrow as raw pointer", |diag| {
+ diag.span_suggestion_verbose(
+ expr.span.until(pointee.span),
+ "use a raw pointer instead",
+ format!("&raw {} ", mutability.ptr_str()),
+ Applicability::MachineApplicable,
+ );
+ });
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
index 8b3529e..164d3540 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
@@ -36,7 +36,7 @@ pub(super) fn check(
span,
format!("casting the result of `{cast_from}::abs()` to {cast_to}"),
"replace with",
- format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_par()),
+ format!("{}.unsigned_abs()", Sugg::hir(cx, receiver, "..").maybe_paren()),
Applicability::MachineApplicable,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
index 3ae4373..0f066fa 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
@@ -42,7 +42,7 @@ pub(super) fn check(
diag.span_suggestion_verbose(
expr.span,
"use `Into::into` instead",
- format!("{}.into()", from_sugg.maybe_par()),
+ format!("{}.into()", from_sugg.maybe_paren()),
applicability,
);
},
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
index ca973f4..8742f5f 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs
@@ -64,11 +64,11 @@ fn apply_reductions(cx: &LateContext<'_>, nbits: u64, expr: &Expr<'_>, signed: b
apply_reductions(cx, nbits, left, signed).min(max_bits.unwrap_or(u64::MAX))
},
ExprKind::MethodCall(method, _, [lo, hi], _) => {
- if method.ident.as_str() == "clamp" {
+ if method.ident.as_str() == "clamp"
//FIXME: make this a diagnostic item
- if let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi)) {
- return lo_bits.max(hi_bits);
- }
+ && let (Some(lo_bits), Some(hi_bits)) = (get_constant_bits(cx, lo), get_constant_bits(cx, hi))
+ {
+ return lo_bits.max(hi_bits);
}
nbits
},
@@ -185,7 +185,7 @@ fn offer_suggestion(
) {
let cast_to_snip = snippet(cx, cast_to_span, "..");
let suggestion = if cast_to_snip == "_" {
- format!("{}.try_into()", Sugg::hir(cx, cast_expr, "..").maybe_par())
+ format!("{}.try_into()", Sugg::hir(cx, cast_expr, "..").maybe_paren())
} else {
format!("{cast_to_snip}::try_from({})", Sugg::hir(cx, cast_expr, ".."))
};
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
index 57a135a..3fca0f8 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -19,16 +19,15 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
cx.typeck_results().expr_ty(expr),
);
lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
- } else if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind {
- if method_path.ident.name.as_str() == "cast"
- && let Some(generic_args) = method_path.args
- && let [GenericArg::Type(cast_to)] = generic_args.args
- // There probably is no obvious reason to do this, just to be consistent with `as` cases.
- && !is_hir_ty_cfg_dependant(cx, cast_to.as_unambig_ty())
- {
- let (cast_from, cast_to) = (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr));
- lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
- }
+ } else if let ExprKind::MethodCall(method_path, self_arg, [], _) = &expr.kind
+ && method_path.ident.name.as_str() == "cast"
+ && let Some(generic_args) = method_path.args
+ && let [GenericArg::Type(cast_to)] = generic_args.args
+ // There probably is no obvious reason to do this, just to be consistent with `as` cases.
+ && !is_hir_ty_cfg_dependant(cx, cast_to.as_unambig_ty())
+ {
+ let (cast_from, cast_to) = (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr));
+ lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
index c48f2536..a5b295c 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
@@ -21,42 +21,41 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: Msrv)
start_ty,
end_ty,
}) = expr_cast_chain_tys(cx, expr)
+ && let (Ok(from_layout), Ok(to_layout)) = (cx.layout_of(start_ty.ty), cx.layout_of(end_ty.ty))
{
- if let (Ok(from_layout), Ok(to_layout)) = (cx.layout_of(start_ty.ty), cx.layout_of(end_ty.ty)) {
- let from_size = from_layout.size.bytes();
- let to_size = to_layout.size.bytes();
- if from_size != to_size && from_size != 0 && to_size != 0 && msrv.meets(cx, msrvs::PTR_SLICE_RAW_PARTS) {
- span_lint_and_then(
- cx,
- CAST_SLICE_DIFFERENT_SIZES,
- expr.span,
- format!(
- "casting between raw pointers to `[{}]` (element size {from_size}) and `[{}]` (element size {to_size}) does not adjust the count",
- start_ty.ty, end_ty.ty,
- ),
- |diag| {
- let ptr_snippet = source::snippet(cx, left_cast.span, "..");
+ let from_size = from_layout.size.bytes();
+ let to_size = to_layout.size.bytes();
+ if from_size != to_size && from_size != 0 && to_size != 0 && msrv.meets(cx, msrvs::PTR_SLICE_RAW_PARTS) {
+ span_lint_and_then(
+ cx,
+ CAST_SLICE_DIFFERENT_SIZES,
+ expr.span,
+ format!(
+ "casting between raw pointers to `[{}]` (element size {from_size}) and `[{}]` (element size {to_size}) does not adjust the count",
+ start_ty.ty, end_ty.ty,
+ ),
+ |diag| {
+ let ptr_snippet = source::snippet(cx, left_cast.span, "..");
- let (mutbl_fn_str, mutbl_ptr_str) = match end_ty.mutbl {
- Mutability::Mut => ("_mut", "mut"),
- Mutability::Not => ("", "const"),
- };
- let sugg = format!(
- "core::ptr::slice_from_raw_parts{mutbl_fn_str}({ptr_snippet} as *{mutbl_ptr_str} {}, ..)",
- // get just the ty from the TypeAndMut so that the printed type isn't something like `mut
- // T`, extract just the `T`
- end_ty.ty
- );
+ let (mutbl_fn_str, mutbl_ptr_str) = match end_ty.mutbl {
+ Mutability::Mut => ("_mut", "mut"),
+ Mutability::Not => ("", "const"),
+ };
+ let sugg = format!(
+ "core::ptr::slice_from_raw_parts{mutbl_fn_str}({ptr_snippet} as *{mutbl_ptr_str} {}, ..)",
+ // get just the ty from the TypeAndMut so that the printed type isn't something like `mut
+ // T`, extract just the `T`
+ end_ty.ty
+ );
- diag.span_suggestion(
- expr.span,
- format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
- sugg,
- rustc_errors::Applicability::HasPlaceholders,
- );
- },
- );
- }
+ diag.span_suggestion(
+ expr.span,
+ format!("replace with `ptr::slice_from_raw_parts{mutbl_fn_str}`"),
+ sugg,
+ rustc_errors::Applicability::HasPlaceholders,
+ );
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
new file mode 100644
index 0000000..8ace27e
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs
@@ -0,0 +1,82 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::SpanRangeExt;
+use clippy_utils::ty::is_normalizable;
+use clippy_utils::{expr_or_init, match_def_path, path_def_id, paths, std_or_core};
+use rustc_ast::LitKind;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind, GenericArg, Mutability, QPath, Ty, TyKind};
+use rustc_lint::LateContext;
+use rustc_span::source_map::Spanned;
+
+use super::MANUAL_DANGLING_PTR;
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, from: &Expr<'_>, to: &Ty<'_>) {
+ if let TyKind::Ptr(ref ptr_ty) = to.kind {
+ let init_expr = expr_or_init(cx, from);
+ if is_expr_const_aligned(cx, init_expr, ptr_ty.ty)
+ && let Some(std_or_core) = std_or_core(cx)
+ {
+ let sugg_fn = match ptr_ty.mutbl {
+ Mutability::Not => "ptr::dangling",
+ Mutability::Mut => "ptr::dangling_mut",
+ };
+
+ let sugg = if let TyKind::Infer(()) = ptr_ty.ty.kind {
+ format!("{std_or_core}::{sugg_fn}()")
+ } else if let Some(mut_ty_snip) = ptr_ty.ty.span.get_source_text(cx) {
+ format!("{std_or_core}::{sugg_fn}::<{mut_ty_snip}>()")
+ } else {
+ return;
+ };
+
+ span_lint_and_sugg(
+ cx,
+ MANUAL_DANGLING_PTR,
+ expr.span,
+ "manual creation of a dangling pointer",
+ "use",
+ sugg,
+ Applicability::MachineApplicable,
+ );
+ }
+ }
+}
+
+// Checks if the given expression is a call to `align_of` whose generic argument matches the target
+// type, or a positive constant literal that matches the target type's alignment.
+fn is_expr_const_aligned(cx: &LateContext<'_>, expr: &Expr<'_>, to: &Ty<'_>) -> bool {
+ match expr.kind {
+ ExprKind::Call(fun, _) => is_align_of_call(cx, fun, to),
+ ExprKind::Lit(lit) => is_literal_aligned(cx, lit, to),
+ _ => false,
+ }
+}
+
+fn is_align_of_call(cx: &LateContext<'_>, fun: &Expr<'_>, to: &Ty<'_>) -> bool {
+ if let ExprKind::Path(QPath::Resolved(_, path)) = fun.kind
+ && let Some(fun_id) = path_def_id(cx, fun)
+ && match_def_path(cx, fun_id, &paths::ALIGN_OF)
+ && let Some(args) = path.segments.last().and_then(|seg| seg.args)
+ && let [GenericArg::Type(generic_ty)] = args.args
+ {
+ let typeck = cx.typeck_results();
+ return typeck.node_type(generic_ty.hir_id) == typeck.node_type(to.hir_id);
+ }
+ false
+}
+
+fn is_literal_aligned(cx: &LateContext<'_>, lit: &Spanned<LitKind>, to: &Ty<'_>) -> bool {
+ let LitKind::Int(val, _) = lit.node else { return false };
+ if val == 0 {
+ return false;
+ }
+ let to_mid_ty = cx.typeck_results().node_type(to.hir_id);
+ is_normalizable(cx, cx.param_env, to_mid_ty)
+ && cx
+ .tcx
+ .layout_of(cx.typing_env().as_query_input(to_mid_ty))
+ .is_ok_and(|layout| {
+ let align = u128::from(layout.align.abi.bytes());
+ u128::from(val) <= align
+ })
+}
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index dc2a1fa..76931fc 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -17,6 +17,7 @@
mod fn_to_numeric_cast;
mod fn_to_numeric_cast_any;
mod fn_to_numeric_cast_with_truncation;
+mod manual_dangling_ptr;
mod ptr_as_ptr;
mod ptr_cast_constness;
mod ref_as_ptr;
@@ -71,7 +72,7 @@
/// ### Example
/// ```no_run
/// let y: i8 = -1;
- /// y as u128; // will return 18446744073709551615
+ /// y as u64; // will return 18446744073709551615
/// ```
#[clippy::version = "pre 1.29.0"]
pub CAST_SIGN_LOSS,
@@ -759,6 +760,32 @@
"detects `as *mut _` and `as *const _` conversion"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for casts of small constant literals or `mem::align_of` results to raw pointers.
+ ///
+ /// ### Why is this bad?
+ /// This creates a dangling pointer and is better expressed as
+ /// {`std`, `core`}`::ptr::`{`dangling`, `dangling_mut`}.
+ ///
+ /// ### Example
+ /// ```no_run
+ /// let ptr = 4 as *const u32;
+ /// let aligned = std::mem::align_of::<u32>() as *const u32;
+ /// let mut_ptr: *mut i64 = 8 as *mut _;
+ /// ```
+ /// Use instead:
+ /// ```no_run
+ /// let ptr = std::ptr::dangling::<u32>();
+ /// let aligned = std::ptr::dangling::<u32>();
+ /// let mut_ptr: *mut i64 = std::ptr::dangling_mut();
+ /// ```
+ #[clippy::version = "1.87.0"]
+ pub MANUAL_DANGLING_PTR,
+ style,
+ "casting small constant literals to pointers to create dangling pointers"
+}
+
pub struct Casts {
msrv: Msrv,
}
@@ -795,6 +822,7 @@ pub fn new(conf: &'static Conf) -> Self {
ZERO_PTR,
REF_AS_PTR,
AS_POINTER_UNDERSCORE,
+ MANUAL_DANGLING_PTR,
]);
impl<'tcx> LateLintPass<'tcx> for Casts {
@@ -823,6 +851,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
fn_to_numeric_cast_with_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to);
zero_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
+ if self.msrv.meets(cx, msrvs::MANUAL_DANGLING_PTR) {
+ manual_dangling_ptr::check(cx, expr, cast_from_expr, cast_to_hir);
+ }
+
if cast_to.is_numeric() {
cast_possible_truncation::check(cx, expr, cast_from_expr, cast_from, cast_to, cast_to_hir.span);
if cast_from.is_numeric() {
@@ -846,6 +878,9 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
}
}
+ if self.msrv.meets(cx, msrvs::RAW_REF_OP) {
+ borrow_as_ptr::check_implicit_cast(cx, expr);
+ }
cast_ptr_alignment::check(cx, expr);
char_lit_as_u8::check(cx, expr);
ptr_as_ptr::check(cx, expr, self.msrv);
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index d57e391..6f94491 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -81,7 +81,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, msrv: Msrv) {
(
"try `pointer::cast`, a safer alternative",
- format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_par()),
+ format!("{}.cast{turbofish}()", cast_expr_sugg.maybe_paren()),
)
};
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
index cad9c1d..2471c73 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
@@ -53,7 +53,8 @@ pub(super) fn check<'tcx>(
}
if msrv.meets(cx, msrvs::POINTER_CAST_CONSTNESS) {
- let sugg = Sugg::hir(cx, cast_expr, "_");
+ let mut app = Applicability::MachineApplicable;
+ let sugg = Sugg::hir_with_context(cx, cast_expr, expr.span.ctxt(), "_", &mut app);
let constness = match *to_mutbl {
Mutability::Not => "const",
Mutability::Mut => "mut",
@@ -65,8 +66,8 @@ pub(super) fn check<'tcx>(
expr.span,
"`as` casting between raw pointers while changing only its constness",
format!("try `pointer::cast_{constness}`, a safer alternative"),
- format!("{}.cast_{constness}()", sugg.maybe_par()),
- Applicability::MachineApplicable,
+ format!("{}.cast_{constness}()", sugg.maybe_paren()),
+ app,
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index 7295381..ae994e9 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -130,11 +130,11 @@ pub(super) fn check<'tcx>(
| LitKind::Float(_, LitFloatType::Suffixed(_))
if cast_from.kind() == cast_to.kind() =>
{
- if let Some(src) = cast_expr.span.get_source_text(cx) {
- if let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node) {
- lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
- return true;
- }
+ if let Some(src) = cast_expr.span.get_source_text(cx)
+ && let Some(num_lit) = NumericLiteral::from_lit_kind(&src, &lit.node)
+ {
+ lint_unnecessary_cast(cx, expr, num_lit.integer, cast_from, cast_to);
+ return true;
}
},
_ => {},
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index b36c866..8ada608 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -253,11 +253,11 @@ fn get_types_from_cast<'a>(
match limit.kind {
// `from_type::from(_)`
ExprKind::Call(path, _) => {
- if let ExprKind::Path(ref path) = path.kind {
+ if let ExprKind::Path(ref path) = path.kind
// `to_type`
- if let Some(to_type) = get_implementing_type(path, types, func) {
- return Some((from_type, to_type));
- }
+ && let Some(to_type) = get_implementing_type(path, types, func)
+ {
+ return Some((from_type, to_type));
}
},
// `to_type::MAX`
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index a1ff20d..1d44c7e 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -62,6 +62,7 @@ fn check<'tcx>(
let mut cc = 1u64;
let mut returns = 0u64;
+ let mut prev_expr: Option<&ExprKind<'tcx>> = None;
let _: Option<!> = for_each_expr_without_closures(expr, |e| {
match e.kind {
ExprKind::If(_, _, _) => {
@@ -73,9 +74,14 @@ fn check<'tcx>(
}
cc += arms.iter().filter(|arm| arm.guard.is_some()).count() as u64;
},
- ExprKind::Ret(_) => returns += 1,
+ ExprKind::Ret(_) => {
+ if !matches!(prev_expr, Some(ExprKind::Ret(_))) {
+ returns += 1;
+ }
+ },
_ => {},
}
+ prev_expr = Some(&e.kind);
ControlFlow::Continue(())
});
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
index e73bfc6..20fae8a 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
@@ -1,10 +1,12 @@
+use clippy_config::Conf;
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::source::{snippet, snippet_block, snippet_block_with_applicability};
-use clippy_utils::sugg::Sugg;
-use rustc_ast::ast;
+use clippy_utils::source::{IntoSpan as _, SpanRangeExt, snippet, snippet_block, snippet_block_with_applicability};
+use rustc_ast::BinOpKind;
use rustc_errors::Applicability;
-use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::declare_lint_pass;
+use rustc_hir::{Block, Expr, ExprKind, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::TyCtxt;
+use rustc_session::impl_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
@@ -75,105 +77,152 @@
"nested `else`-`if` expressions that can be collapsed (e.g., `else { if x { ... } }`)"
}
-declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]);
+pub struct CollapsibleIf {
+ let_chains_enabled: bool,
+ lint_commented_code: bool,
+}
-impl EarlyLintPass for CollapsibleIf {
- fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) {
- if let ast::ExprKind::If(cond, then, else_) = &expr.kind
+impl CollapsibleIf {
+ pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
+ Self {
+ let_chains_enabled: tcx.features().let_chains(),
+ lint_commented_code: conf.lint_commented_code,
+ }
+ }
+
+ fn check_collapsible_else_if(cx: &LateContext<'_>, then_span: Span, else_block: &Block<'_>) {
+ if !block_starts_with_comment(cx, else_block)
+ && let Some(else_) = expr_block(else_block)
+ && cx.tcx.hir_attrs(else_.hir_id).is_empty()
+ && !else_.span.from_expansion()
+ && let ExprKind::If(..) = else_.kind
+ {
+ // Prevent "elseif"
+ // Check that the "else" is followed by whitespace
+ let up_to_else = then_span.between(else_block.span);
+ let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() {
+ !c.is_whitespace()
+ } else {
+ false
+ };
+
+ let mut applicability = Applicability::MachineApplicable;
+ span_lint_and_sugg(
+ cx,
+ COLLAPSIBLE_ELSE_IF,
+ else_block.span,
+ "this `else { if .. }` block can be collapsed",
+ "collapse nested if block",
+ format!(
+ "{}{}",
+ if requires_space { " " } else { "" },
+ snippet_block_with_applicability(cx, else_.span, "..", Some(else_block.span), &mut applicability)
+ ),
+ applicability,
+ );
+ }
+ }
+
+ fn check_collapsible_if_if(&self, cx: &LateContext<'_>, expr: &Expr<'_>, check: &Expr<'_>, then: &Block<'_>) {
+ if let Some(inner) = expr_block(then)
+ && cx.tcx.hir_attrs(inner.hir_id).is_empty()
+ && let ExprKind::If(check_inner, _, None) = &inner.kind
+ && self.eligible_condition(check_inner)
+ && let ctxt = expr.span.ctxt()
+ && inner.span.ctxt() == ctxt
+ && (self.lint_commented_code || !block_starts_with_comment(cx, then))
+ {
+ span_lint_and_then(
+ cx,
+ COLLAPSIBLE_IF,
+ expr.span,
+ "this `if` statement can be collapsed",
+ |diag| {
+ let then_open_bracket = then.span.split_at(1).0.with_leading_whitespace(cx).into_span();
+ let then_closing_bracket = {
+ let end = then.span.shrink_to_hi();
+ end.with_lo(end.lo() - rustc_span::BytePos(1))
+ .with_leading_whitespace(cx)
+ .into_span()
+ };
+ let inner_if = inner.span.split_at(2).0;
+ let mut sugg = vec![
+ // Remove the outer then block `{`
+ (then_open_bracket, String::new()),
+ // Remove the outer then block '}'
+ (then_closing_bracket, String::new()),
+ // Replace inner `if` by `&&`
+ (inner_if, String::from("&&")),
+ ];
+ sugg.extend(parens_around(check));
+ sugg.extend(parens_around(check_inner));
+
+ diag.multipart_suggestion("collapse nested if block", sugg, Applicability::MachineApplicable);
+ },
+ );
+ }
+ }
+
+ pub fn eligible_condition(&self, cond: &Expr<'_>) -> bool {
+ self.let_chains_enabled || !matches!(cond.kind, ExprKind::Let(..))
+ }
+}
+
+impl_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]);
+
+impl LateLintPass<'_> for CollapsibleIf {
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if let ExprKind::If(cond, then, else_) = &expr.kind
&& !expr.span.from_expansion()
{
- if let Some(else_) = else_ {
- check_collapsible_maybe_if_let(cx, then.span, else_);
- } else if !matches!(cond.kind, ast::ExprKind::Let(..)) {
- check_collapsible_no_if_let(cx, expr, cond, then);
+ if let Some(else_) = else_
+ && let ExprKind::Block(else_, None) = else_.kind
+ {
+ Self::check_collapsible_else_if(cx, then.span, else_);
+ } else if else_.is_none()
+ && self.eligible_condition(cond)
+ && let ExprKind::Block(then, None) = then.kind
+ {
+ self.check_collapsible_if_if(cx, expr, cond, then);
}
}
}
}
-fn block_starts_with_comment(cx: &EarlyContext<'_>, expr: &ast::Block) -> bool {
+fn block_starts_with_comment(cx: &LateContext<'_>, block: &Block<'_>) -> bool {
// We trim all opening braces and whitespaces and then check if the next string is a comment.
- let trimmed_block_text = snippet_block(cx, expr.span, "..", None)
+ let trimmed_block_text = snippet_block(cx, block.span, "..", None)
.trim_start_matches(|c: char| c.is_whitespace() || c == '{')
.to_owned();
trimmed_block_text.starts_with("//") || trimmed_block_text.starts_with("/*")
}
-fn check_collapsible_maybe_if_let(cx: &EarlyContext<'_>, then_span: Span, else_: &ast::Expr) {
- if let ast::ExprKind::Block(ref block, _) = else_.kind
- && !block_starts_with_comment(cx, block)
- && let Some(else_) = expr_block(block)
- && else_.attrs.is_empty()
- && !else_.span.from_expansion()
- && let ast::ExprKind::If(..) = else_.kind
- {
- // Prevent "elseif"
- // Check that the "else" is followed by whitespace
- let up_to_else = then_span.between(block.span);
- let requires_space = if let Some(c) = snippet(cx, up_to_else, "..").chars().last() {
- !c.is_whitespace()
- } else {
- false
- };
-
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- COLLAPSIBLE_ELSE_IF,
- block.span,
- "this `else { if .. }` block can be collapsed",
- "collapse nested if block",
- format!(
- "{}{}",
- if requires_space { " " } else { "" },
- snippet_block_with_applicability(cx, else_.span, "..", Some(block.span), &mut applicability)
- ),
- applicability,
- );
+/// If `block` is a block with either one expression or a statement containing an expression,
+/// return the expression. We don't peel blocks recursively, as extra blocks might be intentional.
+fn expr_block<'tcx>(block: &Block<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+ match block.stmts {
+ [] => block.expr,
+ [stmt] => {
+ if let StmtKind::Semi(expr) = stmt.kind {
+ Some(expr)
+ } else {
+ None
+ }
+ },
+ _ => None,
}
}
-fn check_collapsible_no_if_let(cx: &EarlyContext<'_>, expr: &ast::Expr, check: &ast::Expr, then: &ast::Block) {
- if !block_starts_with_comment(cx, then)
- && let Some(inner) = expr_block(then)
- && inner.attrs.is_empty()
- && let ast::ExprKind::If(ref check_inner, ref content, None) = inner.kind
- // Prevent triggering on `if c { if let a = b { .. } }`.
- && !matches!(check_inner.kind, ast::ExprKind::Let(..))
- && let ctxt = expr.span.ctxt()
- && inner.span.ctxt() == ctxt
+/// If the expression is a `||`, suggest parentheses around it.
+fn parens_around(expr: &Expr<'_>) -> Vec<(Span, String)> {
+ if let ExprKind::Binary(op, _, _) = expr.peel_drop_temps().kind
+ && op.node == BinOpKind::Or
{
- span_lint_and_then(
- cx,
- COLLAPSIBLE_IF,
- expr.span,
- "this `if` statement can be collapsed",
- |diag| {
- let mut app = Applicability::MachineApplicable;
- let lhs = Sugg::ast(cx, check, "..", ctxt, &mut app);
- let rhs = Sugg::ast(cx, check_inner, "..", ctxt, &mut app);
- diag.span_suggestion(
- expr.span,
- "collapse nested if block",
- format!(
- "if {} {}",
- lhs.and(&rhs),
- snippet_block(cx, content.span, "..", Some(expr.span)),
- ),
- app, // snippet
- );
- },
- );
- }
-}
-
-/// If the block contains only one expression, return it.
-fn expr_block(block: &ast::Block) -> Option<&ast::Expr> {
- if let [stmt] = &*block.stmts
- && let ast::StmtKind::Expr(expr) | ast::StmtKind::Semi(expr) = &stmt.kind
- {
- Some(expr)
+ vec![
+ (expr.span.shrink_to_lo(), String::from("(")),
+ (expr.span.shrink_to_hi(), String::from(")")),
+ ]
} else {
- None
+ vec![]
}
}
diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
index 0e7f01e..9c3009a 100644
--- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs
+++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
@@ -125,7 +125,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let ExprKind::Binary(_, lhs, rhs) = conds[0].kind else {
unreachable!();
};
- let lhs = Sugg::hir(cx, lhs, "..").maybe_par();
+ let lhs = Sugg::hir(cx, lhs, "..").maybe_paren();
let rhs = Sugg::hir(cx, rhs, "..").addr();
span_lint_and_sugg(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index 03ed9c6..42fbe64 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -256,7 +256,7 @@ fn lint_branches_sharing_code<'tcx>(
let suggestion = reindent_multiline(&suggestion, true, indent);
let span = span.with_hi(last_block.span.hi());
- // Improve formatting if the inner block has indention (i.e. normal Rust formatting)
+ // Improve formatting if the inner block has indentation (i.e. normal Rust formatting)
let span = span
.map_range(cx, |src, range| {
(range.start > 4 && src.get(range.start - 4..range.start)? == " ")
@@ -539,10 +539,10 @@ fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbo
.filter(|stmt| !ignore_span.overlaps(stmt.span))
.try_for_each(|stmt| intravisit::walk_stmt(&mut walker, stmt));
- if let Some(expr) = block.expr {
- if res.is_continue() {
- res = intravisit::walk_expr(&mut walker, expr);
- }
+ if let Some(expr) = block.expr
+ && res.is_continue()
+ {
+ res = intravisit::walk_expr(&mut walker, expr);
}
res.is_break()
diff --git a/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs b/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs
index 4d908af..9f82f87 100644
--- a/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs
+++ b/src/tools/clippy/clippy_lints/src/declare_clippy_lint.rs
@@ -165,17 +165,4 @@ macro_rules! declare_clippy_lint {
$(, $eval_always)?
}
};
-
- (
- $(#[doc = $lit:literal])*
- pub $lint_name:ident,
- internal,
- $desc:literal
- ) => {
- declare_clippy_lint! {@
- $(#[doc = $lit])*
- pub $lint_name, Allow, crate::LintCategory::Internal, $desc,
- None, "0.0.0"
- }
- };
}
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 39e4516..2cccd6b 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -3,36 +3,6 @@
// Manual edits will be overwritten.
pub static LINTS: &[&crate::LintInfo] = &[
- #[cfg(feature = "internal")]
- crate::utils::internal_lints::almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION_INFO,
- #[cfg(feature = "internal")]
- crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO,
- #[cfg(feature = "internal")]
- crate::utils::internal_lints::interning_defined_symbol::INTERNING_DEFINED_SYMBOL_INFO,
- #[cfg(feature = "internal")]
- crate::utils::internal_lints::interning_defined_symbol::UNNECESSARY_SYMBOL_STR_INFO,
- #[cfg(feature = "internal")]
- crate::utils::internal_lints::invalid_paths::INVALID_PATHS_INFO,
- #[cfg(feature = "internal")]
- crate::utils::internal_lints::lint_without_lint_pass::DEFAULT_LINT_INFO,
- #[cfg(feature = "internal")]
- crate::utils::internal_lints::lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE_INFO,
- #[cfg(feature = "internal")]
- crate::utils::internal_lints::lint_without_lint_pass::LINT_WITHOUT_LINT_PASS_INFO,
- #[cfg(feature = "internal")]
- crate::utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE_INFO,
- #[cfg(feature = "internal")]
- crate::utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL_INFO,
- #[cfg(feature = "internal")]
- crate::utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA_INFO,
- #[cfg(feature = "internal")]
- crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
- #[cfg(feature = "internal")]
- crate::utils::internal_lints::slow_symbol_comparisons::SLOW_SYMBOL_COMPARISONS_INFO,
- #[cfg(feature = "internal")]
- crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
- #[cfg(feature = "internal")]
- crate::utils::internal_lints::unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS_INFO,
crate::absolute_paths::ABSOLUTE_PATHS_INFO,
crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
crate::approx_const::APPROX_CONSTANT_INFO,
@@ -52,6 +22,7 @@
crate::attrs::DEPRECATED_CLIPPY_CFG_ATTR_INFO,
crate::attrs::DEPRECATED_SEMVER_INFO,
crate::attrs::DUPLICATED_ATTRIBUTES_INFO,
+ crate::attrs::IGNORE_WITHOUT_REASON_INFO,
crate::attrs::INLINE_ALWAYS_INFO,
crate::attrs::MIXED_ATTRIBUTES_STYLE_INFO,
crate::attrs::NON_MINIMAL_CFG_INFO,
@@ -96,6 +67,7 @@
crate::casts::FN_TO_NUMERIC_CAST_INFO,
crate::casts::FN_TO_NUMERIC_CAST_ANY_INFO,
crate::casts::FN_TO_NUMERIC_CAST_WITH_TRUNCATION_INFO,
+ crate::casts::MANUAL_DANGLING_PTR_INFO,
crate::casts::PTR_AS_PTR_INFO,
crate::casts::PTR_CAST_CONSTNESS_INFO,
crate::casts::REF_AS_PTR_INFO,
@@ -286,6 +258,7 @@
crate::literal_representation::UNREADABLE_LITERAL_INFO,
crate::literal_representation::UNUSUAL_BYTE_GROUPINGS_INFO,
crate::literal_string_with_formatting_args::LITERAL_STRING_WITH_FORMATTING_ARGS_INFO,
+ crate::loops::CHAR_INDICES_AS_BYTE_INDICES_INFO,
crate::loops::EMPTY_LOOP_INFO,
crate::loops::EXPLICIT_COUNTER_LOOP_INFO,
crate::loops::EXPLICIT_INTO_ITER_LOOP_INFO,
@@ -312,6 +285,7 @@
crate::macro_metavars_in_unsafe::MACRO_METAVARS_IN_UNSAFE_INFO,
crate::macro_use::MACRO_USE_IMPORTS_INFO,
crate::main_recursion::MAIN_RECURSION_INFO,
+ crate::manual_abs_diff::MANUAL_ABS_DIFF_INFO,
crate::manual_assert::MANUAL_ASSERT_INFO,
crate::manual_async_fn::MANUAL_ASYNC_FN_INFO,
crate::manual_bits::MANUAL_BITS_INFO,
@@ -334,7 +308,6 @@
crate::manual_slice_size_calculation::MANUAL_SLICE_SIZE_CALCULATION_INFO,
crate::manual_string_new::MANUAL_STRING_NEW_INFO,
crate::manual_strip::MANUAL_STRIP_INFO,
- crate::manual_unwrap_or_default::MANUAL_UNWRAP_OR_DEFAULT_INFO,
crate::map_unit_fn::OPTION_MAP_UNIT_FN_INFO,
crate::map_unit_fn::RESULT_MAP_UNIT_FN_INFO,
crate::match_result_ok::MATCH_RESULT_OK_INFO,
@@ -344,10 +317,10 @@
crate::matches::MANUAL_MAP_INFO,
crate::matches::MANUAL_OK_ERR_INFO,
crate::matches::MANUAL_UNWRAP_OR_INFO,
+ crate::matches::MANUAL_UNWRAP_OR_DEFAULT_INFO,
crate::matches::MATCH_AS_REF_INFO,
crate::matches::MATCH_BOOL_INFO,
crate::matches::MATCH_LIKE_MATCHES_MACRO_INFO,
- crate::matches::MATCH_ON_VEC_ITEMS_INFO,
crate::matches::MATCH_OVERLAPPING_ARM_INFO,
crate::matches::MATCH_REF_PATS_INFO,
crate::matches::MATCH_SAME_ARMS_INFO,
@@ -488,6 +461,7 @@
crate::methods::SUSPICIOUS_OPEN_OPTIONS_INFO,
crate::methods::SUSPICIOUS_SPLITN_INFO,
crate::methods::SUSPICIOUS_TO_OWNED_INFO,
+ crate::methods::SWAP_WITH_TEMPORARY_INFO,
crate::methods::TYPE_ID_ON_BOX_INFO,
crate::methods::UNBUFFERED_BYTES_INFO,
crate::methods::UNINIT_ASSUMED_INIT_INFO,
@@ -664,6 +638,7 @@
crate::redundant_slicing::DEREF_BY_SLICING_INFO,
crate::redundant_slicing::REDUNDANT_SLICING_INFO,
crate::redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES_INFO,
+ crate::redundant_test_prefix::REDUNDANT_TEST_PREFIX_INFO,
crate::redundant_type_annotations::REDUNDANT_TYPE_ANNOTATIONS_INFO,
crate::ref_option_ref::REF_OPTION_REF_INFO,
crate::ref_patterns::REF_PATTERNS_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
index bbd5dc1..f8a9037 100644
--- a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
+++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
@@ -1,5 +1,6 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_ty_alias;
+use clippy_utils::source::SpanRangeExt as _;
use hir::ExprKind;
use hir::def::Res;
use rustc_errors::Applicability;
@@ -70,15 +71,26 @@ fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tc
&& let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant()
&& !var.is_field_list_non_exhaustive()
&& !expr.span.from_expansion() && !qpath.span().from_expansion()
+ // do not suggest replacing an expression by a type name with placeholders
+ && !base.is_suggestable_infer_ty()
{
- span_lint_and_sugg(
+ let mut removals = vec![(expr.span.with_lo(qpath.qself_span().hi()), String::new())];
+ if expr.span.with_source_text(cx, |s| s.starts_with('<')) == Some(true) {
+ // Remove `<`, '>` has already been removed by the existing removal expression.
+ removals.push((expr.span.with_hi(qpath.qself_span().lo()), String::new()));
+ }
+ span_lint_and_then(
cx,
DEFAULT_CONSTRUCTED_UNIT_STRUCTS,
- expr.span.with_lo(qpath.qself_span().hi()),
+ expr.span,
"use of `default` to create a unit struct",
- "remove this call to `default`",
- String::new(),
- Applicability::MachineApplicable,
+ |diag| {
+ diag.multipart_suggestion(
+ "remove this call to `default`",
+ removals,
+ Applicability::MachineApplicable,
+ );
+ },
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
index de66ead..b60c11d 100644
--- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs
@@ -42,6 +42,8 @@ macro_rules! declare_with_version {
("clippy::wrong_pub_self_convention", "`clippy::wrong_self_convention` now covers this case via the `avoid-breaking-exported-api` config"),
#[clippy::version = "1.86.0"]
("clippy::option_map_or_err_ok", "`clippy::manual_ok_or` covers this case"),
+ #[clippy::version = "1.86.0"]
+ ("clippy::match_on_vec_items", "`clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`"),
// end deprecated lints. used by `cargo dev deprecate_lint`
]}
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 849c60b..7da5a53 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1133,61 +1133,60 @@ fn report<'tcx>(
impl<'tcx> Dereferencing<'tcx> {
fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &Expr<'tcx>, local: HirId) {
- if let Some(outer_pat) = self.ref_locals.get_mut(&local) {
- if let Some(pat) = outer_pat {
- // Check for auto-deref
- if !matches!(
- cx.typeck_results().expr_adjustments(e),
- [
- Adjustment {
- kind: Adjust::Deref(_),
- ..
- },
- Adjustment {
- kind: Adjust::Deref(_),
- ..
- },
+ if let Some(outer_pat) = self.ref_locals.get_mut(&local)
+ && let Some(pat) = outer_pat
+ // Check for auto-deref
+ && !matches!(
+ cx.typeck_results().expr_adjustments(e),
+ [
+ Adjustment {
+ kind: Adjust::Deref(_),
..
- ]
- ) {
- match get_parent_expr(cx, e) {
- // Field accesses are the same no matter the number of references.
- Some(Expr {
- kind: ExprKind::Field(..),
- ..
- }) => (),
- Some(&Expr {
- span,
- kind: ExprKind::Unary(UnOp::Deref, _),
- ..
- }) if !span.from_expansion() => {
- // Remove explicit deref.
- let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0;
- pat.replacements.push((span, snip.into()));
- },
- Some(parent) if !parent.span.from_expansion() => {
- // Double reference might be needed at this point.
- if parent.precedence() == ExprPrecedence::Unambiguous {
- // Parentheses would be needed here, don't lint.
- *outer_pat = None;
- } else {
- pat.always_deref = false;
- let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0;
- pat.replacements.push((e.span, format!("&{snip}")));
- }
- },
- _ if !e.span.from_expansion() => {
- // Double reference might be needed at this point.
- pat.always_deref = false;
- let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app);
- pat.replacements.push((e.span, format!("&{snip}")));
- },
- // Edge case for macros. The span of the identifier will usually match the context of the
- // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc
- // macros
- _ => *outer_pat = None,
+ },
+ Adjustment {
+ kind: Adjust::Deref(_),
+ ..
+ },
+ ..
+ ]
+ )
+ {
+ match get_parent_expr(cx, e) {
+ // Field accesses are the same no matter the number of references.
+ Some(Expr {
+ kind: ExprKind::Field(..),
+ ..
+ }) => (),
+ Some(&Expr {
+ span,
+ kind: ExprKind::Unary(UnOp::Deref, _),
+ ..
+ }) if !span.from_expansion() => {
+ // Remove explicit deref.
+ let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0;
+ pat.replacements.push((span, snip.into()));
+ },
+ Some(parent) if !parent.span.from_expansion() => {
+ // Double reference might be needed at this point.
+ if parent.precedence() == ExprPrecedence::Unambiguous {
+ // Parentheses would be needed here, don't lint.
+ *outer_pat = None;
+ } else {
+ pat.always_deref = false;
+ let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0;
+ pat.replacements.push((e.span, format!("&{snip}")));
}
- }
+ },
+ _ if !e.span.from_expansion() => {
+ // Double reference might be needed at this point.
+ pat.always_deref = false;
+ let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app);
+ pat.replacements.push((e.span, format!("&{snip}")));
+ },
+ // Edge case for macros. The span of the identifier will usually match the context of the
+ // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc
+ // macros
+ _ => *outer_pat = None,
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index 8d9222e..10331b3 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -94,18 +94,18 @@ fn check_struct<'tcx>(
ty_args: GenericArgsRef<'_>,
typeck_results: &'tcx TypeckResults<'tcx>,
) {
- if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind {
- if let Some(PathSegment { args, .. }) = p.segments.last() {
- let args = args.map(|a| a.args).unwrap_or(&[]);
+ if let TyKind::Path(QPath::Resolved(_, p)) = self_ty.kind
+ && let Some(PathSegment { args, .. }) = p.segments.last()
+ {
+ let args = args.map(|a| a.args).unwrap_or(&[]);
- // ty_args contains the generic parameters of the type declaration, while args contains the
- // arguments used at instantiation time. If both len are not equal, it means that some
- // parameters were not provided (which means that the default values were used); in this
- // case we will not risk suggesting too broad a rewrite. We won't either if any argument
- // is a type or a const.
- if ty_args.len() != args.len() || args.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_))) {
- return;
- }
+ // ty_args contains the generic parameters of the type declaration, while args contains the
+ // arguments used at instantiation time. If both len are not equal, it means that some
+ // parameters were not provided (which means that the default values were used); in this
+ // case we will not risk suggesting too broad a rewrite. We won't either if any argument
+ // is a type or a const.
+ if ty_args.len() != args.len() || args.iter().any(|arg| !matches!(arg, GenericArg::Lifetime(_))) {
+ return;
}
}
@@ -188,7 +188,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
self_ty,
..
}) = item.kind
- && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived)
+ && !cx.tcx.is_automatically_derived(item.owner_id.to_def_id())
&& !item.span.from_expansion()
&& let Some(def_id) = trait_ref.trait_def_id()
&& cx.tcx.is_diagnostic_item(sym::Default, def_id)
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index c85aca8..06528f8 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -206,7 +206,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
}) = item.kind
{
let ty = cx.tcx.type_of(item.owner_id).instantiate_identity();
- let is_automatically_derived = cx.tcx.has_attr(item.owner_id, sym::automatically_derived);
+ let is_automatically_derived = cx.tcx.is_automatically_derived(item.owner_id.to_def_id());
check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
@@ -235,7 +235,7 @@ fn check_hash_peq<'tcx>(
{
// Look for the PartialEq implementations for `ty`
cx.tcx.for_each_relevant_impl(peq_trait_def_id, ty, |impl_id| {
- let peq_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived);
+ let peq_is_automatically_derived = cx.tcx.is_automatically_derived(impl_id);
if !hash_is_automatically_derived || peq_is_automatically_derived {
return;
@@ -278,7 +278,7 @@ fn check_ord_partial_ord<'tcx>(
{
// Look for the PartialOrd implementations for `ty`
cx.tcx.for_each_relevant_impl(partial_ord_trait_def_id, ty, |impl_id| {
- let partial_ord_is_automatically_derived = cx.tcx.has_attr(impl_id, sym::automatically_derived);
+ let partial_ord_is_automatically_derived = cx.tcx.is_automatically_derived(impl_id);
if partial_ord_is_automatically_derived == ord_is_automatically_derived {
return;
@@ -349,6 +349,10 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h
{
return;
}
+ // The presence of `unsafe` fields prevents deriving `Clone` automatically
+ if ty_adt.all_fields().any(|f| f.safety.is_unsafe()) {
+ return;
+ }
span_lint_and_note(
cx,
@@ -426,10 +430,10 @@ fn visit_fn(
}
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) -> Self::Result {
- if let ExprKind::Block(block, _) = expr.kind {
- if block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) {
- return ControlFlow::Break(());
- }
+ if let ExprKind::Block(block, _) = expr.kind
+ && block.rules == BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
+ {
+ return ControlFlow::Break(());
}
walk_expr(self, expr)
@@ -479,7 +483,7 @@ fn ty_implements_eq_trait<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, eq_trait_id: De
tcx.non_blanket_impls_for_ty(eq_trait_id, ty).next().is_some()
}
-/// Creates the `ParamEnv` used for the give type's derived `Eq` impl.
+/// Creates the `ParamEnv` used for the given type's derived `Eq` impl.
fn typing_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> ty::TypingEnv<'_> {
// Initial map from generic index to param def.
// Vec<(param_def, needs_eq)>
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index 4b8a689..fc6af20 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -4,6 +4,7 @@
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::macros::macro_backtrace;
use rustc_data_structures::fx::FxHashSet;
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefIdMap;
use rustc_hir::{
AmbigArg, Expr, ExprKind, ForeignItem, HirId, ImplItem, Item, ItemKind, OwnerId, Pat, Path, Stmt, TraitItem, Ty,
@@ -72,8 +73,15 @@ pub struct DisallowedMacros {
impl DisallowedMacros {
pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf, earlies: AttrStorage) -> Self {
+ let (disallowed, _) = create_disallowed_map(
+ tcx,
+ &conf.disallowed_macros,
+ |def_kind| matches!(def_kind, DefKind::Macro(_)),
+ "macro",
+ false,
+ );
Self {
- disallowed: create_disallowed_map(tcx, &conf.disallowed_macros),
+ disallowed,
seen: FxHashSet::default(),
derive_src: None,
earlies,
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index 149cf1c..1382daf 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -63,9 +63,19 @@ pub struct DisallowedMethods {
impl DisallowedMethods {
pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
- Self {
- disallowed: create_disallowed_map(tcx, &conf.disallowed_methods),
- }
+ let (disallowed, _) = create_disallowed_map(
+ tcx,
+ &conf.disallowed_methods,
+ |def_kind| {
+ matches!(
+ def_kind,
+ DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn
+ )
+ },
+ "function",
+ false,
+ );
+ Self { disallowed }
}
}
@@ -74,12 +84,7 @@ pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
impl<'tcx> LateLintPass<'tcx> for DisallowedMethods {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let (id, span) = match &expr.kind {
- ExprKind::Path(path)
- if let Res::Def(DefKind::Fn | DefKind::Ctor(_, CtorKind::Fn) | DefKind::AssocFn, id) =
- cx.qpath_res(path, expr.hir_id) =>
- {
- (id, expr.span)
- },
+ ExprKind::Path(path) if let Res::Def(_, id) = cx.qpath_res(path, expr.hir_id) => (id, expr.span),
ExprKind::MethodCall(name, ..) if let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) => {
(id, name.ident.span)
},
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
index 3890359..2bae826 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
@@ -1,8 +1,8 @@
use clippy_config::Conf;
-use clippy_config::types::DisallowedPath;
+use clippy_config::types::{DisallowedPath, create_disallowed_map};
use clippy_utils::diagnostics::span_lint_and_then;
use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def::Res;
+use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefIdMap;
use rustc_hir::{AmbigArg, Item, ItemKind, PolyTraitRef, PrimTy, Ty, TyKind, UseKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -60,22 +60,7 @@ pub struct DisallowedTypes {
impl DisallowedTypes {
pub fn new(tcx: TyCtxt<'_>, conf: &'static Conf) -> Self {
- let mut def_ids = DefIdMap::default();
- let mut prim_tys = FxHashMap::default();
- for disallowed_path in &conf.disallowed_types {
- let path: Vec<_> = disallowed_path.path().split("::").collect::<Vec<_>>();
- for res in clippy_utils::def_path_res(tcx, &path) {
- match res {
- Res::Def(_, id) => {
- def_ids.insert(id, (disallowed_path.path(), disallowed_path));
- },
- Res::PrimTy(ty) => {
- prim_tys.insert(ty, (disallowed_path.path(), disallowed_path));
- },
- _ => {},
- }
- }
- }
+ let (def_ids, prim_tys) = create_disallowed_map(tcx, &conf.disallowed_types, def_kind_predicate, "type", true);
Self { def_ids, prim_tys }
}
@@ -95,6 +80,19 @@ fn check_res_emit(&self, cx: &LateContext<'_>, res: &Res, span: Span) {
}
}
+pub fn def_kind_predicate(def_kind: DefKind) -> bool {
+ matches!(
+ def_kind,
+ DefKind::Struct
+ | DefKind::Union
+ | DefKind::Enum
+ | DefKind::Trait
+ | DefKind::TyAlias
+ | DefKind::ForeignTy
+ | DefKind::AssocTy
+ )
+}
+
impl_lint_pass!(DisallowedTypes => [DISALLOWED_TYPES]);
impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
diff --git a/src/tools/clippy/clippy_lints/src/doc/markdown.rs b/src/tools/clippy/clippy_lints/src/doc/markdown.rs
index 8cdaba8..7a1c7c6 100644
--- a/src/tools/clippy/clippy_lints/src/doc/markdown.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/markdown.rs
@@ -113,20 +113,20 @@ fn has_hyphen(s: &str) -> bool {
s != "-" && s.contains('-')
}
- if let Ok(url) = Url::parse(word) {
+ if let Ok(url) = Url::parse(word)
// try to get around the fact that `foo::bar` parses as a valid URL
- if !url.cannot_be_a_base() {
- span_lint_and_sugg(
- cx,
- DOC_MARKDOWN,
- span,
- "you should put bare URLs between `<`/`>` or make a proper Markdown link",
- "try",
- format!("<{word}>"),
- Applicability::MachineApplicable,
- );
- return;
- }
+ && !url.cannot_be_a_base()
+ {
+ span_lint_and_sugg(
+ cx,
+ DOC_MARKDOWN,
+ span,
+ "you should put bare URLs between `<`/`>` or make a proper Markdown link",
+ "try",
+ format!("<{word}>"),
+ Applicability::MachineApplicable,
+ );
+ return;
}
// We assume that mixed-case words are not meant to be put inside backticks. (Issue #2343)
diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
index e75abf2..039937e 100644
--- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
@@ -1,11 +1,14 @@
use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC};
use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
-use clippy_utils::ty::{implements_trait_with_env, is_type_diagnostic_item};
-use clippy_utils::{is_doc_hidden, return_ty};
+use clippy_utils::macros::{is_panic, root_macro_call_first_node};
+use clippy_utils::ty::{get_type_diagnostic_name, implements_trait_with_env, is_type_diagnostic_item};
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{fulfill_or_allowed, is_doc_hidden, method_chain_args, return_ty};
use rustc_hir::{BodyId, FnSig, OwnerId, Safety};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::{Span, sym};
+use std::ops::ControlFlow;
pub fn check(
cx: &LateContext<'_>,
@@ -13,7 +16,6 @@ pub fn check(
sig: FnSig<'_>,
headers: DocHeaders,
body_id: Option<BodyId>,
- panic_info: Option<(Span, bool)>,
check_private_items: bool,
) {
if !check_private_items && !cx.effective_visibilities.is_exported(owner_id.def_id) {
@@ -46,13 +48,16 @@ pub fn check(
),
_ => (),
}
- if !headers.panics && panic_info.is_some_and(|el| !el.1) {
+ if !headers.panics
+ && let Some(body_id) = body_id
+ && let Some(panic_span) = find_panic(cx, body_id)
+ {
span_lint_and_note(
cx,
MISSING_PANICS_DOC,
span,
"docs for function which may panic missing `# Panics` section",
- panic_info.map(|el| el.0),
+ Some(panic_span),
"first possible panic found here",
);
}
@@ -89,3 +94,39 @@ pub fn check(
}
}
}
+
+fn find_panic(cx: &LateContext<'_>, body_id: BodyId) -> Option<Span> {
+ let mut panic_span = None;
+ let typeck = cx.tcx.typeck_body(body_id);
+ for_each_expr(cx, cx.tcx.hir_body(body_id), |expr| {
+ if let Some(macro_call) = root_macro_call_first_node(cx, expr)
+ && (is_panic(cx, macro_call.def_id)
+ || matches!(
+ cx.tcx.get_diagnostic_name(macro_call.def_id),
+ Some(sym::assert_macro | sym::assert_eq_macro | sym::assert_ne_macro)
+ ))
+ && !cx.tcx.hir_is_inside_const_context(expr.hir_id)
+ && !fulfill_or_allowed(cx, MISSING_PANICS_DOC, [expr.hir_id])
+ && panic_span.is_none()
+ {
+ panic_span = Some(macro_call.span);
+ }
+
+ // check for `unwrap` and `expect` for both `Option` and `Result`
+ if let Some(arglists) = method_chain_args(expr, &["unwrap"]).or_else(|| method_chain_args(expr, &["expect"]))
+ && let receiver_ty = typeck.expr_ty(arglists[0].0).peel_refs()
+ && matches!(
+ get_type_diagnostic_name(cx, receiver_ty),
+ Some(sym::Option | sym::Result)
+ )
+ && !fulfill_or_allowed(cx, MISSING_PANICS_DOC, [expr.hir_id])
+ && panic_span.is_none()
+ {
+ panic_span = Some(expr.span);
+ }
+
+ // Visit all nodes to fulfill any `#[expect]`s after the first linted panic
+ ControlFlow::<!>::Continue(())
+ });
+ panic_span
+}
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 36fd396..ab77edf 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -3,11 +3,8 @@
use clippy_config::Conf;
use clippy_utils::attrs::is_doc_hidden;
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_then};
-use clippy_utils::macros::{is_panic, root_macro_call_first_node};
use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::visitors::Visitable;
-use clippy_utils::{is_entrypoint_fn, is_trait_impl_item, method_chain_args};
+use clippy_utils::{is_entrypoint_fn, is_trait_impl_item};
use pulldown_cmark::Event::{
Code, DisplayMath, End, FootnoteReference, HardBreak, Html, InlineHtml, InlineMath, Rule, SoftBreak, Start,
TaskListMarker, Text,
@@ -16,18 +13,15 @@
use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options, TagEnd};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
-use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{AnonConst, Attribute, Expr, ImplItemKind, ItemKind, Node, Safety, TraitItemKind};
+use rustc_hir::{Attribute, ImplItemKind, ItemKind, Node, Safety, TraitItemKind};
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
-use rustc_middle::hir::nested_filter;
-use rustc_middle::ty;
use rustc_resolve::rustdoc::{
DocFragment, add_doc_fragment, attrs_to_doc_fragments, main_body_opts, source_span_for_markdown_range,
span_of_fragments,
};
use rustc_session::impl_lint_pass;
+use rustc_span::Span;
use rustc_span::edition::Edition;
-use rustc_span::{Span, sym};
use std::ops::Range;
use url::Url;
@@ -194,6 +188,19 @@
/// }
/// }
/// ```
+ ///
+ /// Individual panics within a function can be ignored with `#[expect]` or
+ /// `#[allow]`:
+ ///
+ /// ```no_run
+ /// # use std::num::NonZeroUsize;
+ /// pub fn will_not_panic(x: usize) {
+ /// #[expect(clippy::missing_panics_doc, reason = "infallible")]
+ /// let y = NonZeroUsize::new(1).unwrap();
+ ///
+ /// // If any panics are added in the future the lint will still catch them
+ /// }
+ /// ```
#[clippy::version = "1.51.0"]
pub MISSING_PANICS_DOC,
pedantic,
@@ -657,20 +664,16 @@ fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute])
self.check_private_items,
);
match item.kind {
- ItemKind::Fn { sig, body: body_id, .. } => {
+ ItemKind::Fn { sig, body, .. } => {
if !(is_entrypoint_fn(cx, item.owner_id.to_def_id())
|| item.span.in_external_macro(cx.tcx.sess.source_map()))
{
- let body = cx.tcx.hir_body(body_id);
-
- let panic_info = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
missing_headers::check(
cx,
item.owner_id,
sig,
headers,
- Some(body_id),
- panic_info,
+ Some(body),
self.check_private_items,
);
}
@@ -697,15 +700,7 @@ fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute])
if let TraitItemKind::Fn(sig, ..) = trait_item.kind
&& !trait_item.span.in_external_macro(cx.tcx.sess.source_map())
{
- missing_headers::check(
- cx,
- trait_item.owner_id,
- sig,
- headers,
- None,
- None,
- self.check_private_items,
- );
+ missing_headers::check(cx, trait_item.owner_id, sig, headers, None, self.check_private_items);
}
},
Node::ImplItem(impl_item) => {
@@ -713,16 +708,12 @@ fn check_attributes(&mut self, cx: &LateContext<'tcx>, attrs: &'tcx [Attribute])
&& !impl_item.span.in_external_macro(cx.tcx.sess.source_map())
&& !is_trait_impl_item(cx, impl_item.hir_id())
{
- let body = cx.tcx.hir_body(body_id);
-
- let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(impl_item.owner_id), body.value);
missing_headers::check(
cx,
impl_item.owner_id,
sig,
headers,
Some(body_id),
- panic_span,
self.check_private_items,
);
}
@@ -880,19 +871,18 @@ fn check_for_code_clusters<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a
if let Some(start) = code_starts_at
&& let Some(end) = code_ends_at
&& code_includes_link
+ && let Some(span) = fragments.span(cx, start..end)
{
- if let Some(span) = fragments.span(cx, start..end) {
- span_lint_and_then(cx, DOC_LINK_CODE, span, "code link adjacent to code text", |diag| {
- let sugg = format!("<code>{}</code>", doc[start..end].replace('`', ""));
- diag.span_suggestion_verbose(
- span,
- "wrap the entire group in `<code>` tags",
- sugg,
- Applicability::MaybeIncorrect,
- );
- diag.help("separate code snippets will be shown with a gap");
- });
- }
+ span_lint_and_then(cx, DOC_LINK_CODE, span, "code link adjacent to code text", |diag| {
+ let sugg = format!("<code>{}</code>", doc[start..end].replace('`', ""));
+ diag.span_suggestion_verbose(
+ span,
+ "wrap the entire group in `<code>` tags",
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+ diag.help("separate code snippets will be shown with a gap");
+ });
}
code_includes_link = false;
code_starts_at = None;
@@ -1169,72 +1159,6 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
headers
}
-struct FindPanicUnwrap<'a, 'tcx> {
- cx: &'a LateContext<'tcx>,
- is_const: bool,
- panic_span: Option<Span>,
- typeck_results: &'tcx ty::TypeckResults<'tcx>,
-}
-
-impl<'a, 'tcx> FindPanicUnwrap<'a, 'tcx> {
- pub fn find_span(
- cx: &'a LateContext<'tcx>,
- typeck_results: &'tcx ty::TypeckResults<'tcx>,
- body: impl Visitable<'tcx>,
- ) -> Option<(Span, bool)> {
- let mut vis = Self {
- cx,
- is_const: false,
- panic_span: None,
- typeck_results,
- };
- body.visit(&mut vis);
- vis.panic_span.map(|el| (el, vis.is_const))
- }
-}
-
-impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> {
- type NestedFilter = nested_filter::OnlyBodies;
-
- fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
- if self.panic_span.is_some() {
- return;
- }
-
- if let Some(macro_call) = root_macro_call_first_node(self.cx, expr) {
- if is_panic(self.cx, macro_call.def_id)
- || matches!(
- self.cx.tcx.item_name(macro_call.def_id).as_str(),
- "assert" | "assert_eq" | "assert_ne"
- )
- {
- self.is_const = self.cx.tcx.hir_is_inside_const_context(expr.hir_id);
- self.panic_span = Some(macro_call.span);
- }
- }
-
- // check for `unwrap` and `expect` for both `Option` and `Result`
- if let Some(arglists) = method_chain_args(expr, &["unwrap"]).or(method_chain_args(expr, &["expect"])) {
- let receiver_ty = self.typeck_results.expr_ty(arglists[0].0).peel_refs();
- if is_type_diagnostic_item(self.cx, receiver_ty, sym::Option)
- || is_type_diagnostic_item(self.cx, receiver_ty, sym::Result)
- {
- self.panic_span = Some(expr.span);
- }
- }
-
- // and check sub-expressions
- intravisit::walk_expr(self, expr);
- }
-
- // Panics in const blocks will cause compilation to fail.
- fn visit_anon_const(&mut self, _: &'tcx AnonConst) {}
-
- fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
- self.cx.tcx
- }
-}
-
#[expect(clippy::range_plus_one)] // inclusive ranges aren't the same type
fn looks_like_refdef(doc: &str, range: Range<usize>) -> Option<Range<usize>> {
if range.end < range.start {
diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
index bf549dc..ec45380 100644
--- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
@@ -64,7 +64,10 @@ fn check_code_sample(code: String, edition: Edition, ignore: bool) -> (bool, Vec
match parser.parse_item(ForceCollect::No) {
Ok(Some(item)) => match &item.kind {
ItemKind::Fn(box Fn {
- ident, sig, body: Some(block), ..
+ ident,
+ sig,
+ body: Some(block),
+ ..
}) if ident.name == sym::main => {
if !ignore {
get_test_spans(&item, *ident, &mut test_attr_spans);
diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
index 617982f..5c360ce 100644
--- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
@@ -144,10 +144,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// ..
// }
fn is_single_call_in_arm<'tcx>(cx: &LateContext<'tcx>, arg: &'tcx Expr<'_>, drop_expr: &'tcx Expr<'_>) -> bool {
- if matches!(arg.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)) {
- if let Node::Arm(Arm { body, .. }) = cx.tcx.parent_hir_node(drop_expr.hir_id) {
- return body.hir_id == drop_expr.hir_id;
- }
+ if matches!(arg.kind, ExprKind::Call(..) | ExprKind::MethodCall(..))
+ && let Node::Arm(Arm { body, .. }) = cx.tcx.parent_hir_node(drop_expr.hir_id)
+ {
+ return body.hir_id == drop_expr.hir_id;
}
false
}
diff --git a/src/tools/clippy/clippy_lints/src/empty_line_after.rs b/src/tools/clippy/clippy_lints/src/empty_line_after.rs
index c67dcd3..0c5f8bb 100644
--- a/src/tools/clippy/clippy_lints/src/empty_line_after.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_line_after.rs
@@ -1,3 +1,5 @@
+use std::borrow::Cow;
+
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::{SpanRangeExt, snippet_indent};
use clippy_utils::tokenize_with_text;
@@ -89,7 +91,7 @@
#[derive(Debug)]
struct ItemInfo {
kind: &'static str,
- name: Symbol,
+ name: Option<Symbol>,
span: Span,
mod_items: Option<NodeId>,
}
@@ -315,8 +317,12 @@ fn check_gaps(&self, cx: &EarlyContext<'_>, gaps: &[Gap<'_>], id: NodeId) {
for stop in gaps.iter().flat_map(|gap| gap.prev_chunk) {
stop.comment_out(cx, &mut suggestions);
}
+ let name = match info.name {
+ Some(name) => format!("{} `{name}`", info.kind).into(),
+ None => Cow::from("the following item"),
+ };
diag.multipart_suggestion_verbose(
- format!("if the doc comment should not document `{}` comment it out", info.name),
+ format!("if the doc comment should not document {name} then comment it out"),
suggestions,
Applicability::MaybeIncorrect,
);
@@ -381,13 +387,10 @@ fn check_item_kind(
) {
self.items.push(ItemInfo {
kind: kind.descr(),
- // FIXME: this `sym::empty` can be leaked, see
- // https://github.com/rust-lang/rust/pull/138740#discussion_r2021979899
- name: if let Some(ident) = ident { ident.name } else { kw::Empty },
- span: if let Some(ident) = ident {
- span.with_hi(ident.span.hi())
- } else {
- span.with_hi(span.lo())
+ name: ident.map(|ident| ident.name),
+ span: match ident {
+ Some(ident) => span.with_hi(ident.span.hi()),
+ None => span.shrink_to_lo(),
},
mod_items: match kind {
ItemKind::Mod(_, _, ModKind::Loaded(items, _, _, _)) => items
@@ -447,7 +450,7 @@ impl EarlyLintPass for EmptyLineAfter {
fn check_crate(&mut self, _: &EarlyContext<'_>, krate: &Crate) {
self.items.push(ItemInfo {
kind: "crate",
- name: kw::Crate,
+ name: Some(kw::Crate),
span: krate.spans.inner_span.with_hi(krate.spans.inner_span.lo()),
mod_items: krate
.items
diff --git a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
index 7d87f04..a38d6df 100644
--- a/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_with_brackets.rs
@@ -1,10 +1,15 @@
-use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::snippet_opt;
-use rustc_ast::ast::{Item, ItemKind, Variant, VariantData};
+use clippy_utils::attrs::span_contains_cfg;
+use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
+use rustc_data_structures::fx::FxIndexMap;
use rustc_errors::Applicability;
-use rustc_lexer::TokenKind;
-use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::declare_lint_pass;
+use rustc_hir::def::CtorOf;
+use rustc_hir::def::DefKind::Ctor;
+use rustc_hir::def::Res::Def;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node, Path, QPath, Variant, VariantData};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::TyCtxt;
+use rustc_session::impl_lint_pass;
use rustc_span::Span;
declare_clippy_lint! {
@@ -70,10 +75,23 @@
"finds enum variants with empty brackets"
}
-declare_lint_pass!(EmptyWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS, EMPTY_ENUM_VARIANTS_WITH_BRACKETS]);
+#[derive(Debug)]
+enum Usage {
+ Unused { redundant_use_sites: Vec<Span> },
+ Used,
+ NoDefinition { redundant_use_sites: Vec<Span> },
+}
-impl EarlyLintPass for EmptyWithBrackets {
- fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
+#[derive(Default)]
+pub struct EmptyWithBrackets {
+ // Value holds `Usage::Used` if the empty tuple variant was used as a function
+ empty_tuple_enum_variants: FxIndexMap<LocalDefId, Usage>,
+}
+
+impl_lint_pass!(EmptyWithBrackets => [EMPTY_STRUCTS_WITH_BRACKETS, EMPTY_ENUM_VARIANTS_WITH_BRACKETS]);
+
+impl LateLintPass<'_> for EmptyWithBrackets {
+ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
if let ItemKind::Struct(ident, var_data, _) = &item.kind
&& has_brackets(var_data)
&& let span_after_ident = item.span.with_lo(ident.span.hi())
@@ -96,70 +114,175 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
}
}
- fn check_variant(&mut self, cx: &EarlyContext<'_>, variant: &Variant) {
+ fn check_variant(&mut self, cx: &LateContext<'_>, variant: &Variant<'_>) {
+ // the span of the parentheses/braces
let span_after_ident = variant.span.with_lo(variant.ident.span.hi());
- if has_brackets(&variant.data) && has_no_fields(cx, &variant.data, span_after_ident) {
- span_lint_and_then(
+ if has_no_fields(cx, &variant.data, span_after_ident) {
+ match variant.data {
+ VariantData::Struct { .. } => {
+ // Empty struct variants can be linted immediately
+ span_lint_and_then(
+ cx,
+ EMPTY_ENUM_VARIANTS_WITH_BRACKETS,
+ span_after_ident,
+ "enum variant has empty brackets",
+ |diagnostic| {
+ diagnostic.span_suggestion_hidden(
+ span_after_ident,
+ "remove the brackets",
+ "",
+ Applicability::MaybeIncorrect,
+ );
+ },
+ );
+ },
+ VariantData::Tuple(.., local_def_id) => {
+ // Don't lint reachable tuple enums
+ if cx.effective_visibilities.is_reachable(variant.def_id) {
+ return;
+ }
+ if let Some(entry) = self.empty_tuple_enum_variants.get_mut(&local_def_id) {
+ // empty_tuple_enum_variants contains Usage::NoDefinition if the variant was called before the
+ // definition was encountered. Now that there's a definition, convert it
+ // to Usage::Unused.
+ if let Usage::NoDefinition { redundant_use_sites } = entry {
+ *entry = Usage::Unused {
+ redundant_use_sites: redundant_use_sites.clone(),
+ };
+ }
+ } else {
+ self.empty_tuple_enum_variants.insert(
+ local_def_id,
+ Usage::Unused {
+ redundant_use_sites: vec![],
+ },
+ );
+ }
+ },
+ VariantData::Unit(..) => {},
+ }
+ }
+ }
+
+ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if let Some(def_id) = check_expr_for_enum_as_function(expr) {
+ if let Some(parentheses_span) = call_parentheses_span(cx.tcx, expr) {
+ // Do not count expressions from macro expansion as a redundant use site.
+ if expr.span.from_expansion() {
+ return;
+ }
+ match self.empty_tuple_enum_variants.get_mut(&def_id) {
+ Some(
+ &mut (Usage::Unused {
+ ref mut redundant_use_sites,
+ }
+ | Usage::NoDefinition {
+ ref mut redundant_use_sites,
+ }),
+ ) => {
+ redundant_use_sites.push(parentheses_span);
+ },
+ None => {
+ // The variant isn't in the IndexMap which means its definition wasn't encountered yet.
+ self.empty_tuple_enum_variants.insert(
+ def_id,
+ Usage::NoDefinition {
+ redundant_use_sites: vec![parentheses_span],
+ },
+ );
+ },
+ _ => {},
+ }
+ } else {
+ // The parentheses are not redundant.
+ self.empty_tuple_enum_variants.insert(def_id, Usage::Used);
+ }
+ }
+ }
+
+ fn check_crate_post(&mut self, cx: &LateContext<'_>) {
+ for (local_def_id, usage) in &self.empty_tuple_enum_variants {
+ // Ignore all variants with Usage::Used or Usage::NoDefinition
+ let Usage::Unused { redundant_use_sites } = usage else {
+ continue;
+ };
+ // Attempt to fetch the Variant from LocalDefId.
+ let Node::Variant(variant) = cx.tcx.hir_node(
+ cx.tcx
+ .local_def_id_to_hir_id(cx.tcx.parent(local_def_id.to_def_id()).expect_local()),
+ ) else {
+ continue;
+ };
+ // Span of the parentheses in variant definition
+ let span = variant.span.with_lo(variant.ident.span.hi());
+ span_lint_hir_and_then(
cx,
EMPTY_ENUM_VARIANTS_WITH_BRACKETS,
- span_after_ident,
+ variant.hir_id,
+ span,
"enum variant has empty brackets",
|diagnostic| {
- diagnostic.span_suggestion_hidden(
- span_after_ident,
- "remove the brackets",
- "",
- Applicability::MaybeIncorrect,
- );
+ if redundant_use_sites.is_empty() {
+ // If there's no redundant use sites, the definition is the only place to modify.
+ diagnostic.span_suggestion_hidden(
+ span,
+ "remove the brackets",
+ "",
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ let mut parentheses_spans: Vec<_> =
+ redundant_use_sites.iter().map(|span| (*span, String::new())).collect();
+ parentheses_spans.push((span, String::new()));
+ diagnostic.multipart_suggestion(
+ "remove the brackets",
+ parentheses_spans,
+ Applicability::MaybeIncorrect,
+ );
+ }
},
);
}
}
}
-fn has_no_ident_token(braces_span_str: &str) -> bool {
- !rustc_lexer::tokenize(braces_span_str).any(|t| t.kind == TokenKind::Ident)
+fn has_brackets(var_data: &VariantData<'_>) -> bool {
+ !matches!(var_data, VariantData::Unit(..))
}
-fn has_brackets(var_data: &VariantData) -> bool {
- !matches!(var_data, VariantData::Unit(_))
-}
-
-fn has_no_fields(cx: &EarlyContext<'_>, var_data: &VariantData, braces_span: Span) -> bool {
- if !var_data.fields().is_empty() {
- return false;
- }
-
+fn has_no_fields(cx: &LateContext<'_>, var_data: &VariantData<'_>, braces_span: Span) -> bool {
+ var_data.fields().is_empty() &&
// there might still be field declarations hidden from the AST
// (conditionally compiled code using #[cfg(..)])
-
- let Some(braces_span_str) = snippet_opt(cx, braces_span) else {
- return false;
- };
-
- has_no_ident_token(braces_span_str.as_ref())
+ !span_contains_cfg(cx, braces_span)
}
-#[cfg(test)]
-mod unit_test {
- use super::*;
+// If expression HIR ID and callee HIR ID are same, returns the span of the parentheses, else,
+// returns None.
+fn call_parentheses_span(tcx: TyCtxt<'_>, expr: &Expr<'_>) -> Option<Span> {
+ if let Node::Expr(parent) = tcx.parent_hir_node(expr.hir_id)
+ && let ExprKind::Call(callee, ..) = parent.kind
+ && callee.hir_id == expr.hir_id
+ {
+ Some(parent.span.with_lo(expr.span.hi()))
+ } else {
+ None
+ }
+}
- #[test]
- fn test_has_no_ident_token() {
- let input = "{ field: u8 }";
- assert!(!has_no_ident_token(input));
-
- let input = "(u8, String);";
- assert!(!has_no_ident_token(input));
-
- let input = " {
- // test = 5
- }
- ";
- assert!(has_no_ident_token(input));
-
- let input = " ();";
- assert!(has_no_ident_token(input));
+// Returns the LocalDefId of the variant being called as a function if it exists.
+fn check_expr_for_enum_as_function(expr: &Expr<'_>) -> Option<LocalDefId> {
+ if let ExprKind::Path(QPath::Resolved(
+ _,
+ Path {
+ res: Def(Ctor(CtorOf::Variant, _), def_id),
+ ..
+ },
+ )) = expr.kind
+ {
+ def_id.as_local()
+ } else {
+ None
}
}
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index dcfee0b..182cb4e 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -95,14 +95,13 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
return;
};
- if then_search.is_key_used_and_no_copy || else_search.is_key_used_and_no_copy {
- span_lint(cx, MAP_ENTRY, expr.span, lint_msg);
- return;
- }
-
if then_search.edits.is_empty() && else_search.edits.is_empty() {
// No insertions
return;
+ } else if then_search.is_key_used_and_no_copy || else_search.is_key_used_and_no_copy {
+ // If there are other uses of the key, and the key is not copy,
+ // we cannot perform a fix automatically, but continue to emit a lint.
+ None
} else if then_search.edits.is_empty() || else_search.edits.is_empty() {
// if .. { insert } else { .. } or if .. { .. } else { insert }
let ((then_str, entry_kind), else_str) = match (else_search.edits.is_empty(), contains_expr.negated) {
@@ -123,10 +122,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
snippet_with_applicability(cx, then_expr.span, "{ .. }", &mut app),
),
};
- format!(
+ Some(format!(
"if let {}::{entry_kind} = {map_str}.entry({key_str}) {then_str} else {else_str}",
map_ty.entry_path(),
- )
+ ))
} else {
// if .. { insert } else { insert }
let ((then_str, then_entry), (else_str, else_entry)) = if contains_expr.negated {
@@ -142,13 +141,13 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
};
let indent_str = snippet_indent(cx, expr.span);
let indent_str = indent_str.as_deref().unwrap_or("");
- format!(
+ Some(format!(
"match {map_str}.entry({key_str}) {{\n{indent_str} {entry}::{then_entry} => {}\n\
{indent_str} {entry}::{else_entry} => {}\n{indent_str}}}",
reindent_multiline(&then_str, true, Some(4 + indent_str.len())),
reindent_multiline(&else_str, true, Some(4 + indent_str.len())),
entry = map_ty.entry_path(),
- )
+ ))
}
} else {
if then_search.edits.is_empty() {
@@ -163,17 +162,17 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
} else {
then_search.snippet_occupied(cx, then_expr.span, &mut app)
};
- format!(
+ Some(format!(
"if let {}::{entry_kind} = {map_str}.entry({key_str}) {body_str}",
map_ty.entry_path(),
- )
+ ))
} else if let Some(insertion) = then_search.as_single_insertion() {
let value_str = snippet_with_context(cx, insertion.value.span, then_expr.span.ctxt(), "..", &mut app).0;
if contains_expr.negated {
if insertion.value.can_have_side_effects() {
- format!("{map_str}.entry({key_str}).or_insert_with(|| {value_str});")
+ Some(format!("{map_str}.entry({key_str}).or_insert_with(|| {value_str});"))
} else {
- format!("{map_str}.entry({key_str}).or_insert({value_str});")
+ Some(format!("{map_str}.entry({key_str}).or_insert({value_str});"))
}
} else {
// TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here.
@@ -183,7 +182,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
} else {
let block_str = then_search.snippet_closure(cx, then_expr.span, &mut app);
if contains_expr.negated {
- format!("{map_str}.entry({key_str}).or_insert_with(|| {block_str});")
+ Some(format!("{map_str}.entry({key_str}).or_insert_with(|| {block_str});"))
} else {
// TODO: suggest using `if let Some(v) = map.get_mut(k) { .. }` here.
// This would need to be a different lint.
@@ -192,7 +191,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
}
};
- span_lint_and_sugg(cx, MAP_ENTRY, expr.span, lint_msg, "try", sugg, app);
+ if let Some(sugg) = sugg {
+ span_lint_and_sugg(cx, MAP_ENTRY, expr.span, lint_msg, "try", sugg, app);
+ } else {
+ span_lint(cx, MAP_ENTRY, expr.span, lint_msg);
+ }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index f01b5c8..ec81294 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -49,10 +49,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
.ok()
.map(|val| rustc_middle::mir::Const::from_value(val, ty));
if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx.tcx, c)) {
- if let ty::Adt(adt, _) = ty.kind() {
- if adt.is_enum() {
- ty = adt.repr().discr_type().to_ty(cx.tcx);
- }
+ if let ty::Adt(adt, _) = ty.kind()
+ && adt.is_enum()
+ {
+ ty = adt.repr().discr_type().to_ty(cx.tcx);
}
match ty.kind() {
ty::Int(IntTy::Isize) => {
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index e248f08..2cb3b32 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -72,10 +72,10 @@ fn check_fn(
_: Span,
fn_def_id: LocalDefId,
) {
- if let Some(header) = fn_kind.header() {
- if header.abi != ExternAbi::Rust {
- return;
- }
+ if let Some(header) = fn_kind.header()
+ && header.abi != ExternAbi::Rust
+ {
+ return;
}
let parent_id = cx
@@ -93,12 +93,11 @@ fn check_fn(
// find `self` ty for this trait if relevant
if let ItemKind::Trait(_, _, _, _, _, items) = item.kind {
for trait_item in items {
- if trait_item.id.owner_id.def_id == fn_def_id {
+ if trait_item.id.owner_id.def_id == fn_def_id
// be sure we have `self` parameter in this function
- if trait_item.kind == (AssocItemKind::Fn { has_self: true }) {
- trait_self_ty =
- Some(TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id()).self_ty());
- }
+ && trait_item.kind == (AssocItemKind::Fn { has_self: true })
+ {
+ trait_self_ty = Some(TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id()).self_ty());
}
}
}
@@ -142,22 +141,22 @@ fn is_argument(tcx: TyCtxt<'_>, id: HirId) -> bool {
impl<'tcx> Delegate<'tcx> for EscapeDelegate<'_, 'tcx> {
fn consume(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
- if cmt.place.projections.is_empty() {
- if let PlaceBase::Local(lid) = cmt.place.base {
- // FIXME(rust/#120456) - is `swap_remove` correct?
- self.set.swap_remove(&lid);
- }
+ if cmt.place.projections.is_empty()
+ && let PlaceBase::Local(lid) = cmt.place.base
+ {
+ // FIXME(rust/#120456) - is `swap_remove` correct?
+ self.set.swap_remove(&lid);
}
}
fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {
- if cmt.place.projections.is_empty() {
- if let PlaceBase::Local(lid) = cmt.place.base {
- // FIXME(rust/#120456) - is `swap_remove` correct?
- self.set.swap_remove(&lid);
- }
+ if cmt.place.projections.is_empty()
+ && let PlaceBase::Local(lid) = cmt.place.base
+ {
+ // FIXME(rust/#120456) - is `swap_remove` correct?
+ self.set.swap_remove(&lid);
}
}
@@ -171,10 +170,11 @@ fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) {
// skip if there is a `self` parameter binding to a type
// that contains `Self` (i.e.: `self: Box<Self>`), see #4804
- if let Some(trait_self_ty) = self.trait_self_ty {
- if self.cx.tcx.hir_name(cmt.hir_id) == kw::SelfLower && cmt.place.ty().contains(trait_self_ty) {
- return;
- }
+ if let Some(trait_self_ty) = self.trait_self_ty
+ && self.cx.tcx.hir_name(cmt.hir_id) == kw::SelfLower
+ && cmt.place.ty().contains(trait_self_ty)
+ {
+ return;
}
if is_non_trait_box(cmt.place.ty()) && !self.is_large_box(cmt.place.ty()) {
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index f67d38d..c868b78 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -75,10 +75,10 @@ struct FindPanicUnwrap<'a, 'tcx> {
impl<'tcx> Visitor<'tcx> for FindPanicUnwrap<'_, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
- if let Some(macro_call) = root_macro_call_first_node(self.lcx, expr) {
- if is_panic(self.lcx, macro_call.def_id) {
- self.result.push(expr.span);
- }
+ if let Some(macro_call) = root_macro_call_first_node(self.lcx, expr)
+ && is_panic(self.lcx, macro_call.def_id)
+ {
+ self.result.push(expr.span);
}
// check for `unwrap`
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index daa1997..d5f0659 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -154,7 +154,7 @@ fn prepare_receiver_sugg<'a>(cx: &LateContext<'_>, mut expr: &'a Expr<'a>) -> Su
};
}
- suggestion.maybe_par()
+ suggestion.maybe_paren()
}
fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
@@ -165,7 +165,7 @@ fn check_log_base(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, ar
expr.span,
"logarithm for bases 2, 10 and e can be computed more accurately",
"consider using",
- format!("{}.{method}()", Sugg::hir(cx, receiver, "..").maybe_par()),
+ format!("{}.{method}()", Sugg::hir(cx, receiver, "..").maybe_paren()),
Applicability::MachineApplicable,
);
}
@@ -228,24 +228,24 @@ fn get_integer_from_float_constant(value: &Constant<'_>) -> Option<i32> {
fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
// Check receiver
- if let Some(value) = ConstEvalCtxt::new(cx).eval(receiver) {
- if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
+ if let Some(value) = ConstEvalCtxt::new(cx).eval(receiver)
+ && let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value {
Some("exp")
} else if F32(2.0) == value || F64(2.0) == value {
Some("exp2")
} else {
None
- } {
- span_lint_and_sugg(
- cx,
- SUBOPTIMAL_FLOPS,
- expr.span,
- "exponent for bases 2 and e can be computed more accurately",
- "consider using",
- format!("{}.{method}()", prepare_receiver_sugg(cx, &args[0])),
- Applicability::MachineApplicable,
- );
}
+ {
+ span_lint_and_sugg(
+ cx,
+ SUBOPTIMAL_FLOPS,
+ expr.span,
+ "exponent for bases 2 and e can be computed more accurately",
+ "consider using",
+ format!("{}.{method}()", prepare_receiver_sugg(cx, &args[0])),
+ Applicability::MachineApplicable,
+ );
}
// Check argument
@@ -254,13 +254,13 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
(
SUBOPTIMAL_FLOPS,
"square-root of a number can be computed more efficiently and accurately",
- format!("{}.sqrt()", Sugg::hir(cx, receiver, "..").maybe_par()),
+ format!("{}.sqrt()", Sugg::hir(cx, receiver, "..").maybe_paren()),
)
} else if F32(1.0 / 3.0) == value || F64(1.0 / 3.0) == value {
(
IMPRECISE_FLOPS,
"cube-root of a number can be computed more accurately",
- format!("{}.cbrt()", Sugg::hir(cx, receiver, "..").maybe_par()),
+ format!("{}.cbrt()", Sugg::hir(cx, receiver, "..").maybe_paren()),
)
} else if let Some(exponent) = get_integer_from_float_constant(&value) {
(
@@ -268,7 +268,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
"exponentiation with integer powers can be computed more efficiently",
format!(
"{}.powi({})",
- Sugg::hir(cx, receiver, "..").maybe_par(),
+ Sugg::hir(cx, receiver, "..").maybe_paren(),
numeric_literal::format(&exponent.to_string(), None, false)
),
)
@@ -289,55 +289,53 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
}
fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) {
- if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0]) {
- if value == Int(2) {
- if let Some(parent) = get_parent_expr(cx, expr) {
- if let Some(grandparent) = get_parent_expr(cx, parent) {
- if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind
- {
- if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() {
- return;
- }
- }
+ if let Some(value) = ConstEvalCtxt::new(cx).eval(&args[0])
+ && value == Int(2)
+ && let Some(parent) = get_parent_expr(cx, expr)
+ {
+ if let Some(grandparent) = get_parent_expr(cx, parent)
+ && let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = grandparent.kind
+ && method_name.as_str() == "sqrt"
+ && detect_hypot(cx, receiver).is_some()
+ {
+ return;
+ }
+
+ if let ExprKind::Binary(
+ Spanned {
+ node: op @ (BinOpKind::Add | BinOpKind::Sub),
+ ..
+ },
+ lhs,
+ rhs,
+ ) = parent.kind
+ {
+ let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs };
+
+ // Negate expr if original code has subtraction and expr is on the right side
+ let maybe_neg_sugg = |expr, hir_id| {
+ let sugg = Sugg::hir(cx, expr, "..");
+ if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id {
+ -sugg
+ } else {
+ sugg
}
+ };
- if let ExprKind::Binary(
- Spanned {
- node: op @ (BinOpKind::Add | BinOpKind::Sub),
- ..
- },
- lhs,
- rhs,
- ) = parent.kind
- {
- let other_addend = if lhs.hir_id == expr.hir_id { rhs } else { lhs };
-
- // Negate expr if original code has subtraction and expr is on the right side
- let maybe_neg_sugg = |expr, hir_id| {
- let sugg = Sugg::hir(cx, expr, "..");
- if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id {
- -sugg
- } else {
- sugg
- }
- };
-
- span_lint_and_sugg(
- cx,
- SUBOPTIMAL_FLOPS,
- parent.span,
- "multiply and add expressions can be calculated more efficiently and accurately",
- "consider using",
- format!(
- "{}.mul_add({}, {})",
- Sugg::hir(cx, receiver, "..").maybe_par(),
- maybe_neg_sugg(receiver, expr.hir_id),
- maybe_neg_sugg(other_addend, other_addend.hir_id),
- ),
- Applicability::MachineApplicable,
- );
- }
- }
+ span_lint_and_sugg(
+ cx,
+ SUBOPTIMAL_FLOPS,
+ parent.span,
+ "multiply and add expressions can be calculated more efficiently and accurately",
+ "consider using",
+ format!(
+ "{}.mul_add({}, {})",
+ Sugg::hir(cx, receiver, "..").maybe_paren(),
+ maybe_neg_sugg(receiver, expr.hir_id),
+ maybe_neg_sugg(other_addend, other_addend.hir_id),
+ ),
+ Applicability::MachineApplicable,
+ );
}
}
}
@@ -371,7 +369,7 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
{
return Some(format!(
"{}.hypot({})",
- Sugg::hir(cx, lmul_lhs, "..").maybe_par(),
+ Sugg::hir(cx, lmul_lhs, "..").maybe_paren(),
Sugg::hir(cx, rmul_lhs, "..")
));
}
@@ -403,7 +401,7 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> {
{
return Some(format!(
"{}.hypot({})",
- Sugg::hir(cx, largs_0, "..").maybe_par(),
+ Sugg::hir(cx, largs_0, "..").maybe_paren(),
Sugg::hir(cx, rargs_0, "..")
));
}
@@ -449,7 +447,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) {
expr.span,
"(e.pow(x) - 1) can be computed more accurately",
"consider using",
- format!("{}.exp_m1()", Sugg::hir(cx, self_arg, "..").maybe_par()),
+ format!("{}.exp_m1()", Sugg::hir(cx, self_arg, "..").maybe_paren()),
Applicability::MachineApplicable,
);
}
@@ -483,12 +481,12 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
rhs,
) = &expr.kind
{
- if let Some(parent) = get_parent_expr(cx, expr) {
- if let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind {
- if method_name.as_str() == "sqrt" && detect_hypot(cx, receiver).is_some() {
- return;
- }
- }
+ if let Some(parent) = get_parent_expr(cx, expr)
+ && let ExprKind::MethodCall(PathSegment { ident: method_name, .. }, receiver, ..) = parent.kind
+ && method_name.as_str() == "sqrt"
+ && detect_hypot(cx, receiver).is_some()
+ {
+ return;
}
let maybe_neg_sugg = |expr| {
@@ -566,15 +564,15 @@ fn is_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
/// If the two expressions are not negations of each other, then it
/// returns None.
fn are_negated<'a>(cx: &LateContext<'_>, expr1: &'a Expr<'a>, expr2: &'a Expr<'a>) -> Option<(bool, &'a Expr<'a>)> {
- if let ExprKind::Unary(UnOp::Neg, expr1_negated) = &expr1.kind {
- if eq_expr_value(cx, expr1_negated, expr2) {
- return Some((false, expr2));
- }
+ if let ExprKind::Unary(UnOp::Neg, expr1_negated) = &expr1.kind
+ && eq_expr_value(cx, expr1_negated, expr2)
+ {
+ return Some((false, expr2));
}
- if let ExprKind::Unary(UnOp::Neg, expr2_negated) = &expr2.kind {
- if eq_expr_value(cx, expr1, expr2_negated) {
- return Some((true, expr1));
- }
+ if let ExprKind::Unary(UnOp::Neg, expr2_negated) = &expr2.kind
+ && eq_expr_value(cx, expr1, expr2_negated)
+ {
+ return Some((true, expr1));
}
None
}
@@ -591,11 +589,11 @@ fn check_custom_abs(cx: &LateContext<'_>, expr: &Expr<'_>) {
{
let positive_abs_sugg = (
"manual implementation of `abs` method",
- format!("{}.abs()", Sugg::hir(cx, body, "..").maybe_par()),
+ format!("{}.abs()", Sugg::hir(cx, body, "..").maybe_paren()),
);
let negative_abs_sugg = (
"manual implementation of negation of `abs` method",
- format!("-{}.abs()", Sugg::hir(cx, body, "..").maybe_par()),
+ format!("-{}.abs()", Sugg::hir(cx, body, "..").maybe_paren()),
);
let sugg = if is_testing_positive(cx, cond, body) {
if if_expr_positive {
@@ -672,7 +670,7 @@ fn check_log_division(cx: &LateContext<'_>, expr: &Expr<'_>) {
"consider using",
format!(
"{}.log({})",
- Sugg::hir(cx, largs_self, "..").maybe_par(),
+ Sugg::hir(cx, largs_self, "..").maybe_paren(),
Sugg::hir(cx, rargs_self, ".."),
),
Applicability::MachineApplicable,
@@ -703,7 +701,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue)
&& (F32(180_f32) == lvalue || F64(180_f64) == lvalue)
{
- let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
+ let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_paren());
if let ExprKind::Lit(literal) = mul_lhs.kind
&& let ast::LitKind::Float(ref value, float_type) = literal.node
&& float_type == ast::LitFloatType::Unsuffixed
@@ -726,7 +724,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) {
} else if (F32(180_f32) == rvalue || F64(180_f64) == rvalue)
&& (F32(f32_consts::PI) == lvalue || F64(f64_consts::PI) == lvalue)
{
- let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par());
+ let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_paren());
if let ExprKind::Lit(literal) = mul_lhs.kind
&& let ast::LitKind::Float(ref value, float_type) = literal.node
&& float_type == ast::LitFloatType::Unsuffixed
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs
index 5e3f6b6..94e6676 100644
--- a/src/tools/clippy/clippy_lints/src/format.rs
+++ b/src/tools/clippy/clippy_lints/src/format.rs
@@ -94,7 +94,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
.into_owned()
} else {
let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "<arg>", &mut applicability);
- format!("{}.to_string()", sugg.maybe_par())
+ format!("{}.to_string()", sugg.maybe_paren())
};
span_useless_format(cx, call_site, sugg, applicability);
}
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 3862ff7..8a3f8e1 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -141,7 +141,7 @@
/// format!("{var:.prec$}");
/// ```
///
- /// If allow-mixed-uninlined-format-args is set to false in clippy.toml,
+ /// If `allow-mixed-uninlined-format-args` is set to `false` in clippy.toml,
/// the following code will also trigger the lint:
/// ```no_run
/// # let var = 42;
@@ -159,7 +159,7 @@
/// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`.
#[clippy::version = "1.66.0"]
pub UNINLINED_FORMAT_ARGS,
- pedantic,
+ style,
"using non-inlined variables in `format!` calls"
}
@@ -550,7 +550,7 @@ fn can_display_format(&self, ty: Ty<'tcx>) -> bool {
// a `Target` that is in `self.ty_msrv_map`.
if let Some(deref_trait_id) = self.cx.tcx.lang_items().deref_trait()
&& implements_trait(self.cx, ty, deref_trait_id, &[])
- && let Some(target_ty) = self.cx.get_associated_type(ty, deref_trait_id, "Target")
+ && let Some(target_ty) = self.cx.get_associated_type(ty, deref_trait_id, sym::Target)
&& let Some(msrv) = self.ty_msrv_map.get(&target_ty)
&& msrv.is_none_or(|msrv| self.msrv.meets(self.cx, msrv))
{
diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs
index 5b42a40..0535ecf 100644
--- a/src/tools/clippy/clippy_lints/src/format_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/format_impl.rs
@@ -1,13 +1,13 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::macros::{FormatArgsStorage, find_format_arg_expr, is_format_macro, root_macro_call_first_node};
-use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators};
+use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators, sym};
use rustc_ast::{FormatArgsPiece, FormatTrait};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, Impl, ImplItem, ImplItemKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
+use rustc_span::Symbol;
use rustc_span::symbol::kw;
-use rustc_span::{Symbol, sym};
declare_clippy_lint! {
/// ### What it does
@@ -185,13 +185,13 @@ fn check_self_in_format_args(&self) {
&& let trait_name = match placeholder.format_trait {
FormatTrait::Display => sym::Display,
FormatTrait::Debug => sym::Debug,
- FormatTrait::LowerExp => sym!(LowerExp),
- FormatTrait::UpperExp => sym!(UpperExp),
- FormatTrait::Octal => sym!(Octal),
+ FormatTrait::LowerExp => sym::LowerExp,
+ FormatTrait::UpperExp => sym::UpperExp,
+ FormatTrait::Octal => sym::Octal,
FormatTrait::Pointer => sym::Pointer,
- FormatTrait::Binary => sym!(Binary),
- FormatTrait::LowerHex => sym!(LowerHex),
- FormatTrait::UpperHex => sym!(UpperHex),
+ FormatTrait::Binary => sym::Binary,
+ FormatTrait::LowerHex => sym::LowerHex,
+ FormatTrait::UpperHex => sym::UpperHex,
}
&& trait_name == self.format_trait_impl.name
&& let Ok(index) = placeholder.argument.index
diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs
index c8fe7ac..4b482f7 100644
--- a/src/tools/clippy/clippy_lints/src/formatting.rs
+++ b/src/tools/clippy/clippy_lints/src/formatting.rs
@@ -138,27 +138,28 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
/// Implementation of the `SUSPICIOUS_ASSIGNMENT_FORMATTING` lint.
fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
- if let ExprKind::Assign(ref lhs, ref rhs, _) = expr.kind {
- if !lhs.span.from_expansion() && !rhs.span.from_expansion() {
- let eq_span = lhs.span.between(rhs.span);
- if let ExprKind::Unary(op, ref sub_rhs) = rhs.kind {
- if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
- let op = op.as_str();
- let eqop_span = lhs.span.between(sub_rhs.span);
- if eq_snippet.ends_with('=') {
- span_lint_and_note(
- cx,
- SUSPICIOUS_ASSIGNMENT_FORMATTING,
- eqop_span,
- format!(
- "this looks like you are trying to use `.. {op}= ..`, but you \
+ if let ExprKind::Assign(ref lhs, ref rhs, _) = expr.kind
+ && !lhs.span.from_expansion()
+ && !rhs.span.from_expansion()
+ {
+ let eq_span = lhs.span.between(rhs.span);
+ if let ExprKind::Unary(op, ref sub_rhs) = rhs.kind
+ && let Some(eq_snippet) = snippet_opt(cx, eq_span)
+ {
+ let op = op.as_str();
+ let eqop_span = lhs.span.between(sub_rhs.span);
+ if eq_snippet.ends_with('=') {
+ span_lint_and_note(
+ cx,
+ SUSPICIOUS_ASSIGNMENT_FORMATTING,
+ eqop_span,
+ format!(
+ "this looks like you are trying to use `.. {op}= ..`, but you \
really are doing `.. = ({op} ..)`"
- ),
- None,
- format!("to remove this lint, use either `{op}=` or `= {op}`"),
- );
- }
- }
+ ),
+ None,
+ format!("to remove this lint, use either `{op}=` or `= {op}`"),
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
index 7361546..25b087e 100644
--- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
+++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
@@ -73,7 +73,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
};
let sugg =
- Sugg::hir_with_applicability(cx, expr, "<string>", &mut Applicability::MachineApplicable).maybe_par();
+ Sugg::hir_with_applicability(cx, expr, "<string>", &mut Applicability::MachineApplicable).maybe_paren();
span_lint_and_sugg(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
index 854fe14..fa63876 100644
--- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
@@ -2,7 +2,7 @@
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, ExprKind, FnDecl, ImplicitSelfKind};
+use rustc_hir::{BlockCheckMode, Body, ExprKind, FnDecl, ImplicitSelfKind, UnsafeSource};
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::Span;
@@ -40,14 +40,25 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body:
name
};
- // Body must be &(mut) <self_data>.name
+ // Body must be `&(mut) <self_data>.name`, potentially in an `unsafe` block
// self_data is not necessarily self, to also lint sub-getters, etc…
let block_expr = if let ExprKind::Block(block, _) = body.value.kind
&& block.stmts.is_empty()
&& let Some(block_expr) = block.expr
{
- block_expr
+ if let ExprKind::Block(unsafe_block, _) = block_expr.kind
+ && unsafe_block.stmts.is_empty()
+ && matches!(
+ unsafe_block.rules,
+ BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
+ )
+ && let Some(unsafe_block_expr) = unsafe_block.expr
+ {
+ unsafe_block_expr
+ } else {
+ block_expr
+ }
} else {
return;
};
diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
index 4495aeb..2d22bb1 100644
--- a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
@@ -59,9 +59,7 @@ fn new<I1, I2>(default_idents: &mut I1, current_idents: &mut I2) -> Self
let mut renamed: Vec<(Span, String)> = vec![];
debug_assert!(default_idents.size_hint() == current_idents.size_hint());
- while let (Some(default_ident), Some(current_ident)) =
- (default_idents.next(), current_idents.next())
- {
+ while let (Some(default_ident), Some(current_ident)) = (default_idents.next(), current_idents.next()) {
let has_name_to_check = |ident: Option<Ident>| {
if let Some(ident) = ident
&& ident.name != kw::Underscore
diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
index 05dc47f..48d050a 100644
--- a/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/too_many_arguments.rs
@@ -47,16 +47,16 @@ pub(super) fn check_fn(
}
pub(super) fn check_trait_item(cx: &LateContext<'_>, item: &hir::TraitItem<'_>, too_many_arguments_threshold: u64) {
- if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
+ if let hir::TraitItemKind::Fn(ref sig, _) = item.kind
// don't lint extern functions decls, it's not their fault
- if sig.header.abi == ExternAbi::Rust {
- check_arg_number(
- cx,
- sig.decl,
- item.span.with_hi(sig.decl.output.span().hi()),
- too_many_arguments_threshold,
- );
- }
+ && sig.header.abi == ExternAbi::Rust
+ {
+ check_arg_number(
+ cx,
+ sig.decl,
+ item.span.with_hi(sig.decl.output.span().hi()),
+ too_many_arguments_threshold,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
index fbbd33e..9e94280 100644
--- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
@@ -94,7 +94,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
|diag| {
let mut app = Applicability::MachineApplicable;
let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app)
- .maybe_par()
+ .maybe_paren()
.to_string();
let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0;
let method_body = if let Some(first_stmt) = then_block.stmts.first() {
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index 5f95464..076017a 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::source::{snippet_with_applicability, snippet_with_context, walk_span_to_context};
use clippy_utils::visitors::for_each_expr_without_closures;
-use clippy_utils::{get_async_fn_body, is_async_fn, is_from_proc_macro};
+use clippy_utils::{desugar_await, get_async_closure_expr, get_async_fn_body, is_async_fn, is_from_proc_macro};
use core::ops::ControlFlow;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
@@ -134,6 +134,10 @@ fn lint_implicit_returns(
},
ExprKind::Match(_, arms, _) => {
+ if let Some(await_expr) = desugar_await(expr) {
+ lint_return(cx, await_expr.hir_id, await_expr.span);
+ return LintLocation::Inner;
+ }
for arm in arms {
let res = lint_implicit_returns(
cx,
@@ -153,18 +157,18 @@ fn lint_implicit_returns(
ExprKind::Loop(block, ..) => {
let mut add_return = false;
let _: Option<!> = for_each_expr_without_closures(block, |e| {
- if let ExprKind::Break(dest, sub_expr) = e.kind {
- if dest.target_id.ok() == Some(expr.hir_id) {
- if call_site_span.is_none() && e.span.ctxt() == ctxt {
- // At this point sub_expr can be `None` in async functions which either diverge, or return
- // the unit type.
- if let Some(sub_expr) = sub_expr {
- lint_break(cx, e.hir_id, e.span, sub_expr.span);
- }
- } else {
- // the break expression is from a macro call, add a return to the loop
- add_return = true;
+ if let ExprKind::Break(dest, sub_expr) = e.kind
+ && dest.target_id.ok() == Some(expr.hir_id)
+ {
+ if call_site_span.is_none() && e.span.ctxt() == ctxt {
+ // At this point sub_expr can be `None` in async functions which either diverge, or return
+ // the unit type.
+ if let Some(sub_expr) = sub_expr {
+ lint_break(cx, e.hir_id, e.span, sub_expr.span);
}
+ } else {
+ // the break expression is from a macro call, add a return to the loop
+ add_return = true;
}
}
ControlFlow::Continue(())
@@ -241,6 +245,8 @@ fn check_fn(
Some(e) => e,
None => return,
}
+ } else if let Some(expr) = get_async_closure_expr(cx.tcx, body.value) {
+ expr
} else {
body.value
};
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index 5d7d3ae..514e72a 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -239,7 +239,7 @@ fn check_subtraction(
// This part of the condition is voluntarily split from the one before to ensure that
// if `snippet_opt` fails, it won't try the next conditions.
if (!is_in_const_context(cx) || msrv.meets(cx, msrvs::SATURATING_SUB_CONST))
- && let Some(big_expr_sugg) = Sugg::hir_opt(cx, big_expr).map(Sugg::maybe_par)
+ && let Some(big_expr_sugg) = Sugg::hir_opt(cx, big_expr).map(Sugg::maybe_paren)
&& let Some(little_expr_sugg) = Sugg::hir_opt(cx, little_expr)
{
let sugg = format!(
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index d02d9b2..6b89abd 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -8,7 +8,7 @@
};
use rustc_hir_analysis::lower_ty;
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, ClauseKind, Generics, Ty, TyCtxt};
+use rustc_middle::ty::{self, AssocItem, ClauseKind, Generics, Ty, TyCtxt};
use rustc_session::declare_lint_pass;
use rustc_span::Span;
@@ -315,7 +315,7 @@ fn check<'tcx>(cx: &LateContext<'tcx>, bounds: GenericBounds<'tcx>) {
assocs
.filter_by_name_unhygienic(constraint.ident.name)
.next()
- .is_some_and(|assoc| assoc.kind == ty::AssocKind::Type)
+ .is_some_and(AssocItem::is_type)
})
{
emit_lint(cx, poly_trait, bounds, index, implied_constraints, bound);
diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
index e1dd787..e612975 100644
--- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -65,13 +65,13 @@
}
pub struct InconsistentStructConstructor {
- lint_inconsistent_struct_field_initializers: bool,
+ check_inconsistent_struct_field_initializers: bool,
}
impl InconsistentStructConstructor {
pub fn new(conf: &'static Conf) -> Self {
Self {
- lint_inconsistent_struct_field_initializers: conf.lint_inconsistent_struct_field_initializers,
+ check_inconsistent_struct_field_initializers: conf.check_inconsistent_struct_field_initializers,
}
}
}
@@ -86,7 +86,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
let all_fields_are_shorthand = fields.iter().all(|f| f.is_shorthand);
let applicability = if all_fields_are_shorthand {
Applicability::MachineApplicable
- } else if self.lint_inconsistent_struct_field_initializers {
+ } else if self.check_inconsistent_struct_field_initializers {
Applicability::MaybeIncorrect
} else {
return;
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index 3343138..99a393b 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -2,13 +2,12 @@
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
use clippy_utils::ty::{deref_chain, get_adt_inherent_method};
-use clippy_utils::{higher, is_from_proc_macro, is_in_test};
+use clippy_utils::{higher, is_from_proc_macro, is_in_test, sym};
use rustc_ast::ast::RangeLimits;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
use rustc_session::impl_lint_pass;
-use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -136,28 +135,28 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let const_range = to_const_range(cx, range, size);
- if let (Some(start), _) = const_range {
- if start > size {
- span_lint(
- cx,
- OUT_OF_BOUNDS_INDEXING,
- range.start.map_or(expr.span, |start| start.span),
- "range is out of bounds",
- );
- return;
- }
+ if let (Some(start), _) = const_range
+ && start > size
+ {
+ span_lint(
+ cx,
+ OUT_OF_BOUNDS_INDEXING,
+ range.start.map_or(expr.span, |start| start.span),
+ "range is out of bounds",
+ );
+ return;
}
- if let (_, Some(end)) = const_range {
- if end > size {
- span_lint(
- cx,
- OUT_OF_BOUNDS_INDEXING,
- range.end.map_or(expr.span, |end| end.span),
- "range is out of bounds",
- );
- return;
- }
+ if let (_, Some(end)) = const_range
+ && end > size
+ {
+ span_lint(
+ cx,
+ OUT_OF_BOUNDS_INDEXING,
+ range.end.map_or(expr.span, |end| end.span),
+ "range is out of bounds",
+ );
+ return;
}
if let (Some(_), Some(_)) = const_range {
@@ -268,7 +267,7 @@ fn ty_has_applicable_get_function<'tcx>(
index_expr: &Expr<'_>,
) -> bool {
if let ty::Adt(_, _) = array_ty.kind()
- && let Some(get_output_ty) = get_adt_inherent_method(cx, ty, sym!(get)).map(|m| {
+ && let Some(get_output_ty) = get_adt_inherent_method(cx, ty, sym::get).map(|m| {
cx.tcx
.fn_sig(m.def_id)
.skip_binder()
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index 960b9aa..427a1f8 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -156,11 +156,12 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
.and(cap);
}
}
- if method.ident.name.as_str() == "flat_map" && args.len() == 1 {
- if let ExprKind::Closure(&Closure { body, .. }) = args[0].kind {
- let body = cx.tcx.hir_body(body);
- return is_infinite(cx, body.value);
- }
+ if method.ident.name.as_str() == "flat_map"
+ && args.len() == 1
+ && let ExprKind::Closure(&Closure { body, .. }) = args[0].kind
+ {
+ let body = cx.tcx.hir_body(body);
+ return is_infinite(cx, body.value);
}
Finite
},
diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
index 4ae1119..91f65d0 100644
--- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
+++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
@@ -123,7 +123,7 @@ fn print_manual_instant_elapsed_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, sugg
expr.span,
"manual implementation of `Instant::elapsed`",
"try",
- format!("{}.elapsed()", sugg.maybe_par()),
+ format!("{}.elapsed()", sugg.maybe_paren()),
Applicability::MachineApplicable,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
index fc575bf..67ce57d 100644
--- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs
+++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
@@ -130,14 +130,14 @@ fn generate_recommendation(
BinOpKind::Le => "<",
_ => return None,
};
- if let Some(snippet) = node.span.get_source_text(cx) {
- if let Some(other_side_snippet) = other_side.span.get_source_text(cx) {
- let rec = match side {
- Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")),
- Side::Rhs => Some(format!("{other_side_snippet} {binop_string} {snippet}")),
- };
- return rec;
- }
+ if let Some(snippet) = node.span.get_source_text(cx)
+ && let Some(other_side_snippet) = other_side.span.get_source_text(cx)
+ {
+ let rec = match side {
+ Side::Lhs => Some(format!("{snippet} {binop_string} {other_side_snippet}")),
+ Side::Rhs => Some(format!("{other_side_snippet} {binop_string} {snippet}")),
+ };
+ return rec;
}
None
}
@@ -157,10 +157,10 @@ fn emit_warning(cx: &EarlyContext<'_>, block: &Expr, recommendation: String) {
impl EarlyLintPass for IntPlusOne {
fn check_expr(&mut self, cx: &EarlyContext<'_>, item: &Expr) {
- if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.kind {
- if let Some(rec) = Self::check_binop(cx, kind.node, lhs, rhs) {
- Self::emit_warning(cx, item, rec);
- }
+ if let ExprKind::Binary(ref kind, ref lhs, ref rhs) = item.kind
+ && let Some(rec) = Self::check_binop(cx, kind.node, lhs, rhs)
+ {
+ Self::emit_warning(cx, item, rec);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
index b426643..b0ecc5d 100644
--- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -91,49 +91,49 @@ fn upcast_comparison_bounds_err<'tcx>(
rhs: &'tcx Expr<'_>,
invert: bool,
) {
- if let Some((lb, ub)) = lhs_bounds {
- if let Some(norm_rhs_val) = ConstEvalCtxt::new(cx).eval_full_int(rhs) {
- if rel == Rel::Eq || rel == Rel::Ne {
- if norm_rhs_val < lb || norm_rhs_val > ub {
- err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
- }
- } else if match rel {
- Rel::Lt => {
- if invert {
- norm_rhs_val < lb
- } else {
- ub < norm_rhs_val
- }
- },
- Rel::Le => {
- if invert {
- norm_rhs_val <= lb
- } else {
- ub <= norm_rhs_val
- }
- },
- Rel::Eq | Rel::Ne => unreachable!(),
- } {
- err_upcast_comparison(cx, span, lhs, true);
- } else if match rel {
- Rel::Lt => {
- if invert {
- norm_rhs_val >= ub
- } else {
- lb >= norm_rhs_val
- }
- },
- Rel::Le => {
- if invert {
- norm_rhs_val > ub
- } else {
- lb > norm_rhs_val
- }
- },
- Rel::Eq | Rel::Ne => unreachable!(),
- } {
- err_upcast_comparison(cx, span, lhs, false);
+ if let Some((lb, ub)) = lhs_bounds
+ && let Some(norm_rhs_val) = ConstEvalCtxt::new(cx).eval_full_int(rhs)
+ {
+ if rel == Rel::Eq || rel == Rel::Ne {
+ if norm_rhs_val < lb || norm_rhs_val > ub {
+ err_upcast_comparison(cx, span, lhs, rel == Rel::Ne);
}
+ } else if match rel {
+ Rel::Lt => {
+ if invert {
+ norm_rhs_val < lb
+ } else {
+ ub < norm_rhs_val
+ }
+ },
+ Rel::Le => {
+ if invert {
+ norm_rhs_val <= lb
+ } else {
+ ub <= norm_rhs_val
+ }
+ },
+ Rel::Eq | Rel::Ne => unreachable!(),
+ } {
+ err_upcast_comparison(cx, span, lhs, true);
+ } else if match rel {
+ Rel::Lt => {
+ if invert {
+ norm_rhs_val >= ub
+ } else {
+ lb >= norm_rhs_val
+ }
+ },
+ Rel::Le => {
+ if invert {
+ norm_rhs_val > ub
+ } else {
+ lb > norm_rhs_val
+ }
+ },
+ Rel::Eq | Rel::Ne => unreachable!(),
+ } {
+ err_upcast_comparison(cx, span, lhs, false);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
index 977fd5f..b1271a2 100644
--- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
+++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
@@ -377,22 +377,21 @@ fn check_struct_name_repetition(&self, cx: &LateContext<'_>, item: &Item<'_>, fi
"field name starts with the struct's name",
);
}
- if field_words.len() > item_name_words.len() {
+ if field_words.len() > item_name_words.len()
// lint only if the end is not covered by the start
- if field_words
+ && field_words
.iter()
.rev()
.zip(item_name_words.iter().rev())
.all(|(a, b)| a == b)
- {
- span_lint_hir(
- cx,
- STRUCT_FIELD_NAMES,
- field.hir_id,
- field.span,
- "field name ends with the struct's name",
- );
- }
+ {
+ span_lint_hir(
+ cx,
+ STRUCT_FIELD_NAMES,
+ field.hir_id,
+ field.span,
+ "field name ends with the struct's name",
+ );
}
}
}
@@ -445,56 +444,55 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
let item_name = ident.name.as_str();
let item_camel = to_camel_case(item_name);
- if !item.span.from_expansion() && is_present_in_source(cx, item.span) {
- if let [.., (mod_name, mod_camel, mod_owner_id)] = &*self.modules {
- // constants don't have surrounding modules
- if !mod_camel.is_empty() {
- if mod_name == &ident.name
- && let ItemKind::Mod(..) = item.kind
- && (!self.allow_private_module_inception || cx.tcx.visibility(mod_owner_id.def_id).is_public())
- {
- span_lint(
+ if !item.span.from_expansion() && is_present_in_source(cx, item.span)
+ && let [.., (mod_name, mod_camel, mod_owner_id)] = &*self.modules
+ // constants don't have surrounding modules
+ && !mod_camel.is_empty()
+ {
+ if mod_name == &ident.name
+ && let ItemKind::Mod(..) = item.kind
+ && (!self.allow_private_module_inception || cx.tcx.visibility(mod_owner_id.def_id).is_public())
+ {
+ span_lint(
+ cx,
+ MODULE_INCEPTION,
+ item.span,
+ "module has the same name as its containing module",
+ );
+ }
+
+ // The `module_name_repetitions` lint should only trigger if the item has the module in its
+ // name. Having the same name is accepted.
+ if cx.tcx.visibility(item.owner_id).is_public()
+ && cx.tcx.visibility(mod_owner_id.def_id).is_public()
+ && item_camel.len() > mod_camel.len()
+ {
+ let matching = count_match_start(mod_camel, &item_camel);
+ let rmatching = count_match_end(mod_camel, &item_camel);
+ let nchars = mod_camel.chars().count();
+
+ let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric();
+
+ if matching.char_count == nchars {
+ match item_camel.chars().nth(nchars) {
+ Some(c) if is_word_beginning(c) => span_lint(
cx,
- MODULE_INCEPTION,
- item.span,
- "module has the same name as its containing module",
- );
+ MODULE_NAME_REPETITIONS,
+ ident.span,
+ "item name starts with its containing module's name",
+ ),
+ _ => (),
}
-
- // The `module_name_repetitions` lint should only trigger if the item has the module in its
- // name. Having the same name is accepted.
- if cx.tcx.visibility(item.owner_id).is_public()
- && cx.tcx.visibility(mod_owner_id.def_id).is_public()
- && item_camel.len() > mod_camel.len()
- {
- let matching = count_match_start(mod_camel, &item_camel);
- let rmatching = count_match_end(mod_camel, &item_camel);
- let nchars = mod_camel.chars().count();
-
- let is_word_beginning = |c: char| c == '_' || c.is_uppercase() || c.is_numeric();
-
- if matching.char_count == nchars {
- match item_camel.chars().nth(nchars) {
- Some(c) if is_word_beginning(c) => span_lint(
- cx,
- MODULE_NAME_REPETITIONS,
- ident.span,
- "item name starts with its containing module's name",
- ),
- _ => (),
- }
- }
- if rmatching.char_count == nchars
- && !self.is_allowed_prefix(&item_camel[..item_camel.len() - rmatching.byte_count])
- {
- span_lint(
- cx,
- MODULE_NAME_REPETITIONS,
- ident.span,
- "item name ends with its containing module's name",
- );
- }
- }
+ }
+ if rmatching.char_count == nchars
+ && !self.is_allowed_prefix(&item_camel[..item_camel.len() - rmatching.byte_count])
+ {
+ span_lint(
+ cx,
+ MODULE_NAME_REPETITIONS,
+ ident.span,
+ "item name ends with its containing module's name",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index 72e22ae..8c71d34 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -2,21 +2,20 @@
use clippy_utils::source::{SpanRangeExt, snippet_with_context};
use clippy_utils::sugg::{Sugg, has_enclosing_paren};
use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_item_name, get_parent_as_impl, is_lint_allowed, is_trait_method, peel_ref_operators};
+use clippy_utils::{fulfill_or_allowed, get_item_name, get_parent_as_impl, is_trait_method, peel_ref_operators, sym};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::def_id::{DefId, DefIdSet};
use rustc_hir::{
- AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, ImplItem, ImplItemKind,
+ AssocItemKind, BinOpKind, Expr, ExprKind, FnRetTy, GenericArg, GenericBound, HirId, ImplItem, ImplItemKind,
ImplicitSelfKind, Item, ItemKind, Mutability, Node, OpaqueTyOrigin, PatExprKind, PatKind, PathSegment, PrimTy,
QPath, TraitItemRef, TyKind,
};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
+use rustc_middle::ty::{self, FnSig, Ty};
use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned;
-use rustc_span::symbol::sym;
use rustc_span::{Ident, Span, Symbol};
use rustc_trait_selection::traits::supertrait_def_ids;
@@ -143,7 +142,6 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>)
&& let Some(ty_id) = cx.qpath_res(ty_path, imp.self_ty.hir_id).opt_def_id()
&& let Some(local_id) = ty_id.as_local()
&& let ty_hir_id = cx.tcx.local_def_id_to_hir_id(local_id)
- && !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id)
&& let Some(output) =
parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder())
{
@@ -157,7 +155,17 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>)
},
_ => return,
};
- check_for_is_empty(cx, sig.span, sig.decl.implicit_self, output, ty_id, name, kind);
+ check_for_is_empty(
+ cx,
+ sig.span,
+ sig.decl.implicit_self,
+ output,
+ ty_id,
+ name,
+ kind,
+ item.hir_id(),
+ ty_hir_id,
+ );
}
}
@@ -180,7 +188,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let mut applicability = Applicability::MachineApplicable;
let lit1 = peel_ref_operators(cx, lt.init);
- let lit_str = Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_par();
+ let lit_str = Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_paren();
span_lint_and_sugg(
cx,
@@ -202,7 +210,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
expr.span,
lhs_expr,
peel_ref_operators(cx, rhs_expr),
- (method.ident.name == sym::ne).then_some("!").unwrap_or_default(),
+ if method.ident.name == sym::ne {
+ "!"
+ } else {
+ Default::default()
+ },
);
}
@@ -282,16 +294,10 @@ fn fill_trait_set(traitt: DefId, set: &mut DefIdSet, cx: &LateContext<'_>) {
{
let mut current_and_super_traits = DefIdSet::default();
fill_trait_set(visited_trait.owner_id.to_def_id(), &mut current_and_super_traits, cx);
- let is_empty = sym!(is_empty);
-
let is_empty_method_found = current_and_super_traits
.items()
- .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(is_empty))
- .any(|i| {
- i.kind == AssocKind::Fn
- && i.fn_has_self_parameter
- && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1
- });
+ .flat_map(|&i| cx.tcx.associated_items(i).filter_by_name_unhygienic(sym::is_empty))
+ .any(|i| i.is_method() && cx.tcx.fn_sig(i.def_id).skip_binder().inputs().skip_binder().len() == 1);
if !is_empty_method_found {
span_lint(
@@ -443,6 +449,7 @@ fn check_is_empty_sig<'tcx>(
}
/// Checks if the given type has an `is_empty` method with the appropriate signature.
+#[expect(clippy::too_many_arguments)]
fn check_for_is_empty(
cx: &LateContext<'_>,
span: Span,
@@ -451,6 +458,8 @@ fn check_for_is_empty(
impl_ty: DefId,
item_name: Symbol,
item_kind: &str,
+ len_method_hir_id: HirId,
+ ty_decl_hir_id: HirId,
) {
// Implementor may be a type alias, in which case we need to get the `DefId` of the aliased type to
// find the correct inherent impls.
@@ -460,13 +469,12 @@ fn check_for_is_empty(
return;
};
- let is_empty = Symbol::intern("is_empty");
let is_empty = cx
.tcx
.inherent_impls(impl_ty)
.iter()
- .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(is_empty))
- .find(|item| item.kind == AssocKind::Fn);
+ .flat_map(|&id| cx.tcx.associated_items(id).filter_by_name_unhygienic(sym::is_empty))
+ .find(|item| item.is_fn());
let (msg, is_empty_span, self_kind) = match is_empty {
None => (
@@ -486,7 +494,7 @@ fn check_for_is_empty(
None,
),
Some(is_empty)
- if !(is_empty.fn_has_self_parameter
+ if !(is_empty.is_method()
&& check_is_empty_sig(
cx,
cx.tcx.fn_sig(is_empty.def_id).instantiate_identity().skip_binder(),
@@ -506,14 +514,16 @@ fn check_for_is_empty(
Some(_) => return,
};
- span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, span, msg, |db| {
- if let Some(span) = is_empty_span {
- db.span_note(span, "`is_empty` defined here");
- }
- if let Some(self_kind) = self_kind {
- db.note(output.expected_sig(self_kind));
- }
- });
+ if !fulfill_or_allowed(cx, LEN_WITHOUT_IS_EMPTY, [len_method_hir_id, ty_decl_hir_id]) {
+ span_lint_and_then(cx, LEN_WITHOUT_IS_EMPTY, span, msg, |db| {
+ if let Some(span) = is_empty_span {
+ db.span_note(span, "`is_empty` defined here");
+ }
+ if let Some(self_kind) = self_kind {
+ db.note(output.expected_sig(self_kind));
+ }
+ });
+ }
}
fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>, op: &str, compare_to: u32) {
@@ -523,10 +533,10 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_>
if let (&ExprKind::MethodCall(method_path, receiver, [], _), ExprKind::Lit(lit)) = (&method.kind, &lit.kind) {
// check if we are in an is_empty() method
- if let Some(name) = get_item_name(cx, method) {
- if name.as_str() == "is_empty" {
- return;
- }
+ if let Some(name) = get_item_name(cx, method)
+ && name.as_str() == "is_empty"
+ {
+ return;
}
check_len(cx, span, method_path.ident.name, receiver, &lit.node, op, compare_to);
@@ -573,7 +583,7 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex
let mut applicability = Applicability::MachineApplicable;
let lit1 = peel_ref_operators(cx, lit1);
- let lit_str = Sugg::hir_with_context(cx, lit1, span.ctxt(), "_", &mut applicability).maybe_par();
+ let lit_str = Sugg::hir_with_context(cx, lit1, span.ctxt(), "_", &mut applicability).maybe_paren();
span_lint_and_sugg(
cx,
@@ -588,11 +598,11 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex
}
fn is_empty_string(expr: &Expr<'_>) -> bool {
- if let ExprKind::Lit(lit) = expr.kind {
- if let LitKind::Str(lit, _) = lit.node {
- let lit = lit.as_str();
- return lit.is_empty();
- }
+ if let ExprKind::Lit(lit) = expr.kind
+ && let LitKind::Str(lit, _) = lit.node
+ {
+ let lit = lit.as_str();
+ return lit.is_empty();
}
false
}
@@ -608,7 +618,7 @@ fn is_empty_array(expr: &Expr<'_>) -> bool {
fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
/// Gets an `AssocItem` and return true if it matches `is_empty(self)`.
fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
- if item.kind == AssocKind::Fn {
+ if item.is_fn() {
let sig = cx.tcx.fn_sig(item.def_id).skip_binder();
let ty = sig.skip_binder();
ty.inputs().len() == 1
@@ -619,11 +629,10 @@ fn is_is_empty(cx: &LateContext<'_>, item: &ty::AssocItem) -> bool {
/// Checks the inherent impl's items for an `is_empty(self)` method.
fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
- let is_empty = sym!(is_empty);
cx.tcx.inherent_impls(id).iter().any(|imp| {
cx.tcx
.associated_items(*imp)
- .filter_by_name_unhygienic(is_empty)
+ .filter_by_name_unhygienic(sym::is_empty)
.any(|item| is_is_empty(cx, item))
})
}
@@ -631,10 +640,9 @@ fn has_is_empty_impl(cx: &LateContext<'_>, id: DefId) -> bool {
fn ty_has_is_empty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, depth: usize) -> bool {
match ty.kind() {
ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| {
- let is_empty = sym!(is_empty);
cx.tcx
.associated_items(principal.def_id())
- .filter_by_name_unhygienic(is_empty)
+ .filter_by_name_unhygienic(sym::is_empty)
.any(|item| is_is_empty(cx, item))
}),
ty::Alias(ty::Projection, proj) => has_is_empty_impl(cx, proj.def_id),
@@ -644,7 +652,7 @@ fn ty_has_is_empty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, depth: usize) ->
&& cx.tcx.get_diagnostic_item(sym::Deref).is_some_and(|deref_id| {
implements_trait(cx, ty, deref_id, &[])
&& cx
- .get_associated_type(ty, deref_id, "Target")
+ .get_associated_type(ty, deref_id, sym::Target)
.is_some_and(|deref_ty| ty_has_is_empty(cx, deref_ty, depth + 1))
}))
},
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 3fe3cd6..5fa8f6f 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -65,7 +65,6 @@
#[macro_use]
extern crate clippy_utils;
-#[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
mod utils;
pub mod ctfe; // Very important lint, do not remove (rust#125116)
@@ -205,6 +204,7 @@
mod macro_metavars_in_unsafe;
mod macro_use;
mod main_recursion;
+mod manual_abs_diff;
mod manual_assert;
mod manual_async_fn;
mod manual_bits;
@@ -226,7 +226,6 @@
mod manual_slice_size_calculation;
mod manual_string_new;
mod manual_strip;
-mod manual_unwrap_or_default;
mod map_unit_fn;
mod match_result_ok;
mod matches;
@@ -320,6 +319,7 @@
mod redundant_pub_crate;
mod redundant_slicing;
mod redundant_static_lifetimes;
+mod redundant_test_prefix;
mod redundant_type_annotations;
mod ref_option_ref;
mod ref_patterns;
@@ -412,21 +412,6 @@
use rustc_lint::{Lint, LintId};
use utils::attr_collector::{AttrCollector, AttrStorage};
-/// Register all pre expansion lints
-///
-/// Pre-expansion lints run before any macro expansion has happened.
-///
-/// Note that due to the architecture of the compiler, currently `cfg_attr` attributes on crate
-/// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass.
-///
-/// Used in `./src/driver.rs`.
-pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
- // NOTE: Do not add any more pre-expansion passes. These should be removed eventually.
- store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes::new(conf)));
-
- store.register_early_pass(move || Box::new(attrs::PostExpansionEarlyAttributes::new(conf)));
-}
-
#[derive(Default)]
struct RegistrationGroups {
all: Vec<LintId>,
@@ -439,8 +424,6 @@ struct RegistrationGroups {
restriction: Vec<LintId>,
style: Vec<LintId>,
suspicious: Vec<LintId>,
- #[cfg(feature = "internal")]
- internal: Vec<LintId>,
}
impl RegistrationGroups {
@@ -456,8 +439,6 @@ fn register(self, store: &mut rustc_lint::LintStore) {
store.register_group(true, "clippy::restriction", Some("clippy_restriction"), self.restriction);
store.register_group(true, "clippy::style", Some("clippy_style"), self.style);
store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), self.suspicious);
- #[cfg(feature = "internal")]
- store.register_group(true, "clippy::internal", Some("clippy_internal"), self.internal);
}
}
@@ -472,8 +453,6 @@ pub(crate) enum LintCategory {
Restriction,
Style,
Suspicious,
- #[cfg(feature = "internal")]
- Internal,
}
#[allow(clippy::enum_glob_use)]
@@ -495,8 +474,6 @@ fn group(self, groups: &mut RegistrationGroups) -> &mut Vec<LintId> {
Restriction => &mut groups.restriction,
Style => &mut groups.style,
Suspicious => &mut groups.suspicious,
- #[cfg(feature = "internal")]
- Internal => &mut groups.internal,
}
}
}
@@ -530,8 +507,6 @@ pub fn category_str(&self) -> &'static str {
Restriction => "restriction",
Style => "style",
Suspicious => "suspicious",
- #[cfg(feature = "internal")]
- Internal => "internal",
}
}
}
@@ -589,6 +564,13 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_removed(name, reason);
}
+ // NOTE: Do not add any more pre-expansion passes. These should be removed eventually.
+ // Due to the architecture of the compiler, currently `cfg_attr` attributes on crate
+ // level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass.
+ store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes::new(conf)));
+
+ store.register_early_pass(move || Box::new(attrs::PostExpansionEarlyAttributes::new(conf)));
+
let format_args_storage = FormatArgsStorage::default();
let format_args = format_args_storage.clone();
store.register_early_pass(move || {
@@ -601,30 +583,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
let attrs = attr_storage.clone();
store.register_early_pass(move || Box::new(AttrCollector::new(attrs.clone())));
- // all the internal lints
- #[cfg(feature = "internal")]
- {
- store.register_early_pass(|| {
- Box::new(utils::internal_lints::unsorted_clippy_utils_paths::UnsortedClippyUtilsPaths)
- });
- store.register_early_pass(|| Box::new(utils::internal_lints::produce_ice::ProduceIce));
- store.register_late_pass(|_| Box::new(utils::internal_lints::collapsible_calls::CollapsibleCalls));
- store.register_late_pass(|_| Box::new(utils::internal_lints::invalid_paths::InvalidPaths));
- store.register_late_pass(|_| {
- Box::<utils::internal_lints::interning_defined_symbol::InterningDefinedSymbol>::default()
- });
- store.register_late_pass(|_| {
- Box::<utils::internal_lints::lint_without_lint_pass::LintWithoutLintPass>::default()
- });
- store.register_late_pass(|_| Box::<utils::internal_lints::unnecessary_def_path::UnnecessaryDefPath>::default());
- store.register_late_pass(|_| Box::new(utils::internal_lints::outer_expn_data_pass::OuterExpnDataPass));
- store.register_late_pass(|_| Box::new(utils::internal_lints::msrv_attr_impl::MsrvAttrImpl));
- store.register_late_pass(|_| {
- Box::new(utils::internal_lints::almost_standard_lint_formulation::AlmostStandardFormulation::new())
- });
- store.register_late_pass(|_| Box::new(utils::internal_lints::slow_symbol_comparisons::SlowSymbolComparisons));
- }
-
store.register_late_pass(|_| Box::new(ctfe::ClippyCtfe));
store.register_late_pass(move |_| Box::new(operators::arithmetic_side_effects::ArithmeticSideEffects::new(conf)));
@@ -772,7 +730,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(|_| Box::new(redundant_closure_call::RedundantClosureCall));
store.register_early_pass(|| Box::new(unused_unit::UnusedUnit));
store.register_late_pass(|_| Box::new(returns::Return));
- store.register_early_pass(|| Box::new(collapsible_if::CollapsibleIf));
+ store.register_late_pass(move |tcx| Box::new(collapsible_if::CollapsibleIf::new(tcx, conf)));
store.register_late_pass(|_| Box::new(items_after_statements::ItemsAfterStatements));
store.register_early_pass(|| Box::new(precedence::Precedence));
store.register_late_pass(|_| Box::new(needless_parens_on_range_literals::NeedlessParensOnRangeLiterals));
@@ -857,7 +815,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(move |_| Box::new(write::Write::new(conf, format_args.clone())));
store.register_late_pass(move |_| Box::new(cargo::Cargo::new(conf)));
store.register_early_pass(|| Box::new(crate_in_macro_def::CrateInMacroDef));
- store.register_early_pass(|| Box::new(empty_with_brackets::EmptyWithBrackets));
+ store.register_late_pass(|_| Box::new(empty_with_brackets::EmptyWithBrackets::default()));
store.register_late_pass(|_| Box::new(unnecessary_owned_empty_strings::UnnecessaryOwnedEmptyStrings));
store.register_early_pass(|| Box::new(pub_use::PubUse));
store.register_late_pass(|_| Box::new(format_push_string::FormatPushString));
@@ -879,6 +837,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(move |_| Box::new(std_instead_of_core::StdReexports::new(conf)));
store.register_late_pass(move |_| Box::new(instant_subtraction::InstantSubtraction::new(conf)));
store.register_late_pass(|_| Box::new(partialeq_to_none::PartialeqToNone));
+ store.register_late_pass(move |_| Box::new(manual_abs_diff::ManualAbsDiff::new(conf)));
store.register_late_pass(move |_| Box::new(manual_clamp::ManualClamp::new(conf)));
store.register_late_pass(|_| Box::new(manual_string_new::ManualStringNew));
store.register_late_pass(|_| Box::new(unused_peekable::UnusedPeekable));
@@ -960,7 +919,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_early_pass(|| Box::new(multiple_bound_locations::MultipleBoundLocations));
store.register_late_pass(move |_| Box::new(assigning_clones::AssigningClones::new(conf)));
store.register_late_pass(|_| Box::new(zero_repeat_side_effects::ZeroRepeatSideEffects));
- store.register_late_pass(|_| Box::new(manual_unwrap_or_default::ManualUnwrapOrDefault));
store.register_late_pass(|_| Box::new(integer_division_remainder_used::IntegerDivisionRemainderUsed));
store.register_late_pass(move |_| Box::new(macro_metavars_in_unsafe::ExprMetavarsInUnsafe::new(conf)));
store.register_late_pass(move |_| Box::new(string_patterns::StringPatterns::new(conf)));
@@ -971,7 +929,7 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(|_| Box::new(zombie_processes::ZombieProcesses));
store.register_late_pass(|_| Box::new(pointers_in_nomem_asm_block::PointersInNomemAsmBlock));
store.register_late_pass(move |_| Box::new(manual_div_ceil::ManualDivCeil::new(conf)));
- store.register_late_pass(|_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo));
+ store.register_late_pass(move |_| Box::new(manual_is_power_of_two::ManualIsPowerOfTwo::new(conf)));
store.register_late_pass(|_| Box::new(non_zero_suggestions::NonZeroSuggestions));
store.register_late_pass(|_| Box::new(literal_string_with_formatting_args::LiteralStringWithFormattingArg));
store.register_late_pass(move |_| Box::new(unused_trait_names::UnusedTraitNames::new(conf)));
@@ -984,5 +942,6 @@ pub fn register_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
store.register_late_pass(move |_| Box::new(non_std_lazy_statics::NonStdLazyStatic::new(conf)));
store.register_late_pass(|_| Box::new(manual_option_as_slice::ManualOptionAsSlice::new(conf)));
store.register_late_pass(|_| Box::new(single_option_map::SingleOptionMap));
+ store.register_late_pass(move |_| Box::new(redundant_test_prefix::RedundantTestPrefix));
// add lints here, do not remove this comment, it's used in `new_lint`
}
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 8d47c75..5ef5e3a 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -14,7 +14,7 @@
};
use rustc_hir::{
AmbigArg, BareFnTy, BodyId, FnDecl, FnSig, GenericArg, GenericArgs, GenericBound, GenericParam, GenericParamKind,
- Generics, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, LifetimeParamKind, Node,
+ Generics, HirId, Impl, ImplItem, ImplItemKind, Item, ItemKind, Lifetime, LifetimeKind, LifetimeParamKind, Node,
PolyTraitRef, PredicateOrigin, TraitFn, TraitItem, TraitItemKind, Ty, TyKind, WhereBoundPredicate, WherePredicate,
WherePredicateKind, lang_items,
};
@@ -150,10 +150,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
} = item.kind
{
check_fn_inner(cx, sig, Some(id), None, generics, item.span, true, self.msrv);
- } else if let ItemKind::Impl(impl_) = item.kind {
- if !item.span.from_expansion() {
- report_extra_impl_lifetimes(cx, impl_);
- }
+ } else if let ItemKind::Impl(impl_) = item.kind
+ && !item.span.from_expansion()
+ {
+ report_extra_impl_lifetimes(cx, impl_);
}
}
@@ -218,7 +218,7 @@ fn check_fn_inner<'tcx>(
for bound in pred.bounds {
let mut visitor = RefVisitor::new(cx);
walk_param_bound(&mut visitor, bound);
- if visitor.lts.iter().any(|lt| matches!(lt.res, LifetimeName::Param(_))) {
+ if visitor.lts.iter().any(|lt| matches!(lt.kind, LifetimeKind::Param(_))) {
return;
}
if let GenericBound::Trait(ref trait_ref) = *bound {
@@ -235,7 +235,7 @@ fn check_fn_inner<'tcx>(
_ => None,
});
for bound in lifetimes {
- if bound.res != LifetimeName::Static && !bound.is_elided() {
+ if bound.kind != LifetimeKind::Static && !bound.is_elided() {
return;
}
}
@@ -300,8 +300,8 @@ fn could_use_elision<'tcx>(
let input_lts = input_visitor.lts;
let output_lts = output_visitor.lts;
- if let Some(trait_sig) = trait_sig
- && non_elidable_self_type(cx, func, trait_sig.first().copied(), msrv)
+ if let Some(&[trait_sig]) = trait_sig
+ && non_elidable_self_type(cx, func, trait_sig, msrv)
{
return None;
}
@@ -310,11 +310,11 @@ fn could_use_elision<'tcx>(
let body = cx.tcx.hir_body(body_id);
let first_ident = body.params.first().and_then(|param| param.pat.simple_ident());
- if non_elidable_self_type(cx, func, Some(first_ident), msrv) {
+ if non_elidable_self_type(cx, func, first_ident, msrv) {
return None;
}
- let mut checker = BodyLifetimeChecker;
+ let mut checker = BodyLifetimeChecker::new(cx);
if checker.visit_expr(body.value).is_break() {
return None;
}
@@ -384,8 +384,8 @@ fn allowed_lts_from(named_generics: &[GenericParam<'_>]) -> FxIndexSet<LocalDefI
}
// elision doesn't work for explicit self types before Rust 1.81, see rust-lang/rust#69064
-fn non_elidable_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Option<Ident>>, msrv: Msrv) -> bool {
- if let Some(Some(ident)) = ident
+fn non_elidable_self_type<'tcx>(cx: &LateContext<'tcx>, func: &FnDecl<'tcx>, ident: Option<Ident>, msrv: Msrv) -> bool {
+ if let Some(ident) = ident
&& ident.name == kw::SelfLower
&& !func.implicit_self.has_implicit_self()
&& let Some(self_ty) = func.inputs.first()
@@ -421,8 +421,8 @@ fn named_lifetime_occurrences(lts: &[Lifetime]) -> Vec<(LocalDefId, usize)> {
}
fn named_lifetime(lt: &Lifetime) -> Option<LocalDefId> {
- match lt.res {
- LifetimeName::Param(id) if !lt.is_anonymous() => Some(id),
+ match lt.kind {
+ LifetimeKind::Param(id) if !lt.is_anonymous() => Some(id),
_ => None,
}
}
@@ -614,7 +614,7 @@ impl<'tcx, F> Visitor<'tcx> for LifetimeChecker<'_, 'tcx, F>
// for lifetimes as parameters of generics
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) {
- if let LifetimeName::Param(def_id) = lifetime.res
+ if let LifetimeKind::Param(def_id) = lifetime.kind
&& let Some(usages) = self.map.get_mut(&def_id)
{
usages.push(Usage {
@@ -826,7 +826,7 @@ fn report_elidable_lifetimes(
.iter()
.map(|<| cx.tcx.def_span(lt))
.chain(usages.iter().filter_map(|usage| {
- if let LifetimeName::Param(def_id) = usage.res
+ if let LifetimeKind::Param(def_id) = usage.kind
&& elidable_lts.contains(&def_id)
{
return Some(usage.ident.span);
@@ -911,10 +911,23 @@ fn elision_suggestions(
Some(suggestions)
}
-struct BodyLifetimeChecker;
+struct BodyLifetimeChecker<'tcx> {
+ tcx: TyCtxt<'tcx>,
+}
-impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker {
+impl<'tcx> BodyLifetimeChecker<'tcx> {
+ fn new(cx: &LateContext<'tcx>) -> Self {
+ Self { tcx: cx.tcx }
+ }
+}
+
+impl<'tcx> Visitor<'tcx> for BodyLifetimeChecker<'tcx> {
type Result = ControlFlow<()>;
+ type NestedFilter = middle_nested_filter::OnlyBodies;
+
+ fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+ self.tcx
+ }
// for lifetimes as parameters of generics
fn visit_lifetime(&mut self, lifetime: &'tcx Lifetime) -> ControlFlow<()> {
if !lifetime.is_anonymous() && lifetime.ident.name != kw::StaticLifetime {
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index 805de23..7cbfa2d 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -387,12 +387,11 @@ fn get_group_size<'a>(
let first = groups.next().expect("At least one group");
- if radix == Radix::Binary || radix == Radix::Octal || radix == Radix::Hexadecimal {
- if let Some(second_size) = groups.next() {
- if !groups.all(|i| i == second_size) || first > second_size {
- return Err(WarningType::UnusualByteGroupings);
- }
- }
+ if (radix == Radix::Binary || radix == Radix::Octal || radix == Radix::Hexadecimal)
+ && let Some(second_size) = groups.next()
+ && (!groups.all(|i| i == second_size) || first > second_size)
+ {
+ return Err(WarningType::UnusualByteGroupings);
}
if let Some(second) = groups.next() {
diff --git a/src/tools/clippy/clippy_lints/src/literal_string_with_formatting_args.rs b/src/tools/clippy/clippy_lints/src/literal_string_with_formatting_args.rs
index 975e683..244e7c9 100644
--- a/src/tools/clippy/clippy_lints/src/literal_string_with_formatting_args.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_string_with_formatting_args.rs
@@ -45,15 +45,14 @@ fn emit_lint(cx: &LateContext<'_>, expr: &Expr<'_>, spans: &[(Span, Option<Strin
let spans = spans
.iter()
.filter_map(|(span, name)| {
- if let Some(name) = name {
+ if let Some(name) = name
// We need to check that the name is a local.
- if !mir
+ && !mir
.var_debug_info
.iter()
.any(|local| !local.source_info.span.from_expansion() && local.name.as_str() == name)
- {
- return None;
- }
+ {
+ return None;
}
Some(*span)
})
diff --git a/src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs b/src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs
new file mode 100644
index 0000000..8916454
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/loops/char_indices_as_byte_indices.rs
@@ -0,0 +1,141 @@
+use std::ops::ControlFlow;
+
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::ty::is_type_lang_item;
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{eq_expr_value, higher, path_to_local_id};
+use rustc_errors::{Applicability, MultiSpan};
+use rustc_hir::{Expr, ExprKind, LangItem, Node, Pat, PatKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty::Ty;
+use rustc_span::{Span, sym};
+
+use super::CHAR_INDICES_AS_BYTE_INDICES;
+
+// The list of `str` methods we want to lint that have a `usize` argument representing a byte index.
+// Note: `String` also has methods that work with byte indices,
+// but they all take `&mut self` and aren't worth considering since the user couldn't have called
+// them while the chars iterator is live anyway.
+const BYTE_INDEX_METHODS: &[&str] = &[
+ "is_char_boundary",
+ "floor_char_boundary",
+ "ceil_char_boundary",
+ "get",
+ "index",
+ "index_mut",
+ "get_mut",
+ "get_unchecked",
+ "get_unchecked_mut",
+ "slice_unchecked",
+ "slice_mut_unchecked",
+ "split_at",
+ "split_at_mut",
+ "split_at_checked",
+ "split_at_mut_checked",
+];
+
+const CONTINUE: ControlFlow<!, ()> = ControlFlow::Continue(());
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'_>, iterable: &Expr<'_>, body: &'tcx Expr<'tcx>) {
+ if let ExprKind::MethodCall(_, enumerate_recv, _, enumerate_span) = iterable.kind
+ && let Some(method_id) = cx.typeck_results().type_dependent_def_id(iterable.hir_id)
+ && cx.tcx.is_diagnostic_item(sym::enumerate_method, method_id)
+ && let ExprKind::MethodCall(_, chars_recv, _, chars_span) = enumerate_recv.kind
+ && let Some(method_id) = cx.typeck_results().type_dependent_def_id(enumerate_recv.hir_id)
+ && cx.tcx.is_diagnostic_item(sym::str_chars, method_id)
+ {
+ if let PatKind::Tuple([pat, _], _) = pat.kind
+ && let PatKind::Binding(_, binding_id, ..) = pat.kind
+ {
+ // Destructured iterator element `(idx, _)`, look for uses of the binding
+ for_each_expr(cx, body, |expr| {
+ if path_to_local_id(expr, binding_id) {
+ check_index_usage(cx, expr, pat, enumerate_span, chars_span, chars_recv);
+ }
+ CONTINUE
+ });
+ } else if let PatKind::Binding(_, binding_id, ..) = pat.kind {
+ // Bound as a tuple, look for `tup.0`
+ for_each_expr(cx, body, |expr| {
+ if let ExprKind::Field(e, field) = expr.kind
+ && path_to_local_id(e, binding_id)
+ && field.name == sym::integer(0)
+ {
+ check_index_usage(cx, expr, pat, enumerate_span, chars_span, chars_recv);
+ }
+ CONTINUE
+ });
+ }
+ }
+}
+
+fn check_index_usage<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'tcx>,
+ pat: &Pat<'_>,
+ enumerate_span: Span,
+ chars_span: Span,
+ chars_recv: &Expr<'_>,
+) {
+ let Some(parent_expr) = index_consumed_at(cx, expr) else {
+ return;
+ };
+
+ let is_string_like = |ty: Ty<'_>| ty.is_str() || is_type_lang_item(cx, ty, LangItem::String);
+ let message = match parent_expr.kind {
+ ExprKind::MethodCall(segment, recv, ..)
+ // We currently only lint `str` methods (which `String` can deref to), so a `.is_str()` check is sufficient here
+ // (contrary to the `ExprKind::Index` case which needs to handle both with `is_string_like` because `String` implements
+ // `Index` directly and no deref to `str` would happen in that case).
+ if cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_str()
+ && BYTE_INDEX_METHODS.contains(&segment.ident.name.as_str())
+ && eq_expr_value(cx, chars_recv, recv) =>
+ {
+ "passing a character position to a method that expects a byte index"
+ },
+ ExprKind::Index(target, ..)
+ if is_string_like(cx.typeck_results().expr_ty_adjusted(target).peel_refs())
+ && eq_expr_value(cx, chars_recv, target) =>
+ {
+ "indexing into a string with a character position where a byte index is expected"
+ },
+ _ => return,
+ };
+
+ span_lint_hir_and_then(
+ cx,
+ CHAR_INDICES_AS_BYTE_INDICES,
+ expr.hir_id,
+ expr.span,
+ message,
+ |diag| {
+ diag.note("a character can take up more than one byte, so they are not interchangeable")
+ .span_note(
+ MultiSpan::from_spans(vec![pat.span, enumerate_span]),
+ "position comes from the enumerate iterator",
+ )
+ .span_suggestion_verbose(
+ chars_span.to(enumerate_span),
+ "consider using `.char_indices()` instead",
+ "char_indices()",
+ Applicability::MaybeIncorrect,
+ );
+ },
+ );
+}
+
+/// Returns the expression which ultimately consumes the index.
+/// This is usually the parent expression, i.e. `.split_at(idx)` for `idx`,
+/// but for `.get(..idx)` we want to consider the method call the consuming expression,
+/// which requires skipping past the range expression.
+fn index_consumed_at<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+ for (_, node) in cx.tcx.hir_parent_iter(expr.hir_id) {
+ match node {
+ Node::Expr(expr) if higher::Range::hir(expr).is_some() => {},
+ Node::ExprField(_) => {},
+ Node::Expr(expr) => return Some(expr),
+ _ => break,
+ }
+ }
+ None
+}
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index 412c78c..d0b26c9 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -2,6 +2,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sym;
use clippy_utils::ty::{
implements_trait, implements_trait_with_env, is_copy, is_type_lang_item, make_normalized_projection,
make_normalized_projection_with_regions, normalize_with_regions,
@@ -11,7 +12,6 @@
use rustc_lint::LateContext;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability};
use rustc_middle::ty::{self, EarlyBinder, Ty};
-use rustc_span::sym;
pub(super) fn check(
cx: &LateContext<'_>,
@@ -119,7 +119,7 @@ fn is_ref_iterable<'tcx>(
&& let typing_env = ty::TypingEnv::non_body_analysis(cx.tcx, fn_id)
&& implements_trait_with_env(cx.tcx, typing_env, req_self_ty, trait_id, Some(fn_id), &[])
&& let Some(into_iter_ty) =
- make_normalized_projection_with_regions(cx.tcx, typing_env, trait_id, sym!(IntoIter), [req_self_ty])
+ make_normalized_projection_with_regions(cx.tcx, typing_env, trait_id, sym::IntoIter, [req_self_ty])
&& let req_res_ty = normalize_with_regions(cx.tcx, typing_env, req_res_ty)
&& into_iter_ty == req_res_ty
{
@@ -152,7 +152,7 @@ fn is_ref_iterable<'tcx>(
// Using by value won't consume anything
if implements_trait(cx, self_ty, trait_id, &[])
&& let Some(ty) =
- make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty])
+ make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [self_ty])
&& ty == res_ty
{
return Some((AdjustKind::None, self_ty));
@@ -169,7 +169,7 @@ fn is_ref_iterable<'tcx>(
};
if implements_trait(cx, self_ty, trait_id, &[])
&& let Some(ty) =
- make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty])
+ make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [self_ty])
&& ty == res_ty
{
return Some((AdjustKind::reborrow(mutbl), self_ty));
@@ -183,7 +183,7 @@ fn is_ref_iterable<'tcx>(
let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, self_ty, mutbl);
if implements_trait(cx, self_ty, trait_id, &[])
&& let Some(ty) =
- make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [self_ty])
+ make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [self_ty])
&& ty == res_ty
{
return Some((AdjustKind::borrow(mutbl), self_ty));
@@ -206,7 +206,7 @@ fn is_ref_iterable<'tcx>(
&& target != self_ty
&& implements_trait(cx, target, trait_id, &[])
&& let Some(ty) =
- make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target])
+ make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [target])
&& ty == res_ty
{
Some((AdjustKind::auto_reborrow(mutbl), target))
@@ -224,7 +224,7 @@ fn is_ref_iterable<'tcx>(
if is_copy(cx, target)
&& implements_trait(cx, target, trait_id, &[])
&& let Some(ty) =
- make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target])
+ make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [target])
&& ty == res_ty
{
Some((AdjustKind::Deref, target))
@@ -242,7 +242,7 @@ fn is_ref_iterable<'tcx>(
if self_ty.is_ref()
&& implements_trait(cx, target, trait_id, &[])
&& let Some(ty) =
- make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym!(IntoIter), [target])
+ make_normalized_projection(cx.tcx, cx.typing_env(), trait_id, sym::IntoIter, [target])
&& ty == res_ty
{
Some((AdjustKind::auto_borrow(mutbl), target))
diff --git a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
index 185d834..e314bc2 100644
--- a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
@@ -13,45 +13,45 @@
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
let pat_span = pat.span;
- if let PatKind::Tuple(pat, _) = pat.kind {
- if pat.len() == 2 {
- let arg_span = arg.span;
- let (new_pat_span, kind, ty, mutbl) = match *cx.typeck_results().expr_ty(arg).kind() {
- ty::Ref(_, ty, mutbl) => match (&pat[0].kind, &pat[1].kind) {
- (key, _) if pat_is_wild(cx, key, body) => (pat[1].span, "value", ty, mutbl),
- (_, value) if pat_is_wild(cx, value, body) => (pat[0].span, "key", ty, Mutability::Not),
- _ => return,
- },
+ if let PatKind::Tuple(pat, _) = pat.kind
+ && pat.len() == 2
+ {
+ let arg_span = arg.span;
+ let (new_pat_span, kind, ty, mutbl) = match *cx.typeck_results().expr_ty(arg).kind() {
+ ty::Ref(_, ty, mutbl) => match (&pat[0].kind, &pat[1].kind) {
+ (key, _) if pat_is_wild(cx, key, body) => (pat[1].span, "value", ty, mutbl),
+ (_, value) if pat_is_wild(cx, value, body) => (pat[0].span, "key", ty, Mutability::Not),
_ => return,
- };
- let mutbl = match mutbl {
- Mutability::Not => "",
- Mutability::Mut => "_mut",
- };
- let arg = match arg.kind {
- ExprKind::AddrOf(BorrowKind::Ref, _, expr) => expr,
- _ => arg,
- };
+ },
+ _ => return,
+ };
+ let mutbl = match mutbl {
+ Mutability::Not => "",
+ Mutability::Mut => "_mut",
+ };
+ let arg = match arg.kind {
+ ExprKind::AddrOf(BorrowKind::Ref, _, expr) => expr,
+ _ => arg,
+ };
- if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap) {
- span_lint_and_then(
- cx,
- FOR_KV_MAP,
- arg_span,
- format!("you seem to want to iterate on a map's {kind}s"),
- |diag| {
- let map = sugg::Sugg::hir(cx, arg, "map");
- diag.multipart_suggestion(
- "use the corresponding method",
- vec![
- (pat_span, snippet(cx, new_pat_span, kind).into_owned()),
- (arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_par())),
- ],
- Applicability::MachineApplicable,
- );
- },
- );
- }
+ if is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap) {
+ span_lint_and_then(
+ cx,
+ FOR_KV_MAP,
+ arg_span,
+ format!("you seem to want to iterate on a map's {kind}s"),
+ |diag| {
+ let map = sugg::Sugg::hir(cx, arg, "map");
+ diag.multipart_suggestion(
+ "use the corresponding method",
+ vec![
+ (pat_span, snippet(cx, new_pat_span, kind).into_owned()),
+ (arg_span, format!("{}.{kind}s{mutbl}()", map.maybe_paren())),
+ ],
+ Applicability::MachineApplicable,
+ );
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
index aa8a293..35737f3 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
@@ -3,6 +3,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::implements_trait;
+use clippy_utils::usage::contains_return_break_continue_macro;
use clippy_utils::{higher, is_res_lang_ctor, path_res, peel_blocks_with_stmt};
use rustc_errors::Applicability;
use rustc_hir::def::Res;
@@ -35,6 +36,7 @@ pub(super) fn check<'tcx>(
&& let ExprKind::Call(ctor, [inner_ret]) = ret_value.kind
&& is_res_lang_ctor(cx, path_res(cx, ctor), LangItem::OptionSome)
&& path_res(cx, inner_ret) == Res::Local(binding_id)
+ && !contains_return_break_continue_macro(cond)
&& let Some((last_stmt, last_ret)) = last_stmt_and_ret(cx, expr)
{
let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index 701567a..d9c4b52 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -28,37 +28,37 @@ pub(super) fn check<'tcx>(
end: Some(end),
limits,
}) = higher::Range::hir(arg)
- {
// the var must be a single name
- if let PatKind::Binding(_, canonical_id, _, _) = pat.kind {
- let mut starts = vec![Start {
- id: canonical_id,
- kind: StartKind::Range,
- }];
+ && let PatKind::Binding(_, canonical_id, _, _) = pat.kind
+ {
+ let mut starts = vec![Start {
+ id: canonical_id,
+ kind: StartKind::Range,
+ }];
- // This is one of few ways to return different iterators
- // derived from: https://stackoverflow.com/questions/29760668/conditionally-iterate-over-one-of-several-possible-iterators/52064434#52064434
- let mut iter_a = None;
- let mut iter_b = None;
+ // This is one of few ways to return different iterators
+ // derived from: https://stackoverflow.com/questions/29760668/conditionally-iterate-over-one-of-several-possible-iterators/52064434#52064434
+ let mut iter_a = None;
+ let mut iter_b = None;
- if let ExprKind::Block(block, _) = body.kind {
- if let Some(loop_counters) = get_loop_counters(cx, block, expr) {
- starts.extend(loop_counters);
- }
- iter_a = Some(get_assignments(block, &starts));
- } else {
- iter_b = Some(get_assignment(body));
+ if let ExprKind::Block(block, _) = body.kind {
+ if let Some(loop_counters) = get_loop_counters(cx, block, expr) {
+ starts.extend(loop_counters);
}
+ iter_a = Some(get_assignments(block, &starts));
+ } else {
+ iter_b = Some(get_assignment(body));
+ }
- let assignments = iter_a.into_iter().flatten().chain(iter_b);
+ let assignments = iter_a.into_iter().flatten().chain(iter_b);
- let big_sugg = assignments
- // The only statements in the for loops can be indexed assignments from
- // indexed retrievals (except increments of loop counters).
- .map(|o| {
- o.and_then(|(lhs, rhs)| {
- let rhs = fetch_cloned_expr(rhs);
- if let ExprKind::Index(base_left, idx_left, _) = lhs.kind
+ let big_sugg = assignments
+ // The only statements in the for loops can be indexed assignments from
+ // indexed retrievals (except increments of loop counters).
+ .map(|o| {
+ o.and_then(|(lhs, rhs)| {
+ let rhs = fetch_cloned_expr(rhs);
+ if let ExprKind::Index(base_left, idx_left, _) = lhs.kind
&& let ExprKind::Index(base_right, idx_right, _) = rhs.kind
&& let Some(ty) = get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_left))
&& get_slice_like_element_ty(cx, cx.typeck_results().expr_ty(base_right)).is_some()
@@ -68,42 +68,41 @@ pub(super) fn check<'tcx>(
&& !local_used_in(cx, canonical_id, base_right)
// Source and destination must be different
&& path_to_local(base_left) != path_to_local(base_right)
- {
- Some((
- ty,
- IndexExpr {
- base: base_left,
- idx: start_left,
- idx_offset: offset_left,
- },
- IndexExpr {
- base: base_right,
- idx: start_right,
- idx_offset: offset_right,
- },
- ))
- } else {
- None
- }
- })
+ {
+ Some((
+ ty,
+ IndexExpr {
+ base: base_left,
+ idx: start_left,
+ idx_offset: offset_left,
+ },
+ IndexExpr {
+ base: base_right,
+ idx: start_right,
+ idx_offset: offset_right,
+ },
+ ))
+ } else {
+ None
+ }
})
- .map(|o| o.map(|(ty, dst, src)| build_manual_memcpy_suggestion(cx, start, end, limits, ty, &dst, &src)))
- .collect::<Option<Vec<_>>>()
- .filter(|v| !v.is_empty())
- .map(|v| v.join("\n "));
+ })
+ .map(|o| o.map(|(ty, dst, src)| build_manual_memcpy_suggestion(cx, start, end, limits, ty, &dst, &src)))
+ .collect::<Option<Vec<_>>>()
+ .filter(|v| !v.is_empty())
+ .map(|v| v.join("\n "));
- if let Some(big_sugg) = big_sugg {
- span_lint_and_sugg(
- cx,
- MANUAL_MEMCPY,
- expr.span,
- "it looks like you're manually copying between slices",
- "try replacing the loop by",
- big_sugg,
- Applicability::Unspecified,
- );
- return true;
- }
+ if let Some(big_sugg) = big_sugg {
+ span_lint_and_sugg(
+ cx,
+ MANUAL_MEMCPY,
+ expr.span,
+ "it looks like you're manually copying between slices",
+ "try replacing the loop by",
+ big_sugg,
+ Applicability::Unspecified,
+ );
+ return true;
}
}
false
@@ -184,7 +183,12 @@ fn print_offset(offset: MinifyingSugg<'static>) -> MinifyingSugg<'static> {
{
dst_base_str
} else {
- format!("{dst_base_str}[{}..{}]", dst_offset.maybe_par(), dst_limit.maybe_par()).into()
+ format!(
+ "{dst_base_str}[{}..{}]",
+ dst_offset.maybe_paren(),
+ dst_limit.maybe_paren()
+ )
+ .into()
};
let method_str = if is_copy(cx, elem_ty) {
@@ -196,7 +200,12 @@ fn print_offset(offset: MinifyingSugg<'static>) -> MinifyingSugg<'static> {
let src = if is_array_length_equal_to_range(cx, start, end, src.base) {
src_base_str
} else {
- format!("{src_base_str}[{}..{}]", src_offset.maybe_par(), src_limit.maybe_par()).into()
+ format!(
+ "{src_base_str}[{}..{}]",
+ src_offset.maybe_paren(),
+ src_limit.maybe_paren()
+ )
+ .into()
};
format!("{dst}.{method_str}(&{src});")
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
index 4473a33..9527e25 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs
@@ -81,15 +81,15 @@ fn check_local(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>,
}
fn check_call_arguments(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) {
- if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind {
- if let ExprKind::MethodCall(.., args, _) | ExprKind::Call(_, args) = expr.kind {
- let offending_arg = args
- .iter()
- .find_map(|arg| is_vec_pop_unwrap(cx, arg, is_empty_recv).then_some(arg.span));
+ if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind
+ && let ExprKind::MethodCall(.., args, _) | ExprKind::Call(_, args) = expr.kind
+ {
+ let offending_arg = args
+ .iter()
+ .find_map(|arg| is_vec_pop_unwrap(cx, arg, is_empty_recv).then_some(arg.span));
- if let Some(offending_arg) = offending_arg {
- report_lint(cx, offending_arg, PopStmt::Anonymous, loop_span, is_empty_recv.span);
- }
+ if let Some(offending_arg) = offending_arg {
+ report_lint(cx, offending_arg, PopStmt::Anonymous, loop_span, is_empty_recv.span);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 4b0bf5a..2b66827 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -1,3 +1,4 @@
+mod char_indices_as_byte_indices;
mod empty_loop;
mod explicit_counter_loop;
mod explicit_into_iter_loop;
@@ -740,6 +741,49 @@
"manually filling a slice with a value"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for usage of a character position yielded by `.chars().enumerate()` in a context where a **byte index** is expected,
+ /// such as an argument to a specific `str` method or indexing into a `str` or `String`.
+ ///
+ /// ### Why is this bad?
+ /// A character (more specifically, a Unicode scalar value) that is yielded by `str::chars` can take up multiple bytes,
+ /// so a character position does not necessarily have the same byte index at which the character is stored.
+ /// Thus, using the character position where a byte index is expected can unexpectedly return wrong values
+ /// or panic when the string consists of multibyte characters.
+ ///
+ /// For example, the character `a` in `äa` is stored at byte index 2 but has the character position 1.
+ /// Using the character position 1 to index into the string will lead to a panic as it is in the middle of the first character.
+ ///
+ /// Instead of `.chars().enumerate()`, the correct iterator to use is `.char_indices()`, which yields byte indices.
+ ///
+ /// This pattern is technically fine if the strings are known to only use the ASCII subset,
+ /// though in those cases it would be better to use `bytes()` directly to make the intent clearer,
+ /// but there is also no downside to just using `.char_indices()` directly and supporting non-ASCII strings.
+ ///
+ /// You may also want to read the [chapter on strings in the Rust Book](https://doc.rust-lang.org/book/ch08-02-strings.html)
+ /// which goes into this in more detail.
+ ///
+ /// ### Example
+ /// ```no_run
+ /// # let s = "...";
+ /// for (idx, c) in s.chars().enumerate() {
+ /// let _ = s[idx..]; // ⚠️ Panics for strings consisting of multibyte characters
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```no_run
+ /// # let s = "...";
+ /// for (idx, c) in s.char_indices() {
+ /// let _ = s[idx..];
+ /// }
+ /// ```
+ #[clippy::version = "1.83.0"]
+ pub CHAR_INDICES_AS_BYTE_INDICES,
+ correctness,
+ "using the character position yielded by `.chars().enumerate()` in a context where a byte index is expected"
+}
+
pub struct Loops {
msrv: Msrv,
enforce_iter_loop_reborrow: bool,
@@ -777,6 +821,7 @@ pub fn new(conf: &'static Conf) -> Self {
UNUSED_ENUMERATE_INDEX,
INFINITE_LOOP,
MANUAL_SLICE_FILL,
+ CHAR_INDICES_AS_BYTE_INDICES,
]);
impl<'tcx> LateLintPass<'tcx> for Loops {
@@ -860,6 +905,7 @@ fn check_for_loop<'tcx>(
manual_flatten::check(cx, pat, arg, body, span, self.msrv);
manual_find::check(cx, pat, arg, body, span, expr);
unused_enumerate_index::check(cx, pat, arg, body);
+ char_indices_as_byte_indices::check(cx, pat, arg, body);
}
fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index a24dd44..70ca452 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -82,14 +82,14 @@ fn consume(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
fn use_cloned(&mut self, _: &PlaceWithHirId<'tcx>, _: HirId) {}
fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId, bk: ty::BorrowKind) {
- if bk == ty::BorrowKind::Mutable {
- if let PlaceBase::Local(id) = cmt.place.base {
- if Some(id) == self.hir_id_low && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) {
- self.span_low = Some(self.cx.tcx.hir_span(diag_expr_id));
- }
- if Some(id) == self.hir_id_high && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) {
- self.span_high = Some(self.cx.tcx.hir_span(diag_expr_id));
- }
+ if bk == ty::BorrowKind::Mutable
+ && let PlaceBase::Local(id) = cmt.place.base
+ {
+ if Some(id) == self.hir_id_low && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) {
+ self.span_low = Some(self.cx.tcx.hir_span(diag_expr_id));
+ }
+ if Some(id) == self.hir_id_high && !BreakAfterExprVisitor::is_found(self.cx, diag_expr_id) {
+ self.span_high = Some(self.cx.tcx.hir_span(diag_expr_id));
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
index 0f62183..7837b18 100644
--- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs
@@ -31,155 +31,154 @@ pub(super) fn check<'tcx>(
ref end,
limits,
}) = higher::Range::hir(arg)
- {
// the var must be a single name
- if let PatKind::Binding(_, canonical_id, ident, _) = pat.kind {
- let mut visitor = VarVisitor {
- cx,
- var: canonical_id,
- indexed_mut: FxHashSet::default(),
- indexed_indirectly: FxHashMap::default(),
- indexed_directly: FxIndexMap::default(),
- referenced: FxHashSet::default(),
- nonindex: false,
- prefer_mutable: false,
+ && let PatKind::Binding(_, canonical_id, ident, _) = pat.kind
+ {
+ let mut visitor = VarVisitor {
+ cx,
+ var: canonical_id,
+ indexed_mut: FxHashSet::default(),
+ indexed_indirectly: FxHashMap::default(),
+ indexed_directly: FxIndexMap::default(),
+ referenced: FxHashSet::default(),
+ nonindex: false,
+ prefer_mutable: false,
+ };
+ walk_expr(&mut visitor, body);
+
+ // linting condition: we only indexed one variable, and indexed it directly
+ if visitor.indexed_indirectly.is_empty() && visitor.indexed_directly.len() == 1 {
+ let (indexed, (indexed_extent, indexed_ty)) = visitor
+ .indexed_directly
+ .into_iter()
+ .next()
+ .expect("already checked that we have exactly 1 element");
+
+ // ensure that the indexed variable was declared before the loop, see #601
+ if let Some(indexed_extent) = indexed_extent {
+ let parent_def_id = cx.tcx.hir_get_parent_item(expr.hir_id);
+ let region_scope_tree = cx.tcx.region_scope_tree(parent_def_id);
+ let pat_extent = region_scope_tree.var_scope(pat.hir_id.local_id).unwrap();
+ if region_scope_tree.is_subscope_of(indexed_extent, pat_extent) {
+ return;
+ }
+ }
+
+ // don't lint if the container that is indexed does not have .iter() method
+ let has_iter = has_iter_method(cx, indexed_ty);
+ if has_iter.is_none() {
+ return;
+ }
+
+ // don't lint if the container that is indexed into is also used without
+ // indexing
+ if visitor.referenced.contains(&indexed) {
+ return;
+ }
+
+ let starts_at_zero = is_integer_const(cx, start, 0);
+
+ let skip = if starts_at_zero {
+ String::new()
+ } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start, cx) {
+ return;
+ } else {
+ format!(".skip({})", snippet(cx, start.span, ".."))
};
- walk_expr(&mut visitor, body);
- // linting condition: we only indexed one variable, and indexed it directly
- if visitor.indexed_indirectly.is_empty() && visitor.indexed_directly.len() == 1 {
- let (indexed, (indexed_extent, indexed_ty)) = visitor
- .indexed_directly
- .into_iter()
- .next()
- .expect("already checked that we have exactly 1 element");
+ let mut end_is_start_plus_val = false;
- // ensure that the indexed variable was declared before the loop, see #601
- if let Some(indexed_extent) = indexed_extent {
- let parent_def_id = cx.tcx.hir_get_parent_item(expr.hir_id);
- let region_scope_tree = cx.tcx.region_scope_tree(parent_def_id);
- let pat_extent = region_scope_tree.var_scope(pat.hir_id.local_id).unwrap();
- if region_scope_tree.is_subscope_of(indexed_extent, pat_extent) {
- return;
+ let take = if let Some(end) = *end {
+ let mut take_expr = end;
+
+ if let ExprKind::Binary(ref op, left, right) = end.kind
+ && op.node == BinOpKind::Add
+ {
+ let start_equal_left = SpanlessEq::new(cx).eq_expr(start, left);
+ let start_equal_right = SpanlessEq::new(cx).eq_expr(start, right);
+
+ if start_equal_left {
+ take_expr = right;
+ } else if start_equal_right {
+ take_expr = left;
}
+
+ end_is_start_plus_val = start_equal_left | start_equal_right;
}
- // don't lint if the container that is indexed does not have .iter() method
- let has_iter = has_iter_method(cx, indexed_ty);
- if has_iter.is_none() {
- return;
- }
-
- // don't lint if the container that is indexed into is also used without
- // indexing
- if visitor.referenced.contains(&indexed) {
- return;
- }
-
- let starts_at_zero = is_integer_const(cx, start, 0);
-
- let skip = if starts_at_zero {
+ if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) {
String::new()
- } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, start, cx) {
+ } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr, cx) {
return;
} else {
- format!(".skip({})", snippet(cx, start.span, ".."))
- };
-
- let mut end_is_start_plus_val = false;
-
- let take = if let Some(end) = *end {
- let mut take_expr = end;
-
- if let ExprKind::Binary(ref op, left, right) = end.kind {
- if op.node == BinOpKind::Add {
- let start_equal_left = SpanlessEq::new(cx).eq_expr(start, left);
- let start_equal_right = SpanlessEq::new(cx).eq_expr(start, right);
-
- if start_equal_left {
- take_expr = right;
- } else if start_equal_right {
- take_expr = left;
- }
-
- end_is_start_plus_val = start_equal_left | start_equal_right;
- }
- }
-
- if is_len_call(end, indexed) || is_end_eq_array_len(cx, end, limits, indexed_ty) {
- String::new()
- } else if visitor.indexed_mut.contains(&indexed) && contains_name(indexed, take_expr, cx) {
- return;
- } else {
- match limits {
- ast::RangeLimits::Closed => {
- let take_expr = sugg::Sugg::hir(cx, take_expr, "<count>");
- format!(".take({})", take_expr + sugg::ONE)
- },
- ast::RangeLimits::HalfOpen => {
- format!(".take({})", snippet(cx, take_expr.span, ".."))
- },
- }
- }
- } else {
- String::new()
- };
-
- let (ref_mut, method) = if visitor.indexed_mut.contains(&indexed) {
- ("mut ", "iter_mut")
- } else {
- ("", "iter")
- };
-
- let take_is_empty = take.is_empty();
- let mut method_1 = take;
- let mut method_2 = skip;
-
- if end_is_start_plus_val {
- mem::swap(&mut method_1, &mut method_2);
- }
-
- if visitor.nonindex {
- span_lint_and_then(
- cx,
- NEEDLESS_RANGE_LOOP,
- arg.span,
- format!("the loop variable `{}` is used to index `{indexed}`", ident.name),
- |diag| {
- diag.multipart_suggestion(
- "consider using an iterator and enumerate()",
- vec![
- (pat.span, format!("({}, <item>)", ident.name)),
- (
- arg.span,
- format!("{indexed}.{method}().enumerate(){method_1}{method_2}"),
- ),
- ],
- Applicability::HasPlaceholders,
- );
+ match limits {
+ ast::RangeLimits::Closed => {
+ let take_expr = sugg::Sugg::hir(cx, take_expr, "<count>");
+ format!(".take({})", take_expr + sugg::ONE)
},
- );
- } else {
- let repl = if starts_at_zero && take_is_empty {
- format!("&{ref_mut}{indexed}")
- } else {
- format!("{indexed}.{method}(){method_1}{method_2}")
- };
-
- span_lint_and_then(
- cx,
- NEEDLESS_RANGE_LOOP,
- arg.span,
- format!("the loop variable `{}` is only used to index `{indexed}`", ident.name),
- |diag| {
- diag.multipart_suggestion(
- "consider using an iterator",
- vec![(pat.span, "<item>".to_string()), (arg.span, repl)],
- Applicability::HasPlaceholders,
- );
+ ast::RangeLimits::HalfOpen => {
+ format!(".take({})", snippet(cx, take_expr.span, ".."))
},
- );
+ }
}
+ } else {
+ String::new()
+ };
+
+ let (ref_mut, method) = if visitor.indexed_mut.contains(&indexed) {
+ ("mut ", "iter_mut")
+ } else {
+ ("", "iter")
+ };
+
+ let take_is_empty = take.is_empty();
+ let mut method_1 = take;
+ let mut method_2 = skip;
+
+ if end_is_start_plus_val {
+ mem::swap(&mut method_1, &mut method_2);
+ }
+
+ if visitor.nonindex {
+ span_lint_and_then(
+ cx,
+ NEEDLESS_RANGE_LOOP,
+ arg.span,
+ format!("the loop variable `{}` is used to index `{indexed}`", ident.name),
+ |diag| {
+ diag.multipart_suggestion(
+ "consider using an iterator and enumerate()",
+ vec![
+ (pat.span, format!("({}, <item>)", ident.name)),
+ (
+ arg.span,
+ format!("{indexed}.{method}().enumerate(){method_1}{method_2}"),
+ ),
+ ],
+ Applicability::HasPlaceholders,
+ );
+ },
+ );
+ } else {
+ let repl = if starts_at_zero && take_is_empty {
+ format!("&{ref_mut}{indexed}")
+ } else {
+ format!("{indexed}.{method}(){method_1}{method_2}")
+ };
+
+ span_lint_and_then(
+ cx,
+ NEEDLESS_RANGE_LOOP,
+ arg.span,
+ format!("the loop variable `{}` is only used to index `{indexed}`", ident.name),
+ |diag| {
+ diag.multipart_suggestion(
+ "consider using an iterator",
+ vec![(pat.span, "<item>".to_string()), (arg.span, repl)],
+ Applicability::HasPlaceholders,
+ );
+ },
+ );
}
}
}
@@ -346,10 +345,10 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
for expr in args {
let ty = self.cx.typeck_results().expr_ty_adjusted(expr);
self.prefer_mutable = false;
- if let ty::Ref(_, _, mutbl) = *ty.kind() {
- if mutbl == Mutability::Mut {
- self.prefer_mutable = true;
- }
+ if let ty::Ref(_, _, mutbl) = *ty.kind()
+ && mutbl == Mutability::Mut
+ {
+ self.prefer_mutable = true;
}
self.visit_expr(expr);
}
@@ -361,10 +360,10 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
iter::once(receiver).chain(args.iter()),
) {
self.prefer_mutable = false;
- if let ty::Ref(_, _, mutbl) = *ty.kind() {
- if mutbl == Mutability::Mut {
- self.prefer_mutable = true;
- }
+ if let ty::Ref(_, _, mutbl) = *ty.kind()
+ && mutbl == Mutability::Mut
+ {
+ self.prefer_mutable = true;
}
self.visit_expr(expr);
}
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index c3a2a38..69c84bc 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -244,10 +244,10 @@ fn never_loop_expr<'tcx>(
});
combine_seq(first, || {
// checks if break targets a block instead of a loop
- if let ExprKind::Break(Destination { target_id: Ok(t), .. }, _) = expr.kind {
- if let Some((_, reachable)) = local_labels.iter_mut().find(|(label, _)| *label == t) {
- *reachable = true;
- }
+ if let ExprKind::Break(Destination { target_id: Ok(t), .. }, _) = expr.kind
+ && let Some((_, reachable)) = local_labels.iter_mut().find(|(label, _)| *label == t)
+ {
+ *reachable = true;
}
NeverLoopResult::Diverging
})
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index 3c6fbef..2f6950b 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -3,9 +3,7 @@
use rustc_ast::ast::{LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{Visitor, walk_expr, walk_local};
-use rustc_hir::{
- AssignOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, LetStmt, Mutability, PatKind
-};
+use rustc_hir::{AssignOpKind, BorrowKind, Expr, ExprKind, HirId, HirIdMap, LetStmt, Mutability, PatKind};
use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, Ty};
@@ -265,7 +263,7 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic
if impls_iterator {
format!(
"{}",
- sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par()
+ sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_paren()
)
} else {
// (&x).into_iter() ==> x.iter()
@@ -283,12 +281,12 @@ pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic
};
format!(
"{}.{method_name}()",
- sugg::Sugg::hir_with_applicability(cx, caller, "_", applic_ref).maybe_par(),
+ sugg::Sugg::hir_with_applicability(cx, caller, "_", applic_ref).maybe_paren(),
)
},
_ => format!(
"{}.into_iter()",
- sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_par()
+ sugg::Sugg::hir_with_applicability(cx, arg, "_", applic_ref).maybe_paren()
),
}
}
diff --git a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
index df6e856..9071c9c 100644
--- a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
+++ b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
@@ -5,7 +5,8 @@
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{Visitor, walk_block, walk_expr, walk_stmt};
use rustc_hir::{BlockCheckMode, Expr, ExprKind, HirId, Stmt, UnsafeSource};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, Level, LintContext};
+use rustc_middle::lint::LevelAndSource;
use rustc_session::impl_lint_pass;
use rustc_span::{Span, SyntaxContext, sym};
use std::collections::BTreeMap;
@@ -249,6 +250,20 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
})
.flatten()
.copied()
+ .inspect(|&unsafe_block| {
+ if let LevelAndSource {
+ level: Level::Expect,
+ lint_id: Some(id),
+ ..
+ } = cx.tcx.lint_level_at_node(MACRO_METAVARS_IN_UNSAFE, unsafe_block)
+ {
+ // Since we're going to deduplicate expanded unsafe blocks by its enclosing macro definition soon,
+ // which would lead to unfulfilled `#[expect()]`s in all other unsafe blocks that are filtered out
+ // except for the one we emit the warning at, we must manually fulfill the lint
+ // for all unsafe blocks here.
+ cx.fulfill_expectation(id);
+ }
+ })
.map(|id| {
// Remove the syntax context to hide "in this macro invocation" in the diagnostic.
// The invocation doesn't matter. Also we want to dedupe by the unsafe block and not by anything
diff --git a/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
new file mode 100644
index 0000000..c515e41
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_abs_diff.rs
@@ -0,0 +1,152 @@
+use clippy_config::Conf;
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::higher::If;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::source::HasSession as _;
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::{eq_expr_value, peel_blocks, span_contains_comment};
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{self, Ty};
+use rustc_session::impl_lint_pass;
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Detects patterns like `if a > b { a - b } else { b - a }` and suggests using `a.abs_diff(b)`.
+ ///
+ /// ### Why is this bad?
+ /// Using `abs_diff` is shorter, more readable, and avoids control flow.
+ ///
+ /// ### Examples
+ /// ```no_run
+ /// # let (a, b) = (5_usize, 3_usize);
+ /// if a > b {
+ /// a - b
+ /// } else {
+ /// b - a
+ /// }
+ /// # ;
+ /// ```
+ /// Use instead:
+ /// ```no_run
+ /// # let (a, b) = (5_usize, 3_usize);
+ /// a.abs_diff(b)
+ /// # ;
+ /// ```
+ #[clippy::version = "1.86.0"]
+ pub MANUAL_ABS_DIFF,
+ complexity,
+ "using an if-else pattern instead of `abs_diff`"
+}
+
+impl_lint_pass!(ManualAbsDiff => [MANUAL_ABS_DIFF]);
+
+pub struct ManualAbsDiff {
+ msrv: Msrv,
+}
+
+impl ManualAbsDiff {
+ pub fn new(conf: &'static Conf) -> Self {
+ Self { msrv: conf.msrv }
+ }
+}
+
+impl<'tcx> LateLintPass<'tcx> for ManualAbsDiff {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+ if !expr.span.from_expansion()
+ && let Some(if_expr) = If::hir(expr)
+ && let Some(r#else) = if_expr.r#else
+ && let ExprKind::Binary(op, rhs, lhs) = if_expr.cond.kind
+ && let (BinOpKind::Gt | BinOpKind::Ge, mut a, mut b) | (BinOpKind::Lt | BinOpKind::Le, mut b, mut a) =
+ (op.node, rhs, lhs)
+ && let Some(ty) = self.are_ty_eligible(cx, a, b)
+ && is_sub_expr(cx, if_expr.then, a, b, ty)
+ && is_sub_expr(cx, r#else, b, a, ty)
+ {
+ span_lint_and_then(
+ cx,
+ MANUAL_ABS_DIFF,
+ expr.span,
+ "manual absolute difference pattern without using `abs_diff`",
+ |diag| {
+ if is_unsuffixed_numeral_lit(a) && !is_unsuffixed_numeral_lit(b) {
+ (a, b) = (b, a);
+ }
+ let applicability = {
+ let source_map = cx.sess().source_map();
+ if span_contains_comment(source_map, if_expr.then.span)
+ || span_contains_comment(source_map, r#else.span)
+ {
+ Applicability::MaybeIncorrect
+ } else {
+ Applicability::MachineApplicable
+ }
+ };
+ let sugg = format!(
+ "{}.abs_diff({})",
+ Sugg::hir(cx, a, "..").maybe_paren(),
+ Sugg::hir(cx, b, "..")
+ );
+ diag.span_suggestion(expr.span, "replace with `abs_diff`", sugg, applicability);
+ },
+ );
+ }
+ }
+}
+
+impl ManualAbsDiff {
+ /// Returns a type if `a` and `b` are both of it, and this lint can be applied to that
+ /// type (currently, any primitive int, or a `Duration`)
+ fn are_ty_eligible<'tcx>(&self, cx: &LateContext<'tcx>, a: &Expr<'_>, b: &Expr<'_>) -> Option<Ty<'tcx>> {
+ let is_int = |ty: Ty<'_>| matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) && self.msrv.meets(cx, msrvs::ABS_DIFF);
+ let is_duration =
+ |ty| is_type_diagnostic_item(cx, ty, sym::Duration) && self.msrv.meets(cx, msrvs::DURATION_ABS_DIFF);
+
+ let a_ty = cx.typeck_results().expr_ty(a).peel_refs();
+ (a_ty == cx.typeck_results().expr_ty(b).peel_refs() && (is_int(a_ty) || is_duration(a_ty))).then_some(a_ty)
+ }
+}
+
+/// Checks if the given expression is a subtraction operation between two expected expressions,
+/// i.e. if `expr` is `{expected_a} - {expected_b}`.
+///
+/// If `expected_ty` is a signed primitive integer, this function will only return `Some` if the
+/// subtraction expr is wrapped in a cast to the equivalent unsigned int.
+fn is_sub_expr(
+ cx: &LateContext<'_>,
+ expr: &Expr<'_>,
+ expected_a: &Expr<'_>,
+ expected_b: &Expr<'_>,
+ expected_ty: Ty<'_>,
+) -> bool {
+ let expr = peel_blocks(expr).kind;
+
+ if let ty::Int(ty) = expected_ty.kind() {
+ let unsigned = Ty::new_uint(cx.tcx, ty.to_unsigned());
+
+ return if let ExprKind::Cast(expr, cast_ty) = expr
+ && cx.typeck_results().node_type(cast_ty.hir_id) == unsigned
+ {
+ is_sub_expr(cx, expr, expected_a, expected_b, unsigned)
+ } else {
+ false
+ };
+ }
+
+ if let ExprKind::Binary(op, a, b) = expr
+ && let BinOpKind::Sub = op.node
+ && eq_expr_value(cx, a, expected_a)
+ && eq_expr_value(cx, b, expected_b)
+ {
+ true
+ } else {
+ false
+ }
+}
+
+fn is_unsuffixed_numeral_lit(expr: &Expr<'_>) -> bool {
+ matches!(expr.kind, ExprKind::Lit(lit) if lit.node.is_numeric() && lit.node.is_unsuffixed())
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index 83c16d4..8378e15 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -60,7 +60,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
ExprKind::Unary(UnOp::Not, e) => (e, ""),
_ => (cond, "!"),
};
- let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
+ let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_paren();
let semicolon = if is_parent_stmt(cx, expr.hir_id) { ";" } else { "" };
let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip}){semicolon}");
// we show to the user the suggestion without the comments, but when applying the fix, include the
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
index 50c8331..02afe9f 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -181,7 +181,7 @@ fn maybe_emit_suggestion<'tcx>(cx: &LateContext<'tcx>, suggestion: &ClampSuggest
make_assignment,
hir_with_ignore_attr,
} = suggestion;
- let input = Sugg::hir(cx, input, "..").maybe_par();
+ let input = Sugg::hir(cx, input, "..").maybe_paren();
let min = Sugg::hir(cx, min, "..");
let max = Sugg::hir(cx, max, "..");
let semicolon = if make_assignment.is_some() { ";" } else { "" };
diff --git a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
index 9944c4f..444ecd5 100644
--- a/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_div_ceil.rs
@@ -1,8 +1,9 @@
-use clippy_utils::SpanlessEq;
+use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::{Sugg, has_enclosing_paren};
+use clippy_utils::{SpanlessEq, sym};
use rustc_ast::{BinOpKind, LitIntType, LitKind, UnOp};
use rustc_data_structures::packed::Pu128;
use rustc_errors::Applicability;
@@ -11,9 +12,6 @@
use rustc_middle::ty::{self};
use rustc_session::impl_lint_pass;
use rustc_span::source_map::Spanned;
-use rustc_span::symbol::Symbol;
-
-use clippy_config::Conf;
declare_clippy_lint! {
/// ### What it does
@@ -141,8 +139,7 @@ fn check_int_ty_and_feature(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let expr_ty = cx.typeck_results().expr_ty(expr);
match expr_ty.peel_refs().kind() {
ty::Uint(_) => true,
- ty::Int(_) => cx.tcx.features().enabled(Symbol::intern("int_roundings")),
-
+ ty::Int(_) => cx.tcx.features().enabled(sym::int_roundings),
_ => false,
}
}
@@ -167,7 +164,7 @@ fn build_suggestion(
rhs: &Expr<'_>,
applicability: &mut Applicability,
) {
- let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_par();
+ let dividend_sugg = Sugg::hir_with_applicability(cx, lhs, "..", applicability).maybe_paren();
let type_suffix = if cx.typeck_results().expr_ty(lhs).is_numeric()
&& matches!(
lhs.kind,
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
index faf01a2..8ab49bd 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -148,7 +148,7 @@ fn check_is_ascii(
};
let default_snip = "..";
let mut app = Applicability::MachineApplicable;
- let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_par();
+ let recv = Sugg::hir_with_context(cx, recv, span.ctxt(), default_snip, &mut app).maybe_paren();
let mut suggestion = vec![(span, format!("{recv}.{sugg}()"))];
if let Some((ty_span, ty)) = ty_sugg {
suggestion.push((ty_span, format!("{recv}: {ty}")));
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs b/src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs
index 841adfe..b4cd988 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_power_of_two.rs
@@ -1,13 +1,14 @@
-use clippy_utils::SpanlessEq;
+use clippy_config::Conf;
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet_with_applicability;
-use rustc_ast::LitKind;
-use rustc_data_structures::packed::Pu128;
+use clippy_utils::msrvs::{self, Msrv};
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::ty_from_hir_ty;
+use clippy_utils::{SpanlessEq, is_in_const_context, is_integer_literal};
use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind};
+use rustc_hir::{BinOpKind, Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::Uint;
-use rustc_session::declare_lint_pass;
+use rustc_middle::ty;
+use rustc_session::impl_lint_pass;
declare_clippy_lint! {
/// ### What it does
@@ -33,112 +34,111 @@
"manually reimplementing `is_power_of_two`"
}
-declare_lint_pass!(ManualIsPowerOfTwo => [MANUAL_IS_POWER_OF_TWO]);
+pub struct ManualIsPowerOfTwo {
+ msrv: Msrv,
+}
-impl LateLintPass<'_> for ManualIsPowerOfTwo {
- fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
+impl_lint_pass!(ManualIsPowerOfTwo => [MANUAL_IS_POWER_OF_TWO]);
+
+impl ManualIsPowerOfTwo {
+ pub fn new(conf: &'static Conf) -> Self {
+ Self { msrv: conf.msrv }
+ }
+
+ fn build_sugg(&self, cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) {
+ if is_in_const_context(cx) && !self.msrv.meets(cx, msrvs::CONST_IS_POWER_OF_TWO) {
+ return;
+ }
+
let mut applicability = Applicability::MachineApplicable;
+ let snippet = Sugg::hir_with_applicability(cx, receiver, "_", &mut applicability);
- if let ExprKind::Binary(bin_op, left, right) = expr.kind
- && bin_op.node == BinOpKind::Eq
+ span_lint_and_sugg(
+ cx,
+ MANUAL_IS_POWER_OF_TWO,
+ expr.span,
+ "manually reimplementing `is_power_of_two`",
+ "consider using `.is_power_of_two()`",
+ format!("{}.is_power_of_two()", snippet.maybe_paren()),
+ applicability,
+ );
+ }
+}
+
+impl<'tcx> LateLintPass<'tcx> for ManualIsPowerOfTwo {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+ if !expr.span.from_expansion()
+ && let Some((lhs, rhs)) = unexpanded_binop_operands(expr, BinOpKind::Eq)
{
- // a.count_ones() == 1
- if let ExprKind::MethodCall(method_name, receiver, [], _) = left.kind
- && method_name.ident.as_str() == "count_ones"
- && let &Uint(_) = cx.typeck_results().expr_ty(receiver).kind()
- && check_lit(right, 1)
+ if let Some(a) = count_ones_receiver(cx, lhs)
+ && is_integer_literal(rhs, 1)
{
- build_sugg(cx, expr, receiver, &mut applicability);
- }
-
- // 1 == a.count_ones()
- if let ExprKind::MethodCall(method_name, receiver, [], _) = right.kind
- && method_name.ident.as_str() == "count_ones"
- && let &Uint(_) = cx.typeck_results().expr_ty(receiver).kind()
- && check_lit(left, 1)
+ self.build_sugg(cx, expr, a);
+ } else if let Some(a) = count_ones_receiver(cx, rhs)
+ && is_integer_literal(lhs, 1)
{
- build_sugg(cx, expr, receiver, &mut applicability);
- }
-
- // a & (a - 1) == 0
- if let ExprKind::Binary(op1, left1, right1) = left.kind
- && op1.node == BinOpKind::BitAnd
- && let ExprKind::Binary(op2, left2, right2) = right1.kind
- && op2.node == BinOpKind::Sub
- && check_eq_expr(cx, left1, left2)
- && let &Uint(_) = cx.typeck_results().expr_ty(left1).kind()
- && check_lit(right2, 1)
- && check_lit(right, 0)
+ self.build_sugg(cx, expr, a);
+ } else if is_integer_literal(rhs, 0)
+ && let Some(a) = is_and_minus_one(cx, lhs)
{
- build_sugg(cx, expr, left1, &mut applicability);
- }
-
- // (a - 1) & a == 0;
- if let ExprKind::Binary(op1, left1, right1) = left.kind
- && op1.node == BinOpKind::BitAnd
- && let ExprKind::Binary(op2, left2, right2) = left1.kind
- && op2.node == BinOpKind::Sub
- && check_eq_expr(cx, right1, left2)
- && let &Uint(_) = cx.typeck_results().expr_ty(right1).kind()
- && check_lit(right2, 1)
- && check_lit(right, 0)
+ self.build_sugg(cx, expr, a);
+ } else if is_integer_literal(lhs, 0)
+ && let Some(a) = is_and_minus_one(cx, rhs)
{
- build_sugg(cx, expr, right1, &mut applicability);
- }
-
- // 0 == a & (a - 1);
- if let ExprKind::Binary(op1, left1, right1) = right.kind
- && op1.node == BinOpKind::BitAnd
- && let ExprKind::Binary(op2, left2, right2) = right1.kind
- && op2.node == BinOpKind::Sub
- && check_eq_expr(cx, left1, left2)
- && let &Uint(_) = cx.typeck_results().expr_ty(left1).kind()
- && check_lit(right2, 1)
- && check_lit(left, 0)
- {
- build_sugg(cx, expr, left1, &mut applicability);
- }
-
- // 0 == (a - 1) & a
- if let ExprKind::Binary(op1, left1, right1) = right.kind
- && op1.node == BinOpKind::BitAnd
- && let ExprKind::Binary(op2, left2, right2) = left1.kind
- && op2.node == BinOpKind::Sub
- && check_eq_expr(cx, right1, left2)
- && let &Uint(_) = cx.typeck_results().expr_ty(right1).kind()
- && check_lit(right2, 1)
- && check_lit(left, 0)
- {
- build_sugg(cx, expr, right1, &mut applicability);
+ self.build_sugg(cx, expr, a);
}
}
}
}
-fn build_sugg(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, applicability: &mut Applicability) {
- let snippet = snippet_with_applicability(cx, receiver.span, "..", applicability);
-
- span_lint_and_sugg(
- cx,
- MANUAL_IS_POWER_OF_TWO,
- expr.span,
- "manually reimplementing `is_power_of_two`",
- "consider using `.is_power_of_two()`",
- format!("{snippet}.is_power_of_two()"),
- *applicability,
- );
-}
-
-fn check_lit(expr: &Expr<'_>, expected_num: u128) -> bool {
- if let ExprKind::Lit(lit) = expr.kind
- && let LitKind::Int(Pu128(num), _) = lit.node
- && num == expected_num
+/// Return the unsigned integer receiver of `.count_ones()` or the argument of
+/// `<int-type>::count_ones(…)`.
+fn count_ones_receiver<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+ let (method, ty, receiver) = if let ExprKind::MethodCall(method_name, receiver, [], _) = expr.kind {
+ (method_name, cx.typeck_results().expr_ty_adjusted(receiver), receiver)
+ } else if let ExprKind::Call(func, [arg]) = expr.kind
+ && let ExprKind::Path(QPath::TypeRelative(ty, func_name)) = func.kind
{
- return true;
- }
- false
+ (func_name, ty_from_hir_ty(cx, ty), arg)
+ } else {
+ return None;
+ };
+ (method.ident.as_str() == "count_ones" && matches!(ty.kind(), ty::Uint(_))).then_some(receiver)
}
-fn check_eq_expr(cx: &LateContext<'_>, lhs: &Expr<'_>, rhs: &Expr<'_>) -> bool {
- SpanlessEq::new(cx).eq_expr(lhs, rhs)
+/// Return `greater` if `smaller == greater - 1`
+fn is_one_less<'tcx>(
+ cx: &LateContext<'tcx>,
+ greater: &'tcx Expr<'tcx>,
+ smaller: &Expr<'tcx>,
+) -> Option<&'tcx Expr<'tcx>> {
+ if let Some((lhs, rhs)) = unexpanded_binop_operands(smaller, BinOpKind::Sub)
+ && SpanlessEq::new(cx).eq_expr(greater, lhs)
+ && is_integer_literal(rhs, 1)
+ && matches!(cx.typeck_results().expr_ty_adjusted(greater).kind(), ty::Uint(_))
+ {
+ Some(greater)
+ } else {
+ None
+ }
+}
+
+/// Return `v` if `expr` is `v & (v - 1)` or `(v - 1) & v`
+fn is_and_minus_one<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+ let (lhs, rhs) = unexpanded_binop_operands(expr, BinOpKind::BitAnd)?;
+ is_one_less(cx, lhs, rhs).or_else(|| is_one_less(cx, rhs, lhs))
+}
+
+/// Return the operands of the `expr` binary operation if the operator is `op` and none of the
+/// operands come from expansion.
+fn unexpanded_binop_operands<'hir>(expr: &Expr<'hir>, op: BinOpKind) -> Option<(&'hir Expr<'hir>, &'hir Expr<'hir>)> {
+ if let ExprKind::Binary(binop, lhs, rhs) = expr.kind
+ && binop.node == op
+ && !lhs.span.from_expansion()
+ && !rhs.span.from_expansion()
+ {
+ Some((lhs, rhs))
+ } else {
+ None
+ }
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
index 8dee29b..e4ad395 100644
--- a/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_option_as_slice.rs
@@ -34,7 +34,7 @@
/// _ = opt.as_slice();
/// _ = opt.as_slice();
/// ```
- #[clippy::version = "1.85.0"]
+ #[clippy::version = "1.86.0"]
pub MANUAL_OPTION_AS_SLICE,
complexity,
"manual `Option::as_slice`"
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 16dd1ad..98e8b1f 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -92,10 +92,10 @@ fn check_into_iter(
&& let [filter_params] = filter_body.params
{
if match_map_type(cx, left_expr) {
- if let hir::PatKind::Tuple([key_pat, value_pat], _) = filter_params.pat.kind {
- if let Some(sugg) = make_sugg(cx, key_pat, value_pat, left_expr, filter_body) {
- make_span_lint_and_sugg(cx, parent_expr_span, sugg);
- }
+ if let hir::PatKind::Tuple([key_pat, value_pat], _) = filter_params.pat.kind
+ && let Some(sugg) = make_sugg(cx, key_pat, value_pat, left_expr, filter_body)
+ {
+ make_span_lint_and_sugg(cx, parent_expr_span, sugg);
}
// Cannot lint other cases because `retain` requires two parameters
} else {
@@ -196,22 +196,21 @@ fn check_to_owned(
&& let filter_body = cx.tcx.hir_body(closure.body)
&& let [filter_params] = filter_body.params
&& msrv.meets(cx, msrvs::STRING_RETAIN)
+ && let hir::PatKind::Ref(pat, _) = filter_params.pat.kind
{
- if let hir::PatKind::Ref(pat, _) = filter_params.pat.kind {
- make_span_lint_and_sugg(
- cx,
- parent_expr_span,
- format!(
- "{}.retain(|{}| {})",
- snippet(cx, left_expr.span, ".."),
- snippet(cx, pat.span, ".."),
- snippet(cx, filter_body.value.span, "..")
- ),
- );
- }
- // Be conservative now. Do nothing for the `Binding` case.
- // TODO: Ideally, we can rewrite the lambda by stripping one level of reference
+ make_span_lint_and_sugg(
+ cx,
+ parent_expr_span,
+ format!(
+ "{}.retain(|{}| {})",
+ snippet(cx, left_expr.span, ".."),
+ snippet(cx, pat.span, ".."),
+ snippet(cx, filter_body.value.span, "..")
+ ),
+ );
}
+ // Be conservative now. Do nothing for the `Binding` case.
+ // TODO: Ideally, we can rewrite the lambda by stripping one level of reference
}
fn make_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/manual_rotate.rs b/src/tools/clippy/clippy_lints/src/manual_rotate.rs
index 07537fc..06ee00c 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rotate.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rotate.rs
@@ -101,7 +101,7 @@ fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
(r_shift_dir, r_amount)
};
let mut applicability = Applicability::MachineApplicable;
- let expr_sugg = sugg::Sugg::hir_with_applicability(cx, l_expr, "_", &mut applicability).maybe_par();
+ let expr_sugg = sugg::Sugg::hir_with_applicability(cx, l_expr, "_", &mut applicability).maybe_paren();
span_lint_and_sugg(
cx,
MANUAL_ROTATE,
diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
index 5c2a711..7ca3b71 100644
--- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
@@ -113,15 +113,14 @@ fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, arg: &Expr<'_>)
&& is_expr_kind_empty_str(&arg.kind)
{
warn_then_suggest(cx, span);
- } else if let QPath::Resolved(_, path) = qpath {
+ } else if let QPath::Resolved(_, path) = qpath
// From::from(...) or TryFrom::try_from(...)
- if let [path_seg1, path_seg2] = path.segments
- && is_expr_kind_empty_str(&arg.kind)
- && ((path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from)
- || (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from))
- {
- warn_then_suggest(cx, span);
- }
+ && let [path_seg1, path_seg2] = path.segments
+ && is_expr_kind_empty_str(&arg.kind)
+ && ((path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from)
+ || (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from))
+ {
+ warn_then_suggest(cx, span);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
deleted file mode 100644
index 87d2faa..0000000
--- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
+++ /dev/null
@@ -1,212 +0,0 @@
-use rustc_errors::Applicability;
-use rustc_hir::def::Res;
-use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::ty::GenericArgKind;
-use rustc_session::declare_lint_pass;
-use rustc_span::sym;
-
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::higher::IfLetOrMatch;
-use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{expr_type_is_certain, implements_trait};
-use clippy_utils::{is_default_equivalent, is_in_const_context, path_res, peel_blocks, span_contains_comment};
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks if a `match` or `if let` expression can be simplified using
- /// `.unwrap_or_default()`.
- ///
- /// ### Why is this bad?
- /// It can be done in one call with `.unwrap_or_default()`.
- ///
- /// ### Example
- /// ```no_run
- /// let x: Option<String> = Some(String::new());
- /// let y: String = match x {
- /// Some(v) => v,
- /// None => String::new(),
- /// };
- ///
- /// let x: Option<Vec<String>> = Some(Vec::new());
- /// let y: Vec<String> = if let Some(v) = x {
- /// v
- /// } else {
- /// Vec::new()
- /// };
- /// ```
- /// Use instead:
- /// ```no_run
- /// let x: Option<String> = Some(String::new());
- /// let y: String = x.unwrap_or_default();
- ///
- /// let x: Option<Vec<String>> = Some(Vec::new());
- /// let y: Vec<String> = x.unwrap_or_default();
- /// ```
- #[clippy::version = "1.79.0"]
- pub MANUAL_UNWRAP_OR_DEFAULT,
- suspicious,
- "check if a `match` or `if let` can be simplified with `unwrap_or_default`"
-}
-
-declare_lint_pass!(ManualUnwrapOrDefault => [MANUAL_UNWRAP_OR_DEFAULT]);
-
-fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<HirId> {
- if let PatKind::TupleStruct(QPath::Resolved(_, path), &[pat], _) = pat.kind
- && let PatKind::Binding(_, pat_id, _, _) = pat.kind
- && let Some(def_id) = path.res.opt_def_id()
- // Since it comes from a pattern binding, we need to get the parent to actually match
- // against it.
- && let Some(def_id) = cx.tcx.opt_parent(def_id)
- && (cx.tcx.lang_items().get(LangItem::OptionSome) == Some(def_id)
- || cx.tcx.lang_items().get(LangItem::ResultOk) == Some(def_id))
- {
- Some(pat_id)
- } else {
- None
- }
-}
-
-fn get_none<'tcx>(cx: &LateContext<'tcx>, arm: &Arm<'tcx>) -> Option<&'tcx Expr<'tcx>> {
- if let PatKind::Expr(PatExpr { kind: PatExprKind::Path(QPath::Resolved(_, path)), .. }) = arm.pat.kind
- && let Some(def_id) = path.res.opt_def_id()
- // Since it comes from a pattern binding, we need to get the parent to actually match
- // against it.
- && let Some(def_id) = cx.tcx.opt_parent(def_id)
- && cx.tcx.lang_items().get(LangItem::OptionNone) == Some(def_id)
- {
- Some(arm.body)
- } else if let PatKind::TupleStruct(QPath::Resolved(_, path), _, _)= arm.pat.kind
- && let Some(def_id) = path.res.opt_def_id()
- // Since it comes from a pattern binding, we need to get the parent to actually match
- // against it.
- && let Some(def_id) = cx.tcx.opt_parent(def_id)
- && cx.tcx.lang_items().get(LangItem::ResultErr) == Some(def_id)
- {
- Some(arm.body)
- } else if let PatKind::Wild = arm.pat.kind {
- // We consider that the `Some` check will filter it out if it's not right.
- Some(arm.body)
- } else {
- None
- }
-}
-
-fn get_some_and_none_bodies<'tcx>(
- cx: &LateContext<'tcx>,
- arm1: &'tcx Arm<'tcx>,
- arm2: &'tcx Arm<'tcx>,
-) -> Option<((&'tcx Expr<'tcx>, HirId), &'tcx Expr<'tcx>)> {
- if let Some(binding_id) = get_some(cx, arm1.pat)
- && let Some(body_none) = get_none(cx, arm2)
- {
- Some(((arm1.body, binding_id), body_none))
- } else if let Some(binding_id) = get_some(cx, arm2.pat)
- && let Some(body_none) = get_none(cx, arm1)
- {
- Some(((arm2.body, binding_id), body_none))
- } else {
- None
- }
-}
-
-#[allow(clippy::needless_pass_by_value)]
-fn handle<'tcx>(cx: &LateContext<'tcx>, if_let_or_match: IfLetOrMatch<'tcx>, expr: &'tcx Expr<'tcx>) {
- // Get expr_name ("if let" or "match" depending on kind of expression), the condition, the body for
- // the some arm, the body for the none arm and the binding id of the some arm
- let (expr_name, condition, body_some, body_none, binding_id) = match if_let_or_match {
- IfLetOrMatch::Match(condition, [arm1, arm2], MatchSource::Normal | MatchSource::ForLoopDesugar)
- // Make sure there are no guards to keep things simple
- if arm1.guard.is_none()
- && arm2.guard.is_none()
- // Get the some and none bodies and the binding id of the some arm
- && let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2) =>
- {
- ("match", condition, body_some, body_none, binding_id)
- },
- IfLetOrMatch::IfLet(condition, pat, if_expr, Some(else_expr), _)
- if let Some(binding_id) = get_some(cx, pat) =>
- {
- ("if let", condition, if_expr, else_expr, binding_id)
- },
- _ => {
- // All other cases (match with number of arms != 2, if let without else, etc.)
- return;
- },
- };
-
- // We check if the return type of the expression implements Default.
- let expr_type = cx.typeck_results().expr_ty(expr);
- if let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default)
- && implements_trait(cx, expr_type, default_trait_id, &[])
- // We check if the initial condition implements Default.
- && let Some(condition_ty) = cx.typeck_results().expr_ty(condition).walk().nth(1)
- && let GenericArgKind::Type(condition_ty) = condition_ty.unpack()
- && implements_trait(cx, condition_ty, default_trait_id, &[])
- // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`.
- && let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(body_some).kind
- && let Res::Local(local_id) = path.res
- && local_id == binding_id
- // We now check the `None` arm is calling a method equivalent to `Default::default`.
- && let body_none = peel_blocks(body_none)
- && is_default_equivalent(cx, body_none)
- && let Some(receiver) = Sugg::hir_opt(cx, condition).map(Sugg::maybe_par)
- {
- // Machine applicable only if there are no comments present
- let applicability = if span_contains_comment(cx.sess().source_map(), expr.span) {
- Applicability::MaybeIncorrect
- } else {
- Applicability::MachineApplicable
- };
-
- // We now check if the condition is a None variant, in which case we need to specify the type
- if path_res(cx, condition)
- .opt_def_id()
- .is_some_and(|id| Some(cx.tcx.parent(id)) == cx.tcx.lang_items().option_none_variant())
- {
- return span_lint_and_sugg(
- cx,
- MANUAL_UNWRAP_OR_DEFAULT,
- expr.span,
- format!("{expr_name} can be simplified with `.unwrap_or_default()`"),
- "replace it with",
- format!("{receiver}::<{expr_type}>.unwrap_or_default()"),
- applicability,
- );
- }
-
- // We check if the expression type is still uncertain, in which case we ask the user to specify it
- if !expr_type_is_certain(cx, condition) {
- return span_lint_and_sugg(
- cx,
- MANUAL_UNWRAP_OR_DEFAULT,
- expr.span,
- format!("{expr_name} can be simplified with `.unwrap_or_default()`"),
- format!("ascribe the type {expr_type} and replace your expression with"),
- format!("{receiver}.unwrap_or_default()"),
- Applicability::Unspecified,
- );
- }
-
- span_lint_and_sugg(
- cx,
- MANUAL_UNWRAP_OR_DEFAULT,
- expr.span,
- format!("{expr_name} can be simplified with `.unwrap_or_default()`"),
- "replace it with",
- format!("{receiver}.unwrap_or_default()"),
- applicability,
- );
- }
-}
-
-impl<'tcx> LateLintPass<'tcx> for ManualUnwrapOrDefault {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
- if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, expr)
- && !expr.span.from_expansion()
- && !is_in_const_context(cx)
- {
- handle(cx, if_let_or_match, expr);
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index 56aead85..b607f81 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -101,10 +101,10 @@ fn is_unit_type(ty: Ty<'_>) -> bool {
fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
let ty = cx.typeck_results().expr_ty(expr);
- if let ty::FnDef(id, _) = *ty.kind() {
- if let Some(fn_type) = cx.tcx.fn_sig(id).instantiate_identity().no_bound_vars() {
- return is_unit_type(fn_type.output());
- }
+ if let ty::FnDef(id, _) = *ty.kind()
+ && let Some(fn_type) = cx.tcx.fn_sig(id).instantiate_identity().no_bound_vars()
+ {
+ return is_unit_type(fn_type.output());
}
false
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
index 6f446bf..5b50efa 100644
--- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
@@ -1,4 +1,4 @@
-use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::higher::IfLetOrMatch;
use clippy_utils::msrvs::Msrv;
use clippy_utils::source::snippet;
@@ -99,7 +99,7 @@ fn check_arm<'tcx>(
} else {
String::new()
};
- span_lint_and_then(cx, COLLAPSIBLE_MATCH, inner_expr.span, msg, |diag| {
+ span_lint_hir_and_then(cx, COLLAPSIBLE_MATCH, inner_expr.hir_id, inner_expr.span, msg, |diag| {
let mut help_span = MultiSpan::from_spans(vec![binding_span, inner_then_pat.span]);
help_span.push_span_label(binding_span, "replace this binding");
help_span.push_span_label(inner_then_pat.span, format!("with this pattern{replace_msg}"));
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
index 4cc43e4..abf723f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
@@ -41,10 +41,10 @@ fn get_cond_expr<'tcx>(
fn peels_blocks_incl_unsafe_opt<'a>(expr: &'a Expr<'a>) -> Option<&'a Expr<'a>> {
// we don't want to use `peel_blocks` here because we don't care if the block is unsafe, it's
// checked by `contains_unsafe_block`
- if let ExprKind::Block(block, None) = expr.kind {
- if block.stmts.is_empty() {
- return block.expr;
- }
+ if let ExprKind::Block(block, None) = expr.kind
+ && block.stmts.is_empty()
+ {
+ return block.expr;
}
None
}
@@ -61,13 +61,13 @@ fn peels_blocks_incl_unsafe<'a>(expr: &'a Expr<'a>) -> &'a Expr<'a> {
// }
// Returns true if <expr> resolves to `Some(x)`, `false` otherwise
fn is_some_expr(cx: &LateContext<'_>, target: HirId, ctxt: SyntaxContext, expr: &Expr<'_>) -> bool {
- if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr) {
+ if let Some(inner_expr) = peels_blocks_incl_unsafe_opt(expr)
// there can be not statements in the block as they would be removed when switching to `.filter`
- if let ExprKind::Call(callee, [arg]) = inner_expr.kind {
- return ctxt == expr.span.ctxt()
- && is_res_lang_ctor(cx, path_res(cx, callee), OptionSome)
- && path_to_local_id(arg, target);
- }
+ && let ExprKind::Call(callee, [arg]) = inner_expr.kind
+ {
+ return ctxt == expr.span.ctxt()
+ && is_res_lang_ctor(cx, path_res(cx, callee), OptionSome)
+ && path_to_local_id(arg, target);
}
false
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
index 576e42a..4959908 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
@@ -85,7 +85,7 @@ fn is_variant_or_wildcard(cx: &LateContext<'_>, pat: &Pat<'_>, can_be_wild: bool
/// contains `Err(IDENT)`, `None` otherwise.
fn is_ok_or_err<'hir>(cx: &LateContext<'_>, pat: &Pat<'hir>) -> Option<(bool, &'hir Ident)> {
if let PatKind::TupleStruct(qpath, [arg], _) = &pat.kind
- && let PatKind::Binding(BindingMode::NONE, _, ident, _) = &arg.kind
+ && let PatKind::Binding(BindingMode::NONE, _, ident, None) = &arg.kind
&& let res = cx.qpath_res(qpath, pat.hir_id)
&& let Res::Def(DefKind::Ctor(..), id) = res
&& let id @ Some(_) = cx.tcx.opt_parent(id)
@@ -132,7 +132,7 @@ fn apply_lint(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Expr<'_>, is_ok
} else {
Applicability::MachineApplicable
};
- let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_par();
+ let scrut = Sugg::hir_with_applicability(cx, scrutinee, "..", &mut app).maybe_paren();
let sugg = format!("{scrut}.{method}()");
// If the expression being expanded is the `if …` part of an `else if …`, it must be blockified.
let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr)
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
index 2bf7ec8..b64ae0b 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -1,133 +1,219 @@
use clippy_utils::consts::ConstEvalCtxt;
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline};
-use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::usage::contains_return_break_continue_macro;
-use clippy_utils::{is_res_lang_ctor, path_to_local_id, peel_blocks, sugg};
+use clippy_utils::source::{SpanRangeExt as _, indent_of, reindent_multiline};
use rustc_errors::Applicability;
-use rustc_hir::LangItem::{OptionNone, ResultErr};
-use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Arm, Expr, Pat, PatExpr, PatExprKind, PatKind};
-use rustc_lint::LateContext;
-use rustc_middle::ty::Ty;
+use rustc_hir::def::Res;
+use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, Pat, PatExpr, PatExprKind, PatKind, QPath};
+use rustc_lint::{LateContext, LintContext};
+use rustc_middle::ty::{GenericArgKind, Ty};
use rustc_span::sym;
-use super::MANUAL_UNWRAP_OR;
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::sugg::Sugg;
+use clippy_utils::ty::{expr_type_is_certain, get_type_diagnostic_name, implements_trait};
+use clippy_utils::{is_default_equivalent, is_lint_allowed, path_res, peel_blocks, span_contains_comment};
-pub(super) fn check_match<'tcx>(
- cx: &LateContext<'tcx>,
- expr: &'tcx Expr<'tcx>,
- scrutinee: &'tcx Expr<'_>,
- arms: &'tcx [Arm<'_>],
-) {
- let ty = cx.typeck_results().expr_ty(scrutinee);
- if let Some((or_arm, unwrap_arm)) = applicable_or_arm(cx, arms) {
- check_and_lint(cx, expr, unwrap_arm.pat, scrutinee, unwrap_arm.body, or_arm.body, ty);
+use super::{MANUAL_UNWRAP_OR, MANUAL_UNWRAP_OR_DEFAULT};
+
+fn get_some(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<HirId> {
+ if let PatKind::TupleStruct(QPath::Resolved(_, path), &[pat], _) = pat.kind
+ && let PatKind::Binding(_, pat_id, _, _) = pat.kind
+ && let Some(def_id) = path.res.opt_def_id()
+ // Since it comes from a pattern binding, we need to get the parent to actually match
+ // against it.
+ && let Some(def_id) = cx.tcx.opt_parent(def_id)
+ && let Some(lang_item) = cx.tcx.lang_items().from_def_id(def_id)
+ && matches!(lang_item, LangItem::OptionSome | LangItem::ResultOk)
+ {
+ Some(pat_id)
+ } else {
+ None
}
}
-pub(super) fn check_if_let<'tcx>(
- cx: &LateContext<'tcx>,
- expr: &'tcx Expr<'_>,
- let_pat: &'tcx Pat<'_>,
- let_expr: &'tcx Expr<'_>,
- then_expr: &'tcx Expr<'_>,
- else_expr: &'tcx Expr<'_>,
-) {
- let ty = cx.typeck_results().expr_ty(let_expr);
- let then_ty = cx.typeck_results().expr_ty(then_expr);
- // The signature is `fn unwrap_or<T>(self: Option<T>, default: T) -> T`.
- // When `expr_adjustments(then_expr).is_empty()`, `T` should equate to `default`'s type.
- // Otherwise, type error will occur.
- if cx.typeck_results().expr_adjustments(then_expr).is_empty()
- && let rustc_middle::ty::Adt(_did, args) = ty.kind()
- && let Some(some_ty) = args.first().and_then(|arg| arg.as_type())
- && some_ty != then_ty
+fn get_none<'tcx>(cx: &LateContext<'_>, arm: &Arm<'tcx>) -> Option<&'tcx Expr<'tcx>> {
+ if let PatKind::Expr(PatExpr { kind: PatExprKind::Path(QPath::Resolved(_, path)), .. }) = arm.pat.kind
+ && let Some(def_id) = path.res.opt_def_id()
+ // Since it comes from a pattern binding, we need to get the parent to actually match
+ // against it.
+ && let Some(def_id) = cx.tcx.opt_parent(def_id)
+ && cx.tcx.lang_items().get(LangItem::OptionNone) == Some(def_id)
{
+ Some(arm.body)
+ } else if let PatKind::TupleStruct(QPath::Resolved(_, path), _, _)= arm.pat.kind
+ && let Some(def_id) = path.res.opt_def_id()
+ // Since it comes from a pattern binding, we need to get the parent to actually match
+ // against it.
+ && let Some(def_id) = cx.tcx.opt_parent(def_id)
+ && cx.tcx.lang_items().get(LangItem::ResultErr) == Some(def_id)
+ {
+ Some(arm.body)
+ } else if let PatKind::Wild = arm.pat.kind {
+ // We consider that the `Some` check will filter it out if it's not right.
+ Some(arm.body)
+ } else {
+ None
+ }
+}
+
+fn get_some_and_none_bodies<'tcx>(
+ cx: &LateContext<'tcx>,
+ arm1: &'tcx Arm<'tcx>,
+ arm2: &'tcx Arm<'tcx>,
+) -> Option<((&'tcx Expr<'tcx>, HirId), &'tcx Expr<'tcx>)> {
+ if let Some(binding_id) = get_some(cx, arm1.pat)
+ && let Some(body_none) = get_none(cx, arm2)
+ {
+ Some(((arm1.body, binding_id), body_none))
+ } else if let Some(binding_id) = get_some(cx, arm2.pat)
+ && let Some(body_none) = get_none(cx, arm1)
+ {
+ Some(((arm2.body, binding_id), body_none))
+ } else {
+ None
+ }
+}
+
+fn handle(
+ cx: &LateContext<'_>,
+ expr: &Expr<'_>,
+ expr_name: &'static str,
+ condition: &Expr<'_>,
+ body_some: &Expr<'_>,
+ body_none: &Expr<'_>,
+ binding_id: HirId,
+) {
+ // Only deal with situations where both alternatives return the same non-adjusted type.
+ if cx.typeck_results().expr_ty(body_some) != cx.typeck_results().expr_ty(body_none) {
return;
}
- check_and_lint(cx, expr, let_pat, let_expr, then_expr, peel_blocks(else_expr), ty);
-}
-fn check_and_lint<'tcx>(
- cx: &LateContext<'tcx>,
- expr: &'tcx Expr<'_>,
- let_pat: &'tcx Pat<'_>,
- let_expr: &'tcx Expr<'_>,
- then_expr: &'tcx Expr<'_>,
- else_expr: &'tcx Expr<'_>,
- ty: Ty<'tcx>,
-) {
- if let PatKind::TupleStruct(ref qpath, [unwrap_pat], _) = let_pat.kind
- && let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(qpath, let_pat.hir_id)
- && let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
- && (cx.tcx.lang_items().option_some_variant() == Some(variant_id)
- || cx.tcx.lang_items().result_ok_variant() == Some(variant_id))
- && let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind
- && path_to_local_id(peel_blocks(then_expr), binding_hir_id)
- && cx.typeck_results().expr_adjustments(then_expr).is_empty()
- && let Some(ty_name) = find_type_name(cx, ty)
- && let Some(or_body_snippet) = else_expr.span.get_source_text(cx)
- && let Some(indent) = indent_of(cx, expr.span)
- && ConstEvalCtxt::new(cx).eval_simple(else_expr).is_some()
+ let expr_type = cx.typeck_results().expr_ty(expr);
+ // We check that the `Some(x) => x` doesn't do anything apart "returning" the value in `Some`.
+ if let ExprKind::Path(QPath::Resolved(_, path)) = peel_blocks(body_some).kind
+ && let Res::Local(local_id) = path.res
+ && local_id == binding_id
{
- lint(cx, expr, let_expr, ty_name, &or_body_snippet, indent);
+ // Machine applicable only if there are no comments present
+ let mut applicability = if span_contains_comment(cx.sess().source_map(), expr.span) {
+ Applicability::MaybeIncorrect
+ } else {
+ Applicability::MachineApplicable
+ };
+ let receiver = Sugg::hir_with_applicability(cx, condition, "_", &mut applicability).maybe_paren();
+
+ // We now check the `None` arm is calling a method equivalent to `Default::default`.
+ if !is_lint_allowed(cx, MANUAL_UNWRAP_OR_DEFAULT, expr.hir_id)
+ // We check if the return type of the expression implements Default.
+ && let Some(default_trait_id) = cx.tcx.get_diagnostic_item(sym::Default)
+ && implements_trait(cx, expr_type, default_trait_id, &[])
+ // We check if the initial condition implements Default.
+ && let Some(condition_ty) = cx.typeck_results().expr_ty(condition).walk().nth(1)
+ && let GenericArgKind::Type(condition_ty) = condition_ty.unpack()
+ && implements_trait(cx, condition_ty, default_trait_id, &[])
+ && is_default_equivalent(cx, peel_blocks(body_none))
+ {
+ // We now check if the condition is a None variant, in which case we need to specify the type
+ if path_res(cx, condition)
+ .opt_def_id()
+ .is_some_and(|id| Some(cx.tcx.parent(id)) == cx.tcx.lang_items().option_none_variant())
+ {
+ return span_lint_and_sugg(
+ cx,
+ MANUAL_UNWRAP_OR_DEFAULT,
+ expr.span,
+ format!("{expr_name} can be simplified with `.unwrap_or_default()`"),
+ "replace it with",
+ format!("{receiver}::<{expr_type}>.unwrap_or_default()"),
+ applicability,
+ );
+ }
+
+ // We check if the expression type is still uncertain, in which case we ask the user to specify it
+ if !expr_type_is_certain(cx, condition) {
+ return span_lint_and_sugg(
+ cx,
+ MANUAL_UNWRAP_OR_DEFAULT,
+ expr.span,
+ format!("{expr_name} can be simplified with `.unwrap_or_default()`"),
+ format!("ascribe the type {expr_type} and replace your expression with"),
+ format!("{receiver}.unwrap_or_default()"),
+ Applicability::Unspecified,
+ );
+ }
+
+ span_lint_and_sugg(
+ cx,
+ MANUAL_UNWRAP_OR_DEFAULT,
+ expr.span,
+ format!("{expr_name} can be simplified with `.unwrap_or_default()`"),
+ "replace it with",
+ format!("{receiver}.unwrap_or_default()"),
+ applicability,
+ );
+ } else if let Some(ty_name) = find_type_name(cx, cx.typeck_results().expr_ty(condition))
+ && cx.typeck_results().expr_adjustments(body_some).is_empty()
+ && let Some(or_body_snippet) = peel_blocks(body_none).span.get_source_text(cx)
+ && let Some(indent) = indent_of(cx, expr.span)
+ && ConstEvalCtxt::new(cx).eval_simple(body_none).is_some()
+ {
+ let reindented_or_body = reindent_multiline(&or_body_snippet, true, Some(indent));
+ let mut app = Applicability::MachineApplicable;
+ let suggestion = Sugg::hir_with_context(cx, condition, expr.span.ctxt(), "..", &mut app).maybe_paren();
+ span_lint_and_sugg(
+ cx,
+ MANUAL_UNWRAP_OR,
+ expr.span,
+ format!("this pattern reimplements `{ty_name}::unwrap_or`"),
+ "replace with",
+ format!("{suggestion}.unwrap_or({reindented_or_body})",),
+ app,
+ );
+ }
}
}
fn find_type_name<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'static str> {
- if is_type_diagnostic_item(cx, ty, sym::Option) {
- Some("Option")
- } else if is_type_diagnostic_item(cx, ty, sym::Result) {
- Some("Result")
- } else {
- None
+ match get_type_diagnostic_name(cx, ty)? {
+ sym::Option => Some("Option"),
+ sym::Result => Some("Result"),
+ _ => None,
}
}
-fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<(&'a Arm<'a>, &'a Arm<'a>)> {
- if arms.len() == 2
- && arms.iter().all(|arm| arm.guard.is_none())
- && let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| match arm.pat.kind {
- PatKind::Expr(PatExpr {
- hir_id,
- kind: PatExprKind::Path(qpath),
- ..
- }) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
- PatKind::TupleStruct(ref qpath, [pat], _) => {
- matches!(pat.kind, PatKind::Wild)
- && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr)
- },
- _ => false,
- })
- && let unwrap_arm = &arms[1 - idx]
- && !contains_return_break_continue_macro(or_arm.body)
- {
- Some((or_arm, unwrap_arm))
- } else {
- None
- }
-}
-
-fn lint<'tcx>(
+pub fn check_match<'tcx>(
cx: &LateContext<'tcx>,
- expr: &Expr<'tcx>,
- scrutinee: &'tcx Expr<'_>,
- ty_name: &str,
- or_body_snippet: &str,
- indent: usize,
+ expr: &'tcx Expr<'tcx>,
+ scrutinee: &'tcx Expr<'tcx>,
+ arms: &'tcx [Arm<'tcx>],
) {
- let reindented_or_body = reindent_multiline(or_body_snippet, true, Some(indent));
+ if let [arm1, arm2] = arms
+ // Make sure there are no guards to keep things simple
+ && arm1.guard.is_none()
+ && arm2.guard.is_none()
+ // Get the some and none bodies and the binding id of the some arm
+ && let Some(((body_some, binding_id), body_none)) = get_some_and_none_bodies(cx, arm1, arm2)
+ {
+ handle(cx, expr, "match", scrutinee, body_some, body_none, binding_id);
+ }
+}
- let mut app = Applicability::MachineApplicable;
- let suggestion = sugg::Sugg::hir_with_context(cx, scrutinee, expr.span.ctxt(), "..", &mut app).maybe_par();
- span_lint_and_sugg(
- cx,
- MANUAL_UNWRAP_OR,
- expr.span,
- format!("this pattern reimplements `{ty_name}::unwrap_or`"),
- "replace with",
- format!("{suggestion}.unwrap_or({reindented_or_body})",),
- app,
- );
+pub fn check_if_let<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &'tcx Expr<'tcx>,
+ pat: &'tcx Pat<'tcx>,
+ scrutinee: &'tcx Expr<'tcx>,
+ then_expr: &'tcx Expr<'tcx>,
+ else_expr: &'tcx Expr<'tcx>,
+) {
+ if let Some(binding_id) = get_some(cx, pat) {
+ handle(
+ cx,
+ expr,
+ "if let",
+ scrutinee,
+ peel_blocks(then_expr),
+ peel_blocks(else_expr),
+ binding_id,
+ );
+ }
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
index d29d1ea..f14b69d 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
@@ -76,17 +76,18 @@ fn find_matches_sugg<'a, 'b, I>(
&& first_attrs.is_empty()
&& iter.all(|arm| find_bool_lit(&arm.2.kind).is_some_and(|b| b == b0) && arm.3.is_none() && arm.0.is_empty())
{
- if let Some(last_pat) = last_pat_opt {
- if !is_wild(last_pat) {
- return false;
- }
+ if let Some(last_pat) = last_pat_opt
+ && !is_wild(last_pat)
+ {
+ return false;
}
for arm in iter_without_last.clone() {
- if let Some(pat) = arm.1 {
- if !is_lint_allowed(cx, REDUNDANT_PATTERN_MATCHING, pat.hir_id) && is_some(pat.kind) {
- return false;
- }
+ if let Some(pat) = arm.1
+ && !is_lint_allowed(cx, REDUNDANT_PATTERN_MATCHING, pat.hir_id)
+ && is_some(pat.kind)
+ {
+ return false;
}
}
@@ -113,10 +114,10 @@ fn find_matches_sugg<'a, 'b, I>(
// strip potential borrows (#6503), but only if the type is a reference
let mut ex_new = ex;
- if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind {
- if let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind() {
- ex_new = ex_inner;
- }
+ if let ExprKind::AddrOf(BorrowKind::Ref, .., ex_inner) = ex.kind
+ && let ty::Ref(..) = cx.typeck_results().expr_ty(ex_inner).kind()
+ {
+ ex_new = ex_inner;
}
span_lint_and_sugg(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs b/src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs
deleted file mode 100644
index dd71560..0000000
--- a/src/tools/clippy/clippy_lints/src/matches/match_on_vec_items.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet;
-use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
-use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, LangItem};
-use rustc_lint::LateContext;
-use rustc_span::sym;
-
-use super::MATCH_ON_VEC_ITEMS;
-
-pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>) {
- if let Some(idx_expr) = is_vec_indexing(cx, scrutinee)
- && let ExprKind::Index(vec, idx, _) = idx_expr.kind
- {
- // FIXME: could be improved to suggest surrounding every pattern with Some(_),
- // but only when `or_patterns` are stabilized.
- span_lint_and_sugg(
- cx,
- MATCH_ON_VEC_ITEMS,
- scrutinee.span,
- "indexing into a vector may panic",
- "try",
- format!("{}.get({})", snippet(cx, vec.span, ".."), snippet(cx, idx.span, "..")),
- Applicability::MaybeIncorrect,
- );
- }
-}
-
-fn is_vec_indexing<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
- if let ExprKind::Index(array, index, _) = expr.kind
- && is_vector(cx, array)
- && !is_full_range(cx, index)
- {
- return Some(expr);
- }
-
- None
-}
-
-fn is_vector(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- let ty = cx.typeck_results().expr_ty(expr);
- let ty = ty.peel_refs();
- is_type_diagnostic_item(cx, ty, sym::Vec)
-}
-
-fn is_full_range(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- let ty = cx.typeck_results().expr_ty(expr);
- let ty = ty.peel_refs();
- is_type_lang_item(cx, ty, LangItem::RangeFull)
-}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
index 864923b..adda358 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::HirNode;
-use clippy_utils::source::{indent_of, snippet, snippet_block_with_context, snippet_with_applicability};
+use clippy_utils::source::{indent_of, snippet, snippet_block_with_context, snippet_with_context};
use clippy_utils::{get_parent_expr, is_refutable, peel_blocks};
use rustc_errors::Applicability;
use rustc_hir::{Arm, Expr, ExprKind, Node, PatKind, StmtKind};
@@ -24,16 +24,10 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
let bind_names = arms[0].pat.span;
let match_body = peel_blocks(arms[0].body);
let mut app = Applicability::MaybeIncorrect;
- let mut snippet_body = snippet_block_with_context(
- cx,
- match_body.span,
- arms[0].span.ctxt(),
- "..",
- Some(expr.span),
- &mut app,
- )
- .0
- .to_string();
+ let ctxt = expr.span.ctxt();
+ let mut snippet_body = snippet_block_with_context(cx, match_body.span, ctxt, "..", Some(expr.span), &mut app)
+ .0
+ .to_string();
// Do we need to add ';' to suggestion ?
if let Node::Stmt(stmt) = cx.tcx.parent_hir_node(expr.hir_id)
@@ -77,10 +71,10 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
span,
format!(
"let {} = {};\n{}let {} = {snippet_body};",
- snippet_with_applicability(cx, bind_names, "..", &mut app),
- snippet_with_applicability(cx, matched_vars, "..", &mut app),
+ snippet_with_context(cx, bind_names, ctxt, "..", &mut app).0,
+ snippet_with_context(cx, matched_vars, ctxt, "..", &mut app).0,
" ".repeat(indent_of(cx, expr.span).unwrap_or(0)),
- snippet_with_applicability(cx, pat_span, "..", &mut app)
+ snippet_with_context(cx, pat_span, ctxt, "..", &mut app).0
),
),
None => {
@@ -178,24 +172,24 @@ fn sugg_with_curlies<'a>(
let mut indent = " ".repeat(indent_of(cx, ex.span).unwrap_or(0));
let (mut cbrace_start, mut cbrace_end) = (String::new(), String::new());
- if let Some(parent_expr) = get_parent_expr(cx, match_expr) {
- if let ExprKind::Closure { .. } = parent_expr.kind {
- cbrace_end = format!("\n{indent}}}");
- // Fix body indent due to the closure
- indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
- cbrace_start = format!("{{\n{indent}");
- }
+ if let Some(parent_expr) = get_parent_expr(cx, match_expr)
+ && let ExprKind::Closure { .. } = parent_expr.kind
+ {
+ cbrace_end = format!("\n{indent}}}");
+ // Fix body indent due to the closure
+ indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
+ cbrace_start = format!("{{\n{indent}");
}
// If the parent is already an arm, and the body is another match statement,
// we need curly braces around suggestion
- if let Node::Arm(arm) = &cx.tcx.parent_hir_node(match_expr.hir_id) {
- if let ExprKind::Match(..) = arm.body.kind {
- cbrace_end = format!("\n{indent}}}");
- // Fix body indent due to the match
- indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
- cbrace_start = format!("{{\n{indent}");
- }
+ if let Node::Arm(arm) = &cx.tcx.parent_hir_node(match_expr.hir_id)
+ && let ExprKind::Match(..) = arm.body.kind
+ {
+ cbrace_end = format!("\n{indent}}}");
+ // Fix body indent due to the match
+ indent = " ".repeat(indent_of(cx, bind_names).unwrap_or(0));
+ cbrace_start = format!("{{\n{indent}");
}
let assignment_str = assignment.map_or_else(String::new, |span| {
@@ -204,14 +198,17 @@ fn sugg_with_curlies<'a>(
s
});
+ let ctxt = match_expr.span.ctxt();
let scrutinee = if needs_var_binding {
format!(
"let {} = {}",
- snippet_with_applicability(cx, bind_names, "..", applicability),
- snippet_with_applicability(cx, matched_vars, "..", applicability)
+ snippet_with_context(cx, bind_names, ctxt, "..", applicability).0,
+ snippet_with_context(cx, matched_vars, ctxt, "..", applicability).0
)
} else {
- snippet_with_applicability(cx, matched_vars, "..", applicability).to_string()
+ snippet_with_context(cx, matched_vars, ctxt, "..", applicability)
+ .0
+ .to_string()
};
format!("{cbrace_start}{scrutinee};\n{indent}{assignment_str}{snippet_body}{cbrace_end}")
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
index df1b83c..65b93a0 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_str_case_mismatch.rs
@@ -26,10 +26,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, scrutinee: &'tcx Expr<'_>, arm
&& let ty::Str = ty.kind()
{
let mut visitor = MatchExprVisitor { cx };
- if let ControlFlow::Break(case_method) = visitor.visit_expr(scrutinee) {
- if let Some((bad_case_span, bad_case_sym)) = verify_case(&case_method, arms) {
- lint(cx, &case_method, bad_case_span, bad_case_sym.as_str());
- }
+ if let ControlFlow::Break(case_method) = visitor.visit_expr(scrutinee)
+ && let Some((bad_case_span, bad_case_sym)) = verify_case(&case_method, arms)
+ {
+ lint(cx, &case_method, bad_case_span, bad_case_sym.as_str());
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
index 11b588b..24b4a67 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
@@ -80,18 +80,20 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
path
},
PatKind::TupleStruct(path, patterns, ..) => {
- if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
- if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p)) {
- missing_variants.retain(|e| e.ctor_def_id() != Some(id));
- }
+ if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id()
+ && arm.guard.is_none()
+ && patterns.iter().all(|p| !is_refutable(cx, p))
+ {
+ missing_variants.retain(|e| e.ctor_def_id() != Some(id));
}
path
},
PatKind::Struct(path, patterns, ..) => {
- if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id() {
- if arm.guard.is_none() && patterns.iter().all(|p| !is_refutable(cx, p.pat)) {
- missing_variants.retain(|e| e.def_id != id);
- }
+ if let Some(id) = cx.qpath_res(path, pat.hir_id).opt_def_id()
+ && arm.guard.is_none()
+ && patterns.iter().all(|p| !is_refutable(cx, p.pat))
+ {
+ missing_variants.retain(|e| e.def_id != id);
}
path
},
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
index d0d2025..8ce8453 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
@@ -26,11 +26,12 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'
if !matching_wild {
// Looking for unused bindings (i.e.: `_e`)
for pat in inner {
- if let PatKind::Binding(_, id, ident, None) = pat.kind {
- if ident.as_str().starts_with('_') && !is_local_used(cx, arm.body, id) {
- ident_bind_name = ident.name;
- matching_wild = true;
- }
+ if let PatKind::Binding(_, id, ident, None) = pat.kind
+ && ident.as_str().starts_with('_')
+ && !is_local_used(cx, arm.body, id)
+ {
+ ident_bind_name = ident.name;
+ matching_wild = true;
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index 2b9173e..c6ebd61 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -8,7 +8,6 @@
mod match_as_ref;
mod match_bool;
mod match_like_matches;
-mod match_on_vec_items;
mod match_ref_pats;
mod match_same_arms;
mod match_single_binding;
@@ -724,38 +723,39 @@
declare_clippy_lint! {
/// ### What it does
- /// Checks for `match vec[idx]` or `match vec[n..m]`.
+ /// Checks if a `match` or `if let` expression can be simplified using
+ /// `.unwrap_or_default()`.
///
/// ### Why is this bad?
- /// This can panic at runtime.
+ /// It can be done in one call with `.unwrap_or_default()`.
///
/// ### Example
- /// ```rust, no_run
- /// let arr = vec![0, 1, 2, 3];
- /// let idx = 1;
+ /// ```no_run
+ /// let x: Option<String> = Some(String::new());
+ /// let y: String = match x {
+ /// Some(v) => v,
+ /// None => String::new(),
+ /// };
///
- /// match arr[idx] {
- /// 0 => println!("{}", 0),
- /// 1 => println!("{}", 3),
- /// _ => {},
- /// }
+ /// let x: Option<Vec<String>> = Some(Vec::new());
+ /// let y: Vec<String> = if let Some(v) = x {
+ /// v
+ /// } else {
+ /// Vec::new()
+ /// };
/// ```
- ///
/// Use instead:
- /// ```rust, no_run
- /// let arr = vec![0, 1, 2, 3];
- /// let idx = 1;
+ /// ```no_run
+ /// let x: Option<String> = Some(String::new());
+ /// let y: String = x.unwrap_or_default();
///
- /// match arr.get(idx) {
- /// Some(0) => println!("{}", 0),
- /// Some(1) => println!("{}", 3),
- /// _ => {},
- /// }
+ /// let x: Option<Vec<String>> = Some(Vec::new());
+ /// let y: Vec<String> = x.unwrap_or_default();
/// ```
- #[clippy::version = "1.45.0"]
- pub MATCH_ON_VEC_ITEMS,
- pedantic,
- "matching on vector elements can panic"
+ #[clippy::version = "1.79.0"]
+ pub MANUAL_UNWRAP_OR_DEFAULT,
+ suspicious,
+ "check if a `match` or `if let` can be simplified with `unwrap_or_default`"
}
declare_clippy_lint! {
@@ -1040,7 +1040,7 @@ pub fn new(conf: &'static Conf) -> Self {
NEEDLESS_MATCH,
COLLAPSIBLE_MATCH,
MANUAL_UNWRAP_OR,
- MATCH_ON_VEC_ITEMS,
+ MANUAL_UNWRAP_OR_DEFAULT,
MATCH_STR_CASE_MISMATCH,
SIGNIFICANT_DROP_IN_SCRUTINEE,
TRY_ERR,
@@ -1118,7 +1118,6 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
match_wild_enum::check(cx, ex, arms);
match_as_ref::check(cx, ex, arms, expr);
needless_match::check_match(cx, ex, arms, expr);
- match_on_vec_items::check(cx, ex);
match_str_case_mismatch::check(cx, ex, arms);
redundant_guards::check(cx, arms, self.msrv);
diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
index 7e65d58..6c5d7ca 100644
--- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
@@ -67,10 +67,10 @@ fn check_all_arms(cx: &LateContext<'_>, match_expr: &Expr<'_>, arms: &[Arm<'_>])
for arm in arms {
let arm_expr = peel_blocks_with_stmt(arm.body);
- if let Some(guard_expr) = &arm.guard {
- if guard_expr.can_have_side_effects() {
- return false;
- }
+ if let Some(guard_expr) = &arm.guard
+ && guard_expr.can_have_side_effects()
+ {
+ return false;
}
if let PatKind::Wild = arm.pat.kind {
diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
index 4184f8b..d3136c8 100644
--- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
@@ -11,17 +11,17 @@
pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>]) {
if arms.len() >= 2 && cx.typeck_results().expr_ty(ex).is_integral() {
let ranges = all_ranges(cx, arms, cx.typeck_results().expr_ty(ex));
- if !ranges.is_empty() {
- if let Some((start, end)) = overlapping(&ranges) {
- span_lint_and_note(
- cx,
- MATCH_OVERLAPPING_ARM,
- start.span,
- "some ranges overlap",
- Some(end.span),
- "overlaps with this",
- );
- }
+ if !ranges.is_empty()
+ && let Some((start, end)) = overlapping(&ranges)
+ {
+ span_lint_and_note(
+ cx,
+ MATCH_OVERLAPPING_ARM,
+ start.span,
+ "some ranges overlap",
+ Some(end.span),
+ "overlaps with this",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index 722ea70..db20be40 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -4,7 +4,7 @@
use clippy_utils::sugg::{Sugg, make_unop};
use clippy_utils::ty::{is_type_diagnostic_item, needs_ordered_drop};
use clippy_utils::visitors::{any_temporaries_need_ordered_drop, for_each_expr_without_closures};
-use clippy_utils::{higher, is_expn_of, is_trait_method};
+use clippy_utils::{higher, is_expn_of, is_trait_method, sym};
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
@@ -12,7 +12,7 @@
use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatExpr, PatExprKind, PatKind, QPath, UnOp};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, GenericArgKind, Ty};
-use rustc_span::{Span, Symbol, sym};
+use rustc_span::{Span, Symbol};
use std::fmt::Write;
use std::ops::ControlFlow;
@@ -138,9 +138,9 @@ fn find_method_and_type<'tcx>(
Some(("is_some()", op_ty))
} else if Some(id) == lang_items.poll_ready_variant() {
Some(("is_ready()", op_ty))
- } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V4))) {
+ } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym::V4)) {
Some(("is_ipv4()", op_ty))
- } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym!(V6))) {
+ } else if is_pat_variant(cx, check_pat, qpath, Item::Diag(sym::IpAddr, sym::V6)) {
Some(("is_ipv6()", op_ty))
} else {
None
@@ -255,7 +255,7 @@ fn find_method_sugg_for_if_let<'tcx>(
};
let sugg = Sugg::hir_with_context(cx, result_expr, ctxt, "_", &mut app)
- .maybe_par()
+ .maybe_paren()
.to_string();
diag.span_suggestion(span, "try", format!("{keyword} {sugg}.{good_method}"), app);
@@ -279,7 +279,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
_ => op,
};
let mut app = Applicability::MachineApplicable;
- let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_par();
+ let receiver_sugg = Sugg::hir_with_applicability(cx, result_expr, "_", &mut app).maybe_paren();
let mut sugg = format!("{receiver_sugg}.{good_method}");
if let Some(guard) = maybe_guard {
@@ -303,7 +303,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op
}
let guard = Sugg::hir(cx, guard, "..");
- let _ = write!(sugg, " && {}", guard.maybe_par());
+ let _ = write!(sugg, " && {}", guard.maybe_paren());
}
span_lint_and_sugg(
@@ -345,8 +345,8 @@ fn found_good_method<'tcx>(
arms,
path_left,
path_right,
- Item::Diag(sym::IpAddr, sym!(V4)),
- Item::Diag(sym::IpAddr, sym!(V6)),
+ Item::Diag(sym::IpAddr, sym::V4),
+ Item::Diag(sym::IpAddr, sym::V6),
"is_ipv4()",
"is_ipv6()",
)
@@ -437,8 +437,8 @@ fn get_good_method<'tcx>(
"None" => (Item::Lang(OptionNone), "is_none()", "is_some()"),
"Ready" => (Item::Lang(PollReady), "is_ready()", "is_pending()"),
"Pending" => (Item::Lang(PollPending), "is_pending()", "is_ready()"),
- "V4" => (Item::Diag(sym::IpAddr, sym!(V4)), "is_ipv4()", "is_ipv6()"),
- "V6" => (Item::Diag(sym::IpAddr, sym!(V6)), "is_ipv6()", "is_ipv4()"),
+ "V4" => (Item::Diag(sym::IpAddr, sym::V4), "is_ipv4()", "is_ipv6()"),
+ "V6" => (Item::Diag(sym::IpAddr, sym::V6), "is_ipv6()", "is_ipv4()"),
_ => return None,
};
return find_good_method_for_matches_macro(
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index 37bac56..d7dc760 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -182,17 +182,16 @@ fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool {
}
fn has_sig_drop_attr_impl(&mut self, ty: Ty<'tcx>) -> bool {
- if let Some(adt) = ty.ty_adt_def() {
- if get_attr(
+ if let Some(adt) = ty.ty_adt_def()
+ && get_attr(
self.cx.sess(),
self.cx.tcx.get_attrs_unchecked(adt.did()),
"has_significant_drop",
)
.count()
> 0
- {
- return true;
- }
+ {
+ return true;
}
if !self.seen_types.insert(ty) {
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 836c462..08c0caa 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -1,5 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::source::{SpanRangeExt, expr_block, snippet, snippet_block_with_context};
+use clippy_utils::source::{
+ SpanRangeExt, expr_block, snippet, snippet_block_with_context, snippet_with_applicability, snippet_with_context,
+};
use clippy_utils::ty::implements_trait;
use clippy_utils::{
is_lint_allowed, is_unit_expr, peel_blocks, peel_hir_pat_refs, peel_middle_ty_refs, peel_n_hir_expr_refs,
@@ -34,8 +36,7 @@ fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
#[rustfmt::skip]
pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &'tcx Expr<'_>, arms: &'tcx [Arm<'_>], expr: &'tcx Expr<'_>, contains_comments: bool) {
if let [arm1, arm2] = arms
- && arm1.guard.is_none()
- && arm2.guard.is_none()
+ && !arms.iter().any(|arm| arm.guard.is_some() || arm.pat.span.from_expansion())
&& !expr.span.from_expansion()
// don't lint for or patterns for now, this makes
// the lint noisy in unnecessary situations
@@ -106,7 +107,7 @@ fn report_single_pattern(
format!(" else {}", expr_block(cx, els, ctxt, "..", Some(expr.span), &mut app))
});
- if snippet(cx, ex.span, "..") == snippet(cx, arm.pat.span, "..") {
+ if ex.span.eq_ctxt(expr.span) && snippet(cx, ex.span, "..") == snippet(cx, arm.pat.span, "..") {
let msg = "this pattern is irrefutable, `match` is useless";
let (sugg, help) = if is_unit_expr(arm.body) {
(String::new(), "`match` expression can be removed")
@@ -163,10 +164,10 @@ fn report_single_pattern(
let msg = "you seem to be trying to use `match` for an equality check. Consider using `if`";
let sugg = format!(
"if {} == {}{} {}{els_str}",
- snippet(cx, ex.span, ".."),
+ snippet_with_context(cx, ex.span, ctxt, "..", &mut app).0,
// PartialEq for different reference counts may not exist.
"&".repeat(ref_count_diff),
- snippet(cx, arm.pat.span, ".."),
+ snippet_with_applicability(cx, arm.pat.span, "..", &mut app),
expr_block(cx, arm.body, ctxt, "..", Some(expr.span), &mut app),
);
(msg, sugg)
@@ -174,8 +175,8 @@ fn report_single_pattern(
let msg = "you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`";
let sugg = format!(
"if let {} = {} {}{els_str}",
- snippet(cx, arm.pat.span, ".."),
- snippet(cx, ex.span, ".."),
+ snippet_with_applicability(cx, arm.pat.span, "..", &mut app),
+ snippet_with_context(cx, ex.span, ctxt, "..", &mut app).0,
expr_block(cx, arm.body, ctxt, "..", Some(expr.span), &mut app),
);
(msg, sugg)
diff --git a/src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs b/src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs
index b75d1ab..43102d7 100644
--- a/src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/wild_in_or_pats.rs
@@ -15,18 +15,18 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, arms: &[Arm<'_>]) {
return;
}
for arm in arms {
- if let PatKind::Or(fields) = arm.pat.kind {
+ if let PatKind::Or(fields) = arm.pat.kind
// look for multiple fields in this arm that contains at least one Wild pattern
- if fields.len() > 1 && fields.iter().any(is_wild) {
- span_lint_and_help(
- cx,
- WILDCARD_IN_OR_PATTERNS,
- arm.pat.span,
- "wildcard pattern covers any other pattern as it will match anyway",
- None,
- "consider handling `_` separately",
- );
- }
+ && fields.len() > 1 && fields.iter().any(is_wild)
+ {
+ span_lint_and_help(
+ cx,
+ WILDCARD_IN_OR_PATTERNS,
+ arm.pat.span,
+ "wildcard pattern covers any other pattern as it will match anyway",
+ None,
+ "consider handling `_` separately",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs
index a091994..a54d835 100644
--- a/src/tools/clippy/clippy_lints/src/mem_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs
@@ -145,7 +145,7 @@ fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &E
"consider `Option::take()` instead",
format!(
"{}.take()",
- Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "", &mut applicability).maybe_par()
+ Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "", &mut applicability).maybe_paren()
),
applicability,
);
@@ -178,7 +178,7 @@ fn check_replace_option_with_some(
"consider `Option::replace()` instead",
format!(
"{}.replace({})",
- Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "_", &mut applicability).maybe_par(),
+ Sugg::hir_with_context(cx, sugg_expr, expr_span.ctxt(), "_", &mut applicability).maybe_paren(),
snippet_with_applicability(cx, src_arg.span, "_", &mut applicability)
),
applicability,
@@ -304,14 +304,12 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
&& let ExprKind::Path(ref func_qpath) = func.kind
&& let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id()
&& cx.tcx.is_diagnostic_item(sym::mem_replace, def_id)
- {
// Check that second argument is `Option::None`
- if !check_replace_option_with_none(cx, src, dest, expr.span)
- && !check_replace_option_with_some(cx, src, dest, expr.span, self.msrv)
- && !check_replace_with_default(cx, src, dest, expr, self.msrv)
- {
- check_replace_with_uninit(cx, src, dest, expr.span);
- }
+ && !check_replace_option_with_none(cx, src, dest, expr.span)
+ && !check_replace_option_with_some(cx, src, dest, expr.span, self.msrv)
+ && !check_replace_with_default(cx, src, dest, expr, self.msrv)
+ {
+ check_replace_with_uninit(cx, src, dest, expr.span);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
index 1e9b29f..f8520c2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs
@@ -192,10 +192,10 @@ fn check(&self, cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>
}
fn is_variant(&self, cx: &LateContext<'_>, res: Res) -> bool {
- if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
- if let Some(variant_id) = cx.tcx.lang_items().get(self.variant_lang_item) {
- return cx.tcx.parent(id) == variant_id;
- }
+ if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res
+ && let Some(variant_id) = cx.tcx.lang_items().get(self.variant_lang_item)
+ {
+ return cx.tcx.parent(id) == variant_id;
}
false
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
index 18568e3..d07870d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/case_sensitive_file_extension_comparisons.rs
@@ -1,4 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{SpanRangeExt, indent_of, reindent_multiline};
use clippy_utils::ty::is_type_lang_item;
use rustc_ast::ast::LitKind;
@@ -16,14 +17,15 @@ pub(super) fn check<'tcx>(
call_span: Span,
recv: &'tcx Expr<'_>,
arg: &'tcx Expr<'_>,
+ msrv: Msrv,
) {
- if let ExprKind::MethodCall(path_segment, ..) = recv.kind {
- if matches!(
+ if let ExprKind::MethodCall(path_segment, ..) = recv.kind
+ && matches!(
path_segment.ident.name.as_str(),
"to_lowercase" | "to_uppercase" | "to_ascii_lowercase" | "to_ascii_uppercase"
- ) {
- return;
- }
+ )
+ {
+ return;
}
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
@@ -58,11 +60,15 @@ pub(super) fn check<'tcx>(
let suggestion_source = reindent_multiline(
&format!(
- "std::path::Path::new({})
+ "std::path::Path::new({recv_source})
.extension()
- .map_or(false, |ext| ext.eq_ignore_ascii_case(\"{}\"))",
- recv_source,
- ext_str.strip_prefix('.').unwrap()
+ .{}|ext| ext.eq_ignore_ascii_case(\"{}\"))",
+ if msrv.meets(cx, msrvs::OPTION_RESULT_IS_VARIANT_AND) {
+ "is_some_and("
+ } else {
+ "map_or(false, "
+ },
+ ext_str.strip_prefix('.').unwrap(),
),
true,
Some(indent_of(cx, call_span).unwrap_or(0) + 4),
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
index 1ee27d9..2ecf3eb 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs
@@ -40,10 +40,10 @@ pub(super) fn check(
.map_or_else(|| cx.typeck_results().expr_ty(arg), |a| a.target);
let ty = cx.typeck_results().expr_ty(expr);
- if let ty::Ref(_, inner, _) = arg_ty.kind() {
- if let ty::Ref(..) = inner.kind() {
- return; // don't report clone_on_copy
- }
+ if let ty::Ref(_, inner, _) = arg_ty.kind()
+ && let ty::Ref(..) = inner.kind()
+ {
+ return; // don't report clone_on_copy
}
if is_copy(cx, ty) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
index e82211b..e666f31 100644
--- a/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/double_ended_iterator_last.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::implements_trait;
+use clippy_utils::ty::{has_non_owning_mutable_access, implements_trait};
use clippy_utils::{is_mutable, is_trait_method, path_to_local};
use rustc_errors::Applicability;
use rustc_hir::{Expr, Node, PatKind};
@@ -24,13 +24,18 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, self_expr: &'_ Exp
&& let Ok(Some(fn_def)) = Instance::try_resolve(cx.tcx, cx.typing_env(), id, args)
// find the provided definition of Iterator::last
&& let Some(item) = cx.tcx.get_diagnostic_item(sym::Iterator)
- && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name.as_str() == "last")
+ && let Some(last_def) = cx.tcx.provided_trait_methods(item).find(|m| m.name().as_str() == "last")
// if the resolved method is the same as the provided definition
&& fn_def.def_id() == last_def.def_id
+ && let self_ty = cx.typeck_results().expr_ty(self_expr)
+ && !has_non_owning_mutable_access(cx, self_ty)
{
let mut sugg = vec![(call_span, String::from("next_back()"))];
let mut dont_apply = false;
+
// if `self_expr` is a reference, it is mutable because it is used for `.last()`
+ // TODO: Change this to lint only when the referred iterator is not used later. If it is used later,
+ // changing to `next_back()` may change its behavior.
if !(is_mutable(cx, self_expr) || self_type.is_ref()) {
if let Some(hir_id) = path_to_local(self_expr)
&& let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index daa6e0e..f5688e3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -54,10 +54,11 @@ fn requires_to_string(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
if is_type_lang_item(cx, arg_ty, hir::LangItem::String) {
return false;
}
- if let ty::Ref(_, ty, ..) = arg_ty.kind() {
- if ty.is_str() && can_be_static_str(cx, arg) {
- return false;
- }
+ if let ty::Ref(_, ty, ..) = arg_ty.kind()
+ && ty.is_str()
+ && can_be_static_str(cx, arg)
+ {
+ return false;
}
true
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index ae300cd..da123f1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -2,7 +2,7 @@
use clippy_utils::macros::{is_panic, matching_root_macro_call, root_macro_call};
use clippy_utils::source::{indent_of, reindent_multiline, snippet};
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{SpanlessEq, higher, is_trait_method, path_to_local_id, peel_blocks};
+use clippy_utils::{SpanlessEq, higher, is_trait_method, path_to_local_id, peel_blocks, sym};
use hir::{Body, HirId, MatchSource, Pat};
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -11,7 +11,7 @@
use rustc_lint::LateContext;
use rustc_middle::ty::adjustment::Adjust;
use rustc_span::Span;
-use rustc_span::symbol::{Ident, Symbol, sym};
+use rustc_span::symbol::{Ident, Symbol};
use super::{MANUAL_FILTER_MAP, MANUAL_FIND_MAP, OPTION_FILTER_MAP, RESULT_FILTER_MAP};
@@ -43,10 +43,10 @@ fn is_method(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol) -> bool
}
fn is_option_filter_map(cx: &LateContext<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool {
- is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_some))
+ is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym::is_some)
}
fn is_ok_filter_map(cx: &LateContext<'_>, filter_arg: &Expr<'_>, map_arg: &Expr<'_>) -> bool {
- is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym!(is_ok))
+ is_method(cx, map_arg, sym::unwrap) && is_method(cx, filter_arg, sym::is_ok)
}
#[derive(Debug, Copy, Clone)]
@@ -429,16 +429,15 @@ fn is_find_or_filter<'a>(
}
fn acceptable_methods(method: &PathSegment<'_>) -> bool {
- let methods: [Symbol; 8] = [
- sym::clone,
- sym::as_ref,
- sym!(copied),
- sym!(cloned),
- sym!(as_deref),
- sym!(as_mut),
- sym!(as_deref_mut),
- sym!(to_owned),
- ];
-
- methods.contains(&method.ident.name)
+ matches!(
+ method.ident.name,
+ sym::clone
+ | sym::as_ref
+ | sym::copied
+ | sym::cloned
+ | sym::as_deref
+ | sym::as_mut
+ | sym::as_deref_mut
+ | sym::to_owned
+ )
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
index f7e116c..9659938 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
@@ -1,10 +1,14 @@
use super::FILTER_MAP_BOOL_THEN;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::SpanRangeExt;
use clippy_utils::ty::is_copy;
-use clippy_utils::{is_from_proc_macro, is_trait_method, peel_blocks};
+use clippy_utils::{
+ CaptureKind, can_move_expr_to_closure, contains_return, is_from_proc_macro, is_trait_method, peel_blocks,
+};
+use rustc_ast::Mutability;
+use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{Expr, ExprKind, HirId, Param, Pat};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::Binder;
use rustc_middle::ty::adjustment::Adjust;
@@ -44,17 +48,69 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
&& let Some(filter) = recv.span.get_source_text(cx)
&& let Some(map) = then_body.span.get_source_text(cx)
{
- span_lint_and_sugg(
+ span_lint_and_then(
cx,
FILTER_MAP_BOOL_THEN,
call_span,
"usage of `bool::then` in `filter_map`",
- "use `filter` then `map` instead",
- format!(
- "filter(|&{param_snippet}| {derefs}{filter}).map(|{param_snippet}| {map})",
- derefs = "*".repeat(needed_derefs)
- ),
- Applicability::MachineApplicable,
+ |diag| {
+ if can_filter_and_then_move_to_closure(cx, ¶m, recv, then_body) {
+ diag.span_suggestion(
+ call_span,
+ "use `filter` then `map` instead",
+ format!(
+ "filter(|&{param_snippet}| {derefs}{filter}).map(|{param_snippet}| {map})",
+ derefs = "*".repeat(needed_derefs)
+ ),
+ Applicability::MachineApplicable,
+ );
+ } else {
+ diag.help("consider using `filter` then `map` instead");
+ }
+ },
);
}
}
+
+/// Returns a set of all bindings found in the given pattern.
+fn find_bindings_from_pat(pat: &Pat<'_>) -> FxHashSet<HirId> {
+ let mut bindings = FxHashSet::default();
+ pat.walk(|p| {
+ if let rustc_hir::PatKind::Binding(_, hir_id, _, _) = p.kind {
+ bindings.insert(hir_id);
+ }
+ true
+ });
+ bindings
+}
+
+/// Returns true if we can take a closure parameter and have it in both the `filter` function and
+/// the`map` function. This is not the case if:
+///
+/// - The `filter` would contain an early return,
+/// - `filter` and `then` contain captures, and any of those are &mut
+fn can_filter_and_then_move_to_closure<'tcx>(
+ cx: &LateContext<'tcx>,
+ param: &Param<'tcx>,
+ filter: &'tcx Expr<'tcx>,
+ then: &'tcx Expr<'tcx>,
+) -> bool {
+ if contains_return(filter) {
+ return false;
+ }
+
+ let Some(filter_captures) = can_move_expr_to_closure(cx, filter) else {
+ return true;
+ };
+ let Some(then_captures) = can_move_expr_to_closure(cx, then) else {
+ return true;
+ };
+
+ let param_bindings = find_bindings_from_pat(param.pat);
+ filter_captures.iter().all(|(hir_id, filter_cap)| {
+ param_bindings.contains(hir_id)
+ || !then_captures
+ .get(hir_id)
+ .is_some_and(|then_cap| matches!(*filter_cap | *then_cap, CaptureKind::Ref(Mutability::Mut)))
+ })
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
index f484078..0453630 100644
--- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
@@ -1,25 +1,31 @@
+use std::fmt::Write as _;
+
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::SpanRangeExt;
+use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::implements_trait;
use clippy_utils::{is_path_diagnostic_item, sugg};
use rustc_errors::Applicability;
-use rustc_hir as hir;
+use rustc_hir::def::Res;
+use rustc_hir::{self as hir, Expr, ExprKind, GenericArg, QPath, TyKind};
use rustc_lint::LateContext;
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::GenericParamDefKind;
use rustc_span::sym;
use super::FROM_ITER_INSTEAD_OF_COLLECT;
-pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func: &hir::Expr<'_>) {
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>], func: &Expr<'_>) {
if is_path_diagnostic_item(cx, func, sym::from_iter_fn)
- && let ty = cx.typeck_results().expr_ty(expr)
&& let arg_ty = cx.typeck_results().expr_ty(&args[0])
&& let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
&& implements_trait(cx, arg_ty, iter_id, &[])
{
- // `expr` implements `FromIterator` trait
- let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_par();
- let turbofish = extract_turbofish(cx, expr, ty);
+ let mut app = Applicability::MaybeIncorrect;
+ let turbofish = match func.kind {
+ ExprKind::Path(QPath::TypeRelative(hir_ty, _)) => build_full_type(cx, hir_ty, &mut app),
+ ExprKind::Path(QPath::Resolved(Some(self_ty), _)) => build_full_type(cx, self_ty, &mut app),
+ _ => return,
+ };
+ let iter_expr = sugg::Sugg::hir(cx, &args[0], "..").maybe_paren();
let sugg = format!("{iter_expr}.collect::<{turbofish}>()");
span_lint_and_sugg(
cx,
@@ -28,54 +34,47 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp
"usage of `FromIterator::from_iter`",
"use `.collect()` instead of `::from_iter()`",
sugg,
- Applicability::MaybeIncorrect,
+ app,
);
}
}
-fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'_>) -> String {
- fn strip_angle_brackets(s: &str) -> Option<&str> {
- s.strip_prefix('<')?.strip_suffix('>')
- }
-
- let call_site = expr.span.source_callsite();
- if let Some(snippet) = call_site.get_source_text(cx)
- && let snippet_split = snippet.split("::").collect::<Vec<_>>()
- && let Some((_, elements)) = snippet_split.split_last()
+/// Build a type which can be used in a turbofish syntax from `hir_ty`, either by copying the
+/// existing generic arguments with the exception of elided lifetimes, or by inserting placeholders
+/// for types and consts without default values.
+fn build_full_type(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, app: &mut Applicability) -> String {
+ if let TyKind::Path(ty_qpath) = hir_ty.kind
+ && let QPath::Resolved(None, ty_path) = &ty_qpath
+ && let Res::Def(_, ty_did) = ty_path.res
{
- if let [type_specifier, _] = snippet_split.as_slice()
- && let Some(type_specifier) = strip_angle_brackets(type_specifier)
- && let Some((type_specifier, ..)) = type_specifier.split_once(" as ")
- {
- type_specifier.to_string()
+ let mut ty_str = itertools::join(ty_path.segments.iter().map(|s| s.ident), "::");
+ let mut first = true;
+ let mut append = |arg: &str| {
+ write!(&mut ty_str, "{}{arg}", [", ", "<"][usize::from(first)]).unwrap();
+ first = false;
+ };
+ if let Some(args) = ty_path.segments.last().and_then(|segment| segment.args) {
+ args.args
+ .iter()
+ .filter(|arg| !matches!(arg, GenericArg::Lifetime(lt) if lt.is_elided()))
+ .for_each(|arg| append(&snippet_with_applicability(cx, arg.span().source_callsite(), "_", app)));
} else {
- // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`)
- if let Some(type_specifier) = snippet_split.iter().find(|e| strip_angle_brackets(e).is_some()) {
- // remove the type specifier from the path elements
- let without_ts = elements
- .iter()
- .filter_map(|e| {
- if e == type_specifier {
- None
- } else {
- Some((*e).to_string())
- }
- })
- .collect::<Vec<_>>();
- // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`)
- format!("{}{type_specifier}", without_ts.join("::"))
- } else {
- // type is not explicitly specified so wildcards are needed
- // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>`
- let ty_str = ty.to_string();
- let start = ty_str.find('<').unwrap_or(0);
- let end = ty_str.find('>').unwrap_or(ty_str.len());
- let nb_wildcard = ty_str[start..end].split(',').count();
- let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1));
- format!("{}<{wildcards}>", elements.join("::"))
- }
+ cx.tcx
+ .generics_of(ty_did)
+ .own_params
+ .iter()
+ .filter(|param| {
+ matches!(
+ param.kind,
+ GenericParamDefKind::Type { has_default: false, .. }
+ | GenericParamDefKind::Const { has_default: false, .. }
+ )
+ })
+ .for_each(|_| append("_"));
}
+ ty_str.push_str([">", ""][usize::from(first)]);
+ ty_str
} else {
- ty.to_string()
+ snippet_with_applicability(cx, hir_ty.span.source_callsite(), "_", app).into()
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
index 4c81b22..545bef1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/is_empty.rs
@@ -14,15 +14,13 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &'_ Expr<'_>, receiver: &Expr<'_
if expr.span.in_external_macro(cx.sess().source_map()) || !receiver.span.eq_ctxt(expr.span) {
return;
}
- if let Some(parent) = get_parent_expr(cx, expr) {
- if let Some(parent) = get_parent_expr(cx, parent) {
- if is_inside_always_const_context(cx.tcx, expr.hir_id)
- && let Some(macro_call) = root_macro_call(parent.span)
- && is_assert_macro(cx, macro_call.def_id)
- {
- return;
- }
- }
+ if let Some(parent) = get_parent_expr(cx, expr)
+ && let Some(parent) = get_parent_expr(cx, parent)
+ && is_inside_always_const_context(cx.tcx, expr.hir_id)
+ && let Some(macro_call) = root_macro_call(parent.span)
+ && is_assert_macro(cx, macro_call.def_id)
+ {
+ return;
}
let init_expr = expr_or_init(cx, receiver);
if !receiver.span.eq_ctxt(init_expr.span) {
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
index 49de838..17cc07b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_cloned_collect.rs
@@ -1,16 +1,22 @@
use crate::methods::utils::derefs_to_slice;
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::ty::is_type_diagnostic_item;
+use clippy_utils::ty::{get_iterator_item_ty, is_type_diagnostic_item};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
+use rustc_middle::ty;
use rustc_span::sym;
use super::ITER_CLONED_COLLECT;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, method_name: &str, expr: &hir::Expr<'_>, recv: &'tcx hir::Expr<'_>) {
- if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec)
+ let expr_ty = cx.typeck_results().expr_ty(expr);
+ if is_type_diagnostic_item(cx, expr_ty, sym::Vec)
&& let Some(slice) = derefs_to_slice(cx, recv, cx.typeck_results().expr_ty(recv))
+ && let ty::Adt(_, args) = expr_ty.kind()
+ && let Some(iter_item_ty) = get_iterator_item_ty(cx, cx.typeck_results().expr_ty(recv))
+ && let ty::Ref(_, iter_item_ty, _) = iter_item_ty.kind()
+ && *iter_item_ty == args.type_at(0)
&& let Some(to_replace) = expr.span.trim_start(slice.span.source_callsite())
{
span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
index bafabec..adeff37 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
@@ -6,12 +6,12 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{indent_of, reindent_multiline};
-use clippy_utils::{get_parent_expr, is_trait_method, peel_blocks, span_contains_comment};
+use clippy_utils::{get_parent_expr, is_trait_method, peel_blocks, span_contains_comment, sym};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::QPath;
use rustc_span::Span;
-use rustc_span::symbol::{Ident, Symbol, sym};
+use rustc_span::symbol::{Ident, Symbol};
///
/// Returns true if the expression is a method call to `method_name`
@@ -154,7 +154,7 @@ fn expression_type(
if let Some(opt_defid) = cx.tcx.get_diagnostic_item(sym::Option)
&& let opt_ty = cx.tcx.type_of(opt_defid).skip_binder()
&& iter_item_ty.ty_adt_def() == opt_ty.ty_adt_def()
- && is_method(cx, filter_arg, sym::Option, sym!(is_some), &[])
+ && is_method(cx, filter_arg, sym::Option, sym::is_some, &[])
{
return Some(FilterType::IsSome);
}
@@ -162,7 +162,7 @@ fn expression_type(
if let Some(opt_defid) = cx.tcx.get_diagnostic_item(sym::Result)
&& let opt_ty = cx.tcx.type_of(opt_defid).skip_binder()
&& iter_item_ty.ty_adt_def() == opt_ty.ty_adt_def()
- && is_method(cx, filter_arg, sym::Result, sym!(is_ok), &[])
+ && is_method(cx, filter_arg, sym::Result, sym::is_ok, &[])
{
return Some(FilterType::IsOk);
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
index 94415fc..3ac9299 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -37,7 +37,7 @@ pub(super) fn check<'tcx>(
(PatKind::Binding(ann, _, key, _), value) if pat_is_wild(cx, value, m_arg) => ("key", ann, key),
_ => return,
}
- && let ty = cx.typeck_results().expr_ty(recv)
+ && let ty = cx.typeck_results().expr_ty_adjusted(recv).peel_refs()
&& (is_type_diagnostic_item(cx, ty, sym::HashMap) || is_type_diagnostic_item(cx, ty, sym::BTreeMap))
{
let mut applicability = rustc_errors::Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index f51bdc7..7bb6252 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -48,7 +48,7 @@ pub(super) fn check<'tcx>(
&& let Some(method_id) = typeck.type_dependent_def_id(cloned_call.hir_id)
&& cx.tcx.trait_of_item(method_id) == Some(iter_id)
&& let cloned_recv_ty = typeck.expr_ty_adjusted(cloned_recv)
- && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, "Item")
+ && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, sym::Item)
&& matches!(*iter_assoc_ty.kind(), ty::Ref(_, ty, _) if !is_copy(cx, ty))
{
if needs_into_iter
diff --git a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
index 9b35823..90d5d9d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs
@@ -8,14 +8,14 @@
use super::ITERATOR_STEP_BY_ZERO;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) {
- if is_trait_method(cx, expr, sym::Iterator) {
- if let Some(Constant::Int(0)) = ConstEvalCtxt::new(cx).eval(arg) {
- span_lint(
- cx,
- ITERATOR_STEP_BY_ZERO,
- expr.span,
- "`Iterator::step_by(0)` will panic at runtime",
- );
- }
+ if is_trait_method(cx, expr, sym::Iterator)
+ && let Some(Constant::Int(0)) = ConstEvalCtxt::new(cx).eval(arg)
+ {
+ span_lint(
+ cx,
+ ITERATOR_STEP_BY_ZERO,
+ expr.span,
+ "`Iterator::step_by(0)` will panic at runtime",
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
index 13918ed..18978a1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_saturating_arithmetic.rs
@@ -106,15 +106,15 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> {
};
let check_lit = |expr: &hir::Expr<'_>, check_min: bool| {
- if let hir::ExprKind::Lit(lit) = &expr.kind {
- if let ast::LitKind::Int(value, _) = lit.node {
- if value == maxval {
- return Some(MinMax::Max);
- }
+ if let hir::ExprKind::Lit(lit) = &expr.kind
+ && let ast::LitKind::Int(value, _) = lit.node
+ {
+ if value == maxval {
+ return Some(MinMax::Max);
+ }
- if check_min && value == minval {
- return Some(MinMax::Min);
- }
+ if check_min && value == minval {
+ return Some(MinMax::Min);
}
}
@@ -125,10 +125,10 @@ fn is_min_or_max(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<MinMax> {
return r;
}
- if ty.is_signed() {
- if let hir::ExprKind::Unary(hir::UnOp::Neg, val) = &expr.kind {
- return check_lit(val, true);
- }
+ if ty.is_signed()
+ && let hir::ExprKind::Unary(hir::UnOp::Neg, val) = &expr.kind
+ {
+ return check_lit(val, true);
}
None
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
index 098721d..8167e4f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
@@ -77,7 +77,7 @@ pub(super) fn check(
s @ Cow::Borrowed(_) => s,
},
RepeatKind::String => Sugg::hir_with_context(cx, repeat_arg, ctxt, "..", &mut app)
- .maybe_par()
+ .maybe_paren()
.to_string()
.into(),
};
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
index 128b369..333a33f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -51,19 +51,19 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_
let closure_expr = peel_blocks(closure_body.value);
match closure_body.params[0].pat.kind {
hir::PatKind::Ref(inner, Mutability::Not) => {
- if let hir::PatKind::Binding(hir::BindingMode::NONE, .., name, None) = inner.kind {
- if ident_eq(name, closure_expr) {
- lint_explicit_closure(cx, e.span, recv.span, true, msrv);
- }
+ if let hir::PatKind::Binding(hir::BindingMode::NONE, .., name, None) = inner.kind
+ && ident_eq(name, closure_expr)
+ {
+ lint_explicit_closure(cx, e.span, recv.span, true, msrv);
}
},
hir::PatKind::Binding(hir::BindingMode::NONE, .., name, None) => {
match closure_expr.kind {
hir::ExprKind::Unary(hir::UnOp::Deref, inner) => {
- if ident_eq(name, inner) {
- if let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind() {
- lint_explicit_closure(cx, e.span, recv.span, true, msrv);
- }
+ if ident_eq(name, inner)
+ && let ty::Ref(.., Mutability::Not) = cx.typeck_results().expr_ty(inner).kind()
+ {
+ lint_explicit_closure(cx, e.span, recv.span, true, msrv);
}
},
hir::ExprKind::MethodCall(method, obj, [], _) => {
@@ -114,19 +114,17 @@ fn handle_path(
) {
if let Some(path_def_id) = cx.qpath_res(qpath, arg.hir_id).opt_def_id()
&& cx.tcx.lang_items().get(LangItem::CloneFn) == Some(path_def_id)
- {
// The `copied` and `cloned` methods are only available on `&T` and `&mut T` in `Option`
// and `Result`.
- if let ty::Adt(_, args) = cx.typeck_results().expr_ty(recv).kind()
- && let args = args.as_slice()
- && let Some(ty) = args.iter().find_map(|generic_arg| generic_arg.as_type())
- && let ty::Ref(_, ty, Mutability::Not) = ty.kind()
- && let ty::FnDef(_, lst) = cx.typeck_results().expr_ty(arg).kind()
- && lst.iter().all(|l| l.as_type() == Some(*ty))
- && !should_call_clone_as_function(cx, *ty)
- {
- lint_path(cx, e.span, recv.span, is_copy(cx, ty.peel_refs()));
- }
+ && let ty::Adt(_, args) = cx.typeck_results().expr_ty(recv).kind()
+ && let args = args.as_slice()
+ && let Some(ty) = args.iter().find_map(|generic_arg| generic_arg.as_type())
+ && let ty::Ref(_, ty, Mutability::Not) = ty.kind()
+ && let ty::FnDef(_, lst) = cx.typeck_results().expr_ty(arg).kind()
+ && lst.iter().all(|l| l.as_type() == Some(*ty))
+ && !should_call_clone_as_function(cx, *ty)
+ {
+ lint_path(cx, e.span, recv.span, is_copy(cx, ty.peel_refs()));
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs b/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs
index 6cf0936..a2a522a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_with_unused_argument_over_ranges.rs
@@ -41,7 +41,7 @@ fn extract_count_with_applicability(
return Some(format!("{count}"));
}
let end_snippet = Sugg::hir_with_applicability(cx, end, "...", applicability)
- .maybe_par()
+ .maybe_paren()
.into_string();
if lower_bound == 0 {
if range.limits == RangeLimits::Closed {
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 1d92960..ad374de 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -114,6 +114,7 @@
mod suspicious_map;
mod suspicious_splitn;
mod suspicious_to_owned;
+mod swap_with_temporary;
mod type_id_on_box;
mod unbuffered_bytes;
mod uninit_assumed_init;
@@ -478,9 +479,6 @@
/// Because you usually call `expect()` on the `Result`
/// directly to get a better error message.
///
- /// ### Known problems
- /// The error type needs to implement `Debug`
- ///
/// ### Example
/// ```no_run
/// # let x = Ok::<_, ()>(());
@@ -2429,7 +2427,7 @@
///
/// ### Limitations
/// This lint currently only looks for usages of
- /// `.then_some(..).unwrap_or(..)` and `.then(..).unwrap_or(..)`, but will be expanded
+ /// `.{then, then_some}(..).{unwrap_or, unwrap_or_else, unwrap_or_default}(..)`, but will be expanded
/// to account for similar patterns.
///
/// ### Example
@@ -4286,7 +4284,7 @@
/// ```no_run
/// let last_arg = "echo hello world".split(' ').next_back();
/// ```
- #[clippy::version = "1.85.0"]
+ #[clippy::version = "1.86.0"]
pub DOUBLE_ENDED_ITERATOR_LAST,
perf,
"using `Iterator::last` on a `DoubleEndedIterator`"
@@ -4478,12 +4476,59 @@
/// ```no_run
/// let _ = std::io::Error::other("bad".to_string());
/// ```
- #[clippy::version = "1.86.0"]
+ #[clippy::version = "1.87.0"]
pub IO_OTHER_ERROR,
style,
"calling `std::io::Error::new(std::io::ErrorKind::Other, _)`"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for usage of `std::mem::swap` with temporary values.
+ ///
+ /// ### Why is this bad?
+ /// Storing a new value in place of a temporary value which will
+ /// be dropped right after the `swap` is an inefficient way of performing
+ /// an assignment. The same result can be achieved by using a regular
+ /// assignment.
+ ///
+ /// ### Examples
+ /// ```no_run
+ /// fn replace_string(s: &mut String) {
+ /// std::mem::swap(s, &mut String::from("replaced"));
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```no_run
+ /// fn replace_string(s: &mut String) {
+ /// *s = String::from("replaced");
+ /// }
+ /// ```
+ ///
+ /// Also, swapping two temporary values has no effect, as they will
+ /// both be dropped right after swapping them. This is likely an indication
+ /// of a bug. For example, the following code swaps the references to
+ /// the last element of the vectors, instead of swapping the elements
+ /// themselves:
+ ///
+ /// ```no_run
+ /// fn bug(v1: &mut [i32], v2: &mut [i32]) {
+ /// // Incorrect: swapping temporary references (`&mut &mut` passed to swap)
+ /// std::mem::swap(&mut v1.last_mut().unwrap(), &mut v2.last_mut().unwrap());
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```no_run
+ /// fn correct(v1: &mut [i32], v2: &mut [i32]) {
+ /// std::mem::swap(v1.last_mut().unwrap(), v2.last_mut().unwrap());
+ /// }
+ /// ```
+ #[clippy::version = "1.88.0"]
+ pub SWAP_WITH_TEMPORARY,
+ complexity,
+ "detect swap with a temporary value"
+}
+
#[expect(clippy::struct_excessive_bools)]
pub struct Methods {
avoid_breaking_exported_api: bool,
@@ -4661,17 +4706,19 @@ pub fn new(conf: &'static Conf, format_args: FormatArgsStorage) -> Self {
UNBUFFERED_BYTES,
MANUAL_CONTAINS,
IO_OTHER_ERROR,
+ SWAP_WITH_TEMPORARY,
]);
/// Extracts a method call name, args, and `Span` of the method name.
pub fn method_call<'tcx>(
recv: &'tcx Expr<'tcx>,
) -> Option<(&'tcx str, &'tcx Expr<'tcx>, &'tcx [Expr<'tcx>], Span, Span)> {
- if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind {
- if !args.iter().any(|e| e.span.from_expansion()) && !receiver.span.from_expansion() {
- let name = path.ident.name.as_str();
- return Some((name, receiver, args, path.ident.span, call_span));
- }
+ if let ExprKind::MethodCall(path, receiver, args, call_span) = recv.kind
+ && !args.iter().any(|e| e.span.from_expansion())
+ && !receiver.span.from_expansion()
+ {
+ let name = path.ident.name.as_str();
+ return Some((name, receiver, args, path.ident.span, call_span));
}
None
}
@@ -4691,6 +4738,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
manual_c_str_literals::check(cx, expr, func, args, self.msrv);
useless_nonzero_new_unchecked::check(cx, expr, func, args, self.msrv);
io_other_error::check(cx, expr, func, args, self.msrv);
+ swap_with_temporary::check(cx, expr, func, args);
},
ExprKind::MethodCall(method_call, receiver, args, _) => {
let method_span = method_call.ident.span;
@@ -4992,7 +5040,7 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
},
("ends_with", [arg]) => {
if let ExprKind::MethodCall(.., span) = expr.kind {
- case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg);
+ case_sensitive_file_extension_comparisons::check(cx, expr, span, recv, arg, self.msrv);
}
path_ends_with_ext::check(cx, recv, arg, expr, self.msrv, &self.allowed_dotfiles);
},
@@ -5421,15 +5469,21 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span, self.msrv);
},
Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => {
- obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg, then_method, "unwrap_or");
+ obfuscated_if_else::check(cx, expr, t_recv, t_arg, Some(u_arg), then_method, "unwrap_or");
},
_ => {},
}
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
},
("unwrap_or_default", []) => {
- if let Some(("map", m_recv, [arg], span, _)) = method_call(recv) {
- manual_is_variant_and::check(cx, expr, m_recv, arg, span, self.msrv);
+ match method_call(recv) {
+ Some(("map", m_recv, [arg], span, _)) => {
+ manual_is_variant_and::check(cx, expr, m_recv, arg, span, self.msrv);
+ },
+ Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => {
+ obfuscated_if_else::check(cx, expr, t_recv, t_arg, None, then_method, "unwrap_or_default");
+ },
+ _ => {},
}
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
},
@@ -5441,7 +5495,15 @@ fn check_methods<'tcx>(&self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
Some(("map", recv, [map_arg], _, _))
if map_unwrap_or::check(cx, expr, recv, map_arg, u_arg, self.msrv) => {},
Some((then_method @ ("then" | "then_some"), t_recv, [t_arg], _, _)) => {
- obfuscated_if_else::check(cx, expr, t_recv, t_arg, u_arg, then_method, "unwrap_or_else");
+ obfuscated_if_else::check(
+ cx,
+ expr,
+ t_recv,
+ t_arg,
+ Some(u_arg),
+ then_method,
+ "unwrap_or_else",
+ );
},
_ => {
unnecessary_lazy_eval::check(cx, expr, recv, u_arg, "unwrap_or");
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 239ee6c..6efaba5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -4,7 +4,9 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
-use clippy_utils::ty::{get_type_diagnostic_name, make_normalized_projection, make_projection};
+use clippy_utils::ty::{
+ get_type_diagnostic_name, has_non_owning_mutable_access, make_normalized_projection, make_projection,
+};
use clippy_utils::{
CaptureKind, can_move_expr_to_closure, fn_def_id, get_enclosing_block, higher, is_trait_method, path_to_local,
path_to_local_id,
@@ -17,12 +19,13 @@
};
use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty};
+use rustc_middle::ty::{self, AssocTag, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty};
use rustc_span::symbol::Ident;
use rustc_span::{Span, sym};
const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";
+#[expect(clippy::too_many_lines)]
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
name_span: Span,
@@ -30,6 +33,11 @@ pub(super) fn check<'tcx>(
iter_expr: &'tcx Expr<'tcx>,
call_span: Span,
) {
+ let iter_ty = cx.typeck_results().expr_ty(iter_expr);
+ if has_non_owning_mutable_access(cx, iter_ty) {
+ return; // don't lint if the iterator has side effects
+ }
+
match cx.tcx.parent_hir_node(collect_expr.hir_id) {
Node::Expr(parent) => {
check_collect_into_intoiterator(cx, parent, collect_expr, call_span, iter_expr);
@@ -241,7 +249,7 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -
&& let Some(iter_item) = cx.tcx.associated_items(iter_trait).find_by_ident_and_kind(
cx.tcx,
Ident::with_dummy_span(sym::Item),
- AssocKind::Type,
+ AssocTag::Type,
iter_trait,
)
&& let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))])
@@ -377,20 +385,20 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) {
return;
}
- if let Some(hir_id) = path_to_local(recv) {
- if let Some(index) = self.hir_id_uses_map.remove(&hir_id) {
- if self
- .illegal_mutable_capture_ids
- .intersection(&self.current_mutably_captured_ids)
- .next()
- .is_none()
- {
- if let Some(hir_id) = self.current_statement_hir_id {
- self.hir_id_uses_map.insert(hir_id, index);
- }
- } else {
- self.uses[index] = None;
+ if let Some(hir_id) = path_to_local(recv)
+ && let Some(index) = self.hir_id_uses_map.remove(&hir_id)
+ {
+ if self
+ .illegal_mutable_capture_ids
+ .intersection(&self.current_mutably_captured_ids)
+ .next()
+ .is_none()
+ {
+ if let Some(hir_id) = self.current_statement_hir_id {
+ self.hir_id_uses_map.insert(hir_id, index);
}
+ } else {
+ self.uses[index] = None;
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs b/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs
index 88b9c69..cd1b97f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_option_take.rs
@@ -9,26 +9,27 @@
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
// Checks if expression type is equal to sym::Option and if the expr is not a syntactic place
- if !recv.is_syntactic_place_expr() && is_expr_option(cx, recv) {
- if let Some(function_name) = source_of_temporary_value(recv) {
- span_lint_and_then(
- cx,
- NEEDLESS_OPTION_TAKE,
- expr.span,
- "called `Option::take()` on a temporary value",
- |diag| {
- diag.note(format!(
- "`{function_name}` creates a temporary value, so calling take() has no effect"
- ));
- diag.span_suggestion(
- expr.span.with_lo(recv.span.hi()),
- "remove",
- "",
- Applicability::MachineApplicable,
- );
- },
- );
- }
+ if !recv.is_syntactic_place_expr()
+ && is_expr_option(cx, recv)
+ && let Some(function_name) = source_of_temporary_value(recv)
+ {
+ span_lint_and_then(
+ cx,
+ NEEDLESS_OPTION_TAKE,
+ expr.span,
+ "called `Option::take()` on a temporary value",
+ |diag| {
+ diag.note(format!(
+ "`{function_name}` creates a temporary value, so calling take() has no effect"
+ ));
+ diag.span_suggestion(
+ expr.span.with_lo(recv.span.hi()),
+ "remove",
+ "",
+ Applicability::MachineApplicable,
+ );
+ },
+ );
}
}
@@ -44,10 +45,10 @@ fn is_expr_option(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
fn source_of_temporary_value<'a>(expr: &'a Expr<'_>) -> Option<&'a str> {
match expr.peel_borrows().kind {
ExprKind::Call(function, _) => {
- if let ExprKind::Path(QPath::Resolved(_, func_path)) = function.kind {
- if !func_path.segments.is_empty() {
- return Some(func_path.segments[0].ident.name.as_str());
- }
+ if let ExprKind::Path(QPath::Resolved(_, func_path)) = function.kind
+ && !func_path.segments.is_empty()
+ {
+ return Some(func_path.segments[0].ident.name.as_str());
}
if let ExprKind::Path(QPath::TypeRelative(_, func_path_segment)) = function.kind {
return Some(func_path_segment.ident.name.as_str());
diff --git a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
index 9a5ffde..1cc56de 100644
--- a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs
@@ -14,14 +14,17 @@ pub(super) fn check<'tcx>(
expr: &'tcx hir::Expr<'_>,
then_recv: &'tcx hir::Expr<'_>,
then_arg: &'tcx hir::Expr<'_>,
- unwrap_arg: &'tcx hir::Expr<'_>,
+ unwrap_arg: Option<&'tcx hir::Expr<'_>>,
then_method_name: &str,
unwrap_method_name: &str,
) {
let recv_ty = cx.typeck_results().expr_ty(then_recv);
if recv_ty.is_bool() {
- let mut applicability = if switch_to_eager_eval(cx, then_arg) && switch_to_eager_eval(cx, unwrap_arg) {
+ let then_eager = switch_to_eager_eval(cx, then_arg);
+ let unwrap_eager = unwrap_arg.is_none_or(|arg| switch_to_eager_eval(cx, arg));
+
+ let mut applicability = if then_eager && unwrap_eager {
Applicability::MachineApplicable
} else {
Applicability::MaybeIncorrect
@@ -36,16 +39,17 @@ pub(super) fn check<'tcx>(
_ => return,
};
- // FIXME: Add `unwrap_or_else` symbol
+ // FIXME: Add `unwrap_or_else` and `unwrap_or_default` symbol
let els = match unwrap_method_name {
- "unwrap_or" => snippet_with_applicability(cx, unwrap_arg.span, "..", &mut applicability),
- "unwrap_or_else" if let ExprKind::Closure(closure) = unwrap_arg.kind => {
+ "unwrap_or" => snippet_with_applicability(cx, unwrap_arg.unwrap().span, "..", &mut applicability),
+ "unwrap_or_else" if let ExprKind::Closure(closure) = unwrap_arg.unwrap().kind => {
let body = cx.tcx.hir_body(closure.body);
snippet_with_applicability(cx, body.value.span, "..", &mut applicability)
},
- "unwrap_or_else" if let ExprKind::Path(_) = unwrap_arg.kind => {
- snippet_with_applicability(cx, unwrap_arg.span, "_", &mut applicability) + "()"
+ "unwrap_or_else" if let ExprKind::Path(_) = unwrap_arg.unwrap().kind => {
+ snippet_with_applicability(cx, unwrap_arg.unwrap().span, "_", &mut applicability) + "()"
},
+ "unwrap_or_default" => "Default::default()".into(),
_ => return,
};
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index c03420a..b78b082 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -6,13 +6,13 @@
use clippy_utils::ty::{expr_type_is_certain, implements_trait, is_type_diagnostic_item};
use clippy_utils::visitors::for_each_expr;
use clippy_utils::{
- contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment, peel_blocks,
+ contains_return, is_default_equivalent, is_default_equivalent_call, last_path_segment, peel_blocks, sym,
};
use rustc_errors::Applicability;
use rustc_lint::LateContext;
use rustc_middle::ty;
use rustc_span::Span;
-use rustc_span::symbol::{self, Symbol, sym};
+use rustc_span::symbol::{self, Symbol};
use {rustc_ast as ast, rustc_hir as hir};
use super::{OR_FUN_CALL, UNWRAP_OR_DEFAULT};
@@ -66,8 +66,8 @@ fn check_unwrap_or_default(
};
let sugg = match (name, call_expr.is_some()) {
- ("unwrap_or", true) | ("unwrap_or_else", false) => sym!(unwrap_or_default),
- ("or_insert", true) | ("or_insert_with", false) => sym!(or_default),
+ ("unwrap_or", true) | ("unwrap_or_else", false) => sym::unwrap_or_default,
+ ("or_insert", true) | ("or_insert_with", false) => sym::or_default,
_ => return false,
};
@@ -78,8 +78,7 @@ fn check_unwrap_or_default(
.iter()
.flat_map(|impl_id| cx.tcx.associated_items(impl_id).filter_by_name_unhygienic(sugg))
.find_map(|assoc| {
- if assoc.fn_has_self_parameter
- && cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1
+ if assoc.is_method() && cx.tcx.fn_sig(assoc.def_id).skip_binder().inputs().skip_binder().len() == 1
{
Some(assoc.def_id)
} else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
index d318462..8b51268 100644
--- a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
@@ -3,33 +3,33 @@
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
-use rustc_span::sym;
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_enum_variant_ctor;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::implements_trait;
+use clippy_utils::{is_enum_variant_ctor, sym};
use super::SEEK_FROM_CURRENT;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
let ty = cx.typeck_results().expr_ty(recv);
- if let Some(def_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) {
- if implements_trait(cx, ty, def_id, &[]) && arg_is_seek_from_current(cx, arg) {
- let mut applicability = Applicability::MachineApplicable;
- let snip = snippet_with_applicability(cx, recv.span, "..", &mut applicability);
+ if let Some(def_id) = cx.tcx.get_diagnostic_item(sym::IoSeek)
+ && implements_trait(cx, ty, def_id, &[])
+ && arg_is_seek_from_current(cx, arg)
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let snip = snippet_with_applicability(cx, recv.span, "..", &mut applicability);
- span_lint_and_sugg(
- cx,
- SEEK_FROM_CURRENT,
- expr.span,
- "using `SeekFrom::Current` to start from current position",
- "replace with",
- format!("{snip}.stream_position()"),
- applicability,
- );
- }
+ span_lint_and_sugg(
+ cx,
+ SEEK_FROM_CURRENT,
+ expr.span,
+ "using `SeekFrom::Current` to start from current position",
+ "replace with",
+ format!("{snip}.stream_position()"),
+ applicability,
+ );
}
}
@@ -37,14 +37,12 @@ fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>)
if let ExprKind::Call(f, [arg]) = expr.kind
&& let ExprKind::Path(ref path) = f.kind
&& let Some(ctor_call_id) = cx.qpath_res(path, f.hir_id).opt_def_id()
- && is_enum_variant_ctor(cx, sym::SeekFrom, sym!(Current), ctor_call_id)
- {
+ && is_enum_variant_ctor(cx, sym::SeekFrom, sym::Current, ctor_call_id)
// check if argument of `SeekFrom::Current` is `0`
- if let ExprKind::Lit(lit) = arg.kind
- && let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node
- {
- return true;
- }
+ && let ExprKind::Lit(lit) = arg.kind
+ && let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node
+ {
+ return true;
}
false
diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
index 7b1dd9e..b8405a7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
@@ -1,12 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::implements_trait;
-use clippy_utils::{is_enum_variant_ctor, is_expr_used_or_unified};
+use clippy_utils::{is_enum_variant_ctor, is_expr_used_or_unified, sym};
use rustc_ast::ast::{LitIntType, LitKind};
use rustc_data_structures::packed::Pu128;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
-use rustc_span::{Span, sym};
+use rustc_span::Span;
use super::SEEK_TO_START_INSTEAD_OF_REWIND;
@@ -29,7 +29,7 @@ pub(super) fn check<'tcx>(
&& let ExprKind::Call(func, [arg]) = arg.kind
&& let ExprKind::Path(ref path) = func.kind
&& let Some(ctor_call_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
- && is_enum_variant_ctor(cx, sym::SeekFrom, sym!(Start), ctor_call_id)
+ && is_enum_variant_ctor(cx, sym::SeekFrom, sym::Start, ctor_call_id)
&& let ExprKind::Lit(lit) = arg.kind
&& let LitKind::Int(Pu128(0), LitIntType::Unsuffixed) = lit.node
{
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 4ccefb7..d183457 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -238,15 +238,14 @@ fn indirect_usage<'tcx>(
unwrap_kind: Some(unwrap_kind),
..
} = iter_usage
+ && parent_id == local_hir_id
{
- if parent_id == local_hir_id {
- return Some(IndirectUsage {
- name: ident.name,
- span: stmt.span,
- init_expr,
- unwrap_kind,
- });
- }
+ return Some(IndirectUsage {
+ name: ident.name,
+ span: stmt.span,
+ init_expr,
+ unwrap_kind,
+ });
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
index 1bd4852..788014d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_map.rs
@@ -13,11 +13,11 @@ pub fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, count_recv: &hir::Expr<
&& let closure_body = cx.tcx.hir_body(closure.body)
&& !cx.typeck_results().expr_ty(closure_body.value).is_unit()
{
- if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx) {
+ if let Some(map_mutated_vars) = mutated_variables(closure_body.value, cx)
// A variable is used mutably inside of the closure. Suppress the lint.
- if !map_mutated_vars.is_empty() {
- return;
- }
+ && !map_mutated_vars.is_empty()
+ {
+ return;
}
span_lint_and_help(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/swap_with_temporary.rs b/src/tools/clippy/clippy_lints/src/methods/swap_with_temporary.rs
new file mode 100644
index 0000000..de729fb
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/swap_with_temporary.rs
@@ -0,0 +1,125 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::sugg::Sugg;
+use rustc_ast::BorrowKind;
+use rustc_errors::{Applicability, Diag};
+use rustc_hir::{Expr, ExprKind, Node, QPath};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::SWAP_WITH_TEMPORARY;
+
+const MSG_TEMPORARY: &str = "this expression returns a temporary value";
+const MSG_TEMPORARY_REFMUT: &str = "this is a mutable reference to a temporary value";
+
+pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, func: &Expr<'_>, args: &[Expr<'_>]) {
+ if let ExprKind::Path(QPath::Resolved(_, func_path)) = func.kind
+ && let Some(func_def_id) = func_path.res.opt_def_id()
+ && cx.tcx.is_diagnostic_item(sym::mem_swap, func_def_id)
+ {
+ match (ArgKind::new(&args[0]), ArgKind::new(&args[1])) {
+ (ArgKind::RefMutToTemp(left_temp), ArgKind::RefMutToTemp(right_temp)) => {
+ emit_lint_useless(cx, expr, &args[0], &args[1], left_temp, right_temp);
+ },
+ (ArgKind::RefMutToTemp(left_temp), right) => emit_lint_assign(cx, expr, &right, &args[0], left_temp),
+ (left, ArgKind::RefMutToTemp(right_temp)) => emit_lint_assign(cx, expr, &left, &args[1], right_temp),
+ _ => {},
+ }
+ }
+}
+
+enum ArgKind<'tcx> {
+ // Mutable reference to a place, coming from a macro
+ RefMutToPlaceAsMacro(&'tcx Expr<'tcx>),
+ // Place behind a mutable reference
+ RefMutToPlace(&'tcx Expr<'tcx>),
+ // Temporary value behind a mutable reference
+ RefMutToTemp(&'tcx Expr<'tcx>),
+ // Any other case
+ Expr(&'tcx Expr<'tcx>),
+}
+
+impl<'tcx> ArgKind<'tcx> {
+ fn new(arg: &'tcx Expr<'tcx>) -> Self {
+ if let ExprKind::AddrOf(BorrowKind::Ref, _, target) = arg.kind {
+ if target.is_syntactic_place_expr() {
+ if arg.span.from_expansion() {
+ ArgKind::RefMutToPlaceAsMacro(arg)
+ } else {
+ ArgKind::RefMutToPlace(target)
+ }
+ } else {
+ ArgKind::RefMutToTemp(target)
+ }
+ } else {
+ ArgKind::Expr(arg)
+ }
+ }
+}
+
+// Emits a note either on the temporary expression if it can be found in the same context as the
+// base and returns `true`, or on the mutable reference to the temporary expression otherwise and
+// returns `false`.
+fn emit_note(diag: &mut Diag<'_, ()>, base: &Expr<'_>, expr: &Expr<'_>, expr_temp: &Expr<'_>) -> bool {
+ if base.span.eq_ctxt(expr.span) {
+ diag.span_note(expr_temp.span.source_callsite(), MSG_TEMPORARY);
+ true
+ } else {
+ diag.span_note(expr.span.source_callsite(), MSG_TEMPORARY_REFMUT);
+ false
+ }
+}
+
+fn emit_lint_useless(
+ cx: &LateContext<'_>,
+ expr: &Expr<'_>,
+ left: &Expr<'_>,
+ right: &Expr<'_>,
+ left_temp: &Expr<'_>,
+ right_temp: &Expr<'_>,
+) {
+ span_lint_and_then(
+ cx,
+ SWAP_WITH_TEMPORARY,
+ expr.span,
+ "swapping temporary values has no effect",
+ |diag| {
+ emit_note(diag, expr, left, left_temp);
+ emit_note(diag, expr, right, right_temp);
+ },
+ );
+}
+
+fn emit_lint_assign(cx: &LateContext<'_>, expr: &Expr<'_>, target: &ArgKind<'_>, reftemp: &Expr<'_>, temp: &Expr<'_>) {
+ span_lint_and_then(
+ cx,
+ SWAP_WITH_TEMPORARY,
+ expr.span,
+ "swapping with a temporary value is inefficient",
+ |diag| {
+ if !emit_note(diag, expr, reftemp, temp) {
+ return;
+ }
+
+ // Make the suggestion only when the original `swap()` call is a statement
+ // or the last expression in a block.
+ if matches!(cx.tcx.parent_hir_node(expr.hir_id), Node::Stmt(..) | Node::Block(..)) {
+ let mut applicability = Applicability::MachineApplicable;
+ let ctxt = expr.span.ctxt();
+ let assign_target = match target {
+ ArgKind::Expr(target) | ArgKind::RefMutToPlaceAsMacro(target) => {
+ Sugg::hir_with_context(cx, target, ctxt, "_", &mut applicability).deref()
+ },
+ ArgKind::RefMutToPlace(target) => Sugg::hir_with_context(cx, target, ctxt, "_", &mut applicability),
+ ArgKind::RefMutToTemp(_) => unreachable!(),
+ };
+ let assign_source = Sugg::hir_with_context(cx, temp, ctxt, "_", &mut applicability);
+ diag.span_suggestion(
+ expr.span,
+ "use assignment instead",
+ format!("{assign_target} = {assign_source}"),
+ applicability,
+ );
+ }
+ },
+ );
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
index ca42a9a..f920f30 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_filter_map.rs
@@ -1,11 +1,10 @@
use super::utils::clone_or_copy_needed;
-use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::is_copy;
use clippy_utils::usage::mutated_variables;
use clippy_utils::visitors::{Descend, for_each_expr_without_closures};
use clippy_utils::{is_res_lang_ctor, is_trait_method, path_res, path_to_local_id};
use core::ops::ControlFlow;
-use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::LangItem::{OptionNone, OptionSome};
use rustc_lint::LateContext;
@@ -45,30 +44,32 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
&& is_res_lang_ctor(cx, path_res(cx, expr), OptionSome)
&& let hir::ExprKind::Path(_) = args[0].kind
{
- span_lint_and_sugg(
+ span_lint(
cx,
UNNECESSARY_FILTER_MAP,
expr.span,
- format!("{name} is unnecessary"),
- "try removing the filter_map",
- String::new(),
- Applicability::MaybeIncorrect,
+ String::from("this call to `.filter_map(..)` is unnecessary"),
);
+ return;
}
- if name == "filter_map" { "map" } else { "map(..).next()" }
+ if name == "filter_map" {
+ "map(..)"
+ } else {
+ "map(..).next()"
+ }
} else if !found_mapping && !mutates_arg && (!clone_or_copy_needed || is_copy(cx, in_ty)) {
match cx.typeck_results().expr_ty(body.value).kind() {
ty::Adt(adt, subst)
if cx.tcx.is_diagnostic_item(sym::Option, adt.did()) && in_ty == subst.type_at(0) =>
{
- if name == "filter_map" { "filter" } else { "find" }
+ if name == "filter_map" { "filter(..)" } else { "find(..)" }
},
_ => return,
}
} else {
return;
};
- span_lint_and_sugg(
+ span_lint(
cx,
if name == "filter_map" {
UNNECESSARY_FILTER_MAP
@@ -76,10 +77,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>, a
UNNECESSARY_FIND_MAP
},
expr.span,
- format!("this `.{name}` can be written more simply"),
- "try instead",
- sugg.to_string(),
- Applicability::MaybeIncorrect,
+ format!("this `.{name}(..)` can be written more simply using `.{sugg}`"),
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
index c0e0156..20cf353 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
@@ -99,7 +99,7 @@ fn is_caller_or_fields_change(cx: &LateContext<'_>, body: &Expr<'_>, caller: &Ex
&& let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
&& let collection_ty = cx.typeck_results().expr_ty(collection)
&& implements_trait(cx, collection_ty, into_iterator_trait_id, &[])
- && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item")
+ && let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, sym::Item)
&& iter_item_ty == into_iter_item_ty
&& let Some(collection_snippet) = collection.span.get_source_text(cx)
{
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index 9f40801..71e606a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -23,56 +23,61 @@ pub(super) fn check<'tcx>(
let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
let is_bool = cx.typeck_results().expr_ty(recv).is_bool();
- if is_option || is_result || is_bool {
- if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl, .. }) = arg.kind {
- let body = cx.tcx.hir_body(body);
- let body_expr = &body.value;
+ if (is_option || is_result || is_bool)
+ && let hir::ExprKind::Closure(&hir::Closure {
+ body,
+ fn_decl,
+ kind: hir::ClosureKind::Closure,
+ ..
+ }) = arg.kind
+ {
+ let body = cx.tcx.hir_body(body);
+ let body_expr = &body.value;
- if usage::BindingUsageFinder::are_params_used(cx, body) || is_from_proc_macro(cx, expr) {
- return false;
- }
+ if usage::BindingUsageFinder::are_params_used(cx, body) || is_from_proc_macro(cx, expr) {
+ return false;
+ }
- if eager_or_lazy::switch_to_eager_eval(cx, body_expr) {
- let msg = if is_option {
- "unnecessary closure used to substitute value for `Option::None`"
- } else if is_result {
- "unnecessary closure used to substitute value for `Result::Err`"
- } else {
- "unnecessary closure used with `bool::then`"
- };
- let applicability = if body
- .params
- .iter()
- // bindings are checked to be unused above
- .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild))
- && matches!(
- fn_decl.output,
- FnRetTy::DefaultReturn(_)
- | FnRetTy::Return(hir::Ty {
- kind: hir::TyKind::Infer(()),
- ..
- })
- ) {
- Applicability::MachineApplicable
- } else {
- // replacing the lambda may break type inference
- Applicability::MaybeIncorrect
- };
+ if eager_or_lazy::switch_to_eager_eval(cx, body_expr) {
+ let msg = if is_option {
+ "unnecessary closure used to substitute value for `Option::None`"
+ } else if is_result {
+ "unnecessary closure used to substitute value for `Result::Err`"
+ } else {
+ "unnecessary closure used with `bool::then`"
+ };
+ let applicability = if body
+ .params
+ .iter()
+ // bindings are checked to be unused above
+ .all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild))
+ && matches!(
+ fn_decl.output,
+ FnRetTy::DefaultReturn(_)
+ | FnRetTy::Return(hir::Ty {
+ kind: hir::TyKind::Infer(()),
+ ..
+ })
+ ) {
+ Applicability::MachineApplicable
+ } else {
+ // replacing the lambda may break type inference
+ Applicability::MaybeIncorrect
+ };
- // This is a duplicate of what's happening in clippy_lints::methods::method_call,
- // which isn't ideal, We want to get the method call span,
- // but prefer to avoid changing the signature of the function itself.
- if let hir::ExprKind::MethodCall(.., span) = expr.kind {
- span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| {
- diag.span_suggestion_verbose(
- span,
- format!("use `{simplify_using}` instead"),
- format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")),
- applicability,
- );
- });
- return true;
- }
+ // This is a duplicate of what's happening in clippy_lints::methods::method_call,
+ // which isn't ideal, We want to get the method call span,
+ // but prefer to avoid changing the signature of the function itself.
+ if let hir::ExprKind::MethodCall(.., span) = expr.kind {
+ span_lint_and_then(cx, UNNECESSARY_LAZY_EVALUATIONS, expr.span, msg, |diag| {
+ diag.span_suggestion_verbose(
+ span,
+ format!("use `{simplify_using}` instead"),
+ format!("{simplify_using}({})", snippet(cx, body_expr.span, "..")),
+ applicability,
+ );
+ });
+ return true;
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
index d7bd522..b90748d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
@@ -76,7 +76,7 @@ pub(super) fn check<'a>(
&& ((BinOpKind::Eq == op.node && !def_bool) || (BinOpKind::Ne == op.node && def_bool))
&& let non_binding_location = if path_to_local_id(l, hir_id) { r } else { l }
&& switch_to_eager_eval(cx, non_binding_location)
- // xor, because if its both then thats a strange edge case and
+ // xor, because if its both then that's a strange edge case and
// we can just ignore it, since by default clippy will error on this
&& (path_to_local_id(l, hir_id) ^ path_to_local_id(r, hir_id))
&& !is_local_used(cx, non_binding_location, hir_id)
@@ -92,7 +92,7 @@ pub(super) fn check<'a>(
// we may need to add parens around the suggestion
// in case the parent expression has additional method calls,
// since for example `Some(5).map_or(false, |x| x == 5).then(|| 1)`
- // being converted to `Some(5) == Some(5).then(|| 1)` isnt
+ // being converted to `Some(5) == Some(5).then(|| 1)` isn't
// the same thing
let inner_non_binding = Sugg::NonParen(Cow::Owned(format!(
@@ -109,8 +109,8 @@ pub(super) fn check<'a>(
let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr) {
match parent_expr.kind {
- ExprKind::Binary(..) | ExprKind::Unary(..) | ExprKind::Cast(..) => binop.maybe_par(),
- ExprKind::MethodCall(_, receiver, _, _) if receiver.hir_id == expr.hir_id => binop.maybe_par(),
+ ExprKind::Binary(..) | ExprKind::Unary(..) | ExprKind::Cast(..) => binop.maybe_paren(),
+ ExprKind::MethodCall(_, receiver, _, _) if receiver.hir_id == expr.hir_id => binop.maybe_paren(),
_ => binop,
}
} else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 62ba301..206b0a8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -153,7 +153,7 @@ fn check_addr_of_expr(
}
if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
&& implements_trait(cx, receiver_ty, deref_trait_id, &[])
- && cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty)
+ && cx.get_associated_type(receiver_ty, deref_trait_id, sym::Target) == Some(target_ty)
// Make sure that it's actually calling the right `.to_string()`, (#10033)
// *or* this is a `Cow::into_owned()` call (which would be the wrong into_owned receiver (str != Cow)
// but that's ok for Cow::into_owned specifically)
@@ -322,7 +322,7 @@ fn check_split_call_arg(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symb
// add `.as_ref()` to the suggestion.
let as_ref = if is_type_lang_item(cx, cx.typeck_results().expr_ty(expr), LangItem::String)
&& let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
- && cx.get_associated_type(cx.typeck_results().expr_ty(receiver), deref_trait_id, "Target")
+ && cx.get_associated_type(cx.typeck_results().expr_ty(receiver), deref_trait_id, sym::Target)
!= Some(cx.tcx.types.str_)
{
".as_ref()"
@@ -648,7 +648,7 @@ fn is_to_string_on_string_like<'a>(
&& let GenericArgKind::Type(ty) = generic_arg.unpack()
&& let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
&& let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
- && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_)
+ && (cx.get_associated_type(ty, deref_trait_id, sym::Target) == Some(cx.tcx.types.str_)
|| implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()]))
{
true
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index 3611b34..b0cc7a7 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -8,6 +8,9 @@
use rustc_span::Span;
use rustc_span::symbol::sym;
+/// Checks if `expr`, of type `ty`, corresponds to a slice or can be dereferenced to a slice, or if
+/// `expr` is a method call to `.iter()` on such a type. In these cases, return the slice-like
+/// expression.
pub(super) fn derefs_to_slice<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/builtin_type_shadow.rs b/src/tools/clippy/clippy_lints/src/misc_early/builtin_type_shadow.rs
index 662f7cd..9ee1e2f 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/builtin_type_shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/builtin_type_shadow.rs
@@ -6,14 +6,14 @@
use super::BUILTIN_TYPE_SHADOW;
pub(super) fn check(cx: &EarlyContext<'_>, param: &GenericParam) {
- if let GenericParamKind::Type { .. } = param.kind {
- if let Some(prim_ty) = PrimTy::from_name(param.ident.name) {
- span_lint(
- cx,
- BUILTIN_TYPE_SHADOW,
- param.ident.span,
- format!("this generic shadows the built-in type `{}`", prim_ty.name()),
- );
- }
+ if let GenericParamKind::Type { .. } = param.kind
+ && let Some(prim_ty) = PrimTy::from_name(param.ident.name)
+ {
+ span_lint(
+ cx,
+ BUILTIN_TYPE_SHADOW,
+ param.ident.span,
+ format!("this generic shadows the built-in type `{}`", prim_ty.name()),
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs
index d5b5b2b..3cb5167 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/redundant_pattern.rs
@@ -6,20 +6,20 @@
use super::REDUNDANT_PATTERN;
pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
- if let PatKind::Ident(ann, ident, Some(ref right)) = pat.kind {
- if let PatKind::Wild = right.kind {
- span_lint_and_sugg(
- cx,
- REDUNDANT_PATTERN,
- pat.span,
- format!(
- "the `{} @ _` pattern can be written as just `{}`",
- ident.name, ident.name,
- ),
- "try",
- format!("{}{}", ann.prefix_str(), ident.name),
- Applicability::MachineApplicable,
- );
- }
+ if let PatKind::Ident(ann, ident, Some(ref right)) = pat.kind
+ && let PatKind::Wild = right.kind
+ {
+ span_lint_and_sugg(
+ cx,
+ REDUNDANT_PATTERN,
+ pat.span,
+ format!(
+ "the `{} @ _` pattern can be written as just `{}`",
+ ident.name, ident.name,
+ ),
+ "try",
+ format!("{}{}", ann.prefix_str(), ident.name),
+ Applicability::MachineApplicable,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
index 00f4662..fffaf40 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
@@ -7,30 +7,30 @@
use super::UNNEEDED_WILDCARD_PATTERN;
pub(super) fn check(cx: &EarlyContext<'_>, pat: &Pat) {
- if let PatKind::TupleStruct(_, _, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind {
- if let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest()) {
- if let Some((left_index, left_pat)) = patterns[..rest_index]
- .iter()
- .rev()
- .take_while(|pat| matches!(pat.kind, PatKind::Wild))
- .enumerate()
- .last()
- {
- span_lint(cx, left_pat.span.until(patterns[rest_index].span), left_index == 0);
- }
+ if let PatKind::TupleStruct(_, _, ref patterns) | PatKind::Tuple(ref patterns) = pat.kind
+ && let Some(rest_index) = patterns.iter().position(|pat| pat.is_rest())
+ {
+ if let Some((left_index, left_pat)) = patterns[..rest_index]
+ .iter()
+ .rev()
+ .take_while(|pat| matches!(pat.kind, PatKind::Wild))
+ .enumerate()
+ .last()
+ {
+ span_lint(cx, left_pat.span.until(patterns[rest_index].span), left_index == 0);
+ }
- if let Some((right_index, right_pat)) = patterns[rest_index + 1..]
- .iter()
- .take_while(|pat| matches!(pat.kind, PatKind::Wild))
- .enumerate()
- .last()
- {
- span_lint(
- cx,
- patterns[rest_index].span.shrink_to_hi().to(right_pat.span),
- right_index == 0,
- );
- }
+ if let Some((right_index, right_pat)) = patterns[rest_index + 1..]
+ .iter()
+ .take_while(|pat| matches!(pat.kind, PatKind::Wild))
+ .enumerate()
+ .last()
+ {
+ span_lint(
+ cx,
+ patterns[rest_index].span.shrink_to_hi().to(right_pat.span),
+ right_index == 0,
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
index d52fe7e..394bc4a 100644
--- a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
+++ b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
@@ -111,10 +111,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
// Checks if impl_param_name is the same as one of type_param_names,
// and is in a different position
fn mismatch_param_name(i: usize, impl_param_name: &String, type_param_names: &FxHashMap<&String, usize>) -> bool {
- if let Some(j) = type_param_names.get(impl_param_name) {
- if i != *j {
- return true;
- }
+ if let Some(j) = type_param_names.get(impl_param_name)
+ && i != *j
+ {
+ return true;
}
false
}
diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
index cdd6f4e..c8e3462 100644
--- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
@@ -3,14 +3,15 @@
use clippy_utils::comparisons::{Rel, normalize_comparison};
use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::macros::{find_assert_eq_args, first_node_macro_backtrace};
use clippy_utils::source::snippet;
use clippy_utils::visitors::for_each_expr_without_closures;
use clippy_utils::{eq_expr_value, hash_expr, higher};
-use rustc_ast::{LitKind, RangeLimits};
+use rustc_ast::{BinOpKind, LitKind, RangeLimits};
use rustc_data_structures::packed::Pu128;
use rustc_data_structures::unhash::UnindexMap;
use rustc_errors::{Applicability, Diag};
-use rustc_hir::{BinOpKind, Block, Body, Expr, ExprKind, UnOp};
+use rustc_hir::{Block, Body, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned;
@@ -134,19 +135,31 @@ fn assert_len_expr<'hir>(
cx: &LateContext<'_>,
expr: &'hir Expr<'hir>,
) -> Option<(LengthComparison, usize, &'hir Expr<'hir>)> {
- if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr)
+ let (cmp, asserted_len, slice_len) = if let Some(higher::If { cond, then, .. }) = higher::If::hir(expr)
&& let ExprKind::Unary(UnOp::Not, condition) = &cond.kind
&& let ExprKind::Binary(bin_op, left, right) = &condition.kind
-
- && let Some((cmp, asserted_len, slice_len)) = len_comparison(bin_op.node, left, right)
- && let ExprKind::MethodCall(method, recv, [], _) = &slice_len.kind
- && cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_slice()
- && method.ident.name == sym::len
-
// check if `then` block has a never type expression
&& let ExprKind::Block(Block { expr: Some(then_expr), .. }, _) = then.kind
&& cx.typeck_results().expr_ty(then_expr).is_never()
{
+ len_comparison(bin_op.node, left, right)?
+ } else if let Some((macro_call, bin_op)) = first_node_macro_backtrace(cx, expr).find_map(|macro_call| {
+ match cx.tcx.get_diagnostic_name(macro_call.def_id) {
+ Some(sym::assert_eq_macro) => Some((macro_call, BinOpKind::Eq)),
+ Some(sym::assert_ne_macro) => Some((macro_call, BinOpKind::Ne)),
+ _ => None,
+ }
+ }) && let Some((left, right, _)) = find_assert_eq_args(cx, expr, macro_call.expn)
+ {
+ len_comparison(bin_op, left, right)?
+ } else {
+ return None;
+ };
+
+ if let ExprKind::MethodCall(method, recv, [], _) = &slice_len.kind
+ && cx.typeck_results().expr_ty_adjusted(recv).peel_refs().is_slice()
+ && method.ident.name == sym::len
+ {
Some((cmp, asserted_len, recv))
} else {
None
@@ -168,6 +181,7 @@ enum IndexEntry<'hir> {
/// if the `assert!` asserts the right length.
AssertWithIndex {
highest_index: usize,
+ is_first_highest: bool,
asserted_len: usize,
assert_span: Span,
slice: &'hir Expr<'hir>,
@@ -177,6 +191,7 @@ enum IndexEntry<'hir> {
/// Indexing without an `assert!`
IndexWithoutAssert {
highest_index: usize,
+ is_first_highest: bool,
indexes: Vec<Span>,
slice: &'hir Expr<'hir>,
},
@@ -244,28 +259,41 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Uni
assert_span,
slice,
} => {
- *entry = IndexEntry::AssertWithIndex {
- highest_index: index,
- asserted_len: *asserted_len,
- assert_span: *assert_span,
- slice,
- indexes: vec![expr.span],
- comparison: *comparison,
- };
+ if slice.span.lo() > assert_span.lo() {
+ *entry = IndexEntry::AssertWithIndex {
+ highest_index: index,
+ is_first_highest: true,
+ asserted_len: *asserted_len,
+ assert_span: *assert_span,
+ slice,
+ indexes: vec![expr.span],
+ comparison: *comparison,
+ };
+ }
},
IndexEntry::IndexWithoutAssert {
- highest_index, indexes, ..
+ highest_index,
+ indexes,
+ is_first_highest,
+ ..
}
| IndexEntry::AssertWithIndex {
- highest_index, indexes, ..
+ highest_index,
+ indexes,
+ is_first_highest,
+ ..
} => {
indexes.push(expr.span);
+ if *is_first_highest {
+ (*is_first_highest) = *highest_index >= index;
+ }
*highest_index = (*highest_index).max(index);
},
}
} else {
indexes.push(IndexEntry::IndexWithoutAssert {
highest_index: index,
+ is_first_highest: true,
indexes: vec![expr.span],
slice,
});
@@ -284,15 +312,18 @@ fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Un
if let Some(entry) = entry {
if let IndexEntry::IndexWithoutAssert {
highest_index,
+ is_first_highest,
indexes,
slice,
} = entry
+ && expr.span.lo() <= slice.span.lo()
{
*entry = IndexEntry::AssertWithIndex {
highest_index: *highest_index,
indexes: mem::take(indexes),
+ is_first_highest: *is_first_highest,
slice,
- assert_span: expr.span,
+ assert_span: expr.span.source_callsite(),
comparison,
asserted_len,
};
@@ -301,7 +332,7 @@ fn check_assert<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Un
indexes.push(IndexEntry::StrayAssert {
asserted_len,
comparison,
- assert_span: expr.span,
+ assert_span: expr.span.source_callsite(),
slice,
});
}
@@ -325,12 +356,13 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap<u64, Vec<IndexEntry<'_>
match *entry {
IndexEntry::AssertWithIndex {
highest_index,
+ is_first_highest,
asserted_len,
ref indexes,
comparison,
assert_span,
slice,
- } if indexes.len() > 1 => {
+ } if indexes.len() > 1 && !is_first_highest => {
// if we have found an `assert!`, let's also check that it's actually right
// and if it covers the highest index and if not, suggest the correct length
let sugg = match comparison {
@@ -378,8 +410,9 @@ fn report_indexes(cx: &LateContext<'_>, map: &UnindexMap<u64, Vec<IndexEntry<'_>
IndexEntry::IndexWithoutAssert {
ref indexes,
highest_index,
+ is_first_highest,
slice,
- } if indexes.len() > 1 => {
+ } if indexes.len() > 1 && !is_first_highest => {
// if there was no `assert!` but more than one index, suggest
// adding an `assert!` that covers the highest index
report_lint(
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index 38a19dd..67537a2 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -139,12 +139,11 @@ fn check_fn(
// Const fns are not allowed as methods in a trait.
{
let parent = cx.tcx.hir_get_parent_item(hir_id).def_id;
- if parent != CRATE_DEF_ID {
- if let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(parent) {
- if let hir::ItemKind::Trait(..) = &item.kind {
- return;
- }
- }
+ if parent != CRATE_DEF_ID
+ && let hir::Node::Item(item) = cx.tcx.hir_node_by_def_id(parent)
+ && let hir::ItemKind::Trait(..) = &item.kind
+ {
+ return;
}
}
@@ -156,9 +155,9 @@ fn check_fn(
return;
}
- let mir = cx.tcx.optimized_mir(def_id);
+ let mir = cx.tcx.mir_drops_elaborated_and_const_checked(def_id);
- if let Ok(()) = is_min_const_fn(cx, mir, self.msrv)
+ if let Ok(()) = is_min_const_fn(cx, &mir.borrow(), self.msrv)
&& let hir::Node::Item(hir::Item { vis_span, .. }) | hir::Node::ImplItem(hir::ImplItem { vis_span, .. }) =
cx.tcx.hir_node_by_def_id(def_id)
{
diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
index 28dc242..1932d2d5 100644
--- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
@@ -209,7 +209,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
&& let Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Union, self_path_did) = self_path.res
&& cx.tcx.is_diagnostic_item(sym::Debug, trait_def_id)
// don't trigger if this impl was derived
- && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived)
+ && !cx.tcx.is_automatically_derived(item.owner_id.to_def_id())
&& !item.span.from_expansion()
// find `Debug::fmt` function
&& let Some(fmt_item) = items.iter().find(|i| i.ident.name == sym::fmt)
@@ -224,11 +224,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
// NB: can't call cx.typeck_results() as we are not in a body
&& let typeck_results = cx.tcx.typeck_body(*body_id)
&& should_lint(cx, typeck_results, block)
- {
// we intentionally only lint structs, see lint description
- if let ItemKind::Struct(_, data, _) = &self_item.kind {
- check_struct(cx, typeck_results, block, self_ty, item, data);
- }
+ && let ItemKind::Struct(_, data, _) = &self_item.kind
+ {
+ check_struct(cx, typeck_results, block, self_ty, item, data);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index f49e03e..1f61317 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -160,12 +160,13 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::Impl
AssocItemContainer::Impl => cx.tcx.impl_trait_ref(container_id).map(|t| t.skip_binder().def_id),
};
- if let Some(trait_def_id) = trait_def_id {
- if trait_def_id.is_local() && !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) {
- // If a trait is being implemented for an item, and the
- // trait is not exported, we don't need #[inline]
- return;
- }
+ if let Some(trait_def_id) = trait_def_id
+ && trait_def_id.is_local()
+ && !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id)
+ {
+ // If a trait is being implemented for an item, and the
+ // trait is not exported, we don't need #[inline]
+ return;
}
let attrs = cx.tcx.hir_attrs(impl_item.hir_id());
diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
index 7ee7463..e266c36 100644
--- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -81,7 +81,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
cx,
MISSING_TRAIT_METHODS,
cx.tcx.def_span(item.owner_id),
- format!("missing trait method provided by default: `{}`", assoc.name),
+ format!("missing trait method provided by default: `{}`", assoc.name()),
|diag| {
diag.span_help(cx.tcx.def_span(assoc.def_id), "implement the method");
},
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index fbd287f..0e08558 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -135,10 +135,10 @@ fn maybe_walk_expr(&mut self, e: &'tcx Expr<'_>) {
}
fn report_diverging_sub_expr(&mut self, e: &Expr<'_>) {
- if let Some(macro_call) = root_macro_call_first_node(self.cx, e) {
- if self.cx.tcx.item_name(macro_call.def_id).as_str() == "todo" {
- return;
- }
+ if let Some(macro_call) = root_macro_call_first_node(self.cx, e)
+ && self.cx.tcx.item_name(macro_call.def_id).as_str() == "todo"
+ {
+ return;
}
span_lint(self.cx, DIVERGING_SUB_EXPRESSION, e.span, "sub-expression diverges");
}
@@ -328,22 +328,22 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
return;
}
- if path_to_local_id(expr, self.var) {
+ if path_to_local_id(expr, self.var)
// Check that this is a read, not a write.
- if !is_in_assignment_position(self.cx, expr) {
- span_lint_and_then(
- self.cx,
- MIXED_READ_WRITE_IN_EXPRESSION,
- expr.span,
- format!("unsequenced read of `{}`", self.cx.tcx.hir_name(self.var)),
- |diag| {
- diag.span_note(
- self.write_expr.span,
- "whether read occurs before this write depends on evaluation order",
- );
- },
- );
- }
+ && !is_in_assignment_position(self.cx, expr)
+ {
+ span_lint_and_then(
+ self.cx,
+ MIXED_READ_WRITE_IN_EXPRESSION,
+ expr.span,
+ format!("unsequenced read of `{}`", self.cx.tcx.hir_name(self.var)),
+ |diag| {
+ diag.span_note(
+ self.write_expr.span,
+ "whether read occurs before this write depends on evaluation order",
+ );
+ },
+ );
}
match expr.kind {
// We're about to descend a closure. Since we don't know when (or
@@ -373,10 +373,10 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
/// Returns `true` if `expr` is the LHS of an assignment, like `expr = ...`.
fn is_in_assignment_position(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- if let Some(parent) = get_parent_expr(cx, expr) {
- if let ExprKind::Assign(lhs, ..) = parent.kind {
- return lhs.hir_id == expr.hir_id;
- }
+ if let Some(parent) = get_parent_expr(cx, expr)
+ && let ExprKind::Assign(lhs, ..) = parent.kind
+ {
+ return lhs.hir_id == expr.hir_id;
}
false
}
diff --git a/src/tools/clippy/clippy_lints/src/module_style.rs b/src/tools/clippy/clippy_lints/src/module_style.rs
index 7287193..98614ba 100644
--- a/src/tools/clippy/clippy_lints/src/module_style.rs
+++ b/src/tools/clippy/clippy_lints/src/module_style.rs
@@ -119,22 +119,22 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
}
for folder in &folder_segments {
- if !mod_folders.contains(folder) {
- if let Some((file, path)) = file_map.get(folder) {
- span_lint_and_then(
- cx,
- SELF_NAMED_MODULE_FILES,
- Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
- format!("`mod.rs` files are required, found `{}`", path.display()),
- |diag| {
- let mut correct = path.to_path_buf();
- correct.pop();
- correct.push(folder);
- correct.push("mod.rs");
- diag.help(format!("move `{}` to `{}`", path.display(), correct.display(),));
- },
- );
- }
+ if !mod_folders.contains(folder)
+ && let Some((file, path)) = file_map.get(folder)
+ {
+ span_lint_and_then(
+ cx,
+ SELF_NAMED_MODULE_FILES,
+ Span::new(file.start_pos, file.start_pos, SyntaxContext::root(), None),
+ format!("`mod.rs` files are required, found `{}`", path.display()),
+ |diag| {
+ let mut correct = path.to_path_buf();
+ correct.pop();
+ correct.push(folder);
+ correct.push("mod.rs");
+ diag.help(format!("move `{}` to `{}`", path.display(), correct.display(),));
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index 2adc27c..c6c27e2 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -142,10 +142,9 @@ fn collect_unsafe_exprs<'tcx>(
.typeck_results()
.type_dependent_def_id(expr.hir_id)
.map(|def_id| cx.tcx.fn_sig(def_id))
+ && sig.skip_binder().safety().is_unsafe()
{
- if sig.skip_binder().safety().is_unsafe() {
- unsafe_ops.push(("unsafe method call occurs here", expr.span));
- }
+ unsafe_ops.push(("unsafe method call occurs here", expr.span));
}
},
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index 7abc587..a45031c 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -82,10 +82,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
}
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) {
- if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind {
- if trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
- self.check_sig(cx, item.owner_id.def_id, sig.decl);
- }
+ if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind
+ && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
+ {
+ self.check_sig(cx, item.owner_id.def_id, sig.decl);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs
index 3c4ba51..d98c70e 100644
--- a/src/tools/clippy/clippy_lints/src/mut_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs
@@ -77,16 +77,16 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'_>) {
expr.span,
"generally you want to avoid `&mut &mut _` if possible",
);
- } else if let ty::Ref(_, ty, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind() {
- if ty.peel_refs().is_sized(self.cx.tcx, self.cx.typing_env()) {
- span_lint_hir(
- self.cx,
- MUT_MUT,
- expr.hir_id,
- expr.span,
- "this expression mutably borrows a mutable reference. Consider reborrowing",
- );
- }
+ } else if let ty::Ref(_, ty, hir::Mutability::Mut) = self.cx.typeck_results().expr_ty(e).kind()
+ && ty.peel_refs().is_sized(self.cx.tcx, self.cx.typing_env())
+ {
+ span_lint_hir(
+ self.cx,
+ MUT_MUT,
+ expr.hir_id,
+ expr.span,
+ "this expression mutably borrows a mutable reference. Consider reborrowing",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
index 13a23a1..270eebe 100644
--- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
+++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs
@@ -101,14 +101,13 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
return;
},
ExprKind::Path(_) => {
- if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id) {
- if adj
+ if let Some(adj) = self.cx.typeck_results().adjustments().get(expr.hir_id)
+ && adj
.iter()
.any(|a| matches!(a.target.kind(), ty::Ref(_, _, Mutability::Mut)))
- {
- self.found = true;
- return;
- }
+ {
+ self.found = true;
+ return;
}
},
// Don't check await desugars
diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
index 49fd29d..fe2157c 100644
--- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
+++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
@@ -91,19 +91,19 @@
impl<'tcx> LateLintPass<'tcx> for Mutex {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let ty = cx.typeck_results().expr_ty(expr);
- if let ty::Adt(_, subst) = ty.kind() {
- if is_type_diagnostic_item(cx, ty, sym::Mutex) {
- let mutex_param = subst.type_at(0);
- if let Some(atomic_name) = get_atomic_name(mutex_param) {
- let msg = format!(
- "consider using an `{atomic_name}` instead of a `Mutex` here; if you just want the locking \
+ if let ty::Adt(_, subst) = ty.kind()
+ && is_type_diagnostic_item(cx, ty, sym::Mutex)
+ {
+ let mutex_param = subst.type_at(0);
+ if let Some(atomic_name) = get_atomic_name(mutex_param) {
+ let msg = format!(
+ "consider using an `{atomic_name}` instead of a `Mutex` here; if you just want the locking \
behavior and not the internal type, consider using `Mutex<()>`"
- );
- match *mutex_param.kind() {
- ty::Uint(t) if t != UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, msg),
- ty::Int(t) if t != IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, msg),
- _ => span_lint(cx, MUTEX_ATOMIC, expr.span, msg),
- }
+ );
+ match *mutex_param.kind() {
+ ty::Uint(t) if t != UintTy::Usize => span_lint(cx, MUTEX_INTEGER, expr.span, msg),
+ ty::Int(t) if t != IntTy::Isize => span_lint(cx, MUTEX_INTEGER, expr.span, msg),
+ _ => span_lint(cx, MUTEX_ATOMIC, expr.span, msg),
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index 2eacd68..f768e11 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -154,7 +154,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
|| is_receiver_of_method_call(cx, e)
|| is_as_argument(cx, e)
{
- snip = snip.maybe_par();
+ snip = snip.maybe_paren();
}
span_lint_and_sugg(
@@ -426,10 +426,10 @@ fn fetch_bool_block(expr: &Expr<'_>) -> Option<Expression> {
}
fn fetch_bool_expr(expr: &Expr<'_>) -> Option<bool> {
- if let ExprKind::Lit(lit_ptr) = peel_blocks(expr).kind {
- if let LitKind::Bool(value) = lit_ptr.node {
- return Some(value);
- }
+ if let ExprKind::Lit(lit_ptr) = peel_blocks(expr).kind
+ && let LitKind::Bool(value) = lit_ptr.node
+ {
+ return Some(value);
}
None
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index f686cc9..e579dd5 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -299,7 +299,7 @@ fn has_ref_mut_self_method(cx: &LateContext<'_>, trait_def_id: DefId) -> bool {
.associated_items(trait_def_id)
.in_definition_order()
.any(|assoc_item| {
- if assoc_item.fn_has_self_parameter {
+ if assoc_item.is_method() {
let self_ty = cx
.tcx
.fn_sig(assoc_item.def_id)
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index b61061d..7052e1d 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -86,11 +86,11 @@ fn should_skip<'tcx>(
return false;
}
- if let PatKind::Binding(.., name, _) = arg.pat.kind {
+ if let PatKind::Binding(.., name, _) = arg.pat.kind
// If it's a potentially unused variable, we don't check it.
- if name.name == kw::Underscore || name.as_str().starts_with('_') {
- return true;
- }
+ && (name.name == kw::Underscore || name.as_str().starts_with('_'))
+ {
+ return true;
}
// All spans generated from a proc-macro invocation are the same...
@@ -164,13 +164,13 @@ fn check_fn(
};
// Exclude non-inherent impls
- if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
- if matches!(
+ if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id)
+ && matches!(
item.kind,
ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
- ) {
- return;
- }
+ )
+ {
+ return;
}
let fn_sig = cx.tcx.fn_sig(fn_def_id).instantiate_identity();
@@ -353,10 +353,10 @@ fn is_in_unsafe_block(&self, item: HirId) -> bool {
for (parent, node) in self.tcx.hir_parent_iter(item) {
if let Some(fn_sig) = self.tcx.hir_fn_sig_by_hir_id(parent) {
return fn_sig.header.is_unsafe();
- } else if let Node::Block(block) = node {
- if matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) {
- return true;
- }
+ } else if let Node::Block(block) = node
+ && matches!(block.rules, BlockCheckMode::UnsafeBlock(_))
+ {
+ return true;
}
}
false
@@ -426,10 +426,10 @@ fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId, borrow: ty::Bor
// upon!
self.add_mutably_used_var(*vid);
}
- } else if borrow == ty::BorrowKind::Immutable {
+ } else if borrow == ty::BorrowKind::Immutable
// If there is an `async block`, it'll contain a call to a closure which we need to
// go into to ensure all "mutate" checks are found.
- if let Node::Expr(Expr {
+ && let Node::Expr(Expr {
kind:
ExprKind::Call(
_,
@@ -442,9 +442,8 @@ fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId, borrow: ty::Bor
),
..
}) = self.tcx.hir_node(cmt.hir_id)
- {
- self.async_closures.insert(*def_id);
- }
+ {
+ self.async_closures.insert(*def_id);
}
}
@@ -460,10 +459,9 @@ fn mutate(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) {
}),
..
} = &cmt.place
+ && !projections.is_empty()
{
- if !projections.is_empty() {
- self.add_mutably_used_var(*vid);
- }
+ self.add_mutably_used_var(*vid);
}
}
@@ -477,10 +475,9 @@ fn copy(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
}),
..
} = &cmt.place
+ && self.is_in_unsafe_block(id)
{
- if self.is_in_unsafe_block(id) {
- self.add_mutably_used_var(*vid);
- }
+ self.add_mutably_used_var(*vid);
}
self.prev_bind = None;
}
@@ -499,15 +496,14 @@ fn fake_read(
}),
..
} = &cmt.place
+ && let FakeReadCause::ForLet(Some(inner)) = cause
{
- if let FakeReadCause::ForLet(Some(inner)) = cause {
- // Seems like we are inside an async function. We need to store the closure `DefId`
- // to go through it afterwards.
- self.async_closures.insert(inner);
- self.add_alias(cmt.hir_id, *vid);
- self.prev_move_to_closure.insert(*vid);
- self.prev_bind = None;
- }
+ // Seems like we are inside an async function. We need to store the closure `DefId`
+ // to go through it afterwards.
+ self.async_closures.insert(inner);
+ self.add_alias(cmt.hir_id, *vid);
+ self.prev_move_to_closure.insert(*vid);
+ self.prev_bind = None;
}
}
@@ -522,10 +518,9 @@ fn bind(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
}),
..
} = &cmt.place
+ && self.is_in_unsafe_block(id)
{
- if self.is_in_unsafe_block(id) {
- self.add_mutably_used_var(*vid);
- }
+ self.add_mutably_used_var(*vid);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 978fde3..275d710 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -98,13 +98,13 @@ fn check_fn(
}
// Exclude non-inherent impls
- if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
- if matches!(
+ if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id)
+ && matches!(
item.kind,
ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
- ) {
- return;
- }
+ )
+ {
+ return;
}
// Allow `Borrow` or functions to be taken by value
@@ -197,20 +197,18 @@ fn check_fn(
{
// Dereference suggestion
let sugg = |diag: &mut Diag<'_, ()>| {
- if let ty::Adt(def, ..) = ty.kind() {
- if let Some(span) = cx.tcx.hir_span_if_local(def.did()) {
- if type_allowed_to_implement_copy(
- cx.tcx,
- cx.param_env,
- ty,
- traits::ObligationCause::dummy_with_span(span),
- rustc_hir::Safety::Safe,
- )
- .is_ok()
- {
- diag.span_help(span, "or consider marking this type as `Copy`");
- }
- }
+ if let ty::Adt(def, ..) = ty.kind()
+ && let Some(span) = cx.tcx.hir_span_if_local(def.did())
+ && type_allowed_to_implement_copy(
+ cx.tcx,
+ cx.param_env,
+ ty,
+ traits::ObligationCause::dummy_with_span(span),
+ rustc_hir::Safety::Safe,
+ )
+ .is_ok()
+ {
+ diag.span_help(span, "or consider marking this type as `Copy`");
}
if is_type_diagnostic_item(cx, ty, sym::Vec)
@@ -254,29 +252,28 @@ fn check_fn(
return;
}
- if is_type_lang_item(cx, ty, LangItem::String) {
- if let Some(clone_spans) =
+ if is_type_lang_item(cx, ty, LangItem::String)
+ && let Some(clone_spans) =
get_spans(cx, Some(body.id()), idx, &[("clone", ".to_string()"), ("as_str", "")])
- {
+ {
+ diag.span_suggestion(
+ input.span,
+ "consider changing the type to",
+ "&str",
+ Applicability::Unspecified,
+ );
+
+ for (span, suggestion) in clone_spans {
diag.span_suggestion(
- input.span,
- "consider changing the type to",
- "&str",
+ span,
+ span.get_source_text(cx)
+ .map_or("change the call to".to_owned(), |src| format!("change `{src}` to")),
+ suggestion,
Applicability::Unspecified,
);
-
- for (span, suggestion) in clone_spans {
- diag.span_suggestion(
- span,
- span.get_source_text(cx)
- .map_or("change the call to".to_owned(), |src| format!("change `{src}` to")),
- suggestion,
- Applicability::Unspecified,
- );
- }
-
- return;
}
+
+ return;
}
diag.span_suggestion_verbose(
diff --git a/src/tools/clippy/clippy_lints/src/needless_update.rs b/src/tools/clippy/clippy_lints/src/needless_update.rs
index cce0617..4a86c37 100644
--- a/src/tools/clippy/clippy_lints/src/needless_update.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_update.rs
@@ -53,18 +53,16 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessUpdate {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
if let ExprKind::Struct(_, fields, StructTailExpr::Base(base)) = expr.kind {
let ty = cx.typeck_results().expr_ty(expr);
- if let ty::Adt(def, _) = ty.kind() {
- let variant = def.non_enum_variant();
- if fields.len() == variant.fields.len()
- && !variant.is_field_list_non_exhaustive()
- {
- span_lint(
- cx,
- NEEDLESS_UPDATE,
- base.span,
- "struct update has no effect, all the fields in the struct have already been specified",
- );
- }
+ if let ty::Adt(def, _) = ty.kind()
+ && fields.len() == def.non_enum_variant().fields.len()
+ && !def.variant(0_usize.into()).is_field_list_non_exhaustive()
+ {
+ span_lint(
+ cx,
+ NEEDLESS_UPDATE,
+ base.span,
+ "struct update has no effect, all the fields in the struct have already been specified",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
index 429afff..74c8142 100644
--- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -16,9 +16,6 @@
/// ### Why is this bad?
/// It's more readable to just negate.
///
- /// ### Known problems
- /// This only catches integers (for now).
- ///
/// ### Example
/// ```rust,ignore
/// let a = x * -1;
@@ -38,23 +35,32 @@
impl<'tcx> LateLintPass<'tcx> for NegMultiply {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
- if let ExprKind::Binary(ref op, left, right) = e.kind {
- if BinOpKind::Mul == op.node {
- match (&left.kind, &right.kind) {
- (&ExprKind::Unary(..), &ExprKind::Unary(..)) => {},
- (&ExprKind::Unary(UnOp::Neg, lit), _) => check_mul(cx, e.span, lit, right),
- (_, &ExprKind::Unary(UnOp::Neg, lit)) => check_mul(cx, e.span, lit, left),
- _ => {},
- }
+ if let ExprKind::Binary(ref op, left, right) = e.kind
+ && BinOpKind::Mul == op.node
+ {
+ match (&left.kind, &right.kind) {
+ (&ExprKind::Unary(..), &ExprKind::Unary(..)) => {},
+ (&ExprKind::Unary(UnOp::Neg, lit), _) => check_mul(cx, e.span, lit, right),
+ (_, &ExprKind::Unary(UnOp::Neg, lit)) => check_mul(cx, e.span, lit, left),
+ _ => {},
}
}
}
}
fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
+ const F16_ONE: u16 = 1.0_f16.to_bits();
+ const F128_ONE: u128 = 1.0_f128.to_bits();
if let ExprKind::Lit(l) = lit.kind
- && consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1)
- && cx.typeck_results().expr_ty(exp).is_integral()
+ && matches!(
+ consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)),
+ Constant::Int(1)
+ | Constant::F16(F16_ONE)
+ | Constant::F32(1.0)
+ | Constant::F64(1.0)
+ | Constant::F128(F128_ONE)
+ )
+ && cx.typeck_results().expr_ty(exp).is_numeric()
{
let mut applicability = Applicability::MachineApplicable;
let (snip, from_macro) = snippet_with_context(cx, exp.span, span.ctxt(), "..", &mut applicability);
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index 1e469c3..4b73a44 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -99,10 +99,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
let mut impls = HirIdSet::default();
for &d in cx.tcx.local_trait_impls(default_trait_id) {
let ty = cx.tcx.type_of(d).instantiate_identity();
- if let Some(ty_def) = ty.ty_adt_def() {
- if let Some(local_def_id) = ty_def.did().as_local() {
- impls.insert(cx.tcx.local_def_id_to_hir_id(local_def_id));
- }
+ if let Some(ty_def) = ty.ty_adt_def()
+ && let Some(local_def_id) = ty_def.did().as_local()
+ {
+ impls.insert(cx.tcx.local_def_id_to_hir_id(local_def_id));
}
}
self.impling_types = Some(impls);
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index 7187a8f..7ab7976 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -182,23 +182,22 @@ fn check_no_effect(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
);
return true;
}
- } else if let StmtKind::Let(local) = stmt.kind {
- if !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id)
- && !matches!(local.source, LocalSource::AsyncFn)
- && let Some(init) = local.init
- && local.els.is_none()
- && !local.pat.span.from_expansion()
- && has_no_effect(cx, init)
- && let PatKind::Binding(_, hir_id, ident, _) = local.pat.kind
- && ident.name.to_ident_string().starts_with('_')
- && !in_automatically_derived(cx.tcx, local.hir_id)
- {
- if let Some(l) = self.local_bindings.last_mut() {
- l.push(hir_id);
- self.underscore_bindings.insert(hir_id, ident.span);
- }
- return true;
+ } else if let StmtKind::Let(local) = stmt.kind
+ && !is_lint_allowed(cx, NO_EFFECT_UNDERSCORE_BINDING, local.hir_id)
+ && !matches!(local.source, LocalSource::AsyncFn)
+ && let Some(init) = local.init
+ && local.els.is_none()
+ && !local.pat.span.from_expansion()
+ && has_no_effect(cx, init)
+ && let PatKind::Binding(_, hir_id, ident, _) = local.pat.kind
+ && ident.name.to_ident_string().starts_with('_')
+ && !in_automatically_derived(cx.tcx, local.hir_id)
+ {
+ if let Some(l) = self.local_bindings.last_mut() {
+ l.push(hir_id);
+ self.underscore_bindings.insert(hir_id, ident.span);
}
+ return true;
}
false
}
diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
index 448bb60..9386519 100644
--- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
@@ -1,6 +1,8 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::ty::implements_trait;
-use clippy_utils::{is_from_proc_macro, is_res_lang_ctor, last_path_segment, path_res, std_or_core};
+use clippy_utils::{
+ is_diag_trait_item, is_from_proc_macro, is_res_lang_ctor, last_path_segment, path_res, std_or_core,
+};
use rustc_errors::Applicability;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp};
@@ -98,7 +100,7 @@
///
/// impl PartialOrd for A {
/// fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
- /// Some(self.cmp(other))
+ /// Some(self.cmp(other)) // or self.cmp(other).into()
/// }
/// }
/// ```
@@ -185,65 +187,66 @@ fn check_impl_item<'tcx>(&mut self, cx: &LateContext<'tcx>, impl_item: &ImplItem
if block.stmts.is_empty()
&& let Some(expr) = block.expr
- && expr_is_cmp(cx, &expr.kind, impl_item, &mut needs_fully_qualified)
+ && expr_is_cmp(cx, expr, impl_item, &mut needs_fully_qualified)
{
+ return;
}
// Fix #12683, allow [`needless_return`] here
else if block.expr.is_none()
&& let Some(stmt) = block.stmts.first()
&& let rustc_hir::StmtKind::Semi(Expr {
- kind: ExprKind::Ret(Some(Expr { kind: ret_kind, .. })),
+ kind: ExprKind::Ret(Some(ret)),
..
}) = stmt.kind
- && expr_is_cmp(cx, ret_kind, impl_item, &mut needs_fully_qualified)
+ && expr_is_cmp(cx, ret, impl_item, &mut needs_fully_qualified)
{
- } else {
- // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid
- // suggestion tons more complex.
- if let [lhs, rhs, ..] = trait_impl.args.as_slice()
- && lhs != rhs
- {
- return;
- }
-
- span_lint_and_then(
- cx,
- NON_CANONICAL_PARTIAL_ORD_IMPL,
- item.span,
- "non-canonical implementation of `partial_cmp` on an `Ord` type",
- |diag| {
- let [_, other] = body.params else {
- return;
- };
- let Some(std_or_core) = std_or_core(cx) else {
- return;
- };
-
- let suggs = match (other.pat.simple_ident(), needs_fully_qualified) {
- (Some(other_ident), true) => vec![(
- block.span,
- format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, {})) }}", other_ident.name),
- )],
- (Some(other_ident), false) => {
- vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))]
- },
- (None, true) => vec![
- (
- block.span,
- format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, other)) }}"),
- ),
- (other.pat.span, "other".to_owned()),
- ],
- (None, false) => vec![
- (block.span, "{ Some(self.cmp(other)) }".to_owned()),
- (other.pat.span, "other".to_owned()),
- ],
- };
-
- diag.multipart_suggestion("change this to", suggs, Applicability::Unspecified);
- },
- );
+ return;
}
+ // If `Self` and `Rhs` are not the same type, bail. This makes creating a valid
+ // suggestion tons more complex.
+ else if let [lhs, rhs, ..] = trait_impl.args.as_slice()
+ && lhs != rhs
+ {
+ return;
+ }
+
+ span_lint_and_then(
+ cx,
+ NON_CANONICAL_PARTIAL_ORD_IMPL,
+ item.span,
+ "non-canonical implementation of `partial_cmp` on an `Ord` type",
+ |diag| {
+ let [_, other] = body.params else {
+ return;
+ };
+ let Some(std_or_core) = std_or_core(cx) else {
+ return;
+ };
+
+ let suggs = match (other.pat.simple_ident(), needs_fully_qualified) {
+ (Some(other_ident), true) => vec![(
+ block.span,
+ format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, {})) }}", other_ident.name),
+ )],
+ (Some(other_ident), false) => {
+ vec![(block.span, format!("{{ Some(self.cmp({})) }}", other_ident.name))]
+ },
+ (None, true) => vec![
+ (
+ block.span,
+ format!("{{ Some({std_or_core}::cmp::Ord::cmp(self, other)) }}"),
+ ),
+ (other.pat.span, "other".to_owned()),
+ ],
+ (None, false) => vec![
+ (block.span, "{ Some(self.cmp(other)) }".to_owned()),
+ (other.pat.span, "other".to_owned()),
+ ],
+ };
+
+ diag.multipart_suggestion("change this to", suggs, Applicability::Unspecified);
+ },
+ );
}
}
}
@@ -251,10 +254,11 @@ fn check_impl_item<'tcx>(&mut self, cx: &LateContext<'tcx>, impl_item: &ImplItem
/// Return true if `expr_kind` is a `cmp` call.
fn expr_is_cmp<'tcx>(
cx: &LateContext<'tcx>,
- expr_kind: &'tcx ExprKind<'tcx>,
+ expr: &'tcx Expr<'tcx>,
impl_item: &ImplItem<'_>,
needs_fully_qualified: &mut bool,
) -> bool {
+ let impl_item_did = impl_item.owner_id.def_id;
if let ExprKind::Call(
Expr {
kind: ExprKind::Path(some_path),
@@ -262,11 +266,17 @@ fn expr_is_cmp<'tcx>(
..
},
[cmp_expr],
- ) = expr_kind
+ ) = expr.kind
{
is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome)
// Fix #11178, allow `Self::cmp(self, ..)` too
- && self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, needs_fully_qualified)
+ && self_cmp_call(cx, cmp_expr, impl_item_did, needs_fully_qualified)
+ } else if let ExprKind::MethodCall(_, recv, [], _) = expr.kind {
+ cx.tcx
+ .typeck(impl_item_did)
+ .type_dependent_def_id(expr.hir_id)
+ .is_some_and(|def_id| is_diag_trait_item(cx, def_id, sym::Into))
+ && self_cmp_call(cx, recv, impl_item_did, needs_fully_qualified)
} else {
false
}
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 9b53608..63859c0 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -449,7 +449,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
dereferenced_expr = parent_expr;
},
- ExprKind::Index(e, _, _) if ptr::eq(&**e, cur_expr) => {
+ ExprKind::Index(e, _, _) if ptr::eq(&raw const **e, cur_expr) => {
// `e[i]` => desugared to `*Index::index(&e, i)`,
// meaning `e` must be referenced.
// no need to go further up since a method call is involved now.
diff --git a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
index 8305bf3..f6bc942 100644
--- a/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
+++ b/src/tools/clippy/clippy_lints/src/non_std_lazy_statics.rs
@@ -37,7 +37,7 @@
/// static FOO: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| "FOO".to_lowercase());
/// static BAR: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| "BAR".to_lowercase());
/// ```
- #[clippy::version = "1.81.0"]
+ #[clippy::version = "1.86.0"]
pub NON_STD_LAZY_STATICS,
pedantic,
"lazy static that could be replaced by `std::sync::LazyLock`"
@@ -121,7 +121,7 @@ fn check_item(&mut self, cx: &LateContext<'hir>, item: &Item<'hir>) {
cx,
NON_STD_LAZY_STATICS,
macro_call.span,
- "this macro has been superceded by `std::sync::LazyLock`",
+ "this macro has been superseded by `std::sync::LazyLock`",
);
return;
}
@@ -240,7 +240,7 @@ fn lint(&self, cx: &LateContext<'_>, sugg_map: &FxIndexMap<DefId, Option<String>
cx,
NON_STD_LAZY_STATICS,
self.ty_span_no_args,
- "this type has been superceded by `LazyLock` in the standard library",
+ "this type has been superseded by `LazyLock` in the standard library",
|diag| {
diag.multipart_suggestion("use `std::sync::LazyLock` instead", suggs, appl);
},
diff --git a/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs
index 16c4391..635f567 100644
--- a/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs
+++ b/src/tools/clippy/clippy_lints/src/non_zero_suggestions.rs
@@ -82,11 +82,10 @@ fn check_non_zero_conversion(cx: &LateContext<'_>, expr: &Expr<'_>, applicabilit
if let ty::Adt(adt_def, _) = receiver_ty.kind()
&& adt_def.is_struct()
&& cx.tcx.get_diagnostic_name(adt_def.did()) == Some(sym::NonZero)
+ && let Some(target_non_zero_type) = get_target_non_zero_type(target_ty)
{
- if let Some(target_non_zero_type) = get_target_non_zero_type(target_ty) {
- let arg_snippet = get_arg_snippet(cx, arg, rcv_path);
- suggest_non_zero_conversion(cx, expr, fn_name, target_non_zero_type, &arg_snippet, applicability);
- }
+ let arg_snippet = get_arg_snippet(cx, arg, rcv_path);
+ suggest_non_zero_conversion(cx, expr, fn_name, target_non_zero_type, &arg_snippet, applicability);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
index cf6b899..9b2cfd9 100644
--- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
@@ -98,7 +98,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
let arg_snip = snippet(cx, arg_span, "..");
let expr_snip;
let eq_impl;
- if with_deref.is_implemented() {
+ if with_deref.is_implemented() && !arg_ty.peel_refs().is_str() {
expr_snip = format!("*{arg_snip}");
eq_impl = with_deref;
} else {
diff --git a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs
index 74e0a63..047a5a0 100644
--- a/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/float_equality_without_abs.rs
@@ -50,7 +50,7 @@ pub(crate) fn check<'tcx>(
// format the suggestion
let suggestion = format!(
"{}.abs()",
- sugg::make_assoc(AssocOp::Binary(BinOpKind::Sub), &sug_l, &sug_r).maybe_par()
+ sugg::make_assoc(AssocOp::Binary(BinOpKind::Sub), &sug_l, &sug_r).maybe_paren()
);
// spans the lint
span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
index 0358232..e1fd095 100644
--- a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
@@ -103,7 +103,7 @@ enum Parens {
///
/// e.g. `-(x + y + 0)` cannot be reduced to `-x + y`, as the behavior changes silently.
/// e.g. `1u64 + ((x + y + 0i32) as u64)` cannot be reduced to `1u64 + x + y as u64`, since
-/// the the cast expression will not apply to the same expression.
+/// the cast expression will not apply to the same expression.
/// e.g. `0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }` cannot be reduced
/// to `if b { 1 } else { 2 } + if b { 3 } else { 4 }` where the `if` could be
/// interpreted as a statement. The same behavior happens for `match`, `loop`,
diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_one.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_one.rs
index fc5565e..2e6a071 100644
--- a/src/tools/clippy/clippy_lints/src/operators/modulo_one.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/modulo_one.rs
@@ -12,15 +12,15 @@ pub(crate) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, op: BinOpKind, right:
span_lint(cx, MODULO_ONE, expr.span, "any number modulo 1 will be 0");
}
- if let ty::Int(ity) = cx.typeck_results().expr_ty(right).kind() {
- if is_integer_const(cx, right, unsext(cx.tcx, -1, *ity)) {
- span_lint(
- cx,
- MODULO_ONE,
- expr.span,
- "any number modulo -1 will panic/overflow or result in 0",
- );
- }
+ if let ty::Int(ity) = cx.typeck_results().expr_ty(right).kind()
+ && is_integer_const(cx, right, unsext(cx.tcx, -1, *ity))
+ {
+ span_lint(
+ cx,
+ MODULO_ONE,
+ expr.span,
+ "any number modulo -1 will panic/overflow or result in 0",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
index 96c9775..e6be536 100644
--- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
@@ -75,10 +75,10 @@ pub fn enter_body(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
hir::BodyOwnerKind::Static(_) | hir::BodyOwnerKind::Const { .. } => {
let body_span = cx.tcx.hir_span_with_body(body_owner);
- if let Some(span) = self.const_span {
- if span.contains(body_span) {
- return;
- }
+ if let Some(span) = self.const_span
+ && span.contains(body_span)
+ {
+ return;
}
self.const_span = Some(body_span);
},
@@ -90,10 +90,10 @@ pub fn body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
let body_owner = cx.tcx.hir_body_owner(body.id());
let body_span = cx.tcx.hir_span_with_body(body_owner);
- if let Some(span) = self.const_span {
- if span.contains(body_span) {
- return;
- }
+ if let Some(span) = self.const_span
+ && span.contains(body_span)
+ {
+ return;
}
self.const_span = None;
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
index 378fed4..0faa7b9 100644
--- a/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/op_ref.rs
@@ -47,12 +47,11 @@ pub(crate) fn check<'tcx>(
let rty = cx.typeck_results().expr_ty(r);
let lcpy = is_copy(cx, lty);
let rcpy = is_copy(cx, rty);
- if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id) {
- if (are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty))
- || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty))
- {
- return; // Don't lint
- }
+ if let Some((self_ty, other_ty)) = in_impl(cx, e, trait_id)
+ && ((are_equal(cx, rty, self_ty) && are_equal(cx, lty, other_ty))
+ || (are_equal(cx, rty, other_ty) && are_equal(cx, lty, self_ty)))
+ {
+ return; // Don't lint
}
// either operator autorefs or both args are copyable
if (requires_ref || (lcpy && rcpy)) && implements_trait(cx, lty, trait_id, &[rty.into()]) {
@@ -86,7 +85,7 @@ pub(crate) fn check<'tcx>(
left.span,
"use the left value directly",
lsnip,
- Applicability::MaybeIncorrect, // FIXME #2597
+ Applicability::MachineApplicable,
);
},
);
@@ -105,7 +104,7 @@ pub(crate) fn check<'tcx>(
right.span,
"use the right value directly",
rsnip,
- Applicability::MaybeIncorrect, // FIXME #2597
+ Applicability::MachineApplicable,
);
},
);
@@ -137,7 +136,7 @@ pub(crate) fn check<'tcx>(
left.span,
"use the left value directly",
lsnip,
- Applicability::MaybeIncorrect, // FIXME #2597
+ Applicability::MachineApplicable,
);
},
);
@@ -164,7 +163,7 @@ pub(crate) fn check<'tcx>(
right.span,
"use the right value directly",
rsnip,
- Applicability::MaybeIncorrect, // FIXME #2597
+ Applicability::MachineApplicable,
);
});
}
diff --git a/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs
index a6aba33..1477378 100644
--- a/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/verbose_bit_mask.rs
@@ -32,7 +32,7 @@ pub(super) fn check<'tcx>(
e.span,
"bit mask could be simplified with a call to `trailing_zeros`",
|diag| {
- let sugg = Sugg::hir(cx, left1, "...").maybe_par();
+ let sugg = Sugg::hir(cx, left1, "...").maybe_paren();
diag.span_suggestion(
e.span,
"try",
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index 6f302ea..9487cec 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -4,8 +4,8 @@
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_copy;
use clippy_utils::{
- CaptureKind, can_move_expr_to_closure, eager_or_lazy, higher, is_else_clause, is_in_const_context,
- is_res_lang_ctor, peel_blocks, peel_hir_expr_while,
+ CaptureKind, can_move_expr_to_closure, eager_or_lazy, expr_requires_coercion, higher, is_else_clause,
+ is_in_const_context, is_res_lang_ctor, peel_blocks, peel_hir_expr_while,
};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@@ -106,7 +106,7 @@ struct OptionOccurrence {
fn format_option_in_sugg(cond_sugg: Sugg<'_>, as_ref: bool, as_mut: bool) -> String {
format!(
"{}{}",
- cond_sugg.maybe_par(),
+ cond_sugg.maybe_paren(),
if as_mut {
".as_mut()"
} else if as_ref {
@@ -212,6 +212,15 @@ fn try_get_option_occurrence<'tcx>(
}
}
+ let some_body_ty = cx.typeck_results().expr_ty(some_body);
+ let none_body_ty = cx.typeck_results().expr_ty(none_body);
+ // Check if coercion is needed for the `None` arm. If so, we cannot suggest because it will
+ // introduce a type mismatch. A special case is when both arms have the same type, then
+ // coercion is fine.
+ if some_body_ty != none_body_ty && expr_requires_coercion(cx, none_body) {
+ return None;
+ }
+
let mut app = Applicability::Unspecified;
let (none_body, is_argless_call) = match none_body.kind {
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
index 65671b4..8eaf65e 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
@@ -38,7 +38,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
items: impl_items,
..
}) = item.kind
- && !cx.tcx.has_attr(item.owner_id, sym::automatically_derived)
+ && !cx.tcx.is_automatically_derived(item.owner_id.to_def_id())
&& let Some(eq_trait) = cx.tcx.lang_items().eq_trait()
&& trait_ref.path.res.def_id() == eq_trait
{
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
index 6d42169..9b9024c 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
@@ -81,7 +81,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
let sugg = format!(
"{}.{}",
sugg::Sugg::hir_with_applicability(cx, peel_ref_operators(cx, scrutinee), "..", &mut applicability)
- .maybe_par(),
+ .maybe_paren(),
if is_eq { "is_none()" } else { "is_some()" }
);
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 0a8e288..5d30b66 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -178,19 +178,18 @@ fn check_poly_fn(&mut self, cx: &LateContext<'_>, def_id: LocalDefId, decl: &FnD
&& size <= self.ref_min_size
&& let hir::TyKind::Ref(_, MutTy { ty: decl_ty, .. }) = input.kind
{
- if let Some(typeck) = cx.maybe_typeck_results() {
+ if let Some(typeck) = cx.maybe_typeck_results()
// Don't lint if a raw pointer is created.
// TODO: Limit the check only to raw pointers to the argument (or part of the argument)
// which escape the current function.
- if typeck.node_types().items().any(|(_, &ty)| ty.is_raw_ptr())
+ && (typeck.node_types().items().any(|(_, &ty)| ty.is_raw_ptr())
|| typeck
.adjustments()
.items()
.flat_map(|(_, a)| a)
- .any(|a| matches!(a.kind, Adjust::Pointer(PointerCoercion::UnsafeFnPointer)))
- {
- continue;
- }
+ .any(|a| matches!(a.kind, Adjust::Pointer(PointerCoercion::UnsafeFnPointer))))
+ {
+ continue;
}
let value_type = if fn_body.and_then(|body| body.params.get(index)).is_some_and(is_self) {
"self".into()
@@ -282,12 +281,11 @@ fn check_fn(
}
let attrs = cx.tcx.hir_attrs(hir_id);
for a in attrs {
- if let Some(meta_items) = a.meta_item_list() {
- if a.has_name(sym::proc_macro_derive)
- || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always))
- {
- return;
- }
+ if let Some(meta_items) = a.meta_item_list()
+ && (a.has_name(sym::proc_macro_derive)
+ || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always)))
+ {
+ return;
}
}
},
@@ -296,13 +294,13 @@ fn check_fn(
}
// Exclude non-inherent impls
- if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
- if matches!(
+ if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id)
+ && matches!(
item.kind,
ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
- ) {
- return;
- }
+ )
+ {
+ return;
}
self.check_poly_fn(cx, def_id, decl, Some(span));
diff --git a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
index b653b45..35caac8 100644
--- a/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/pathbuf_init_then_push.rs
@@ -173,16 +173,15 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
}
fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
- if let Some(mut searcher) = self.searcher.take() {
- if let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
- && let ExprKind::MethodCall(name, self_arg, [arg_expr], _) = expr.kind
- && path_to_local_id(self_arg, searcher.local_id)
- && name.ident.as_str() == "push"
- {
- searcher.err_span = searcher.err_span.to(stmt.span);
- searcher.arg = Some(*arg_expr);
- searcher.display_err(cx);
- }
+ if let Some(mut searcher) = self.searcher.take()
+ && let StmtKind::Expr(expr) | StmtKind::Semi(expr) = stmt.kind
+ && let ExprKind::MethodCall(name, self_arg, [arg_expr], _) = expr.kind
+ && path_to_local_id(self_arg, searcher.local_id)
+ && name.ident.as_str() == "push"
+ {
+ searcher.err_span = searcher.err_span.to(stmt.span);
+ searcher.arg = Some(*arg_expr);
+ searcher.display_err(cx);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
index 8f1a1ee..19d9acf 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -177,17 +177,16 @@ fn find_first_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<(Span, Mut
PatKind::Or([p, ..]) => p,
_ => p,
};
- if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id) {
- if let [first, ..] = **adjustments {
- if let ty::Ref(.., mutability) = *first.kind() {
- let level = if p.hir_id == pat.hir_id {
- Level::Top
- } else {
- Level::Lower
- };
- result = Some((p.span, mutability, level));
- }
- }
+ if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id)
+ && let [first, ..] = **adjustments
+ && let ty::Ref(.., mutability) = *first.source.kind()
+ {
+ let level = if p.hir_id == pat.hir_id {
+ Level::Top
+ } else {
+ Level::Lower
+ };
+ result = Some((p.span, mutability, level));
}
result.is_none()
});
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 50ef56d..4919614 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -3,7 +3,7 @@
use clippy_utils::sugg::Sugg;
use clippy_utils::visitors::contains_unsafe_block;
use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, std_or_core};
-use hir::LifetimeName;
+use hir::LifetimeKind;
use rustc_abi::ExternAbi;
use rustc_errors::{Applicability, MultiSpan};
use rustc_hir::hir_id::{HirId, HirIdMap};
@@ -264,8 +264,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
is_null_path(cx, l),
is_null_path(cx, r),
) {
- (false, true, false) if let Some(sugg) = Sugg::hir_opt(cx, r) => sugg.maybe_par(),
- (false, false, true) if let Some(sugg) = Sugg::hir_opt(cx, l) => sugg.maybe_par(),
+ (false, true, false) if let Some(sugg) = Sugg::hir_opt(cx, r) => sugg.maybe_paren(),
+ (false, false, true) if let Some(sugg) = Sugg::hir_opt(cx, l) => sugg.maybe_paren(),
_ => return check_ptr_eq(cx, expr, op.node, l, r),
};
@@ -432,7 +432,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
}
None
}) {
- if let LifetimeName::Param(param_def_id) = lifetime.res
+ if let LifetimeKind::Param(param_def_id) = lifetime.kind
&& !lifetime.is_anonymous()
&& fn_sig
.output()
@@ -498,29 +498,33 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
}
fn check_mut_from_ref<'tcx>(cx: &LateContext<'tcx>, sig: &FnSig<'_>, body: Option<&Body<'tcx>>) {
- if let FnRetTy::Return(ty) = sig.decl.output
- && let Some((out, Mutability::Mut, _)) = get_ref_lm(ty)
- {
+ let FnRetTy::Return(ty) = sig.decl.output else { return };
+ for (out, mutability, out_span) in get_lifetimes(ty) {
+ if mutability != Some(Mutability::Mut) {
+ continue;
+ }
let out_region = cx.tcx.named_bound_var(out.hir_id);
- let args: Option<Vec<_>> = sig
+ // `None` if one of the types contains `&'a mut T` or `T<'a>`.
+ // Else, contains all the locations of `&'a T` types.
+ let args_immut_refs: Option<Vec<Span>> = sig
.decl
.inputs
.iter()
- .filter_map(get_ref_lm)
+ .flat_map(get_lifetimes)
.filter(|&(lt, _, _)| cx.tcx.named_bound_var(lt.hir_id) == out_region)
- .map(|(_, mutability, span)| (mutability == Mutability::Not).then_some(span))
+ .map(|(_, mutability, span)| (mutability == Some(Mutability::Not)).then_some(span))
.collect();
- if let Some(args) = args
- && !args.is_empty()
+ if let Some(args_immut_refs) = args_immut_refs
+ && !args_immut_refs.is_empty()
&& body.is_none_or(|body| sig.header.is_unsafe() || contains_unsafe_block(cx, body.value))
{
span_lint_and_then(
cx,
MUT_FROM_REF,
- ty.span,
+ out_span,
"mutable borrow from immutable input(s)",
|diag| {
- let ms = MultiSpan::from_spans(args);
+ let ms = MultiSpan::from_spans(args_immut_refs);
diag.span_note(ms, "immutable borrow here");
},
);
@@ -686,12 +690,36 @@ fn matches_preds<'tcx>(
})
}
-fn get_ref_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutability, Span)> {
- if let TyKind::Ref(lt, ref m) = ty.kind {
- Some((lt, m.mutbl, ty.span))
- } else {
- None
+struct LifetimeVisitor<'tcx> {
+ result: Vec<(&'tcx Lifetime, Option<Mutability>, Span)>,
+}
+
+impl<'tcx> Visitor<'tcx> for LifetimeVisitor<'tcx> {
+ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) {
+ if let TyKind::Ref(lt, ref m) = ty.kind {
+ self.result.push((lt, Some(m.mutbl), ty.span));
+ }
+ hir::intravisit::walk_ty(self, ty);
}
+
+ fn visit_generic_arg(&mut self, generic_arg: &'tcx GenericArg<'tcx>) {
+ if let GenericArg::Lifetime(lt) = generic_arg {
+ self.result.push((lt, None, generic_arg.span()));
+ }
+ hir::intravisit::walk_generic_arg(self, generic_arg);
+ }
+}
+
+/// Visit `ty` and collect the all the lifetimes appearing in it, implicit or not.
+///
+/// The second field of the vector's elements indicate if the lifetime is attached to a
+/// shared reference, a mutable reference, or neither.
+fn get_lifetimes<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Vec<(&'tcx Lifetime, Option<Mutability>, Span)> {
+ use hir::intravisit::VisitorExt as _;
+
+ let mut visitor = LifetimeVisitor { result: Vec::new() };
+ visitor.visit_ty_unambig(ty);
+ visitor.result
}
fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
@@ -728,8 +756,9 @@ fn check_ptr_eq<'tcx>(
let (left_var, right_var) = (peel_raw_casts(cx, left, left_ty), peel_raw_casts(cx, right, right_ty));
- if let Some(left_snip) = left_var.span.get_source_text(cx)
- && let Some(right_snip) = right_var.span.get_source_text(cx)
+ let mut app = Applicability::MachineApplicable;
+ let left_snip = Sugg::hir_with_context(cx, left_var, expr.span.ctxt(), "_", &mut app);
+ let right_snip = Sugg::hir_with_context(cx, right_var, expr.span.ctxt(), "_", &mut app);
{
let Some(top_crate) = std_or_core(cx) else { return };
let invert = if op == BinOpKind::Eq { "" } else { "!" };
@@ -740,7 +769,7 @@ fn check_ptr_eq<'tcx>(
format!("use `{top_crate}::ptr::eq` when comparing raw pointers"),
"try",
format!("{invert}{top_crate}::ptr::eq({left_snip}, {right_snip})"),
- Applicability::MachineApplicable,
+ app,
);
}
}
@@ -748,7 +777,8 @@ fn check_ptr_eq<'tcx>(
// If the given expression is a cast to a usize, return the lhs of the cast
// E.g., `foo as *const _ as usize` returns `foo as *const _`.
fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
- if cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize
+ if !cast_expr.span.from_expansion()
+ && cx.typeck_results().expr_ty(cast_expr) == cx.tcx.types.usize
&& let ExprKind::Cast(expr, _) = cast_expr.kind
{
Some(expr)
@@ -759,7 +789,8 @@ fn expr_as_cast_to_usize<'tcx>(cx: &LateContext<'tcx>, cast_expr: &'tcx Expr<'_>
// Peel raw casts if the remaining expression can be coerced to it
fn peel_raw_casts<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, expr_ty: Ty<'tcx>) -> &'tcx Expr<'tcx> {
- if let ExprKind::Cast(inner, _) = expr.kind
+ if !expr.span.from_expansion()
+ && let ExprKind::Cast(inner, _) = expr.kind
&& let ty::RawPtr(target_ty, _) = expr_ty.kind()
&& let inner_ty = cx.typeck_results().expr_ty(inner)
&& let ty::RawPtr(inner_target_ty, _) | ty::Ref(_, inner_target_ty, _) = inner_ty.kind()
diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
index 68ae575..7f74a2f 100644
--- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
@@ -77,10 +77,10 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// If the given expression is a cast from a usize, return the lhs of the cast
fn expr_as_cast_from_usize<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> {
- if let ExprKind::Cast(cast_lhs_expr, _) = expr.kind {
- if is_expr_ty_usize(cx, cast_lhs_expr) {
- return Some(cast_lhs_expr);
- }
+ if let ExprKind::Cast(cast_lhs_expr, _) = expr.kind
+ && is_expr_ty_usize(cx, cast_lhs_expr)
+ {
+ return Some(cast_lhs_expr);
}
None
}
@@ -91,14 +91,14 @@ fn expr_as_ptr_offset_call<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>,
) -> Option<(&'tcx Expr<'tcx>, &'tcx Expr<'tcx>, Method)> {
- if let ExprKind::MethodCall(path_segment, arg_0, [arg_1], _) = &expr.kind {
- if is_expr_ty_raw_ptr(cx, arg_0) {
- if path_segment.ident.name == sym::offset {
- return Some((arg_0, arg_1, Method::Offset));
- }
- if path_segment.ident.name.as_str() == "wrapping_offset" {
- return Some((arg_0, arg_1, Method::WrappingOffset));
- }
+ if let ExprKind::MethodCall(path_segment, arg_0, [arg_1], _) = &expr.kind
+ && is_expr_ty_raw_ptr(cx, arg_0)
+ {
+ if path_segment.ident.name == sym::offset {
+ return Some((arg_0, arg_1, Method::Offset));
+ }
+ if path_segment.ident.name.as_str() == "wrapping_offset" {
+ return Some((arg_0, arg_1, Method::WrappingOffset));
}
}
None
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index a80e1f7..d318897 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -5,6 +5,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
use clippy_utils::{
eq_expr_value, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor,
@@ -144,7 +145,7 @@ fn init_expr_can_use_question_mark(cx: &LateContext<'_>, init_expr: &Expr<'_>) -
&& !span_contains_comment(cx.tcx.sess.source_map(), els.span)
{
let mut applicability = Applicability::MaybeIncorrect;
- let init_expr_str = snippet_with_applicability(cx, init_expr.span, "..", &mut applicability);
+ let init_expr_str = Sugg::hir_with_applicability(cx, init_expr, "..", &mut applicability).maybe_paren();
// Take care when binding is `ref`
let sugg = if let PatKind::Binding(
BindingMode(ByRef::Yes(ref_mutability), binding_mutability),
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index cc423ec..d292ed8 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -179,10 +179,10 @@ pub fn new(conf: &'static Conf) -> Self {
impl<'tcx> LateLintPass<'tcx> for Ranges {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if let ExprKind::Binary(ref op, l, r) = expr.kind {
- if self.msrv.meets(cx, msrvs::RANGE_CONTAINS) {
- check_possible_range_contains(cx, op.node, l, r, expr, expr.span);
- }
+ if let ExprKind::Binary(ref op, l, r) = expr.kind
+ && self.msrv.meets(cx, msrvs::RANGE_CONTAINS)
+ {
+ check_possible_range_contains(cx, op.node, l, r, expr, expr.span);
}
check_exclusive_range_plus_one(cx, expr);
@@ -327,18 +327,18 @@ fn check_range_bounds<'a, 'tcx>(cx: &'a LateContext<'tcx>, ex: &'a Expr<'_>) ->
inc: inclusive,
});
}
- } else if let Some(id) = path_to_local(r) {
- if let Some(c) = ConstEvalCtxt::new(cx).eval(l) {
- return Some(RangeBounds {
- val: c,
- expr: l,
- id,
- name_span: r.span,
- val_span: l.span,
- ord: ordering.reverse(),
- inc: inclusive,
- });
- }
+ } else if let Some(id) = path_to_local(r)
+ && let Some(c) = ConstEvalCtxt::new(cx).eval(l)
+ {
+ return Some(RangeBounds {
+ val: c,
+ expr: l,
+ id,
+ name_span: r.span,
+ val_span: l.span,
+ ord: ordering.reverse(),
+ inc: inclusive,
+ });
}
}
None
@@ -361,8 +361,8 @@ fn check_exclusive_range_plus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
span,
"an inclusive range would be more readable",
|diag| {
- let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string());
- let end = Sugg::hir(cx, y, "y").maybe_par();
+ let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_paren().to_string());
+ let end = Sugg::hir(cx, y, "y").maybe_paren();
match span.with_source_text(cx, |src| src.starts_with('(') && src.ends_with(')')) {
Some(true) => {
diag.span_suggestion(span, "use", format!("({start}..={end})"), Applicability::MaybeIncorrect);
@@ -398,8 +398,8 @@ fn check_inclusive_range_minus_one(cx: &LateContext<'_>, expr: &Expr<'_>) {
expr.span,
"an exclusive range would be more readable",
|diag| {
- let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_par().to_string());
- let end = Sugg::hir(cx, y, "y").maybe_par();
+ let start = start.map_or(String::new(), |x| Sugg::hir(cx, x, "x").maybe_paren().to_string());
+ let end = Sugg::hir(cx, y, "y").maybe_paren();
diag.span_suggestion(
expr.span,
"use",
diff --git a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
index 6bb7650..689a2ac 100644
--- a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
+++ b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
@@ -1,14 +1,14 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::VecArgs;
-use clippy_utils::last_path_segment;
use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::source::{indent_of, snippet};
+use clippy_utils::{last_path_segment, sym};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::declare_lint_pass;
-use rustc_span::{Span, Symbol, sym};
+use rustc_span::{Span, Symbol};
declare_clippy_lint! {
/// ### What it does
@@ -135,7 +135,7 @@ fn ref_init(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(Symbol, Span)> {
if let ty::Adt(adt, _) = *cx.typeck_results().expr_ty(expr).kind()
&& matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::RcWeak | sym::ArcWeak))
{
- return Some((Symbol::intern("Weak"), func.span));
+ return Some((sym::Weak, func.span));
}
}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
index 8289ec4..d2442ad 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
@@ -1,14 +1,9 @@
-use std::ops::ControlFlow;
-
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::peel_blocks;
use clippy_utils::source::{snippet, walk_span_to_context};
use clippy_utils::ty::implements_trait;
-use clippy_utils::visitors::for_each_expr_without_closures;
+use clippy_utils::{desugar_await, peel_blocks};
use rustc_errors::Applicability;
-use rustc_hir::{
- Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource,
-};
+use rustc_hir::{Closure, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::UpvarCapture;
use rustc_session::declare_lint_pass;
@@ -99,20 +94,3 @@ fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Op
None
}
}
-
-/// If `expr` is a desugared `.await`, return the original expression if it does not come from a
-/// macro expansion.
-fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
- if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind
- && let ExprKind::Call(_, [into_future_arg]) = match_value.kind
- && let ctxt = expr.span.ctxt()
- && for_each_expr_without_closures(into_future_arg, |e| {
- walk_span_to_context(e.span, ctxt).map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(()))
- })
- .is_none()
- {
- Some(into_future_arg)
- } else {
- None
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index cfa622a..e57b8cc 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -109,10 +109,10 @@ fn check_fn(
continue;
}
- if let ty::Adt(def, _) = arg_ty.kind() {
- if def.is_manually_drop() {
- continue;
- }
+ if let ty::Adt(def, _) = arg_ty.kind()
+ && def.is_manually_drop()
+ {
+ continue;
}
// `{ arg = &cloned; clone(move arg); }` or `{ arg = &cloned; to_path_buf(arg); }`
@@ -182,20 +182,25 @@ fn check_fn(
let clone_usage = if local == ret_local {
CloneUsage {
- cloned_used: false,
+ cloned_use_loc: None.into(),
cloned_consume_or_mutate_loc: None,
clone_consumed_or_mutated: true,
}
} else {
let clone_usage = visit_clone_usage(local, ret_local, mir, bb);
- if clone_usage.cloned_used && clone_usage.clone_consumed_or_mutated {
+ if clone_usage.cloned_use_loc.maybe_used() && clone_usage.clone_consumed_or_mutated {
// cloned value is used, and the clone is modified or moved
continue;
- } else if let Some(loc) = clone_usage.cloned_consume_or_mutate_loc {
+ } else if let MirLocalUsage::Used(loc) = clone_usage.cloned_use_loc
+ && possible_borrower.local_is_alive_at(ret_local, loc)
+ {
+ // cloned value is used, and the clone is alive.
+ continue;
+ } else if let Some(loc) = clone_usage.cloned_consume_or_mutate_loc
// cloned value is mutated, and the clone is alive.
- if possible_borrower.local_is_alive_at(ret_local, loc) {
- continue;
- }
+ && possible_borrower.local_is_alive_at(ret_local, loc)
+ {
+ continue;
}
clone_usage
};
@@ -216,19 +221,18 @@ fn check_fn(
let call_snip = &snip[dot + 1..];
// Machine applicable when `call_snip` looks like `foobar()`
- if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim) {
- if call_snip
+ if let Some(call_snip) = call_snip.strip_suffix("()").map(str::trim)
+ && call_snip
.as_bytes()
.iter()
.all(|b| b.is_ascii_alphabetic() || *b == b'_')
- {
- app = Applicability::MachineApplicable;
- }
+ {
+ app = Applicability::MachineApplicable;
}
span_lint_hir_and_then(cx, REDUNDANT_CLONE, node, sugg_span, "redundant clone", |diag| {
diag.span_suggestion(sugg_span, "remove this", "", app);
- if clone_usage.cloned_used {
+ if clone_usage.cloned_use_loc.maybe_used() {
diag.span_note(span, "cloned value is neither consumed nor mutated");
} else {
diag.span_note(
@@ -329,10 +333,33 @@ fn base_local_and_movability<'tcx>(
(place.local, deref || field || slice)
}
-#[derive(Default)]
+#[derive(Debug, Default)]
+enum MirLocalUsage {
+ /// The local maybe used, but we are not sure how.
+ Unknown,
+ /// The local is not used.
+ #[default]
+ Unused,
+ /// The local is used at a specific location.
+ Used(mir::Location),
+}
+
+impl MirLocalUsage {
+ fn maybe_used(&self) -> bool {
+ matches!(self, MirLocalUsage::Unknown | MirLocalUsage::Used(_))
+ }
+}
+
+impl From<Option<mir::Location>> for MirLocalUsage {
+ fn from(loc: Option<mir::Location>) -> Self {
+ loc.map_or(MirLocalUsage::Unused, MirLocalUsage::Used)
+ }
+}
+
+#[derive(Debug, Default)]
struct CloneUsage {
- /// Whether the cloned value is used after the clone.
- cloned_used: bool,
+ /// The first location where the cloned value is used, if any.
+ cloned_use_loc: MirLocalUsage,
/// The first location where the cloned value is consumed or mutated, if any.
cloned_consume_or_mutate_loc: Option<mir::Location>,
/// Whether the clone value is mutated.
@@ -360,7 +387,7 @@ fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>,
.map(|mut vec| (vec.remove(0), vec.remove(0)))
{
CloneUsage {
- cloned_used: !cloned_use_locs.is_empty(),
+ cloned_use_loc: cloned_use_locs.first().copied().into(),
cloned_consume_or_mutate_loc: cloned_consume_or_mutate_locs.first().copied(),
// Consider non-temporary clones consumed.
// TODO: Actually check for mutation of non-temporaries.
@@ -369,7 +396,7 @@ fn visit_clone_usage(cloned: mir::Local, clone: mir::Local, mir: &mir::Body<'_>,
}
} else {
CloneUsage {
- cloned_used: true,
+ cloned_use_loc: MirLocalUsage::Unknown,
cloned_consume_or_mutate_loc: None,
clone_consumed_or_mutated: true,
}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index 1498a49..8459726 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -206,7 +206,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
// avoid clippy::double_parens
if !is_in_fn_call_arg {
- hint = hint.maybe_par();
+ hint = hint.maybe_paren();
}
diag.span_suggestion(full_expr.span, "try doing something like", hint, applicability);
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index f2fdac5..7b381fa 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -52,13 +52,10 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
&& is_not_macro_export(item)
&& !item.span.in_external_macro(cx.sess().source_map())
{
- // FIXME: `DUMMY_SP` isn't right here, because it causes the
- // resulting span to begin at the start of the file.
- let span = item.span.with_hi(
- item.kind
- .ident()
- .map_or(rustc_span::DUMMY_SP.hi(), |ident| ident.span.hi()),
- );
+ let span = item
+ .kind
+ .ident()
+ .map_or(item.span, |ident| item.span.with_hi(ident.span.hi()));
let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id());
span_lint_and_then(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 7038b19..1117dea 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -135,25 +135,24 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
};
diag.span_suggestion(expr.span, help_msg, sugg, app);
});
- } else if let Some(target_id) = cx.tcx.lang_items().deref_target() {
- if let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
+ } else if let Some(target_id) = cx.tcx.lang_items().deref_target()
+ && let Ok(deref_ty) = cx.tcx.try_normalize_erasing_regions(
cx.typing_env(),
Ty::new_projection_from_args(cx.tcx, target_id, cx.tcx.mk_args(&[GenericArg::from(indexed_ty)])),
- ) {
- if deref_ty == expr_ty {
- let (lint, msg) = DEREF_BY_SLICING_LINT;
- span_lint_and_then(cx, lint, expr.span, msg, |diag| {
- let mut app = Applicability::MachineApplicable;
- let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
- let sugg = if needs_parens_for_prefix {
- format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count))
- } else {
- format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count))
- };
- diag.span_suggestion(expr.span, "dereference the original value instead", sugg, app);
- });
- }
- }
+ )
+ && deref_ty == expr_ty
+ {
+ let (lint, msg) = DEREF_BY_SLICING_LINT;
+ span_lint_and_then(cx, lint, expr.span, msg, |diag| {
+ let mut app = Applicability::MachineApplicable;
+ let snip = snippet_with_context(cx, indexed.span, ctxt, "..", &mut app).0;
+ let sugg = if needs_parens_for_prefix {
+ format!("(&{}{}*{snip})", mutability.prefix_str(), "*".repeat(indexed_ref_count))
+ } else {
+ format!("&{}{}*{snip}", mutability.prefix_str(), "*".repeat(indexed_ref_count))
+ };
+ diag.span_suggestion(expr.span, "dereference the original value instead", sugg, app);
+ });
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_test_prefix.rs b/src/tools/clippy/clippy_lints/src/redundant_test_prefix.rs
new file mode 100644
index 0000000..84276e3
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/redundant_test_prefix.rs
@@ -0,0 +1,161 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_test_function;
+use clippy_utils::visitors::for_each_expr;
+use rustc_errors::Applicability;
+use rustc_hir::intravisit::FnKind;
+use rustc_hir::{self as hir, Body, ExprKind, FnDecl};
+use rustc_lexer::is_ident;
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::declare_lint_pass;
+use rustc_span::def_id::LocalDefId;
+use rustc_span::{Span, Symbol, edition};
+use std::borrow::Cow;
+use std::ops::ControlFlow;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for test functions (functions annotated with `#[test]`) that are prefixed
+ /// with `test_` which is redundant.
+ ///
+ /// ### Why is this bad?
+ /// This is redundant because test functions are already annotated with `#[test]`.
+ /// Moreover, it clutters the output of `cargo test` since test functions are expanded as
+ /// `module::tests::test_use_case` in the output. Without the redundant prefix, the output
+ /// becomes `module::tests::use_case`, which is more readable.
+ ///
+ /// ### Example
+ /// ```no_run
+ /// #[cfg(test)]
+ /// mod tests {
+ /// use super::*;
+ ///
+ /// #[test]
+ /// fn test_use_case() {
+ /// // test code
+ /// }
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```no_run
+ /// #[cfg(test)]
+ /// mod tests {
+ /// use super::*;
+ ///
+ /// #[test]
+ /// fn use_case() {
+ /// // test code
+ /// }
+ /// }
+ /// ```
+ #[clippy::version = "1.88.0"]
+ pub REDUNDANT_TEST_PREFIX,
+ restriction,
+ "redundant `test_` prefix in test function name"
+}
+
+declare_lint_pass!(RedundantTestPrefix => [REDUNDANT_TEST_PREFIX]);
+
+impl<'tcx> LateLintPass<'tcx> for RedundantTestPrefix {
+ fn check_fn(
+ &mut self,
+ cx: &LateContext<'tcx>,
+ kind: FnKind<'_>,
+ _decl: &FnDecl<'_>,
+ body: &'tcx Body<'_>,
+ _span: Span,
+ fn_def_id: LocalDefId,
+ ) {
+ // Ignore methods and closures.
+ let FnKind::ItemFn(ref ident, ..) = kind else {
+ return;
+ };
+
+ // Skip the lint if the function is within a macro expansion.
+ if ident.span.from_expansion() {
+ return;
+ }
+
+ // Skip if the function name does not start with `test_`.
+ if !ident.as_str().starts_with("test_") {
+ return;
+ }
+
+ // If the function is not a test function, skip the lint.
+ if !is_test_function(cx.tcx, fn_def_id) {
+ return;
+ }
+
+ span_lint_and_then(
+ cx,
+ REDUNDANT_TEST_PREFIX,
+ ident.span,
+ "redundant `test_` prefix in test function name",
+ |diag| {
+ let non_prefixed = Symbol::intern(ident.as_str().trim_start_matches("test_"));
+ if is_invalid_ident(non_prefixed) {
+ // If the prefix-trimmed name is not a valid function name, do not provide an
+ // automatic fix, just suggest renaming the function.
+ diag.help(
+ "consider function renaming (just removing `test_` prefix will produce invalid function name)",
+ );
+ } else {
+ let (sugg, msg): (Cow<'_, str>, _) = if name_conflicts(cx, body, non_prefixed) {
+ // If `non_prefixed` conflicts with another function in the same module/scope,
+ // do not provide an automatic fix, but still emit a fix suggestion.
+ (
+ format!("{non_prefixed}_works").into(),
+ "consider function renaming (just removing `test_` prefix will cause a name conflict)",
+ )
+ } else {
+ // If `non_prefixed` is a valid identifier and does not conflict with another function,
+ // so we can suggest an auto-fix.
+ (non_prefixed.as_str().into(), "consider removing the `test_` prefix")
+ };
+ diag.span_suggestion(ident.span, msg, sugg, Applicability::MaybeIncorrect);
+ }
+ },
+ );
+ }
+}
+
+/// Checks whether removal of the `_test` prefix from the function name will cause a name conflict.
+///
+/// There should be no other function with the same name in the same module/scope. Also, there
+/// should not be any function call with the same name within the body of the function, to avoid
+/// recursion.
+fn name_conflicts<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, fn_name: Symbol) -> bool {
+ let tcx = cx.tcx;
+ let id = body.id().hir_id;
+
+ // Iterate over items in the same module/scope
+ let (module, _module_span, _module_hir) = tcx.hir_get_module(tcx.parent_module(id));
+ if module
+ .item_ids
+ .iter()
+ .any(|item| matches!(tcx.hir_item(*item).kind, hir::ItemKind::Fn { ident, .. } if ident.name == fn_name))
+ {
+ // Name conflict found
+ return true;
+ }
+
+ // Also check that within the body of the function there is also no function call
+ // with the same name (since it will result in recursion)
+ for_each_expr(cx, body, |expr| {
+ if let ExprKind::Path(qpath) = &expr.kind
+ && let Some(def_id) = cx.qpath_res(qpath, expr.hir_id).opt_def_id()
+ && let Some(name) = tcx.opt_item_name(def_id)
+ && name == fn_name
+ {
+ // Function call with the same name found
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(())
+ }
+ })
+ .is_some()
+}
+
+fn is_invalid_ident(ident: Symbol) -> bool {
+ // The identifier is either a reserved keyword, or starts with an invalid sequence.
+ ident.is_reserved(|| edition::LATEST_STABLE_EDITION) || !is_ident(ident.as_str())
+}
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index 9443dca..834ff2a 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -3,7 +3,7 @@
use clippy_utils::consts::{ConstEvalCtxt, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
use clippy_utils::source::SpanRangeExt;
-use clippy_utils::{def_path_res_with_base, find_crates, path_def_id, paths};
+use clippy_utils::{def_path_res_with_base, find_crates, path_def_id, paths, sym};
use rustc_ast::ast::{LitKind, StrStyle};
use rustc_hir::def_id::DefIdMap;
use rustc_hir::{BorrowKind, Expr, ExprKind, OwnerId};
@@ -76,7 +76,7 @@
/// This is documented as an antipattern [on the regex documentation](https://docs.rs/regex/latest/regex/#avoid-re-compiling-regexes-especially-in-a-loop)
///
/// ### Example
- /// ```no_run
+ /// ```rust,ignore
/// # let haystacks = [""];
/// # const MY_REGEX: &str = "a.b";
/// for haystack in haystacks {
@@ -87,7 +87,7 @@
/// }
/// ```
/// can be replaced with
- /// ```no_run
+ /// ```rust,ignore
/// # let haystacks = [""];
/// # const MY_REGEX: &str = "a.b";
/// let regex = regex::Regex::new(MY_REGEX).unwrap();
@@ -126,7 +126,7 @@ fn check_crate(&mut self, cx: &LateContext<'tcx>) {
//
// `def_path_res_with_base` will resolve through re-exports but is relatively heavy, so we only
// perform the operation once and store the results
- let regex_crates = find_crates(cx.tcx, sym!(regex));
+ let regex_crates = find_crates(cx.tcx, sym::regex);
let mut resolve = |path: &[&str], kind: RegexKind| {
for res in def_path_res_with_base(cx.tcx, regex_crates.clone(), &path[1..]) {
if let Some(id) = res.opt_def_id() {
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index 552135b..226e8ff 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -3,7 +3,7 @@
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{HirId, Impl, ItemKind, Node, Path, QPath, TraitRef, TyKind};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::AssocKind;
+use rustc_middle::ty::AssocItem;
use rustc_session::declare_lint_pass;
use rustc_span::Span;
use rustc_span::symbol::Symbol;
@@ -85,8 +85,8 @@ fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
cx.tcx
.associated_items(did)
.in_definition_order()
- .filter(|assoc_item| matches!(assoc_item.kind, AssocKind::Fn))
- .map(|assoc_item| assoc_item.name)
+ .filter(|assoc_item| assoc_item.is_fn())
+ .map(AssocItem::name)
.collect()
} else {
BTreeSet::new()
diff --git a/src/tools/clippy/clippy_lints/src/serde_api.rs b/src/tools/clippy/clippy_lints/src/serde_api.rs
index 6a0dfde..a8c6518 100644
--- a/src/tools/clippy/clippy_lints/src/serde_api.rs
+++ b/src/tools/clippy/clippy_lints/src/serde_api.rs
@@ -32,27 +32,27 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
}) = item.kind
{
let did = trait_ref.path.res.def_id();
- if let Some(visit_did) = get_trait_def_id(cx.tcx, &paths::SERDE_DE_VISITOR) {
- if did == visit_did {
- let mut seen_str = None;
- let mut seen_string = None;
- for item in *items {
- match item.ident.as_str() {
- "visit_str" => seen_str = Some(item.span),
- "visit_string" => seen_string = Some(item.span),
- _ => {},
- }
+ if let Some(visit_did) = get_trait_def_id(cx.tcx, &paths::SERDE_DE_VISITOR)
+ && did == visit_did
+ {
+ let mut seen_str = None;
+ let mut seen_string = None;
+ for item in *items {
+ match item.ident.as_str() {
+ "visit_str" => seen_str = Some(item.span),
+ "visit_string" => seen_string = Some(item.span),
+ _ => {},
}
- if let Some(span) = seen_string {
- if seen_str.is_none() {
- span_lint(
- cx,
- SERDE_API_MISUSE,
- span,
- "you should not implement `visit_string` without also implementing `visit_str`",
- );
- }
- }
+ }
+ if let Some(span) = seen_string
+ && seen_str.is_none()
+ {
+ span_lint(
+ cx,
+ SERDE_API_MISUSE,
+ span,
+ "you should not implement `visit_string` without also implementing `visit_str`",
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
index 1185d67..ff6e6ef 100644
--- a/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
+++ b/src/tools/clippy/clippy_lints/src/set_contains_or_insert.rs
@@ -3,12 +3,12 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::for_each_expr;
-use clippy_utils::{SpanlessEq, higher, peel_hir_expr_while};
+use clippy_utils::{SpanlessEq, higher, peel_hir_expr_while, sym};
use rustc_hir::{Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::declare_lint_pass;
+use rustc_span::Span;
use rustc_span::symbol::Symbol;
-use rustc_span::{Span, sym};
declare_clippy_lint! {
/// ### What it does
@@ -58,7 +58,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
then: then_expr,
..
}) = higher::If::hir(expr)
- && let Some((contains_expr, sym)) = try_parse_op_call(cx, cond_expr, sym!(contains))//try_parse_contains(cx, cond_expr)
+ && let Some((contains_expr, sym)) = try_parse_op_call(cx, cond_expr, sym::contains)//try_parse_contains(cx, cond_expr)
&& let Some(insert_expr) = find_insert_calls(cx, &contains_expr, then_expr)
{
span_lint(
@@ -118,7 +118,7 @@ fn find_insert_calls<'tcx>(
expr: &'tcx Expr<'_>,
) -> Option<OpExpr<'tcx>> {
for_each_expr(cx, expr, |e| {
- if let Some((insert_expr, _)) = try_parse_op_call(cx, e, sym!(insert))
+ if let Some((insert_expr, _)) = try_parse_op_call(cx, e, sym::insert)
&& SpanlessEq::new(cx).eq_expr(contains_expr.receiver, insert_expr.receiver)
&& SpanlessEq::new(cx).eq_expr(contains_expr.value, insert_expr.value)
{
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index b82dded..1439986 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -8,7 +8,9 @@
use rustc_hir::def::Res;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::hir_id::ItemLocalId;
-use rustc_hir::{Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, LetExpr, Node, Pat, PatKind, QPath, UnOp};
+use rustc_hir::{
+ Block, Body, BodyOwnerKind, Expr, ExprKind, HirId, LetExpr, LocalSource, Node, Pat, PatKind, QPath, UnOp,
+};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::impl_lint_pass;
use rustc_span::{Span, Symbol};
@@ -65,7 +67,7 @@
#[clippy::version = "pre 1.29.0"]
pub SHADOW_REUSE,
restriction,
- "rebinding a name to an expression that re-uses the original value, e.g., `let x = x + 1`"
+ "rebinding a name to an expression that reuses the original value, e.g., `let x = x + 1`"
}
declare_clippy_lint! {
@@ -125,6 +127,17 @@ fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
return;
}
+ // Desugaring of a destructuring assignment may reuse the same identifier internally.
+ // Peel `Pat` and `PatField` nodes and check if we reach a desugared `Let` assignment.
+ if let Some((_, Node::LetStmt(let_stmt))) = cx
+ .tcx
+ .hir_parent_iter(pat.hir_id)
+ .find(|(_, node)| !matches!(node, Node::Pat(_) | Node::PatField(_)))
+ && let LocalSource::AssignDesugar(_) = let_stmt.source
+ {
+ return;
+ }
+
let HirId { owner, local_id } = id;
// get (or insert) the list of items for this owner and symbol
let (ref mut data, scope_owner) = *self.bindings.last_mut().unwrap();
@@ -167,10 +180,10 @@ fn check_body_post(&mut self, cx: &LateContext<'_>, body: &Body<'_>) {
fn is_shadow(cx: &LateContext<'_>, owner: LocalDefId, first: ItemLocalId, second: ItemLocalId) -> bool {
let scope_tree = cx.tcx.region_scope_tree(owner.to_def_id());
- if let Some(first_scope) = scope_tree.var_scope(first) {
- if let Some(second_scope) = scope_tree.var_scope(second) {
- return scope_tree.is_subscope_of(second_scope, first_scope);
- }
+ if let Some(first_scope) = scope_tree.var_scope(first)
+ && let Some(second_scope) = scope_tree.var_scope(second)
+ {
+ return scope_tree.is_subscope_of(second_scope, first_scope);
}
false
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
index 76874cc..ccb1209 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -124,8 +124,7 @@ fn check_fn(
diag.span_label(
apa.first_block_span,
format!(
- "temporary `{}` is currently being dropped at the end of its contained scope",
- first_bind_ident
+ "temporary `{first_bind_ident}` is currently being dropped at the end of its contained scope"
),
);
},
@@ -145,7 +144,10 @@ pub(crate) fn new(cx: &'cx LateContext<'tcx>, type_cache: &'others mut FxHashMap
Self { cx, type_cache }
}
- fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool {
+ fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>, depth: usize) -> bool {
+ if !self.cx.tcx.recursion_limit().value_within_limit(depth) {
+ return false;
+ }
let ty = self
.cx
.tcx
@@ -157,12 +159,12 @@ fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool {
e.insert(false);
},
}
- let value = self.has_sig_drop_attr_uncached(ty);
+ let value = self.has_sig_drop_attr_uncached(ty, depth + 1);
self.type_cache.insert(ty, value);
value
}
- fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>) -> bool {
+ fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>, depth: usize) -> bool {
if let Some(adt) = ty.ty_adt_def() {
let mut iter = get_attr(
self.cx.sess(),
@@ -177,15 +179,15 @@ fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>) -> bool {
rustc_middle::ty::Adt(a, b) => {
for f in a.all_fields() {
let ty = f.ty(self.cx.tcx, b);
- if self.has_sig_drop_attr(ty) {
+ if self.has_sig_drop_attr(ty, depth) {
return true;
}
}
for generic_arg in *b {
- if let GenericArgKind::Type(ty) = generic_arg.unpack() {
- if self.has_sig_drop_attr(ty) {
- return true;
- }
+ if let GenericArgKind::Type(ty) = generic_arg.unpack()
+ && self.has_sig_drop_attr(ty, depth)
+ {
+ return true;
}
}
false
@@ -193,7 +195,7 @@ fn has_sig_drop_attr_uncached(&mut self, ty: Ty<'tcx>) -> bool {
rustc_middle::ty::Array(ty, _)
| rustc_middle::ty::RawPtr(ty, _)
| rustc_middle::ty::Ref(_, ty, _)
- | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(*ty),
+ | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(*ty, depth),
_ => false,
}
}
@@ -269,7 +271,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
apa.has_expensive_expr_after_last_attr = false;
};
let mut ac = AttrChecker::new(self.cx, self.type_cache);
- if ac.has_sig_drop_attr(self.cx.typeck_results().expr_ty(expr)) {
+ if ac.has_sig_drop_attr(self.cx.typeck_results().expr_ty(expr), 0) {
if let hir::StmtKind::Let(local) = self.ap.curr_stmt.kind
&& let hir::PatKind::Binding(_, hir_id, ident, _) = local.pat.kind
&& !self.ap.apas.contains_key(&hir_id)
@@ -317,7 +319,7 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
}
},
hir::StmtKind::Semi(semi_expr) => {
- if has_drop(semi_expr, &apa.first_bind_ident, self.cx) {
+ if has_drop(semi_expr, apa.first_bind_ident, self.cx) {
apa.has_expensive_expr_after_last_attr = false;
apa.last_stmt_span = DUMMY_SP;
return;
@@ -414,7 +416,7 @@ fn dummy_stmt_expr<'any>(expr: &'any hir::Expr<'any>) -> hir::Stmt<'any> {
}
}
-fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Option<Ident>, lcx: &LateContext<'_>) -> bool {
+fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: Option<Ident>, lcx: &LateContext<'_>) -> bool {
if let hir::ExprKind::Call(fun, [first_arg]) = expr.kind
&& let hir::ExprKind::Path(hir::QPath::Resolved(_, fun_path)) = &fun.kind
&& let Res::Def(DefKind::Fn, did) = fun_path.res
@@ -424,7 +426,7 @@ fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Option<Ident>, lcx: &LateCo
if let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &local_expr.kind
&& let [first_arg_ps, ..] = arg_path.segments
&& let Some(first_bind_ident) = first_bind_ident
- && &first_arg_ps.ident == first_bind_ident
+ && first_arg_ps.ident == first_bind_ident
{
true
} else {
diff --git a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
index 50a6ee3..8c34da0 100644
--- a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
+++ b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
@@ -45,19 +45,20 @@ fn check_generic_param(&mut self, ctx: &EarlyContext<'_>, param: &GenericParam)
return;
}
- if let GenericParamKind::Lifetime = param.kind {
- if !param.is_placeholder && param.ident.as_str().len() <= 2 {
- #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
- span_lint_and_then(
- ctx,
- SINGLE_CHAR_LIFETIME_NAMES,
- param.ident.span,
- "single-character lifetime names are likely uninformative",
- |diag| {
- diag.help("use a more informative name");
- },
- );
- }
+ if let GenericParamKind::Lifetime = param.kind
+ && !param.is_placeholder
+ && param.ident.as_str().len() <= 2
+ {
+ #[expect(clippy::collapsible_span_lint_calls, reason = "rust-clippy#7797")]
+ span_lint_and_then(
+ ctx,
+ SINGLE_CHAR_LIFETIME_NAMES,
+ param.ident.span,
+ "single-character lifetime names are likely uninformative",
+ |diag| {
+ diag.help("use a more informative name");
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
index 35f80b2..6293991 100644
--- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
@@ -204,17 +204,17 @@ fn track_uses(
if let UseTreeKind::Nested { items, .. } = &use_tree.kind {
for tree in items {
let segments = &tree.0.prefix.segments;
- if segments.len() == 1 {
- if let UseTreeKind::Simple(None) = tree.0.kind {
- let name = segments[0].ident.name;
- if !macros.contains(&name) {
- single_use_usages.push(SingleUse {
- name,
- span: tree.0.span,
- item_id: item.id,
- can_suggest: false,
- });
- }
+ if segments.len() == 1
+ && let UseTreeKind::Simple(None) = tree.0.kind
+ {
+ let name = segments[0].ident.name;
+ if !macros.contains(&name) {
+ single_use_usages.push(SingleUse {
+ name,
+ span: tree.0.span,
+ item_id: item.id,
+ can_suggest: false,
+ });
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 27c548b..43a3e69 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -3,7 +3,7 @@
use clippy_utils::ty::is_type_lang_item;
use clippy_utils::{
SpanlessEq, get_expr_use_or_unification_node, get_parent_expr, is_lint_allowed, method_calls, path_def_id,
- peel_blocks,
+ peel_blocks, sym,
};
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
@@ -12,7 +12,6 @@
use rustc_middle::ty;
use rustc_session::declare_lint_pass;
use rustc_span::source_map::Spanned;
-use rustc_span::sym;
use std::ops::ControlFlow;
@@ -162,13 +161,12 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if is_string(cx, left) {
if !is_lint_allowed(cx, STRING_ADD_ASSIGN, e.hir_id) {
let parent = get_parent_expr(cx, e);
- if let Some(p) = parent {
- if let ExprKind::Assign(target, _, _) = p.kind {
+ if let Some(p) = parent
+ && let ExprKind::Assign(target, _, _) = p.kind
// avoid duplicate matches
- if SpanlessEq::new(cx).eq_expr(target, left) {
- return;
- }
- }
+ && SpanlessEq::new(cx).eq_expr(target, left)
+ {
+ return;
}
}
span_lint(
@@ -263,7 +261,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
&& let ExprKind::AddrOf(BorrowKind::Ref, _, args) = bytes_arg.kind
&& let ExprKind::Index(left, right, _) = args.kind
&& let (method_names, expressions, _) = method_calls(left, 1)
- && method_names == [sym!(as_bytes)]
+ && method_names == [sym::as_bytes]
&& expressions.len() == 1
&& expressions[0].1.is_empty()
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
index 56bd8fe..83241f9 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_trait_impl.rs
@@ -59,25 +59,18 @@ impl<'tcx> LateLintPass<'tcx> for SuspiciousImpl {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
match expr.kind {
hir::ExprKind::Binary(op, _, _) => {
- self.check_expr_inner(cx, expr, op.node, op.span);
- }
+ check_expr_inner(cx, expr, op.node, op.span);
+ },
hir::ExprKind::AssignOp(op, _, _) => {
- self.check_expr_inner(cx, expr, op.node.into(), op.span);
- }
- _ => {}
+ check_expr_inner(cx, expr, op.node.into(), op.span);
+ },
+ _ => {},
}
}
}
-impl<'tcx> SuspiciousImpl {
- fn check_expr_inner(
- &mut self,
- cx: &LateContext<'tcx>,
- expr: &'tcx hir::Expr<'_>,
- binop: hir::BinOpKind,
- span: Span,
- ) {
- if let Some((binop_trait_lang, op_assign_trait_lang)) = binop_traits(binop)
+fn check_expr_inner<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, binop: hir::BinOpKind, span: Span) {
+ if let Some((binop_trait_lang, op_assign_trait_lang)) = binop_traits(binop)
&& let Some(binop_trait_id) = cx.tcx.lang_items().get(binop_trait_lang)
&& let Some(op_assign_trait_id) = cx.tcx.lang_items().get(op_assign_trait_lang)
@@ -98,18 +91,17 @@ fn check_expr_inner(
.iter()
.find(|&(ts, _)| ts.iter().any(|&t| Some(trait_id) == cx.tcx.lang_items().get(t)))
&& count_binops(body.value) == 1
- {
- span_lint(
- cx,
- lint,
- span,
- format!(
- "suspicious use of `{}` in `{}` impl",
- binop.as_str(),
- cx.tcx.item_name(trait_id)
- ),
- );
- }
+ {
+ span_lint(
+ cx,
+ lint,
+ span,
+ format!(
+ "suspicious use of `{}` in `{}` impl",
+ binop.as_str(),
+ cx.tcx.item_name(trait_id)
+ ),
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 0337b74..e3ecd65 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -133,7 +133,7 @@ fn generate_swap_warning<'tcx>(
applicability: &mut applicability,
}
.snippet_index_bindings(&[idx1, idx2, rhs1, rhs2]),
- slice.maybe_par(),
+ slice.maybe_paren(),
snippet_with_context(cx, idx1.span, ctxt, "..", &mut applicability).0,
snippet_with_context(cx, idx2.span, ctxt, "..", &mut applicability).0,
),
@@ -269,12 +269,11 @@ fn parse<'a, 'hir>(stmt: &'a Stmt<'hir>) -> Option<(ExprOrIdent<'hir>, &'a Expr<
if let ExprKind::Assign(lhs, rhs, _) = expr.kind {
return Some((ExprOrIdent::Expr(lhs), rhs));
}
- } else if let StmtKind::Let(expr) = stmt.kind {
- if let Some(rhs) = expr.init {
- if let PatKind::Binding(_, _, ident_l, _) = expr.pat.kind {
- return Some((ExprOrIdent::Ident(ident_l), rhs));
- }
- }
+ } else if let StmtKind::Let(expr) = stmt.kind
+ && let Some(rhs) = expr.init
+ && let PatKind::Binding(_, _, ident_l, _) = expr.pat.kind
+ {
+ return Some((ExprOrIdent::Ident(ident_l), rhs));
}
None
}
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index fa36c9a..8aac3a5 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -151,20 +151,19 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tc
.iter()
.filter_map(get_trait_info_from_bound)
.for_each(|(trait_item_res, trait_item_segments, span)| {
- if let Some(self_segments) = self_bounds_map.get(&trait_item_res) {
- if SpanlessEq::new(cx)
+ if let Some(self_segments) = self_bounds_map.get(&trait_item_res)
+ && SpanlessEq::new(cx)
.paths_by_resolution()
.eq_path_segments(self_segments, trait_item_segments)
- {
- span_lint_and_help(
- cx,
- TRAIT_DUPLICATION_IN_BOUNDS,
- span,
- "this trait bound is already specified in trait declaration",
- None,
- "consider removing this trait bound",
- );
- }
+ {
+ span_lint_and_help(
+ cx,
+ TRAIT_DUPLICATION_IN_BOUNDS,
+ span,
+ "this trait bound is already specified in trait declaration",
+ None,
+ "consider removing this trait bound",
+ );
}
});
}
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
index f2c7579..df2f681 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_float_to_int.rs
@@ -47,7 +47,7 @@ pub(super) fn check<'tcx>(
}
}
- sugg = sugg::Sugg::NonParen(format!("{}.to_bits()", sugg.maybe_par()).into());
+ sugg = sugg::Sugg::NonParen(format!("{}.to_bits()", sugg.maybe_paren()).into());
// cast the result of `to_bits` if `to_ty` is signed
sugg = if let ty::Int(int_ty) = to_ty.kind() {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
index fcc7637..933e25f 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ptr.rs
@@ -33,7 +33,7 @@ pub(super) fn check<'tcx>(
diag.span_suggestion_verbose(
e.span,
"use `pointer::cast` instead",
- format!("{}.cast::<{to_pointee_ty}>()", arg.maybe_par()),
+ format!("{}.cast::<{to_pointee_ty}>()", arg.maybe_paren()),
Applicability::MaybeIncorrect,
);
} else if from_pointee_ty == to_pointee_ty
@@ -48,7 +48,7 @@ pub(super) fn check<'tcx>(
diag.span_suggestion_verbose(
e.span,
format!("use `pointer::{method}` instead"),
- format!("{}.{method}()", arg.maybe_par()),
+ format!("{}.{method}()", arg.maybe_paren()),
Applicability::MaybeIncorrect,
);
} else {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
index 45ee83c..e58212f 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
@@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(
let sugg = if let Some(ty) = get_explicit_type(path) {
let ty_snip = snippet_with_applicability(cx, ty.span, "..", &mut app);
if msrv.meets(cx, msrvs::POINTER_CAST) {
- format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_par())
+ format!("{deref}{}.cast::<{ty_snip}>()", arg.maybe_paren())
} else if from_ptr_ty.has_erased_regions() {
sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {ty_snip}"))).to_string()
} else {
@@ -47,7 +47,7 @@ pub(super) fn check<'tcx>(
} else if *from_ptr_ty == *to_ref_ty {
if from_ptr_ty.has_erased_regions() {
if msrv.meets(cx, msrvs::POINTER_CAST) {
- format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_par())
+ format!("{deref}{}.cast::<{to_ref_ty}>()", arg.maybe_paren())
} else {
sugg::make_unop(deref, arg.as_ty(format!("{cast} () as {cast} {to_ref_ty}")))
.to_string()
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index b6f4c4d..3147058 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -591,26 +591,26 @@ fn check_ty<'tcx>(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx>, mut
TyKind::Path(ref qpath) if !context.in_body => {
let hir_id = hir_ty.hir_id;
let res = cx.qpath_res(qpath, hir_id);
- if let Some(def_id) = res.opt_def_id() {
- if self.is_type_change_allowed(context) {
- // All lints that are being checked in this block are guarded by
- // the `avoid_breaking_exported_api` configuration. When adding a
- // new lint, please also add the name to the configuration documentation
- // in `clippy_config::conf`
+ if let Some(def_id) = res.opt_def_id()
+ && self.is_type_change_allowed(context)
+ {
+ // All lints that are being checked in this block are guarded by
+ // the `avoid_breaking_exported_api` configuration. When adding a
+ // new lint, please also add the name to the configuration documentation
+ // in `clippy_config::conf`
- let mut triggered = false;
- triggered |= box_collection::check(cx, hir_ty, qpath, def_id);
- triggered |= redundant_allocation::check(cx, hir_ty, qpath, def_id);
- triggered |= rc_buffer::check(cx, hir_ty, qpath, def_id);
- triggered |= vec_box::check(cx, hir_ty, qpath, def_id, self.vec_box_size_threshold);
- triggered |= option_option::check(cx, hir_ty, qpath, def_id);
- triggered |= linked_list::check(cx, hir_ty, def_id);
- triggered |= rc_mutex::check(cx, hir_ty, qpath, def_id);
- triggered |= owned_cow::check(cx, qpath, def_id);
+ let mut triggered = false;
+ triggered |= box_collection::check(cx, hir_ty, qpath, def_id);
+ triggered |= redundant_allocation::check(cx, hir_ty, qpath, def_id);
+ triggered |= rc_buffer::check(cx, hir_ty, qpath, def_id);
+ triggered |= vec_box::check(cx, hir_ty, qpath, def_id, self.vec_box_size_threshold);
+ triggered |= option_option::check(cx, hir_ty, qpath, def_id);
+ triggered |= linked_list::check(cx, hir_ty, def_id);
+ triggered |= rc_mutex::check(cx, hir_ty, qpath, def_id);
+ triggered |= owned_cow::check(cx, qpath, def_id);
- if triggered {
- return;
- }
+ if triggered {
+ return;
}
}
match *qpath {
diff --git a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
index 51c7d6f..d321c48 100644
--- a/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/unconditional_recursion.rs
@@ -10,7 +10,7 @@
use rustc_hir_analysis::lower_ty;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::{self, AssocKind, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::impl_lint_pass;
use rustc_span::symbol::{Ident, kw};
use rustc_span::{Span, sym};
@@ -23,8 +23,8 @@
/// implementations.
///
/// ### Why is this bad?
- /// This is a hard to find infinite recursion that will crash any code
- /// using it.
+ /// Infinite recursion in trait implementation will either cause crashes
+ /// or result in an infinite loop, and it is hard to detect.
///
/// ### Example
/// ```no_run
@@ -39,9 +39,31 @@
/// }
/// }
/// ```
+ ///
/// Use instead:
///
- /// In such cases, either use `#[derive(PartialEq)]` or don't implement it.
+ /// ```no_run
+ /// #[derive(PartialEq)]
+ /// enum Foo {
+ /// A,
+ /// B,
+ /// }
+ /// ```
+ ///
+ /// As an alternative, rewrite the logic without recursion:
+ ///
+ /// ```no_run
+ /// enum Foo {
+ /// A,
+ /// B,
+ /// }
+ ///
+ /// impl PartialEq for Foo {
+ /// fn eq(&self, other: &Self) -> bool {
+ /// matches!((self, other), (Foo::A, Foo::A) | (Foo::B, Foo::B))
+ /// }
+ /// }
+ /// ```
#[clippy::version = "1.77.0"]
pub UNCONDITIONAL_RECURSION,
suspicious,
@@ -113,7 +135,7 @@ fn get_impl_trait_def_id(cx: &LateContext<'_>, method_def_id: LocalDefId) -> Opt
}),
)) = cx.tcx.hir_parent_iter(hir_id).next()
// We exclude `impl` blocks generated from rustc's proc macros.
- && !cx.tcx.has_attr(*owner_id, sym::automatically_derived)
+ && !cx.tcx.is_automatically_derived(owner_id.to_def_id())
// It is a implementation of a trait.
&& let Some(trait_) = impl_.of_trait
{
@@ -218,7 +240,7 @@ fn check_to_string(cx: &LateContext<'_>, method_span: Span, method_def_id: Local
}),
)) = cx.tcx.hir_parent_iter(hir_id).next()
// We exclude `impl` blocks generated from rustc's proc macros.
- && !cx.tcx.has_attr(*owner_id, sym::automatically_derived)
+ && !cx.tcx.is_automatically_derived(owner_id.to_def_id())
// It is a implementation of a trait.
&& let Some(trait_) = impl_.of_trait
&& let Some(trait_def_id) = trait_.trait_def_id()
@@ -315,14 +337,14 @@ fn init_default_impl_for_type_if_needed(&mut self, cx: &LateContext<'_>) {
for (ty, impl_def_ids) in impls.non_blanket_impls() {
let Some(self_def_id) = ty.def() else { continue };
for impl_def_id in impl_def_ids {
- if !cx.tcx.has_attr(*impl_def_id, sym::automatically_derived) &&
+ if !cx.tcx.is_automatically_derived(*impl_def_id) &&
let Some(assoc_item) = cx
.tcx
.associated_items(impl_def_id)
.in_definition_order()
// We're not interested in foreign implementations of the `Default` trait.
.find(|item| {
- item.kind == AssocKind::Fn && item.def_id.is_local() && item.name == kw::Default
+ item.is_fn() && item.def_id.is_local() && item.name() == kw::Default
})
&& let Some(body_node) = cx.tcx.hir_get_if_local(assoc_item.def_id)
&& let Some(body_id) = body_node.body_id()
diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs
index e1fc644..79571b0 100644
--- a/src/tools/clippy/clippy_lints/src/unicode.rs
+++ b/src/tools/clippy/clippy_lints/src/unicode.rs
@@ -76,10 +76,10 @@
impl LateLintPass<'_> for Unicode {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) {
- if let ExprKind::Lit(lit) = expr.kind {
- if let LitKind::Str(_, _) | LitKind::Char(_) = lit.node {
- check_str(cx, lit.span, expr.hir_id);
- }
+ if let ExprKind::Lit(lit) = expr.kind
+ && let LitKind::Str(_, _) | LitKind::Char(_) = lit.node
+ {
+ check_str(cx, lit.span, expr.hir_id);
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index 937e35d..bcd05cc 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -93,13 +93,13 @@ fn check_fn(
// Abort if the method is implementing a trait or of it a trait method.
let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
- if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
- if matches!(
+ if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id)
+ && matches!(
item.kind,
ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
- ) {
- return;
- }
+ )
+ {
+ return;
}
// Get the wrapper and inner types, if can't, abort.
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 8966e68..9ad1844 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -69,10 +69,10 @@ fn check_arm(&mut self, cx: &EarlyContext<'_>, a: &ast::Arm) {
}
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
- if self.msrv.meets(msrvs::OR_PATTERNS) {
- if let ast::ExprKind::Let(pat, _, _, _) = &e.kind {
- lint_unnested_or_patterns(cx, pat);
- }
+ if self.msrv.meets(msrvs::OR_PATTERNS)
+ && let ast::ExprKind::Let(pat, _, _, _) = &e.kind
+ {
+ lint_unnested_or_patterns(cx, pat);
}
}
@@ -120,18 +120,25 @@ fn lint_unnested_or_patterns(cx: &EarlyContext<'_>, pat: &Pat) {
/// Remove all `(p)` patterns in `pat`.
fn remove_all_parens(pat: &mut P<Pat>) {
- struct Visitor;
+ #[derive(Default)]
+ struct Visitor {
+ /// If is not in the outer most pattern. This is needed to avoid removing the outermost
+ /// parens because top-level or-patterns are not allowed in let statements.
+ is_inner: bool,
+ }
+
impl MutVisitor for Visitor {
fn visit_pat(&mut self, pat: &mut P<Pat>) {
+ let is_inner = mem::replace(&mut self.is_inner, true);
walk_pat(self, pat);
let inner = match &mut pat.kind {
- Paren(i) => mem::replace(&mut i.kind, Wild),
+ Paren(i) if is_inner => mem::replace(&mut i.kind, Wild),
_ => return,
};
pat.kind = inner;
}
}
- Visitor.visit_pat(pat);
+ Visitor::default().visit_pat(pat);
}
/// Insert parens where necessary according to Rust's precedence rules for patterns.
diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
index 0687fc3..2d88c49 100644
--- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs
@@ -265,15 +265,14 @@ fn unpack_match<'a>(mut expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
/// If `expr` is an (e).await, return the inner expression "e" that's being
/// waited on. Otherwise return None.
fn unpack_await<'a>(expr: &'a hir::Expr<'a>) -> &'a hir::Expr<'a> {
- if let ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind {
- if let ExprKind::Call(func, [arg_0]) = expr.kind {
- if matches!(
- func.kind,
- ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..))
- ) {
- return arg_0;
- }
- }
+ if let ExprKind::Match(expr, _, hir::MatchSource::AwaitDesugar) = expr.kind
+ && let ExprKind::Call(func, [arg_0]) = expr.kind
+ && matches!(
+ func.kind,
+ ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoFutureIntoFuture, ..))
+ )
+ {
+ return arg_0;
}
expr
}
diff --git a/src/tools/clippy/clippy_lints/src/unused_self.rs b/src/tools/clippy/clippy_lints/src/unused_self.rs
index 582aa6e..d0067b1 100644
--- a/src/tools/clippy/clippy_lints/src/unused_self.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_self.rs
@@ -74,7 +74,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &ImplItem<'_>)
.is_some()
};
if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind
- && assoc_item.fn_has_self_parameter
+ && assoc_item.is_method()
&& let ImplItemKind::Fn(.., body_id) = &impl_item.kind
&& (!cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api)
&& let body = cx.tcx.hir_body(*body_id)
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index b466a8e..ce82b56 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::usage::is_potentially_local_place;
-use clippy_utils::{higher, path_to_local};
+use clippy_utils::{higher, path_to_local, sym};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr, walk_fn};
use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegment, UnOp};
@@ -11,8 +11,8 @@
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::declare_lint_pass;
+use rustc_span::Span;
use rustc_span::def_id::LocalDefId;
-use rustc_span::{Span, sym};
declare_clippy_lint! {
/// ### What it does
@@ -307,8 +307,8 @@ fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
if let ExprKind::MethodCall(method_name, self_arg, ..) = expr.kind
&& let (self_arg, as_ref_kind) = consume_option_as_ref(self_arg)
&& let Some(id) = path_to_local(self_arg)
- && [sym::unwrap, sym::expect, sym!(unwrap_err)].contains(&method_name.ident.name)
- && let call_to_unwrap = [sym::unwrap, sym::expect].contains(&method_name.ident.name)
+ && matches!(method_name.ident.name, sym::unwrap | sym::expect | sym::unwrap_err)
+ && let call_to_unwrap = matches!(method_name.ident.name, sym::unwrap | sym::expect)
&& let Some(unwrappable) = self.unwrappables.iter()
.find(|u| u.local_id == id)
// Span contexts should not differ with the conditional branch
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index 57bb2fc..3a9c997 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -92,36 +92,36 @@ fn into_iter_bound<'tcx>(
let mut into_iter_span = None;
for (pred, span) in cx.tcx.explicit_predicates_of(fn_did).predicates {
- if let ty::ClauseKind::Trait(tr) = pred.kind().skip_binder() {
- if tr.self_ty().is_param(param_index) {
- if tr.def_id() == into_iter_did {
- into_iter_span = Some(*span);
- } else {
- let tr = cx.tcx.erase_regions(tr);
- if tr.has_escaping_bound_vars() {
- return None;
- }
+ if let ty::ClauseKind::Trait(tr) = pred.kind().skip_binder()
+ && tr.self_ty().is_param(param_index)
+ {
+ if tr.def_id() == into_iter_did {
+ into_iter_span = Some(*span);
+ } else {
+ let tr = cx.tcx.erase_regions(tr);
+ if tr.has_escaping_bound_vars() {
+ return None;
+ }
- // Substitute generics in the predicate and replace the IntoIterator type parameter with the
- // `.into_iter()` receiver to see if the bound also holds for that type.
- let args = cx.tcx.mk_args_from_iter(node_args.iter().enumerate().map(|(i, arg)| {
- if i == param_index as usize {
- GenericArg::from(into_iter_receiver)
- } else {
- arg
- }
- }));
-
- let predicate = EarlyBinder::bind(tr).instantiate(cx.tcx, args);
- let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
- if !cx
- .tcx
- .infer_ctxt()
- .build(cx.typing_mode())
- .predicate_must_hold_modulo_regions(&obligation)
- {
- return None;
+ // Substitute generics in the predicate and replace the IntoIterator type parameter with the
+ // `.into_iter()` receiver to see if the bound also holds for that type.
+ let args = cx.tcx.mk_args_from_iter(node_args.iter().enumerate().map(|(i, arg)| {
+ if i == param_index as usize {
+ GenericArg::from(into_iter_receiver)
+ } else {
+ arg
}
+ }));
+
+ let predicate = EarlyBinder::bind(tr).instantiate(cx.tcx, args);
+ let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
+ if !cx
+ .tcx
+ .infer_ctxt()
+ .build(cx.typing_mode())
+ .predicate_must_hold_modulo_regions(&obligation)
+ {
+ return None;
}
}
}
@@ -356,7 +356,7 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
if cx.tcx.is_diagnostic_item(sym::from_fn, def_id) && same_type_and_consts(a, b) {
let mut app = Applicability::MachineApplicable;
- let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "<expr>", &mut app).maybe_par();
+ let sugg = Sugg::hir_with_context(cx, arg, e.span.ctxt(), "<expr>", &mut app).maybe_paren();
let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from"));
span_lint_and_sugg(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
deleted file mode 100644
index deb983b..0000000
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-pub mod almost_standard_lint_formulation;
-pub mod collapsible_calls;
-pub mod interning_defined_symbol;
-pub mod invalid_paths;
-pub mod lint_without_lint_pass;
-pub mod msrv_attr_impl;
-pub mod outer_expn_data_pass;
-pub mod produce_ice;
-pub mod slow_symbol_comparisons;
-pub mod unnecessary_def_path;
-pub mod unsorted_clippy_utils_paths;
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
deleted file mode 100644
index e454427..0000000
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
+++ /dev/null
@@ -1,241 +0,0 @@
-use clippy_utils::consts::{ConstEvalCtxt, Constant};
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::source::snippet;
-use clippy_utils::ty::match_type;
-use clippy_utils::{def_path_def_ids, is_expn_of, match_def_path, paths};
-use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::Applicability;
-use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::DefId;
-use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::mir::ConstValue;
-use rustc_middle::ty;
-use rustc_session::impl_lint_pass;
-use rustc_span::sym;
-use rustc_span::symbol::Symbol;
-
-use std::borrow::Cow;
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for interning symbols that have already been pre-interned and defined as constants.
- ///
- /// ### Why is this bad?
- /// It's faster and easier to use the symbol constant.
- ///
- /// ### Example
- /// ```rust,ignore
- /// let _ = sym!(f32);
- /// ```
- ///
- /// Use instead:
- /// ```rust,ignore
- /// let _ = sym::f32;
- /// ```
- pub INTERNING_DEFINED_SYMBOL,
- internal,
- "interning a symbol that is pre-interned and defined as a constant"
-}
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks for unnecessary conversion from Symbol to a string.
- ///
- /// ### Why is this bad?
- /// It's faster use symbols directly instead of strings.
- ///
- /// ### Example
- /// ```rust,ignore
- /// symbol.as_str() == "clippy";
- /// ```
- ///
- /// Use instead:
- /// ```rust,ignore
- /// symbol == sym::clippy;
- /// ```
- pub UNNECESSARY_SYMBOL_STR,
- internal,
- "unnecessary conversion between Symbol and string"
-}
-
-#[derive(Default)]
-pub struct InterningDefinedSymbol {
- // Maps the symbol value to the constant DefId.
- symbol_map: FxHashMap<u32, DefId>,
-}
-
-impl_lint_pass!(InterningDefinedSymbol => [INTERNING_DEFINED_SYMBOL, UNNECESSARY_SYMBOL_STR]);
-
-impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
- fn check_crate(&mut self, cx: &LateContext<'_>) {
- if !self.symbol_map.is_empty() {
- return;
- }
-
- for &module in &[&paths::KW_MODULE, &paths::SYM_MODULE] {
- for def_id in def_path_def_ids(cx.tcx, module) {
- for item in cx.tcx.module_children(def_id) {
- if let Res::Def(DefKind::Const, item_def_id) = item.res
- && let ty = cx.tcx.type_of(item_def_id).instantiate_identity()
- && match_type(cx, ty, &paths::SYMBOL)
- && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id)
- && let Some(value) = value.to_u32().discard_err()
- {
- self.symbol_map.insert(value, item_def_id);
- }
- }
- }
- }
- }
-
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- if let ExprKind::Call(func, [arg]) = &expr.kind
- && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind()
- && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id)
- && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg)
- && let value = Symbol::intern(&arg).as_u32()
- && let Some(&def_id) = self.symbol_map.get(&value)
- {
- span_lint_and_sugg(
- cx,
- INTERNING_DEFINED_SYMBOL,
- is_expn_of(expr.span, "sym").unwrap_or(expr.span),
- "interning a defined symbol",
- "try",
- cx.tcx.def_path_str(def_id),
- Applicability::MachineApplicable,
- );
- }
- if let ExprKind::Binary(op, left, right) = expr.kind {
- if matches!(op.node, BinOpKind::Eq | BinOpKind::Ne) {
- let data = [
- (left, self.symbol_str_expr(left, cx)),
- (right, self.symbol_str_expr(right, cx)),
- ];
- match data {
- // both operands are a symbol string
- [(_, Some(left)), (_, Some(right))] => {
- span_lint_and_sugg(
- cx,
- UNNECESSARY_SYMBOL_STR,
- expr.span,
- "unnecessary `Symbol` to string conversion",
- "try",
- format!(
- "{} {} {}",
- left.as_symbol_snippet(cx),
- op.node.as_str(),
- right.as_symbol_snippet(cx),
- ),
- Applicability::MachineApplicable,
- );
- },
- // one of the operands is a symbol string
- [(expr, Some(symbol)), _] | [_, (expr, Some(symbol))] => {
- // creating an owned string for comparison
- if matches!(symbol, SymbolStrExpr::Expr { is_to_owned: true, .. }) {
- span_lint_and_sugg(
- cx,
- UNNECESSARY_SYMBOL_STR,
- expr.span,
- "unnecessary string allocation",
- "try",
- format!("{}.as_str()", symbol.as_symbol_snippet(cx)),
- Applicability::MachineApplicable,
- );
- }
- },
- // nothing found
- [(_, None), (_, None)] => {},
- }
- }
- }
- }
-}
-
-impl InterningDefinedSymbol {
- fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option<SymbolStrExpr<'tcx>> {
- static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR];
- static SYMBOL_STR_PATHS: &[&[&str]] = &[&paths::SYMBOL_AS_STR, &paths::SYMBOL_TO_IDENT_STRING];
- let call = if let ExprKind::AddrOf(_, _, e) = expr.kind
- && let ExprKind::Unary(UnOp::Deref, e) = e.kind
- {
- e
- } else {
- expr
- };
- if let ExprKind::MethodCall(_, item, [], _) = call.kind
- // is a method call
- && let Some(did) = cx.typeck_results().type_dependent_def_id(call.hir_id)
- && let ty = cx.typeck_results().expr_ty(item)
- // ...on either an Ident or a Symbol
- && let Some(is_ident) = if match_type(cx, ty, &paths::SYMBOL) {
- Some(false)
- } else if match_type(cx, ty, &paths::IDENT) {
- Some(true)
- } else {
- None
- }
- // ...which converts it to a string
- && let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS }
- && let Some(is_to_owned) = paths
- .iter()
- .find_map(|path| if match_def_path(cx, did, path) {
- Some(path == &paths::SYMBOL_TO_IDENT_STRING)
- } else {
- None
- })
- .or_else(|| if cx.tcx.is_diagnostic_item(sym::to_string_method, did) {
- Some(true)
- } else {
- None
- })
- {
- return Some(SymbolStrExpr::Expr {
- item,
- is_ident,
- is_to_owned,
- });
- }
- // is a string constant
- if let Some(Constant::Str(s)) = ConstEvalCtxt::new(cx).eval_simple(expr) {
- let value = Symbol::intern(&s).as_u32();
- // ...which matches a symbol constant
- if let Some(&def_id) = self.symbol_map.get(&value) {
- return Some(SymbolStrExpr::Const(def_id));
- }
- }
- None
- }
-}
-
-enum SymbolStrExpr<'tcx> {
- /// a string constant with a corresponding symbol constant
- Const(DefId),
- /// a "symbol to string" expression like `symbol.as_str()`
- Expr {
- /// part that evaluates to `Symbol` or `Ident`
- item: &'tcx Expr<'tcx>,
- is_ident: bool,
- /// whether an owned `String` is created like `to_ident_string()`
- is_to_owned: bool,
- },
-}
-
-impl<'tcx> SymbolStrExpr<'tcx> {
- /// Returns a snippet that evaluates to a `Symbol` and is const if possible
- fn as_symbol_snippet(&self, cx: &LateContext<'_>) -> Cow<'tcx, str> {
- match *self {
- Self::Const(def_id) => cx.tcx.def_path_str(def_id).into(),
- Self::Expr { item, is_ident, .. } => {
- let mut snip = snippet(cx, item.span.source_callsite(), "..");
- if is_ident {
- // get `Ident.name`
- snip.to_mut().push_str(".name");
- }
- snip
- },
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs
deleted file mode 100644
index b8bcb9b..0000000
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/slow_symbol_comparisons.rs
+++ /dev/null
@@ -1,74 +0,0 @@
-use clippy_utils::consts::{ConstEvalCtxt, Constant};
-use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::paths;
-use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::match_type;
-use rustc_errors::Applicability;
-use rustc_hir::{BinOpKind, Expr, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
-use rustc_span::{Span, sym};
-
-declare_clippy_lint! {
- /// ### What it does
- ///
- /// Detects symbol comparison using `Symbol::intern`.
- ///
- /// ### Why is this bad?
- ///
- /// Comparison via `Symbol::as_str()` is faster if the interned symbols are not reused.
- ///
- /// ### Example
- ///
- /// None, see suggestion.
- pub SLOW_SYMBOL_COMPARISONS,
- internal,
- "detects slow comparisons of symbol"
-}
-
-declare_lint_pass!(SlowSymbolComparisons => [SLOW_SYMBOL_COMPARISONS]);
-
-fn check_slow_comparison<'tcx>(
- cx: &LateContext<'tcx>,
- op1: &'tcx Expr<'tcx>,
- op2: &'tcx Expr<'tcx>,
-) -> Option<(Span, String)> {
- if match_type(cx, cx.typeck_results().expr_ty(op1), &paths::SYMBOL)
- && let ExprKind::Call(fun, args) = op2.kind
- && let ExprKind::Path(ref qpath) = fun.kind
- && cx
- .tcx
- .is_diagnostic_item(sym::SymbolIntern, cx.qpath_res(qpath, fun.hir_id).opt_def_id()?)
- && let [symbol_name_expr] = args
- && let Some(Constant::Str(symbol_name)) = ConstEvalCtxt::new(cx).eval_simple(symbol_name_expr)
- {
- Some((op1.span, symbol_name))
- } else {
- None
- }
-}
-
-impl<'tcx> LateLintPass<'tcx> for SlowSymbolComparisons {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
- if let ExprKind::Binary(op, left, right) = expr.kind
- && (op.node == BinOpKind::Eq || op.node == BinOpKind::Ne)
- && let Some((symbol_span, symbol_name)) =
- check_slow_comparison(cx, left, right).or_else(|| check_slow_comparison(cx, right, left))
- {
- let mut applicability = Applicability::MachineApplicable;
- span_lint_and_sugg(
- cx,
- SLOW_SYMBOL_COMPARISONS,
- expr.span,
- "comparing `Symbol` via `Symbol::intern`",
- "use `Symbol::as_str` and check the string instead",
- format!(
- "{}.as_str() {} \"{symbol_name}\"",
- snippet_with_applicability(cx, symbol_span, "symbol", &mut applicability),
- op.node.as_str()
- ),
- applicability,
- );
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs
deleted file mode 100644
index a5c4bf4..0000000
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-use clippy_utils::diagnostics::span_lint;
-use rustc_ast::ast::{Crate, ItemKind, ModKind};
-use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::declare_lint_pass;
-
-declare_clippy_lint! {
- /// ### What it does
- /// Checks that [`clippy_utils::paths`] is sorted lexically
- ///
- /// ### Why is this bad?
- /// We like to pretend we're an example of tidy code.
- ///
- /// ### Example
- /// Wrong ordering of the util::paths constants.
- pub UNSORTED_CLIPPY_UTILS_PATHS,
- internal,
- "various things that will negatively affect your clippy experience"
-}
-
-declare_lint_pass!(UnsortedClippyUtilsPaths => [UNSORTED_CLIPPY_UTILS_PATHS]);
-
-impl EarlyLintPass for UnsortedClippyUtilsPaths {
- fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
- if let Some(utils) = krate.items.iter().find(|item| item.ident.name.as_str() == "utils") {
- if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind {
- if let Some(paths) = items.iter().find(|item| item.ident.name.as_str() == "paths") {
- if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = paths.kind {
- let mut last_name: Option<&str> = None;
- for item in items {
- let name = item.ident.as_str();
- if let Some(last_name) = last_name {
- if *last_name > *name {
- span_lint(
- cx,
- UNSORTED_CLIPPY_UTILS_PATHS,
- item.span,
- "this constant should be before the previous constant due to lexical \
- ordering",
- );
- }
- }
- last_name = Some(name);
- }
- }
- }
- }
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 4476cd1..16066dd 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -2,6 +2,3 @@
pub mod author;
pub mod dump_hir;
pub mod format_args_collector;
-
-#[cfg(feature = "internal")]
-pub mod internal_lints;
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index 4053105..5b3f60a 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -68,6 +68,8 @@
/// (including the standard library) provide modules named "prelude" specifically designed
/// for wildcard import.
///
+ /// Wildcard imports reexported through `pub use` are also allowed.
+ ///
/// `use super::*` is allowed in test modules. This is defined as any module with "test" in the name.
///
/// These exceptions can be disabled using the `warn-on-all-wildcard-imports` configuration flag.
@@ -121,7 +123,9 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
}
let module = cx.tcx.parent_module_from_def_id(item.owner_id.def_id);
- if cx.tcx.visibility(item.owner_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) {
+ if cx.tcx.visibility(item.owner_id.def_id) != ty::Visibility::Restricted(module.to_def_id())
+ && !self.warn_on_all
+ {
return;
}
if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index f6948be..a97643e 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -74,10 +74,10 @@ fn check_ty<'tcx>(&mut self, cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'tcx, Ambi
fn in_trait_impl(cx: &LateContext<'_>, hir_id: HirId) -> bool {
let parent_id = cx.tcx.hir_get_parent_item(hir_id);
let second_parent_id = cx.tcx.hir_get_parent_item(parent_id.into()).def_id;
- if let Node::Item(item) = cx.tcx.hir_node_by_def_id(second_parent_id) {
- if let ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind {
- return true;
- }
+ if let Node::Item(item) = cx.tcx.hir_node_by_def_id(second_parent_id)
+ && let ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) = item.kind
+ {
+ return true;
}
false
}
diff --git a/src/tools/clippy/clippy_lints/src/zombie_processes.rs b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
index 7667db4..39c1aab 100644
--- a/src/tools/clippy/clippy_lints/src/zombie_processes.rs
+++ b/src/tools/clippy/clippy_lints/src/zombie_processes.rs
@@ -131,7 +131,7 @@ struct WaitFinder<'a, 'tcx> {
local_id: HirId,
state: VisitorState,
early_return: Option<Span>,
- // When joining two if branches where one of them doesn't call `wait()`, stores its span for more targetted help
+ // When joining two if branches where one of them doesn't call `wait()`, stores its span for more targeted help
// messages
missing_wait_branch: Option<MissingWaitBranch>,
}
diff --git a/src/tools/clippy/clippy_lints_internal/Cargo.toml b/src/tools/clippy/clippy_lints_internal/Cargo.toml
new file mode 100644
index 0000000..2a0ceac
--- /dev/null
+++ b/src/tools/clippy/clippy_lints_internal/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "clippy_lints_internal"
+version = "0.0.1"
+edition = "2021"
+
+[dependencies]
+clippy_config = { path = "../clippy_config" }
+clippy_utils = { path = "../clippy_utils" }
+regex = { version = "1.5" }
+rustc-semver = "1.1"
+
+[package.metadata.rust-analyzer]
+# This crate uses #[feature(rustc_private)]
+rustc_private = true
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs
similarity index 92%
rename from src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
rename to src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs
index 0a01a36..4fd5ea4 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/almost_standard_lint_formulation.rs
@@ -1,11 +1,12 @@
-use crate::utils::internal_lints::lint_without_lint_pass::is_lint_ref_type;
+use crate::lint_without_lint_pass::is_lint_ref_type;
use clippy_utils::diagnostics::span_lint_and_help;
use regex::Regex;
use rustc_hir::{Attribute, Item, ItemKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint_defs::declare_tool_lint;
use rustc_session::impl_lint_pass;
-declare_clippy_lint! {
+declare_tool_lint! {
/// ### What it does
/// Checks if lint formulations have a standardized format.
///
@@ -14,9 +15,10 @@
///
/// ### Example
/// `Checks for use...` can be written as `Checks for usage...` .
- pub ALMOST_STANDARD_LINT_FORMULATION,
- internal,
- "lint formulations must have a standardized format."
+ pub clippy::ALMOST_STANDARD_LINT_FORMULATION,
+ Warn,
+ "lint formulations must have a standardized format.",
+ report_in_external_macro: true
}
impl_lint_pass!(AlmostStandardFormulation => [ALMOST_STANDARD_LINT_FORMULATION]);
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs b/src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs
similarity index 97%
rename from src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
rename to src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs
index 2e6fb7c..d7967a0 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/collapsible_calls.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/collapsible_calls.rs
@@ -4,12 +4,13 @@
use rustc_errors::Applicability;
use rustc_hir::{Closure, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint_defs::declare_tool_lint;
use rustc_session::declare_lint_pass;
use rustc_span::Span;
use std::borrow::{Borrow, Cow};
-declare_clippy_lint! {
+declare_tool_lint! {
/// ### What it does
/// Lints `span_lint_and_then` function calls, where the
/// closure argument has only one statement and that statement is a method
@@ -64,9 +65,10 @@
/// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, Some(expr.span), note_msg);
/// span_lint_and_note(cx, TEST_LINT, expr.span, lint_msg, None, note_msg);
/// ```
- pub COLLAPSIBLE_SPAN_LINT_CALLS,
- internal,
- "found collapsible `span_lint_and_then` calls"
+ pub clippy::COLLAPSIBLE_SPAN_LINT_CALLS,
+ Warn,
+ "found collapsible `span_lint_and_then` calls",
+ report_in_external_macro: true
}
declare_lint_pass!(CollapsibleCalls => [COLLAPSIBLE_SPAN_LINT_CALLS]);
diff --git a/src/tools/clippy/clippy_lints_internal/src/interning_literals.rs b/src/tools/clippy/clippy_lints_internal/src/interning_literals.rs
new file mode 100644
index 0000000..6cee374
--- /dev/null
+++ b/src/tools/clippy/clippy_lints_internal/src/interning_literals.rs
@@ -0,0 +1,102 @@
+use clippy_utils::consts::{ConstEvalCtxt, Constant};
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::ty::match_type;
+use clippy_utils::{def_path_def_ids, paths};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::Applicability;
+use rustc_hir::def::{DefKind, Res};
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint_defs::declare_tool_lint;
+use rustc_middle::mir::ConstValue;
+use rustc_middle::ty;
+use rustc_session::impl_lint_pass;
+use rustc_span::sym;
+use rustc_span::symbol::Symbol;
+
+declare_tool_lint! {
+ /// ### What it does
+ /// Checks for interning string literals as symbols
+ ///
+ /// ### Why is this bad?
+ /// It's faster and easier to use the symbol constant. If one doesn't exist it can be added to `clippy_utils/src/sym.rs`
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// let _ = Symbol::intern("f32");
+ /// ```
+ ///
+ /// Use instead:
+ /// ```rust,ignore
+ /// let _ = sym::f32;
+ /// ```
+ pub clippy::INTERNING_LITERALS,
+ Warn,
+ "interning a symbol that is a literal",
+ report_in_external_macro: true
+}
+
+#[derive(Default)]
+pub struct InterningDefinedSymbol {
+ // Maps the symbol to the import path
+ symbol_map: FxHashMap<u32, (&'static str, Symbol)>,
+}
+
+impl_lint_pass!(InterningDefinedSymbol => [INTERNING_LITERALS]);
+
+impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
+ fn check_crate(&mut self, cx: &LateContext<'_>) {
+ let modules = [
+ ("kw", &paths::KW_MODULE[..]),
+ ("sym", &paths::SYM_MODULE),
+ ("sym", &paths::CLIPPY_SYM_MODULE),
+ ];
+ for (prefix, module) in modules {
+ for def_id in def_path_def_ids(cx.tcx, module) {
+ // When linting `clippy_utils` itself we can't use `module_children` as it's a local def id. It will
+ // still lint but the suggestion will say to add it to `sym.rs` even if it's already there
+ if def_id.is_local() {
+ continue;
+ }
+
+ for item in cx.tcx.module_children(def_id) {
+ if let Res::Def(DefKind::Const, item_def_id) = item.res
+ && let ty = cx.tcx.type_of(item_def_id).instantiate_identity()
+ && match_type(cx, ty, &paths::SYMBOL)
+ && let Ok(ConstValue::Scalar(value)) = cx.tcx.const_eval_poly(item_def_id)
+ && let Some(value) = value.to_u32().discard_err()
+ {
+ self.symbol_map.insert(value, (prefix, item.ident.name));
+ }
+ }
+ }
+ }
+ }
+
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+ if let ExprKind::Call(func, [arg]) = &expr.kind
+ && let ty::FnDef(def_id, _) = cx.typeck_results().expr_ty(func).kind()
+ && cx.tcx.is_diagnostic_item(sym::SymbolIntern, *def_id)
+ && let Some(Constant::Str(arg)) = ConstEvalCtxt::new(cx).eval_simple(arg)
+ {
+ span_lint_and_then(
+ cx,
+ INTERNING_LITERALS,
+ expr.span,
+ "interning a string literal",
+ |diag| {
+ let value = Symbol::intern(&arg).as_u32();
+ let (message, path) = if let Some((prefix, name)) = self.symbol_map.get(&value) {
+ ("use the preinterned symbol", format!("{prefix}::{name}"))
+ } else {
+ (
+ "add the symbol to `clippy_utils/src/sym.rs` and use it",
+ format!("sym::{}", arg.replace(|ch: char| !ch.is_alphanumeric(), "_")),
+ )
+ };
+ diag.span_suggestion_verbose(expr.span, message, path, Applicability::MaybeIncorrect);
+ },
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs b/src/tools/clippy/clippy_lints_internal/src/invalid_paths.rs
similarity index 78%
rename from src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
rename to src/tools/clippy/clippy_lints_internal/src/invalid_paths.rs
index 252ac5e..bee87ef 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/invalid_paths.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/invalid_paths.rs
@@ -5,12 +5,13 @@
use rustc_hir::Item;
use rustc_hir::def::DefKind;
use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint_defs::declare_tool_lint;
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::{self, FloatTy};
use rustc_session::declare_lint_pass;
use rustc_span::symbol::Symbol;
-declare_clippy_lint! {
+declare_tool_lint! {
/// ### What it does
/// Checks the paths module for invalid paths.
///
@@ -19,9 +20,10 @@
///
/// ### Example
/// None.
- pub INVALID_PATHS,
- internal,
- "invalid path"
+ pub clippy::INVALID_PATHS,
+ Warn,
+ "invalid path",
+ report_in_external_macro: true
}
declare_lint_pass!(InvalidPaths => [INVALID_PATHS]);
@@ -80,22 +82,22 @@ pub fn check_path(cx: &LateContext<'_>, path: &[&str]) -> bool {
.copied();
for item_def_id in lang_items.iter().map(|(_, def_id)| def_id).chain(incoherent_impls) {
let lang_item_path = cx.get_def_path(item_def_id);
- if path_syms.starts_with(&lang_item_path) {
- if let [item] = &path_syms[lang_item_path.len()..] {
- if matches!(
- cx.tcx.def_kind(item_def_id),
- DefKind::Mod | DefKind::Enum | DefKind::Trait
- ) {
- for child in cx.tcx.module_children(item_def_id) {
- if child.ident.name == *item {
- return true;
- }
+ if path_syms.starts_with(&lang_item_path)
+ && let [item] = &path_syms[lang_item_path.len()..]
+ {
+ if matches!(
+ cx.tcx.def_kind(item_def_id),
+ DefKind::Mod | DefKind::Enum | DefKind::Trait
+ ) {
+ for child in cx.tcx.module_children(item_def_id) {
+ if child.ident.name == *item {
+ return true;
}
- } else {
- for child in cx.tcx.associated_item_def_ids(item_def_id) {
- if cx.tcx.item_name(*child) == *item {
- return true;
- }
+ }
+ } else {
+ for child in cx.tcx.associated_item_def_ids(item_def_id) {
+ if cx.tcx.item_name(*child) == *item {
+ return true;
}
}
}
diff --git a/src/tools/clippy/clippy_lints_internal/src/lib.rs b/src/tools/clippy/clippy_lints_internal/src/lib.rs
new file mode 100644
index 0000000..1c42f41
--- /dev/null
+++ b/src/tools/clippy/clippy_lints_internal/src/lib.rs
@@ -0,0 +1,74 @@
+#![feature(let_chains, rustc_private)]
+#![allow(
+ clippy::missing_docs_in_private_items,
+ clippy::must_use_candidate,
+ rustc::diagnostic_outside_of_impl,
+ rustc::untranslatable_diagnostic
+)]
+#![warn(
+ trivial_casts,
+ trivial_numeric_casts,
+ rust_2018_idioms,
+ unused_lifetimes,
+ unused_qualifications,
+ rustc::internal
+)]
+// Disable this rustc lint for now, as it was also done in rustc
+#![allow(rustc::potential_query_instability)]
+// None of these lints need a version.
+#![allow(clippy::missing_clippy_version_attribute)]
+
+extern crate rustc_ast;
+extern crate rustc_attr_parsing;
+extern crate rustc_data_structures;
+extern crate rustc_errors;
+extern crate rustc_hir;
+extern crate rustc_lint;
+extern crate rustc_lint_defs;
+extern crate rustc_middle;
+extern crate rustc_session;
+extern crate rustc_span;
+
+mod almost_standard_lint_formulation;
+mod collapsible_calls;
+mod interning_literals;
+mod invalid_paths;
+mod lint_without_lint_pass;
+mod msrv_attr_impl;
+mod outer_expn_data_pass;
+mod produce_ice;
+mod unnecessary_def_path;
+mod unsorted_clippy_utils_paths;
+
+use rustc_lint::{Lint, LintStore};
+
+static LINTS: &[&Lint] = &[
+ almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION,
+ collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS,
+ interning_literals::INTERNING_LITERALS,
+ invalid_paths::INVALID_PATHS,
+ lint_without_lint_pass::DEFAULT_LINT,
+ lint_without_lint_pass::INVALID_CLIPPY_VERSION_ATTRIBUTE,
+ lint_without_lint_pass::LINT_WITHOUT_LINT_PASS,
+ lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE,
+ msrv_attr_impl::MISSING_MSRV_ATTR_IMPL,
+ outer_expn_data_pass::OUTER_EXPN_EXPN_DATA,
+ produce_ice::PRODUCE_ICE,
+ unnecessary_def_path::UNNECESSARY_DEF_PATH,
+ unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS,
+];
+
+pub fn register_lints(store: &mut LintStore) {
+ store.register_lints(LINTS);
+
+ store.register_early_pass(|| Box::new(unsorted_clippy_utils_paths::UnsortedClippyUtilsPaths));
+ store.register_early_pass(|| Box::new(produce_ice::ProduceIce));
+ store.register_late_pass(|_| Box::new(collapsible_calls::CollapsibleCalls));
+ store.register_late_pass(|_| Box::new(invalid_paths::InvalidPaths));
+ store.register_late_pass(|_| Box::<interning_literals::InterningDefinedSymbol>::default());
+ store.register_late_pass(|_| Box::<lint_without_lint_pass::LintWithoutLintPass>::default());
+ store.register_late_pass(|_| Box::<unnecessary_def_path::UnnecessaryDefPath>::default());
+ store.register_late_pass(|_| Box::new(outer_expn_data_pass::OuterExpnDataPass));
+ store.register_late_pass(|_| Box::new(msrv_attr_impl::MsrvAttrImpl));
+ store.register_late_pass(|_| Box::new(almost_standard_lint_formulation::AlmostStandardFormulation::new()));
+}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
similarity index 90%
rename from src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
rename to src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
index 94a2e59..6a75def 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/lint_without_lint_pass.rs
@@ -9,13 +9,14 @@
use rustc_hir::intravisit::Visitor;
use rustc_hir::{ExprKind, HirId, Item, MutTy, Mutability, Path, TyKind};
use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint_defs::declare_tool_lint;
use rustc_middle::hir::nested_filter;
use rustc_session::impl_lint_pass;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::Symbol;
use rustc_span::{Span, sym};
-declare_clippy_lint! {
+declare_tool_lint! {
/// ### What it does
/// Ensures every lint is associated to a `LintPass`.
///
@@ -37,12 +38,14 @@
/// declare_lint_pass!(Pass => [LINT_1, LINT_2]);
/// // missing FORGOTTEN_LINT
/// ```
- pub LINT_WITHOUT_LINT_PASS,
- internal,
- "declaring a lint without associating it in a LintPass"
+ pub clippy::LINT_WITHOUT_LINT_PASS,
+ Warn,
+ "declaring a lint without associating it in a LintPass",
+ report_in_external_macro: true
+
}
-declare_clippy_lint! {
+declare_tool_lint! {
/// ### What it does
/// Checks for cases of an auto-generated lint without an updated description,
/// i.e. `default lint description`.
@@ -59,30 +62,32 @@
/// ```rust,ignore
/// declare_lint! { pub COOL_LINT, nursery, "a great new lint" }
/// ```
- pub DEFAULT_LINT,
- internal,
- "found 'default lint description' in a lint declaration"
+ pub clippy::DEFAULT_LINT,
+ Warn,
+ "found 'default lint description' in a lint declaration",
+ report_in_external_macro: true
}
-declare_clippy_lint! {
+declare_tool_lint! {
/// ### What it does
/// Checks for invalid `clippy::version` attributes.
///
/// Valid values are:
/// * "pre 1.29.0"
/// * any valid semantic version
- pub INVALID_CLIPPY_VERSION_ATTRIBUTE,
- internal,
- "found an invalid `clippy::version` attribute"
+ pub clippy::INVALID_CLIPPY_VERSION_ATTRIBUTE,
+ Warn,
+ "found an invalid `clippy::version` attribute",
+ report_in_external_macro: true
}
-declare_clippy_lint! {
+declare_tool_lint! {
/// ### What it does
/// Checks for declared clippy lints without the `clippy::version` attribute.
- ///
- pub MISSING_CLIPPY_VERSION_ATTRIBUTE,
- internal,
- "found clippy lint without `clippy::version` attribute"
+ pub clippy::MISSING_CLIPPY_VERSION_ATTRIBUTE,
+ Warn,
+ "found clippy lint without `clippy::version` attribute",
+ report_in_external_macro: true
}
#[derive(Clone, Debug, Default)]
@@ -100,10 +105,6 @@ pub struct LintWithoutLintPass {
impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
- if is_lint_allowed(cx, DEFAULT_LINT, item.hir_id()) {
- return;
- }
-
if let hir::ItemKind::Static(ident, ty, Mutability::Not, body_id) = item.kind {
if is_lint_ref_type(cx, ty) {
check_invalid_clippy_version_attribute(cx, item);
@@ -205,12 +206,10 @@ pub(super) fn is_lint_ref_type(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
mutbl: Mutability::Not,
},
) = ty.kind
+ && let TyKind::Path(ref path) = inner.kind
+ && let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id)
{
- if let TyKind::Path(ref path) = inner.kind {
- if let Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, inner.hir_id) {
- return match_def_path(cx, def_id, &paths::LINT);
- }
- }
+ return match_def_path(cx, def_id, &paths::LINT);
}
false
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs b/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs
similarity index 92%
rename from src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
rename to src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs
index 558acac..dda0545 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/msrv_attr_impl.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/msrv_attr_impl.rs
@@ -5,16 +5,17 @@
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint_defs::declare_tool_lint;
use rustc_middle::ty::{self, EarlyBinder, GenericArgKind};
use rustc_session::declare_lint_pass;
-declare_clippy_lint! {
+declare_tool_lint! {
/// ### What it does
/// Check that the `extract_msrv_attr!` macro is used, when a lint has a MSRV.
- ///
- pub MISSING_MSRV_ATTR_IMPL,
- internal,
- "checking if all necessary steps were taken when adding a MSRV to a lint"
+ pub clippy::MISSING_MSRV_ATTR_IMPL,
+ Warn,
+ "checking if all necessary steps were taken when adding a MSRV to a lint",
+ report_in_external_macro: true
}
declare_lint_pass!(MsrvAttrImpl => [MISSING_MSRV_ATTR_IMPL]);
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs b/src/tools/clippy/clippy_lints_internal/src/outer_expn_data_pass.rs
similarity index 92%
rename from src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs
rename to src/tools/clippy/clippy_lints_internal/src/outer_expn_data_pass.rs
index 326e172..e944196 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/outer_expn_data_pass.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/outer_expn_data_pass.rs
@@ -4,10 +4,11 @@
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint_defs::declare_tool_lint;
use rustc_session::declare_lint_pass;
use rustc_span::symbol::Symbol;
-declare_clippy_lint! {
+declare_tool_lint! {
/// ### What it does
/// Checks for calls to `cx.outer().expn_data()` and suggests to use
/// the `cx.outer_expn_data()`
@@ -24,9 +25,10 @@
/// ```rust,ignore
/// expr.span.ctxt().outer_expn_data()
/// ```
- pub OUTER_EXPN_EXPN_DATA,
- internal,
- "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`"
+ pub clippy::OUTER_EXPN_EXPN_DATA,
+ Warn,
+ "using `cx.outer_expn().expn_data()` instead of `cx.outer_expn_data()`",
+ report_in_external_macro: true
}
declare_lint_pass!(OuterExpnDataPass => [OUTER_EXPN_EXPN_DATA]);
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs b/src/tools/clippy/clippy_lints_internal/src/produce_ice.rs
similarity index 79%
rename from src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs
rename to src/tools/clippy/clippy_lints_internal/src/produce_ice.rs
index 0a07919..14e93dc 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/produce_ice.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/produce_ice.rs
@@ -1,10 +1,11 @@
use rustc_ast::ast::NodeId;
use rustc_ast::visit::FnKind;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
+use rustc_lint_defs::declare_tool_lint;
use rustc_session::declare_lint_pass;
use rustc_span::Span;
-declare_clippy_lint! {
+declare_tool_lint! {
/// ### What it does
/// Not an actual lint. This lint is only meant for testing our customized internal compiler
/// error message by calling `panic`.
@@ -16,9 +17,10 @@
/// ```rust,ignore
/// 🍦🍦🍦🍦🍦
/// ```
- pub PRODUCE_ICE,
- internal,
- "this message should not appear anywhere as we ICE before and don't emit the lint"
+ pub clippy::PRODUCE_ICE,
+ Warn,
+ "this message should not appear anywhere as we ICE before and don't emit the lint",
+ report_in_external_macro: true
}
declare_lint_pass!(ProduceIce => [PRODUCE_ICE]);
@@ -35,7 +37,7 @@ fn check_fn(&mut self, ctx: &EarlyContext<'_>, fn_kind: FnKind<'_>, span: Span,
fn is_trigger_fn(fn_kind: FnKind<'_>) -> bool {
match fn_kind {
- FnKind::Fn(_, ident, ..) => ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy",
+ FnKind::Fn(_, _, func) => func.ident.name.as_str() == "it_looks_like_you_are_trying_to_kill_clippy",
FnKind::Closure(..) => false,
}
}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints_internal/src/unnecessary_def_path.rs
similarity index 96%
rename from src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
rename to src/tools/clippy/clippy_lints_internal/src/unnecessary_def_path.rs
index 76b0a52..6bdfbed 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
+++ b/src/tools/clippy/clippy_lints_internal/src/unnecessary_def_path.rs
@@ -8,6 +8,7 @@
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind, LetStmt, Mutability, Node};
use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint_defs::declare_tool_lint;
use rustc_middle::mir::ConstValue;
use rustc_middle::mir::interpret::{Allocation, GlobalAlloc};
use rustc_middle::ty::{self, Ty};
@@ -17,7 +18,7 @@
use std::str;
-declare_clippy_lint! {
+declare_tool_lint! {
/// ### What it does
/// Checks for usage of def paths when a diagnostic item or a `LangItem` could be used.
///
@@ -34,9 +35,10 @@
/// ```rust,ignore
/// utils::is_type_diagnostic_item(cx, ty, sym::Vec)
/// ```
- pub UNNECESSARY_DEF_PATH,
- internal,
- "using a def path when a diagnostic item or a `LangItem` is available"
+ pub clippy::UNNECESSARY_DEF_PATH,
+ Warn,
+ "using a def path when a diagnostic item or a `LangItem` is available",
+ report_in_external_macro: true
}
impl_lint_pass!(UnnecessaryDefPath => [UNNECESSARY_DEF_PATH]);
@@ -281,10 +283,10 @@ fn path_from_array(exprs: &[Expr<'_>]) -> Option<Vec<String>> {
exprs
.iter()
.map(|expr| {
- if let ExprKind::Lit(lit) = &expr.kind {
- if let LitKind::Str(sym, _) = lit.node {
- return Some((*sym.as_str()).to_owned());
- }
+ if let ExprKind::Lit(lit) = &expr.kind
+ && let LitKind::Str(sym, _) = lit.node
+ {
+ return Some((*sym.as_str()).to_owned());
}
None
diff --git a/src/tools/clippy/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs b/src/tools/clippy/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs
new file mode 100644
index 0000000..8e281ec
--- /dev/null
+++ b/src/tools/clippy/clippy_lints_internal/src/unsorted_clippy_utils_paths.rs
@@ -0,0 +1,54 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_ast::ast::{Crate, ItemKind, ModKind};
+use rustc_lint::{EarlyContext, EarlyLintPass};
+use rustc_lint_defs::declare_tool_lint;
+use rustc_session::declare_lint_pass;
+
+declare_tool_lint! {
+ /// ### What it does
+ /// Checks that [`clippy_utils::paths`] is sorted lexically
+ ///
+ /// ### Why is this bad?
+ /// We like to pretend we're an example of tidy code.
+ ///
+ /// ### Example
+ /// Wrong ordering of the util::paths constants.
+ pub clippy::UNSORTED_CLIPPY_UTILS_PATHS,
+ Warn,
+ "various things that will negatively affect your clippy experience",
+ report_in_external_macro: true
+}
+
+declare_lint_pass!(UnsortedClippyUtilsPaths => [UNSORTED_CLIPPY_UTILS_PATHS]);
+
+impl EarlyLintPass for UnsortedClippyUtilsPaths {
+ fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
+ if let Some(utils) = krate
+ .items
+ .iter()
+ .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "utils"))
+ && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = utils.kind
+ && let Some(paths) = items
+ .iter()
+ .find(|item| item.kind.ident().is_some_and(|i| i.name.as_str() == "paths"))
+ && let ItemKind::Mod(_, _, ModKind::Loaded(ref items, ..)) = paths.kind
+ {
+ let mut last_name: Option<String> = None;
+ for item in items {
+ let name = item.kind.ident().expect("const items have idents").to_string();
+ if let Some(last_name) = last_name
+ && *last_name > *name
+ {
+ span_lint(
+ cx,
+ UNSORTED_CLIPPY_UTILS_PATHS,
+ item.span,
+ "this constant should be before the previous constant due to lexical \
+ ordering",
+ );
+ }
+ last_name = Some(name);
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index ba4bb1d..b98e990 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "clippy_utils"
# begin autogenerated version
-version = "0.1.87"
+version = "0.1.88"
# end autogenerated version
edition = "2024"
description = "Helpful tools for writing lints, provided as they are used in Clippy"
diff --git a/src/tools/clippy/clippy_utils/README.md b/src/tools/clippy/clippy_utils/README.md
index 7c665b4..aceff14 100644
--- a/src/tools/clippy/clippy_utils/README.md
+++ b/src/tools/clippy/clippy_utils/README.md
@@ -8,7 +8,7 @@
<!-- begin autogenerated nightly -->
```
-nightly-2025-03-20
+nightly-2025-04-22
```
<!-- end autogenerated nightly -->
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
index c5dce26..8996b69 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils/mod.rs
@@ -348,11 +348,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
safety: rs,
define_opaque: _,
}),
- ) => eq_id(*li, *ri)
- && lm == rm
- && ls == rs
- && eq_ty(lt, rt)
- && eq_expr_opt(le.as_ref(), re.as_ref()),
+ ) => eq_id(*li, *ri) && lm == rm && ls == rs && eq_ty(lt, rt) && eq_expr_opt(le.as_ref(), re.as_ref()),
(
Const(box ConstItem {
defaultness: ld,
@@ -370,11 +366,13 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
expr: re,
define_opaque: _,
}),
- ) => eq_defaultness(*ld, *rd)
+ ) => {
+ eq_defaultness(*ld, *rd)
&& eq_id(*li, *ri)
&& eq_generics(lg, rg)
&& eq_ty(lt, rt)
- && eq_expr_opt(le.as_ref(), re.as_ref()),
+ && eq_expr_opt(le.as_ref(), re.as_ref())
+ },
(
Fn(box ast::Fn {
defaultness: ld,
@@ -440,7 +438,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
},
(Enum(li, le, lg), Enum(ri, re, rg)) => {
eq_id(*li, *ri) && over(&le.variants, &re.variants, eq_variant) && eq_generics(lg, rg)
- }
+ },
(Struct(li, lv, lg), Struct(ri, rv, rg)) | (Union(li, lv, lg), Union(ri, rv, rg)) => {
eq_id(*li, *ri) && eq_variant_data(lv, rv) && eq_generics(lg, rg)
},
@@ -471,7 +469,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
},
(TraitAlias(li, lg, lb), TraitAlias(ri, rg, rb)) => {
eq_id(*li, *ri) && eq_generics(lg, rg) && over(lb, rb, eq_generic_bound)
- }
+ },
(
Impl(box ast::Impl {
safety: lu,
@@ -506,7 +504,7 @@ pub fn eq_item_kind(l: &ItemKind, r: &ItemKind) -> bool {
(MacCall(l), MacCall(r)) => eq_mac_call(l, r),
(MacroDef(li, ld), MacroDef(ri, rd)) => {
eq_id(*li, *ri) && ld.macro_rules == rd.macro_rules && eq_delim_args(&ld.body, &rd.body)
- }
+ },
_ => false,
}
}
@@ -531,13 +529,7 @@ pub fn eq_foreign_item_kind(l: &ForeignItemKind, r: &ForeignItemKind) -> bool {
safety: rs,
define_opaque: _,
}),
- ) => {
- eq_id(*li, *ri)
- && eq_ty(lt, rt)
- && lm == rm
- && eq_expr_opt(le.as_ref(), re.as_ref())
- && ls == rs
- }
+ ) => eq_id(*li, *ri) && eq_ty(lt, rt) && lm == rm && eq_expr_opt(le.as_ref(), re.as_ref()) && ls == rs,
(
Fn(box ast::Fn {
defaultness: ld,
@@ -620,7 +612,7 @@ pub fn eq_assoc_item_kind(l: &AssocItemKind, r: &AssocItemKind) -> bool {
&& eq_generics(lg, rg)
&& eq_ty(lt, rt)
&& eq_expr_opt(le.as_ref(), re.as_ref())
- }
+ },
(
Fn(box ast::Fn {
defaultness: ld,
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index 17751e8..b9928b8 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -43,14 +43,16 @@ pub enum Constant<'tcx> {
Char(char),
/// An integer's bit representation.
Int(u128),
- /// An `f16`.
- F16(f16),
+ /// An `f16` bitcast to a `u16`.
+ // FIXME(f16_f128): use `f16` once builtins are available on all host tools platforms.
+ F16(u16),
/// An `f32`.
F32(f32),
/// An `f64`.
F64(f64),
- /// An `f128`.
- F128(f128),
+ /// An `f128` bitcast to a `u128`.
+ // FIXME(f16_f128): use `f128` once builtins are available on all host tools platforms.
+ F128(u128),
/// `true` or `false`.
Bool(bool),
/// An array of constants.
@@ -177,7 +179,7 @@ fn hash<H>(&self, state: &mut H)
},
Self::F16(f) => {
// FIXME(f16_f128): once conversions to/from `f128` are available on all platforms,
- f.to_bits().hash(state);
+ f.hash(state);
},
Self::F32(f) => {
f64::from(f).to_bits().hash(state);
@@ -186,7 +188,7 @@ fn hash<H>(&self, state: &mut H)
f.to_bits().hash(state);
},
Self::F128(f) => {
- f.to_bits().hash(state);
+ f.hash(state);
},
Self::Bool(b) => {
b.hash(state);
@@ -292,12 +294,12 @@ pub fn peel_refs(mut self) -> Self {
fn parse_f16(s: &str) -> Self {
let f: Half = s.parse().unwrap();
- Self::F16(f16::from_bits(f.to_bits().try_into().unwrap()))
+ Self::F16(f.to_bits().try_into().unwrap())
}
fn parse_f128(s: &str) -> Self {
let f: Quad = s.parse().unwrap();
- Self::F128(f128::from_bits(f.to_bits()))
+ Self::F128(f.to_bits())
}
}
@@ -868,10 +870,10 @@ pub fn mir_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.to_bits(int.size()))),
- ty::Float(FloatTy::F16) => Some(Constant::F16(f16::from_bits(int.into()))),
+ ty::Float(FloatTy::F16) => Some(Constant::F16(int.into())),
ty::Float(FloatTy::F32) => Some(Constant::F32(f32::from_bits(int.into()))),
ty::Float(FloatTy::F64) => Some(Constant::F64(f64::from_bits(int.into()))),
- ty::Float(FloatTy::F128) => Some(Constant::F128(f128::from_bits(int.into()))),
+ ty::Float(FloatTy::F128) => Some(Constant::F128(int.into())),
ty::RawPtr(_, _) => Some(Constant::RawPtr(int.to_bits(int.size()))),
_ => None,
},
@@ -892,10 +894,10 @@ pub fn mir_to_const<'tcx>(tcx: TyCtxt<'tcx>, result: mir::Const<'tcx>) -> Option
let range = alloc_range(offset + size * idx, size);
let val = alloc.read_scalar(&tcx, range, /* read_provenance */ false).ok()?;
res.push(match flt {
- FloatTy::F16 => Constant::F16(f16::from_bits(val.to_u16().discard_err()?)),
+ FloatTy::F16 => Constant::F16(val.to_u16().discard_err()?),
FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().discard_err()?)),
FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().discard_err()?)),
- FloatTy::F128 => Constant::F128(f128::from_bits(val.to_u128().discard_err()?)),
+ FloatTy::F128 => Constant::F128(val.to_u128().discard_err()?),
});
}
Some(Constant::Vec(res))
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index 2927924..cd2098a 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -17,16 +17,16 @@
use std::env;
fn docs_link(diag: &mut Diag<'_, ()>, lint: &'static Lint) {
- if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err() {
- if let Some(lint) = lint.name_lower().strip_prefix("clippy::") {
- diag.help(format!(
- "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}",
- &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
- // extract just major + minor version and ignore patch versions
- format!("rust-{}", n.rsplit_once('.').unwrap().1)
- })
- ));
- }
+ if env::var("CLIPPY_DISABLE_DOCS_LINKS").is_err()
+ && let Some(lint) = lint.name_lower().strip_prefix("clippy::")
+ {
+ diag.help(format!(
+ "for further information visit https://rust-lang.github.io/rust-clippy/{}/index.html#{lint}",
+ &option_env!("RUST_RELEASE_NUM").map_or("master".to_string(), |n| {
+ // extract just major + minor version and ignore patch versions
+ format!("rust-{}", n.rsplit_once('.').unwrap().1)
+ })
+ ));
}
}
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index c4d0000..d4e66eb 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -118,18 +118,17 @@ pub fn hir(cx: &LateContext<'_>, expr: &Expr<'hir>) -> Option<Self> {
) = expr.kind
{
let mut iter = cx.tcx.hir_parent_iter(expr.hir_id);
- if let Some((_, Node::Block(Block { stmts: [], .. }))) = iter.next() {
- if let Some((
+ if let Some((_, Node::Block(Block { stmts: [], .. }))) = iter.next()
+ && let Some((
_,
Node::Expr(Expr {
kind: ExprKind::Loop(_, _, LoopSource::While, _),
..
}),
)) = iter.next()
- {
- // while loop desugar
- return None;
- }
+ {
+ // while loop desugar
+ return None;
}
return Some(Self {
let_pat,
@@ -176,6 +175,12 @@ pub fn parse(cx: &LateContext<'_>, expr: &Expr<'hir>) -> Option<Self> {
),
}
}
+
+ pub fn scrutinee(&self) -> &'hir Expr<'hir> {
+ match self {
+ Self::Match(scrutinee, _, _) | Self::IfLet(scrutinee, _, _, _, _) => scrutinee,
+ }
+ }
}
/// An `if` or `if let` expression
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index b813cd3..fe1fd70 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -8,7 +8,7 @@
use rustc_hir::def::{DefKind, Res};
use rustc_hir::{
AssocItemConstraint, BinOpKind, BindingMode, Block, BodyId, Closure, ConstArg, ConstArgKind, Expr, ExprField,
- ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeName,
+ ExprKind, FnRetTy, GenericArg, GenericArgs, HirId, HirIdMap, InlineAsmOperand, LetExpr, Lifetime, LifetimeKind,
Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr,
TraitBoundModifiers, Ty, TyKind, TyPat, TyPatKind,
};
@@ -148,7 +148,7 @@ pub struct HirEqInterExpr<'a, 'b, 'tcx> {
impl HirEqInterExpr<'_, '_, '_> {
pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
match (&left.kind, &right.kind) {
- (&StmtKind::Let(l), &StmtKind::Let(r)) => {
+ (StmtKind::Let(l), StmtKind::Let(r)) => {
// This additional check ensures that the type of the locals are equivalent even if the init
// expression or type have some inferred parts.
if let Some((typeck_lhs, typeck_rhs)) = self.inner.maybe_typeck_results {
@@ -166,7 +166,7 @@ pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool {
&& both(l.els.as_ref(), r.els.as_ref(), |l, r| self.eq_block(l, r))
&& self.eq_pat(l.pat, r.pat)
},
- (&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r),
+ (StmtKind::Expr(l), StmtKind::Expr(r)) | (StmtKind::Semi(l), StmtKind::Semi(r)) => self.eq_expr(l, r),
_ => false,
}
}
@@ -260,7 +260,7 @@ fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool {
fn should_ignore(&mut self, expr: &Expr<'_>) -> bool {
macro_backtrace(expr.span).last().is_some_and(|macro_call| {
matches!(
- &self.inner.cx.tcx.get_diagnostic_name(macro_call.def_id),
+ self.inner.cx.tcx.get_diagnostic_name(macro_call.def_id),
Some(sym::todo_macro | sym::unimplemented_macro)
)
})
@@ -301,58 +301,58 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
reduce_exprkind(self.inner.cx, &left.kind),
reduce_exprkind(self.inner.cx, &right.kind),
) {
- (&ExprKind::AddrOf(lb, l_mut, le), &ExprKind::AddrOf(rb, r_mut, re)) => {
+ (ExprKind::AddrOf(lb, l_mut, le), ExprKind::AddrOf(rb, r_mut, re)) => {
lb == rb && l_mut == r_mut && self.eq_expr(le, re)
},
- (&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r),
- (&ExprKind::Assign(ll, lr, _), &ExprKind::Assign(rl, rr, _)) => {
+ (ExprKind::Array(l), ExprKind::Array(r)) => self.eq_exprs(l, r),
+ (ExprKind::Assign(ll, lr, _), ExprKind::Assign(rl, rr, _)) => {
self.inner.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
},
- (&ExprKind::AssignOp(ref lo, ll, lr), &ExprKind::AssignOp(ref ro, rl, rr)) => {
+ (ExprKind::AssignOp(lo, ll, lr), ExprKind::AssignOp(ro, rl, rr)) => {
self.inner.allow_side_effects && lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
},
- (&ExprKind::Block(l, _), &ExprKind::Block(r, _)) => self.eq_block(l, r),
- (&ExprKind::Binary(l_op, ll, lr), &ExprKind::Binary(r_op, rl, rr)) => {
+ (ExprKind::Block(l, _), ExprKind::Block(r, _)) => self.eq_block(l, r),
+ (ExprKind::Binary(l_op, ll, lr), ExprKind::Binary(r_op, rl, rr)) => {
l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
|| swap_binop(l_op.node, ll, lr).is_some_and(|(l_op, ll, lr)| {
l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
})
},
- (&ExprKind::Break(li, ref le), &ExprKind::Break(ri, ref re)) => {
+ (ExprKind::Break(li, le), ExprKind::Break(ri, re)) => {
both(li.label.as_ref(), ri.label.as_ref(), |l, r| l.ident.name == r.ident.name)
&& both(le.as_ref(), re.as_ref(), |l, r| self.eq_expr(l, r))
},
- (&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => {
+ (ExprKind::Call(l_fun, l_args), ExprKind::Call(r_fun, r_args)) => {
self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args)
},
- (&ExprKind::Cast(lx, lt), &ExprKind::Cast(rx, rt)) => {
+ (ExprKind::Cast(lx, lt), ExprKind::Cast(rx, rt)) => {
self.eq_expr(lx, rx) && self.eq_ty(lt, rt)
},
- (&ExprKind::Closure(_l), &ExprKind::Closure(_r)) => false,
- (&ExprKind::ConstBlock(lb), &ExprKind::ConstBlock(rb)) => self.eq_body(lb.body, rb.body),
- (&ExprKind::Continue(li), &ExprKind::Continue(ri)) => {
+ (ExprKind::Closure(_l), ExprKind::Closure(_r)) => false,
+ (ExprKind::ConstBlock(lb), ExprKind::ConstBlock(rb)) => self.eq_body(lb.body, rb.body),
+ (ExprKind::Continue(li), ExprKind::Continue(ri)) => {
both(li.label.as_ref(), ri.label.as_ref(), |l, r| l.ident.name == r.ident.name)
},
- (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re),
- (&ExprKind::Field(l_f_exp, ref l_f_ident), &ExprKind::Field(r_f_exp, ref r_f_ident)) => {
+ (ExprKind::DropTemps(le), ExprKind::DropTemps(re)) => self.eq_expr(le, re),
+ (ExprKind::Field(l_f_exp, l_f_ident), ExprKind::Field(r_f_exp, r_f_ident)) => {
l_f_ident.name == r_f_ident.name && self.eq_expr(l_f_exp, r_f_exp)
},
- (&ExprKind::Index(la, li, _), &ExprKind::Index(ra, ri, _)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
- (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => {
+ (ExprKind::Index(la, li, _), ExprKind::Index(ra, ri, _)) => self.eq_expr(la, ra) && self.eq_expr(li, ri),
+ (ExprKind::If(lc, lt, le), ExprKind::If(rc, rt, re)) => {
self.eq_expr(lc, rc) && self.eq_expr(lt, rt)
&& both(le.as_ref(), re.as_ref(), |l, r| self.eq_expr(l, r))
},
- (&ExprKind::Let(l), &ExprKind::Let(r)) => {
+ (ExprKind::Let(l), ExprKind::Let(r)) => {
self.eq_pat(l.pat, r.pat)
&& both(l.ty.as_ref(), r.ty.as_ref(), |l, r| self.eq_ty(l, r))
&& self.eq_expr(l.init, r.init)
},
(ExprKind::Lit(l), ExprKind::Lit(r)) => l.node == r.node,
- (&ExprKind::Loop(lb, ref ll, ref lls, _), &ExprKind::Loop(rb, ref rl, ref rls, _)) => {
+ (ExprKind::Loop(lb, ll, lls, _), ExprKind::Loop(rb, rl, rls, _)) => {
lls == rls && self.eq_block(lb, rb)
&& both(ll.as_ref(), rl.as_ref(), |l, r| l.ident.name == r.ident.name)
},
- (&ExprKind::Match(le, la, ref ls), &ExprKind::Match(re, ra, ref rs)) => {
+ (ExprKind::Match(le, la, ls), ExprKind::Match(re, ra, rs)) => {
(ls == rs || (matches!((ls, rs), (TryDesugar(_), TryDesugar(_)))))
&& self.eq_expr(le, re)
&& over(la, ra, |l, r| {
@@ -362,27 +362,27 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
})
},
(
- &ExprKind::MethodCall(l_path, l_receiver, l_args, _),
- &ExprKind::MethodCall(r_path, r_receiver, r_args, _),
+ ExprKind::MethodCall(l_path, l_receiver, l_args, _),
+ ExprKind::MethodCall(r_path, r_receiver, r_args, _),
) => {
self.inner.allow_side_effects
&& self.eq_path_segment(l_path, r_path)
&& self.eq_expr(l_receiver, r_receiver)
&& self.eq_exprs(l_args, r_args)
},
- (&ExprKind::UnsafeBinderCast(lkind, le, None), &ExprKind::UnsafeBinderCast(rkind, re, None)) =>
+ (ExprKind::UnsafeBinderCast(lkind, le, None), ExprKind::UnsafeBinderCast(rkind, re, None)) =>
lkind == rkind && self.eq_expr(le, re),
- (&ExprKind::UnsafeBinderCast(lkind, le, Some(lt)), &ExprKind::UnsafeBinderCast(rkind, re, Some(rt))) =>
+ (ExprKind::UnsafeBinderCast(lkind, le, Some(lt)), ExprKind::UnsafeBinderCast(rkind, re, Some(rt))) =>
lkind == rkind && self.eq_expr(le, re) && self.eq_ty(lt, rt),
- (&ExprKind::OffsetOf(l_container, l_fields), &ExprKind::OffsetOf(r_container, r_fields)) => {
+ (ExprKind::OffsetOf(l_container, l_fields), ExprKind::OffsetOf(r_container, r_fields)) => {
self.eq_ty(l_container, r_container) && over(l_fields, r_fields, |l, r| l.name == r.name)
},
(ExprKind::Path(l), ExprKind::Path(r)) => self.eq_qpath(l, r),
- (&ExprKind::Repeat(le, ll), &ExprKind::Repeat(re, rl)) => {
+ (ExprKind::Repeat(le, ll), ExprKind::Repeat(re, rl)) => {
self.eq_expr(le, re) && self.eq_const_arg(ll, rl)
},
(ExprKind::Ret(l), ExprKind::Ret(r)) => both(l.as_ref(), r.as_ref(), |l, r| self.eq_expr(l, r)),
- (&ExprKind::Struct(l_path, lf, ref lo), &ExprKind::Struct(r_path, rf, ref ro)) => {
+ (ExprKind::Struct(l_path, lf, lo), ExprKind::Struct(r_path, rf, ro)) => {
self.eq_qpath(l_path, r_path)
&& match (lo, ro) {
(StructTailExpr::Base(l),StructTailExpr::Base(r)) => self.eq_expr(l, r),
@@ -392,58 +392,58 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
}
&& over(lf, rf, |l, r| self.eq_expr_field(l, r))
},
- (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup),
- (&ExprKind::Use(l_expr, _), &ExprKind::Use(r_expr, _)) => self.eq_expr(l_expr, r_expr),
- (&ExprKind::Type(le, lt), &ExprKind::Type(re, rt)) => self.eq_expr(le, re) && self.eq_ty(lt, rt),
- (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re),
- (&ExprKind::Yield(le, _), &ExprKind::Yield(re, _)) => return self.eq_expr(le, re),
+ (ExprKind::Tup(l_tup), ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup),
+ (ExprKind::Use(l_expr, _), ExprKind::Use(r_expr, _)) => self.eq_expr(l_expr, r_expr),
+ (ExprKind::Type(le, lt), ExprKind::Type(re, rt)) => self.eq_expr(le, re) && self.eq_ty(lt, rt),
+ (ExprKind::Unary(l_op, le), ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re),
+ (ExprKind::Yield(le, _), ExprKind::Yield(re, _)) => return self.eq_expr(le, re),
(
// Else branches for branches above, grouped as per `match_same_arms`.
- | &ExprKind::AddrOf(..)
- | &ExprKind::Array(..)
- | &ExprKind::Assign(..)
- | &ExprKind::AssignOp(..)
- | &ExprKind::Binary(..)
- | &ExprKind::Become(..)
- | &ExprKind::Block(..)
- | &ExprKind::Break(..)
- | &ExprKind::Call(..)
- | &ExprKind::Cast(..)
- | &ExprKind::ConstBlock(..)
- | &ExprKind::Continue(..)
- | &ExprKind::DropTemps(..)
- | &ExprKind::Field(..)
- | &ExprKind::Index(..)
- | &ExprKind::If(..)
- | &ExprKind::Let(..)
- | &ExprKind::Lit(..)
- | &ExprKind::Loop(..)
- | &ExprKind::Match(..)
- | &ExprKind::MethodCall(..)
- | &ExprKind::OffsetOf(..)
- | &ExprKind::Path(..)
- | &ExprKind::Repeat(..)
- | &ExprKind::Ret(..)
- | &ExprKind::Struct(..)
- | &ExprKind::Tup(..)
- | &ExprKind::Use(..)
- | &ExprKind::Type(..)
- | &ExprKind::Unary(..)
- | &ExprKind::Yield(..)
- | &ExprKind::UnsafeBinderCast(..)
+ | ExprKind::AddrOf(..)
+ | ExprKind::Array(..)
+ | ExprKind::Assign(..)
+ | ExprKind::AssignOp(..)
+ | ExprKind::Binary(..)
+ | ExprKind::Become(..)
+ | ExprKind::Block(..)
+ | ExprKind::Break(..)
+ | ExprKind::Call(..)
+ | ExprKind::Cast(..)
+ | ExprKind::ConstBlock(..)
+ | ExprKind::Continue(..)
+ | ExprKind::DropTemps(..)
+ | ExprKind::Field(..)
+ | ExprKind::Index(..)
+ | ExprKind::If(..)
+ | ExprKind::Let(..)
+ | ExprKind::Lit(..)
+ | ExprKind::Loop(..)
+ | ExprKind::Match(..)
+ | ExprKind::MethodCall(..)
+ | ExprKind::OffsetOf(..)
+ | ExprKind::Path(..)
+ | ExprKind::Repeat(..)
+ | ExprKind::Ret(..)
+ | ExprKind::Struct(..)
+ | ExprKind::Tup(..)
+ | ExprKind::Use(..)
+ | ExprKind::Type(..)
+ | ExprKind::Unary(..)
+ | ExprKind::Yield(..)
+ | ExprKind::UnsafeBinderCast(..)
// --- Special cases that do not have a positive branch.
// `Err` represents an invalid expression, so let's never assume that
// an invalid expressions is equal to anything.
- | &ExprKind::Err(..)
+ | ExprKind::Err(..)
// For the time being, we always consider that two closures are unequal.
// This behavior may change in the future.
- | &ExprKind::Closure(..)
+ | ExprKind::Closure(..)
// For the time being, we always consider that two instances of InlineAsm are different.
// This behavior may change in the future.
- | &ExprKind::InlineAsm(_)
+ | ExprKind::InlineAsm(_)
, _
) => false,
};
@@ -483,7 +483,7 @@ fn eq_const_arg(&mut self, left: &ConstArg<'_>, right: &ConstArg<'_>) -> bool {
}
fn eq_lifetime(left: &Lifetime, right: &Lifetime) -> bool {
- left.res == right.res
+ left.kind == right.kind
}
fn eq_pat_field(&mut self, left: &PatField<'_>, right: &PatField<'_>) -> bool {
@@ -494,11 +494,11 @@ fn eq_pat_field(&mut self, left: &PatField<'_>, right: &PatField<'_>) -> bool {
fn eq_pat_expr(&mut self, left: &PatExpr<'_>, right: &PatExpr<'_>) -> bool {
match (&left.kind, &right.kind) {
(
- &PatExprKind::Lit {
+ PatExprKind::Lit {
lit: left,
negated: left_neg,
},
- &PatExprKind::Lit {
+ PatExprKind::Lit {
lit: right,
negated: right_neg,
},
@@ -512,47 +512,47 @@ fn eq_pat_expr(&mut self, left: &PatExpr<'_>, right: &PatExpr<'_>) -> bool {
/// Checks whether two patterns are the same.
fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool {
match (&left.kind, &right.kind) {
- (&PatKind::Box(l), &PatKind::Box(r)) => self.eq_pat(l, r),
- (&PatKind::Struct(ref lp, la, ..), &PatKind::Struct(ref rp, ra, ..)) => {
+ (PatKind::Box(l), PatKind::Box(r)) => self.eq_pat(l, r),
+ (PatKind::Struct(lp, la, ..), PatKind::Struct(rp, ra, ..)) => {
self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat_field(l, r))
},
- (&PatKind::TupleStruct(ref lp, la, ls), &PatKind::TupleStruct(ref rp, ra, rs)) => {
+ (PatKind::TupleStruct(lp, la, ls), PatKind::TupleStruct(rp, ra, rs)) => {
self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs
},
- (&PatKind::Binding(lb, li, _, ref lp), &PatKind::Binding(rb, ri, _, ref rp)) => {
+ (PatKind::Binding(lb, li, _, lp), PatKind::Binding(rb, ri, _, rp)) => {
let eq = lb == rb && both(lp.as_ref(), rp.as_ref(), |l, r| self.eq_pat(l, r));
if eq {
- self.locals.insert(li, ri);
+ self.locals.insert(*li, *ri);
}
eq
},
- (&PatKind::Expr(l), &PatKind::Expr(r)) => self.eq_pat_expr(l, r),
- (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
- (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
+ (PatKind::Expr(l), PatKind::Expr(r)) => self.eq_pat_expr(l, r),
+ (PatKind::Tuple(l, ls), PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
+ (PatKind::Range(ls, le, li), PatKind::Range(rs, re, ri)) => {
both(ls.as_ref(), rs.as_ref(), |a, b| self.eq_pat_expr(a, b))
&& both(le.as_ref(), re.as_ref(), |a, b| self.eq_pat_expr(a, b))
&& (li == ri)
},
- (&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re),
- (&PatKind::Slice(ls, ref li, le), &PatKind::Slice(rs, ref ri, re)) => {
+ (PatKind::Ref(le, lm), PatKind::Ref(re, rm)) => lm == rm && self.eq_pat(le, re),
+ (PatKind::Slice(ls, li, le), PatKind::Slice(rs, ri, re)) => {
over(ls, rs, |l, r| self.eq_pat(l, r))
&& over(le, re, |l, r| self.eq_pat(l, r))
&& both(li.as_ref(), ri.as_ref(), |l, r| self.eq_pat(l, r))
},
- (&PatKind::Wild, &PatKind::Wild) => true,
+ (PatKind::Wild, PatKind::Wild) => true,
_ => false,
}
}
fn eq_qpath(&mut self, left: &QPath<'_>, right: &QPath<'_>) -> bool {
match (left, right) {
- (&QPath::Resolved(ref lty, lpath), &QPath::Resolved(ref rty, rpath)) => {
+ (QPath::Resolved(lty, lpath), QPath::Resolved(rty, rpath)) => {
both(lty.as_ref(), rty.as_ref(), |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath)
},
- (&QPath::TypeRelative(lty, lseg), &QPath::TypeRelative(rty, rseg)) => {
+ (QPath::TypeRelative(lty, lseg), QPath::TypeRelative(rty, rseg)) => {
self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg)
},
- (&QPath::LangItem(llang_item, ..), &QPath::LangItem(rlang_item, ..)) => llang_item == rlang_item,
+ (QPath::LangItem(llang_item, ..), QPath::LangItem(rlang_item, ..)) => llang_item == rlang_item,
_ => false,
}
}
@@ -611,15 +611,15 @@ pub fn eq_path_segment(&mut self, left: &PathSegment<'_>, right: &PathSegment<'_
pub fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool {
match (&left.kind, &right.kind) {
- (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
- (&TyKind::Array(lt, ll), &TyKind::Array(rt, rl)) => self.eq_ty(lt, rt) && self.eq_const_arg(ll, rl),
+ (TyKind::Slice(l_vec), TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec),
+ (TyKind::Array(lt, ll), TyKind::Array(rt, rl)) => self.eq_ty(lt, rt) && self.eq_const_arg(ll, rl),
(TyKind::Ptr(l_mut), TyKind::Ptr(r_mut)) => l_mut.mutbl == r_mut.mutbl && self.eq_ty(l_mut.ty, r_mut.ty),
(TyKind::Ref(_, l_rmut), TyKind::Ref(_, r_rmut)) => {
l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(l_rmut.ty, r_rmut.ty)
},
(TyKind::Path(l), TyKind::Path(r)) => self.eq_qpath(l, r),
- (&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)),
- (&TyKind::Infer(()), &TyKind::Infer(())) => true,
+ (TyKind::Tup(l), TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)),
+ (TyKind::Infer(()), TyKind::Infer(())) => true,
_ => false,
}
}
@@ -853,9 +853,9 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
std::mem::discriminant(&e.kind).hash(&mut self.s);
- match e.kind {
+ match &e.kind {
ExprKind::AddrOf(kind, m, e) => {
- std::mem::discriminant(&kind).hash(&mut self.s);
+ std::mem::discriminant(kind).hash(&mut self.s);
m.hash(&mut self.s);
self.hash_expr(e);
},
@@ -871,7 +871,7 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
self.hash_expr(l);
self.hash_expr(r);
},
- ExprKind::AssignOp(ref o, l, r) => {
+ ExprKind::AssignOp(o, l, r) => {
std::mem::discriminant(&o.node).hash(&mut self.s);
self.hash_expr(l);
self.hash_expr(r);
@@ -887,11 +887,11 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
self.hash_expr(l);
self.hash_expr(r);
},
- ExprKind::Break(i, ref j) => {
+ ExprKind::Break(i, j) => {
if let Some(i) = i.label {
self.hash_name(i.ident.name);
}
- if let Some(j) = *j {
+ if let Some(j) = j {
self.hash_expr(j);
}
},
@@ -903,20 +903,20 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
self.hash_expr(e);
self.hash_ty(ty);
},
- ExprKind::Closure(&Closure {
+ ExprKind::Closure(Closure {
capture_clause, body, ..
}) => {
- std::mem::discriminant(&capture_clause).hash(&mut self.s);
+ std::mem::discriminant(capture_clause).hash(&mut self.s);
// closures inherit TypeckResults
- self.hash_expr(self.cx.tcx.hir_body(body).value);
+ self.hash_expr(self.cx.tcx.hir_body(*body).value);
},
- ExprKind::ConstBlock(ref l_id) => {
+ ExprKind::ConstBlock(l_id) => {
self.hash_body(l_id.body);
},
ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => {
self.hash_expr(e);
},
- ExprKind::Field(e, ref f) => {
+ ExprKind::Field(e, f) => {
self.hash_expr(e);
self.hash_name(f.name);
},
@@ -991,23 +991,23 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
ExprKind::Lit(l) => {
l.node.hash(&mut self.s);
},
- ExprKind::Loop(b, ref i, ..) => {
+ ExprKind::Loop(b, i, ..) => {
self.hash_block(b);
- if let Some(i) = *i {
+ if let Some(i) = i {
self.hash_name(i.ident.name);
}
},
- ExprKind::If(cond, then, ref else_opt) => {
+ ExprKind::If(cond, then, else_opt) => {
self.hash_expr(cond);
self.hash_expr(then);
- if let Some(e) = *else_opt {
+ if let Some(e) = else_opt {
self.hash_expr(e);
}
},
- ExprKind::Match(e, arms, ref s) => {
+ ExprKind::Match(e, arms, s) => {
self.hash_expr(e);
- for arm in arms {
+ for arm in *arms {
self.hash_pat(arm.pat);
if let Some(e) = arm.guard {
self.hash_expr(e);
@@ -1017,38 +1017,38 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
s.hash(&mut self.s);
},
- ExprKind::MethodCall(path, receiver, args, ref _fn_span) => {
+ ExprKind::MethodCall(path, receiver, args, _fn_span) => {
self.hash_name(path.ident.name);
self.hash_expr(receiver);
self.hash_exprs(args);
},
ExprKind::OffsetOf(container, fields) => {
self.hash_ty(container);
- for field in fields {
+ for field in *fields {
self.hash_name(field.name);
}
},
- ExprKind::Path(ref qpath) => {
+ ExprKind::Path(qpath) => {
self.hash_qpath(qpath);
},
ExprKind::Repeat(e, len) => {
self.hash_expr(e);
self.hash_const_arg(len);
},
- ExprKind::Ret(ref e) => {
- if let Some(e) = *e {
+ ExprKind::Ret(e) => {
+ if let Some(e) = e {
self.hash_expr(e);
}
},
- ExprKind::Struct(path, fields, ref expr) => {
+ ExprKind::Struct(path, fields, expr) => {
self.hash_qpath(path);
- for f in fields {
+ for f in *fields {
self.hash_name(f.ident.name);
self.hash_expr(f.expr);
}
- if let StructTailExpr::Base(e) = *expr {
+ if let StructTailExpr::Base(e) = expr {
self.hash_expr(e);
}
},
@@ -1059,11 +1059,11 @@ pub fn hash_expr(&mut self, e: &Expr<'_>) {
self.hash_expr(expr);
},
ExprKind::Unary(lop, le) => {
- std::mem::discriminant(&lop).hash(&mut self.s);
+ std::mem::discriminant(lop).hash(&mut self.s);
self.hash_expr(le);
},
ExprKind::UnsafeBinderCast(kind, expr, ty) => {
- std::mem::discriminant(&kind).hash(&mut self.s);
+ std::mem::discriminant(kind).hash(&mut self.s);
self.hash_expr(expr);
if let Some(ty) = ty {
self.hash_ty(ty);
@@ -1084,7 +1084,7 @@ pub fn hash_name(&mut self, n: Symbol) {
}
pub fn hash_qpath(&mut self, p: &QPath<'_>) {
- match *p {
+ match p {
QPath::Resolved(_, path) => {
self.hash_path(path);
},
@@ -1092,7 +1092,7 @@ pub fn hash_qpath(&mut self, p: &QPath<'_>) {
self.hash_name(path.ident.name);
},
QPath::LangItem(lang_item, ..) => {
- std::mem::discriminant(&lang_item).hash(&mut self.s);
+ std::mem::discriminant(lang_item).hash(&mut self.s);
},
}
// self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s);
@@ -1123,11 +1123,11 @@ pub fn hash_ty_pat(&mut self, pat: &TyPat<'_>) {
pub fn hash_pat(&mut self, pat: &Pat<'_>) {
std::mem::discriminant(&pat.kind).hash(&mut self.s);
- match pat.kind {
+ match &pat.kind {
PatKind::Missing => unreachable!(),
PatKind::Binding(BindingMode(by_ref, mutability), _, _, pat) => {
- std::mem::discriminant(&by_ref).hash(&mut self.s);
- std::mem::discriminant(&mutability).hash(&mut self.s);
+ std::mem::discriminant(by_ref).hash(&mut self.s);
+ std::mem::discriminant(mutability).hash(&mut self.s);
if let Some(pat) = pat {
self.hash_pat(pat);
}
@@ -1135,7 +1135,7 @@ pub fn hash_pat(&mut self, pat: &Pat<'_>) {
PatKind::Box(pat) | PatKind::Deref(pat) => self.hash_pat(pat),
PatKind::Expr(expr) => self.hash_pat_expr(expr),
PatKind::Or(pats) => {
- for pat in pats {
+ for pat in *pats {
self.hash_pat(pat);
}
},
@@ -1146,44 +1146,44 @@ pub fn hash_pat(&mut self, pat: &Pat<'_>) {
if let Some(e) = e {
self.hash_pat_expr(e);
}
- std::mem::discriminant(&i).hash(&mut self.s);
+ std::mem::discriminant(i).hash(&mut self.s);
},
PatKind::Ref(pat, mu) => {
self.hash_pat(pat);
- std::mem::discriminant(&mu).hash(&mut self.s);
+ std::mem::discriminant(mu).hash(&mut self.s);
},
PatKind::Guard(pat, guard) => {
self.hash_pat(pat);
self.hash_expr(guard);
},
PatKind::Slice(l, m, r) => {
- for pat in l {
+ for pat in *l {
self.hash_pat(pat);
}
if let Some(pat) = m {
self.hash_pat(pat);
}
- for pat in r {
+ for pat in *r {
self.hash_pat(pat);
}
},
- PatKind::Struct(ref qpath, fields, e) => {
+ PatKind::Struct(qpath, fields, e) => {
self.hash_qpath(qpath);
- for f in fields {
+ for f in *fields {
self.hash_name(f.ident.name);
self.hash_pat(f.pat);
}
e.hash(&mut self.s);
},
PatKind::Tuple(pats, e) => {
- for pat in pats {
+ for pat in *pats {
self.hash_pat(pat);
}
e.hash(&mut self.s);
},
- PatKind::TupleStruct(ref qpath, pats, e) => {
+ PatKind::TupleStruct(qpath, pats, e) => {
self.hash_qpath(qpath);
- for pat in pats {
+ for pat in *pats {
self.hash_pat(pat);
}
e.hash(&mut self.s);
@@ -1245,8 +1245,8 @@ pub fn hash_stmt(&mut self, b: &Stmt<'_>) {
pub fn hash_lifetime(&mut self, lifetime: &Lifetime) {
lifetime.ident.name.hash(&mut self.s);
- std::mem::discriminant(&lifetime.res).hash(&mut self.s);
- if let LifetimeName::Param(param_id) = lifetime.res {
+ std::mem::discriminant(&lifetime.kind).hash(&mut self.s);
+ if let LifetimeKind::Param(param_id) = lifetime.kind {
param_id.hash(&mut self.s);
}
}
@@ -1261,7 +1261,7 @@ pub fn hash_tykind(&mut self, ty: &TyKind<'_>) {
TyKind::Slice(ty) => {
self.hash_ty(ty);
},
- &TyKind::Array(ty, len) => {
+ TyKind::Array(ty, len) => {
self.hash_ty(ty);
self.hash_const_arg(len);
},
@@ -1334,11 +1334,11 @@ fn hash_const_arg(&mut self, const_arg: &ConstArg<'_>) {
fn hash_generic_args(&mut self, arg_list: &[GenericArg<'_>]) {
for arg in arg_list {
- match *arg {
+ match arg {
GenericArg::Lifetime(l) => self.hash_lifetime(l),
GenericArg::Type(ty) => self.hash_ty(ty.as_unambig_ty()),
GenericArg::Const(ca) => self.hash_const_arg(ca.as_unambig_ct()),
- GenericArg::Infer(ref inf) => self.hash_ty(&inf.to_ty()),
+ GenericArg::Infer(inf) => self.hash_ty(&inf.to_ty()),
}
}
}
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 9f450d6..264b9b0 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1,10 +1,8 @@
#![feature(array_chunks)]
#![feature(box_patterns)]
-#![feature(f128)]
-#![feature(f16)]
#![feature(if_let_guard)]
-#![feature(macro_metavar_expr)]
#![feature(macro_metavar_expr_concat)]
+#![feature(macro_metavar_expr)]
#![feature(let_chains)]
#![feature(never_type)]
#![feature(rustc_private)]
@@ -53,9 +51,6 @@
extern crate rustc_trait_selection;
extern crate smallvec;
-#[macro_use]
-pub mod sym_helper;
-
pub mod ast_utils;
pub mod attrs;
mod check_proc_macro;
@@ -108,10 +103,10 @@
use rustc_hir::intravisit::{FnKind, Visitor, walk_expr};
use rustc_hir::{
self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext,
- Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg, GenericArgs, HirId, Impl, ImplItem,
- ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode,
- Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitFn, TraitItem,
- TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, def,
+ CoroutineDesugaring, CoroutineKind, Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArg,
+ GenericArgs, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource,
+ Mutability, Node, OwnerId, OwnerNode, Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath,
+ Stmt, StmtKind, TraitFn, TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, def,
};
use rustc_lexer::{TokenKind, tokenize};
use rustc_lint::{LateContext, Level, Lint, LintContext};
@@ -129,6 +124,7 @@
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{Ident, Symbol, kw};
use rustc_span::{InnerSpan, Span};
+use source::walk_span_to_context;
use visitors::{Visitable, for_each_unconsumed_temporary};
use crate::consts::{ConstEvalCtxt, Constant, mir_to_const};
@@ -370,10 +366,10 @@ pub fn is_inherent_method_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
/// Checks if a method is defined in an impl of a diagnostic item
pub fn is_diag_item_method(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol) -> bool {
- if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
- if let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def() {
- return cx.tcx.is_diagnostic_item(diag_item, adt.did());
- }
+ if let Some(impl_did) = cx.tcx.impl_of_method(def_id)
+ && let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def()
+ {
+ return cx.tcx.is_diagnostic_item(diag_item, adt.did());
}
false
}
@@ -460,10 +456,10 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
QPath::Resolved(_, path) => match_path(path, segments),
QPath::TypeRelative(ty, segment) => match ty.kind {
TyKind::Path(ref inner_path) => {
- if let [prefix @ .., end] = segments {
- if match_qpath(inner_path, prefix) {
- return segment.ident.name.as_str() == *end;
- }
+ if let [prefix @ .., end] = segments
+ && match_qpath(inner_path, prefix)
+ {
+ return segment.ident.name.as_str() == *end;
}
false
},
@@ -526,10 +522,10 @@ pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool {
/// If the expression is a path to a local, returns the canonical `HirId` of the local.
pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> {
- if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
- if let Res::Local(id) = path.res {
- return Some(id);
- }
+ if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind
+ && let Res::Local(id) = path.res
+ {
+ return Some(id);
}
None
}
@@ -896,16 +892,14 @@ fn is_default_equivalent_ctor(cx: &LateContext<'_>, def_id: DefId, path: &QPath<
sym::BinaryHeap,
];
- if let QPath::TypeRelative(_, method) = path {
- if method.ident.name == sym::new {
- if let Some(impl_did) = cx.tcx.impl_of_method(def_id) {
- if let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def() {
- return std_types_symbols.iter().any(|&symbol| {
- cx.tcx.is_diagnostic_item(symbol, adt.did()) || Some(adt.did()) == cx.tcx.lang_items().string()
- });
- }
- }
- }
+ if let QPath::TypeRelative(_, method) = path
+ && method.ident.name == sym::new
+ && let Some(impl_did) = cx.tcx.impl_of_method(def_id)
+ && let Some(adt) = cx.tcx.type_of(impl_did).instantiate_identity().ty_adt_def()
+ {
+ return std_types_symbols.iter().any(|&symbol| {
+ cx.tcx.is_diagnostic_item(symbol, adt.did()) || Some(adt.did()) == cx.tcx.lang_items().string()
+ });
}
false
}
@@ -1030,6 +1024,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
ExprKind::Call(from_func, [arg]) => is_default_equivalent_from(cx, from_func, arg),
ExprKind::Path(qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, e.hir_id), OptionNone),
ExprKind::AddrOf(rustc_hir::BorrowKind::Ref, _, expr) => matches!(expr.kind, ExprKind::Array([])),
+ ExprKind::Block(Block { stmts: [], expr, .. }, _) => expr.is_some_and(|e| is_default_equivalent(cx, e)),
_ => false,
}
}
@@ -1206,12 +1201,10 @@ fn pat_capture_kind(cx: &LateContext<'_>, pat: &Pat<'_>) -> CaptureKind {
.adjustments()
.get(child_id)
.map_or(&[][..], |x| &**x)
- {
- if let rustc_ty::RawPtr(_, mutability) | rustc_ty::Ref(_, _, mutability) =
+ && let rustc_ty::RawPtr(_, mutability) | rustc_ty::Ref(_, _, mutability) =
*adjust.last().map_or(target, |a| a.target).kind()
- {
- return CaptureKind::Ref(mutability);
- }
+ {
+ return CaptureKind::Ref(mutability);
}
match parent {
@@ -1739,10 +1732,10 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool
/// Checks whether the given expression is a constant literal of the given value.
pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool {
// FIXME: use constant folding
- if let ExprKind::Lit(spanned) = expr.kind {
- if let LitKind::Int(v, _) = spanned.node {
- return v == value;
- }
+ if let ExprKind::Lit(spanned) = expr.kind
+ && let LitKind::Int(v, _) = spanned.node
+ {
+ return v == value;
}
false
}
@@ -1779,10 +1772,10 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
let data = span.ctxt().outer_expn_data();
let new_span = data.call_site;
- if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind {
- if mac_name.as_str() == name {
- return Some(new_span);
- }
+ if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind
+ && mac_name.as_str() == name
+ {
+ return Some(new_span);
}
span = new_span;
@@ -1808,10 +1801,10 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> {
let data = span.ctxt().outer_expn_data();
let new_span = data.call_site;
- if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind {
- if mac_name.as_str() == name {
- return Some(new_span);
- }
+ if let ExpnKind::Macro(MacroKind::Bang, mac_name) = data.kind
+ && mac_name.as_str() == name
+ {
+ return Some(new_span);
}
}
@@ -1832,15 +1825,15 @@ pub fn nth_arg<'tcx>(cx: &LateContext<'tcx>, fn_def_id: OwnerId, nth: usize) ->
/// Checks if an expression is constructing a tuple-like enum variant or struct
pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- if let ExprKind::Call(fun, _) = expr.kind {
- if let ExprKind::Path(ref qp) = fun.kind {
- let res = cx.qpath_res(qp, fun.hir_id);
- return match res {
- Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
- Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
- _ => false,
- };
- }
+ if let ExprKind::Call(fun, _) = expr.kind
+ && let ExprKind::Path(ref qp) = fun.kind
+ {
+ let res = cx.qpath_res(qp, fun.hir_id);
+ return match res {
+ Res::Def(DefKind::Variant | DefKind::Ctor(..), ..) => true,
+ Res::Def(_, def_id) => cx.tcx.is_promotable_const_fn(def_id),
+ _ => false,
+ };
}
false
}
@@ -1914,10 +1907,10 @@ pub fn is_self(slf: &Param<'_>) -> bool {
}
pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool {
- if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind {
- if let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path.res {
- return true;
- }
+ if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind
+ && let Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } = path.res
+ {
+ return true;
}
false
}
@@ -2122,10 +2115,10 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>,
}
// final `else {..}`
- if !blocks.is_empty() {
- if let ExprKind::Block(block, _) = expr.kind {
- blocks.push(block);
- }
+ if !blocks.is_empty()
+ && let ExprKind::Block(block, _) = expr.kind
+ {
+ blocks.push(block);
}
(conds, blocks)
@@ -2140,26 +2133,34 @@ pub fn is_async_fn(kind: FnKind<'_>) -> bool {
}
}
-/// Peels away all the compiler generated code surrounding the body of an async function,
-pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
- if let ExprKind::Closure(&Closure { body, .. }) = body.value.kind {
- if let ExprKind::Block(
+/// Peels away all the compiler generated code surrounding the body of an async closure.
+pub fn get_async_closure_expr<'tcx>(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+ if let ExprKind::Closure(&Closure {
+ body,
+ kind: hir::ClosureKind::Coroutine(CoroutineKind::Desugared(CoroutineDesugaring::Async, _)),
+ ..
+ }) = expr.kind
+ && let ExprKind::Block(
Block {
- stmts: [],
expr:
Some(Expr {
- kind: ExprKind::DropTemps(expr),
+ kind: ExprKind::DropTemps(inner_expr),
..
}),
..
},
_,
) = tcx.hir_body(body).value.kind
- {
- return Some(expr);
- }
+ {
+ Some(inner_expr)
+ } else {
+ None
}
- None
+}
+
+/// Peels away all the compiler generated code surrounding the body of an async function,
+pub fn get_async_fn_body<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'_>) -> Option<&'tcx Expr<'tcx>> {
+ get_async_closure_expr(tcx, body.value)
}
// check if expr is calling method or function with #[must_use] attribute
@@ -2363,14 +2364,14 @@ pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
cx.tcx
.hir_attrs(hir::CRATE_HIR_ID)
.iter()
- .any(|attr| attr.name_or_empty() == sym::no_std)
+ .any(|attr| attr.has_name(sym::no_std))
}
pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
cx.tcx
.hir_attrs(hir::CRATE_HIR_ID)
.iter()
- .any(|attr| attr.name_or_empty() == sym::no_core)
+ .any(|attr| attr.has_name(sym::no_core))
}
/// Check if parent of a hir node is a trait implementation block.
@@ -2631,17 +2632,19 @@ pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>
}
pub fn is_hir_ty_cfg_dependant(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool {
- if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
- if let Res::Def(_, def_id) = path.res {
- return cx.tcx.has_attr(def_id, sym::cfg_trace) || cx.tcx.has_attr(def_id, sym::cfg_attr);
- }
+ if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind
+ && let Res::Def(_, def_id) = path.res
+ {
+ return cx.tcx.has_attr(def_id, sym::cfg) || cx.tcx.has_attr(def_id, sym::cfg_attr);
}
false
}
static TEST_ITEM_NAMES_CACHE: OnceLock<Mutex<FxHashMap<LocalModDefId, Vec<Symbol>>>> = OnceLock::new();
-fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Symbol]) -> bool) -> bool {
+/// Apply `f()` to the set of test item names.
+/// The names are sorted using the default `Symbol` ordering.
+fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl FnOnce(&[Symbol]) -> bool) -> bool {
let cache = TEST_ITEM_NAMES_CACHE.get_or_init(|| Mutex::new(FxHashMap::default()));
let mut map: MutexGuard<'_, FxHashMap<LocalModDefId, Vec<Symbol>>> = cache.lock().unwrap();
let value = map.entry(module);
@@ -2653,18 +2656,16 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Sym
if matches!(tcx.def_kind(id.owner_id), DefKind::Const)
&& let item = tcx.hir_item(id)
&& let ItemKind::Const(ident, ty, _generics, _body) = item.kind
- {
- if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
+ && let TyKind::Path(QPath::Resolved(_, path)) = ty.kind
// We could also check for the type name `test::TestDescAndFn`
- if let Res::Def(DefKind::Struct, _) = path.res {
- let has_test_marker = tcx
- .hir_attrs(item.hir_id())
- .iter()
- .any(|a| a.has_name(sym::rustc_test_marker));
- if has_test_marker {
- names.push(ident.name);
- }
- }
+ && let Res::Def(DefKind::Struct, _) = path.res
+ {
+ let has_test_marker = tcx
+ .hir_attrs(item.hir_id())
+ .iter()
+ .any(|a| a.has_name(sym::rustc_test_marker));
+ if has_test_marker {
+ names.push(ident.name);
}
}
}
@@ -2685,18 +2686,37 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: HirId) -> bool {
// Since you can nest functions we need to collect all until we leave
// function scope
.any(|(_id, node)| {
- if let Node::Item(item) = node {
- if let ItemKind::Fn { ident, .. } = item.kind {
- // Note that we have sorted the item names in the visitor,
- // so the binary_search gets the same as `contains`, but faster.
- return names.binary_search(&ident.name).is_ok();
- }
+ if let Node::Item(item) = node
+ && let ItemKind::Fn { ident, .. } = item.kind
+ {
+ // Note that we have sorted the item names in the visitor,
+ // so the binary_search gets the same as `contains`, but faster.
+ return names.binary_search(&ident.name).is_ok();
}
false
})
})
}
+/// Checks if `fn_def_id` has a `#[test]` attribute applied
+///
+/// This only checks directly applied attributes. To see if a node has a parent function marked with
+/// `#[test]` use [`is_in_test_function`].
+///
+/// Note: Add `//@compile-flags: --test` to UI tests with a `#[test]` function
+pub fn is_test_function(tcx: TyCtxt<'_>, fn_def_id: LocalDefId) -> bool {
+ let id = tcx.local_def_id_to_hir_id(fn_def_id);
+ if let Node::Item(item) = tcx.hir_node(id)
+ && let ItemKind::Fn { ident, .. } = item.kind
+ {
+ with_test_item_names(tcx, tcx.parent_module(id), |names| {
+ names.binary_search(&ident.name).is_ok()
+ })
+ } else {
+ false
+ }
+}
+
/// Checks if `id` has a `#[cfg(test)]` attribute applied
///
/// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent
@@ -3728,3 +3748,20 @@ pub fn peel_hir_ty_options<'tcx>(cx: &LateContext<'tcx>, mut hir_ty: &'tcx hir::
}
hir_ty
}
+
+/// If `expr` is a desugared `.await`, return the original expression if it does not come from a
+/// macro expansion.
+pub fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
+ if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind
+ && let ExprKind::Call(_, [into_future_arg]) = match_value.kind
+ && let ctxt = expr.span.ctxt()
+ && for_each_expr_without_closures(into_future_arg, |e| {
+ walk_span_to_context(e.span, ctxt).map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(()))
+ })
+ .is_none()
+ {
+ Some(into_future_arg)
+ } else {
+ None
+ }
+}
diff --git a/src/tools/clippy/clippy_utils/src/mir/mod.rs b/src/tools/clippy/clippy_utils/src/mir/mod.rs
index ffcfcd24..9ba644f 100644
--- a/src/tools/clippy/clippy_utils/src/mir/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/mod.rs
@@ -76,7 +76,7 @@ fn visit_place(&mut self, place: &Place<'tcx>, ctx: PlaceContext, loc: Location)
}
if matches!(
ctx,
- PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::Move | NonMutatingUseContext::Inspect)
| PlaceContext::MutatingUse(MutatingUseContext::Borrow)
) {
self.results[i].local_consume_or_mutate_locs.push(loc);
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs
index 86f4f19..19061b5 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_utils/src/msrvs.rs
@@ -1,10 +1,10 @@
+use crate::sym;
use rustc_ast::Attribute;
use rustc_ast::attr::AttributeExt;
-
use rustc_attr_parsing::{RustcVersion, parse_version};
use rustc_lint::LateContext;
use rustc_session::Session;
-use rustc_span::{Symbol, sym};
+use rustc_span::Symbol;
use serde::Deserialize;
use smallvec::SmallVec;
use std::iter::once;
@@ -24,10 +24,10 @@ macro_rules! msrv_aliases {
msrv_aliases! {
1,87,0 { OS_STR_DISPLAY, INT_MIDPOINT }
1,85,0 { UINT_FLOAT_MIDPOINT }
- 1,84,0 { CONST_OPTION_AS_SLICE }
+ 1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR }
1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP }
- 1,81,0 { LINT_REASONS_STABILIZATION, ERROR_IN_CORE, EXPLICIT_SELF_TYPE_ELISION }
+ 1,81,0 { LINT_REASONS_STABILIZATION, ERROR_IN_CORE, EXPLICIT_SELF_TYPE_ELISION, DURATION_ABS_DIFF }
1,80,0 { BOX_INTO_ITER, LAZY_CELL }
1,77,0 { C_STR_LITERALS }
1,76,0 { PTR_FROM_REF, OPTION_RESULT_INSPECT }
@@ -40,6 +40,7 @@ macro_rules! msrv_aliases {
1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
1,63,0 { CLONE_INTO }
1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE, CONST_EXTERN_C_FN }
+ 1,60,0 { ABS_DIFF }
1,59,0 { THREAD_LOCAL_CONST_INIT }
1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF }
1,57,0 { MAP_WHILE }
@@ -63,6 +64,7 @@ macro_rules! msrv_aliases {
1,35,0 { OPTION_COPIED, RANGE_CONTAINS }
1,34,0 { TRY_FROM }
1,33,0 { UNDERSCORE_IMPORTS }
+ 1,32,0 { CONST_IS_POWER_OF_TWO }
1,31,0 { OPTION_REPLACE }
1,30,0 { ITERATOR_FIND_MAP, TOOL_ATTRIBUTES }
1,29,0 { ITER_FLATTEN }
@@ -182,8 +184,7 @@ pub fn check_attributes_post(&mut self, sess: &Session, attrs: &[Attribute]) {
}
fn parse_attrs(sess: &Session, attrs: &[impl AttributeExt]) -> Option<RustcVersion> {
- let sym_msrv = Symbol::intern("msrv");
- let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv]));
+ let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym::msrv]));
if let Some(msrv_attr) = msrv_attrs.next() {
if let Some(duplicate) = msrv_attrs.next_back() {
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 51d06ad..7f64ebd 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -30,9 +30,11 @@
pub const CHAR_IS_ASCII: [&str; 5] = ["core", "char", "methods", "<impl char>", "is_ascii"];
pub const IO_ERROR_NEW: [&str; 5] = ["std", "io", "error", "Error", "new"];
pub const IO_ERRORKIND_OTHER: [&str; 5] = ["std", "io", "error", "ErrorKind", "Other"];
+pub const ALIGN_OF: [&str; 3] = ["core", "mem", "align_of"];
// Paths in clippy itself
pub const MSRV_STACK: [&str; 3] = ["clippy_utils", "msrvs", "MsrvStack"];
+pub const CLIPPY_SYM_MODULE: [&str; 2] = ["clippy_utils", "sym"];
// Paths in external crates
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index 80066e9..8645d57 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -142,7 +142,20 @@ fn map_range(
map_range(cx.sess().source_map(), self.into_range(), f)
}
- /// Extends the range to include all preceding whitespace characters.
+ #[allow(rustdoc::invalid_rust_codeblocks, reason = "The codeblock is intentionally broken")]
+ /// Extends the range to include all preceding whitespace characters, unless there
+ /// are non-whitespace characters left on the same line after `self`.
+ ///
+ /// This extra condition prevents a problem when removing the '}' in:
+ /// ```ignore
+ /// ( // There was an opening bracket after the parenthesis, which has been removed
+ /// // This is a comment
+ /// })
+ /// ```
+ /// Removing the whitespaces, including the linefeed, before the '}', would put the
+ /// closing parenthesis at the end of the `// This is a comment` line, which would
+ /// make it part of the comment as well. In this case, it is best to keep the span
+ /// on the '}' alone.
fn with_leading_whitespace(self, cx: &impl HasSession) -> Range<BytePos> {
with_leading_whitespace(cx.sess().source_map(), self.into_range())
}
@@ -263,10 +276,15 @@ fn map_range(
}
fn with_leading_whitespace(sm: &SourceMap, sp: Range<BytePos>) -> Range<BytePos> {
- map_range(sm, sp.clone(), |src, range| {
- Some(src.get(..range.start)?.trim_end().len()..range.end)
+ map_range(sm, sp, |src, range| {
+ let non_blank_after = src.len() - src.get(range.end..)?.trim_start().len();
+ if src.get(range.end..non_blank_after)?.contains(['\r', '\n']) {
+ Some(src.get(..range.start)?.trim_end().len()..range.end)
+ } else {
+ Some(range)
+ }
})
- .unwrap_or(sp)
+ .unwrap()
}
fn trim_start(sm: &SourceMap, sp: Range<BytePos>) -> Range<BytePos> {
@@ -384,10 +402,10 @@ pub fn snippet_indent(sess: &impl HasSession, span: Span) -> Option<String> {
// For some reason these attributes don't have any expansion info on them, so
// we have to check it this way until there is a better way.
pub fn is_present_in_source(sess: &impl HasSession, span: Span) -> bool {
- if let Some(snippet) = snippet_opt(sess, span) {
- if snippet.is_empty() {
- return false;
- }
+ if let Some(snippet) = snippet_opt(sess, span)
+ && snippet.is_empty()
+ {
+ return false;
}
true
}
@@ -408,11 +426,11 @@ pub fn position_before_rarrow(s: &str) -> Option<usize> {
let mut rpos = rpos;
let chars: Vec<char> = s.chars().collect();
while rpos > 1 {
- if let Some(c) = chars.get(rpos - 1) {
- if c.is_whitespace() {
- rpos -= 1;
- continue;
- }
+ if let Some(c) = chars.get(rpos - 1)
+ && c.is_whitespace()
+ {
+ rpos -= 1;
+ continue;
}
break;
}
diff --git a/src/tools/clippy/clippy_utils/src/str_utils.rs b/src/tools/clippy/clippy_utils/src/str_utils.rs
index 421b25a..f0f82c8 100644
--- a/src/tools/clippy/clippy_utils/src/str_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/str_utils.rs
@@ -1,4 +1,4 @@
-/// Dealing with sting indices can be hard, this struct ensures that both the
+/// Dealing with string indices can be hard, this struct ensures that both the
/// character and byte index are provided for correct indexing.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct StrIndex {
@@ -165,7 +165,7 @@ pub fn camel_case_split(s: &str) -> Vec<&str> {
offsets.windows(2).map(|w| &s[w[0]..w[1]]).collect()
}
-/// Dealing with sting comparison can be complicated, this struct ensures that both the
+/// Dealing with string comparison can be complicated, this struct ensures that both the
/// character and byte count are provided for correct indexing.
#[derive(Debug, Default, PartialEq, Eq)]
pub struct StrCount {
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index e92c0c7..93dec11 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -326,7 +326,7 @@ pub fn range(self, end: &Self, limits: ast::RangeLimits) -> Sugg<'static> {
/// `self` argument of a method call
/// (e.g., to build `bar.foo()` or `(1 + 2).foo()`).
#[must_use]
- pub fn maybe_par(self) -> Self {
+ pub fn maybe_paren(self) -> Self {
match self {
Sugg::NonParen(..) => self,
// `(x)` and `(x).y()` both don't need additional parens.
@@ -494,7 +494,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
/// operators have the same
/// precedence.
pub fn make_unop(op: &str, expr: Sugg<'_>) -> Sugg<'static> {
- Sugg::MaybeParen(format!("{op}{}", expr.maybe_par()).into())
+ Sugg::MaybeParen(format!("{op}{}", expr.maybe_paren()).into())
}
/// Builds the string for `<lhs> <op> <rhs>` adding parenthesis when necessary.
@@ -946,10 +946,9 @@ fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, _: ty::BorrowKind) {
// some items do not need explicit deref, such as array accesses,
// so we mark them as already processed
// i.e.: don't suggest `*sub[1..4].len()` for `|sub| sub[1..4].len() == 3`
- if let ty::Ref(_, inner, _) = cmt.place.ty_before_projection(i).kind() {
- if matches!(inner.kind(), ty::Ref(_, innermost, _) if innermost.is_array()) {
- projections_handled = true;
- }
+ if let ty::Ref(_, inner, _) = cmt.place.ty_before_projection(i).kind()
+ && matches!(inner.kind(), ty::Ref(_, innermost, _) if innermost.is_array()) {
+ projections_handled = true;
}
},
}
@@ -1008,12 +1007,12 @@ fn blockify_transforms_sugg_into_a_block() {
}
#[test]
- fn binop_maybe_par() {
+ fn binop_maybe_paren() {
let sugg = Sugg::BinOp(AssocOp::Binary(ast::BinOpKind::Add), "1".into(), "1".into());
- assert_eq!("(1 + 1)", sugg.maybe_par().to_string());
+ assert_eq!("(1 + 1)", sugg.maybe_paren().to_string());
let sugg = Sugg::BinOp(AssocOp::Binary(ast::BinOpKind::Add), "(1 + 1)".into(), "(1 + 1)".into());
- assert_eq!("((1 + 1) + (1 + 1))", sugg.maybe_par().to_string());
+ assert_eq!("((1 + 1) + (1 + 1))", sugg.maybe_paren().to_string());
}
#[test]
fn not_op() {
diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs
index 9cc72a5..1a30b47 100644
--- a/src/tools/clippy/clippy_utils/src/sym.rs
+++ b/src/tools/clippy/clippy_utils/src/sym.rs
@@ -1,23 +1,69 @@
#![allow(non_upper_case_globals)]
-use rustc_span::symbol::{Symbol, PREDEFINED_SYMBOLS_COUNT};
+use rustc_span::symbol::{PREDEFINED_SYMBOLS_COUNT, Symbol};
+#[doc(no_inline)]
pub use rustc_span::sym::*;
+macro_rules! val {
+ ($name:ident) => {
+ stringify!($name)
+ };
+ ($name:ident $value:literal) => {
+ $value
+ };
+}
+
macro_rules! generate {
- ($($sym:ident,)*) => {
+ ($($name:ident $(: $value:literal)? ,)*) => {
/// To be supplied to `rustc_interface::Config`
pub const EXTRA_SYMBOLS: &[&str] = &[
- $(stringify!($sym),)*
+ $(
+ val!($name $($value)?),
+ )*
];
$(
- pub const $sym: Symbol = Symbol::new(PREDEFINED_SYMBOLS_COUNT + ${index()});
+ pub const $name: Symbol = Symbol::new(PREDEFINED_SYMBOLS_COUNT + ${index()});
)*
};
}
generate! {
+ as_bytes,
+ as_deref_mut,
+ as_deref,
+ as_mut,
+ Binary,
+ Cargo_toml: "Cargo.toml",
+ CLIPPY_ARGS,
+ CLIPPY_CONF_DIR,
+ cloned,
+ contains,
+ copied,
+ Current,
+ get,
+ insert,
+ int_roundings,
+ IntoIter,
+ is_empty,
+ is_ok,
+ is_some,
+ LowerExp,
+ LowerHex,
+ msrv,
+ Octal,
+ or_default,
+ regex,
rustfmt_skip,
+ Start,
+ to_owned,
unused_extern_crates,
+ unwrap_err,
+ unwrap_or_default,
+ UpperExp,
+ UpperHex,
+ V4,
+ V6,
+ Weak,
}
diff --git a/src/tools/clippy/clippy_utils/src/sym_helper.rs b/src/tools/clippy/clippy_utils/src/sym_helper.rs
deleted file mode 100644
index f47dc80..0000000
--- a/src/tools/clippy/clippy_utils/src/sym_helper.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#[macro_export]
-/// Convenience wrapper around rustc's `Symbol::intern`
-macro_rules! sym {
- ($tt:tt) => {
- rustc_span::symbol::Symbol::intern(stringify!($tt))
- };
-}
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index 29cbf62..8db9cd5 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -19,9 +19,9 @@
use rustc_middle::traits::EvaluationResult;
use rustc_middle::ty::layout::ValidityRequirement;
use rustc_middle::ty::{
- self, AdtDef, AliasTy, AssocItem, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind,
- GenericArgsRef, GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable,
- TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
+ self, AdtDef, AliasTy, AssocItem, AssocTag, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
+ GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable,
+ TypeVisitableExt, TypeVisitor, UintTy, Upcast, VariantDef, VariantDiscr,
};
use rustc_span::symbol::Ident;
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
@@ -128,10 +128,10 @@ fn contains_ty_adt_constructor_opaque_inner<'tcx>(
// For `impl Trait<Assoc=U>`, it will register a predicate of `<T as Trait>::Assoc = U`,
// so we check the term for `U`.
ty::ClauseKind::Projection(projection_predicate) => {
- if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack() {
- if contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen) {
- return true;
- }
+ if let ty::TermKind::Ty(ty) = projection_predicate.term.unpack()
+ && contains_ty_adt_constructor_opaque_inner(cx, ty, needle, seen)
+ {
+ return true;
}
},
_ => (),
@@ -156,7 +156,7 @@ fn contains_ty_adt_constructor_opaque_inner<'tcx>(
pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
cx.tcx
.get_diagnostic_item(sym::Iterator)
- .and_then(|iter_did| cx.get_associated_type(ty, iter_did, "Item"))
+ .and_then(|iter_did| cx.get_associated_type(ty, iter_did, sym::Item))
}
/// Get the diagnostic name of a type, e.g. `sym::HashMap`. To check if a type
@@ -337,20 +337,20 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
ty::Tuple(args) => args.iter().any(|ty| is_must_use_ty(cx, ty)),
ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => {
for (predicate, _) in cx.tcx.explicit_item_self_bounds(def_id).skip_binder() {
- if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() {
- if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) {
- return true;
- }
+ if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
+ && cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use)
+ {
+ return true;
}
}
false
},
ty::Dynamic(binder, _, _) => {
for predicate in *binder {
- if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() {
- if cx.tcx.has_attr(trait_ref.def_id, sym::must_use) {
- return true;
- }
+ if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
+ && cx.tcx.has_attr(trait_ref.def_id, sym::must_use)
+ {
+ return true;
}
}
false
@@ -1112,7 +1112,7 @@ fn helper<'tcx>(
let Some(assoc_item) = tcx.associated_items(container_id).find_by_ident_and_kind(
tcx,
Ident::with_dummy_span(assoc_ty),
- AssocKind::Type,
+ AssocTag::Type,
container_id,
) else {
debug_assert!(false, "type `{assoc_ty}` not found in `{container_id:?}`");
@@ -1345,14 +1345,14 @@ pub fn get_adt_inherent_method<'a>(cx: &'a LateContext<'_>, ty: Ty<'_>, method_n
.associated_items(did)
.filter_by_name_unhygienic(method_name)
.next()
- .filter(|item| item.kind == AssocKind::Fn)
+ .filter(|item| item.as_tag() == AssocTag::Fn)
})
} else {
None
}
}
-/// Get's the type of a field by name.
+/// Gets the type of a field by name.
pub fn get_field_by_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, name: Symbol) -> Option<Ty<'tcx>> {
match *ty.kind() {
ty::Adt(def, args) if def.is_union() || def.is_struct() => def
@@ -1376,3 +1376,49 @@ pub fn option_arg_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'t
_ => None,
}
}
+
+/// Check if a Ty<'_> of `Iterator` contains any mutable access to non-owning types by checking if
+/// it contains fields of mutable references or pointers, or references/pointers to non-`Freeze`
+/// types, or `PhantomData` types containing any of the previous. This can be used to check whether
+/// skipping iterating over an iterator will change its behavior.
+pub fn has_non_owning_mutable_access<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>) -> bool {
+ fn normalize_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+ cx.tcx.try_normalize_erasing_regions(cx.typing_env(), ty).unwrap_or(ty)
+ }
+
+ /// Check if `ty` contains mutable references or equivalent, which includes:
+ /// - A mutable reference/pointer.
+ /// - A reference/pointer to a non-`Freeze` type.
+ /// - A `PhantomData` type containing any of the previous.
+ fn has_non_owning_mutable_access_inner<'tcx>(
+ cx: &LateContext<'tcx>,
+ phantoms: &mut FxHashSet<Ty<'tcx>>,
+ ty: Ty<'tcx>,
+ ) -> bool {
+ match ty.kind() {
+ ty::Adt(adt_def, args) if adt_def.is_phantom_data() => {
+ phantoms.insert(ty)
+ && args
+ .types()
+ .any(|arg_ty| has_non_owning_mutable_access_inner(cx, phantoms, arg_ty))
+ },
+ ty::Adt(adt_def, args) => adt_def.all_fields().any(|field| {
+ has_non_owning_mutable_access_inner(cx, phantoms, normalize_ty(cx, field.ty(cx.tcx, args)))
+ }),
+ ty::Array(elem_ty, _) | ty::Slice(elem_ty) => has_non_owning_mutable_access_inner(cx, phantoms, *elem_ty),
+ ty::RawPtr(pointee_ty, mutability) | ty::Ref(_, pointee_ty, mutability) => {
+ mutability.is_mut() || !pointee_ty.is_freeze(cx.tcx, cx.typing_env())
+ },
+ ty::Closure(_, closure_args) => {
+ matches!(closure_args.types().next_back(), Some(captures) if has_non_owning_mutable_access_inner(cx, phantoms, captures))
+ },
+ ty::Tuple(tuple_args) => tuple_args
+ .iter()
+ .any(|arg_ty| has_non_owning_mutable_access_inner(cx, phantoms, arg_ty)),
+ _ => false,
+ }
+ }
+
+ let mut phantoms = FxHashSet::default();
+ has_non_owning_mutable_access_inner(cx, &mut phantoms, iter_ty)
+}
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index a079fd9..1b049b6 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -126,10 +126,10 @@ impl<'tcx> Visitor<'tcx> for BindingUsageFinder<'_, 'tcx> {
type NestedFilter = nested_filter::OnlyBodies;
fn visit_path(&mut self, path: &hir::Path<'tcx>, _: HirId) -> Self::Result {
- if let Res::Local(id) = path.res {
- if self.binding_ids.contains(&id) {
- return ControlFlow::Break(());
- }
+ if let Res::Local(id) = path.res
+ && self.binding_ids.contains(&id)
+ {
+ return ControlFlow::Break(());
}
ControlFlow::Continue(())
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 63dd00f..fc6e30a 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -297,10 +297,10 @@ fn visit_expr(&mut self, expr: &'hir Expr<'_>) {
/// Checks if the given resolved path is used in the given body.
pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool {
for_each_expr(cx, cx.tcx.hir_body(body).value, |e| {
- if let ExprKind::Path(p) = &e.kind {
- if cx.qpath_res(p, e.hir_id) == res {
- return ControlFlow::Break(());
- }
+ if let ExprKind::Path(p) = &e.kind
+ && cx.qpath_res(p, e.hir_id) == res
+ {
+ return ControlFlow::Break(());
}
ControlFlow::Continue(())
})
diff --git a/src/tools/clippy/lintcheck/ci-config/clippy.toml b/src/tools/clippy/lintcheck/ci-config/clippy.toml
new file mode 100644
index 0000000..9853465
--- /dev/null
+++ b/src/tools/clippy/lintcheck/ci-config/clippy.toml
@@ -0,0 +1,7 @@
+# Configuration applied when running lintcheck from the CI
+#
+# The CI will set the `CLIPPY_CONF_DIR` environment variable
+# to `$PWD/lintcheck/ci-config`.
+
+avoid-breaking-exported-api = false
+lint-commented-code = false
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index 8d0d41a..fe488ef 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -120,14 +120,17 @@ fn run_clippy_lints(
if config.perf {
cmd = Command::new("perf");
+ let perf_data_filename = get_perf_data_filename(&self.path);
cmd.args(&[
"record",
"-e",
"instructions", // Only count instructions
"-g", // Enable call-graph, useful for flamegraphs and produces richer reports
"--quiet", // Do not tamper with lintcheck's normal output
+ "--compression-level=22",
+ "--freq=3000", // Slow down program to capture all events
"-o",
- "perf.data",
+ &perf_data_filename,
"--",
"cargo",
]);
@@ -165,7 +168,7 @@ fn run_clippy_lints(
return Vec::new();
}
- if !config.fix {
+ if !config.fix && !config.perf {
cmd.arg("--message-format=json");
}
@@ -203,6 +206,11 @@ fn run_clippy_lints(
return Vec::new();
}
+ // We don't want to keep target directories if benchmarking
+ if config.perf {
+ let _ = fs::remove_dir_all(&shared_target_dir);
+ }
+
// get all clippy warnings and ICEs
let mut entries: Vec<ClippyCheckOutput> = Message::parse_stream(stdout.as_bytes())
.filter_map(|msg| match msg {
@@ -441,6 +449,35 @@ fn lintcheck(config: LintcheckConfig) {
fs::write(&config.lintcheck_results_path, text).unwrap();
}
+/// Traverse a directory looking for `perf.data.<number>` files, and adds one
+/// to the most recent of those files, returning the new most recent `perf.data`
+/// file name.
+fn get_perf_data_filename(source_path: &Path) -> String {
+ if source_path.join("perf.data").exists() {
+ let mut max_number = 0;
+ fs::read_dir(source_path)
+ .unwrap()
+ .filter_map(Result::ok)
+ .filter(|path| {
+ path.file_name()
+ .as_os_str()
+ .to_string_lossy() // We don't care about data loss, as we're checking for equality
+ .starts_with("perf.data")
+ })
+ .for_each(|path| {
+ let file_name = path.file_name();
+ let file_name = file_name.as_os_str().to_str().unwrap().split('.').next_back().unwrap();
+ if let Ok(parsed_file_name) = file_name.parse::<usize>()
+ && parsed_file_name >= max_number
+ {
+ max_number = parsed_file_name + 1;
+ }
+ });
+ return format!("perf.data.{max_number}");
+ }
+ String::from("perf.data")
+}
+
/// Returns the path to the Clippy project directory
#[must_use]
fn clippy_project_root() -> &'static Path {
diff --git a/src/tools/clippy/lintcheck/src/recursive.rs b/src/tools/clippy/lintcheck/src/recursive.rs
index 57073f5..6406b2d 100644
--- a/src/tools/clippy/lintcheck/src/recursive.rs
+++ b/src/tools/clippy/lintcheck/src/recursive.rs
@@ -64,7 +64,7 @@ fn process_stream(
// It's 99% likely that dependencies compiled with recursive mode are on crates.io
// and therefore on docs.rs. This links to the sources directly, do avoid invalid
- // links due to remaped paths. See rust-lang/docs.rs#2551 for more details.
+ // links due to remapped paths. See rust-lang/docs.rs#2551 for more details.
let base_url = format!(
"https://docs.rs/crate/{}/{}/source/src/{{file}}#{{line}}",
driver_info.package_name, driver_info.version
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain.toml
similarity index 85%
rename from src/tools/clippy/rust-toolchain
rename to src/tools/clippy/rust-toolchain.toml
index fcaeedc..d2f79da 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain.toml
@@ -1,6 +1,6 @@
[toolchain]
# begin autogenerated nightly
-channel = "nightly-2025-03-20"
+channel = "nightly-2025-04-22"
# end autogenerated nightly
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
profile = "minimal"
diff --git a/src/tools/clippy/rustc_tools_util/src/lib.rs b/src/tools/clippy/rustc_tools_util/src/lib.rs
index 423154a..b45edf2 100644
--- a/src/tools/clippy/rustc_tools_util/src/lib.rs
+++ b/src/tools/clippy/rustc_tools_util/src/lib.rs
@@ -121,7 +121,7 @@ fn get_output(cmd: &str, args: &[&str]) -> Option<String> {
pub fn rerun_if_git_changes() -> Option<()> {
// Make sure we get rerun when the git commit changes.
// We want to watch two files: HEAD, which tracks which branch we are on,
- // and the file for that branch that tracks which commit is is on.
+ // and the file for that branch that tracks which commit is checked out.
// First, find the `HEAD` file. This should work even with worktrees.
let git_head_file = PathBuf::from(get_output("git", &["rev-parse", "--git-path", "HEAD"])?);
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index df9c4e8e..87ca9c5 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -14,6 +14,7 @@
extern crate rustc_session;
extern crate rustc_span;
+use clippy_utils::sym;
use rustc_interface::interface;
use rustc_session::EarlyDiagCtxt;
use rustc_session::config::ErrorOutputType;
@@ -78,7 +79,7 @@ fn track_clippy_args(psess: &mut ParseSess, args_env_var: Option<&str>) {
psess
.env_depinfo
.get_mut()
- .insert((Symbol::intern("CLIPPY_ARGS"), args_env_var.map(Symbol::intern)));
+ .insert((sym::CLIPPY_ARGS, args_env_var.map(Symbol::intern)));
}
/// Track files that may be accessed at runtime in `file_depinfo` so that cargo will re-run clippy
@@ -89,7 +90,7 @@ fn track_files(psess: &mut ParseSess) {
// Used by `clippy::cargo` lints and to determine the MSRV. `cargo clippy` executes `clippy-driver`
// with the current directory set to `CARGO_MANIFEST_DIR` so a relative path is fine
if Path::new("Cargo.toml").exists() {
- file_depinfo.insert(Symbol::intern("Cargo.toml"));
+ file_depinfo.insert(sym::Cargo_toml);
}
// `clippy.toml` will be automatically tracked as it's loaded with `sess.source_map().load_file()`
@@ -145,7 +146,7 @@ fn config(&mut self, config: &mut interface::Config) {
// Trigger a rebuild if CLIPPY_CONF_DIR changes. The value must be a valid string so
// changes between dirs that are invalid UTF-8 will not trigger rebuilds
psess.env_depinfo.get_mut().insert((
- Symbol::intern("CLIPPY_CONF_DIR"),
+ sym::CLIPPY_CONF_DIR,
env::var("CLIPPY_CONF_DIR").ok().map(|dir| Symbol::intern(&dir)),
));
}));
@@ -158,9 +159,10 @@ fn config(&mut self, config: &mut interface::Config) {
let conf = clippy_config::Conf::read(sess, &conf_path);
clippy_lints::register_lints(lint_store, conf);
- clippy_lints::register_pre_expansion_lints(lint_store, conf);
+ #[cfg(feature = "internal")]
+ clippy_lints_internal::register_lints(lint_store);
}));
- config.extra_symbols = clippy_utils::sym::EXTRA_SYMBOLS.into();
+ config.extra_symbols = sym::EXTRA_SYMBOLS.into();
// FIXME: #4825; This is required, because Clippy lints that are based on MIR have to be
// run on the unoptimized MIR. On the other hand this results in some false negatives. If
@@ -208,12 +210,12 @@ pub fn main() {
// Beside checking for existence of `--sysroot` on the command line, we need to
// check for the arg files that are prefixed with @ as well to be consistent with rustc
for arg in args.iter() {
- if let Some(arg_file_path) = arg.strip_prefix('@') {
- if let Ok(arg_file) = read_to_string(arg_file_path) {
- let split_arg_file: Vec<String> = arg_file.lines().map(ToString::to_string).collect();
- if has_arg(&split_arg_file, "--sysroot") {
- return true;
- }
+ if let Some(arg_file_path) = arg.strip_prefix('@')
+ && let Ok(arg_file) = read_to_string(arg_file_path)
+ {
+ let split_arg_file: Vec<String> = arg_file.lines().map(ToString::to_string).collect();
+ if has_arg(&split_arg_file, "--sysroot") {
+ return true;
}
}
}
@@ -222,10 +224,10 @@ pub fn main() {
let sys_root_env = std::env::var("SYSROOT").ok();
let pass_sysroot_env_if_given = |args: &mut Vec<String>, sys_root_env| {
- if let Some(sys_root) = sys_root_env {
- if !has_sysroot_arg(args) {
- args.extend(vec!["--sysroot".into(), sys_root]);
- }
+ if let Some(sys_root) = sys_root_env
+ && !has_sysroot_arg(args)
+ {
+ args.extend(vec!["--sysroot".into(), sys_root]);
}
};
diff --git a/src/tools/clippy/tests/clippy.toml b/src/tools/clippy/tests/clippy.toml
index 5eb7ac0..91a2e55 100644
--- a/src/tools/clippy/tests/clippy.toml
+++ b/src/tools/clippy/tests/clippy.toml
@@ -1 +1,2 @@
# default config for tests, overrides clippy.toml at the project root
+lint-commented-code = false
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index 956a0528..6d391bd 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -2,6 +2,8 @@
#![warn(rust_2018_idioms, unused_lifetimes)]
#![allow(unused_extern_crates)]
+use askama::Template;
+use askama::filters::Safe;
use cargo_metadata::Message;
use cargo_metadata::diagnostic::{Applicability, Diagnostic};
use clippy_config::ClippyConfiguration;
@@ -9,11 +11,10 @@
use clippy_lints::declared_lints::LINTS;
use clippy_lints::deprecated_lints::{DEPRECATED, DEPRECATED_VERSION, RENAMED};
use pulldown_cmark::{Options, Parser, html};
-use rinja::Template;
-use rinja::filters::Safe;
use serde::Deserialize;
use test_utils::IS_RUSTC_TEST_SUITE;
use ui_test::custom_flags::Flag;
+use ui_test::custom_flags::edition::Edition;
use ui_test::custom_flags::rustfix::RustfixMode;
use ui_test::spanned::Spanned;
use ui_test::{Args, CommandBuilder, Config, Match, error_on_output_conflict, status_emitter};
@@ -86,13 +87,13 @@ fn extern_flags() -> Vec<String> {
let name = name.strip_prefix("lib").unwrap_or(name);
Some((name, path_str))
};
- if let Some((name, path)) = parse_name_path() {
- if TEST_DEPENDENCIES.contains(&name) {
- // A dependency may be listed twice if it is available in sysroot,
- // and the sysroot dependencies are listed first. As of the writing,
- // this only seems to apply to if_chain.
- crates.insert(name, path);
- }
+ if let Some((name, path)) = parse_name_path()
+ && TEST_DEPENDENCIES.contains(&name)
+ {
+ // A dependency may be listed twice if it is available in sysroot,
+ // and the sysroot dependencies are listed first. As of the writing,
+ // this only seems to apply to if_chain.
+ crates.insert(name, path);
}
}
let not_found: Vec<&str> = TEST_DEPENDENCIES
@@ -147,11 +148,16 @@ fn base_config(&self, test_dir: &str, mandatory_annotations: bool) -> Config {
.map(|filters| filters.split(',').map(str::to_string).collect())
.unwrap_or_default(),
target: None,
- bless_command: Some("cargo uibless".into()),
+ bless_command: Some(if IS_RUSTC_TEST_SUITE {
+ "./x test src/tools/clippy --bless".into()
+ } else {
+ "cargo uibless".into()
+ }),
out_dir: target_dir.join("ui_test"),
..Config::rustc(Path::new("tests").join(test_dir))
};
let defaults = config.comment_defaults.base();
+ defaults.set_custom("edition", Edition("2024".into()));
defaults.exit_status = None.into();
if mandatory_annotations {
defaults.require_annotations = Some(Spanned::dummy(true)).into();
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index 858be38..16a1a415 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -36,6 +36,7 @@ fn dogfood() {
for package in [
"./",
"clippy_dev",
+ "clippy_lints_internal",
"clippy_lints",
"clippy_utils",
"clippy_config",
@@ -80,11 +81,9 @@ fn run_clippy_for_package(project: &str, args: &[&str]) -> bool {
command.arg("--").args(args);
command.arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir
+ command.args(["-D", "clippy::dbg_macro"]);
- if cfg!(feature = "internal") {
- // internal lints only exist if we build with the internal feature
- command.args(["-D", "clippy::internal"]);
- } else {
+ if !cfg!(feature = "internal") {
// running a clippy built without internal lints on the clippy source
// that contains e.g. `allow(clippy::invalid_paths)`
command.args(["-A", "unknown_lints"]);
diff --git a/src/tools/clippy/tests/ui-internal/auxiliary/paths.rs b/src/tools/clippy/tests/ui-internal/auxiliary/paths.rs
index 52fcaec..f730f56 100644
--- a/src/tools/clippy/tests/ui-internal/auxiliary/paths.rs
+++ b/src/tools/clippy/tests/ui-internal/auxiliary/paths.rs
@@ -1,2 +1,4 @@
+#![allow(clippy::unnecessary_def_path)]
+
pub static OPTION: [&str; 3] = ["core", "option", "Option"];
pub const RESULT: &[&str] = &["core", "result", "Result"];
diff --git a/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.rs b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.rs
index e5f6001..8970029 100644
--- a/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.rs
+++ b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.rs
@@ -1,5 +1,5 @@
-#![deny(clippy::internal)]
#![feature(rustc_private)]
+#![deny(clippy::invalid_clippy_version_attribute, clippy::missing_clippy_version_attribute)]
#[macro_use]
extern crate rustc_middle;
@@ -86,6 +86,15 @@ mod internal_clippy_lints {
}
use crate::internal_clippy_lints::ALLOW_MISSING_ATTRIBUTE_ONE;
-declare_lint_pass!(Pass2 => [VALID_ONE, VALID_TWO, VALID_THREE, INVALID_ONE, INVALID_TWO, MISSING_ATTRIBUTE_ONE, MISSING_ATTRIBUTE_TWO, ALLOW_MISSING_ATTRIBUTE_ONE]);
+declare_lint_pass!(Pass2 => [
+ VALID_ONE,
+ VALID_TWO,
+ VALID_THREE,
+ INVALID_ONE,
+ INVALID_TWO,
+ MISSING_ATTRIBUTE_ONE,
+ MISSING_ATTRIBUTE_TWO,
+ ALLOW_MISSING_ATTRIBUTE_ONE,
+]);
fn main() {}
diff --git a/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr
index 1129c35..952bc94 100644
--- a/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr
+++ b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr
@@ -12,11 +12,10 @@
|
= help: please use a valid semantic version, see `doc/adding_lints.md`
note: the lint level is defined here
- --> tests/ui-internal/check_clippy_version_attribute.rs:1:9
+ --> tests/ui-internal/check_clippy_version_attribute.rs:2:9
|
-LL | #![deny(clippy::internal)]
- | ^^^^^^^^^^^^^^^^
- = note: `#[deny(clippy::invalid_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]`
+LL | #![deny(clippy::invalid_clippy_version_attribute, clippy::missing_clippy_version_attribute)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this item has an invalid `clippy::version` attribute
@@ -47,7 +46,11 @@
| |_^
|
= help: please use a `clippy::version` attribute, see `doc/adding_lints.md`
- = note: `#[deny(clippy::missing_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]`
+note: the lint level is defined here
+ --> tests/ui-internal/check_clippy_version_attribute.rs:2:51
+ |
+LL | #![deny(clippy::invalid_clippy_version_attribute, clippy::missing_clippy_version_attribute)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this lint is missing the `clippy::version` attribute or version value
diff --git a/src/tools/clippy/tests/ui-internal/check_formulation.rs b/src/tools/clippy/tests/ui-internal/check_formulation.rs
index 8265a78..bcbb0d7 100644
--- a/src/tools/clippy/tests/ui-internal/check_formulation.rs
+++ b/src/tools/clippy/tests/ui-internal/check_formulation.rs
@@ -1,4 +1,5 @@
-#![warn(clippy::almost_standard_lint_formulation)]
+#![deny(clippy::almost_standard_lint_formulation)]
+#![allow(clippy::lint_without_lint_pass)]
#![feature(rustc_private)]
#[macro_use]
diff --git a/src/tools/clippy/tests/ui-internal/check_formulation.stderr b/src/tools/clippy/tests/ui-internal/check_formulation.stderr
index b16e1bf..9aeb9e1 100644
--- a/src/tools/clippy/tests/ui-internal/check_formulation.stderr
+++ b/src/tools/clippy/tests/ui-internal/check_formulation.stderr
@@ -1,15 +1,18 @@
error: non-standard lint formulation
- --> tests/ui-internal/check_formulation.rs:23:5
+ --> tests/ui-internal/check_formulation.rs:24:5
|
LL | /// Check for lint formulations that are correct
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: consider using `Checks for`
- = note: `-D clippy::almost-standard-lint-formulation` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::almost_standard_lint_formulation)]`
+note: the lint level is defined here
+ --> tests/ui-internal/check_formulation.rs:1:9
+ |
+LL | #![deny(clippy::almost_standard_lint_formulation)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: non-standard lint formulation
- --> tests/ui-internal/check_formulation.rs:34:5
+ --> tests/ui-internal/check_formulation.rs:35:5
|
LL | /// Detects uses of incorrect formulations
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed
index 918e333..76f6868 100644
--- a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed
+++ b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed
@@ -1,4 +1,4 @@
-#![deny(clippy::internal)]
+#![deny(clippy::collapsible_span_lint_calls)]
#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
diff --git a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs
index 2f289ae..214c878 100644
--- a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs
+++ b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs
@@ -1,4 +1,4 @@
-#![deny(clippy::internal)]
+#![deny(clippy::collapsible_span_lint_calls)]
#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
diff --git a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.stderr b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.stderr
index a2be1f1..9c83538 100644
--- a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.stderr
+++ b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.stderr
@@ -10,9 +10,8 @@
note: the lint level is defined here
--> tests/ui-internal/collapsible_span_lint_calls.rs:1:9
|
-LL | #![deny(clippy::internal)]
- | ^^^^^^^^^^^^^^^^
- = note: `#[deny(clippy::collapsible_span_lint_calls)]` implied by `#[deny(clippy::internal)]`
+LL | #![deny(clippy::collapsible_span_lint_calls)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this call is collapsible
--> tests/ui-internal/collapsible_span_lint_calls.rs:39:9
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs
index 71819fe..c7e92b1 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs
@@ -6,7 +6,7 @@
//@normalize-stderr-test: "rustc 1\.\d+.* running on .*" -> "rustc <version> running on <target>"
//@normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> ""
-#![deny(clippy::internal)]
+#![deny(clippy::produce_ice)]
#![allow(clippy::missing_clippy_version_attribute)]
fn it_looks_like_you_are_trying_to_kill_clippy() {}
diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
index 589e119..884d3d0 100644
--- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
+++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr
@@ -8,7 +8,7 @@
LL | fn it_looks_like_you_are_trying_to_kill_clippy() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: delayed at clippy_lints/src/utils/internal_lints/produce_ice.rs - disabled backtrace
+note: delayed at clippy_lints_internal/src/produce_ice.rs - disabled backtrace
--> tests/ui-internal/custom_ice_message.rs:12:1
|
LL | fn it_looks_like_you_are_trying_to_kill_clippy() {}
diff --git a/src/tools/clippy/tests/ui-internal/default_lint.rs b/src/tools/clippy/tests/ui-internal/default_lint.rs
index 959bfd2..809f2c4 100644
--- a/src/tools/clippy/tests/ui-internal/default_lint.rs
+++ b/src/tools/clippy/tests/ui-internal/default_lint.rs
@@ -1,4 +1,4 @@
-#![deny(clippy::internal)]
+#![deny(clippy::default_lint)]
#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
diff --git a/src/tools/clippy/tests/ui-internal/default_lint.stderr b/src/tools/clippy/tests/ui-internal/default_lint.stderr
index 9d4c2e1..2c700ec 100644
--- a/src/tools/clippy/tests/ui-internal/default_lint.stderr
+++ b/src/tools/clippy/tests/ui-internal/default_lint.stderr
@@ -13,9 +13,8 @@
note: the lint level is defined here
--> tests/ui-internal/default_lint.rs:1:9
|
-LL | #![deny(clippy::internal)]
- | ^^^^^^^^^^^^^^^^
- = note: `#[deny(clippy::default_lint)]` implied by `#[deny(clippy::internal)]`
+LL | #![deny(clippy::default_lint)]
+ | ^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 1 previous error
diff --git a/src/tools/clippy/tests/ui-internal/disallow_span_lint.rs b/src/tools/clippy/tests/ui-internal/disallow_span_lint.rs
index 3fed38c..36e4158 100644
--- a/src/tools/clippy/tests/ui-internal/disallow_span_lint.rs
+++ b/src/tools/clippy/tests/ui-internal/disallow_span_lint.rs
@@ -1,4 +1,5 @@
#![feature(rustc_private)]
+#![deny(clippy::disallowed_methods)]
extern crate rustc_errors;
extern crate rustc_hir;
diff --git a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
index 9a7a7ec..f03a745 100644
--- a/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
+++ b/src/tools/clippy/tests/ui-internal/disallow_span_lint.stderr
@@ -1,15 +1,18 @@
error: use of a disallowed method `rustc_lint::context::LintContext::span_lint`
- --> tests/ui-internal/disallow_span_lint.rs:14:8
+ --> tests/ui-internal/disallow_span_lint.rs:15:8
|
LL | cx.span_lint(lint, span, |lint| {
| ^^^^^^^^^
|
= note: this function does not add a link to our documentation, please use the `clippy_utils::diagnostics::span_lint*` functions instead
- = note: `-D clippy::disallowed-methods` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::disallowed_methods)]`
+note: the lint level is defined here
+ --> tests/ui-internal/disallow_span_lint.rs:2:9
+ |
+LL | #![deny(clippy::disallowed_methods)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of a disallowed method `rustc_middle::ty::context::TyCtxt::node_span_lint`
- --> tests/ui-internal/disallow_span_lint.rs:21:9
+ --> tests/ui-internal/disallow_span_lint.rs:22:9
|
LL | tcx.node_span_lint(lint, hir_id, span, |lint| {
| ^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed
deleted file mode 100644
index 92d3b15..0000000
--- a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed
+++ /dev/null
@@ -1,40 +0,0 @@
-#![deny(clippy::internal)]
-#![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)]
-#![feature(rustc_private)]
-
-extern crate rustc_span;
-
-use rustc_span::symbol::Symbol;
-
-macro_rules! sym {
- ($tt:tt) => {
- rustc_span::symbol::Symbol::intern(stringify!($tt))
- };
-}
-
-fn main() {
- // Direct use of Symbol::intern
- let _ = rustc_span::sym::f32;
- //~^ interning_defined_symbol
-
- // Using a sym macro
- let _ = rustc_span::sym::f32;
- //~^ interning_defined_symbol
-
- // Correct suggestion when symbol isn't stringified constant name
- let _ = rustc_span::sym::proc_dash_macro;
- //~^ interning_defined_symbol
-
- // interning a keyword
- let _ = rustc_span::kw::SelfLower;
- //~^ interning_defined_symbol
-
- // Interning a symbol that is not defined
- let _ = Symbol::intern("xyz123");
- let _ = sym!(xyz123);
-
- // Using a different `intern` function
- let _ = intern("f32");
-}
-
-fn intern(_: &str) {}
diff --git a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs
deleted file mode 100644
index d1e6f9c..0000000
--- a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-#![deny(clippy::internal)]
-#![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)]
-#![feature(rustc_private)]
-
-extern crate rustc_span;
-
-use rustc_span::symbol::Symbol;
-
-macro_rules! sym {
- ($tt:tt) => {
- rustc_span::symbol::Symbol::intern(stringify!($tt))
- };
-}
-
-fn main() {
- // Direct use of Symbol::intern
- let _ = Symbol::intern("f32");
- //~^ interning_defined_symbol
-
- // Using a sym macro
- let _ = sym!(f32);
- //~^ interning_defined_symbol
-
- // Correct suggestion when symbol isn't stringified constant name
- let _ = Symbol::intern("proc-macro");
- //~^ interning_defined_symbol
-
- // interning a keyword
- let _ = Symbol::intern("self");
- //~^ interning_defined_symbol
-
- // Interning a symbol that is not defined
- let _ = Symbol::intern("xyz123");
- let _ = sym!(xyz123);
-
- // Using a different `intern` function
- let _ = intern("f32");
-}
-
-fn intern(_: &str) {}
diff --git a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.stderr b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.stderr
deleted file mode 100644
index c84a566..0000000
--- a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.stderr
+++ /dev/null
@@ -1,33 +0,0 @@
-error: interning a defined symbol
- --> tests/ui-internal/interning_defined_symbol.rs:17:13
- |
-LL | let _ = Symbol::intern("f32");
- | ^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::f32`
- |
-note: the lint level is defined here
- --> tests/ui-internal/interning_defined_symbol.rs:1:9
- |
-LL | #![deny(clippy::internal)]
- | ^^^^^^^^^^^^^^^^
- = note: `#[deny(clippy::interning_defined_symbol)]` implied by `#[deny(clippy::internal)]`
-
-error: interning a defined symbol
- --> tests/ui-internal/interning_defined_symbol.rs:21:13
- |
-LL | let _ = sym!(f32);
- | ^^^^^^^^^ help: try: `rustc_span::sym::f32`
-
-error: interning a defined symbol
- --> tests/ui-internal/interning_defined_symbol.rs:25:13
- |
-LL | let _ = Symbol::intern("proc-macro");
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::proc_dash_macro`
-
-error: interning a defined symbol
- --> tests/ui-internal/interning_defined_symbol.rs:29:13
- |
-LL | let _ = Symbol::intern("self");
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::kw::SelfLower`
-
-error: aborting due to 4 previous errors
-
diff --git a/src/tools/clippy/tests/ui-internal/interning_literals.fixed b/src/tools/clippy/tests/ui-internal/interning_literals.fixed
new file mode 100644
index 0000000..03e9776
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/interning_literals.fixed
@@ -0,0 +1,31 @@
+#![allow(clippy::let_unit_value)]
+#![feature(rustc_private)]
+
+extern crate rustc_span;
+
+use clippy_utils::sym;
+use rustc_span::{Symbol, kw};
+
+fn main() {
+ let _ = sym::f32;
+ //~^ interning_literals
+
+ // Correct suggestion when symbol isn't stringified constant name
+ let _ = sym::proc_dash_macro;
+ //~^ interning_literals
+
+ // Interning a keyword
+ let _ = kw::SelfLower;
+ //~^ interning_literals
+
+ // Defined in clippy_utils
+ let _ = sym::msrv;
+ //~^ interning_literals
+ let _ = sym::Cargo_toml;
+ //~^ interning_literals
+
+ // Using a different `intern` function
+ let _ = intern("f32");
+}
+
+fn intern(_: &str) {}
diff --git a/src/tools/clippy/tests/ui-internal/interning_literals.rs b/src/tools/clippy/tests/ui-internal/interning_literals.rs
new file mode 100644
index 0000000..561fd57
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/interning_literals.rs
@@ -0,0 +1,31 @@
+#![allow(clippy::let_unit_value)]
+#![feature(rustc_private)]
+
+extern crate rustc_span;
+
+use clippy_utils::sym;
+use rustc_span::{Symbol, kw};
+
+fn main() {
+ let _ = Symbol::intern("f32");
+ //~^ interning_literals
+
+ // Correct suggestion when symbol isn't stringified constant name
+ let _ = Symbol::intern("proc-macro");
+ //~^ interning_literals
+
+ // Interning a keyword
+ let _ = Symbol::intern("self");
+ //~^ interning_literals
+
+ // Defined in clippy_utils
+ let _ = Symbol::intern("msrv");
+ //~^ interning_literals
+ let _ = Symbol::intern("Cargo.toml");
+ //~^ interning_literals
+
+ // Using a different `intern` function
+ let _ = intern("f32");
+}
+
+fn intern(_: &str) {}
diff --git a/src/tools/clippy/tests/ui-internal/interning_literals.stderr b/src/tools/clippy/tests/ui-internal/interning_literals.stderr
new file mode 100644
index 0000000..628b97e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/interning_literals.stderr
@@ -0,0 +1,64 @@
+error: interning a string literal
+ --> tests/ui-internal/interning_literals.rs:10:13
+ |
+LL | let _ = Symbol::intern("f32");
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::interning-literals` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::interning_literals)]`
+help: use the preinterned symbol
+ |
+LL - let _ = Symbol::intern("f32");
+LL + let _ = sym::f32;
+ |
+
+error: interning a string literal
+ --> tests/ui-internal/interning_literals.rs:14:13
+ |
+LL | let _ = Symbol::intern("proc-macro");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: use the preinterned symbol
+ |
+LL - let _ = Symbol::intern("proc-macro");
+LL + let _ = sym::proc_dash_macro;
+ |
+
+error: interning a string literal
+ --> tests/ui-internal/interning_literals.rs:18:13
+ |
+LL | let _ = Symbol::intern("self");
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: use the preinterned symbol
+ |
+LL - let _ = Symbol::intern("self");
+LL + let _ = kw::SelfLower;
+ |
+
+error: interning a string literal
+ --> tests/ui-internal/interning_literals.rs:22:13
+ |
+LL | let _ = Symbol::intern("msrv");
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: use the preinterned symbol
+ |
+LL - let _ = Symbol::intern("msrv");
+LL + let _ = sym::msrv;
+ |
+
+error: interning a string literal
+ --> tests/ui-internal/interning_literals.rs:24:13
+ |
+LL | let _ = Symbol::intern("Cargo.toml");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: use the preinterned symbol
+ |
+LL - let _ = Symbol::intern("Cargo.toml");
+LL + let _ = sym::Cargo_toml;
+ |
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui-internal/interning_literals_unfixable.rs b/src/tools/clippy/tests/ui-internal/interning_literals_unfixable.rs
new file mode 100644
index 0000000..43872e9
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/interning_literals_unfixable.rs
@@ -0,0 +1,16 @@
+//@no-rustfix: paths that don't exist yet
+#![feature(rustc_private)]
+
+extern crate rustc_span;
+
+use rustc_span::Symbol;
+
+fn main() {
+ // Not yet defined
+ let _ = Symbol::intern("xyz123");
+ //~^ interning_literals
+ let _ = Symbol::intern("with-dash");
+ //~^ interning_literals
+ let _ = Symbol::intern("with.dot");
+ //~^ interning_literals
+}
diff --git a/src/tools/clippy/tests/ui-internal/interning_literals_unfixable.stderr b/src/tools/clippy/tests/ui-internal/interning_literals_unfixable.stderr
new file mode 100644
index 0000000..8294453
--- /dev/null
+++ b/src/tools/clippy/tests/ui-internal/interning_literals_unfixable.stderr
@@ -0,0 +1,40 @@
+error: interning a string literal
+ --> tests/ui-internal/interning_literals_unfixable.rs:10:13
+ |
+LL | let _ = Symbol::intern("xyz123");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::interning-literals` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::interning_literals)]`
+help: add the symbol to `clippy_utils/src/sym.rs` and use it
+ |
+LL - let _ = Symbol::intern("xyz123");
+LL + let _ = sym::xyz123;
+ |
+
+error: interning a string literal
+ --> tests/ui-internal/interning_literals_unfixable.rs:12:13
+ |
+LL | let _ = Symbol::intern("with-dash");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: add the symbol to `clippy_utils/src/sym.rs` and use it
+ |
+LL - let _ = Symbol::intern("with-dash");
+LL + let _ = sym::with_dash;
+ |
+
+error: interning a string literal
+ --> tests/ui-internal/interning_literals_unfixable.rs:14:13
+ |
+LL | let _ = Symbol::intern("with.dot");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: add the symbol to `clippy_utils/src/sym.rs` and use it
+ |
+LL - let _ = Symbol::intern("with.dot");
+LL + let _ = sym::with_dot;
+ |
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed
index 6804e2b..238ef9a 100644
--- a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed
+++ b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed
@@ -1,4 +1,4 @@
-#![deny(clippy::internal)]
+#![deny(clippy::missing_msrv_attr_impl)]
#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
diff --git a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs
index c625a5d..7753dca 100644
--- a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs
+++ b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs
@@ -1,4 +1,4 @@
-#![deny(clippy::internal)]
+#![deny(clippy::missing_msrv_attr_impl)]
#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
diff --git a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.stderr b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.stderr
index 0a76363..d5928d8 100644
--- a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.stderr
+++ b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.stderr
@@ -7,9 +7,8 @@
note: the lint level is defined here
--> tests/ui-internal/invalid_msrv_attr_impl.rs:1:9
|
-LL | #![deny(clippy::internal)]
- | ^^^^^^^^^^^^^^^^
- = note: `#[deny(clippy::missing_msrv_attr_impl)]` implied by `#[deny(clippy::internal)]`
+LL | #![deny(clippy::missing_msrv_attr_impl)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
help: add `extract_msrv_attr!()` to the `EarlyLintPass` implementation
|
LL ~ impl EarlyLintPass for Pass {
diff --git a/src/tools/clippy/tests/ui-internal/invalid_paths.rs b/src/tools/clippy/tests/ui-internal/invalid_paths.rs
index abfb111..7317abc 100644
--- a/src/tools/clippy/tests/ui-internal/invalid_paths.rs
+++ b/src/tools/clippy/tests/ui-internal/invalid_paths.rs
@@ -1,4 +1,4 @@
-#![warn(clippy::internal)]
+#![deny(clippy::invalid_paths)]
#![allow(clippy::missing_clippy_version_attribute, clippy::unnecessary_def_path)]
mod paths {
diff --git a/src/tools/clippy/tests/ui-internal/invalid_paths.stderr b/src/tools/clippy/tests/ui-internal/invalid_paths.stderr
index 7bde376..7b7b25c 100644
--- a/src/tools/clippy/tests/ui-internal/invalid_paths.stderr
+++ b/src/tools/clippy/tests/ui-internal/invalid_paths.stderr
@@ -4,8 +4,11 @@
LL | pub const TRANSMUTE: [&str; 4] = ["core", "intrinsics", "", "transmute"];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::invalid-paths` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::invalid_paths)]`
+note: the lint level is defined here
+ --> tests/ui-internal/invalid_paths.rs:1:9
+ |
+LL | #![deny(clippy::invalid_paths)]
+ | ^^^^^^^^^^^^^^^^^^^^^
error: invalid path
--> tests/ui-internal/invalid_paths.rs:19:5
diff --git a/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.rs b/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.rs
index 6959152..6b64913 100644
--- a/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.rs
+++ b/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.rs
@@ -1,4 +1,4 @@
-#![deny(clippy::internal)]
+#![deny(clippy::lint_without_lint_pass)]
#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
diff --git a/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.stderr b/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.stderr
index 9cca96c..3798293 100644
--- a/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.stderr
+++ b/src/tools/clippy/tests/ui-internal/lint_without_lint_pass.stderr
@@ -13,9 +13,8 @@
note: the lint level is defined here
--> tests/ui-internal/lint_without_lint_pass.rs:1:9
|
-LL | #![deny(clippy::internal)]
- | ^^^^^^^^^^^^^^^^
- = note: `#[deny(clippy::lint_without_lint_pass)]` implied by `#[deny(clippy::internal)]`
+LL | #![deny(clippy::lint_without_lint_pass)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: this error originates in the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 1 previous error
diff --git a/src/tools/clippy/tests/ui-internal/outer_expn_data.fixed b/src/tools/clippy/tests/ui-internal/outer_expn_data.fixed
index cb7680b..900ca5b 100644
--- a/src/tools/clippy/tests/ui-internal/outer_expn_data.fixed
+++ b/src/tools/clippy/tests/ui-internal/outer_expn_data.fixed
@@ -1,4 +1,4 @@
-#![deny(clippy::internal)]
+#![deny(clippy::outer_expn_expn_data)]
#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
diff --git a/src/tools/clippy/tests/ui-internal/outer_expn_data.rs b/src/tools/clippy/tests/ui-internal/outer_expn_data.rs
index 41d7351..bcfc42a 100644
--- a/src/tools/clippy/tests/ui-internal/outer_expn_data.rs
+++ b/src/tools/clippy/tests/ui-internal/outer_expn_data.rs
@@ -1,4 +1,4 @@
-#![deny(clippy::internal)]
+#![deny(clippy::outer_expn_expn_data)]
#![allow(clippy::missing_clippy_version_attribute)]
#![feature(rustc_private)]
diff --git a/src/tools/clippy/tests/ui-internal/outer_expn_data.stderr b/src/tools/clippy/tests/ui-internal/outer_expn_data.stderr
index 33ac91e..b86138a 100644
--- a/src/tools/clippy/tests/ui-internal/outer_expn_data.stderr
+++ b/src/tools/clippy/tests/ui-internal/outer_expn_data.stderr
@@ -7,9 +7,8 @@
note: the lint level is defined here
--> tests/ui-internal/outer_expn_data.rs:1:9
|
-LL | #![deny(clippy::internal)]
- | ^^^^^^^^^^^^^^^^
- = note: `#[deny(clippy::outer_expn_expn_data)]` implied by `#[deny(clippy::internal)]`
+LL | #![deny(clippy::outer_expn_expn_data)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
diff --git a/src/tools/clippy/tests/ui-internal/slow_symbol_comparisons.fixed b/src/tools/clippy/tests/ui-internal/slow_symbol_comparisons.fixed
deleted file mode 100644
index 2cbd646..0000000
--- a/src/tools/clippy/tests/ui-internal/slow_symbol_comparisons.fixed
+++ /dev/null
@@ -1,24 +0,0 @@
-#![feature(rustc_private)]
-#![warn(clippy::slow_symbol_comparisons)]
-
-extern crate rustc_span;
-
-use clippy_utils::sym;
-use rustc_span::Symbol;
-
-fn main() {
- let symbol = sym!(example);
- let other_symbol = sym!(other_example);
-
- // Should lint
- let slow_comparison = symbol.as_str() == "example";
- //~^ error: comparing `Symbol` via `Symbol::intern`
- let slow_comparison_macro = symbol.as_str() == "example";
- //~^ error: comparing `Symbol` via `Symbol::intern`
- let slow_comparison_backwards = symbol.as_str() == "example";
- //~^ error: comparing `Symbol` via `Symbol::intern`
-
- // Should not lint
- let faster_comparison = symbol.as_str() == "other_example";
- let preinterned_comparison = symbol == other_symbol;
-}
diff --git a/src/tools/clippy/tests/ui-internal/slow_symbol_comparisons.rs b/src/tools/clippy/tests/ui-internal/slow_symbol_comparisons.rs
deleted file mode 100644
index 0cea3c3..0000000
--- a/src/tools/clippy/tests/ui-internal/slow_symbol_comparisons.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-#![feature(rustc_private)]
-#![warn(clippy::slow_symbol_comparisons)]
-
-extern crate rustc_span;
-
-use clippy_utils::sym;
-use rustc_span::Symbol;
-
-fn main() {
- let symbol = sym!(example);
- let other_symbol = sym!(other_example);
-
- // Should lint
- let slow_comparison = symbol == Symbol::intern("example");
- //~^ error: comparing `Symbol` via `Symbol::intern`
- let slow_comparison_macro = symbol == sym!(example);
- //~^ error: comparing `Symbol` via `Symbol::intern`
- let slow_comparison_backwards = sym!(example) == symbol;
- //~^ error: comparing `Symbol` via `Symbol::intern`
-
- // Should not lint
- let faster_comparison = symbol.as_str() == "other_example";
- let preinterned_comparison = symbol == other_symbol;
-}
diff --git a/src/tools/clippy/tests/ui-internal/slow_symbol_comparisons.stderr b/src/tools/clippy/tests/ui-internal/slow_symbol_comparisons.stderr
deleted file mode 100644
index 72cb20a..0000000
--- a/src/tools/clippy/tests/ui-internal/slow_symbol_comparisons.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error: comparing `Symbol` via `Symbol::intern`
- --> tests/ui-internal/slow_symbol_comparisons.rs:14:27
- |
-LL | let slow_comparison = symbol == Symbol::intern("example");
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `Symbol::as_str` and check the string instead: `symbol.as_str() == "example"`
- |
- = note: `-D clippy::slow-symbol-comparisons` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::slow_symbol_comparisons)]`
-
-error: comparing `Symbol` via `Symbol::intern`
- --> tests/ui-internal/slow_symbol_comparisons.rs:16:33
- |
-LL | let slow_comparison_macro = symbol == sym!(example);
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `Symbol::as_str` and check the string instead: `symbol.as_str() == "example"`
-
-error: comparing `Symbol` via `Symbol::intern`
- --> tests/ui-internal/slow_symbol_comparisons.rs:18:37
- |
-LL | let slow_comparison_backwards = sym!(example) == symbol;
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: use `Symbol::as_str` and check the string instead: `symbol.as_str() == "example"`
-
-error: aborting due to 3 previous errors
-
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed
index 577fad9..89902eb 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed
@@ -1,5 +1,5 @@
//@aux-build:paths.rs
-#![deny(clippy::internal)]
+#![deny(clippy::unnecessary_def_path)]
#![feature(rustc_private)]
#![allow(clippy::unnecessary_map_or)]
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs
index d4deb36..cfca152 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs
@@ -1,5 +1,5 @@
//@aux-build:paths.rs
-#![deny(clippy::internal)]
+#![deny(clippy::unnecessary_def_path)]
#![feature(rustc_private)]
#![allow(clippy::unnecessary_map_or)]
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr
index 0053ba3..d7fb4ea 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr
@@ -7,9 +7,8 @@
note: the lint level is defined here
--> tests/ui-internal/unnecessary_def_path.rs:2:9
|
-LL | #![deny(clippy::internal)]
- | ^^^^^^^^^^^^^^^^
- = note: `#[deny(clippy::unnecessary_def_path)]` implied by `#[deny(clippy::internal)]`
+LL | #![deny(clippy::unnecessary_def_path)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: use of a def path to a diagnostic item
--> tests/ui-internal/unnecessary_def_path.rs:39:13
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
index 4801d76..bd7a551 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
@@ -1,6 +1,6 @@
#![feature(rustc_private)]
#![allow(unused)]
-#![warn(clippy::unnecessary_def_path)]
+#![deny(clippy::unnecessary_def_path)]
extern crate rustc_hir;
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
index b938395..88fdf6f 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
@@ -5,8 +5,11 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: convert all references to use `sym::Deref`
- = note: `-D clippy::unnecessary-def-path` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::unnecessary_def_path)]`
+note: the lint level is defined here
+ --> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:3:9
+ |
+LL | #![deny(clippy::unnecessary_def_path)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: hardcoded path to a language item
--> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:12:40
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed
deleted file mode 100644
index dc564da..0000000
--- a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed
+++ /dev/null
@@ -1,26 +0,0 @@
-#![feature(rustc_private)]
-#![deny(clippy::internal)]
-#![allow(
- clippy::slow_symbol_comparisons,
- clippy::borrow_deref_ref,
- clippy::unnecessary_operation,
- unused_must_use,
- clippy::missing_clippy_version_attribute
-)]
-
-extern crate rustc_span;
-
-use rustc_span::symbol::{Ident, Symbol};
-
-fn main() {
- Symbol::intern("foo") == rustc_span::sym::clippy;
- //~^ unnecessary_symbol_str
- Symbol::intern("foo") == rustc_span::kw::SelfLower;
- //~^ unnecessary_symbol_str
- Symbol::intern("foo") != rustc_span::kw::SelfUpper;
- //~^ unnecessary_symbol_str
- Ident::empty().name == rustc_span::sym::clippy;
- //~^ unnecessary_symbol_str
- rustc_span::sym::clippy == Ident::empty().name;
- //~^ unnecessary_symbol_str
-}
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs
deleted file mode 100644
index d74262d..0000000
--- a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-#![feature(rustc_private)]
-#![deny(clippy::internal)]
-#![allow(
- clippy::slow_symbol_comparisons,
- clippy::borrow_deref_ref,
- clippy::unnecessary_operation,
- unused_must_use,
- clippy::missing_clippy_version_attribute
-)]
-
-extern crate rustc_span;
-
-use rustc_span::symbol::{Ident, Symbol};
-
-fn main() {
- Symbol::intern("foo").as_str() == "clippy";
- //~^ unnecessary_symbol_str
- Symbol::intern("foo").to_string() == "self";
- //~^ unnecessary_symbol_str
- Symbol::intern("foo").to_ident_string() != "Self";
- //~^ unnecessary_symbol_str
- &*Ident::empty().as_str() == "clippy";
- //~^ unnecessary_symbol_str
- "clippy" == Ident::empty().to_string();
- //~^ unnecessary_symbol_str
-}
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.stderr
deleted file mode 100644
index 517a395..0000000
--- a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.stderr
+++ /dev/null
@@ -1,39 +0,0 @@
-error: unnecessary `Symbol` to string conversion
- --> tests/ui-internal/unnecessary_symbol_str.rs:16:5
- |
-LL | Symbol::intern("foo").as_str() == "clippy";
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::sym::clippy`
- |
-note: the lint level is defined here
- --> tests/ui-internal/unnecessary_symbol_str.rs:2:9
- |
-LL | #![deny(clippy::internal)]
- | ^^^^^^^^^^^^^^^^
- = note: `#[deny(clippy::unnecessary_symbol_str)]` implied by `#[deny(clippy::internal)]`
-
-error: unnecessary `Symbol` to string conversion
- --> tests/ui-internal/unnecessary_symbol_str.rs:18:5
- |
-LL | Symbol::intern("foo").to_string() == "self";
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") == rustc_span::kw::SelfLower`
-
-error: unnecessary `Symbol` to string conversion
- --> tests/ui-internal/unnecessary_symbol_str.rs:20:5
- |
-LL | Symbol::intern("foo").to_ident_string() != "Self";
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Symbol::intern("foo") != rustc_span::kw::SelfUpper`
-
-error: unnecessary `Symbol` to string conversion
- --> tests/ui-internal/unnecessary_symbol_str.rs:22:5
- |
-LL | &*Ident::empty().as_str() == "clippy";
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ident::empty().name == rustc_span::sym::clippy`
-
-error: unnecessary `Symbol` to string conversion
- --> tests/ui-internal/unnecessary_symbol_str.rs:24:5
- |
-LL | "clippy" == Ident::empty().to_string();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `rustc_span::sym::clippy == Ident::empty().name`
-
-error: aborting due to 5 previous errors
-
diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_good.rs b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_good.rs
index b437915..694ef45 100644
--- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_good.rs
+++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/ordering_good.rs
@@ -16,6 +16,7 @@
//@[bad_conf_4] error-in-other-file:
//@[bad_conf_5] error-in-other-file:
//@[bad_conf_6] error-in-other-file:
+//@compile-flags: --test
#![allow(dead_code)]
#![warn(clippy::arbitrary_source_item_ordering)]
diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.default.stderr b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.default.stderr
index 7fc216b..fcd7864 100644
--- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.default.stderr
+++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.default.stderr
@@ -1,16 +1,16 @@
error: incorrect ordering of items (must be alphabetically ordered)
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:35:5
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:36:5
|
LL | a: bool,
| ^
|
note: should be placed before `b`
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:34:5
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:35:5
|
LL | b: bool,
| ^
note: the lint level is defined here
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:32:8
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:33:8
|
LL | #[deny(clippy::arbitrary_source_item_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_2.stderr b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_2.stderr
index 1f75f50..81c35ff 100644
--- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_2.stderr
+++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_2.stderr
@@ -1,33 +1,33 @@
error: incorrect ordering of items (must be alphabetically ordered)
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:24:8
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:25:8
|
LL | struct OrderedChecked {
| ^^^^^^^^^^^^^^
|
note: should be placed before `Unordered`
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:18:8
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:19:8
|
LL | struct Unordered {
| ^^^^^^^^^
note: the lint level is defined here
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:9:9
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:10:9
|
LL | #![deny(clippy::arbitrary_source_item_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: incorrect ordering of items (must be alphabetically ordered)
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:35:5
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:36:5
|
LL | a: bool,
| ^
|
note: should be placed before `b`
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:34:5
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:35:5
|
LL | b: bool,
| ^
note: the lint level is defined here
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:32:8
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:33:8
|
LL | #[deny(clippy::arbitrary_source_item_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_3.stderr b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_3.stderr
index 8027f55..09ede57 100644
--- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_3.stderr
+++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_in_3.stderr
@@ -1,16 +1,16 @@
error: incorrect ordering of items (must be alphabetically ordered)
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:24:8
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:25:8
|
LL | struct OrderedChecked {
| ^^^^^^^^^^^^^^
|
note: should be placed before `Unordered`
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:18:8
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:19:8
|
LL | struct Unordered {
| ^^^^^^^^^
note: the lint level is defined here
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:9:9
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:10:9
|
LL | #![deny(clippy::arbitrary_source_item_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_within.stderr b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_within.stderr
index 333a601..7c515f0 100644
--- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_within.stderr
+++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.ord_within.stderr
@@ -1,48 +1,60 @@
error: incorrect ordering of items (must be alphabetically ordered)
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:24:8
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:25:8
|
LL | struct OrderedChecked {
| ^^^^^^^^^^^^^^
|
note: should be placed before `Unordered`
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:18:8
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:19:8
|
LL | struct Unordered {
| ^^^^^^^^^
note: the lint level is defined here
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:9:9
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:10:9
|
LL | #![deny(clippy::arbitrary_source_item_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: incorrect ordering of items (must be alphabetically ordered)
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:45:4
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:46:4
|
LL | fn before_main() {}
| ^^^^^^^^^^^
|
note: should be placed before `main`
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:41:4
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:42:4
|
LL | fn main() {
| ^^^^
error: incorrect ordering of items (must be alphabetically ordered)
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:35:5
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:36:5
|
LL | a: bool,
| ^
|
note: should be placed before `b`
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:34:5
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:35:5
|
LL | b: bool,
| ^
note: the lint level is defined here
- --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:32:8
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:33:8
|
LL | #[deny(clippy::arbitrary_source_item_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 3 previous errors
+error: incorrect ordering of items (must be alphabetically ordered)
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:52:11
+ |
+LL | const A: i8 = 0;
+ | ^
+ |
+note: should be placed before `B`
+ --> tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs:51:11
+ |
+LL | const B: i8 = 1;
+ | ^
+
+error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs
index e32b921..cb6d017 100644
--- a/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs
+++ b/src/tools/clippy/tests/ui-toml/arbitrary_source_item_ordering/selective_ordering.rs
@@ -4,6 +4,7 @@
//@[ord_within] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/ord_within
//@[ord_in_2] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/ord_in_2
//@[ord_in_3] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/arbitrary_source_item_ordering/ord_in_3
+//@compile-flags: --test
#![allow(dead_code)]
#![deny(clippy::arbitrary_source_item_ordering)]
@@ -44,3 +45,10 @@ fn main() {
fn before_main() {}
//~[ord_within]^ arbitrary_source_item_ordering
+
+#[cfg(test)]
+mod test {
+ const B: i8 = 1;
+ const A: i8 = 0;
+ //~[ord_within]^ arbitrary_source_item_ordering
+}
diff --git a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr
index 86e3040..d0fce36 100644
--- a/src/tools/clippy/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr
+++ b/src/tools/clippy/tests/ui-toml/await_holding_invalid_type_with_replacement/await_holding_invalid_type.stderr
@@ -1,11 +1,8 @@
error: error reading Clippy's configuration file: replacement not allowed for this configuration
- --> $DIR/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml:1:31
+ --> $DIR/tests/ui-toml/await_holding_invalid_type_with_replacement/clippy.toml:2:5
|
-LL | await-holding-invalid-types = [
- | _______________________________^
-LL | | { path = "std::string::String", replacement = "std::net::Ipv4Addr" },
-LL | | ]
- | |_^
+LL | { path = "std::string::String", replacement = "std::net::Ipv4Addr" },
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/clippy.toml b/src/tools/clippy/tests/ui-toml/collapsible_if/clippy.toml
new file mode 100644
index 0000000..592cea9
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/clippy.toml
@@ -0,0 +1 @@
+lint-commented-code = true
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.fixed b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.fixed
new file mode 100644
index 0000000..6f5cc47
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.fixed
@@ -0,0 +1,34 @@
+#![allow(clippy::eq_op, clippy::nonminimal_bool)]
+
+#[rustfmt::skip]
+#[warn(clippy::collapsible_if)]
+fn main() {
+ let (x, y) = ("hello", "world");
+
+ if x == "hello"
+ // Comment must be kept
+ && y == "world" {
+ println!("Hello world!");
+ }
+ //~^^^^^^ collapsible_if
+
+ // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798
+ if x == "hello" // Inner comment
+ && y == "world" {
+ println!("Hello world!");
+ }
+ //~^^^^^ collapsible_if
+
+ if x == "hello"
+ /* Inner comment */
+ && y == "world" {
+ println!("Hello world!");
+ }
+ //~^^^^^^ collapsible_if
+
+ if x == "hello" /* Inner comment */
+ && y == "world" {
+ println!("Hello world!");
+ }
+ //~^^^^^ collapsible_if
+}
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.rs b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.rs
new file mode 100644
index 0000000..868b4ad
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.rs
@@ -0,0 +1,38 @@
+#![allow(clippy::eq_op, clippy::nonminimal_bool)]
+
+#[rustfmt::skip]
+#[warn(clippy::collapsible_if)]
+fn main() {
+ let (x, y) = ("hello", "world");
+
+ if x == "hello" {
+ // Comment must be kept
+ if y == "world" {
+ println!("Hello world!");
+ }
+ }
+ //~^^^^^^ collapsible_if
+
+ // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798
+ if x == "hello" { // Inner comment
+ if y == "world" {
+ println!("Hello world!");
+ }
+ }
+ //~^^^^^ collapsible_if
+
+ if x == "hello" {
+ /* Inner comment */
+ if y == "world" {
+ println!("Hello world!");
+ }
+ }
+ //~^^^^^^ collapsible_if
+
+ if x == "hello" { /* Inner comment */
+ if y == "world" {
+ println!("Hello world!");
+ }
+ }
+ //~^^^^^ collapsible_if
+}
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.stderr b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.stderr
new file mode 100644
index 0000000..357ce4a
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if.stderr
@@ -0,0 +1,80 @@
+error: this `if` statement can be collapsed
+ --> tests/ui-toml/collapsible_if/collapsible_if.rs:8:5
+ |
+LL | / if x == "hello" {
+LL | | // Comment must be kept
+LL | | if y == "world" {
+LL | | println!("Hello world!");
+LL | | }
+LL | | }
+ | |_____^
+ |
+ = note: `-D clippy::collapsible-if` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::collapsible_if)]`
+help: collapse nested if block
+ |
+LL ~ if x == "hello"
+LL | // Comment must be kept
+LL ~ && y == "world" {
+LL | println!("Hello world!");
+LL ~ }
+ |
+
+error: this `if` statement can be collapsed
+ --> tests/ui-toml/collapsible_if/collapsible_if.rs:17:5
+ |
+LL | / if x == "hello" { // Inner comment
+LL | | if y == "world" {
+LL | | println!("Hello world!");
+LL | | }
+LL | | }
+ | |_____^
+ |
+help: collapse nested if block
+ |
+LL ~ if x == "hello" // Inner comment
+LL ~ && y == "world" {
+LL | println!("Hello world!");
+LL ~ }
+ |
+
+error: this `if` statement can be collapsed
+ --> tests/ui-toml/collapsible_if/collapsible_if.rs:24:5
+ |
+LL | / if x == "hello" {
+LL | | /* Inner comment */
+LL | | if y == "world" {
+LL | | println!("Hello world!");
+LL | | }
+LL | | }
+ | |_____^
+ |
+help: collapse nested if block
+ |
+LL ~ if x == "hello"
+LL | /* Inner comment */
+LL ~ && y == "world" {
+LL | println!("Hello world!");
+LL ~ }
+ |
+
+error: this `if` statement can be collapsed
+ --> tests/ui-toml/collapsible_if/collapsible_if.rs:32:5
+ |
+LL | / if x == "hello" { /* Inner comment */
+LL | | if y == "world" {
+LL | | println!("Hello world!");
+LL | | }
+LL | | }
+ | |_____^
+ |
+help: collapse nested if block
+ |
+LL ~ if x == "hello" /* Inner comment */
+LL ~ && y == "world" {
+LL | println!("Hello world!");
+LL ~ }
+ |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed
new file mode 100644
index 0000000..f122739
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.fixed
@@ -0,0 +1,25 @@
+#![feature(let_chains)]
+#![warn(clippy::collapsible_if)]
+
+fn main() {
+ if let Some(a) = Some(3)
+ // with comment
+ && let Some(b) = Some(4) {
+ let _ = a + b;
+ }
+ //~^^^^^^ collapsible_if
+
+ if let Some(a) = Some(3)
+ // with comment
+ && a + 1 == 4 {
+ let _ = a;
+ }
+ //~^^^^^^ collapsible_if
+
+ if Some(3) == Some(4).map(|x| x - 1)
+ // with comment
+ && let Some(b) = Some(4) {
+ let _ = b;
+ }
+ //~^^^^^^ collapsible_if
+}
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs
new file mode 100644
index 0000000..5a984d7
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs
@@ -0,0 +1,28 @@
+#![feature(let_chains)]
+#![warn(clippy::collapsible_if)]
+
+fn main() {
+ if let Some(a) = Some(3) {
+ // with comment
+ if let Some(b) = Some(4) {
+ let _ = a + b;
+ }
+ }
+ //~^^^^^^ collapsible_if
+
+ if let Some(a) = Some(3) {
+ // with comment
+ if a + 1 == 4 {
+ let _ = a;
+ }
+ }
+ //~^^^^^^ collapsible_if
+
+ if Some(3) == Some(4).map(|x| x - 1) {
+ // with comment
+ if let Some(b) = Some(4) {
+ let _ = b;
+ }
+ }
+ //~^^^^^^ collapsible_if
+}
diff --git a/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr
new file mode 100644
index 0000000..c22a65a
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/collapsible_if/collapsible_if_let_chains.stderr
@@ -0,0 +1,64 @@
+error: this `if` statement can be collapsed
+ --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:5:5
+ |
+LL | / if let Some(a) = Some(3) {
+LL | | // with comment
+LL | | if let Some(b) = Some(4) {
+LL | | let _ = a + b;
+LL | | }
+LL | | }
+ | |_____^
+ |
+ = note: `-D clippy::collapsible-if` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::collapsible_if)]`
+help: collapse nested if block
+ |
+LL ~ if let Some(a) = Some(3)
+LL | // with comment
+LL ~ && let Some(b) = Some(4) {
+LL | let _ = a + b;
+LL ~ }
+ |
+
+error: this `if` statement can be collapsed
+ --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:13:5
+ |
+LL | / if let Some(a) = Some(3) {
+LL | | // with comment
+LL | | if a + 1 == 4 {
+LL | | let _ = a;
+LL | | }
+LL | | }
+ | |_____^
+ |
+help: collapse nested if block
+ |
+LL ~ if let Some(a) = Some(3)
+LL | // with comment
+LL ~ && a + 1 == 4 {
+LL | let _ = a;
+LL ~ }
+ |
+
+error: this `if` statement can be collapsed
+ --> tests/ui-toml/collapsible_if/collapsible_if_let_chains.rs:21:5
+ |
+LL | / if Some(3) == Some(4).map(|x| x - 1) {
+LL | | // with comment
+LL | | if let Some(b) = Some(4) {
+LL | | let _ = b;
+LL | | }
+LL | | }
+ | |_____^
+ |
+help: collapse nested if block
+ |
+LL ~ if Some(3) == Some(4).map(|x| x - 1)
+LL | // with comment
+LL ~ && let Some(b) = Some(4) {
+LL | let _ = b;
+LL ~ }
+ |
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs
index 2465fe4..d3d5b0c 100644
--- a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs
+++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs
@@ -251,6 +251,16 @@ pub fn f(p: *const i32) -> i32 {
}
}
+#[macro_export]
+macro_rules! issue14488 {
+ ($e:expr) => {
+ #[expect(clippy::macro_metavars_in_unsafe)]
+ unsafe {
+ $e
+ }
+ };
+}
+
fn main() {
allow_works!(1);
simple!(1);
@@ -271,4 +281,10 @@ fn main() {
multiple_unsafe_blocks!(1, 1, 1);
unsafe_from_root_ctxt!(unsafe { 1 });
nested_macros!(1, 1);
+
+ // These two invocations lead to two expanded unsafe blocks, each with an `#[expect]` on it.
+ // Only of them gets a warning, which used to result in an unfulfilled expectation for the other
+ // expanded unsafe block.
+ issue14488!(1);
+ issue14488!(2);
}
diff --git a/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed
index 36540bf..2877871 100644
--- a/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed
+++ b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.fixed
@@ -1,3 +1,4 @@
+#![allow(clippy::uninlined_format_args)]
#![deny(clippy::index_refutable_slice)]
fn below_limit() {
diff --git a/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs
index da76bb2..f958b92 100644
--- a/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs
+++ b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::uninlined_format_args)]
#![deny(clippy::index_refutable_slice)]
fn below_limit() {
diff --git a/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr
index 022deb3..e1a8941 100644
--- a/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr
+++ b/src/tools/clippy/tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.stderr
@@ -1,11 +1,11 @@
error: this binding can be a slice pattern to avoid indexing
- --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:5:17
+ --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:6:17
|
LL | if let Some(slice) = slice {
| ^^^^^
|
note: the lint level is defined here
- --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:1:9
+ --> tests/ui-toml/max_suggested_slice_pattern_length/index_refutable_slice.rs:2:9
|
LL | #![deny(clippy::index_refutable_slice)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs b/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs
index 08a8e11..13e19e9 100644
--- a/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs
+++ b/src/tools/clippy/tests/ui-toml/strict_non_send_fields_in_send_ty/test.rs
@@ -29,7 +29,7 @@ unsafe impl<T> Send for MyOption<T> {}
//~^ non_send_fields_in_send_ty
// All fields are disallowed when raw pointer heuristic is off
-extern "C" {
+unsafe extern "C" {
type NonSend;
}
diff --git a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml
index f43c9d9..3cb8523 100644
--- a/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/toml_inconsistent_struct_constructor/clippy.toml
@@ -1 +1 @@
-lint-inconsistent-struct-field-initializers = true
+check-inconsistent-struct-field-initializers = true
diff --git a/src/tools/clippy/tests/ui-toml/toml_invalid_path/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_invalid_path/clippy.toml
new file mode 100644
index 0000000..6d0d732
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_invalid_path/clippy.toml
@@ -0,0 +1,14 @@
+[[disallowed-types]]
+path = "std::result::Result::Err"
+
+[[disallowed-macros]]
+path = "bool"
+
+[[disallowed-methods]]
+path = "std::process::current_exe"
+
+# negative test
+
+[[disallowed-methods]]
+path = "std::current_exe"
+allow-invalid = true
diff --git a/src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.rs b/src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.rs
new file mode 100644
index 0000000..c152038
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.rs
@@ -0,0 +1,5 @@
+//@error-in-other-file: expected a macro, found a primitive type
+//@error-in-other-file: `std::process::current_exe` does not refer to an existing function
+//@error-in-other-file: expected a type, found a tuple variant
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr b/src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr
new file mode 100644
index 0000000..8255010
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/toml_invalid_path/conf_invalid_path.stderr
@@ -0,0 +1,23 @@
+warning: expected a macro, found a primitive type
+ --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:4:1
+ |
+LL | / [[disallowed-macros]]
+LL | | path = "bool"
+ | |_____________^
+
+warning: `std::process::current_exe` does not refer to an existing function
+ --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:7:1
+ |
+LL | / [[disallowed-methods]]
+LL | | path = "std::process::current_exe"
+ | |__________________________________^
+
+warning: expected a type, found a tuple variant
+ --> $DIR/tests/ui-toml/toml_invalid_path/clippy.toml:1:1
+ |
+LL | / [[disallowed-types]]
+LL | | path = "std::result::Result::Err"
+ | |_________________________________^
+
+warning: 3 warnings emitted
+
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index fee5b01..f2eaa66 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -29,12 +29,11 @@
array-size-threshold
avoid-breaking-exported-api
await-holding-invalid-types
- blacklisted-names
cargo-ignore-publish
check-incompatible-msrv-in-tests
+ check-inconsistent-struct-field-initializers
check-private-items
cognitive-complexity-threshold
- cyclomatic-complexity-threshold
disallowed-macros
disallowed-methods
disallowed-names
@@ -49,7 +48,7 @@
future-size-threshold
ignore-interior-mutability
large-error-threshold
- lint-inconsistent-struct-field-initializers
+ lint-commented-code
literal-representation-threshold
matches-for-let-else
max-fn-params-bools
@@ -122,12 +121,11 @@
array-size-threshold
avoid-breaking-exported-api
await-holding-invalid-types
- blacklisted-names
cargo-ignore-publish
check-incompatible-msrv-in-tests
+ check-inconsistent-struct-field-initializers
check-private-items
cognitive-complexity-threshold
- cyclomatic-complexity-threshold
disallowed-macros
disallowed-methods
disallowed-names
@@ -142,7 +140,7 @@
future-size-threshold
ignore-interior-mutability
large-error-threshold
- lint-inconsistent-struct-field-initializers
+ lint-commented-code
literal-representation-threshold
matches-for-let-else
max-fn-params-bools
@@ -215,12 +213,11 @@
array-size-threshold
avoid-breaking-exported-api
await-holding-invalid-types
- blacklisted-names
cargo-ignore-publish
check-incompatible-msrv-in-tests
+ check-inconsistent-struct-field-initializers
check-private-items
cognitive-complexity-threshold
- cyclomatic-complexity-threshold
disallowed-macros
disallowed-methods
disallowed-names
@@ -235,7 +232,7 @@
future-size-threshold
ignore-interior-mutability
large-error-threshold
- lint-inconsistent-struct-field-initializers
+ lint-commented-code
literal-representation-threshold
matches-for-let-else
max-fn-params-bools
diff --git a/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.fixed b/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.fixed
index af72d6b..20511cb 100644
--- a/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.fixed
+++ b/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.fixed
@@ -15,7 +15,7 @@
}
}
-use utils::{BAR, print};
+pub use utils::{BAR, print};
//~^ ERROR: usage of wildcard import
use my_crate::utils::my_util_fn;
//~^ ERROR: usage of wildcard import
diff --git a/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.rs b/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.rs
index 91009dd..8d05910 100644
--- a/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.rs
+++ b/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.rs
@@ -15,7 +15,7 @@ pub fn my_util_fn() {}
}
}
-use utils::*;
+pub use utils::*;
//~^ ERROR: usage of wildcard import
use my_crate::utils::*;
//~^ ERROR: usage of wildcard import
diff --git a/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.stderr b/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.stderr
index 3d3be96..5e624dd 100644
--- a/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.stderr
+++ b/src/tools/clippy/tests/ui-toml/wildcard_imports/wildcard_imports.stderr
@@ -1,8 +1,8 @@
error: usage of wildcard import
- --> tests/ui-toml/wildcard_imports/wildcard_imports.rs:18:5
+ --> tests/ui-toml/wildcard_imports/wildcard_imports.rs:18:9
|
-LL | use utils::*;
- | ^^^^^^^^ help: try: `utils::{BAR, print}`
+LL | pub use utils::*;
+ | ^^^^^^^^ help: try: `utils::{BAR, print}`
|
= note: `-D clippy::wildcard-imports` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::wildcard_imports)]`
diff --git a/src/tools/clippy/tests/ui/asm_syntax_not_x86.rs b/src/tools/clippy/tests/ui/asm_syntax_not_x86.rs
index edcd524..361bc20 100644
--- a/src/tools/clippy/tests/ui/asm_syntax_not_x86.rs
+++ b/src/tools/clippy/tests/ui/asm_syntax_not_x86.rs
@@ -8,9 +8,11 @@ mod dont_warn {
use std::arch::{asm, global_asm};
pub(super) unsafe fn use_asm() {
- asm!("");
- asm!("", options());
- asm!("", options(nostack));
+ unsafe {
+ asm!("");
+ asm!("", options());
+ asm!("", options(nostack));
+ }
}
global_asm!("");
diff --git a/src/tools/clippy/tests/ui/asm_syntax_x86.rs b/src/tools/clippy/tests/ui/asm_syntax_x86.rs
index 4e91f27..30401c9 100644
--- a/src/tools/clippy/tests/ui/asm_syntax_x86.rs
+++ b/src/tools/clippy/tests/ui/asm_syntax_x86.rs
@@ -5,17 +5,19 @@ mod warn_intel {
use std::arch::{asm, global_asm};
pub(super) unsafe fn use_asm() {
- asm!("");
- //~^ inline_asm_x86_intel_syntax
+ unsafe {
+ asm!("");
+ //~^ inline_asm_x86_intel_syntax
- asm!("", options());
- //~^ inline_asm_x86_intel_syntax
+ asm!("", options());
+ //~^ inline_asm_x86_intel_syntax
- asm!("", options(nostack));
- //~^ inline_asm_x86_intel_syntax
+ asm!("", options(nostack));
+ //~^ inline_asm_x86_intel_syntax
- asm!("", options(att_syntax));
- asm!("", options(nostack, att_syntax));
+ asm!("", options(att_syntax));
+ asm!("", options(nostack, att_syntax));
+ }
}
global_asm!("");
@@ -32,14 +34,16 @@ mod warn_att {
use std::arch::{asm, global_asm};
pub(super) unsafe fn use_asm() {
- asm!("");
- asm!("", options());
- asm!("", options(nostack));
- asm!("", options(att_syntax));
- //~^ inline_asm_x86_att_syntax
+ unsafe {
+ asm!("");
+ asm!("", options());
+ asm!("", options(nostack));
+ asm!("", options(att_syntax));
+ //~^ inline_asm_x86_att_syntax
- asm!("", options(nostack, att_syntax));
- //~^ inline_asm_x86_att_syntax
+ asm!("", options(nostack, att_syntax));
+ //~^ inline_asm_x86_att_syntax
+ }
}
global_asm!("");
diff --git a/src/tools/clippy/tests/ui/asm_syntax_x86.stderr b/src/tools/clippy/tests/ui/asm_syntax_x86.stderr
index 2dcd955..8e068cf 100644
--- a/src/tools/clippy/tests/ui/asm_syntax_x86.stderr
+++ b/src/tools/clippy/tests/ui/asm_syntax_x86.stderr
@@ -1,31 +1,31 @@
error: Intel x86 assembly syntax used
- --> tests/ui/asm_syntax_x86.rs:8:9
+ --> tests/ui/asm_syntax_x86.rs:9:13
|
-LL | asm!("");
- | ^^^^^^^^
+LL | asm!("");
+ | ^^^^^^^^
|
= help: use AT&T x86 assembly syntax
= note: `-D clippy::inline-asm-x86-intel-syntax` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::inline_asm_x86_intel_syntax)]`
error: Intel x86 assembly syntax used
- --> tests/ui/asm_syntax_x86.rs:11:9
+ --> tests/ui/asm_syntax_x86.rs:12:13
|
-LL | asm!("", options());
- | ^^^^^^^^^^^^^^^^^^^
+LL | asm!("", options());
+ | ^^^^^^^^^^^^^^^^^^^
|
= help: use AT&T x86 assembly syntax
error: Intel x86 assembly syntax used
- --> tests/ui/asm_syntax_x86.rs:14:9
+ --> tests/ui/asm_syntax_x86.rs:15:13
|
-LL | asm!("", options(nostack));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | asm!("", options(nostack));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: use AT&T x86 assembly syntax
error: Intel x86 assembly syntax used
- --> tests/ui/asm_syntax_x86.rs:21:5
+ --> tests/ui/asm_syntax_x86.rs:23:5
|
LL | global_asm!("");
| ^^^^^^^^^^^^^^^
@@ -33,7 +33,7 @@
= help: use AT&T x86 assembly syntax
error: Intel x86 assembly syntax used
- --> tests/ui/asm_syntax_x86.rs:24:5
+ --> tests/ui/asm_syntax_x86.rs:26:5
|
LL | global_asm!("", options());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,25 +41,25 @@
= help: use AT&T x86 assembly syntax
error: AT&T x86 assembly syntax used
- --> tests/ui/asm_syntax_x86.rs:38:9
+ --> tests/ui/asm_syntax_x86.rs:41:13
|
-LL | asm!("", options(att_syntax));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | asm!("", options(att_syntax));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: use Intel x86 assembly syntax
= note: `-D clippy::inline-asm-x86-att-syntax` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::inline_asm_x86_att_syntax)]`
error: AT&T x86 assembly syntax used
- --> tests/ui/asm_syntax_x86.rs:41:9
+ --> tests/ui/asm_syntax_x86.rs:44:13
|
-LL | asm!("", options(nostack, att_syntax));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | asm!("", options(nostack, att_syntax));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: use Intel x86 assembly syntax
error: AT&T x86 assembly syntax used
- --> tests/ui/asm_syntax_x86.rs:47:5
+ --> tests/ui/asm_syntax_x86.rs:51:5
|
LL | global_asm!("", options(att_syntax));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/author/if.rs b/src/tools/clippy/tests/ui/author/if.rs
index 59bc9f5..abefc34 100644
--- a/src/tools/clippy/tests/ui/author/if.rs
+++ b/src/tools/clippy/tests/ui/author/if.rs
@@ -1,6 +1,6 @@
//@ check-pass
-#[allow(clippy::all)]
+#![allow(clippy::all)]
fn main() {
#[clippy::author]
diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.rs b/src/tools/clippy/tests/ui/author/macro_in_closure.rs
index 8a02f38..373f014 100644
--- a/src/tools/clippy/tests/ui/author/macro_in_closure.rs
+++ b/src/tools/clippy/tests/ui/author/macro_in_closure.rs
@@ -1,5 +1,7 @@
//@ check-pass
+#![allow(clippy::uninlined_format_args)]
+
fn main() {
#[clippy::author]
let print_text = |x| println!("{}", x);
diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.rs b/src/tools/clippy/tests/ui/author/macro_in_loop.rs
index 84ffe41..f68275f 100644
--- a/src/tools/clippy/tests/ui/author/macro_in_loop.rs
+++ b/src/tools/clippy/tests/ui/author/macro_in_loop.rs
@@ -1,6 +1,7 @@
//@ check-pass
#![feature(stmt_expr_attributes)]
+#![allow(clippy::uninlined_format_args)]
fn main() {
#[clippy::author]
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs
index 1a2a4ec..7a4cc4f 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs
@@ -131,12 +131,12 @@ fn write_with_span(s: Span, mut input: IntoIter, out: &mut TokenStream) -> Resul
pub fn make_it_big(input: TokenStream) -> TokenStream {
let mut expr_repeat = syn::parse_macro_input!(input as syn::ExprRepeat);
let len_span = expr_repeat.len.span();
- if let syn::Expr::Lit(expr_lit) = &mut *expr_repeat.len {
- if let syn::Lit::Int(lit_int) = &expr_lit.lit {
- let orig_val = lit_int.base10_parse::<usize>().expect("not a valid length parameter");
- let new_val = orig_val.saturating_mul(10);
- expr_lit.lit = syn::parse_quote_spanned!( len_span => #new_val);
- }
+ if let syn::Expr::Lit(expr_lit) = &mut *expr_repeat.len
+ && let syn::Lit::Int(lit_int) = &expr_lit.lit
+ {
+ let orig_val = lit_int.base10_parse::<usize>().expect("not a valid length parameter");
+ let new_val = orig_val.saturating_mul(10);
+ expr_lit.lit = syn::parse_quote_spanned!( len_span => #new_val);
}
quote::quote!(#expr_repeat).into()
}
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed
index cd307e8..c82276b 100644
--- a/src/tools/clippy/tests/ui/blocks_in_conditions.fixed
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions.fixed
@@ -1,12 +1,7 @@
//@aux-build:proc_macro_attr.rs
#![warn(clippy::blocks_in_conditions)]
-#![allow(
- unused,
- clippy::let_and_return,
- clippy::needless_if,
- clippy::missing_transmute_annotations
-)]
+#![allow(unused, clippy::needless_if, clippy::missing_transmute_annotations)]
#![warn(clippy::nonminimal_bool)]
macro_rules! blocky {
@@ -71,28 +66,6 @@
);
}
-// issue #11814
-fn block_in_match_expr(num: i32) -> i32 {
- let res = {
- //~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
- let opt = Some(2);
- opt
- }; match res {
- Some(0) => 1,
- Some(n) => num * 2,
- None => 0,
- };
-
- match unsafe {
- let hearty_hearty_hearty = vec![240, 159, 146, 150];
- String::from_utf8_unchecked(hearty_hearty_hearty).as_str()
- } {
- "💖" => 1,
- "what" => 2,
- _ => 3,
- }
-}
-
// issue #12162
macro_rules! timed {
($name:expr, $body:expr $(,)?) => {{
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.rs b/src/tools/clippy/tests/ui/blocks_in_conditions.rs
index 6a211c8..6a4a7c6 100644
--- a/src/tools/clippy/tests/ui/blocks_in_conditions.rs
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions.rs
@@ -1,12 +1,7 @@
//@aux-build:proc_macro_attr.rs
#![warn(clippy::blocks_in_conditions)]
-#![allow(
- unused,
- clippy::let_and_return,
- clippy::needless_if,
- clippy::missing_transmute_annotations
-)]
+#![allow(unused, clippy::needless_if, clippy::missing_transmute_annotations)]
#![warn(clippy::nonminimal_bool)]
macro_rules! blocky {
@@ -71,28 +66,6 @@ fn block_in_assert() {
);
}
-// issue #11814
-fn block_in_match_expr(num: i32) -> i32 {
- match {
- //~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
- let opt = Some(2);
- opt
- } {
- Some(0) => 1,
- Some(n) => num * 2,
- None => 0,
- };
-
- match unsafe {
- let hearty_hearty_hearty = vec![240, 159, 146, 150];
- String::from_utf8_unchecked(hearty_hearty_hearty).as_str()
- } {
- "💖" => 1,
- "what" => 2,
- _ => 3,
- }
-}
-
// issue #12162
macro_rules! timed {
($name:expr, $body:expr $(,)?) => {{
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr
index da21344..e57eca5 100644
--- a/src/tools/clippy/tests/ui/blocks_in_conditions.stderr
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions.stderr
@@ -1,5 +1,5 @@
error: in an `if` condition, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
- --> tests/ui/blocks_in_conditions.rs:30:5
+ --> tests/ui/blocks_in_conditions.rs:25:5
|
LL | / if {
LL | |
@@ -20,13 +20,13 @@
|
error: omit braces around single expression condition
- --> tests/ui/blocks_in_conditions.rs:42:8
+ --> tests/ui/blocks_in_conditions.rs:37:8
|
LL | if { true } { 6 } else { 10 }
| ^^^^^^^^ help: try: `true`
error: this boolean expression can be simplified
- --> tests/ui/blocks_in_conditions.rs:48:8
+ --> tests/ui/blocks_in_conditions.rs:43:8
|
LL | if true && x == 3 { 6 } else { 10 }
| ^^^^^^^^^^^^^^ help: try: `x == 3`
@@ -34,24 +34,5 @@
= note: `-D clippy::nonminimal-bool` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::nonminimal_bool)]`
-error: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
- --> tests/ui/blocks_in_conditions.rs:76:5
- |
-LL | / match {
-LL | |
-LL | | let opt = Some(2);
-LL | | opt
-LL | | } {
- | |_____^
- |
-help: try
- |
-LL ~ let res = {
-LL +
-LL + let opt = Some(2);
-LL + opt
-LL ~ }; match res {
- |
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions_2021.fixed b/src/tools/clippy/tests/ui/blocks_in_conditions_2021.fixed
new file mode 100644
index 0000000..c7cc643
--- /dev/null
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions_2021.fixed
@@ -0,0 +1,25 @@
+//@edition: 2021
+
+#![allow(clippy::let_and_return)]
+
+// issue #11814
+fn block_in_match_expr(num: i32) -> i32 {
+ let res = {
+ //~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
+ let opt = Some(2);
+ opt
+ }; match res {
+ Some(0) => 1,
+ Some(n) => num * 2,
+ None => 0,
+ };
+
+ match unsafe {
+ let hearty_hearty_hearty = vec![240, 159, 146, 150];
+ String::from_utf8_unchecked(hearty_hearty_hearty).as_str()
+ } {
+ "💖" => 1,
+ "what" => 2,
+ _ => 3,
+ }
+}
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions_2021.rs b/src/tools/clippy/tests/ui/blocks_in_conditions_2021.rs
new file mode 100644
index 0000000..a911237
--- /dev/null
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions_2021.rs
@@ -0,0 +1,25 @@
+//@edition: 2021
+
+#![allow(clippy::let_and_return)]
+
+// issue #11814
+fn block_in_match_expr(num: i32) -> i32 {
+ match {
+ //~^ ERROR: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
+ let opt = Some(2);
+ opt
+ } {
+ Some(0) => 1,
+ Some(n) => num * 2,
+ None => 0,
+ };
+
+ match unsafe {
+ let hearty_hearty_hearty = vec![240, 159, 146, 150];
+ String::from_utf8_unchecked(hearty_hearty_hearty).as_str()
+ } {
+ "💖" => 1,
+ "what" => 2,
+ _ => 3,
+ }
+}
diff --git a/src/tools/clippy/tests/ui/blocks_in_conditions_2021.stderr b/src/tools/clippy/tests/ui/blocks_in_conditions_2021.stderr
new file mode 100644
index 0000000..497ee9d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/blocks_in_conditions_2021.stderr
@@ -0,0 +1,23 @@
+error: in a `match` scrutinee, avoid complex blocks or closures with blocks; instead, move the block or closure higher and bind it with a `let`
+ --> tests/ui/blocks_in_conditions_2021.rs:7:5
+ |
+LL | / match {
+LL | |
+LL | | let opt = Some(2);
+LL | | opt
+LL | | } {
+ | |_____^
+ |
+ = note: `-D clippy::blocks-in-conditions` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::blocks_in_conditions)]`
+help: try
+ |
+LL ~ let res = {
+LL +
+LL + let opt = Some(2);
+LL + opt
+LL ~ }; match res {
+ |
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
index 0080801..ed61412 100644
--- a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
@@ -117,3 +117,27 @@
0
};
}
+
+fn issue14628() {
+ macro_rules! mac {
+ (if $cond:expr, $then:expr, $else:expr) => {
+ if $cond { $then } else { $else }
+ };
+ (zero) => {
+ 0
+ };
+ (one) => {
+ 1
+ };
+ }
+
+ let _ = i32::from(dbg!(4 > 0));
+ //~^ bool_to_int_with_if
+
+ let _ = dbg!(i32::from(4 > 0));
+ //~^ bool_to_int_with_if
+
+ let _ = mac!(if 4 > 0, 1, 0);
+ let _ = if 4 > 0 { mac!(one) } else { 0 };
+ let _ = if 4 > 0 { 1 } else { mac!(zero) };
+}
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
index 72c7e2c..3f1f1c7 100644
--- a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
@@ -157,3 +157,27 @@ fn if_let(a: Enum, b: Enum) {
0
};
}
+
+fn issue14628() {
+ macro_rules! mac {
+ (if $cond:expr, $then:expr, $else:expr) => {
+ if $cond { $then } else { $else }
+ };
+ (zero) => {
+ 0
+ };
+ (one) => {
+ 1
+ };
+ }
+
+ let _ = if dbg!(4 > 0) { 1 } else { 0 };
+ //~^ bool_to_int_with_if
+
+ let _ = dbg!(if 4 > 0 { 1 } else { 0 });
+ //~^ bool_to_int_with_if
+
+ let _ = mac!(if 4 > 0, 1, 0);
+ let _ = if 4 > 0 { mac!(one) } else { 0 };
+ let _ = if 4 > 0 { 1 } else { mac!(zero) };
+}
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
index 415e80f..94089bc 100644
--- a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
@@ -114,5 +114,21 @@
|
= note: `a as u8` or `a.into()` can also be valid options
-error: aborting due to 9 previous errors
+error: boolean to int conversion using if
+ --> tests/ui/bool_to_int_with_if.rs:174:13
+ |
+LL | let _ = if dbg!(4 > 0) { 1 } else { 0 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `i32::from(dbg!(4 > 0))`
+ |
+ = note: `dbg!(4 > 0) as i32` or `dbg!(4 > 0).into()` can also be valid options
+
+error: boolean to int conversion using if
+ --> tests/ui/bool_to_int_with_if.rs:177:18
+ |
+LL | let _ = dbg!(if 4 > 0 { 1 } else { 0 });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `i32::from(4 > 0)`
+ |
+ = note: `(4 > 0) as i32` or `(4 > 0).into()` can also be valid options
+
+error: aborting due to 11 previous errors
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
index 3dca06f..3ba2eea 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed
@@ -29,3 +29,21 @@
let _raw = (&raw mut x[1]).wrapping_offset(-1);
//~^ borrow_as_ptr
}
+
+fn implicit_cast() {
+ let val = 1;
+ let p: *const i32 = &raw const val;
+ //~^ borrow_as_ptr
+
+ let mut val = 1;
+ let p: *mut i32 = &raw mut val;
+ //~^ borrow_as_ptr
+
+ let mut val = 1;
+ // Only lint the leftmost argument, the rightmost is ref to a temporary
+ core::ptr::eq(&raw const val, &1);
+ //~^ borrow_as_ptr
+
+ // Do not lint references to temporaries
+ core::ptr::eq(&0i32, &1i32);
+}
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.rs b/src/tools/clippy/tests/ui/borrow_as_ptr.rs
index 3559dc2..8cdd051 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr.rs
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr.rs
@@ -29,3 +29,21 @@ fn issue_13882() {
let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
//~^ borrow_as_ptr
}
+
+fn implicit_cast() {
+ let val = 1;
+ let p: *const i32 = &val;
+ //~^ borrow_as_ptr
+
+ let mut val = 1;
+ let p: *mut i32 = &mut val;
+ //~^ borrow_as_ptr
+
+ let mut val = 1;
+ // Only lint the leftmost argument, the rightmost is ref to a temporary
+ core::ptr::eq(&val, &1);
+ //~^ borrow_as_ptr
+
+ // Do not lint references to temporaries
+ core::ptr::eq(&0i32, &1i32);
+}
diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
index 4a9f2ed..b1fcce4 100644
--- a/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
+++ b/src/tools/clippy/tests/ui/borrow_as_ptr.stderr
@@ -25,5 +25,38 @@
LL | let _raw = (&mut x[1] as *mut i32).wrapping_offset(-1);
| ^^^^^^^^^^^^^^^^^^^^^ help: try: `&raw mut x[1]`
-error: aborting due to 4 previous errors
+error: implicit borrow as raw pointer
+ --> tests/ui/borrow_as_ptr.rs:35:25
+ |
+LL | let p: *const i32 = &val;
+ | ^^^^
+ |
+help: use a raw pointer instead
+ |
+LL | let p: *const i32 = &raw const val;
+ | +++++++++
+
+error: implicit borrow as raw pointer
+ --> tests/ui/borrow_as_ptr.rs:39:23
+ |
+LL | let p: *mut i32 = &mut val;
+ | ^^^^^^^^
+ |
+help: use a raw pointer instead
+ |
+LL | let p: *mut i32 = &raw mut val;
+ | +++
+
+error: implicit borrow as raw pointer
+ --> tests/ui/borrow_as_ptr.rs:44:19
+ |
+LL | core::ptr::eq(&val, &1);
+ | ^^^^
+ |
+help: use a raw pointer instead
+ |
+LL | core::ptr::eq(&raw const val, &1);
+ | +++++++++
+
+error: aborting due to 7 previous errors
diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed
index 17c224f..765dd75 100644
--- a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed
+++ b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed
@@ -81,3 +81,46 @@
let p = &raw const *s;
let _ = p as *const i8;
}
+
+mod issue_9905 {
+ use std::{fs, io};
+
+ pub enum File {
+ Stdio,
+ File(fs::File),
+ }
+
+ impl io::Read for &'_ File {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ match self {
+ File::Stdio => io::stdin().read(buf),
+ File::File(file) => (&*file).read(buf),
+ }
+ }
+ }
+}
+
+mod issue_11346 {
+ struct Struct;
+
+ impl Struct {
+ fn foo(self: &mut &Self) {}
+ }
+
+ trait Trait {
+ fn bar(&mut self) {}
+ }
+
+ impl Trait for &Struct {}
+
+ fn bar() {
+ let s = &Struct;
+ (&*s).foo();
+ (&*s).bar();
+
+ let mut s = &Struct;
+ s.foo(); // To avoid a warning about `s` not needing to be mutable
+ s.foo();
+ //~^ borrow_deref_ref
+ }
+}
diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.rs b/src/tools/clippy/tests/ui/borrow_deref_ref.rs
index 130ed29..8ee66bf 100644
--- a/src/tools/clippy/tests/ui/borrow_deref_ref.rs
+++ b/src/tools/clippy/tests/ui/borrow_deref_ref.rs
@@ -81,3 +81,46 @@ fn issue_13584() {
let p = &raw const *s;
let _ = p as *const i8;
}
+
+mod issue_9905 {
+ use std::{fs, io};
+
+ pub enum File {
+ Stdio,
+ File(fs::File),
+ }
+
+ impl io::Read for &'_ File {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ match self {
+ File::Stdio => io::stdin().read(buf),
+ File::File(file) => (&*file).read(buf),
+ }
+ }
+ }
+}
+
+mod issue_11346 {
+ struct Struct;
+
+ impl Struct {
+ fn foo(self: &mut &Self) {}
+ }
+
+ trait Trait {
+ fn bar(&mut self) {}
+ }
+
+ impl Trait for &Struct {}
+
+ fn bar() {
+ let s = &Struct;
+ (&*s).foo();
+ (&*s).bar();
+
+ let mut s = &Struct;
+ s.foo(); // To avoid a warning about `s` not needing to be mutable
+ (&*s).foo();
+ //~^ borrow_deref_ref
+ }
+}
diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr
index f5868aa..3d55da2 100644
--- a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr
+++ b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr
@@ -19,5 +19,11 @@
LL | let addr_y = &&*x as *const _ as usize; // assert ok
| ^^^ help: if you would like to reborrow, try removing `&*`: `x`
-error: aborting due to 3 previous errors
+error: deref on an immutable reference
+ --> tests/ui/borrow_deref_ref.rs:123:9
+ |
+LL | (&*s).foo();
+ | ^^^^^ help: if you would like to reborrow, try removing `&*`: `s`
+
+error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/box_collection.rs b/src/tools/clippy/tests/ui/box_collection.rs
index 0f7d3c7..7ae5446 100644
--- a/src/tools/clippy/tests/ui/box_collection.rs
+++ b/src/tools/clippy/tests/ui/box_collection.rs
@@ -1,4 +1,3 @@
-#![warn(clippy::all)]
#![allow(
clippy::boxed_local,
clippy::needless_pass_by_value,
diff --git a/src/tools/clippy/tests/ui/box_collection.stderr b/src/tools/clippy/tests/ui/box_collection.stderr
index ebbc3d9..d730e2d 100644
--- a/src/tools/clippy/tests/ui/box_collection.stderr
+++ b/src/tools/clippy/tests/ui/box_collection.stderr
@@ -1,5 +1,5 @@
error: you seem to be trying to use `Box<Vec<..>>`. Consider using just `Vec<..>`
- --> tests/ui/box_collection.rs:21:15
+ --> tests/ui/box_collection.rs:20:15
|
LL | fn test1(foo: Box<Vec<bool>>) {}
| ^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@
= help: to override `-D warnings` add `#[allow(clippy::box_collection)]`
error: you seem to be trying to use `Box<String>`. Consider using just `String`
- --> tests/ui/box_collection.rs:29:15
+ --> tests/ui/box_collection.rs:28:15
|
LL | fn test3(foo: Box<String>) {}
| ^^^^^^^^^^^
@@ -17,7 +17,7 @@
= help: `String` is already on the heap, `Box<String>` makes an extra allocation
error: you seem to be trying to use `Box<HashMap<..>>`. Consider using just `HashMap<..>`
- --> tests/ui/box_collection.rs:32:15
+ --> tests/ui/box_collection.rs:31:15
|
LL | fn test4(foo: Box<HashMap<String, String>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@
= help: `HashMap<..>` is already on the heap, `Box<HashMap<..>>` makes an extra allocation
error: you seem to be trying to use `Box<HashSet<..>>`. Consider using just `HashSet<..>`
- --> tests/ui/box_collection.rs:35:15
+ --> tests/ui/box_collection.rs:34:15
|
LL | fn test5(foo: Box<HashSet<i64>>) {}
| ^^^^^^^^^^^^^^^^^
@@ -33,7 +33,7 @@
= help: `HashSet<..>` is already on the heap, `Box<HashSet<..>>` makes an extra allocation
error: you seem to be trying to use `Box<VecDeque<..>>`. Consider using just `VecDeque<..>`
- --> tests/ui/box_collection.rs:38:15
+ --> tests/ui/box_collection.rs:37:15
|
LL | fn test6(foo: Box<VecDeque<i32>>) {}
| ^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@
= help: `VecDeque<..>` is already on the heap, `Box<VecDeque<..>>` makes an extra allocation
error: you seem to be trying to use `Box<LinkedList<..>>`. Consider using just `LinkedList<..>`
- --> tests/ui/box_collection.rs:41:15
+ --> tests/ui/box_collection.rs:40:15
|
LL | fn test7(foo: Box<LinkedList<i16>>) {}
| ^^^^^^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@
= help: `LinkedList<..>` is already on the heap, `Box<LinkedList<..>>` makes an extra allocation
error: you seem to be trying to use `Box<BTreeMap<..>>`. Consider using just `BTreeMap<..>`
- --> tests/ui/box_collection.rs:44:15
+ --> tests/ui/box_collection.rs:43:15
|
LL | fn test8(foo: Box<BTreeMap<i8, String>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -57,7 +57,7 @@
= help: `BTreeMap<..>` is already on the heap, `Box<BTreeMap<..>>` makes an extra allocation
error: you seem to be trying to use `Box<BTreeSet<..>>`. Consider using just `BTreeSet<..>`
- --> tests/ui/box_collection.rs:47:15
+ --> tests/ui/box_collection.rs:46:15
|
LL | fn test9(foo: Box<BTreeSet<u64>>) {}
| ^^^^^^^^^^^^^^^^^^
@@ -65,7 +65,7 @@
= help: `BTreeSet<..>` is already on the heap, `Box<BTreeSet<..>>` makes an extra allocation
error: you seem to be trying to use `Box<BinaryHeap<..>>`. Consider using just `BinaryHeap<..>`
- --> tests/ui/box_collection.rs:50:16
+ --> tests/ui/box_collection.rs:49:16
|
LL | fn test10(foo: Box<BinaryHeap<u32>>) {}
| ^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed
index bf7635f..0c9d212 100644
--- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed
+++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed
@@ -1,5 +1,4 @@
#![warn(clippy::case_sensitive_file_extension_comparisons)]
-#![allow(clippy::unnecessary_map_or)]
use std::string::String;
@@ -13,7 +12,7 @@
fn is_rust_file(filename: &str) -> bool {
std::path::Path::new(filename)
.extension()
- .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
+ .is_some_and(|ext| ext.eq_ignore_ascii_case("rs"))
//~^ case_sensitive_file_extension_comparisons
}
@@ -21,18 +20,18 @@
// std::string::String and &str should trigger the lint failure with .ext12
let _ = std::path::Path::new(&String::new())
.extension()
- .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
+ .is_some_and(|ext| ext.eq_ignore_ascii_case("ext12"));
//~^ case_sensitive_file_extension_comparisons
let _ = std::path::Path::new("str")
.extension()
- .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
+ .is_some_and(|ext| ext.eq_ignore_ascii_case("ext12"));
//~^ case_sensitive_file_extension_comparisons
// The fixup should preserve the indentation level
{
let _ = std::path::Path::new("str")
.extension()
- .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
+ .is_some_and(|ext| ext.eq_ignore_ascii_case("ext12"));
//~^ case_sensitive_file_extension_comparisons
}
@@ -42,11 +41,11 @@
// std::string::String and &str should trigger the lint failure with .EXT12
let _ = std::path::Path::new(&String::new())
.extension()
- .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12"));
+ .is_some_and(|ext| ext.eq_ignore_ascii_case("EXT12"));
//~^ case_sensitive_file_extension_comparisons
let _ = std::path::Path::new("str")
.extension()
- .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12"));
+ .is_some_and(|ext| ext.eq_ignore_ascii_case("EXT12"));
//~^ case_sensitive_file_extension_comparisons
// Should not trigger the lint failure because of the calls to to_lowercase and to_uppercase
@@ -76,3 +75,11 @@
let _ = "str".ends_with(".123");
TestStruct {}.ends_with(".123");
}
+
+#[clippy::msrv = "1.69"]
+fn msrv_check() {
+ let _ = std::path::Path::new(&String::new())
+ .extension()
+ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
+ //~^ case_sensitive_file_extension_comparisons
+}
diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs
index 0c4070a..f8a947a 100644
--- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs
+++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs
@@ -1,5 +1,4 @@
#![warn(clippy::case_sensitive_file_extension_comparisons)]
-#![allow(clippy::unnecessary_map_or)]
use std::string::String;
@@ -64,3 +63,9 @@ fn main() {
let _ = "str".ends_with(".123");
TestStruct {}.ends_with(".123");
}
+
+#[clippy::msrv = "1.69"]
+fn msrv_check() {
+ let _ = String::new().ends_with(".ext12");
+ //~^ case_sensitive_file_extension_comparisons
+}
diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr
index e035534..93bee8e 100644
--- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr
+++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr
@@ -1,5 +1,5 @@
error: case-sensitive file extension comparison
- --> tests/ui/case_sensitive_file_extension_comparisons.rs:14:5
+ --> tests/ui/case_sensitive_file_extension_comparisons.rs:13:5
|
LL | filename.ends_with(".rs")
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -11,11 +11,81 @@
|
LL ~ std::path::Path::new(filename)
LL + .extension()
-LL + .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
+LL + .is_some_and(|ext| ext.eq_ignore_ascii_case("rs"))
|
error: case-sensitive file extension comparison
- --> tests/ui/case_sensitive_file_extension_comparisons.rs:20:13
+ --> tests/ui/case_sensitive_file_extension_comparisons.rs:19:13
+ |
+LL | let _ = String::new().ends_with(".ext12");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using a case-insensitive comparison instead
+help: use std::path::Path
+ |
+LL ~ let _ = std::path::Path::new(&String::new())
+LL + .extension()
+LL ~ .is_some_and(|ext| ext.eq_ignore_ascii_case("ext12"));
+ |
+
+error: case-sensitive file extension comparison
+ --> tests/ui/case_sensitive_file_extension_comparisons.rs:21:13
+ |
+LL | let _ = "str".ends_with(".ext12");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using a case-insensitive comparison instead
+help: use std::path::Path
+ |
+LL ~ let _ = std::path::Path::new("str")
+LL + .extension()
+LL ~ .is_some_and(|ext| ext.eq_ignore_ascii_case("ext12"));
+ |
+
+error: case-sensitive file extension comparison
+ --> tests/ui/case_sensitive_file_extension_comparisons.rs:26:17
+ |
+LL | let _ = "str".ends_with(".ext12");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using a case-insensitive comparison instead
+help: use std::path::Path
+ |
+LL ~ let _ = std::path::Path::new("str")
+LL + .extension()
+LL ~ .is_some_and(|ext| ext.eq_ignore_ascii_case("ext12"));
+ |
+
+error: case-sensitive file extension comparison
+ --> tests/ui/case_sensitive_file_extension_comparisons.rs:34:13
+ |
+LL | let _ = String::new().ends_with(".EXT12");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using a case-insensitive comparison instead
+help: use std::path::Path
+ |
+LL ~ let _ = std::path::Path::new(&String::new())
+LL + .extension()
+LL ~ .is_some_and(|ext| ext.eq_ignore_ascii_case("EXT12"));
+ |
+
+error: case-sensitive file extension comparison
+ --> tests/ui/case_sensitive_file_extension_comparisons.rs:36:13
+ |
+LL | let _ = "str".ends_with(".EXT12");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using a case-insensitive comparison instead
+help: use std::path::Path
+ |
+LL ~ let _ = std::path::Path::new("str")
+LL + .extension()
+LL ~ .is_some_and(|ext| ext.eq_ignore_ascii_case("EXT12"));
+ |
+
+error: case-sensitive file extension comparison
+ --> tests/ui/case_sensitive_file_extension_comparisons.rs:69:13
|
LL | let _ = String::new().ends_with(".ext12");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -28,61 +98,5 @@
LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
|
-error: case-sensitive file extension comparison
- --> tests/ui/case_sensitive_file_extension_comparisons.rs:22:13
- |
-LL | let _ = "str".ends_with(".ext12");
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider using a case-insensitive comparison instead
-help: use std::path::Path
- |
-LL ~ let _ = std::path::Path::new("str")
-LL + .extension()
-LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
- |
-
-error: case-sensitive file extension comparison
- --> tests/ui/case_sensitive_file_extension_comparisons.rs:27:17
- |
-LL | let _ = "str".ends_with(".ext12");
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider using a case-insensitive comparison instead
-help: use std::path::Path
- |
-LL ~ let _ = std::path::Path::new("str")
-LL + .extension()
-LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
- |
-
-error: case-sensitive file extension comparison
- --> tests/ui/case_sensitive_file_extension_comparisons.rs:35:13
- |
-LL | let _ = String::new().ends_with(".EXT12");
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider using a case-insensitive comparison instead
-help: use std::path::Path
- |
-LL ~ let _ = std::path::Path::new(&String::new())
-LL + .extension()
-LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12"));
- |
-
-error: case-sensitive file extension comparison
- --> tests/ui/case_sensitive_file_extension_comparisons.rs:37:13
- |
-LL | let _ = "str".ends_with(".EXT12");
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: consider using a case-insensitive comparison instead
-help: use std::path::Path
- |
-LL ~ let _ = std::path::Path::new("str")
-LL + .extension()
-LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12"));
- |
-
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
diff --git a/src/tools/clippy/tests/ui/char_indices_as_byte_indices.fixed b/src/tools/clippy/tests/ui/char_indices_as_byte_indices.fixed
new file mode 100644
index 0000000..04c8f67
--- /dev/null
+++ b/src/tools/clippy/tests/ui/char_indices_as_byte_indices.fixed
@@ -0,0 +1,65 @@
+#![feature(round_char_boundary)]
+#![warn(clippy::char_indices_as_byte_indices)]
+
+trait StrExt {
+ fn use_index(&self, _: usize);
+}
+impl StrExt for str {
+ fn use_index(&self, _: usize) {}
+}
+
+fn bad(prim: &str, string: String) {
+ for (idx, _) in prim.char_indices() {
+ let _ = prim[..idx];
+ //~^ char_indices_as_byte_indices
+ prim.split_at(idx);
+ //~^ char_indices_as_byte_indices
+
+ // This won't panic, but it can still return a wrong substring
+ let _ = prim[..prim.floor_char_boundary(idx)];
+ //~^ char_indices_as_byte_indices
+
+ // can't use #[expect] here because the .fixed file will still have the attribute and create an
+ // unfulfilled expectation, but make sure lint level attributes work on the use expression:
+ #[allow(clippy::char_indices_as_byte_indices)]
+ let _ = prim[..idx];
+ }
+
+ for c in prim.char_indices() {
+ let _ = prim[..c.0];
+ //~^ char_indices_as_byte_indices
+ prim.split_at(c.0);
+ //~^ char_indices_as_byte_indices
+ }
+
+ for (idx, _) in string.char_indices() {
+ let _ = string[..idx];
+ //~^ char_indices_as_byte_indices
+ string.split_at(idx);
+ //~^ char_indices_as_byte_indices
+ }
+}
+
+fn good(prim: &str, prim2: &str) {
+ for (idx, _) in prim.chars().enumerate() {
+ // Indexing into a different string
+ let _ = prim2[..idx];
+
+ // Unknown use
+ std::hint::black_box(idx);
+
+ // Method call to user defined extension trait
+ prim.use_index(idx);
+
+ // str method taking a usize that doesn't represent a byte index
+ prim.splitn(idx, prim2);
+ }
+
+ let mut string = "äa".to_owned();
+ for (idx, _) in string.clone().chars().enumerate() {
+ // Even though the receiver is the same expression, it should not be treated as the same value.
+ string.clone().remove(idx);
+ }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/char_indices_as_byte_indices.rs b/src/tools/clippy/tests/ui/char_indices_as_byte_indices.rs
new file mode 100644
index 0000000..773a4fc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/char_indices_as_byte_indices.rs
@@ -0,0 +1,65 @@
+#![feature(round_char_boundary)]
+#![warn(clippy::char_indices_as_byte_indices)]
+
+trait StrExt {
+ fn use_index(&self, _: usize);
+}
+impl StrExt for str {
+ fn use_index(&self, _: usize) {}
+}
+
+fn bad(prim: &str, string: String) {
+ for (idx, _) in prim.chars().enumerate() {
+ let _ = prim[..idx];
+ //~^ char_indices_as_byte_indices
+ prim.split_at(idx);
+ //~^ char_indices_as_byte_indices
+
+ // This won't panic, but it can still return a wrong substring
+ let _ = prim[..prim.floor_char_boundary(idx)];
+ //~^ char_indices_as_byte_indices
+
+ // can't use #[expect] here because the .fixed file will still have the attribute and create an
+ // unfulfilled expectation, but make sure lint level attributes work on the use expression:
+ #[allow(clippy::char_indices_as_byte_indices)]
+ let _ = prim[..idx];
+ }
+
+ for c in prim.chars().enumerate() {
+ let _ = prim[..c.0];
+ //~^ char_indices_as_byte_indices
+ prim.split_at(c.0);
+ //~^ char_indices_as_byte_indices
+ }
+
+ for (idx, _) in string.chars().enumerate() {
+ let _ = string[..idx];
+ //~^ char_indices_as_byte_indices
+ string.split_at(idx);
+ //~^ char_indices_as_byte_indices
+ }
+}
+
+fn good(prim: &str, prim2: &str) {
+ for (idx, _) in prim.chars().enumerate() {
+ // Indexing into a different string
+ let _ = prim2[..idx];
+
+ // Unknown use
+ std::hint::black_box(idx);
+
+ // Method call to user defined extension trait
+ prim.use_index(idx);
+
+ // str method taking a usize that doesn't represent a byte index
+ prim.splitn(idx, prim2);
+ }
+
+ let mut string = "äa".to_owned();
+ for (idx, _) in string.clone().chars().enumerate() {
+ // Even though the receiver is the same expression, it should not be treated as the same value.
+ string.clone().remove(idx);
+ }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/char_indices_as_byte_indices.stderr b/src/tools/clippy/tests/ui/char_indices_as_byte_indices.stderr
new file mode 100644
index 0000000..e2b4c1d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/char_indices_as_byte_indices.stderr
@@ -0,0 +1,130 @@
+error: indexing into a string with a character position where a byte index is expected
+ --> tests/ui/char_indices_as_byte_indices.rs:13:24
+ |
+LL | let _ = prim[..idx];
+ | ^^^
+ |
+ = note: a character can take up more than one byte, so they are not interchangeable
+note: position comes from the enumerate iterator
+ --> tests/ui/char_indices_as_byte_indices.rs:12:10
+ |
+LL | for (idx, _) in prim.chars().enumerate() {
+ | ^^^ ^^^^^^^^^^^
+ = note: `-D clippy::char-indices-as-byte-indices` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::char_indices_as_byte_indices)]`
+help: consider using `.char_indices()` instead
+ |
+LL - for (idx, _) in prim.chars().enumerate() {
+LL + for (idx, _) in prim.char_indices() {
+ |
+
+error: passing a character position to a method that expects a byte index
+ --> tests/ui/char_indices_as_byte_indices.rs:15:23
+ |
+LL | prim.split_at(idx);
+ | ^^^
+ |
+ = note: a character can take up more than one byte, so they are not interchangeable
+note: position comes from the enumerate iterator
+ --> tests/ui/char_indices_as_byte_indices.rs:12:10
+ |
+LL | for (idx, _) in prim.chars().enumerate() {
+ | ^^^ ^^^^^^^^^^^
+help: consider using `.char_indices()` instead
+ |
+LL - for (idx, _) in prim.chars().enumerate() {
+LL + for (idx, _) in prim.char_indices() {
+ |
+
+error: passing a character position to a method that expects a byte index
+ --> tests/ui/char_indices_as_byte_indices.rs:19:49
+ |
+LL | let _ = prim[..prim.floor_char_boundary(idx)];
+ | ^^^
+ |
+ = note: a character can take up more than one byte, so they are not interchangeable
+note: position comes from the enumerate iterator
+ --> tests/ui/char_indices_as_byte_indices.rs:12:10
+ |
+LL | for (idx, _) in prim.chars().enumerate() {
+ | ^^^ ^^^^^^^^^^^
+help: consider using `.char_indices()` instead
+ |
+LL - for (idx, _) in prim.chars().enumerate() {
+LL + for (idx, _) in prim.char_indices() {
+ |
+
+error: indexing into a string with a character position where a byte index is expected
+ --> tests/ui/char_indices_as_byte_indices.rs:29:24
+ |
+LL | let _ = prim[..c.0];
+ | ^^^
+ |
+ = note: a character can take up more than one byte, so they are not interchangeable
+note: position comes from the enumerate iterator
+ --> tests/ui/char_indices_as_byte_indices.rs:28:9
+ |
+LL | for c in prim.chars().enumerate() {
+ | ^ ^^^^^^^^^^^
+help: consider using `.char_indices()` instead
+ |
+LL - for c in prim.chars().enumerate() {
+LL + for c in prim.char_indices() {
+ |
+
+error: passing a character position to a method that expects a byte index
+ --> tests/ui/char_indices_as_byte_indices.rs:31:23
+ |
+LL | prim.split_at(c.0);
+ | ^^^
+ |
+ = note: a character can take up more than one byte, so they are not interchangeable
+note: position comes from the enumerate iterator
+ --> tests/ui/char_indices_as_byte_indices.rs:28:9
+ |
+LL | for c in prim.chars().enumerate() {
+ | ^ ^^^^^^^^^^^
+help: consider using `.char_indices()` instead
+ |
+LL - for c in prim.chars().enumerate() {
+LL + for c in prim.char_indices() {
+ |
+
+error: indexing into a string with a character position where a byte index is expected
+ --> tests/ui/char_indices_as_byte_indices.rs:36:26
+ |
+LL | let _ = string[..idx];
+ | ^^^
+ |
+ = note: a character can take up more than one byte, so they are not interchangeable
+note: position comes from the enumerate iterator
+ --> tests/ui/char_indices_as_byte_indices.rs:35:10
+ |
+LL | for (idx, _) in string.chars().enumerate() {
+ | ^^^ ^^^^^^^^^^^
+help: consider using `.char_indices()` instead
+ |
+LL - for (idx, _) in string.chars().enumerate() {
+LL + for (idx, _) in string.char_indices() {
+ |
+
+error: passing a character position to a method that expects a byte index
+ --> tests/ui/char_indices_as_byte_indices.rs:38:25
+ |
+LL | string.split_at(idx);
+ | ^^^
+ |
+ = note: a character can take up more than one byte, so they are not interchangeable
+note: position comes from the enumerate iterator
+ --> tests/ui/char_indices_as_byte_indices.rs:35:10
+ |
+LL | for (idx, _) in string.chars().enumerate() {
+ | ^^^ ^^^^^^^^^^^
+help: consider using `.char_indices()` instead
+ |
+LL - for (idx, _) in string.chars().enumerate() {
+LL + for (idx, _) in string.char_indices() {
+ |
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
index c17eaef..bdac1e4 100644
--- a/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
+++ b/src/tools/clippy/tests/ui/checked_unwrap/simple_conditionals.stderr
@@ -244,8 +244,7 @@
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
= note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
- = note: `-D static-mut-refs` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(static_mut_refs)]`
+ = note: `#[deny(static_mut_refs)]` on by default
error: aborting due to 26 previous errors
diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed
index eb01633..85d0991 100644
--- a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed
+++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed
@@ -74,3 +74,12 @@
Baz
}
}
+
+fn issue_8103() {
+ let foo1 = String::from("foo");
+ let _ = foo1 == "foo";
+ //~^ cmp_owned
+ let foo2 = "foo";
+ let _ = foo1 == foo2;
+ //~^ cmp_owned
+}
diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs
index 82409f2..2393757 100644
--- a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs
+++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs
@@ -74,3 +74,12 @@ fn to_owned(&self) -> Baz {
Baz
}
}
+
+fn issue_8103() {
+ let foo1 = String::from("foo");
+ let _ = foo1 == "foo".to_owned();
+ //~^ cmp_owned
+ let foo2 = "foo";
+ let _ = foo1 == foo2.to_owned();
+ //~^ cmp_owned
+}
diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr
index ca2ab44..dd9ffa7 100644
--- a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr
+++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.stderr
@@ -37,5 +37,17 @@
LL | "abc".chars().filter(|c| c.to_owned() != 'X');
| ^^^^^^^^^^^^ help: try: `*c`
-error: aborting due to 6 previous errors
+error: this creates an owned instance just for comparison
+ --> tests/ui/cmp_owned/with_suggestion.rs:80:21
+ |
+LL | let _ = foo1 == "foo".to_owned();
+ | ^^^^^^^^^^^^^^^^ help: try: `"foo"`
+
+error: this creates an owned instance just for comparison
+ --> tests/ui/cmp_owned/with_suggestion.rs:83:21
+ |
+LL | let _ = foo1 == foo2.to_owned();
+ | ^^^^^^^^^^^^^^^ help: try: `foo2`
+
+error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui/cognitive_complexity.rs b/src/tools/clippy/tests/ui/cognitive_complexity.rs
index 2dbec95..8080c67 100644
--- a/src/tools/clippy/tests/ui/cognitive_complexity.rs
+++ b/src/tools/clippy/tests/ui/cognitive_complexity.rs
@@ -1,6 +1,11 @@
-#![allow(clippy::all)]
#![warn(clippy::cognitive_complexity)]
-#![allow(unused, unused_crate_dependencies)]
+#![allow(
+ clippy::eq_op,
+ clippy::needless_borrows_for_generic_args,
+ clippy::needless_return,
+ clippy::nonminimal_bool,
+ clippy::uninlined_format_args
+)]
#[rustfmt::skip]
fn main() {
@@ -448,3 +453,22 @@ pub async fn async_method() {
}
}
}
+
+#[clippy::cognitive_complexity = "1"]
+mod issue14422 {
+ fn foo() {
+ //~^ cognitive_complexity
+ for _ in 0..10 {
+ println!("hello there");
+ }
+ }
+
+ fn bar() {
+ //~^ cognitive_complexity
+ for _ in 0..10 {
+ println!("hello there");
+ }
+ return;
+ return;
+ }
+}
diff --git a/src/tools/clippy/tests/ui/cognitive_complexity.stderr b/src/tools/clippy/tests/ui/cognitive_complexity.stderr
index 52607b8..67ef4e5 100644
--- a/src/tools/clippy/tests/ui/cognitive_complexity.stderr
+++ b/src/tools/clippy/tests/ui/cognitive_complexity.stderr
@@ -1,5 +1,5 @@
error: the function has a cognitive complexity of (28/25)
- --> tests/ui/cognitive_complexity.rs:6:4
+ --> tests/ui/cognitive_complexity.rs:11:4
|
LL | fn main() {
| ^^^^
@@ -9,7 +9,7 @@
= help: to override `-D warnings` add `#[allow(clippy::cognitive_complexity)]`
error: the function has a cognitive complexity of (7/1)
- --> tests/ui/cognitive_complexity.rs:93:4
+ --> tests/ui/cognitive_complexity.rs:98:4
|
LL | fn kaboom() {
| ^^^^^^
@@ -17,7 +17,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (2/1)
- --> tests/ui/cognitive_complexity.rs:153:4
+ --> tests/ui/cognitive_complexity.rs:158:4
|
LL | fn baa() {
| ^^^
@@ -25,7 +25,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (2/1)
- --> tests/ui/cognitive_complexity.rs:156:13
+ --> tests/ui/cognitive_complexity.rs:161:13
|
LL | let x = || match 99 {
| ^^
@@ -33,7 +33,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (2/1)
- --> tests/ui/cognitive_complexity.rs:174:4
+ --> tests/ui/cognitive_complexity.rs:179:4
|
LL | fn bar() {
| ^^^
@@ -41,7 +41,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (2/1)
- --> tests/ui/cognitive_complexity.rs:187:4
+ --> tests/ui/cognitive_complexity.rs:192:4
|
LL | fn dont_warn_on_tests() {
| ^^^^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (2/1)
- --> tests/ui/cognitive_complexity.rs:197:4
+ --> tests/ui/cognitive_complexity.rs:202:4
|
LL | fn barr() {
| ^^^^
@@ -57,7 +57,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (3/1)
- --> tests/ui/cognitive_complexity.rs:209:4
+ --> tests/ui/cognitive_complexity.rs:214:4
|
LL | fn barr2() {
| ^^^^^
@@ -65,7 +65,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (2/1)
- --> tests/ui/cognitive_complexity.rs:227:4
+ --> tests/ui/cognitive_complexity.rs:232:4
|
LL | fn barrr() {
| ^^^^^
@@ -73,7 +73,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (3/1)
- --> tests/ui/cognitive_complexity.rs:239:4
+ --> tests/ui/cognitive_complexity.rs:244:4
|
LL | fn barrr2() {
| ^^^^^^
@@ -81,7 +81,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (2/1)
- --> tests/ui/cognitive_complexity.rs:257:4
+ --> tests/ui/cognitive_complexity.rs:262:4
|
LL | fn barrrr() {
| ^^^^^^
@@ -89,7 +89,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (3/1)
- --> tests/ui/cognitive_complexity.rs:269:4
+ --> tests/ui/cognitive_complexity.rs:274:4
|
LL | fn barrrr2() {
| ^^^^^^^
@@ -97,7 +97,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (2/1)
- --> tests/ui/cognitive_complexity.rs:287:4
+ --> tests/ui/cognitive_complexity.rs:292:4
|
LL | fn cake() {
| ^^^^
@@ -105,7 +105,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (4/1)
- --> tests/ui/cognitive_complexity.rs:299:8
+ --> tests/ui/cognitive_complexity.rs:304:8
|
LL | pub fn read_file(input_path: &str) -> String {
| ^^^^^^^^^
@@ -113,7 +113,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (2/1)
- --> tests/ui/cognitive_complexity.rs:332:4
+ --> tests/ui/cognitive_complexity.rs:337:4
|
LL | fn void(void: Void) {
| ^^^^
@@ -121,7 +121,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (8/1)
- --> tests/ui/cognitive_complexity.rs:385:4
+ --> tests/ui/cognitive_complexity.rs:390:4
|
LL | fn early_ret() -> i32 {
| ^^^^^^^^^
@@ -129,7 +129,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (2/1)
- --> tests/ui/cognitive_complexity.rs:408:13
+ --> tests/ui/cognitive_complexity.rs:413:13
|
LL | let x = |a: i32, b: i32| -> i32 {
| ^^^^^^^^^^^^^^^^
@@ -137,7 +137,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (2/1)
- --> tests/ui/cognitive_complexity.rs:423:8
+ --> tests/ui/cognitive_complexity.rs:428:8
|
LL | fn moo(&self) {
| ^^^
@@ -145,7 +145,7 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (2/1)
- --> tests/ui/cognitive_complexity.rs:434:14
+ --> tests/ui/cognitive_complexity.rs:439:14
|
LL | async fn a() {
| ^
@@ -153,12 +153,28 @@
= help: you could split it up into multiple smaller functions
error: the function has a cognitive complexity of (2/1)
- --> tests/ui/cognitive_complexity.rs:443:22
+ --> tests/ui/cognitive_complexity.rs:448:22
|
LL | pub async fn async_method() {
| ^^^^^^^^^^^^
|
= help: you could split it up into multiple smaller functions
-error: aborting due to 20 previous errors
+error: the function has a cognitive complexity of (2/1)
+ --> tests/ui/cognitive_complexity.rs:459:8
+ |
+LL | fn foo() {
+ | ^^^
+ |
+ = help: you could split it up into multiple smaller functions
+
+error: the function has a cognitive complexity of (2/1)
+ --> tests/ui/cognitive_complexity.rs:466:8
+ |
+LL | fn bar() {
+ | ^^^
+ |
+ = help: you could split it up into multiple smaller functions
+
+error: aborting due to 22 previous errors
diff --git a/src/tools/clippy/tests/ui/collapsible_if.fixed b/src/tools/clippy/tests/ui/collapsible_if.fixed
index 6e99401..e1ceb04 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.fixed
+++ b/src/tools/clippy/tests/ui/collapsible_if.fixed
@@ -12,34 +12,40 @@
fn main() {
let x = "hello";
let y = "world";
- if x == "hello" && y == "world" {
- println!("Hello world!");
- }
+ if x == "hello"
+ && y == "world" {
+ println!("Hello world!");
+ }
//~^^^^^ collapsible_if
- if (x == "hello" || x == "world") && (y == "world" || y == "hello") {
- println!("Hello world!");
- }
+ if (x == "hello" || x == "world")
+ && (y == "world" || y == "hello") {
+ println!("Hello world!");
+ }
//~^^^^^ collapsible_if
- if x == "hello" && x == "world" && (y == "world" || y == "hello") {
- println!("Hello world!");
- }
+ if x == "hello" && x == "world"
+ && (y == "world" || y == "hello") {
+ println!("Hello world!");
+ }
//~^^^^^ collapsible_if
- if (x == "hello" || x == "world") && y == "world" && y == "hello" {
- println!("Hello world!");
- }
+ if (x == "hello" || x == "world")
+ && y == "world" && y == "hello" {
+ println!("Hello world!");
+ }
//~^^^^^ collapsible_if
- if x == "hello" && x == "world" && y == "world" && y == "hello" {
- println!("Hello world!");
- }
+ if x == "hello" && x == "world"
+ && y == "world" && y == "hello" {
+ println!("Hello world!");
+ }
//~^^^^^ collapsible_if
- if 42 == 1337 && 'a' != 'A' {
- println!("world!")
- }
+ if 42 == 1337
+ && 'a' != 'A' {
+ println!("world!")
+ }
//~^^^^^ collapsible_if
// Works because any if with an else statement cannot be collapsed.
@@ -71,60 +77,27 @@
assert!(true); // assert! is just an `if`
}
-
- // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798
- if x == "hello" {// Not collapsible
- if y == "world" {
+ if x == "hello"
+ && y == "world" { // Collapsible
println!("Hello world!");
}
- }
-
- if x == "hello" { // Not collapsible
- if y == "world" {
- println!("Hello world!");
- }
- }
-
- if x == "hello" {
- // Not collapsible
- if y == "world" {
- println!("Hello world!");
- }
- }
-
- if x == "hello" && y == "world" { // Collapsible
- println!("Hello world!");
- }
//~^^^^^ collapsible_if
if x == "hello" {
print!("Hello ");
} else {
// Not collapsible
- if y == "world" {
- println!("world!")
- }
- }
-
- if x == "hello" {
- print!("Hello ");
- } else {
- // Not collapsible
if let Some(42) = Some(42) {
println!("world!")
}
}
if x == "hello" {
- /* Not collapsible */
+ print!("Hello ");
+ } else {
+ // Not collapsible
if y == "world" {
- println!("Hello world!");
- }
- }
-
- if x == "hello" { /* Not collapsible */
- if y == "world" {
- println!("Hello world!");
+ println!("world!")
}
}
@@ -150,11 +123,13 @@
}
// Fix #5962
- if matches!(true, true) && matches!(true, true) {}
+ if matches!(true, true)
+ && matches!(true, true) {}
//~^^^ collapsible_if
// Issue #9375
- if matches!(true, true) && truth() && matches!(true, true) {}
+ if matches!(true, true) && truth()
+ && matches!(true, true) {}
//~^^^ collapsible_if
if true {
@@ -163,4 +138,27 @@
println!("Hello world!");
}
}
+
+ if true
+ && true {
+ println!("No comment, linted");
+ }
+ //~^^^^^ collapsible_if
+
+ if true {
+ // Do not collapse because of this comment
+ if true {
+ println!("Hello world!");
+ }
+ }
+}
+
+#[rustfmt::skip]
+fn layout_check() -> u32 {
+ if true
+ && true {
+ }
+ // This is a comment, do not collapse code to it
+ ; 3
+ //~^^^^^ collapsible_if
}
diff --git a/src/tools/clippy/tests/ui/collapsible_if.rs b/src/tools/clippy/tests/ui/collapsible_if.rs
index 5cf591a..0b996dc 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.rs
+++ b/src/tools/clippy/tests/ui/collapsible_if.rs
@@ -83,27 +83,6 @@ fn main() {
assert!(true); // assert! is just an `if`
}
-
- // The following tests check for the fix of https://github.com/rust-lang/rust-clippy/issues/798
- if x == "hello" {// Not collapsible
- if y == "world" {
- println!("Hello world!");
- }
- }
-
- if x == "hello" { // Not collapsible
- if y == "world" {
- println!("Hello world!");
- }
- }
-
- if x == "hello" {
- // Not collapsible
- if y == "world" {
- println!("Hello world!");
- }
- }
-
if x == "hello" {
if y == "world" { // Collapsible
println!("Hello world!");
@@ -115,7 +94,7 @@ fn main() {
print!("Hello ");
} else {
// Not collapsible
- if y == "world" {
+ if let Some(42) = Some(42) {
println!("world!")
}
}
@@ -124,24 +103,11 @@ fn main() {
print!("Hello ");
} else {
// Not collapsible
- if let Some(42) = Some(42) {
+ if y == "world" {
println!("world!")
}
}
- if x == "hello" {
- /* Not collapsible */
- if y == "world" {
- println!("Hello world!");
- }
- }
-
- if x == "hello" { /* Not collapsible */
- if y == "world" {
- println!("Hello world!");
- }
- }
-
// Test behavior wrt. `let_chains`.
// None of the cases below should be collapsed.
fn truth() -> bool { true }
@@ -181,4 +147,28 @@ fn truth() -> bool { true }
println!("Hello world!");
}
}
+
+ if true {
+ if true {
+ println!("No comment, linted");
+ }
+ }
+ //~^^^^^ collapsible_if
+
+ if true {
+ // Do not collapse because of this comment
+ if true {
+ println!("Hello world!");
+ }
+ }
+}
+
+#[rustfmt::skip]
+fn layout_check() -> u32 {
+ if true {
+ if true {
+ }
+ // This is a comment, do not collapse code to it
+ }; 3
+ //~^^^^^ collapsible_if
}
diff --git a/src/tools/clippy/tests/ui/collapsible_if.stderr b/src/tools/clippy/tests/ui/collapsible_if.stderr
index 3cc3fe5..5328114 100644
--- a/src/tools/clippy/tests/ui/collapsible_if.stderr
+++ b/src/tools/clippy/tests/ui/collapsible_if.stderr
@@ -12,9 +12,10 @@
= help: to override `-D warnings` add `#[allow(clippy::collapsible_if)]`
help: collapse nested if block
|
-LL ~ if x == "hello" && y == "world" {
-LL + println!("Hello world!");
-LL + }
+LL ~ if x == "hello"
+LL ~ && y == "world" {
+LL | println!("Hello world!");
+LL ~ }
|
error: this `if` statement can be collapsed
@@ -29,9 +30,10 @@
|
help: collapse nested if block
|
-LL ~ if (x == "hello" || x == "world") && (y == "world" || y == "hello") {
-LL + println!("Hello world!");
-LL + }
+LL ~ if (x == "hello" || x == "world") {
+LL ~ && (y == "world" || y == "hello") {
+LL | println!("Hello world!");
+LL ~ }
|
error: this `if` statement can be collapsed
@@ -46,9 +48,10 @@
|
help: collapse nested if block
|
-LL ~ if x == "hello" && x == "world" && (y == "world" || y == "hello") {
-LL + println!("Hello world!");
-LL + }
+LL ~ if x == "hello" && x == "world"
+LL ~ && (y == "world" || y == "hello") {
+LL | println!("Hello world!");
+LL ~ }
|
error: this `if` statement can be collapsed
@@ -63,9 +66,10 @@
|
help: collapse nested if block
|
-LL ~ if (x == "hello" || x == "world") && y == "world" && y == "hello" {
-LL + println!("Hello world!");
-LL + }
+LL ~ if (x == "hello" || x == "world") {
+LL ~ && y == "world" && y == "hello" {
+LL | println!("Hello world!");
+LL ~ }
|
error: this `if` statement can be collapsed
@@ -80,9 +84,10 @@
|
help: collapse nested if block
|
-LL ~ if x == "hello" && x == "world" && y == "world" && y == "hello" {
-LL + println!("Hello world!");
-LL + }
+LL ~ if x == "hello" && x == "world"
+LL ~ && y == "world" && y == "hello" {
+LL | println!("Hello world!");
+LL ~ }
|
error: this `if` statement can be collapsed
@@ -97,13 +102,14 @@
|
help: collapse nested if block
|
-LL ~ if 42 == 1337 && 'a' != 'A' {
-LL + println!("world!")
-LL + }
+LL ~ if 42 == 1337
+LL ~ && 'a' != 'A' {
+LL | println!("world!")
+LL ~ }
|
error: this `if` statement can be collapsed
- --> tests/ui/collapsible_if.rs:107:5
+ --> tests/ui/collapsible_if.rs:86:5
|
LL | / if x == "hello" {
LL | | if y == "world" { // Collapsible
@@ -114,26 +120,75 @@
|
help: collapse nested if block
|
-LL ~ if x == "hello" && y == "world" { // Collapsible
-LL + println!("Hello world!");
-LL + }
+LL ~ if x == "hello"
+LL ~ && y == "world" { // Collapsible
+LL | println!("Hello world!");
+LL ~ }
|
error: this `if` statement can be collapsed
- --> tests/ui/collapsible_if.rs:167:5
+ --> tests/ui/collapsible_if.rs:133:5
|
LL | / if matches!(true, true) {
LL | | if matches!(true, true) {}
LL | | }
- | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}`
+ | |_____^
+ |
+help: collapse nested if block
+ |
+LL ~ if matches!(true, true)
+LL ~ && matches!(true, true) {}
+ |
error: this `if` statement can be collapsed
- --> tests/ui/collapsible_if.rs:173:5
+ --> tests/ui/collapsible_if.rs:139:5
|
LL | / if matches!(true, true) && truth() {
LL | | if matches!(true, true) {}
LL | | }
- | |_____^ help: collapse nested if block: `if matches!(true, true) && truth() && matches!(true, true) {}`
+ | |_____^
+ |
+help: collapse nested if block
+ |
+LL ~ if matches!(true, true) && truth()
+LL ~ && matches!(true, true) {}
+ |
-error: aborting due to 9 previous errors
+error: this `if` statement can be collapsed
+ --> tests/ui/collapsible_if.rs:151:5
+ |
+LL | / if true {
+LL | | if true {
+LL | | println!("No comment, linted");
+LL | | }
+LL | | }
+ | |_____^
+ |
+help: collapse nested if block
+ |
+LL ~ if true
+LL ~ && true {
+LL | println!("No comment, linted");
+LL ~ }
+ |
+
+error: this `if` statement can be collapsed
+ --> tests/ui/collapsible_if.rs:168:5
+ |
+LL | / if true {
+LL | | if true {
+... |
+LL | | }; 3
+ | |_____^
+ |
+help: collapse nested if block
+ |
+LL ~ if true
+LL ~ && true {
+LL | }
+LL | // This is a comment, do not collapse code to it
+LL ~ ; 3
+ |
+
+error: aborting due to 11 previous errors
diff --git a/src/tools/clippy/tests/ui/collapsible_if_let_chains.fixed b/src/tools/clippy/tests/ui/collapsible_if_let_chains.fixed
new file mode 100644
index 0000000..3dd9498
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_if_let_chains.fixed
@@ -0,0 +1,29 @@
+#![feature(let_chains)]
+#![warn(clippy::collapsible_if)]
+
+fn main() {
+ if let Some(a) = Some(3) {
+ // with comment, so do not lint
+ if let Some(b) = Some(4) {
+ let _ = a + b;
+ }
+ }
+
+ if let Some(a) = Some(3)
+ && let Some(b) = Some(4) {
+ let _ = a + b;
+ }
+ //~^^^^^ collapsible_if
+
+ if let Some(a) = Some(3)
+ && a + 1 == 4 {
+ let _ = a;
+ }
+ //~^^^^^ collapsible_if
+
+ if Some(3) == Some(4).map(|x| x - 1)
+ && let Some(b) = Some(4) {
+ let _ = b;
+ }
+ //~^^^^^ collapsible_if
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_if_let_chains.rs b/src/tools/clippy/tests/ui/collapsible_if_let_chains.rs
new file mode 100644
index 0000000..064b9a0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_if_let_chains.rs
@@ -0,0 +1,32 @@
+#![feature(let_chains)]
+#![warn(clippy::collapsible_if)]
+
+fn main() {
+ if let Some(a) = Some(3) {
+ // with comment, so do not lint
+ if let Some(b) = Some(4) {
+ let _ = a + b;
+ }
+ }
+
+ if let Some(a) = Some(3) {
+ if let Some(b) = Some(4) {
+ let _ = a + b;
+ }
+ }
+ //~^^^^^ collapsible_if
+
+ if let Some(a) = Some(3) {
+ if a + 1 == 4 {
+ let _ = a;
+ }
+ }
+ //~^^^^^ collapsible_if
+
+ if Some(3) == Some(4).map(|x| x - 1) {
+ if let Some(b) = Some(4) {
+ let _ = b;
+ }
+ }
+ //~^^^^^ collapsible_if
+}
diff --git a/src/tools/clippy/tests/ui/collapsible_if_let_chains.stderr b/src/tools/clippy/tests/ui/collapsible_if_let_chains.stderr
new file mode 100644
index 0000000..64a8811
--- /dev/null
+++ b/src/tools/clippy/tests/ui/collapsible_if_let_chains.stderr
@@ -0,0 +1,58 @@
+error: this `if` statement can be collapsed
+ --> tests/ui/collapsible_if_let_chains.rs:12:5
+ |
+LL | / if let Some(a) = Some(3) {
+LL | | if let Some(b) = Some(4) {
+LL | | let _ = a + b;
+LL | | }
+LL | | }
+ | |_____^
+ |
+ = note: `-D clippy::collapsible-if` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::collapsible_if)]`
+help: collapse nested if block
+ |
+LL ~ if let Some(a) = Some(3)
+LL ~ && let Some(b) = Some(4) {
+LL | let _ = a + b;
+LL ~ }
+ |
+
+error: this `if` statement can be collapsed
+ --> tests/ui/collapsible_if_let_chains.rs:19:5
+ |
+LL | / if let Some(a) = Some(3) {
+LL | | if a + 1 == 4 {
+LL | | let _ = a;
+LL | | }
+LL | | }
+ | |_____^
+ |
+help: collapse nested if block
+ |
+LL ~ if let Some(a) = Some(3)
+LL ~ && a + 1 == 4 {
+LL | let _ = a;
+LL ~ }
+ |
+
+error: this `if` statement can be collapsed
+ --> tests/ui/collapsible_if_let_chains.rs:26:5
+ |
+LL | / if Some(3) == Some(4).map(|x| x - 1) {
+LL | | if let Some(b) = Some(4) {
+LL | | let _ = b;
+LL | | }
+LL | | }
+ | |_____^
+ |
+help: collapse nested if block
+ |
+LL ~ if Some(3) == Some(4).map(|x| x - 1)
+LL ~ && let Some(b) = Some(4) {
+LL | let _ = b;
+LL ~ }
+ |
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/collapsible_match.rs b/src/tools/clippy/tests/ui/collapsible_match.rs
index 796cabd..55ef558 100644
--- a/src/tools/clippy/tests/ui/collapsible_match.rs
+++ b/src/tools/clippy/tests/ui/collapsible_match.rs
@@ -303,6 +303,18 @@ pub fn test_2(x: Issue9647) {
}
}
+// https://github.com/rust-lang/rust-clippy/issues/14281
+fn lint_emitted_at_right_node(opt: Option<Result<u64, String>>) {
+ let n = match opt {
+ #[expect(clippy::collapsible_match)]
+ Some(n) => match n {
+ Ok(n) => n,
+ _ => return,
+ },
+ None => return,
+ };
+}
+
fn make<T>() -> T {
unimplemented!()
}
diff --git a/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs b/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs
index bbcd599..3352e82 100644
--- a/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs
+++ b/src/tools/clippy/tests/ui/crashes/enum-glob-import-crate.rs
@@ -1,8 +1,5 @@
//@ check-pass
-#![deny(clippy::all)]
-#![allow(unused_imports)]
-
use std::*;
fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-11230.fixed b/src/tools/clippy/tests/ui/crashes/ice-11230.fixed
index 181e1eb..c49a419 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-11230.fixed
+++ b/src/tools/clippy/tests/ui/crashes/ice-11230.fixed
@@ -12,7 +12,7 @@
// needless_collect
trait Helper<'a>: Iterator<Item = fn()> {}
+// Should not be linted because we have no idea whether the iterator has side effects
fn x(w: &mut dyn for<'a> Helper<'a>) {
- w.next().is_none();
- //~^ needless_collect
+ w.collect::<Vec<_>>().is_empty();
}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-11230.rs b/src/tools/clippy/tests/ui/crashes/ice-11230.rs
index fb05dc7..f66b7e9 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-11230.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-11230.rs
@@ -12,7 +12,7 @@ fn main() {
// needless_collect
trait Helper<'a>: Iterator<Item = fn()> {}
+// Should not be linted because we have no idea whether the iterator has side effects
fn x(w: &mut dyn for<'a> Helper<'a>) {
w.collect::<Vec<_>>().is_empty();
- //~^ needless_collect
}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-11230.stderr b/src/tools/clippy/tests/ui/crashes/ice-11230.stderr
index b4a3f67..91d5912 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-11230.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-11230.stderr
@@ -7,14 +7,5 @@
= note: `-D clippy::explicit-iter-loop` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::explicit_iter_loop)]`
-error: avoid using `collect()` when not needed
- --> tests/ui/crashes/ice-11230.rs:16:7
- |
-LL | w.collect::<Vec<_>>().is_empty();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()`
- |
- = note: `-D clippy::needless-collect` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::needless_collect)]`
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
diff --git a/src/tools/clippy/tests/ui/crashes/ice-13544-original.rs b/src/tools/clippy/tests/ui/crashes/ice-13544-original.rs
new file mode 100644
index 0000000..1709eae
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-13544-original.rs
@@ -0,0 +1,45 @@
+//@ check-pass
+#![warn(clippy::significant_drop_tightening)]
+
+use std::mem::ManuallyDrop;
+use std::ops::{Deref, DerefMut};
+
+trait Scopable: Sized {
+ type SubType: Scopable;
+}
+
+struct Subtree<T: Scopable>(ManuallyDrop<Box<Tree<T::SubType>>>);
+
+impl<T: Scopable> Drop for Subtree<T> {
+ fn drop(&mut self) {
+ // SAFETY: The field cannot be used after we drop
+ unsafe { ManuallyDrop::drop(&mut self.0) }
+ }
+}
+
+impl<T: Scopable> Deref for Subtree<T> {
+ type Target = Tree<T::SubType>;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+impl<T: Scopable> DerefMut for Subtree<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.0
+ }
+}
+
+enum Tree<T: Scopable> {
+ Group(Vec<Tree<T>>),
+ Subtree(Subtree<T>),
+ Leaf(T),
+}
+
+impl<T: Scopable> Tree<T> {
+ fn foo(self) -> Self {
+ self
+ }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-13544-reduced.rs b/src/tools/clippy/tests/ui/crashes/ice-13544-reduced.rs
new file mode 100644
index 0000000..9266e71
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-13544-reduced.rs
@@ -0,0 +1,16 @@
+//@ check-pass
+#![warn(clippy::significant_drop_tightening)]
+#![allow(unused, clippy::no_effect)]
+
+use std::marker::PhantomData;
+
+trait Trait {
+ type Assoc: Trait;
+}
+struct S<T: Trait>(*const S<T::Assoc>, PhantomData<T>);
+
+fn f<T: Trait>(x: &mut S<T>) {
+ &mut x.0;
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-1588.rs b/src/tools/clippy/tests/ui/crashes/ice-1588.rs
index 3ccd330..422c29b 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-1588.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-1588.rs
@@ -1,6 +1,6 @@
//@ check-pass
-#![allow(clippy::all)]
+#![expect(clippy::no_effect)]
// Test for https://github.com/rust-lang/rust-clippy/issues/1588
diff --git a/src/tools/clippy/tests/ui/crashes/ice-1969.rs b/src/tools/clippy/tests/ui/crashes/ice-1969.rs
index 34ff725..813972a 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-1969.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-1969.rs
@@ -1,7 +1,5 @@
//@ check-pass
-#![allow(clippy::all)]
-
// Test for https://github.com/rust-lang/rust-clippy/issues/1969
fn main() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-3462.rs b/src/tools/clippy/tests/ui/crashes/ice-3462.rs
index 4ce4849..e06eccd 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-3462.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-3462.rs
@@ -1,8 +1,6 @@
//@ check-pass
-#![warn(clippy::all)]
-#![allow(clippy::disallowed_names, clippy::equatable_if_let, clippy::needless_if)]
-#![allow(unused)]
+#![expect(clippy::disallowed_names)]
// Test for https://github.com/rust-lang/rust-clippy/issues/3462
diff --git a/src/tools/clippy/tests/ui/crashes/ice-700.rs b/src/tools/clippy/tests/ui/crashes/ice-700.rs
index aa3bf49..ca82f63 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-700.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-700.rs
@@ -1,7 +1,5 @@
//@ check-pass
-#![deny(clippy::all)]
-
// Test for https://github.com/rust-lang/rust-clippy/issues/700
fn core() {}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7012.rs b/src/tools/clippy/tests/ui/crashes/ice-7012.rs
index d76995a..48c1c5a 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-7012.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-7012.rs
@@ -1,6 +1,6 @@
//@ check-pass
-#![allow(clippy::all)]
+#![expect(clippy::single_match)]
enum _MyOption {
None,
diff --git a/src/tools/clippy/tests/ui/crashes/ice-7423.rs b/src/tools/clippy/tests/ui/crashes/ice-7423.rs
index a039818..fbf5d65 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-7423.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-7423.rs
@@ -6,7 +6,7 @@ pub trait Trait {
impl Trait for usize {
fn f() {
- extern "C" {
+ unsafe extern "C" {
fn g() -> usize;
}
}
diff --git a/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs b/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs
index cb4685e..0aa55cd 100644
--- a/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs
@@ -1,10 +1,7 @@
//@ check-pass
-#![deny(clippy::all)]
-
// Test for https://github.com/rust-lang/rust-clippy/issues/1336
-#[allow(dead_code)]
struct Foo;
impl Iterator for Foo {
diff --git a/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs b/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs
index 68e3953..1b3b029 100644
--- a/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs
+++ b/src/tools/clippy/tests/ui/crashes/needless_borrow_fp.rs
@@ -1,6 +1,5 @@
//@ check-pass
-#[deny(clippy::all)]
#[derive(Debug)]
pub enum Error {
Type(&'static str),
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed
index e09a913..9d977e9 100644
--- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed
+++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.fixed
@@ -3,7 +3,6 @@
use core::panic::PanicInfo;
-#[warn(clippy::all)]
pub fn main() {
let mut a = 42;
let mut b = 1337;
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs
index 66ca976..0967efe 100644
--- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs
+++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.rs
@@ -3,7 +3,6 @@
use core::panic::PanicInfo;
-#[warn(clippy::all)]
pub fn main() {
let mut a = 42;
let mut b = 1337;
diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr
index 3e37bd9..e16b53b 100644
--- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr
+++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_swap.stderr
@@ -1,5 +1,5 @@
error: this looks like you are trying to swap `a` and `b`
- --> tests/ui/crate_level_checks/no_std_swap.rs:11:5
+ --> tests/ui/crate_level_checks/no_std_swap.rs:10:5
|
LL | / a = b;
... |
@@ -7,8 +7,7 @@
| |_________^ help: try: `core::mem::swap(&mut a, &mut b)`
|
= note: or maybe you should use `core::mem::replace`?
- = note: `-D clippy::almost-swapped` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::almost_swapped)]`
+ = note: `#[deny(clippy::almost_swapped)]` on by default
error: aborting due to 1 previous error
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed
index fd1a0d8..3b9dee8 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.fixed
@@ -1,5 +1,10 @@
+#![allow(
+ clippy::no_effect,
+ clippy::uninlined_format_args,
+ clippy::unit_arg,
+ clippy::unnecessary_operation
+)]
#![warn(clippy::dbg_macro)]
-#![allow(clippy::unnecessary_operation, clippy::no_effect, clippy::unit_arg)]
fn foo(n: u32) -> u32 {
if let Some(n) = n.checked_sub(4) { n } else { n }
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs
index c96e2c7..1dbbc6f 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.rs
@@ -1,5 +1,10 @@
+#![allow(
+ clippy::no_effect,
+ clippy::uninlined_format_args,
+ clippy::unit_arg,
+ clippy::unnecessary_operation
+)]
#![warn(clippy::dbg_macro)]
-#![allow(clippy::unnecessary_operation, clippy::no_effect, clippy::unit_arg)]
fn foo(n: u32) -> u32 {
if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n }
diff --git a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
index cd6dce5..f141202 100644
--- a/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
+++ b/src/tools/clippy/tests/ui/dbg_macro/dbg_macro.stderr
@@ -1,5 +1,5 @@
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:5:22
+ --> tests/ui/dbg_macro/dbg_macro.rs:10:22
|
LL | if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n }
| ^^^^^^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:11:8
+ --> tests/ui/dbg_macro/dbg_macro.rs:16:8
|
LL | if dbg!(n <= 1) {
| ^^^^^^^^^^^^
@@ -25,7 +25,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:14:9
+ --> tests/ui/dbg_macro/dbg_macro.rs:19:9
|
LL | dbg!(1)
| ^^^^^^^
@@ -37,7 +37,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:17:9
+ --> tests/ui/dbg_macro/dbg_macro.rs:22:9
|
LL | dbg!(n * factorial(n - 1))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:23:5
+ --> tests/ui/dbg_macro/dbg_macro.rs:28:5
|
LL | dbg!(42);
| ^^^^^^^^
@@ -61,7 +61,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:26:14
+ --> tests/ui/dbg_macro/dbg_macro.rs:31:14
|
LL | foo(3) + dbg!(factorial(4));
| ^^^^^^^^^^^^^^^^^^
@@ -73,7 +73,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:29:5
+ --> tests/ui/dbg_macro/dbg_macro.rs:34:5
|
LL | dbg!(1, 2, 3, 4, 5);
| ^^^^^^^^^^^^^^^^^^^
@@ -85,7 +85,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:51:5
+ --> tests/ui/dbg_macro/dbg_macro.rs:56:5
|
LL | dbg!();
| ^^^^^^
@@ -96,7 +96,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:55:13
+ --> tests/ui/dbg_macro/dbg_macro.rs:60:13
|
LL | let _ = dbg!();
| ^^^^^^
@@ -108,7 +108,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:58:9
+ --> tests/ui/dbg_macro/dbg_macro.rs:63:9
|
LL | bar(dbg!());
| ^^^^^^
@@ -120,7 +120,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:61:10
+ --> tests/ui/dbg_macro/dbg_macro.rs:66:10
|
LL | foo!(dbg!());
| ^^^^^^
@@ -132,7 +132,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:64:16
+ --> tests/ui/dbg_macro/dbg_macro.rs:69:16
|
LL | foo2!(foo!(dbg!()));
| ^^^^^^
@@ -144,7 +144,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:46:13
+ --> tests/ui/dbg_macro/dbg_macro.rs:51:13
|
LL | dbg!();
| ^^^^^^
@@ -159,7 +159,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:87:9
+ --> tests/ui/dbg_macro/dbg_macro.rs:92:9
|
LL | dbg!(2);
| ^^^^^^^
@@ -171,7 +171,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:94:5
+ --> tests/ui/dbg_macro/dbg_macro.rs:99:5
|
LL | dbg!(1);
| ^^^^^^^
@@ -183,7 +183,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:100:5
+ --> tests/ui/dbg_macro/dbg_macro.rs:105:5
|
LL | dbg!(1);
| ^^^^^^^
@@ -195,7 +195,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:107:9
+ --> tests/ui/dbg_macro/dbg_macro.rs:112:9
|
LL | dbg!(1);
| ^^^^^^^
@@ -207,7 +207,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:114:31
+ --> tests/ui/dbg_macro/dbg_macro.rs:119:31
|
LL | println!("dbg: {:?}", dbg!(s));
| ^^^^^^^
@@ -219,7 +219,7 @@
|
error: the `dbg!` macro is intended as a debugging tool
- --> tests/ui/dbg_macro/dbg_macro.rs:117:22
+ --> tests/ui/dbg_macro/dbg_macro.rs:122:22
|
LL | print!("{}", dbg!(s));
| ^^^^^^^
diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs
index 03f5ca3..40f40f7 100644
--- a/src/tools/clippy/tests/ui/def_id_nocore.rs
+++ b/src/tools/clippy/tests/ui/def_id_nocore.rs
@@ -5,7 +5,7 @@
#![allow(clippy::missing_safety_doc)]
#[link(name = "c")]
-extern "C" {}
+unsafe extern "C" {}
#[lang = "sized"]
pub trait Sized {}
diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed
index fa4d551..1ca9be0c 100644
--- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed
+++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed
@@ -161,3 +161,17 @@
let _ = <struct_from_macro!()>::default();
}
+
+fn issue12654() {
+ #[derive(Default)]
+ struct G;
+
+ fn f(_g: G) {}
+
+ f(<_>::default());
+ f(G);
+ //~^ default_constructed_unit_structs
+
+ // No lint because `as Default` hides the singleton
+ f(<G as Default>::default());
+}
diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs
index 291cd89..99eb891 100644
--- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs
+++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs
@@ -161,3 +161,17 @@ macro_rules! struct_from_macro {
let _ = <struct_from_macro!()>::default();
}
+
+fn issue12654() {
+ #[derive(Default)]
+ struct G;
+
+ fn f(_g: G) {}
+
+ f(<_>::default());
+ f(<G>::default());
+ //~^ default_constructed_unit_structs
+
+ // No lint because `as Default` hides the singleton
+ f(<G as Default>::default());
+}
diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr
index 6d4e1bdc..97fad79 100644
--- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr
+++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr
@@ -1,41 +1,65 @@
error: use of `default` to create a unit struct
- --> tests/ui/default_constructed_unit_structs.rs:11:13
+ --> tests/ui/default_constructed_unit_structs.rs:11:9
|
LL | Self::default()
- | ^^^^^^^^^^^ help: remove this call to `default`
+ | ^^^^-----------
+ | |
+ | help: remove this call to `default`
|
= note: `-D clippy::default-constructed-unit-structs` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::default_constructed_unit_structs)]`
error: use of `default` to create a unit struct
- --> tests/ui/default_constructed_unit_structs.rs:54:31
+ --> tests/ui/default_constructed_unit_structs.rs:54:20
|
LL | inner: PhantomData::default(),
- | ^^^^^^^^^^^ help: remove this call to `default`
+ | ^^^^^^^^^^^-----------
+ | |
+ | help: remove this call to `default`
error: use of `default` to create a unit struct
- --> tests/ui/default_constructed_unit_structs.rs:128:33
+ --> tests/ui/default_constructed_unit_structs.rs:128:13
|
LL | let _ = PhantomData::<usize>::default();
- | ^^^^^^^^^^^ help: remove this call to `default`
+ | ^^^^^^^^^^^^^^^^^^^^-----------
+ | |
+ | help: remove this call to `default`
error: use of `default` to create a unit struct
- --> tests/ui/default_constructed_unit_structs.rs:130:42
+ --> tests/ui/default_constructed_unit_structs.rs:130:31
|
LL | let _: PhantomData<i32> = PhantomData::default();
- | ^^^^^^^^^^^ help: remove this call to `default`
+ | ^^^^^^^^^^^-----------
+ | |
+ | help: remove this call to `default`
error: use of `default` to create a unit struct
- --> tests/ui/default_constructed_unit_structs.rs:132:55
+ --> tests/ui/default_constructed_unit_structs.rs:132:31
|
LL | let _: PhantomData<i32> = std::marker::PhantomData::default();
- | ^^^^^^^^^^^ help: remove this call to `default`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^-----------
+ | |
+ | help: remove this call to `default`
error: use of `default` to create a unit struct
- --> tests/ui/default_constructed_unit_structs.rs:134:23
+ --> tests/ui/default_constructed_unit_structs.rs:134:13
|
LL | let _ = UnitStruct::default();
- | ^^^^^^^^^^^ help: remove this call to `default`
+ | ^^^^^^^^^^-----------
+ | |
+ | help: remove this call to `default`
-error: aborting due to 6 previous errors
+error: use of `default` to create a unit struct
+ --> tests/ui/default_constructed_unit_structs.rs:172:7
+ |
+LL | f(<G>::default());
+ | ^^^^^^^^^^^^^^
+ |
+help: remove this call to `default`
+ |
+LL - f(<G>::default());
+LL + f(G);
+ |
+
+error: aborting due to 7 previous errors
diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs
index 35646e1..2787f64 100644
--- a/src/tools/clippy/tests/ui/deprecated.rs
+++ b/src/tools/clippy/tests/ui/deprecated.rs
@@ -16,5 +16,6 @@
#![warn(clippy::pub_enum_variant_names)] //~ ERROR: lint `clippy::pub_enum_variant_names`
#![warn(clippy::wrong_pub_self_convention)] //~ ERROR: lint `clippy::wrong_pub_self_convention`
#![warn(clippy::option_map_or_err_ok)] //~ ERROR: lint `clippy::option_map_or_err_ok`
+#![warn(clippy::match_on_vec_items)] //~ ERROR: lint `clippy::match_on_vec_items`
fn main() {}
diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr
index d7be1e5..6047324 100644
--- a/src/tools/clippy/tests/ui/deprecated.stderr
+++ b/src/tools/clippy/tests/ui/deprecated.stderr
@@ -85,5 +85,11 @@
LL | #![warn(clippy::option_map_or_err_ok)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 14 previous errors
+error: lint `clippy::match_on_vec_items` has been removed: `clippy::indexing_slicing` covers indexing and slicing on `Vec<_>`
+ --> tests/ui/deprecated.rs:19:9
+ |
+LL | #![warn(clippy::match_on_vec_items)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 15 previous errors
diff --git a/src/tools/clippy/tests/ui/derive.rs b/src/tools/clippy/tests/ui/derive.rs
index 707a9ff..e334203 100644
--- a/src/tools/clippy/tests/ui/derive.rs
+++ b/src/tools/clippy/tests/ui/derive.rs
@@ -6,6 +6,8 @@
dead_code
)]
#![warn(clippy::expl_impl_clone_on_copy)]
+#![expect(incomplete_features)] // `unsafe_fields` is incomplete for the time being
+#![feature(unsafe_fields)] // `clone()` cannot be derived automatically on unsafe fields
#[derive(Copy)]
@@ -113,4 +115,19 @@ fn clone(&self) -> Self {
}
}
+fn issue14558() {
+ pub struct Valid {
+ pub unsafe actual: (),
+ }
+
+ unsafe impl Copy for Valid {}
+
+ impl Clone for Valid {
+ #[inline]
+ fn clone(&self) -> Self {
+ *self
+ }
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/derive.stderr b/src/tools/clippy/tests/ui/derive.stderr
index 20278d4..9004ced 100644
--- a/src/tools/clippy/tests/ui/derive.stderr
+++ b/src/tools/clippy/tests/ui/derive.stderr
@@ -1,5 +1,5 @@
error: you are implementing `Clone` explicitly on a `Copy` type
- --> tests/ui/derive.rs:14:1
+ --> tests/ui/derive.rs:16:1
|
LL | / impl Clone for Qux {
LL | |
@@ -10,7 +10,7 @@
| |_^
|
note: consider deriving `Clone` or removing `Copy`
- --> tests/ui/derive.rs:14:1
+ --> tests/ui/derive.rs:16:1
|
LL | / impl Clone for Qux {
LL | |
@@ -23,7 +23,7 @@
= help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]`
error: you are implementing `Clone` explicitly on a `Copy` type
- --> tests/ui/derive.rs:40:1
+ --> tests/ui/derive.rs:42:1
|
LL | / impl<'a> Clone for Lt<'a> {
LL | |
@@ -34,7 +34,7 @@
| |_^
|
note: consider deriving `Clone` or removing `Copy`
- --> tests/ui/derive.rs:40:1
+ --> tests/ui/derive.rs:42:1
|
LL | / impl<'a> Clone for Lt<'a> {
LL | |
@@ -45,7 +45,7 @@
| |_^
error: you are implementing `Clone` explicitly on a `Copy` type
- --> tests/ui/derive.rs:53:1
+ --> tests/ui/derive.rs:55:1
|
LL | / impl Clone for BigArray {
LL | |
@@ -56,7 +56,7 @@
| |_^
|
note: consider deriving `Clone` or removing `Copy`
- --> tests/ui/derive.rs:53:1
+ --> tests/ui/derive.rs:55:1
|
LL | / impl Clone for BigArray {
LL | |
@@ -67,7 +67,7 @@
| |_^
error: you are implementing `Clone` explicitly on a `Copy` type
- --> tests/ui/derive.rs:66:1
+ --> tests/ui/derive.rs:68:1
|
LL | / impl Clone for FnPtr {
LL | |
@@ -78,7 +78,7 @@
| |_^
|
note: consider deriving `Clone` or removing `Copy`
- --> tests/ui/derive.rs:66:1
+ --> tests/ui/derive.rs:68:1
|
LL | / impl Clone for FnPtr {
LL | |
@@ -89,7 +89,7 @@
| |_^
error: you are implementing `Clone` explicitly on a `Copy` type
- --> tests/ui/derive.rs:88:1
+ --> tests/ui/derive.rs:90:1
|
LL | / impl<T: Clone> Clone for Generic2<T> {
LL | |
@@ -100,7 +100,7 @@
| |_^
|
note: consider deriving `Clone` or removing `Copy`
- --> tests/ui/derive.rs:88:1
+ --> tests/ui/derive.rs:90:1
|
LL | / impl<T: Clone> Clone for Generic2<T> {
LL | |
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
index 5f2b697..8cf20d8 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
@@ -1,4 +1,3 @@
-
//! This file tests for the `DOC_MARKDOWN` lint.
#![allow(dead_code, incomplete_features)]
@@ -272,7 +271,7 @@
/// UXes
fn plural_acronym_test() {}
-extern "C" {
+unsafe extern "C" {
/// `foo()`
//~^ doc_markdown
fn in_extern();
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
index ed39256..5b6f2bd 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
@@ -1,4 +1,3 @@
-
//! This file tests for the `DOC_MARKDOWN` lint.
#![allow(dead_code, incomplete_features)]
@@ -272,7 +271,7 @@ fn parenthesized_word() {}
/// UXes
fn plural_acronym_test() {}
-extern "C" {
+unsafe extern "C" {
/// foo()
//~^ doc_markdown
fn in_extern();
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
index d67da75..98c26e6 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.stderr
@@ -1,5 +1,5 @@
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:9:9
+ --> tests/ui/doc/doc-fixable.rs:8:9
|
LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
| ^^^^^^^
@@ -13,7 +13,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:9:51
+ --> tests/ui/doc/doc-fixable.rs:8:51
|
LL | /// The foo_bar function does _nothing_. See also foo::bar. (note the dot there)
| ^^^^^^^^
@@ -25,7 +25,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:12:83
+ --> tests/ui/doc/doc-fixable.rs:11:83
|
LL | /// Markdown is _weird_. I mean _really weird_. This \_ is ok. So is `_`. But not Foo::some_fun
| ^^^^^^^^^^^^^
@@ -37,7 +37,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:15:13
+ --> tests/ui/doc/doc-fixable.rs:14:13
|
LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
| ^^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:15:36
+ --> tests/ui/doc/doc-fixable.rs:14:36
|
LL | /// Here be ::a::global:path, and _::another::global::path_. :: is not a path though.
| ^^^^^^^^^^^^^^^^^^^^^^^
@@ -61,7 +61,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:18:25
+ --> tests/ui/doc/doc-fixable.rs:17:25
|
LL | /// Import an item from ::awesome::global::blob:: (Intended postfix)
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -73,7 +73,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:20:31
+ --> tests/ui/doc/doc-fixable.rs:19:31
|
LL | /// These are the options for ::Cat: (Intended trailing single colon, shouldn't be linted)
| ^^^^^
@@ -85,7 +85,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:22:22
+ --> tests/ui/doc/doc-fixable.rs:21:22
|
LL | /// That's not code ~NotInCodeBlock~.
| ^^^^^^^^^^^^^^
@@ -97,7 +97,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:24:5
+ --> tests/ui/doc/doc-fixable.rs:23:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -109,7 +109,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:39:5
+ --> tests/ui/doc/doc-fixable.rs:38:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -121,7 +121,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:47:5
+ --> tests/ui/doc/doc-fixable.rs:46:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -133,7 +133,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:62:5
+ --> tests/ui/doc/doc-fixable.rs:61:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -145,7 +145,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:91:5
+ --> tests/ui/doc/doc-fixable.rs:90:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -157,7 +157,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:109:5
+ --> tests/ui/doc/doc-fixable.rs:108:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -169,7 +169,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:118:8
+ --> tests/ui/doc/doc-fixable.rs:117:8
|
LL | /// ## CamelCaseThing
| ^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:122:7
+ --> tests/ui/doc/doc-fixable.rs:121:7
|
LL | /// # CamelCaseThing
| ^^^^^^^^^^^^^^
@@ -193,7 +193,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:125:22
+ --> tests/ui/doc/doc-fixable.rs:124:22
|
LL | /// Not a title #897 CamelCaseThing
| ^^^^^^^^^^^^^^
@@ -205,7 +205,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:127:5
+ --> tests/ui/doc/doc-fixable.rs:126:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -217,7 +217,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:135:5
+ --> tests/ui/doc/doc-fixable.rs:134:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -229,7 +229,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:149:5
+ --> tests/ui/doc/doc-fixable.rs:148:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -241,7 +241,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:161:43
+ --> tests/ui/doc/doc-fixable.rs:160:43
|
LL | /** E.g., serialization of an empty list: FooBar
| ^^^^^^
@@ -253,7 +253,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:166:5
+ --> tests/ui/doc/doc-fixable.rs:165:5
|
LL | And BarQuz too.
| ^^^^^^
@@ -265,7 +265,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:167:1
+ --> tests/ui/doc/doc-fixable.rs:166:1
|
LL | be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -277,7 +277,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:175:43
+ --> tests/ui/doc/doc-fixable.rs:174:43
|
LL | /** E.g., serialization of an empty list: FooBar
| ^^^^^^
@@ -289,7 +289,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:180:5
+ --> tests/ui/doc/doc-fixable.rs:179:5
|
LL | And BarQuz too.
| ^^^^^^
@@ -301,7 +301,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:181:1
+ --> tests/ui/doc/doc-fixable.rs:180:1
|
LL | be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -313,7 +313,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:195:5
+ --> tests/ui/doc/doc-fixable.rs:194:5
|
LL | /// be_sure_we_got_to_the_end_of_it
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -325,7 +325,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:215:22
+ --> tests/ui/doc/doc-fixable.rs:214:22
|
LL | /// An iterator over mycrate::Collection's values.
| ^^^^^^^^^^^^^^^^^^^
@@ -337,7 +337,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:240:34
+ --> tests/ui/doc/doc-fixable.rs:239:34
|
LL | /// Foo \[bar\] \[baz\] \[qux\]. DocMarkdownLint
| ^^^^^^^^^^^^^^^
@@ -349,7 +349,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:264:22
+ --> tests/ui/doc/doc-fixable.rs:263:22
|
LL | /// There is no try (do() or do_not()).
| ^^^^
@@ -361,7 +361,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:264:30
+ --> tests/ui/doc/doc-fixable.rs:263:30
|
LL | /// There is no try (do() or do_not()).
| ^^^^^^^^
@@ -373,7 +373,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:269:5
+ --> tests/ui/doc/doc-fixable.rs:268:5
|
LL | /// ABes
| ^^^^
@@ -385,7 +385,7 @@
|
error: item in documentation is missing backticks
- --> tests/ui/doc/doc-fixable.rs:276:9
+ --> tests/ui/doc/doc-fixable.rs:275:9
|
LL | /// foo()
| ^^^^^
@@ -397,7 +397,7 @@
|
error: you should put bare URLs between `<`/`>` or make a proper Markdown link
- --> tests/ui/doc/doc-fixable.rs:281:5
+ --> tests/ui/doc/doc-fixable.rs:280:5
|
LL | /// https://github.com/rust-lang/rust-clippy/pull/12836
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `<https://github.com/rust-lang/rust-clippy/pull/12836>`
diff --git a/src/tools/clippy/tests/ui/doc_unsafe.rs b/src/tools/clippy/tests/ui/doc_unsafe.rs
index 1bdf01e..7146fd7 100644
--- a/src/tools/clippy/tests/ui/doc_unsafe.rs
+++ b/src/tools/clippy/tests/ui/doc_unsafe.rs
@@ -103,7 +103,7 @@ pub unsafe fn whee() {
///
/// Please keep the seat belt fastened
pub unsafe fn drive() {
- whee()
+ unsafe { whee() }
}
};
}
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed
index 17d0d71..2ce0c04 100644
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.fixed
@@ -52,28 +52,35 @@
let _ = CustomLast.last();
}
+// Should not be linted because applying the lint would move the original iterator. This can only be
+// linted if the iterator is used thereafter.
fn issue_14139() {
let mut index = [true, true, false, false, false, true].iter();
- let mut subindex = index.by_ref().take(3);
- let _ = subindex.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
+ let subindex = index.by_ref().take(3);
+ let _ = subindex.last();
+ let _ = index.next();
let mut index = [true, true, false, false, false, true].iter();
let mut subindex = index.by_ref().take(3);
- let _ = subindex.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
+ let _ = subindex.last();
+ let _ = index.next();
let mut index = [true, true, false, false, false, true].iter();
let mut subindex = index.by_ref().take(3);
let subindex = &mut subindex;
- let _ = subindex.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
+ let _ = subindex.last();
+ let _ = index.next();
let mut index = [true, true, false, false, false, true].iter();
let mut subindex = index.by_ref().take(3);
let subindex = &mut subindex;
- let _ = subindex.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
+ let _ = subindex.last();
+ let _ = index.next();
let mut index = [true, true, false, false, false, true].iter();
- let (mut subindex, _) = (index.by_ref().take(3), 42);
- let _ = subindex.next_back(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
+ let (subindex, _) = (index.by_ref().take(3), 42);
+ let _ = subindex.last();
+ let _ = index.next();
}
fn drop_order() {
@@ -90,3 +97,14 @@
//~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
println!("Done");
}
+
+fn issue_14444() {
+ let mut squares = vec![];
+ let last_square = [1, 2, 3]
+ .into_iter()
+ .map(|x| {
+ squares.push(x * x);
+ Some(x * x)
+ })
+ .last();
+}
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs
index 41bc669..a4eb9b3 100644
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last.rs
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.rs
@@ -52,28 +52,35 @@ fn next_back(&mut self) -> Option<Self::Item> {
let _ = CustomLast.last();
}
+// Should not be linted because applying the lint would move the original iterator. This can only be
+// linted if the iterator is used thereafter.
fn issue_14139() {
let mut index = [true, true, false, false, false, true].iter();
let subindex = index.by_ref().take(3);
- let _ = subindex.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
+ let _ = subindex.last();
+ let _ = index.next();
let mut index = [true, true, false, false, false, true].iter();
let mut subindex = index.by_ref().take(3);
- let _ = subindex.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
+ let _ = subindex.last();
+ let _ = index.next();
let mut index = [true, true, false, false, false, true].iter();
let mut subindex = index.by_ref().take(3);
let subindex = &mut subindex;
- let _ = subindex.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
+ let _ = subindex.last();
+ let _ = index.next();
let mut index = [true, true, false, false, false, true].iter();
let mut subindex = index.by_ref().take(3);
let subindex = &mut subindex;
- let _ = subindex.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
+ let _ = subindex.last();
+ let _ = index.next();
let mut index = [true, true, false, false, false, true].iter();
let (subindex, _) = (index.by_ref().take(3), 42);
- let _ = subindex.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
+ let _ = subindex.last();
+ let _ = index.next();
}
fn drop_order() {
@@ -90,3 +97,14 @@ fn drop(&mut self) {
//~^ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
println!("Done");
}
+
+fn issue_14444() {
+ let mut squares = vec![];
+ let last_square = [1, 2, 3]
+ .into_iter()
+ .map(|x| {
+ squares.push(x * x);
+ Some(x * x)
+ })
+ .last();
+}
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr
index 1702a24..fe8cf2d 100644
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last.stderr
@@ -18,55 +18,7 @@
| help: try: `next_back()`
error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
- --> tests/ui/double_ended_iterator_last.rs:58:13
- |
-LL | let _ = subindex.last();
- | ^^^^^^^^^^^^^^^
- |
-help: try
- |
-LL ~ let mut subindex = index.by_ref().take(3);
-LL ~ let _ = subindex.next_back();
- |
-
-error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
- --> tests/ui/double_ended_iterator_last.rs:62:13
- |
-LL | let _ = subindex.last();
- | ^^^^^^^^^------
- | |
- | help: try: `next_back()`
-
-error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
- --> tests/ui/double_ended_iterator_last.rs:67:13
- |
-LL | let _ = subindex.last();
- | ^^^^^^^^^------
- | |
- | help: try: `next_back()`
-
-error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
- --> tests/ui/double_ended_iterator_last.rs:72:13
- |
-LL | let _ = subindex.last();
- | ^^^^^^^^^------
- | |
- | help: try: `next_back()`
-
-error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
- --> tests/ui/double_ended_iterator_last.rs:76:13
- |
-LL | let _ = subindex.last();
- | ^^^^^^^^^^^^^^^
- |
-help: try
- |
-LL ~ let (mut subindex, _) = (index.by_ref().take(3), 42);
-LL ~ let _ = subindex.next_back();
- |
-
-error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
- --> tests/ui/double_ended_iterator_last.rs:89:36
+ --> tests/ui/double_ended_iterator_last.rs:96:36
|
LL | println!("Last element is {}", v.last().unwrap().0);
| ^^^^^^^^
@@ -78,5 +30,5 @@
LL ~ println!("Last element is {}", v.next_back().unwrap().0);
|
-error: aborting due to 8 previous errors
+error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs
index 3f125c7..7c5de88 100644
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.rs
@@ -1,10 +1,13 @@
//@no-rustfix
#![warn(clippy::double_ended_iterator_last)]
+// Should not be linted because applying the lint would move the original iterator. This can only be
+// linted if the iterator is used thereafter.
fn main() {
let mut index = [true, true, false, false, false, true].iter();
let subindex = (index.by_ref().take(3), 42);
- let _ = subindex.0.last(); //~ ERROR: called `Iterator::last` on a `DoubleEndedIterator`
+ let _ = subindex.0.last();
+ let _ = index.next();
}
fn drop_order() {
diff --git a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr
index f4be757..845afc1 100644
--- a/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/double_ended_iterator_last_unfixable.stderr
@@ -1,21 +1,5 @@
error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
- --> tests/ui/double_ended_iterator_last_unfixable.rs:7:13
- |
-LL | let _ = subindex.0.last();
- | ^^^^^^^^^^^------
- | |
- | help: try: `next_back()`
- |
-note: this must be made mutable to use `.next_back()`
- --> tests/ui/double_ended_iterator_last_unfixable.rs:7:13
- |
-LL | let _ = subindex.0.last();
- | ^^^^^^^^^^
- = note: `-D clippy::double-ended-iterator-last` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::double_ended_iterator_last)]`
-
-error: called `Iterator::last` on a `DoubleEndedIterator`; this will needlessly iterate the entire iterator
- --> tests/ui/double_ended_iterator_last_unfixable.rs:20:36
+ --> tests/ui/double_ended_iterator_last_unfixable.rs:23:36
|
LL | println!("Last element is {}", v.0.last().unwrap().0);
| ^^^^------
@@ -24,10 +8,12 @@
|
= note: this change will alter drop order which may be undesirable
note: this must be made mutable to use `.next_back()`
- --> tests/ui/double_ended_iterator_last_unfixable.rs:20:36
+ --> tests/ui/double_ended_iterator_last_unfixable.rs:23:36
|
LL | println!("Last element is {}", v.0.last().unwrap().0);
| ^^^
+ = note: `-D clippy::double-ended-iterator-last` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::double_ended_iterator_last)]`
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
diff --git a/src/tools/clippy/tests/ui/eager_transmute.fixed b/src/tools/clippy/tests/ui/eager_transmute.fixed
index 14cbb61..47a32ec 100644
--- a/src/tools/clippy/tests/ui/eager_transmute.fixed
+++ b/src/tools/clippy/tests/ui/eager_transmute.fixed
@@ -71,8 +71,10 @@
}
unsafe fn f2(op: u8) {
- (op < 4).then(|| std::mem::transmute::<_, Opcode>(op));
- //~^ eager_transmute
+ unsafe {
+ (op < 4).then(|| std::mem::transmute::<_, Opcode>(op));
+ //~^ eager_transmute
+ }
}
#[rustc_layout_scalar_valid_range_end(254)]
diff --git a/src/tools/clippy/tests/ui/eager_transmute.rs b/src/tools/clippy/tests/ui/eager_transmute.rs
index 48d7d50..906cd7b 100644
--- a/src/tools/clippy/tests/ui/eager_transmute.rs
+++ b/src/tools/clippy/tests/ui/eager_transmute.rs
@@ -71,8 +71,10 @@ fn f(op: u8, op2: Data, unrelated: u8) {
}
unsafe fn f2(op: u8) {
- (op < 4).then_some(std::mem::transmute::<_, Opcode>(op));
- //~^ eager_transmute
+ unsafe {
+ (op < 4).then_some(std::mem::transmute::<_, Opcode>(op));
+ //~^ eager_transmute
+ }
}
#[rustc_layout_scalar_valid_range_end(254)]
diff --git a/src/tools/clippy/tests/ui/eager_transmute.stderr b/src/tools/clippy/tests/ui/eager_transmute.stderr
index 54850d1..c719ca8 100644
--- a/src/tools/clippy/tests/ui/eager_transmute.stderr
+++ b/src/tools/clippy/tests/ui/eager_transmute.stderr
@@ -157,19 +157,19 @@
|
error: this transmute is always evaluated eagerly, even if the condition is false
- --> tests/ui/eager_transmute.rs:74:24
+ --> tests/ui/eager_transmute.rs:75:28
|
-LL | (op < 4).then_some(std::mem::transmute::<_, Opcode>(op));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | (op < 4).then_some(std::mem::transmute::<_, Opcode>(op));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider using `bool::then` to only transmute if the condition holds
|
-LL - (op < 4).then_some(std::mem::transmute::<_, Opcode>(op));
-LL + (op < 4).then(|| std::mem::transmute::<_, Opcode>(op));
+LL - (op < 4).then_some(std::mem::transmute::<_, Opcode>(op));
+LL + (op < 4).then(|| std::mem::transmute::<_, Opcode>(op));
|
error: this transmute is always evaluated eagerly, even if the condition is false
- --> tests/ui/eager_transmute.rs:104:62
+ --> tests/ui/eager_transmute.rs:106:62
|
LL | let _: Option<NonZero<u8>> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) });
| ^^^^^^^^^^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@
|
error: this transmute is always evaluated eagerly, even if the condition is false
- --> tests/ui/eager_transmute.rs:111:86
+ --> tests/ui/eager_transmute.rs:113:86
|
LL | let _: Option<NonMaxU8> = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
| ^^^^^^^^^^^^^^^^^^^^^^^
@@ -193,7 +193,7 @@
|
error: this transmute is always evaluated eagerly, even if the condition is false
- --> tests/ui/eager_transmute.rs:118:93
+ --> tests/ui/eager_transmute.rs:120:93
|
LL | let _: Option<NonZeroNonMaxU8> = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
| ^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/empty_docs.rs b/src/tools/clippy/tests/ui/empty_docs.rs
index d7768e0..57f8976 100644
--- a/src/tools/clippy/tests/ui/empty_docs.rs
+++ b/src/tools/clippy/tests/ui/empty_docs.rs
@@ -84,7 +84,7 @@ mod issue_12377 {
use proc_macro_attr::with_empty_docs;
#[with_empty_docs]
- extern "C" {
+ unsafe extern "C" {
type Test;
}
diff --git a/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.fixed b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.fixed
index 885f6a5..abdf6ca 100644
--- a/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.fixed
+++ b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.fixed
@@ -6,8 +6,7 @@
NonEmptyParentheses(i32, i32), // No error
EmptyBraces,
//~^ empty_enum_variants_with_brackets
- EmptyParentheses,
- //~^ empty_enum_variants_with_brackets
+ EmptyParentheses(), // No error as enum is pub
}
enum TestEnum {
@@ -20,6 +19,67 @@
AnotherEnum, // No error
}
+mod issue12551 {
+ enum EvenOdd {
+ // Used as functions -> no error
+ Even(),
+ Odd(),
+ // Not used as a function
+ Unknown,
+ //~^ empty_enum_variants_with_brackets
+ }
+
+ fn even_odd(x: i32) -> EvenOdd {
+ (x % 2 == 0).then(EvenOdd::Even).unwrap_or_else(EvenOdd::Odd)
+ }
+
+ fn natural_number(x: i32) -> NaturalOrNot {
+ (x > 0)
+ .then(NaturalOrNot::Natural)
+ .unwrap_or_else(NaturalOrNot::NotNatural)
+ }
+
+ enum NaturalOrNot {
+ // Used as functions -> no error
+ Natural(),
+ NotNatural(),
+ // Not used as a function
+ Unknown,
+ //~^ empty_enum_variants_with_brackets
+ }
+
+ enum RedundantParenthesesFunctionCall {
+ // Used as a function call but with redundant parentheses
+ Parentheses,
+ //~^ empty_enum_variants_with_brackets
+ // Not used as a function
+ NoParentheses,
+ }
+
+ #[allow(clippy::no_effect)]
+ fn redundant_parentheses_function_call() {
+ // The parentheses in the below line are redundant.
+ RedundantParenthesesFunctionCall::Parentheses;
+ RedundantParenthesesFunctionCall::NoParentheses;
+ }
+
+ // Same test as above but with usage of the enum occurring before the definition.
+ #[allow(clippy::no_effect)]
+ fn redundant_parentheses_function_call_2() {
+ // The parentheses in the below line are redundant.
+ RedundantParenthesesFunctionCall2::Parentheses;
+ RedundantParenthesesFunctionCall2::NoParentheses;
+ }
+
+ enum RedundantParenthesesFunctionCall2 {
+ // Used as a function call but with redundant parentheses
+ Parentheses,
+ //~^ empty_enum_variants_with_brackets
+ // Not used as a function
+ NoParentheses,
+ }
+}
+
enum TestEnumWithFeatures {
NonEmptyBraces {
#[cfg(feature = "thisisneverenabled")]
@@ -28,4 +88,18 @@
NonEmptyParentheses(#[cfg(feature = "thisisneverenabled")] i32), // No error
}
+#[derive(Clone)]
+enum Foo {
+ Variant1(i32),
+ Variant2,
+ Variant3, //~ ERROR: enum variant has empty brackets
+}
+
+#[derive(Clone)]
+pub enum PubFoo {
+ Variant1(i32),
+ Variant2,
+ Variant3(),
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.rs b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.rs
index 092712e..63a5a8e 100644
--- a/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.rs
+++ b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.rs
@@ -6,8 +6,7 @@ pub enum PublicTestEnum {
NonEmptyParentheses(i32, i32), // No error
EmptyBraces {},
//~^ empty_enum_variants_with_brackets
- EmptyParentheses(),
- //~^ empty_enum_variants_with_brackets
+ EmptyParentheses(), // No error as enum is pub
}
enum TestEnum {
@@ -20,6 +19,67 @@ enum TestEnum {
AnotherEnum, // No error
}
+mod issue12551 {
+ enum EvenOdd {
+ // Used as functions -> no error
+ Even(),
+ Odd(),
+ // Not used as a function
+ Unknown(),
+ //~^ empty_enum_variants_with_brackets
+ }
+
+ fn even_odd(x: i32) -> EvenOdd {
+ (x % 2 == 0).then(EvenOdd::Even).unwrap_or_else(EvenOdd::Odd)
+ }
+
+ fn natural_number(x: i32) -> NaturalOrNot {
+ (x > 0)
+ .then(NaturalOrNot::Natural)
+ .unwrap_or_else(NaturalOrNot::NotNatural)
+ }
+
+ enum NaturalOrNot {
+ // Used as functions -> no error
+ Natural(),
+ NotNatural(),
+ // Not used as a function
+ Unknown(),
+ //~^ empty_enum_variants_with_brackets
+ }
+
+ enum RedundantParenthesesFunctionCall {
+ // Used as a function call but with redundant parentheses
+ Parentheses(),
+ //~^ empty_enum_variants_with_brackets
+ // Not used as a function
+ NoParentheses,
+ }
+
+ #[allow(clippy::no_effect)]
+ fn redundant_parentheses_function_call() {
+ // The parentheses in the below line are redundant.
+ RedundantParenthesesFunctionCall::Parentheses();
+ RedundantParenthesesFunctionCall::NoParentheses;
+ }
+
+ // Same test as above but with usage of the enum occurring before the definition.
+ #[allow(clippy::no_effect)]
+ fn redundant_parentheses_function_call_2() {
+ // The parentheses in the below line are redundant.
+ RedundantParenthesesFunctionCall2::Parentheses();
+ RedundantParenthesesFunctionCall2::NoParentheses;
+ }
+
+ enum RedundantParenthesesFunctionCall2 {
+ // Used as a function call but with redundant parentheses
+ Parentheses(),
+ //~^ empty_enum_variants_with_brackets
+ // Not used as a function
+ NoParentheses,
+ }
+}
+
enum TestEnumWithFeatures {
NonEmptyBraces {
#[cfg(feature = "thisisneverenabled")]
@@ -28,4 +88,18 @@ enum TestEnumWithFeatures {
NonEmptyParentheses(#[cfg(feature = "thisisneverenabled")] i32), // No error
}
+#[derive(Clone)]
+enum Foo {
+ Variant1(i32),
+ Variant2,
+ Variant3(), //~ ERROR: enum variant has empty brackets
+}
+
+#[derive(Clone)]
+pub enum PubFoo {
+ Variant1(i32),
+ Variant2,
+ Variant3(),
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.stderr b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.stderr
index a9ae3b4..7fe85e8 100644
--- a/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.stderr
+++ b/src/tools/clippy/tests/ui/empty_enum_variants_with_brackets.stderr
@@ -9,15 +9,7 @@
= help: remove the brackets
error: enum variant has empty brackets
- --> tests/ui/empty_enum_variants_with_brackets.rs:9:21
- |
-LL | EmptyParentheses(),
- | ^^
- |
- = help: remove the brackets
-
-error: enum variant has empty brackets
- --> tests/ui/empty_enum_variants_with_brackets.rs:16:16
+ --> tests/ui/empty_enum_variants_with_brackets.rs:15:16
|
LL | EmptyBraces {},
| ^^^
@@ -25,12 +17,66 @@
= help: remove the brackets
error: enum variant has empty brackets
- --> tests/ui/empty_enum_variants_with_brackets.rs:18:21
+ --> tests/ui/empty_enum_variants_with_brackets.rs:17:21
|
LL | EmptyParentheses(),
| ^^
|
= help: remove the brackets
-error: aborting due to 4 previous errors
+error: enum variant has empty brackets
+ --> tests/ui/empty_enum_variants_with_brackets.rs:28:16
+ |
+LL | Unknown(),
+ | ^^
+ |
+ = help: remove the brackets
+
+error: enum variant has empty brackets
+ --> tests/ui/empty_enum_variants_with_brackets.rs:47:16
+ |
+LL | Unknown(),
+ | ^^
+ |
+ = help: remove the brackets
+
+error: enum variant has empty brackets
+ --> tests/ui/empty_enum_variants_with_brackets.rs:53:20
+ |
+LL | Parentheses(),
+ | ^^
+ |
+help: remove the brackets
+ |
+LL ~ Parentheses,
+LL |
+...
+LL | // The parentheses in the below line are redundant.
+LL ~ RedundantParenthesesFunctionCall::Parentheses;
+ |
+
+error: enum variant has empty brackets
+ --> tests/ui/empty_enum_variants_with_brackets.rs:76:20
+ |
+LL | Parentheses(),
+ | ^^
+ |
+help: remove the brackets
+ |
+LL ~ RedundantParenthesesFunctionCall2::Parentheses;
+LL | RedundantParenthesesFunctionCall2::NoParentheses;
+...
+LL | // Used as a function call but with redundant parentheses
+LL ~ Parentheses,
+ |
+
+error: enum variant has empty brackets
+ --> tests/ui/empty_enum_variants_with_brackets.rs:95:13
+ |
+LL | Variant3(),
+ | ^^
+ |
+ = help: remove the brackets
+
+error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed
index e4ba09e..70ab235 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed
+++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.1.fixed
@@ -142,4 +142,9 @@
fn bar() {}
}
+//~v empty_line_after_doc_comments
+/// Docs for this item.
+// fn some_item() {}
+impl LineComment {} // or any other nameless item kind
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed
index a20f9bc..87c636c 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed
+++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.2.fixed
@@ -152,4 +152,10 @@
fn bar() {}
}
+//~v empty_line_after_doc_comments
+// /// Docs for this item.
+// fn some_item() {}
+
+impl LineComment {} // or any other nameless item kind
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs
index 9e3ddfd..91e9c1a 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs
+++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.rs
@@ -155,4 +155,10 @@ impl Foo for LineComment {
fn bar() {}
}
+//~v empty_line_after_doc_comments
+/// Docs for this item.
+// fn some_item() {}
+
+impl LineComment {} // or any other nameless item kind
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr
index fe25ba9..ae8cb91 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr
+++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr
@@ -87,7 +87,7 @@
| ----------- the comment documents this function
|
= help: if the empty line is unintentional, remove it
-help: if the doc comment should not document `new_code` comment it out
+help: if the doc comment should not document function `new_code` then comment it out
|
LL | // /// docs for `old_code`
| ++
@@ -107,7 +107,7 @@
| --------------- the comment documents this struct
|
= help: if the empty lines are unintentional, remove them
-help: if the doc comment should not document `Multiple` comment it out
+help: if the doc comment should not document struct `Multiple` then comment it out
|
LL ~ // /// Docs
LL ~ // /// for OldA
@@ -149,7 +149,7 @@
| ----------- the comment documents this function
|
= help: if the empty line is unintentional, remove it
-help: if the doc comment should not document `new_code` comment it out
+help: if the doc comment should not document function `new_code` then comment it out
|
LL - /**
LL + /*
@@ -167,7 +167,7 @@
| ------------ the comment documents this function
|
= help: if the empty line is unintentional, remove it
-help: if the doc comment should not document `new_code2` comment it out
+help: if the doc comment should not document function `new_code2` then comment it out
|
LL | // /// Docs for `old_code2`
| ++
@@ -183,10 +183,26 @@
| ------ the comment documents this function
|
= help: if the empty line is unintentional, remove it
-help: if the doc comment should not document `bar` comment it out
+help: if the doc comment should not document function `bar` then comment it out
|
LL | // /// comment on assoc item
| ++
-error: aborting due to 11 previous errors
+error: empty line after doc comment
+ --> tests/ui/empty_line_after/doc_comments.rs:159:1
+ |
+LL | / /// Docs for this item.
+LL | | // fn some_item() {}
+LL | |
+ | |_^
+LL | impl LineComment {} // or any other nameless item kind
+ | - the comment documents this implementation
+ |
+ = help: if the empty line is unintentional, remove it
+help: if the doc comment should not document the following item then comment it out
+ |
+LL | // /// Docs for this item.
+ | ++
+
+error: aborting due to 12 previous errors
diff --git a/src/tools/clippy/tests/ui/entry.fixed b/src/tools/clippy/tests/ui/entry.fixed
index 69452a8..f2df9f0 100644
--- a/src/tools/clippy/tests/ui/entry.fixed
+++ b/src/tools/clippy/tests/ui/entry.fixed
@@ -226,4 +226,26 @@
}
}
+mod issue14449 {
+ use std::collections::BTreeMap;
+
+ pub struct Meow {
+ map: BTreeMap<String, String>,
+ }
+
+ impl Meow {
+ fn pet(&self, _key: &str, _v: u32) -> u32 {
+ 42
+ }
+ }
+
+ pub fn f(meow: &Meow, x: String) {
+ if meow.map.contains_key(&x) {
+ let _ = meow.pet(&x, 1);
+ } else {
+ let _ = meow.pet(&x, 0);
+ }
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/entry.rs b/src/tools/clippy/tests/ui/entry.rs
index 3578324..166eea4 100644
--- a/src/tools/clippy/tests/ui/entry.rs
+++ b/src/tools/clippy/tests/ui/entry.rs
@@ -232,4 +232,26 @@ fn issue11976() {
}
}
+mod issue14449 {
+ use std::collections::BTreeMap;
+
+ pub struct Meow {
+ map: BTreeMap<String, String>,
+ }
+
+ impl Meow {
+ fn pet(&self, _key: &str, _v: u32) -> u32 {
+ 42
+ }
+ }
+
+ pub fn f(meow: &Meow, x: String) {
+ if meow.map.contains_key(&x) {
+ let _ = meow.pet(&x, 1);
+ } else {
+ let _ = meow.pet(&x, 0);
+ }
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
index 7235f7d..ec6bed1 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed
@@ -59,7 +59,7 @@
fn f_box_t<T>(_: &Box<T>) {}
-extern "C" {
+unsafe extern "C" {
fn var(_: u32, ...);
}
diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.rs b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
index c4d2b28..ca58c65 100644
--- a/src/tools/clippy/tests/ui/explicit_auto_deref.rs
+++ b/src/tools/clippy/tests/ui/explicit_auto_deref.rs
@@ -59,7 +59,7 @@ fn f_str_t<T>(_: &str, _: T) {}
fn f_box_t<T>(_: &Box<T>) {}
-extern "C" {
+unsafe extern "C" {
fn var(_: u32, ...);
}
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.rs b/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.rs
new file mode 100644
index 0000000..6829429
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.rs
@@ -0,0 +1,63 @@
+#![allow(clippy::question_mark, unused)]
+#![warn(clippy::filter_map_bool_then)]
+//@no-rustfix
+
+fn issue11617() {
+ let mut x: Vec<usize> = vec![0; 10];
+ let _ = (0..x.len()).zip(x.clone().iter()).filter_map(|(i, v)| {
+ //~^ filter_map_bool_then
+ (x[i] != *v).then(|| {
+ x[i] = i;
+ i
+ })
+ });
+}
+
+mod issue14368 {
+
+ fn do_something(_: ()) -> bool {
+ true
+ }
+
+ fn option_with_early_return(x: &[Option<bool>]) {
+ let _ = x.iter().filter_map(|&x| x?.then(|| do_something(())));
+ //~^ filter_map_bool_then
+ let _ = x
+ .iter()
+ .filter_map(|&x| if let Some(x) = x { x } else { return None }.then(|| do_something(())));
+ //~^ filter_map_bool_then
+ let _ = x.iter().filter_map(|&x| {
+ //~^ filter_map_bool_then
+ match x {
+ Some(x) => x,
+ None => return None,
+ }
+ .then(|| do_something(()))
+ });
+ }
+
+ #[derive(Copy, Clone)]
+ enum Foo {
+ One(bool),
+ Two,
+ Three(Option<i32>),
+ }
+
+ fn nested_type_with_early_return(x: &[Foo]) {
+ let _ = x.iter().filter_map(|&x| {
+ //~^ filter_map_bool_then
+ match x {
+ Foo::One(x) => x,
+ Foo::Two => return None,
+ Foo::Three(inner) => {
+ if inner? == 0 {
+ return Some(false);
+ } else {
+ true
+ }
+ },
+ }
+ .then(|| do_something(()))
+ });
+ }
+}
diff --git a/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.stderr b/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.stderr
new file mode 100644
index 0000000..2025958
--- /dev/null
+++ b/src/tools/clippy/tests/ui/filter_map_bool_then_unfixable.stderr
@@ -0,0 +1,65 @@
+error: usage of `bool::then` in `filter_map`
+ --> tests/ui/filter_map_bool_then_unfixable.rs:7:48
+ |
+LL | let _ = (0..x.len()).zip(x.clone().iter()).filter_map(|(i, v)| {
+ | ________________________________________________^
+LL | |
+LL | | (x[i] != *v).then(|| {
+LL | | x[i] = i;
+LL | | i
+LL | | })
+LL | | });
+ | |______^
+ |
+ = help: consider using `filter` then `map` instead
+ = note: `-D clippy::filter-map-bool-then` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::filter_map_bool_then)]`
+
+error: usage of `bool::then` in `filter_map`
+ --> tests/ui/filter_map_bool_then_unfixable.rs:23:26
+ |
+LL | let _ = x.iter().filter_map(|&x| x?.then(|| do_something(())));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using `filter` then `map` instead
+
+error: usage of `bool::then` in `filter_map`
+ --> tests/ui/filter_map_bool_then_unfixable.rs:27:14
+ |
+LL | .filter_map(|&x| if let Some(x) = x { x } else { return None }.then(|| do_something(())));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider using `filter` then `map` instead
+
+error: usage of `bool::then` in `filter_map`
+ --> tests/ui/filter_map_bool_then_unfixable.rs:29:26
+ |
+LL | let _ = x.iter().filter_map(|&x| {
+ | __________________________^
+LL | |
+LL | | match x {
+LL | | Some(x) => x,
+... |
+LL | | .then(|| do_something(()))
+LL | | });
+ | |__________^
+ |
+ = help: consider using `filter` then `map` instead
+
+error: usage of `bool::then` in `filter_map`
+ --> tests/ui/filter_map_bool_then_unfixable.rs:47:26
+ |
+LL | let _ = x.iter().filter_map(|&x| {
+ | __________________________^
+LL | |
+LL | | match x {
+LL | | Foo::One(x) => x,
+... |
+LL | | .then(|| do_something(()))
+LL | | });
+ | |__________^
+ |
+ = help: consider using `filter` then `map` instead
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/filter_map_next.rs b/src/tools/clippy/tests/ui/filter_map_next.rs
index 2a2237e..5414e01 100644
--- a/src/tools/clippy/tests/ui/filter_map_next.rs
+++ b/src/tools/clippy/tests/ui/filter_map_next.rs
@@ -1,4 +1,4 @@
-#![warn(clippy::all, clippy::pedantic)]
+#![warn(clippy::filter_map_next)]
fn main() {
let a = ["1", "lol", "3", "NaN", "5"];
diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed b/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed
index 285863e..09c4160 100644
--- a/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed
+++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed
@@ -1,5 +1,4 @@
-#![warn(clippy::all, clippy::pedantic)]
-#![allow(unused)]
+#![warn(clippy::filter_map_next)]
fn main() {
let a = ["1", "lol", "3", "NaN", "5"];
diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.rs b/src/tools/clippy/tests/ui/filter_map_next_fixable.rs
index af91168..3d686ef 100644
--- a/src/tools/clippy/tests/ui/filter_map_next_fixable.rs
+++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.rs
@@ -1,5 +1,4 @@
-#![warn(clippy::all, clippy::pedantic)]
-#![allow(unused)]
+#![warn(clippy::filter_map_next)]
fn main() {
let a = ["1", "lol", "3", "NaN", "5"];
diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr b/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr
index 707dec8..1002837 100644
--- a/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr
+++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.stderr
@@ -1,5 +1,5 @@
error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead
- --> tests/ui/filter_map_next_fixable.rs:7:32
+ --> tests/ui/filter_map_next_fixable.rs:6:32
|
LL | let element: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.iter().find_map(|s| s.parse().ok())`
@@ -8,7 +8,7 @@
= help: to override `-D warnings` add `#[allow(clippy::filter_map_next)]`
error: called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find_map(..)` instead
- --> tests/ui/filter_map_next_fixable.rs:21:26
+ --> tests/ui/filter_map_next_fixable.rs:20:26
|
LL | let _: Option<i32> = a.iter().filter_map(|s| s.parse().ok()).next();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `a.iter().find_map(|s| s.parse().ok())`
diff --git a/src/tools/clippy/tests/ui/find_map.rs b/src/tools/clippy/tests/ui/find_map.rs
index aba1f2c..a9a8508 100644
--- a/src/tools/clippy/tests/ui/find_map.rs
+++ b/src/tools/clippy/tests/ui/find_map.rs
@@ -1,6 +1,5 @@
//@ check-pass
-#![warn(clippy::all, clippy::pedantic)]
#![allow(clippy::useless_vec)]
#[derive(Debug, Copy, Clone)]
diff --git a/src/tools/clippy/tests/ui/fn_params_excessive_bools.rs b/src/tools/clippy/tests/ui/fn_params_excessive_bools.rs
index cc18708..25d2566 100644
--- a/src/tools/clippy/tests/ui/fn_params_excessive_bools.rs
+++ b/src/tools/clippy/tests/ui/fn_params_excessive_bools.rs
@@ -1,7 +1,7 @@
#![warn(clippy::fn_params_excessive_bools)]
#![allow(clippy::too_many_arguments)]
-extern "C" {
+unsafe extern "C" {
// Should not lint, most of the time users have no control over extern function signatures
fn f(_: bool, _: bool, _: bool, _: bool);
}
@@ -14,8 +14,8 @@ fn fff(_: bool, _: bool, _: bool, _: bool) {}
foo!();
-#[no_mangle]
-extern "C" fn k(_: bool, _: bool, _: bool, _: bool) {}
+#[unsafe(no_mangle)]
+unsafe extern "C" fn k(_: bool, _: bool, _: bool, _: bool) {}
fn g(_: bool, _: bool, _: bool, _: bool) {}
//~^ ERROR: more than 3 bools in function parameters
fn h(_: bool, _: bool, _: bool) {}
@@ -39,8 +39,8 @@ impl S {
fn f(&self, _: bool, _: bool, _: bool, _: bool) {}
//~^ ERROR: more than 3 bools in function parameters
fn g(&self, _: bool, _: bool, _: bool) {}
- #[no_mangle]
- extern "C" fn h(_: bool, _: bool, _: bool, _: bool) {}
+ #[unsafe(no_mangle)]
+ unsafe extern "C" fn h(_: bool, _: bool, _: bool, _: bool) {}
}
impl Trait for S {
diff --git a/src/tools/clippy/tests/ui/formatting.rs b/src/tools/clippy/tests/ui/formatting.rs
index 4e84dcf..0098156 100644
--- a/src/tools/clippy/tests/ui/formatting.rs
+++ b/src/tools/clippy/tests/ui/formatting.rs
@@ -1,6 +1,3 @@
-#![warn(clippy::all)]
-#![allow(unused_variables)]
-#![allow(unused_assignments)]
#![allow(clippy::if_same_then_else)]
#![allow(clippy::deref_addrof)]
#![allow(clippy::nonminimal_bool)]
diff --git a/src/tools/clippy/tests/ui/formatting.stderr b/src/tools/clippy/tests/ui/formatting.stderr
index 972bd3a..d9dc2a5 100644
--- a/src/tools/clippy/tests/ui/formatting.stderr
+++ b/src/tools/clippy/tests/ui/formatting.stderr
@@ -1,5 +1,5 @@
error: this looks like you are trying to use `.. -= ..`, but you really are doing `.. = (- ..)`
- --> tests/ui/formatting.rs:16:6
+ --> tests/ui/formatting.rs:13:6
|
LL | a =- 35;
| ^^^^
@@ -9,7 +9,7 @@
= help: to override `-D warnings` add `#[allow(clippy::suspicious_assignment_formatting)]`
error: this looks like you are trying to use `.. *= ..`, but you really are doing `.. = (* ..)`
- --> tests/ui/formatting.rs:20:6
+ --> tests/ui/formatting.rs:17:6
|
LL | a =* &191;
| ^^^^
@@ -17,7 +17,7 @@
= note: to remove this lint, use either `*=` or `= *`
error: this looks like you are trying to use `.. != ..`, but you really are doing `.. = (! ..)`
- --> tests/ui/formatting.rs:26:6
+ --> tests/ui/formatting.rs:23:6
|
LL | b =! false;
| ^^^^
@@ -25,17 +25,16 @@
= note: to remove this lint, use either `!=` or `= !`
error: possibly missing a comma here
- --> tests/ui/formatting.rs:38:19
+ --> tests/ui/formatting.rs:35:19
|
LL | -1, -2, -3 // <= no comma here
| ^
|
= note: to remove this lint, add a comma or write the expr in a single line
- = note: `-D clippy::possible-missing-comma` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::possible_missing_comma)]`
+ = note: `#[deny(clippy::possible_missing_comma)]` on by default
error: possibly missing a comma here
- --> tests/ui/formatting.rs:45:19
+ --> tests/ui/formatting.rs:42:19
|
LL | -1, -2, -3 // <= no comma here
| ^
@@ -43,7 +42,7 @@
= note: to remove this lint, add a comma or write the expr in a single line
error: possibly missing a comma here
- --> tests/ui/formatting.rs:85:11
+ --> tests/ui/formatting.rs:82:11
|
LL | -1
| ^
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
index 8618004..be98b22 100644
--- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed
@@ -73,3 +73,46 @@
for _i in [1, 2, 3].iter().collect::<Vec<&i32>>() {}
//~^ from_iter_instead_of_collect
}
+
+fn issue14581() {
+ let nums = [0, 1, 2];
+ let _ = &nums.iter().map(|&num| char::from_u32(num).unwrap()).collect::<String>();
+ //~^ from_iter_instead_of_collect
+}
+
+fn test_implicit_generic_args(iter: impl Iterator<Item = &'static i32> + Copy) {
+ struct S<'l, T = i32, const A: usize = 3, const B: usize = 3> {
+ a: [&'l T; A],
+ b: [&'l T; B],
+ }
+
+ impl<'l, T, const A: usize, const B: usize> FromIterator<&'l T> for S<'l, T, A, B> {
+ fn from_iter<I: IntoIterator<Item = &'l T>>(_: I) -> Self {
+ todo!()
+ }
+ }
+
+ let _ = iter.collect::<S<'static, i32, 7>>();
+ //~^ from_iter_instead_of_collect
+
+ let _ = iter.collect::<S<'static, i32>>();
+ //~^ from_iter_instead_of_collect
+
+ let _ = iter.collect::<S<'static, _, 7>>();
+ //~^ from_iter_instead_of_collect
+
+ let _ = iter.collect::<S<'static, _, 7, 8>>();
+ //~^ from_iter_instead_of_collect
+
+ let _ = iter.collect::<S<_, 7, 8>>();
+ //~^ from_iter_instead_of_collect
+
+ let _ = iter.collect::<S<i32>>();
+ //~^ from_iter_instead_of_collect
+
+ let _ = iter.collect::<S<i32>>();
+ //~^ from_iter_instead_of_collect
+
+ let _ = iter.collect::<S>();
+ //~^ from_iter_instead_of_collect
+}
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
index c46397e..ce20fef 100644
--- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs
@@ -73,3 +73,46 @@ fn main() {
for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {}
//~^ from_iter_instead_of_collect
}
+
+fn issue14581() {
+ let nums = [0, 1, 2];
+ let _ = &String::from_iter(nums.iter().map(|&num| char::from_u32(num).unwrap()));
+ //~^ from_iter_instead_of_collect
+}
+
+fn test_implicit_generic_args(iter: impl Iterator<Item = &'static i32> + Copy) {
+ struct S<'l, T = i32, const A: usize = 3, const B: usize = 3> {
+ a: [&'l T; A],
+ b: [&'l T; B],
+ }
+
+ impl<'l, T, const A: usize, const B: usize> FromIterator<&'l T> for S<'l, T, A, B> {
+ fn from_iter<I: IntoIterator<Item = &'l T>>(_: I) -> Self {
+ todo!()
+ }
+ }
+
+ let _ = <S<'static, i32, 7>>::from_iter(iter);
+ //~^ from_iter_instead_of_collect
+
+ let _ = <S<'static, i32>>::from_iter(iter);
+ //~^ from_iter_instead_of_collect
+
+ let _ = <S<'static, _, 7>>::from_iter(iter);
+ //~^ from_iter_instead_of_collect
+
+ let _ = <S<'static, _, 7, 8>>::from_iter(iter);
+ //~^ from_iter_instead_of_collect
+
+ let _ = <S<'_, _, 7, 8>>::from_iter(iter);
+ //~^ from_iter_instead_of_collect
+
+ let _ = <S<i32>>::from_iter(iter);
+ //~^ from_iter_instead_of_collect
+
+ let _ = <S<'_, i32>>::from_iter(iter);
+ //~^ from_iter_instead_of_collect
+
+ let _ = <S>::from_iter(iter);
+ //~^ from_iter_instead_of_collect
+}
diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr
index b46d97af1..ec11a37 100644
--- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr
+++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr
@@ -91,5 +91,59 @@
LL | for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<&i32>>()`
-error: aborting due to 15 previous errors
+error: usage of `FromIterator::from_iter`
+ --> tests/ui/from_iter_instead_of_collect.rs:79:14
+ |
+LL | let _ = &String::from_iter(nums.iter().map(|&num| char::from_u32(num).unwrap()));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `nums.iter().map(|&num| char::from_u32(num).unwrap()).collect::<String>()`
+
+error: usage of `FromIterator::from_iter`
+ --> tests/ui/from_iter_instead_of_collect.rs:95:13
+ |
+LL | let _ = <S<'static, i32, 7>>::from_iter(iter);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::<S<'static, i32, 7>>()`
+
+error: usage of `FromIterator::from_iter`
+ --> tests/ui/from_iter_instead_of_collect.rs:98:13
+ |
+LL | let _ = <S<'static, i32>>::from_iter(iter);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::<S<'static, i32>>()`
+
+error: usage of `FromIterator::from_iter`
+ --> tests/ui/from_iter_instead_of_collect.rs:101:13
+ |
+LL | let _ = <S<'static, _, 7>>::from_iter(iter);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::<S<'static, _, 7>>()`
+
+error: usage of `FromIterator::from_iter`
+ --> tests/ui/from_iter_instead_of_collect.rs:104:13
+ |
+LL | let _ = <S<'static, _, 7, 8>>::from_iter(iter);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::<S<'static, _, 7, 8>>()`
+
+error: usage of `FromIterator::from_iter`
+ --> tests/ui/from_iter_instead_of_collect.rs:107:13
+ |
+LL | let _ = <S<'_, _, 7, 8>>::from_iter(iter);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::<S<_, 7, 8>>()`
+
+error: usage of `FromIterator::from_iter`
+ --> tests/ui/from_iter_instead_of_collect.rs:110:13
+ |
+LL | let _ = <S<i32>>::from_iter(iter);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::<S<i32>>()`
+
+error: usage of `FromIterator::from_iter`
+ --> tests/ui/from_iter_instead_of_collect.rs:113:13
+ |
+LL | let _ = <S<'_, i32>>::from_iter(iter);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::<S<i32>>()`
+
+error: usage of `FromIterator::from_iter`
+ --> tests/ui/from_iter_instead_of_collect.rs:116:13
+ |
+LL | let _ = <S>::from_iter(iter);
+ | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.collect::<S>()`
+
+error: aborting due to 24 previous errors
diff --git a/src/tools/clippy/tests/ui/functions.rs b/src/tools/clippy/tests/ui/functions.rs
index 9c1ca8b..ceaba39 100644
--- a/src/tools/clippy/tests/ui/functions.rs
+++ b/src/tools/clippy/tests/ui/functions.rs
@@ -1,5 +1,3 @@
-#![warn(clippy::all)]
-#![allow(dead_code, unused_unsafe)]
#![allow(clippy::missing_safety_doc, clippy::uninlined_format_args)]
// TOO_MANY_ARGUMENTS
diff --git a/src/tools/clippy/tests/ui/functions.stderr b/src/tools/clippy/tests/ui/functions.stderr
index c877002..65cc627 100644
--- a/src/tools/clippy/tests/ui/functions.stderr
+++ b/src/tools/clippy/tests/ui/functions.stderr
@@ -1,5 +1,5 @@
error: this function has too many arguments (8/7)
- --> tests/ui/functions.rs:8:1
+ --> tests/ui/functions.rs:6:1
|
LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,7 +8,7 @@
= help: to override `-D warnings` add `#[allow(clippy::too_many_arguments)]`
error: this function has too many arguments (8/7)
- --> tests/ui/functions.rs:12:1
+ --> tests/ui/functions.rs:10:1
|
LL | / fn bad_multiline(
LL | |
@@ -20,88 +20,87 @@
| |_^
error: this function has too many arguments (8/7)
- --> tests/ui/functions.rs:48:5
+ --> tests/ui/functions.rs:46:5
|
LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this function has too many arguments (8/7)
- --> tests/ui/functions.rs:58:5
+ --> tests/ui/functions.rs:56:5
|
LL | fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this public function might dereference a raw pointer but is not marked `unsafe`
- --> tests/ui/functions.rs:68:34
+ --> tests/ui/functions.rs:66:34
|
LL | println!("{}", unsafe { *p });
| ^
|
- = note: `-D clippy::not-unsafe-ptr-arg-deref` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::not_unsafe_ptr_arg_deref)]`
+ = note: `#[deny(clippy::not_unsafe_ptr_arg_deref)]` on by default
error: this public function might dereference a raw pointer but is not marked `unsafe`
- --> tests/ui/functions.rs:71:35
+ --> tests/ui/functions.rs:69:35
|
LL | println!("{:?}", unsafe { p.as_ref() });
| ^
error: this public function might dereference a raw pointer but is not marked `unsafe`
- --> tests/ui/functions.rs:74:33
+ --> tests/ui/functions.rs:72:33
|
LL | unsafe { std::ptr::read(p) };
| ^
error: this public function might dereference a raw pointer but is not marked `unsafe`
- --> tests/ui/functions.rs:86:30
+ --> tests/ui/functions.rs:84:30
|
LL | println!("{}", unsafe { *p });
| ^
error: this public function might dereference a raw pointer but is not marked `unsafe`
- --> tests/ui/functions.rs:89:31
+ --> tests/ui/functions.rs:87:31
|
LL | println!("{:?}", unsafe { p.as_ref() });
| ^
error: this public function might dereference a raw pointer but is not marked `unsafe`
- --> tests/ui/functions.rs:92:29
+ --> tests/ui/functions.rs:90:29
|
LL | unsafe { std::ptr::read(p) };
| ^
error: this public function might dereference a raw pointer but is not marked `unsafe`
- --> tests/ui/functions.rs:99:30
+ --> tests/ui/functions.rs:97:30
|
LL | println!("{}", unsafe { *p });
| ^
error: this public function might dereference a raw pointer but is not marked `unsafe`
- --> tests/ui/functions.rs:102:31
+ --> tests/ui/functions.rs:100:31
|
LL | println!("{:?}", unsafe { p.as_ref() });
| ^
error: this public function might dereference a raw pointer but is not marked `unsafe`
- --> tests/ui/functions.rs:105:29
+ --> tests/ui/functions.rs:103:29
|
LL | unsafe { std::ptr::read(p) };
| ^
error: this public function might dereference a raw pointer but is not marked `unsafe`
- --> tests/ui/functions.rs:115:34
+ --> tests/ui/functions.rs:113:34
|
LL | println!("{}", unsafe { *p });
| ^
error: this public function might dereference a raw pointer but is not marked `unsafe`
- --> tests/ui/functions.rs:118:35
+ --> tests/ui/functions.rs:116:35
|
LL | println!("{:?}", unsafe { p.as_ref() });
| ^
error: this public function might dereference a raw pointer but is not marked `unsafe`
- --> tests/ui/functions.rs:121:33
+ --> tests/ui/functions.rs:119:33
|
LL | unsafe { std::ptr::read(p) };
| ^
diff --git a/src/tools/clippy/tests/ui/if_not_else.fixed b/src/tools/clippy/tests/ui/if_not_else.fixed
index d26a151..4e6f43e 100644
--- a/src/tools/clippy/tests/ui/if_not_else.fixed
+++ b/src/tools/clippy/tests/ui/if_not_else.fixed
@@ -1,4 +1,3 @@
-#![warn(clippy::all)]
#![warn(clippy::if_not_else)]
fn foo() -> bool {
diff --git a/src/tools/clippy/tests/ui/if_not_else.rs b/src/tools/clippy/tests/ui/if_not_else.rs
index 6171cf1..6cd2e3b 100644
--- a/src/tools/clippy/tests/ui/if_not_else.rs
+++ b/src/tools/clippy/tests/ui/if_not_else.rs
@@ -1,4 +1,3 @@
-#![warn(clippy::all)]
#![warn(clippy::if_not_else)]
fn foo() -> bool {
diff --git a/src/tools/clippy/tests/ui/if_not_else.stderr b/src/tools/clippy/tests/ui/if_not_else.stderr
index f44dd0a..824837b 100644
--- a/src/tools/clippy/tests/ui/if_not_else.stderr
+++ b/src/tools/clippy/tests/ui/if_not_else.stderr
@@ -1,5 +1,5 @@
error: unnecessary boolean `not` operation
- --> tests/ui/if_not_else.rs:12:5
+ --> tests/ui/if_not_else.rs:11:5
|
LL | / if !bla() {
LL | |
@@ -24,7 +24,7 @@
|
error: unnecessary `!=` operation
- --> tests/ui/if_not_else.rs:19:5
+ --> tests/ui/if_not_else.rs:18:5
|
LL | / if 4 != 5 {
LL | |
@@ -47,7 +47,7 @@
|
error: unnecessary boolean `not` operation
- --> tests/ui/if_not_else.rs:34:5
+ --> tests/ui/if_not_else.rs:33:5
|
LL | / if !(foo() && bla()) {
LL | |
@@ -79,7 +79,7 @@
|
error: unnecessary boolean `not` operation
- --> tests/ui/if_not_else.rs:53:5
+ --> tests/ui/if_not_else.rs:52:5
|
LL | / if !foo() {
LL | |
@@ -102,7 +102,7 @@
|
error: unnecessary boolean `not` operation
- --> tests/ui/if_not_else.rs:61:5
+ --> tests/ui/if_not_else.rs:60:5
|
LL | / if !bla() {
LL | |
@@ -125,7 +125,7 @@
|
error: unnecessary boolean `not` operation
- --> tests/ui/if_not_else.rs:72:5
+ --> tests/ui/if_not_else.rs:71:5
|
LL | / if !foo() {
LL | |
diff --git a/src/tools/clippy/tests/ui/ignore_without_reason.rs b/src/tools/clippy/tests/ui/ignore_without_reason.rs
new file mode 100644
index 0000000..53ac34c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ignore_without_reason.rs
@@ -0,0 +1,14 @@
+#![warn(clippy::ignore_without_reason)]
+
+fn main() {}
+
+#[test]
+fn unignored_test() {}
+
+#[test]
+#[ignore = "Some good reason"]
+fn ignored_with_reason() {}
+
+#[test]
+#[ignore] //~ ignore_without_reason
+fn ignored_without_reason() {}
diff --git a/src/tools/clippy/tests/ui/ignore_without_reason.stderr b/src/tools/clippy/tests/ui/ignore_without_reason.stderr
new file mode 100644
index 0000000..4c0210c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/ignore_without_reason.stderr
@@ -0,0 +1,12 @@
+error: `#[ignore]` without reason
+ --> tests/ui/ignore_without_reason.rs:13:1
+ |
+LL | #[ignore]
+ | ^^^^^^^^^
+ |
+ = help: add a reason with `= ".."`
+ = note: `-D clippy::ignore-without-reason` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::ignore_without_reason)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/implicit_return.fixed b/src/tools/clippy/tests/ui/implicit_return.fixed
index 1cb639b..728c6e0 100644
--- a/src/tools/clippy/tests/ui/implicit_return.fixed
+++ b/src/tools/clippy/tests/ui/implicit_return.fixed
@@ -165,3 +165,46 @@
x
}
);
+
+fn desugared_closure_14446() {
+ let _ = async || return 0;
+ //~^ implicit_return
+ #[rustfmt::skip]
+ let _ = async || -> i32 { return 0 };
+ //~^ implicit_return
+ let _ = async |a: i32| return a;
+ //~^ implicit_return
+ #[rustfmt::skip]
+ let _ = async |a: i32| { return a };
+ //~^ implicit_return
+
+ let _ = async || return 0;
+ let _ = async || -> i32 { return 0 };
+ let _ = async |a: i32| return a;
+ #[rustfmt::skip]
+ let _ = async |a: i32| { return a; };
+
+ let _ = async || return foo().await;
+ //~^ implicit_return
+ let _ = async || {
+ foo().await;
+ return foo().await
+ };
+ //~^^ implicit_return
+ #[rustfmt::skip]
+ let _ = async || { return foo().await };
+ //~^ implicit_return
+ let _ = async || -> bool { return foo().await };
+ //~^ implicit_return
+
+ let _ = async || return foo().await;
+ let _ = async || {
+ foo().await;
+ return foo().await;
+ };
+ #[rustfmt::skip]
+ let _ = async || { return foo().await; };
+ let _ = async || -> bool {
+ return foo().await;
+ };
+}
diff --git a/src/tools/clippy/tests/ui/implicit_return.rs b/src/tools/clippy/tests/ui/implicit_return.rs
index 99d75e4..3381fff 100644
--- a/src/tools/clippy/tests/ui/implicit_return.rs
+++ b/src/tools/clippy/tests/ui/implicit_return.rs
@@ -165,3 +165,46 @@ fn dont_lint_proc_macro(x: usize) -> usize{
x
}
);
+
+fn desugared_closure_14446() {
+ let _ = async || 0;
+ //~^ implicit_return
+ #[rustfmt::skip]
+ let _ = async || -> i32 { 0 };
+ //~^ implicit_return
+ let _ = async |a: i32| a;
+ //~^ implicit_return
+ #[rustfmt::skip]
+ let _ = async |a: i32| { a };
+ //~^ implicit_return
+
+ let _ = async || return 0;
+ let _ = async || -> i32 { return 0 };
+ let _ = async |a: i32| return a;
+ #[rustfmt::skip]
+ let _ = async |a: i32| { return a; };
+
+ let _ = async || foo().await;
+ //~^ implicit_return
+ let _ = async || {
+ foo().await;
+ foo().await
+ };
+ //~^^ implicit_return
+ #[rustfmt::skip]
+ let _ = async || { foo().await };
+ //~^ implicit_return
+ let _ = async || -> bool { foo().await };
+ //~^ implicit_return
+
+ let _ = async || return foo().await;
+ let _ = async || {
+ foo().await;
+ return foo().await;
+ };
+ #[rustfmt::skip]
+ let _ = async || { return foo().await; };
+ let _ = async || -> bool {
+ return foo().await;
+ };
+}
diff --git a/src/tools/clippy/tests/ui/implicit_return.stderr b/src/tools/clippy/tests/ui/implicit_return.stderr
index 02044df..05cd7f6 100644
--- a/src/tools/clippy/tests/ui/implicit_return.stderr
+++ b/src/tools/clippy/tests/ui/implicit_return.stderr
@@ -183,5 +183,93 @@
LL | return true
| ++++++
-error: aborting due to 16 previous errors
+error: missing `return` statement
+ --> tests/ui/implicit_return.rs:170:22
+ |
+LL | let _ = async || 0;
+ | ^
+ |
+help: add `return` as shown
+ |
+LL | let _ = async || return 0;
+ | ++++++
+
+error: missing `return` statement
+ --> tests/ui/implicit_return.rs:173:31
+ |
+LL | let _ = async || -> i32 { 0 };
+ | ^
+ |
+help: add `return` as shown
+ |
+LL | let _ = async || -> i32 { return 0 };
+ | ++++++
+
+error: missing `return` statement
+ --> tests/ui/implicit_return.rs:175:28
+ |
+LL | let _ = async |a: i32| a;
+ | ^
+ |
+help: add `return` as shown
+ |
+LL | let _ = async |a: i32| return a;
+ | ++++++
+
+error: missing `return` statement
+ --> tests/ui/implicit_return.rs:178:30
+ |
+LL | let _ = async |a: i32| { a };
+ | ^
+ |
+help: add `return` as shown
+ |
+LL | let _ = async |a: i32| { return a };
+ | ++++++
+
+error: missing `return` statement
+ --> tests/ui/implicit_return.rs:187:22
+ |
+LL | let _ = async || foo().await;
+ | ^^^^^
+ |
+help: add `return` as shown
+ |
+LL | let _ = async || return foo().await;
+ | ++++++
+
+error: missing `return` statement
+ --> tests/ui/implicit_return.rs:191:9
+ |
+LL | foo().await
+ | ^^^^^
+ |
+help: add `return` as shown
+ |
+LL | return foo().await
+ | ++++++
+
+error: missing `return` statement
+ --> tests/ui/implicit_return.rs:195:24
+ |
+LL | let _ = async || { foo().await };
+ | ^^^^^
+ |
+help: add `return` as shown
+ |
+LL | let _ = async || { return foo().await };
+ | ++++++
+
+error: missing `return` statement
+ --> tests/ui/implicit_return.rs:197:32
+ |
+LL | let _ = async || -> bool { foo().await };
+ | ^^^^^
+ |
+help: add `return` as shown
+ |
+LL | let _ = async || -> bool { return foo().await };
+ | ++++++
+
+error: aborting due to 24 previous errors
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/root_module.fixed b/src/tools/clippy/tests/ui/items_after_test_module/root_module.fixed
index f036b36..c00d644 100644
--- a/src/tools/clippy/tests/ui/items_after_test_module/root_module.fixed
+++ b/src/tools/clippy/tests/ui/items_after_test_module/root_module.fixed
@@ -1,4 +1,3 @@
-#![allow(unused)]
#![warn(clippy::items_after_test_module)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/root_module.rs b/src/tools/clippy/tests/ui/items_after_test_module/root_module.rs
index de0cbb1..23d191e 100644
--- a/src/tools/clippy/tests/ui/items_after_test_module/root_module.rs
+++ b/src/tools/clippy/tests/ui/items_after_test_module/root_module.rs
@@ -1,4 +1,3 @@
-#![allow(unused)]
#![warn(clippy::items_after_test_module)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/root_module.stderr b/src/tools/clippy/tests/ui/items_after_test_module/root_module.stderr
index bed8d4b..952489f 100644
--- a/src/tools/clippy/tests/ui/items_after_test_module/root_module.stderr
+++ b/src/tools/clippy/tests/ui/items_after_test_module/root_module.stderr
@@ -1,5 +1,5 @@
error: items after a test module
- --> tests/ui/items_after_test_module/root_module.rs:12:1
+ --> tests/ui/items_after_test_module/root_module.rs:11:1
|
LL | mod tests {
| ^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.fixed b/src/tools/clippy/tests/ui/iter_cloned_collect.fixed
index e9fb44e..231fac7 100644
--- a/src/tools/clippy/tests/ui/iter_cloned_collect.fixed
+++ b/src/tools/clippy/tests/ui/iter_cloned_collect.fixed
@@ -29,3 +29,30 @@
let _: Vec<isize> = v.to_vec();
//~^ iter_cloned_collect
}
+
+mod issue9119 {
+
+ use std::iter;
+
+ #[derive(Clone)]
+ struct Example(u16);
+
+ impl iter::FromIterator<Example> for Vec<u8> {
+ fn from_iter<T>(iter: T) -> Self
+ where
+ T: IntoIterator<Item = Example>,
+ {
+ iter.into_iter().flat_map(|e| e.0.to_le_bytes()).collect()
+ }
+ }
+
+ fn foo() {
+ let examples = [Example(1), Example(0x1234)];
+ let encoded: Vec<u8> = examples.iter().cloned().collect();
+ assert_eq!(encoded, vec![0x01, 0x00, 0x34, 0x12]);
+
+ let a = [&&String::new()];
+ let v: Vec<&&String> = a.to_vec();
+ //~^ iter_cloned_collect
+ }
+}
diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.rs b/src/tools/clippy/tests/ui/iter_cloned_collect.rs
index c9b8abc..e73b6ec 100644
--- a/src/tools/clippy/tests/ui/iter_cloned_collect.rs
+++ b/src/tools/clippy/tests/ui/iter_cloned_collect.rs
@@ -33,3 +33,30 @@ fn main() {
let _: Vec<isize> = v.iter().copied().collect();
//~^ iter_cloned_collect
}
+
+mod issue9119 {
+
+ use std::iter;
+
+ #[derive(Clone)]
+ struct Example(u16);
+
+ impl iter::FromIterator<Example> for Vec<u8> {
+ fn from_iter<T>(iter: T) -> Self
+ where
+ T: IntoIterator<Item = Example>,
+ {
+ iter.into_iter().flat_map(|e| e.0.to_le_bytes()).collect()
+ }
+ }
+
+ fn foo() {
+ let examples = [Example(1), Example(0x1234)];
+ let encoded: Vec<u8> = examples.iter().cloned().collect();
+ assert_eq!(encoded, vec![0x01, 0x00, 0x34, 0x12]);
+
+ let a = [&&String::new()];
+ let v: Vec<&&String> = a.iter().cloned().collect();
+ //~^ iter_cloned_collect
+ }
+}
diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.stderr b/src/tools/clippy/tests/ui/iter_cloned_collect.stderr
index 119698c..f8a5079 100644
--- a/src/tools/clippy/tests/ui/iter_cloned_collect.stderr
+++ b/src/tools/clippy/tests/ui/iter_cloned_collect.stderr
@@ -36,5 +36,11 @@
LL | let _: Vec<isize> = v.iter().copied().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
-error: aborting due to 5 previous errors
+error: called `iter().cloned().collect()` on a slice to create a `Vec`. Calling `to_vec()` is both faster and more readable
+ --> tests/ui/iter_cloned_collect.rs:59:33
+ |
+LL | let v: Vec<&&String> = a.iter().cloned().collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `.to_vec()`
+
+error: aborting due to 6 previous errors
diff --git a/src/tools/clippy/tests/ui/iter_kv_map.fixed b/src/tools/clippy/tests/ui/iter_kv_map.fixed
index 7fcab65..874f749 100644
--- a/src/tools/clippy/tests/ui/iter_kv_map.fixed
+++ b/src/tools/clippy/tests/ui/iter_kv_map.fixed
@@ -166,3 +166,18 @@
let _ = map.values().map(|v| v + 2).collect::<Vec<_>>();
//~^ iter_kv_map
}
+
+fn issue14595() {
+ pub struct Foo(BTreeMap<String, i32>);
+
+ impl AsRef<BTreeMap<String, i32>> for Foo {
+ fn as_ref(&self) -> &BTreeMap<String, i32> {
+ &self.0
+ }
+ }
+
+ let map = Foo(BTreeMap::default());
+
+ let _ = map.as_ref().values().copied().collect::<Vec<_>>();
+ //~^ iter_kv_map
+}
diff --git a/src/tools/clippy/tests/ui/iter_kv_map.rs b/src/tools/clippy/tests/ui/iter_kv_map.rs
index b590aef..f570e3c 100644
--- a/src/tools/clippy/tests/ui/iter_kv_map.rs
+++ b/src/tools/clippy/tests/ui/iter_kv_map.rs
@@ -170,3 +170,18 @@ fn msrv_1_54() {
let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
//~^ iter_kv_map
}
+
+fn issue14595() {
+ pub struct Foo(BTreeMap<String, i32>);
+
+ impl AsRef<BTreeMap<String, i32>> for Foo {
+ fn as_ref(&self) -> &BTreeMap<String, i32> {
+ &self.0
+ }
+ }
+
+ let map = Foo(BTreeMap::default());
+
+ let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::<Vec<_>>();
+ //~^ iter_kv_map
+}
diff --git a/src/tools/clippy/tests/ui/iter_kv_map.stderr b/src/tools/clippy/tests/ui/iter_kv_map.stderr
index 00d566e..31ee76c 100644
--- a/src/tools/clippy/tests/ui/iter_kv_map.stderr
+++ b/src/tools/clippy/tests/ui/iter_kv_map.stderr
@@ -263,5 +263,11 @@
LL | let _ = map.iter().map(|(_, v)| v + 2).collect::<Vec<_>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.values().map(|v| v + 2)`
-error: aborting due to 38 previous errors
+error: iterating on a map's values
+ --> tests/ui/iter_kv_map.rs:185:13
+ |
+LL | let _ = map.as_ref().iter().map(|(_, v)| v).copied().collect::<Vec<_>>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `map.as_ref().values()`
+
+error: aborting due to 39 previous errors
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
index 9999126..b0e548f 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed
@@ -59,7 +59,7 @@
iter: impl Iterator<Item = &'a (&'a u32, String)> + 'a,
target: String,
) -> impl Iterator<Item = (&'a u32, String)> + 'a {
- iter.filter(move |&(&a, b)| a == 1 && b == &target).cloned()
+ iter.filter(move |&&(&a, ref b)| a == 1 && b == &target).cloned()
//~^ iter_overeager_cloned
}
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
index 6a860da..cedf62a 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs
@@ -60,7 +60,7 @@ fn test_move<'a>(
iter: impl Iterator<Item = &'a (&'a u32, String)> + 'a,
target: String,
) -> impl Iterator<Item = (&'a u32, String)> + 'a {
- iter.cloned().filter(move |(&a, b)| a == 1 && b == &target)
+ iter.cloned().filter(move |&(&a, ref b)| a == 1 && b == &target)
//~^ iter_overeager_cloned
}
diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
index f3239b5..1616dec 100644
--- a/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
+++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.stderr
@@ -120,10 +120,10 @@
error: unnecessarily eager cloning of iterator items
--> tests/ui/iter_overeager_cloned.rs:63:9
|
-LL | iter.cloned().filter(move |(&a, b)| a == 1 && b == &target)
- | ^^^^-------------------------------------------------------
+LL | iter.cloned().filter(move |&(&a, ref b)| a == 1 && b == &target)
+ | ^^^^------------------------------------------------------------
| |
- | help: try: `.filter(move |&(&a, b)| a == 1 && b == &target).cloned()`
+ | help: try: `.filter(move |&&(&a, ref b)| a == 1 && b == &target).cloned()`
error: unnecessarily eager cloning of iterator items
--> tests/ui/iter_overeager_cloned.rs:75:13
diff --git a/src/tools/clippy/tests/ui/large_futures.fixed b/src/tools/clippy/tests/ui/large_futures.fixed
index c2159c5..4c7215f 100644
--- a/src/tools/clippy/tests/ui/large_futures.fixed
+++ b/src/tools/clippy/tests/ui/large_futures.fixed
@@ -1,7 +1,10 @@
+#![allow(
+ clippy::future_not_send,
+ clippy::manual_async_fn,
+ clippy::never_loop,
+ clippy::uninlined_format_args
+)]
#![warn(clippy::large_futures)]
-#![allow(clippy::never_loop)]
-#![allow(clippy::future_not_send)]
-#![allow(clippy::manual_async_fn)]
async fn big_fut(_arg: [u8; 1024 * 16]) {}
diff --git a/src/tools/clippy/tests/ui/large_futures.rs b/src/tools/clippy/tests/ui/large_futures.rs
index 567f634..2b58605 100644
--- a/src/tools/clippy/tests/ui/large_futures.rs
+++ b/src/tools/clippy/tests/ui/large_futures.rs
@@ -1,7 +1,10 @@
+#![allow(
+ clippy::future_not_send,
+ clippy::manual_async_fn,
+ clippy::never_loop,
+ clippy::uninlined_format_args
+)]
#![warn(clippy::large_futures)]
-#![allow(clippy::never_loop)]
-#![allow(clippy::future_not_send)]
-#![allow(clippy::manual_async_fn)]
async fn big_fut(_arg: [u8; 1024 * 16]) {}
diff --git a/src/tools/clippy/tests/ui/large_futures.stderr b/src/tools/clippy/tests/ui/large_futures.stderr
index fd6ba4e..4280c9e 100644
--- a/src/tools/clippy/tests/ui/large_futures.stderr
+++ b/src/tools/clippy/tests/ui/large_futures.stderr
@@ -1,5 +1,5 @@
error: large future with a size of 16385 bytes
- --> tests/ui/large_futures.rs:10:9
+ --> tests/ui/large_futures.rs:13:9
|
LL | big_fut([0u8; 1024 * 16]).await;
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(big_fut([0u8; 1024 * 16]))`
@@ -8,37 +8,37 @@
= help: to override `-D warnings` add `#[allow(clippy::large_futures)]`
error: large future with a size of 16386 bytes
- --> tests/ui/large_futures.rs:13:5
+ --> tests/ui/large_futures.rs:16:5
|
LL | f.await
| ^ help: consider `Box::pin` on it: `Box::pin(f)`
error: large future with a size of 16387 bytes
- --> tests/ui/large_futures.rs:18:9
+ --> tests/ui/large_futures.rs:21:9
|
LL | wait().await;
| ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())`
error: large future with a size of 16387 bytes
- --> tests/ui/large_futures.rs:24:13
+ --> tests/ui/large_futures.rs:27:13
|
LL | wait().await;
| ^^^^^^ help: consider `Box::pin` on it: `Box::pin(wait())`
error: large future with a size of 65540 bytes
- --> tests/ui/large_futures.rs:32:5
+ --> tests/ui/large_futures.rs:35:5
|
LL | foo().await;
| ^^^^^ help: consider `Box::pin` on it: `Box::pin(foo())`
error: large future with a size of 49159 bytes
- --> tests/ui/large_futures.rs:35:5
+ --> tests/ui/large_futures.rs:38:5
|
LL | calls_fut(fut).await;
| ^^^^^^^^^^^^^^ help: consider `Box::pin` on it: `Box::pin(calls_fut(fut))`
error: large future with a size of 65540 bytes
- --> tests/ui/large_futures.rs:48:5
+ --> tests/ui/large_futures.rs:51:5
|
LL | / async {
LL | |
@@ -61,7 +61,7 @@
|
error: large future with a size of 65540 bytes
- --> tests/ui/large_futures.rs:61:13
+ --> tests/ui/large_futures.rs:64:13
|
LL | / async {
LL | |
diff --git a/src/tools/clippy/tests/ui/len_without_is_empty_expect.rs b/src/tools/clippy/tests/ui/len_without_is_empty_expect.rs
new file mode 100644
index 0000000..9d1245e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/len_without_is_empty_expect.rs
@@ -0,0 +1,28 @@
+//@no-rustfix
+#![allow(clippy::len_without_is_empty)]
+
+// Check that the lint expectation is fulfilled even if the lint is allowed at the type level.
+pub struct Empty;
+
+impl Empty {
+ #[expect(clippy::len_without_is_empty)]
+ pub fn len(&self) -> usize {
+ 0
+ }
+}
+
+// Check that the lint expectation is not triggered if it should not
+pub struct Empty2;
+
+impl Empty2 {
+ #[expect(clippy::len_without_is_empty)] //~ ERROR: this lint expectation is unfulfilled
+ pub fn len(&self) -> usize {
+ 0
+ }
+
+ pub fn is_empty(&self) -> bool {
+ false
+ }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/len_without_is_empty_expect.stderr b/src/tools/clippy/tests/ui/len_without_is_empty_expect.stderr
new file mode 100644
index 0000000..e96870f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/len_without_is_empty_expect.stderr
@@ -0,0 +1,11 @@
+error: this lint expectation is unfulfilled
+ --> tests/ui/len_without_is_empty_expect.rs:18:14
+ |
+LL | #[expect(clippy::len_without_is_empty)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D unfulfilled-lint-expectations` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(unfulfilled_lint_expectations)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/manual_abs_diff.fixed b/src/tools/clippy/tests/ui/manual_abs_diff.fixed
new file mode 100644
index 0000000..f1b1278
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_abs_diff.fixed
@@ -0,0 +1,106 @@
+#![warn(clippy::manual_abs_diff)]
+
+use std::time::Duration;
+
+fn main() {
+ let a: usize = 5;
+ let b: usize = 3;
+ let c: usize = 8;
+ let d: usize = 11;
+
+ let _ = a.abs_diff(b);
+ //~^ manual_abs_diff
+ let _ = b.abs_diff(a);
+ //~^ manual_abs_diff
+
+ let _ = b.abs_diff(5);
+ //~^ manual_abs_diff
+ let _ = b.abs_diff(5);
+ //~^ manual_abs_diff
+
+ let _ = a.abs_diff(b);
+ //~^ manual_abs_diff
+ let _ = b.abs_diff(a);
+ //~^ manual_abs_diff
+
+ #[allow(arithmetic_overflow)]
+ {
+ let _ = if a > b { b - a } else { a - b };
+ let _ = if a < b { a - b } else { b - a };
+ }
+
+ let _ = (a + b).abs_diff(c + d);
+ let _ = (c + d).abs_diff(a + b);
+
+ const A: usize = 5;
+ const B: usize = 3;
+ // check const context
+ const _: usize = A.abs_diff(B);
+ //~^ manual_abs_diff
+
+ let a = Duration::from_secs(3);
+ let b = Duration::from_secs(5);
+ let _ = a.abs_diff(b);
+ //~^ manual_abs_diff
+
+ let a: i32 = 3;
+ let b: i32 = -5;
+ let _ = if a > b { a - b } else { b - a };
+ let _ = a.abs_diff(b);
+ //~^ manual_abs_diff
+}
+
+// FIXME: bunch of patterns that should be linted
+fn fixme() {
+ let a: usize = 5;
+ let b: usize = 3;
+ let c: usize = 8;
+ let d: usize = 11;
+
+ {
+ let out;
+ if a > b {
+ out = a - b;
+ } else {
+ out = b - a;
+ }
+ }
+
+ {
+ let mut out = 0;
+ if a > b {
+ out = a - b;
+ } else if a < b {
+ out = b - a;
+ }
+ }
+
+ #[allow(clippy::implicit_saturating_sub)]
+ let _ = if a > b {
+ a - b
+ } else if a < b {
+ b - a
+ } else {
+ 0
+ };
+
+ let a: i32 = 3;
+ let b: i32 = 5;
+ let _: u32 = if a > b { a - b } else { b - a } as u32;
+}
+
+fn non_primitive_ty() {
+ #[derive(Eq, PartialEq, PartialOrd)]
+ struct S(i32);
+
+ impl std::ops::Sub for S {
+ type Output = S;
+
+ fn sub(self, rhs: Self) -> Self::Output {
+ Self(self.0 - rhs.0)
+ }
+ }
+
+ let (a, b) = (S(10), S(20));
+ let _ = if a < b { b - a } else { a - b };
+}
diff --git a/src/tools/clippy/tests/ui/manual_abs_diff.rs b/src/tools/clippy/tests/ui/manual_abs_diff.rs
new file mode 100644
index 0000000..60ef819
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_abs_diff.rs
@@ -0,0 +1,116 @@
+#![warn(clippy::manual_abs_diff)]
+
+use std::time::Duration;
+
+fn main() {
+ let a: usize = 5;
+ let b: usize = 3;
+ let c: usize = 8;
+ let d: usize = 11;
+
+ let _ = if a > b { a - b } else { b - a };
+ //~^ manual_abs_diff
+ let _ = if a < b { b - a } else { a - b };
+ //~^ manual_abs_diff
+
+ let _ = if 5 > b { 5 - b } else { b - 5 };
+ //~^ manual_abs_diff
+ let _ = if b > 5 { b - 5 } else { 5 - b };
+ //~^ manual_abs_diff
+
+ let _ = if a >= b { a - b } else { b - a };
+ //~^ manual_abs_diff
+ let _ = if a <= b { b - a } else { a - b };
+ //~^ manual_abs_diff
+
+ #[allow(arithmetic_overflow)]
+ {
+ let _ = if a > b { b - a } else { a - b };
+ let _ = if a < b { a - b } else { b - a };
+ }
+
+ let _ = if (a + b) > (c + d) {
+ //~^ manual_abs_diff
+ (a + b) - (c + d)
+ } else {
+ (c + d) - (a + b)
+ };
+ let _ = if (a + b) < (c + d) {
+ //~^ manual_abs_diff
+ (c + d) - (a + b)
+ } else {
+ (a + b) - (c + d)
+ };
+
+ const A: usize = 5;
+ const B: usize = 3;
+ // check const context
+ const _: usize = if A > B { A - B } else { B - A };
+ //~^ manual_abs_diff
+
+ let a = Duration::from_secs(3);
+ let b = Duration::from_secs(5);
+ let _ = if a > b { a - b } else { b - a };
+ //~^ manual_abs_diff
+
+ let a: i32 = 3;
+ let b: i32 = -5;
+ let _ = if a > b { a - b } else { b - a };
+ let _ = if a > b { (a - b) as u32 } else { (b - a) as u32 };
+ //~^ manual_abs_diff
+}
+
+// FIXME: bunch of patterns that should be linted
+fn fixme() {
+ let a: usize = 5;
+ let b: usize = 3;
+ let c: usize = 8;
+ let d: usize = 11;
+
+ {
+ let out;
+ if a > b {
+ out = a - b;
+ } else {
+ out = b - a;
+ }
+ }
+
+ {
+ let mut out = 0;
+ if a > b {
+ out = a - b;
+ } else if a < b {
+ out = b - a;
+ }
+ }
+
+ #[allow(clippy::implicit_saturating_sub)]
+ let _ = if a > b {
+ a - b
+ } else if a < b {
+ b - a
+ } else {
+ 0
+ };
+
+ let a: i32 = 3;
+ let b: i32 = 5;
+ let _: u32 = if a > b { a - b } else { b - a } as u32;
+}
+
+fn non_primitive_ty() {
+ #[derive(Eq, PartialEq, PartialOrd)]
+ struct S(i32);
+
+ impl std::ops::Sub for S {
+ type Output = S;
+
+ fn sub(self, rhs: Self) -> Self::Output {
+ Self(self.0 - rhs.0)
+ }
+ }
+
+ let (a, b) = (S(10), S(20));
+ let _ = if a < b { b - a } else { a - b };
+}
diff --git a/src/tools/clippy/tests/ui/manual_abs_diff.stderr b/src/tools/clippy/tests/ui/manual_abs_diff.stderr
new file mode 100644
index 0000000..c14c1dc
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_abs_diff.stderr
@@ -0,0 +1,83 @@
+error: manual absolute difference pattern without using `abs_diff`
+ --> tests/ui/manual_abs_diff.rs:11:13
+ |
+LL | let _ = if a > b { a - b } else { b - a };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `a.abs_diff(b)`
+ |
+ = note: `-D clippy::manual-abs-diff` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::manual_abs_diff)]`
+
+error: manual absolute difference pattern without using `abs_diff`
+ --> tests/ui/manual_abs_diff.rs:13:13
+ |
+LL | let _ = if a < b { b - a } else { a - b };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `b.abs_diff(a)`
+
+error: manual absolute difference pattern without using `abs_diff`
+ --> tests/ui/manual_abs_diff.rs:16:13
+ |
+LL | let _ = if 5 > b { 5 - b } else { b - 5 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `b.abs_diff(5)`
+
+error: manual absolute difference pattern without using `abs_diff`
+ --> tests/ui/manual_abs_diff.rs:18:13
+ |
+LL | let _ = if b > 5 { b - 5 } else { 5 - b };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `b.abs_diff(5)`
+
+error: manual absolute difference pattern without using `abs_diff`
+ --> tests/ui/manual_abs_diff.rs:21:13
+ |
+LL | let _ = if a >= b { a - b } else { b - a };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `a.abs_diff(b)`
+
+error: manual absolute difference pattern without using `abs_diff`
+ --> tests/ui/manual_abs_diff.rs:23:13
+ |
+LL | let _ = if a <= b { b - a } else { a - b };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `b.abs_diff(a)`
+
+error: manual absolute difference pattern without using `abs_diff`
+ --> tests/ui/manual_abs_diff.rs:32:13
+ |
+LL | let _ = if (a + b) > (c + d) {
+ | _____________^
+LL | |
+LL | | (a + b) - (c + d)
+LL | | } else {
+LL | | (c + d) - (a + b)
+LL | | };
+ | |_____^ help: replace with `abs_diff`: `(a + b).abs_diff(c + d)`
+
+error: manual absolute difference pattern without using `abs_diff`
+ --> tests/ui/manual_abs_diff.rs:38:13
+ |
+LL | let _ = if (a + b) < (c + d) {
+ | _____________^
+LL | |
+LL | | (c + d) - (a + b)
+LL | | } else {
+LL | | (a + b) - (c + d)
+LL | | };
+ | |_____^ help: replace with `abs_diff`: `(c + d).abs_diff(a + b)`
+
+error: manual absolute difference pattern without using `abs_diff`
+ --> tests/ui/manual_abs_diff.rs:48:22
+ |
+LL | const _: usize = if A > B { A - B } else { B - A };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `A.abs_diff(B)`
+
+error: manual absolute difference pattern without using `abs_diff`
+ --> tests/ui/manual_abs_diff.rs:53:13
+ |
+LL | let _ = if a > b { a - b } else { b - a };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `a.abs_diff(b)`
+
+error: manual absolute difference pattern without using `abs_diff`
+ --> tests/ui/manual_abs_diff.rs:59:13
+ |
+LL | let _ = if a > b { (a - b) as u32 } else { (b - a) as u32 };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with `abs_diff`: `a.abs_diff(b)`
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_async_fn.fixed b/src/tools/clippy/tests/ui/manual_async_fn.fixed
index ad0266d..a284ca9 100644
--- a/src/tools/clippy/tests/ui/manual_async_fn.fixed
+++ b/src/tools/clippy/tests/ui/manual_async_fn.fixed
@@ -75,7 +75,7 @@
async fn elided(_: &i32) -> i32 { 42 }
// should be ignored
-fn elided_not_bound(_: &i32) -> impl Future<Output = i32> {
+fn elided_not_bound(_: &i32) -> impl Future<Output = i32> + use<> {
async { 42 }
}
@@ -84,7 +84,7 @@
// should be ignored
#[allow(clippy::needless_lifetimes)]
-fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> {
+fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + use<> {
async { 42 }
}
@@ -94,7 +94,7 @@
struct A;
impl A {
- fn f(&self) -> impl Future<Output = ()> {
+ fn f(&self) -> impl Future<Output = ()> + use<> {
async {}
}
}
diff --git a/src/tools/clippy/tests/ui/manual_async_fn.rs b/src/tools/clippy/tests/ui/manual_async_fn.rs
index fe367b4..188f8a4 100644
--- a/src/tools/clippy/tests/ui/manual_async_fn.rs
+++ b/src/tools/clippy/tests/ui/manual_async_fn.rs
@@ -102,7 +102,7 @@ fn elided(_: &i32) -> impl Future<Output = i32> + '_ {
}
// should be ignored
-fn elided_not_bound(_: &i32) -> impl Future<Output = i32> {
+fn elided_not_bound(_: &i32) -> impl Future<Output = i32> + use<> {
async { 42 }
}
@@ -114,7 +114,7 @@ fn explicit<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + 'a +
// should be ignored
#[allow(clippy::needless_lifetimes)]
-fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> {
+fn explicit_not_bound<'a, 'b>(_: &'a i32, _: &'b i32) -> impl Future<Output = i32> + use<> {
async { 42 }
}
@@ -124,7 +124,7 @@ mod issue_5765 {
struct A;
impl A {
- fn f(&self) -> impl Future<Output = ()> {
+ fn f(&self) -> impl Future<Output = ()> + use<> {
async {}
}
}
diff --git a/src/tools/clippy/tests/ui/manual_dangling_ptr.fixed b/src/tools/clippy/tests/ui/manual_dangling_ptr.fixed
new file mode 100644
index 0000000..b6afe78
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_dangling_ptr.fixed
@@ -0,0 +1,44 @@
+#![warn(clippy::manual_dangling_ptr)]
+use std::mem;
+
+pub fn foo(_const: *const f32, _mut: *mut i32) {}
+
+fn main() {
+ let _: *const u8 = std::ptr::dangling();
+ //~^ manual_dangling_ptr
+ let _ = std::ptr::dangling::<u32>();
+ //~^ manual_dangling_ptr
+ let _ = std::ptr::dangling_mut::<f32>();
+ //~^ manual_dangling_ptr
+
+ let _ = std::ptr::dangling::<u8>();
+ //~^ manual_dangling_ptr
+ let _ = std::ptr::dangling::<u32>();
+ //~^ manual_dangling_ptr
+ let _ = std::ptr::dangling::<usize>();
+ //~^ manual_dangling_ptr
+
+ foo(std::ptr::dangling(), std::ptr::dangling_mut());
+ //~^ manual_dangling_ptr
+ //~| manual_dangling_ptr
+}
+
+fn should_not_lint() {
+ let _ = 0x10 as *mut i32;
+ let _ = mem::align_of::<u32>() as *const u8;
+
+ foo(0 as _, 0 as _);
+}
+
+#[clippy::msrv = "1.83"]
+fn _msrv_1_83() {
+ // `{core, std}::ptr::dangling` was stabilized in 1.84. Do not lint this
+ foo(4 as *const _, 4 as *mut _);
+}
+
+#[clippy::msrv = "1.84"]
+fn _msrv_1_84() {
+ foo(std::ptr::dangling(), std::ptr::dangling_mut());
+ //~^ manual_dangling_ptr
+ //~| manual_dangling_ptr
+}
diff --git a/src/tools/clippy/tests/ui/manual_dangling_ptr.rs b/src/tools/clippy/tests/ui/manual_dangling_ptr.rs
new file mode 100644
index 0000000..581ad50
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_dangling_ptr.rs
@@ -0,0 +1,44 @@
+#![warn(clippy::manual_dangling_ptr)]
+use std::mem;
+
+pub fn foo(_const: *const f32, _mut: *mut i32) {}
+
+fn main() {
+ let _: *const u8 = 1 as *const _;
+ //~^ manual_dangling_ptr
+ let _ = 2 as *const u32;
+ //~^ manual_dangling_ptr
+ let _ = 4 as *mut f32;
+ //~^ manual_dangling_ptr
+
+ let _ = mem::align_of::<u8>() as *const u8;
+ //~^ manual_dangling_ptr
+ let _ = mem::align_of::<u32>() as *const u32;
+ //~^ manual_dangling_ptr
+ let _ = mem::align_of::<usize>() as *const usize;
+ //~^ manual_dangling_ptr
+
+ foo(4 as *const _, 4 as *mut _);
+ //~^ manual_dangling_ptr
+ //~| manual_dangling_ptr
+}
+
+fn should_not_lint() {
+ let _ = 0x10 as *mut i32;
+ let _ = mem::align_of::<u32>() as *const u8;
+
+ foo(0 as _, 0 as _);
+}
+
+#[clippy::msrv = "1.83"]
+fn _msrv_1_83() {
+ // `{core, std}::ptr::dangling` was stabilized in 1.84. Do not lint this
+ foo(4 as *const _, 4 as *mut _);
+}
+
+#[clippy::msrv = "1.84"]
+fn _msrv_1_84() {
+ foo(4 as *const _, 4 as *mut _);
+ //~^ manual_dangling_ptr
+ //~| manual_dangling_ptr
+}
diff --git a/src/tools/clippy/tests/ui/manual_dangling_ptr.stderr b/src/tools/clippy/tests/ui/manual_dangling_ptr.stderr
new file mode 100644
index 0000000..e3bc9b1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_dangling_ptr.stderr
@@ -0,0 +1,65 @@
+error: manual creation of a dangling pointer
+ --> tests/ui/manual_dangling_ptr.rs:7:24
+ |
+LL | let _: *const u8 = 1 as *const _;
+ | ^^^^^^^^^^^^^ help: use: `std::ptr::dangling()`
+ |
+ = note: `-D clippy::manual-dangling-ptr` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::manual_dangling_ptr)]`
+
+error: manual creation of a dangling pointer
+ --> tests/ui/manual_dangling_ptr.rs:9:13
+ |
+LL | let _ = 2 as *const u32;
+ | ^^^^^^^^^^^^^^^ help: use: `std::ptr::dangling::<u32>()`
+
+error: manual creation of a dangling pointer
+ --> tests/ui/manual_dangling_ptr.rs:11:13
+ |
+LL | let _ = 4 as *mut f32;
+ | ^^^^^^^^^^^^^ help: use: `std::ptr::dangling_mut::<f32>()`
+
+error: manual creation of a dangling pointer
+ --> tests/ui/manual_dangling_ptr.rs:14:13
+ |
+LL | let _ = mem::align_of::<u8>() as *const u8;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `std::ptr::dangling::<u8>()`
+
+error: manual creation of a dangling pointer
+ --> tests/ui/manual_dangling_ptr.rs:16:13
+ |
+LL | let _ = mem::align_of::<u32>() as *const u32;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `std::ptr::dangling::<u32>()`
+
+error: manual creation of a dangling pointer
+ --> tests/ui/manual_dangling_ptr.rs:18:13
+ |
+LL | let _ = mem::align_of::<usize>() as *const usize;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `std::ptr::dangling::<usize>()`
+
+error: manual creation of a dangling pointer
+ --> tests/ui/manual_dangling_ptr.rs:21:9
+ |
+LL | foo(4 as *const _, 4 as *mut _);
+ | ^^^^^^^^^^^^^ help: use: `std::ptr::dangling()`
+
+error: manual creation of a dangling pointer
+ --> tests/ui/manual_dangling_ptr.rs:21:24
+ |
+LL | foo(4 as *const _, 4 as *mut _);
+ | ^^^^^^^^^^^ help: use: `std::ptr::dangling_mut()`
+
+error: manual creation of a dangling pointer
+ --> tests/ui/manual_dangling_ptr.rs:41:9
+ |
+LL | foo(4 as *const _, 4 as *mut _);
+ | ^^^^^^^^^^^^^ help: use: `std::ptr::dangling()`
+
+error: manual creation of a dangling pointer
+ --> tests/ui/manual_dangling_ptr.rs:41:24
+ |
+LL | foo(4 as *const _, 4 as *mut _);
+ | ^^^^^^^^^^^ help: use: `std::ptr::dangling_mut()`
+
+error: aborting due to 10 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_find.rs b/src/tools/clippy/tests/ui/manual_find.rs
index 20b557f..7b9846c 100644
--- a/src/tools/clippy/tests/ui/manual_find.rs
+++ b/src/tools/clippy/tests/ui/manual_find.rs
@@ -23,4 +23,32 @@ fn tuple(arr: Vec<(String, i32)>) -> Option<String> {
None
}
+mod issue9521 {
+ fn condition(x: u32, y: u32) -> Result<bool, ()> {
+ todo!()
+ }
+
+ fn find_with_early_return(v: Vec<u32>) -> Option<u32> {
+ for x in v {
+ if condition(x, 10).ok()? {
+ return Some(x);
+ }
+ }
+ None
+ }
+
+ fn find_with_early_break(v: Vec<u32>) -> Option<u32> {
+ for x in v {
+ if if x < 3 {
+ break;
+ } else {
+ x < 10
+ } {
+ return Some(x);
+ }
+ }
+ None
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/manual_ignore_case_cmp.fixed b/src/tools/clippy/tests/ui/manual_ignore_case_cmp.fixed
index c1c9295..cd7adc2 100644
--- a/src/tools/clippy/tests/ui/manual_ignore_case_cmp.fixed
+++ b/src/tools/clippy/tests/ui/manual_ignore_case_cmp.fixed
@@ -1,5 +1,11 @@
-#![allow(clippy::all)]
-#![deny(clippy::manual_ignore_case_cmp)]
+#![warn(clippy::manual_ignore_case_cmp)]
+#![allow(
+ clippy::deref_addrof,
+ clippy::op_ref,
+ clippy::ptr_arg,
+ clippy::short_circuit_statement,
+ clippy::unnecessary_operation
+)]
use std::ffi::{OsStr, OsString};
diff --git a/src/tools/clippy/tests/ui/manual_ignore_case_cmp.rs b/src/tools/clippy/tests/ui/manual_ignore_case_cmp.rs
index ca401e5..85f6719 100644
--- a/src/tools/clippy/tests/ui/manual_ignore_case_cmp.rs
+++ b/src/tools/clippy/tests/ui/manual_ignore_case_cmp.rs
@@ -1,5 +1,11 @@
-#![allow(clippy::all)]
-#![deny(clippy::manual_ignore_case_cmp)]
+#![warn(clippy::manual_ignore_case_cmp)]
+#![allow(
+ clippy::deref_addrof,
+ clippy::op_ref,
+ clippy::ptr_arg,
+ clippy::short_circuit_statement,
+ clippy::unnecessary_operation
+)]
use std::ffi::{OsStr, OsString};
diff --git a/src/tools/clippy/tests/ui/manual_ignore_case_cmp.stderr b/src/tools/clippy/tests/ui/manual_ignore_case_cmp.stderr
index 47378a6..fa7fadd9 100644
--- a/src/tools/clippy/tests/ui/manual_ignore_case_cmp.stderr
+++ b/src/tools/clippy/tests/ui/manual_ignore_case_cmp.stderr
@@ -1,14 +1,11 @@
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:9:8
+ --> tests/ui/manual_ignore_case_cmp.rs:15:8
|
LL | if a.to_ascii_lowercase() == b.to_ascii_lowercase() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-note: the lint level is defined here
- --> tests/ui/manual_ignore_case_cmp.rs:2:9
- |
-LL | #![deny(clippy::manual_ignore_case_cmp)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: `-D clippy::manual-ignore-case-cmp` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::manual_ignore_case_cmp)]`
help: consider using `.eq_ignore_ascii_case()` instead
|
LL - if a.to_ascii_lowercase() == b.to_ascii_lowercase() {
@@ -16,7 +13,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:13:8
+ --> tests/ui/manual_ignore_case_cmp.rs:19:8
|
LL | if a.to_ascii_uppercase() == b.to_ascii_uppercase() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -28,7 +25,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:17:13
+ --> tests/ui/manual_ignore_case_cmp.rs:23:13
|
LL | let r = a.to_ascii_lowercase() == b.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -40,7 +37,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:19:18
+ --> tests/ui/manual_ignore_case_cmp.rs:25:18
|
LL | let r = r || a.to_ascii_uppercase() == b.to_ascii_uppercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -52,7 +49,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:21:10
+ --> tests/ui/manual_ignore_case_cmp.rs:27:10
|
LL | r && a.to_ascii_lowercase() == b.to_uppercase().to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -64,7 +61,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:24:8
+ --> tests/ui/manual_ignore_case_cmp.rs:30:8
|
LL | if a.to_ascii_lowercase() != b.to_ascii_lowercase() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -76,7 +73,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:28:8
+ --> tests/ui/manual_ignore_case_cmp.rs:34:8
|
LL | if a.to_ascii_uppercase() != b.to_ascii_uppercase() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -88,7 +85,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:32:13
+ --> tests/ui/manual_ignore_case_cmp.rs:38:13
|
LL | let r = a.to_ascii_lowercase() != b.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +97,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:34:18
+ --> tests/ui/manual_ignore_case_cmp.rs:40:18
|
LL | let r = r || a.to_ascii_uppercase() != b.to_ascii_uppercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -112,7 +109,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:36:10
+ --> tests/ui/manual_ignore_case_cmp.rs:42:10
|
LL | r && a.to_ascii_lowercase() != b.to_uppercase().to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -124,7 +121,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:48:5
+ --> tests/ui/manual_ignore_case_cmp.rs:54:5
|
LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -136,7 +133,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:52:5
+ --> tests/ui/manual_ignore_case_cmp.rs:58:5
|
LL | a.to_ascii_lowercase() == 'a';
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -148,7 +145,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:54:5
+ --> tests/ui/manual_ignore_case_cmp.rs:60:5
|
LL | 'a' == b.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -160,7 +157,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:58:5
+ --> tests/ui/manual_ignore_case_cmp.rs:64:5
|
LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -172,7 +169,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:60:5
+ --> tests/ui/manual_ignore_case_cmp.rs:66:5
|
LL | a.to_ascii_lowercase() == b'a';
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -184,7 +181,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:62:5
+ --> tests/ui/manual_ignore_case_cmp.rs:68:5
|
LL | b'a' == b.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -196,7 +193,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:66:5
+ --> tests/ui/manual_ignore_case_cmp.rs:72:5
|
LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -208,7 +205,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:68:5
+ --> tests/ui/manual_ignore_case_cmp.rs:74:5
|
LL | a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -220,56 +217,8 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:70:5
- |
-LL | a.to_ascii_lowercase() == "a";
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: consider using `.eq_ignore_ascii_case()` instead
- |
-LL - a.to_ascii_lowercase() == "a";
-LL + a.eq_ignore_ascii_case("a");
- |
-
-error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:72:5
- |
-LL | "a" == b.to_ascii_lowercase();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: consider using `.eq_ignore_ascii_case()` instead
- |
-LL - "a" == b.to_ascii_lowercase();
-LL + "a".eq_ignore_ascii_case(b);
- |
-
-error: manual case-insensitive ASCII comparison
--> tests/ui/manual_ignore_case_cmp.rs:76:5
|
-LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: consider using `.eq_ignore_ascii_case()` instead
- |
-LL - a.to_ascii_lowercase() == b.to_ascii_lowercase();
-LL + a.eq_ignore_ascii_case(b);
- |
-
-error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:78:5
- |
-LL | a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: consider using `.eq_ignore_ascii_case()` instead
- |
-LL - a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase();
-LL + a.to_uppercase().eq_ignore_ascii_case(b);
- |
-
-error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:80:5
- |
LL | a.to_ascii_lowercase() == "a";
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
@@ -280,7 +229,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:82:5
+ --> tests/ui/manual_ignore_case_cmp.rs:78:5
|
LL | "a" == b.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -292,8 +241,56 @@
|
error: manual case-insensitive ASCII comparison
+ --> tests/ui/manual_ignore_case_cmp.rs:82:5
+ |
+LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider using `.eq_ignore_ascii_case()` instead
+ |
+LL - a.to_ascii_lowercase() == b.to_ascii_lowercase();
+LL + a.eq_ignore_ascii_case(b);
+ |
+
+error: manual case-insensitive ASCII comparison
+ --> tests/ui/manual_ignore_case_cmp.rs:84:5
+ |
+LL | a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider using `.eq_ignore_ascii_case()` instead
+ |
+LL - a.to_uppercase().to_ascii_lowercase() == b.to_ascii_lowercase();
+LL + a.to_uppercase().eq_ignore_ascii_case(b);
+ |
+
+error: manual case-insensitive ASCII comparison
--> tests/ui/manual_ignore_case_cmp.rs:86:5
|
+LL | a.to_ascii_lowercase() == "a";
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider using `.eq_ignore_ascii_case()` instead
+ |
+LL - a.to_ascii_lowercase() == "a";
+LL + a.eq_ignore_ascii_case("a");
+ |
+
+error: manual case-insensitive ASCII comparison
+ --> tests/ui/manual_ignore_case_cmp.rs:88:5
+ |
+LL | "a" == b.to_ascii_lowercase();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider using `.eq_ignore_ascii_case()` instead
+ |
+LL - "a" == b.to_ascii_lowercase();
+LL + "a".eq_ignore_ascii_case(b);
+ |
+
+error: manual case-insensitive ASCII comparison
+ --> tests/ui/manual_ignore_case_cmp.rs:92:5
+ |
LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
@@ -304,30 +301,6 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:88:5
- |
-LL | a.to_ascii_lowercase() == "a";
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: consider using `.eq_ignore_ascii_case()` instead
- |
-LL - a.to_ascii_lowercase() == "a";
-LL + a.eq_ignore_ascii_case("a");
- |
-
-error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:90:5
- |
-LL | "a" == b.to_ascii_lowercase();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: consider using `.eq_ignore_ascii_case()` instead
- |
-LL - "a" == b.to_ascii_lowercase();
-LL + "a".eq_ignore_ascii_case(&b);
- |
-
-error: manual case-insensitive ASCII comparison
--> tests/ui/manual_ignore_case_cmp.rs:94:5
|
LL | a.to_ascii_lowercase() == "a";
@@ -354,18 +327,42 @@
error: manual case-insensitive ASCII comparison
--> tests/ui/manual_ignore_case_cmp.rs:100:5
|
-LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | a.to_ascii_lowercase() == "a";
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider using `.eq_ignore_ascii_case()` instead
|
-LL - a.to_ascii_lowercase() == b.to_ascii_lowercase();
-LL + a.eq_ignore_ascii_case(b);
+LL - a.to_ascii_lowercase() == "a";
+LL + a.eq_ignore_ascii_case("a");
|
error: manual case-insensitive ASCII comparison
--> tests/ui/manual_ignore_case_cmp.rs:102:5
|
+LL | "a" == b.to_ascii_lowercase();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider using `.eq_ignore_ascii_case()` instead
+ |
+LL - "a" == b.to_ascii_lowercase();
+LL + "a".eq_ignore_ascii_case(&b);
+ |
+
+error: manual case-insensitive ASCII comparison
+ --> tests/ui/manual_ignore_case_cmp.rs:106:5
+ |
+LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider using `.eq_ignore_ascii_case()` instead
+ |
+LL - a.to_ascii_lowercase() == b.to_ascii_lowercase();
+LL + a.eq_ignore_ascii_case(b);
+ |
+
+error: manual case-insensitive ASCII comparison
+ --> tests/ui/manual_ignore_case_cmp.rs:108:5
+ |
LL | a.to_ascii_lowercase() == "a";
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
@@ -376,7 +373,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:104:5
+ --> tests/ui/manual_ignore_case_cmp.rs:110:5
|
LL | "a" == b.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -388,7 +385,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:107:5
+ --> tests/ui/manual_ignore_case_cmp.rs:113:5
|
LL | b.to_ascii_lowercase() == a.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -400,80 +397,8 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:109:5
- |
-LL | b.to_ascii_lowercase() == "a";
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: consider using `.eq_ignore_ascii_case()` instead
- |
-LL - b.to_ascii_lowercase() == "a";
-LL + b.eq_ignore_ascii_case("a");
- |
-
-error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:111:5
- |
-LL | "a" == a.to_ascii_lowercase();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: consider using `.eq_ignore_ascii_case()` instead
- |
-LL - "a" == a.to_ascii_lowercase();
-LL + "a".eq_ignore_ascii_case(&a);
- |
-
-error: manual case-insensitive ASCII comparison
--> tests/ui/manual_ignore_case_cmp.rs:115:5
|
-LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: consider using `.eq_ignore_ascii_case()` instead
- |
-LL - a.to_ascii_lowercase() == b.to_ascii_lowercase();
-LL + a.eq_ignore_ascii_case(b);
- |
-
-error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:117:5
- |
-LL | a.to_ascii_lowercase() == "a";
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: consider using `.eq_ignore_ascii_case()` instead
- |
-LL - a.to_ascii_lowercase() == "a";
-LL + a.eq_ignore_ascii_case("a");
- |
-
-error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:119:5
- |
-LL | "a" == b.to_ascii_lowercase();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: consider using `.eq_ignore_ascii_case()` instead
- |
-LL - "a" == b.to_ascii_lowercase();
-LL + "a".eq_ignore_ascii_case(b);
- |
-
-error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:122:5
- |
-LL | b.to_ascii_lowercase() == a.to_ascii_lowercase();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: consider using `.eq_ignore_ascii_case()` instead
- |
-LL - b.to_ascii_lowercase() == a.to_ascii_lowercase();
-LL + b.eq_ignore_ascii_case(&a);
- |
-
-error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:124:5
- |
LL | b.to_ascii_lowercase() == "a";
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
@@ -484,7 +409,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:126:5
+ --> tests/ui/manual_ignore_case_cmp.rs:117:5
|
LL | "a" == a.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -496,7 +421,7 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:130:5
+ --> tests/ui/manual_ignore_case_cmp.rs:121:5
|
LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -508,19 +433,67 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:134:5
+ --> tests/ui/manual_ignore_case_cmp.rs:123:5
|
-LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
+LL | a.to_ascii_lowercase() == "a";
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider using `.eq_ignore_ascii_case()` instead
+ |
+LL - a.to_ascii_lowercase() == "a";
+LL + a.eq_ignore_ascii_case("a");
+ |
+
+error: manual case-insensitive ASCII comparison
+ --> tests/ui/manual_ignore_case_cmp.rs:125:5
+ |
+LL | "a" == b.to_ascii_lowercase();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider using `.eq_ignore_ascii_case()` instead
+ |
+LL - "a" == b.to_ascii_lowercase();
+LL + "a".eq_ignore_ascii_case(b);
+ |
+
+error: manual case-insensitive ASCII comparison
+ --> tests/ui/manual_ignore_case_cmp.rs:128:5
+ |
+LL | b.to_ascii_lowercase() == a.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider using `.eq_ignore_ascii_case()` instead
|
-LL - a.to_ascii_lowercase() == b.to_ascii_lowercase();
-LL + a.eq_ignore_ascii_case(&b);
+LL - b.to_ascii_lowercase() == a.to_ascii_lowercase();
+LL + b.eq_ignore_ascii_case(&a);
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:138:5
+ --> tests/ui/manual_ignore_case_cmp.rs:130:5
+ |
+LL | b.to_ascii_lowercase() == "a";
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider using `.eq_ignore_ascii_case()` instead
+ |
+LL - b.to_ascii_lowercase() == "a";
+LL + b.eq_ignore_ascii_case("a");
+ |
+
+error: manual case-insensitive ASCII comparison
+ --> tests/ui/manual_ignore_case_cmp.rs:132:5
+ |
+LL | "a" == a.to_ascii_lowercase();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider using `.eq_ignore_ascii_case()` instead
+ |
+LL - "a" == a.to_ascii_lowercase();
+LL + "a".eq_ignore_ascii_case(&a);
+ |
+
+error: manual case-insensitive ASCII comparison
+ --> tests/ui/manual_ignore_case_cmp.rs:136:5
|
LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -534,13 +507,13 @@
error: manual case-insensitive ASCII comparison
--> tests/ui/manual_ignore_case_cmp.rs:140:5
|
-LL | b.to_ascii_lowercase() == a.to_ascii_lowercase();
+LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider using `.eq_ignore_ascii_case()` instead
|
-LL - b.to_ascii_lowercase() == a.to_ascii_lowercase();
-LL + b.eq_ignore_ascii_case(&a);
+LL - a.to_ascii_lowercase() == b.to_ascii_lowercase();
+LL + a.eq_ignore_ascii_case(&b);
|
error: manual case-insensitive ASCII comparison
@@ -556,19 +529,19 @@
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:148:5
+ --> tests/ui/manual_ignore_case_cmp.rs:146:5
|
-LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
+LL | b.to_ascii_lowercase() == a.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: consider using `.eq_ignore_ascii_case()` instead
|
-LL - a.to_ascii_lowercase() == b.to_ascii_lowercase();
-LL + a.eq_ignore_ascii_case(b);
+LL - b.to_ascii_lowercase() == a.to_ascii_lowercase();
+LL + b.eq_ignore_ascii_case(&a);
|
error: manual case-insensitive ASCII comparison
- --> tests/ui/manual_ignore_case_cmp.rs:152:5
+ --> tests/ui/manual_ignore_case_cmp.rs:150:5
|
LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -582,6 +555,30 @@
error: manual case-insensitive ASCII comparison
--> tests/ui/manual_ignore_case_cmp.rs:154:5
|
+LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider using `.eq_ignore_ascii_case()` instead
+ |
+LL - a.to_ascii_lowercase() == b.to_ascii_lowercase();
+LL + a.eq_ignore_ascii_case(b);
+ |
+
+error: manual case-insensitive ASCII comparison
+ --> tests/ui/manual_ignore_case_cmp.rs:158:5
+ |
+LL | a.to_ascii_lowercase() == b.to_ascii_lowercase();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: consider using `.eq_ignore_ascii_case()` instead
+ |
+LL - a.to_ascii_lowercase() == b.to_ascii_lowercase();
+LL + a.eq_ignore_ascii_case(b);
+ |
+
+error: manual case-insensitive ASCII comparison
+ --> tests/ui/manual_ignore_case_cmp.rs:160:5
+ |
LL | b.to_ascii_lowercase() == a.to_ascii_lowercase();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
diff --git a/src/tools/clippy/tests/ui/manual_inspect.fixed b/src/tools/clippy/tests/ui/manual_inspect.fixed
index 44f15d6..ec87fe2 100644
--- a/src/tools/clippy/tests/ui/manual_inspect.fixed
+++ b/src/tools/clippy/tests/ui/manual_inspect.fixed
@@ -1,5 +1,5 @@
+#![allow(clippy::no_effect, clippy::op_ref, clippy::uninlined_format_args)]
#![warn(clippy::manual_inspect)]
-#![allow(clippy::no_effect, clippy::op_ref)]
fn main() {
let _ = Some(0).inspect(|&x| {
@@ -107,7 +107,7 @@
let _ = || {
let _x = x;
};
- return;
+ return ;
}
println!("test");
});
@@ -185,3 +185,12 @@
});
}
}
+
+#[rustfmt::skip]
+fn layout_check() {
+ if let Some(x) = Some(1).inspect(|&x| { println!("{x}"); //~ manual_inspect
+ // Do not collapse code into this comment
+ }) {
+ println!("{x}");
+ }
+}
diff --git a/src/tools/clippy/tests/ui/manual_inspect.rs b/src/tools/clippy/tests/ui/manual_inspect.rs
index d34f2ab..e679636 100644
--- a/src/tools/clippy/tests/ui/manual_inspect.rs
+++ b/src/tools/clippy/tests/ui/manual_inspect.rs
@@ -1,5 +1,5 @@
+#![allow(clippy::no_effect, clippy::op_ref, clippy::uninlined_format_args)]
#![warn(clippy::manual_inspect)]
-#![allow(clippy::no_effect, clippy::op_ref)]
fn main() {
let _ = Some(0).map(|x| {
@@ -197,3 +197,12 @@ fn map_err<U>(self, f: impl FnOnce(T) -> U) -> S<U> {
});
}
}
+
+#[rustfmt::skip]
+fn layout_check() {
+ if let Some(x) = Some(1).map(|x| { println!("{x}"); //~ manual_inspect
+ // Do not collapse code into this comment
+ x }) {
+ println!("{x}");
+ }
+}
diff --git a/src/tools/clippy/tests/ui/manual_inspect.stderr b/src/tools/clippy/tests/ui/manual_inspect.stderr
index 510325d..eb98f9f 100644
--- a/src/tools/clippy/tests/ui/manual_inspect.stderr
+++ b/src/tools/clippy/tests/ui/manual_inspect.stderr
@@ -98,7 +98,7 @@
LL | let _ = || {
LL ~ let _x = x;
LL | };
-LL ~ return;
+LL ~ return ;
LL | }
LL ~ println!("test");
|
@@ -187,5 +187,18 @@
LL ~ println!("{}", x);
|
-error: aborting due to 13 previous errors
+error: using `map` over `inspect`
+ --> tests/ui/manual_inspect.rs:203:30
+ |
+LL | if let Some(x) = Some(1).map(|x| { println!("{x}");
+ | ^^^
+ |
+help: try
+ |
+LL ~ if let Some(x) = Some(1).inspect(|&x| { println!("{x}");
+LL | // Do not collapse code into this comment
+LL ~ }) {
+ |
+
+error: aborting due to 14 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_is_power_of_two.fixed b/src/tools/clippy/tests/ui/manual_is_power_of_two.fixed
index 6f29d76..8a1ab78 100644
--- a/src/tools/clippy/tests/ui/manual_is_power_of_two.fixed
+++ b/src/tools/clippy/tests/ui/manual_is_power_of_two.fixed
@@ -1,4 +1,17 @@
#![warn(clippy::manual_is_power_of_two)]
+#![allow(clippy::precedence)]
+
+macro_rules! binop {
+ ($a: expr, equal, $b: expr) => {
+ $a == $b
+ };
+ ($a: expr, and, $b: expr) => {
+ $a & $b
+ };
+ ($a: expr, minus, $b: expr) => {
+ $a - $b
+ };
+}
fn main() {
let a = 16_u64;
@@ -7,6 +20,8 @@
//~^ manual_is_power_of_two
let _ = a.is_power_of_two();
//~^ manual_is_power_of_two
+ let _ = a.is_power_of_two();
+ //~^ manual_is_power_of_two
// Test different orders of expression
let _ = a.is_power_of_two();
@@ -23,4 +38,23 @@
// is_power_of_two only works for unsigned integers
let _ = b.count_ones() == 1;
let _ = b & (b - 1) == 0;
+
+ let i: i32 = 3;
+ let _ = (i as u32).is_power_of_two();
+ //~^ manual_is_power_of_two
+
+ let _ = binop!(a.count_ones(), equal, 1);
+ let _ = binop!(a, and, a - 1) == 0;
+ let _ = a & binop!(a, minus, 1) == 0;
+}
+
+#[clippy::msrv = "1.31"]
+const fn low_msrv(a: u32) -> bool {
+ a & (a - 1) == 0
+}
+
+#[clippy::msrv = "1.32"]
+const fn high_msrv(a: u32) -> bool {
+ a.is_power_of_two()
+ //~^ manual_is_power_of_two
}
diff --git a/src/tools/clippy/tests/ui/manual_is_power_of_two.rs b/src/tools/clippy/tests/ui/manual_is_power_of_two.rs
index 0c44d7a..57a3b05 100644
--- a/src/tools/clippy/tests/ui/manual_is_power_of_two.rs
+++ b/src/tools/clippy/tests/ui/manual_is_power_of_two.rs
@@ -1,10 +1,25 @@
#![warn(clippy::manual_is_power_of_two)]
+#![allow(clippy::precedence)]
+
+macro_rules! binop {
+ ($a: expr, equal, $b: expr) => {
+ $a == $b
+ };
+ ($a: expr, and, $b: expr) => {
+ $a & $b
+ };
+ ($a: expr, minus, $b: expr) => {
+ $a - $b
+ };
+}
fn main() {
let a = 16_u64;
let _ = a.count_ones() == 1;
//~^ manual_is_power_of_two
+ let _ = u64::count_ones(a) == 1;
+ //~^ manual_is_power_of_two
let _ = a & (a - 1) == 0;
//~^ manual_is_power_of_two
@@ -23,4 +38,23 @@ fn main() {
// is_power_of_two only works for unsigned integers
let _ = b.count_ones() == 1;
let _ = b & (b - 1) == 0;
+
+ let i: i32 = 3;
+ let _ = i as u32 & (i as u32 - 1) == 0;
+ //~^ manual_is_power_of_two
+
+ let _ = binop!(a.count_ones(), equal, 1);
+ let _ = binop!(a, and, a - 1) == 0;
+ let _ = a & binop!(a, minus, 1) == 0;
+}
+
+#[clippy::msrv = "1.31"]
+const fn low_msrv(a: u32) -> bool {
+ a & (a - 1) == 0
+}
+
+#[clippy::msrv = "1.32"]
+const fn high_msrv(a: u32) -> bool {
+ a & (a - 1) == 0
+ //~^ manual_is_power_of_two
}
diff --git a/src/tools/clippy/tests/ui/manual_is_power_of_two.stderr b/src/tools/clippy/tests/ui/manual_is_power_of_two.stderr
index ad12ee1..5781a09 100644
--- a/src/tools/clippy/tests/ui/manual_is_power_of_two.stderr
+++ b/src/tools/clippy/tests/ui/manual_is_power_of_two.stderr
@@ -1,5 +1,5 @@
error: manually reimplementing `is_power_of_two`
- --> tests/ui/manual_is_power_of_two.rs:6:13
+ --> tests/ui/manual_is_power_of_two.rs:19:13
|
LL | let _ = a.count_ones() == 1;
| ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
@@ -8,34 +8,52 @@
= help: to override `-D warnings` add `#[allow(clippy::manual_is_power_of_two)]`
error: manually reimplementing `is_power_of_two`
- --> tests/ui/manual_is_power_of_two.rs:8:13
+ --> tests/ui/manual_is_power_of_two.rs:21:13
+ |
+LL | let _ = u64::count_ones(a) == 1;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
+
+error: manually reimplementing `is_power_of_two`
+ --> tests/ui/manual_is_power_of_two.rs:23:13
|
LL | let _ = a & (a - 1) == 0;
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
error: manually reimplementing `is_power_of_two`
- --> tests/ui/manual_is_power_of_two.rs:12:13
+ --> tests/ui/manual_is_power_of_two.rs:27:13
|
LL | let _ = 1 == a.count_ones();
| ^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
error: manually reimplementing `is_power_of_two`
- --> tests/ui/manual_is_power_of_two.rs:14:13
+ --> tests/ui/manual_is_power_of_two.rs:29:13
|
LL | let _ = (a - 1) & a == 0;
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
error: manually reimplementing `is_power_of_two`
- --> tests/ui/manual_is_power_of_two.rs:16:13
+ --> tests/ui/manual_is_power_of_two.rs:31:13
|
LL | let _ = 0 == a & (a - 1);
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
error: manually reimplementing `is_power_of_two`
- --> tests/ui/manual_is_power_of_two.rs:18:13
+ --> tests/ui/manual_is_power_of_two.rs:33:13
|
LL | let _ = 0 == (a - 1) & a;
| ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
-error: aborting due to 6 previous errors
+error: manually reimplementing `is_power_of_two`
+ --> tests/ui/manual_is_power_of_two.rs:43:13
+ |
+LL | let _ = i as u32 & (i as u32 - 1) == 0;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `(i as u32).is_power_of_two()`
+
+error: manually reimplementing `is_power_of_two`
+ --> tests/ui/manual_is_power_of_two.rs:58:5
+ |
+LL | a & (a - 1) == 0
+ | ^^^^^^^^^^^^^^^^ help: consider using `.is_power_of_two()`: `a.is_power_of_two()`
+
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_map_option.rs b/src/tools/clippy/tests/ui/manual_map_option.rs
index 9477d0d7..4013374 100644
--- a/src/tools/clippy/tests/ui/manual_map_option.rs
+++ b/src/tools/clippy/tests/ui/manual_map_option.rs
@@ -101,7 +101,7 @@ fn main() {
match &mut Some(String::new()) {
//~^ manual_map
- Some(ref x) => Some(x.len()),
+ &mut Some(ref x) => Some(x.len()),
None => None,
};
diff --git a/src/tools/clippy/tests/ui/manual_map_option.stderr b/src/tools/clippy/tests/ui/manual_map_option.stderr
index 8f9bce4..486379c 100644
--- a/src/tools/clippy/tests/ui/manual_map_option.stderr
+++ b/src/tools/clippy/tests/ui/manual_map_option.stderr
@@ -127,7 +127,7 @@
|
LL | / match &mut Some(String::new()) {
LL | |
-LL | | Some(ref x) => Some(x.len()),
+LL | | &mut Some(ref x) => Some(x.len()),
LL | | None => None,
LL | | };
| |_____^ help: try: `Some(String::new()).as_ref().map(|x| x.len())`
diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.fixed b/src/tools/clippy/tests/ui/manual_map_option_2.fixed
index d698cc7..206c6d5 100644
--- a/src/tools/clippy/tests/ui/manual_map_option_2.fixed
+++ b/src/tools/clippy/tests/ui/manual_map_option_2.fixed
@@ -115,7 +115,7 @@
fn with_fn_ret(s: &Option<String>) -> Option<(String, &str)> {
// Don't lint, `map` doesn't work as the return type is adjusted.
match s {
- Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
+ Some(x) => Some({ if let Some(s) = s { (x.clone(), s) } else { panic!() } }),
None => None,
}
}
@@ -124,7 +124,7 @@
if true {
// Don't lint, `map` doesn't work as the return type is adjusted.
return match s {
- Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
+ Some(x) => Some({ if let Some(s) = s { (x.clone(), s) } else { panic!() } }),
None => None,
};
}
@@ -136,7 +136,7 @@
let x: Option<(String, &'a str)>;
x = {
match s {
- Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
+ Some(x) => Some({ if let Some(s) = s { (x.clone(), s) } else { panic!() } }),
None => None,
}
};
diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.rs b/src/tools/clippy/tests/ui/manual_map_option_2.rs
index 069c238..a47dc95 100644
--- a/src/tools/clippy/tests/ui/manual_map_option_2.rs
+++ b/src/tools/clippy/tests/ui/manual_map_option_2.rs
@@ -143,7 +143,7 @@ fn g(b: &[u8]) -> Box<&[u8]> {
fn with_fn_ret(s: &Option<String>) -> Option<(String, &str)> {
// Don't lint, `map` doesn't work as the return type is adjusted.
match s {
- Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
+ Some(x) => Some({ if let Some(s) = s { (x.clone(), s) } else { panic!() } }),
None => None,
}
}
@@ -152,7 +152,7 @@ fn with_fn_ret_2(s: &Option<String>) -> Option<(String, &str)> {
if true {
// Don't lint, `map` doesn't work as the return type is adjusted.
return match s {
- Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
+ Some(x) => Some({ if let Some(s) = s { (x.clone(), s) } else { panic!() } }),
None => None,
};
}
@@ -164,7 +164,7 @@ fn with_fn_ret_3<'a>(s: &'a Option<String>) -> Option<(String, &'a str)> {
let x: Option<(String, &'a str)>;
x = {
match s {
- Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
+ Some(x) => Some({ if let Some(s) = s { (x.clone(), s) } else { panic!() } }),
None => None,
}
};
diff --git a/src/tools/clippy/tests/ui/manual_ok_err.fixed b/src/tools/clippy/tests/ui/manual_ok_err.fixed
index bc169b6..e6f799a 100644
--- a/src/tools/clippy/tests/ui/manual_ok_err.fixed
+++ b/src/tools/clippy/tests/ui/manual_ok_err.fixed
@@ -80,6 +80,11 @@
Ok(3) => None,
Ok(v) => Some(v),
};
+
+ let _ = match funcall() {
+ Ok(v @ 1..) => Some(v),
+ _ => None,
+ };
}
const fn cf(x: Result<u32, &'static str>) -> Option<u32> {
diff --git a/src/tools/clippy/tests/ui/manual_ok_err.rs b/src/tools/clippy/tests/ui/manual_ok_err.rs
index 03c730d..972b2c4 100644
--- a/src/tools/clippy/tests/ui/manual_ok_err.rs
+++ b/src/tools/clippy/tests/ui/manual_ok_err.rs
@@ -116,6 +116,11 @@ fn no_lint() {
Ok(3) => None,
Ok(v) => Some(v),
};
+
+ let _ = match funcall() {
+ Ok(v @ 1..) => Some(v),
+ _ => None,
+ };
}
const fn cf(x: Result<u32, &'static str>) -> Option<u32> {
diff --git a/src/tools/clippy/tests/ui/manual_ok_err.stderr b/src/tools/clippy/tests/ui/manual_ok_err.stderr
index 13fceac..040e170 100644
--- a/src/tools/clippy/tests/ui/manual_ok_err.stderr
+++ b/src/tools/clippy/tests/ui/manual_ok_err.stderr
@@ -94,7 +94,7 @@
| |_____^ help: replace with: `(-S).ok()`
error: manual implementation of `ok`
- --> tests/ui/manual_ok_err.rs:132:12
+ --> tests/ui/manual_ok_err.rs:137:12
|
LL | } else if let Ok(n) = "1".parse::<u8>() {
| ____________^
diff --git a/src/tools/clippy/tests/ui/manual_retain.fixed b/src/tools/clippy/tests/ui/manual_retain.fixed
index ca84911..016f520 100644
--- a/src/tools/clippy/tests/ui/manual_retain.fixed
+++ b/src/tools/clippy/tests/ui/manual_retain.fixed
@@ -1,5 +1,5 @@
#![warn(clippy::manual_retain)]
-#![allow(unused, clippy::redundant_clone)]
+#![allow(unused, clippy::needless_borrowed_reference, clippy::redundant_clone)]
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
fn main() {
@@ -31,7 +31,7 @@
// Do lint, because we use pattern matching
let mut tuples = BinaryHeap::from([(0, 1), (1, 2), (2, 3)]);
- tuples.retain(|(ref x, ref y)| *x == 0);
+ tuples.retain(|&(ref x, ref y)| *x == 0);
//~^ manual_retain
tuples.retain(|(x, y)| *x == 0);
//~^ manual_retain
@@ -99,7 +99,7 @@
// Do lint, because we use pattern matching
let mut tuples = BTreeSet::from([(0, 1), (1, 2), (2, 3)]);
- tuples.retain(|(ref x, ref y)| *x == 0);
+ tuples.retain(|&(ref x, ref y)| *x == 0);
//~^ manual_retain
tuples.retain(|(x, y)| *x == 0);
//~^ manual_retain
@@ -166,7 +166,7 @@
// Do lint, because we use pattern matching
let mut tuples = HashSet::from([(0, 1), (1, 2), (2, 3)]);
- tuples.retain(|(ref x, ref y)| *x == 0);
+ tuples.retain(|&(ref x, ref y)| *x == 0);
//~^ manual_retain
tuples.retain(|(x, y)| *x == 0);
//~^ manual_retain
@@ -220,7 +220,7 @@
// Do lint, because we use pattern matching
let mut tuples = vec![(0, 1), (1, 2), (2, 3)];
- tuples.retain(|(ref x, ref y)| *x == 0);
+ tuples.retain(|&(ref x, ref y)| *x == 0);
//~^ manual_retain
tuples.retain(|(x, y)| *x == 0);
//~^ manual_retain
diff --git a/src/tools/clippy/tests/ui/manual_retain.rs b/src/tools/clippy/tests/ui/manual_retain.rs
index cd05a41..62f9b7b 100644
--- a/src/tools/clippy/tests/ui/manual_retain.rs
+++ b/src/tools/clippy/tests/ui/manual_retain.rs
@@ -1,5 +1,5 @@
#![warn(clippy::manual_retain)]
-#![allow(unused, clippy::redundant_clone)]
+#![allow(unused, clippy::needless_borrowed_reference, clippy::redundant_clone)]
use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, VecDeque};
fn main() {
@@ -31,7 +31,7 @@ fn binary_heap_retain() {
// Do lint, because we use pattern matching
let mut tuples = BinaryHeap::from([(0, 1), (1, 2), (2, 3)]);
- tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
+ tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect();
//~^ manual_retain
tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
//~^ manual_retain
@@ -103,7 +103,7 @@ fn btree_set_retain() {
// Do lint, because we use pattern matching
let mut tuples = BTreeSet::from([(0, 1), (1, 2), (2, 3)]);
- tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
+ tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect();
//~^ manual_retain
tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
//~^ manual_retain
@@ -174,7 +174,7 @@ fn hash_set_retain() {
// Do lint, because we use pattern matching
let mut tuples = HashSet::from([(0, 1), (1, 2), (2, 3)]);
- tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
+ tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect();
//~^ manual_retain
tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
//~^ manual_retain
@@ -228,7 +228,7 @@ fn vec_retain() {
// Do lint, because we use pattern matching
let mut tuples = vec![(0, 1), (1, 2), (2, 3)];
- tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
+ tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect();
//~^ manual_retain
tuples = tuples.iter().filter(|(x, y)| *x == 0).copied().collect();
//~^ manual_retain
diff --git a/src/tools/clippy/tests/ui/manual_retain.stderr b/src/tools/clippy/tests/ui/manual_retain.stderr
index 2f81647..e7d3e34 100644
--- a/src/tools/clippy/tests/ui/manual_retain.stderr
+++ b/src/tools/clippy/tests/ui/manual_retain.stderr
@@ -22,8 +22,8 @@
error: this expression can be written more simply using `.retain()`
--> tests/ui/manual_retain.rs:34:5
|
-LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)`
+LL | tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|&(ref x, ref y)| *x == 0)`
error: this expression can be written more simply using `.retain()`
--> tests/ui/manual_retain.rs:36:5
@@ -74,8 +74,8 @@
error: this expression can be written more simply using `.retain()`
--> tests/ui/manual_retain.rs:106:5
|
-LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)`
+LL | tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|&(ref x, ref y)| *x == 0)`
error: this expression can be written more simply using `.retain()`
--> tests/ui/manual_retain.rs:108:5
@@ -126,8 +126,8 @@
error: this expression can be written more simply using `.retain()`
--> tests/ui/manual_retain.rs:177:5
|
-LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)`
+LL | tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|&(ref x, ref y)| *x == 0)`
error: this expression can be written more simply using `.retain()`
--> tests/ui/manual_retain.rs:179:5
@@ -162,8 +162,8 @@
error: this expression can be written more simply using `.retain()`
--> tests/ui/manual_retain.rs:231:5
|
-LL | tuples = tuples.iter().filter(|(ref x, ref y)| *x == 0).copied().collect();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|(ref x, ref y)| *x == 0)`
+LL | tuples = tuples.iter().filter(|&&(ref x, ref y)| *x == 0).copied().collect();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider calling `.retain()` instead: `tuples.retain(|&(ref x, ref y)| *x == 0)`
error: this expression can be written more simply using `.retain()`
--> tests/ui/manual_retain.rs:233:5
diff --git a/src/tools/clippy/tests/ui/manual_strip_fixable.fixed b/src/tools/clippy/tests/ui/manual_strip_fixable.fixed
index 75a3f16..b59e371 100644
--- a/src/tools/clippy/tests/ui/manual_strip_fixable.fixed
+++ b/src/tools/clippy/tests/ui/manual_strip_fixable.fixed
@@ -1,4 +1,5 @@
#![warn(clippy::manual_strip)]
+#![allow(clippy::uninlined_format_args)]
fn main() {
let s = "abc";
diff --git a/src/tools/clippy/tests/ui/manual_strip_fixable.rs b/src/tools/clippy/tests/ui/manual_strip_fixable.rs
index 5080068..4fb3a9b 100644
--- a/src/tools/clippy/tests/ui/manual_strip_fixable.rs
+++ b/src/tools/clippy/tests/ui/manual_strip_fixable.rs
@@ -1,4 +1,5 @@
#![warn(clippy::manual_strip)]
+#![allow(clippy::uninlined_format_args)]
fn main() {
let s = "abc";
diff --git a/src/tools/clippy/tests/ui/manual_strip_fixable.stderr b/src/tools/clippy/tests/ui/manual_strip_fixable.stderr
index 1c276e5..da8b0cd 100644
--- a/src/tools/clippy/tests/ui/manual_strip_fixable.stderr
+++ b/src/tools/clippy/tests/ui/manual_strip_fixable.stderr
@@ -1,11 +1,11 @@
error: stripping a prefix manually
- --> tests/ui/manual_strip_fixable.rs:7:24
+ --> tests/ui/manual_strip_fixable.rs:8:24
|
LL | let stripped = &s["ab".len()..];
| ^^^^^^^^^^^^^^^^
|
note: the prefix was tested here
- --> tests/ui/manual_strip_fixable.rs:6:5
+ --> tests/ui/manual_strip_fixable.rs:7:5
|
LL | if s.starts_with("ab") {
| ^^^^^^^^^^^^^^^^^^^^^^^
@@ -19,13 +19,13 @@
|
error: stripping a suffix manually
- --> tests/ui/manual_strip_fixable.rs:13:24
+ --> tests/ui/manual_strip_fixable.rs:14:24
|
LL | let stripped = &s[..s.len() - "bc".len()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: the suffix was tested here
- --> tests/ui/manual_strip_fixable.rs:12:5
+ --> tests/ui/manual_strip_fixable.rs:13:5
|
LL | if s.ends_with("bc") {
| ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed
index 07e4bdd..e12287a 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed
@@ -18,11 +18,9 @@
// multiline case
#[rustfmt::skip]
- Some(1).unwrap_or({
- 42 + 42
- + 42 + 42 + 42
- + 42 + 42 + 42
- });
+ Some(1).unwrap_or(42 + 42
+ + 42 + 42 + 42
+ + 42 + 42 + 42);
// string case
Some("Bob").unwrap_or("Alice");
@@ -125,11 +123,9 @@
// multiline case
#[rustfmt::skip]
- Ok::<i32, &str>(1).unwrap_or({
- 42 + 42
- + 42 + 42 + 42
- + 42 + 42 + 42
- });
+ Ok::<i32, &str>(1).unwrap_or(42 + 42
+ + 42 + 42 + 42
+ + 42 + 42 + 42);
// string case
Ok::<&str, &str>("Bob").unwrap_or("Alice");
@@ -159,11 +155,7 @@
Ok(s) => s,
Err(s) => s,
};
- // could lint, but unused_variables takes care of it
- match Ok::<&str, &str>("Alice") {
- Ok(s) => s,
- Err(s) => "Bob",
- };
+ Ok::<&str, &str>("Alice").unwrap_or("Bob");
Ok::<i32, i32>(1).unwrap_or(42);
@@ -250,4 +242,12 @@
}
}
+fn implicit_deref(v: Vec<String>) {
+ let _ = if let Some(s) = v.first() { s } else { "" };
+}
+
+fn allowed_manual_unwrap_or_zero() -> u32 {
+ Some(42).unwrap_or(0)
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.rs b/src/tools/clippy/tests/ui/manual_unwrap_or.rs
index c88b6f9..53cffca 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or.rs
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or.rs
@@ -216,8 +216,8 @@ fn method(self) -> Option<i32> {
Ok(s) => s,
Err(s) => s,
};
- // could lint, but unused_variables takes care of it
match Ok::<&str, &str>("Alice") {
+ //~^ manual_unwrap_or
Ok(s) => s,
Err(s) => "Bob",
};
@@ -316,4 +316,17 @@ pub fn get_match(index: &HashMap<usize, Vec<RefName>>, id: usize) -> &[RefName]
}
}
+fn implicit_deref(v: Vec<String>) {
+ let _ = if let Some(s) = v.first() { s } else { "" };
+}
+
+fn allowed_manual_unwrap_or_zero() -> u32 {
+ if let Some(x) = Some(42) {
+ //~^ manual_unwrap_or
+ x
+ } else {
+ 0
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.stderr b/src/tools/clippy/tests/ui/manual_unwrap_or.stderr
index a5deb55..320e895 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or.stderr
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or.stderr
@@ -44,11 +44,9 @@
|
help: replace with
|
-LL ~ Some(1).unwrap_or({
-LL + 42 + 42
-LL + + 42 + 42 + 42
-LL + + 42 + 42 + 42
-LL ~ });
+LL ~ Some(1).unwrap_or(42 + 42
+LL + + 42 + 42 + 42
+LL ~ + 42 + 42 + 42);
|
error: this pattern reimplements `Option::unwrap_or`
@@ -145,11 +143,9 @@
|
help: replace with
|
-LL ~ Ok::<i32, &str>(1).unwrap_or({
-LL + 42 + 42
-LL + + 42 + 42 + 42
-LL + + 42 + 42 + 42
-LL ~ });
+LL ~ Ok::<i32, &str>(1).unwrap_or(42 + 42
+LL + + 42 + 42 + 42
+LL ~ + 42 + 42 + 42);
|
error: this pattern reimplements `Result::unwrap_or`
@@ -163,6 +159,16 @@
| |_____^ help: replace with: `Ok::<&str, &str>("Bob").unwrap_or("Alice")`
error: this pattern reimplements `Result::unwrap_or`
+ --> tests/ui/manual_unwrap_or.rs:219:5
+ |
+LL | / match Ok::<&str, &str>("Alice") {
+LL | |
+LL | | Ok(s) => s,
+LL | | Err(s) => "Bob",
+LL | | };
+ | |_____^ help: replace with: `Ok::<&str, &str>("Alice").unwrap_or("Bob")`
+
+error: this pattern reimplements `Result::unwrap_or`
--> tests/ui/manual_unwrap_or.rs:225:5
|
LL | / if let Ok(x) = Ok::<i32, i32>(1) {
@@ -184,5 +190,16 @@
LL | | };
| |_________^ help: replace with: `some_macro!().unwrap_or(0)`
-error: aborting due to 16 previous errors
+error: this pattern reimplements `Option::unwrap_or`
+ --> tests/ui/manual_unwrap_or.rs:324:5
+ |
+LL | / if let Some(x) = Some(42) {
+LL | |
+LL | | x
+LL | | } else {
+LL | | 0
+LL | | }
+ | |_____^ help: replace with: `Some(42).unwrap_or(0)`
+
+error: aborting due to 18 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
index 832376f..9dae9fc 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.fixed
@@ -1,5 +1,5 @@
#![warn(clippy::manual_unwrap_or_default)]
-#![allow(clippy::unnecessary_literal_unwrap, clippy::manual_unwrap_or)]
+#![allow(clippy::unnecessary_literal_unwrap)]
fn main() {
let x: Option<Vec<String>> = None;
@@ -36,10 +36,12 @@
// Issue #12531
unsafe fn no_deref_ptr(a: Option<i32>, b: *const Option<i32>) -> i32 {
- match a {
- // `*b` being correct depends on `a == Some(_)`
- Some(_) => (*b).unwrap_or_default(),
- _ => 0,
+ unsafe {
+ match a {
+ // `*b` being correct depends on `a == Some(_)`
+ Some(_) => (*b).unwrap_or_default(),
+ _ => 0,
+ }
}
}
@@ -99,3 +101,8 @@
let y = if let Some(Y(a, _)) = x { a } else { 0 };
let y = if let Some(Y(a, ..)) = x { a } else { 0 };
}
+
+// For symetry with `manual_unwrap_or` test
+fn allowed_manual_unwrap_or_zero() -> u32 {
+ Some(42).unwrap_or_default()
+}
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
index bedb3f0..539d7a8 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.rs
@@ -1,5 +1,5 @@
#![warn(clippy::manual_unwrap_or_default)]
-#![allow(clippy::unnecessary_literal_unwrap, clippy::manual_unwrap_or)]
+#![allow(clippy::unnecessary_literal_unwrap)]
fn main() {
let x: Option<Vec<String>> = None;
@@ -68,14 +68,16 @@ fn main() {
// Issue #12531
unsafe fn no_deref_ptr(a: Option<i32>, b: *const Option<i32>) -> i32 {
- match a {
- // `*b` being correct depends on `a == Some(_)`
- Some(_) => match *b {
- //~^ manual_unwrap_or_default
- Some(v) => v,
+ unsafe {
+ match a {
+ // `*b` being correct depends on `a == Some(_)`
+ Some(_) => match *b {
+ //~^ manual_unwrap_or_default
+ Some(v) => v,
+ _ => 0,
+ },
_ => 0,
- },
- _ => 0,
+ }
}
}
@@ -135,3 +137,13 @@ struct X {
let y = if let Some(Y(a, _)) = x { a } else { 0 };
let y = if let Some(Y(a, ..)) = x { a } else { 0 };
}
+
+// For symetry with `manual_unwrap_or` test
+fn allowed_manual_unwrap_or_zero() -> u32 {
+ if let Some(x) = Some(42) {
+ //~^ manual_unwrap_or_default
+ x
+ } else {
+ 0
+ }
+}
diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr b/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr
index ca9aa15..e8f38a2 100644
--- a/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr
+++ b/src/tools/clippy/tests/ui/manual_unwrap_or_default.stderr
@@ -76,15 +76,26 @@
| |_____^ help: replace it with: `x.unwrap_or_default()`
error: match can be simplified with `.unwrap_or_default()`
- --> tests/ui/manual_unwrap_or_default.rs:73:20
+ --> tests/ui/manual_unwrap_or_default.rs:74:24
|
-LL | Some(_) => match *b {
- | ____________________^
+LL | Some(_) => match *b {
+ | ________________________^
LL | |
-LL | | Some(v) => v,
-LL | | _ => 0,
-LL | | },
- | |_________^ help: replace it with: `(*b).unwrap_or_default()`
+LL | | Some(v) => v,
+LL | | _ => 0,
+LL | | },
+ | |_____________^ help: replace it with: `(*b).unwrap_or_default()`
-error: aborting due to 8 previous errors
+error: if let can be simplified with `.unwrap_or_default()`
+ --> tests/ui/manual_unwrap_or_default.rs:143:5
+ |
+LL | / if let Some(x) = Some(42) {
+LL | |
+LL | | x
+LL | | } else {
+LL | | 0
+LL | | }
+ | |_____^ help: replace it with: `Some(42).unwrap_or_default()`
+
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed
index 948fec9..f8379ed 100644
--- a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed
+++ b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed
@@ -1,10 +1,11 @@
-#![warn(clippy::all, clippy::pedantic)]
-#![allow(clippy::let_underscore_untyped)]
-#![allow(clippy::missing_docs_in_private_items)]
-#![allow(clippy::map_identity)]
-#![allow(clippy::redundant_closure)]
-#![allow(clippy::unnecessary_wraps)]
#![feature(result_flattening)]
+#![allow(
+ clippy::let_underscore_untyped,
+ clippy::missing_docs_in_private_items,
+ clippy::map_identity,
+ clippy::redundant_closure,
+ clippy::unnecessary_wraps
+)]
fn main() {
// mapping to Option on Iterator
diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.rs b/src/tools/clippy/tests/ui/map_flatten_fixable.rs
index 67a91ab..040a9ca 100644
--- a/src/tools/clippy/tests/ui/map_flatten_fixable.rs
+++ b/src/tools/clippy/tests/ui/map_flatten_fixable.rs
@@ -1,10 +1,11 @@
-#![warn(clippy::all, clippy::pedantic)]
-#![allow(clippy::let_underscore_untyped)]
-#![allow(clippy::missing_docs_in_private_items)]
-#![allow(clippy::map_identity)]
-#![allow(clippy::redundant_closure)]
-#![allow(clippy::unnecessary_wraps)]
#![feature(result_flattening)]
+#![allow(
+ clippy::let_underscore_untyped,
+ clippy::missing_docs_in_private_items,
+ clippy::map_identity,
+ clippy::redundant_closure,
+ clippy::unnecessary_wraps
+)]
fn main() {
// mapping to Option on Iterator
diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr
index 05d4d9a..fe68eb7 100644
--- a/src/tools/clippy/tests/ui/map_flatten_fixable.stderr
+++ b/src/tools/clippy/tests/ui/map_flatten_fixable.stderr
@@ -1,5 +1,5 @@
error: called `map(..).flatten()` on `Iterator`
- --> tests/ui/map_flatten_fixable.rs:16:47
+ --> tests/ui/map_flatten_fixable.rs:17:47
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id)`
@@ -8,43 +8,43 @@
= help: to override `-D warnings` add `#[allow(clippy::map_flatten)]`
error: called `map(..).flatten()` on `Iterator`
- --> tests/ui/map_flatten_fixable.rs:18:47
+ --> tests/ui/map_flatten_fixable.rs:19:47
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_ref).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_ref)`
error: called `map(..).flatten()` on `Iterator`
- --> tests/ui/map_flatten_fixable.rs:20:47
+ --> tests/ui/map_flatten_fixable.rs:21:47
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(option_id_closure).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(option_id_closure)`
error: called `map(..).flatten()` on `Iterator`
- --> tests/ui/map_flatten_fixable.rs:22:47
+ --> tests/ui/map_flatten_fixable.rs:23:47
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| x.checked_add(1)).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `filter_map` and remove the `.flatten()`: `filter_map(|x| x.checked_add(1))`
error: called `map(..).flatten()` on `Iterator`
- --> tests/ui/map_flatten_fixable.rs:26:47
+ --> tests/ui/map_flatten_fixable.rs:27:47
|
LL | let _: Vec<_> = vec![5_i8; 6].into_iter().map(|x| 0..x).flatten().collect();
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `flat_map` and remove the `.flatten()`: `flat_map(|x| 0..x)`
error: called `map(..).flatten()` on `Option`
- --> tests/ui/map_flatten_fixable.rs:30:40
+ --> tests/ui/map_flatten_fixable.rs:31:40
|
LL | let _: Option<_> = (Some(Some(1))).map(|x| x).flatten();
| ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)`
error: called `map(..).flatten()` on `Result`
- --> tests/ui/map_flatten_fixable.rs:34:42
+ --> tests/ui/map_flatten_fixable.rs:35:42
|
LL | let _: Result<_, &str> = (Ok(Ok(1))).map(|x| x).flatten();
| ^^^^^^^^^^^^^^^^^^^^ help: try replacing `map` with `and_then` and remove the `.flatten()`: `and_then(|x| x)`
error: called `map(..).flatten()` on `Iterator`
- --> tests/ui/map_flatten_fixable.rs:44:10
+ --> tests/ui/map_flatten_fixable.rs:45:10
|
LL | .map(|n| match n {
| __________^
@@ -74,7 +74,7 @@
|
error: called `map(..).flatten()` on `Option`
- --> tests/ui/map_flatten_fixable.rs:65:10
+ --> tests/ui/map_flatten_fixable.rs:66:10
|
LL | .map(|_| {
| __________^
diff --git a/src/tools/clippy/tests/ui/match_on_vec_items.rs b/src/tools/clippy/tests/ui/match_on_vec_items.rs
deleted file mode 100644
index f3174ec..0000000
--- a/src/tools/clippy/tests/ui/match_on_vec_items.rs
+++ /dev/null
@@ -1,161 +0,0 @@
-#![warn(clippy::match_on_vec_items)]
-#![allow(clippy::redundant_at_rest_pattern, clippy::useless_vec)]
-//@no-rustfix
-fn match_with_wildcard() {
- let arr = vec![0, 1, 2, 3];
- let range = 1..3;
- let idx = 1;
-
- // Lint, may panic
- match arr[idx] {
- //~^ match_on_vec_items
- 0 => println!("0"),
- 1 => println!("1"),
- _ => {},
- }
-
- // Lint, may panic
- match arr[range] {
- //~^ match_on_vec_items
- [0, 1] => println!("0 1"),
- [1, 2] => println!("1 2"),
- _ => {},
- }
-}
-
-fn match_without_wildcard() {
- let arr = vec![0, 1, 2, 3];
- let range = 1..3;
- let idx = 2;
-
- // Lint, may panic
- match arr[idx] {
- //~^ match_on_vec_items
- 0 => println!("0"),
- 1 => println!("1"),
- num => {},
- }
-
- // Lint, may panic
- match arr[range] {
- //~^ match_on_vec_items
- [0, 1] => println!("0 1"),
- [1, 2] => println!("1 2"),
- [ref sub @ ..] => {},
- }
-}
-
-fn match_wildcard_and_action() {
- let arr = vec![0, 1, 2, 3];
- let range = 1..3;
- let idx = 3;
-
- // Lint, may panic
- match arr[idx] {
- //~^ match_on_vec_items
- 0 => println!("0"),
- 1 => println!("1"),
- _ => println!("Hello, World!"),
- }
-
- // Lint, may panic
- match arr[range] {
- //~^ match_on_vec_items
- [0, 1] => println!("0 1"),
- [1, 2] => println!("1 2"),
- _ => println!("Hello, World!"),
- }
-}
-
-fn match_vec_ref() {
- let arr = &vec![0, 1, 2, 3];
- let range = 1..3;
- let idx = 3;
-
- // Lint, may panic
- match arr[idx] {
- //~^ match_on_vec_items
- 0 => println!("0"),
- 1 => println!("1"),
- _ => {},
- }
-
- // Lint, may panic
- match arr[range] {
- //~^ match_on_vec_items
- [0, 1] => println!("0 1"),
- [1, 2] => println!("1 2"),
- _ => {},
- }
-}
-
-fn match_with_get() {
- let arr = vec![0, 1, 2, 3];
- let range = 1..3;
- let idx = 3;
-
- // Ok
- match arr.get(idx) {
- Some(0) => println!("0"),
- Some(1) => println!("1"),
- _ => {},
- }
-
- // Ok
- match arr.get(range) {
- Some(&[0, 1]) => println!("0 1"),
- Some(&[1, 2]) => println!("1 2"),
- _ => {},
- }
-}
-
-fn match_with_array() {
- let arr = [0, 1, 2, 3];
- let range = 1..3;
- let idx = 3;
-
- // Ok
- match arr[idx] {
- 0 => println!("0"),
- 1 => println!("1"),
- _ => {},
- }
-
- // Ok
- match arr[range] {
- [0, 1] => println!("0 1"),
- [1, 2] => println!("1 2"),
- _ => {},
- }
-}
-
-fn match_with_endless_range() {
- let arr = vec![0, 1, 2, 3];
- let range = ..;
-
- // Ok
- match arr[range] {
- [0, 1] => println!("0 1"),
- [1, 2] => println!("1 2"),
- [0, 1, 2, 3] => println!("0, 1, 2, 3"),
- _ => {},
- }
-
- // Ok
- match arr[..] {
- [0, 1] => println!("0 1"),
- [1, 2] => println!("1 2"),
- [0, 1, 2, 3] => println!("0, 1, 2, 3"),
- _ => {},
- }
-}
-
-fn main() {
- match_with_wildcard();
- match_without_wildcard();
- match_wildcard_and_action();
- match_vec_ref();
- match_with_get();
- match_with_array();
- match_with_endless_range();
-}
diff --git a/src/tools/clippy/tests/ui/match_on_vec_items.stderr b/src/tools/clippy/tests/ui/match_on_vec_items.stderr
deleted file mode 100644
index ae79e13..0000000
--- a/src/tools/clippy/tests/ui/match_on_vec_items.stderr
+++ /dev/null
@@ -1,53 +0,0 @@
-error: indexing into a vector may panic
- --> tests/ui/match_on_vec_items.rs:10:11
- |
-LL | match arr[idx] {
- | ^^^^^^^^ help: try: `arr.get(idx)`
- |
- = note: `-D clippy::match-on-vec-items` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::match_on_vec_items)]`
-
-error: indexing into a vector may panic
- --> tests/ui/match_on_vec_items.rs:18:11
- |
-LL | match arr[range] {
- | ^^^^^^^^^^ help: try: `arr.get(range)`
-
-error: indexing into a vector may panic
- --> tests/ui/match_on_vec_items.rs:32:11
- |
-LL | match arr[idx] {
- | ^^^^^^^^ help: try: `arr.get(idx)`
-
-error: indexing into a vector may panic
- --> tests/ui/match_on_vec_items.rs:40:11
- |
-LL | match arr[range] {
- | ^^^^^^^^^^ help: try: `arr.get(range)`
-
-error: indexing into a vector may panic
- --> tests/ui/match_on_vec_items.rs:54:11
- |
-LL | match arr[idx] {
- | ^^^^^^^^ help: try: `arr.get(idx)`
-
-error: indexing into a vector may panic
- --> tests/ui/match_on_vec_items.rs:62:11
- |
-LL | match arr[range] {
- | ^^^^^^^^^^ help: try: `arr.get(range)`
-
-error: indexing into a vector may panic
- --> tests/ui/match_on_vec_items.rs:76:11
- |
-LL | match arr[idx] {
- | ^^^^^^^^ help: try: `arr.get(idx)`
-
-error: indexing into a vector may panic
- --> tests/ui/match_on_vec_items.rs:84:11
- |
-LL | match arr[range] {
- | ^^^^^^^^^^ help: try: `arr.get(range)`
-
-error: aborting due to 8 previous errors
-
diff --git a/src/tools/clippy/tests/ui/match_single_binding.fixed b/src/tools/clippy/tests/ui/match_single_binding.fixed
index 3a3eee4..bdf3979 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.fixed
+++ b/src/tools/clippy/tests/ui/match_single_binding.fixed
@@ -171,3 +171,20 @@
2
}
+
+fn issue14634() {
+ macro_rules! id {
+ ($i:ident) => {
+ $i
+ };
+ }
+ dbg!(3);
+ println!("here");
+ //~^^^ match_single_binding
+ let id!(a) = dbg!(3);
+ println!("found {a}");
+ //~^^^ match_single_binding
+ let id!(b) = dbg!(3);
+ let id!(_a) = dbg!(b + 1);
+ //~^^^ match_single_binding
+}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs
index ada5125..419ff95 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.rs
+++ b/src/tools/clippy/tests/ui/match_single_binding.rs
@@ -229,3 +229,23 @@ fn issue_10447() -> usize {
2
}
+
+fn issue14634() {
+ macro_rules! id {
+ ($i:ident) => {
+ $i
+ };
+ }
+ match dbg!(3) {
+ _ => println!("here"),
+ }
+ //~^^^ match_single_binding
+ match dbg!(3) {
+ id!(a) => println!("found {a}"),
+ }
+ //~^^^ match_single_binding
+ let id!(_a) = match dbg!(3) {
+ id!(b) => dbg!(b + 1),
+ };
+ //~^^^ match_single_binding
+}
diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr
index 7e1ec32..bdd0134 100644
--- a/src/tools/clippy/tests/ui/match_single_binding.stderr
+++ b/src/tools/clippy/tests/ui/match_single_binding.stderr
@@ -336,5 +336,47 @@
LL | | },
| |_________^ help: consider using the match body instead: `println!("1")`
-error: aborting due to 24 previous errors
+error: this match could be replaced by its scrutinee and body
+ --> tests/ui/match_single_binding.rs:239:5
+ |
+LL | / match dbg!(3) {
+LL | | _ => println!("here"),
+LL | | }
+ | |_____^
+ |
+help: consider using the scrutinee and body instead
+ |
+LL ~ dbg!(3);
+LL + println!("here");
+ |
+
+error: this match could be written as a `let` statement
+ --> tests/ui/match_single_binding.rs:243:5
+ |
+LL | / match dbg!(3) {
+LL | | id!(a) => println!("found {a}"),
+LL | | }
+ | |_____^
+ |
+help: consider using a `let` statement
+ |
+LL ~ let id!(a) = dbg!(3);
+LL + println!("found {a}");
+ |
+
+error: this match could be written as a `let` statement
+ --> tests/ui/match_single_binding.rs:247:5
+ |
+LL | / let id!(_a) = match dbg!(3) {
+LL | | id!(b) => dbg!(b + 1),
+LL | | };
+ | |______^
+ |
+help: consider using a `let` statement
+ |
+LL ~ let id!(b) = dbg!(3);
+LL + let id!(_a) = dbg!(b + 1);
+ |
+
+error: aborting due to 27 previous errors
diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs
index 76b0d13..2f40041 100644
--- a/src/tools/clippy/tests/ui/methods.rs
+++ b/src/tools/clippy/tests/ui/methods.rs
@@ -1,6 +1,5 @@
//@aux-build:option_helpers.rs
-#![warn(clippy::all, clippy::pedantic)]
#![allow(
clippy::disallowed_names,
clippy::default_trait_access,
@@ -19,8 +18,7 @@
clippy::wrong_self_convention,
clippy::unused_async,
clippy::unused_self,
- clippy::useless_vec,
- unused
+ clippy::useless_vec
)]
#[macro_use]
diff --git a/src/tools/clippy/tests/ui/methods.stderr b/src/tools/clippy/tests/ui/methods.stderr
index 353b999..b226ce7 100644
--- a/src/tools/clippy/tests/ui/methods.stderr
+++ b/src/tools/clippy/tests/ui/methods.stderr
@@ -1,5 +1,5 @@
error: methods called `new` usually return `Self`
- --> tests/ui/methods.rs:104:5
+ --> tests/ui/methods.rs:102:5
|
LL | / fn new() -> i32 {
LL | |
@@ -11,7 +11,7 @@
= help: to override `-D warnings` add `#[allow(clippy::new_ret_no_self)]`
error: called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling `.find(..)` instead
- --> tests/ui/methods.rs:126:13
+ --> tests/ui/methods.rs:124:13
|
LL | let _ = v.iter().filter(|&x| {
| _____________^
diff --git a/src/tools/clippy/tests/ui/min_max.rs b/src/tools/clippy/tests/ui/min_max.rs
index f3eeb85..ee19d3ff 100644
--- a/src/tools/clippy/tests/ui/min_max.rs
+++ b/src/tools/clippy/tests/ui/min_max.rs
@@ -1,4 +1,3 @@
-#![warn(clippy::all)]
#![allow(clippy::manual_clamp)]
use std::cmp::{max as my_max, max, min as my_min, min};
diff --git a/src/tools/clippy/tests/ui/min_max.stderr b/src/tools/clippy/tests/ui/min_max.stderr
index 84b4d37..87510a4 100644
--- a/src/tools/clippy/tests/ui/min_max.stderr
+++ b/src/tools/clippy/tests/ui/min_max.stderr
@@ -1,80 +1,79 @@
error: this `min`/`max` combination leads to constant result
- --> tests/ui/min_max.rs:22:5
+ --> tests/ui/min_max.rs:21:5
|
LL | min(1, max(3, x));
| ^^^^^^^^^^^^^^^^^
|
- = note: `-D clippy::min-max` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::min_max)]`
+ = note: `#[deny(clippy::min_max)]` on by default
error: this `min`/`max` combination leads to constant result
- --> tests/ui/min_max.rs:25:5
+ --> tests/ui/min_max.rs:24:5
|
LL | min(max(3, x), 1);
| ^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> tests/ui/min_max.rs:28:5
+ --> tests/ui/min_max.rs:27:5
|
LL | max(min(x, 1), 3);
| ^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> tests/ui/min_max.rs:31:5
+ --> tests/ui/min_max.rs:30:5
|
LL | max(3, min(x, 1));
| ^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> tests/ui/min_max.rs:34:5
+ --> tests/ui/min_max.rs:33:5
|
LL | my_max(3, my_min(x, 1));
| ^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> tests/ui/min_max.rs:45:5
+ --> tests/ui/min_max.rs:44:5
|
LL | min("Apple", max("Zoo", s));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> tests/ui/min_max.rs:48:5
+ --> tests/ui/min_max.rs:47:5
|
LL | max(min(s, "Apple"), "Zoo");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> tests/ui/min_max.rs:54:5
+ --> tests/ui/min_max.rs:53:5
|
LL | x.min(1).max(3);
| ^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> tests/ui/min_max.rs:57:5
+ --> tests/ui/min_max.rs:56:5
|
LL | x.max(3).min(1);
| ^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> tests/ui/min_max.rs:60:5
+ --> tests/ui/min_max.rs:59:5
|
LL | f.max(3f32).min(1f32);
| ^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> tests/ui/min_max.rs:67:5
+ --> tests/ui/min_max.rs:66:5
|
LL | max(x.min(1), 3);
| ^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> tests/ui/min_max.rs:72:5
+ --> tests/ui/min_max.rs:71:5
|
LL | s.max("Zoo").min("Apple");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: this `min`/`max` combination leads to constant result
- --> tests/ui/min_max.rs:75:5
+ --> tests/ui/min_max.rs:74:5
|
LL | s.min("Apple").max("Zoo");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/misnamed_getters.fixed b/src/tools/clippy/tests/ui/misnamed_getters.fixed
index cada530..bc123d1 100644
--- a/src/tools/clippy/tests/ui/misnamed_getters.fixed
+++ b/src/tools/clippy/tests/ui/misnamed_getters.fixed
@@ -54,63 +54,63 @@
unsafe fn a(&self) -> &u8 {
//~^ misnamed_getters
- &self.a
+ unsafe { &self.a }
}
unsafe fn a_mut(&mut self) -> &mut u8 {
//~^ misnamed_getters
- &mut self.a
+ unsafe { &mut self.a }
}
unsafe fn b(self) -> u8 {
//~^ misnamed_getters
- self.b
+ unsafe { self.b }
}
unsafe fn b_mut(&mut self) -> &mut u8 {
//~^ misnamed_getters
- &mut self.b
+ unsafe { &mut self.b }
}
unsafe fn c(&self) -> &u8 {
- &self.b
+ unsafe { &self.b }
}
unsafe fn c_mut(&mut self) -> &mut u8 {
- &mut self.a
+ unsafe { &mut self.a }
}
unsafe fn a_unchecked(&self) -> &u8 {
//~^ misnamed_getters
- &self.a
+ unsafe { &self.a }
}
unsafe fn a_unchecked_mut(&mut self) -> &mut u8 {
//~^ misnamed_getters
- &mut self.a
+ unsafe { &mut self.a }
}
unsafe fn b_unchecked(self) -> u8 {
//~^ misnamed_getters
- self.b
+ unsafe { self.b }
}
unsafe fn b_unchecked_mut(&mut self) -> &mut u8 {
//~^ misnamed_getters
- &mut self.b
+ unsafe { &mut self.b }
}
unsafe fn c_unchecked(&self) -> &u8 {
- &self.b
+ unsafe { &self.b }
}
unsafe fn c_unchecked_mut(&mut self) -> &mut u8 {
- &mut self.a
+ unsafe { &mut self.a }
}
}
diff --git a/src/tools/clippy/tests/ui/misnamed_getters.rs b/src/tools/clippy/tests/ui/misnamed_getters.rs
index f529c56..6590101 100644
--- a/src/tools/clippy/tests/ui/misnamed_getters.rs
+++ b/src/tools/clippy/tests/ui/misnamed_getters.rs
@@ -54,63 +54,63 @@ impl B {
unsafe fn a(&self) -> &u8 {
//~^ misnamed_getters
- &self.b
+ unsafe { &self.b }
}
unsafe fn a_mut(&mut self) -> &mut u8 {
//~^ misnamed_getters
- &mut self.b
+ unsafe { &mut self.b }
}
unsafe fn b(self) -> u8 {
//~^ misnamed_getters
- self.a
+ unsafe { self.a }
}
unsafe fn b_mut(&mut self) -> &mut u8 {
//~^ misnamed_getters
- &mut self.a
+ unsafe { &mut self.a }
}
unsafe fn c(&self) -> &u8 {
- &self.b
+ unsafe { &self.b }
}
unsafe fn c_mut(&mut self) -> &mut u8 {
- &mut self.a
+ unsafe { &mut self.a }
}
unsafe fn a_unchecked(&self) -> &u8 {
//~^ misnamed_getters
- &self.b
+ unsafe { &self.b }
}
unsafe fn a_unchecked_mut(&mut self) -> &mut u8 {
//~^ misnamed_getters
- &mut self.b
+ unsafe { &mut self.b }
}
unsafe fn b_unchecked(self) -> u8 {
//~^ misnamed_getters
- self.a
+ unsafe { self.a }
}
unsafe fn b_unchecked_mut(&mut self) -> &mut u8 {
//~^ misnamed_getters
- &mut self.a
+ unsafe { &mut self.a }
}
unsafe fn c_unchecked(&self) -> &u8 {
- &self.b
+ unsafe { &self.b }
}
unsafe fn c_unchecked_mut(&mut self) -> &mut u8 {
- &mut self.a
+ unsafe { &mut self.a }
}
}
diff --git a/src/tools/clippy/tests/ui/misnamed_getters.stderr b/src/tools/clippy/tests/ui/misnamed_getters.stderr
index 5dd1d75..aaf21ce 100644
--- a/src/tools/clippy/tests/ui/misnamed_getters.stderr
+++ b/src/tools/clippy/tests/ui/misnamed_getters.stderr
@@ -73,8 +73,8 @@
LL | / unsafe fn a(&self) -> &u8 {
LL | |
LL | |
-LL | | &self.b
- | | ------- help: consider using: `&self.a`
+LL | | unsafe { &self.b }
+ | | ------- help: consider using: `&self.a`
LL | | }
| |_____^
@@ -84,8 +84,8 @@
LL | / unsafe fn a_mut(&mut self) -> &mut u8 {
LL | |
LL | |
-LL | | &mut self.b
- | | ----------- help: consider using: `&mut self.a`
+LL | | unsafe { &mut self.b }
+ | | ----------- help: consider using: `&mut self.a`
LL | | }
| |_____^
@@ -95,8 +95,8 @@
LL | / unsafe fn b(self) -> u8 {
LL | |
LL | |
-LL | | self.a
- | | ------ help: consider using: `self.b`
+LL | | unsafe { self.a }
+ | | ------ help: consider using: `self.b`
LL | | }
| |_____^
@@ -106,8 +106,8 @@
LL | / unsafe fn b_mut(&mut self) -> &mut u8 {
LL | |
LL | |
-LL | | &mut self.a
- | | ----------- help: consider using: `&mut self.b`
+LL | | unsafe { &mut self.a }
+ | | ----------- help: consider using: `&mut self.b`
LL | | }
| |_____^
@@ -117,8 +117,8 @@
LL | / unsafe fn a_unchecked(&self) -> &u8 {
LL | |
LL | |
-LL | | &self.b
- | | ------- help: consider using: `&self.a`
+LL | | unsafe { &self.b }
+ | | ------- help: consider using: `&self.a`
LL | | }
| |_____^
@@ -128,8 +128,8 @@
LL | / unsafe fn a_unchecked_mut(&mut self) -> &mut u8 {
LL | |
LL | |
-LL | | &mut self.b
- | | ----------- help: consider using: `&mut self.a`
+LL | | unsafe { &mut self.b }
+ | | ----------- help: consider using: `&mut self.a`
LL | | }
| |_____^
@@ -139,8 +139,8 @@
LL | / unsafe fn b_unchecked(self) -> u8 {
LL | |
LL | |
-LL | | self.a
- | | ------ help: consider using: `self.b`
+LL | | unsafe { self.a }
+ | | ------ help: consider using: `self.b`
LL | | }
| |_____^
@@ -150,8 +150,8 @@
LL | / unsafe fn b_unchecked_mut(&mut self) -> &mut u8 {
LL | |
LL | |
-LL | | &mut self.a
- | | ----------- help: consider using: `&mut self.b`
+LL | | unsafe { &mut self.a }
+ | | ----------- help: consider using: `&mut self.b`
LL | | }
| |_____^
diff --git a/src/tools/clippy/tests/ui/misnamed_getters_2021.fixed b/src/tools/clippy/tests/ui/misnamed_getters_2021.fixed
new file mode 100644
index 0000000..7112719
--- /dev/null
+++ b/src/tools/clippy/tests/ui/misnamed_getters_2021.fixed
@@ -0,0 +1,24 @@
+//@edition: 2021
+#![allow(unused)]
+#![allow(clippy::struct_field_names)]
+#![warn(clippy::misnamed_getters)]
+
+// Edition 2021 specific check, where `unsafe` blocks are not required
+// inside `unsafe fn`.
+
+union B {
+ a: u8,
+ b: u8,
+}
+
+impl B {
+ unsafe fn a(&self) -> &u8 {
+ //~^ misnamed_getters
+
+ &self.a
+ }
+}
+
+fn main() {
+ // test code goes here
+}
diff --git a/src/tools/clippy/tests/ui/misnamed_getters_2021.rs b/src/tools/clippy/tests/ui/misnamed_getters_2021.rs
new file mode 100644
index 0000000..19b5d08
--- /dev/null
+++ b/src/tools/clippy/tests/ui/misnamed_getters_2021.rs
@@ -0,0 +1,24 @@
+//@edition: 2021
+#![allow(unused)]
+#![allow(clippy::struct_field_names)]
+#![warn(clippy::misnamed_getters)]
+
+// Edition 2021 specific check, where `unsafe` blocks are not required
+// inside `unsafe fn`.
+
+union B {
+ a: u8,
+ b: u8,
+}
+
+impl B {
+ unsafe fn a(&self) -> &u8 {
+ //~^ misnamed_getters
+
+ &self.b
+ }
+}
+
+fn main() {
+ // test code goes here
+}
diff --git a/src/tools/clippy/tests/ui/misnamed_getters_2021.stderr b/src/tools/clippy/tests/ui/misnamed_getters_2021.stderr
new file mode 100644
index 0000000..5495e2e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/misnamed_getters_2021.stderr
@@ -0,0 +1,16 @@
+error: getter function appears to return the wrong field
+ --> tests/ui/misnamed_getters_2021.rs:15:5
+ |
+LL | / unsafe fn a(&self) -> &u8 {
+LL | |
+LL | |
+LL | | &self.b
+ | | ------- help: consider using: `&self.a`
+LL | | }
+ | |_____^
+ |
+ = note: `-D clippy::misnamed-getters` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::misnamed_getters)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed
index 3bbafe0..9018f38 100644
--- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed
+++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.fixed
@@ -139,4 +139,31 @@
let _ = v4[0] + v4[1] + v4[2];
}
+// ok
+fn same_index_multiple_times(v1: &[u8]) {
+ let _ = v1[0] + v1[0];
+}
+
+// ok
+fn highest_index_first(v1: &[u8]) {
+ let _ = v1[2] + v1[1] + v1[0];
+}
+
+fn issue14255(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) {
+ assert!(v1.len() == 3);
+ assert_eq!(v2.len(), 4);
+ assert!(v3.len() == 3);
+ assert_eq!(4, v4.len());
+
+ let _ = v1[0] + v1[1] + v1[2];
+ //~^ missing_asserts_for_indexing
+
+ let _ = v2[0] + v2[1] + v2[2];
+
+ let _ = v3[0] + v3[1] + v3[2];
+ //~^ missing_asserts_for_indexing
+
+ let _ = v4[0] + v4[1] + v4[2];
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs
index f8ea017..44c5edd 100644
--- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs
+++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.rs
@@ -139,4 +139,31 @@ fn issue11835(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) {
let _ = v4[0] + v4[1] + v4[2];
}
+// ok
+fn same_index_multiple_times(v1: &[u8]) {
+ let _ = v1[0] + v1[0];
+}
+
+// ok
+fn highest_index_first(v1: &[u8]) {
+ let _ = v1[2] + v1[1] + v1[0];
+}
+
+fn issue14255(v1: &[u8], v2: &[u8], v3: &[u8], v4: &[u8]) {
+ assert_eq!(v1.len(), 2);
+ assert_eq!(v2.len(), 4);
+ assert_eq!(2, v3.len());
+ assert_eq!(4, v4.len());
+
+ let _ = v1[0] + v1[1] + v1[2];
+ //~^ missing_asserts_for_indexing
+
+ let _ = v2[0] + v2[1] + v2[2];
+
+ let _ = v3[0] + v3[1] + v3[2];
+ //~^ missing_asserts_for_indexing
+
+ let _ = v4[0] + v4[1] + v4[2];
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr
index 5d30920..b610de9 100644
--- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr
+++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing.stderr
@@ -301,5 +301,57 @@
| ^^^^^
= note: asserting the length before indexing will elide bounds checks
-error: aborting due to 11 previous errors
+error: indexing into a slice multiple times with an `assert` that does not cover the highest index
+ --> tests/ui/missing_asserts_for_indexing.rs:158:13
+ |
+LL | assert_eq!(v1.len(), 2);
+ | ----------------------- help: provide the highest index that is indexed with: `assert!(v1.len() == 3)`
+...
+LL | let _ = v1[0] + v1[1] + v1[2];
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+note: slice indexed here
+ --> tests/ui/missing_asserts_for_indexing.rs:158:13
+ |
+LL | let _ = v1[0] + v1[1] + v1[2];
+ | ^^^^^
+note: slice indexed here
+ --> tests/ui/missing_asserts_for_indexing.rs:158:21
+ |
+LL | let _ = v1[0] + v1[1] + v1[2];
+ | ^^^^^
+note: slice indexed here
+ --> tests/ui/missing_asserts_for_indexing.rs:158:29
+ |
+LL | let _ = v1[0] + v1[1] + v1[2];
+ | ^^^^^
+ = note: asserting the length before indexing will elide bounds checks
+
+error: indexing into a slice multiple times with an `assert` that does not cover the highest index
+ --> tests/ui/missing_asserts_for_indexing.rs:163:13
+ |
+LL | assert_eq!(2, v3.len());
+ | ----------------------- help: provide the highest index that is indexed with: `assert!(v3.len() == 3)`
+...
+LL | let _ = v3[0] + v3[1] + v3[2];
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+note: slice indexed here
+ --> tests/ui/missing_asserts_for_indexing.rs:163:13
+ |
+LL | let _ = v3[0] + v3[1] + v3[2];
+ | ^^^^^
+note: slice indexed here
+ --> tests/ui/missing_asserts_for_indexing.rs:163:21
+ |
+LL | let _ = v3[0] + v3[1] + v3[2];
+ | ^^^^^
+note: slice indexed here
+ --> tests/ui/missing_asserts_for_indexing.rs:163:29
+ |
+LL | let _ = v3[0] + v3[1] + v3[2];
+ | ^^^^^
+ = note: asserting the length before indexing will elide bounds checks
+
+error: aborting due to 13 previous errors
diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs
index a520151..eb98969 100644
--- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs
+++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.rs
@@ -73,4 +73,17 @@ pub fn issue11856(values: &[i32]) -> usize {
ascending.len()
}
+fn assert_after_indexing(v1: &[u8]) {
+ let _ = v1[1] + v1[2];
+ //~^ ERROR: indexing into a slice multiple times without an `assert`
+ assert!(v1.len() > 2);
+}
+
+fn issue14255(v1: &[u8]) {
+ assert_ne!(v1.len(), 2);
+
+ let _ = v1[0] + v1[1] + v1[2];
+ //~^ missing_asserts_for_indexing
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr
index 24109b0..a17ad02 100644
--- a/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/missing_asserts_for_indexing_unfixable.stderr
@@ -180,5 +180,48 @@
| ^^^^
= note: asserting the length before indexing will elide bounds checks
-error: aborting due to 8 previous errors
+error: indexing into a slice multiple times without an `assert`
+ --> tests/ui/missing_asserts_for_indexing_unfixable.rs:77:13
+ |
+LL | let _ = v1[1] + v1[2];
+ | ^^^^^^^^^^^^^
+ |
+ = help: consider asserting the length before indexing: `assert!(v1.len() > 2);`
+note: slice indexed here
+ --> tests/ui/missing_asserts_for_indexing_unfixable.rs:77:13
+ |
+LL | let _ = v1[1] + v1[2];
+ | ^^^^^
+note: slice indexed here
+ --> tests/ui/missing_asserts_for_indexing_unfixable.rs:77:21
+ |
+LL | let _ = v1[1] + v1[2];
+ | ^^^^^
+ = note: asserting the length before indexing will elide bounds checks
+
+error: indexing into a slice multiple times without an `assert`
+ --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:13
+ |
+LL | let _ = v1[0] + v1[1] + v1[2];
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: consider asserting the length before indexing: `assert!(v1.len() > 2);`
+note: slice indexed here
+ --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:13
+ |
+LL | let _ = v1[0] + v1[1] + v1[2];
+ | ^^^^^
+note: slice indexed here
+ --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:21
+ |
+LL | let _ = v1[0] + v1[1] + v1[2];
+ | ^^^^^
+note: slice indexed here
+ --> tests/ui/missing_asserts_for_indexing_unfixable.rs:85:29
+ |
+LL | let _ = v1[0] + v1[1] + v1[2];
+ | ^^^^^
+ = note: asserting the length before indexing will elide bounds checks
+
+error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
index 10df44e..65eb2d5 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.fixed
@@ -144,7 +144,7 @@
#[clippy::msrv = "1.62"]
mod with_extern {
- const extern "C" fn c() {}
+ const unsafe extern "C" fn c() {}
//~^ missing_const_for_fn
#[rustfmt::skip]
@@ -153,7 +153,7 @@
//~^ missing_const_for_fn
// any item functions in extern block won't trigger this lint
- extern "C" {
+ unsafe extern "C" {
fn c_in_block();
}
}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
index bc44b34..3690d2f 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -144,7 +144,7 @@ fn union_access_can_be_const() {
#[clippy::msrv = "1.62"]
mod with_extern {
- extern "C" fn c() {}
+ unsafe extern "C" fn c() {}
//~^ missing_const_for_fn
#[rustfmt::skip]
@@ -153,7 +153,7 @@ extern "C" fn c() {}
//~^ missing_const_for_fn
// any item functions in extern block won't trigger this lint
- extern "C" {
+ unsafe extern "C" {
fn c_in_block();
}
}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
index 5df5a54..10e07d1 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
@@ -212,12 +212,12 @@
error: this could be a `const fn`
--> tests/ui/missing_const_for_fn/could_be_const.rs:147:9
|
-LL | extern "C" fn c() {}
- | ^^^^^^^^^^^^^^^^^^^^
+LL | unsafe extern "C" fn c() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: make the function `const`
|
-LL | const extern "C" fn c() {}
+LL | const unsafe extern "C" fn c() {}
| +++++
error: this could be a `const fn`
diff --git a/src/tools/clippy/tests/ui/missing_panics_doc.rs b/src/tools/clippy/tests/ui/missing_panics_doc.rs
index 95e361c..ffdae85 100644
--- a/src/tools/clippy/tests/ui/missing_panics_doc.rs
+++ b/src/tools/clippy/tests/ui/missing_panics_doc.rs
@@ -151,6 +151,45 @@ pub fn debug_assertions() {
debug_assert_ne!(1, 2);
}
+pub fn partially_const<const N: usize>(n: usize) {
+ //~^ missing_panics_doc
+
+ const {
+ assert!(N > 5);
+ }
+
+ assert!(N > n);
+}
+
+pub fn expect_allow(i: Option<isize>) {
+ #[expect(clippy::missing_panics_doc)]
+ i.unwrap();
+
+ #[allow(clippy::missing_panics_doc)]
+ i.unwrap();
+}
+
+pub fn expect_allow_with_error(i: Option<isize>) {
+ //~^ missing_panics_doc
+
+ #[expect(clippy::missing_panics_doc)]
+ i.unwrap();
+
+ #[allow(clippy::missing_panics_doc)]
+ i.unwrap();
+
+ i.unwrap();
+}
+
+pub fn expect_after_error(x: Option<u32>, y: Option<u32>) {
+ //~^ missing_panics_doc
+
+ let x = x.unwrap();
+
+ #[expect(clippy::missing_panics_doc)]
+ let y = y.unwrap();
+}
+
// all function must be triggered the lint.
// `pub` is required, because the lint does not consider unreachable items
pub mod issue10240 {
diff --git a/src/tools/clippy/tests/ui/missing_panics_doc.stderr b/src/tools/clippy/tests/ui/missing_panics_doc.stderr
index a83e2fa..7f0acf8 100644
--- a/src/tools/clippy/tests/ui/missing_panics_doc.stderr
+++ b/src/tools/clippy/tests/ui/missing_panics_doc.stderr
@@ -73,76 +73,112 @@
| ^^^^^^^^^^^^^^^^
error: docs for function which may panic missing `# Panics` section
- --> tests/ui/missing_panics_doc.rs:157:5
+ --> tests/ui/missing_panics_doc.rs:154:1
+ |
+LL | pub fn partially_const<const N: usize>(n: usize) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: first possible panic found here
+ --> tests/ui/missing_panics_doc.rs:161:5
+ |
+LL | assert!(N > n);
+ | ^^^^^^^^^^^^^^
+
+error: docs for function which may panic missing `# Panics` section
+ --> tests/ui/missing_panics_doc.rs:172:1
+ |
+LL | pub fn expect_allow_with_error(i: Option<isize>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: first possible panic found here
+ --> tests/ui/missing_panics_doc.rs:181:5
+ |
+LL | i.unwrap();
+ | ^^^^^^^^^^
+
+error: docs for function which may panic missing `# Panics` section
+ --> tests/ui/missing_panics_doc.rs:184:1
+ |
+LL | pub fn expect_after_error(x: Option<u32>, y: Option<u32>) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: first possible panic found here
+ --> tests/ui/missing_panics_doc.rs:187:13
+ |
+LL | let x = x.unwrap();
+ | ^^^^^^^^^^
+
+error: docs for function which may panic missing `# Panics` section
+ --> tests/ui/missing_panics_doc.rs:196:5
|
LL | pub fn option_unwrap<T>(v: &[T]) -> &T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first possible panic found here
- --> tests/ui/missing_panics_doc.rs:160:9
+ --> tests/ui/missing_panics_doc.rs:199:9
|
LL | o.unwrap()
| ^^^^^^^^^^
error: docs for function which may panic missing `# Panics` section
- --> tests/ui/missing_panics_doc.rs:163:5
+ --> tests/ui/missing_panics_doc.rs:202:5
|
LL | pub fn option_expect<T>(v: &[T]) -> &T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first possible panic found here
- --> tests/ui/missing_panics_doc.rs:166:9
+ --> tests/ui/missing_panics_doc.rs:205:9
|
LL | o.expect("passed an empty thing")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: docs for function which may panic missing `# Panics` section
- --> tests/ui/missing_panics_doc.rs:169:5
+ --> tests/ui/missing_panics_doc.rs:208:5
|
LL | pub fn result_unwrap<T>(v: &[T]) -> &T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first possible panic found here
- --> tests/ui/missing_panics_doc.rs:172:9
+ --> tests/ui/missing_panics_doc.rs:211:9
|
LL | res.unwrap()
| ^^^^^^^^^^^^
error: docs for function which may panic missing `# Panics` section
- --> tests/ui/missing_panics_doc.rs:175:5
+ --> tests/ui/missing_panics_doc.rs:214:5
|
LL | pub fn result_expect<T>(v: &[T]) -> &T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first possible panic found here
- --> tests/ui/missing_panics_doc.rs:178:9
+ --> tests/ui/missing_panics_doc.rs:217:9
|
LL | res.expect("passed an empty thing")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: docs for function which may panic missing `# Panics` section
- --> tests/ui/missing_panics_doc.rs:181:5
+ --> tests/ui/missing_panics_doc.rs:220:5
|
LL | pub fn last_unwrap(v: &[u32]) -> u32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first possible panic found here
- --> tests/ui/missing_panics_doc.rs:183:10
+ --> tests/ui/missing_panics_doc.rs:222:10
|
LL | *v.last().unwrap()
| ^^^^^^^^^^^^^^^^^
error: docs for function which may panic missing `# Panics` section
- --> tests/ui/missing_panics_doc.rs:186:5
+ --> tests/ui/missing_panics_doc.rs:225:5
|
LL | pub fn last_expect(v: &[u32]) -> u32 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first possible panic found here
- --> tests/ui/missing_panics_doc.rs:188:10
+ --> tests/ui/missing_panics_doc.rs:227:10
|
LL | *v.last().expect("passed an empty thing")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 12 previous errors
+error: aborting due to 15 previous errors
diff --git a/src/tools/clippy/tests/ui/missing_transmute_annotations.fixed b/src/tools/clippy/tests/ui/missing_transmute_annotations.fixed
index a3c94ab..58faeae 100644
--- a/src/tools/clippy/tests/ui/missing_transmute_annotations.fixed
+++ b/src/tools/clippy/tests/ui/missing_transmute_annotations.fixed
@@ -18,8 +18,10 @@
}
unsafe fn foo1() -> i32 {
- // Should not warn!
- std::mem::transmute([1u16, 2u16])
+ unsafe {
+ // Should not warn!
+ std::mem::transmute([1u16, 2u16])
+ }
}
// Should not warn!
@@ -31,33 +33,35 @@
}
unsafe fn foo2() -> i32 {
- let mut i: i32 = 0;
- i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
- //~^ ERROR: transmute used without annotations
- i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
- //~^ ERROR: transmute used without annotations
- i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
- //~^ ERROR: transmute used without annotations
- i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
- //~^ ERROR: transmute used without annotations
+ unsafe {
+ let mut i: i32 = 0;
+ i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
+ //~^ ERROR: transmute used without annotations
+ i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
+ //~^ ERROR: transmute used without annotations
+ i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
+ //~^ ERROR: transmute used without annotations
+ i = std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]);
+ //~^ ERROR: transmute used without annotations
- let x: i32 = bar(std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]));
- //~^ ERROR: transmute used without annotations
- bar(std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]));
- //~^ ERROR: transmute used without annotations
+ let x: i32 = bar(std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]));
+ //~^ ERROR: transmute used without annotations
+ bar(std::mem::transmute::<[u16; 2], i32>([1u16, 2u16]));
+ //~^ ERROR: transmute used without annotations
- i = local_bad_transmute!([1u16, 2u16]);
+ i = local_bad_transmute!([1u16, 2u16]);
- // Should not warn.
- i = bad_transmute!([1u16, 2u16]);
+ // Should not warn.
+ i = bad_transmute!([1u16, 2u16]);
- i = std::mem::transmute::<[i16; 2], i32>([0i16, 0i16]);
- //~^ ERROR: transmute used without annotations
+ i = std::mem::transmute::<[i16; 2], i32>([0i16, 0i16]);
+ //~^ ERROR: transmute used without annotations
- i = std::mem::transmute::<Foo, i32>(Foo::A);
- //~^ ERROR: transmute used without annotations
+ i = std::mem::transmute::<Foo, i32>(Foo::A);
+ //~^ ERROR: transmute used without annotations
- i
+ i
+ }
}
fn main() {
diff --git a/src/tools/clippy/tests/ui/missing_transmute_annotations.rs b/src/tools/clippy/tests/ui/missing_transmute_annotations.rs
index c12e1b0..c9a4c5f 100644
--- a/src/tools/clippy/tests/ui/missing_transmute_annotations.rs
+++ b/src/tools/clippy/tests/ui/missing_transmute_annotations.rs
@@ -18,8 +18,10 @@ fn bar(x: i32) -> i32 {
}
unsafe fn foo1() -> i32 {
- // Should not warn!
- std::mem::transmute([1u16, 2u16])
+ unsafe {
+ // Should not warn!
+ std::mem::transmute([1u16, 2u16])
+ }
}
// Should not warn!
@@ -31,33 +33,35 @@ enum Foo {
}
unsafe fn foo2() -> i32 {
- let mut i: i32 = 0;
- i = std::mem::transmute([1u16, 2u16]);
- //~^ ERROR: transmute used without annotations
- i = std::mem::transmute::<_, _>([1u16, 2u16]);
- //~^ ERROR: transmute used without annotations
- i = std::mem::transmute::<_, i32>([1u16, 2u16]);
- //~^ ERROR: transmute used without annotations
- i = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]);
- //~^ ERROR: transmute used without annotations
+ unsafe {
+ let mut i: i32 = 0;
+ i = std::mem::transmute([1u16, 2u16]);
+ //~^ ERROR: transmute used without annotations
+ i = std::mem::transmute::<_, _>([1u16, 2u16]);
+ //~^ ERROR: transmute used without annotations
+ i = std::mem::transmute::<_, i32>([1u16, 2u16]);
+ //~^ ERROR: transmute used without annotations
+ i = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]);
+ //~^ ERROR: transmute used without annotations
- let x: i32 = bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16]));
- //~^ ERROR: transmute used without annotations
- bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16]));
- //~^ ERROR: transmute used without annotations
+ let x: i32 = bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16]));
+ //~^ ERROR: transmute used without annotations
+ bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16]));
+ //~^ ERROR: transmute used without annotations
- i = local_bad_transmute!([1u16, 2u16]);
+ i = local_bad_transmute!([1u16, 2u16]);
- // Should not warn.
- i = bad_transmute!([1u16, 2u16]);
+ // Should not warn.
+ i = bad_transmute!([1u16, 2u16]);
- i = std::mem::transmute([0i16, 0i16]);
- //~^ ERROR: transmute used without annotations
+ i = std::mem::transmute([0i16, 0i16]);
+ //~^ ERROR: transmute used without annotations
- i = std::mem::transmute(Foo::A);
- //~^ ERROR: transmute used without annotations
+ i = std::mem::transmute(Foo::A);
+ //~^ ERROR: transmute used without annotations
- i
+ i
+ }
}
fn main() {
diff --git a/src/tools/clippy/tests/ui/missing_transmute_annotations.stderr b/src/tools/clippy/tests/ui/missing_transmute_annotations.stderr
index 5903ed4..63f7e28 100644
--- a/src/tools/clippy/tests/ui/missing_transmute_annotations.stderr
+++ b/src/tools/clippy/tests/ui/missing_transmute_annotations.stderr
@@ -1,41 +1,41 @@
error: transmute used without annotations
- --> tests/ui/missing_transmute_annotations.rs:35:19
+ --> tests/ui/missing_transmute_annotations.rs:38:23
|
-LL | i = std::mem::transmute([1u16, 2u16]);
- | ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
+LL | i = std::mem::transmute([1u16, 2u16]);
+ | ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
|
= note: `-D clippy::missing-transmute-annotations` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::missing_transmute_annotations)]`
error: transmute used without annotations
- --> tests/ui/missing_transmute_annotations.rs:37:19
+ --> tests/ui/missing_transmute_annotations.rs:40:23
|
-LL | i = std::mem::transmute::<_, _>([1u16, 2u16]);
- | ^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
+LL | i = std::mem::transmute::<_, _>([1u16, 2u16]);
+ | ^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
error: transmute used without annotations
- --> tests/ui/missing_transmute_annotations.rs:39:19
+ --> tests/ui/missing_transmute_annotations.rs:42:23
|
-LL | i = std::mem::transmute::<_, i32>([1u16, 2u16]);
- | ^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
+LL | i = std::mem::transmute::<_, i32>([1u16, 2u16]);
+ | ^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
error: transmute used without annotations
- --> tests/ui/missing_transmute_annotations.rs:41:19
+ --> tests/ui/missing_transmute_annotations.rs:44:23
|
-LL | i = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]);
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
+LL | i = std::mem::transmute::<[u16; 2], _>([1u16, 2u16]);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
error: transmute used without annotations
- --> tests/ui/missing_transmute_annotations.rs:44:32
+ --> tests/ui/missing_transmute_annotations.rs:47:36
|
-LL | let x: i32 = bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16]));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
+LL | let x: i32 = bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16]));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
error: transmute used without annotations
- --> tests/ui/missing_transmute_annotations.rs:46:19
+ --> tests/ui/missing_transmute_annotations.rs:49:23
|
-LL | bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16]));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
+LL | bar(std::mem::transmute::<[u16; 2], _>([1u16, 2u16]));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
error: transmute used without annotations
--> tests/ui/missing_transmute_annotations.rs:11:19
@@ -43,31 +43,31 @@
LL | std::mem::transmute($e)
| ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
...
-LL | i = local_bad_transmute!([1u16, 2u16]);
- | ---------------------------------- in this macro invocation
+LL | i = local_bad_transmute!([1u16, 2u16]);
+ | ---------------------------------- in this macro invocation
|
= note: this error originates in the macro `local_bad_transmute` (in Nightly builds, run with -Z macro-backtrace for more info)
error: transmute used without annotations
- --> tests/ui/missing_transmute_annotations.rs:54:19
+ --> tests/ui/missing_transmute_annotations.rs:57:23
|
-LL | i = std::mem::transmute([0i16, 0i16]);
- | ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[i16; 2], i32>`
+LL | i = std::mem::transmute([0i16, 0i16]);
+ | ^^^^^^^^^ help: consider adding missing annotations: `transmute::<[i16; 2], i32>`
error: transmute used without annotations
- --> tests/ui/missing_transmute_annotations.rs:57:19
+ --> tests/ui/missing_transmute_annotations.rs:60:23
|
-LL | i = std::mem::transmute(Foo::A);
- | ^^^^^^^^^ help: consider adding missing annotations: `transmute::<Foo, i32>`
+LL | i = std::mem::transmute(Foo::A);
+ | ^^^^^^^^^ help: consider adding missing annotations: `transmute::<Foo, i32>`
error: transmute used without annotations
- --> tests/ui/missing_transmute_annotations.rs:64:35
+ --> tests/ui/missing_transmute_annotations.rs:68:35
|
LL | let x: _ = unsafe { std::mem::transmute::<_, i32>([1u16, 2u16]) };
| ^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
error: transmute used without annotations
- --> tests/ui/missing_transmute_annotations.rs:67:30
+ --> tests/ui/missing_transmute_annotations.rs:71:30
|
LL | let x: _ = std::mem::transmute::<_, i32>([1u16, 2u16]);
| ^^^^^^^^^^^^^^^^^^^ help: consider adding missing annotations: `transmute::<[u16; 2], i32>`
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.fixed b/src/tools/clippy/tests/ui/must_use_candidates.fixed
index b5d356a..4c1d6b1 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.fixed
+++ b/src/tools/clippy/tests/ui/must_use_candidates.fixed
@@ -88,11 +88,13 @@
///
/// Don't ever call this from multiple threads
pub unsafe fn mutates_static() -> usize {
- COUNTER += 1;
- COUNTER
+ unsafe {
+ COUNTER += 1;
+ COUNTER
+ }
}
-#[no_mangle]
+#[unsafe(no_mangle)]
pub extern "C" fn unmangled(i: bool) -> bool {
!i
}
diff --git a/src/tools/clippy/tests/ui/must_use_candidates.rs b/src/tools/clippy/tests/ui/must_use_candidates.rs
index 14ea166..71d5467 100644
--- a/src/tools/clippy/tests/ui/must_use_candidates.rs
+++ b/src/tools/clippy/tests/ui/must_use_candidates.rs
@@ -88,11 +88,13 @@ pub fn inner_types(_m: &MyAtomic) -> bool {
///
/// Don't ever call this from multiple threads
pub unsafe fn mutates_static() -> usize {
- COUNTER += 1;
- COUNTER
+ unsafe {
+ COUNTER += 1;
+ COUNTER
+ }
}
-#[no_mangle]
+#[unsafe(no_mangle)]
pub extern "C" fn unmangled(i: bool) -> bool {
!i
}
diff --git a/src/tools/clippy/tests/ui/mut_from_ref.rs b/src/tools/clippy/tests/ui/mut_from_ref.rs
index b8c10f3..1b0b351 100644
--- a/src/tools/clippy/tests/ui/mut_from_ref.rs
+++ b/src/tools/clippy/tests/ui/mut_from_ref.rs
@@ -1,4 +1,10 @@
-#![allow(unused, clippy::needless_lifetimes, clippy::needless_pass_by_ref_mut)]
+#![allow(
+ unused,
+ clippy::needless_lifetimes,
+ clippy::needless_pass_by_ref_mut,
+ clippy::redundant_allocation,
+ clippy::boxed_local
+)]
#![warn(clippy::mut_from_ref)]
struct Foo;
@@ -40,6 +46,18 @@ fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 {
unsafe { unimplemented!() }
}
+fn fail_tuples<'a>(x: (&'a u32, &'a u32)) -> &'a mut u32 {
+ //~^ mut_from_ref
+
+ unsafe { unimplemented!() }
+}
+
+fn fail_box<'a>(x: Box<&'a u32>) -> &'a mut u32 {
+ //~^ mut_from_ref
+
+ unsafe { unimplemented!() }
+}
+
// this is OK, because the result borrows y
fn works<'a>(x: &u32, y: &'a mut u32) -> &'a mut u32 {
unsafe { unimplemented!() }
@@ -50,6 +68,20 @@ fn also_works<'a>(x: &'a u32, y: &'a mut u32) -> &'a mut u32 {
unsafe { unimplemented!() }
}
+fn works_tuples<'a>(x: (&'a u32, &'a mut u32)) -> &'a mut u32 {
+ unsafe { unimplemented!() }
+}
+
+fn works_box<'a>(x: &'a u32, y: Box<&'a mut u32>) -> &'a mut u32 {
+ unsafe { unimplemented!() }
+}
+
+struct RefMut<'a>(&'a mut u32);
+
+fn works_parameter<'a>(x: &'a u32, y: RefMut<'a>) -> &'a mut u32 {
+ unsafe { unimplemented!() }
+}
+
unsafe fn also_broken(x: &u32) -> &mut u32 {
//~^ mut_from_ref
diff --git a/src/tools/clippy/tests/ui/mut_from_ref.stderr b/src/tools/clippy/tests/ui/mut_from_ref.stderr
index 8c3c8e0..0974268 100644
--- a/src/tools/clippy/tests/ui/mut_from_ref.stderr
+++ b/src/tools/clippy/tests/ui/mut_from_ref.stderr
@@ -1,11 +1,11 @@
error: mutable borrow from immutable input(s)
- --> tests/ui/mut_from_ref.rs:7:39
+ --> tests/ui/mut_from_ref.rs:13:39
|
LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo {
| ^^^^^^^^
|
note: immutable borrow here
- --> tests/ui/mut_from_ref.rs:7:29
+ --> tests/ui/mut_from_ref.rs:13:29
|
LL | fn this_wont_hurt_a_bit(&self) -> &mut Foo {
| ^^^^^
@@ -13,64 +13,88 @@
= help: to override `-D warnings` add `#[allow(clippy::mut_from_ref)]`
error: mutable borrow from immutable input(s)
- --> tests/ui/mut_from_ref.rs:15:25
+ --> tests/ui/mut_from_ref.rs:21:25
|
LL | fn ouch(x: &Foo) -> &mut Foo;
| ^^^^^^^^
|
note: immutable borrow here
- --> tests/ui/mut_from_ref.rs:15:16
+ --> tests/ui/mut_from_ref.rs:21:16
|
LL | fn ouch(x: &Foo) -> &mut Foo;
| ^^^^
error: mutable borrow from immutable input(s)
- --> tests/ui/mut_from_ref.rs:25:21
+ --> tests/ui/mut_from_ref.rs:31:21
|
LL | fn fail(x: &u32) -> &mut u16 {
| ^^^^^^^^
|
note: immutable borrow here
- --> tests/ui/mut_from_ref.rs:25:12
+ --> tests/ui/mut_from_ref.rs:31:12
|
LL | fn fail(x: &u32) -> &mut u16 {
| ^^^^
error: mutable borrow from immutable input(s)
- --> tests/ui/mut_from_ref.rs:31:50
+ --> tests/ui/mut_from_ref.rs:37:50
|
LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 {
| ^^^^^^^^^^^
|
note: immutable borrow here
- --> tests/ui/mut_from_ref.rs:31:25
+ --> tests/ui/mut_from_ref.rs:37:25
|
LL | fn fail_lifetime<'a>(x: &'a u32, y: &mut u32) -> &'a mut u32 {
| ^^^^^^^
error: mutable borrow from immutable input(s)
- --> tests/ui/mut_from_ref.rs:37:67
+ --> tests/ui/mut_from_ref.rs:43:67
|
LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 {
| ^^^^^^^^^^^
|
note: immutable borrow here
- --> tests/ui/mut_from_ref.rs:37:27
+ --> tests/ui/mut_from_ref.rs:43:27
|
LL | fn fail_double<'a, 'b>(x: &'a u32, y: &'a u32, z: &'b mut u32) -> &'a mut u32 {
| ^^^^^^^ ^^^^^^^
error: mutable borrow from immutable input(s)
- --> tests/ui/mut_from_ref.rs:53:35
+ --> tests/ui/mut_from_ref.rs:49:46
+ |
+LL | fn fail_tuples<'a>(x: (&'a u32, &'a u32)) -> &'a mut u32 {
+ | ^^^^^^^^^^^
+ |
+note: immutable borrow here
+ --> tests/ui/mut_from_ref.rs:49:24
+ |
+LL | fn fail_tuples<'a>(x: (&'a u32, &'a u32)) -> &'a mut u32 {
+ | ^^^^^^^ ^^^^^^^
+
+error: mutable borrow from immutable input(s)
+ --> tests/ui/mut_from_ref.rs:55:37
+ |
+LL | fn fail_box<'a>(x: Box<&'a u32>) -> &'a mut u32 {
+ | ^^^^^^^^^^^
+ |
+note: immutable borrow here
+ --> tests/ui/mut_from_ref.rs:55:24
+ |
+LL | fn fail_box<'a>(x: Box<&'a u32>) -> &'a mut u32 {
+ | ^^^^^^^
+
+error: mutable borrow from immutable input(s)
+ --> tests/ui/mut_from_ref.rs:85:35
|
LL | unsafe fn also_broken(x: &u32) -> &mut u32 {
| ^^^^^^^^
|
note: immutable borrow here
- --> tests/ui/mut_from_ref.rs:53:26
+ --> tests/ui/mut_from_ref.rs:85:26
|
LL | unsafe fn also_broken(x: &u32) -> &mut u32 {
| ^^^^
-error: aborting due to 6 previous errors
+error: aborting due to 8 previous errors
diff --git a/src/tools/clippy/tests/ui/mutex_atomic.rs b/src/tools/clippy/tests/ui/mutex_atomic.rs
index 80a712a..7db5c9f 100644
--- a/src/tools/clippy/tests/ui/mutex_atomic.rs
+++ b/src/tools/clippy/tests/ui/mutex_atomic.rs
@@ -1,4 +1,3 @@
-#![warn(clippy::all)]
#![warn(clippy::mutex_integer)]
#![warn(clippy::mutex_atomic)]
#![allow(clippy::borrow_as_ptr)]
diff --git a/src/tools/clippy/tests/ui/mutex_atomic.stderr b/src/tools/clippy/tests/ui/mutex_atomic.stderr
index 838fc1d..a6d5d60 100644
--- a/src/tools/clippy/tests/ui/mutex_atomic.stderr
+++ b/src/tools/clippy/tests/ui/mutex_atomic.stderr
@@ -1,5 +1,5 @@
error: consider using an `AtomicBool` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
- --> tests/ui/mutex_atomic.rs:8:5
+ --> tests/ui/mutex_atomic.rs:7:5
|
LL | Mutex::new(true);
| ^^^^^^^^^^^^^^^^
@@ -8,31 +8,31 @@
= help: to override `-D warnings` add `#[allow(clippy::mutex_atomic)]`
error: consider using an `AtomicUsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
- --> tests/ui/mutex_atomic.rs:11:5
+ --> tests/ui/mutex_atomic.rs:10:5
|
LL | Mutex::new(5usize);
| ^^^^^^^^^^^^^^^^^^
error: consider using an `AtomicIsize` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
- --> tests/ui/mutex_atomic.rs:14:5
+ --> tests/ui/mutex_atomic.rs:13:5
|
LL | Mutex::new(9isize);
| ^^^^^^^^^^^^^^^^^^
error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
- --> tests/ui/mutex_atomic.rs:18:5
+ --> tests/ui/mutex_atomic.rs:17:5
|
LL | Mutex::new(&x as *const u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: consider using an `AtomicPtr` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
- --> tests/ui/mutex_atomic.rs:21:5
+ --> tests/ui/mutex_atomic.rs:20:5
|
LL | Mutex::new(&mut x as *mut u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: consider using an `AtomicU32` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
- --> tests/ui/mutex_atomic.rs:24:5
+ --> tests/ui/mutex_atomic.rs:23:5
|
LL | Mutex::new(0u32);
| ^^^^^^^^^^^^^^^^
@@ -41,31 +41,31 @@
= help: to override `-D warnings` add `#[allow(clippy::mutex_integer)]`
error: consider using an `AtomicI32` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
- --> tests/ui/mutex_atomic.rs:27:5
+ --> tests/ui/mutex_atomic.rs:26:5
|
LL | Mutex::new(0i32);
| ^^^^^^^^^^^^^^^^
error: consider using an `AtomicU8` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
- --> tests/ui/mutex_atomic.rs:31:5
+ --> tests/ui/mutex_atomic.rs:30:5
|
LL | Mutex::new(0u8);
| ^^^^^^^^^^^^^^^
error: consider using an `AtomicI16` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
- --> tests/ui/mutex_atomic.rs:34:5
+ --> tests/ui/mutex_atomic.rs:33:5
|
LL | Mutex::new(0i16);
| ^^^^^^^^^^^^^^^^
error: consider using an `AtomicI8` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
- --> tests/ui/mutex_atomic.rs:37:25
+ --> tests/ui/mutex_atomic.rs:36:25
|
LL | let _x: Mutex<i8> = Mutex::new(0);
| ^^^^^^^^^^^^^
error: consider using an `AtomicI64` instead of a `Mutex` here; if you just want the locking behavior and not the internal type, consider using `Mutex<()>`
- --> tests/ui/mutex_atomic.rs:41:5
+ --> tests/ui/mutex_atomic.rs:40:5
|
LL | Mutex::new(X);
| ^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed b/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed
index e4504bc..84924ca 100644
--- a/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed
@@ -89,7 +89,7 @@
tuple_struct: TupleStruct,
s: Struct,
) {
- if let [ref a] = slice {}
+ if let [a] = slice {}
if let &[ref a, b] = slice {}
if let &[ref a, .., b] = slice {}
diff --git a/src/tools/clippy/tests/ui/needless_borrowed_ref.rs b/src/tools/clippy/tests/ui/needless_borrowed_ref.rs
index 7edfda6..280cef4 100644
--- a/src/tools/clippy/tests/ui/needless_borrowed_ref.rs
+++ b/src/tools/clippy/tests/ui/needless_borrowed_ref.rs
@@ -89,7 +89,7 @@ fn should_not_lint(
tuple_struct: TupleStruct,
s: Struct,
) {
- if let [ref a] = slice {}
+ if let [a] = slice {}
if let &[ref a, b] = slice {}
if let &[ref a, .., b] = slice {}
diff --git a/src/tools/clippy/tests/ui/needless_collect.fixed b/src/tools/clippy/tests/ui/needless_collect.fixed
index 6551fa5..b09efe9 100644
--- a/src/tools/clippy/tests/ui/needless_collect.fixed
+++ b/src/tools/clippy/tests/ui/needless_collect.fixed
@@ -126,3 +126,87 @@
fn foo(_: impl IntoIterator<Item = usize>) {}
fn bar<I: IntoIterator<Item = usize>>(_: Vec<usize>, _: I) {}
fn baz<I: IntoIterator<Item = usize>>(_: I, _: (), _: impl IntoIterator<Item = char>) {}
+
+mod issue9191 {
+ use std::cell::Cell;
+ use std::collections::HashSet;
+ use std::hash::Hash;
+ use std::marker::PhantomData;
+ use std::ops::Deref;
+
+ fn captures_ref_mut(xs: Vec<i32>, mut ys: HashSet<i32>) {
+ if xs.iter().map(|x| ys.remove(x)).collect::<Vec<_>>().contains(&true) {
+ todo!()
+ }
+ }
+
+ #[derive(Debug, Clone)]
+ struct MyRef<'a>(PhantomData<&'a mut Cell<HashSet<i32>>>, *mut Cell<HashSet<i32>>);
+
+ impl MyRef<'_> {
+ fn new(target: &mut Cell<HashSet<i32>>) -> Self {
+ MyRef(PhantomData, target)
+ }
+
+ fn get(&mut self) -> &mut Cell<HashSet<i32>> {
+ unsafe { &mut *self.1 }
+ }
+ }
+
+ fn captures_phantom(xs: Vec<i32>, mut ys: Cell<HashSet<i32>>) {
+ let mut ys_ref = MyRef::new(&mut ys);
+ if xs
+ .iter()
+ .map({
+ let mut ys_ref = ys_ref.clone();
+ move |x| ys_ref.get().get_mut().remove(x)
+ })
+ .collect::<Vec<_>>()
+ .contains(&true)
+ {
+ todo!()
+ }
+ }
+}
+
+pub fn issue8055(v: impl IntoIterator<Item = i32>) -> Result<impl Iterator<Item = i32>, usize> {
+ let mut zeros = 0;
+
+ let res: Vec<_> = v
+ .into_iter()
+ .filter(|i| {
+ if *i == 0 {
+ zeros += 1
+ };
+ *i != 0
+ })
+ .collect();
+
+ if zeros != 0 {
+ return Err(zeros);
+ }
+ Ok(res.into_iter())
+}
+
+mod issue8055_regression {
+ struct Foo<T> {
+ inner: T,
+ marker: core::marker::PhantomData<Self>,
+ }
+
+ impl<T: Iterator> Iterator for Foo<T> {
+ type Item = T::Item;
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner.next()
+ }
+ }
+
+ fn foo() {
+ Foo {
+ inner: [].iter(),
+ marker: core::marker::PhantomData,
+ }
+ .collect::<Vec<&i32>>()
+ .len();
+ }
+}
diff --git a/src/tools/clippy/tests/ui/needless_collect.rs b/src/tools/clippy/tests/ui/needless_collect.rs
index 973c41c..da41829 100644
--- a/src/tools/clippy/tests/ui/needless_collect.rs
+++ b/src/tools/clippy/tests/ui/needless_collect.rs
@@ -126,3 +126,87 @@ fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
fn foo(_: impl IntoIterator<Item = usize>) {}
fn bar<I: IntoIterator<Item = usize>>(_: Vec<usize>, _: I) {}
fn baz<I: IntoIterator<Item = usize>>(_: I, _: (), _: impl IntoIterator<Item = char>) {}
+
+mod issue9191 {
+ use std::cell::Cell;
+ use std::collections::HashSet;
+ use std::hash::Hash;
+ use std::marker::PhantomData;
+ use std::ops::Deref;
+
+ fn captures_ref_mut(xs: Vec<i32>, mut ys: HashSet<i32>) {
+ if xs.iter().map(|x| ys.remove(x)).collect::<Vec<_>>().contains(&true) {
+ todo!()
+ }
+ }
+
+ #[derive(Debug, Clone)]
+ struct MyRef<'a>(PhantomData<&'a mut Cell<HashSet<i32>>>, *mut Cell<HashSet<i32>>);
+
+ impl MyRef<'_> {
+ fn new(target: &mut Cell<HashSet<i32>>) -> Self {
+ MyRef(PhantomData, target)
+ }
+
+ fn get(&mut self) -> &mut Cell<HashSet<i32>> {
+ unsafe { &mut *self.1 }
+ }
+ }
+
+ fn captures_phantom(xs: Vec<i32>, mut ys: Cell<HashSet<i32>>) {
+ let mut ys_ref = MyRef::new(&mut ys);
+ if xs
+ .iter()
+ .map({
+ let mut ys_ref = ys_ref.clone();
+ move |x| ys_ref.get().get_mut().remove(x)
+ })
+ .collect::<Vec<_>>()
+ .contains(&true)
+ {
+ todo!()
+ }
+ }
+}
+
+pub fn issue8055(v: impl IntoIterator<Item = i32>) -> Result<impl Iterator<Item = i32>, usize> {
+ let mut zeros = 0;
+
+ let res: Vec<_> = v
+ .into_iter()
+ .filter(|i| {
+ if *i == 0 {
+ zeros += 1
+ };
+ *i != 0
+ })
+ .collect();
+
+ if zeros != 0 {
+ return Err(zeros);
+ }
+ Ok(res.into_iter())
+}
+
+mod issue8055_regression {
+ struct Foo<T> {
+ inner: T,
+ marker: core::marker::PhantomData<Self>,
+ }
+
+ impl<T: Iterator> Iterator for Foo<T> {
+ type Item = T::Item;
+ fn next(&mut self) -> Option<Self::Item> {
+ self.inner.next()
+ }
+ }
+
+ fn foo() {
+ Foo {
+ inner: [].iter(),
+ marker: core::marker::PhantomData,
+ }
+ .collect::<Vec<&i32>>()
+ .len();
+ }
+}
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.fixed b/src/tools/clippy/tests/ui/needless_lifetimes.fixed
index d59393f..e9d8119 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.fixed
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.fixed
@@ -534,4 +534,11 @@
impl<'a, T: 'a> Generic<T> {}
}
+pub fn issue14607<'s>(x: &'s u8) {
+ #[expect(clippy::redundant_closure_call)]
+ (|| {
+ let _: &'s u8 = x;
+ })();
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs
index e24907a..0b6eb97 100644
--- a/src/tools/clippy/tests/ui/needless_lifetimes.rs
+++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs
@@ -534,4 +534,11 @@ mod issue13749bis {
impl<'a, T: 'a> Generic<T> {}
}
+pub fn issue14607<'s>(x: &'s u8) {
+ #[expect(clippy::redundant_closure_call)]
+ (|| {
+ let _: &'s u8 = x;
+ })();
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
index f0c5a71..bdad3e3 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
@@ -1,8 +1,9 @@
#![allow(
clippy::if_same_then_else,
clippy::no_effect,
+ clippy::ptr_arg,
clippy::redundant_closure_call,
- clippy::ptr_arg
+ clippy::uninlined_format_args
)]
#![warn(clippy::needless_pass_by_ref_mut)]
//@no-rustfix
@@ -300,7 +301,7 @@ struct Data<T: ?Sized> {
}
// Unsafe functions should not warn.
unsafe fn get_mut_unchecked<T>(ptr: &mut NonNull<Data<T>>) -> &mut T {
- &mut (*ptr.as_ptr()).value
+ unsafe { &mut (*ptr.as_ptr()).value }
}
// Unsafe blocks should not warn.
fn get_mut_unchecked2<T>(ptr: &mut NonNull<Data<T>>) -> &mut T {
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
index 6637a25..94d98f0 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
@@ -1,5 +1,5 @@
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:11:11
+ --> tests/ui/needless_pass_by_ref_mut.rs:12:11
|
LL | fn foo(s: &mut Vec<u32>, b: &u32, x: &mut u32) {
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
@@ -8,79 +8,79 @@
= help: to override `-D warnings` add `#[allow(clippy::needless_pass_by_ref_mut)]`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:37:12
+ --> tests/ui/needless_pass_by_ref_mut.rs:38:12
|
LL | fn foo6(s: &mut Vec<u32>) {
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<u32>`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:48:12
+ --> tests/ui/needless_pass_by_ref_mut.rs:49:12
|
LL | fn bar(&mut self) {}
| ^^^^^^^^^ help: consider changing to: `&self`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:51:29
+ --> tests/ui/needless_pass_by_ref_mut.rs:52:29
|
LL | fn mushroom(&self, vec: &mut Vec<i32>) -> usize {
| ^^^^^^^^^^^^^ help: consider changing to: `&Vec<i32>`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:129:16
+ --> tests/ui/needless_pass_by_ref_mut.rs:130:16
|
LL | async fn a1(x: &mut i32) {
| ^^^^^^^^ help: consider changing to: `&i32`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:134:16
+ --> tests/ui/needless_pass_by_ref_mut.rs:135:16
|
LL | async fn a2(x: &mut i32, y: String) {
| ^^^^^^^^ help: consider changing to: `&i32`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:139:16
+ --> tests/ui/needless_pass_by_ref_mut.rs:140:16
|
LL | async fn a3(x: &mut i32, y: String, z: String) {
| ^^^^^^^^ help: consider changing to: `&i32`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:144:16
+ --> tests/ui/needless_pass_by_ref_mut.rs:145:16
|
LL | async fn a4(x: &mut i32, y: i32) {
| ^^^^^^^^ help: consider changing to: `&i32`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:149:24
+ --> tests/ui/needless_pass_by_ref_mut.rs:150:24
|
LL | async fn a5(x: i32, y: &mut i32) {
| ^^^^^^^^ help: consider changing to: `&i32`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:154:24
+ --> tests/ui/needless_pass_by_ref_mut.rs:155:24
|
LL | async fn a6(x: i32, y: &mut i32) {
| ^^^^^^^^ help: consider changing to: `&i32`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:159:32
+ --> tests/ui/needless_pass_by_ref_mut.rs:160:32
|
LL | async fn a7(x: i32, y: i32, z: &mut i32) {
| ^^^^^^^^ help: consider changing to: `&i32`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:164:24
+ --> tests/ui/needless_pass_by_ref_mut.rs:165:24
|
LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
| ^^^^^^^^ help: consider changing to: `&i32`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:164:45
+ --> tests/ui/needless_pass_by_ref_mut.rs:165:45
|
LL | async fn a8(x: i32, a: &mut i32, y: i32, z: &mut i32) {
| ^^^^^^^^ help: consider changing to: `&i32`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:200:16
+ --> tests/ui/needless_pass_by_ref_mut.rs:201:16
|
LL | fn cfg_warn(s: &mut u32) {}
| ^^^^^^^^ help: consider changing to: `&u32`
@@ -88,7 +88,7 @@
= note: this is cfg-gated and may require further changes
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:205:20
+ --> tests/ui/needless_pass_by_ref_mut.rs:206:20
|
LL | fn cfg_warn(s: &mut u32) {}
| ^^^^^^^^ help: consider changing to: `&u32`
@@ -96,115 +96,115 @@
= note: this is cfg-gated and may require further changes
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:218:39
+ --> tests/ui/needless_pass_by_ref_mut.rs:219:39
|
LL | async fn inner_async2(x: &mut i32, y: &mut u32) {
| ^^^^^^^^ help: consider changing to: `&u32`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:227:26
+ --> tests/ui/needless_pass_by_ref_mut.rs:228:26
|
LL | async fn inner_async3(x: &mut i32, y: &mut u32) {
| ^^^^^^^^ help: consider changing to: `&i32`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:247:30
+ --> tests/ui/needless_pass_by_ref_mut.rs:248:30
|
LL | async fn call_in_closure1(n: &mut str) {
| ^^^^^^^^ help: consider changing to: `&str`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:267:16
+ --> tests/ui/needless_pass_by_ref_mut.rs:268:16
|
LL | fn closure2(n: &mut usize) -> impl '_ + FnMut() -> usize {
| ^^^^^^^^^^ help: consider changing to: `&usize`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:279:22
+ --> tests/ui/needless_pass_by_ref_mut.rs:280:22
|
LL | async fn closure4(n: &mut usize) {
| ^^^^^^^^^^ help: consider changing to: `&usize`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:334:12
+ --> tests/ui/needless_pass_by_ref_mut.rs:335:12
|
LL | fn bar(&mut self) {}
| ^^^^^^^^^ help: consider changing to: `&self`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:337:18
+ --> tests/ui/needless_pass_by_ref_mut.rs:338:18
|
LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) {
| ^^^^^^^^^ help: consider changing to: `&self`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:337:45
+ --> tests/ui/needless_pass_by_ref_mut.rs:338:45
|
LL | async fn foo(&mut self, u: &mut i32, v: &mut u32) {
| ^^^^^^^^ help: consider changing to: `&u32`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:346:46
+ --> tests/ui/needless_pass_by_ref_mut.rs:347:46
|
LL | async fn foo2(&mut self, u: &mut i32, v: &mut u32) {
| ^^^^^^^^ help: consider changing to: `&u32`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:363:18
+ --> tests/ui/needless_pass_by_ref_mut.rs:364:18
|
LL | fn _empty_tup(x: &mut (())) {}
| ^^^^^^^^^ help: consider changing to: `&()`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:365:19
+ --> tests/ui/needless_pass_by_ref_mut.rs:366:19
|
LL | fn _single_tup(x: &mut ((i32,))) {}
| ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:367:18
+ --> tests/ui/needless_pass_by_ref_mut.rs:368:18
|
LL | fn _multi_tup(x: &mut ((i32, u32))) {}
| ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:369:11
+ --> tests/ui/needless_pass_by_ref_mut.rs:370:11
|
LL | fn _fn(x: &mut (fn())) {}
| ^^^^^^^^^^^ help: consider changing to: `&fn()`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:372:23
+ --> tests/ui/needless_pass_by_ref_mut.rs:373:23
|
LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:374:20
+ --> tests/ui/needless_pass_by_ref_mut.rs:375:20
|
LL | fn _extern_c_fn(x: &mut extern "C" fn()) {}
| ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:376:18
+ --> tests/ui/needless_pass_by_ref_mut.rs:377:18
|
LL | fn _unsafe_fn(x: &mut unsafe fn()) {}
| ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:378:25
+ --> tests/ui/needless_pass_by_ref_mut.rs:379:25
|
LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:380:20
+ --> tests/ui/needless_pass_by_ref_mut.rs:381:20
|
LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)`
error: this argument is a mutable reference, but not used mutably
- --> tests/ui/needless_pass_by_ref_mut.rs:382:20
+ --> tests/ui/needless_pass_by_ref_mut.rs:383:20
|
LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)`
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut_2021.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut_2021.rs
new file mode 100644
index 0000000..994eba9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut_2021.rs
@@ -0,0 +1,12 @@
+//@edition: 2021
+//@check-pass
+#![warn(clippy::needless_pass_by_ref_mut)]
+
+struct Data<T: ?Sized> {
+ value: T,
+}
+
+// Unsafe functions should not warn.
+unsafe fn get_mut_unchecked<T>(ptr: &mut std::ptr::NonNull<Data<T>>) -> &mut T {
+ &mut (*ptr.as_ptr()).value
+}
diff --git a/src/tools/clippy/tests/ui/neg_multiply.fixed b/src/tools/clippy/tests/ui/neg_multiply.fixed
index 9954704..ff6e083 100644
--- a/src/tools/clippy/tests/ui/neg_multiply.fixed
+++ b/src/tools/clippy/tests/ui/neg_multiply.fixed
@@ -53,3 +53,32 @@
X * -1; // should be ok
-1 * X; // should also be ok
}
+
+fn float() {
+ let x = 0.0;
+
+ -x;
+ //~^ neg_multiply
+
+ -x;
+ //~^ neg_multiply
+
+ 100.0 + -x;
+ //~^ neg_multiply
+
+ -(100.0 + x);
+ //~^ neg_multiply
+
+ -17.0;
+ //~^ neg_multiply
+
+ 0.0 + -0.0;
+ //~^ neg_multiply
+
+ -(3.0_f32 as f64);
+ //~^ neg_multiply
+ -(3.0_f32 as f64);
+ //~^ neg_multiply
+
+ -1.0 * -1.0; // should be ok
+}
diff --git a/src/tools/clippy/tests/ui/neg_multiply.rs b/src/tools/clippy/tests/ui/neg_multiply.rs
index 95b94e2..b0f4e85 100644
--- a/src/tools/clippy/tests/ui/neg_multiply.rs
+++ b/src/tools/clippy/tests/ui/neg_multiply.rs
@@ -53,3 +53,32 @@ fn main() {
X * -1; // should be ok
-1 * X; // should also be ok
}
+
+fn float() {
+ let x = 0.0;
+
+ x * -1.0;
+ //~^ neg_multiply
+
+ -1.0 * x;
+ //~^ neg_multiply
+
+ 100.0 + x * -1.0;
+ //~^ neg_multiply
+
+ (100.0 + x) * -1.0;
+ //~^ neg_multiply
+
+ -1.0 * 17.0;
+ //~^ neg_multiply
+
+ 0.0 + 0.0 * -1.0;
+ //~^ neg_multiply
+
+ 3.0_f32 as f64 * -1.0;
+ //~^ neg_multiply
+ (3.0_f32 as f64) * -1.0;
+ //~^ neg_multiply
+
+ -1.0 * -1.0; // should be ok
+}
diff --git a/src/tools/clippy/tests/ui/neg_multiply.stderr b/src/tools/clippy/tests/ui/neg_multiply.stderr
index 9efa5d3..2ef7e32 100644
--- a/src/tools/clippy/tests/ui/neg_multiply.stderr
+++ b/src/tools/clippy/tests/ui/neg_multiply.stderr
@@ -49,5 +49,53 @@
LL | (3_usize as i32) * -1;
| ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `-(3_usize as i32)`
-error: aborting due to 8 previous errors
+error: this multiplication by -1 can be written more succinctly
+ --> tests/ui/neg_multiply.rs:60:5
+ |
+LL | x * -1.0;
+ | ^^^^^^^^ help: consider using: `-x`
+
+error: this multiplication by -1 can be written more succinctly
+ --> tests/ui/neg_multiply.rs:63:5
+ |
+LL | -1.0 * x;
+ | ^^^^^^^^ help: consider using: `-x`
+
+error: this multiplication by -1 can be written more succinctly
+ --> tests/ui/neg_multiply.rs:66:13
+ |
+LL | 100.0 + x * -1.0;
+ | ^^^^^^^^ help: consider using: `-x`
+
+error: this multiplication by -1 can be written more succinctly
+ --> tests/ui/neg_multiply.rs:69:5
+ |
+LL | (100.0 + x) * -1.0;
+ | ^^^^^^^^^^^^^^^^^^ help: consider using: `-(100.0 + x)`
+
+error: this multiplication by -1 can be written more succinctly
+ --> tests/ui/neg_multiply.rs:72:5
+ |
+LL | -1.0 * 17.0;
+ | ^^^^^^^^^^^ help: consider using: `-17.0`
+
+error: this multiplication by -1 can be written more succinctly
+ --> tests/ui/neg_multiply.rs:75:11
+ |
+LL | 0.0 + 0.0 * -1.0;
+ | ^^^^^^^^^^ help: consider using: `-0.0`
+
+error: this multiplication by -1 can be written more succinctly
+ --> tests/ui/neg_multiply.rs:78:5
+ |
+LL | 3.0_f32 as f64 * -1.0;
+ | ^^^^^^^^^^^^^^^^^^^^^ help: consider using: `-(3.0_f32 as f64)`
+
+error: this multiplication by -1 can be written more succinctly
+ --> tests/ui/neg_multiply.rs:80:5
+ |
+LL | (3.0_f32 as f64) * -1.0;
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `-(3.0_f32 as f64)`
+
+error: aborting due to 16 previous errors
diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs
index 0d09b3cee..f4248ff 100644
--- a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs
+++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs
@@ -43,7 +43,7 @@ extern "C" fn c_abi_fn(arg_one: u32, arg_two: usize) {}
extern "C" fn c_abi_fn_again(arg_one: u32, arg_two: usize) {}
-extern "C" {
+unsafe extern "C" {
fn c_abi_in_block(arg_one: u32, arg_two: usize);
}
diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed
index 8774c66..23dbee5 100644
--- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.fixed
@@ -162,3 +162,36 @@
return Some(self.cmp(other));
}
}
+
+// #13640, do not lint
+
+#[derive(Eq, PartialEq)]
+struct J(u32);
+
+impl Ord for J {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for J {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.cmp(other).into()
+ }
+}
+
+// #13640, check that a simple `.into()` does not obliterate the lint
+
+#[derive(Eq, PartialEq)]
+struct K(u32);
+
+impl Ord for K {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for K {
+ //~^ non_canonical_partial_ord_impl
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
+}
diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs
index 568b97c..12f055a 100644
--- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.rs
@@ -166,3 +166,38 @@ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
return Some(self.cmp(other));
}
}
+
+// #13640, do not lint
+
+#[derive(Eq, PartialEq)]
+struct J(u32);
+
+impl Ord for J {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for J {
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ self.cmp(other).into()
+ }
+}
+
+// #13640, check that a simple `.into()` does not obliterate the lint
+
+#[derive(Eq, PartialEq)]
+struct K(u32);
+
+impl Ord for K {
+ fn cmp(&self, other: &Self) -> Ordering {
+ todo!();
+ }
+}
+
+impl PartialOrd for K {
+ //~^ non_canonical_partial_ord_impl
+ fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ Ordering::Greater.into()
+ }
+}
diff --git a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr
index 86845df..c7de968 100644
--- a/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr
+++ b/src/tools/clippy/tests/ui/non_canonical_partial_ord_impl.stderr
@@ -31,5 +31,18 @@
LL + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
|
-error: aborting due to 2 previous errors
+error: non-canonical implementation of `partial_cmp` on an `Ord` type
+ --> tests/ui/non_canonical_partial_ord_impl.rs:198:1
+ |
+LL | / impl PartialOrd for K {
+LL | |
+LL | | fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+ | | _____________________________________________________________-
+LL | || Ordering::Greater.into()
+LL | || }
+ | ||_____- help: change this to: `{ Some(self.cmp(other)) }`
+LL | | }
+ | |__^
+
+error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/non_expressive_names.rs b/src/tools/clippy/tests/ui/non_expressive_names.rs
index b772c75..3f34dff 100644
--- a/src/tools/clippy/tests/ui/non_expressive_names.rs
+++ b/src/tools/clippy/tests/ui/non_expressive_names.rs
@@ -1,5 +1,4 @@
-#![warn(clippy::all)]
-#![allow(unused, clippy::println_empty_string, non_snake_case, clippy::let_unit_value)]
+#![allow(clippy::println_empty_string, non_snake_case, clippy::let_unit_value)]
#[derive(Clone, Debug)]
enum MaybeInst {
diff --git a/src/tools/clippy/tests/ui/non_expressive_names.stderr b/src/tools/clippy/tests/ui/non_expressive_names.stderr
index 3bd77a7..11b12d2 100644
--- a/src/tools/clippy/tests/ui/non_expressive_names.stderr
+++ b/src/tools/clippy/tests/ui/non_expressive_names.stderr
@@ -1,5 +1,5 @@
error: consider choosing a more descriptive name
- --> tests/ui/non_expressive_names.rs:28:9
+ --> tests/ui/non_expressive_names.rs:27:9
|
LL | let _1 = 1;
| ^^
@@ -8,31 +8,31 @@
= help: to override `-D warnings` add `#[allow(clippy::just_underscores_and_digits)]`
error: consider choosing a more descriptive name
- --> tests/ui/non_expressive_names.rs:30:9
+ --> tests/ui/non_expressive_names.rs:29:9
|
LL | let ____1 = 1;
| ^^^^^
error: consider choosing a more descriptive name
- --> tests/ui/non_expressive_names.rs:32:9
+ --> tests/ui/non_expressive_names.rs:31:9
|
LL | let __1___2 = 12;
| ^^^^^^^
error: consider choosing a more descriptive name
- --> tests/ui/non_expressive_names.rs:54:13
+ --> tests/ui/non_expressive_names.rs:53:13
|
LL | let _1 = 1;
| ^^
error: consider choosing a more descriptive name
- --> tests/ui/non_expressive_names.rs:56:13
+ --> tests/ui/non_expressive_names.rs:55:13
|
LL | let ____1 = 1;
| ^^^^^
error: consider choosing a more descriptive name
- --> tests/ui/non_expressive_names.rs:58:13
+ --> tests/ui/non_expressive_names.rs:57:13
|
LL | let __1___2 = 12;
| ^^^^^^^
diff --git a/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs b/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs
index 046ea70..31778f7 100644
--- a/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/tests/ui/non_send_fields_in_send_ty.rs
@@ -35,7 +35,7 @@ unsafe impl<RC, T: Send> Send for ArcGuard<RC, T> {}
//~^ ERROR: some fields in `ArcGuard<RC, T>` are not safe to be sent to another thread
// rusb / RUSTSEC-2020-0098
-extern "C" {
+unsafe extern "C" {
type libusb_device_handle;
}
@@ -90,7 +90,7 @@ unsafe impl<A, B> Send for MultiParam<A, B> {}
//~^ ERROR: some fields in `MultiParam<A, B>` are not safe to be sent to another thread
// Tests for raw pointer heuristic
-extern "C" {
+unsafe extern "C" {
type NonSend;
}
diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed
index f7c56b6..2b30c8f 100644
--- a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed
+++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.fixed
@@ -9,16 +9,16 @@
fn main() {}
static LAZY_FOO: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| "foo".to_uppercase());
-//~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+//~^ ERROR: this type has been superseded by `LazyLock` in the standard library
static LAZY_BAR: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| {
- //~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+ //~^ ERROR: this type has been superseded by `LazyLock` in the standard library
let x = "bar";
x.to_uppercase()
});
static LAZY_BAZ: std::sync::LazyLock<String> = { std::sync::LazyLock::new(|| "baz".to_uppercase()) };
-//~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+//~^ ERROR: this type has been superseded by `LazyLock` in the standard library
static LAZY_QUX: std::sync::LazyLock<String> = {
- //~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+ //~^ ERROR: this type has been superseded by `LazyLock` in the standard library
if "qux".len() == 3 {
std::sync::LazyLock::new(|| "qux".to_uppercase())
} else if "qux".is_ascii() {
@@ -39,11 +39,11 @@
use once_cell::sync::Lazy;
static LAZY_FOO: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| "foo".to_uppercase());
- //~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+ //~^ ERROR: this type has been superseded by `LazyLock` in the standard library
static LAZY_BAR: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| "bar".to_uppercase());
- //~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+ //~^ ERROR: this type has been superseded by `LazyLock` in the standard library
static mut LAZY_BAZ: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| "baz".to_uppercase());
- //~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+ //~^ ERROR: this type has been superseded by `LazyLock` in the standard library
fn calling_replaceable_fns() {
let _ = std::sync::LazyLock::force(&LAZY_FOO);
diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs
index 90bc428..c52338e 100644
--- a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs
+++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs
@@ -9,16 +9,16 @@
fn main() {}
static LAZY_FOO: Lazy<String> = Lazy::new(|| "foo".to_uppercase());
-//~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+//~^ ERROR: this type has been superseded by `LazyLock` in the standard library
static LAZY_BAR: Lazy<String> = Lazy::new(|| {
- //~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+ //~^ ERROR: this type has been superseded by `LazyLock` in the standard library
let x = "bar";
x.to_uppercase()
});
static LAZY_BAZ: Lazy<String> = { Lazy::new(|| "baz".to_uppercase()) };
-//~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+//~^ ERROR: this type has been superseded by `LazyLock` in the standard library
static LAZY_QUX: Lazy<String> = {
- //~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+ //~^ ERROR: this type has been superseded by `LazyLock` in the standard library
if "qux".len() == 3 {
Lazy::new(|| "qux".to_uppercase())
} else if "qux".is_ascii() {
@@ -39,11 +39,11 @@ mod once_cell_lazy_with_fns {
use once_cell::sync::Lazy;
static LAZY_FOO: Lazy<String> = Lazy::new(|| "foo".to_uppercase());
- //~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+ //~^ ERROR: this type has been superseded by `LazyLock` in the standard library
static LAZY_BAR: Lazy<String> = Lazy::new(|| "bar".to_uppercase());
- //~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+ //~^ ERROR: this type has been superseded by `LazyLock` in the standard library
static mut LAZY_BAZ: Lazy<String> = Lazy::new(|| "baz".to_uppercase());
- //~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+ //~^ ERROR: this type has been superseded by `LazyLock` in the standard library
fn calling_replaceable_fns() {
let _ = Lazy::force(&LAZY_FOO);
diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.stderr b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.stderr
index 333052a..bb80cd1 100644
--- a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.stderr
+++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.stderr
@@ -1,4 +1,4 @@
-error: this type has been superceded by `LazyLock` in the standard library
+error: this type has been superseded by `LazyLock` in the standard library
--> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:11:18
|
LL | static LAZY_FOO: Lazy<String> = Lazy::new(|| "foo".to_uppercase());
@@ -12,7 +12,7 @@
LL + static LAZY_FOO: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| "foo".to_uppercase());
|
-error: this type has been superceded by `LazyLock` in the standard library
+error: this type has been superseded by `LazyLock` in the standard library
--> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:13:18
|
LL | static LAZY_BAR: Lazy<String> = Lazy::new(|| {
@@ -24,7 +24,7 @@
LL + static LAZY_BAR: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| {
|
-error: this type has been superceded by `LazyLock` in the standard library
+error: this type has been superseded by `LazyLock` in the standard library
--> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:18:18
|
LL | static LAZY_BAZ: Lazy<String> = { Lazy::new(|| "baz".to_uppercase()) };
@@ -36,7 +36,7 @@
LL + static LAZY_BAZ: std::sync::LazyLock<String> = { std::sync::LazyLock::new(|| "baz".to_uppercase()) };
|
-error: this type has been superceded by `LazyLock` in the standard library
+error: this type has been superseded by `LazyLock` in the standard library
--> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:20:18
|
LL | static LAZY_QUX: Lazy<String> = {
@@ -54,7 +54,7 @@
LL ~ std::sync::LazyLock::new(|| "qux".to_string())
|
-error: this type has been superceded by `LazyLock` in the standard library
+error: this type has been superseded by `LazyLock` in the standard library
--> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:41:22
|
LL | static LAZY_FOO: Lazy<String> = Lazy::new(|| "foo".to_uppercase());
@@ -69,7 +69,7 @@
LL ~ let _ = std::sync::LazyLock::force(&LAZY_FOO);
|
-error: this type has been superceded by `LazyLock` in the standard library
+error: this type has been superseded by `LazyLock` in the standard library
--> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:43:22
|
LL | static LAZY_BAR: Lazy<String> = Lazy::new(|| "bar".to_uppercase());
@@ -84,7 +84,7 @@
LL ~ let _ = std::sync::LazyLock::force(&LAZY_BAR);
|
-error: this type has been superceded by `LazyLock` in the standard library
+error: this type has been superseded by `LazyLock` in the standard library
--> tests/ui/non_std_lazy_static/non_std_lazy_static_fixable.rs:45:26
|
LL | static mut LAZY_BAZ: Lazy<String> = Lazy::new(|| "baz".to_uppercase());
diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs
index 34f8dd1..acc8c04 100644
--- a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs
+++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs
@@ -9,11 +9,11 @@ mod once_cell_lazy {
use once_cell::sync::Lazy;
static LAZY_FOO: Lazy<String> = Lazy::new(|| "foo".to_uppercase());
- //~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+ //~^ ERROR: this type has been superseded by `LazyLock` in the standard library
static mut LAZY_BAR: Lazy<String> = Lazy::new(|| "bar".to_uppercase());
- //~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+ //~^ ERROR: this type has been superseded by `LazyLock` in the standard library
static mut LAZY_BAZ: Lazy<String> = Lazy::new(|| "baz".to_uppercase());
- //~^ ERROR: this type has been superceded by `LazyLock` in the standard library
+ //~^ ERROR: this type has been superseded by `LazyLock` in the standard library
fn calling_irreplaceable_fns() {
let _ = Lazy::get(&LAZY_FOO);
@@ -31,13 +31,13 @@ mod lazy_static_lazy_static {
lazy_static! {
static ref LAZY_FOO: String = "foo".to_uppercase();
}
- //~^^^ ERROR: this macro has been superceded by `std::sync::LazyLock`
+ //~^^^ ERROR: this macro has been superseded by `std::sync::LazyLock`
lazy_static! {
static ref LAZY_BAR: String = "bar".to_uppercase();
static ref LAZY_BAZ: String = "baz".to_uppercase();
}
- //~^^^^ ERROR: this macro has been superceded by `std::sync::LazyLock`
- //~| ERROR: this macro has been superceded by `std::sync::LazyLock`
+ //~^^^^ ERROR: this macro has been superseded by `std::sync::LazyLock`
+ //~| ERROR: this macro has been superseded by `std::sync::LazyLock`
}
fn main() {}
diff --git a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.stderr b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.stderr
index 216190a..2c35cad 100644
--- a/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.stderr
@@ -1,4 +1,4 @@
-error: this macro has been superceded by `std::sync::LazyLock`
+error: this macro has been superseded by `std::sync::LazyLock`
--> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:31:5
|
LL | / lazy_static! {
@@ -9,7 +9,7 @@
= note: `-D clippy::non-std-lazy-statics` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::non_std_lazy_statics)]`
-error: this macro has been superceded by `std::sync::LazyLock`
+error: this macro has been superseded by `std::sync::LazyLock`
--> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:35:5
|
LL | / lazy_static! {
@@ -18,7 +18,7 @@
LL | | }
| |_____^
-error: this macro has been superceded by `std::sync::LazyLock`
+error: this macro has been superseded by `std::sync::LazyLock`
--> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:35:5
|
LL | / lazy_static! {
@@ -29,7 +29,7 @@
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-error: this type has been superceded by `LazyLock` in the standard library
+error: this type has been superseded by `LazyLock` in the standard library
--> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:11:22
|
LL | static LAZY_FOO: Lazy<String> = Lazy::new(|| "foo".to_uppercase());
@@ -41,7 +41,7 @@
LL + static LAZY_FOO: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| "foo".to_uppercase());
|
-error: this type has been superceded by `LazyLock` in the standard library
+error: this type has been superseded by `LazyLock` in the standard library
--> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:13:26
|
LL | static mut LAZY_BAR: Lazy<String> = Lazy::new(|| "bar".to_uppercase());
@@ -53,7 +53,7 @@
LL + static mut LAZY_BAR: std::sync::LazyLock<String> = std::sync::LazyLock::new(|| "bar".to_uppercase());
|
-error: this type has been superceded by `LazyLock` in the standard library
+error: this type has been superseded by `LazyLock` in the standard library
--> tests/ui/non_std_lazy_static/non_std_lazy_static_unfixable.rs:15:26
|
LL | static mut LAZY_BAZ: Lazy<String> = Lazy::new(|| "baz".to_uppercase());
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.rs b/src/tools/clippy/tests/ui/nonminimal_bool.rs
index a155ff3..1eecc3d 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.rs
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.rs
@@ -216,3 +216,23 @@ fn issue14184(a: f32, b: bool) {
println!("Hi");
}
}
+
+mod issue14404 {
+ enum TyKind {
+ Ref(i32, i32, i32),
+ Other,
+ }
+
+ struct Expr;
+
+ fn is_mutable(expr: &Expr) -> bool {
+ todo!()
+ }
+
+ fn should_not_give_macro(ty: TyKind, expr: Expr) {
+ if !(matches!(ty, TyKind::Ref(_, _, _)) && !is_mutable(&expr)) {
+ //~^ nonminimal_bool
+ todo!()
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/nonminimal_bool.stderr b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
index 336cce4..0e3e4cf 100644
--- a/src/tools/clippy/tests/ui/nonminimal_bool.stderr
+++ b/src/tools/clippy/tests/ui/nonminimal_bool.stderr
@@ -227,7 +227,13 @@
--> tests/ui/nonminimal_bool.rs:214:8
|
LL | if !(a < 2.0 && !b) {
- | ^^^^^^^^^^^^^^^^ help: try: `!(a < 2.0) || b`
+ | ^^^^^^^^^^^^^^^^ help: try: `a >= 2.0 || b`
-error: aborting due to 30 previous errors
+error: this boolean expression can be simplified
+ --> tests/ui/nonminimal_bool.rs:233:12
+ |
+LL | if !(matches!(ty, TyKind::Ref(_, _, _)) && !is_mutable(&expr)) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!matches!(ty, TyKind::Ref(_, _, _)) || is_mutable(&expr)`
+
+error: aborting due to 31 previous errors
diff --git a/src/tools/clippy/tests/ui/obfuscated_if_else.fixed b/src/tools/clippy/tests/ui/obfuscated_if_else.fixed
index 66f5070..70ae090 100644
--- a/src/tools/clippy/tests/ui/obfuscated_if_else.fixed
+++ b/src/tools/clippy/tests/ui/obfuscated_if_else.fixed
@@ -46,6 +46,18 @@
let partial = true.then_some(1);
partial.unwrap_or_else(|| n * 2); // not lint
+
+ if true { () } else { Default::default() };
+ //~^ obfuscated_if_else
+
+ if true { () } else { Default::default() };
+ //~^ obfuscated_if_else
+
+ if true { 1 } else { Default::default() };
+ //~^ obfuscated_if_else
+
+ if true { 1 } else { Default::default() };
+ //~^ obfuscated_if_else
}
fn issue11141() {
diff --git a/src/tools/clippy/tests/ui/obfuscated_if_else.rs b/src/tools/clippy/tests/ui/obfuscated_if_else.rs
index 4efd740..8e1f57c 100644
--- a/src/tools/clippy/tests/ui/obfuscated_if_else.rs
+++ b/src/tools/clippy/tests/ui/obfuscated_if_else.rs
@@ -46,6 +46,18 @@ fn main() {
let partial = true.then_some(1);
partial.unwrap_or_else(|| n * 2); // not lint
+
+ true.then_some(()).unwrap_or_default();
+ //~^ obfuscated_if_else
+
+ true.then(|| ()).unwrap_or_default();
+ //~^ obfuscated_if_else
+
+ true.then_some(1).unwrap_or_default();
+ //~^ obfuscated_if_else
+
+ true.then(|| 1).unwrap_or_default();
+ //~^ obfuscated_if_else
}
fn issue11141() {
diff --git a/src/tools/clippy/tests/ui/obfuscated_if_else.stderr b/src/tools/clippy/tests/ui/obfuscated_if_else.stderr
index d676c25..0de7259 100644
--- a/src/tools/clippy/tests/ui/obfuscated_if_else.stderr
+++ b/src/tools/clippy/tests/ui/obfuscated_if_else.stderr
@@ -68,52 +68,76 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 1 } else { Default::default() }`
error: this method chain can be written more clearly with `if .. else ..`
- --> tests/ui/obfuscated_if_else.rs:53:13
+ --> tests/ui/obfuscated_if_else.rs:50:5
+ |
+LL | true.then_some(()).unwrap_or_default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { () } else { Default::default() }`
+
+error: this method chain can be written more clearly with `if .. else ..`
+ --> tests/ui/obfuscated_if_else.rs:53:5
+ |
+LL | true.then(|| ()).unwrap_or_default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { () } else { Default::default() }`
+
+error: this method chain can be written more clearly with `if .. else ..`
+ --> tests/ui/obfuscated_if_else.rs:56:5
+ |
+LL | true.then_some(1).unwrap_or_default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 1 } else { Default::default() }`
+
+error: this method chain can be written more clearly with `if .. else ..`
+ --> tests/ui/obfuscated_if_else.rs:59:5
+ |
+LL | true.then(|| 1).unwrap_or_default();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 1 } else { Default::default() }`
+
+error: this method chain can be written more clearly with `if .. else ..`
+ --> tests/ui/obfuscated_if_else.rs:65:13
|
LL | let _ = true.then_some(40).unwrap_or(17) | 2;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(if true { 40 } else { 17 })`
error: this method chain can be written more clearly with `if .. else ..`
- --> tests/ui/obfuscated_if_else.rs:57:13
+ --> tests/ui/obfuscated_if_else.rs:69:13
|
LL | let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(if true { 30 } else { 17 })`
error: this method chain can be written more clearly with `if .. else ..`
- --> tests/ui/obfuscated_if_else.rs:57:48
+ --> tests/ui/obfuscated_if_else.rs:69:48
|
LL | let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 2 } else { 3 }`
error: this method chain can be written more clearly with `if .. else ..`
- --> tests/ui/obfuscated_if_else.rs:57:81
+ --> tests/ui/obfuscated_if_else.rs:69:81
|
LL | let _ = true.then_some(30).unwrap_or(17) | true.then_some(2).unwrap_or(3) | true.then_some(10).unwrap_or(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 10 } else { 1 }`
error: this method chain can be written more clearly with `if .. else ..`
- --> tests/ui/obfuscated_if_else.rs:63:17
+ --> tests/ui/obfuscated_if_else.rs:75:17
|
LL | let _ = 2 | true.then_some(40).unwrap_or(17);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 40 } else { 17 }`
error: this method chain can be written more clearly with `if .. else ..`
- --> tests/ui/obfuscated_if_else.rs:67:13
+ --> tests/ui/obfuscated_if_else.rs:79:13
|
LL | let _ = true.then_some(42).unwrap_or(17) as u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { 42 } else { 17 }`
error: this method chain can be written more clearly with `if .. else ..`
- --> tests/ui/obfuscated_if_else.rs:71:14
+ --> tests/ui/obfuscated_if_else.rs:83:14
|
LL | let _ = *true.then_some(&42).unwrap_or(&17);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { &42 } else { &17 }`
error: this method chain can be written more clearly with `if .. else ..`
- --> tests/ui/obfuscated_if_else.rs:75:14
+ --> tests/ui/obfuscated_if_else.rs:87:14
|
LL | let _ = *true.then_some(&42).unwrap_or(&17) as u8;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `if true { &42 } else { &17 }`
-error: aborting due to 19 previous errors
+error: aborting due to 23 previous errors
diff --git a/src/tools/clippy/tests/ui/op_ref.fixed b/src/tools/clippy/tests/ui/op_ref.fixed
index 46a59e4..f412190 100644
--- a/src/tools/clippy/tests/ui/op_ref.fixed
+++ b/src/tools/clippy/tests/ui/op_ref.fixed
@@ -98,3 +98,15 @@
self * &rhs
}
}
+
+mod issue_2597 {
+ fn ex1() {
+ let a: &str = "abc";
+ let b: String = "abc".to_owned();
+ println!("{}", a > &b);
+ }
+
+ pub fn ex2<T: Ord + PartialOrd>(array: &[T], val: &T, idx: usize) -> bool {
+ &array[idx] < val
+ }
+}
diff --git a/src/tools/clippy/tests/ui/op_ref.rs b/src/tools/clippy/tests/ui/op_ref.rs
index e10840f..a4bbd86 100644
--- a/src/tools/clippy/tests/ui/op_ref.rs
+++ b/src/tools/clippy/tests/ui/op_ref.rs
@@ -98,3 +98,15 @@ fn mul(self, rhs: A) -> Self::Output {
self * &rhs
}
}
+
+mod issue_2597 {
+ fn ex1() {
+ let a: &str = "abc";
+ let b: String = "abc".to_owned();
+ println!("{}", a > &b);
+ }
+
+ pub fn ex2<T: Ord + PartialOrd>(array: &[T], val: &T, idx: usize) -> bool {
+ &array[idx] < val
+ }
+}
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index ee30988..fe3ac9e 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -288,3 +288,17 @@
};
}
}
+
+mod issue11059 {
+ use std::fmt::Debug;
+
+ fn box_coercion_unsize(o: Option<i32>) -> Box<dyn Debug> {
+ if let Some(o) = o { Box::new(o) } else { Box::new("foo") }
+ }
+
+ static S: String = String::new();
+
+ fn deref_with_overload(o: Option<&str>) -> &str {
+ if let Some(o) = o { o } else { &S }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index 525a5df..5b7498b 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -351,3 +351,17 @@ fn bar(a: A) {
};
}
}
+
+mod issue11059 {
+ use std::fmt::Debug;
+
+ fn box_coercion_unsize(o: Option<i32>) -> Box<dyn Debug> {
+ if let Some(o) = o { Box::new(o) } else { Box::new("foo") }
+ }
+
+ static S: String = String::new();
+
+ fn deref_with_overload(o: Option<&str>) -> &str {
+ if let Some(o) = o { o } else { &S }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed
index 1794ac5..a1119d7 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.fixed
+++ b/src/tools/clippy/tests/ui/or_fun_call.fixed
@@ -179,16 +179,20 @@
mod issue6675 {
unsafe fn ptr_to_ref<'a, T>(p: *const T) -> &'a T {
- #[allow(unused)]
- let x = vec![0; 1000]; // future-proofing, make this function expensive.
- &*p
+ unsafe {
+ #[allow(unused)]
+ let x = vec![0; 1000]; // future-proofing, make this function expensive.
+ &*p
+ }
}
unsafe fn foo() {
- let s = "test".to_owned();
- let s = &s as *const _;
- None.unwrap_or_else(|| ptr_to_ref(s));
- //~^ or_fun_call
+ unsafe {
+ let s = "test".to_owned();
+ let s = &s as *const _;
+ None.unwrap_or_else(|| ptr_to_ref(s));
+ //~^ or_fun_call
+ }
}
fn bar() {
diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs
index 256db34..a7cd632 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.rs
+++ b/src/tools/clippy/tests/ui/or_fun_call.rs
@@ -179,16 +179,20 @@ fn f() -> Option<()> {
mod issue6675 {
unsafe fn ptr_to_ref<'a, T>(p: *const T) -> &'a T {
- #[allow(unused)]
- let x = vec![0; 1000]; // future-proofing, make this function expensive.
- &*p
+ unsafe {
+ #[allow(unused)]
+ let x = vec![0; 1000]; // future-proofing, make this function expensive.
+ &*p
+ }
}
unsafe fn foo() {
- let s = "test".to_owned();
- let s = &s as *const _;
- None.unwrap_or(ptr_to_ref(s));
- //~^ or_fun_call
+ unsafe {
+ let s = "test".to_owned();
+ let s = &s as *const _;
+ None.unwrap_or(ptr_to_ref(s));
+ //~^ or_fun_call
+ }
}
fn bar() {
diff --git a/src/tools/clippy/tests/ui/or_fun_call.stderr b/src/tools/clippy/tests/ui/or_fun_call.stderr
index 93c87b2..35bda7e 100644
--- a/src/tools/clippy/tests/ui/or_fun_call.stderr
+++ b/src/tools/clippy/tests/ui/or_fun_call.stderr
@@ -125,91 +125,91 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_else(|| Some("b".to_string()))`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:190:14
+ --> tests/ui/or_fun_call.rs:193:18
|
-LL | None.unwrap_or(ptr_to_ref(s));
- | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))`
+LL | None.unwrap_or(ptr_to_ref(s));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| ptr_to_ref(s))`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:197:14
+ --> tests/ui/or_fun_call.rs:201:14
|
LL | None.unwrap_or(unsafe { ptr_to_ref(s) });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:200:14
+ --> tests/ui/or_fun_call.rs:204:14
|
LL | None.unwrap_or( unsafe { ptr_to_ref(s) } );
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| unsafe { ptr_to_ref(s) })`
error: function call inside of `map_or`
- --> tests/ui/or_fun_call.rs:276:25
+ --> tests/ui/or_fun_call.rs:280:25
|
LL | let _ = Some(4).map_or(g(), |v| v);
| ^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(g, |v| v)`
error: function call inside of `map_or`
- --> tests/ui/or_fun_call.rs:278:25
+ --> tests/ui/or_fun_call.rs:282:25
|
LL | let _ = Some(4).map_or(g(), f);
| ^^^^^^^^^^^^^^ help: try: `map_or_else(g, f)`
error: use of `unwrap_or_else` to construct default value
- --> tests/ui/or_fun_call.rs:310:18
+ --> tests/ui/or_fun_call.rs:314:18
|
LL | with_new.unwrap_or_else(Vec::new);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
- --> tests/ui/or_fun_call.rs:314:28
+ --> tests/ui/or_fun_call.rs:318:28
|
LL | with_default_trait.unwrap_or_else(Default::default);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
- --> tests/ui/or_fun_call.rs:318:27
+ --> tests/ui/or_fun_call.rs:322:27
|
LL | with_default_type.unwrap_or_else(u64::default);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `unwrap_or_else` to construct default value
- --> tests/ui/or_fun_call.rs:322:22
+ --> tests/ui/or_fun_call.rs:326:22
|
LL | real_default.unwrap_or_else(<FakeDefault as Default>::default);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: use of `or_insert_with` to construct default value
- --> tests/ui/or_fun_call.rs:326:23
+ --> tests/ui/or_fun_call.rs:330:23
|
LL | map.entry(42).or_insert_with(String::new);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
error: use of `or_insert_with` to construct default value
- --> tests/ui/or_fun_call.rs:330:25
+ --> tests/ui/or_fun_call.rs:334:25
|
LL | btree.entry(42).or_insert_with(String::new);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `or_default()`
error: use of `unwrap_or_else` to construct default value
- --> tests/ui/or_fun_call.rs:334:25
+ --> tests/ui/or_fun_call.rs:338:25
|
LL | let _ = stringy.unwrap_or_else(String::new);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:376:17
+ --> tests/ui/or_fun_call.rs:380:17
|
LL | let _ = opt.unwrap_or({ f() }); // suggest `.unwrap_or_else(f)`
| ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(f)`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:381:17
+ --> tests/ui/or_fun_call.rs:385:17
|
LL | let _ = opt.unwrap_or(f() + 1); // suggest `.unwrap_or_else(|| f() + 1)`
| ^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| f() + 1)`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:386:17
+ --> tests/ui/or_fun_call.rs:390:17
|
LL | let _ = opt.unwrap_or({
| _________________^
@@ -229,19 +229,19 @@
|
error: function call inside of `map_or`
- --> tests/ui/or_fun_call.rs:392:17
+ --> tests/ui/or_fun_call.rs:396:17
|
LL | let _ = opt.map_or(f() + 1, |v| v); // suggest `.map_or_else(|| f() + 1, |v| v)`
| ^^^^^^^^^^^^^^^^^^^^^^ help: try: `map_or_else(|| f() + 1, |v| v)`
error: use of `unwrap_or` to construct default value
- --> tests/ui/or_fun_call.rs:397:17
+ --> tests/ui/or_fun_call.rs:401:17
|
LL | let _ = opt.unwrap_or({ i32::default() });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_default()`
error: function call inside of `unwrap_or`
- --> tests/ui/or_fun_call.rs:404:21
+ --> tests/ui/or_fun_call.rs:408:21
|
LL | let _ = opt_foo.unwrap_or(Foo { val: String::default() });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `unwrap_or_else(|| Foo { val: String::default() })`
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs
index bdac376..643d8fe 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/mutability.rs
@@ -1,5 +1,5 @@
-#![allow(clippy::all)]
#![warn(clippy::pattern_type_mismatch)]
+#![allow(clippy::single_match)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.rs
index 3c789f5..a1c447d 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.rs
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.rs
@@ -1,4 +1,3 @@
-#![allow(clippy::all)]
#![warn(clippy::pattern_type_mismatch)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr
index 763f688..b3ae63e 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_alternatives.stderr
@@ -1,5 +1,5 @@
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:15:12
+ --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:14:12
|
LL | if let Value::B | Value::A(_) = ref_value {}
| ^^^^^^^^^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@
= help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]`
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:18:34
+ --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:17:34
|
LL | if let &Value::B | &Value::A(Some(_)) = ref_value {}
| ^^^^^^^
@@ -17,7 +17,7 @@
= help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:21:32
+ --> tests/ui/pattern_type_mismatch/pattern_alternatives.rs:20:32
|
LL | if let Value::B | Value::A(Some(_)) = *ref_value {}
| ^^^^^^^
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.rs
index 7fc53d5..c5e395c 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.rs
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.rs
@@ -1,4 +1,3 @@
-#![allow(clippy::all)]
#![warn(clippy::pattern_type_mismatch)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr
index 70f7bdc..e18a88c 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_structs.stderr
@@ -1,5 +1,5 @@
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_structs.rs:13:9
+ --> tests/ui/pattern_type_mismatch/pattern_structs.rs:12:9
|
LL | let Struct { .. } = ref_value;
| ^^^^^^^^^^^^^
@@ -9,7 +9,7 @@
= help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]`
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_structs.rs:16:33
+ --> tests/ui/pattern_type_mismatch/pattern_structs.rs:15:33
|
LL | if let &Struct { ref_inner: Some(_) } = ref_value {}
| ^^^^^^^
@@ -17,7 +17,7 @@
= help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_structs.rs:19:32
+ --> tests/ui/pattern_type_mismatch/pattern_structs.rs:18:32
|
LL | if let Struct { ref_inner: Some(_) } = *ref_value {}
| ^^^^^^^
@@ -25,7 +25,7 @@
= help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_structs.rs:37:12
+ --> tests/ui/pattern_type_mismatch/pattern_structs.rs:36:12
|
LL | if let StructEnum::Var { .. } = ref_value {}
| ^^^^^^^^^^^^^^^^^^^^^^
@@ -33,7 +33,7 @@
= help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_structs.rs:40:12
+ --> tests/ui/pattern_type_mismatch/pattern_structs.rs:39:12
|
LL | if let StructEnum::Var { inner_ref: Some(_) } = ref_value {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -41,7 +41,7 @@
= help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_structs.rs:43:42
+ --> tests/ui/pattern_type_mismatch/pattern_structs.rs:42:42
|
LL | if let &StructEnum::Var { inner_ref: Some(_) } = ref_value {}
| ^^^^^^^
@@ -49,7 +49,7 @@
= help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_structs.rs:46:41
+ --> tests/ui/pattern_type_mismatch/pattern_structs.rs:45:41
|
LL | if let StructEnum::Var { inner_ref: Some(_) } = *ref_value {}
| ^^^^^^^
@@ -57,7 +57,7 @@
= help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_structs.rs:49:12
+ --> tests/ui/pattern_type_mismatch/pattern_structs.rs:48:12
|
LL | if let StructEnum::Empty = ref_value {}
| ^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.rs
index ecd95d9..8bec5ab 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.rs
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.rs
@@ -1,4 +1,3 @@
-#![allow(clippy::all)]
#![warn(clippy::pattern_type_mismatch)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr
index d47c5d5..ee307be 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/pattern_tuples.stderr
@@ -1,5 +1,5 @@
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:11:9
+ --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:10:9
|
LL | let TupleStruct(_) = ref_value;
| ^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@
= help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]`
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:14:25
+ --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:13:25
|
LL | if let &TupleStruct(Some(_)) = ref_value {}
| ^^^^^^^
@@ -17,7 +17,7 @@
= help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:17:24
+ --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:16:24
|
LL | if let TupleStruct(Some(_)) = *ref_value {}
| ^^^^^^^
@@ -25,7 +25,7 @@
= help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:35:12
+ --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:34:12
|
LL | if let TupleEnum::Var(_) = ref_value {}
| ^^^^^^^^^^^^^^^^^
@@ -33,7 +33,7 @@
= help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:38:28
+ --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:37:28
|
LL | if let &TupleEnum::Var(Some(_)) = ref_value {}
| ^^^^^^^
@@ -41,7 +41,7 @@
= help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:41:27
+ --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:40:27
|
LL | if let TupleEnum::Var(Some(_)) = *ref_value {}
| ^^^^^^^
@@ -49,7 +49,7 @@
= help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:44:12
+ --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:43:12
|
LL | if let TupleEnum::Empty = ref_value {}
| ^^^^^^^^^^^^^^^^
@@ -57,7 +57,7 @@
= help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:60:9
+ --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:59:9
|
LL | let (_a, _b) = ref_value;
| ^^^^^^^^
@@ -65,7 +65,7 @@
= help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:63:18
+ --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:62:18
|
LL | if let &(_a, Some(_)) = ref_value {}
| ^^^^^^^
@@ -73,7 +73,7 @@
= help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:66:17
+ --> tests/ui/pattern_type_mismatch/pattern_tuples.rs:65:17
|
LL | if let (_a, Some(_)) = *ref_value {}
| ^^^^^^^
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs
index 0bbc26a..49ea1d3 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.rs
@@ -1,5 +1,10 @@
-#![allow(clippy::all)]
#![warn(clippy::pattern_type_mismatch)]
+#![allow(
+ clippy::match_ref_pats,
+ clippy::never_loop,
+ clippy::redundant_pattern_matching,
+ clippy::single_match
+)]
fn main() {}
diff --git a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr
index 3f6b5fe..cd604d6 100644
--- a/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr
+++ b/src/tools/clippy/tests/ui/pattern_type_mismatch/syntax.stderr
@@ -1,5 +1,5 @@
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/syntax.rs:11:9
+ --> tests/ui/pattern_type_mismatch/syntax.rs:16:9
|
LL | Some(_) => (),
| ^^^^^^^
@@ -9,7 +9,7 @@
= help: to override `-D warnings` add `#[allow(clippy::pattern_type_mismatch)]`
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/syntax.rs:31:12
+ --> tests/ui/pattern_type_mismatch/syntax.rs:36:12
|
LL | if let Some(_) = ref_value {}
| ^^^^^^^
@@ -17,7 +17,7 @@
= help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/syntax.rs:43:15
+ --> tests/ui/pattern_type_mismatch/syntax.rs:48:15
|
LL | while let Some(_) = ref_value {
| ^^^^^^^
@@ -25,7 +25,7 @@
= help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/syntax.rs:63:9
+ --> tests/ui/pattern_type_mismatch/syntax.rs:68:9
|
LL | for (_a, _b) in slice.iter() {}
| ^^^^^^^^
@@ -33,7 +33,7 @@
= help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/syntax.rs:74:9
+ --> tests/ui/pattern_type_mismatch/syntax.rs:79:9
|
LL | let (_n, _m) = ref_value;
| ^^^^^^^^
@@ -41,7 +41,7 @@
= help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/syntax.rs:84:12
+ --> tests/ui/pattern_type_mismatch/syntax.rs:89:12
|
LL | fn foo((_a, _b): &(i32, i32)) {}
| ^^^^^^^^
@@ -49,7 +49,7 @@
= help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/syntax.rs:99:10
+ --> tests/ui/pattern_type_mismatch/syntax.rs:104:10
|
LL | foo(|(_a, _b)| ());
| ^^^^^^^^
@@ -57,7 +57,7 @@
= help: explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/syntax.rs:116:9
+ --> tests/ui/pattern_type_mismatch/syntax.rs:121:9
|
LL | Some(_) => (),
| ^^^^^^^
@@ -65,7 +65,7 @@
= help: use `*` to dereference the match expression or explicitly match against a `&_` pattern and adjust the enclosed variable bindings
error: type of pattern does not match the expression type
- --> tests/ui/pattern_type_mismatch/syntax.rs:137:17
+ --> tests/ui/pattern_type_mismatch/syntax.rs:142:17
|
LL | Some(_) => (),
| ^^^^^^^
diff --git a/src/tools/clippy/tests/ui/patterns.fixed b/src/tools/clippy/tests/ui/patterns.fixed
index bcb8ecf..a6dd5fd 100644
--- a/src/tools/clippy/tests/ui/patterns.fixed
+++ b/src/tools/clippy/tests/ui/patterns.fixed
@@ -1,6 +1,4 @@
//@aux-build:proc_macros.rs
-#![warn(clippy::all)]
-#![allow(unused)]
#![allow(clippy::uninlined_format_args, clippy::single_match)]
#[macro_use]
diff --git a/src/tools/clippy/tests/ui/patterns.rs b/src/tools/clippy/tests/ui/patterns.rs
index 19639eb..64bfbde 100644
--- a/src/tools/clippy/tests/ui/patterns.rs
+++ b/src/tools/clippy/tests/ui/patterns.rs
@@ -1,6 +1,4 @@
//@aux-build:proc_macros.rs
-#![warn(clippy::all)]
-#![allow(unused)]
#![allow(clippy::uninlined_format_args, clippy::single_match)]
#[macro_use]
diff --git a/src/tools/clippy/tests/ui/patterns.stderr b/src/tools/clippy/tests/ui/patterns.stderr
index b9950fe..ff5e1a8 100644
--- a/src/tools/clippy/tests/ui/patterns.stderr
+++ b/src/tools/clippy/tests/ui/patterns.stderr
@@ -1,5 +1,5 @@
error: the `y @ _` pattern can be written as just `y`
- --> tests/ui/patterns.rs:14:9
+ --> tests/ui/patterns.rs:12:9
|
LL | y @ _ => (),
| ^^^^^ help: try: `y`
@@ -8,13 +8,13 @@
= help: to override `-D warnings` add `#[allow(clippy::redundant_pattern)]`
error: the `x @ _` pattern can be written as just `x`
- --> tests/ui/patterns.rs:30:9
+ --> tests/ui/patterns.rs:28:9
|
LL | ref mut x @ _ => {
| ^^^^^^^^^^^^^ help: try: `ref mut x`
error: the `x @ _` pattern can be written as just `x`
- --> tests/ui/patterns.rs:39:9
+ --> tests/ui/patterns.rs:37:9
|
LL | ref x @ _ => println!("vec: {:?}", x),
| ^^^^^^^^^ help: try: `ref x`
diff --git a/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.rs b/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.rs
index 171716b..7f69c61 100644
--- a/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.rs
+++ b/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.rs
@@ -6,29 +6,37 @@
use core::arch::asm;
unsafe fn nomem_bad(p: &i32) {
- asm!(
- "asdf {p1}, {p2}, {p3}",
- p1 = in(reg) p,
- //~^ pointers_in_nomem_asm_block
+ unsafe {
+ asm!(
+ "asdf {p1}, {p2}, {p3}",
+ p1 = in(reg) p,
+ //~^ pointers_in_nomem_asm_block
- p2 = in(reg) p as *const _ as usize,
- p3 = in(reg) p,
- options(nomem, nostack, preserves_flags)
- );
+ p2 = in(reg) p as *const _ as usize,
+ p3 = in(reg) p,
+ options(nomem, nostack, preserves_flags)
+ );
+ }
}
unsafe fn nomem_good(p: &i32) {
- asm!("asdf {p}", p = in(reg) p, options(readonly, nostack, preserves_flags));
- let p = p as *const i32 as usize;
- asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags));
+ unsafe {
+ asm!("asdf {p}", p = in(reg) p, options(readonly, nostack, preserves_flags));
+ let p = p as *const i32 as usize;
+ asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags));
+ }
}
unsafe fn nomem_bad2(p: &mut i32) {
- asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags));
- //~^ pointers_in_nomem_asm_block
+ unsafe {
+ asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags));
+ //~^ pointers_in_nomem_asm_block
+ }
}
unsafe fn nomem_fn(p: extern "C" fn()) {
- asm!("call {p}", p = in(reg) p, options(nomem));
- //~^ pointers_in_nomem_asm_block
+ unsafe {
+ asm!("call {p}", p = in(reg) p, options(nomem));
+ //~^ pointers_in_nomem_asm_block
+ }
}
diff --git a/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.stderr b/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.stderr
index ca24e34..eabac24 100644
--- a/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.stderr
+++ b/src/tools/clippy/tests/ui/pointers_in_nomem_asm_block.stderr
@@ -1,11 +1,11 @@
error: passing pointers to nomem asm block
- --> tests/ui/pointers_in_nomem_asm_block.rs:11:9
+ --> tests/ui/pointers_in_nomem_asm_block.rs:12:13
|
-LL | p1 = in(reg) p,
- | ^^^^^^^^^^^^^^
+LL | p1 = in(reg) p,
+ | ^^^^^^^^^^^^^^
...
-LL | p3 = in(reg) p,
- | ^^^^^^^^^^^^^^
+LL | p3 = in(reg) p,
+ | ^^^^^^^^^^^^^^
|
= note: `nomem` means that no memory write or read happens inside the asm! block
= note: if this is intentional and no pointers are read or written to, consider allowing the lint
@@ -13,19 +13,19 @@
= help: to override `-D warnings` add `#[allow(clippy::pointers_in_nomem_asm_block)]`
error: passing pointers to nomem asm block
- --> tests/ui/pointers_in_nomem_asm_block.rs:27:22
+ --> tests/ui/pointers_in_nomem_asm_block.rs:32:26
|
-LL | asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags));
- | ^^^^^^^^^^^^^
+LL | asm!("asdf {p}", p = in(reg) p, options(nomem, nostack, preserves_flags));
+ | ^^^^^^^^^^^^^
|
= note: `nomem` means that no memory write or read happens inside the asm! block
= note: if this is intentional and no pointers are read or written to, consider allowing the lint
error: passing pointers to nomem asm block
- --> tests/ui/pointers_in_nomem_asm_block.rs:32:22
+ --> tests/ui/pointers_in_nomem_asm_block.rs:39:26
|
-LL | asm!("call {p}", p = in(reg) p, options(nomem));
- | ^^^^^^^^^^^^^
+LL | asm!("call {p}", p = in(reg) p, options(nomem));
+ | ^^^^^^^^^^^^^
|
= note: `nomem` means that no memory write or read happens inside the asm! block
= note: if this is intentional and no pointers are read or written to, consider allowing the lint
diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.fixed b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed
index 6dded72..79bfae1 100644
--- a/src/tools/clippy/tests/ui/ptr_cast_constness.fixed
+++ b/src/tools/clippy/tests/ui/ptr_cast_constness.fixed
@@ -12,11 +12,13 @@
use proc_macros::{external, inline_macros};
unsafe fn ptr_to_ref<T, U>(p: *const T, om: *mut U) {
- let _: &mut T = std::mem::transmute(p.cast_mut());
- //~^ ptr_cast_constness
- let _ = &mut *p.cast_mut();
- //~^ ptr_cast_constness
- let _: &T = &*(om as *const T);
+ unsafe {
+ let _: &mut T = std::mem::transmute(p.cast_mut());
+ //~^ ptr_cast_constness
+ let _ = &mut *p.cast_mut();
+ //~^ ptr_cast_constness
+ let _: &T = &*(om as *const T);
+ }
}
#[inline_macros]
@@ -98,3 +100,9 @@
let _ = external!(ptr::null::<u32>() as *mut u32);
let _ = external!(ptr::null::<u32>().cast_mut());
}
+
+fn issue14621() {
+ let mut local = 4;
+ let _ = std::ptr::addr_of_mut!(local).cast_const();
+ //~^ ptr_cast_constness
+}
diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.rs b/src/tools/clippy/tests/ui/ptr_cast_constness.rs
index e9629f5..f6590da 100644
--- a/src/tools/clippy/tests/ui/ptr_cast_constness.rs
+++ b/src/tools/clippy/tests/ui/ptr_cast_constness.rs
@@ -12,11 +12,13 @@
use proc_macros::{external, inline_macros};
unsafe fn ptr_to_ref<T, U>(p: *const T, om: *mut U) {
- let _: &mut T = std::mem::transmute(p as *mut T);
- //~^ ptr_cast_constness
- let _ = &mut *(p as *mut T);
- //~^ ptr_cast_constness
- let _: &T = &*(om as *const T);
+ unsafe {
+ let _: &mut T = std::mem::transmute(p as *mut T);
+ //~^ ptr_cast_constness
+ let _ = &mut *(p as *mut T);
+ //~^ ptr_cast_constness
+ let _: &T = &*(om as *const T);
+ }
}
#[inline_macros]
@@ -98,3 +100,9 @@ fn null_pointers() {
let _ = external!(ptr::null::<u32>() as *mut u32);
let _ = external!(ptr::null::<u32>().cast_mut());
}
+
+fn issue14621() {
+ let mut local = 4;
+ let _ = std::ptr::addr_of_mut!(local) as *const _;
+ //~^ ptr_cast_constness
+}
diff --git a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr
index 1eeeef7..0b16441 100644
--- a/src/tools/clippy/tests/ui/ptr_cast_constness.stderr
+++ b/src/tools/clippy/tests/ui/ptr_cast_constness.stderr
@@ -1,74 +1,74 @@
error: `as` casting between raw pointers while changing only its constness
- --> tests/ui/ptr_cast_constness.rs:15:41
+ --> tests/ui/ptr_cast_constness.rs:16:45
|
-LL | let _: &mut T = std::mem::transmute(p as *mut T);
- | ^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `p.cast_mut()`
+LL | let _: &mut T = std::mem::transmute(p as *mut T);
+ | ^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `p.cast_mut()`
|
= note: `-D clippy::ptr-cast-constness` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::ptr_cast_constness)]`
error: `as` casting between raw pointers while changing only its constness
- --> tests/ui/ptr_cast_constness.rs:17:19
+ --> tests/ui/ptr_cast_constness.rs:18:23
|
-LL | let _ = &mut *(p as *mut T);
- | ^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `p.cast_mut()`
+LL | let _ = &mut *(p as *mut T);
+ | ^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `p.cast_mut()`
error: `as` casting between raw pointers while changing only its constness
- --> tests/ui/ptr_cast_constness.rs:33:17
+ --> tests/ui/ptr_cast_constness.rs:35:17
|
LL | let _ = *ptr_ptr as *mut u32;
| ^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `(*ptr_ptr).cast_mut()`
error: `as` casting between raw pointers while changing only its constness
- --> tests/ui/ptr_cast_constness.rs:37:13
+ --> tests/ui/ptr_cast_constness.rs:39:13
|
LL | let _ = ptr as *mut u32;
| ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()`
error: `as` casting between raw pointers while changing only its constness
- --> tests/ui/ptr_cast_constness.rs:39:13
+ --> tests/ui/ptr_cast_constness.rs:41:13
|
LL | let _ = mut_ptr as *const u32;
| ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()`
error: `as` casting between raw pointers while changing only its constness
- --> tests/ui/ptr_cast_constness.rs:73:13
+ --> tests/ui/ptr_cast_constness.rs:75:13
|
LL | let _ = ptr as *mut u32;
| ^^^^^^^^^^^^^^^ help: try `pointer::cast_mut`, a safer alternative: `ptr.cast_mut()`
error: `as` casting between raw pointers while changing only its constness
- --> tests/ui/ptr_cast_constness.rs:75:13
+ --> tests/ui/ptr_cast_constness.rs:77:13
|
LL | let _ = mut_ptr as *const u32;
| ^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `mut_ptr.cast_const()`
error: `as` casting to make a const null pointer into a mutable null pointer
- --> tests/ui/ptr_cast_constness.rs:82:13
+ --> tests/ui/ptr_cast_constness.rs:84:13
|
LL | let _ = ptr::null::<String>() as *mut String;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::<String>()`
error: `as` casting to make a mutable null pointer into a const null pointer
- --> tests/ui/ptr_cast_constness.rs:84:13
+ --> tests/ui/ptr_cast_constness.rs:86:13
|
LL | let _ = ptr::null_mut::<u32>() as *const u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::<u32>()`
error: changing constness of a null pointer
- --> tests/ui/ptr_cast_constness.rs:86:13
+ --> tests/ui/ptr_cast_constness.rs:88:13
|
LL | let _ = ptr::null::<u32>().cast_mut();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::<u32>()`
error: changing constness of a null pointer
- --> tests/ui/ptr_cast_constness.rs:88:13
+ --> tests/ui/ptr_cast_constness.rs:90:13
|
LL | let _ = ptr::null_mut::<u32>().cast_const();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null()` directly instead: `std::ptr::null::<u32>()`
error: `as` casting to make a const null pointer into a mutable null pointer
- --> tests/ui/ptr_cast_constness.rs:92:21
+ --> tests/ui/ptr_cast_constness.rs:94:21
|
LL | let _ = inline!(ptr::null::<u32>() as *mut u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::<u32>()`
@@ -76,12 +76,18 @@
= note: this error originates in the macro `__inline_mac_fn_null_pointers` (in Nightly builds, run with -Z macro-backtrace for more info)
error: changing constness of a null pointer
- --> tests/ui/ptr_cast_constness.rs:94:21
+ --> tests/ui/ptr_cast_constness.rs:96:21
|
LL | let _ = inline!(ptr::null::<u32>().cast_mut());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `null_mut()` directly instead: `std::ptr::null_mut::<u32>()`
|
= note: this error originates in the macro `__inline_mac_fn_null_pointers` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 13 previous errors
+error: `as` casting between raw pointers while changing only its constness
+ --> tests/ui/ptr_cast_constness.rs:106:13
+ |
+LL | let _ = std::ptr::addr_of_mut!(local) as *const _;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try `pointer::cast_const`, a safer alternative: `std::ptr::addr_of_mut!(local).cast_const()`
+
+error: aborting due to 14 previous errors
diff --git a/src/tools/clippy/tests/ui/ptr_eq.fixed b/src/tools/clippy/tests/ui/ptr_eq.fixed
index df6305e..484ff30 100644
--- a/src/tools/clippy/tests/ui/ptr_eq.fixed
+++ b/src/tools/clippy/tests/ui/ptr_eq.fixed
@@ -4,6 +4,9 @@
($a:expr, $b:expr) => {
$a as *const _ as usize == $b as *const _ as usize
};
+ (cast $a:expr) => {
+ $a as *const [i32; 3]
+ };
}
macro_rules! another_mac {
@@ -51,4 +54,8 @@
#[allow(clippy::eq_op)]
let _issue14337 = std::ptr::eq(main as *const (), main as *const ());
//~^ ptr_eq
+
+ // Do not peel the content of macros
+ let _ = std::ptr::eq(mac!(cast a), mac!(cast b));
+ //~^ ptr_eq
}
diff --git a/src/tools/clippy/tests/ui/ptr_eq.rs b/src/tools/clippy/tests/ui/ptr_eq.rs
index 0ed0ff0..f28707c 100644
--- a/src/tools/clippy/tests/ui/ptr_eq.rs
+++ b/src/tools/clippy/tests/ui/ptr_eq.rs
@@ -4,6 +4,9 @@ macro_rules! mac {
($a:expr, $b:expr) => {
$a as *const _ as usize == $b as *const _ as usize
};
+ (cast $a:expr) => {
+ $a as *const [i32; 3]
+ };
}
macro_rules! another_mac {
@@ -51,4 +54,8 @@ fn main() {
#[allow(clippy::eq_op)]
let _issue14337 = main as *const () == main as *const ();
//~^ ptr_eq
+
+ // Do not peel the content of macros
+ let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _;
+ //~^ ptr_eq
}
diff --git a/src/tools/clippy/tests/ui/ptr_eq.stderr b/src/tools/clippy/tests/ui/ptr_eq.stderr
index 33190df..906831b 100644
--- a/src/tools/clippy/tests/ui/ptr_eq.stderr
+++ b/src/tools/clippy/tests/ui/ptr_eq.stderr
@@ -1,5 +1,5 @@
error: use `std::ptr::eq` when comparing raw pointers
- --> tests/ui/ptr_eq.rs:19:13
+ --> tests/ui/ptr_eq.rs:22:13
|
LL | let _ = a as *const _ as usize == b as *const _ as usize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)`
@@ -8,52 +8,58 @@
= help: to override `-D warnings` add `#[allow(clippy::ptr_eq)]`
error: use `std::ptr::eq` when comparing raw pointers
- --> tests/ui/ptr_eq.rs:21:13
+ --> tests/ui/ptr_eq.rs:24:13
|
LL | let _ = a as *const _ == b as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a, b)`
error: use `std::ptr::eq` when comparing raw pointers
- --> tests/ui/ptr_eq.rs:23:13
+ --> tests/ui/ptr_eq.rs:26:13
|
LL | let _ = a.as_ptr() == b as *const _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b as *const _)`
error: use `std::ptr::eq` when comparing raw pointers
- --> tests/ui/ptr_eq.rs:25:13
+ --> tests/ui/ptr_eq.rs:28:13
|
LL | let _ = a.as_ptr() == b.as_ptr();
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_ptr(), b.as_ptr())`
error: use `std::ptr::eq` when comparing raw pointers
- --> tests/ui/ptr_eq.rs:36:13
+ --> tests/ui/ptr_eq.rs:39:13
|
LL | let _ = a.as_mut_ptr() == b as *mut [i32] as *mut _;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b as *mut [i32] as *mut _)`
error: use `std::ptr::eq` when comparing raw pointers
- --> tests/ui/ptr_eq.rs:38:13
+ --> tests/ui/ptr_eq.rs:41:13
|
LL | let _ = a.as_mut_ptr() == b.as_mut_ptr();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(a.as_mut_ptr(), b.as_mut_ptr())`
error: use `std::ptr::eq` when comparing raw pointers
- --> tests/ui/ptr_eq.rs:45:13
+ --> tests/ui/ptr_eq.rs:48:13
|
LL | let _ = x as *const u32 == y as *mut u32 as *const u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(x, y)`
error: use `std::ptr::eq` when comparing raw pointers
- --> tests/ui/ptr_eq.rs:48:13
+ --> tests/ui/ptr_eq.rs:51:13
|
LL | let _ = x as *const u32 != y as *mut u32 as *const u32;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `!std::ptr::eq(x, y)`
error: use `std::ptr::eq` when comparing raw pointers
- --> tests/ui/ptr_eq.rs:52:23
+ --> tests/ui/ptr_eq.rs:55:23
|
LL | let _issue14337 = main as *const () == main as *const ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(main as *const (), main as *const ())`
-error: aborting due to 9 previous errors
+error: use `std::ptr::eq` when comparing raw pointers
+ --> tests/ui/ptr_eq.rs:59:13
+ |
+LL | let _ = mac!(cast a) as *const _ == mac!(cast b) as *const _;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::ptr::eq(mac!(cast a), mac!(cast b))`
+
+error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
index fff41f5..6bd071d 100644
--- a/src/tools/clippy/tests/ui/question_mark.fixed
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -3,6 +3,8 @@
#![allow(dead_code)]
#![allow(clippy::unnecessary_wraps)]
+use std::sync::MutexGuard;
+
fn some_func(a: Option<u32>) -> Option<u32> {
a?;
@@ -430,3 +432,9 @@
println!("{}", val);
Some(val)
}
+
+fn issue_14615(a: MutexGuard<Option<u32>>) -> Option<String> {
+ let a = (*a)?;
+ //~^^^ question_mark
+ Some(format!("{a}"))
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
index c71c8ee..dd093c9 100644
--- a/src/tools/clippy/tests/ui/question_mark.rs
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -3,6 +3,8 @@
#![allow(dead_code)]
#![allow(clippy::unnecessary_wraps)]
+use std::sync::MutexGuard;
+
fn some_func(a: Option<u32>) -> Option<u32> {
if a.is_none() {
//~^ question_mark
@@ -524,3 +526,11 @@ fn msrv_1_13(arg: Option<i32>) -> Option<i32> {
println!("{}", val);
Some(val)
}
+
+fn issue_14615(a: MutexGuard<Option<u32>>) -> Option<String> {
+ let Some(a) = *a else {
+ return None;
+ };
+ //~^^^ question_mark
+ Some(format!("{a}"))
+}
diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr
index 183b886..8fe04b8 100644
--- a/src/tools/clippy/tests/ui/question_mark.stderr
+++ b/src/tools/clippy/tests/ui/question_mark.stderr
@@ -1,5 +1,5 @@
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:7:5
+ --> tests/ui/question_mark.rs:9:5
|
LL | / if a.is_none() {
LL | |
@@ -11,7 +11,7 @@
= help: to override `-D warnings` add `#[allow(clippy::question_mark)]`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:53:9
+ --> tests/ui/question_mark.rs:55:9
|
LL | / if (self.opt).is_none() {
LL | |
@@ -20,7 +20,7 @@
| |_________^ help: replace it with: `(self.opt)?;`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:58:9
+ --> tests/ui/question_mark.rs:60:9
|
LL | / if self.opt.is_none() {
LL | |
@@ -29,7 +29,7 @@
| |_________^ help: replace it with: `self.opt?;`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:63:17
+ --> tests/ui/question_mark.rs:65:17
|
LL | let _ = if self.opt.is_none() {
| _________________^
@@ -41,7 +41,7 @@
| |_________^ help: replace it with: `Some(self.opt?)`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:70:17
+ --> tests/ui/question_mark.rs:72:17
|
LL | let _ = if let Some(x) = self.opt {
| _________________^
@@ -53,7 +53,7 @@
| |_________^ help: replace it with: `self.opt?`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:88:9
+ --> tests/ui/question_mark.rs:90:9
|
LL | / if self.opt.is_none() {
LL | |
@@ -62,7 +62,7 @@
| |_________^ help: replace it with: `self.opt.as_ref()?;`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:97:9
+ --> tests/ui/question_mark.rs:99:9
|
LL | / if self.opt.is_none() {
LL | |
@@ -71,7 +71,7 @@
| |_________^ help: replace it with: `self.opt.as_ref()?;`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:106:9
+ --> tests/ui/question_mark.rs:108:9
|
LL | / if self.opt.is_none() {
LL | |
@@ -80,7 +80,7 @@
| |_________^ help: replace it with: `self.opt.as_ref()?;`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:114:26
+ --> tests/ui/question_mark.rs:116:26
|
LL | let v: &Vec<_> = if let Some(ref v) = self.opt {
| __________________________^
@@ -92,7 +92,7 @@
| |_________^ help: replace it with: `self.opt.as_ref()?`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:125:17
+ --> tests/ui/question_mark.rs:127:17
|
LL | let v = if let Some(v) = self.opt {
| _________________^
@@ -104,7 +104,7 @@
| |_________^ help: replace it with: `self.opt?`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:147:5
+ --> tests/ui/question_mark.rs:149:5
|
LL | / if f().is_none() {
LL | |
@@ -113,7 +113,7 @@
| |_____^ help: replace it with: `f()?;`
error: this `match` expression can be replaced with `?`
- --> tests/ui/question_mark.rs:152:16
+ --> tests/ui/question_mark.rs:154:16
|
LL | let _val = match f() {
| ________________^
@@ -124,7 +124,7 @@
| |_____^ help: try instead: `f()?`
error: this `match` expression can be replaced with `?`
- --> tests/ui/question_mark.rs:163:5
+ --> tests/ui/question_mark.rs:165:5
|
LL | / match f() {
LL | |
@@ -134,7 +134,7 @@
| |_____^ help: try instead: `f()?`
error: this `match` expression can be replaced with `?`
- --> tests/ui/question_mark.rs:169:5
+ --> tests/ui/question_mark.rs:171:5
|
LL | / match opt_none!() {
LL | |
@@ -144,13 +144,13 @@
| |_____^ help: try instead: `opt_none!()?`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:196:13
+ --> tests/ui/question_mark.rs:198:13
|
LL | let _ = if let Ok(x) = x { x } else { return x };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:199:5
+ --> tests/ui/question_mark.rs:201:5
|
LL | / if x.is_err() {
LL | |
@@ -159,7 +159,7 @@
| |_____^ help: replace it with: `x?;`
error: this `match` expression can be replaced with `?`
- --> tests/ui/question_mark.rs:204:16
+ --> tests/ui/question_mark.rs:206:16
|
LL | let _val = match func_returning_result() {
| ________________^
@@ -170,7 +170,7 @@
| |_____^ help: try instead: `func_returning_result()?`
error: this `match` expression can be replaced with `?`
- --> tests/ui/question_mark.rs:210:5
+ --> tests/ui/question_mark.rs:212:5
|
LL | / match func_returning_result() {
LL | |
@@ -180,7 +180,7 @@
| |_____^ help: try instead: `func_returning_result()?`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:302:5
+ --> tests/ui/question_mark.rs:304:5
|
LL | / if let Err(err) = func_returning_result() {
LL | |
@@ -189,7 +189,7 @@
| |_____^ help: replace it with: `func_returning_result()?;`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:310:5
+ --> tests/ui/question_mark.rs:312:5
|
LL | / if let Err(err) = func_returning_result() {
LL | |
@@ -198,7 +198,7 @@
| |_____^ help: replace it with: `func_returning_result()?;`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:388:13
+ --> tests/ui/question_mark.rs:390:13
|
LL | / if a.is_none() {
LL | |
@@ -208,7 +208,7 @@
| |_____________^ help: replace it with: `a?;`
error: this `let...else` may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:449:5
+ --> tests/ui/question_mark.rs:451:5
|
LL | / let Some(v) = bar.foo.owned.clone() else {
LL | | return None;
@@ -216,7 +216,7 @@
| |______^ help: replace it with: `let v = bar.foo.owned.clone()?;`
error: this `let...else` may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:464:5
+ --> tests/ui/question_mark.rs:466:5
|
LL | / let Some(ref x) = foo.opt_x else {
LL | | return None;
@@ -224,7 +224,7 @@
| |______^ help: replace it with: `let x = foo.opt_x.as_ref()?;`
error: this `let...else` may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:474:5
+ --> tests/ui/question_mark.rs:476:5
|
LL | / let Some(ref mut x) = foo.opt_x else {
LL | | return None;
@@ -232,7 +232,7 @@
| |______^ help: replace it with: `let x = foo.opt_x.as_mut()?;`
error: this `let...else` may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:485:5
+ --> tests/ui/question_mark.rs:487:5
|
LL | / let Some(ref x @ ref y) = foo.opt_x else {
LL | | return None;
@@ -240,7 +240,7 @@
| |______^ help: replace it with: `let x @ y = foo.opt_x.as_ref()?;`
error: this `let...else` may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:489:5
+ --> tests/ui/question_mark.rs:491:5
|
LL | / let Some(ref x @ WrapperStructWithString(_)) = bar else {
LL | | return None;
@@ -248,7 +248,7 @@
| |______^ help: replace it with: `let x @ &WrapperStructWithString(_) = bar.as_ref()?;`
error: this `let...else` may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:493:5
+ --> tests/ui/question_mark.rs:495:5
|
LL | / let Some(ref mut x @ WrapperStructWithString(_)) = bar else {
LL | | return None;
@@ -256,7 +256,7 @@
| |______^ help: replace it with: `let x @ &mut WrapperStructWithString(_) = bar.as_mut()?;`
error: this block may be rewritten with the `?` operator
- --> tests/ui/question_mark.rs:515:5
+ --> tests/ui/question_mark.rs:517:5
|
LL | / if arg.is_none() {
LL | |
@@ -265,7 +265,7 @@
| |_____^ help: replace it with: `arg?;`
error: this `match` expression can be replaced with `?`
- --> tests/ui/question_mark.rs:519:15
+ --> tests/ui/question_mark.rs:521:15
|
LL | let val = match arg {
| _______________^
@@ -275,5 +275,13 @@
LL | | };
| |_____^ help: try instead: `arg?`
-error: aborting due to 29 previous errors
+error: this `let...else` may be rewritten with the `?` operator
+ --> tests/ui/question_mark.rs:531:5
+ |
+LL | / let Some(a) = *a else {
+LL | | return None;
+LL | | };
+ | |______^ help: replace it with: `let a = (*a)?;`
+
+error: aborting due to 30 previous errors
diff --git a/src/tools/clippy/tests/ui/redundant_allocation.rs b/src/tools/clippy/tests/ui/redundant_allocation.rs
index 0562f7d..832f147 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation.rs
+++ b/src/tools/clippy/tests/ui/redundant_allocation.rs
@@ -1,4 +1,3 @@
-#![warn(clippy::all)]
#![allow(clippy::boxed_local, clippy::disallowed_names)]
pub struct MyStruct;
diff --git a/src/tools/clippy/tests/ui/redundant_allocation.stderr b/src/tools/clippy/tests/ui/redundant_allocation.stderr
index 44d30f9..886ed20 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation.stderr
+++ b/src/tools/clippy/tests/ui/redundant_allocation.stderr
@@ -1,5 +1,5 @@
error: usage of `Box<Rc<T>>`
- --> tests/ui/redundant_allocation.rs:16:30
+ --> tests/ui/redundant_allocation.rs:15:30
|
LL | pub fn box_test6<T>(foo: Box<Rc<T>>) {}
| ^^^^^^^^^^
@@ -10,7 +10,7 @@
= help: to override `-D warnings` add `#[allow(clippy::redundant_allocation)]`
error: usage of `Box<Arc<T>>`
- --> tests/ui/redundant_allocation.rs:19:30
+ --> tests/ui/redundant_allocation.rs:18:30
|
LL | pub fn box_test7<T>(foo: Box<Arc<T>>) {}
| ^^^^^^^^^^^
@@ -19,7 +19,7 @@
= help: consider using just `Box<T>` or `Arc<T>`
error: usage of `Box<Rc<SubT<usize>>>`
- --> tests/ui/redundant_allocation.rs:22:27
+ --> tests/ui/redundant_allocation.rs:21:27
|
LL | pub fn box_test8() -> Box<Rc<SubT<usize>>> {
| ^^^^^^^^^^^^^^^^^^^^
@@ -28,7 +28,7 @@
= help: consider using just `Box<SubT<usize>>` or `Rc<SubT<usize>>`
error: usage of `Box<Arc<T>>`
- --> tests/ui/redundant_allocation.rs:28:30
+ --> tests/ui/redundant_allocation.rs:27:30
|
LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
| ^^^^^^^^^^^
@@ -37,7 +37,7 @@
= help: consider using just `Box<T>` or `Arc<T>`
error: usage of `Box<Arc<SubT<T>>>`
- --> tests/ui/redundant_allocation.rs:28:46
+ --> tests/ui/redundant_allocation.rs:27:46
|
LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> {
| ^^^^^^^^^^^^^^^^^
@@ -46,7 +46,7 @@
= help: consider using just `Box<SubT<T>>` or `Arc<SubT<T>>`
error: usage of `Rc<Box<bool>>`
- --> tests/ui/redundant_allocation.rs:42:24
+ --> tests/ui/redundant_allocation.rs:41:24
|
LL | pub fn rc_test5(a: Rc<Box<bool>>) {}
| ^^^^^^^^^^^^^
@@ -55,7 +55,7 @@
= help: consider using just `Rc<bool>` or `Box<bool>`
error: usage of `Rc<Arc<bool>>`
- --> tests/ui/redundant_allocation.rs:45:24
+ --> tests/ui/redundant_allocation.rs:44:24
|
LL | pub fn rc_test7(a: Rc<Arc<bool>>) {}
| ^^^^^^^^^^^^^
@@ -64,7 +64,7 @@
= help: consider using just `Rc<bool>` or `Arc<bool>`
error: usage of `Rc<Box<SubT<usize>>>`
- --> tests/ui/redundant_allocation.rs:48:26
+ --> tests/ui/redundant_allocation.rs:47:26
|
LL | pub fn rc_test8() -> Rc<Box<SubT<usize>>> {
| ^^^^^^^^^^^^^^^^^^^^
@@ -73,7 +73,7 @@
= help: consider using just `Rc<SubT<usize>>` or `Box<SubT<usize>>`
error: usage of `Rc<Arc<T>>`
- --> tests/ui/redundant_allocation.rs:54:29
+ --> tests/ui/redundant_allocation.rs:53:29
|
LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
| ^^^^^^^^^^
@@ -82,7 +82,7 @@
= help: consider using just `Rc<T>` or `Arc<T>`
error: usage of `Rc<Arc<SubT<T>>>`
- --> tests/ui/redundant_allocation.rs:54:44
+ --> tests/ui/redundant_allocation.rs:53:44
|
LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> {
| ^^^^^^^^^^^^^^^^
@@ -91,7 +91,7 @@
= help: consider using just `Rc<SubT<T>>` or `Arc<SubT<T>>`
error: usage of `Arc<Box<bool>>`
- --> tests/ui/redundant_allocation.rs:68:25
+ --> tests/ui/redundant_allocation.rs:67:25
|
LL | pub fn arc_test5(a: Arc<Box<bool>>) {}
| ^^^^^^^^^^^^^^
@@ -100,7 +100,7 @@
= help: consider using just `Arc<bool>` or `Box<bool>`
error: usage of `Arc<Rc<bool>>`
- --> tests/ui/redundant_allocation.rs:71:25
+ --> tests/ui/redundant_allocation.rs:70:25
|
LL | pub fn arc_test6(a: Arc<Rc<bool>>) {}
| ^^^^^^^^^^^^^
@@ -109,7 +109,7 @@
= help: consider using just `Arc<bool>` or `Rc<bool>`
error: usage of `Arc<Box<SubT<usize>>>`
- --> tests/ui/redundant_allocation.rs:74:27
+ --> tests/ui/redundant_allocation.rs:73:27
|
LL | pub fn arc_test8() -> Arc<Box<SubT<usize>>> {
| ^^^^^^^^^^^^^^^^^^^^^
@@ -118,7 +118,7 @@
= help: consider using just `Arc<SubT<usize>>` or `Box<SubT<usize>>`
error: usage of `Arc<Rc<T>>`
- --> tests/ui/redundant_allocation.rs:80:30
+ --> tests/ui/redundant_allocation.rs:79:30
|
LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
| ^^^^^^^^^^
@@ -127,7 +127,7 @@
= help: consider using just `Arc<T>` or `Rc<T>`
error: usage of `Arc<Rc<SubT<T>>>`
- --> tests/ui/redundant_allocation.rs:80:45
+ --> tests/ui/redundant_allocation.rs:79:45
|
LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> {
| ^^^^^^^^^^^^^^^^
@@ -136,7 +136,7 @@
= help: consider using just `Arc<SubT<T>>` or `Rc<SubT<T>>`
error: usage of `Rc<Box<Box<dyn T>>>`
- --> tests/ui/redundant_allocation.rs:105:27
+ --> tests/ui/redundant_allocation.rs:104:27
|
LL | pub fn test_rc_box(_: Rc<Box<Box<dyn T>>>) {}
| ^^^^^^^^^^^^^^^^^^^
@@ -145,7 +145,7 @@
= help: consider using just `Rc<Box<dyn T>>` or `Box<Box<dyn T>>`
error: usage of `Rc<Box<Box<str>>>`
- --> tests/ui/redundant_allocation.rs:138:31
+ --> tests/ui/redundant_allocation.rs:137:31
|
LL | pub fn test_rc_box_str(_: Rc<Box<Box<str>>>) {}
| ^^^^^^^^^^^^^^^^^
@@ -154,7 +154,7 @@
= help: consider using just `Rc<Box<str>>` or `Box<Box<str>>`
error: usage of `Rc<Box<Box<[usize]>>>`
- --> tests/ui/redundant_allocation.rs:141:33
+ --> tests/ui/redundant_allocation.rs:140:33
|
LL | pub fn test_rc_box_slice(_: Rc<Box<Box<[usize]>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^
@@ -163,7 +163,7 @@
= help: consider using just `Rc<Box<[usize]>>` or `Box<Box<[usize]>>`
error: usage of `Rc<Box<Box<Path>>>`
- --> tests/ui/redundant_allocation.rs:144:32
+ --> tests/ui/redundant_allocation.rs:143:32
|
LL | pub fn test_rc_box_path(_: Rc<Box<Box<Path>>>) {}
| ^^^^^^^^^^^^^^^^^^
@@ -172,7 +172,7 @@
= help: consider using just `Rc<Box<Path>>` or `Box<Box<Path>>`
error: usage of `Rc<Box<Box<DynSized>>>`
- --> tests/ui/redundant_allocation.rs:147:34
+ --> tests/ui/redundant_allocation.rs:146:34
|
LL | pub fn test_rc_box_custom(_: Rc<Box<Box<DynSized>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed b/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed
index 7773ba1..dbc6c07 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed
+++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed
@@ -1,7 +1,5 @@
-#![warn(clippy::all)]
#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
-#![allow(clippy::disallowed_names, unused_variables, dead_code)]
-#![allow(unused_imports)]
+#![allow(clippy::disallowed_names)]
pub struct MyStruct;
diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs b/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs
index fb86ed2..05b6429 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs
+++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs
@@ -1,7 +1,5 @@
-#![warn(clippy::all)]
#![allow(clippy::boxed_local, clippy::needless_pass_by_value)]
-#![allow(clippy::disallowed_names, unused_variables, dead_code)]
-#![allow(unused_imports)]
+#![allow(clippy::disallowed_names)]
pub struct MyStruct;
diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr b/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr
index ed8282c..4073766 100644
--- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr
+++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.stderr
@@ -1,5 +1,5 @@
error: usage of `Box<&T>`
- --> tests/ui/redundant_allocation_fixable.rs:23:30
+ --> tests/ui/redundant_allocation_fixable.rs:21:30
|
LL | pub fn box_test1<T>(foo: Box<&T>) {}
| ^^^^^^^ help: try: `&T`
@@ -9,7 +9,7 @@
= help: to override `-D warnings` add `#[allow(clippy::redundant_allocation)]`
error: usage of `Box<&MyStruct>`
- --> tests/ui/redundant_allocation_fixable.rs:26:27
+ --> tests/ui/redundant_allocation_fixable.rs:24:27
|
LL | pub fn box_test2(foo: Box<&MyStruct>) {}
| ^^^^^^^^^^^^^^ help: try: `&MyStruct`
@@ -17,7 +17,7 @@
= note: `&MyStruct` is already a pointer, `Box<&MyStruct>` allocates a pointer on the heap
error: usage of `Box<&MyEnum>`
- --> tests/ui/redundant_allocation_fixable.rs:29:27
+ --> tests/ui/redundant_allocation_fixable.rs:27:27
|
LL | pub fn box_test3(foo: Box<&MyEnum>) {}
| ^^^^^^^^^^^^ help: try: `&MyEnum`
@@ -25,7 +25,7 @@
= note: `&MyEnum` is already a pointer, `Box<&MyEnum>` allocates a pointer on the heap
error: usage of `Box<Box<T>>`
- --> tests/ui/redundant_allocation_fixable.rs:34:30
+ --> tests/ui/redundant_allocation_fixable.rs:32:30
|
LL | pub fn box_test5<T>(foo: Box<Box<T>>) {}
| ^^^^^^^^^^^ help: try: `Box<T>`
@@ -33,7 +33,7 @@
= note: `Box<T>` is already on the heap, `Box<Box<T>>` makes an extra allocation
error: usage of `Rc<&T>`
- --> tests/ui/redundant_allocation_fixable.rs:44:29
+ --> tests/ui/redundant_allocation_fixable.rs:42:29
|
LL | pub fn rc_test1<T>(foo: Rc<&T>) {}
| ^^^^^^ help: try: `&T`
@@ -41,7 +41,7 @@
= note: `&T` is already a pointer, `Rc<&T>` allocates a pointer on the heap
error: usage of `Rc<&MyStruct>`
- --> tests/ui/redundant_allocation_fixable.rs:47:26
+ --> tests/ui/redundant_allocation_fixable.rs:45:26
|
LL | pub fn rc_test2(foo: Rc<&MyStruct>) {}
| ^^^^^^^^^^^^^ help: try: `&MyStruct`
@@ -49,7 +49,7 @@
= note: `&MyStruct` is already a pointer, `Rc<&MyStruct>` allocates a pointer on the heap
error: usage of `Rc<&MyEnum>`
- --> tests/ui/redundant_allocation_fixable.rs:50:26
+ --> tests/ui/redundant_allocation_fixable.rs:48:26
|
LL | pub fn rc_test3(foo: Rc<&MyEnum>) {}
| ^^^^^^^^^^^ help: try: `&MyEnum`
@@ -57,7 +57,7 @@
= note: `&MyEnum` is already a pointer, `Rc<&MyEnum>` allocates a pointer on the heap
error: usage of `Rc<Rc<bool>>`
- --> tests/ui/redundant_allocation_fixable.rs:55:24
+ --> tests/ui/redundant_allocation_fixable.rs:53:24
|
LL | pub fn rc_test6(a: Rc<Rc<bool>>) {}
| ^^^^^^^^^^^^ help: try: `Rc<bool>`
@@ -65,7 +65,7 @@
= note: `Rc<bool>` is already on the heap, `Rc<Rc<bool>>` makes an extra allocation
error: usage of `Arc<&T>`
- --> tests/ui/redundant_allocation_fixable.rs:65:30
+ --> tests/ui/redundant_allocation_fixable.rs:63:30
|
LL | pub fn arc_test1<T>(foo: Arc<&T>) {}
| ^^^^^^^ help: try: `&T`
@@ -73,7 +73,7 @@
= note: `&T` is already a pointer, `Arc<&T>` allocates a pointer on the heap
error: usage of `Arc<&MyStruct>`
- --> tests/ui/redundant_allocation_fixable.rs:68:27
+ --> tests/ui/redundant_allocation_fixable.rs:66:27
|
LL | pub fn arc_test2(foo: Arc<&MyStruct>) {}
| ^^^^^^^^^^^^^^ help: try: `&MyStruct`
@@ -81,7 +81,7 @@
= note: `&MyStruct` is already a pointer, `Arc<&MyStruct>` allocates a pointer on the heap
error: usage of `Arc<&MyEnum>`
- --> tests/ui/redundant_allocation_fixable.rs:71:27
+ --> tests/ui/redundant_allocation_fixable.rs:69:27
|
LL | pub fn arc_test3(foo: Arc<&MyEnum>) {}
| ^^^^^^^^^^^^ help: try: `&MyEnum`
@@ -89,7 +89,7 @@
= note: `&MyEnum` is already a pointer, `Arc<&MyEnum>` allocates a pointer on the heap
error: usage of `Arc<Arc<bool>>`
- --> tests/ui/redundant_allocation_fixable.rs:76:25
+ --> tests/ui/redundant_allocation_fixable.rs:74:25
|
LL | pub fn arc_test7(a: Arc<Arc<bool>>) {}
| ^^^^^^^^^^^^^^ help: try: `Arc<bool>`
diff --git a/src/tools/clippy/tests/ui/redundant_clone.fixed b/src/tools/clippy/tests/ui/redundant_clone.fixed
index 23c00b3..c1c389f 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.fixed
+++ b/src/tools/clippy/tests/ui/redundant_clone.fixed
@@ -259,3 +259,35 @@
let _z = x.clone(); // pr 7346 can't lint on `x`
drop(y);
}
+
+mod issue10074 {
+ #[derive(Debug, Clone)]
+ enum MyEnum {
+ A = 1,
+ }
+
+ fn false_positive_on_as() {
+ let e = MyEnum::A;
+ let v = e.clone() as u16;
+
+ println!("{e:?}");
+ println!("{v}");
+ }
+}
+
+mod issue13900 {
+ use std::fmt::Display;
+
+ fn do_something(f: impl Display + Clone) -> String {
+ let g = f.clone();
+ format!("{} + {}", f, g)
+ }
+
+ fn regression() {
+ let mut a = String::new();
+ let mut b = String::new();
+ for _ in 1..10 {
+ b = a.clone();
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_clone.rs b/src/tools/clippy/tests/ui/redundant_clone.rs
index f9fe8ba..78d9876 100644
--- a/src/tools/clippy/tests/ui/redundant_clone.rs
+++ b/src/tools/clippy/tests/ui/redundant_clone.rs
@@ -259,3 +259,35 @@ fn foo(_x: &Alpha, _y: &mut Alpha) {}
let _z = x.clone(); // pr 7346 can't lint on `x`
drop(y);
}
+
+mod issue10074 {
+ #[derive(Debug, Clone)]
+ enum MyEnum {
+ A = 1,
+ }
+
+ fn false_positive_on_as() {
+ let e = MyEnum::A;
+ let v = e.clone() as u16;
+
+ println!("{e:?}");
+ println!("{v}");
+ }
+}
+
+mod issue13900 {
+ use std::fmt::Display;
+
+ fn do_something(f: impl Display + Clone) -> String {
+ let g = f.clone();
+ format!("{} + {}", f, g)
+ }
+
+ fn regression() {
+ let mut a = String::new();
+ let mut b = String::new();
+ for _ in 1..10 {
+ b = a.clone();
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed
index 549c97d..1cec19a 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed
@@ -1,5 +1,4 @@
-#![warn(clippy::all, clippy::redundant_pattern_matching)]
-#![allow(unused_must_use)]
+#![warn(clippy::redundant_pattern_matching)]
#![allow(
clippy::match_like_matches_macro,
clippy::needless_bool,
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs
index decb139..123573a 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs
@@ -1,5 +1,4 @@
-#![warn(clippy::all, clippy::redundant_pattern_matching)]
-#![allow(unused_must_use)]
+#![warn(clippy::redundant_pattern_matching)]
#![allow(
clippy::match_like_matches_macro,
clippy::needless_bool,
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr
index 66d2cec..3be7cf8 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.stderr
@@ -1,5 +1,5 @@
error: redundant pattern matching, consider using `is_ipv4()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:15:12
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:14:12
|
LL | if let V4(_) = &ipaddr {}
| -------^^^^^---------- help: try: `if ipaddr.is_ipv4()`
@@ -8,43 +8,43 @@
= help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]`
error: redundant pattern matching, consider using `is_ipv4()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:18:12
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:17:12
|
LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
| -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:21:12
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:20:12
|
LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
| -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:25:8
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:24:8
|
LL | if matches!(V4(Ipv4Addr::LOCALHOST), V4(_)) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:29:8
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:28:8
|
LL | if matches!(V6(Ipv6Addr::LOCALHOST), V6(_)) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:32:15
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:31:15
|
LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
| ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:35:15
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:34:15
|
LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
| ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:46:5
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:45:5
|
LL | / match V4(Ipv4Addr::LOCALHOST) {
LL | |
@@ -54,7 +54,7 @@
| |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:52:5
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:51:5
|
LL | / match V4(Ipv4Addr::LOCALHOST) {
LL | |
@@ -64,7 +64,7 @@
| |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:58:5
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:57:5
|
LL | / match V6(Ipv6Addr::LOCALHOST) {
LL | |
@@ -74,7 +74,7 @@
| |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:64:5
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:63:5
|
LL | / match V6(Ipv6Addr::LOCALHOST) {
LL | |
@@ -84,49 +84,49 @@
| |_____^ help: try: `V6(Ipv6Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:70:20
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:69:20
|
LL | let _ = if let V4(_) = V4(Ipv4Addr::LOCALHOST) {
| -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:79:20
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:78:20
|
LL | let _ = if let V4(_) = gen_ipaddr() {
| -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:82:19
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:81:19
|
LL | } else if let V6(_) = gen_ipaddr() {
| -------^^^^^--------------- help: try: `if gen_ipaddr().is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:95:12
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:94:12
|
LL | if let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
| -------^^^^^-------------------------- help: try: `if V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:98:12
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:97:12
|
LL | if let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
| -------^^^^^-------------------------- help: try: `if V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:101:15
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:100:15
|
LL | while let V4(_) = V4(Ipv4Addr::LOCALHOST) {}
| ----------^^^^^-------------------------- help: try: `while V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:104:15
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:103:15
|
LL | while let V6(_) = V6(Ipv6Addr::LOCALHOST) {}
| ----------^^^^^-------------------------- help: try: `while V6(Ipv6Addr::LOCALHOST).is_ipv6()`
error: redundant pattern matching, consider using `is_ipv4()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:107:5
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:106:5
|
LL | / match V4(Ipv4Addr::LOCALHOST) {
LL | |
@@ -136,7 +136,7 @@
| |_____^ help: try: `V4(Ipv4Addr::LOCALHOST).is_ipv4()`
error: redundant pattern matching, consider using `is_ipv6()`
- --> tests/ui/redundant_pattern_matching_ipaddr.rs:113:5
+ --> tests/ui/redundant_pattern_matching_ipaddr.rs:112:5
|
LL | / match V6(Ipv6Addr::LOCALHOST) {
LL | |
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
index 5585006..33a5308 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
@@ -1,14 +1,12 @@
-#![warn(clippy::all)]
+#![feature(let_chains, if_let_guard)]
#![warn(clippy::redundant_pattern_matching)]
#![allow(
- unused_must_use,
clippy::needless_bool,
clippy::needless_if,
clippy::match_like_matches_macro,
clippy::equatable_if_let,
clippy::if_same_then_else
)]
-#![feature(let_chains, if_let_guard)]
fn issue_11174<T>(boolean: bool, maybe_some: Option<T>) -> bool {
maybe_some.is_none() && (!boolean)
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
index 581a432..60bce29 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
@@ -1,14 +1,12 @@
-#![warn(clippy::all)]
+#![feature(let_chains, if_let_guard)]
#![warn(clippy::redundant_pattern_matching)]
#![allow(
- unused_must_use,
clippy::needless_bool,
clippy::needless_if,
clippy::match_like_matches_macro,
clippy::equatable_if_let,
clippy::if_same_then_else
)]
-#![feature(let_chains, if_let_guard)]
fn issue_11174<T>(boolean: bool, maybe_some: Option<T>) -> bool {
matches!(maybe_some, None if !boolean)
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
index 6816025..e5a6598 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
@@ -1,5 +1,5 @@
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:14:5
+ --> tests/ui/redundant_pattern_matching_option.rs:12:5
|
LL | matches!(maybe_some, None if !boolean)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (!boolean)`
@@ -8,55 +8,55 @@
= help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:19:13
+ --> tests/ui/redundant_pattern_matching_option.rs:17:13
|
LL | let _ = matches!(maybe_some, None if boolean || boolean2); // guard needs parentheses
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (boolean || boolean2)`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:35:12
+ --> tests/ui/redundant_pattern_matching_option.rs:33:12
|
LL | if let None = None::<()> {}
| -------^^^^------------- help: try: `if None::<()>.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_option.rs:38:12
+ --> tests/ui/redundant_pattern_matching_option.rs:36:12
|
LL | if let Some(_) = Some(42) {}
| -------^^^^^^^----------- help: try: `if Some(42).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_option.rs:41:12
+ --> tests/ui/redundant_pattern_matching_option.rs:39:12
|
LL | if let Some(_) = Some(42) {
| -------^^^^^^^----------- help: try: `if Some(42).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_option.rs:48:15
+ --> tests/ui/redundant_pattern_matching_option.rs:46:15
|
LL | while let Some(_) = Some(42) {}
| ----------^^^^^^^----------- help: try: `while Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:51:15
+ --> tests/ui/redundant_pattern_matching_option.rs:49:15
|
LL | while let None = Some(42) {}
| ----------^^^^----------- help: try: `while Some(42).is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:54:15
+ --> tests/ui/redundant_pattern_matching_option.rs:52:15
|
LL | while let None = None::<()> {}
| ----------^^^^------------- help: try: `while None::<()>.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_option.rs:58:15
+ --> tests/ui/redundant_pattern_matching_option.rs:56:15
|
LL | while let Some(_) = v.pop() {
| ----------^^^^^^^---------- help: try: `while v.pop().is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_option.rs:67:5
+ --> tests/ui/redundant_pattern_matching_option.rs:65:5
|
LL | / match Some(42) {
LL | |
@@ -66,7 +66,7 @@
| |_____^ help: try: `Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:73:5
+ --> tests/ui/redundant_pattern_matching_option.rs:71:5
|
LL | / match None::<()> {
LL | |
@@ -76,7 +76,7 @@
| |_____^ help: try: `None::<()>.is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:79:13
+ --> tests/ui/redundant_pattern_matching_option.rs:77:13
|
LL | let _ = match None::<()> {
| _____________^
@@ -87,55 +87,55 @@
| |_____^ help: try: `None::<()>.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_option.rs:86:20
+ --> tests/ui/redundant_pattern_matching_option.rs:84:20
|
LL | let _ = if let Some(_) = opt { true } else { false };
| -------^^^^^^^------ help: try: `if opt.is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_option.rs:93:20
+ --> tests/ui/redundant_pattern_matching_option.rs:91:20
|
LL | let _ = if let Some(_) = gen_opt() {
| -------^^^^^^^------------ help: try: `if gen_opt().is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:96:19
+ --> tests/ui/redundant_pattern_matching_option.rs:94:19
|
LL | } else if let None = gen_opt() {
| -------^^^^------------ help: try: `if gen_opt().is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_option.rs:103:12
+ --> tests/ui/redundant_pattern_matching_option.rs:101:12
|
LL | if let Some(..) = gen_opt() {}
| -------^^^^^^^^------------ help: try: `if gen_opt().is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_option.rs:119:12
+ --> tests/ui/redundant_pattern_matching_option.rs:117:12
|
LL | if let Some(_) = Some(42) {}
| -------^^^^^^^----------- help: try: `if Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:122:12
+ --> tests/ui/redundant_pattern_matching_option.rs:120:12
|
LL | if let None = None::<()> {}
| -------^^^^------------- help: try: `if None::<()>.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_option.rs:125:15
+ --> tests/ui/redundant_pattern_matching_option.rs:123:15
|
LL | while let Some(_) = Some(42) {}
| ----------^^^^^^^----------- help: try: `while Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:128:15
+ --> tests/ui/redundant_pattern_matching_option.rs:126:15
|
LL | while let None = None::<()> {}
| ----------^^^^------------- help: try: `while None::<()>.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_option.rs:131:5
+ --> tests/ui/redundant_pattern_matching_option.rs:129:5
|
LL | / match Some(42) {
LL | |
@@ -145,7 +145,7 @@
| |_____^ help: try: `Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:137:5
+ --> tests/ui/redundant_pattern_matching_option.rs:135:5
|
LL | / match None::<()> {
LL | |
@@ -155,19 +155,19 @@
| |_____^ help: try: `None::<()>.is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:146:12
+ --> tests/ui/redundant_pattern_matching_option.rs:144:12
|
LL | if let None = *(&None::<()>) {}
| -------^^^^----------------- help: try: `if (&None::<()>).is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:148:12
+ --> tests/ui/redundant_pattern_matching_option.rs:146:12
|
LL | if let None = *&None::<()> {}
| -------^^^^--------------- help: try: `if (&None::<()>).is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_option.rs:155:5
+ --> tests/ui/redundant_pattern_matching_option.rs:153:5
|
LL | / match x {
LL | |
@@ -177,7 +177,7 @@
| |_____^ help: try: `x.is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:161:5
+ --> tests/ui/redundant_pattern_matching_option.rs:159:5
|
LL | / match x {
LL | |
@@ -187,7 +187,7 @@
| |_____^ help: try: `x.is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:167:5
+ --> tests/ui/redundant_pattern_matching_option.rs:165:5
|
LL | / match x {
LL | |
@@ -197,7 +197,7 @@
| |_____^ help: try: `x.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_option.rs:173:5
+ --> tests/ui/redundant_pattern_matching_option.rs:171:5
|
LL | / match x {
LL | |
@@ -207,19 +207,19 @@
| |_____^ help: try: `x.is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_option.rs:189:13
+ --> tests/ui/redundant_pattern_matching_option.rs:187:13
|
LL | let _ = matches!(x, Some(_));
| ^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:192:13
+ --> tests/ui/redundant_pattern_matching_option.rs:190:13
|
LL | let _ = matches!(x, None);
| ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> tests/ui/redundant_pattern_matching_option.rs:203:17
+ --> tests/ui/redundant_pattern_matching_option.rs:201:17
|
LL | let _ = matches!(*p, None);
| ^^^^^^^^^^^^^^^^^^ help: try: `(*p).is_none()`
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed
index c8e18e8..800889b 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed
@@ -1,7 +1,5 @@
-#![warn(clippy::all)]
#![warn(clippy::redundant_pattern_matching)]
#![allow(
- unused_must_use,
clippy::needless_bool,
clippy::needless_if,
clippy::match_like_matches_macro,
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs
index 727503d..1668c2f 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs
@@ -1,7 +1,5 @@
-#![warn(clippy::all)]
#![warn(clippy::redundant_pattern_matching)]
#![allow(
- unused_must_use,
clippy::needless_bool,
clippy::needless_if,
clippy::match_like_matches_macro,
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr
index 5f65918..5cd9d96 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.stderr
@@ -1,5 +1,5 @@
error: redundant pattern matching, consider using `is_pending()`
- --> tests/ui/redundant_pattern_matching_poll.rs:15:12
+ --> tests/ui/redundant_pattern_matching_poll.rs:13:12
|
LL | if let Pending = Pending::<()> {}
| -------^^^^^^^---------------- help: try: `if Pending::<()>.is_pending()`
@@ -8,49 +8,49 @@
= help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]`
error: redundant pattern matching, consider using `is_ready()`
- --> tests/ui/redundant_pattern_matching_poll.rs:18:12
+ --> tests/ui/redundant_pattern_matching_poll.rs:16:12
|
LL | if let Ready(_) = Ready(42) {}
| -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()`
error: redundant pattern matching, consider using `is_ready()`
- --> tests/ui/redundant_pattern_matching_poll.rs:21:12
+ --> tests/ui/redundant_pattern_matching_poll.rs:19:12
|
LL | if let Ready(_) = Ready(42) {
| -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()`
error: redundant pattern matching, consider using `is_ready()`
- --> tests/ui/redundant_pattern_matching_poll.rs:29:8
+ --> tests/ui/redundant_pattern_matching_poll.rs:27:8
|
LL | if matches!(Ready(42), Ready(_)) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Ready(42).is_ready()`
error: redundant pattern matching, consider using `is_pending()`
- --> tests/ui/redundant_pattern_matching_poll.rs:33:8
+ --> tests/ui/redundant_pattern_matching_poll.rs:31:8
|
LL | if matches!(Pending::<()>, Pending) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Pending::<()>.is_pending()`
error: redundant pattern matching, consider using `is_ready()`
- --> tests/ui/redundant_pattern_matching_poll.rs:36:15
+ --> tests/ui/redundant_pattern_matching_poll.rs:34:15
|
LL | while let Ready(_) = Ready(42) {}
| ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()`
error: redundant pattern matching, consider using `is_pending()`
- --> tests/ui/redundant_pattern_matching_poll.rs:39:15
+ --> tests/ui/redundant_pattern_matching_poll.rs:37:15
|
LL | while let Pending = Ready(42) {}
| ----------^^^^^^^------------ help: try: `while Ready(42).is_pending()`
error: redundant pattern matching, consider using `is_pending()`
- --> tests/ui/redundant_pattern_matching_poll.rs:42:15
+ --> tests/ui/redundant_pattern_matching_poll.rs:40:15
|
LL | while let Pending = Pending::<()> {}
| ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()`
error: redundant pattern matching, consider using `is_ready()`
- --> tests/ui/redundant_pattern_matching_poll.rs:49:5
+ --> tests/ui/redundant_pattern_matching_poll.rs:47:5
|
LL | / match Ready(42) {
LL | |
@@ -60,7 +60,7 @@
| |_____^ help: try: `Ready(42).is_ready()`
error: redundant pattern matching, consider using `is_pending()`
- --> tests/ui/redundant_pattern_matching_poll.rs:55:5
+ --> tests/ui/redundant_pattern_matching_poll.rs:53:5
|
LL | / match Pending::<()> {
LL | |
@@ -70,7 +70,7 @@
| |_____^ help: try: `Pending::<()>.is_pending()`
error: redundant pattern matching, consider using `is_pending()`
- --> tests/ui/redundant_pattern_matching_poll.rs:61:13
+ --> tests/ui/redundant_pattern_matching_poll.rs:59:13
|
LL | let _ = match Pending::<()> {
| _____________^
@@ -81,49 +81,49 @@
| |_____^ help: try: `Pending::<()>.is_pending()`
error: redundant pattern matching, consider using `is_ready()`
- --> tests/ui/redundant_pattern_matching_poll.rs:68:20
+ --> tests/ui/redundant_pattern_matching_poll.rs:66:20
|
LL | let _ = if let Ready(_) = poll { true } else { false };
| -------^^^^^^^^------- help: try: `if poll.is_ready()`
error: redundant pattern matching, consider using `is_ready()`
- --> tests/ui/redundant_pattern_matching_poll.rs:73:20
+ --> tests/ui/redundant_pattern_matching_poll.rs:71:20
|
LL | let _ = if let Ready(_) = gen_poll() {
| -------^^^^^^^^------------- help: try: `if gen_poll().is_ready()`
error: redundant pattern matching, consider using `is_pending()`
- --> tests/ui/redundant_pattern_matching_poll.rs:76:19
+ --> tests/ui/redundant_pattern_matching_poll.rs:74:19
|
LL | } else if let Pending = gen_poll() {
| -------^^^^^^^------------- help: try: `if gen_poll().is_pending()`
error: redundant pattern matching, consider using `is_ready()`
- --> tests/ui/redundant_pattern_matching_poll.rs:93:12
+ --> tests/ui/redundant_pattern_matching_poll.rs:91:12
|
LL | if let Ready(_) = Ready(42) {}
| -------^^^^^^^^------------ help: try: `if Ready(42).is_ready()`
error: redundant pattern matching, consider using `is_pending()`
- --> tests/ui/redundant_pattern_matching_poll.rs:96:12
+ --> tests/ui/redundant_pattern_matching_poll.rs:94:12
|
LL | if let Pending = Pending::<()> {}
| -------^^^^^^^---------------- help: try: `if Pending::<()>.is_pending()`
error: redundant pattern matching, consider using `is_ready()`
- --> tests/ui/redundant_pattern_matching_poll.rs:99:15
+ --> tests/ui/redundant_pattern_matching_poll.rs:97:15
|
LL | while let Ready(_) = Ready(42) {}
| ----------^^^^^^^^------------ help: try: `while Ready(42).is_ready()`
error: redundant pattern matching, consider using `is_pending()`
- --> tests/ui/redundant_pattern_matching_poll.rs:102:15
+ --> tests/ui/redundant_pattern_matching_poll.rs:100:15
|
LL | while let Pending = Pending::<()> {}
| ----------^^^^^^^---------------- help: try: `while Pending::<()>.is_pending()`
error: redundant pattern matching, consider using `is_ready()`
- --> tests/ui/redundant_pattern_matching_poll.rs:105:5
+ --> tests/ui/redundant_pattern_matching_poll.rs:103:5
|
LL | / match Ready(42) {
LL | |
@@ -133,7 +133,7 @@
| |_____^ help: try: `Ready(42).is_ready()`
error: redundant pattern matching, consider using `is_pending()`
- --> tests/ui/redundant_pattern_matching_poll.rs:111:5
+ --> tests/ui/redundant_pattern_matching_poll.rs:109:5
|
LL | / match Pending::<()> {
LL | |
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed
index 1158796..dab8167 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed
@@ -1,6 +1,5 @@
-#![warn(clippy::all)]
#![warn(clippy::redundant_pattern_matching)]
-#![allow(deprecated, unused_must_use)]
+#![allow(deprecated)]
#![allow(
clippy::if_same_then_else,
clippy::match_like_matches_macro,
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs
index 35f8f91..3fd7051 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs
@@ -1,6 +1,5 @@
-#![warn(clippy::all)]
#![warn(clippy::redundant_pattern_matching)]
-#![allow(deprecated, unused_must_use)]
+#![allow(deprecated)]
#![allow(
clippy::if_same_then_else,
clippy::match_like_matches_macro,
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr
index 4f78b95..7e7d27d 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr
@@ -1,5 +1,5 @@
error: redundant pattern matching, consider using `is_ok()`
- --> tests/ui/redundant_pattern_matching_result.rs:15:12
+ --> tests/ui/redundant_pattern_matching_result.rs:14:12
|
LL | if let Ok(_) = &result {}
| -------^^^^^---------- help: try: `if result.is_ok()`
@@ -8,31 +8,31 @@
= help: to override `-D warnings` add `#[allow(clippy::redundant_pattern_matching)]`
error: redundant pattern matching, consider using `is_ok()`
- --> tests/ui/redundant_pattern_matching_result.rs:18:12
+ --> tests/ui/redundant_pattern_matching_result.rs:17:12
|
LL | if let Ok(_) = Ok::<i32, i32>(42) {}
| -------^^^^^--------------------- help: try: `if Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> tests/ui/redundant_pattern_matching_result.rs:21:12
+ --> tests/ui/redundant_pattern_matching_result.rs:20:12
|
LL | if let Err(_) = Err::<i32, i32>(42) {}
| -------^^^^^^---------------------- help: try: `if Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> tests/ui/redundant_pattern_matching_result.rs:24:15
+ --> tests/ui/redundant_pattern_matching_result.rs:23:15
|
LL | while let Ok(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^--------------------- help: try: `while Ok::<i32, i32>(10).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> tests/ui/redundant_pattern_matching_result.rs:27:15
+ --> tests/ui/redundant_pattern_matching_result.rs:26:15
|
LL | while let Err(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^^--------------------- help: try: `while Ok::<i32, i32>(10).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> tests/ui/redundant_pattern_matching_result.rs:38:5
+ --> tests/ui/redundant_pattern_matching_result.rs:37:5
|
LL | / match Ok::<i32, i32>(42) {
LL | |
@@ -42,7 +42,7 @@
| |_____^ help: try: `Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> tests/ui/redundant_pattern_matching_result.rs:44:5
+ --> tests/ui/redundant_pattern_matching_result.rs:43:5
|
LL | / match Ok::<i32, i32>(42) {
LL | |
@@ -52,7 +52,7 @@
| |_____^ help: try: `Ok::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_err()`
- --> tests/ui/redundant_pattern_matching_result.rs:50:5
+ --> tests/ui/redundant_pattern_matching_result.rs:49:5
|
LL | / match Err::<i32, i32>(42) {
LL | |
@@ -62,7 +62,7 @@
| |_____^ help: try: `Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> tests/ui/redundant_pattern_matching_result.rs:56:5
+ --> tests/ui/redundant_pattern_matching_result.rs:55:5
|
LL | / match Err::<i32, i32>(42) {
LL | |
@@ -72,73 +72,73 @@
| |_____^ help: try: `Err::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_ok()`
- --> tests/ui/redundant_pattern_matching_result.rs:62:20
+ --> tests/ui/redundant_pattern_matching_result.rs:61:20
|
LL | let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false };
| -------^^^^^--------------------- help: try: `if Ok::<usize, ()>(4).is_ok()`
error: redundant pattern matching, consider using `is_ok()`
- --> tests/ui/redundant_pattern_matching_result.rs:71:20
+ --> tests/ui/redundant_pattern_matching_result.rs:70:20
|
LL | let _ = if let Ok(_) = gen_res() {
| -------^^^^^------------ help: try: `if gen_res().is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> tests/ui/redundant_pattern_matching_result.rs:74:19
+ --> tests/ui/redundant_pattern_matching_result.rs:73:19
|
LL | } else if let Err(_) = gen_res() {
| -------^^^^^^------------ help: try: `if gen_res().is_err()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_result.rs:98:19
+ --> tests/ui/redundant_pattern_matching_result.rs:97:19
|
LL | while let Some(_) = r#try!(result_opt()) {}
| ----------^^^^^^^----------------------- help: try: `while r#try!(result_opt()).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_result.rs:100:16
+ --> tests/ui/redundant_pattern_matching_result.rs:99:16
|
LL | if let Some(_) = r#try!(result_opt()) {}
| -------^^^^^^^----------------------- help: try: `if r#try!(result_opt()).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_result.rs:107:12
+ --> tests/ui/redundant_pattern_matching_result.rs:106:12
|
LL | if let Some(_) = m!() {}
| -------^^^^^^^------- help: try: `if m!().is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> tests/ui/redundant_pattern_matching_result.rs:109:15
+ --> tests/ui/redundant_pattern_matching_result.rs:108:15
|
LL | while let Some(_) = m!() {}
| ----------^^^^^^^------- help: try: `while m!().is_some()`
error: redundant pattern matching, consider using `is_ok()`
- --> tests/ui/redundant_pattern_matching_result.rs:128:12
+ --> tests/ui/redundant_pattern_matching_result.rs:127:12
|
LL | if let Ok(_) = Ok::<i32, i32>(42) {}
| -------^^^^^--------------------- help: try: `if Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> tests/ui/redundant_pattern_matching_result.rs:131:12
+ --> tests/ui/redundant_pattern_matching_result.rs:130:12
|
LL | if let Err(_) = Err::<i32, i32>(42) {}
| -------^^^^^^---------------------- help: try: `if Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> tests/ui/redundant_pattern_matching_result.rs:134:15
+ --> tests/ui/redundant_pattern_matching_result.rs:133:15
|
LL | while let Ok(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^--------------------- help: try: `while Ok::<i32, i32>(10).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> tests/ui/redundant_pattern_matching_result.rs:137:15
+ --> tests/ui/redundant_pattern_matching_result.rs:136:15
|
LL | while let Err(_) = Ok::<i32, i32>(10) {}
| ----------^^^^^^--------------------- help: try: `while Ok::<i32, i32>(10).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> tests/ui/redundant_pattern_matching_result.rs:140:5
+ --> tests/ui/redundant_pattern_matching_result.rs:139:5
|
LL | / match Ok::<i32, i32>(42) {
LL | |
@@ -148,7 +148,7 @@
| |_____^ help: try: `Ok::<i32, i32>(42).is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> tests/ui/redundant_pattern_matching_result.rs:146:5
+ --> tests/ui/redundant_pattern_matching_result.rs:145:5
|
LL | / match Err::<i32, i32>(42) {
LL | |
@@ -158,7 +158,7 @@
| |_____^ help: try: `Err::<i32, i32>(42).is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> tests/ui/redundant_pattern_matching_result.rs:157:5
+ --> tests/ui/redundant_pattern_matching_result.rs:156:5
|
LL | / match x {
LL | |
@@ -168,7 +168,7 @@
| |_____^ help: try: `x.is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> tests/ui/redundant_pattern_matching_result.rs:163:5
+ --> tests/ui/redundant_pattern_matching_result.rs:162:5
|
LL | / match x {
LL | |
@@ -178,7 +178,7 @@
| |_____^ help: try: `x.is_err()`
error: redundant pattern matching, consider using `is_err()`
- --> tests/ui/redundant_pattern_matching_result.rs:169:5
+ --> tests/ui/redundant_pattern_matching_result.rs:168:5
|
LL | / match x {
LL | |
@@ -188,7 +188,7 @@
| |_____^ help: try: `x.is_err()`
error: redundant pattern matching, consider using `is_ok()`
- --> tests/ui/redundant_pattern_matching_result.rs:175:5
+ --> tests/ui/redundant_pattern_matching_result.rs:174:5
|
LL | / match x {
LL | |
@@ -198,13 +198,13 @@
| |_____^ help: try: `x.is_ok()`
error: redundant pattern matching, consider using `is_ok()`
- --> tests/ui/redundant_pattern_matching_result.rs:197:13
+ --> tests/ui/redundant_pattern_matching_result.rs:196:13
|
LL | let _ = matches!(x, Ok(_));
| ^^^^^^^^^^^^^^^^^^ help: try: `x.is_ok()`
error: redundant pattern matching, consider using `is_err()`
- --> tests/ui/redundant_pattern_matching_result.rs:200:13
+ --> tests/ui/redundant_pattern_matching_result.rs:199:13
|
LL | let _ = matches!(x, Err(_));
| ^^^^^^^^^^^^^^^^^^^ help: try: `x.is_err()`
diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.fixed b/src/tools/clippy/tests/ui/redundant_pub_crate.fixed
index a645012..8a30fed 100644
--- a/src/tools/clippy/tests/ui/redundant_pub_crate.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pub_crate.fixed
@@ -131,6 +131,14 @@
}
}
+mod m5 {
+ pub mod m5_1 {}
+ // Test that the primary span isn't butchered for item kinds that don't have an ident.
+ pub use m5_1::*; //~ redundant_pub_crate
+ #[rustfmt::skip]
+ pub use m5_1::{*}; //~ redundant_pub_crate
+}
+
pub use m4::*;
mod issue_8732 {
diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.rs b/src/tools/clippy/tests/ui/redundant_pub_crate.rs
index 7415d34..45ba13a 100644
--- a/src/tools/clippy/tests/ui/redundant_pub_crate.rs
+++ b/src/tools/clippy/tests/ui/redundant_pub_crate.rs
@@ -131,6 +131,14 @@ pub fn h() {}
}
}
+mod m5 {
+ pub mod m5_1 {}
+ // Test that the primary span isn't butchered for item kinds that don't have an ident.
+ pub(crate) use m5_1::*; //~ redundant_pub_crate
+ #[rustfmt::skip]
+ pub(crate) use m5_1::{*}; //~ redundant_pub_crate
+}
+
pub use m4::*;
mod issue_8732 {
diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.stderr b/src/tools/clippy/tests/ui/redundant_pub_crate.stderr
index 95909ea..4a47a32 100644
--- a/src/tools/clippy/tests/ui/redundant_pub_crate.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pub_crate.stderr
@@ -129,5 +129,21 @@
| |
| help: consider using: `pub`
-error: aborting due to 16 previous errors
+error: pub(crate) import inside private module
+ --> tests/ui/redundant_pub_crate.rs:137:5
+ |
+LL | pub(crate) use m5_1::*;
+ | ----------^^^^^^^^^^^^^
+ | |
+ | help: consider using: `pub`
+
+error: pub(crate) import inside private module
+ --> tests/ui/redundant_pub_crate.rs:139:27
+ |
+LL | pub(crate) use m5_1::{*};
+ | ---------- ^
+ | |
+ | help: consider using: `pub`
+
+error: aborting due to 18 previous errors
diff --git a/src/tools/clippy/tests/ui/redundant_test_prefix.fixed b/src/tools/clippy/tests/ui/redundant_test_prefix.fixed
new file mode 100644
index 0000000..b99771f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_test_prefix.fixed
@@ -0,0 +1,158 @@
+#![allow(dead_code)]
+#![warn(clippy::redundant_test_prefix)]
+
+fn main() {
+ // Normal function, no redundant prefix.
+}
+
+fn f1() {
+ // Normal function, no redundant prefix.
+}
+
+fn test_f2() {
+ // Has prefix, but no `#[test]` attribute, ignore.
+}
+
+#[test]
+fn f3() {
+ //~^ redundant_test_prefix
+
+ // Has prefix, has `#[test]` attribute. Not within a `#[cfg(test)]`.
+ // No collision with other functions, should emit warning.
+}
+
+#[cfg(test)]
+#[test]
+fn f4() {
+ //~^ redundant_test_prefix
+
+ // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`.
+ // No collision with other functions, should emit warning.
+}
+
+mod m1 {
+ pub fn f5() {}
+}
+
+#[cfg(test)]
+#[test]
+fn f6() {
+ //~^ redundant_test_prefix
+
+ use m1::f5;
+
+ f5();
+ // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`.
+ // No collision, has function call, but it will not result in recursion.
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn foo() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn foo_with_call() {
+ //~^ redundant_test_prefix
+
+ main();
+ }
+
+ #[test]
+ fn f1() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn f2() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn f3() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn f4() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn f5() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn f6() {
+ //~^ redundant_test_prefix
+ }
+}
+
+mod tests_no_annotations {
+ use super::*;
+
+ #[test]
+ fn foo() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn foo_with_call() {
+ //~^ redundant_test_prefix
+
+ main();
+ }
+
+ #[test]
+ fn f1() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn f2() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn f3() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn f4() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn f5() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn f6() {
+ //~^ redundant_test_prefix
+ }
+}
+
+// This test is inspired by real test in `clippy_utils/src/sugg.rs`.
+// The `is_in_test_function()` checks whether any identifier within a given node's parents is
+// marked with `#[test]` attribute. Thus flagging false positives when nested functions are
+// prefixed with `test_`. Therefore `is_test_function()` has been defined in `clippy_utils`,
+// allowing to select only functions that are immediately marked with `#[test]` annotation.
+//
+// This test case ensures that for such nested functions no error is emitted.
+#[test]
+fn not_op() {
+ fn test_not(foo: bool) {
+ assert!(foo);
+ }
+
+ // Use helper function
+ test_not(true);
+ test_not(false);
+}
diff --git a/src/tools/clippy/tests/ui/redundant_test_prefix.rs b/src/tools/clippy/tests/ui/redundant_test_prefix.rs
new file mode 100644
index 0000000..3aec577
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_test_prefix.rs
@@ -0,0 +1,158 @@
+#![allow(dead_code)]
+#![warn(clippy::redundant_test_prefix)]
+
+fn main() {
+ // Normal function, no redundant prefix.
+}
+
+fn f1() {
+ // Normal function, no redundant prefix.
+}
+
+fn test_f2() {
+ // Has prefix, but no `#[test]` attribute, ignore.
+}
+
+#[test]
+fn test_f3() {
+ //~^ redundant_test_prefix
+
+ // Has prefix, has `#[test]` attribute. Not within a `#[cfg(test)]`.
+ // No collision with other functions, should emit warning.
+}
+
+#[cfg(test)]
+#[test]
+fn test_f4() {
+ //~^ redundant_test_prefix
+
+ // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`.
+ // No collision with other functions, should emit warning.
+}
+
+mod m1 {
+ pub fn f5() {}
+}
+
+#[cfg(test)]
+#[test]
+fn test_f6() {
+ //~^ redundant_test_prefix
+
+ use m1::f5;
+
+ f5();
+ // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`.
+ // No collision, has function call, but it will not result in recursion.
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_foo() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_foo_with_call() {
+ //~^ redundant_test_prefix
+
+ main();
+ }
+
+ #[test]
+ fn test_f1() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f2() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f3() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f4() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f5() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f6() {
+ //~^ redundant_test_prefix
+ }
+}
+
+mod tests_no_annotations {
+ use super::*;
+
+ #[test]
+ fn test_foo() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_foo_with_call() {
+ //~^ redundant_test_prefix
+
+ main();
+ }
+
+ #[test]
+ fn test_f1() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f2() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f3() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f4() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f5() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f6() {
+ //~^ redundant_test_prefix
+ }
+}
+
+// This test is inspired by real test in `clippy_utils/src/sugg.rs`.
+// The `is_in_test_function()` checks whether any identifier within a given node's parents is
+// marked with `#[test]` attribute. Thus flagging false positives when nested functions are
+// prefixed with `test_`. Therefore `is_test_function()` has been defined in `clippy_utils`,
+// allowing to select only functions that are immediately marked with `#[test]` annotation.
+//
+// This test case ensures that for such nested functions no error is emitted.
+#[test]
+fn not_op() {
+ fn test_not(foo: bool) {
+ assert!(foo);
+ }
+
+ // Use helper function
+ test_not(true);
+ test_not(false);
+}
diff --git a/src/tools/clippy/tests/ui/redundant_test_prefix.stderr b/src/tools/clippy/tests/ui/redundant_test_prefix.stderr
new file mode 100644
index 0000000..d156af5
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_test_prefix.stderr
@@ -0,0 +1,119 @@
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:17:4
+ |
+LL | fn test_f3() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f3`
+ |
+ = note: `-D clippy::redundant-test-prefix` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::redundant_test_prefix)]`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:26:4
+ |
+LL | fn test_f4() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f4`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:39:4
+ |
+LL | fn test_f6() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f6`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:54:8
+ |
+LL | fn test_foo() {
+ | ^^^^^^^^ help: consider removing the `test_` prefix: `foo`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:59:8
+ |
+LL | fn test_foo_with_call() {
+ | ^^^^^^^^^^^^^^^^^^ help: consider removing the `test_` prefix: `foo_with_call`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:66:8
+ |
+LL | fn test_f1() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f1`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:71:8
+ |
+LL | fn test_f2() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f2`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:76:8
+ |
+LL | fn test_f3() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f3`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:81:8
+ |
+LL | fn test_f4() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f4`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:86:8
+ |
+LL | fn test_f5() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f5`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:91:8
+ |
+LL | fn test_f6() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f6`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:100:8
+ |
+LL | fn test_foo() {
+ | ^^^^^^^^ help: consider removing the `test_` prefix: `foo`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:105:8
+ |
+LL | fn test_foo_with_call() {
+ | ^^^^^^^^^^^^^^^^^^ help: consider removing the `test_` prefix: `foo_with_call`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:112:8
+ |
+LL | fn test_f1() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f1`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:117:8
+ |
+LL | fn test_f2() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f2`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:122:8
+ |
+LL | fn test_f3() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f3`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:127:8
+ |
+LL | fn test_f4() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f4`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:132:8
+ |
+LL | fn test_f5() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f5`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix.rs:137:8
+ |
+LL | fn test_f6() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f6`
+
+error: aborting due to 19 previous errors
+
diff --git a/src/tools/clippy/tests/ui/redundant_test_prefix_noautofix.rs b/src/tools/clippy/tests/ui/redundant_test_prefix_noautofix.rs
new file mode 100644
index 0000000..6ad5d01
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_test_prefix_noautofix.rs
@@ -0,0 +1,288 @@
+//@no-rustfix: name conflicts
+
+#![allow(dead_code)]
+#![warn(clippy::redundant_test_prefix)]
+
+fn main() {
+ // Normal function, no redundant prefix.
+}
+
+fn f1() {
+ // Normal function, no redundant prefix.
+}
+
+fn test_f2() {
+ // Has prefix, but no `#[test]` attribute, ignore.
+}
+
+#[test]
+fn test_f3() {
+ //~^ redundant_test_prefix
+
+ // Has prefix, has `#[test]` attribute. Not within a `#[cfg(test)]`.
+ // No collision with other functions, should emit warning.
+}
+
+#[cfg(test)]
+#[test]
+fn test_f4() {
+ //~^ redundant_test_prefix
+
+ // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`.
+ // No collision with other functions, should emit warning.
+}
+
+fn f5() {}
+
+#[cfg(test)]
+#[test]
+fn test_f5() {
+ //~^ redundant_test_prefix
+
+ // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`.
+ // Collision with existing function.
+}
+
+mod m1 {
+ pub fn f6() {}
+ pub fn f7() {}
+}
+
+#[cfg(test)]
+#[test]
+fn test_f6() {
+ //~^ redundant_test_prefix
+
+ use m1::f6;
+
+ f6();
+ // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`.
+ // No collision, but has a function call that will result in recursion.
+}
+
+#[cfg(test)]
+#[test]
+fn test_f8() {
+ //~^ redundant_test_prefix
+
+ use m1::f7;
+
+ f7();
+ // Has prefix, has `#[test]` attribute, within a `#[cfg(test)]`.
+ // No collision, has function call, but it will not result in recursion.
+}
+
+// Although there's no direct call of `f` in the test, name collision still exists,
+// since all `m3` functions are imported and then `map` is used to call `f`.
+mod m2 {
+ mod m3 {
+ pub fn f(_: i32) -> i32 {
+ 0
+ }
+ }
+
+ use m3::*;
+
+ #[cfg(test)]
+ #[test]
+ fn test_f() {
+ //~^ redundant_test_prefix
+ let a = Some(3);
+ let _ = a.map(f);
+ }
+}
+
+mod m3 {
+ fn test_m3_1() {
+ // Has prefix, but no `#[test]` attribute, ignore.
+ }
+
+ #[test]
+ fn test_m3_2() {
+ //~^ redundant_test_prefix
+
+ // Has prefix, has `#[test]` attribute. Not within a `#[cfg(test)]`.
+ // No collision with other functions, should emit warning.
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_foo() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_foo_with_call() {
+ //~^ redundant_test_prefix
+
+ main();
+ }
+
+ #[test]
+ fn test_f1() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f2() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f3() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f4() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f5() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f6() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_1() {
+ //~^ redundant_test_prefix
+
+ // `1` is invalid function name, so suggestion to rename is emitted
+ }
+
+ #[test]
+ fn test_const() {
+ //~^ redundant_test_prefix
+
+ // `const` is reserved keyword, so suggestion to rename is emitted
+ }
+
+ #[test]
+ fn test_async() {
+ //~^ redundant_test_prefix
+
+ // `async` is reserved keyword, so suggestion to rename is emitted
+ }
+
+ #[test]
+ fn test_yield() {
+ //~^ redundant_test_prefix
+
+ // `yield` is reserved keyword for future use, so suggestion to rename is emitted
+ }
+
+ #[test]
+ fn test_() {
+ //~^ redundant_test_prefix
+
+ // `` is invalid function name, so suggestion to rename is emitted
+ }
+}
+
+mod tests_no_annotations {
+ use super::*;
+
+ #[test]
+ fn test_foo() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_foo_with_call() {
+ //~^ redundant_test_prefix
+
+ main();
+ }
+
+ #[test]
+ fn test_f1() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f2() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f3() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f4() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f5() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_f6() {
+ //~^ redundant_test_prefix
+ }
+
+ #[test]
+ fn test_1() {
+ //~^ redundant_test_prefix
+
+ // `1` is invalid function name, so suggestion to rename is emitted
+ }
+
+ #[test]
+ fn test_const() {
+ //~^ redundant_test_prefix
+
+ // `const` is reserved keyword, so suggestion to rename is emitted
+ }
+
+ #[test]
+ fn test_async() {
+ //~^ redundant_test_prefix
+
+ // `async` is reserved keyword, so suggestion to rename is emitted
+ }
+
+ #[test]
+ fn test_yield() {
+ //~^ redundant_test_prefix
+
+ // `yield` is reserved keyword for future use, so suggestion to rename is emitted
+ }
+
+ #[test]
+ fn test_() {
+ //~^ redundant_test_prefix
+
+ // `` is invalid function name, so suggestion to rename is emitted
+ }
+}
+
+// This test is inspired by real test in `clippy_utils/src/sugg.rs`.
+// The `is_in_test_function()` checks whether any identifier within a given node's parents is
+// marked with `#[test]` attribute. Thus flagging false positives when nested functions are
+// prefixed with `test_`. Therefore `is_test_function()` has been defined in `clippy_utils`,
+// allowing to select only functions that are immediately marked with `#[test]` annotation.
+//
+// This test case ensures that for such nested functions no error is emitted.
+#[test]
+fn not_op() {
+ fn test_not(foo: bool) {
+ assert!(foo);
+ }
+
+ // Use helper function
+ test_not(true);
+ test_not(false);
+}
diff --git a/src/tools/clippy/tests/ui/redundant_test_prefix_noautofix.stderr b/src/tools/clippy/tests/ui/redundant_test_prefix_noautofix.stderr
new file mode 100644
index 0000000..6440faf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/redundant_test_prefix_noautofix.stderr
@@ -0,0 +1,241 @@
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:19:4
+ |
+LL | fn test_f3() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f3`
+ |
+ = note: `-D clippy::redundant-test-prefix` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::redundant_test_prefix)]`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:28:4
+ |
+LL | fn test_f4() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f4`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:39:4
+ |
+LL | fn test_f5() {
+ | ^^^^^^^
+ |
+help: consider function renaming (just removing `test_` prefix will cause a name conflict)
+ |
+LL - fn test_f5() {
+LL + fn f5_works() {
+ |
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:53:4
+ |
+LL | fn test_f6() {
+ | ^^^^^^^
+ |
+help: consider function renaming (just removing `test_` prefix will cause a name conflict)
+ |
+LL - fn test_f6() {
+LL + fn f6_works() {
+ |
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:65:4
+ |
+LL | fn test_f8() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f8`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:88:8
+ |
+LL | fn test_f() {
+ | ^^^^^^
+ |
+help: consider function renaming (just removing `test_` prefix will cause a name conflict)
+ |
+LL - fn test_f() {
+LL + fn f_works() {
+ |
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:101:8
+ |
+LL | fn test_m3_2() {
+ | ^^^^^^^^^ help: consider removing the `test_` prefix: `m3_2`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:114:8
+ |
+LL | fn test_foo() {
+ | ^^^^^^^^ help: consider removing the `test_` prefix: `foo`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:119:8
+ |
+LL | fn test_foo_with_call() {
+ | ^^^^^^^^^^^^^^^^^^ help: consider removing the `test_` prefix: `foo_with_call`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:126:8
+ |
+LL | fn test_f1() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f1`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:131:8
+ |
+LL | fn test_f2() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f2`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:136:8
+ |
+LL | fn test_f3() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f3`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:141:8
+ |
+LL | fn test_f4() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f4`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:146:8
+ |
+LL | fn test_f5() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f5`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:151:8
+ |
+LL | fn test_f6() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f6`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:156:8
+ |
+LL | fn test_1() {
+ | ^^^^^^
+ |
+ = help: consider function renaming (just removing `test_` prefix will produce invalid function name)
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:163:8
+ |
+LL | fn test_const() {
+ | ^^^^^^^^^^
+ |
+ = help: consider function renaming (just removing `test_` prefix will produce invalid function name)
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:170:8
+ |
+LL | fn test_async() {
+ | ^^^^^^^^^^
+ |
+ = help: consider function renaming (just removing `test_` prefix will produce invalid function name)
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:177:8
+ |
+LL | fn test_yield() {
+ | ^^^^^^^^^^
+ |
+ = help: consider function renaming (just removing `test_` prefix will produce invalid function name)
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:184:8
+ |
+LL | fn test_() {
+ | ^^^^^
+ |
+ = help: consider function renaming (just removing `test_` prefix will produce invalid function name)
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:195:8
+ |
+LL | fn test_foo() {
+ | ^^^^^^^^ help: consider removing the `test_` prefix: `foo`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:200:8
+ |
+LL | fn test_foo_with_call() {
+ | ^^^^^^^^^^^^^^^^^^ help: consider removing the `test_` prefix: `foo_with_call`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:207:8
+ |
+LL | fn test_f1() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f1`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:212:8
+ |
+LL | fn test_f2() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f2`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:217:8
+ |
+LL | fn test_f3() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f3`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:222:8
+ |
+LL | fn test_f4() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f4`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:227:8
+ |
+LL | fn test_f5() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f5`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:232:8
+ |
+LL | fn test_f6() {
+ | ^^^^^^^ help: consider removing the `test_` prefix: `f6`
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:237:8
+ |
+LL | fn test_1() {
+ | ^^^^^^
+ |
+ = help: consider function renaming (just removing `test_` prefix will produce invalid function name)
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:244:8
+ |
+LL | fn test_const() {
+ | ^^^^^^^^^^
+ |
+ = help: consider function renaming (just removing `test_` prefix will produce invalid function name)
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:251:8
+ |
+LL | fn test_async() {
+ | ^^^^^^^^^^
+ |
+ = help: consider function renaming (just removing `test_` prefix will produce invalid function name)
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:258:8
+ |
+LL | fn test_yield() {
+ | ^^^^^^^^^^
+ |
+ = help: consider function renaming (just removing `test_` prefix will produce invalid function name)
+
+error: redundant `test_` prefix in test function name
+ --> tests/ui/redundant_test_prefix_noautofix.rs:265:8
+ |
+LL | fn test_() {
+ | ^^^^^
+ |
+ = help: consider function renaming (just removing `test_` prefix will produce invalid function name)
+
+error: aborting due to 33 previous errors
+
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr
index 030a9a2..886bf2b 100644
--- a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr
+++ b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.all.stderr
@@ -1,5 +1,5 @@
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
- --> tests/ui/ref_option/ref_option_traits.rs:10:5
+ --> tests/ui/ref_option/ref_option_traits.rs:9:5
|
LL | fn pub_trait_opt(&self, a: &Option<Vec<u8>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^^
@@ -10,7 +10,7 @@
= help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
- --> tests/ui/ref_option/ref_option_traits.rs:12:5
+ --> tests/ui/ref_option/ref_option_traits.rs:11:5
|
LL | fn pub_trait_ret(&self) -> &Option<Vec<u8>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^----------------^
@@ -18,7 +18,7 @@
| help: change this to: `Option<&Vec<u8>>`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
- --> tests/ui/ref_option/ref_option_traits.rs:17:5
+ --> tests/ui/ref_option/ref_option_traits.rs:16:5
|
LL | fn trait_opt(&self, a: &Option<String>);
| ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
@@ -26,7 +26,7 @@
| help: change this to: `Option<&String>`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
- --> tests/ui/ref_option/ref_option_traits.rs:19:5
+ --> tests/ui/ref_option/ref_option_traits.rs:18:5
|
LL | fn trait_ret(&self) -> &Option<String>;
| ^^^^^^^^^^^^^^^^^^^^^^^---------------^
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr
index 2837ee8..cfab7fa 100644
--- a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr
+++ b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.private.stderr
@@ -1,5 +1,5 @@
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
- --> tests/ui/ref_option/ref_option_traits.rs:17:5
+ --> tests/ui/ref_option/ref_option_traits.rs:16:5
|
LL | fn trait_opt(&self, a: &Option<String>);
| ^^^^^^^^^^^^^^^^^^^^^^^---------------^^
@@ -10,7 +10,7 @@
= help: to override `-D warnings` add `#[allow(clippy::ref_option)]`
error: it is more idiomatic to use `Option<&T>` instead of `&Option<T>`
- --> tests/ui/ref_option/ref_option_traits.rs:19:5
+ --> tests/ui/ref_option/ref_option_traits.rs:18:5
|
LL | fn trait_ret(&self) -> &Option<String>;
| ^^^^^^^^^^^^^^^^^^^^^^^---------------^
diff --git a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs
index 811da2e..4c773e8 100644
--- a/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs
+++ b/src/tools/clippy/tests/ui/ref_option/ref_option_traits.rs
@@ -3,7 +3,6 @@
//@[private] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/private
//@[all] rustc-env:CLIPPY_CONF_DIR=tests/ui/ref_option/all
-#![allow(unused, clippy::all)]
#![warn(clippy::ref_option)]
pub trait PubTrait {
diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed
index 7964047..acf7914 100644
--- a/src/tools/clippy/tests/ui/rename.fixed
+++ b/src/tools/clippy/tests/ui/rename.fixed
@@ -13,8 +13,9 @@
#![allow(clippy::disallowed_methods)]
#![allow(clippy::disallowed_types)]
#![allow(clippy::mixed_read_write_in_expression)]
-#![allow(clippy::manual_filter_map)]
#![allow(clippy::manual_find_map)]
+#![allow(clippy::manual_filter_map)]
+#![allow(unpredictable_function_pointer_comparisons)]
#![allow(clippy::useless_conversion)]
#![allow(clippy::redundant_pattern_matching)]
#![allow(clippy::match_result_ok)]
@@ -29,7 +30,6 @@
#![allow(clippy::unwrap_used)]
#![allow(clippy::panicking_overflow_checks)]
#![allow(clippy::needless_borrow)]
-#![allow(clippy::reversed_empty_ranges)]
#![allow(clippy::single_char_add_str)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::missing_const_for_thread_local)]
@@ -39,11 +39,11 @@
#![allow(invalid_reference_casting)]
#![allow(suspicious_double_ref_op)]
#![allow(invalid_nan_comparisons)]
+#![allow(invalid_null_arguments)]
#![allow(double_negations)]
#![allow(drop_bounds)]
#![allow(dropping_copy_types)]
#![allow(dropping_references)]
-#![allow(unpredictable_function_pointer_comparisons)]
#![allow(useless_ptr_null_checks)]
#![allow(for_loops_over_fallibles)]
#![allow(forgetting_copy_types)]
@@ -62,6 +62,7 @@
#![allow(unknown_lints)]
#![allow(unused_labels)]
#![allow(ambiguous_wide_pointer_comparisons)]
+#![allow(clippy::reversed_empty_ranges)]
#![warn(clippy::almost_complete_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
#![warn(clippy::disallowed_names)] //~ ERROR: lint `clippy::blacklisted_name`
#![warn(clippy::blocks_in_conditions)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
@@ -74,8 +75,9 @@
#![warn(clippy::disallowed_methods)] //~ ERROR: lint `clippy::disallowed_method`
#![warn(clippy::disallowed_types)] //~ ERROR: lint `clippy::disallowed_type`
#![warn(clippy::mixed_read_write_in_expression)] //~ ERROR: lint `clippy::eval_order_dependence`
-#![warn(clippy::manual_filter_map)] //~ ERROR: lint `clippy::filter_map`
#![warn(clippy::manual_find_map)] //~ ERROR: lint `clippy::find_map`
+#![warn(clippy::manual_filter_map)] //~ ERROR: lint `clippy::filter_map`
+#![warn(unpredictable_function_pointer_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
#![warn(clippy::useless_conversion)] //~ ERROR: lint `clippy::identity_conversion`
#![warn(clippy::redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
#![warn(clippy::match_result_ok)] //~ ERROR: lint `clippy::if_let_some_result`
@@ -94,7 +96,6 @@
#![warn(clippy::expect_used)] //~ ERROR: lint `clippy::result_expect_used`
#![warn(clippy::map_unwrap_or)] //~ ERROR: lint `clippy::result_map_unwrap_or_else`
#![warn(clippy::unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used`
-#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop`
#![warn(clippy::single_char_add_str)] //~ ERROR: lint `clippy::single_char_push_str`
#![warn(clippy::module_name_repetitions)] //~ ERROR: lint `clippy::stutter`
#![warn(clippy::missing_const_for_thread_local)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const`
@@ -104,11 +105,11 @@
#![warn(invalid_reference_casting)] //~ ERROR: lint `clippy::cast_ref_to_mut`
#![warn(suspicious_double_ref_op)] //~ ERROR: lint `clippy::clone_double_ref`
#![warn(invalid_nan_comparisons)] //~ ERROR: lint `clippy::cmp_nan`
+#![warn(invalid_null_arguments)] //~ ERROR: lint `clippy::invalid_null_ptr_usage`
#![warn(double_negations)] //~ ERROR: lint `clippy::double_neg`
#![warn(drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
#![warn(dropping_copy_types)] //~ ERROR: lint `clippy::drop_copy`
#![warn(dropping_references)] //~ ERROR: lint `clippy::drop_ref`
-#![warn(unpredictable_function_pointer_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
#![warn(useless_ptr_null_checks)] //~ ERROR: lint `clippy::fn_null_check`
#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_option`
#![warn(for_loops_over_fallibles)] //~ ERROR: lint `clippy::for_loop_over_result`
@@ -119,7 +120,6 @@
#![warn(invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering`
#![warn(invalid_value)] //~ ERROR: lint `clippy::invalid_ref`
#![warn(invalid_from_utf8_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked`
-#![warn(invalid_null_arguments)] //~ ERROR: lint `clippy::invalid_null_ptr_usage`
#![warn(let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop`
#![warn(unexpected_cfgs)] //~ ERROR: lint `clippy::maybe_misused_cfg`
#![warn(enum_intrinsics_non_enums)] //~ ERROR: lint `clippy::mem_discriminant_non_enum`
@@ -131,5 +131,6 @@
#![warn(unknown_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
#![warn(unused_labels)] //~ ERROR: lint `clippy::unused_label`
#![warn(ambiguous_wide_pointer_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
+#![warn(clippy::reversed_empty_ranges)] //~ ERROR: lint `clippy::reverse_range_loop`
fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs
index aa7b905..32641a6 100644
--- a/src/tools/clippy/tests/ui/rename.rs
+++ b/src/tools/clippy/tests/ui/rename.rs
@@ -13,8 +13,9 @@
#![allow(clippy::disallowed_methods)]
#![allow(clippy::disallowed_types)]
#![allow(clippy::mixed_read_write_in_expression)]
-#![allow(clippy::manual_filter_map)]
#![allow(clippy::manual_find_map)]
+#![allow(clippy::manual_filter_map)]
+#![allow(unpredictable_function_pointer_comparisons)]
#![allow(clippy::useless_conversion)]
#![allow(clippy::redundant_pattern_matching)]
#![allow(clippy::match_result_ok)]
@@ -29,7 +30,6 @@
#![allow(clippy::unwrap_used)]
#![allow(clippy::panicking_overflow_checks)]
#![allow(clippy::needless_borrow)]
-#![allow(clippy::reversed_empty_ranges)]
#![allow(clippy::single_char_add_str)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::missing_const_for_thread_local)]
@@ -39,11 +39,11 @@
#![allow(invalid_reference_casting)]
#![allow(suspicious_double_ref_op)]
#![allow(invalid_nan_comparisons)]
+#![allow(invalid_null_arguments)]
#![allow(double_negations)]
#![allow(drop_bounds)]
#![allow(dropping_copy_types)]
#![allow(dropping_references)]
-#![allow(unpredictable_function_pointer_comparisons)]
#![allow(useless_ptr_null_checks)]
#![allow(for_loops_over_fallibles)]
#![allow(forgetting_copy_types)]
@@ -62,6 +62,7 @@
#![allow(unknown_lints)]
#![allow(unused_labels)]
#![allow(ambiguous_wide_pointer_comparisons)]
+#![allow(clippy::reversed_empty_ranges)]
#![warn(clippy::almost_complete_letter_range)] //~ ERROR: lint `clippy::almost_complete_letter_range`
#![warn(clippy::blacklisted_name)] //~ ERROR: lint `clippy::blacklisted_name`
#![warn(clippy::block_in_if_condition_expr)] //~ ERROR: lint `clippy::block_in_if_condition_expr`
@@ -74,8 +75,9 @@
#![warn(clippy::disallowed_method)] //~ ERROR: lint `clippy::disallowed_method`
#![warn(clippy::disallowed_type)] //~ ERROR: lint `clippy::disallowed_type`
#![warn(clippy::eval_order_dependence)] //~ ERROR: lint `clippy::eval_order_dependence`
-#![warn(clippy::filter_map)] //~ ERROR: lint `clippy::filter_map`
#![warn(clippy::find_map)] //~ ERROR: lint `clippy::find_map`
+#![warn(clippy::filter_map)] //~ ERROR: lint `clippy::filter_map`
+#![warn(clippy::fn_address_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
#![warn(clippy::identity_conversion)] //~ ERROR: lint `clippy::identity_conversion`
#![warn(clippy::if_let_redundant_pattern_matching)] //~ ERROR: lint `clippy::if_let_redundant_pattern_matching`
#![warn(clippy::if_let_some_result)] //~ ERROR: lint `clippy::if_let_some_result`
@@ -94,7 +96,6 @@
#![warn(clippy::result_expect_used)] //~ ERROR: lint `clippy::result_expect_used`
#![warn(clippy::result_map_unwrap_or_else)] //~ ERROR: lint `clippy::result_map_unwrap_or_else`
#![warn(clippy::result_unwrap_used)] //~ ERROR: lint `clippy::result_unwrap_used`
-#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop`
#![warn(clippy::single_char_push_str)] //~ ERROR: lint `clippy::single_char_push_str`
#![warn(clippy::stutter)] //~ ERROR: lint `clippy::stutter`
#![warn(clippy::thread_local_initializer_can_be_made_const)] //~ ERROR: lint `clippy::thread_local_initializer_can_be_made_const`
@@ -104,11 +105,11 @@
#![warn(clippy::cast_ref_to_mut)] //~ ERROR: lint `clippy::cast_ref_to_mut`
#![warn(clippy::clone_double_ref)] //~ ERROR: lint `clippy::clone_double_ref`
#![warn(clippy::cmp_nan)] //~ ERROR: lint `clippy::cmp_nan`
+#![warn(clippy::invalid_null_ptr_usage)] //~ ERROR: lint `clippy::invalid_null_ptr_usage`
#![warn(clippy::double_neg)] //~ ERROR: lint `clippy::double_neg`
#![warn(clippy::drop_bounds)] //~ ERROR: lint `clippy::drop_bounds`
#![warn(clippy::drop_copy)] //~ ERROR: lint `clippy::drop_copy`
#![warn(clippy::drop_ref)] //~ ERROR: lint `clippy::drop_ref`
-#![warn(clippy::fn_address_comparisons)] //~ ERROR: lint `clippy::fn_address_comparisons`
#![warn(clippy::fn_null_check)] //~ ERROR: lint `clippy::fn_null_check`
#![warn(clippy::for_loop_over_option)] //~ ERROR: lint `clippy::for_loop_over_option`
#![warn(clippy::for_loop_over_result)] //~ ERROR: lint `clippy::for_loop_over_result`
@@ -119,7 +120,6 @@
#![warn(clippy::invalid_atomic_ordering)] //~ ERROR: lint `clippy::invalid_atomic_ordering`
#![warn(clippy::invalid_ref)] //~ ERROR: lint `clippy::invalid_ref`
#![warn(clippy::invalid_utf8_in_unchecked)] //~ ERROR: lint `clippy::invalid_utf8_in_unchecked`
-#![warn(clippy::invalid_null_ptr_usage)] //~ ERROR: lint `clippy::invalid_null_ptr_usage`
#![warn(clippy::let_underscore_drop)] //~ ERROR: lint `clippy::let_underscore_drop`
#![warn(clippy::maybe_misused_cfg)] //~ ERROR: lint `clippy::maybe_misused_cfg`
#![warn(clippy::mem_discriminant_non_enum)] //~ ERROR: lint `clippy::mem_discriminant_non_enum`
@@ -131,5 +131,6 @@
#![warn(clippy::unknown_clippy_lints)] //~ ERROR: lint `clippy::unknown_clippy_lints`
#![warn(clippy::unused_label)] //~ ERROR: lint `clippy::unused_label`
#![warn(clippy::vtable_address_comparisons)] //~ ERROR: lint `clippy::vtable_address_comparisons`
+#![warn(clippy::reverse_range_loop)] //~ ERROR: lint `clippy::reverse_range_loop`
fn main() {}
diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr
index b3c8816..e9d2deb 100644
--- a/src/tools/clippy/tests/ui/rename.stderr
+++ b/src/tools/clippy/tests/ui/rename.stderr
@@ -1,5 +1,5 @@
error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range`
- --> tests/ui/rename.rs:65:9
+ --> tests/ui/rename.rs:66:9
|
LL | #![warn(clippy::almost_complete_letter_range)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range`
@@ -8,347 +8,341 @@
= help: to override `-D warnings` add `#[allow(renamed_and_removed_lints)]`
error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names`
- --> tests/ui/rename.rs:66:9
+ --> tests/ui/rename.rs:67:9
|
LL | #![warn(clippy::blacklisted_name)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names`
error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_conditions`
- --> tests/ui/rename.rs:67:9
+ --> tests/ui/rename.rs:68:9
|
LL | #![warn(clippy::block_in_if_condition_expr)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_conditions`
- --> tests/ui/rename.rs:68:9
+ --> tests/ui/rename.rs:69:9
|
LL | #![warn(clippy::block_in_if_condition_stmt)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
error: lint `clippy::blocks_in_if_conditions` has been renamed to `clippy::blocks_in_conditions`
- --> tests/ui/rename.rs:69:9
+ --> tests/ui/rename.rs:70:9
|
LL | #![warn(clippy::blocks_in_if_conditions)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_conditions`
error: lint `clippy::box_vec` has been renamed to `clippy::box_collection`
- --> tests/ui/rename.rs:70:9
+ --> tests/ui/rename.rs:71:9
|
LL | #![warn(clippy::box_vec)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection`
error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes`
- --> tests/ui/rename.rs:71:9
+ --> tests/ui/rename.rs:72:9
|
LL | #![warn(clippy::const_static_lifetime)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes`
error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity`
- --> tests/ui/rename.rs:72:9
+ --> tests/ui/rename.rs:73:9
|
LL | #![warn(clippy::cyclomatic_complexity)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity`
error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq`
- --> tests/ui/rename.rs:73:9
+ --> tests/ui/rename.rs:74:9
|
LL | #![warn(clippy::derive_hash_xor_eq)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq`
error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods`
- --> tests/ui/rename.rs:74:9
+ --> tests/ui/rename.rs:75:9
|
LL | #![warn(clippy::disallowed_method)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods`
error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types`
- --> tests/ui/rename.rs:75:9
+ --> tests/ui/rename.rs:76:9
|
LL | #![warn(clippy::disallowed_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types`
error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression`
- --> tests/ui/rename.rs:76:9
+ --> tests/ui/rename.rs:77:9
|
LL | #![warn(clippy::eval_order_dependence)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression`
-error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map`
- --> tests/ui/rename.rs:77:9
- |
-LL | #![warn(clippy::filter_map)]
- | ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map`
-
error: lint `clippy::find_map` has been renamed to `clippy::manual_find_map`
--> tests/ui/rename.rs:78:9
|
LL | #![warn(clippy::find_map)]
| ^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_find_map`
-error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
+error: lint `clippy::filter_map` has been renamed to `clippy::manual_filter_map`
--> tests/ui/rename.rs:79:9
|
+LL | #![warn(clippy::filter_map)]
+ | ^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::manual_filter_map`
+
+error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons`
+ --> tests/ui/rename.rs:80:9
+ |
+LL | #![warn(clippy::fn_address_comparisons)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons`
+
+error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion`
+ --> tests/ui/rename.rs:81:9
+ |
LL | #![warn(clippy::identity_conversion)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion`
error: lint `clippy::if_let_redundant_pattern_matching` has been renamed to `clippy::redundant_pattern_matching`
- --> tests/ui/rename.rs:80:9
+ --> tests/ui/rename.rs:82:9
|
LL | #![warn(clippy::if_let_redundant_pattern_matching)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_pattern_matching`
error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok`
- --> tests/ui/rename.rs:81:9
+ --> tests/ui/rename.rs:83:9
|
LL | #![warn(clippy::if_let_some_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok`
error: lint `clippy::incorrect_clone_impl_on_copy_type` has been renamed to `clippy::non_canonical_clone_impl`
- --> tests/ui/rename.rs:82:9
+ --> tests/ui/rename.rs:84:9
|
LL | #![warn(clippy::incorrect_clone_impl_on_copy_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_clone_impl`
error: lint `clippy::incorrect_partial_ord_impl_on_ord_type` has been renamed to `clippy::non_canonical_partial_ord_impl`
- --> tests/ui/rename.rs:83:9
+ --> tests/ui/rename.rs:85:9
|
LL | #![warn(clippy::incorrect_partial_ord_impl_on_ord_type)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::non_canonical_partial_ord_impl`
error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects`
- --> tests/ui/rename.rs:84:9
+ --> tests/ui/rename.rs:86:9
|
LL | #![warn(clippy::integer_arithmetic)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects`
error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr`
- --> tests/ui/rename.rs:85:9
+ --> tests/ui/rename.rs:87:9
|
LL | #![warn(clippy::logic_bug)]
| ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr`
error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default`
- --> tests/ui/rename.rs:86:9
+ --> tests/ui/rename.rs:88:9
|
LL | #![warn(clippy::new_without_default_derive)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default`
error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map`
- --> tests/ui/rename.rs:87:9
+ --> tests/ui/rename.rs:89:9
|
LL | #![warn(clippy::option_and_then_some)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map`
error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used`
- --> tests/ui/rename.rs:88:9
+ --> tests/ui/rename.rs:90:9
|
LL | #![warn(clippy::option_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or`
- --> tests/ui/rename.rs:89:9
+ --> tests/ui/rename.rs:91:9
|
LL | #![warn(clippy::option_map_unwrap_or)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
- --> tests/ui/rename.rs:90:9
+ --> tests/ui/rename.rs:92:9
|
LL | #![warn(clippy::option_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used`
- --> tests/ui/rename.rs:91:9
+ --> tests/ui/rename.rs:93:9
|
LL | #![warn(clippy::option_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
error: lint `clippy::overflow_check_conditional` has been renamed to `clippy::panicking_overflow_checks`
- --> tests/ui/rename.rs:92:9
+ --> tests/ui/rename.rs:94:9
|
LL | #![warn(clippy::overflow_check_conditional)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::panicking_overflow_checks`
error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow`
- --> tests/ui/rename.rs:93:9
+ --> tests/ui/rename.rs:95:9
|
LL | #![warn(clippy::ref_in_deref)]
| ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow`
error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used`
- --> tests/ui/rename.rs:94:9
+ --> tests/ui/rename.rs:96:9
|
LL | #![warn(clippy::result_expect_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used`
error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or`
- --> tests/ui/rename.rs:95:9
+ --> tests/ui/rename.rs:97:9
|
LL | #![warn(clippy::result_map_unwrap_or_else)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or`
error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used`
- --> tests/ui/rename.rs:96:9
+ --> tests/ui/rename.rs:98:9
|
LL | #![warn(clippy::result_unwrap_used)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used`
-error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges`
- --> tests/ui/rename.rs:97:9
- |
-LL | #![warn(clippy::reverse_range_loop)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
-
error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str`
- --> tests/ui/rename.rs:98:9
+ --> tests/ui/rename.rs:99:9
|
LL | #![warn(clippy::single_char_push_str)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str`
error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions`
- --> tests/ui/rename.rs:99:9
+ --> tests/ui/rename.rs:100:9
|
LL | #![warn(clippy::stutter)]
| ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions`
error: lint `clippy::thread_local_initializer_can_be_made_const` has been renamed to `clippy::missing_const_for_thread_local`
- --> tests/ui/rename.rs:100:9
+ --> tests/ui/rename.rs:101:9
|
LL | #![warn(clippy::thread_local_initializer_can_be_made_const)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::missing_const_for_thread_local`
error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl`
- --> tests/ui/rename.rs:101:9
+ --> tests/ui/rename.rs:102:9
|
LL | #![warn(clippy::to_string_in_display)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl`
error: lint `clippy::unwrap_or_else_default` has been renamed to `clippy::unwrap_or_default`
- --> tests/ui/rename.rs:102:9
+ --> tests/ui/rename.rs:103:9
|
LL | #![warn(clippy::unwrap_or_else_default)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_or_default`
error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters`
- --> tests/ui/rename.rs:103:9
+ --> tests/ui/rename.rs:104:9
|
LL | #![warn(clippy::zero_width_space)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters`
error: lint `clippy::cast_ref_to_mut` has been renamed to `invalid_reference_casting`
- --> tests/ui/rename.rs:104:9
+ --> tests/ui/rename.rs:105:9
|
LL | #![warn(clippy::cast_ref_to_mut)]
| ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_reference_casting`
error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op`
- --> tests/ui/rename.rs:105:9
+ --> tests/ui/rename.rs:106:9
|
LL | #![warn(clippy::clone_double_ref)]
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op`
error: lint `clippy::cmp_nan` has been renamed to `invalid_nan_comparisons`
- --> tests/ui/rename.rs:106:9
+ --> tests/ui/rename.rs:107:9
|
LL | #![warn(clippy::cmp_nan)]
| ^^^^^^^^^^^^^^^ help: use the new name: `invalid_nan_comparisons`
+error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments`
+ --> tests/ui/rename.rs:108:9
+ |
+LL | #![warn(clippy::invalid_null_ptr_usage)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments`
+
error: lint `clippy::double_neg` has been renamed to `double_negations`
- --> tests/ui/rename.rs:107:9
+ --> tests/ui/rename.rs:109:9
|
LL | #![warn(clippy::double_neg)]
| ^^^^^^^^^^^^^^^^^^ help: use the new name: `double_negations`
error: lint `clippy::drop_bounds` has been renamed to `drop_bounds`
- --> tests/ui/rename.rs:108:9
+ --> tests/ui/rename.rs:110:9
|
LL | #![warn(clippy::drop_bounds)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds`
error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types`
- --> tests/ui/rename.rs:109:9
+ --> tests/ui/rename.rs:111:9
|
LL | #![warn(clippy::drop_copy)]
| ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types`
error: lint `clippy::drop_ref` has been renamed to `dropping_references`
- --> tests/ui/rename.rs:110:9
+ --> tests/ui/rename.rs:112:9
|
LL | #![warn(clippy::drop_ref)]
| ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references`
-error: lint `clippy::fn_address_comparisons` has been renamed to `unpredictable_function_pointer_comparisons`
- --> tests/ui/rename.rs:111:9
- |
-LL | #![warn(clippy::fn_address_comparisons)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unpredictable_function_pointer_comparisons`
-
error: lint `clippy::fn_null_check` has been renamed to `useless_ptr_null_checks`
- --> tests/ui/rename.rs:112:9
+ --> tests/ui/rename.rs:113:9
|
LL | #![warn(clippy::fn_null_check)]
| ^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `useless_ptr_null_checks`
error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles`
- --> tests/ui/rename.rs:113:9
+ --> tests/ui/rename.rs:114:9
|
LL | #![warn(clippy::for_loop_over_option)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles`
- --> tests/ui/rename.rs:114:9
+ --> tests/ui/rename.rs:115:9
|
LL | #![warn(clippy::for_loop_over_result)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles`
- --> tests/ui/rename.rs:115:9
+ --> tests/ui/rename.rs:116:9
|
LL | #![warn(clippy::for_loops_over_fallibles)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles`
error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types`
- --> tests/ui/rename.rs:116:9
+ --> tests/ui/rename.rs:117:9
|
LL | #![warn(clippy::forget_copy)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types`
error: lint `clippy::forget_ref` has been renamed to `forgetting_references`
- --> tests/ui/rename.rs:117:9
+ --> tests/ui/rename.rs:118:9
|
LL | #![warn(clippy::forget_ref)]
| ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references`
error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter`
- --> tests/ui/rename.rs:118:9
+ --> tests/ui/rename.rs:119:9
|
LL | #![warn(clippy::into_iter_on_array)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter`
error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering`
- --> tests/ui/rename.rs:119:9
+ --> tests/ui/rename.rs:120:9
|
LL | #![warn(clippy::invalid_atomic_ordering)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering`
error: lint `clippy::invalid_ref` has been renamed to `invalid_value`
- --> tests/ui/rename.rs:120:9
+ --> tests/ui/rename.rs:121:9
|
LL | #![warn(clippy::invalid_ref)]
| ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value`
error: lint `clippy::invalid_utf8_in_unchecked` has been renamed to `invalid_from_utf8_unchecked`
- --> tests/ui/rename.rs:121:9
+ --> tests/ui/rename.rs:122:9
|
LL | #![warn(clippy::invalid_utf8_in_unchecked)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_from_utf8_unchecked`
-error: lint `clippy::invalid_null_ptr_usage` has been renamed to `invalid_null_arguments`
- --> tests/ui/rename.rs:122:9
- |
-LL | #![warn(clippy::invalid_null_ptr_usage)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_null_arguments`
-
error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop`
--> tests/ui/rename.rs:123:9
|
@@ -415,5 +409,11 @@
LL | #![warn(clippy::vtable_address_comparisons)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `ambiguous_wide_pointer_comparisons`
+error: lint `clippy::reverse_range_loop` has been renamed to `clippy::reversed_empty_ranges`
+ --> tests/ui/rename.rs:134:9
+ |
+LL | #![warn(clippy::reverse_range_loop)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::reversed_empty_ranges`
+
error: aborting due to 69 previous errors
diff --git a/src/tools/clippy/tests/ui/repr_packed_without_abi.stderr b/src/tools/clippy/tests/ui/repr_packed_without_abi.stderr
index d1078b3..f688e4b 100644
--- a/src/tools/clippy/tests/ui/repr_packed_without_abi.stderr
+++ b/src/tools/clippy/tests/ui/repr_packed_without_abi.stderr
@@ -11,7 +11,7 @@
| |_^
|
= warning: unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI
- = help: qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`
+ = help: qualify the desired ABI explicitly via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`
note: the lint level is defined here
--> tests/ui/repr_packed_without_abi.rs:1:9
|
@@ -31,7 +31,7 @@
| |_^
|
= warning: unqualified `#[repr(packed)]` defaults to `#[repr(Rust, packed)]`, which has no stable ABI
- = help: qualify the desired ABI explicity via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`
+ = help: qualify the desired ABI explicitly via `#[repr(C, packed)]` or `#[repr(Rust, packed)]`
error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/result_unit_error_no_std.rs b/src/tools/clippy/tests/ui/result_unit_error_no_std.rs
index 8a1849b..a64e841 100644
--- a/src/tools/clippy/tests/ui/result_unit_error_no_std.rs
+++ b/src/tools/clippy/tests/ui/result_unit_error_no_std.rs
@@ -14,7 +14,7 @@ pub fn returns_unit_error_lint() -> Result<u32, ()> {
Err(())
}
-#[no_mangle]
+#[unsafe(no_mangle)]
extern "C" fn main(_argc: core::ffi::c_int, _argv: *const *const u8) -> core::ffi::c_int {
0
}
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed
index 847e514..cc4dbc9 100644
--- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed
@@ -214,10 +214,9 @@
}
fn ref_bindings() {
- let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
- //~^ search_is_some
- let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
- //~^ search_is_some
+ let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)]
+ //~^ search_is_some
+ .iter().any(|&&(&x, ref y)| x == *y);
}
fn test_string_1(s: &str) -> bool {
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs
index e976d12..fa31a9d 100644
--- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs
@@ -221,10 +221,11 @@ pub fn by_ref(&self, x: &u32) -> bool {
}
fn ref_bindings() {
- let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none();
- //~^ search_is_some
- let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none();
- //~^ search_is_some
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)]
+ //~^ search_is_some
+ .iter()
+ .find(|&&&(&x, ref y)| x == *y)
+ .is_none();
}
fn test_string_1(s: &str) -> bool {
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr
index ccc1702..b079cf7 100644
--- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.stderr
@@ -248,116 +248,122 @@
error: called `is_none()` after searching an `Iterator` with `find`
--> tests/ui/search_is_some_fixable_none.rs:224:17
|
-LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)`
-
-error: called `is_none()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_none.rs:226:17
+LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)]
+ | _________________^
+LL | |
+LL | | .iter()
+LL | | .find(|&&&(&x, ref y)| x == *y)
+LL | | .is_none();
+ | |______________________^
|
-LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)`
+help: consider using
+ |
+LL ~ let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)]
+LL +
+LL ~ .iter().any(|&&(&x, ref y)| x == *y);
+ |
error: called `is_none()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_none.rs:246:17
+ --> tests/ui/search_is_some_fixable_none.rs:247:17
|
LL | let _ = v.iter().find(|s| s[0].is_empty()).is_none();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|s| s[0].is_empty())`
error: called `is_none()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_none.rs:248:17
+ --> tests/ui/search_is_some_fixable_none.rs:249:17
|
LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_none();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|s| test_string_1(&s[0]))`
error: called `is_none()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_none.rs:258:17
+ --> tests/ui/search_is_some_fixable_none.rs:259:17
|
LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_none();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| fp.field.is_power_of_two())`
error: called `is_none()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_none.rs:260:17
+ --> tests/ui/search_is_some_fixable_none.rs:261:17
|
LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_none();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_1(fp.field))`
error: called `is_none()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_none.rs:262:17
+ --> tests/ui/search_is_some_fixable_none.rs:263:17
|
LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_none();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|fp| test_u32_2(*fp.field))`
error: called `is_none()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_none.rs:279:17
+ --> tests/ui/search_is_some_fixable_none.rs:280:17
|
LL | let _ = v.iter().find(|x| **x == 42).is_none();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 42)`
error: called `is_none()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_none.rs:281:17
+ --> tests/ui/search_is_some_fixable_none.rs:282:17
|
LL | Foo.bar(v.iter().find(|x| **x == 42).is_none());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!v.iter().any(|x| *x == 42)`
error: called `is_none()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_none.rs:287:9
+ --> tests/ui/search_is_some_fixable_none.rs:288:9
|
LL | v.iter().find(|x| **x == 42).is_none().then(computations);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!v.iter().any(|x| *x == 42))`
error: called `is_none()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_none.rs:293:9
+ --> tests/ui/search_is_some_fixable_none.rs:294:9
|
LL | v.iter().find(|x| **x == 42).is_none().then_some(0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!v.iter().any(|x| *x == 42))`
error: called `is_none()` after calling `find()` on a string
- --> tests/ui/search_is_some_fixable_none.rs:299:17
+ --> tests/ui/search_is_some_fixable_none.rs:300:17
|
LL | let _ = s.find("world").is_none();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")`
error: called `is_none()` after calling `find()` on a string
- --> tests/ui/search_is_some_fixable_none.rs:301:17
+ --> tests/ui/search_is_some_fixable_none.rs:302:17
|
LL | Foo.bar(s.find("world").is_none());
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")`
error: called `is_none()` after calling `find()` on a string
- --> tests/ui/search_is_some_fixable_none.rs:304:17
+ --> tests/ui/search_is_some_fixable_none.rs:305:17
|
LL | let _ = s.find("world").is_none();
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")`
error: called `is_none()` after calling `find()` on a string
- --> tests/ui/search_is_some_fixable_none.rs:306:17
+ --> tests/ui/search_is_some_fixable_none.rs:307:17
|
LL | Foo.bar(s.find("world").is_none());
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `!s.contains("world")`
error: called `is_none()` after calling `find()` on a string
- --> tests/ui/search_is_some_fixable_none.rs:312:17
+ --> tests/ui/search_is_some_fixable_none.rs:313:17
|
LL | let _ = s.find("world").is_none().then(computations);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))`
error: called `is_none()` after calling `find()` on a string
- --> tests/ui/search_is_some_fixable_none.rs:315:17
+ --> tests/ui/search_is_some_fixable_none.rs:316:17
|
LL | let _ = s.find("world").is_none().then(computations);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))`
error: called `is_none()` after calling `find()` on a string
- --> tests/ui/search_is_some_fixable_none.rs:321:17
+ --> tests/ui/search_is_some_fixable_none.rs:322:17
|
LL | let _ = s.find("world").is_none().then_some(0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))`
error: called `is_none()` after calling `find()` on a string
- --> tests/ui/search_is_some_fixable_none.rs:324:17
+ --> tests/ui/search_is_some_fixable_none.rs:325:17
|
LL | let _ = s.find("world").is_none().then_some(0);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `(!s.contains("world"))`
-error: aborting due to 55 previous errors
+error: aborting due to 54 previous errors
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none_2021.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable_none_2021.fixed
new file mode 100644
index 0000000..6e15244
--- /dev/null
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none_2021.fixed
@@ -0,0 +1,14 @@
+//@edition: 2021
+#![warn(clippy::search_is_some)]
+
+fn main() {
+ fn ref_bindings() {
+ let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
+ //~^ search_is_some
+ let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
+ //~^ search_is_some
+ let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)]
+ //~^ search_is_some
+ .iter().any(|&&(&x, ref y)| x == *y);
+ }
+}
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none_2021.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_none_2021.rs
new file mode 100644
index 0000000..4b1db3f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none_2021.rs
@@ -0,0 +1,16 @@
+//@edition: 2021
+#![warn(clippy::search_is_some)]
+
+fn main() {
+ fn ref_bindings() {
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none();
+ //~^ search_is_some
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none();
+ //~^ search_is_some
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)]
+ //~^ search_is_some
+ .iter()
+ .find(|&&&(&x, ref y)| x == *y)
+ .is_none();
+ }
+}
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none_2021.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_none_2021.stderr
new file mode 100644
index 0000000..af93be1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none_2021.stderr
@@ -0,0 +1,35 @@
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> tests/ui/search_is_some_fixable_none_2021.rs:6:17
+ |
+LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)`
+ |
+ = note: `-D clippy::search-is-some` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> tests/ui/search_is_some_fixable_none_2021.rs:8:17
+ |
+LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_none();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `![&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y)`
+
+error: called `is_none()` after searching an `Iterator` with `find`
+ --> tests/ui/search_is_some_fixable_none_2021.rs:10:17
+ |
+LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)]
+ | _________________^
+LL | |
+LL | | .iter()
+LL | | .find(|&&&(&x, ref y)| x == *y)
+LL | | .is_none();
+ | |______________________^
+ |
+help: consider using
+ |
+LL ~ let _ = ![&(&1, 2), &(&3, 4), &(&5, 4)]
+LL +
+LL ~ .iter().any(|&&(&x, ref y)| x == *y);
+ |
+
+error: aborting due to 3 previous errors
+
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed
index 05e88b8..42b39b3 100644
--- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed
@@ -214,10 +214,9 @@
}
fn ref_bindings() {
- let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
- //~^ search_is_some
- let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
- //~^ search_is_some
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)]
+ .iter()
+ .any(|&&(&x, ref y)| x == *y);
}
fn test_string_1(s: &str) -> bool {
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs
index caab816..ca4f4d9 100644
--- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs
@@ -220,10 +220,11 @@ pub fn by_ref(&self, x: &u32) -> bool {
}
fn ref_bindings() {
- let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some();
- //~^ search_is_some
- let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some();
- //~^ search_is_some
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)]
+ .iter()
+ .find(|&&&(&x, ref y)| x == *y)
+ //~^ search_is_some
+ .is_some();
}
fn test_string_1(s: &str) -> bool {
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr
index af719b7..8291f48d 100644
--- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.stderr
@@ -227,70 +227,67 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|v| v.by_ref(&v.bar))`
error: called `is_some()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_some.rs:223:55
+ --> tests/ui/search_is_some_fixable_some.rs:225:14
|
-LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|(&x, y)| x == *y)`
+LL | .find(|&&&(&x, ref y)| x == *y)
+ | ______________^
+LL | |
+LL | | .is_some();
+ | |______________________^ help: consider using: `any(|&&(&x, ref y)| x == *y)`
error: called `is_some()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_some.rs:225:55
- |
-LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|(&x, y)| x == *y)`
-
-error: called `is_some()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_some.rs:245:26
+ --> tests/ui/search_is_some_fixable_some.rs:246:26
|
LL | let _ = v.iter().find(|s| s[0].is_empty()).is_some();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|s| s[0].is_empty())`
error: called `is_some()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_some.rs:247:26
+ --> tests/ui/search_is_some_fixable_some.rs:248:26
|
LL | let _ = v.iter().find(|s| test_string_1(&s[0])).is_some();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|s| test_string_1(&s[0]))`
error: called `is_some()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_some.rs:257:26
+ --> tests/ui/search_is_some_fixable_some.rs:258:26
|
LL | let _ = v.iter().find(|fp| fp.field.is_power_of_two()).is_some();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|fp| fp.field.is_power_of_two())`
error: called `is_some()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_some.rs:259:26
+ --> tests/ui/search_is_some_fixable_some.rs:260:26
|
LL | let _ = v.iter().find(|fp| test_u32_1(fp.field)).is_some();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|fp| test_u32_1(fp.field))`
error: called `is_some()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_some.rs:261:26
+ --> tests/ui/search_is_some_fixable_some.rs:262:26
|
LL | let _ = v.iter().find(|fp| test_u32_2(*fp.field)).is_some();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|fp| test_u32_2(*fp.field))`
error: called `is_some()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_some.rs:277:18
+ --> tests/ui/search_is_some_fixable_some.rs:278:18
|
LL | v.iter().find(|x: &&u32| func(x)).is_some()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| func(&x))`
error: called `is_some()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_some.rs:287:26
+ --> tests/ui/search_is_some_fixable_some.rs:288:26
|
LL | let _ = v.iter().find(|x: &&u32| arg_no_deref_impl(x)).is_some();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| arg_no_deref_impl(&x))`
error: called `is_some()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_some.rs:291:26
+ --> tests/ui/search_is_some_fixable_some.rs:292:26
|
LL | let _ = v.iter().find(|x: &&u32| arg_no_deref_dyn(x)).is_some();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| arg_no_deref_dyn(&x))`
error: called `is_some()` after searching an `Iterator` with `find`
- --> tests/ui/search_is_some_fixable_some.rs:295:26
+ --> tests/ui/search_is_some_fixable_some.rs:296:26
|
LL | let _ = v.iter().find(|x: &&u32| (*arg_no_deref_dyn)(x)).is_some();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|x: &u32| (*arg_no_deref_dyn)(&x))`
-error: aborting due to 47 previous errors
+error: aborting due to 46 previous errors
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some_2021.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable_some_2021.fixed
new file mode 100644
index 0000000..d2b05db
--- /dev/null
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some_2021.fixed
@@ -0,0 +1,11 @@
+//@edition: 2021
+#![warn(clippy::search_is_some)]
+
+fn main() {
+ fn ref_bindings() {
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
+ //~^ search_is_some
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().any(|(&x, y)| x == *y);
+ //~^ search_is_some
+ }
+}
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some_2021.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_some_2021.rs
new file mode 100644
index 0000000..c3f5ef7
--- /dev/null
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some_2021.rs
@@ -0,0 +1,11 @@
+//@edition: 2021
+#![warn(clippy::search_is_some)]
+
+fn main() {
+ fn ref_bindings() {
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some();
+ //~^ search_is_some
+ let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some();
+ //~^ search_is_some
+ }
+}
diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some_2021.stderr b/src/tools/clippy/tests/ui/search_is_some_fixable_some_2021.stderr
new file mode 100644
index 0000000..91d9540
--- /dev/null
+++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some_2021.stderr
@@ -0,0 +1,17 @@
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> tests/ui/search_is_some_fixable_some_2021.rs:6:55
+ |
+LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|(&x, y)| x == *y).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|(&x, y)| x == *y)`
+ |
+ = note: `-D clippy::search-is-some` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::search_is_some)]`
+
+error: called `is_some()` after searching an `Iterator` with `find`
+ --> tests/ui/search_is_some_fixable_some_2021.rs:8:55
+ |
+LL | let _ = [&(&1, 2), &(&3, 4), &(&5, 4)].iter().find(|&(&x, y)| x == *y).is_some();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `any(|(&x, y)| x == *y)`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/shadow.rs b/src/tools/clippy/tests/ui/shadow.rs
index 7d503a1..05009b2 100644
--- a/src/tools/clippy/tests/ui/shadow.rs
+++ b/src/tools/clippy/tests/ui/shadow.rs
@@ -167,4 +167,19 @@ fn issue13795(value: Issue13795) {
//~^ shadow_same
}
+fn issue14377() {
+ let a;
+ let b;
+ (a, b) = (0, 1);
+
+ struct S {
+ c: i32,
+ d: i32,
+ }
+
+ let c;
+ let d;
+ S { c, d } = S { c: 1, d: 2 };
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs b/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs
index 4ec0f02..53704f5 100644
--- a/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs
+++ b/src/tools/clippy/tests/ui/should_impl_trait/corner_cases.rs
@@ -1,6 +1,5 @@
//@ check-pass
-#![warn(clippy::all, clippy::pedantic)]
#![allow(
clippy::missing_errors_doc,
clippy::needless_pass_by_value,
diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs
index 87b3a7d..e8de0e0 100644
--- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs
+++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.rs
@@ -1,4 +1,3 @@
-#![warn(clippy::all, clippy::pedantic)]
#![allow(
clippy::missing_errors_doc,
clippy::needless_pass_by_value,
diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr
index 8738b61..5609d6a 100644
--- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr
+++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_1.stderr
@@ -1,5 +1,5 @@
error: method `add` can be confused for the standard trait method `std::ops::Add::add`
- --> tests/ui/should_impl_trait/method_list_1.rs:25:5
+ --> tests/ui/should_impl_trait/method_list_1.rs:24:5
|
LL | / pub fn add(self, other: T) -> T {
LL | |
@@ -13,7 +13,7 @@
= help: to override `-D warnings` add `#[allow(clippy::should_implement_trait)]`
error: method `as_mut` can be confused for the standard trait method `std::convert::AsMut::as_mut`
- --> tests/ui/should_impl_trait/method_list_1.rs:31:5
+ --> tests/ui/should_impl_trait/method_list_1.rs:30:5
|
LL | / pub fn as_mut(&mut self) -> &mut T {
LL | |
@@ -25,7 +25,7 @@
= help: consider implementing the trait `std::convert::AsMut` or choosing a less ambiguous method name
error: method `as_ref` can be confused for the standard trait method `std::convert::AsRef::as_ref`
- --> tests/ui/should_impl_trait/method_list_1.rs:37:5
+ --> tests/ui/should_impl_trait/method_list_1.rs:36:5
|
LL | / pub fn as_ref(&self) -> &T {
LL | |
@@ -37,7 +37,7 @@
= help: consider implementing the trait `std::convert::AsRef` or choosing a less ambiguous method name
error: method `bitand` can be confused for the standard trait method `std::ops::BitAnd::bitand`
- --> tests/ui/should_impl_trait/method_list_1.rs:43:5
+ --> tests/ui/should_impl_trait/method_list_1.rs:42:5
|
LL | / pub fn bitand(self, rhs: T) -> T {
LL | |
@@ -49,7 +49,7 @@
= help: consider implementing the trait `std::ops::BitAnd` or choosing a less ambiguous method name
error: method `bitor` can be confused for the standard trait method `std::ops::BitOr::bitor`
- --> tests/ui/should_impl_trait/method_list_1.rs:49:5
+ --> tests/ui/should_impl_trait/method_list_1.rs:48:5
|
LL | / pub fn bitor(self, rhs: Self) -> Self {
LL | |
@@ -61,7 +61,7 @@
= help: consider implementing the trait `std::ops::BitOr` or choosing a less ambiguous method name
error: method `bitxor` can be confused for the standard trait method `std::ops::BitXor::bitxor`
- --> tests/ui/should_impl_trait/method_list_1.rs:55:5
+ --> tests/ui/should_impl_trait/method_list_1.rs:54:5
|
LL | / pub fn bitxor(self, rhs: Self) -> Self {
LL | |
@@ -73,7 +73,7 @@
= help: consider implementing the trait `std::ops::BitXor` or choosing a less ambiguous method name
error: method `borrow` can be confused for the standard trait method `std::borrow::Borrow::borrow`
- --> tests/ui/should_impl_trait/method_list_1.rs:61:5
+ --> tests/ui/should_impl_trait/method_list_1.rs:60:5
|
LL | / pub fn borrow(&self) -> &str {
LL | |
@@ -85,7 +85,7 @@
= help: consider implementing the trait `std::borrow::Borrow` or choosing a less ambiguous method name
error: method `borrow_mut` can be confused for the standard trait method `std::borrow::BorrowMut::borrow_mut`
- --> tests/ui/should_impl_trait/method_list_1.rs:67:5
+ --> tests/ui/should_impl_trait/method_list_1.rs:66:5
|
LL | / pub fn borrow_mut(&mut self) -> &mut str {
LL | |
@@ -97,7 +97,7 @@
= help: consider implementing the trait `std::borrow::BorrowMut` or choosing a less ambiguous method name
error: method `clone` can be confused for the standard trait method `std::clone::Clone::clone`
- --> tests/ui/should_impl_trait/method_list_1.rs:73:5
+ --> tests/ui/should_impl_trait/method_list_1.rs:72:5
|
LL | / pub fn clone(&self) -> Self {
LL | |
@@ -109,7 +109,7 @@
= help: consider implementing the trait `std::clone::Clone` or choosing a less ambiguous method name
error: method `cmp` can be confused for the standard trait method `std::cmp::Ord::cmp`
- --> tests/ui/should_impl_trait/method_list_1.rs:79:5
+ --> tests/ui/should_impl_trait/method_list_1.rs:78:5
|
LL | / pub fn cmp(&self, other: &Self) -> Self {
LL | |
@@ -121,7 +121,7 @@
= help: consider implementing the trait `std::cmp::Ord` or choosing a less ambiguous method name
error: method `default` can be confused for the standard trait method `std::default::Default::default`
- --> tests/ui/should_impl_trait/method_list_1.rs:85:5
+ --> tests/ui/should_impl_trait/method_list_1.rs:84:5
|
LL | / pub fn default() -> Self {
LL | |
@@ -133,7 +133,7 @@
= help: consider implementing the trait `std::default::Default` or choosing a less ambiguous method name
error: method `deref` can be confused for the standard trait method `std::ops::Deref::deref`
- --> tests/ui/should_impl_trait/method_list_1.rs:91:5
+ --> tests/ui/should_impl_trait/method_list_1.rs:90:5
|
LL | / pub fn deref(&self) -> &Self {
LL | |
@@ -145,7 +145,7 @@
= help: consider implementing the trait `std::ops::Deref` or choosing a less ambiguous method name
error: method `deref_mut` can be confused for the standard trait method `std::ops::DerefMut::deref_mut`
- --> tests/ui/should_impl_trait/method_list_1.rs:97:5
+ --> tests/ui/should_impl_trait/method_list_1.rs:96:5
|
LL | / pub fn deref_mut(&mut self) -> &mut Self {
LL | |
@@ -157,7 +157,7 @@
= help: consider implementing the trait `std::ops::DerefMut` or choosing a less ambiguous method name
error: method `div` can be confused for the standard trait method `std::ops::Div::div`
- --> tests/ui/should_impl_trait/method_list_1.rs:103:5
+ --> tests/ui/should_impl_trait/method_list_1.rs:102:5
|
LL | / pub fn div(self, rhs: Self) -> Self {
LL | |
@@ -169,7 +169,7 @@
= help: consider implementing the trait `std::ops::Div` or choosing a less ambiguous method name
error: method `drop` can be confused for the standard trait method `std::ops::Drop::drop`
- --> tests/ui/should_impl_trait/method_list_1.rs:109:5
+ --> tests/ui/should_impl_trait/method_list_1.rs:108:5
|
LL | / pub fn drop(&mut self) {
LL | |
diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs
index f0c4d4f..1f25ab3 100644
--- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs
+++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.rs
@@ -1,4 +1,3 @@
-#![warn(clippy::all, clippy::pedantic)]
#![allow(
clippy::missing_errors_doc,
clippy::needless_pass_by_value,
diff --git a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
index 85de743..0f58185 100644
--- a/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
+++ b/src/tools/clippy/tests/ui/should_impl_trait/method_list_2.stderr
@@ -1,5 +1,5 @@
error: method `eq` can be confused for the standard trait method `std::cmp::PartialEq::eq`
- --> tests/ui/should_impl_trait/method_list_2.rs:26:5
+ --> tests/ui/should_impl_trait/method_list_2.rs:25:5
|
LL | / pub fn eq(&self, other: &Self) -> bool {
LL | |
@@ -13,7 +13,7 @@
= help: to override `-D warnings` add `#[allow(clippy::should_implement_trait)]`
error: method `from_iter` can be confused for the standard trait method `std::iter::FromIterator::from_iter`
- --> tests/ui/should_impl_trait/method_list_2.rs:32:5
+ --> tests/ui/should_impl_trait/method_list_2.rs:31:5
|
LL | / pub fn from_iter<T>(iter: T) -> Self {
LL | |
@@ -25,7 +25,7 @@
= help: consider implementing the trait `std::iter::FromIterator` or choosing a less ambiguous method name
error: method `from_str` can be confused for the standard trait method `std::str::FromStr::from_str`
- --> tests/ui/should_impl_trait/method_list_2.rs:38:5
+ --> tests/ui/should_impl_trait/method_list_2.rs:37:5
|
LL | / pub fn from_str(s: &str) -> Result<Self, Self> {
LL | |
@@ -37,7 +37,7 @@
= help: consider implementing the trait `std::str::FromStr` or choosing a less ambiguous method name
error: method `hash` can be confused for the standard trait method `std::hash::Hash::hash`
- --> tests/ui/should_impl_trait/method_list_2.rs:44:5
+ --> tests/ui/should_impl_trait/method_list_2.rs:43:5
|
LL | / pub fn hash(&self, state: &mut T) {
LL | |
@@ -49,7 +49,7 @@
= help: consider implementing the trait `std::hash::Hash` or choosing a less ambiguous method name
error: method `index` can be confused for the standard trait method `std::ops::Index::index`
- --> tests/ui/should_impl_trait/method_list_2.rs:50:5
+ --> tests/ui/should_impl_trait/method_list_2.rs:49:5
|
LL | / pub fn index(&self, index: usize) -> &Self {
LL | |
@@ -61,7 +61,7 @@
= help: consider implementing the trait `std::ops::Index` or choosing a less ambiguous method name
error: method `index_mut` can be confused for the standard trait method `std::ops::IndexMut::index_mut`
- --> tests/ui/should_impl_trait/method_list_2.rs:56:5
+ --> tests/ui/should_impl_trait/method_list_2.rs:55:5
|
LL | / pub fn index_mut(&mut self, index: usize) -> &mut Self {
LL | |
@@ -73,7 +73,7 @@
= help: consider implementing the trait `std::ops::IndexMut` or choosing a less ambiguous method name
error: method `into_iter` can be confused for the standard trait method `std::iter::IntoIterator::into_iter`
- --> tests/ui/should_impl_trait/method_list_2.rs:62:5
+ --> tests/ui/should_impl_trait/method_list_2.rs:61:5
|
LL | / pub fn into_iter(self) -> Self {
LL | |
@@ -85,7 +85,7 @@
= help: consider implementing the trait `std::iter::IntoIterator` or choosing a less ambiguous method name
error: method `mul` can be confused for the standard trait method `std::ops::Mul::mul`
- --> tests/ui/should_impl_trait/method_list_2.rs:68:5
+ --> tests/ui/should_impl_trait/method_list_2.rs:67:5
|
LL | / pub fn mul(self, rhs: Self) -> Self {
LL | |
@@ -97,7 +97,7 @@
= help: consider implementing the trait `std::ops::Mul` or choosing a less ambiguous method name
error: method `neg` can be confused for the standard trait method `std::ops::Neg::neg`
- --> tests/ui/should_impl_trait/method_list_2.rs:74:5
+ --> tests/ui/should_impl_trait/method_list_2.rs:73:5
|
LL | / pub fn neg(self) -> Self {
LL | |
@@ -109,7 +109,7 @@
= help: consider implementing the trait `std::ops::Neg` or choosing a less ambiguous method name
error: method `next` can be confused for the standard trait method `std::iter::Iterator::next`
- --> tests/ui/should_impl_trait/method_list_2.rs:80:5
+ --> tests/ui/should_impl_trait/method_list_2.rs:79:5
|
LL | / pub fn next(&mut self) -> Option<Self> {
LL | |
@@ -121,7 +121,7 @@
= help: consider implementing the trait `std::iter::Iterator` or choosing a less ambiguous method name
error: method `not` can be confused for the standard trait method `std::ops::Not::not`
- --> tests/ui/should_impl_trait/method_list_2.rs:86:5
+ --> tests/ui/should_impl_trait/method_list_2.rs:85:5
|
LL | / pub fn not(self) -> Self {
LL | |
@@ -133,7 +133,7 @@
= help: consider implementing the trait `std::ops::Not` or choosing a less ambiguous method name
error: method `rem` can be confused for the standard trait method `std::ops::Rem::rem`
- --> tests/ui/should_impl_trait/method_list_2.rs:92:5
+ --> tests/ui/should_impl_trait/method_list_2.rs:91:5
|
LL | / pub fn rem(self, rhs: Self) -> Self {
LL | |
@@ -145,7 +145,7 @@
= help: consider implementing the trait `std::ops::Rem` or choosing a less ambiguous method name
error: method `shl` can be confused for the standard trait method `std::ops::Shl::shl`
- --> tests/ui/should_impl_trait/method_list_2.rs:98:5
+ --> tests/ui/should_impl_trait/method_list_2.rs:97:5
|
LL | / pub fn shl(self, rhs: Self) -> Self {
LL | |
@@ -157,7 +157,7 @@
= help: consider implementing the trait `std::ops::Shl` or choosing a less ambiguous method name
error: method `shr` can be confused for the standard trait method `std::ops::Shr::shr`
- --> tests/ui/should_impl_trait/method_list_2.rs:104:5
+ --> tests/ui/should_impl_trait/method_list_2.rs:103:5
|
LL | / pub fn shr(self, rhs: Self) -> Self {
LL | |
@@ -169,7 +169,7 @@
= help: consider implementing the trait `std::ops::Shr` or choosing a less ambiguous method name
error: method `sub` can be confused for the standard trait method `std::ops::Sub::sub`
- --> tests/ui/should_impl_trait/method_list_2.rs:110:5
+ --> tests/ui/should_impl_trait/method_list_2.rs:109:5
|
LL | / pub fn sub(self, rhs: Self) -> Self {
LL | |
diff --git a/src/tools/clippy/tests/ui/single_call_fn.rs b/src/tools/clippy/tests/ui/single_call_fn.rs
index c1cc403..a1ecd7b 100644
--- a/src/tools/clippy/tests/ui/single_call_fn.rs
+++ b/src/tools/clippy/tests/ui/single_call_fn.rs
@@ -94,7 +94,7 @@ fn default() {}
//~^ single_call_fn
fn foo(&self);
}
-extern "C" {
+unsafe extern "C" {
// test some kind of foreign item
fn rand() -> std::ffi::c_int;
}
diff --git a/src/tools/clippy/tests/ui/single_match.fixed b/src/tools/clippy/tests/ui/single_match.fixed
index 0e198ec..db51076 100644
--- a/src/tools/clippy/tests/ui/single_match.fixed
+++ b/src/tools/clippy/tests/ui/single_match.fixed
@@ -366,3 +366,39 @@
//~^^^^^^^^^ single_match
//~| NOTE: you might want to preserve the comments from inside the `match`
}
+
+fn issue_14493() {
+ macro_rules! mac {
+ (some) => {
+ Some(42)
+ };
+ (any) => {
+ _
+ };
+ (str) => {
+ "foo"
+ };
+ }
+
+ if let Some(u) = mac!(some) { println!("{u}") }
+ //~^^^^ single_match
+
+ // When scrutinee comes from macro, do not tell that arm will always match
+ // and suggest an equality check instead.
+ if mac!(str) == "foo" { println!("eq") }
+ //~^^^^ ERROR: for an equality check
+
+ // Do not lint if any match arm come from expansion
+ match Some(0) {
+ mac!(some) => println!("eq"),
+ mac!(any) => println!("neq"),
+ }
+ match Some(0) {
+ Some(42) => println!("eq"),
+ mac!(any) => println!("neq"),
+ }
+ match Some(0) {
+ mac!(some) => println!("eq"),
+ _ => println!("neq"),
+ }
+}
diff --git a/src/tools/clippy/tests/ui/single_match.rs b/src/tools/clippy/tests/ui/single_match.rs
index fcac65f..a367b94 100644
--- a/src/tools/clippy/tests/ui/single_match.rs
+++ b/src/tools/clippy/tests/ui/single_match.rs
@@ -461,3 +461,45 @@ fn irrefutable_match() {
//~^^^^^^^^^ single_match
//~| NOTE: you might want to preserve the comments from inside the `match`
}
+
+fn issue_14493() {
+ macro_rules! mac {
+ (some) => {
+ Some(42)
+ };
+ (any) => {
+ _
+ };
+ (str) => {
+ "foo"
+ };
+ }
+
+ match mac!(some) {
+ Some(u) => println!("{u}"),
+ _ => (),
+ }
+ //~^^^^ single_match
+
+ // When scrutinee comes from macro, do not tell that arm will always match
+ // and suggest an equality check instead.
+ match mac!(str) {
+ "foo" => println!("eq"),
+ _ => (),
+ }
+ //~^^^^ ERROR: for an equality check
+
+ // Do not lint if any match arm come from expansion
+ match Some(0) {
+ mac!(some) => println!("eq"),
+ mac!(any) => println!("neq"),
+ }
+ match Some(0) {
+ Some(42) => println!("eq"),
+ mac!(any) => println!("neq"),
+ }
+ match Some(0) {
+ mac!(some) => println!("eq"),
+ _ => println!("neq"),
+ }
+}
diff --git a/src/tools/clippy/tests/ui/single_match.stderr b/src/tools/clippy/tests/ui/single_match.stderr
index 2467423..1a4edc4 100644
--- a/src/tools/clippy/tests/ui/single_match.stderr
+++ b/src/tools/clippy/tests/ui/single_match.stderr
@@ -321,5 +321,23 @@
LL + }
|
-error: aborting due to 29 previous errors
+error: you seem to be trying to use `match` for destructuring a single pattern. Consider using `if let`
+ --> tests/ui/single_match.rs:478:5
+ |
+LL | / match mac!(some) {
+LL | | Some(u) => println!("{u}"),
+LL | | _ => (),
+LL | | }
+ | |_____^ help: try: `if let Some(u) = mac!(some) { println!("{u}") }`
+
+error: you seem to be trying to use `match` for an equality check. Consider using `if`
+ --> tests/ui/single_match.rs:486:5
+ |
+LL | / match mac!(str) {
+LL | | "foo" => println!("eq"),
+LL | | _ => (),
+LL | | }
+ | |_____^ help: try: `if mac!(str) == "foo" { println!("eq") }`
+
+error: aborting due to 31 previous errors
diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed b/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed
index 3696b0e..3faa4b2 100644
--- a/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed
+++ b/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed
@@ -87,4 +87,8 @@
use std::mem;
}
+// Do not lint, this is not a `///!`
+#[doc = "! here's some docs !"]
+fn issue14265() {}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments.rs b/src/tools/clippy/tests/ui/suspicious_doc_comments.rs
index 4107f55..4af6ed8 100644
--- a/src/tools/clippy/tests/ui/suspicious_doc_comments.rs
+++ b/src/tools/clippy/tests/ui/suspicious_doc_comments.rs
@@ -87,4 +87,8 @@ pub mod useless_outer_doc {
use std::mem;
}
+// Do not lint, this is not a `///!`
+#[doc = "! here's some docs !"]
+fn issue14265() {}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/swap.fixed b/src/tools/clippy/tests/ui/swap.fixed
index 888665a..6a64e64 100644
--- a/src/tools/clippy/tests/ui/swap.fixed
+++ b/src/tools/clippy/tests/ui/swap.fixed
@@ -1,14 +1,9 @@
//@aux-build: macro_rules.rs
-#![warn(clippy::all)]
#![allow(
clippy::disallowed_names,
clippy::no_effect,
clippy::redundant_clone,
- redundant_semicolons,
- dead_code,
- unused_assignments,
- unused_variables,
clippy::let_and_return,
clippy::useless_vec,
clippy::redundant_locals
diff --git a/src/tools/clippy/tests/ui/swap.rs b/src/tools/clippy/tests/ui/swap.rs
index 51af55e..e2d89c4 100644
--- a/src/tools/clippy/tests/ui/swap.rs
+++ b/src/tools/clippy/tests/ui/swap.rs
@@ -1,14 +1,9 @@
//@aux-build: macro_rules.rs
-#![warn(clippy::all)]
#![allow(
clippy::disallowed_names,
clippy::no_effect,
clippy::redundant_clone,
- redundant_semicolons,
- dead_code,
- unused_assignments,
- unused_variables,
clippy::let_and_return,
clippy::useless_vec,
clippy::redundant_locals
diff --git a/src/tools/clippy/tests/ui/swap.stderr b/src/tools/clippy/tests/ui/swap.stderr
index 15f7566..195b888 100644
--- a/src/tools/clippy/tests/ui/swap.stderr
+++ b/src/tools/clippy/tests/ui/swap.stderr
@@ -1,5 +1,5 @@
error: this looks like you are swapping `bar.a` and `bar.b` manually
- --> tests/ui/swap.rs:28:5
+ --> tests/ui/swap.rs:23:5
|
LL | / let temp = bar.a;
LL | |
@@ -12,7 +12,7 @@
= help: to override `-D warnings` add `#[allow(clippy::manual_swap)]`
error: this looks like you are swapping elements of `foo` manually
- --> tests/ui/swap.rs:41:5
+ --> tests/ui/swap.rs:36:5
|
LL | / let temp = foo[0];
LL | |
@@ -21,7 +21,7 @@
| |__________________^ help: try: `foo.swap(0, 1);`
error: this looks like you are swapping elements of `foo` manually
- --> tests/ui/swap.rs:51:5
+ --> tests/ui/swap.rs:46:5
|
LL | / let temp = foo[0];
LL | |
@@ -30,7 +30,7 @@
| |__________________^ help: try: `foo.swap(0, 1);`
error: this looks like you are swapping elements of `foo` manually
- --> tests/ui/swap.rs:71:5
+ --> tests/ui/swap.rs:66:5
|
LL | / let temp = foo[0];
LL | |
@@ -39,7 +39,7 @@
| |__________________^ help: try: `foo.swap(0, 1);`
error: this looks like you are swapping `a` and `b` manually
- --> tests/ui/swap.rs:83:5
+ --> tests/ui/swap.rs:78:5
|
LL | / a ^= b;
LL | |
@@ -48,7 +48,7 @@
| |___________^ help: try: `std::mem::swap(&mut a, &mut b);`
error: this looks like you are swapping `bar.a` and `bar.b` manually
- --> tests/ui/swap.rs:92:5
+ --> tests/ui/swap.rs:87:5
|
LL | / bar.a ^= bar.b;
LL | |
@@ -57,7 +57,7 @@
| |___________________^ help: try: `std::mem::swap(&mut bar.a, &mut bar.b);`
error: this looks like you are swapping elements of `foo` manually
- --> tests/ui/swap.rs:101:5
+ --> tests/ui/swap.rs:96:5
|
LL | / foo[0] ^= foo[1];
LL | |
@@ -66,7 +66,7 @@
| |_____________________^ help: try: `foo.swap(0, 1);`
error: this looks like you are swapping `foo[0][1]` and `bar[1][0]` manually
- --> tests/ui/swap.rs:131:5
+ --> tests/ui/swap.rs:126:5
|
LL | / let temp = foo[0][1];
LL | |
@@ -77,7 +77,7 @@
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are swapping `a` and `b` manually
- --> tests/ui/swap.rs:147:7
+ --> tests/ui/swap.rs:142:7
|
LL | ; let t = a;
| _______^
@@ -89,7 +89,7 @@
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are swapping `c.0` and `a` manually
- --> tests/ui/swap.rs:158:7
+ --> tests/ui/swap.rs:153:7
|
LL | ; let t = c.0;
| _______^
@@ -101,7 +101,7 @@
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are swapping `b` and `a` manually
- --> tests/ui/swap.rs:188:5
+ --> tests/ui/swap.rs:183:5
|
LL | / let t = b;
LL | |
@@ -112,7 +112,7 @@
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are trying to swap `a` and `b`
- --> tests/ui/swap.rs:143:5
+ --> tests/ui/swap.rs:138:5
|
LL | / a = b;
LL | |
@@ -120,11 +120,10 @@
| |_________^ help: try: `std::mem::swap(&mut a, &mut b)`
|
= note: or maybe you should use `std::mem::replace`?
- = note: `-D clippy::almost-swapped` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::almost_swapped)]`
+ = note: `#[deny(clippy::almost_swapped)]` on by default
error: this looks like you are trying to swap `c.0` and `a`
- --> tests/ui/swap.rs:154:5
+ --> tests/ui/swap.rs:149:5
|
LL | / c.0 = a;
LL | |
@@ -134,7 +133,7 @@
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are trying to swap `a` and `b`
- --> tests/ui/swap.rs:163:5
+ --> tests/ui/swap.rs:158:5
|
LL | / let a = b;
LL | |
@@ -144,7 +143,7 @@
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are trying to swap `d` and `c`
- --> tests/ui/swap.rs:169:5
+ --> tests/ui/swap.rs:164:5
|
LL | / d = c;
LL | |
@@ -154,7 +153,7 @@
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are trying to swap `a` and `b`
- --> tests/ui/swap.rs:174:5
+ --> tests/ui/swap.rs:169:5
|
LL | / let a = b;
LL | |
@@ -164,7 +163,7 @@
= note: or maybe you should use `std::mem::replace`?
error: this looks like you are swapping `s.0.x` and `s.0.y` manually
- --> tests/ui/swap.rs:224:5
+ --> tests/ui/swap.rs:219:5
|
LL | / let t = s.0.x;
LL | |
diff --git a/src/tools/clippy/tests/ui/swap_with_temporary.fixed b/src/tools/clippy/tests/ui/swap_with_temporary.fixed
new file mode 100644
index 0000000..4007d99
--- /dev/null
+++ b/src/tools/clippy/tests/ui/swap_with_temporary.fixed
@@ -0,0 +1,74 @@
+#![warn(clippy::swap_with_temporary)]
+
+use std::mem::swap;
+
+fn func() -> String {
+ String::from("func")
+}
+
+fn func_returning_refmut(s: &mut String) -> &mut String {
+ s
+}
+
+fn main() {
+ let mut x = String::from("x");
+ let mut y = String::from("y");
+ let mut zz = String::from("zz");
+ let z = &mut zz;
+
+ // No lint
+ swap(&mut x, &mut y);
+
+ y = func();
+ //~^ ERROR: swapping with a temporary value is inefficient
+
+ x = func();
+ //~^ ERROR: swapping with a temporary value is inefficient
+
+ *z = func();
+ //~^ ERROR: swapping with a temporary value is inefficient
+
+ // No lint
+ swap(z, func_returning_refmut(&mut x));
+
+ swap(&mut y, z);
+
+ *z = func();
+ //~^ ERROR: swapping with a temporary value is inefficient
+
+ macro_rules! mac {
+ (refmut $x:expr) => {
+ &mut $x
+ };
+ (funcall $f:ident) => {
+ $f()
+ };
+ (wholeexpr) => {
+ swap(&mut 42, &mut 0)
+ };
+ (ident $v:ident) => {
+ $v
+ };
+ }
+ *z = mac!(funcall func);
+ //~^ ERROR: swapping with a temporary value is inefficient
+ *mac!(ident z) = mac!(funcall func);
+ //~^ ERROR: swapping with a temporary value is inefficient
+ *mac!(ident z) = mac!(funcall func);
+ //~^ ERROR: swapping with a temporary value is inefficient
+ *mac!(refmut y) = func();
+ //~^ ERROR: swapping with a temporary value is inefficient
+
+ // No lint if it comes from a macro as it may depend on the arguments
+ mac!(wholeexpr);
+}
+
+struct S {
+ t: String,
+}
+
+fn dont_lint_those(s: &mut S, v: &mut [String], w: Option<&mut String>) {
+ swap(&mut s.t, &mut v[0]);
+ swap(&mut s.t, v.get_mut(0).unwrap());
+ swap(w.unwrap(), &mut s.t);
+}
diff --git a/src/tools/clippy/tests/ui/swap_with_temporary.rs b/src/tools/clippy/tests/ui/swap_with_temporary.rs
new file mode 100644
index 0000000..d403c08
--- /dev/null
+++ b/src/tools/clippy/tests/ui/swap_with_temporary.rs
@@ -0,0 +1,74 @@
+#![warn(clippy::swap_with_temporary)]
+
+use std::mem::swap;
+
+fn func() -> String {
+ String::from("func")
+}
+
+fn func_returning_refmut(s: &mut String) -> &mut String {
+ s
+}
+
+fn main() {
+ let mut x = String::from("x");
+ let mut y = String::from("y");
+ let mut zz = String::from("zz");
+ let z = &mut zz;
+
+ // No lint
+ swap(&mut x, &mut y);
+
+ swap(&mut func(), &mut y);
+ //~^ ERROR: swapping with a temporary value is inefficient
+
+ swap(&mut x, &mut func());
+ //~^ ERROR: swapping with a temporary value is inefficient
+
+ swap(z, &mut func());
+ //~^ ERROR: swapping with a temporary value is inefficient
+
+ // No lint
+ swap(z, func_returning_refmut(&mut x));
+
+ swap(&mut y, z);
+
+ swap(&mut func(), z);
+ //~^ ERROR: swapping with a temporary value is inefficient
+
+ macro_rules! mac {
+ (refmut $x:expr) => {
+ &mut $x
+ };
+ (funcall $f:ident) => {
+ $f()
+ };
+ (wholeexpr) => {
+ swap(&mut 42, &mut 0)
+ };
+ (ident $v:ident) => {
+ $v
+ };
+ }
+ swap(&mut mac!(funcall func), z);
+ //~^ ERROR: swapping with a temporary value is inefficient
+ swap(&mut mac!(funcall func), mac!(ident z));
+ //~^ ERROR: swapping with a temporary value is inefficient
+ swap(mac!(ident z), &mut mac!(funcall func));
+ //~^ ERROR: swapping with a temporary value is inefficient
+ swap(mac!(refmut y), &mut func());
+ //~^ ERROR: swapping with a temporary value is inefficient
+
+ // No lint if it comes from a macro as it may depend on the arguments
+ mac!(wholeexpr);
+}
+
+struct S {
+ t: String,
+}
+
+fn dont_lint_those(s: &mut S, v: &mut [String], w: Option<&mut String>) {
+ swap(&mut s.t, &mut v[0]);
+ swap(&mut s.t, v.get_mut(0).unwrap());
+ swap(w.unwrap(), &mut s.t);
+}
diff --git a/src/tools/clippy/tests/ui/swap_with_temporary.stderr b/src/tools/clippy/tests/ui/swap_with_temporary.stderr
new file mode 100644
index 0000000..5935577
--- /dev/null
+++ b/src/tools/clippy/tests/ui/swap_with_temporary.stderr
@@ -0,0 +1,100 @@
+error: swapping with a temporary value is inefficient
+ --> tests/ui/swap_with_temporary.rs:22:5
+ |
+LL | swap(&mut func(), &mut y);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `y = func()`
+ |
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary.rs:22:15
+ |
+LL | swap(&mut func(), &mut y);
+ | ^^^^^^
+ = note: `-D clippy::swap-with-temporary` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::swap_with_temporary)]`
+
+error: swapping with a temporary value is inefficient
+ --> tests/ui/swap_with_temporary.rs:25:5
+ |
+LL | swap(&mut x, &mut func());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `x = func()`
+ |
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary.rs:25:23
+ |
+LL | swap(&mut x, &mut func());
+ | ^^^^^^
+
+error: swapping with a temporary value is inefficient
+ --> tests/ui/swap_with_temporary.rs:28:5
+ |
+LL | swap(z, &mut func());
+ | ^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `*z = func()`
+ |
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary.rs:28:18
+ |
+LL | swap(z, &mut func());
+ | ^^^^^^
+
+error: swapping with a temporary value is inefficient
+ --> tests/ui/swap_with_temporary.rs:36:5
+ |
+LL | swap(&mut func(), z);
+ | ^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `*z = func()`
+ |
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary.rs:36:15
+ |
+LL | swap(&mut func(), z);
+ | ^^^^^^
+
+error: swapping with a temporary value is inefficient
+ --> tests/ui/swap_with_temporary.rs:53:5
+ |
+LL | swap(&mut mac!(funcall func), z);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `*z = mac!(funcall func)`
+ |
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary.rs:53:15
+ |
+LL | swap(&mut mac!(funcall func), z);
+ | ^^^^^^^^^^^^^^^^^^
+
+error: swapping with a temporary value is inefficient
+ --> tests/ui/swap_with_temporary.rs:55:5
+ |
+LL | swap(&mut mac!(funcall func), mac!(ident z));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `*mac!(ident z) = mac!(funcall func)`
+ |
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary.rs:55:15
+ |
+LL | swap(&mut mac!(funcall func), mac!(ident z));
+ | ^^^^^^^^^^^^^^^^^^
+
+error: swapping with a temporary value is inefficient
+ --> tests/ui/swap_with_temporary.rs:57:5
+ |
+LL | swap(mac!(ident z), &mut mac!(funcall func));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `*mac!(ident z) = mac!(funcall func)`
+ |
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary.rs:57:30
+ |
+LL | swap(mac!(ident z), &mut mac!(funcall func));
+ | ^^^^^^^^^^^^^^^^^^
+
+error: swapping with a temporary value is inefficient
+ --> tests/ui/swap_with_temporary.rs:59:5
+ |
+LL | swap(mac!(refmut y), &mut func());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use assignment instead: `*mac!(refmut y) = func()`
+ |
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary.rs:59:31
+ |
+LL | swap(mac!(refmut y), &mut func());
+ | ^^^^^^
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/swap_with_temporary_unfixable.rs b/src/tools/clippy/tests/ui/swap_with_temporary_unfixable.rs
new file mode 100644
index 0000000..a974ca8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/swap_with_temporary_unfixable.rs
@@ -0,0 +1,62 @@
+//@no-rustfix
+#![warn(clippy::swap_with_temporary)]
+
+use std::mem::swap;
+
+fn func() -> String {
+ String::from("func")
+}
+
+fn func_returning_refmut(s: &mut String) -> &mut String {
+ s
+}
+
+fn main() {
+ let mut x = String::from("x");
+ let mut y = String::from("y");
+ let mut zz = String::from("zz");
+ let z = &mut zz;
+
+ swap(&mut func(), &mut func());
+ //~^ ERROR: swapping temporary values has no effect
+
+ if matches!(swap(&mut func(), &mut func()), ()) {
+ //~^ ERROR: swapping temporary values has no effect
+ println!("Yeah");
+ }
+
+ if matches!(swap(z, &mut func()), ()) {
+ //~^ ERROR: swapping with a temporary value is inefficient
+ println!("Yeah");
+ }
+
+ macro_rules! mac {
+ (refmut $x:expr) => {
+ &mut $x
+ };
+ (refmut) => {
+ mac!(refmut String::new())
+ };
+ (funcall $f:ident) => {
+ $f()
+ };
+ }
+
+ swap(mac!(refmut func()), z);
+ //~^ ERROR: swapping with a temporary value is inefficient
+ swap(&mut mac!(funcall func), &mut mac!(funcall func));
+ //~^ ERROR: swapping temporary values has no effect
+ swap(mac!(refmut), mac!(refmut));
+ //~^ ERROR: swapping temporary values has no effect
+ swap(mac!(refmut y), mac!(refmut));
+ //~^ ERROR: swapping with a temporary value is inefficient
+}
+
+fn bug(v1: &mut [i32], v2: &mut [i32]) {
+ // Incorrect: swapping temporary references (`&mut &mut` passed to swap)
+ std::mem::swap(&mut v1.last_mut().unwrap(), &mut v2.last_mut().unwrap());
+ //~^ ERROR: swapping temporary values has no effect
+
+ // Correct
+ std::mem::swap(v1.last_mut().unwrap(), v2.last_mut().unwrap());
+}
diff --git a/src/tools/clippy/tests/ui/swap_with_temporary_unfixable.stderr b/src/tools/clippy/tests/ui/swap_with_temporary_unfixable.stderr
new file mode 100644
index 0000000..856c541
--- /dev/null
+++ b/src/tools/clippy/tests/ui/swap_with_temporary_unfixable.stderr
@@ -0,0 +1,125 @@
+error: swapping temporary values has no effect
+ --> tests/ui/swap_with_temporary_unfixable.rs:20:5
+ |
+LL | swap(&mut func(), &mut func());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary_unfixable.rs:20:15
+ |
+LL | swap(&mut func(), &mut func());
+ | ^^^^^^
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary_unfixable.rs:20:28
+ |
+LL | swap(&mut func(), &mut func());
+ | ^^^^^^
+ = note: `-D clippy::swap-with-temporary` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::swap_with_temporary)]`
+
+error: swapping temporary values has no effect
+ --> tests/ui/swap_with_temporary_unfixable.rs:23:17
+ |
+LL | if matches!(swap(&mut func(), &mut func()), ()) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary_unfixable.rs:23:27
+ |
+LL | if matches!(swap(&mut func(), &mut func()), ()) {
+ | ^^^^^^
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary_unfixable.rs:23:40
+ |
+LL | if matches!(swap(&mut func(), &mut func()), ()) {
+ | ^^^^^^
+
+error: swapping with a temporary value is inefficient
+ --> tests/ui/swap_with_temporary_unfixable.rs:28:17
+ |
+LL | if matches!(swap(z, &mut func()), ()) {
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary_unfixable.rs:28:30
+ |
+LL | if matches!(swap(z, &mut func()), ()) {
+ | ^^^^^^
+
+error: swapping with a temporary value is inefficient
+ --> tests/ui/swap_with_temporary_unfixable.rs:45:5
+ |
+LL | swap(mac!(refmut func()), z);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: this is a mutable reference to a temporary value
+ --> tests/ui/swap_with_temporary_unfixable.rs:45:10
+ |
+LL | swap(mac!(refmut func()), z);
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: swapping temporary values has no effect
+ --> tests/ui/swap_with_temporary_unfixable.rs:47:5
+ |
+LL | swap(&mut mac!(funcall func), &mut mac!(funcall func));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary_unfixable.rs:47:15
+ |
+LL | swap(&mut mac!(funcall func), &mut mac!(funcall func));
+ | ^^^^^^^^^^^^^^^^^^
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary_unfixable.rs:47:40
+ |
+LL | swap(&mut mac!(funcall func), &mut mac!(funcall func));
+ | ^^^^^^^^^^^^^^^^^^
+
+error: swapping temporary values has no effect
+ --> tests/ui/swap_with_temporary_unfixable.rs:49:5
+ |
+LL | swap(mac!(refmut), mac!(refmut));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: this is a mutable reference to a temporary value
+ --> tests/ui/swap_with_temporary_unfixable.rs:49:10
+ |
+LL | swap(mac!(refmut), mac!(refmut));
+ | ^^^^^^^^^^^^
+note: this is a mutable reference to a temporary value
+ --> tests/ui/swap_with_temporary_unfixable.rs:49:24
+ |
+LL | swap(mac!(refmut), mac!(refmut));
+ | ^^^^^^^^^^^^
+
+error: swapping with a temporary value is inefficient
+ --> tests/ui/swap_with_temporary_unfixable.rs:51:5
+ |
+LL | swap(mac!(refmut y), mac!(refmut));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: this is a mutable reference to a temporary value
+ --> tests/ui/swap_with_temporary_unfixable.rs:51:26
+ |
+LL | swap(mac!(refmut y), mac!(refmut));
+ | ^^^^^^^^^^^^
+
+error: swapping temporary values has no effect
+ --> tests/ui/swap_with_temporary_unfixable.rs:57:5
+ |
+LL | std::mem::swap(&mut v1.last_mut().unwrap(), &mut v2.last_mut().unwrap());
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary_unfixable.rs:57:25
+ |
+LL | std::mem::swap(&mut v1.last_mut().unwrap(), &mut v2.last_mut().unwrap());
+ | ^^^^^^^^^^^^^^^^^^^^^^
+note: this expression returns a temporary value
+ --> tests/ui/swap_with_temporary_unfixable.rs:57:54
+ |
+LL | std::mem::swap(&mut v1.last_mut().unwrap(), &mut v2.last_mut().unwrap());
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+
diff --git a/src/tools/clippy/tests/ui/transmute.rs b/src/tools/clippy/tests/ui/transmute.rs
index 3aecde3..8c8674a 100644
--- a/src/tools/clippy/tests/ui/transmute.rs
+++ b/src/tools/clippy/tests/ui/transmute.rs
@@ -23,19 +23,21 @@ fn my_vec() -> MyVec<i32> {
#[allow(clippy::needless_lifetimes, clippy::transmute_ptr_to_ptr)]
#[warn(clippy::useless_transmute)]
unsafe fn _generic<'a, T, U: 'a>(t: &'a T) {
- // FIXME: should lint
- // let _: &'a T = core::mem::transmute(t);
+ unsafe {
+ // FIXME: should lint
+ // let _: &'a T = core::mem::transmute(t);
- let _: &'a U = core::mem::transmute(t);
+ let _: &'a U = core::mem::transmute(t);
- let _: *const T = core::mem::transmute(t);
- //~^ useless_transmute
+ let _: *const T = core::mem::transmute(t);
+ //~^ useless_transmute
- let _: *mut T = core::mem::transmute(t);
- //~^ useless_transmute
+ let _: *mut T = core::mem::transmute(t);
+ //~^ useless_transmute
- let _: *const U = core::mem::transmute(t);
- //~^ useless_transmute
+ let _: *const U = core::mem::transmute(t);
+ //~^ useless_transmute
+ }
}
#[warn(clippy::useless_transmute)]
@@ -59,7 +61,7 @@ fn useless() {
let _: *const usize = std::mem::transmute(5_isize);
//~^ useless_transmute
- let _ = 5_isize as *const usize;
+ let _ = std::ptr::dangling::<usize>();
let _: *const usize = std::mem::transmute(1 + 1usize);
//~^ useless_transmute
@@ -68,19 +70,19 @@ fn useless() {
}
unsafe fn _f<'a, 'b>(x: &'a u32) -> &'b u32 {
- std::mem::transmute(x)
+ unsafe { std::mem::transmute(x) }
}
unsafe fn _f2<'a, 'b>(x: *const (dyn Iterator<Item = u32> + 'a)) -> *const (dyn Iterator<Item = u32> + 'b) {
- std::mem::transmute(x)
+ unsafe { std::mem::transmute(x) }
}
unsafe fn _f3<'a, 'b>(x: fn(&'a u32)) -> fn(&'b u32) {
- std::mem::transmute(x)
+ unsafe { std::mem::transmute(x) }
}
unsafe fn _f4<'a, 'b>(x: std::borrow::Cow<'a, str>) -> std::borrow::Cow<'b, str> {
- std::mem::transmute(x)
+ unsafe { std::mem::transmute(x) }
}
}
diff --git a/src/tools/clippy/tests/ui/transmute.stderr b/src/tools/clippy/tests/ui/transmute.stderr
index e0d2843..4219e09 100644
--- a/src/tools/clippy/tests/ui/transmute.stderr
+++ b/src/tools/clippy/tests/ui/transmute.stderr
@@ -1,68 +1,68 @@
error: transmute from a reference to a pointer
- --> tests/ui/transmute.rs:31:23
+ --> tests/ui/transmute.rs:32:27
|
-LL | let _: *const T = core::mem::transmute(t);
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T`
+LL | let _: *const T = core::mem::transmute(t);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T`
|
= note: `-D clippy::useless-transmute` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::useless_transmute)]`
error: transmute from a reference to a pointer
- --> tests/ui/transmute.rs:34:21
+ --> tests/ui/transmute.rs:35:25
|
-LL | let _: *mut T = core::mem::transmute(t);
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T`
+LL | let _: *mut T = core::mem::transmute(t);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *mut T`
error: transmute from a reference to a pointer
- --> tests/ui/transmute.rs:37:23
+ --> tests/ui/transmute.rs:38:27
|
-LL | let _: *const U = core::mem::transmute(t);
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U`
+LL | let _: *const U = core::mem::transmute(t);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `t as *const T as *const U`
error: transmute from a type (`std::vec::Vec<i32>`) to itself
- --> tests/ui/transmute.rs:44:27
+ --> tests/ui/transmute.rs:46:27
|
LL | let _: Vec<i32> = core::mem::transmute(my_vec());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmute from a type (`std::vec::Vec<i32>`) to itself
- --> tests/ui/transmute.rs:47:27
+ --> tests/ui/transmute.rs:49:27
|
LL | let _: Vec<i32> = core::mem::transmute(my_vec());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmute from a type (`std::vec::Vec<i32>`) to itself
- --> tests/ui/transmute.rs:50:27
+ --> tests/ui/transmute.rs:52:27
|
LL | let _: Vec<i32> = std::mem::transmute(my_vec());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmute from a type (`std::vec::Vec<i32>`) to itself
- --> tests/ui/transmute.rs:53:27
+ --> tests/ui/transmute.rs:55:27
|
LL | let _: Vec<i32> = std::mem::transmute(my_vec());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmute from a type (`std::vec::Vec<i32>`) to itself
- --> tests/ui/transmute.rs:56:27
+ --> tests/ui/transmute.rs:58:27
|
LL | let _: Vec<i32> = my_transmute(my_vec());
| ^^^^^^^^^^^^^^^^^^^^^^
error: transmute from an integer to a pointer
- --> tests/ui/transmute.rs:59:31
+ --> tests/ui/transmute.rs:61:31
|
LL | let _: *const usize = std::mem::transmute(5_isize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `5_isize as *const usize`
error: transmute from an integer to a pointer
- --> tests/ui/transmute.rs:64:31
+ --> tests/ui/transmute.rs:66:31
|
LL | let _: *const usize = std::mem::transmute(1 + 1usize);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(1 + 1usize) as *const usize`
error: transmute from a type (`*const Usize`) to the type that it points to (`Usize`)
- --> tests/ui/transmute.rs:96:24
+ --> tests/ui/transmute.rs:98:24
|
LL | let _: Usize = core::mem::transmute(int_const_ptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -71,25 +71,25 @@
= help: to override `-D warnings` add `#[allow(clippy::crosspointer_transmute)]`
error: transmute from a type (`*mut Usize`) to the type that it points to (`Usize`)
- --> tests/ui/transmute.rs:99:24
+ --> tests/ui/transmute.rs:101:24
|
LL | let _: Usize = core::mem::transmute(int_mut_ptr);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmute from a type (`Usize`) to a pointer to that type (`*const Usize`)
- --> tests/ui/transmute.rs:102:31
+ --> tests/ui/transmute.rs:104:31
|
LL | let _: *const Usize = core::mem::transmute(my_int());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmute from a type (`Usize`) to a pointer to that type (`*mut Usize`)
- --> tests/ui/transmute.rs:105:29
+ --> tests/ui/transmute.rs:107:29
|
LL | let _: *mut Usize = core::mem::transmute(my_int());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmute from a `u8` to a `bool`
- --> tests/ui/transmute.rs:112:28
+ --> tests/ui/transmute.rs:114:28
|
LL | let _: bool = unsafe { std::mem::transmute(0_u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `0_u8 != 0`
@@ -98,7 +98,7 @@
= help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_bool)]`
error: transmute from a `u16` to a `f16`
- --> tests/ui/transmute.rs:119:31
+ --> tests/ui/transmute.rs:121:31
|
LL | let _: f16 = unsafe { std::mem::transmute(0_u16) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)`
@@ -107,97 +107,97 @@
= help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_float)]`
error: transmute from a `i16` to a `f16`
- --> tests/ui/transmute.rs:122:31
+ --> tests/ui/transmute.rs:124:31
|
LL | let _: f16 = unsafe { std::mem::transmute(0_i16) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_i16 as u16)`
error: transmute from a `u32` to a `f32`
- --> tests/ui/transmute.rs:125:31
+ --> tests/ui/transmute.rs:127:31
|
LL | let _: f32 = unsafe { std::mem::transmute(0_u32) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
error: transmute from a `i32` to a `f32`
- --> tests/ui/transmute.rs:128:31
+ --> tests/ui/transmute.rs:130:31
|
LL | let _: f32 = unsafe { std::mem::transmute(0_i32) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_i32 as u32)`
error: transmute from a `u64` to a `f64`
- --> tests/ui/transmute.rs:131:31
+ --> tests/ui/transmute.rs:133:31
|
LL | let _: f64 = unsafe { std::mem::transmute(0_u64) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_u64)`
error: transmute from a `i64` to a `f64`
- --> tests/ui/transmute.rs:134:31
+ --> tests/ui/transmute.rs:136:31
|
LL | let _: f64 = unsafe { std::mem::transmute(0_i64) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
error: transmute from a `u128` to a `f128`
- --> tests/ui/transmute.rs:137:32
+ --> tests/ui/transmute.rs:139:32
|
LL | let _: f128 = unsafe { std::mem::transmute(0_u128) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_u128)`
error: transmute from a `i128` to a `f128`
- --> tests/ui/transmute.rs:140:32
+ --> tests/ui/transmute.rs:142:32
|
LL | let _: f128 = unsafe { std::mem::transmute(0_i128) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)`
error: transmute from a `u16` to a `f16`
- --> tests/ui/transmute.rs:145:39
+ --> tests/ui/transmute.rs:147:39
|
LL | const VALUE16: f16 = unsafe { std::mem::transmute(0_u16) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(0_u16)`
error: transmute from a `u32` to a `f32`
- --> tests/ui/transmute.rs:148:39
+ --> tests/ui/transmute.rs:150:39
|
LL | const VALUE32: f32 = unsafe { std::mem::transmute(0_u32) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(0_u32)`
error: transmute from a `i64` to a `f64`
- --> tests/ui/transmute.rs:151:39
+ --> tests/ui/transmute.rs:153:39
|
LL | const VALUE64: f64 = unsafe { std::mem::transmute(0_i64) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(0_i64 as u64)`
error: transmute from a `i128` to a `f128`
- --> tests/ui/transmute.rs:154:41
+ --> tests/ui/transmute.rs:156:41
|
LL | const VALUE128: f128 = unsafe { std::mem::transmute(0_i128) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(0_i128 as u128)`
error: transmute from a `i16` to a `f16`
- --> tests/ui/transmute.rs:158:22
+ --> tests/ui/transmute.rs:160:22
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f16::from_bits(v as u16)`
error: transmute from a `i32` to a `f32`
- --> tests/ui/transmute.rs:163:22
+ --> tests/ui/transmute.rs:165:22
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f32::from_bits(v as u32)`
error: transmute from a `u64` to a `f64`
- --> tests/ui/transmute.rs:168:22
+ --> tests/ui/transmute.rs:170:22
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f64::from_bits(v)`
error: transmute from a `u128` to a `f128`
- --> tests/ui/transmute.rs:173:22
+ --> tests/ui/transmute.rs:175:22
|
LL | unsafe { std::mem::transmute(v) }
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `f128::from_bits(v)`
error: transmute from a `u8` to a `[u8; 1]`
- --> tests/ui/transmute.rs:182:30
+ --> tests/ui/transmute.rs:184:30
|
LL | let _: [u8; 1] = std::mem::transmute(0u8);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
@@ -206,121 +206,121 @@
= help: to override `-D warnings` add `#[allow(clippy::transmute_num_to_bytes)]`
error: transmute from a `u32` to a `[u8; 4]`
- --> tests/ui/transmute.rs:185:30
+ --> tests/ui/transmute.rs:187:30
|
LL | let _: [u8; 4] = std::mem::transmute(0u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
error: transmute from a `u128` to a `[u8; 16]`
- --> tests/ui/transmute.rs:188:31
+ --> tests/ui/transmute.rs:190:31
|
LL | let _: [u8; 16] = std::mem::transmute(0u128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
error: transmute from a `i8` to a `[u8; 1]`
- --> tests/ui/transmute.rs:191:30
+ --> tests/ui/transmute.rs:193:30
|
LL | let _: [u8; 1] = std::mem::transmute(0i8);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
error: transmute from a `i32` to a `[u8; 4]`
- --> tests/ui/transmute.rs:194:30
+ --> tests/ui/transmute.rs:196:30
|
LL | let _: [u8; 4] = std::mem::transmute(0i32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
error: transmute from a `i128` to a `[u8; 16]`
- --> tests/ui/transmute.rs:197:31
+ --> tests/ui/transmute.rs:199:31
|
LL | let _: [u8; 16] = std::mem::transmute(0i128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
error: transmute from a `f16` to a `[u8; 2]`
- --> tests/ui/transmute.rs:200:30
+ --> tests/ui/transmute.rs:202:30
|
LL | let _: [u8; 2] = std::mem::transmute(0.0f16);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()`
error: transmute from a `f32` to a `[u8; 4]`
- --> tests/ui/transmute.rs:203:30
+ --> tests/ui/transmute.rs:205:30
|
LL | let _: [u8; 4] = std::mem::transmute(0.0f32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
error: transmute from a `f64` to a `[u8; 8]`
- --> tests/ui/transmute.rs:206:30
+ --> tests/ui/transmute.rs:208:30
|
LL | let _: [u8; 8] = std::mem::transmute(0.0f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
error: transmute from a `f128` to a `[u8; 16]`
- --> tests/ui/transmute.rs:209:31
+ --> tests/ui/transmute.rs:211:31
|
LL | let _: [u8; 16] = std::mem::transmute(0.0f128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()`
error: transmute from a `u8` to a `[u8; 1]`
- --> tests/ui/transmute.rs:215:30
+ --> tests/ui/transmute.rs:217:30
|
LL | let _: [u8; 1] = std::mem::transmute(0u8);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u8.to_ne_bytes()`
error: transmute from a `u32` to a `[u8; 4]`
- --> tests/ui/transmute.rs:218:30
+ --> tests/ui/transmute.rs:220:30
|
LL | let _: [u8; 4] = std::mem::transmute(0u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u32.to_ne_bytes()`
error: transmute from a `u128` to a `[u8; 16]`
- --> tests/ui/transmute.rs:221:31
+ --> tests/ui/transmute.rs:223:31
|
LL | let _: [u8; 16] = std::mem::transmute(0u128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0u128.to_ne_bytes()`
error: transmute from a `i8` to a `[u8; 1]`
- --> tests/ui/transmute.rs:224:30
+ --> tests/ui/transmute.rs:226:30
|
LL | let _: [u8; 1] = std::mem::transmute(0i8);
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i8.to_ne_bytes()`
error: transmute from a `i32` to a `[u8; 4]`
- --> tests/ui/transmute.rs:227:30
+ --> tests/ui/transmute.rs:229:30
|
LL | let _: [u8; 4] = std::mem::transmute(0i32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i32.to_ne_bytes()`
error: transmute from a `i128` to a `[u8; 16]`
- --> tests/ui/transmute.rs:230:31
+ --> tests/ui/transmute.rs:232:31
|
LL | let _: [u8; 16] = std::mem::transmute(0i128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0i128.to_ne_bytes()`
error: transmute from a `f16` to a `[u8; 2]`
- --> tests/ui/transmute.rs:233:30
+ --> tests/ui/transmute.rs:235:30
|
LL | let _: [u8; 2] = std::mem::transmute(0.0f16);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f16.to_ne_bytes()`
error: transmute from a `f32` to a `[u8; 4]`
- --> tests/ui/transmute.rs:236:30
+ --> tests/ui/transmute.rs:238:30
|
LL | let _: [u8; 4] = std::mem::transmute(0.0f32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f32.to_ne_bytes()`
error: transmute from a `f64` to a `[u8; 8]`
- --> tests/ui/transmute.rs:239:30
+ --> tests/ui/transmute.rs:241:30
|
LL | let _: [u8; 8] = std::mem::transmute(0.0f64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f64.to_ne_bytes()`
error: transmute from a `f128` to a `[u8; 16]`
- --> tests/ui/transmute.rs:242:31
+ --> tests/ui/transmute.rs:244:31
|
LL | let _: [u8; 16] = std::mem::transmute(0.0f128);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `to_ne_bytes()`: `0.0f128.to_ne_bytes()`
error: transmute from a `&[u8]` to a `&str`
- --> tests/ui/transmute.rs:251:28
+ --> tests/ui/transmute.rs:253:28
|
LL | let _: &str = unsafe { std::mem::transmute(B) };
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8(B).unwrap()`
@@ -329,13 +329,13 @@
= help: to override `-D warnings` add `#[allow(clippy::transmute_bytes_to_str)]`
error: transmute from a `&mut [u8]` to a `&mut str`
- --> tests/ui/transmute.rs:254:32
+ --> tests/ui/transmute.rs:256:32
|
LL | let _: &mut str = unsafe { std::mem::transmute(mb) };
| ^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_mut(mb).unwrap()`
error: transmute from a `&[u8]` to a `&str`
- --> tests/ui/transmute.rs:257:30
+ --> tests/ui/transmute.rs:259:30
|
LL | const _: &str = unsafe { std::mem::transmute(B) };
| ^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::str::from_utf8_unchecked(B)`
diff --git a/src/tools/clippy/tests/ui/transmute_null_to_fn.rs b/src/tools/clippy/tests/ui/transmute_null_to_fn.rs
index e88f05b..4712374 100644
--- a/src/tools/clippy/tests/ui/transmute_null_to_fn.rs
+++ b/src/tools/clippy/tests/ui/transmute_null_to_fn.rs
@@ -1,6 +1,7 @@
#![allow(dead_code)]
#![warn(clippy::transmute_null_to_fn)]
#![allow(clippy::zero_ptr, clippy::missing_transmute_annotations)]
+#![allow(clippy::manual_dangling_ptr)]
// Easy to lint because these only span one line.
fn one_liners() {
diff --git a/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr b/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr
index f7d8014..b5b0d4e 100644
--- a/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr
+++ b/src/tools/clippy/tests/ui/transmute_null_to_fn.stderr
@@ -1,5 +1,5 @@
error: transmuting a known null pointer into a function pointer
- --> tests/ui/transmute_null_to_fn.rs:8:23
+ --> tests/ui/transmute_null_to_fn.rs:9:23
|
LL | let _: fn() = std::mem::transmute(0 as *const ());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
@@ -9,7 +9,7 @@
= help: to override `-D warnings` add `#[allow(clippy::transmute_null_to_fn)]`
error: transmuting a known null pointer into a function pointer
- --> tests/ui/transmute_null_to_fn.rs:11:23
+ --> tests/ui/transmute_null_to_fn.rs:12:23
|
LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
@@ -17,7 +17,7 @@
= help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
error: transmuting a known null pointer into a function pointer
- --> tests/ui/transmute_null_to_fn.rs:22:23
+ --> tests/ui/transmute_null_to_fn.rs:23:23
|
LL | let _: fn() = std::mem::transmute(ZPTR);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
@@ -25,7 +25,7 @@
= help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
error: transmuting a known null pointer into a function pointer
- --> tests/ui/transmute_null_to_fn.rs:32:23
+ --> tests/ui/transmute_null_to_fn.rs:33:23
|
LL | let _: fn() = std::mem::transmute(0 as *const u8 as *const ());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
@@ -33,7 +33,7 @@
= help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
error: transmuting a known null pointer into a function pointer
- --> tests/ui/transmute_null_to_fn.rs:35:23
+ --> tests/ui/transmute_null_to_fn.rs:36:23
|
LL | let _: fn() = std::mem::transmute(std::ptr::null::<()>() as *const u8);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
@@ -41,7 +41,7 @@
= help: try wrapping your function pointer type in `Option<T>` instead, and using `None` as a null pointer value
error: transmuting a known null pointer into a function pointer
- --> tests/ui/transmute_null_to_fn.rs:38:23
+ --> tests/ui/transmute_null_to_fn.rs:39:23
|
LL | let _: fn() = std::mem::transmute(ZPTR as *const u8);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this transmute results in undefined behavior
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed
index 3a67be5..476e7e3 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.fixed
@@ -8,12 +8,12 @@
// Make sure we can do static lifetime transmutes
unsafe fn transmute_lifetime_to_static<'a, T>(t: &'a T) -> &'static T {
- transmute::<&'a T, &'static T>(t)
+ unsafe { transmute::<&'a T, &'static T>(t) }
}
// Make sure we can do non-static lifetime transmutes
unsafe fn transmute_lifetime<'a, 'b, T>(t: &'a T, u: &'b T) -> &'b T {
- transmute::<&'a T, &'b T>(t)
+ unsafe { transmute::<&'a T, &'b T>(t) }
}
struct LifetimeParam<'a> {
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs
index 01ad3a3..7356668 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ptr.rs
@@ -8,12 +8,12 @@
// Make sure we can do static lifetime transmutes
unsafe fn transmute_lifetime_to_static<'a, T>(t: &'a T) -> &'static T {
- transmute::<&'a T, &'static T>(t)
+ unsafe { transmute::<&'a T, &'static T>(t) }
}
// Make sure we can do non-static lifetime transmutes
unsafe fn transmute_lifetime<'a, 'b, T>(t: &'a T, u: &'b T) -> &'b T {
- transmute::<&'a T, &'b T>(t)
+ unsafe { transmute::<&'a T, &'b T>(t) }
}
struct LifetimeParam<'a> {
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
index 1bd45bc..61e3ac2f 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed
@@ -6,33 +6,35 @@
)]
unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
- let _: &T = &*p;
- //~^ transmute_ptr_to_ref
- let _: &T = &*p;
+ unsafe {
+ let _: &T = &*p;
+ //~^ transmute_ptr_to_ref
+ let _: &T = &*p;
- let _: &mut T = &mut *m;
- //~^ transmute_ptr_to_ref
- let _: &mut T = &mut *m;
+ let _: &mut T = &mut *m;
+ //~^ transmute_ptr_to_ref
+ let _: &mut T = &mut *m;
- let _: &T = &*m;
- //~^ transmute_ptr_to_ref
- let _: &T = &*m;
+ let _: &T = &*m;
+ //~^ transmute_ptr_to_ref
+ let _: &T = &*m;
- let _: &mut T = &mut *(p as *mut T);
- //~^ transmute_ptr_to_ref
- let _ = &mut *(p as *mut T);
+ let _: &mut T = &mut *(p as *mut T);
+ //~^ transmute_ptr_to_ref
+ let _ = &mut *(p as *mut T);
- let _: &T = &*(o as *const T);
- //~^ transmute_ptr_to_ref
- let _: &T = &*(o as *const T);
+ let _: &T = &*(o as *const T);
+ //~^ transmute_ptr_to_ref
+ let _: &T = &*(o as *const T);
- let _: &mut T = &mut *(om as *mut T);
- //~^ transmute_ptr_to_ref
- let _: &mut T = &mut *(om as *mut T);
+ let _: &mut T = &mut *(om as *mut T);
+ //~^ transmute_ptr_to_ref
+ let _: &mut T = &mut *(om as *mut T);
- let _: &T = &*(om as *const T);
- //~^ transmute_ptr_to_ref
- let _: &T = &*(om as *const T);
+ let _: &T = &*(om as *const T);
+ //~^ transmute_ptr_to_ref
+ let _: &T = &*(om as *const T);
+ }
}
fn _issue1231() {
@@ -54,47 +56,53 @@
}
unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
- match 0 {
- 0 => &*x.cast::<&u32>(),
- //~^ transmute_ptr_to_ref
- 1 => &*y.cast::<&u32>(),
- //~^ transmute_ptr_to_ref
- 2 => &*x.cast::<&'b u32>(),
- //~^ transmute_ptr_to_ref
- _ => &*y.cast::<&'b u32>(),
- //~^ transmute_ptr_to_ref
+ unsafe {
+ match 0 {
+ 0 => &*x.cast::<&u32>(),
+ //~^ transmute_ptr_to_ref
+ 1 => &*y.cast::<&u32>(),
+ //~^ transmute_ptr_to_ref
+ 2 => &*x.cast::<&'b u32>(),
+ //~^ transmute_ptr_to_ref
+ _ => &*y.cast::<&'b u32>(),
+ //~^ transmute_ptr_to_ref
+ }
}
}
#[clippy::msrv = "1.38"]
unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
- let a = 0u32;
- let a = &a as *const u32;
- let _: &u32 = &*a;
- //~^ transmute_ptr_to_ref
- let _: &u32 = &*a.cast::<u32>();
- //~^ transmute_ptr_to_ref
- match 0 {
- 0 => &*x.cast::<&u32>(),
+ unsafe {
+ let a = 0u32;
+ let a = &a as *const u32;
+ let _: &u32 = &*a;
//~^ transmute_ptr_to_ref
- _ => &*x.cast::<&'b u32>(),
+ let _: &u32 = &*a.cast::<u32>();
//~^ transmute_ptr_to_ref
+ match 0 {
+ 0 => &*x.cast::<&u32>(),
+ //~^ transmute_ptr_to_ref
+ _ => &*x.cast::<&'b u32>(),
+ //~^ transmute_ptr_to_ref
+ }
}
}
#[clippy::msrv = "1.37"]
unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
- let a = 0u32;
- let a = &a as *const u32;
- let _: &u32 = &*a;
- //~^ transmute_ptr_to_ref
- let _: &u32 = &*(a as *const u32);
- //~^ transmute_ptr_to_ref
- match 0 {
- 0 => &*(x as *const () as *const &u32),
+ unsafe {
+ let a = 0u32;
+ let a = &a as *const u32;
+ let _: &u32 = &*a;
//~^ transmute_ptr_to_ref
- _ => &*(x as *const () as *const &'b u32),
+ let _: &u32 = &*(a as *const u32);
//~^ transmute_ptr_to_ref
+ match 0 {
+ 0 => &*(x as *const () as *const &u32),
+ //~^ transmute_ptr_to_ref
+ _ => &*(x as *const () as *const &'b u32),
+ //~^ transmute_ptr_to_ref
+ }
}
}
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
index cbe64bf..48e2f52 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs
@@ -6,33 +6,35 @@
)]
unsafe fn _ptr_to_ref<T, U>(p: *const T, m: *mut T, o: *const U, om: *mut U) {
- let _: &T = std::mem::transmute(p);
- //~^ transmute_ptr_to_ref
- let _: &T = &*p;
+ unsafe {
+ let _: &T = std::mem::transmute(p);
+ //~^ transmute_ptr_to_ref
+ let _: &T = &*p;
- let _: &mut T = std::mem::transmute(m);
- //~^ transmute_ptr_to_ref
- let _: &mut T = &mut *m;
+ let _: &mut T = std::mem::transmute(m);
+ //~^ transmute_ptr_to_ref
+ let _: &mut T = &mut *m;
- let _: &T = std::mem::transmute(m);
- //~^ transmute_ptr_to_ref
- let _: &T = &*m;
+ let _: &T = std::mem::transmute(m);
+ //~^ transmute_ptr_to_ref
+ let _: &T = &*m;
- let _: &mut T = std::mem::transmute(p as *mut T);
- //~^ transmute_ptr_to_ref
- let _ = &mut *(p as *mut T);
+ let _: &mut T = std::mem::transmute(p as *mut T);
+ //~^ transmute_ptr_to_ref
+ let _ = &mut *(p as *mut T);
- let _: &T = std::mem::transmute(o);
- //~^ transmute_ptr_to_ref
- let _: &T = &*(o as *const T);
+ let _: &T = std::mem::transmute(o);
+ //~^ transmute_ptr_to_ref
+ let _: &T = &*(o as *const T);
- let _: &mut T = std::mem::transmute(om);
- //~^ transmute_ptr_to_ref
- let _: &mut T = &mut *(om as *mut T);
+ let _: &mut T = std::mem::transmute(om);
+ //~^ transmute_ptr_to_ref
+ let _: &mut T = &mut *(om as *mut T);
- let _: &T = std::mem::transmute(om);
- //~^ transmute_ptr_to_ref
- let _: &T = &*(om as *const T);
+ let _: &T = std::mem::transmute(om);
+ //~^ transmute_ptr_to_ref
+ let _: &T = &*(om as *const T);
+ }
}
fn _issue1231() {
@@ -54,47 +56,53 @@ struct Foo<'a, T> {
}
unsafe fn _issue8924<'a, 'b, 'c>(x: *const &'a u32, y: *const &'b u32) -> &'c &'b u32 {
- match 0 {
- 0 => std::mem::transmute(x),
- //~^ transmute_ptr_to_ref
- 1 => std::mem::transmute(y),
- //~^ transmute_ptr_to_ref
- 2 => std::mem::transmute::<_, &&'b u32>(x),
- //~^ transmute_ptr_to_ref
- _ => std::mem::transmute::<_, &&'b u32>(y),
- //~^ transmute_ptr_to_ref
+ unsafe {
+ match 0 {
+ 0 => std::mem::transmute(x),
+ //~^ transmute_ptr_to_ref
+ 1 => std::mem::transmute(y),
+ //~^ transmute_ptr_to_ref
+ 2 => std::mem::transmute::<_, &&'b u32>(x),
+ //~^ transmute_ptr_to_ref
+ _ => std::mem::transmute::<_, &&'b u32>(y),
+ //~^ transmute_ptr_to_ref
+ }
}
}
#[clippy::msrv = "1.38"]
unsafe fn _meets_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
- let a = 0u32;
- let a = &a as *const u32;
- let _: &u32 = std::mem::transmute(a);
- //~^ transmute_ptr_to_ref
- let _: &u32 = std::mem::transmute::<_, &u32>(a);
- //~^ transmute_ptr_to_ref
- match 0 {
- 0 => std::mem::transmute(x),
+ unsafe {
+ let a = 0u32;
+ let a = &a as *const u32;
+ let _: &u32 = std::mem::transmute(a);
//~^ transmute_ptr_to_ref
- _ => std::mem::transmute::<_, &&'b u32>(x),
+ let _: &u32 = std::mem::transmute::<_, &u32>(a);
//~^ transmute_ptr_to_ref
+ match 0 {
+ 0 => std::mem::transmute(x),
+ //~^ transmute_ptr_to_ref
+ _ => std::mem::transmute::<_, &&'b u32>(x),
+ //~^ transmute_ptr_to_ref
+ }
}
}
#[clippy::msrv = "1.37"]
unsafe fn _under_msrv<'a, 'b, 'c>(x: *const &'a u32) -> &'c &'b u32 {
- let a = 0u32;
- let a = &a as *const u32;
- let _: &u32 = std::mem::transmute(a);
- //~^ transmute_ptr_to_ref
- let _: &u32 = std::mem::transmute::<_, &u32>(a);
- //~^ transmute_ptr_to_ref
- match 0 {
- 0 => std::mem::transmute(x),
+ unsafe {
+ let a = 0u32;
+ let a = &a as *const u32;
+ let _: &u32 = std::mem::transmute(a);
//~^ transmute_ptr_to_ref
- _ => std::mem::transmute::<_, &&'b u32>(x),
+ let _: &u32 = std::mem::transmute::<_, &u32>(a);
//~^ transmute_ptr_to_ref
+ match 0 {
+ 0 => std::mem::transmute(x),
+ //~^ transmute_ptr_to_ref
+ _ => std::mem::transmute::<_, &&'b u32>(x),
+ //~^ transmute_ptr_to_ref
+ }
}
}
diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
index 7fad9b4..7685c34 100644
--- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
+++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.stderr
@@ -1,137 +1,137 @@
error: transmute from a pointer type (`*const T`) to a reference type (`&T`)
- --> tests/ui/transmute_ptr_to_ref.rs:9:17
+ --> tests/ui/transmute_ptr_to_ref.rs:10:21
|
-LL | let _: &T = std::mem::transmute(p);
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p`
+LL | let _: &T = std::mem::transmute(p);
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*p`
|
= note: `-D clippy::transmute-ptr-to-ref` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::transmute_ptr_to_ref)]`
error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
- --> tests/ui/transmute_ptr_to_ref.rs:13:21
+ --> tests/ui/transmute_ptr_to_ref.rs:14:25
|
-LL | let _: &mut T = std::mem::transmute(m);
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m`
+LL | let _: &mut T = std::mem::transmute(m);
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *m`
error: transmute from a pointer type (`*mut T`) to a reference type (`&T`)
- --> tests/ui/transmute_ptr_to_ref.rs:17:17
+ --> tests/ui/transmute_ptr_to_ref.rs:18:21
|
-LL | let _: &T = std::mem::transmute(m);
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m`
+LL | let _: &T = std::mem::transmute(m);
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*m`
error: transmute from a pointer type (`*mut T`) to a reference type (`&mut T`)
- --> tests/ui/transmute_ptr_to_ref.rs:21:21
+ --> tests/ui/transmute_ptr_to_ref.rs:22:25
|
-LL | let _: &mut T = std::mem::transmute(p as *mut T);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)`
+LL | let _: &mut T = std::mem::transmute(p as *mut T);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(p as *mut T)`
error: transmute from a pointer type (`*const U`) to a reference type (`&T`)
- --> tests/ui/transmute_ptr_to_ref.rs:25:17
+ --> tests/ui/transmute_ptr_to_ref.rs:26:21
|
-LL | let _: &T = std::mem::transmute(o);
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)`
+LL | let _: &T = std::mem::transmute(o);
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(o as *const T)`
error: transmute from a pointer type (`*mut U`) to a reference type (`&mut T`)
- --> tests/ui/transmute_ptr_to_ref.rs:29:21
+ --> tests/ui/transmute_ptr_to_ref.rs:30:25
|
-LL | let _: &mut T = std::mem::transmute(om);
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)`
+LL | let _: &mut T = std::mem::transmute(om);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&mut *(om as *mut T)`
error: transmute from a pointer type (`*mut U`) to a reference type (`&T`)
- --> tests/ui/transmute_ptr_to_ref.rs:33:17
+ --> tests/ui/transmute_ptr_to_ref.rs:34:21
|
-LL | let _: &T = std::mem::transmute(om);
- | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)`
+LL | let _: &T = std::mem::transmute(om);
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(om as *const T)`
error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, u8>`)
- --> tests/ui/transmute_ptr_to_ref.rs:44:32
+ --> tests/ui/transmute_ptr_to_ref.rs:46:32
|
LL | let _: &Foo<u8> = unsafe { std::mem::transmute::<_, &Foo<_>>(raw) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<_>>()`
error: transmute from a pointer type (`*const i32`) to a reference type (`&_issue1231::Foo<'_, &u8>`)
- --> tests/ui/transmute_ptr_to_ref.rs:47:33
+ --> tests/ui/transmute_ptr_to_ref.rs:49:33
|
LL | let _: &Foo<&u8> = unsafe { std::mem::transmute::<_, &Foo<&_>>(raw) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*raw.cast::<Foo<&_>>()`
error: transmute from a pointer type (`*const i32`) to a reference type (`&u8`)
- --> tests/ui/transmute_ptr_to_ref.rs:52:14
+ --> tests/ui/transmute_ptr_to_ref.rs:54:14
|
LL | unsafe { std::mem::transmute::<_, Bar>(raw) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(raw as *const u8)`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
- --> tests/ui/transmute_ptr_to_ref.rs:58:14
+ --> tests/ui/transmute_ptr_to_ref.rs:61:18
|
-LL | 0 => std::mem::transmute(x),
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()`
+LL | 0 => std::mem::transmute(x),
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
- --> tests/ui/transmute_ptr_to_ref.rs:60:14
+ --> tests/ui/transmute_ptr_to_ref.rs:63:18
|
-LL | 1 => std::mem::transmute(y),
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&u32>()`
+LL | 1 => std::mem::transmute(y),
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&u32>()`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
- --> tests/ui/transmute_ptr_to_ref.rs:62:14
+ --> tests/ui/transmute_ptr_to_ref.rs:65:18
|
-LL | 2 => std::mem::transmute::<_, &&'b u32>(x),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()`
+LL | 2 => std::mem::transmute::<_, &&'b u32>(x),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
- --> tests/ui/transmute_ptr_to_ref.rs:64:14
+ --> tests/ui/transmute_ptr_to_ref.rs:67:18
|
-LL | _ => std::mem::transmute::<_, &&'b u32>(y),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&'b u32>()`
+LL | _ => std::mem::transmute::<_, &&'b u32>(y),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*y.cast::<&'b u32>()`
error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
- --> tests/ui/transmute_ptr_to_ref.rs:73:19
+ --> tests/ui/transmute_ptr_to_ref.rs:78:23
|
-LL | let _: &u32 = std::mem::transmute(a);
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a`
+LL | let _: &u32 = std::mem::transmute(a);
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a`
error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
- --> tests/ui/transmute_ptr_to_ref.rs:75:19
+ --> tests/ui/transmute_ptr_to_ref.rs:80:23
|
-LL | let _: &u32 = std::mem::transmute::<_, &u32>(a);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a.cast::<u32>()`
+LL | let _: &u32 = std::mem::transmute::<_, &u32>(a);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a.cast::<u32>()`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
- --> tests/ui/transmute_ptr_to_ref.rs:78:14
+ --> tests/ui/transmute_ptr_to_ref.rs:83:18
|
-LL | 0 => std::mem::transmute(x),
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()`
+LL | 0 => std::mem::transmute(x),
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&u32>()`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
- --> tests/ui/transmute_ptr_to_ref.rs:80:14
+ --> tests/ui/transmute_ptr_to_ref.rs:85:18
|
-LL | _ => std::mem::transmute::<_, &&'b u32>(x),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()`
+LL | _ => std::mem::transmute::<_, &&'b u32>(x),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*x.cast::<&'b u32>()`
error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
- --> tests/ui/transmute_ptr_to_ref.rs:89:19
+ --> tests/ui/transmute_ptr_to_ref.rs:96:23
|
-LL | let _: &u32 = std::mem::transmute(a);
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a`
+LL | let _: &u32 = std::mem::transmute(a);
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*a`
error: transmute from a pointer type (`*const u32`) to a reference type (`&u32`)
- --> tests/ui/transmute_ptr_to_ref.rs:91:19
+ --> tests/ui/transmute_ptr_to_ref.rs:98:23
|
-LL | let _: &u32 = std::mem::transmute::<_, &u32>(a);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const u32)`
+LL | let _: &u32 = std::mem::transmute::<_, &u32>(a);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(a as *const u32)`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
- --> tests/ui/transmute_ptr_to_ref.rs:94:14
+ --> tests/ui/transmute_ptr_to_ref.rs:101:18
|
-LL | 0 => std::mem::transmute(x),
- | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &u32)`
+LL | 0 => std::mem::transmute(x),
+ | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &u32)`
error: transmute from a pointer type (`*const &u32`) to a reference type (`&&u32`)
- --> tests/ui/transmute_ptr_to_ref.rs:96:14
+ --> tests/ui/transmute_ptr_to_ref.rs:103:18
|
-LL | _ => std::mem::transmute::<_, &&'b u32>(x),
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)`
+LL | _ => std::mem::transmute::<_, &&'b u32>(x),
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `&*(x as *const () as *const &'b u32)`
error: aborting due to 22 previous errors
diff --git a/src/tools/clippy/tests/ui/transmuting_null.rs b/src/tools/clippy/tests/ui/transmuting_null.rs
index bcd35bb..f3eb506 100644
--- a/src/tools/clippy/tests/ui/transmuting_null.rs
+++ b/src/tools/clippy/tests/ui/transmuting_null.rs
@@ -3,6 +3,7 @@
#![allow(clippy::zero_ptr)]
#![allow(clippy::transmute_ptr_to_ref)]
#![allow(clippy::eq_op, clippy::missing_transmute_annotations)]
+#![allow(clippy::manual_dangling_ptr)]
// Easy to lint because these only span one line.
fn one_liners() {
diff --git a/src/tools/clippy/tests/ui/transmuting_null.stderr b/src/tools/clippy/tests/ui/transmuting_null.stderr
index 84e6e37..c68e410 100644
--- a/src/tools/clippy/tests/ui/transmuting_null.stderr
+++ b/src/tools/clippy/tests/ui/transmuting_null.stderr
@@ -1,5 +1,5 @@
error: transmuting a known null pointer into a reference
- --> tests/ui/transmuting_null.rs:10:23
+ --> tests/ui/transmuting_null.rs:11:23
|
LL | let _: &u64 = std::mem::transmute(0 as *const u64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,13 +8,13 @@
= help: to override `-D warnings` add `#[allow(clippy::transmuting_null)]`
error: transmuting a known null pointer into a reference
- --> tests/ui/transmuting_null.rs:13:23
+ --> tests/ui/transmuting_null.rs:14:23
|
LL | let _: &u64 = std::mem::transmute(std::ptr::null::<u64>());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: transmuting a known null pointer into a reference
- --> tests/ui/transmuting_null.rs:24:23
+ --> tests/ui/transmuting_null.rs:25:23
|
LL | let _: &u64 = std::mem::transmute(ZPTR);
| ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/type_complexity.rs b/src/tools/clippy/tests/ui/type_complexity.rs
index 89c4955..9d14551 100644
--- a/src/tools/clippy/tests/ui/type_complexity.rs
+++ b/src/tools/clippy/tests/ui/type_complexity.rs
@@ -1,6 +1,5 @@
-#![warn(clippy::all)]
-#![allow(unused, clippy::needless_pass_by_value, clippy::vec_box, clippy::useless_vec)]
#![feature(associated_type_defaults)]
+#![allow(clippy::needless_pass_by_value, clippy::vec_box, clippy::useless_vec)]
type Alias = Vec<Vec<Box<(u32, u32, u32, u32)>>>; // no warning here
diff --git a/src/tools/clippy/tests/ui/type_complexity.stderr b/src/tools/clippy/tests/ui/type_complexity.stderr
index 181e04d..a7f6a07 100644
--- a/src/tools/clippy/tests/ui/type_complexity.stderr
+++ b/src/tools/clippy/tests/ui/type_complexity.stderr
@@ -1,5 +1,5 @@
error: very complex type used. Consider factoring parts into `type` definitions
- --> tests/ui/type_complexity.rs:7:12
+ --> tests/ui/type_complexity.rs:6:12
|
LL | const CST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,85 +8,85 @@
= help: to override `-D warnings` add `#[allow(clippy::type_complexity)]`
error: very complex type used. Consider factoring parts into `type` definitions
- --> tests/ui/type_complexity.rs:10:12
+ --> tests/ui/type_complexity.rs:9:12
|
LL | static ST: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> tests/ui/type_complexity.rs:14:8
+ --> tests/ui/type_complexity.rs:13:8
|
LL | f: Vec<Vec<Box<(u32, u32, u32, u32)>>>,
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> tests/ui/type_complexity.rs:18:11
+ --> tests/ui/type_complexity.rs:17:11
|
LL | struct Ts(Vec<Vec<Box<(u32, u32, u32, u32)>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> tests/ui/type_complexity.rs:22:11
+ --> tests/ui/type_complexity.rs:21:11
|
LL | Tuple(Vec<Vec<Box<(u32, u32, u32, u32)>>>),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> tests/ui/type_complexity.rs:24:17
+ --> tests/ui/type_complexity.rs:23:17
|
LL | Struct { f: Vec<Vec<Box<(u32, u32, u32, u32)>>> },
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> tests/ui/type_complexity.rs:29:14
+ --> tests/ui/type_complexity.rs:28:14
|
LL | const A: (u32, (u32, (u32, (u32, u32)))) = (0, (0, (0, (0, 0))));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> tests/ui/type_complexity.rs:32:30
+ --> tests/ui/type_complexity.rs:31:30
|
LL | fn impl_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> tests/ui/type_complexity.rs:37:14
+ --> tests/ui/type_complexity.rs:36:14
|
LL | const A: Vec<Vec<Box<(u32, u32, u32, u32)>>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> tests/ui/type_complexity.rs:40:14
+ --> tests/ui/type_complexity.rs:39:14
|
LL | type B = Vec<Vec<Box<(u32, u32, u32, u32)>>>;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> tests/ui/type_complexity.rs:43:25
+ --> tests/ui/type_complexity.rs:42:25
|
LL | fn method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> tests/ui/type_complexity.rs:46:29
+ --> tests/ui/type_complexity.rs:45:29
|
LL | fn def_method(&self, p: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> tests/ui/type_complexity.rs:59:15
+ --> tests/ui/type_complexity.rs:58:15
|
LL | fn test1() -> Vec<Vec<Box<(u32, u32, u32, u32)>>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> tests/ui/type_complexity.rs:65:14
+ --> tests/ui/type_complexity.rs:64:14
|
LL | fn test2(_x: Vec<Vec<Box<(u32, u32, u32, u32)>>>) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: very complex type used. Consider factoring parts into `type` definitions
- --> tests/ui/type_complexity.rs:69:13
+ --> tests/ui/type_complexity.rs:68:13
|
LL | let _y: Vec<Vec<Box<(u32, u32, u32, u32)>>> = vec![];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/uninit_vec.rs b/src/tools/clippy/tests/ui/uninit_vec.rs
index a483971..eeb2813 100644
--- a/src/tools/clippy/tests/ui/uninit_vec.rs
+++ b/src/tools/clippy/tests/ui/uninit_vec.rs
@@ -15,9 +15,17 @@ union MyOwnMaybeUninit {
// https://github.com/rust-lang/rust/issues/119620
unsafe fn requires_paramenv<S>() {
- let mut vec = Vec::<UnsafeCell<*mut S>>::with_capacity(1);
+ unsafe {
+ let mut vec = Vec::<UnsafeCell<*mut S>>::with_capacity(1);
+ //~^ uninit_vec
+ vec.set_len(1);
+ }
+
+ let mut vec = Vec::<UnsafeCell<*mut S>>::with_capacity(2);
//~^ uninit_vec
- vec.set_len(1);
+ unsafe {
+ vec.set_len(2);
+ }
}
fn main() {
diff --git a/src/tools/clippy/tests/ui/uninit_vec.stderr b/src/tools/clippy/tests/ui/uninit_vec.stderr
index 7ff6140..1b821ef 100644
--- a/src/tools/clippy/tests/ui/uninit_vec.stderr
+++ b/src/tools/clippy/tests/ui/uninit_vec.stderr
@@ -1,18 +1,29 @@
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
- --> tests/ui/uninit_vec.rs:18:5
+ --> tests/ui/uninit_vec.rs:24:5
|
-LL | let mut vec = Vec::<UnsafeCell<*mut S>>::with_capacity(1);
+LL | let mut vec = Vec::<UnsafeCell<*mut S>>::with_capacity(2);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-LL |
-LL | vec.set_len(1);
- | ^^^^^^^^^^^^^^
+...
+LL | vec.set_len(2);
+ | ^^^^^^^^^^^^^^
|
= help: initialize the buffer or wrap the content in `MaybeUninit`
= note: `-D clippy::uninit-vec` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::uninit_vec)]`
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
- --> tests/ui/uninit_vec.rs:25:5
+ --> tests/ui/uninit_vec.rs:19:9
+ |
+LL | let mut vec = Vec::<UnsafeCell<*mut S>>::with_capacity(1);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |
+LL | vec.set_len(1);
+ | ^^^^^^^^^^^^^^
+ |
+ = help: initialize the buffer or wrap the content in `MaybeUninit`
+
+error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
+ --> tests/ui/uninit_vec.rs:33:5
|
LL | let mut vec: Vec<u8> = Vec::with_capacity(1000);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -23,7 +34,7 @@
= help: initialize the buffer or wrap the content in `MaybeUninit`
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
- --> tests/ui/uninit_vec.rs:33:5
+ --> tests/ui/uninit_vec.rs:41:5
|
LL | vec.reserve(1000);
| ^^^^^^^^^^^^^^^^^^
@@ -34,7 +45,7 @@
= help: initialize the buffer or wrap the content in `MaybeUninit`
error: calling `set_len()` on empty `Vec` creates out-of-bound values
- --> tests/ui/uninit_vec.rs:41:5
+ --> tests/ui/uninit_vec.rs:49:5
|
LL | let mut vec: Vec<u8> = Vec::new();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -43,7 +54,7 @@
| ^^^^^^^^^^^^^^^^
error: calling `set_len()` on empty `Vec` creates out-of-bound values
- --> tests/ui/uninit_vec.rs:49:5
+ --> tests/ui/uninit_vec.rs:57:5
|
LL | let mut vec: Vec<u8> = Default::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -52,7 +63,7 @@
| ^^^^^^^^^^^^^^^^
error: calling `set_len()` on empty `Vec` creates out-of-bound values
- --> tests/ui/uninit_vec.rs:56:5
+ --> tests/ui/uninit_vec.rs:64:5
|
LL | let mut vec: Vec<u8> = Vec::default();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -61,7 +72,7 @@
| ^^^^^^^^^^^^^^^^
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
- --> tests/ui/uninit_vec.rs:76:5
+ --> tests/ui/uninit_vec.rs:84:5
|
LL | let mut vec: Vec<u8> = Vec::with_capacity(1000);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -72,7 +83,7 @@
= help: initialize the buffer or wrap the content in `MaybeUninit`
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
- --> tests/ui/uninit_vec.rs:87:5
+ --> tests/ui/uninit_vec.rs:95:5
|
LL | my_vec.vec.reserve(1000);
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -83,7 +94,7 @@
= help: initialize the buffer or wrap the content in `MaybeUninit`
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
- --> tests/ui/uninit_vec.rs:94:5
+ --> tests/ui/uninit_vec.rs:102:5
|
LL | my_vec.vec = Vec::with_capacity(1000);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -94,7 +105,7 @@
= help: initialize the buffer or wrap the content in `MaybeUninit`
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
- --> tests/ui/uninit_vec.rs:65:9
+ --> tests/ui/uninit_vec.rs:73:9
|
LL | let mut vec: Vec<u8> = Vec::with_capacity(1000);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -105,7 +116,7 @@
= help: initialize the buffer or wrap the content in `MaybeUninit`
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
- --> tests/ui/uninit_vec.rs:70:9
+ --> tests/ui/uninit_vec.rs:78:9
|
LL | vec.reserve(1000);
| ^^^^^^^^^^^^^^^^^^
@@ -116,7 +127,7 @@
= help: initialize the buffer or wrap the content in `MaybeUninit`
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
- --> tests/ui/uninit_vec.rs:150:9
+ --> tests/ui/uninit_vec.rs:158:9
|
LL | let mut vec: Vec<T> = Vec::with_capacity(1000);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -127,7 +138,7 @@
= help: initialize the buffer or wrap the content in `MaybeUninit`
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
- --> tests/ui/uninit_vec.rs:178:9
+ --> tests/ui/uninit_vec.rs:186:9
|
LL | let mut vec: Vec<Recursive<T>> = Vec::with_capacity(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -138,7 +149,7 @@
= help: initialize the buffer or wrap the content in `MaybeUninit`
error: calling `set_len()` immediately after reserving a buffer creates uninitialized values
- --> tests/ui/uninit_vec.rs:192:9
+ --> tests/ui/uninit_vec.rs:200:9
|
LL | let mut vec: Vec<Enum<T>> = Vec::with_capacity(1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -148,5 +159,5 @@
|
= help: initialize the buffer or wrap the content in `MaybeUninit`
-error: aborting due to 14 previous errors
+error: aborting due to 15 previous errors
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.rs b/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.rs
index 2bb64c3..4b1f4f7 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.rs
@@ -17,8 +17,10 @@ struct TearOff {
impl TearOff {
unsafe fn query(&self) {
- ((*(*(self.object as *mut *mut _) as *mut Vtbl)).query)()
- //~^ unnecessary_cast
+ unsafe {
+ ((*(*(self.object as *mut *mut _) as *mut Vtbl)).query)()
+ //~^ unnecessary_cast
+ }
}
}
}
diff --git a/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr
index 6ba1c78..6b26bea 100644
--- a/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_cast_unfixable.stderr
@@ -8,10 +8,10 @@
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_cast)]`
error: casting raw pointers to the same type and constness is unnecessary (`*mut issue11113::Vtbl` -> `*mut issue11113::Vtbl`)
- --> tests/ui/unnecessary_cast_unfixable.rs:20:16
+ --> tests/ui/unnecessary_cast_unfixable.rs:21:20
|
-LL | ((*(*(self.object as *mut *mut _) as *mut Vtbl)).query)()
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `*(self.object as *mut *mut _)`
+LL | ((*(*(self.object as *mut *mut _) as *mut Vtbl)).query)()
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `*(self.object as *mut *mut _)`
error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/unnecessary_filter_map.rs b/src/tools/clippy/tests/ui/unnecessary_filter_map.rs
index c4f1b6b..85582c3 100644
--- a/src/tools/clippy/tests/ui/unnecessary_filter_map.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_filter_map.rs
@@ -1,5 +1,4 @@
-//@no-rustfix
-#![allow(dead_code)]
+#![allow(clippy::redundant_closure)]
fn main() {
let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None });
@@ -27,9 +26,7 @@ fn main() {
let _ = (0..4).filter_map(Some);
let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x));
- //~^ redundant_closure
- //~| unnecessary_filter_map
- //~| unnecessary_filter_map
+ //~^ unnecessary_filter_map
}
fn filter_map_none_changes_item_type() -> impl Iterator<Item = bool> {
diff --git a/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr b/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr
index 6683444..a879633 100644
--- a/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_filter_map.stderr
@@ -1,14 +1,14 @@
-error: this `.filter_map` can be written more simply
- --> tests/ui/unnecessary_filter_map.rs:5:13
+error: this `.filter_map(..)` can be written more simply using `.filter(..)`
+ --> tests/ui/unnecessary_filter_map.rs:4:13
|
LL | let _ = (0..4).filter_map(|x| if x > 1 { Some(x) } else { None });
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `filter`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::unnecessary-filter-map` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_filter_map)]`
-error: this `.filter_map` can be written more simply
- --> tests/ui/unnecessary_filter_map.rs:8:13
+error: this `.filter_map(..)` can be written more simply using `.filter(..)`
+ --> tests/ui/unnecessary_filter_map.rs:7:13
|
LL | let _ = (0..4).filter_map(|x| {
| _____________^
@@ -18,10 +18,10 @@
... |
LL | | None
LL | | });
- | |______^ help: try instead: `filter`
+ | |______^
-error: this `.filter_map` can be written more simply
- --> tests/ui/unnecessary_filter_map.rs:16:13
+error: this `.filter_map(..)` can be written more simply using `.filter(..)`
+ --> tests/ui/unnecessary_filter_map.rs:15:13
|
LL | let _ = (0..4).filter_map(|x| match x {
| _____________^
@@ -29,40 +29,25 @@
LL | | 0 | 1 => None,
LL | | _ => Some(x),
LL | | });
- | |______^ help: try instead: `filter`
+ | |______^
-error: this `.filter_map` can be written more simply
- --> tests/ui/unnecessary_filter_map.rs:22:13
+error: this `.filter_map(..)` can be written more simply using `.map(..)`
+ --> tests/ui/unnecessary_filter_map.rs:21:13
|
LL | let _ = (0..4).filter_map(|x| Some(x + 1));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `map`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: redundant closure
- --> tests/ui/unnecessary_filter_map.rs:29:57
+error: this call to `.filter_map(..)` is unnecessary
+ --> tests/ui/unnecessary_filter_map.rs:28:61
|
LL | let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x));
- | ^^^^^^^^^^^ help: replace the closure with the function itself: `Some`
- |
- = note: `-D clippy::redundant-closure` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::redundant_closure)]`
+ | ^^^^
-error: filter_map is unnecessary
- --> tests/ui/unnecessary_filter_map.rs:29:61
- |
-LL | let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x));
- | ^^^^ help: try removing the filter_map
-
-error: this `.filter_map` can be written more simply
- --> tests/ui/unnecessary_filter_map.rs:29:13
- |
-LL | let _ = vec![Some(10), None].into_iter().filter_map(|x| Some(x));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `map`
-
-error: this `.filter_map` can be written more simply
- --> tests/ui/unnecessary_filter_map.rs:169:14
+error: this `.filter_map(..)` can be written more simply using `.filter(..)`
+ --> tests/ui/unnecessary_filter_map.rs:166:14
|
LL | let _x = std::iter::once(1).filter_map(|n| (n > 1).then_some(n));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `filter`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 8 previous errors
+error: aborting due to 6 previous errors
diff --git a/src/tools/clippy/tests/ui/unnecessary_find_map.rs b/src/tools/clippy/tests/ui/unnecessary_find_map.rs
index 8c8a379..33ba707 100644
--- a/src/tools/clippy/tests/ui/unnecessary_find_map.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_find_map.rs
@@ -1,4 +1,3 @@
-//@no-rustfix
#![allow(dead_code)]
fn main() {
diff --git a/src/tools/clippy/tests/ui/unnecessary_find_map.stderr b/src/tools/clippy/tests/ui/unnecessary_find_map.stderr
index 94e3207..3754a3d9 100644
--- a/src/tools/clippy/tests/ui/unnecessary_find_map.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_find_map.stderr
@@ -1,14 +1,14 @@
-error: this `.find_map` can be written more simply
- --> tests/ui/unnecessary_find_map.rs:5:13
+error: this `.find_map(..)` can be written more simply using `.find(..)`
+ --> tests/ui/unnecessary_find_map.rs:4:13
|
LL | let _ = (0..4).find_map(|x| if x > 1 { Some(x) } else { None });
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `find`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::unnecessary-find-map` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_find_map)]`
-error: this `.find_map` can be written more simply
- --> tests/ui/unnecessary_find_map.rs:8:13
+error: this `.find_map(..)` can be written more simply using `.find(..)`
+ --> tests/ui/unnecessary_find_map.rs:7:13
|
LL | let _ = (0..4).find_map(|x| {
| _____________^
@@ -18,10 +18,10 @@
... |
LL | | None
LL | | });
- | |______^ help: try instead: `find`
+ | |______^
-error: this `.find_map` can be written more simply
- --> tests/ui/unnecessary_find_map.rs:16:13
+error: this `.find_map(..)` can be written more simply using `.find(..)`
+ --> tests/ui/unnecessary_find_map.rs:15:13
|
LL | let _ = (0..4).find_map(|x| match x {
| _____________^
@@ -29,19 +29,19 @@
LL | | 0 | 1 => None,
LL | | _ => Some(x),
LL | | });
- | |______^ help: try instead: `find`
+ | |______^
-error: this `.find_map` can be written more simply
- --> tests/ui/unnecessary_find_map.rs:22:13
+error: this `.find_map(..)` can be written more simply using `.map(..).next()`
+ --> tests/ui/unnecessary_find_map.rs:21:13
|
LL | let _ = (0..4).find_map(|x| Some(x + 1));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `map(..).next()`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: this `.find_map` can be written more simply
- --> tests/ui/unnecessary_find_map.rs:34:14
+error: this `.find_map(..)` can be written more simply using `.find(..)`
+ --> tests/ui/unnecessary_find_map.rs:33:14
|
LL | let _x = std::iter::once(1).find_map(|n| (n > 1).then_some(n));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try instead: `find`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed
index aed2dbe..61f2e37 100644
--- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed
@@ -1,4 +1,4 @@
-#![allow(unused_assignments)]
+#![allow(unused_assignments, clippy::uninlined_format_args)]
#![warn(clippy::unnecessary_to_owned)]
#[allow(dead_code)]
diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs
index 12fdd15..b90ca00 100644
--- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs
@@ -1,4 +1,4 @@
-#![allow(unused_assignments)]
+#![allow(unused_assignments, clippy::uninlined_format_args)]
#![warn(clippy::unnecessary_to_owned)]
#[allow(dead_code)]
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
index 9a32908..409a8ef 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
@@ -321,3 +321,7 @@
let _x = false.then_some(f1 + f2);
//~^ unnecessary_lazy_evaluations
}
+
+fn issue14578() {
+ let _: Box<dyn std::future::Future<Output = i32>> = Box::new(true.then(async || 42).unwrap());
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
index 2d05ef5..5473502 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
@@ -321,3 +321,7 @@ fn panicky_arithmetic_ops(x: usize, y: isize) {
let _x = false.then(|| f1 + f2);
//~^ unnecessary_lazy_evaluations
}
+
+fn issue14578() {
+ let _: Box<dyn std::future::Future<Output = i32>> = Box::new(true.then(async || 42).unwrap());
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.fixed b/src/tools/clippy/tests/ui/unnecessary_operation.fixed
index 05dfb72..645b56f 100644
--- a/src/tools/clippy/tests/ui/unnecessary_operation.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.fixed
@@ -1,9 +1,10 @@
#![allow(
clippy::deref_addrof,
- dead_code,
- unused,
clippy::no_effect,
- clippy::unnecessary_struct_initialization
+ clippy::uninlined_format_args,
+ clippy::unnecessary_struct_initialization,
+ dead_code,
+ unused
)]
#![warn(clippy::unnecessary_operation)]
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.rs b/src/tools/clippy/tests/ui/unnecessary_operation.rs
index 6ef74c3..97e9026 100644
--- a/src/tools/clippy/tests/ui/unnecessary_operation.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.rs
@@ -1,9 +1,10 @@
#![allow(
clippy::deref_addrof,
- dead_code,
- unused,
clippy::no_effect,
- clippy::unnecessary_struct_initialization
+ clippy::uninlined_format_args,
+ clippy::unnecessary_struct_initialization,
+ dead_code,
+ unused
)]
#![warn(clippy::unnecessary_operation)]
diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.stderr b/src/tools/clippy/tests/ui/unnecessary_operation.stderr
index eb98af0..0fda1df 100644
--- a/src/tools/clippy/tests/ui/unnecessary_operation.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_operation.stderr
@@ -1,5 +1,5 @@
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:70:5
+ --> tests/ui/unnecessary_operation.rs:71:5
|
LL | Tuple(get_number());
| ^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
@@ -8,103 +8,103 @@
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_operation)]`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:72:5
+ --> tests/ui/unnecessary_operation.rs:73:5
|
LL | Struct { field: get_number() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:74:5
+ --> tests/ui/unnecessary_operation.rs:75:5
|
LL | Struct { ..get_struct() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_struct();`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:76:5
+ --> tests/ui/unnecessary_operation.rs:77:5
|
LL | Enum::Tuple(get_number());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:78:5
+ --> tests/ui/unnecessary_operation.rs:79:5
|
LL | Enum::Struct { field: get_number() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:80:5
+ --> tests/ui/unnecessary_operation.rs:81:5
|
LL | 5 + get_number();
| ^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:82:5
+ --> tests/ui/unnecessary_operation.rs:83:5
|
LL | *&get_number();
| ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:84:5
+ --> tests/ui/unnecessary_operation.rs:85:5
|
LL | &get_number();
| ^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:86:5
+ --> tests/ui/unnecessary_operation.rs:87:5
|
LL | (5, 6, get_number());
| ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;6;get_number();`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:88:5
+ --> tests/ui/unnecessary_operation.rs:89:5
|
LL | get_number()..;
| ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:90:5
+ --> tests/ui/unnecessary_operation.rs:91:5
|
LL | ..get_number();
| ^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:92:5
+ --> tests/ui/unnecessary_operation.rs:93:5
|
LL | 5..get_number();
| ^^^^^^^^^^^^^^^^ help: statement can be reduced to: `5;get_number();`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:94:5
+ --> tests/ui/unnecessary_operation.rs:95:5
|
LL | [42, get_number()];
| ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:96:5
+ --> tests/ui/unnecessary_operation.rs:97:5
|
LL | [42, 55][get_usize()];
| ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:98:5
+ --> tests/ui/unnecessary_operation.rs:99:5
|
LL | (42, get_number()).1;
| ^^^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `42;get_number();`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:100:5
+ --> tests/ui/unnecessary_operation.rs:101:5
|
LL | [get_number(); 55];
| ^^^^^^^^^^^^^^^^^^^ help: statement can be reduced to: `get_number();`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:102:5
+ --> tests/ui/unnecessary_operation.rs:103:5
|
LL | [42; 55][get_usize()];
| ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42; 55].len() > get_usize());`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:104:5
+ --> tests/ui/unnecessary_operation.rs:105:5
|
LL | / {
LL | |
@@ -113,7 +113,7 @@
| |______^ help: statement can be reduced to: `get_number();`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:108:5
+ --> tests/ui/unnecessary_operation.rs:109:5
|
LL | / FooString {
LL | |
@@ -122,7 +122,7 @@
| |______^ help: statement can be reduced to: `String::from("blah");`
error: unnecessary operation
- --> tests/ui/unnecessary_operation.rs:149:5
+ --> tests/ui/unnecessary_operation.rs:150:5
|
LL | [42, 55][get_usize()];
| ^^^^^^^^^^^^^^^^^^^^^^ help: statement can be written as: `assert!([42, 55].len() > get_usize());`
diff --git a/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs
index 12663ec..6652efd 100644
--- a/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.rs
@@ -1,4 +1,5 @@
#![warn(clippy::unnecessary_debug_formatting)]
+#![allow(clippy::uninlined_format_args)]
use std::ffi::{OsStr, OsString};
diff --git a/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr
index 001309a..382e59b 100644
--- a/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_os_str_debug_formatting.stderr
@@ -1,5 +1,5 @@
error: unnecessary `Debug` formatting in `println!` args
- --> tests/ui/unnecessary_os_str_debug_formatting.rs:14:22
+ --> tests/ui/unnecessary_os_str_debug_formatting.rs:15:22
|
LL | println!("{:?}", os_str);
| ^^^^^^
@@ -10,7 +10,7 @@
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_debug_formatting)]`
error: unnecessary `Debug` formatting in `println!` args
- --> tests/ui/unnecessary_os_str_debug_formatting.rs:15:22
+ --> tests/ui/unnecessary_os_str_debug_formatting.rs:16:22
|
LL | println!("{:?}", os_string);
| ^^^^^^^^^
@@ -19,7 +19,7 @@
= note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed
error: unnecessary `Debug` formatting in `println!` args
- --> tests/ui/unnecessary_os_str_debug_formatting.rs:17:16
+ --> tests/ui/unnecessary_os_str_debug_formatting.rs:18:16
|
LL | println!("{os_str:?}");
| ^^^^^^
@@ -28,7 +28,7 @@
= note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed
error: unnecessary `Debug` formatting in `println!` args
- --> tests/ui/unnecessary_os_str_debug_formatting.rs:18:16
+ --> tests/ui/unnecessary_os_str_debug_formatting.rs:19:16
|
LL | println!("{os_string:?}");
| ^^^^^^^^^
@@ -37,7 +37,7 @@
= note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed
error: unnecessary `Debug` formatting in `format!` args
- --> tests/ui/unnecessary_os_str_debug_formatting.rs:20:37
+ --> tests/ui/unnecessary_os_str_debug_formatting.rs:21:37
|
LL | let _: String = format!("{:?}", os_str);
| ^^^^^^
@@ -46,7 +46,7 @@
= note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed
error: unnecessary `Debug` formatting in `format!` args
- --> tests/ui/unnecessary_os_str_debug_formatting.rs:21:37
+ --> tests/ui/unnecessary_os_str_debug_formatting.rs:22:37
|
LL | let _: String = format!("{:?}", os_string);
| ^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/unnecessary_path_debug_formatting.rs b/src/tools/clippy/tests/ui/unnecessary_path_debug_formatting.rs
index f14f608..215e0d5 100644
--- a/src/tools/clippy/tests/ui/unnecessary_path_debug_formatting.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_path_debug_formatting.rs
@@ -1,4 +1,5 @@
#![warn(clippy::unnecessary_debug_formatting)]
+#![allow(clippy::uninlined_format_args)]
use std::ffi::{OsStr, OsString};
use std::ops::Deref;
diff --git a/src/tools/clippy/tests/ui/unnecessary_path_debug_formatting.stderr b/src/tools/clippy/tests/ui/unnecessary_path_debug_formatting.stderr
index f12fa72..d244b9ad 100644
--- a/src/tools/clippy/tests/ui/unnecessary_path_debug_formatting.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_path_debug_formatting.stderr
@@ -1,5 +1,5 @@
error: unnecessary `Debug` formatting in `println!` args
- --> tests/ui/unnecessary_path_debug_formatting.rs:29:22
+ --> tests/ui/unnecessary_path_debug_formatting.rs:30:22
|
LL | println!("{:?}", os_str);
| ^^^^^^
@@ -10,7 +10,7 @@
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_debug_formatting)]`
error: unnecessary `Debug` formatting in `println!` args
- --> tests/ui/unnecessary_path_debug_formatting.rs:30:22
+ --> tests/ui/unnecessary_path_debug_formatting.rs:31:22
|
LL | println!("{:?}", os_string);
| ^^^^^^^^^
@@ -19,7 +19,7 @@
= note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed
error: unnecessary `Debug` formatting in `println!` args
- --> tests/ui/unnecessary_path_debug_formatting.rs:32:22
+ --> tests/ui/unnecessary_path_debug_formatting.rs:33:22
|
LL | println!("{:?}", path);
| ^^^^
@@ -28,7 +28,7 @@
= note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed
error: unnecessary `Debug` formatting in `println!` args
- --> tests/ui/unnecessary_path_debug_formatting.rs:33:22
+ --> tests/ui/unnecessary_path_debug_formatting.rs:34:22
|
LL | println!("{:?}", path_buf);
| ^^^^^^^^
@@ -37,7 +37,7 @@
= note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed
error: unnecessary `Debug` formatting in `println!` args
- --> tests/ui/unnecessary_path_debug_formatting.rs:35:16
+ --> tests/ui/unnecessary_path_debug_formatting.rs:36:16
|
LL | println!("{path:?}");
| ^^^^
@@ -46,7 +46,7 @@
= note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed
error: unnecessary `Debug` formatting in `println!` args
- --> tests/ui/unnecessary_path_debug_formatting.rs:36:16
+ --> tests/ui/unnecessary_path_debug_formatting.rs:37:16
|
LL | println!("{path_buf:?}");
| ^^^^^^^^
@@ -55,7 +55,7 @@
= note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed
error: unnecessary `Debug` formatting in `format!` args
- --> tests/ui/unnecessary_path_debug_formatting.rs:38:37
+ --> tests/ui/unnecessary_path_debug_formatting.rs:39:37
|
LL | let _: String = format!("{:?}", path);
| ^^^^
@@ -64,7 +64,7 @@
= note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed
error: unnecessary `Debug` formatting in `format!` args
- --> tests/ui/unnecessary_path_debug_formatting.rs:39:37
+ --> tests/ui/unnecessary_path_debug_formatting.rs:40:37
|
LL | let _: String = format!("{:?}", path_buf);
| ^^^^^^^^
@@ -73,7 +73,7 @@
= note: switching to `Display` formatting will change how the value is shown; escaped characters will no longer be escaped and surrounding quotes will be removed
error: unnecessary `Debug` formatting in `println!` args
- --> tests/ui/unnecessary_path_debug_formatting.rs:42:22
+ --> tests/ui/unnecessary_path_debug_formatting.rs:43:22
|
LL | println!("{:?}", &*deref_path);
| ^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
index 5410033..b064a8b 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
@@ -1,10 +1,11 @@
#![allow(
+ clippy::manual_async_fn,
clippy::needless_borrow,
clippy::needless_borrows_for_generic_args,
- clippy::ptr_arg,
- clippy::manual_async_fn,
clippy::needless_lifetimes,
- clippy::owned_cow
+ clippy::owned_cow,
+ clippy::ptr_arg,
+ clippy::uninlined_format_args
)]
#![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)]
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
index 0619dd4..7954a4a 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
@@ -1,10 +1,11 @@
#![allow(
+ clippy::manual_async_fn,
clippy::needless_borrow,
clippy::needless_borrows_for_generic_args,
- clippy::ptr_arg,
- clippy::manual_async_fn,
clippy::needless_lifetimes,
- clippy::owned_cow
+ clippy::owned_cow,
+ clippy::ptr_arg,
+ clippy::uninlined_format_args
)]
#![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)]
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
index 8926db3..6c52be8 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
@@ -1,11 +1,11 @@
error: redundant clone
- --> tests/ui/unnecessary_to_owned.rs:217:64
+ --> tests/ui/unnecessary_to_owned.rs:218:64
|
LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
| ^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
- --> tests/ui/unnecessary_to_owned.rs:217:20
+ --> tests/ui/unnecessary_to_owned.rs:218:20
|
LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,55 +13,55 @@
= help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]`
error: redundant clone
- --> tests/ui/unnecessary_to_owned.rs:219:40
+ --> tests/ui/unnecessary_to_owned.rs:220:40
|
LL | require_os_str(&OsString::from("x").to_os_string());
| ^^^^^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
- --> tests/ui/unnecessary_to_owned.rs:219:21
+ --> tests/ui/unnecessary_to_owned.rs:220:21
|
LL | require_os_str(&OsString::from("x").to_os_string());
| ^^^^^^^^^^^^^^^^^^^
error: redundant clone
- --> tests/ui/unnecessary_to_owned.rs:221:48
+ --> tests/ui/unnecessary_to_owned.rs:222:48
|
LL | require_path(&std::path::PathBuf::from("x").to_path_buf());
| ^^^^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
- --> tests/ui/unnecessary_to_owned.rs:221:19
+ --> tests/ui/unnecessary_to_owned.rs:222:19
|
LL | require_path(&std::path::PathBuf::from("x").to_path_buf());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: redundant clone
- --> tests/ui/unnecessary_to_owned.rs:223:35
+ --> tests/ui/unnecessary_to_owned.rs:224:35
|
LL | require_str(&String::from("x").to_string());
| ^^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
- --> tests/ui/unnecessary_to_owned.rs:223:18
+ --> tests/ui/unnecessary_to_owned.rs:224:18
|
LL | require_str(&String::from("x").to_string());
| ^^^^^^^^^^^^^^^^^
error: redundant clone
- --> tests/ui/unnecessary_to_owned.rs:225:39
+ --> tests/ui/unnecessary_to_owned.rs:226:39
|
LL | require_slice(&[String::from("x")].to_owned());
| ^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
- --> tests/ui/unnecessary_to_owned.rs:225:20
+ --> tests/ui/unnecessary_to_owned.rs:226:20
|
LL | require_slice(&[String::from("x")].to_owned());
| ^^^^^^^^^^^^^^^^^^^
error: unnecessary use of `into_owned`
- --> tests/ui/unnecessary_to_owned.rs:65:36
+ --> tests/ui/unnecessary_to_owned.rs:66:36
|
LL | require_c_str(&Cow::from(c_str).into_owned());
| ^^^^^^^^^^^^^ help: remove this
@@ -70,391 +70,391 @@
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:67:19
+ --> tests/ui/unnecessary_to_owned.rs:68:19
|
LL | require_c_str(&c_str.to_owned());
| ^^^^^^^^^^^^^^^^^ help: use: `c_str`
error: unnecessary use of `to_os_string`
- --> tests/ui/unnecessary_to_owned.rs:70:20
+ --> tests/ui/unnecessary_to_owned.rs:71:20
|
LL | require_os_str(&os_str.to_os_string());
| ^^^^^^^^^^^^^^^^^^^^^^ help: use: `os_str`
error: unnecessary use of `into_owned`
- --> tests/ui/unnecessary_to_owned.rs:72:38
+ --> tests/ui/unnecessary_to_owned.rs:73:38
|
LL | require_os_str(&Cow::from(os_str).into_owned());
| ^^^^^^^^^^^^^ help: remove this
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:74:20
+ --> tests/ui/unnecessary_to_owned.rs:75:20
|
LL | require_os_str(&os_str.to_owned());
| ^^^^^^^^^^^^^^^^^^ help: use: `os_str`
error: unnecessary use of `to_path_buf`
- --> tests/ui/unnecessary_to_owned.rs:77:18
+ --> tests/ui/unnecessary_to_owned.rs:78:18
|
LL | require_path(&path.to_path_buf());
| ^^^^^^^^^^^^^^^^^^^ help: use: `path`
error: unnecessary use of `into_owned`
- --> tests/ui/unnecessary_to_owned.rs:79:34
+ --> tests/ui/unnecessary_to_owned.rs:80:34
|
LL | require_path(&Cow::from(path).into_owned());
| ^^^^^^^^^^^^^ help: remove this
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:81:18
+ --> tests/ui/unnecessary_to_owned.rs:82:18
|
LL | require_path(&path.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `path`
error: unnecessary use of `to_string`
- --> tests/ui/unnecessary_to_owned.rs:84:17
+ --> tests/ui/unnecessary_to_owned.rs:85:17
|
LL | require_str(&s.to_string());
| ^^^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `into_owned`
- --> tests/ui/unnecessary_to_owned.rs:86:30
+ --> tests/ui/unnecessary_to_owned.rs:87:30
|
LL | require_str(&Cow::from(s).into_owned());
| ^^^^^^^^^^^^^ help: remove this
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:88:17
+ --> tests/ui/unnecessary_to_owned.rs:89:17
|
LL | require_str(&s.to_owned());
| ^^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_string`
- --> tests/ui/unnecessary_to_owned.rs:90:17
+ --> tests/ui/unnecessary_to_owned.rs:91:17
|
LL | require_str(&x_ref.to_string());
| ^^^^^^^^^^^^^^^^^^ help: use: `x_ref.as_ref()`
error: unnecessary use of `to_vec`
- --> tests/ui/unnecessary_to_owned.rs:93:19
+ --> tests/ui/unnecessary_to_owned.rs:94:19
|
LL | require_slice(&slice.to_vec());
| ^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `into_owned`
- --> tests/ui/unnecessary_to_owned.rs:95:36
+ --> tests/ui/unnecessary_to_owned.rs:96:36
|
LL | require_slice(&Cow::from(slice).into_owned());
| ^^^^^^^^^^^^^ help: remove this
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:97:19
+ --> tests/ui/unnecessary_to_owned.rs:98:19
|
LL | require_slice(&array.to_owned());
| ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:99:19
+ --> tests/ui/unnecessary_to_owned.rs:100:19
|
LL | require_slice(&array_ref.to_owned());
| ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:101:19
+ --> tests/ui/unnecessary_to_owned.rs:102:19
|
LL | require_slice(&slice.to_owned());
| ^^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `into_owned`
- --> tests/ui/unnecessary_to_owned.rs:105:42
+ --> tests/ui/unnecessary_to_owned.rs:106:42
|
LL | require_x(&Cow::<X>::Owned(x.clone()).into_owned());
| ^^^^^^^^^^^^^ help: remove this
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:109:25
+ --> tests/ui/unnecessary_to_owned.rs:110:25
|
LL | require_deref_c_str(c_str.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `c_str`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:111:26
+ --> tests/ui/unnecessary_to_owned.rs:112:26
|
LL | require_deref_os_str(os_str.to_owned());
| ^^^^^^^^^^^^^^^^^ help: use: `os_str`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:113:24
+ --> tests/ui/unnecessary_to_owned.rs:114:24
|
LL | require_deref_path(path.to_owned());
| ^^^^^^^^^^^^^^^ help: use: `path`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:115:23
+ --> tests/ui/unnecessary_to_owned.rs:116:23
|
LL | require_deref_str(s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:117:25
+ --> tests/ui/unnecessary_to_owned.rs:118:25
|
LL | require_deref_slice(slice.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:120:30
+ --> tests/ui/unnecessary_to_owned.rs:121:30
|
LL | require_impl_deref_c_str(c_str.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `c_str`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:122:31
+ --> tests/ui/unnecessary_to_owned.rs:123:31
|
LL | require_impl_deref_os_str(os_str.to_owned());
| ^^^^^^^^^^^^^^^^^ help: use: `os_str`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:124:29
+ --> tests/ui/unnecessary_to_owned.rs:125:29
|
LL | require_impl_deref_path(path.to_owned());
| ^^^^^^^^^^^^^^^ help: use: `path`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:126:28
+ --> tests/ui/unnecessary_to_owned.rs:127:28
|
LL | require_impl_deref_str(s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:128:30
+ --> tests/ui/unnecessary_to_owned.rs:129:30
|
LL | require_impl_deref_slice(slice.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:131:29
+ --> tests/ui/unnecessary_to_owned.rs:132:29
|
LL | require_deref_str_slice(s.to_owned(), slice.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:131:43
+ --> tests/ui/unnecessary_to_owned.rs:132:43
|
LL | require_deref_str_slice(s.to_owned(), slice.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:134:29
+ --> tests/ui/unnecessary_to_owned.rs:135:29
|
LL | require_deref_slice_str(slice.to_owned(), s.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:134:47
+ --> tests/ui/unnecessary_to_owned.rs:135:47
|
LL | require_deref_slice_str(slice.to_owned(), s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:138:26
+ --> tests/ui/unnecessary_to_owned.rs:139:26
|
LL | require_as_ref_c_str(c_str.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `c_str`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:140:27
+ --> tests/ui/unnecessary_to_owned.rs:141:27
|
LL | require_as_ref_os_str(os_str.to_owned());
| ^^^^^^^^^^^^^^^^^ help: use: `os_str`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:142:25
+ --> tests/ui/unnecessary_to_owned.rs:143:25
|
LL | require_as_ref_path(path.to_owned());
| ^^^^^^^^^^^^^^^ help: use: `path`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:144:24
+ --> tests/ui/unnecessary_to_owned.rs:145:24
|
LL | require_as_ref_str(s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:146:24
+ --> tests/ui/unnecessary_to_owned.rs:147:24
|
LL | require_as_ref_str(x.to_owned());
| ^^^^^^^^^^^^ help: use: `&x`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:148:26
+ --> tests/ui/unnecessary_to_owned.rs:149:26
|
LL | require_as_ref_slice(array.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `array`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:150:26
+ --> tests/ui/unnecessary_to_owned.rs:151:26
|
LL | require_as_ref_slice(array_ref.to_owned());
| ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:152:26
+ --> tests/ui/unnecessary_to_owned.rs:153:26
|
LL | require_as_ref_slice(slice.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:155:31
+ --> tests/ui/unnecessary_to_owned.rs:156:31
|
LL | require_impl_as_ref_c_str(c_str.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `c_str`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:157:32
+ --> tests/ui/unnecessary_to_owned.rs:158:32
|
LL | require_impl_as_ref_os_str(os_str.to_owned());
| ^^^^^^^^^^^^^^^^^ help: use: `os_str`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:159:30
+ --> tests/ui/unnecessary_to_owned.rs:160:30
|
LL | require_impl_as_ref_path(path.to_owned());
| ^^^^^^^^^^^^^^^ help: use: `path`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:161:29
+ --> tests/ui/unnecessary_to_owned.rs:162:29
|
LL | require_impl_as_ref_str(s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:163:29
+ --> tests/ui/unnecessary_to_owned.rs:164:29
|
LL | require_impl_as_ref_str(x.to_owned());
| ^^^^^^^^^^^^ help: use: `&x`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:165:31
+ --> tests/ui/unnecessary_to_owned.rs:166:31
|
LL | require_impl_as_ref_slice(array.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `array`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:167:31
+ --> tests/ui/unnecessary_to_owned.rs:168:31
|
LL | require_impl_as_ref_slice(array_ref.to_owned());
| ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:169:31
+ --> tests/ui/unnecessary_to_owned.rs:170:31
|
LL | require_impl_as_ref_slice(slice.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:172:30
+ --> tests/ui/unnecessary_to_owned.rs:173:30
|
LL | require_as_ref_str_slice(s.to_owned(), array.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:172:44
+ --> tests/ui/unnecessary_to_owned.rs:173:44
|
LL | require_as_ref_str_slice(s.to_owned(), array.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `array`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:175:30
+ --> tests/ui/unnecessary_to_owned.rs:176:30
|
LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:175:44
+ --> tests/ui/unnecessary_to_owned.rs:176:44
|
LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned());
| ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:178:30
+ --> tests/ui/unnecessary_to_owned.rs:179:30
|
LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:178:44
+ --> tests/ui/unnecessary_to_owned.rs:179:44
|
LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:181:30
+ --> tests/ui/unnecessary_to_owned.rs:182:30
|
LL | require_as_ref_slice_str(array.to_owned(), s.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `array`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:181:48
+ --> tests/ui/unnecessary_to_owned.rs:182:48
|
LL | require_as_ref_slice_str(array.to_owned(), s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:184:30
+ --> tests/ui/unnecessary_to_owned.rs:185:30
|
LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned());
| ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:184:52
+ --> tests/ui/unnecessary_to_owned.rs:185:52
|
LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:187:30
+ --> tests/ui/unnecessary_to_owned.rs:188:30
|
LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:187:48
+ --> tests/ui/unnecessary_to_owned.rs:188:48
|
LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_string`
- --> tests/ui/unnecessary_to_owned.rs:191:20
+ --> tests/ui/unnecessary_to_owned.rs:192:20
|
LL | let _ = x.join(&x_ref.to_string());
| ^^^^^^^^^^^^^^^^^^ help: use: `x_ref`
error: unnecessary use of `to_vec`
- --> tests/ui/unnecessary_to_owned.rs:194:13
+ --> tests/ui/unnecessary_to_owned.rs:195:13
|
LL | let _ = slice.to_vec().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:196:13
+ --> tests/ui/unnecessary_to_owned.rs:197:13
|
LL | let _ = slice.to_owned().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
error: unnecessary use of `to_vec`
- --> tests/ui/unnecessary_to_owned.rs:199:13
+ --> tests/ui/unnecessary_to_owned.rs:200:13
|
LL | let _ = IntoIterator::into_iter(slice.to_vec());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:201:13
+ --> tests/ui/unnecessary_to_owned.rs:202:13
|
LL | let _ = IntoIterator::into_iter(slice.to_owned());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
error: allocating a new `String` only to create a temporary `&str` from it
- --> tests/ui/unnecessary_to_owned.rs:229:26
+ --> tests/ui/unnecessary_to_owned.rs:230:26
|
LL | let _ref_str: &str = &String::from_utf8(slice.to_vec()).expect("not UTF-8");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -466,7 +466,7 @@
|
error: allocating a new `String` only to create a temporary `&str` from it
- --> tests/ui/unnecessary_to_owned.rs:231:26
+ --> tests/ui/unnecessary_to_owned.rs:232:26
|
LL | let _ref_str: &str = &String::from_utf8(b"foo".to_vec()).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -478,7 +478,7 @@
|
error: allocating a new `String` only to create a temporary `&str` from it
- --> tests/ui/unnecessary_to_owned.rs:233:26
+ --> tests/ui/unnecessary_to_owned.rs:234:26
|
LL | let _ref_str: &str = &String::from_utf8(b"foo".as_slice().to_owned()).unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -490,7 +490,7 @@
|
error: unnecessary use of `to_vec`
- --> tests/ui/unnecessary_to_owned.rs:291:14
+ --> tests/ui/unnecessary_to_owned.rs:292:14
|
LL | for t in file_types.to_vec() {
| ^^^^^^^^^^^^^^^^^^^
@@ -503,49 +503,49 @@
|
error: unnecessary use of `to_string`
- --> tests/ui/unnecessary_to_owned.rs:357:24
+ --> tests/ui/unnecessary_to_owned.rs:358:24
|
LL | Box::new(build(y.to_string()))
| ^^^^^^^^^^^^^ help: use: `y`
error: unnecessary use of `to_string`
- --> tests/ui/unnecessary_to_owned.rs:467:12
+ --> tests/ui/unnecessary_to_owned.rs:468:12
|
LL | id("abc".to_string())
| ^^^^^^^^^^^^^^^^^ help: use: `"abc"`
error: unnecessary use of `to_vec`
- --> tests/ui/unnecessary_to_owned.rs:611:37
+ --> tests/ui/unnecessary_to_owned.rs:612:37
|
LL | IntoFuture::into_future(foo([].to_vec(), &0));
| ^^^^^^^^^^^ help: use: `[]`
error: unnecessary use of `to_vec`
- --> tests/ui/unnecessary_to_owned.rs:622:18
+ --> tests/ui/unnecessary_to_owned.rs:623:18
|
LL | s.remove(&a.to_vec());
| ^^^^^^^^^^^ help: replace it with: `a`
error: unnecessary use of `to_owned`
- --> tests/ui/unnecessary_to_owned.rs:627:14
+ --> tests/ui/unnecessary_to_owned.rs:628:14
|
LL | s.remove(&"b".to_owned());
| ^^^^^^^^^^^^^^^ help: replace it with: `"b"`
error: unnecessary use of `to_string`
- --> tests/ui/unnecessary_to_owned.rs:629:14
+ --> tests/ui/unnecessary_to_owned.rs:630:14
|
LL | s.remove(&"b".to_string());
| ^^^^^^^^^^^^^^^^ help: replace it with: `"b"`
error: unnecessary use of `to_vec`
- --> tests/ui/unnecessary_to_owned.rs:635:14
+ --> tests/ui/unnecessary_to_owned.rs:636:14
|
LL | s.remove(&["b"].to_vec());
| ^^^^^^^^^^^^^^^ help: replace it with: `["b"].as_slice()`
error: unnecessary use of `to_vec`
- --> tests/ui/unnecessary_to_owned.rs:637:14
+ --> tests/ui/unnecessary_to_owned.rs:638:14
|
LL | s.remove(&(&["b"]).to_vec());
| ^^^^^^^^^^^^^^^^^^ help: replace it with: `(&["b"]).as_slice()`
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed
index 791b2fa..2081772 100644
--- a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed
@@ -64,3 +64,16 @@
if let [1 | 53] = [0] {}
//~^ unnested_or_patterns
}
+
+mod issue9952 {
+ fn or_in_local() {
+ let (0 | 1 | _) = 0;
+ //~^ unnested_or_patterns
+
+ if let (0 | 1 | _) = 0 {}
+ //~^ unnested_or_patterns
+ }
+
+ fn or_in_param((x | x | x): i32) {}
+ //~^ unnested_or_patterns
+}
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.rs b/src/tools/clippy/tests/ui/unnested_or_patterns.rs
index e7e7c7c..6bf8fce 100644
--- a/src/tools/clippy/tests/ui/unnested_or_patterns.rs
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns.rs
@@ -64,3 +64,16 @@ fn msrv_1_53() {
if let [1] | [53] = [0] {}
//~^ unnested_or_patterns
}
+
+mod issue9952 {
+ fn or_in_local() {
+ let (0 | (1 | _)) = 0;
+ //~^ unnested_or_patterns
+
+ if let (0 | (1 | _)) = 0 {}
+ //~^ unnested_or_patterns
+ }
+
+ fn or_in_param((x | (x | x)): i32) {}
+ //~^ unnested_or_patterns
+}
diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr
index ec5eb98..c805dc9 100644
--- a/src/tools/clippy/tests/ui/unnested_or_patterns.stderr
+++ b/src/tools/clippy/tests/ui/unnested_or_patterns.stderr
@@ -204,5 +204,41 @@
LL + if let [1 | 53] = [0] {}
|
-error: aborting due to 17 previous errors
+error: unnested or-patterns
+ --> tests/ui/unnested_or_patterns.rs:70:13
+ |
+LL | let (0 | (1 | _)) = 0;
+ | ^^^^^^^^^^^^^
+ |
+help: nest the patterns
+ |
+LL - let (0 | (1 | _)) = 0;
+LL + let (0 | 1 | _) = 0;
+ |
+
+error: unnested or-patterns
+ --> tests/ui/unnested_or_patterns.rs:73:16
+ |
+LL | if let (0 | (1 | _)) = 0 {}
+ | ^^^^^^^^^^^^^
+ |
+help: nest the patterns
+ |
+LL - if let (0 | (1 | _)) = 0 {}
+LL + if let (0 | 1 | _) = 0 {}
+ |
+
+error: unnested or-patterns
+ --> tests/ui/unnested_or_patterns.rs:77:20
+ |
+LL | fn or_in_param((x | (x | x)): i32) {}
+ | ^^^^^^^^^^^^^
+ |
+help: nest the patterns
+ |
+LL - fn or_in_param((x | (x | x)): i32) {}
+LL + fn or_in_param((x | x | x): i32) {}
+ |
+
+error: aborting due to 20 previous errors
diff --git a/src/tools/clippy/tests/ui/unwrap_or.fixed b/src/tools/clippy/tests/ui/unwrap_or.fixed
index c794ed5..e550484 100644
--- a/src/tools/clippy/tests/ui/unwrap_or.fixed
+++ b/src/tools/clippy/tests/ui/unwrap_or.fixed
@@ -1,4 +1,4 @@
-#![warn(clippy::all, clippy::or_fun_call)]
+#![warn(clippy::or_fun_call)]
#![allow(clippy::unnecessary_literal_unwrap)]
fn main() {
diff --git a/src/tools/clippy/tests/ui/unwrap_or.rs b/src/tools/clippy/tests/ui/unwrap_or.rs
index 11a6883..cdd61ac 100644
--- a/src/tools/clippy/tests/ui/unwrap_or.rs
+++ b/src/tools/clippy/tests/ui/unwrap_or.rs
@@ -1,4 +1,4 @@
-#![warn(clippy::all, clippy::or_fun_call)]
+#![warn(clippy::or_fun_call)]
#![allow(clippy::unnecessary_literal_unwrap)]
fn main() {
diff --git a/src/tools/clippy/tests/ui/used_underscore_items.rs b/src/tools/clippy/tests/ui/used_underscore_items.rs
index 3401df6..7e8289f 100644
--- a/src/tools/clippy/tests/ui/used_underscore_items.rs
+++ b/src/tools/clippy/tests/ui/used_underscore_items.rs
@@ -73,7 +73,7 @@ fn external_item_call() {
// should not lint foreign functions.
// issue #14156
-extern "C" {
+unsafe extern "C" {
pub fn _exit(code: i32) -> !;
}
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index 33d3b07..f27b109 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -9,11 +9,32 @@
# See https://forge.rust-lang.org/triagebot/shortcuts.html
[shortcut]
+[merge-conflicts]
+
+[note]
+
+[canonicalize-issue-links]
+
+# Prevents mentions in commits to avoid users being spammed
+[no-mentions]
+
# Have rustbot inform users about the *No Merge Policy*
[no-merges]
exclude_titles = ["Rustup"] # exclude syncs from rust-lang/rust
labels = ["has-merge-commits", "S-waiting-on-author"]
+[review-requested]
+# Those labels are removed when PR author requests a review from an assignee
+remove_labels = ["S-waiting-on-author"]
+# Those labels are added when PR author requests a review from an assignee
+add_labels = ["S-waiting-on-review"]
+
+[review-submitted]
+# These labels are removed when a review is submitted.
+review_labels = ["S-waiting-on-review"]
+# This label is added when a review is submitted.
+reviewed_label = "S-waiting-on-author"
+
[autolabel."S-waiting-on-review"]
new_pr = true
@@ -21,10 +42,12 @@
contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md"
users_on_vacation = [
"matthiaskrgr",
+ "samueltardieu",
]
[assign.owners]
"/.github" = ["@flip1995"]
+"/triagebot.toml" = ["@flip1995"]
"/book" = ["@flip1995"]
"*" = [
"@Manishearth",
@@ -34,4 +57,5 @@
"@Jarcho",
"@blyxyas",
"@y21",
+ "@samueltardieu",
]
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index 3db34ed..ba1b8f2 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -10,6 +10,7 @@
# tidy-alphabetical-start
anstyle-svg = "0.1.3"
build_helper = { path = "../../build_helper" }
+camino = "1"
colored = "2"
diff = "0.1.10"
getopts = "0.2"
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 6750b52..de93e2b 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -1,18 +1,17 @@
use std::collections::{BTreeSet, HashMap, HashSet};
-use std::ffi::OsString;
-use std::path::{Path, PathBuf};
use std::process::Command;
use std::str::FromStr;
use std::sync::OnceLock;
use std::{fmt, iter};
use build_helper::git::GitConfig;
+use camino::{Utf8Path, Utf8PathBuf};
use semver::Version;
use serde::de::{Deserialize, Deserializer, Error as _};
pub use self::Mode::*;
use crate::executor::{ColorConfig, OutputFormat};
-use crate::util::{PathBufExt, add_dylib_path};
+use crate::util::{Utf8PathBufExt, add_dylib_path};
macro_rules! string_enum {
($(#[$meta:meta])* $vis:vis enum $name:ident { $($variant:ident => $repr:expr,)* }) => {
@@ -183,25 +182,25 @@ pub struct Config {
pub fail_fast: bool,
/// The library paths required for running the compiler.
- pub compile_lib_path: PathBuf,
+ pub compile_lib_path: Utf8PathBuf,
/// The library paths required for running compiled programs.
- pub run_lib_path: PathBuf,
+ pub run_lib_path: Utf8PathBuf,
/// The rustc executable.
- pub rustc_path: PathBuf,
+ pub rustc_path: Utf8PathBuf,
/// The cargo executable.
- pub cargo_path: Option<PathBuf>,
+ pub cargo_path: Option<Utf8PathBuf>,
/// Rustc executable used to compile run-make recipes.
- pub stage0_rustc_path: Option<PathBuf>,
+ pub stage0_rustc_path: Option<Utf8PathBuf>,
/// The rustdoc executable.
- pub rustdoc_path: Option<PathBuf>,
+ pub rustdoc_path: Option<Utf8PathBuf>,
/// The coverage-dump executable.
- pub coverage_dump_path: Option<PathBuf>,
+ pub coverage_dump_path: Option<Utf8PathBuf>,
/// The Python executable to use for LLDB and htmldocck.
pub python: String,
@@ -213,27 +212,27 @@ pub struct Config {
pub jsondoclint_path: Option<String>,
/// The LLVM `FileCheck` binary path.
- pub llvm_filecheck: Option<PathBuf>,
+ pub llvm_filecheck: Option<Utf8PathBuf>,
/// Path to LLVM's bin directory.
- pub llvm_bin_dir: Option<PathBuf>,
+ pub llvm_bin_dir: Option<Utf8PathBuf>,
/// The path to the Clang executable to run Clang-based tests with. If
/// `None` then these tests will be ignored.
pub run_clang_based_tests_with: Option<String>,
/// The directory containing the sources.
- pub src_root: PathBuf,
+ pub src_root: Utf8PathBuf,
/// The directory containing the test suite sources. Must be a subdirectory of `src_root`.
- pub src_test_suite_root: PathBuf,
+ pub src_test_suite_root: Utf8PathBuf,
/// Root build directory (e.g. `build/`).
- pub build_root: PathBuf,
+ pub build_root: Utf8PathBuf,
/// Test suite specific build directory (e.g. `build/host/test/ui/`).
- pub build_test_suite_root: PathBuf,
+ pub build_test_suite_root: Utf8PathBuf,
/// The directory containing the compiler sysroot
- pub sysroot_base: PathBuf,
+ pub sysroot_base: Utf8PathBuf,
/// The number of the stage under test.
pub stage: u32,
@@ -301,7 +300,7 @@ pub struct Config {
pub host: String,
/// Path to / name of the Microsoft Console Debugger (CDB) executable
- pub cdb: Option<OsString>,
+ pub cdb: Option<Utf8PathBuf>,
/// Version of CDB
pub cdb_version: Option<[u16; 4]>,
@@ -322,7 +321,7 @@ pub struct Config {
pub system_llvm: bool,
/// Path to the android tools
- pub android_cross_path: PathBuf,
+ pub android_cross_path: Utf8PathBuf,
/// Extra parameter to run adb on arm-linux-androideabi
pub adb_path: String,
@@ -346,7 +345,7 @@ pub struct Config {
pub color: ColorConfig,
/// where to find the remote test client process, if we're using it
- pub remote_test_client: Option<PathBuf>,
+ pub remote_test_client: Option<Utf8PathBuf>,
/// mode describing what file the actual ui output will be compared to
pub compare_mode: Option<CompareMode>,
@@ -414,7 +413,15 @@ pub struct Config {
/// Path to minicore aux library, used for `no_core` tests that need `core` stubs in
/// cross-compilation scenarios that do not otherwise want/need to `-Zbuild-std`. Used in e.g.
/// ABI tests.
- pub minicore_path: PathBuf,
+ pub minicore_path: Utf8PathBuf,
+
+ /// If true, disable the "new" executor, and use the older libtest-based
+ /// executor to run tests instead. This is a temporary fallback, to make
+ /// manual comparative testing easier if bugs are found in the new executor.
+ ///
+ /// FIXME(Zalathar): Eventually remove this flag and remove the libtest
+ /// dependency.
+ pub no_new_executor: bool,
}
impl Config {
@@ -804,8 +811,8 @@ fn serde_parse_u32<'de, D: Deserializer<'de>>(deserializer: D) -> Result<u32, D:
#[derive(Debug, Clone)]
pub struct TestPaths {
- pub file: PathBuf, // e.g., compile-test/foo/bar/baz.rs
- pub relative_dir: PathBuf, // e.g., foo/bar
+ pub file: Utf8PathBuf, // e.g., compile-test/foo/bar/baz.rs
+ pub relative_dir: Utf8PathBuf, // e.g., foo/bar
}
/// Used by `ui` tests to generate things like `foo.stderr` from `foo.rs`.
@@ -814,7 +821,7 @@ pub fn expected_output_path(
revision: Option<&str>,
compare_mode: &Option<CompareMode>,
kind: &str,
-) -> PathBuf {
+) -> Utf8PathBuf {
assert!(UI_EXTENSIONS.contains(&kind));
let mut parts = Vec::new();
@@ -865,7 +872,7 @@ pub fn expected_output_path(
/// ```
///
/// This is created early when tests are collected to avoid race conditions.
-pub fn output_relative_path(config: &Config, relative_dir: &Path) -> PathBuf {
+pub fn output_relative_path(config: &Config, relative_dir: &Utf8Path) -> Utf8PathBuf {
config.build_test_suite_root.join(relative_dir)
}
@@ -874,10 +881,10 @@ pub fn output_testname_unique(
config: &Config,
testpaths: &TestPaths,
revision: Option<&str>,
-) -> PathBuf {
+) -> Utf8PathBuf {
let mode = config.compare_mode.as_ref().map_or("", |m| m.to_str());
let debugger = config.debugger.as_ref().map_or("", |m| m.to_str());
- PathBuf::from(&testpaths.file.file_stem().unwrap())
+ Utf8PathBuf::from(&testpaths.file.file_stem().unwrap())
.with_extra_extension(config.mode.output_dir_disambiguator())
.with_extra_extension(revision.unwrap_or(""))
.with_extra_extension(mode)
@@ -887,7 +894,11 @@ pub fn output_testname_unique(
/// Absolute path to the directory where all output for the given
/// test/revision should reside. Example:
/// /path/to/build/host-tuple/test/ui/relative/testname.revision.mode/
-pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
+pub fn output_base_dir(
+ config: &Config,
+ testpaths: &TestPaths,
+ revision: Option<&str>,
+) -> Utf8PathBuf {
output_relative_path(config, &testpaths.relative_dir)
.join(output_testname_unique(config, testpaths, revision))
}
@@ -895,12 +906,20 @@ pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option<
/// Absolute path to the base filename used as output for the given
/// test/revision. Example:
/// /path/to/build/host-tuple/test/ui/relative/testname.revision.mode/testname
-pub fn output_base_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
+pub fn output_base_name(
+ config: &Config,
+ testpaths: &TestPaths,
+ revision: Option<&str>,
+) -> Utf8PathBuf {
output_base_dir(config, testpaths, revision).join(testpaths.file.file_stem().unwrap())
}
/// Absolute path to the directory to use for incremental compilation. Example:
/// /path/to/build/host-tuple/test/ui/relative/testname.mode/testname.inc
-pub fn incremental_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
+pub fn incremental_dir(
+ config: &Config,
+ testpaths: &TestPaths,
+ revision: Option<&str>,
+) -> Utf8PathBuf {
output_base_name(config, testpaths, revision).with_extension("inc")
}
diff --git a/src/tools/compiletest/src/compute_diff.rs b/src/tools/compiletest/src/compute_diff.rs
index 4c942c5..509e7e1 100644
--- a/src/tools/compiletest/src/compute_diff.rs
+++ b/src/tools/compiletest/src/compute_diff.rs
@@ -1,6 +1,7 @@
use std::collections::VecDeque;
use std::fs::{File, FileType};
-use std::path::Path;
+
+use camino::Utf8Path;
#[derive(Debug, PartialEq)]
pub enum DiffLine {
@@ -112,8 +113,8 @@ pub(crate) fn write_diff(expected: &str, actual: &str, context_size: usize) -> S
/// Returns whether any data was actually written.
pub(crate) fn write_filtered_diff<Filter>(
diff_filename: &str,
- out_dir: &Path,
- compare_dir: &Path,
+ out_dir: &Utf8Path,
+ compare_dir: &Utf8Path,
verbose: bool,
filter: Filter,
) -> bool
@@ -123,19 +124,21 @@ pub(crate) fn write_filtered_diff<Filter>(
use std::io::{Read, Write};
let mut diff_output = File::create(diff_filename).unwrap();
let mut wrote_data = false;
- for entry in walkdir::WalkDir::new(out_dir) {
+ for entry in walkdir::WalkDir::new(out_dir.as_std_path()) {
let entry = entry.expect("failed to read file");
let extension = entry.path().extension().and_then(|p| p.to_str());
if filter(entry.file_type(), extension) {
- let expected_path = compare_dir.join(entry.path().strip_prefix(&out_dir).unwrap());
+ let expected_path = compare_dir
+ .as_std_path()
+ .join(entry.path().strip_prefix(&out_dir.as_std_path()).unwrap());
let expected = if let Ok(s) = std::fs::read(&expected_path) { s } else { continue };
let actual_path = entry.path();
let actual = std::fs::read(&actual_path).unwrap();
let diff = unified_diff::diff(
&expected,
- &expected_path.to_string_lossy(),
+ &expected_path.to_str().unwrap(),
&actual,
- &actual_path.to_string_lossy(),
+ &actual_path.to_str().unwrap(),
3,
);
wrote_data |= !diff.is_empty();
diff --git a/src/tools/compiletest/src/debuggers.rs b/src/tools/compiletest/src/debuggers.rs
index 5126e55..c133d7f 100644
--- a/src/tools/compiletest/src/debuggers.rs
+++ b/src/tools/compiletest/src/debuggers.rs
@@ -1,9 +1,9 @@
use std::env;
-use std::ffi::OsString;
-use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::Arc;
+use camino::{Utf8Path, Utf8PathBuf};
+
use crate::common::{Config, Debugger};
pub(crate) fn configure_cdb(config: &Config) -> Option<Arc<Config>> {
@@ -78,12 +78,15 @@ fn is_pc_windows_msvc_target(target: &str) -> bool {
target.ends_with("-pc-windows-msvc")
}
-fn find_cdb(target: &str) -> Option<OsString> {
+fn find_cdb(target: &str) -> Option<Utf8PathBuf> {
if !(cfg!(windows) && is_pc_windows_msvc_target(target)) {
return None;
}
- let pf86 = env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?;
+ let pf86 = Utf8PathBuf::from_path_buf(
+ env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?.into(),
+ )
+ .unwrap();
let cdb_arch = if cfg!(target_arch = "x86") {
"x86"
} else if cfg!(target_arch = "x86_64") {
@@ -96,8 +99,7 @@ fn find_cdb(target: &str) -> Option<OsString> {
return None; // No compatible CDB.exe in the Windows 10 SDK
};
- let mut path = PathBuf::new();
- path.push(pf86);
+ let mut path = pf86;
path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too?
path.push(cdb_arch);
path.push(r"cdb.exe");
@@ -106,15 +108,15 @@ fn find_cdb(target: &str) -> Option<OsString> {
return None;
}
- Some(path.into_os_string())
+ Some(path)
}
/// Returns Path to CDB
pub(crate) fn analyze_cdb(
cdb: Option<String>,
target: &str,
-) -> (Option<OsString>, Option<[u16; 4]>) {
- let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target));
+) -> (Option<Utf8PathBuf>, Option<[u16; 4]>) {
+ let cdb = cdb.map(Utf8PathBuf::from).or_else(|| find_cdb(target));
let mut version = None;
if let Some(cdb) = cdb.as_ref() {
@@ -143,7 +145,7 @@ pub(crate) fn analyze_cdb(
pub(crate) fn analyze_gdb(
gdb: Option<String>,
target: &str,
- android_cross_path: &Path,
+ android_cross_path: &Utf8Path,
) -> (Option<String>, Option<u32>) {
#[cfg(not(windows))]
const GDB_FALLBACK: &str = "gdb";
@@ -152,10 +154,7 @@ pub(crate) fn analyze_gdb(
let fallback_gdb = || {
if is_android_gdb_target(target) {
- let mut gdb_path = match android_cross_path.to_str() {
- Some(x) => x.to_owned(),
- None => panic!("cannot find android cross path"),
- };
+ let mut gdb_path = android_cross_path.to_string();
gdb_path.push_str("/bin/gdb");
gdb_path
} else {
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index 086a8a6..1449e9a 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -44,6 +44,7 @@
"ignore-arm-unknown-linux-gnueabihf",
"ignore-arm-unknown-linux-musleabi",
"ignore-arm-unknown-linux-musleabihf",
+ "ignore-auxiliary",
"ignore-avr",
"ignore-beta",
"ignore-cdb",
@@ -177,6 +178,7 @@
"only-32bit",
"only-64bit",
"only-aarch64",
+ "only-aarch64-apple-darwin",
"only-aarch64-unknown-linux-gnu",
"only-apple",
"only-arm",
@@ -190,6 +192,7 @@
"only-gnu",
"only-i686-pc-windows-gnu",
"only-i686-pc-windows-msvc",
+ "only-i686-unknown-linux-gnu",
"only-ios",
"only-linux",
"only-loongarch64",
@@ -221,6 +224,7 @@
"only-windows-msvc",
"only-x86",
"only-x86_64",
+ "only-x86_64-apple-darwin",
"only-x86_64-fortanix-unknown-sgx",
"only-x86_64-pc-windows-gnu",
"only-x86_64-pc-windows-msvc",
diff --git a/src/tools/compiletest/src/errors.rs b/src/tools/compiletest/src/errors.rs
index 64d68eb..3bb9827 100644
--- a/src/tools/compiletest/src/errors.rs
+++ b/src/tools/compiletest/src/errors.rs
@@ -2,9 +2,9 @@
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
-use std::path::Path;
use std::sync::OnceLock;
+use camino::Utf8Path;
use regex::Regex;
use tracing::*;
@@ -102,8 +102,8 @@ pub fn line_num_str(&self) -> String {
///
/// If revision is not None, then we look
/// for `//[X]~` instead, where `X` is the current revision.
-pub fn load_errors(testfile: &Path, revision: Option<&str>) -> Vec<Error> {
- let rdr = BufReader::new(File::open(testfile).unwrap());
+pub fn load_errors(testfile: &Utf8Path, revision: Option<&str>) -> Vec<Error> {
+ let rdr = BufReader::new(File::open(testfile.as_std_path()).unwrap());
// `last_nonfollow_error` tracks the most recently seen
// line with an error template that did not use the
diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs
index 527d6b8..990be56 100644
--- a/src/tools/compiletest/src/executor.rs
+++ b/src/tools/compiletest/src/executor.rs
@@ -1,22 +1,253 @@
-//! This module encapsulates all of the code that interacts directly with
-//! libtest, to execute the collected tests.
-//!
-//! This will hopefully make it easier to migrate away from libtest someday.
+//! This module contains a reimplementation of the subset of libtest
+//! functionality needed by compiletest.
use std::borrow::Cow;
-use std::io;
-use std::sync::Arc;
+use std::collections::HashMap;
+use std::hash::{BuildHasherDefault, DefaultHasher};
+use std::num::NonZero;
+use std::sync::{Arc, Mutex, mpsc};
+use std::{env, hint, io, mem, panic, thread};
use crate::common::{Config, TestPaths};
-/// Delegates to libtest to run the list of collected tests.
-///
-/// Returns `Ok(true)` if all tests passed, or `Ok(false)` if one or more tests failed.
-pub(crate) fn execute_tests(config: &Config, tests: Vec<CollectedTest>) -> io::Result<bool> {
- let opts = test_opts(config);
- let tests = tests.into_iter().map(|t| t.into_libtest()).collect::<Vec<_>>();
+mod deadline;
+mod json;
+pub(crate) mod libtest;
- test::run_tests_console(&opts, tests)
+pub(crate) fn run_tests(config: &Config, tests: Vec<CollectedTest>) -> bool {
+ let tests_len = tests.len();
+ let filtered = filter_tests(config, tests);
+ // Iterator yielding tests that haven't been started yet.
+ let mut fresh_tests = (0..).map(TestId).zip(&filtered);
+
+ let concurrency = get_concurrency();
+ assert!(concurrency > 0);
+ let concurrent_capacity = concurrency.min(filtered.len());
+
+ let mut listener = json::Listener::new();
+ let mut running_tests = HashMap::with_capacity_and_hasher(
+ concurrent_capacity,
+ BuildHasherDefault::<DefaultHasher>::new(),
+ );
+ let mut deadline_queue = deadline::DeadlineQueue::with_capacity(concurrent_capacity);
+
+ let num_filtered_out = tests_len - filtered.len();
+ listener.suite_started(filtered.len(), num_filtered_out);
+
+ // Channel used by test threads to report the test outcome when done.
+ let (completion_tx, completion_rx) = mpsc::channel::<TestCompletion>();
+
+ // Unlike libtest, we don't have a separate code path for concurrency=1.
+ // In that case, the tests will effectively be run serially anyway.
+ loop {
+ // Spawn new test threads, up to the concurrency limit.
+ // FIXME(let_chains): Use a let-chain here when stable in bootstrap.
+ 'spawn: while running_tests.len() < concurrency {
+ let Some((id, test)) = fresh_tests.next() else { break 'spawn };
+ listener.test_started(test);
+ deadline_queue.push(id, test);
+ let join_handle = spawn_test_thread(id, test, completion_tx.clone());
+ running_tests.insert(id, RunningTest { test, join_handle });
+ }
+
+ // If all running tests have finished, and there weren't any unstarted
+ // tests to spawn, then we're done.
+ if running_tests.is_empty() {
+ break;
+ }
+
+ let completion = deadline_queue
+ .read_channel_while_checking_deadlines(
+ &completion_rx,
+ |id| running_tests.contains_key(&id),
+ |_id, test| listener.test_timed_out(test),
+ )
+ .expect("receive channel should never be closed early");
+
+ let RunningTest { test, join_handle } = running_tests.remove(&completion.id).unwrap();
+ if let Some(join_handle) = join_handle {
+ join_handle.join().unwrap_or_else(|_| {
+ panic!("thread for `{}` panicked after reporting completion", test.desc.name)
+ });
+ }
+
+ listener.test_finished(test, &completion);
+
+ if completion.outcome.is_failed() && config.fail_fast {
+ // Prevent any other in-flight threads from panicking when they
+ // write to the completion channel.
+ mem::forget(completion_rx);
+ break;
+ }
+ }
+
+ let suite_passed = listener.suite_finished();
+ suite_passed
+}
+
+/// Spawns a thread to run a single test, and returns the thread's join handle.
+///
+/// Returns `None` if the test was ignored, so no thread was spawned.
+fn spawn_test_thread(
+ id: TestId,
+ test: &CollectedTest,
+ completion_tx: mpsc::Sender<TestCompletion>,
+) -> Option<thread::JoinHandle<()>> {
+ if test.desc.ignore && !test.config.run_ignored {
+ completion_tx
+ .send(TestCompletion { id, outcome: TestOutcome::Ignored, stdout: None })
+ .unwrap();
+ return None;
+ }
+
+ let runnable_test = RunnableTest::new(test);
+ let should_panic = test.desc.should_panic;
+ let run_test = move || run_test_inner(id, should_panic, runnable_test, completion_tx);
+
+ let thread_builder = thread::Builder::new().name(test.desc.name.clone());
+ let join_handle = thread_builder.spawn(run_test).unwrap();
+ Some(join_handle)
+}
+
+/// Runs a single test, within the dedicated thread spawned by the caller.
+fn run_test_inner(
+ id: TestId,
+ should_panic: ShouldPanic,
+ runnable_test: RunnableTest,
+ completion_sender: mpsc::Sender<TestCompletion>,
+) {
+ let is_capture = !runnable_test.config.nocapture;
+ let capture_buf = is_capture.then(|| Arc::new(Mutex::new(vec![])));
+
+ if let Some(capture_buf) = &capture_buf {
+ io::set_output_capture(Some(Arc::clone(capture_buf)));
+ }
+
+ let panic_payload = panic::catch_unwind(move || runnable_test.run()).err();
+
+ if is_capture {
+ io::set_output_capture(None);
+ }
+
+ let outcome = match (should_panic, panic_payload) {
+ (ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestOutcome::Succeeded,
+ (ShouldPanic::No, Some(_)) => TestOutcome::Failed { message: None },
+ (ShouldPanic::Yes, None) => {
+ TestOutcome::Failed { message: Some("test did not panic as expected") }
+ }
+ };
+ let stdout = capture_buf.map(|mutex| mutex.lock().unwrap_or_else(|e| e.into_inner()).to_vec());
+
+ completion_sender.send(TestCompletion { id, outcome, stdout }).unwrap();
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+struct TestId(usize);
+
+struct RunnableTest {
+ config: Arc<Config>,
+ testpaths: TestPaths,
+ revision: Option<String>,
+}
+
+impl RunnableTest {
+ fn new(test: &CollectedTest) -> Self {
+ let config = Arc::clone(&test.config);
+ let testpaths = test.testpaths.clone();
+ let revision = test.revision.clone();
+ Self { config, testpaths, revision }
+ }
+
+ fn run(&self) {
+ __rust_begin_short_backtrace(|| {
+ crate::runtest::run(
+ Arc::clone(&self.config),
+ &self.testpaths,
+ self.revision.as_deref(),
+ );
+ });
+ }
+}
+
+/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
+#[inline(never)]
+fn __rust_begin_short_backtrace<T, F: FnOnce() -> T>(f: F) -> T {
+ let result = f();
+
+ // prevent this frame from being tail-call optimised away
+ hint::black_box(result)
+}
+
+struct RunningTest<'a> {
+ test: &'a CollectedTest,
+ join_handle: Option<thread::JoinHandle<()>>,
+}
+
+/// Test completion message sent by individual test threads when their test
+/// finishes (successfully or unsuccessfully).
+struct TestCompletion {
+ id: TestId,
+ outcome: TestOutcome,
+ stdout: Option<Vec<u8>>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq)]
+enum TestOutcome {
+ Succeeded,
+ Failed { message: Option<&'static str> },
+ Ignored,
+}
+
+impl TestOutcome {
+ fn is_failed(&self) -> bool {
+ matches!(self, Self::Failed { .. })
+ }
+}
+
+/// Applies command-line arguments for filtering/skipping tests by name.
+///
+/// Adapted from `filter_tests` in libtest.
+///
+/// FIXME(#139660): After the libtest dependency is removed, redesign the whole
+/// filtering system to do a better job of understanding and filtering _paths_,
+/// instead of being tied to libtest's substring/exact matching behaviour.
+fn filter_tests(opts: &Config, tests: Vec<CollectedTest>) -> Vec<CollectedTest> {
+ let mut filtered = tests;
+
+ let matches_filter = |test: &CollectedTest, filter_str: &str| {
+ let test_name = &test.desc.name;
+ if opts.filter_exact { test_name == filter_str } else { test_name.contains(filter_str) }
+ };
+
+ // Remove tests that don't match the test filter
+ if !opts.filters.is_empty() {
+ filtered.retain(|test| opts.filters.iter().any(|filter| matches_filter(test, filter)));
+ }
+
+ // Skip tests that match any of the skip filters
+ if !opts.skip.is_empty() {
+ filtered.retain(|test| !opts.skip.iter().any(|sf| matches_filter(test, sf)));
+ }
+
+ filtered
+}
+
+/// Determines the number of tests to run concurrently.
+///
+/// Copied from `get_concurrency` in libtest.
+///
+/// FIXME(#139660): After the libtest dependency is removed, consider making
+/// bootstrap specify the number of threads on the command-line, instead of
+/// propagating the `RUST_TEST_THREADS` environment variable.
+fn get_concurrency() -> usize {
+ if let Ok(value) = env::var("RUST_TEST_THREADS") {
+ match value.parse::<NonZero<usize>>().ok() {
+ Some(n) => n.get(),
+ _ => panic!("RUST_TEST_THREADS is `{value}`, should be a positive integer."),
+ }
+ } else {
+ thread::available_parallelism().map(|n| n.get()).unwrap_or(1)
+ }
}
/// Information needed to create a `test::TestDescAndFn`.
@@ -35,45 +266,6 @@ pub(crate) struct CollectedTestDesc {
pub(crate) should_panic: ShouldPanic,
}
-impl CollectedTest {
- fn into_libtest(self) -> test::TestDescAndFn {
- let Self { desc, config, testpaths, revision } = self;
- let CollectedTestDesc { name, ignore, ignore_message, should_panic } = desc;
-
- // Libtest requires the ignore message to be a &'static str, so we might
- // have to leak memory to create it. This is fine, as we only do so once
- // per test, so the leak won't grow indefinitely.
- let ignore_message = ignore_message.map(|msg| match msg {
- Cow::Borrowed(s) => s,
- Cow::Owned(s) => &*String::leak(s),
- });
-
- let desc = test::TestDesc {
- name: test::DynTestName(name),
- ignore,
- ignore_message,
- source_file: "",
- start_line: 0,
- start_col: 0,
- end_line: 0,
- end_col: 0,
- should_panic: should_panic.to_libtest(),
- compile_fail: false,
- no_run: false,
- test_type: test::TestType::Unknown,
- };
-
- // This closure is invoked when libtest returns control to compiletest
- // to execute the test.
- let testfn = test::DynTestFn(Box::new(move || {
- crate::runtest::run(config, &testpaths, revision.as_deref());
- Ok(())
- }));
-
- test::TestDescAndFn { desc, testfn }
- }
-}
-
/// Whether console output should be colored or not.
#[derive(Copy, Clone, Default, Debug)]
pub enum ColorConfig {
@@ -83,16 +275,6 @@ pub enum ColorConfig {
NeverColor,
}
-impl ColorConfig {
- fn to_libtest(self) -> test::ColorConfig {
- match self {
- Self::AutoColor => test::ColorConfig::AutoColor,
- Self::AlwaysColor => test::ColorConfig::AlwaysColor,
- Self::NeverColor => test::ColorConfig::NeverColor,
- }
- }
-}
-
/// Format of the test results output.
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub enum OutputFormat {
@@ -105,52 +287,9 @@ pub enum OutputFormat {
Json,
}
-impl OutputFormat {
- fn to_libtest(self) -> test::OutputFormat {
- match self {
- Self::Pretty => test::OutputFormat::Pretty,
- Self::Terse => test::OutputFormat::Terse,
- Self::Json => test::OutputFormat::Json,
- }
- }
-}
-
/// Whether test is expected to panic or not.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) enum ShouldPanic {
No,
Yes,
}
-
-impl ShouldPanic {
- fn to_libtest(self) -> test::ShouldPanic {
- match self {
- Self::No => test::ShouldPanic::No,
- Self::Yes => test::ShouldPanic::Yes,
- }
- }
-}
-
-fn test_opts(config: &Config) -> test::TestOpts {
- test::TestOpts {
- exclude_should_panic: false,
- filters: config.filters.clone(),
- filter_exact: config.filter_exact,
- run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No },
- format: config.format.to_libtest(),
- logfile: None,
- run_tests: true,
- bench_benchmarks: true,
- nocapture: config.nocapture,
- color: config.color.to_libtest(),
- shuffle: false,
- shuffle_seed: None,
- test_threads: None,
- skip: config.skip.clone(),
- list: false,
- options: test::Options::new(),
- time_options: None,
- force_run_in_process: false,
- fail_fast: config.fail_fast,
- }
-}
diff --git a/src/tools/compiletest/src/executor/deadline.rs b/src/tools/compiletest/src/executor/deadline.rs
new file mode 100644
index 0000000..3536eff
--- /dev/null
+++ b/src/tools/compiletest/src/executor/deadline.rs
@@ -0,0 +1,102 @@
+use std::collections::VecDeque;
+use std::sync::mpsc::{self, RecvError, RecvTimeoutError};
+use std::time::{Duration, Instant};
+
+use crate::executor::{CollectedTest, TestId};
+
+const TEST_WARN_TIMEOUT_S: u64 = 60;
+
+struct DeadlineEntry<'a> {
+ id: TestId,
+ test: &'a CollectedTest,
+ deadline: Instant,
+}
+
+pub(crate) struct DeadlineQueue<'a> {
+ queue: VecDeque<DeadlineEntry<'a>>,
+}
+
+impl<'a> DeadlineQueue<'a> {
+ pub(crate) fn with_capacity(capacity: usize) -> Self {
+ Self { queue: VecDeque::with_capacity(capacity) }
+ }
+
+ /// All calls to [`Instant::now`] go through this wrapper method.
+ /// This makes it easier to find all places that read the current time.
+ fn now(&self) -> Instant {
+ Instant::now()
+ }
+
+ pub(crate) fn push(&mut self, id: TestId, test: &'a CollectedTest) {
+ let deadline = self.now() + Duration::from_secs(TEST_WARN_TIMEOUT_S);
+ if let Some(back) = self.queue.back() {
+ assert!(back.deadline <= deadline);
+ }
+ self.queue.push_back(DeadlineEntry { id, test, deadline });
+ }
+
+ /// Equivalent to `rx.recv()`, except that if a test exceeds its deadline
+ /// during the wait, the given callback will also be called for that test.
+ pub(crate) fn read_channel_while_checking_deadlines<T>(
+ &mut self,
+ rx: &mpsc::Receiver<T>,
+ is_running: impl Fn(TestId) -> bool,
+ mut on_deadline_passed: impl FnMut(TestId, &CollectedTest),
+ ) -> Result<T, RecvError> {
+ loop {
+ let Some(next_deadline) = self.next_deadline() else {
+ // All currently-running tests have already exceeded their
+ // deadline, so do a normal receive.
+ return rx.recv();
+ };
+ let next_deadline_timeout = next_deadline.saturating_duration_since(self.now());
+
+ let recv_result = rx.recv_timeout(next_deadline_timeout);
+ // Process deadlines after every receive attempt, regardless of
+ // outcome, so that we don't build up an unbounded backlog of stale
+ // entries due to a constant stream of tests finishing.
+ self.for_each_entry_past_deadline(&is_running, &mut on_deadline_passed);
+
+ match recv_result {
+ Ok(value) => return Ok(value),
+ // Deadlines have already been processed, so loop and do another receive.
+ Err(RecvTimeoutError::Timeout) => {}
+ Err(RecvTimeoutError::Disconnected) => return Err(RecvError),
+ }
+ }
+ }
+
+ fn next_deadline(&self) -> Option<Instant> {
+ Some(self.queue.front()?.deadline)
+ }
+
+ fn for_each_entry_past_deadline(
+ &mut self,
+ is_running: impl Fn(TestId) -> bool,
+ mut on_deadline_passed: impl FnMut(TestId, &CollectedTest),
+ ) {
+ let now = self.now();
+
+ // Clear out entries that are past their deadline, but only invoke the
+ // callback for tests that are still considered running.
+ while let Some(entry) = pop_front_if(&mut self.queue, |entry| entry.deadline <= now) {
+ if is_running(entry.id) {
+ on_deadline_passed(entry.id, entry.test);
+ }
+ }
+
+ // Also clear out any leading entries that are no longer running, even
+ // if their deadline hasn't been reached.
+ while let Some(_) = pop_front_if(&mut self.queue, |entry| !is_running(entry.id)) {}
+
+ if let Some(front) = self.queue.front() {
+ assert!(now < front.deadline);
+ }
+ }
+}
+
+/// FIXME(vec_deque_pop_if): Use `VecDeque::pop_front_if` when it is stable in bootstrap.
+fn pop_front_if<T>(queue: &mut VecDeque<T>, predicate: impl FnOnce(&T) -> bool) -> Option<T> {
+ let first = queue.front()?;
+ if predicate(first) { queue.pop_front() } else { None }
+}
diff --git a/src/tools/compiletest/src/executor/json.rs b/src/tools/compiletest/src/executor/json.rs
new file mode 100644
index 0000000..c74ed81
--- /dev/null
+++ b/src/tools/compiletest/src/executor/json.rs
@@ -0,0 +1,111 @@
+//! Collects statistics and emits suite/test events as JSON messages, using
+//! the same JSON format as libtest's JSON formatter.
+//!
+//! These messages are then parsed by bootstrap, which replaces them with
+//! user-friendly terminal output.
+
+use std::time::Instant;
+
+use serde_json::json;
+
+use crate::executor::{CollectedTest, TestCompletion, TestOutcome};
+
+pub(crate) struct Listener {
+ suite_start: Option<Instant>,
+ passed: usize,
+ failed: usize,
+ ignored: usize,
+ filtered_out: usize,
+}
+
+impl Listener {
+ pub(crate) fn new() -> Self {
+ Self { suite_start: None, passed: 0, failed: 0, ignored: 0, filtered_out: 0 }
+ }
+
+ fn print_message(&self, message: &serde_json::Value) {
+ println!("{message}");
+ }
+
+ fn now(&self) -> Instant {
+ Instant::now()
+ }
+
+ pub(crate) fn suite_started(&mut self, test_count: usize, filtered_out: usize) {
+ self.suite_start = Some(self.now());
+ self.filtered_out = filtered_out;
+ let message = json!({ "type": "suite", "event": "started", "test_count": test_count });
+ self.print_message(&message);
+ }
+
+ pub(crate) fn test_started(&mut self, test: &CollectedTest) {
+ let name = test.desc.name.as_str();
+ let message = json!({ "type": "test", "event": "started", "name": name });
+ self.print_message(&message);
+ }
+
+ pub(crate) fn test_timed_out(&mut self, test: &CollectedTest) {
+ let name = test.desc.name.as_str();
+ let message = json!({ "type": "test", "event": "timeout", "name": name });
+ self.print_message(&message);
+ }
+
+ pub(crate) fn test_finished(&mut self, test: &CollectedTest, completion: &TestCompletion) {
+ let event;
+ let name = test.desc.name.as_str();
+ let mut maybe_message = None;
+ let maybe_stdout = completion.stdout.as_deref().map(String::from_utf8_lossy);
+
+ match completion.outcome {
+ TestOutcome::Succeeded => {
+ self.passed += 1;
+ event = "ok";
+ }
+ TestOutcome::Failed { message } => {
+ self.failed += 1;
+ maybe_message = message;
+ event = "failed";
+ }
+ TestOutcome::Ignored => {
+ self.ignored += 1;
+ maybe_message = test.desc.ignore_message.as_deref();
+ event = "ignored";
+ }
+ };
+
+ // This emits optional fields as `null`, instead of omitting them
+ // completely as libtest does, but bootstrap can parse the result
+ // either way.
+ let json = json!({
+ "type": "test",
+ "event": event,
+ "name": name,
+ "message": maybe_message,
+ "stdout": maybe_stdout,
+ });
+
+ self.print_message(&json);
+ }
+
+ pub(crate) fn suite_finished(&mut self) -> bool {
+ let exec_time = self.suite_start.map(|start| (self.now() - start).as_secs_f64());
+ let suite_passed = self.failed == 0;
+
+ let event = if suite_passed { "ok" } else { "failed" };
+ let message = json!({
+ "type": "suite",
+ "event": event,
+ "passed": self.passed,
+ "failed": self.failed,
+ "ignored": self.ignored,
+ // Compiletest doesn't run any benchmarks, but we still need to set this
+ // field to 0 so that bootstrap's JSON parser can read our message.
+ "measured": 0,
+ "filtered_out": self.filtered_out,
+ "exec_time": exec_time,
+ });
+
+ self.print_message(&message);
+ suite_passed
+ }
+}
diff --git a/src/tools/compiletest/src/executor/libtest.rs b/src/tools/compiletest/src/executor/libtest.rs
new file mode 100644
index 0000000..032b3f4
--- /dev/null
+++ b/src/tools/compiletest/src/executor/libtest.rs
@@ -0,0 +1,111 @@
+//! This submodule encapsulates all of the code that actually interacts with
+//! libtest, so that it can be easily removed after the new executor becomes
+//! the default.
+
+use std::borrow::Cow;
+use std::io;
+
+use crate::common::Config;
+use crate::executor::{CollectedTest, CollectedTestDesc, ColorConfig, OutputFormat, ShouldPanic};
+
+/// Delegates to libtest to run the list of collected tests.
+///
+/// Returns `Ok(true)` if all tests passed, or `Ok(false)` if one or more tests failed.
+pub(crate) fn execute_tests(config: &Config, tests: Vec<CollectedTest>) -> io::Result<bool> {
+ let opts = test_opts(config);
+ let tests = tests.into_iter().map(|t| t.into_libtest()).collect::<Vec<_>>();
+
+ test::run_tests_console(&opts, tests)
+}
+
+impl CollectedTest {
+ fn into_libtest(self) -> test::TestDescAndFn {
+ let Self { desc, config, testpaths, revision } = self;
+ let CollectedTestDesc { name, ignore, ignore_message, should_panic } = desc;
+
+ // Libtest requires the ignore message to be a &'static str, so we might
+ // have to leak memory to create it. This is fine, as we only do so once
+ // per test, so the leak won't grow indefinitely.
+ let ignore_message = ignore_message.map(|msg| match msg {
+ Cow::Borrowed(s) => s,
+ Cow::Owned(s) => &*String::leak(s),
+ });
+
+ let desc = test::TestDesc {
+ name: test::DynTestName(name),
+ ignore,
+ ignore_message,
+ source_file: "",
+ start_line: 0,
+ start_col: 0,
+ end_line: 0,
+ end_col: 0,
+ should_panic: should_panic.to_libtest(),
+ compile_fail: false,
+ no_run: false,
+ test_type: test::TestType::Unknown,
+ };
+
+ // This closure is invoked when libtest returns control to compiletest
+ // to execute the test.
+ let testfn = test::DynTestFn(Box::new(move || {
+ crate::runtest::run(config, &testpaths, revision.as_deref());
+ Ok(())
+ }));
+
+ test::TestDescAndFn { desc, testfn }
+ }
+}
+
+impl ColorConfig {
+ fn to_libtest(self) -> test::ColorConfig {
+ match self {
+ Self::AutoColor => test::ColorConfig::AutoColor,
+ Self::AlwaysColor => test::ColorConfig::AlwaysColor,
+ Self::NeverColor => test::ColorConfig::NeverColor,
+ }
+ }
+}
+
+impl OutputFormat {
+ fn to_libtest(self) -> test::OutputFormat {
+ match self {
+ Self::Pretty => test::OutputFormat::Pretty,
+ Self::Terse => test::OutputFormat::Terse,
+ Self::Json => test::OutputFormat::Json,
+ }
+ }
+}
+
+impl ShouldPanic {
+ fn to_libtest(self) -> test::ShouldPanic {
+ match self {
+ Self::No => test::ShouldPanic::No,
+ Self::Yes => test::ShouldPanic::Yes,
+ }
+ }
+}
+
+fn test_opts(config: &Config) -> test::TestOpts {
+ test::TestOpts {
+ exclude_should_panic: false,
+ filters: config.filters.clone(),
+ filter_exact: config.filter_exact,
+ run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No },
+ format: config.format.to_libtest(),
+ logfile: None,
+ run_tests: true,
+ bench_benchmarks: true,
+ nocapture: config.nocapture,
+ color: config.color.to_libtest(),
+ shuffle: false,
+ shuffle_seed: None,
+ test_threads: None,
+ skip: config.skip.clone(),
+ list: false,
+ options: test::Options::new(),
+ time_options: None,
+ force_run_in_process: false,
+ fail_fast: config.fail_fast,
+ }
+}
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 3406e87..2b203bb 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -1,11 +1,11 @@
-use std::collections::{HashMap, HashSet};
+use std::collections::HashSet;
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::io::prelude::*;
-use std::path::{Path, PathBuf};
use std::process::Command;
+use camino::{Utf8Path, Utf8PathBuf};
use semver::Version;
use tracing::*;
@@ -45,12 +45,12 @@ pub struct EarlyProps {
}
impl EarlyProps {
- pub fn from_file(config: &Config, testfile: &Path) -> Self {
- let file = File::open(testfile).expect("open test file to parse earlyprops");
+ pub fn from_file(config: &Config, testfile: &Utf8Path) -> Self {
+ let file = File::open(testfile.as_std_path()).expect("open test file to parse earlyprops");
Self::from_reader(config, testfile, file)
}
- pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self {
+ pub fn from_reader<R: Read>(config: &Config, testfile: &Utf8Path, rdr: R) -> Self {
let mut props = EarlyProps::default();
let mut poisoned = false;
iter_header(
@@ -66,7 +66,7 @@ pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self {
);
if poisoned {
- eprintln!("errors encountered during EarlyProps parsing: {}", testfile.display());
+ eprintln!("errors encountered during EarlyProps parsing: {}", testfile);
panic!("errors encountered during EarlyProps parsing");
}
@@ -88,7 +88,7 @@ pub struct TestProps {
pub doc_flags: Vec<String>,
// If present, the name of a file that this test should match when
// pretty-printed
- pub pp_exact: Option<PathBuf>,
+ pub pp_exact: Option<Utf8PathBuf>,
/// Auxiliary crates that should be built and made available to this test.
pub(crate) aux: AuxProps,
// Environment settings to use for compiling
@@ -134,7 +134,7 @@ pub struct TestProps {
// not set by end-users; rather it is set by the incremental
// testing harness and used when generating compilation
// arguments. (In particular, it propagates to the aux-builds.)
- pub incremental_dir: Option<PathBuf>,
+ pub incremental_dir: Option<Utf8PathBuf>,
// If `true`, this test will use incremental compilation.
//
// This can be set manually with the `incremental` header, or implicitly
@@ -198,7 +198,7 @@ pub struct TestProps {
/// that don't otherwise want/need `-Z build-std`.
pub add_core_stubs: bool,
/// Whether line annotatins are required for the given error kind.
- pub require_annotations: HashMap<ErrorKind, bool>,
+ pub dont_require_annotations: HashSet<ErrorKind>,
}
mod directives {
@@ -301,17 +301,16 @@ pub fn new() -> Self {
no_auto_check_cfg: false,
has_enzyme: false,
add_core_stubs: false,
- require_annotations: HashMap::from([
- (ErrorKind::Help, true),
- (ErrorKind::Note, true),
- (ErrorKind::Error, true),
- (ErrorKind::Warning, true),
- (ErrorKind::Suggestion, false),
- ]),
+ dont_require_annotations: Default::default(),
}
}
- pub fn from_aux_file(&self, testfile: &Path, revision: Option<&str>, config: &Config) -> Self {
+ pub fn from_aux_file(
+ &self,
+ testfile: &Utf8Path,
+ revision: Option<&str>,
+ config: &Config,
+ ) -> Self {
let mut props = TestProps::new();
// copy over select properties to the aux build:
@@ -322,10 +321,10 @@ pub fn from_aux_file(&self, testfile: &Path, revision: Option<&str>, config: &Co
props
}
- pub fn from_file(testfile: &Path, revision: Option<&str>, config: &Config) -> Self {
+ pub fn from_file(testfile: &Utf8Path, revision: Option<&str>, config: &Config) -> Self {
let mut props = TestProps::new();
props.load_from(testfile, revision, config);
- props.exec_env.push(("RUSTC".to_string(), config.rustc_path.display().to_string()));
+ props.exec_env.push(("RUSTC".to_string(), config.rustc_path.to_string()));
match (props.pass_mode, props.fail_mode) {
(None, None) if config.mode == Mode::Ui => props.fail_mode = Some(FailMode::Check),
@@ -340,10 +339,10 @@ pub fn from_file(testfile: &Path, revision: Option<&str>, config: &Config) -> Se
/// tied to a particular revision `foo` (indicated by writing
/// `//@[foo]`), then the property is ignored unless `test_revision` is
/// `Some("foo")`.
- fn load_from(&mut self, testfile: &Path, test_revision: Option<&str>, config: &Config) {
+ fn load_from(&mut self, testfile: &Utf8Path, test_revision: Option<&str>, config: &Config) {
let mut has_edition = false;
if !testfile.is_dir() {
- let file = File::open(testfile).unwrap();
+ let file = File::open(testfile.as_std_path()).unwrap();
let mut poisoned = false;
@@ -593,14 +592,14 @@ fn split_flags(flags: &str) -> Vec<String> {
if let Some(err_kind) =
config.parse_name_value_directive(ln, DONT_REQUIRE_ANNOTATIONS)
{
- self.require_annotations
- .insert(ErrorKind::expect_from_user_str(&err_kind), false);
+ self.dont_require_annotations
+ .insert(ErrorKind::expect_from_user_str(err_kind.trim()));
}
},
);
if poisoned {
- eprintln!("errors encountered during TestProps parsing: {}", testfile.display());
+ eprintln!("errors encountered during TestProps parsing: {}", testfile);
panic!("errors encountered during TestProps parsing");
}
}
@@ -871,7 +870,7 @@ fn iter_header(
mode: Mode,
_suite: &str,
poisoned: &mut bool,
- testfile: &Path,
+ testfile: &Utf8Path,
rdr: impl Read,
it: &mut dyn FnMut(DirectiveLine<'_>),
) {
@@ -923,9 +922,7 @@ fn iter_header(
eprintln!(
"error: detected unknown compiletest test directive `{}` in {}:{}",
- directive_line.raw_directive,
- testfile.display(),
- line_number,
+ directive_line.raw_directive, testfile, line_number,
);
return;
@@ -937,10 +934,7 @@ fn iter_header(
eprintln!(
"error: detected trailing compiletest test directive `{}` in {}:{}\n \
help: put the trailing directive in it's own line: `//@ {}`",
- trailing_directive,
- testfile.display(),
- line_number,
- trailing_directive,
+ trailing_directive, testfile, line_number, trailing_directive,
);
return;
@@ -952,7 +946,12 @@ fn iter_header(
}
impl Config {
- fn parse_and_update_revisions(&self, testfile: &Path, line: &str, existing: &mut Vec<String>) {
+ fn parse_and_update_revisions(
+ &self,
+ testfile: &Utf8Path,
+ line: &str,
+ existing: &mut Vec<String>,
+ ) {
const FORBIDDEN_REVISION_NAMES: [&str; 2] = [
// `//@ revisions: true false` Implying `--cfg=true` and `--cfg=false` makes it very
// weird for the test, since if the test writer wants a cfg of the same revision name
@@ -965,26 +964,19 @@ fn parse_and_update_revisions(&self, testfile: &Path, line: &str, existing: &mut
if let Some(raw) = self.parse_name_value_directive(line, "revisions") {
if self.mode == Mode::RunMake {
- panic!("`run-make` tests do not support revisions: {}", testfile.display());
+ panic!("`run-make` tests do not support revisions: {}", testfile);
}
let mut duplicates: HashSet<_> = existing.iter().cloned().collect();
for revision in raw.split_whitespace() {
if !duplicates.insert(revision.to_string()) {
- panic!(
- "duplicate revision: `{}` in line `{}`: {}",
- revision,
- raw,
- testfile.display()
- );
+ panic!("duplicate revision: `{}` in line `{}`: {}", revision, raw, testfile);
}
if FORBIDDEN_REVISION_NAMES.contains(&revision) {
panic!(
"revision name `{revision}` is not permitted: `{}` in line `{}`: {}",
- revision,
- raw,
- testfile.display()
+ revision, raw, testfile
);
}
@@ -995,8 +987,7 @@ fn parse_and_update_revisions(&self, testfile: &Path, line: &str, existing: &mut
"revision name `{revision}` is not permitted in a test suite that uses \
`FileCheck` annotations as it is confusing when used as custom `FileCheck` \
prefix: `{revision}` in line `{}`: {}",
- raw,
- testfile.display()
+ raw, testfile
);
}
@@ -1016,11 +1007,11 @@ fn parse_env(nv: String) -> (String, String) {
(name.to_owned(), value.to_owned())
}
- fn parse_pp_exact(&self, line: &str, testfile: &Path) -> Option<PathBuf> {
+ fn parse_pp_exact(&self, line: &str, testfile: &Utf8Path) -> Option<Utf8PathBuf> {
if let Some(s) = self.parse_name_value_directive(line, "pp-exact") {
- Some(PathBuf::from(&s))
+ Some(Utf8PathBuf::from(&s))
} else if self.parse_name_directive(line, "pp-exact") {
- testfile.file_name().map(PathBuf::from)
+ testfile.file_name().map(Utf8PathBuf::from)
} else {
None
}
@@ -1126,20 +1117,19 @@ fn expand_variables(mut value: String, config: &Config) -> String {
if value.contains(CWD) {
let cwd = env::current_dir().unwrap();
- value = value.replace(CWD, &cwd.to_string_lossy());
+ value = value.replace(CWD, &cwd.to_str().unwrap());
}
if value.contains(SRC_BASE) {
- value = value.replace(SRC_BASE, &config.src_test_suite_root.to_str().unwrap());
+ value = value.replace(SRC_BASE, &config.src_test_suite_root.as_str());
}
if value.contains(TEST_SUITE_BUILD_BASE) {
- value =
- value.replace(TEST_SUITE_BUILD_BASE, &config.build_test_suite_root.to_str().unwrap());
+ value = value.replace(TEST_SUITE_BUILD_BASE, &config.build_test_suite_root.as_str());
}
if value.contains(SYSROOT_BASE) {
- value = value.replace(SYSROOT_BASE, &config.sysroot_base.to_str().unwrap());
+ value = value.replace(SYSROOT_BASE, &config.sysroot_base.as_str());
}
if value.contains(TARGET_LINKER) {
@@ -1152,9 +1142,9 @@ fn expand_variables(mut value: String, config: &Config) -> String {
if value.contains(RUST_SRC_BASE) {
let src_base = config.sysroot_base.join("lib/rustlib/src/rust");
- src_base.try_exists().expect(&*format!("{} should exists", src_base.display()));
- let src_base = src_base.read_link().unwrap_or(src_base);
- value = value.replace(RUST_SRC_BASE, &src_base.to_string_lossy());
+ src_base.try_exists().expect(&*format!("{} should exists", src_base));
+ let src_base = src_base.read_link_utf8().unwrap_or(src_base);
+ value = value.replace(RUST_SRC_BASE, &src_base.as_str());
}
value
@@ -1257,14 +1247,14 @@ pub fn llvm_has_libzstd(config: &Config) -> bool {
// contains a path to that static lib, and that it exists.
//
// See compiler/rustc_llvm/build.rs for more details and similar expectations.
- fn is_zstd_in_config(llvm_bin_dir: &Path) -> Option<()> {
+ fn is_zstd_in_config(llvm_bin_dir: &Utf8Path) -> Option<()> {
let llvm_config_path = llvm_bin_dir.join("llvm-config");
let output = Command::new(llvm_config_path).arg("--system-libs").output().ok()?;
assert!(output.status.success(), "running llvm-config --system-libs failed");
let libs = String::from_utf8(output.stdout).ok()?;
for lib in libs.split_whitespace() {
- if lib.ends_with("libzstd.a") && Path::new(lib).exists() {
+ if lib.ends_with("libzstd.a") && Utf8Path::new(lib).exists() {
return Some(());
}
}
@@ -1282,7 +1272,7 @@ fn is_zstd_in_config(llvm_bin_dir: &Path) -> Option<()> {
// `lld` supports it. If not, an error will be emitted: "LLVM was not built with
// LLVM_ENABLE_ZSTD or did not find zstd at build time".
#[cfg(unix)]
- fn is_lld_built_with_zstd(llvm_bin_dir: &Path) -> Option<()> {
+ fn is_lld_built_with_zstd(llvm_bin_dir: &Utf8Path) -> Option<()> {
let lld_path = llvm_bin_dir.join("lld");
if lld_path.exists() {
// We can't call `lld` as-is, it expects to be invoked by a compiler driver using a
@@ -1318,7 +1308,7 @@ fn is_lld_built_with_zstd(llvm_bin_dir: &Path) -> Option<()> {
}
#[cfg(not(unix))]
- fn is_lld_built_with_zstd(_llvm_bin_dir: &Path) -> Option<()> {
+ fn is_lld_built_with_zstd(_llvm_bin_dir: &Utf8Path) -> Option<()> {
None
}
@@ -1385,7 +1375,7 @@ pub(crate) fn make_test_description<R: Read>(
config: &Config,
cache: &HeadersCache,
name: String,
- path: &Path,
+ path: &Utf8Path,
src: R,
test_revision: Option<&str>,
poisoned: &mut bool,
@@ -1416,7 +1406,7 @@ macro_rules! decision {
ignore_message = Some(reason.into());
}
IgnoreDecision::Error { message } => {
- eprintln!("error: {}:{line_number}: {message}", path.display());
+ eprintln!("error: {}:{line_number}: {message}", path);
*poisoned = true;
return;
}
@@ -1446,7 +1436,7 @@ macro_rules! decision {
);
if local_poisoned {
- eprintln!("errors encountered when trying to make test description: {}", path.display());
+ eprintln!("errors encountered when trying to make test description: {}", path);
panic!("errors encountered when trying to make test description");
}
@@ -1555,7 +1545,7 @@ fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision {
IgnoreDecision::Continue
}
-fn ignore_llvm(config: &Config, path: &Path, line: &str) -> IgnoreDecision {
+fn ignore_llvm(config: &Config, path: &Utf8Path, line: &str) -> IgnoreDecision {
if let Some(needed_components) =
config.parse_name_value_directive(line, "needs-llvm-components")
{
@@ -1567,8 +1557,7 @@ fn ignore_llvm(config: &Config, path: &Path, line: &str) -> IgnoreDecision {
if env::var_os("COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS").is_some() {
panic!(
"missing LLVM component {}, and COMPILETEST_REQUIRE_ALL_LLVM_COMPONENTS is set: {}",
- missing_component,
- path.display()
+ missing_component, path
);
}
return IgnoreDecision::Ignore {
diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs
index c369fff..f1f1384 100644
--- a/src/tools/compiletest/src/header/cfg.rs
+++ b/src/tools/compiletest/src/header/cfg.rs
@@ -101,6 +101,10 @@ macro_rules! condition {
message: "always"
}
condition! {
+ name: "auxiliary",
+ message: "used by another main test file"
+ }
+ condition! {
name: &config.target,
allowed_names: &target_cfgs.all_targets,
message: "when the target is {name}"
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index f3461f3..2525e0a 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -1,6 +1,6 @@
use std::io::Read;
-use std::path::Path;
+use camino::Utf8Path;
use semver::Version;
use super::{
@@ -13,7 +13,7 @@
fn make_test_description<R: Read>(
config: &Config,
name: String,
- path: &Path,
+ path: &Utf8Path,
src: R,
revision: Option<&str>,
) -> CollectedTestDesc {
@@ -230,12 +230,12 @@ fn cfg() -> ConfigBuilder {
fn parse_rs(config: &Config, contents: &str) -> EarlyProps {
let bytes = contents.as_bytes();
- EarlyProps::from_reader(config, Path::new("a.rs"), bytes)
+ EarlyProps::from_reader(config, Utf8Path::new("a.rs"), bytes)
}
fn check_ignore(config: &Config, contents: &str) -> bool {
let tn = String::new();
- let p = Path::new("a.rs");
+ let p = Utf8Path::new("a.rs");
let d = make_test_description(&config, tn, p, std::io::Cursor::new(contents), None);
d.ignore
}
@@ -244,7 +244,7 @@ fn check_ignore(config: &Config, contents: &str) -> bool {
fn should_fail() {
let config: Config = cfg().build();
let tn = String::new();
- let p = Path::new("a.rs");
+ let p = Utf8Path::new("a.rs");
let d = make_test_description(&config, tn.clone(), p, std::io::Cursor::new(""), None);
assert_eq!(d.should_panic, ShouldPanic::No);
@@ -784,7 +784,7 @@ fn threads_support() {
}
}
-fn run_path(poisoned: &mut bool, path: &Path, buf: &[u8]) {
+fn run_path(poisoned: &mut bool, path: &Utf8Path, buf: &[u8]) {
let rdr = std::io::Cursor::new(&buf);
iter_header(Mode::Ui, "ui", poisoned, path, rdr, &mut |_| {});
}
@@ -794,7 +794,7 @@ fn test_unknown_directive_check() {
let mut poisoned = false;
run_path(
&mut poisoned,
- Path::new("a.rs"),
+ Utf8Path::new("a.rs"),
include_bytes!("./test-auxillary/unknown_directive.rs"),
);
assert!(poisoned);
@@ -805,7 +805,7 @@ fn test_known_directive_check_no_error() {
let mut poisoned = false;
run_path(
&mut poisoned,
- Path::new("a.rs"),
+ Utf8Path::new("a.rs"),
include_bytes!("./test-auxillary/known_directive.rs"),
);
assert!(!poisoned);
@@ -816,7 +816,7 @@ fn test_error_annotation_no_error() {
let mut poisoned = false;
run_path(
&mut poisoned,
- Path::new("a.rs"),
+ Utf8Path::new("a.rs"),
include_bytes!("./test-auxillary/error_annotation.rs"),
);
assert!(!poisoned);
@@ -827,7 +827,7 @@ fn test_non_rs_unknown_directive_not_checked() {
let mut poisoned = false;
run_path(
&mut poisoned,
- Path::new("a.Makefile"),
+ Utf8Path::new("a.Makefile"),
include_bytes!("./test-auxillary/not_rs.Makefile"),
);
assert!(!poisoned);
@@ -836,21 +836,21 @@ fn test_non_rs_unknown_directive_not_checked() {
#[test]
fn test_trailing_directive() {
let mut poisoned = false;
- run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86 only-arm");
+ run_path(&mut poisoned, Utf8Path::new("a.rs"), b"//@ only-x86 only-arm");
assert!(poisoned);
}
#[test]
fn test_trailing_directive_with_comment() {
let mut poisoned = false;
- run_path(&mut poisoned, Path::new("a.rs"), b"//@ only-x86 only-arm with comment");
+ run_path(&mut poisoned, Utf8Path::new("a.rs"), b"//@ only-x86 only-arm with comment");
assert!(poisoned);
}
#[test]
fn test_not_trailing_directive() {
let mut poisoned = false;
- run_path(&mut poisoned, Path::new("a.rs"), b"//@ revisions: incremental");
+ run_path(&mut poisoned, Utf8Path::new("a.rs"), b"//@ revisions: incremental");
assert!(!poisoned);
}
@@ -940,3 +940,9 @@ fn test_supported_crate_types() {
"//@ needs-crate-type: bin, cdylib, dylib, lib, proc-macro, rlib, staticlib"
));
}
+
+#[test]
+fn test_ignore_auxiliary() {
+ let config = cfg().build();
+ assert!(check_ignore(&config, "//@ ignore-auxiliary"));
+}
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 720663b..7948a27 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -1,7 +1,8 @@
#![crate_name = "compiletest"]
-// The `test` crate is the only unstable feature
-// allowed here, just to share similar code.
+// Needed by the libtest-based test executor.
#![feature(test)]
+// Needed by the "new" test executor that does not depend on libtest.
+#![feature(internal_output_capture)]
extern crate test;
@@ -22,16 +23,15 @@
use core::panic;
use std::collections::HashSet;
-use std::ffi::OsString;
use std::fmt::Write;
use std::io::{self, ErrorKind};
-use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
use std::sync::{Arc, OnceLock};
use std::time::SystemTime;
use std::{env, fs, vec};
use build_helper::git::{get_git_modified_files, get_git_untracked_files};
+use camino::{Utf8Path, Utf8PathBuf};
use getopts::Options;
use tracing::*;
use walkdir::WalkDir;
@@ -203,6 +203,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
"COMMAND",
)
.reqopt("", "minicore-path", "path to minicore aux library", "PATH")
+ .optflag("N", "no-new-executor", "disables the new test executor, and uses libtest instead")
.optopt(
"",
"debugger",
@@ -230,15 +231,19 @@ pub fn parse_config(args: Vec<String>) -> Config {
panic!()
}
- fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf {
- match m.opt_str(nm) {
- Some(s) => PathBuf::from(&s),
- None => panic!("no option (=path) found for {}", nm),
+ fn make_absolute(path: Utf8PathBuf) -> Utf8PathBuf {
+ if path.is_relative() {
+ Utf8PathBuf::try_from(env::current_dir().unwrap()).unwrap().join(path)
+ } else {
+ path
}
}
- fn make_absolute(path: PathBuf) -> PathBuf {
- if path.is_relative() { env::current_dir().unwrap().join(path) } else { path }
+ fn opt_path(m: &getopts::Matches, nm: &str) -> Utf8PathBuf {
+ match m.opt_str(nm) {
+ Some(s) => Utf8PathBuf::from(&s),
+ None => panic!("no option (=path) found for {}", nm),
+ }
}
let target = opt_str2(matches.opt_str("target"));
@@ -279,12 +284,12 @@ fn make_absolute(path: PathBuf) -> PathBuf {
.free
.iter()
.map(|f| {
- let path = Path::new(f);
+ let path = Utf8Path::new(f);
let mut iter = path.iter().skip(1);
// We skip the test folder and check if the user passed `rmake.rs`.
if iter.next().is_some_and(|s| s == "rmake.rs") && iter.next().is_none() {
- path.parent().unwrap().to_str().unwrap().to_string()
+ path.parent().unwrap().to_string()
} else {
f.to_string()
}
@@ -316,8 +321,8 @@ fn make_absolute(path: PathBuf) -> PathBuf {
assert!(
src_test_suite_root.starts_with(&src_root),
"`src-root` must be a parent of `src-test-suite-root`: `src-root`=`{}`, `src-test-suite-root` = `{}`",
- src_root.display(),
- src_test_suite_root.display()
+ src_root,
+ src_test_suite_root
);
let build_root = opt_path(matches, "build-root");
@@ -332,16 +337,16 @@ fn make_absolute(path: PathBuf) -> PathBuf {
compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")),
run_lib_path: make_absolute(opt_path(matches, "run-lib-path")),
rustc_path: opt_path(matches, "rustc-path"),
- cargo_path: matches.opt_str("cargo-path").map(PathBuf::from),
- stage0_rustc_path: matches.opt_str("stage0-rustc-path").map(PathBuf::from),
- rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from),
- coverage_dump_path: matches.opt_str("coverage-dump-path").map(PathBuf::from),
+ cargo_path: matches.opt_str("cargo-path").map(Utf8PathBuf::from),
+ stage0_rustc_path: matches.opt_str("stage0-rustc-path").map(Utf8PathBuf::from),
+ rustdoc_path: matches.opt_str("rustdoc-path").map(Utf8PathBuf::from),
+ coverage_dump_path: matches.opt_str("coverage-dump-path").map(Utf8PathBuf::from),
python: matches.opt_str("python").unwrap(),
jsondocck_path: matches.opt_str("jsondocck-path"),
jsondoclint_path: matches.opt_str("jsondoclint-path"),
run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"),
- llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from),
- llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from),
+ llvm_filecheck: matches.opt_str("llvm-filecheck").map(Utf8PathBuf::from),
+ llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(Utf8PathBuf::from),
src_root,
src_test_suite_root,
@@ -407,7 +412,7 @@ fn make_absolute(path: PathBuf) -> PathBuf {
},
only_modified: matches.opt_present("only-modified"),
color,
- remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from),
+ remote_test_client: matches.opt_str("remote-test-client").map(Utf8PathBuf::from),
compare_mode,
rustfix_coverage: matches.opt_present("rustfix-coverage"),
has_html_tidy,
@@ -444,25 +449,27 @@ fn make_absolute(path: PathBuf) -> PathBuf {
diff_command: matches.opt_str("compiletest-diff-tool"),
minicore_path: opt_path(matches, "minicore-path"),
+
+ no_new_executor: matches.opt_present("no-new-executor"),
}
}
pub fn log_config(config: &Config) {
let c = config;
logv(c, "configuration:".to_string());
- logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path));
- logv(c, format!("run_lib_path: {:?}", config.run_lib_path));
- logv(c, format!("rustc_path: {:?}", config.rustc_path.display()));
+ logv(c, format!("compile_lib_path: {}", config.compile_lib_path));
+ logv(c, format!("run_lib_path: {}", config.run_lib_path));
+ logv(c, format!("rustc_path: {}", config.rustc_path));
logv(c, format!("cargo_path: {:?}", config.cargo_path));
logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path));
- logv(c, format!("src_root: {}", config.src_root.display()));
- logv(c, format!("src_test_suite_root: {}", config.src_test_suite_root.display()));
+ logv(c, format!("src_root: {}", config.src_root));
+ logv(c, format!("src_test_suite_root: {}", config.src_test_suite_root));
- logv(c, format!("build_root: {}", config.build_root.display()));
- logv(c, format!("build_test_suite_root: {}", config.build_test_suite_root.display()));
+ logv(c, format!("build_root: {}", config.build_root));
+ logv(c, format!("build_test_suite_root: {}", config.build_test_suite_root));
- logv(c, format!("sysroot_base: {}", config.sysroot_base.display()));
+ logv(c, format!("sysroot_base: {}", config.sysroot_base));
logv(c, format!("stage: {}", config.stage));
logv(c, format!("stage_id: {}", config.stage_id));
@@ -480,16 +487,16 @@ pub fn log_config(config: &Config) {
logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags));
logv(c, format!("target: {}", config.target));
logv(c, format!("host: {}", config.host));
- logv(c, format!("android-cross-path: {:?}", config.android_cross_path.display()));
- logv(c, format!("adb_path: {:?}", config.adb_path));
- logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir));
+ logv(c, format!("android-cross-path: {}", config.android_cross_path));
+ logv(c, format!("adb_path: {}", config.adb_path));
+ logv(c, format!("adb_test_dir: {}", config.adb_test_dir));
logv(c, format!("adb_device_status: {}", config.adb_device_status));
logv(c, format!("ar: {}", config.ar));
logv(c, format!("target-linker: {:?}", config.target_linker));
logv(c, format!("host-linker: {:?}", config.host_linker));
logv(c, format!("verbose: {}", config.verbose));
logv(c, format!("format: {:?}", config.format));
- logv(c, format!("minicore_path: {:?}", config.minicore_path.display()));
+ logv(c, format!("minicore_path: {}", config.minicore_path));
logv(c, "\n".to_string());
}
@@ -517,7 +524,7 @@ pub fn run_tests(config: Arc<Config>) {
coverage_file_path.push("rustfix_missing_coverage.txt");
if coverage_file_path.exists() {
if let Err(e) = fs::remove_file(&coverage_file_path) {
- panic!("Could not delete {} due to {}", coverage_file_path.display(), e)
+ panic!("Could not delete {} due to {}", coverage_file_path, e)
}
}
}
@@ -567,10 +574,15 @@ pub fn run_tests(config: Arc<Config>) {
tests.sort_by(|a, b| Ord::cmp(&a.desc.name, &b.desc.name));
- // Delegate to libtest to filter and run the big list of structures created
- // during test discovery. When libtest decides to run a test, it will
- // return control to compiletest by invoking a closure.
- let res = crate::executor::execute_tests(&config, tests);
+ // Delegate to the executor to filter and run the big list of test structures
+ // created during test discovery. When the executor decides to run a test,
+ // it will return control to the rest of compiletest by calling `runtest::run`.
+ let res = if !config.no_new_executor {
+ Ok(executor::run_tests(&config, tests))
+ } else {
+ // FIXME(Zalathar): Eventually remove the libtest executor entirely.
+ crate::executor::libtest::execute_tests(&config, tests)
+ };
// Check the outcome reported by libtest.
match res {
@@ -619,13 +631,13 @@ struct TestCollectorCx {
config: Arc<Config>,
cache: HeadersCache,
common_inputs_stamp: Stamp,
- modified_tests: Vec<PathBuf>,
+ modified_tests: Vec<Utf8PathBuf>,
}
/// Mutable state used during test collection.
struct TestCollector {
tests: Vec<CollectedTest>,
- found_path_stems: HashSet<PathBuf>,
+ found_path_stems: HashSet<Utf8PathBuf>,
poisoned: bool,
}
@@ -635,14 +647,13 @@ struct TestCollector {
/// regardless of whether any filters/tests were specified on the command-line,
/// because filtering is handled later by libtest.
pub(crate) fn collect_and_make_tests(config: Arc<Config>) -> Vec<CollectedTest> {
- debug!("making tests from {}", config.src_test_suite_root.display());
+ debug!("making tests from {}", config.src_test_suite_root);
let common_inputs_stamp = common_inputs_stamp(&config);
let modified_tests =
modified_tests(&config, &config.src_test_suite_root).unwrap_or_else(|err| {
panic!(
"modified_tests got error from dir: {}, error: {}",
- config.src_test_suite_root.display(),
- err
+ config.src_test_suite_root, err
)
});
let cache = HeadersCache::load(&config);
@@ -651,12 +662,9 @@ pub(crate) fn collect_and_make_tests(config: Arc<Config>) -> Vec<CollectedTest>
let mut collector =
TestCollector { tests: vec![], found_path_stems: HashSet::new(), poisoned: false };
- collect_tests_from_dir(&cx, &mut collector, &cx.config.src_test_suite_root, Path::new(""))
+ collect_tests_from_dir(&cx, &mut collector, &cx.config.src_test_suite_root, Utf8Path::new(""))
.unwrap_or_else(|reason| {
- panic!(
- "Could not read tests from {}: {reason}",
- cx.config.src_test_suite_root.display()
- )
+ panic!("Could not read tests from {}: {reason}", cx.config.src_test_suite_root)
});
let TestCollector { tests, found_path_stems, poisoned } = collector;
@@ -725,24 +733,29 @@ fn common_inputs_stamp(config: &Config) -> Stamp {
/// the `--only-modified` flag is in use.
///
/// (Might be inaccurate in some cases.)
-fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> {
+fn modified_tests(config: &Config, dir: &Utf8Path) -> Result<Vec<Utf8PathBuf>, String> {
// If `--only-modified` wasn't passed, the list of modified tests won't be
// used for anything, so avoid some work and just return an empty list.
if !config.only_modified {
return Ok(vec![]);
}
- let files =
- get_git_modified_files(&config.git_config(), Some(dir), &vec!["rs", "stderr", "fixed"])?;
+ let files = get_git_modified_files(
+ &config.git_config(),
+ Some(dir.as_std_path()),
+ &vec!["rs", "stderr", "fixed"],
+ )?;
// Add new test cases to the list, it will be convenient in daily development.
- let untracked_files = get_git_untracked_files(&config.git_config(), None)?.unwrap_or(vec![]);
+ let untracked_files = get_git_untracked_files(Some(dir.as_std_path()))?.unwrap_or(vec![]);
let all_paths = [&files[..], &untracked_files[..]].concat();
let full_paths = {
- let mut full_paths: Vec<PathBuf> = all_paths
+ let mut full_paths: Vec<Utf8PathBuf> = all_paths
.into_iter()
- .map(|f| PathBuf::from(f).with_extension("").with_extension("rs"))
- .filter_map(|f| if Path::new(&f).exists() { f.canonicalize().ok() } else { None })
+ .map(|f| Utf8PathBuf::from(f).with_extension("").with_extension("rs"))
+ .filter_map(
+ |f| if Utf8Path::new(&f).exists() { f.canonicalize_utf8().ok() } else { None },
+ )
.collect();
full_paths.dedup();
full_paths.sort_unstable();
@@ -756,8 +769,8 @@ fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> {
fn collect_tests_from_dir(
cx: &TestCollectorCx,
collector: &mut TestCollector,
- dir: &Path,
- relative_dir_path: &Path,
+ dir: &Utf8Path,
+ relative_dir_path: &Utf8Path,
) -> io::Result<()> {
// Ignore directories that contain a file named `compiletest-ignore-dir`.
if dir.join("compiletest-ignore-dir").exists() {
@@ -790,16 +803,16 @@ fn collect_tests_from_dir(
// subdirectories we find, except for `auxiliary` directories.
// FIXME: this walks full tests tree, even if we have something to ignore
// use walkdir/ignore like in tidy?
- for file in fs::read_dir(dir)? {
+ for file in fs::read_dir(dir.as_std_path())? {
let file = file?;
- let file_path = file.path();
- let file_name = file.file_name();
+ let file_path = Utf8PathBuf::try_from(file.path()).unwrap();
+ let file_name = file_path.file_name().unwrap();
- if is_test(&file_name)
+ if is_test(file_name)
&& (!cx.config.only_modified || cx.modified_tests.contains(&file_path))
{
// We found a test file, so create the corresponding libtest structures.
- debug!("found test file: {:?}", file_path.display());
+ debug!(%file_path, "found test file");
// Record the stem of the test file, to check for overlaps later.
let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap());
@@ -810,22 +823,20 @@ fn collect_tests_from_dir(
make_test(cx, collector, &paths);
} else if file_path.is_dir() {
// Recurse to find more tests in a subdirectory.
- let relative_file_path = relative_dir_path.join(file.file_name());
- if &file_name != "auxiliary" {
- debug!("found directory: {:?}", file_path.display());
+ let relative_file_path = relative_dir_path.join(file_name);
+ if file_name != "auxiliary" {
+ debug!(%file_path, "found directory");
collect_tests_from_dir(cx, collector, &file_path, &relative_file_path)?;
}
} else {
- debug!("found other file/directory: {:?}", file_path.display());
+ debug!(%file_path, "found other file/directory");
}
}
Ok(())
}
/// Returns true if `file_name` looks like a proper test file name.
-pub fn is_test(file_name: &OsString) -> bool {
- let file_name = file_name.to_str().unwrap();
-
+pub fn is_test(file_name: &str) -> bool {
if !file_name.ends_with(".rs") {
return false;
}
@@ -844,7 +855,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
let test_path = if cx.config.mode == Mode::RunMake {
testpaths.file.join("rmake.rs")
} else {
- PathBuf::from(&testpaths.file)
+ testpaths.file.clone()
};
// Scan the test file to discover its revisions, if any.
@@ -899,7 +910,7 @@ fn make_test(cx: &TestCollectorCx, collector: &mut TestCollector, testpaths: &Te
/// The path of the `stamp` file that gets created or updated whenever a
/// particular test completes successfully.
-fn stamp_file_path(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
+fn stamp_file_path(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> Utf8PathBuf {
output_base_dir(config, testpaths, revision).join("stamp")
}
@@ -912,7 +923,7 @@ fn files_related_to_test(
testpaths: &TestPaths,
props: &EarlyProps,
revision: Option<&str>,
-) -> Vec<PathBuf> {
+) -> Vec<Utf8PathBuf> {
let mut related = vec![];
if testpaths.file.is_dir() {
@@ -920,7 +931,7 @@ fn files_related_to_test(
for entry in WalkDir::new(&testpaths.file) {
let path = entry.unwrap().into_path();
if path.is_file() {
- related.push(path);
+ related.push(Utf8PathBuf::try_from(path).unwrap());
}
}
} else {
@@ -991,7 +1002,7 @@ struct Stamp {
impl Stamp {
/// Creates a timestamp holding the last-modified time of the specified file.
- fn from_path(path: &Path) -> Self {
+ fn from_path(path: &Utf8Path) -> Self {
let mut stamp = Stamp { time: SystemTime::UNIX_EPOCH };
stamp.add_path(path);
stamp
@@ -999,8 +1010,8 @@ fn from_path(path: &Path) -> Self {
/// Updates this timestamp to the last-modified time of the specified file,
/// if it is later than the currently-stored timestamp.
- fn add_path(&mut self, path: &Path) {
- let modified = fs::metadata(path)
+ fn add_path(&mut self, path: &Utf8Path) {
+ let modified = fs::metadata(path.as_std_path())
.and_then(|metadata| metadata.modified())
.unwrap_or(SystemTime::UNIX_EPOCH);
self.time = self.time.max(modified);
@@ -1009,7 +1020,8 @@ fn add_path(&mut self, path: &Path) {
/// Updates this timestamp to the most recent last-modified time of all files
/// recursively contained in the given directory, if it is later than the
/// currently-stored timestamp.
- fn add_dir(&mut self, path: &Path) {
+ fn add_dir(&mut self, path: &Utf8Path) {
+ let path = path.as_std_path();
for entry in WalkDir::new(path) {
let entry = entry.unwrap();
if entry.file_type().is_file() {
@@ -1042,7 +1054,7 @@ fn make_test_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>
config.mode,
debugger,
mode_suffix,
- path.display(),
+ path,
revision.map_or("".to_string(), |rev| format!("#{}", rev))
)
}
@@ -1064,7 +1076,7 @@ fn make_test_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>
/// To avoid problems, we forbid test names from overlapping in this way.
///
/// See <https://github.com/rust-lang/rust/pull/109509> for more context.
-fn check_for_overlapping_test_paths(found_path_stems: &HashSet<PathBuf>) {
+fn check_for_overlapping_test_paths(found_path_stems: &HashSet<Utf8PathBuf>) {
let mut collisions = Vec::new();
for path in found_path_stems {
for ancestor in path.ancestors().skip(1) {
@@ -1077,7 +1089,7 @@ fn check_for_overlapping_test_paths(found_path_stems: &HashSet<PathBuf>) {
collisions.sort();
let collisions: String = collisions
.into_iter()
- .map(|(path, check_parent)| format!("test {path:?} clashes with {check_parent:?}\n"))
+ .map(|(path, check_parent)| format!("test {path} clashes with {check_parent}\n"))
.collect();
panic!(
"{collisions}\n\
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 208d328..cc09463 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -1,15 +1,16 @@
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
-use std::ffi::{OsStr, OsString};
+use std::ffi::OsString;
use std::fs::{self, File, create_dir_all};
use std::hash::{DefaultHasher, Hash, Hasher};
use std::io::prelude::*;
use std::io::{self, BufReader};
-use std::path::{Path, PathBuf};
use std::process::{Child, Command, ExitStatus, Output, Stdio};
use std::sync::Arc;
use std::{env, iter, str};
+use build_helper::fs::remove_and_create_dir_all;
+use camino::{Utf8Path, Utf8PathBuf};
use colored::Colorize;
use regex::{Captures, Regex};
use tracing::*;
@@ -22,10 +23,10 @@
output_base_dir, output_base_name, output_testname_unique,
};
use crate::compute_diff::{DiffLine, make_diff, write_diff, write_filtered_diff};
-use crate::errors::{self, Error, ErrorKind};
+use crate::errors::{Error, ErrorKind};
use crate::header::TestProps;
use crate::read2::{Truncated, read2_abbreviated};
-use crate::util::{PathBufExt, add_dylib_path, logv, static_regex};
+use crate::util::{Utf8PathBufExt, add_dylib_path, logv, static_regex};
use crate::{ColorConfig, json, stamp_file_path};
mod debugger;
@@ -131,7 +132,7 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) {
// We're going to be dumping a lot of info. Start on a new line.
print!("\n\n");
}
- debug!("running {:?}", testpaths.file.display());
+ debug!("running {}", testpaths.file);
let mut props = TestProps::from_file(&testpaths.file, revision, &config);
// For non-incremental (i.e. regular UI) tests, the incremental directory
@@ -144,7 +145,7 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) {
let cx = TestCx { config: &config, props: &props, testpaths, revision };
if let Err(e) = create_dir_all(&cx.output_base_dir()) {
- panic!("failed to create output base directory {}: {e}", cx.output_base_dir().display());
+ panic!("failed to create output base directory {}: {e}", cx.output_base_dir());
}
if props.incremental {
@@ -207,11 +208,6 @@ pub fn compute_stamp_hash(config: &Config) -> String {
format!("{:x}", hash.finish())
}
-fn remove_and_create_dir_all(path: &Path) {
- let _ = fs::remove_dir_all(path);
- fs::create_dir_all(path).unwrap();
-}
-
#[derive(Copy, Clone, Debug)]
struct TestCx<'test> {
config: &'test Config,
@@ -423,7 +419,7 @@ fn print_source(&self, read_from: ReadFrom, pretty_type: &str) -> ProcRes {
let aux_dir = self.aux_output_dir_name();
let input: &str = match read_from {
ReadFrom::Stdin(_) => "-",
- ReadFrom::Path => self.testpaths.file.to_str().unwrap(),
+ ReadFrom::Path => self.testpaths.file.as_str(),
};
let mut rustc = Command::new(&self.config.rustc_path);
@@ -522,7 +518,9 @@ fn typecheck_source(&self, src: String) -> ProcRes {
let mut rustc = Command::new(&self.config.rustc_path);
let out_dir = self.output_base_name().with_extension("pretty-out");
- remove_and_create_dir_all(&out_dir);
+ remove_and_create_dir_all(&out_dir).unwrap_or_else(|e| {
+ panic!("failed to remove and recreate output directory `{out_dir}`: {e}")
+ });
let target = if self.props.force_host { &*self.config.host } else { &*self.config.target };
@@ -590,10 +588,7 @@ fn check_all_error_patterns(
// FIXME(#65865)
return;
} else {
- self.fatal(&format!(
- "no error pattern specified in {:?}",
- self.testpaths.file.display()
- ));
+ self.fatal(&format!("no error pattern specified in {}", self.testpaths.file));
}
}
@@ -675,7 +670,7 @@ fn check_forbid_output(&self, output_to_check: &str, proc_res: &ProcRes) {
}
}
- fn check_expected_errors(&self, expected_errors: Vec<errors::Error>, proc_res: &ProcRes) {
+ fn check_expected_errors(&self, expected_errors: Vec<Error>, proc_res: &ProcRes) {
debug!(
"check_expected_errors: expected_errors={:?} proc_res.status={:?}",
expected_errors, proc_res.status
@@ -697,21 +692,25 @@ fn check_expected_errors(&self, expected_errors: Vec<errors::Error>, proc_res: &
}
// On Windows, translate all '\' path separators to '/'
- let file_name = format!("{}", self.testpaths.file.display()).replace(r"\", "/");
+ let file_name = self.testpaths.file.to_string().replace(r"\", "/");
// On Windows, keep all '\' path separators to match the paths reported in the JSON output
// from the compiler
let diagnostic_file_name = if self.props.remap_src_base {
- let mut p = PathBuf::from(FAKE_SRC_BASE);
+ let mut p = Utf8PathBuf::from(FAKE_SRC_BASE);
p.push(&self.testpaths.relative_dir);
p.push(self.testpaths.file.file_name().unwrap());
- p.display().to_string()
+ p.to_string()
} else {
- self.testpaths.file.display().to_string()
+ self.testpaths.file.to_string()
};
- let expect_help = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Help));
- let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note));
+ // Errors and warnings are always expected, other diagnostics are only expected
+ // if one of them actually occurs in the test.
+ let expected_kinds: HashSet<_> = [ErrorKind::Error, ErrorKind::Warning]
+ .into_iter()
+ .chain(expected_errors.iter().filter_map(|e| e.kind))
+ .collect();
// Parse the JSON output from the compiler and extract out the messages.
let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res);
@@ -737,8 +736,11 @@ fn check_expected_errors(&self, expected_errors: Vec<errors::Error>, proc_res: &
}
None => {
- // If the test is a known bug, don't require that the error is annotated
- if self.is_unexpected_compiler_message(&actual_error, expect_help, expect_note)
+ if actual_error.require_annotation
+ && actual_error.kind.map_or(false, |kind| {
+ expected_kinds.contains(&kind)
+ && !self.props.dont_require_annotations.contains(&kind)
+ })
{
self.error(&format!(
"{}:{}: unexpected {}: '{}'",
@@ -796,27 +798,6 @@ fn check_expected_errors(&self, expected_errors: Vec<errors::Error>, proc_res: &
}
}
- /// Returns `true` if we should report an error about `actual_error`,
- /// which did not match any of the expected error.
- fn is_unexpected_compiler_message(
- &self,
- actual_error: &Error,
- expect_help: bool,
- expect_note: bool,
- ) -> bool {
- actual_error.require_annotation
- && actual_error.kind.map_or(false, |err_kind| {
- // If the test being checked doesn't contain any "help" or "note" annotations, then
- // we don't require annotating "help" or "note" (respecively) diagnostics at all.
- let default_require_annotations = self.props.require_annotations[&err_kind];
- match err_kind {
- ErrorKind::Help => expect_help && default_require_annotations,
- ErrorKind::Note => expect_note && default_require_annotations,
- _ => default_require_annotations,
- }
- })
- }
-
fn should_emit_metadata(&self, pm: Option<PassMode>) -> Emit {
match (pm, self.props.fail_mode, self.config.mode) {
(Some(PassMode::Check), ..) | (_, Some(FailMode::Check), Ui) => Emit::Metadata,
@@ -887,7 +868,7 @@ fn compile_test_general(
/// `root_out_dir` and `root_testpaths` refer to the parameters of the actual test being run.
/// Auxiliaries, no matter how deep, have the same root_out_dir and root_testpaths.
- fn document(&self, root_out_dir: &Path, root_testpaths: &TestPaths) -> ProcRes {
+ fn document(&self, root_out_dir: &Utf8Path, root_testpaths: &TestPaths) -> ProcRes {
if self.props.build_aux_docs {
for rel_ab in &self.props.aux.builds {
let aux_testpaths = self.compute_aux_test_paths(root_testpaths, rel_ab);
@@ -916,13 +897,13 @@ fn document(&self, root_out_dir: &Path, root_testpaths: &TestPaths) -> ProcRes {
// actual --out-dir given to the auxiliary or test, as opposed to the root out dir for the entire
// test
- let out_dir: Cow<'_, Path> = if self.props.unique_doc_out_dir {
+ let out_dir: Cow<'_, Utf8Path> = if self.props.unique_doc_out_dir {
let file_name = self.testpaths.file.file_stem().expect("file name should not be empty");
- let out_dir = PathBuf::from_iter([
+ let out_dir = Utf8PathBuf::from_iter([
root_out_dir,
- Path::new("docs"),
- Path::new(file_name),
- Path::new("doc"),
+ Utf8Path::new("docs"),
+ Utf8Path::new(file_name),
+ Utf8Path::new("doc"),
]);
create_dir_all(&out_dir).unwrap();
Cow::Owned(out_dir)
@@ -935,7 +916,7 @@ fn document(&self, root_out_dir: &Path, root_testpaths: &TestPaths) -> ProcRes {
rustdoc.current_dir(current_dir);
rustdoc
.arg("-L")
- .arg(self.config.run_lib_path.to_str().unwrap())
+ .arg(self.config.run_lib_path.as_path())
.arg("-L")
.arg(aux_dir)
.arg("-o")
@@ -1073,7 +1054,7 @@ fn compute_aux_test_paths(&self, of: &TestPaths, rel_ab: &str) -> TestPaths {
let test_ab =
of.file.parent().expect("test file path has no parent").join("auxiliary").join(rel_ab);
if !test_ab.exists() {
- self.fatal(&format!("aux-build `{}` source not found", test_ab.display()))
+ self.fatal(&format!("aux-build `{}` source not found", test_ab))
}
TestPaths {
@@ -1110,23 +1091,29 @@ fn has_aux_dir(&self) -> bool {
|| !self.props.aux.proc_macros.is_empty()
}
- fn aux_output_dir(&self) -> PathBuf {
+ fn aux_output_dir(&self) -> Utf8PathBuf {
let aux_dir = self.aux_output_dir_name();
if !self.props.aux.builds.is_empty() {
- remove_and_create_dir_all(&aux_dir);
+ remove_and_create_dir_all(&aux_dir).unwrap_or_else(|e| {
+ panic!("failed to remove and recreate output directory `{aux_dir}`: {e}")
+ });
}
if !self.props.aux.bins.is_empty() {
let aux_bin_dir = self.aux_bin_output_dir_name();
- remove_and_create_dir_all(&aux_dir);
- remove_and_create_dir_all(&aux_bin_dir);
+ remove_and_create_dir_all(&aux_dir).unwrap_or_else(|e| {
+ panic!("failed to remove and recreate output directory `{aux_dir}`: {e}")
+ });
+ remove_and_create_dir_all(&aux_bin_dir).unwrap_or_else(|e| {
+ panic!("failed to remove and recreate output directory `{aux_bin_dir}`: {e}")
+ });
}
aux_dir
}
- fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Path, rustc: &mut Command) {
+ fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Utf8Path, rustc: &mut Command) {
for rel_ab in &self.props.aux.builds {
self.build_auxiliary(of, rel_ab, &aux_dir, None);
}
@@ -1146,12 +1133,7 @@ fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Path, rustc: &mut Comman
|rustc: &mut Command, aux_name: &str, aux_path: &str, aux_type: AuxType| {
let lib_name = get_lib_name(&path_to_crate_name(aux_path), aux_type);
if let Some(lib_name) = lib_name {
- rustc.arg("--extern").arg(format!(
- "{}={}/{}",
- aux_name,
- aux_dir.display(),
- lib_name
- ));
+ rustc.arg("--extern").arg(format!("{}={}/{}", aux_name, aux_dir, lib_name));
}
};
@@ -1172,7 +1154,7 @@ fn build_all_auxiliary(&self, of: &TestPaths, aux_dir: &Path, rustc: &mut Comman
let aux_type = self.build_auxiliary(of, aux_file, aux_dir, None);
if let Some(lib_name) = get_lib_name(aux_file.trim_end_matches(".rs"), aux_type) {
let lib_path = aux_dir.join(&lib_name);
- rustc.arg(format!("-Zcodegen-backend={}", lib_path.display()));
+ rustc.arg(format!("-Zcodegen-backend={}", lib_path));
}
}
}
@@ -1188,7 +1170,7 @@ fn compose_and_run_compiler(
if self.props.add_core_stubs {
let minicore_path = self.build_minicore();
rustc.arg("--extern");
- rustc.arg(&format!("minicore={}", minicore_path.to_str().unwrap()));
+ rustc.arg(&format!("minicore={}", minicore_path));
}
let aux_dir = self.aux_output_dir();
@@ -1206,7 +1188,7 @@ fn compose_and_run_compiler(
/// Builds `minicore`. Returns the path to the minicore rlib within the base test output
/// directory.
- fn build_minicore(&self) -> PathBuf {
+ fn build_minicore(&self) -> Utf8PathBuf {
let output_file_path = self.output_base_dir().join("libminicore.rlib");
let mut rustc = self.make_compile_args(
&self.config.minicore_path,
@@ -1223,10 +1205,7 @@ fn build_minicore(&self) -> PathBuf {
let res = self.compose_and_run(rustc, self.config.compile_lib_path.as_path(), None, None);
if !res.status.success() {
self.fatal_proc_rec(
- &format!(
- "auxiliary build of {:?} failed to compile: ",
- self.config.minicore_path.display()
- ),
+ &format!("auxiliary build of {} failed to compile: ", self.config.minicore_path),
&res,
);
}
@@ -1241,7 +1220,7 @@ fn build_auxiliary(
&self,
of: &TestPaths,
source_path: &str,
- aux_dir: &Path,
+ aux_dir: &Utf8Path,
aux_type: Option<AuxType>,
) -> AuxType {
let aux_testpaths = self.compute_aux_test_paths(of, source_path);
@@ -1338,10 +1317,7 @@ fn build_auxiliary(
);
if !auxres.status.success() {
self.fatal_proc_rec(
- &format!(
- "auxiliary build of {:?} failed to compile: ",
- aux_testpaths.file.display()
- ),
+ &format!("auxiliary build of {} failed to compile: ", aux_testpaths.file),
&auxres,
);
}
@@ -1350,8 +1326,8 @@ fn build_auxiliary(
fn read2_abbreviated(&self, child: Child) -> (Output, Truncated) {
let mut filter_paths_from_len = Vec::new();
- let mut add_path = |path: &Path| {
- let path = path.display().to_string();
+ let mut add_path = |path: &Utf8Path| {
+ let path = path.to_string();
let windows = path.replace("\\", "\\\\");
if windows != path {
filter_paths_from_len.push(windows);
@@ -1373,8 +1349,8 @@ fn read2_abbreviated(&self, child: Child) -> (Output, Truncated) {
fn compose_and_run(
&self,
mut command: Command,
- lib_path: &Path,
- aux_path: Option<&Path>,
+ lib_path: &Utf8Path,
+ aux_path: Option<&Utf8Path>,
input: Option<String>,
) -> ProcRes {
let cmdline = {
@@ -1419,17 +1395,9 @@ fn is_rustdoc(&self) -> bool {
matches!(self.config.suite.as_str(), "rustdoc-ui" | "rustdoc-js" | "rustdoc-json")
}
- fn get_mir_dump_dir(&self) -> PathBuf {
- let mut mir_dump_dir = self.config.build_test_suite_root.clone();
- debug!("input_file: {:?}", self.testpaths.file);
- mir_dump_dir.push(&self.testpaths.relative_dir);
- mir_dump_dir.push(self.testpaths.file.file_stem().unwrap());
- mir_dump_dir
- }
-
fn make_compile_args(
&self,
- input_file: &Path,
+ input_file: &Utf8Path,
output_file: TargetLocation,
emit: Emit,
allow_unused: AllowUnused,
@@ -1470,7 +1438,7 @@ fn make_compile_args(
// Similarly, vendored sources shouldn't be shown when running from a dist tarball.
rustc.arg("-Z").arg(format!(
"ignore-directory-in-diagnostics-source-blocks={}",
- self.config.src_root.join("vendor").to_str().unwrap(),
+ self.config.src_root.join("vendor"),
));
// Optionally prevent default --sysroot if specified in test compile-flags.
@@ -1494,7 +1462,7 @@ fn make_compile_args(
if !is_rustdoc {
if let Some(ref incremental_dir) = self.props.incremental_dir {
- rustc.args(&["-C", &format!("incremental={}", incremental_dir.display())]);
+ rustc.args(&["-C", &format!("incremental={}", incremental_dir)]);
rustc.args(&["-Z", "incremental-verify-ich"]);
}
@@ -1535,10 +1503,9 @@ fn make_compile_args(
}
let set_mir_dump_dir = |rustc: &mut Command| {
- let mir_dump_dir = self.get_mir_dump_dir();
- remove_and_create_dir_all(&mir_dump_dir);
+ let mir_dump_dir = self.output_base_dir();
let mut dir_opt = "-Zdump-mir-dir=".to_string();
- dir_opt.push_str(mir_dump_dir.to_str().unwrap());
+ dir_opt.push_str(mir_dump_dir.as_str());
debug!("dir_opt: {:?}", dir_opt);
rustc.arg(dir_opt);
};
@@ -1631,8 +1598,7 @@ fn make_compile_args(
if self.props.remap_src_base {
rustc.arg(format!(
"--remap-path-prefix={}={}",
- self.config.src_test_suite_root.to_str().unwrap(),
- FAKE_SRC_BASE,
+ self.config.src_test_suite_root, FAKE_SRC_BASE,
));
}
@@ -1755,7 +1721,7 @@ fn make_compile_args(
rustc
}
- fn make_exe_name(&self) -> PathBuf {
+ fn make_exe_name(&self) -> Utf8PathBuf {
// Using a single letter here to keep the path length down for
// Windows. Some test names get very long. rustc creates `rcgu`
// files with the module name appended to it which can more than
@@ -1806,7 +1772,7 @@ fn split_maybe_args(&self, argstr: &Option<String>) -> Vec<OsString> {
}
}
- fn make_cmdline(&self, command: &Command, libpath: &Path) -> String {
+ fn make_cmdline(&self, command: &Command, libpath: &Utf8Path) -> String {
use crate::util;
// Linux and mac don't require adjusting the library search path
@@ -1819,7 +1785,7 @@ fn lib_path_cmd_prefix(path: &str) -> String {
format!("{}=\"{}\"", util::lib_path_env_var(), util::make_new_path(path))
}
- format!("{} {:?}", lib_path_cmd_prefix(libpath.to_str().unwrap()), command)
+ format!("{} {:?}", lib_path_cmd_prefix(libpath.as_str()), command)
}
}
@@ -1833,20 +1799,19 @@ fn dump_output(&self, print_output: bool, proc_name: &str, out: &str, err: &str)
return;
}
- let path = Path::new(proc_name);
+ let path = Utf8Path::new(proc_name);
let proc_name = if path.file_stem().is_some_and(|p| p == "rmake") {
- OsString::from_iter(
+ String::from_iter(
path.parent()
.unwrap()
.file_name()
.into_iter()
- .chain(Some(OsStr::new("/")))
+ .chain(Some("/"))
.chain(path.file_name()),
)
} else {
path.file_name().unwrap().into()
};
- let proc_name = proc_name.to_string_lossy();
println!("------{proc_name} stdout------------------------------");
println!("{}", out);
println!("------{proc_name} stderr------------------------------");
@@ -1856,18 +1821,18 @@ fn dump_output(&self, print_output: bool, proc_name: &str, out: &str, err: &str)
fn dump_output_file(&self, out: &str, extension: &str) {
let outfile = self.make_out_name(extension);
- fs::write(&outfile, out).unwrap();
+ fs::write(outfile.as_std_path(), out).unwrap();
}
/// Creates a filename for output with the given extension.
/// E.g., `/.../testname.revision.mode/testname.extension`.
- fn make_out_name(&self, extension: &str) -> PathBuf {
+ fn make_out_name(&self, extension: &str) -> Utf8PathBuf {
self.output_base_name().with_extension(extension)
}
/// Gets the directory where auxiliary files are written.
/// E.g., `/.../testname.revision.mode/auxiliary/`.
- fn aux_output_dir_name(&self) -> PathBuf {
+ fn aux_output_dir_name(&self) -> Utf8PathBuf {
self.output_base_dir()
.join("auxiliary")
.with_extra_extension(self.config.mode.aux_dir_disambiguator())
@@ -1875,12 +1840,12 @@ fn aux_output_dir_name(&self) -> PathBuf {
/// Gets the directory where auxiliary binaries are written.
/// E.g., `/.../testname.revision.mode/auxiliary/bin`.
- fn aux_bin_output_dir_name(&self) -> PathBuf {
+ fn aux_bin_output_dir_name(&self) -> Utf8PathBuf {
self.aux_output_dir_name().join("bin")
}
/// Generates a unique name for the test, such as `testname.revision.mode`.
- fn output_testname_unique(&self) -> PathBuf {
+ fn output_testname_unique(&self) -> Utf8PathBuf {
output_testname_unique(self.config, self.testpaths, self.safe_revision())
}
@@ -1893,14 +1858,14 @@ fn safe_revision(&self) -> Option<&str> {
/// Gets the absolute path to the directory where all output for the given
/// test/revision should reside.
/// E.g., `/path/to/build/host-tuple/test/ui/relative/testname.revision.mode/`.
- fn output_base_dir(&self) -> PathBuf {
+ fn output_base_dir(&self) -> Utf8PathBuf {
output_base_dir(self.config, self.testpaths, self.safe_revision())
}
/// Gets the absolute path to the base filename used as output for the given
/// test/revision.
/// E.g., `/.../relative/testname.revision.mode/testname`.
- fn output_base_name(&self) -> PathBuf {
+ fn output_base_name(&self) -> Utf8PathBuf {
output_base_name(self.config, self.testpaths, self.safe_revision())
}
@@ -1935,7 +1900,7 @@ fn fatal_proc_rec_with_ctx(
// codegen tests (using FileCheck)
- fn compile_test_and_save_ir(&self) -> (ProcRes, PathBuf) {
+ fn compile_test_and_save_ir(&self) -> (ProcRes, Utf8PathBuf) {
let output_path = self.output_base_name().with_extension("ll");
let input_file = &self.testpaths.file;
let rustc = self.make_compile_args(
@@ -1951,7 +1916,7 @@ fn compile_test_and_save_ir(&self) -> (ProcRes, PathBuf) {
(proc_res, output_path)
}
- fn verify_with_filecheck(&self, output: &Path) -> ProcRes {
+ fn verify_with_filecheck(&self, output: &Utf8Path) -> ProcRes {
let mut filecheck = Command::new(self.config.llvm_filecheck.as_ref().unwrap());
filecheck.arg("--input-file").arg(output).arg(&self.testpaths.file);
@@ -1981,7 +1946,7 @@ fn verify_with_filecheck(&self, output: &Path) -> ProcRes {
filecheck.args(&self.props.filecheck_flags);
// FIXME(jieyouxu): don't pass an empty Path
- self.compose_and_run(filecheck, Path::new(""), None, None)
+ self.compose_and_run(filecheck, Utf8Path::new(""), None, None)
}
fn charset() -> &'static str {
@@ -1989,7 +1954,7 @@ fn charset() -> &'static str {
if cfg!(target_os = "freebsd") { "ISO-8859-1" } else { "UTF-8" }
}
- fn compare_to_default_rustdoc(&mut self, out_dir: &Path) {
+ fn compare_to_default_rustdoc(&mut self, out_dir: &Utf8Path) {
if !self.config.has_html_tidy {
return;
}
@@ -1998,7 +1963,9 @@ fn compare_to_default_rustdoc(&mut self, out_dir: &Path) {
let suffix =
self.safe_revision().map_or("nightly".into(), |path| path.to_owned() + "-nightly");
let compare_dir = output_base_dir(self.config, self.testpaths, Some(&suffix));
- remove_and_create_dir_all(&compare_dir);
+ remove_and_create_dir_all(&compare_dir).unwrap_or_else(|e| {
+ panic!("failed to remove and recreate output directory `{compare_dir}`: {e}")
+ });
// We need to create a new struct for the lifetimes on `config` to work.
let new_rustdoc = TestCx {
@@ -2141,12 +2108,8 @@ fn compare_to_default_rustdoc(&mut self, out_dir: &Path) {
};
}
- fn get_lines<P: AsRef<Path>>(
- &self,
- path: &P,
- mut other_files: Option<&mut Vec<String>>,
- ) -> Vec<usize> {
- let content = fs::read_to_string(&path).unwrap();
+ fn get_lines(&self, path: &Utf8Path, mut other_files: Option<&mut Vec<String>>) -> Vec<usize> {
+ let content = fs::read_to_string(path.as_std_path()).unwrap();
let mut ignore = false;
content
.lines()
@@ -2192,8 +2155,8 @@ fn check_rustdoc_test_option(&self, res: ProcRes) {
for other_file in other_files {
let mut path = self.testpaths.file.clone();
path.set_file_name(&format!("{}.rs", other_file));
- let path = fs::canonicalize(path).expect("failed to canonicalize");
- let normalized = path.to_str().unwrap().replace('\\', "/");
+ let path = path.canonicalize_utf8().expect("failed to canonicalize");
+ let normalized = path.as_str().replace('\\', "/");
files.insert(normalized, self.get_lines(&path, None));
}
@@ -2377,26 +2340,24 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
let mut normalized = output.to_string();
- let mut normalize_path = |from: &Path, to: &str| {
- let mut from = from.display().to_string();
- if json {
- from = from.replace("\\", "\\\\");
- }
- normalized = normalized.replace(&from, to);
+ let mut normalize_path = |from: &Utf8Path, to: &str| {
+ let from = if json { &from.as_str().replace("\\", "\\\\") } else { from.as_str() };
+
+ normalized = normalized.replace(from, to);
};
let parent_dir = self.testpaths.file.parent().unwrap();
normalize_path(parent_dir, "$DIR");
if self.props.remap_src_base {
- let mut remapped_parent_dir = PathBuf::from(FAKE_SRC_BASE);
- if self.testpaths.relative_dir != Path::new("") {
+ let mut remapped_parent_dir = Utf8PathBuf::from(FAKE_SRC_BASE);
+ if self.testpaths.relative_dir != Utf8Path::new("") {
remapped_parent_dir.push(&self.testpaths.relative_dir);
}
normalize_path(&remapped_parent_dir, "$DIR");
}
- let base_dir = Path::new("/rustc/FAKE_PREFIX");
+ let base_dir = Utf8Path::new("/rustc/FAKE_PREFIX");
// Fake paths into the libstd/libcore
normalize_path(&base_dir.join("library"), "$SRC_DIR");
// `ui-fulldeps` tests can show paths to the compiler source when testing macros from
@@ -2406,19 +2367,26 @@ fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> S
// Real paths into the libstd/libcore
let rust_src_dir = &self.config.sysroot_base.join("lib/rustlib/src/rust");
- rust_src_dir.try_exists().expect(&*format!("{} should exists", rust_src_dir.display()));
- let rust_src_dir = rust_src_dir.read_link().unwrap_or(rust_src_dir.to_path_buf());
+ rust_src_dir.try_exists().expect(&*format!("{} should exists", rust_src_dir));
+ let rust_src_dir = rust_src_dir.read_link_utf8().unwrap_or(rust_src_dir.to_path_buf());
normalize_path(&rust_src_dir.join("library"), "$SRC_DIR_REAL");
// eg.
// /home/user/rust/build/x86_64-unknown-linux-gnu/test/ui/<test_dir>/$name.$revision.$mode/
normalize_path(&self.output_base_dir(), "$TEST_BUILD_DIR");
+ // Same as above, but with a canonicalized path.
+ // This is required because some tests print canonical paths inside test build directory,
+ // so if the build directory is a symlink, normalization doesn't help.
+ //
+ // NOTE: There are also tests which print the non-canonical name, so we need both this and
+ // the above normalizations.
+ normalize_path(&self.output_base_dir().canonicalize_utf8().unwrap(), "$TEST_BUILD_DIR");
// eg. /home/user/rust/build
normalize_path(&self.config.build_root, "$BUILD_DIR");
if json {
// escaped newlines in json strings should be readable
- // in the stderr files. There's no point int being correct,
+ // in the stderr files. There's no point in being correct,
// since only humans process the stderr files.
// Thus we just turn escaped newlines back into newlines.
normalized = normalized.replace("\\n", "\n");
@@ -2547,7 +2515,7 @@ fn normalize_platform_differences(output: &str) -> String {
.replace("\r\n", "\n")
}
- fn expected_output_path(&self, kind: &str) -> PathBuf {
+ fn expected_output_path(&self, kind: &str) -> Utf8PathBuf {
let mut path =
expected_output_path(&self.testpaths, self.revision, &self.config.compare_mode, kind);
@@ -2576,19 +2544,18 @@ fn load_expected_output(&self, kind: &str) -> String {
}
}
- fn load_expected_output_from_path(&self, path: &Path) -> Result<String, String> {
- fs::read_to_string(path).map_err(|err| {
- format!("failed to load expected output from `{}`: {}", path.display(), err)
- })
+ fn load_expected_output_from_path(&self, path: &Utf8Path) -> Result<String, String> {
+ fs::read_to_string(path)
+ .map_err(|err| format!("failed to load expected output from `{}`: {}", path, err))
}
- fn delete_file(&self, file: &Path) {
+ fn delete_file(&self, file: &Utf8Path) {
if !file.exists() {
// Deleting a nonexistent file would error.
return;
}
- if let Err(e) = fs::remove_file(file) {
- self.fatal(&format!("failed to delete `{}`: {}", file.display(), e,));
+ if let Err(e) = fs::remove_file(file.as_std_path()) {
+ self.fatal(&format!("failed to delete `{}`: {}", file, e,));
}
}
@@ -2694,8 +2661,8 @@ fn compare_output(
fn show_diff(
&self,
stream: &str,
- expected_path: &Path,
- actual_path: &Path,
+ expected_path: &Utf8Path,
+ actual_path: &Utf8Path,
expected: &str,
actual: &str,
actual_unnormalized: &str,
@@ -2834,7 +2801,7 @@ fn init_incremental_test(&self) {
fs::create_dir_all(&incremental_dir).unwrap();
if self.config.verbose {
- println!("init_incremental_test: incremental_dir={}", incremental_dir.display());
+ println!("init_incremental_test: incremental_dir={incremental_dir}");
}
}
}
@@ -2892,8 +2859,8 @@ pub fn fatal(&self, err: Option<&str>, on_failure: impl FnOnce()) -> ! {
#[derive(Debug)]
enum TargetLocation {
- ThisFile(PathBuf),
- ThisDirectory(PathBuf),
+ ThisFile(Utf8PathBuf),
+ ThisDirectory(Utf8PathBuf),
}
enum AllowUnused {
diff --git a/src/tools/compiletest/src/runtest/assembly.rs b/src/tools/compiletest/src/runtest/assembly.rs
index 89d7de5..91d4f62 100644
--- a/src/tools/compiletest/src/runtest/assembly.rs
+++ b/src/tools/compiletest/src/runtest/assembly.rs
@@ -1,4 +1,4 @@
-use std::path::PathBuf;
+use camino::Utf8PathBuf;
use super::{AllowUnused, Emit, LinkToAux, ProcRes, TargetLocation, TestCx};
@@ -19,7 +19,7 @@ pub(super) fn run_assembly_test(&self) {
}
}
- fn compile_test_and_save_assembly(&self) -> (ProcRes, PathBuf) {
+ fn compile_test_and_save_assembly(&self) -> (ProcRes, Utf8PathBuf) {
// This works with both `--emit asm` (as default output name for the assembly)
// and `ptx-linker` because the latter can write output at requested location.
let output_path = self.output_base_name().with_extension("s");
diff --git a/src/tools/compiletest/src/runtest/codegen_units.rs b/src/tools/compiletest/src/runtest/codegen_units.rs
index 6c866cb..8dfa8d1 100644
--- a/src/tools/compiletest/src/runtest/codegen_units.rs
+++ b/src/tools/compiletest/src/runtest/codegen_units.rs
@@ -26,9 +26,7 @@ pub(super) fn run_codegen_units_test(&self) {
.stdout
.lines()
.filter(|line| line.starts_with(PREFIX))
- .map(|line| {
- line.replace(&self.testpaths.file.display().to_string(), "TEST_PATH").to_string()
- })
+ .map(|line| line.replace(&self.testpaths.file.as_str(), "TEST_PATH").to_string())
.map(|line| str_to_mono_item(&line, true))
.collect();
diff --git a/src/tools/compiletest/src/runtest/coverage.rs b/src/tools/compiletest/src/runtest/coverage.rs
index 56fc5ba..41cfeae 100644
--- a/src/tools/compiletest/src/runtest/coverage.rs
+++ b/src/tools/compiletest/src/runtest/coverage.rs
@@ -1,9 +1,9 @@
//! Code specific to the coverage test suites.
use std::ffi::OsStr;
-use std::path::{Path, PathBuf};
use std::process::Command;
+use camino::{Utf8Path, Utf8PathBuf};
use glob::glob;
use crate::common::{UI_COVERAGE, UI_COVERAGE_MAP};
@@ -11,7 +11,7 @@
use crate::util::static_regex;
impl<'test> TestCx<'test> {
- fn coverage_dump_path(&self) -> &Path {
+ fn coverage_dump_path(&self) -> &Utf8Path {
self.config
.coverage_dump_path
.as_deref()
@@ -79,10 +79,8 @@ pub(super) fn run_coverage_run_test(&self) {
std::fs::remove_file(&profdata_path).unwrap();
}
- let proc_res = self.exec_compiled_test_general(
- &[("LLVM_PROFILE_FILE", &profraw_path.to_str().unwrap())],
- false,
- );
+ let proc_res =
+ self.exec_compiled_test_general(&[("LLVM_PROFILE_FILE", profraw_path.as_str())], false);
if self.props.failure_status.is_some() {
self.check_correct_failure_status(&proc_res);
} else if !proc_res.status.success() {
@@ -158,8 +156,8 @@ pub(super) fn run_coverage_run_test(&self) {
/// `.profraw` files and doctest executables to the given vectors.
fn run_doctests_for_coverage(
&self,
- profraw_paths: &mut Vec<PathBuf>,
- bin_paths: &mut Vec<PathBuf>,
+ profraw_paths: &mut Vec<Utf8PathBuf>,
+ bin_paths: &mut Vec<Utf8PathBuf>,
) {
// Put .profraw files and doctest executables in dedicated directories,
// to make it easier to glob them all later.
@@ -204,10 +202,9 @@ fn run_doctests_for_coverage(
self.fatal_proc_rec("rustdoc --test failed!", &proc_res)
}
- fn glob_iter(path: impl AsRef<Path>) -> impl Iterator<Item = PathBuf> {
- let path_str = path.as_ref().to_str().unwrap();
- let iter = glob(path_str).unwrap();
- iter.map(Result::unwrap)
+ fn glob_iter(path: impl AsRef<Utf8Path>) -> impl Iterator<Item = Utf8PathBuf> {
+ let iter = glob(path.as_ref().as_str()).unwrap();
+ iter.map(Result::unwrap).map(Utf8PathBuf::try_from).map(Result::unwrap)
}
// Find all profraw files in the profraw directory.
diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs
index d9e5c3f..a4103c5 100644
--- a/src/tools/compiletest/src/runtest/debugger.rs
+++ b/src/tools/compiletest/src/runtest/debugger.rs
@@ -1,7 +1,8 @@
use std::fmt::Write;
use std::fs::File;
use std::io::{BufRead, BufReader};
-use std::path::{Path, PathBuf};
+
+use camino::{Utf8Path, Utf8PathBuf};
use crate::common::Config;
use crate::runtest::ProcRes;
@@ -15,11 +16,15 @@ pub(super) struct DebuggerCommands {
/// Contains the source line number to check and the line itself
check_lines: Vec<(usize, String)>,
/// Source file name
- file: PathBuf,
+ file: Utf8PathBuf,
}
impl DebuggerCommands {
- pub fn parse_from(file: &Path, config: &Config, debugger_prefix: &str) -> Result<Self, String> {
+ pub fn parse_from(
+ file: &Utf8Path,
+ config: &Config,
+ debugger_prefix: &str,
+ ) -> Result<Self, String> {
let command_directive = format!("{debugger_prefix}-command");
let check_directive = format!("{debugger_prefix}-check");
@@ -27,7 +32,7 @@ pub fn parse_from(file: &Path, config: &Config, debugger_prefix: &str) -> Result
let mut commands = vec![];
let mut check_lines = vec![];
let mut counter = 0;
- let reader = BufReader::new(File::open(file).unwrap());
+ let reader = BufReader::new(File::open(file.as_std_path()).unwrap());
for (line_no, line) in reader.lines().enumerate() {
counter += 1;
let line = line.map_err(|e| format!("Error while parsing debugger commands: {}", e))?;
@@ -50,7 +55,7 @@ pub fn parse_from(file: &Path, config: &Config, debugger_prefix: &str) -> Result
}
}
- Ok(Self { commands, breakpoint_lines, check_lines, file: file.to_owned() })
+ Ok(Self { commands, breakpoint_lines, check_lines, file: file.to_path_buf() })
}
/// Given debugger output and lines to check, ensure that every line is
@@ -81,10 +86,10 @@ pub fn check_output(&self, debugger_run_result: &ProcRes) -> Result<(), String>
if missing.is_empty() {
Ok(())
} else {
- let fname = self.file.file_name().unwrap().to_string_lossy();
+ let fname = self.file.file_name().unwrap();
let mut msg = format!(
"check directive(s) from `{}` not found in debugger output. errors:",
- self.file.display()
+ self.file
);
for (src_lineno, err_line) in missing {
diff --git a/src/tools/compiletest/src/runtest/debuginfo.rs b/src/tools/compiletest/src/runtest/debuginfo.rs
index 50e733c..31240df 100644
--- a/src/tools/compiletest/src/runtest/debuginfo.rs
+++ b/src/tools/compiletest/src/runtest/debuginfo.rs
@@ -1,9 +1,9 @@
use std::ffi::{OsStr, OsString};
use std::fs::File;
use std::io::{BufRead, BufReader, Read};
-use std::path::Path;
use std::process::{Command, Output, Stdio};
+use camino::Utf8Path;
use tracing::debug;
use super::debugger::DebuggerCommands;
@@ -73,11 +73,11 @@ fn run_debuginfo_cdb_test_no_opt(&self) {
let mut js_extension = self.testpaths.file.clone();
js_extension.set_extension("cdb.js");
if js_extension.exists() {
- script_str.push_str(&format!(".scriptload \"{}\"\n", js_extension.to_string_lossy()));
+ script_str.push_str(&format!(".scriptload \"{}\"\n", js_extension));
}
// Set breakpoints on every line that contains the string "#break"
- let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy();
+ let source_file_name = self.testpaths.file.file_name().unwrap();
for line in &dbg_cmds.breakpoint_lines {
script_str.push_str(&format!("bp `{}:{}`\n", source_file_name, line));
}
@@ -151,16 +151,11 @@ fn run_debuginfo_gdb_test_no_opt(&self) {
if is_android_gdb_target(&self.config.target) {
cmds = cmds.replace("run", "continue");
- let tool_path = match self.config.android_cross_path.to_str() {
- Some(x) => x.to_owned(),
- None => self.fatal("cannot find android cross path"),
- };
-
// write debugger script
let mut script_str = String::with_capacity(2048);
script_str.push_str(&format!("set charset {}\n", Self::charset()));
- script_str.push_str(&format!("set sysroot {}\n", tool_path));
- script_str.push_str(&format!("file {}\n", exe_file.to_str().unwrap()));
+ script_str.push_str(&format!("set sysroot {}\n", &self.config.android_cross_path));
+ script_str.push_str(&format!("file {}\n", exe_file));
script_str.push_str("target remote :5039\n");
script_str.push_str(&format!(
"set solib-search-path \
@@ -169,12 +164,8 @@ fn run_debuginfo_gdb_test_no_opt(&self) {
));
for line in &dbg_cmds.breakpoint_lines {
script_str.push_str(
- format!(
- "break {:?}:{}\n",
- self.testpaths.file.file_name().unwrap().to_string_lossy(),
- *line
- )
- .as_str(),
+ format!("break {}:{}\n", self.testpaths.file.file_name().unwrap(), *line)
+ .as_str(),
);
}
script_str.push_str(&cmds);
@@ -203,7 +194,7 @@ fn run_debuginfo_gdb_test_no_opt(&self) {
self.config.adb_test_dir.clone(),
if self.config.target.contains("aarch64") { "64" } else { "" },
self.config.adb_test_dir.clone(),
- exe_file.file_name().unwrap().to_str().unwrap()
+ exe_file.file_name().unwrap()
);
debug!("adb arg: {}", adb_arg);
@@ -242,7 +233,7 @@ fn run_debuginfo_gdb_test_no_opt(&self) {
let mut gdb = Command::new(&format!("{}-gdb", self.config.target));
gdb.args(debugger_opts);
// FIXME(jieyouxu): don't pass an empty Path
- let cmdline = self.make_cmdline(&gdb, Path::new(""));
+ let cmdline = self.make_cmdline(&gdb, Utf8Path::new(""));
logv(self.config, format!("executing {}", cmdline));
cmdline
};
@@ -259,7 +250,6 @@ fn run_debuginfo_gdb_test_no_opt(&self) {
}
} else {
let rust_pp_module_abs_path = self.config.src_root.join("src").join("etc");
- let rust_pp_module_abs_path = rust_pp_module_abs_path.to_str().unwrap();
// write debugger script
let mut script_str = String::with_capacity(2048);
script_str.push_str(&format!("set charset {}\n", Self::charset()));
@@ -274,17 +264,15 @@ fn run_debuginfo_gdb_test_no_opt(&self) {
// GDB's script auto loading safe path
script_str.push_str(&format!(
"add-auto-load-safe-path {}\n",
- rust_pp_module_abs_path.replace(r"\", r"\\")
+ rust_pp_module_abs_path.as_str().replace(r"\", r"\\")
));
- let output_base_dir = self.output_base_dir().to_str().unwrap().to_owned();
-
// Add the directory containing the output binary to
// include embedded pretty printers to GDB's script
// auto loading safe path
script_str.push_str(&format!(
"add-auto-load-safe-path {}\n",
- output_base_dir.replace(r"\", r"\\")
+ self.output_base_dir().as_str().replace(r"\", r"\\")
));
}
}
@@ -301,12 +289,13 @@ fn run_debuginfo_gdb_test_no_opt(&self) {
script_str.push_str("set print pretty off\n");
// Add the pretty printer directory to GDB's source-file search path
- script_str
- .push_str(&format!("directory {}\n", rust_pp_module_abs_path.replace(r"\", r"\\")));
+ script_str.push_str(&format!(
+ "directory {}\n",
+ rust_pp_module_abs_path.as_str().replace(r"\", r"\\")
+ ));
// Load the target executable
- script_str
- .push_str(&format!("file {}\n", exe_file.to_str().unwrap().replace(r"\", r"\\")));
+ script_str.push_str(&format!("file {}\n", exe_file.as_str().replace(r"\", r"\\")));
// Force GDB to print values in the Rust format.
script_str.push_str("set language rust\n");
@@ -315,7 +304,7 @@ fn run_debuginfo_gdb_test_no_opt(&self) {
for line in &dbg_cmds.breakpoint_lines {
script_str.push_str(&format!(
"break '{}':{}\n",
- self.testpaths.file.file_name().unwrap().to_string_lossy(),
+ self.testpaths.file.file_name().unwrap(),
*line
));
}
@@ -410,14 +399,14 @@ fn run_debuginfo_lldb_test_no_opt(&self) {
script_str.push_str(&format!(
"command script import {}/lldb_lookup.py\n",
- rust_pp_module_abs_path.to_str().unwrap()
+ rust_pp_module_abs_path
));
File::open(rust_pp_module_abs_path.join("lldb_commands"))
.and_then(|mut file| file.read_to_string(&mut script_str))
.expect("Failed to read lldb_commands");
// Set breakpoints on every line that contains the string "#break"
- let source_file_name = self.testpaths.file.file_name().unwrap().to_string_lossy();
+ let source_file_name = self.testpaths.file.file_name().unwrap();
for line in &dbg_cmds.breakpoint_lines {
script_str.push_str(&format!(
"breakpoint set --file '{}' --line {}\n",
@@ -451,7 +440,7 @@ fn run_debuginfo_lldb_test_no_opt(&self) {
}
}
- fn run_lldb(&self, test_executable: &Path, debugger_script: &Path) -> ProcRes {
+ fn run_lldb(&self, test_executable: &Utf8Path, debugger_script: &Utf8Path) -> ProcRes {
// Prepare the lldb_batchmode which executes the debugger script
let lldb_script_path = self.config.src_root.join("src/etc/lldb_batchmode.py");
let pythonpath = if let Ok(pp) = std::env::var("PYTHONPATH") {
diff --git a/src/tools/compiletest/src/runtest/js_doc.rs b/src/tools/compiletest/src/runtest/js_doc.rs
index d630aff..fd53f01 100644
--- a/src/tools/compiletest/src/runtest/js_doc.rs
+++ b/src/tools/compiletest/src/runtest/js_doc.rs
@@ -9,8 +9,7 @@ pub(super) fn run_rustdoc_js_test(&self) {
self.document(&out_dir, &self.testpaths);
- let file_stem =
- self.testpaths.file.file_stem().and_then(|f| f.to_str()).expect("no file stem");
+ let file_stem = self.testpaths.file.file_stem().expect("no file stem");
let res = self.run_command_to_procres(
Command::new(&nodejs)
.arg(self.config.src_root.join("src/tools/rustdoc-js/tester.js"))
diff --git a/src/tools/compiletest/src/runtest/mir_opt.rs b/src/tools/compiletest/src/runtest/mir_opt.rs
index d1ec003..efdb131 100644
--- a/src/tools/compiletest/src/runtest/mir_opt.rs
+++ b/src/tools/compiletest/src/runtest/mir_opt.rs
@@ -1,6 +1,6 @@
use std::fs;
-use std::path::{Path, PathBuf};
+use camino::{Utf8Path, Utf8PathBuf};
use glob::glob;
use miropt_test_tools::{MiroptTest, MiroptTestFile, files_for_miropt_test};
use tracing::debug;
@@ -14,7 +14,7 @@ pub(super) fn run_mir_opt_test(&self) {
let should_run = self.should_run(pm);
let mut test_info = files_for_miropt_test(
- &self.testpaths.file,
+ &self.testpaths.file.as_std_path(),
self.config.get_pointer_width(),
self.config.target_cfg().panic.for_miropt_test_tools(),
);
@@ -38,20 +38,15 @@ pub(super) fn run_mir_opt_test(&self) {
fn check_mir_dump(&self, test_info: MiroptTest) {
let test_dir = self.testpaths.file.parent().unwrap();
- let test_crate =
- self.testpaths.file.file_stem().unwrap().to_str().unwrap().replace('-', "_");
+ let test_crate = self.testpaths.file.file_stem().unwrap().replace('-', "_");
let MiroptTest { run_filecheck, suffix, files, passes: _ } = test_info;
if self.config.bless {
- for e in
- glob(&format!("{}/{}.*{}.mir", test_dir.display(), test_crate, suffix)).unwrap()
- {
+ for e in glob(&format!("{}/{}.*{}.mir", test_dir, test_crate, suffix)).unwrap() {
fs::remove_file(e.unwrap()).unwrap();
}
- for e in
- glob(&format!("{}/{}.*{}.diff", test_dir.display(), test_crate, suffix)).unwrap()
- {
+ for e in glob(&format!("{}/{}.*{}.diff", test_dir, test_crate, suffix)).unwrap() {
fs::remove_file(e.unwrap()).unwrap();
}
}
@@ -60,19 +55,15 @@ fn check_mir_dump(&self, test_info: MiroptTest) {
let dumped_string = if let Some(after) = to_file {
self.diff_mir_files(from_file.into(), after.into())
} else {
- let mut output_file = PathBuf::new();
- output_file.push(self.get_mir_dump_dir());
+ let mut output_file = Utf8PathBuf::new();
+ output_file.push(self.output_base_dir());
output_file.push(&from_file);
- debug!(
- "comparing the contents of: {} with {}",
- output_file.display(),
- expected_file.display()
- );
+ debug!("comparing the contents of: {} with {:?}", output_file, expected_file);
if !output_file.exists() {
panic!(
"Output file `{}` from test does not exist, available files are in `{}`",
- output_file.display(),
- output_file.parent().unwrap().display()
+ output_file,
+ output_file.parent().unwrap()
);
}
self.check_mir_test_timestamp(&from_file, &output_file);
@@ -107,21 +98,20 @@ fn check_mir_dump(&self, test_info: MiroptTest) {
}
}
- fn diff_mir_files(&self, before: PathBuf, after: PathBuf) -> String {
- let to_full_path = |path: PathBuf| {
- let full = self.get_mir_dump_dir().join(&path);
+ fn diff_mir_files(&self, before: Utf8PathBuf, after: Utf8PathBuf) -> String {
+ let to_full_path = |path: Utf8PathBuf| {
+ let full = self.output_base_dir().join(&path);
if !full.exists() {
panic!(
"the mir dump file for {} does not exist (requested in {})",
- path.display(),
- self.testpaths.file.display(),
+ path, self.testpaths.file,
);
}
full
};
let before = to_full_path(before);
let after = to_full_path(after);
- debug!("comparing the contents of: {} with {}", before.display(), after.display());
+ debug!("comparing the contents of: {} with {}", before, after);
let before = fs::read_to_string(before).unwrap();
let after = fs::read_to_string(after).unwrap();
let before = self.normalize_output(&before, &[]);
@@ -138,8 +128,8 @@ fn diff_mir_files(&self, before: PathBuf, after: PathBuf) -> String {
dumped_string
}
- fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) {
- let t = |file| fs::metadata(file).unwrap().modified().unwrap();
+ fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Utf8Path) {
+ let t = |file: &Utf8Path| fs::metadata(file.as_std_path()).unwrap().modified().unwrap();
let source_file = &self.testpaths.file;
let output_time = t(output_file);
let source_time = t(source_file);
@@ -147,8 +137,7 @@ fn check_mir_test_timestamp(&self, test_name: &str, output_file: &Path) {
debug!("source file time: {:?} output file time: {:?}", source_time, output_time);
panic!(
"test source file `{}` is newer than potentially stale output file `{}`.",
- source_file.display(),
- test_name
+ source_file, test_name
);
}
}
diff --git a/src/tools/compiletest/src/runtest/run_make.rs b/src/tools/compiletest/src/runtest/run_make.rs
index 0731169..a5ce929 100644
--- a/src/tools/compiletest/src/runtest/run_make.rs
+++ b/src/tools/compiletest/src/runtest/run_make.rs
@@ -1,8 +1,8 @@
-use std::path::Path;
use std::process::{Command, Output, Stdio};
use std::{env, fs};
use build_helper::fs::{ignore_not_found, recursive_remove};
+use camino::{Utf8Path, Utf8PathBuf};
use super::{ProcRes, TestCx, disable_error_reporting};
use crate::util::{copy_dir_all, dylib_env_var};
@@ -39,14 +39,16 @@ pub(super) fn run_rmake_test(&self) {
// Copy all input files (apart from rmake.rs) to the temporary directory,
// so that the input directory structure from `tests/run-make/<test>` is mirrored
// to the `rmake_out` directory.
- for path in walkdir::WalkDir::new(&self.testpaths.file).min_depth(1) {
- let path = path.unwrap().path().to_path_buf();
+ for entry in walkdir::WalkDir::new(&self.testpaths.file).min_depth(1) {
+ let entry = entry.unwrap();
+ let path = entry.path();
+ let path = <&Utf8Path>::try_from(path).unwrap();
if path.file_name().is_some_and(|s| s != "rmake.rs") {
let target = rmake_out_dir.join(path.strip_prefix(&self.testpaths.file).unwrap());
if path.is_dir() {
- copy_dir_all(&path, target).unwrap();
+ copy_dir_all(&path, &target).unwrap();
} else {
- fs::copy(&path, target).unwrap();
+ fs::copy(path.as_std_path(), target).unwrap();
}
}
}
@@ -83,8 +85,10 @@ pub(super) fn run_rmake_test(&self) {
// on some linux distros.
// 2. Specific library paths in `self.config.compile_lib_path` needed for running rustc.
- let base_dylib_search_paths =
- Vec::from_iter(env::split_paths(&env::var(dylib_env_var()).unwrap()));
+ let base_dylib_search_paths = Vec::from_iter(
+ env::split_paths(&env::var(dylib_env_var()).unwrap())
+ .map(|p| Utf8PathBuf::try_from(p).expect("dylib env var contains non-UTF8 paths")),
+ );
// Calculate the paths of the recipe binary. As previously discussed, this is placed at
// `<base_dir>/<bin_name>` with `bin_name` being `rmake` or `rmake.exe` depending on
@@ -113,13 +117,13 @@ pub(super) fn run_rmake_test(&self) {
.arg("-o")
.arg(&recipe_bin)
// Specify library search paths for `run_make_support`.
- .arg(format!("-Ldependency={}", &support_lib_path.parent().unwrap().to_string_lossy()))
- .arg(format!("-Ldependency={}", &support_lib_deps.to_string_lossy()))
- .arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy()))
+ .arg(format!("-Ldependency={}", &support_lib_path.parent().unwrap()))
+ .arg(format!("-Ldependency={}", &support_lib_deps))
+ .arg(format!("-Ldependency={}", &support_lib_deps_deps))
// Provide `run_make_support` as extern prelude, so test writers don't need to write
// `extern run_make_support;`.
.arg("--extern")
- .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy()))
+ .arg(format!("run_make_support={}", &support_lib_path))
.arg("--edition=2021")
.arg(&self.testpaths.file.join("rmake.rs"))
.arg("-Cprefer-dynamic");
@@ -240,7 +244,7 @@ pub(super) fn run_rmake_test(&self) {
if self.config.target.contains("msvc") && !self.config.cc.is_empty() {
// We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe`
// and that `lib.exe` lives next to it.
- let lib = Path::new(&self.config.cc).parent().unwrap().join("lib.exe");
+ let lib = Utf8Path::new(&self.config.cc).parent().unwrap().join("lib.exe");
// MSYS doesn't like passing flags of the form `/foo` as it thinks it's
// a path and instead passes `C:\msys64\foo`, so convert all
@@ -262,8 +266,8 @@ pub(super) fn run_rmake_test(&self) {
cmd.env("IS_MSVC", "1")
.env("IS_WINDOWS", "1")
- .env("MSVC_LIB", format!("'{}' -nologo", lib.display()))
- .env("MSVC_LIB_PATH", format!("{}", lib.display()))
+ .env("MSVC_LIB", format!("'{}' -nologo", lib))
+ .env("MSVC_LIB_PATH", &lib)
// Note: we diverge from legacy run_make and don't lump `CC` the compiler and
// default flags together.
.env("CC_DEFAULT_FLAGS", &cflags)
diff --git a/src/tools/compiletest/src/runtest/rustdoc.rs b/src/tools/compiletest/src/runtest/rustdoc.rs
index 2583ae9..637ea83 100644
--- a/src/tools/compiletest/src/runtest/rustdoc.rs
+++ b/src/tools/compiletest/src/runtest/rustdoc.rs
@@ -7,7 +7,9 @@ pub(super) fn run_rustdoc_test(&self) {
assert!(self.revision.is_none(), "revisions not relevant here");
let out_dir = self.output_base_dir();
- remove_and_create_dir_all(&out_dir);
+ remove_and_create_dir_all(&out_dir).unwrap_or_else(|e| {
+ panic!("failed to remove and recreate output directory `{out_dir}`: {e}")
+ });
let proc_res = self.document(&out_dir, &self.testpaths);
if !proc_res.status.success() {
diff --git a/src/tools/compiletest/src/runtest/rustdoc_json.rs b/src/tools/compiletest/src/runtest/rustdoc_json.rs
index bf7eb2e..9f88fac 100644
--- a/src/tools/compiletest/src/runtest/rustdoc_json.rs
+++ b/src/tools/compiletest/src/runtest/rustdoc_json.rs
@@ -9,7 +9,9 @@ pub(super) fn run_rustdoc_json_test(&self) {
assert!(self.revision.is_none(), "revisions not relevant here");
let out_dir = self.output_base_dir();
- remove_and_create_dir_all(&out_dir);
+ remove_and_create_dir_all(&out_dir).unwrap_or_else(|e| {
+ panic!("failed to remove and recreate output directory `{out_dir}`: {e}")
+ });
let proc_res = self.document(&out_dir, &self.testpaths);
if !proc_res.status.success() {
diff --git a/src/tools/compiletest/src/runtest/ui.rs b/src/tools/compiletest/src/runtest/ui.rs
index 974e517..e87b037 100644
--- a/src/tools/compiletest/src/runtest/ui.rs
+++ b/src/tools/compiletest/src/runtest/ui.rs
@@ -68,7 +68,7 @@ pub(super) fn run_ui_test(&self) {
{
let mut coverage_file_path = self.config.build_test_suite_root.clone();
coverage_file_path.push("rustfix_missing_coverage.txt");
- debug!("coverage_file_path: {}", coverage_file_path.display());
+ debug!("coverage_file_path: {}", coverage_file_path);
let mut file = OpenOptions::new()
.create(true)
@@ -76,8 +76,8 @@ pub(super) fn run_ui_test(&self) {
.open(coverage_file_path.as_path())
.expect("could not create or open file");
- if let Err(e) = writeln!(file, "{}", self.testpaths.file.display()) {
- panic!("couldn't write to {}: {e:?}", coverage_file_path.display());
+ if let Err(e) = writeln!(file, "{}", self.testpaths.file) {
+ panic!("couldn't write to {}: {e:?}", coverage_file_path);
}
}
} else if self.props.run_rustfix {
@@ -119,7 +119,7 @@ pub(super) fn run_ui_test(&self) {
self.testpaths.relative_dir.join(self.testpaths.file.file_name().unwrap());
println!(
"To only update this specific test, also pass `--test-args {}`",
- relative_path_to_file.display(),
+ relative_path_to_file,
);
self.fatal_proc_rec(
&format!("{} errors occurred comparing output.", errors),
@@ -211,8 +211,6 @@ pub(super) fn run_ui_test(&self) {
let crate_name =
self.testpaths.file.file_stem().expect("test must have a file stem");
// crate name must be alphanumeric or `_`.
- let crate_name =
- crate_name.to_str().expect("crate name implies file name must be valid UTF-8");
// replace `a.foo` -> `a__foo` for crate name purposes.
// replace `revision-name-with-dashes` -> `revision_name_with_underscore`
let crate_name = crate_name.replace('.', "__");
diff --git a/src/tools/compiletest/src/tests.rs b/src/tools/compiletest/src/tests.rs
index 43c6dc0..e3e4a81 100644
--- a/src/tools/compiletest/src/tests.rs
+++ b/src/tools/compiletest/src/tests.rs
@@ -1,5 +1,3 @@
-use std::ffi::OsString;
-
use crate::debuggers::{extract_gdb_version, extract_lldb_version};
use crate::is_test;
@@ -60,11 +58,11 @@ fn test_extract_lldb_version() {
#[test]
fn is_test_test() {
- assert!(is_test(&OsString::from("a_test.rs")));
- assert!(!is_test(&OsString::from(".a_test.rs")));
- assert!(!is_test(&OsString::from("a_cat.gif")));
- assert!(!is_test(&OsString::from("#a_dog_gif")));
- assert!(!is_test(&OsString::from("~a_temp_file")));
+ assert!(is_test("a_test.rs"));
+ assert!(!is_test(".a_test.rs"));
+ assert!(!is_test("a_cat.gif"));
+ assert!(!is_test("#a_dog_gif"));
+ assert!(!is_test("~a_temp_file"));
}
#[test]
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index bff02f1..81f5679 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -1,8 +1,7 @@
use std::env;
-use std::ffi::OsStr;
-use std::path::{Path, PathBuf};
use std::process::Command;
+use camino::{Utf8Path, Utf8PathBuf};
use tracing::*;
use crate::common::Config;
@@ -34,21 +33,21 @@ pub fn logv(config: &Config, s: String) {
}
}
-pub trait PathBufExt {
+pub trait Utf8PathBufExt {
/// Append an extension to the path, even if it already has one.
- fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf;
+ fn with_extra_extension(&self, extension: &str) -> Utf8PathBuf;
}
-impl PathBufExt for PathBuf {
- fn with_extra_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
- if extension.as_ref().is_empty() {
+impl Utf8PathBufExt for Utf8PathBuf {
+ fn with_extra_extension(&self, extension: &str) -> Utf8PathBuf {
+ if extension.is_empty() {
self.clone()
} else {
- let mut fname = self.file_name().unwrap().to_os_string();
- if !extension.as_ref().to_str().unwrap().starts_with('.') {
- fname.push(".");
+ let mut fname = self.file_name().unwrap().to_string();
+ if !extension.starts_with('.') {
+ fname.push_str(".");
}
- fname.push(extension);
+ fname.push_str(extension);
self.with_file_name(fname)
}
}
@@ -71,22 +70,27 @@ pub fn dylib_env_var() -> &'static str {
/// Adds a list of lookup paths to `cmd`'s dynamic library lookup path.
/// If the dylib_path_var is already set for this cmd, the old value will be overwritten!
-pub fn add_dylib_path(cmd: &mut Command, paths: impl Iterator<Item = impl Into<PathBuf>>) {
+pub fn add_dylib_path(
+ cmd: &mut Command,
+ paths: impl Iterator<Item = impl Into<std::path::PathBuf>>,
+) {
let path_env = env::var_os(dylib_env_var());
let old_paths = path_env.as_ref().map(env::split_paths);
let new_paths = paths.map(Into::into).chain(old_paths.into_iter().flatten());
cmd.env(dylib_env_var(), env::join_paths(new_paths).unwrap());
}
-pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> std::io::Result<()> {
- std::fs::create_dir_all(&dst)?;
- for entry in std::fs::read_dir(src)? {
+pub fn copy_dir_all(src: &Utf8Path, dst: &Utf8Path) -> std::io::Result<()> {
+ std::fs::create_dir_all(dst.as_std_path())?;
+ for entry in std::fs::read_dir(src.as_std_path())? {
let entry = entry?;
+ let path = Utf8PathBuf::try_from(entry.path()).unwrap();
+ let file_name = path.file_name().unwrap();
let ty = entry.file_type()?;
if ty.is_dir() {
- copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
+ copy_dir_all(&path, &dst.join(file_name))?;
} else {
- std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
+ std::fs::copy(path.as_std_path(), dst.join(file_name).as_std_path())?;
}
}
Ok(())
diff --git a/src/tools/compiletest/src/util/tests.rs b/src/tools/compiletest/src/util/tests.rs
index b09a183..5bcae0d 100644
--- a/src/tools/compiletest/src/util/tests.rs
+++ b/src/tools/compiletest/src/util/tests.rs
@@ -3,12 +3,12 @@
#[test]
fn path_buf_with_extra_extension_test() {
assert_eq!(
- PathBuf::from("foo.rs.stderr"),
- PathBuf::from("foo.rs").with_extra_extension("stderr")
+ Utf8PathBuf::from("foo.rs.stderr"),
+ Utf8PathBuf::from("foo.rs").with_extra_extension("stderr")
);
assert_eq!(
- PathBuf::from("foo.rs.stderr"),
- PathBuf::from("foo.rs").with_extra_extension(".stderr")
+ Utf8PathBuf::from("foo.rs.stderr"),
+ Utf8PathBuf::from("foo.rs").with_extra_extension(".stderr")
);
- assert_eq!(PathBuf::from("foo.rs"), PathBuf::from("foo.rs").with_extra_extension(""));
+ assert_eq!(Utf8PathBuf::from("foo.rs"), Utf8PathBuf::from("foo.rs").with_extra_extension(""));
}
diff --git a/src/tools/generate-windows-sys/Cargo.toml b/src/tools/generate-windows-sys/Cargo.toml
index f5c0e56..152cd50 100644
--- a/src/tools/generate-windows-sys/Cargo.toml
+++ b/src/tools/generate-windows-sys/Cargo.toml
@@ -4,4 +4,4 @@
edition = "2021"
[dependencies.windows-bindgen]
-version = "0.59.0"
+version = "0.61.0"
diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs
index 54249fb..65ad38d 100644
--- a/src/tools/jsondocck/src/main.rs
+++ b/src/tools/jsondocck/src/main.rs
@@ -154,9 +154,10 @@ fn parse<'a>(command_name: &str, negated: bool, args: &'a [String]) -> Option<(S
static LINE_PATTERN: LazyLock<Regex> = LazyLock::new(|| {
RegexBuilder::new(
r#"
+ ^\s*
//@\s+
(?P<negated>!?)
- (?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*)
+ (?P<cmd>[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*)
(?P<args>.*)$
"#,
)
diff --git a/src/tools/jsondoclint/src/validator/tests.rs b/src/tools/jsondoclint/src/validator/tests.rs
index 28deb7e..dd0b4ac 100644
--- a/src/tools/jsondoclint/src/validator/tests.rs
+++ b/src/tools/jsondoclint/src/validator/tests.rs
@@ -42,6 +42,7 @@ fn errors_on_missing_links() {
)]),
paths: FxHashMap::default(),
external_crates: FxHashMap::default(),
+ target: rustdoc_json_types::Target { triple: "".to_string(), target_features: vec![] },
format_version: rustdoc_json_types::FORMAT_VERSION,
};
@@ -112,6 +113,7 @@ fn errors_on_local_in_paths_and_not_index() {
},
)]),
external_crates: FxHashMap::default(),
+ target: rustdoc_json_types::Target { triple: "".to_string(), target_features: vec![] },
format_version: rustdoc_json_types::FORMAT_VERSION,
};
@@ -216,6 +218,7 @@ fn errors_on_missing_path() {
ItemSummary { crate_id: 0, path: vec!["foo".to_owned()], kind: ItemKind::Module },
)]),
external_crates: FxHashMap::default(),
+ target: rustdoc_json_types::Target { triple: "".to_string(), target_features: vec![] },
format_version: rustdoc_json_types::FORMAT_VERSION,
};
@@ -259,6 +262,7 @@ fn checks_local_crate_id_is_correct() {
)]),
paths: FxHashMap::default(),
external_crates: FxHashMap::default(),
+ target: rustdoc_json_types::Target { triple: "".to_string(), target_features: vec![] },
format_version: FORMAT_VERSION,
};
check(&krate, &[]);
diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock
index 0c6f4a3..6f4bd3e 100644
--- a/src/tools/miri/Cargo.lock
+++ b/src/tools/miri/Cargo.lock
@@ -257,9 +257,9 @@
[[package]]
name = "crossbeam-channel"
-version = "0.5.14"
+version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
+checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
dependencies = [
"crossbeam-utils",
]
@@ -436,9 +436,9 @@
[[package]]
name = "libffi"
-version = "3.2.0"
+version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce826c243048e3d5cec441799724de52e2d42f820468431fc3fceee2341871e2"
+checksum = "4a9434b6fc77375fb624698d5f8c49d7e80b10d59eb1219afda27d1f824d4074"
dependencies = [
"libc",
"libffi-sys",
@@ -446,9 +446,9 @@
[[package]]
name = "libffi-sys"
-version = "2.3.0"
+version = "3.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f36115160c57e8529781b4183c2bb51fdc1f6d6d1ed345591d84be7703befb3c"
+checksum = "ead36a2496acfc8edd6cc32352110e9478ac5b9b5f5b9856ebd3d28019addb84"
dependencies = [
"cc",
]
diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml
index e9ee19b..bb24e70 100644
--- a/src/tools/miri/Cargo.toml
+++ b/src/tools/miri/Cargo.toml
@@ -37,7 +37,7 @@
[target.'cfg(unix)'.dependencies]
libc = "0.2"
-libffi = "3.2.0"
+libffi = "4.0.0"
libloading = "0.8"
[target.'cfg(target_family = "windows")'.dependencies]
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index b690bd9..755e02d 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -164,9 +164,9 @@
# Partially supported targets (tier 2)
BASIC="empty_main integer heap_alloc libc-mem vec string btreemap" # ensures we have the basics: pre-main code, system allocator
UNIX="hello panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
- TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe concurrency sync
- TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random threadname pthread fs libc-pipe
- TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random sync concurrency thread epoll eventfd
+ TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe
+ TEST_TARGET=i686-unknown-freebsd run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency fs libc-pipe
+ TEST_TARGET=aarch64-linux-android run_tests_minimal $BASIC $UNIX time hashmap random thread sync concurrency epoll eventfd
TEST_TARGET=wasm32-wasip2 run_tests_minimal $BASIC wasm
TEST_TARGET=wasm32-unknown-unknown run_tests_minimal no_std empty_main wasm # this target doesn't really have std
TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index d2b8b51..d1107e5 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-7d7de5bf3c3cbf9c2c5bbc5cbfb9197a8a427d35
+1bc56185ee257ed829a0aea7abdc3b03c5fed887
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index b4098ca..1af3d1a 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -1382,6 +1382,11 @@ pub(crate) fn bool_to_simd_element(b: bool, size: Size) -> Scalar {
}
pub(crate) fn simd_element_to_bool(elem: ImmTy<'_>) -> InterpResult<'_, bool> {
+ assert!(
+ matches!(elem.layout.ty.kind(), ty::Int(_) | ty::Uint(_)),
+ "SIMD mask element type must be an integer, but this is `{}`",
+ elem.layout.ty
+ );
let val = elem.to_scalar().to_int(elem.layout.size)?;
interp_ok(match val {
0 => false,
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 5921ba8..e03611e 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -1,6 +1,5 @@
#![feature(rustc_private)]
#![feature(cfg_match)]
-#![feature(cell_update)]
#![feature(float_gamma)]
#![feature(float_erf)]
#![feature(map_try_insert)]
@@ -169,7 +168,7 @@
"-Zalways-encode-mir",
"-Zextra-const-ub-checks",
"-Zmir-emit-retag",
- "-Zmir-keep-place-mention",
+ "-Zmir-preserve-ub",
"-Zmir-opt-level=0",
"-Zmir-enable-passes=-CheckAlignment,-CheckNull",
// Deduplicating diagnostics means we miss events when tracking what happens during an
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index 7d97e33..8dcadbe 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -65,7 +65,7 @@ fn win_get_full_path_name<'tcx>(path: &Path) -> InterpResult<'tcx, io::Result<Pa
}
// Otherwise we try to do something kind of close to what Windows does, but this is probably not
// right in all cases.
- let mut result: Vec<&[u8]> = vec![]; // will be a vecot of components, joined by `/`.
+ let mut result: Vec<&[u8]> = vec![]; // will be a vector of components, joined by `/`.
let mut bytes = bytes; // the remaining bytes to process
let mut stop = false;
while !stop {
@@ -396,6 +396,25 @@ fn emulate_foreign_item_inner(
let last_error = this.get_last_error()?;
this.write_scalar(last_error, dest)?;
}
+ "RtlNtStatusToDosError" => {
+ let [status] = this.check_shim(abi, sys_conv, link_name, args)?;
+ let status = this.read_scalar(status)?.to_u32()?;
+ let err = match status {
+ // STATUS_MEDIA_WRITE_PROTECTED => ERROR_WRITE_PROTECT
+ 0xC00000A2 => 19,
+ // STATUS_FILE_INVALID => ERROR_FILE_INVALID
+ 0xC0000098 => 1006,
+ // STATUS_DISK_FULL => ERROR_DISK_FULL
+ 0xC000007F => 112,
+ // STATUS_IO_DEVICE_ERROR => ERROR_IO_DEVICE
+ 0xC0000185 => 1117,
+ // STATUS_ACCESS_DENIED => ERROR_ACCESS_DENIED
+ 0xC0000022 => 5,
+ // Anything without an error code => ERROR_MR_MID_NOT_FOUND
+ _ => 317,
+ };
+ this.write_scalar(Scalar::from_i32(err), dest)?;
+ }
// Querying system information
"GetSystemInfo" => {
diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock
index 24a8efc..276c518 100644
--- a/src/tools/miri/test_dependencies/Cargo.lock
+++ b/src/tools/miri/test_dependencies/Cargo.lock
@@ -156,9 +156,9 @@
[[package]]
name = "miniz_oxide"
-version = "0.8.7"
+version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
+checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [
"adler2",
]
diff --git a/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr b/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr
index aadb997..1dcdb4a 100644
--- a/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr
+++ b/src/tools/miri/tests/fail/panic/tls_macro_const_drop_panic.stderr
@@ -1,7 +1,7 @@
thread $NAME panicked at tests/fail/panic/tls_macro_const_drop_panic.rs:LL:CC:
ow
-fatal runtime error: thread local panicked on drop
+fatal runtime error: thread local panicked on drop, aborting
error: abnormal termination: the program aborted execution
error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr
index 546ee7e..7e4907a 100644
--- a/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr
+++ b/src/tools/miri/tests/fail/panic/tls_macro_drop_panic.stderr
@@ -1,7 +1,7 @@
thread $NAME panicked at tests/fail/panic/tls_macro_drop_panic.rs:LL:CC:
ow
-fatal runtime error: thread local panicked on drop
+fatal runtime error: thread local panicked on drop, aborting
error: abnormal termination: the program aborted execution
error: aborting due to 1 previous error
diff --git a/src/tools/miri/tests/fail/read_from_trivial_switch.rs b/src/tools/miri/tests/fail/read_from_trivial_switch.rs
new file mode 100644
index 0000000..d34b1cd
--- /dev/null
+++ b/src/tools/miri/tests/fail/read_from_trivial_switch.rs
@@ -0,0 +1,14 @@
+// Ensure that we don't optimize out `SwitchInt` reads even if that terminator
+// branches to the same basic block on every target, since the operand may have
+// side-effects that affect analysis of the MIR.
+//
+// See <https://github.com/rust-lang/miri/issues/4237>.
+
+use std::mem::MaybeUninit;
+
+fn main() {
+ let uninit: MaybeUninit<i32> = MaybeUninit::uninit();
+ let bad_ref: &i32 = unsafe { uninit.assume_init_ref() };
+ let &(0 | _) = bad_ref;
+ //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+}
diff --git a/src/tools/miri/tests/fail/read_from_trivial_switch.stderr b/src/tools/miri/tests/fail/read_from_trivial_switch.stderr
new file mode 100644
index 0000000..6b3d453
--- /dev/null
+++ b/src/tools/miri/tests/fail/read_from_trivial_switch.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory
+ --> tests/fail/read_from_trivial_switch.rs:LL:CC
+ |
+LL | let &(0 | _) = bad_ref;
+ | ^^^^^^^^ using uninitialized data, but this operation requires initialized memory
+ |
+ = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+ = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+ = note: BACKTRACE:
+ = note: inside `main` at tests/fail/read_from_trivial_switch.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
index 312df9e..a015464 100644
--- a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
+++ b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs
@@ -10,7 +10,9 @@
mod utils;
use windows_sys::Win32::Foundation::{
- CloseHandle, ERROR_ALREADY_EXISTS, GENERIC_READ, GENERIC_WRITE, GetLastError,
+ CloseHandle, ERROR_ACCESS_DENIED, ERROR_ALREADY_EXISTS, ERROR_IO_DEVICE, GENERIC_READ,
+ GENERIC_WRITE, GetLastError, RtlNtStatusToDosError, STATUS_ACCESS_DENIED,
+ STATUS_IO_DEVICE_ERROR,
};
use windows_sys::Win32::Storage::FileSystem::{
BY_HANDLE_FILE_INFORMATION, CREATE_ALWAYS, CREATE_NEW, CreateFileW, FILE_ATTRIBUTE_DIRECTORY,
@@ -26,6 +28,7 @@ fn main() {
test_create_always_twice();
test_open_always_twice();
test_open_dir_reparse();
+ test_ntstatus_to_dos();
}
}
@@ -191,6 +194,12 @@ unsafe fn test_open_dir_reparse() {
};
}
+unsafe fn test_ntstatus_to_dos() {
+ // We won't test all combinations, just a couple common ones
+ assert_eq!(RtlNtStatusToDosError(STATUS_IO_DEVICE_ERROR), ERROR_IO_DEVICE);
+ assert_eq!(RtlNtStatusToDosError(STATUS_ACCESS_DENIED), ERROR_ACCESS_DENIED);
+}
+
fn to_wide_cstr(path: &Path) -> Vec<u16> {
let mut raw_path = path.as_os_str().encode_wide().collect::<Vec<_>>();
raw_path.extend([0, 0]);
diff --git a/src/tools/miri/tests/pass/fn_align.rs b/src/tools/miri/tests/pass/fn_align.rs
new file mode 100644
index 0000000..550bb1c
--- /dev/null
+++ b/src/tools/miri/tests/pass/fn_align.rs
@@ -0,0 +1,21 @@
+//@compile-flags: -Zmin-function-alignment=8
+#![feature(fn_align)]
+
+// When a function uses `repr(align(N))`, the function address should be a multiple of `N`.
+
+#[repr(align(256))]
+fn foo() {}
+
+#[repr(align(16))]
+fn bar() {}
+
+#[repr(align(4))]
+fn baz() {}
+
+fn main() {
+ assert!((foo as usize).is_multiple_of(256));
+ assert!((bar as usize).is_multiple_of(16));
+
+ // The maximum of `repr(align(N))` and `-Zmin-function-alignment=N` is used.
+ assert!((baz as usize).is_multiple_of(8));
+}
diff --git a/src/tools/miri/tests/pass/issues/issue-134713-swap_nonoverlapping_untyped.rs b/src/tools/miri/tests/pass/issues/issue-134713-swap_nonoverlapping_untyped.rs
index a1da60c..27ea123 100644
--- a/src/tools/miri/tests/pass/issues/issue-134713-swap_nonoverlapping_untyped.rs
+++ b/src/tools/miri/tests/pass/issues/issue-134713-swap_nonoverlapping_untyped.rs
@@ -1,4 +1,4 @@
-use std::mem::{size_of, align_of};
+use std::mem::{align_of, size_of};
// See <https://github.com/rust-lang/rust/issues/134713>
diff --git a/src/tools/miri/tests/pass/issues/issue-139553.rs b/src/tools/miri/tests/pass/issues/issue-139553.rs
new file mode 100644
index 0000000..119d589
--- /dev/null
+++ b/src/tools/miri/tests/pass/issues/issue-139553.rs
@@ -0,0 +1,45 @@
+//@compile-flags: -Zmiri-preemption-rate=0 -Zmiri-compare-exchange-weak-failure-rate=0
+use std::sync::mpsc::channel;
+use std::thread;
+
+/// This test aims to trigger a race condition that causes a double free in the unbounded channel
+/// implementation. The test relies on a particular thread scheduling to happen as annotated by the
+/// comments below.
+fn main() {
+ let (s1, r) = channel::<u64>();
+ let s2 = s1.clone();
+
+ let t1 = thread::spawn(move || {
+ // 1. The first action executed is an attempt to send the first value in the channel. This
+ // will begin to initialize the channel but will stop at a critical momement as
+ // indicated by the `yield_now()` call in the `start_send` method of the implementation.
+ let _ = s1.send(42);
+ // 4. The sender is re-scheduled and it finishes the initialization of the channel by
+ // setting head.block to the same value as tail.block. It then proceeds to publish its
+ // value but observes that the channel has already disconnected (due to the concurrent
+ // call of `discard_all_messages`) and aborts the send.
+ });
+ std::thread::yield_now();
+
+ // 2. A second sender attempts to send a value while the channel is in a half-initialized
+ // state. Here, half-initialized means that the `tail.block` pointer points to a valid block
+ // but `head.block` is still null. This condition is ensured by the yield of step 1. When
+ // this call returns the channel state has tail.index != head.index, tail.block != NULL, and
+ // head.block = NULL.
+ s2.send(42).unwrap();
+ // 3. This thread continues with dropping the one and only receiver. When all receivers are
+ // gone `discard_all_messages` will attempt to drop all currently sent values and
+ // de-allocate all the blocks. If `tail.block != NULL` but `head.block = NULL` the
+ // implementation waits for the initializing sender to finish by spinning/yielding.
+ drop(r);
+ // 5. This thread is rescheduled and `discard_all_messages` observes the head.block pointer set
+ // by step 4 and proceeds with deallocation. In the problematic version of the code
+ // `head.block` is simply read via an `Acquire` load and not swapped with NULL. After this
+ // call returns the channel state has tail.index = head.index, tail.block = NULL, and
+ // head.block != NULL.
+ t1.join().unwrap();
+ // 6. The last sender (s2) is dropped here which also attempts to cleanup any data in the
+ // channel. It observes `tail.index = head.index` and so it doesn't attempt to cleanup any
+ // messages but it also observes that `head.block != NULL` and attempts to deallocate it.
+ // This is however already deallocated by `discard_all_messages`, leading to a double free.
+}
diff --git a/src/tools/miri/tests/pass/tls/tls_leak_main_thread_allowed.rs b/src/tools/miri/tests/pass/tls/tls_leak_main_thread_allowed.rs
index 341b228..abc0968 100644
--- a/src/tools/miri/tests/pass/tls/tls_leak_main_thread_allowed.rs
+++ b/src/tools/miri/tests/pass/tls/tls_leak_main_thread_allowed.rs
@@ -13,7 +13,7 @@ pub fn main() {
TLS.set(Some(Box::leak(Box::new(123))));
// We can only ignore leaks on targets that use `#[thread_local]` statics to implement
- // `thread_local!`. Ignore the test on targest that don't.
+ // `thread_local!`. Ignore the test on targets that don't.
if cfg!(target_thread_local) {
thread_local! {
static TLS_KEY: Cell<Option<&'static i32>> = Cell::new(None);
diff --git a/src/tools/nix-dev-shell/flake.nix b/src/tools/nix-dev-shell/flake.nix
index 1b838bd..b8287de 100644
--- a/src/tools/nix-dev-shell/flake.nix
+++ b/src/tools/nix-dev-shell/flake.nix
@@ -1,32 +1,24 @@
{
description = "rustc dev shell";
- inputs = {
- nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
- flake-utils.url = "github:numtide/flake-utils";
- };
+ inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
- outputs = { self, nixpkgs, flake-utils, ... }:
- flake-utils.lib.eachDefaultSystem (system:
- let
- pkgs = import nixpkgs { inherit system; };
- x = import ./x { inherit pkgs; };
- in
- {
- devShells.default = with pkgs; mkShell {
- name = "rustc-dev-shell";
- nativeBuildInputs = with pkgs; [
- binutils cmake ninja pkg-config python3 git curl cacert patchelf nix
- ];
- buildInputs = with pkgs; [
- openssl glibc.out glibc.static x
- ];
- # Avoid creating text files for ICEs.
- RUSTC_ICE = "0";
- # Provide `libstdc++.so.6` for the self-contained lld.
- # Provide `libz.so.1`.
- LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [stdenv.cc.cc.lib zlib]}";
- };
- }
- );
+ outputs =
+ {
+ self,
+ nixpkgs,
+ }:
+ let
+ inherit (nixpkgs) lib;
+ forEachSystem = lib.genAttrs lib.systems.flakeExposed;
+ in
+ {
+ devShells = forEachSystem (system: {
+ default = nixpkgs.legacyPackages.${system}.callPackage ./shell.nix { };
+ });
+
+ packages = forEachSystem (system: {
+ default = nixpkgs.legacyPackages.${system}.callPackage ./x { };
+ });
+ };
}
diff --git a/src/tools/nix-dev-shell/shell.nix b/src/tools/nix-dev-shell/shell.nix
index a3f5969..0adbacf 100644
--- a/src/tools/nix-dev-shell/shell.nix
+++ b/src/tools/nix-dev-shell/shell.nix
@@ -1,18 +1,26 @@
-{ pkgs ? import <nixpkgs> {} }:
-let
- x = import ./x { inherit pkgs; };
+{
+ pkgs ? import <nixpkgs> { },
+}:
+let
+ inherit (pkgs.lib) lists attrsets;
+
+ x = pkgs.callPackage ./x { };
+ inherit (x.passthru) cacert env;
in
pkgs.mkShell {
- name = "rustc";
- nativeBuildInputs = with pkgs; [
- binutils cmake ninja pkg-config python3 git curl cacert patchelf nix
- ];
- buildInputs = with pkgs; [
- openssl glibc.out glibc.static x
- ];
- # Avoid creating text files for ICEs.
- RUSTC_ICE = "0";
- # Provide `libstdc++.so.6` for the self-contained lld.
- # Provide `libz.so.1`
- LD_LIBRARY_PATH = "${with pkgs; lib.makeLibraryPath [stdenv.cc.cc.lib zlib]}";
+ name = "rustc-shell";
+
+ inputsFrom = [ x ];
+ packages = [
+ pkgs.git
+ pkgs.nix
+ x
+ # Get the runtime deps of the x wrapper
+ ] ++ lists.flatten (attrsets.attrValues env);
+
+ env = {
+ # Avoid creating text files for ICEs.
+ RUSTC_ICE = 0;
+ SSL_CERT_FILE = cacert;
+ };
}
diff --git a/src/tools/nix-dev-shell/x/default.nix b/src/tools/nix-dev-shell/x/default.nix
index e6dfbad..422c1c4 100644
--- a/src/tools/nix-dev-shell/x/default.nix
+++ b/src/tools/nix-dev-shell/x/default.nix
@@ -1,22 +1,83 @@
{
- pkgs ? import <nixpkgs> { },
+ pkgs,
+ lib,
+ stdenv,
+ rustc,
+ python3,
+ makeBinaryWrapper,
+ # Bootstrap
+ curl,
+ pkg-config,
+ libiconv,
+ openssl,
+ patchelf,
+ cacert,
+ zlib,
+ # LLVM Deps
+ ninja,
+ cmake,
+ glibc,
}:
-pkgs.stdenv.mkDerivation {
- name = "x";
+stdenv.mkDerivation (self: {
+ strictDeps = true;
+ name = "x-none";
+
+ outputs = [
+ "out"
+ "unwrapped"
+ ];
src = ./x.rs;
dontUnpack = true;
- nativeBuildInputs = with pkgs; [ rustc ];
+ nativeBuildInputs = [
+ rustc
+ makeBinaryWrapper
+ ];
+ env.PYTHON = python3.interpreter;
buildPhase = ''
- PYTHON=${pkgs.lib.getExe pkgs.python3} rustc -Copt-level=3 --crate-name x $src --out-dir $out/bin
+ rustc -Copt-level=3 --crate-name x $src --out-dir $unwrapped/bin
'';
- meta = with pkgs.lib; {
+ installPhase =
+ let
+ inherit (self.passthru) cacert env;
+ in
+ ''
+ makeWrapper $unwrapped/bin/x $out/bin/x \
+ --set-default SSL_CERT_FILE ${cacert} \
+ --prefix CPATH ";" "${lib.makeSearchPath "include" env.cpath}" \
+ --prefix PATH : ${lib.makeBinPath env.path} \
+ --prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath env.ldLib}
+ '';
+
+ # For accessing them in the devshell
+ passthru = {
+ env = {
+ cpath = [ libiconv ];
+ path = [
+ python3
+ patchelf
+ curl
+ pkg-config
+ cmake
+ ninja
+ stdenv.cc
+ ];
+ ldLib = [
+ openssl
+ zlib
+ stdenv.cc.cc.lib
+ ];
+ };
+ cacert = "${cacert}/etc/ssl/certs/ca-bundle.crt";
+ };
+
+ meta = {
description = "Helper for rust-lang/rust x.py";
homepage = "https://github.com/rust-lang/rust/blob/master/src/tools/x";
- license = licenses.mit;
+ license = lib.licenses.mit;
mainProgram = "x";
};
-}
+})
diff --git a/src/tools/opt-dist/src/environment.rs b/src/tools/opt-dist/src/environment.rs
index 90d0ca7..9342d16 100644
--- a/src/tools/opt-dist/src/environment.rs
+++ b/src/tools/opt-dist/src/environment.rs
@@ -25,6 +25,7 @@ pub struct Environment {
prebuilt_rustc_perf: Option<Utf8PathBuf>,
use_bolt: bool,
shared_llvm: bool,
+ run_tests: bool,
}
impl Environment {
@@ -101,6 +102,10 @@ pub fn skipped_tests(&self) -> &[String] {
pub fn benchmark_cargo_config(&self) -> &[String] {
&self.benchmark_cargo_config
}
+
+ pub fn run_tests(&self) -> bool {
+ self.run_tests
+ }
}
/// What is the extension of binary executables on this platform?
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index ac5d294..d5e6640 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -76,7 +76,7 @@ enum EnvironmentCmd {
rustc_perf_checkout_dir: Option<Utf8PathBuf>,
/// Is LLVM for `rustc` built in shared library mode?
- #[arg(long, default_value_t = true)]
+ #[arg(long, default_value_t = true, action(clap::ArgAction::Set))]
llvm_shared: bool,
/// Should BOLT optimization be used? If yes, host LLVM must have BOLT binaries
@@ -94,6 +94,10 @@ enum EnvironmentCmd {
/// Arguments passed to `rustc-perf --cargo-config <value>` when running benchmarks.
#[arg(long)]
benchmark_cargo_config: Vec<String>,
+
+ /// Perform tests after final build if it's not a try build
+ #[arg(long)]
+ run_tests: bool,
},
/// Perform an optimized build on Linux CI, from inside Docker.
LinuxCi {
@@ -125,6 +129,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
skipped_tests,
benchmark_cargo_config,
shared,
+ run_tests,
} => {
let env = EnvironmentBuilder::default()
.host_tuple(target_triple)
@@ -138,6 +143,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
.use_bolt(use_bolt)
.skipped_tests(skipped_tests)
.benchmark_cargo_config(benchmark_cargo_config)
+ .run_tests(run_tests)
.build()?;
(env, shared.build_args)
@@ -160,6 +166,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
// FIXME: Enable bolt for aarch64 once it's fixed upstream. Broken as of December 2024.
.use_bolt(!is_aarch64)
.skipped_tests(vec![])
+ .run_tests(true)
.build()?;
(env, shared.build_args)
@@ -179,6 +186,7 @@ fn create_environment(args: Args) -> anyhow::Result<(Environment, Vec<String>)>
.shared_llvm(false)
.use_bolt(false)
.skipped_tests(vec![])
+ .run_tests(true)
.build()?;
(env, shared.build_args)
@@ -344,7 +352,7 @@ fn execute_pipeline(
// possible regressions.
// The tests are not executed for try builds, which can be in various broken states, so we don't
// want to gatekeep them with tests.
- if !is_try_build() {
+ if !is_try_build() && env.run_tests() {
timer.section("Run tests", |_| run_tests(env))?;
}
diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs
index 30c79f9..47159a4 100644
--- a/src/tools/opt-dist/src/training.rs
+++ b/src/tools/opt-dist/src/training.rs
@@ -70,7 +70,9 @@ fn merge_llvm_profiles(
profdata: LlvmProfdata,
) -> anyhow::Result<()> {
let llvm_profdata = match profdata {
- LlvmProfdata::Host => env.host_llvm_dir().join("bin/llvm-profdata"),
+ LlvmProfdata::Host => {
+ env.host_llvm_dir().join(format!("bin/llvm-profdata{}", executable_extension()))
+ }
LlvmProfdata::Target => env
.build_artifacts()
.join("llvm")
diff --git a/src/tools/opt-dist/src/utils/mod.rs b/src/tools/opt-dist/src/utils/mod.rs
index 32d88a5..fb4f14e 100644
--- a/src/tools/opt-dist/src/utils/mod.rs
+++ b/src/tools/opt-dist/src/utils/mod.rs
@@ -36,7 +36,9 @@ pub fn clear_llvm_files(env: &Environment) -> anyhow::Result<()> {
// directories ourselves.
log::info!("Clearing LLVM build files");
delete_directory(&env.build_artifacts().join("llvm"))?;
- delete_directory(&env.build_artifacts().join("lld"))?;
+ if env.build_artifacts().join("lld").is_dir() {
+ delete_directory(&env.build_artifacts().join("lld"))?;
+ }
Ok(())
}
diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml
index f9beffe..15ed03a 100644
--- a/src/tools/run-make-support/Cargo.toml
+++ b/src/tools/run-make-support/Cargo.toml
@@ -14,9 +14,5 @@
serde_json = "1.0"
libc = "0.2"
-# FIXME(#137532): replace `os_pipe` with `anonymous_pipe` once it stabilizes and
-# reaches beta.
-os_pipe = "1.2.1"
-
[lib]
crate-type = ["lib", "dylib"]
diff --git a/src/tools/run-make-support/src/artifact_names.rs b/src/tools/run-make-support/src/artifact_names.rs
index 8968f83..b0d588d 100644
--- a/src/tools/run-make-support/src/artifact_names.rs
+++ b/src/tools/run-make-support/src/artifact_names.rs
@@ -1,11 +1,11 @@
//! A collection of helpers to construct artifact names, such as names of dynamic or static
-//! librarys which are target-dependent.
+//! libraries which are target-dependent.
-// FIXME(jieyouxu): convert these to return `PathBuf`s instead of strings!
-
+use crate::target;
use crate::targets::is_msvc;
/// Construct the static library name based on the target.
+#[track_caller]
#[must_use]
pub fn static_lib_name(name: &str) -> String {
assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace");
@@ -14,15 +14,34 @@ pub fn static_lib_name(name: &str) -> String {
}
/// Construct the dynamic library name based on the target.
+#[track_caller]
#[must_use]
pub fn dynamic_lib_name(name: &str) -> String {
assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace");
- format!("{}{name}.{}", std::env::consts::DLL_PREFIX, std::env::consts::DLL_EXTENSION)
+ format!("{}{name}.{}", dynamic_lib_prefix(), dynamic_lib_extension())
}
-/// Construct the name of the import library for the dynamic library, exclusive to MSVC and
-/// accepted by link.exe.
+fn dynamic_lib_prefix() -> &'static str {
+ if target().contains("windows") { "" } else { "lib" }
+}
+
+/// Construct the dynamic library extension based on the target.
+#[must_use]
+pub fn dynamic_lib_extension() -> &'static str {
+ let target = target();
+
+ if target.contains("apple") {
+ "dylib"
+ } else if target.contains("windows") {
+ "dll"
+ } else {
+ "so"
+ }
+}
+
+/// Construct the name of the import library for the dynamic library, exclusive to MSVC and accepted
+/// by link.exe.
#[track_caller]
#[must_use]
pub fn msvc_import_dynamic_lib_name(name: &str) -> String {
@@ -32,20 +51,28 @@ pub fn msvc_import_dynamic_lib_name(name: &str) -> String {
format!("{name}.dll.lib")
}
-/// Construct the dynamic library extension based on the target.
-#[must_use]
-pub fn dynamic_lib_extension() -> &'static str {
- std::env::consts::DLL_EXTENSION
-}
-
/// Construct the name of a rust library (rlib).
+#[track_caller]
#[must_use]
pub fn rust_lib_name(name: &str) -> String {
format!("lib{name}.rlib")
}
/// Construct the binary (executable) name based on the target.
+#[track_caller]
#[must_use]
pub fn bin_name(name: &str) -> String {
- format!("{name}{}", std::env::consts::EXE_SUFFIX)
+ let target = target();
+
+ if target.contains("windows") {
+ format!("{name}.exe")
+ } else if target.contains("uefi") {
+ format!("{name}.efi")
+ } else if target.contains("wasm") {
+ format!("{name}.wasm")
+ } else if target.contains("nvptx") {
+ format!("{name}.ptx")
+ } else {
+ name.to_string()
+ }
}
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index c75d500..f37b38a 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -41,8 +41,6 @@ pub mod rfs {
pub use gimli;
pub use libc;
pub use object;
-// FIXME(#137532): replace with std `anonymous_pipe` once it stabilizes and reaches beta.
-pub use os_pipe;
pub use regex;
pub use serde_json;
pub use similar;
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 745a809..2dbb3f5 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -902,9 +902,9 @@
[[package]]
name = "libc"
-version = "0.2.169"
+version = "0.2.172"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
+checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
[[package]]
name = "libloading"
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
index 0a7a7d1..706d044 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
@@ -3795,35 +3795,6 @@ fn main() {
deny_since: None,
},
Lint {
- label: "cfg_boolean_literals",
- description: r##"# `cfg_boolean_literals`
-
-The tracking issue for this feature is: [#131204]
-
-[#131204]: https://github.com/rust-lang/rust/issues/131204
-
-------------------------
-
-The `cfg_boolean_literals` feature makes it possible to use the `true`/`false`
-literal as cfg predicate. They always evaluate to true/false respectively.
-
-## Examples
-
-```rust
-#![feature(cfg_boolean_literals)]
-
-#[cfg(true)]
-const A: i32 = 5;
-
-#[cfg(all(false))]
-const A: i32 = 58 * 89;
-```
-"##,
- default_severity: Severity::Allow,
- warn_since: None,
- deny_since: None,
- },
- Lint {
label: "cfg_eval",
description: r##"# `cfg_eval`
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
index 59293ee..80f6d85 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
@@ -11,7 +11,7 @@
use intern::Symbol;
use proc_macro::bridge::{self, server};
-use span::{FileId, Span, FIXUP_ERASED_FILE_AST_ID_MARKER};
+use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER};
use tt::{TextRange, TextSize};
use crate::server_impl::{literal_kind_to_internal, token_stream::TokenStreamBuilder, TopSubtree};
@@ -27,10 +27,6 @@ mod tt {
type TokenStream = crate::server_impl::TokenStream<Span>;
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub struct SourceFile {
- file_id: FileId,
-}
pub struct FreeFunctions;
pub struct RaSpanServer {
@@ -46,7 +42,6 @@ pub struct RaSpanServer {
impl server::Types for RaSpanServer {
type FreeFunctions = FreeFunctions;
type TokenStream = TokenStream;
- type SourceFile = SourceFile;
type Span = Span;
type Symbol = Symbol;
}
@@ -245,25 +240,17 @@ fn into_trees(
}
}
-impl server::SourceFile for RaSpanServer {
- fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
- file1 == file2
- }
- fn path(&mut self, _file: &Self::SourceFile) -> String {
- // FIXME
- String::new()
- }
- fn is_real(&mut self, _file: &Self::SourceFile) -> bool {
- true
- }
-}
-
impl server::Span for RaSpanServer {
fn debug(&mut self, span: Self::Span) -> String {
format!("{:?}", span)
}
- fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
- SourceFile { file_id: span.anchor.file_id.file_id() }
+ fn file(&mut self, _: Self::Span) -> String {
+ // FIXME
+ String::new()
+ }
+ fn local_file(&mut self, _: Self::Span) -> Option<String> {
+ // FIXME
+ None
}
fn save_span(&mut self, _span: Self::Span) -> usize {
// FIXME, quote is incompatible with third-party tools
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
index 409cf3c..4d7c7c4 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
@@ -24,8 +24,6 @@ mod tt {
type Span = tt::TokenId;
type TokenStream = crate::server_impl::TokenStream<Span>;
-#[derive(Clone)]
-pub struct SourceFile;
pub struct FreeFunctions;
pub struct TokenIdServer {
@@ -37,7 +35,6 @@ pub struct TokenIdServer {
impl server::Types for TokenIdServer {
type FreeFunctions = FreeFunctions;
type TokenStream = TokenStream;
- type SourceFile = SourceFile;
type Span = Span;
type Symbol = Symbol;
}
@@ -223,24 +220,15 @@ fn into_trees(
}
}
-impl server::SourceFile for TokenIdServer {
- fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool {
- true
- }
- fn path(&mut self, _file: &Self::SourceFile) -> String {
- String::new()
- }
- fn is_real(&mut self, _file: &Self::SourceFile) -> bool {
- true
- }
-}
-
impl server::Span for TokenIdServer {
fn debug(&mut self, span: Self::Span) -> String {
format!("{:?}", span.0)
}
- fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile {
- SourceFile {}
+ fn file(&mut self, _span: Self::Span) -> String {
+ String::new()
+ }
+ fn local_file(&mut self, _span: Self::Span) -> Option<String> {
+ None
}
fn save_span(&mut self, _span: Self::Span) -> usize {
0
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
index 15de88e..4bd365b 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
@@ -97,6 +97,7 @@ fn test_fn_like_macro_clone_raw_ident() {
}
#[test]
+#[cfg(not(bootstrap))]
fn test_fn_like_fn_like_span_join() {
assert_expand(
"fn_like_span_join",
@@ -111,6 +112,7 @@ fn test_fn_like_fn_like_span_join() {
}
#[test]
+#[cfg(not(bootstrap))]
fn test_fn_like_fn_like_span_ops() {
assert_expand(
"fn_like_span_ops",
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 09bbbd6..fb58410 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -139,9 +139,9 @@
[[package]]
name = "bstr"
-version = "1.11.3"
+version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "531a9155a481e2ee699d4f98f43c0ca4ff8ee1bfd55c31e9e98fb29d2b176fe0"
+checksum = "234113d19d0d7d613b40e86fb654acf958910802bcceab913a4f9e7cda03b1a4"
dependencies = [
"memchr",
"regex-automata",
@@ -156,9 +156,9 @@
[[package]]
name = "cc"
-version = "1.2.18"
+version = "1.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
+checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362"
dependencies = [
"shlex",
]
@@ -185,9 +185,9 @@
[[package]]
name = "clap"
-version = "4.5.35"
+version = "4.5.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8aa86934b44c19c50f87cc2790e19f54f7a67aedb64101c2e1a2e5ecfb73944"
+checksum = "2df961d8c8a0d08aa9945718ccf584145eee3f3aa06cddbeac12933781102e04"
dependencies = [
"clap_builder",
"clap_derive",
@@ -195,9 +195,9 @@
[[package]]
name = "clap_builder"
-version = "4.5.35"
+version = "4.5.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2414dbb2dd0695280da6ea9261e327479e9d37b0630f6b53ba2a11c60c679fd9"
+checksum = "132dbda40fb6753878316a489d5a1242a8ef2f0d9e47ba01c951ea8aa7d013a5"
dependencies = [
"anstream",
"anstyle",
@@ -775,9 +775,9 @@
[[package]]
name = "jiff"
-version = "0.2.5"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c102670231191d07d37a35af3eb77f1f0dbf7a71be51a962dcd57ea607be7260"
+checksum = "1f33145a5cbea837164362c7bd596106eb7c5198f97d1ba6f6ebb3223952e488"
dependencies = [
"jiff-static",
"log",
@@ -788,9 +788,9 @@
[[package]]
name = "jiff-static"
-version = "0.2.5"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cdde31a9d349f1b1f51a0b3714a5940ac022976f4b49485fc04be052b183b4c"
+checksum = "43ce13c40ec6956157a3635d97a1ee2df323b263f09ea14165131289cb0f5c19"
dependencies = [
"proc-macro2",
"quote",
@@ -840,9 +840,9 @@
[[package]]
name = "linux-raw-sys"
-version = "0.9.3"
+version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe7db12097d22ec582439daf8618b8fdd1a7bef6270e9af3b1ebcd30893cf413"
+checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
[[package]]
name = "litemap"
@@ -951,6 +951,7 @@
"once_cell",
"pathdiff",
"pulldown-cmark 0.10.3",
+ "railroad",
"regex",
"semver",
"serde_json",
@@ -981,9 +982,9 @@
[[package]]
name = "miniz_oxide"
-version = "0.8.7"
+version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430"
+checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a"
dependencies = [
"adler2",
]
@@ -1301,6 +1302,15 @@
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
[[package]]
+name = "railroad"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ecedffc46c1b2cb04f4b80e094eae6b3f3f470a9635f1f396dd5206428f6b58"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2012,9 +2022,9 @@
[[package]]
name = "winnow"
-version = "0.7.4"
+version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36"
+checksum = "63d3fcd9bba44b03821e7d699eeee959f3126dcc4aa8e4ae18ec617c2a5cea10"
dependencies = [
"memchr",
]
diff --git a/src/tools/rustdoc-gui-test/Cargo.toml b/src/tools/rustdoc-gui-test/Cargo.toml
index f7384a9..8d958ac 100644
--- a/src/tools/rustdoc-gui-test/Cargo.toml
+++ b/src/tools/rustdoc-gui-test/Cargo.toml
@@ -5,6 +5,7 @@
[dependencies]
build_helper = { path = "../../build_helper" }
+camino = "1"
compiletest = { path = "../compiletest" }
getopts = "0.2"
walkdir = "2"
diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs
index f1c6e13..addb0af 100644
--- a/src/tools/rustdoc-gui-test/src/main.rs
+++ b/src/tools/rustdoc-gui-test/src/main.rs
@@ -118,7 +118,11 @@ fn main() -> Result<(), ()> {
..Default::default()
};
- let test_props = TestProps::from_file(&librs, None, &compiletest_c);
+ let test_props = TestProps::from_file(
+ &camino::Utf8PathBuf::try_from(librs).unwrap(),
+ None,
+ &compiletest_c,
+ );
if !test_props.compile_flags.is_empty() {
cargo.env("RUSTDOCFLAGS", test_props.compile_flags.join(" "));
diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs
index ddf3d2c..0ff0aad 100644
--- a/src/tools/rustfmt/src/macros.rs
+++ b/src/tools/rustfmt/src/macros.rs
@@ -722,7 +722,7 @@ fn last_tok(tt: &TokenTree) -> Token {
match *tt {
TokenTree::Token(ref t, _) => t.clone(),
TokenTree::Delimited(delim_span, _, delim, _) => Token {
- kind: TokenKind::CloseDelim(delim),
+ kind: delim.as_open_token_kind(),
span: delim_span.close,
},
}
@@ -858,18 +858,18 @@ fn add_repeat(
};
self.result.push(ParsedMacroArg {
- kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok.clone()),
+ kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok),
});
Some(())
}
- fn update_buffer(&mut self, t: &Token) {
+ fn update_buffer(&mut self, t: Token) {
if self.buf.is_empty() {
- self.start_tok = t.clone();
+ self.start_tok = t;
} else {
let needs_space = match next_space(&self.last_tok.kind) {
- SpaceState::Ident => ident_like(t),
- SpaceState::Punctuation => !ident_like(t),
+ SpaceState::Ident => ident_like(&t),
+ SpaceState::Punctuation => !ident_like(&t),
SpaceState::Always => true,
SpaceState::Never => false,
};
@@ -878,7 +878,7 @@ fn update_buffer(&mut self, t: &Token) {
}
}
- self.buf.push_str(&pprust::token_to_string(t));
+ self.buf.push_str(&pprust::token_to_string(&t));
}
fn need_space_prefix(&self) -> bool {
@@ -937,7 +937,7 @@ fn parse(mut self, tokens: TokenStream) -> Option<Vec<ParsedMacroArg>> {
) if self.is_meta_var => {
self.add_meta_variable(&mut iter)?;
}
- TokenTree::Token(ref t, _) => self.update_buffer(t),
+ &TokenTree::Token(t, _) => self.update_buffer(t),
&TokenTree::Delimited(_dspan, _spacing, delimited, ref tts) => {
if !self.buf.is_empty() {
if next_space(&self.last_tok.kind) == SpaceState::Always {
@@ -1124,8 +1124,14 @@ fn next_space(tok: &TokenKind) -> SpaceState {
TokenKind::PathSep
| TokenKind::Pound
| TokenKind::Dollar
- | TokenKind::OpenDelim(_)
- | TokenKind::CloseDelim(_) => SpaceState::Never,
+ | TokenKind::OpenParen
+ | TokenKind::CloseParen
+ | TokenKind::OpenBrace
+ | TokenKind::CloseBrace
+ | TokenKind::OpenBracket
+ | TokenKind::CloseBracket
+ | TokenKind::OpenInvisible(_)
+ | TokenKind::CloseInvisible(_) => SpaceState::Never,
TokenKind::Literal(..) | TokenKind::Ident(..) | TokenKind::Lifetime(..) => {
SpaceState::Ident
diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs
index 0b7b6c4..30b8337 100644
--- a/src/tools/rustfmt/src/parse/macros/cfg_if.rs
+++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs
@@ -1,7 +1,7 @@
use std::panic::{AssertUnwindSafe, catch_unwind};
use rustc_ast::ast;
-use rustc_ast::token::{Delimiter, TokenKind};
+use rustc_ast::token::TokenKind;
use rustc_parse::exp;
use rustc_parse::parser::ForceCollect;
use rustc_span::symbol::kw;
@@ -60,9 +60,7 @@ fn parse_cfg_if_inner<'a>(
return Err("Expected an opening brace");
}
- while parser.token != TokenKind::CloseDelim(Delimiter::Brace)
- && parser.token.kind != TokenKind::Eof
- {
+ while parser.token != TokenKind::CloseBrace && parser.token.kind != TokenKind::Eof {
let item = match parser.parse_item(ForceCollect::No) {
Ok(Some(item_ptr)) => item_ptr.into_inner(),
Ok(None) => continue,
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index bf3b411..dd7f9c6 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -132,15 +132,16 @@
("fiat-crypto", "MIT OR Apache-2.0 OR BSD-1-Clause"),
("foldhash", "Zlib"),
("im-rc", "MPL-2.0+"),
+ ("libz-rs-sys", "Zlib"),
("normalize-line-endings", "Apache-2.0"),
("openssl", "Apache-2.0"),
("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0
- ("sha1_smol", "BSD-3-Clause"),
("similar", "Apache-2.0"),
("sized-chunks", "MPL-2.0+"),
("subtle", "BSD-3-Clause"),
("supports-hyperlinks", "Apache-2.0"),
("unicode-bom", "Apache-2.0"),
+ ("zlib-rs", "Zlib"),
// tidy-alphabetical-end
];
@@ -259,7 +260,6 @@
"constant_time_eq",
"cpufeatures",
"crc32fast",
- "crossbeam-channel",
"crossbeam-deque",
"crossbeam-epoch",
"crossbeam-utils",
@@ -269,7 +269,6 @@
"darling_core",
"darling_macro",
"datafrog",
- "deranged",
"derive-where",
"derive_setters",
"digest",
@@ -295,7 +294,6 @@
"gimli",
"gsgdt",
"hashbrown",
- "hermit-abi",
"icu_list",
"icu_list_data",
"icu_locid",
@@ -310,6 +308,8 @@
"intl_pluralrules",
"itertools",
"itoa",
+ "jiff",
+ "jiff-static",
"jobserver",
"lazy_static",
"leb128",
@@ -327,8 +327,6 @@
"miniz_oxide",
"nix",
"nu-ansi-term",
- "num-conv",
- "num_cpus",
"object",
"odht",
"once_cell",
@@ -340,7 +338,7 @@
"pin-project-lite",
"polonius-engine",
"portable-atomic", // dependency for platforms doesn't support `AtomicU64` in std
- "powerfmt",
+ "portable-atomic-util",
"ppv-lite86",
"proc-macro-hack",
"proc-macro2",
@@ -393,9 +391,6 @@
"thorin-dwp",
"thread_local",
"tikv-jemalloc-sys",
- "time",
- "time-core",
- "time-macros",
"tinystr",
"tinyvec",
"tinyvec_macros",
@@ -685,8 +680,10 @@ fn check_proc_macro_dep_list(root: &Path, cargo: &Path, bless: bool, bad: &mut b
pub fn has_missing_submodule(root: &Path, submodules: &[&str]) -> bool {
!CiEnv::is_ci()
&& submodules.iter().any(|submodule| {
+ let path = root.join(submodule);
+ !path.exists()
// If the directory is empty, we can consider it as an uninitialized submodule.
- read_dir(root.join(submodule)).unwrap().next().is_none()
+ || read_dir(path).unwrap().next().is_none()
})
}
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index d2ae9b1..f1ce3cc 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -1397,7 +1397,6 @@
ui/issues/auxiliary/issue-13620-2.rs
ui/issues/auxiliary/issue-14344-1.rs
ui/issues/auxiliary/issue-14344-2.rs
-ui/issues/auxiliary/issue-14421.rs
ui/issues/auxiliary/issue-14422.rs
ui/issues/auxiliary/issue-15562.rs
ui/issues/auxiliary/issue-16643.rs
@@ -1564,7 +1563,6 @@
ui/issues/issue-14382.rs
ui/issues/issue-14393.rs
ui/issues/issue-14399.rs
-ui/issues/issue-14421.rs
ui/issues/issue-14422.rs
ui/issues/issue-14541.rs
ui/issues/issue-14721.rs
@@ -1629,7 +1627,6 @@
ui/issues/issue-16783.rs
ui/issues/issue-16819.rs
ui/issues/issue-16922-rpass.rs
-ui/issues/issue-16939.rs
ui/issues/issue-16966.rs
ui/issues/issue-16994.rs
ui/issues/issue-17001.rs
@@ -1867,7 +1864,6 @@
ui/issues/issue-23589.rs
ui/issues/issue-23699.rs
ui/issues/issue-2380-b.rs
-ui/issues/issue-23808.rs
ui/issues/issue-2383.rs
ui/issues/issue-23891.rs
ui/issues/issue-23898.rs
@@ -2607,7 +2603,6 @@
ui/issues/issue-9259.rs
ui/issues/issue-92741.rs
ui/issues/issue-9446.rs
-ui/issues/issue-9719.rs
ui/issues/issue-9725.rs
ui/issues/issue-9737.rs
ui/issues/issue-9814.rs
@@ -3138,7 +3133,6 @@
ui/nll/user-annotations/issue-55748-pat-types-constrain-bindings.rs
ui/nll/user-annotations/issue-57731-ascibed-coupled-types.rs
ui/numbers-arithmetic/issue-8460.rs
-ui/on-unimplemented/issue-104140.rs
ui/or-patterns/issue-64879-trailing-before-guard.rs
ui/or-patterns/issue-67514-irrefutable-param.rs
ui/or-patterns/issue-68785-irrefutable-param-with-at.rs
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 61728d0..2e069af 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -17,7 +17,7 @@
const ENTRY_LIMIT: u32 = 901;
// FIXME: The following limits should be reduced eventually.
-const ISSUES_ENTRY_LIMIT: u32 = 1631;
+const ISSUES_ENTRY_LIMIT: u32 = 1626;
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
"rs", // test source files
diff --git a/tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs b/tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs
index faff6e7..257608f 100644
--- a/tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs
+++ b/tests/assembly/auxiliary/dwarf-mixed-versions-lto-aux.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: -g --crate-type=rlib -Zdwarf-version=4
+//@ compile-flags: -g --crate-type=rlib -Cdwarf-version=4
pub fn check_is_even(number: &u64) -> bool {
number % 2 == 0
diff --git a/tests/assembly/cstring-merging.rs b/tests/assembly/cstring-merging.rs
index 07f25d1..f7d0775 100644
--- a/tests/assembly/cstring-merging.rs
+++ b/tests/assembly/cstring-merging.rs
@@ -1,3 +1,5 @@
+// MIPS assembler uses the label prefix `$anon.` for local anonymous variables
+// other architectures (including ARM and x86-64) use the prefix `.Lanon.`
//@ only-linux
//@ assembly-output: emit-asm
//@ compile-flags: --crate-type=lib -Copt-level=3
@@ -5,14 +7,14 @@
use std::ffi::CStr;
-// CHECK: .section .rodata.str1.1,"aMS"
-// CHECK: .Lanon.{{.+}}:
+// CHECK: .section .rodata.str1.{{[12]}},"aMS"
+// CHECK: {{(\.L|\$)}}anon.{{.+}}:
// CHECK-NEXT: .asciz "foo"
#[unsafe(no_mangle)]
static CSTR: &[u8; 4] = b"foo\0";
// CHECK-NOT: .section
-// CHECK: .Lanon.{{.+}}:
+// CHECK: {{(\.L|\$)}}anon.{{.+}}:
// CHECK-NEXT: .asciz "bar"
#[unsafe(no_mangle)]
pub fn cstr() -> &'static CStr {
@@ -20,7 +22,7 @@ pub fn cstr() -> &'static CStr {
}
// CHECK-NOT: .section
-// CHECK: .Lanon.{{.+}}:
+// CHECK: {{(\.L|\$)}}anon.{{.+}}:
// CHECK-NEXT: .asciz "baz"
#[unsafe(no_mangle)]
pub fn manual_cstr() -> &'static str {
diff --git a/tests/assembly/dwarf-mixed-versions-lto.rs b/tests/assembly/dwarf-mixed-versions-lto.rs
index f1fc081..9910a6e 100644
--- a/tests/assembly/dwarf-mixed-versions-lto.rs
+++ b/tests/assembly/dwarf-mixed-versions-lto.rs
@@ -4,7 +4,7 @@
//@ only-linux
//@ aux-build:dwarf-mixed-versions-lto-aux.rs
-//@ compile-flags: -C lto -g -Zdwarf-version=5
+//@ compile-flags: -C lto -g -Cdwarf-version=5
//@ assembly-output: emit-asm
//@ no-prefer-dynamic
diff --git a/tests/assembly/dwarf4.rs b/tests/assembly/dwarf4.rs
index 6013adf..03a3886 100644
--- a/tests/assembly/dwarf4.rs
+++ b/tests/assembly/dwarf4.rs
@@ -1,7 +1,7 @@
-// Makes sure that `-Z dwarf-version=4` causes `rustc` to emit DWARF version 4.
+// Makes sure that `-C dwarf-version=4` causes `rustc` to emit DWARF version 4.
//@ assembly-output: emit-asm
//@ add-core-stubs
-//@ compile-flags: -g --target x86_64-unknown-linux-gnu -Z dwarf-version=4 -Copt-level=0
+//@ compile-flags: -g --target x86_64-unknown-linux-gnu -C dwarf-version=4 -Copt-level=0
//@ needs-llvm-components: x86
#![feature(no_core, lang_items)]
diff --git a/tests/assembly/dwarf5.rs b/tests/assembly/dwarf5.rs
index 9cd596e..9bd92cc 100644
--- a/tests/assembly/dwarf5.rs
+++ b/tests/assembly/dwarf5.rs
@@ -1,7 +1,7 @@
-// Makes sure that `-Z dwarf-version=5` causes `rustc` to emit DWARF version 5.
+// Makes sure that `-C dwarf-version=5` causes `rustc` to emit DWARF version 5.
//@ add-core-stubs
//@ assembly-output: emit-asm
-//@ compile-flags: -g --target x86_64-unknown-linux-gnu -Z dwarf-version=5 -Copt-level=0
+//@ compile-flags: -g --target x86_64-unknown-linux-gnu -C dwarf-version=5 -Copt-level=0
//@ needs-llvm-components: x86
#![feature(no_core, lang_items)]
diff --git a/tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs b/tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs
index 46e627e..860ecc3 100644
--- a/tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs
+++ b/tests/assembly/naked-functions/aarch64-naked-fn-no-bti-prolog.rs
@@ -4,7 +4,7 @@
//@ only-aarch64
#![crate_type = "lib"]
-#![feature(naked_functions)]
+
use std::arch::naked_asm;
// The problem at hand: Rust has adopted a fairly strict meaning for "naked functions",
@@ -13,8 +13,8 @@
// LLVM implements this via making sure of that, even for functions with the naked attribute.
// So, we must emit an appropriate instruction instead!
#[no_mangle]
-#[naked]
-pub unsafe extern "C" fn _hlt() -> ! {
+#[unsafe(naked)]
+pub extern "C" fn _hlt() -> ! {
// CHECK-NOT: hint #34
// CHECK: hlt #0x1
naked_asm!("hlt #1")
diff --git a/tests/assembly/naked-functions/aix.rs b/tests/assembly/naked-functions/aix.rs
index cc0825b..57ff0e1 100644
--- a/tests/assembly/naked-functions/aix.rs
+++ b/tests/assembly/naked-functions/aix.rs
@@ -9,7 +9,7 @@
//@[aix] needs-llvm-components: powerpc
#![crate_type = "lib"]
-#![feature(no_core, naked_functions, asm_experimental_arch, f128, linkage, fn_align)]
+#![feature(no_core, asm_experimental_arch, f128, linkage, fn_align)]
#![no_core]
// tests that naked functions work for the `powerpc64-ibm-aix` target.
@@ -29,7 +29,7 @@
// CHECK-LABEL: blr:
// CHECK: blr
#[no_mangle]
-#[naked]
-unsafe extern "C" fn blr() {
+#[unsafe(naked)]
+extern "C" fn blr() {
naked_asm!("blr")
}
diff --git a/tests/assembly/naked-functions/wasm32.rs b/tests/assembly/naked-functions/wasm32.rs
index 4911a6b..71e4d80 100644
--- a/tests/assembly/naked-functions/wasm32.rs
+++ b/tests/assembly/naked-functions/wasm32.rs
@@ -9,7 +9,7 @@
//@ [wasm32-wasip1] needs-llvm-components: webassembly
#![crate_type = "lib"]
-#![feature(no_core, naked_functions, asm_experimental_arch, f128, linkage, fn_align)]
+#![feature(no_core, asm_experimental_arch, f128, linkage, fn_align)]
#![no_core]
extern crate minicore;
@@ -22,8 +22,8 @@
// CHECK-NOT: .size
// CHECK: end_function
#[no_mangle]
-#[naked]
-unsafe extern "C" fn nop() {
+#[unsafe(naked)]
+extern "C" fn nop() {
naked_asm!("nop")
}
@@ -34,11 +34,11 @@
// CHECK-NOT: .size
// CHECK: end_function
#[no_mangle]
-#[naked]
+#[unsafe(naked)]
#[linkage = "weak"]
// wasm functions cannot be aligned, so this has no effect
#[repr(align(32))]
-unsafe extern "C" fn weak_aligned_nop() {
+extern "C" fn weak_aligned_nop() {
naked_asm!("nop")
}
@@ -51,48 +51,48 @@
//
// CHECK-NEXT: end_function
#[no_mangle]
-#[naked]
-unsafe extern "C" fn fn_i8_i8(num: i8) -> i8 {
+#[unsafe(naked)]
+extern "C" fn fn_i8_i8(num: i8) -> i8 {
naked_asm!("local.get 0", "local.get 0", "i32.mul")
}
// CHECK-LABEL: fn_i8_i8_i8:
// CHECK: .functype fn_i8_i8_i8 (i32, i32) -> (i32)
#[no_mangle]
-#[naked]
-unsafe extern "C" fn fn_i8_i8_i8(a: i8, b: i8) -> i8 {
+#[unsafe(naked)]
+extern "C" fn fn_i8_i8_i8(a: i8, b: i8) -> i8 {
naked_asm!("local.get 1", "local.get 0", "i32.mul")
}
// CHECK-LABEL: fn_unit_i8:
// CHECK: .functype fn_unit_i8 () -> (i32)
#[no_mangle]
-#[naked]
-unsafe extern "C" fn fn_unit_i8() -> i8 {
+#[unsafe(naked)]
+extern "C" fn fn_unit_i8() -> i8 {
naked_asm!("i32.const 42")
}
// CHECK-LABEL: fn_i8_unit:
// CHECK: .functype fn_i8_unit (i32) -> ()
#[no_mangle]
-#[naked]
-unsafe extern "C" fn fn_i8_unit(_: i8) {
+#[unsafe(naked)]
+extern "C" fn fn_i8_unit(_: i8) {
naked_asm!("nop")
}
// CHECK-LABEL: fn_i32_i32:
// CHECK: .functype fn_i32_i32 (i32) -> (i32)
#[no_mangle]
-#[naked]
-unsafe extern "C" fn fn_i32_i32(num: i32) -> i32 {
+#[unsafe(naked)]
+extern "C" fn fn_i32_i32(num: i32) -> i32 {
naked_asm!("local.get 0", "local.get 0", "i32.mul")
}
// CHECK-LABEL: fn_i64_i64:
// CHECK: .functype fn_i64_i64 (i64) -> (i64)
#[no_mangle]
-#[naked]
-unsafe extern "C" fn fn_i64_i64(num: i64) -> i64 {
+#[unsafe(naked)]
+extern "C" fn fn_i64_i64(num: i64) -> i64 {
naked_asm!("local.get 0", "local.get 0", "i64.mul")
}
@@ -101,8 +101,8 @@
// wasm64-unknown: .functype fn_i128_i128 (i64, i64, i64) -> ()
#[allow(improper_ctypes_definitions)]
#[no_mangle]
-#[naked]
-unsafe extern "C" fn fn_i128_i128(num: i128) -> i128 {
+#[unsafe(naked)]
+extern "C" fn fn_i128_i128(num: i128) -> i128 {
naked_asm!(
"local.get 0",
"local.get 2",
@@ -117,8 +117,8 @@
// wasm32-wasip1: .functype fn_f128_f128 (i32, i64, i64) -> ()
// wasm64-unknown: .functype fn_f128_f128 (i64, i64, i64) -> ()
#[no_mangle]
-#[naked]
-unsafe extern "C" fn fn_f128_f128(num: f128) -> f128 {
+#[unsafe(naked)]
+extern "C" fn fn_f128_f128(num: f128) -> f128 {
naked_asm!(
"local.get 0",
"local.get 2",
@@ -139,8 +139,8 @@ struct Compound {
// wasm32-wasip1: .functype fn_compound_compound (i32, i32) -> ()
// wasm64-unknown: .functype fn_compound_compound (i64, i64) -> ()
#[no_mangle]
-#[naked]
-unsafe extern "C" fn fn_compound_compound(_: Compound) -> Compound {
+#[unsafe(naked)]
+extern "C" fn fn_compound_compound(_: Compound) -> Compound {
// this is the wasm32-wasip1 assembly
naked_asm!(
"local.get 0",
@@ -160,8 +160,8 @@ struct Compound {
// CHECK-LABEL: fn_wrapperi32_wrapperi32:
// CHECK: .functype fn_wrapperi32_wrapperi32 (i32) -> (i32)
#[no_mangle]
-#[naked]
-unsafe extern "C" fn fn_wrapperi32_wrapperi32(_: WrapperI32) -> WrapperI32 {
+#[unsafe(naked)]
+extern "C" fn fn_wrapperi32_wrapperi32(_: WrapperI32) -> WrapperI32 {
naked_asm!("local.get 0")
}
@@ -171,8 +171,8 @@ struct Compound {
// CHECK-LABEL: fn_wrapperi64_wrapperi64:
// CHECK: .functype fn_wrapperi64_wrapperi64 (i64) -> (i64)
#[no_mangle]
-#[naked]
-unsafe extern "C" fn fn_wrapperi64_wrapperi64(_: WrapperI64) -> WrapperI64 {
+#[unsafe(naked)]
+extern "C" fn fn_wrapperi64_wrapperi64(_: WrapperI64) -> WrapperI64 {
naked_asm!("local.get 0")
}
@@ -182,8 +182,8 @@ struct Compound {
// CHECK-LABEL: fn_wrapperf32_wrapperf32:
// CHECK: .functype fn_wrapperf32_wrapperf32 (f32) -> (f32)
#[no_mangle]
-#[naked]
-unsafe extern "C" fn fn_wrapperf32_wrapperf32(_: WrapperF32) -> WrapperF32 {
+#[unsafe(naked)]
+extern "C" fn fn_wrapperf32_wrapperf32(_: WrapperF32) -> WrapperF32 {
naked_asm!("local.get 0")
}
@@ -193,7 +193,7 @@ struct Compound {
// CHECK-LABEL: fn_wrapperf64_wrapperf64:
// CHECK: .functype fn_wrapperf64_wrapperf64 (f64) -> (f64)
#[no_mangle]
-#[naked]
-unsafe extern "C" fn fn_wrapperf64_wrapperf64(_: WrapperF64) -> WrapperF64 {
+#[unsafe(naked)]
+extern "C" fn fn_wrapperf64_wrapperf64(_: WrapperF64) -> WrapperF64 {
naked_asm!("local.get 0")
}
diff --git a/tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs b/tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs
index 54e1d93..81ee9b1 100644
--- a/tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs
+++ b/tests/assembly/naked-functions/x86_64-naked-fn-no-cet-prolog.rs
@@ -4,7 +4,7 @@
//@ only-x86_64
#![crate_type = "lib"]
-#![feature(naked_functions)]
+
use std::arch::naked_asm;
// The problem at hand: Rust has adopted a fairly strict meaning for "naked functions",
@@ -13,8 +13,8 @@
// works by using an instruction for each possible landing site,
// and LLVM implements this via making sure of that.
#[no_mangle]
-#[naked]
-pub unsafe extern "sysv64" fn will_halt() -> ! {
+#[unsafe(naked)]
+pub extern "sysv64" fn will_halt() -> ! {
// CHECK-NOT: endbr{{32|64}}
// CHECK: hlt
naked_asm!("hlt")
diff --git a/tests/assembly/simd-bitmask.rs b/tests/assembly/simd-bitmask.rs
index e412246..d3e20f6 100644
--- a/tests/assembly/simd-bitmask.rs
+++ b/tests/assembly/simd-bitmask.rs
@@ -65,8 +65,9 @@
simd_bitmask(mask)
}
-// CHECK-LABEL: bitmask_m8x64
+// x86-avx512-LABEL: bitmask_m8x64
#[no_mangle]
+#[cfg(x86_avx512)]
pub unsafe extern "C" fn bitmask_m8x64(mask: m8x64) -> u64 {
// The simd_bitmask intrinsic already uses the most significant bit, so no shift is necessary.
// Note that x86 has no byte shift, llvm uses a word shift to move the least significant bit
@@ -128,8 +129,10 @@
simd_bitmask(mask)
}
-// CHECK-LABEL: bitmask_m64x4
+// x86-avx2-LABEL: bitmask_m64x4
+// x86-avx512-LABEL: bitmask_m64x4
#[no_mangle]
+#[cfg(any(x86_avx2, x86_avx512))]
pub unsafe extern "C" fn bitmask_m64x4(mask: m64x4) -> u8 {
// The simd_bitmask intrinsic already uses the most significant bit, so no shift is necessary.
//
diff --git a/tests/assembly/simd-intrinsic-select.rs b/tests/assembly/simd-intrinsic-select.rs
index 4f8d6b8..e7c7b0d 100644
--- a/tests/assembly/simd-intrinsic-select.rs
+++ b/tests/assembly/simd-intrinsic-select.rs
@@ -99,8 +99,10 @@
simd_select(mask, a, b)
}
-// CHECK-LABEL: select_f64x4
+// x86-avx2-LABEL: select_f64x4
+// x86-avx512-LABEL: select_f64x4
#[no_mangle]
+#[cfg(any(x86_avx2, x86_avx512))]
pub unsafe extern "C" fn select_f64x4(mask: m64x4, a: f64x4, b: f64x4) -> f64x4 {
// The parameter is a 256 bit vector which in the C abi is only valid for avx targets.
//
@@ -113,8 +115,9 @@
simd_select(mask, a, b)
}
-// CHECK-LABEL: select_f64x8
+// x86-avx512-LABEL: select_f64x8
#[no_mangle]
+#[cfg(x86_avx512)]
pub unsafe extern "C" fn select_f64x8(mask: m64x8, a: f64x8, b: f64x8) -> f64x8 {
// The parameter is a 256 bit vector which in the C abi is only valid for avx512 targets.
//
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index 8f2fef0..3255591 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -571,6 +571,9 @@
//@ revisions: x86_64_linux_android
//@ [x86_64_linux_android] compile-flags: --target x86_64-linux-android
//@ [x86_64_linux_android] needs-llvm-components: x86
+//@ revisions: x86_64_lynx_lynxos178
+//@ [x86_64_lynx_lynxos178] compile-flags: --target x86_64-lynx-lynxos178
+//@ [x86_64_lynx_lynxos178] needs-llvm-components: x86
//@ revisions: x86_64_pc_nto_qnx710
//@ [x86_64_pc_nto_qnx710] compile-flags: --target x86_64-pc-nto-qnx710
//@ [x86_64_pc_nto_qnx710] needs-llvm-components: x86
diff --git a/tests/auxiliary/minicore.rs b/tests/auxiliary/minicore.rs
index 03aa847..941c4ab 100644
--- a/tests/auxiliary/minicore.rs
+++ b/tests/auxiliary/minicore.rs
@@ -22,7 +22,6 @@
negative_impls,
rustc_attrs,
decl_macro,
- naked_functions,
f16,
f128,
asm_experimental_arch,
diff --git a/tests/codegen/align-fn.rs b/tests/codegen/align-fn.rs
index 97f23cc..660d8cd 100644
--- a/tests/codegen/align-fn.rs
+++ b/tests/codegen/align-fn.rs
@@ -47,3 +47,22 @@ impl T for () {}
pub fn foo() {
().trait_method();
}
+
+// CHECK-LABEL: align_specified_twice_1
+// CHECK-SAME: align 64
+#[no_mangle]
+#[repr(align(32), align(64))]
+pub fn align_specified_twice_1() {}
+
+// CHECK-LABEL: align_specified_twice_2
+// CHECK-SAME: align 128
+#[no_mangle]
+#[repr(align(128), align(32))]
+pub fn align_specified_twice_2() {}
+
+// CHECK-LABEL: align_specified_twice_3
+// CHECK-SAME: align 256
+#[no_mangle]
+#[repr(align(32))]
+#[repr(align(256))]
+pub fn align_specified_twice_3() {}
diff --git a/tests/codegen/array-cmp.rs b/tests/codegen/array-cmp.rs
index 2565a38..0d33765 100644
--- a/tests/codegen/array-cmp.rs
+++ b/tests/codegen/array-cmp.rs
@@ -1,6 +1,7 @@
// Ensure the asm for array comparisons is properly optimized.
//@ compile-flags: -C opt-level=2
+//@ needs-deterministic-layouts (checks depend on tuple layout)
#![crate_type = "lib"]
@@ -17,3 +18,57 @@ pub fn compare() -> bool {
[0x00, 0x00, 0x48, 0x41]
}
}
+
+// CHECK-LABEL: @array_of_tuple_le
+#[no_mangle]
+pub fn array_of_tuple_le(a: &[(i16, u16); 2], b: &[(i16, u16); 2]) -> bool {
+ // Ensure that, after all the optimizations have run, the happy path just checks
+ // `eq` on each corresponding pair and moves onto the next one if it is.
+ // Then there's a dedup'd comparison for the place that's different.
+ // (As opposed to, say, running a full `[su]cmp` as part of checking equality.)
+
+ // This is written quite specifically because different library code was triggering
+ // <https://github.com/llvm/llvm-project/issues/132678> along the way, so this
+ // has enough checks to make sure that's not happening. It doesn't need to be
+ // *exactly* this IR, but be careful if you ever need to update these checks.
+
+ // CHECK: start:
+ // CHECK: %[[A00:.+]] = load i16, ptr %a
+ // CHECK: %[[B00:.+]] = load i16, ptr %b
+ // CHECK-NOT: cmp
+ // CHECK: %[[EQ00:.+]] = icmp eq i16 %[[A00]], %[[B00]]
+ // CHECK-NEXT: br i1 %[[EQ00]], label %[[L01:.+]], label %[[EXIT_S:.+]]
+
+ // CHECK: [[L01]]:
+ // CHECK: %[[PA01:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 2
+ // CHECK: %[[PB01:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 2
+ // CHECK: %[[A01:.+]] = load i16, ptr %[[PA01]]
+ // CHECK: %[[B01:.+]] = load i16, ptr %[[PB01]]
+ // CHECK-NOT: cmp
+ // CHECK: %[[EQ01:.+]] = icmp eq i16 %[[A01]], %[[B01]]
+ // CHECK-NEXT: br i1 %[[EQ01]], label %[[L10:.+]], label %[[EXIT_U:.+]]
+
+ // CHECK: [[L10]]:
+ // CHECK: %[[PA10:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 4
+ // CHECK: %[[PB10:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 4
+ // CHECK: %[[A10:.+]] = load i16, ptr %[[PA10]]
+ // CHECK: %[[B10:.+]] = load i16, ptr %[[PB10]]
+ // CHECK-NOT: cmp
+ // CHECK: %[[EQ10:.+]] = icmp eq i16 %[[A10]], %[[B10]]
+ // CHECK-NEXT: br i1 %[[EQ10]], label %[[L11:.+]], label %[[EXIT_S]]
+
+ // CHECK: [[L11]]:
+ // CHECK: %[[PA11:.+]] = getelementptr{{.+}}i8, ptr %a, {{i32|i64}} 6
+ // CHECK: %[[PB11:.+]] = getelementptr{{.+}}i8, ptr %b, {{i32|i64}} 6
+ // CHECK: %[[A11:.+]] = load i16, ptr %[[PA11]]
+ // CHECK: %[[B11:.+]] = load i16, ptr %[[PB11]]
+ // CHECK-NOT: cmp
+ // CHECK: %[[EQ11:.+]] = icmp eq i16 %[[A11]], %[[B11]]
+ // CHECK-NEXT: br i1 %[[EQ11]], label %[[DONE:.+]], label %[[EXIT_U]]
+
+ // CHECK: [[DONE]]:
+ // CHECK: %[[RET:.+]] = phi i1 [ %{{.+}}, %[[EXIT_S]] ], [ %{{.+}}, %[[EXIT_U]] ], [ true, %[[L11]] ]
+ // CHECK: ret i1 %[[RET]]
+
+ a <= b
+}
diff --git a/tests/codegen/autodiffv2.rs b/tests/codegen/autodiffv2.rs
new file mode 100644
index 0000000..a40d19d
--- /dev/null
+++ b/tests/codegen/autodiffv2.rs
@@ -0,0 +1,113 @@
+//@ compile-flags: -Zautodiff=Enable -C opt-level=3 -Clto=fat
+//@ no-prefer-dynamic
+//@ needs-enzyme
+//
+// In Enzyme, we test against a large range of LLVM versions (5+) and don't have overly many
+// breakages. One benefit is that we match the IR generated by Enzyme only after running it
+// through LLVM's O3 pipeline, which will remove most of the noise.
+// However, our integration test could also be affected by changes in how rustc lowers MIR into
+// LLVM-IR, which could cause additional noise and thus breakages. If that's the case, we should
+// reduce this test to only match the first lines and the ret instructions.
+//
+// The function tested here has 4 inputs and 5 outputs, so we could either call forward-mode
+// autodiff 4 times, or reverse mode 5 times. Since a forward-mode call is usually faster than
+// reverse mode, we prefer it here. This file also tests a new optimization (batch mode), which
+// allows us to call forward-mode autodiff only once, and get all 5 outputs in a single call.
+//
+// We support 2 different batch modes. `d_square2` has the same interface as scalar forward-mode,
+// but each shadow argument is `width` times larger (thus 16 and 20 elements here).
+// `d_square3` instead takes `width` (4) shadow arguments, which are all the same size as the
+// original function arguments.
+//
+// FIXME(autodiff): We currently can't test `d_square1` and `d_square3` in the same file, since they
+// generate the same dummy functions which get merged by LLVM, breaking pieces of our pipeline which
+// try to rewrite the dummy functions later. We should consider to change to pure declarations both
+// in our frontend and in the llvm backend to avoid these issues.
+
+#![feature(autodiff)]
+
+use std::autodiff::autodiff;
+
+#[no_mangle]
+//#[autodiff(d_square1, Forward, Dual, Dual)]
+#[autodiff(d_square2, Forward, 4, Dualv, Dualv)]
+#[autodiff(d_square3, Forward, 4, Dual, Dual)]
+fn square(x: &[f32], y: &mut [f32]) {
+ assert!(x.len() >= 4);
+ assert!(y.len() >= 5);
+ y[0] = 4.3 * x[0] + 1.2 * x[1] + 3.4 * x[2] + 2.1 * x[3];
+ y[1] = 2.3 * x[0] + 4.5 * x[1] + 1.7 * x[2] + 6.4 * x[3];
+ y[2] = 1.1 * x[0] + 3.3 * x[1] + 2.5 * x[2] + 4.7 * x[3];
+ y[3] = 5.2 * x[0] + 1.4 * x[1] + 2.6 * x[2] + 3.8 * x[3];
+ y[4] = 1.0 * x[0] + 2.0 * x[1] + 3.0 * x[2] + 4.0 * x[3];
+}
+
+fn main() {
+ let x1 = std::hint::black_box(vec![0.0, 1.0, 2.0, 3.0]);
+
+ let dx1 = std::hint::black_box(vec![1.0; 12]);
+
+ let z1 = std::hint::black_box(vec![1.0, 0.0, 0.0, 0.0]);
+ let z2 = std::hint::black_box(vec![0.0, 1.0, 0.0, 0.0]);
+ let z3 = std::hint::black_box(vec![0.0, 0.0, 1.0, 0.0]);
+ let z4 = std::hint::black_box(vec![0.0, 0.0, 0.0, 1.0]);
+
+ let z5 = std::hint::black_box(vec![
+ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
+ ]);
+
+ let mut y1 = std::hint::black_box(vec![0.0; 5]);
+ let mut y2 = std::hint::black_box(vec![0.0; 5]);
+ let mut y3 = std::hint::black_box(vec![0.0; 5]);
+ let mut y4 = std::hint::black_box(vec![0.0; 5]);
+
+ let mut y5 = std::hint::black_box(vec![0.0; 5]);
+
+ let mut y6 = std::hint::black_box(vec![0.0; 5]);
+
+ let mut dy1_1 = std::hint::black_box(vec![0.0; 5]);
+ let mut dy1_2 = std::hint::black_box(vec![0.0; 5]);
+ let mut dy1_3 = std::hint::black_box(vec![0.0; 5]);
+ let mut dy1_4 = std::hint::black_box(vec![0.0; 5]);
+
+ let mut dy2 = std::hint::black_box(vec![0.0; 20]);
+
+ let mut dy3_1 = std::hint::black_box(vec![0.0; 5]);
+ let mut dy3_2 = std::hint::black_box(vec![0.0; 5]);
+ let mut dy3_3 = std::hint::black_box(vec![0.0; 5]);
+ let mut dy3_4 = std::hint::black_box(vec![0.0; 5]);
+
+ // scalar.
+ //d_square1(&x1, &z1, &mut y1, &mut dy1_1);
+ //d_square1(&x1, &z2, &mut y2, &mut dy1_2);
+ //d_square1(&x1, &z3, &mut y3, &mut dy1_3);
+ //d_square1(&x1, &z4, &mut y4, &mut dy1_4);
+
+ // assert y1 == y2 == y3 == y4
+ //for i in 0..5 {
+ // assert_eq!(y1[i], y2[i]);
+ // assert_eq!(y1[i], y3[i]);
+ // assert_eq!(y1[i], y4[i]);
+ //}
+
+ // batch mode A)
+ d_square2(&x1, &z5, &mut y5, &mut dy2);
+
+ // assert y1 == y2 == y3 == y4 == y5
+ //for i in 0..5 {
+ // assert_eq!(y1[i], y5[i]);
+ //}
+
+ // batch mode B)
+ d_square3(&x1, &z1, &z2, &z3, &z4, &mut y6, &mut dy3_1, &mut dy3_2, &mut dy3_3, &mut dy3_4);
+ for i in 0..5 {
+ assert_eq!(y5[i], y6[i]);
+ }
+
+ for i in 0..5 {
+ assert_eq!(dy2[0..5][i], dy3_1[i]);
+ assert_eq!(dy2[5..10][i], dy3_2[i]);
+ assert_eq!(dy2[10..15][i], dy3_3[i]);
+ assert_eq!(dy2[15..20][i], dy3_4[i]);
+ }
+}
diff --git a/tests/codegen/cffi/c-variadic-naked.rs b/tests/codegen/cffi/c-variadic-naked.rs
index 24b69c5..5843628 100644
--- a/tests/codegen/cffi/c-variadic-naked.rs
+++ b/tests/codegen/cffi/c-variadic-naked.rs
@@ -5,14 +5,11 @@
#![crate_type = "lib"]
#![feature(c_variadic)]
-#![feature(naked_functions)]
#![no_std]
-#[naked]
+#[unsafe(naked)]
pub unsafe extern "C" fn c_variadic(_: usize, _: ...) {
// CHECK-NOT: va_start
// CHECK-NOT: alloca
- core::arch::naked_asm! {
- "ret",
- }
+ core::arch::naked_asm!("ret")
}
diff --git a/tests/codegen/cffi/ffi-const.rs b/tests/codegen/cffi/ffi-const.rs
index 6c90902..3ea9d51 100644
--- a/tests/codegen/cffi/ffi-const.rs
+++ b/tests/codegen/cffi/ffi-const.rs
@@ -10,6 +10,6 @@ pub fn bar() {
// CHECK-LABEL: declare{{.*}}void @foo()
// CHECK-SAME: [[ATTRS:#[0-9]+]]
// CHECK-DAG: attributes [[ATTRS]] = { {{.*}}memory(none){{.*}} }
- #[ffi_const]
+ #[unsafe(ffi_const)]
pub fn foo();
}
diff --git a/tests/codegen/cffi/ffi-pure.rs b/tests/codegen/cffi/ffi-pure.rs
index 2c5d5f5..a61e80e 100644
--- a/tests/codegen/cffi/ffi-pure.rs
+++ b/tests/codegen/cffi/ffi-pure.rs
@@ -10,6 +10,6 @@ pub fn bar() {
// CHECK-LABEL: declare{{.*}}void @foo()
// CHECK-SAME: [[ATTRS:#[0-9]+]]
// CHECK-DAG: attributes [[ATTRS]] = { {{.*}}memory(read){{.*}} }
- #[ffi_pure]
+ #[unsafe(ffi_pure)]
pub fn foo();
}
diff --git a/tests/codegen/const-vector.rs b/tests/codegen/const-vector.rs
index 8343594..1d4edc3 100644
--- a/tests/codegen/const-vector.rs
+++ b/tests/codegen/const-vector.rs
@@ -8,6 +8,7 @@
#![feature(repr_simd)]
#![feature(rustc_attrs)]
#![feature(simd_ffi)]
+#![feature(arm_target_feature)]
#![allow(non_camel_case_types)]
// Setting up structs that can be used as const vectors
@@ -28,33 +29,12 @@
extern "unadjusted" {
fn test_i8x2(a: i8x2);
-}
-
-extern "unadjusted" {
fn test_i8x2_two_args(a: i8x2, b: i8x2);
-}
-
-extern "unadjusted" {
fn test_i8x2_mixed_args(a: i8x2, c: i32, b: i8x2);
-}
-
-extern "unadjusted" {
fn test_i8x2_arr(a: i8x2);
-}
-
-extern "unadjusted" {
fn test_f32x2(a: f32x2);
-}
-
-extern "unadjusted" {
fn test_f32x2_arr(a: f32x2);
-}
-
-extern "unadjusted" {
fn test_simd(a: Simd<i32, 4>);
-}
-
-extern "unadjusted" {
fn test_simd_unaligned(a: Simd<i32, 3>);
}
@@ -62,6 +42,9 @@
// if the size is not a power of 2
// CHECK: %"Simd<i32, 3>" = type { [3 x i32] }
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
pub fn do_call() {
unsafe {
// CHECK: call void @test_i8x2(<2 x i8> <i8 32, i8 64>
diff --git a/tests/codegen/dont-shuffle-bswaps.rs b/tests/codegen/dont-shuffle-bswaps.rs
index e100474..c1dab2b 100644
--- a/tests/codegen/dont-shuffle-bswaps.rs
+++ b/tests/codegen/dont-shuffle-bswaps.rs
@@ -1,8 +1,11 @@
-//@ revisions: OPT2 OPT3
+//@ revisions: OPT2 OPT3 OPT3_S390X
//@[OPT2] compile-flags: -Copt-level=2
//@[OPT3] compile-flags: -C opt-level=3
// some targets don't do the opt we are looking for
//@[OPT3] only-64bit
+//@[OPT3] ignore-s390x
+//@[OPT3_S390X] compile-flags: -C opt-level=3 -C target-cpu=z13
+//@[OPT3_S390X] only-s390x
#![crate_type = "lib"]
#![no_std]
@@ -17,6 +20,10 @@
// OPT3-NEXT: call <8 x i16> @llvm.bswap
// OPT3-NEXT: store <8 x i16>
// OPT3-NEXT: ret void
+// OPT3_S390X: load <8 x i16>
+// OPT3_S390X-NEXT: call <8 x i16> @llvm.bswap
+// OPT3_S390X-NEXT: store <8 x i16>
+// OPT3_S390X-NEXT: ret void
#[no_mangle]
pub fn convert(value: [u16; 8]) -> [u8; 16] {
#[cfg(target_endian = "little")]
diff --git a/tests/codegen/enum/enum-match.rs b/tests/codegen/enum/enum-match.rs
index 6e185cf..6da6ad1 100644
--- a/tests/codegen/enum/enum-match.rs
+++ b/tests/codegen/enum/enum-match.rs
@@ -15,7 +15,7 @@ pub enum Enum0 {
B,
}
-// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match0(i8{{.+}}%0)
+// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match0(i8{{.+}}%0)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[IS_B:.+]] = icmp eq i8 %0, 2
// CHECK-NEXT: %[[TRUNC:.+]] = and i8 %0, 1
@@ -37,7 +37,7 @@ pub enum Enum1 {
C,
}
-// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1(i8{{.+}}%0)
+// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match1(i8{{.+}}%0)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64
@@ -98,7 +98,7 @@ pub enum Enum2 {
E,
}
-// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match2(i8{{.+}}%0)
+// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match2(i8{{.+}}%0)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[REL_VAR:.+]] = add i8 %0, 2
// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64
@@ -121,7 +121,7 @@ pub fn match2(e: Enum2) -> u8 {
// And make sure it works even if the niched scalar is a pointer.
// (For example, that we don't try to `sub` on pointers.)
-// CHECK-LABEL: define noundef{{( range\(i16 -?[0-9]+, -?[0-9]+\))?}} i16 @match3(ptr{{.+}}%0)
+// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i16 -?[0-9]+, -?[0-9]+\))?}} i16 @match3(ptr{{.+}}%0)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[IS_NULL:.+]] = icmp eq ptr %0, null
// CHECK-NEXT: br i1 %[[IS_NULL]]
@@ -145,7 +145,7 @@ pub enum MiddleNiche {
E,
}
-// CHECK-LABEL: define noundef{{( range\(i8 -?[0-9]+, -?[0-9]+\))?}} i8 @match4(i8{{.+}}%0)
+// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 -?[0-9]+, -?[0-9]+\))?}} i8 @match4(i8{{.+}}%0)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
// CHECK-NEXT: %[[IS_NICHE:.+]] = icmp ult i8 %[[REL_VAR]], 5
@@ -449,7 +449,7 @@ pub enum HugeVariantIndex {
Possible259,
}
-// CHECK-LABEL: define noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match5(i8{{.+}}%0)
+// CHECK-LABEL: define{{( dso_local)?}} noundef{{( range\(i8 [0-9]+, [0-9]+\))?}} i8 @match5(i8{{.+}}%0)
// CHECK-NEXT: start:
// CHECK-NEXT: %[[REL_VAR:.+]] = add{{( nsw)?}} i8 %0, -2
// CHECK-NEXT: %[[REL_VAR_WIDE:.+]] = zext i8 %[[REL_VAR]] to i64
diff --git a/tests/codegen/intrinsic-no-unnamed-attr.rs b/tests/codegen/intrinsic-no-unnamed-attr.rs
index 35eb025..4bec579 100644
--- a/tests/codegen/intrinsic-no-unnamed-attr.rs
+++ b/tests/codegen/intrinsic-no-unnamed-attr.rs
@@ -1,9 +1,8 @@
//@ compile-flags: -C no-prepopulate-passes
-#![feature(intrinsics)]
+#![feature(core_intrinsics)]
-#[rustc_intrinsic]
-unsafe fn sqrtf32(x: f32) -> f32;
+use std::intrinsics::sqrtf32;
// CHECK: @llvm.sqrt.f32(float) #{{[0-9]*}}
diff --git a/tests/codegen/intrinsics/select_unpredictable.rs b/tests/codegen/intrinsics/select_unpredictable.rs
index 68a02c8..2db4ae1 100644
--- a/tests/codegen/intrinsics/select_unpredictable.rs
+++ b/tests/codegen/intrinsics/select_unpredictable.rs
@@ -46,21 +46,21 @@ pub fn test_zst(p: bool, a: (), b: ()) -> () {
pub fn test_int2(p: bool, a: u64, b: u64) -> u64 {
// CHECK-LABEL: define{{.*}} @test_int2
// CHECK: select i1 %p, i64 %a, i64 %b, !unpredictable
- p.select_unpredictable(a, b)
+ core::hint::select_unpredictable(p, a, b)
}
#[no_mangle]
pub fn test_pair2(p: bool, a: (u64, u64), b: (u64, u64)) -> (u64, u64) {
// CHECK-LABEL: define{{.*}} @test_pair2
// CHECK: select i1 %p, {{.*}}, !unpredictable
- p.select_unpredictable(a, b)
+ core::hint::select_unpredictable(p, a, b)
}
#[no_mangle]
pub fn test_struct2(p: bool, a: Large, b: Large) -> Large {
// CHECK-LABEL: define{{.*}} @test_struct2
// CHECK: select i1 %p, {{.*}}, !unpredictable
- p.select_unpredictable(a, b)
+ core::hint::select_unpredictable(p, a, b)
}
#[no_mangle]
@@ -68,5 +68,5 @@ pub fn test_zst2(p: bool, a: (), b: ()) -> () {
// CHECK-LABEL: define{{.*}} @test_zst2
// CHECK-NEXT: start:
// CHECK-NEXT: ret void
- p.select_unpredictable(a, b)
+ core::hint::select_unpredictable(p, a, b)
}
diff --git a/tests/codegen/issues/issue-101082.rs b/tests/codegen/issues/issue-101082.rs
index 96cdff6..8d15921 100644
--- a/tests/codegen/issues/issue-101082.rs
+++ b/tests/codegen/issues/issue-101082.rs
@@ -12,6 +12,7 @@
// at the time still sometimes fails, so only verify it for the power-of-two size
// - https://github.com/llvm/llvm-project/issues/134735
//@[x86-64-v3] only-x86_64
+//@[x86-64-v3] min-llvm-version: 21
//@[x86-64-v3] compile-flags: -Ctarget-cpu=x86-64-v3
#![crate_type = "lib"]
@@ -19,16 +20,7 @@
#[no_mangle]
pub fn test() -> usize {
// CHECK-LABEL: @test(
- // host: ret {{i64|i32}} 165
- // x86-64: ret {{i64|i32}} 165
-
- // FIXME: Now that this autovectorizes via a masked load, it doesn't actually
- // const-fold for certain widths. The `test_eight` case below shows that, yes,
- // what we're emitting *can* be const-folded, except that the way LLVM does it
- // for certain widths doesn't today. We should be able to put this back to
- // the same check after <https://github.com/llvm/llvm-project/issues/134513>
- // x86-64-v3: masked.load
-
+ // CHECK: ret {{i64|i32}} 165
let values = [23, 16, 54, 3, 60, 9];
let mut acc = 0;
for item in values {
diff --git a/tests/codegen/naked-asan.rs b/tests/codegen/naked-asan.rs
index 8efedab..223c41b 100644
--- a/tests/codegen/naked-asan.rs
+++ b/tests/codegen/naked-asan.rs
@@ -6,17 +6,17 @@
#![crate_type = "lib"]
#![no_std]
-#![feature(abi_x86_interrupt, naked_functions)]
+#![feature(abi_x86_interrupt)]
pub fn caller() {
page_fault_handler(1, 2);
}
// CHECK: declare x86_intrcc void @page_fault_handler(ptr {{.*}}, i64{{.*}}){{.*}}#[[ATTRS:[0-9]+]]
-#[naked]
+#[unsafe(naked)]
#[no_mangle]
pub extern "x86-interrupt" fn page_fault_handler(_: u64, _: u64) {
- unsafe { core::arch::naked_asm!("ud2") };
+ core::arch::naked_asm!("ud2")
}
// CHECK: #[[ATTRS]] =
diff --git a/tests/codegen/naked-fn/aligned.rs b/tests/codegen/naked-fn/aligned.rs
index d9dcd7f..47ef779 100644
--- a/tests/codegen/naked-fn/aligned.rs
+++ b/tests/codegen/naked-fn/aligned.rs
@@ -3,15 +3,15 @@
//@ ignore-arm no "ret" mnemonic
#![crate_type = "lib"]
-#![feature(naked_functions, fn_align)]
+#![feature(fn_align)]
use std::arch::naked_asm;
// CHECK: .balign 16
// CHECK-LABEL: naked_empty:
#[repr(align(16))]
#[no_mangle]
-#[naked]
-pub unsafe extern "C" fn naked_empty() {
+#[unsafe(naked)]
+pub extern "C" fn naked_empty() {
// CHECK: ret
- naked_asm!("ret");
+ naked_asm!("ret")
}
diff --git a/tests/codegen/naked-fn/generics.rs b/tests/codegen/naked-fn/generics.rs
index 64998df..865be00 100644
--- a/tests/codegen/naked-fn/generics.rs
+++ b/tests/codegen/naked-fn/generics.rs
@@ -2,7 +2,6 @@
//@ only-x86_64
#![crate_type = "lib"]
-#![feature(naked_functions, asm_const)]
use std::arch::naked_asm;
@@ -28,21 +27,19 @@ fn test(x: u64) {
// CHECK: add rax, 1
// CHECK: add rax, 42
-#[naked]
+#[unsafe(naked)]
pub extern "C" fn using_const_generics<const N: u64>(x: u64) -> u64 {
const M: u64 = 42;
- unsafe {
- naked_asm!(
- "xor rax, rax",
- "add rax, rdi",
- "add rax, {}",
- "add rax, {}",
- "ret",
- const N,
- const M,
- )
- }
+ naked_asm!(
+ "xor rax, rax",
+ "add rax, rdi",
+ "add rax, {}",
+ "add rax, {}",
+ "ret",
+ const N,
+ const M,
+ )
}
trait Invert {
@@ -60,16 +57,14 @@ fn invert(self) -> Self {
// CHECK: call
// CHECK: ret
-#[naked]
+#[unsafe(naked)]
#[no_mangle]
pub extern "C" fn generic_function<T: Invert>(x: i64) -> i64 {
- unsafe {
- naked_asm!(
- "call {}",
- "ret",
- sym <T as Invert>::invert,
- )
- }
+ naked_asm!(
+ "call {}",
+ "ret",
+ sym <T as Invert>::invert,
+ )
}
#[derive(Copy, Clone)]
@@ -81,10 +76,10 @@ pub extern "C" fn generic_function<T: Invert>(x: i64) -> i64 {
// CHECK: mov rax, rdi
impl Foo {
- #[naked]
+ #[unsafe(naked)]
#[no_mangle]
extern "C" fn method(self) -> u64 {
- unsafe { naked_asm!("mov rax, rdi", "ret") }
+ naked_asm!("mov rax, rdi", "ret")
}
}
@@ -97,10 +92,10 @@ trait Bar {
}
impl Bar for Foo {
- #[naked]
+ #[unsafe(naked)]
#[no_mangle]
extern "C" fn trait_method(self) -> u64 {
- unsafe { naked_asm!("mov rax, rdi", "ret") }
+ naked_asm!("mov rax, rdi", "ret")
}
}
@@ -109,7 +104,7 @@ extern "C" fn trait_method(self) -> u64 {
// CHECK: lea rax, [rdi + rsi]
// this previously ICE'd, see https://github.com/rust-lang/rust/issues/124375
-#[naked]
+#[unsafe(naked)]
#[no_mangle]
pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
naked_asm!("lea rax, [rdi + rsi]", "ret");
diff --git a/tests/codegen/naked-fn/instruction-set.rs b/tests/codegen/naked-fn/instruction-set.rs
index a7b4c22..67560c5 100644
--- a/tests/codegen/naked-fn/instruction-set.rs
+++ b/tests/codegen/naked-fn/instruction-set.rs
@@ -6,7 +6,7 @@
//@ [thumb-mode] needs-llvm-components: arm
#![crate_type = "lib"]
-#![feature(no_core, lang_items, rustc_attrs, naked_functions)]
+#![feature(no_core, lang_items, rustc_attrs)]
#![no_core]
extern crate minicore;
@@ -20,8 +20,8 @@
// arm-mode: .arm
// thumb-mode: .thumb
#[no_mangle]
-#[naked]
-unsafe extern "C" fn test_unspecified() {
+#[unsafe(naked)]
+extern "C" fn test_unspecified() {
naked_asm!("bx lr");
}
@@ -33,9 +33,9 @@
// arm-mode: .arm
// thumb-mode: .thumb
#[no_mangle]
-#[naked]
+#[unsafe(naked)]
#[instruction_set(arm::t32)]
-unsafe extern "C" fn test_thumb() {
+extern "C" fn test_thumb() {
naked_asm!("bx lr");
}
@@ -46,8 +46,8 @@
// arm-mode: .arm
// thumb-mode: .thumb
#[no_mangle]
-#[naked]
+#[unsafe(naked)]
#[instruction_set(arm::a32)]
-unsafe extern "C" fn test_arm() {
+extern "C" fn test_arm() {
naked_asm!("bx lr");
}
diff --git a/tests/codegen/naked-fn/min-function-alignment.rs b/tests/codegen/naked-fn/min-function-alignment.rs
index 1330d79..1d778be 100644
--- a/tests/codegen/naked-fn/min-function-alignment.rs
+++ b/tests/codegen/naked-fn/min-function-alignment.rs
@@ -2,31 +2,31 @@
//@ needs-asm-support
//@ ignore-arm no "ret" mnemonic
-#![feature(naked_functions, fn_align)]
+#![feature(fn_align)]
#![crate_type = "lib"]
// functions without explicit alignment use the global minimum
//
// CHECK: .balign 16
#[no_mangle]
-#[naked]
-pub unsafe extern "C" fn naked_no_explicit_align() {
+#[unsafe(naked)]
+pub extern "C" fn naked_no_explicit_align() {
core::arch::naked_asm!("ret")
}
// CHECK: .balign 16
#[no_mangle]
#[repr(align(8))]
-#[naked]
-pub unsafe extern "C" fn naked_lower_align() {
+#[unsafe(naked)]
+pub extern "C" fn naked_lower_align() {
core::arch::naked_asm!("ret")
}
// CHECK: .balign 32
#[no_mangle]
#[repr(align(32))]
-#[naked]
-pub unsafe extern "C" fn naked_higher_align() {
+#[unsafe(naked)]
+pub extern "C" fn naked_higher_align() {
core::arch::naked_asm!("ret")
}
@@ -38,7 +38,7 @@
// CHECK: .balign 16
#[no_mangle]
#[cold]
-#[naked]
-pub unsafe extern "C" fn no_explicit_align_cold() {
+#[unsafe(naked)]
+pub extern "C" fn no_explicit_align_cold() {
core::arch::naked_asm!("ret")
}
diff --git a/tests/codegen/naked-fn/naked-functions.rs b/tests/codegen/naked-fn/naked-functions.rs
index 3fe7951..344af6e 100644
--- a/tests/codegen/naked-fn/naked-functions.rs
+++ b/tests/codegen/naked-fn/naked-functions.rs
@@ -13,7 +13,7 @@
//@[thumb] needs-llvm-components: arm
#![crate_type = "lib"]
-#![feature(no_core, lang_items, rustc_attrs, naked_functions)]
+#![feature(no_core, lang_items, rustc_attrs)]
#![no_core]
extern crate minicore;
@@ -60,8 +60,8 @@
// linux,win: .att_syntax
#[no_mangle]
-#[naked]
-pub unsafe extern "C" fn naked_empty() {
+#[unsafe(naked)]
+pub extern "C" fn naked_empty() {
#[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))]
naked_asm!("ret");
@@ -114,8 +114,8 @@
// linux,win: .att_syntax
#[no_mangle]
-#[naked]
-pub unsafe extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
+#[unsafe(naked)]
+pub extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize {
#[cfg(any(target_os = "windows", target_os = "linux"))]
{
naked_asm!("lea rax, [rdi + rsi]", "ret")
@@ -138,9 +138,9 @@
// thumb: .pushsection .text.some_different_name,\22ax\22, %progbits
// CHECK-LABEL: test_link_section:
#[no_mangle]
-#[naked]
+#[unsafe(naked)]
#[link_section = ".text.some_different_name"]
-pub unsafe extern "C" fn test_link_section() {
+pub extern "C" fn test_link_section() {
#[cfg(not(all(target_arch = "arm", target_feature = "thumb-mode")))]
naked_asm!("ret");
@@ -159,7 +159,7 @@
// win_i686-LABEL: @fastcall_cc@4:
#[cfg(target_os = "windows")]
#[no_mangle]
-#[naked]
-pub unsafe extern "fastcall" fn fastcall_cc(x: i32) -> i32 {
+#[unsafe(naked)]
+pub extern "fastcall" fn fastcall_cc(x: i32) -> i32 {
naked_asm!("ret");
}
diff --git a/tests/codegen/regparm-inreg.rs b/tests/codegen/regparm-inreg.rs
index 8dae3a8..1570280 100644
--- a/tests/codegen/regparm-inreg.rs
+++ b/tests/codegen/regparm-inreg.rs
@@ -3,7 +3,7 @@
// x86 only.
//@ add-core-stubs
-//@ compile-flags: --target i686-unknown-linux-gnu -Cno-prepopulate-passes -Copt-level=3
+//@ compile-flags: --target i686-unknown-linux-gnu -Cno-prepopulate-passes -Copt-level=3 -Ctarget-feature=+avx
//@ needs-llvm-components: x86
//@ revisions:regparm0 regparm1 regparm2 regparm3
diff --git a/tests/codegen/remap_path_prefix/aux_mod.rs b/tests/codegen/remap_path_prefix/aux_mod.rs
index c37e91c..3217e9e 100644
--- a/tests/codegen/remap_path_prefix/aux_mod.rs
+++ b/tests/codegen/remap_path_prefix/aux_mod.rs
@@ -1,4 +1,4 @@
-//@ ignore-test: this is not a test
+//@ ignore-auxiliary (used by `./main.rs`)
#[inline]
pub fn some_aux_mod_function() -> i32 {
diff --git a/tests/codegen/repr/transparent.rs b/tests/codegen/repr/transparent.rs
index e7e4c40..5475bfb 100644
--- a/tests/codegen/repr/transparent.rs
+++ b/tests/codegen/repr/transparent.rs
@@ -9,7 +9,7 @@
// For LoongArch: see codegen/loongarch-abi
#![crate_type = "lib"]
-#![feature(repr_simd, transparent_unions)]
+#![feature(repr_simd, transparent_unions, arm_target_feature)]
use std::marker::PhantomData;
@@ -139,6 +139,9 @@ pub extern "C" fn test_Nested2(_: Nested2) -> Nested2 {
// CHECK: define{{.*}}<4 x float> @test_Vector(<4 x float> %_1)
#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
pub extern "C" fn test_Vector(_: Vector) -> Vector {
loop {}
}
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
index 9bb46a3..c06b36d 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
@@ -29,6 +29,19 @@ pub unsafe fn gather_f32x2(
simd_gather(values, pointers, mask)
}
+// CHECK-LABEL: @gather_f32x2_unsigned
+#[no_mangle]
+pub unsafe fn gather_f32x2_unsigned(
+ pointers: Vec2<*const f32>,
+ mask: Vec2<u32>,
+ values: Vec2<f32>,
+) -> Vec2<f32> {
+ // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+ // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+ // CHECK: call <2 x float> @llvm.masked.gather.v2f32.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]], <2 x float> {{.*}})
+ simd_gather(values, pointers, mask)
+}
+
// CHECK-LABEL: @gather_pf32x2
#[no_mangle]
pub unsafe fn gather_pf32x2(
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs
index fcc4cb5..21578e6 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs
@@ -23,6 +23,19 @@ pub unsafe fn load_f32x2(mask: Vec2<i32>, pointer: *const f32, values: Vec2<f32>
simd_masked_load(mask, pointer, values)
}
+// CHECK-LABEL: @load_f32x2_unsigned
+#[no_mangle]
+pub unsafe fn load_f32x2_unsigned(
+ mask: Vec2<u32>,
+ pointer: *const f32,
+ values: Vec2<f32>,
+) -> Vec2<f32> {
+ // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+ // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+ // CHECK: call <2 x float> @llvm.masked.load.v2f32.p0(ptr {{.*}}, i32 4, <2 x i1> [[B]], <2 x float> {{.*}})
+ simd_masked_load(mask, pointer, values)
+}
+
// CHECK-LABEL: @load_pf32x4
#[no_mangle]
pub unsafe fn load_pf32x4(
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs
index 04f4a0c..22a8f7e 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs
@@ -23,6 +23,15 @@ pub unsafe fn store_f32x2(mask: Vec2<i32>, pointer: *mut f32, values: Vec2<f32>)
simd_masked_store(mask, pointer, values)
}
+// CHECK-LABEL: @store_f32x2_unsigned
+#[no_mangle]
+pub unsafe fn store_f32x2_unsigned(mask: Vec2<u32>, pointer: *mut f32, values: Vec2<f32>) {
+ // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+ // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+ // CHECK: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr {{.*}}, i32 4, <2 x i1> [[B]])
+ simd_masked_store(mask, pointer, values)
+}
+
// CHECK-LABEL: @store_pf32x4
#[no_mangle]
pub unsafe fn store_pf32x4(mask: Vec4<i32>, pointer: *mut *const f32, values: Vec4<*const f32>) {
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
index 9506f8f..0cc9e6a 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
@@ -25,6 +25,15 @@ pub unsafe fn scatter_f32x2(pointers: Vec2<*mut f32>, mask: Vec2<i32>, values: V
simd_scatter(values, pointers, mask)
}
+// CHECK-LABEL: @scatter_f32x2_unsigned
+#[no_mangle]
+pub unsafe fn scatter_f32x2_unsigned(pointers: Vec2<*mut f32>, mask: Vec2<u32>, values: Vec2<f32>) {
+ // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
+ // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
+ // CHECK: call void @llvm.masked.scatter.v2f32.v2p0(<2 x float> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]]
+ simd_scatter(values, pointers, mask)
+}
+
// CHECK-LABEL: @scatter_pf32x2
#[no_mangle]
pub unsafe fn scatter_pf32x2(
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs
index 71279d9..f6531c1 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs
@@ -22,6 +22,10 @@
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct i32x4([i32; 4]);
+#[repr(simd)]
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub struct u32x4([u32; 4]);
+
// CHECK-LABEL: @select_m8
#[no_mangle]
pub unsafe fn select_m8(m: b8x4, a: f32x4, b: f32x4) -> f32x4 {
@@ -40,6 +44,15 @@ pub unsafe fn select_m32(m: i32x4, a: f32x4, b: f32x4) -> f32x4 {
simd_select(m, a, b)
}
+// CHECK-LABEL: @select_m32_unsigned
+#[no_mangle]
+pub unsafe fn select_m32_unsigned(m: u32x4, a: f32x4, b: f32x4) -> f32x4 {
+ // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> %{{.*}}, {{<i32 31, i32 31, i32 31, i32 31>|splat \(i32 31\)}}
+ // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1>
+ // CHECK: select <4 x i1> [[B]]
+ simd_select(m, a, b)
+}
+
// CHECK-LABEL: @select_bitmask
#[no_mangle]
pub unsafe fn select_bitmask(m: i8, a: f32x8, b: f32x8) -> f32x8 {
diff --git a/tests/codegen/simd/extract-insert-dyn.rs b/tests/codegen/simd/extract-insert-dyn.rs
index 584e2c7..2c64f5d 100644
--- a/tests/codegen/simd/extract-insert-dyn.rs
+++ b/tests/codegen/simd/extract-insert-dyn.rs
@@ -1,6 +1,6 @@
//@compile-flags: -C opt-level=3 -C no-prepopulate-passes
-#![feature(core_intrinsics, repr_simd)]
+#![feature(core_intrinsics, repr_simd, arm_target_feature)]
#![no_std]
#![crate_type = "lib"]
#![allow(non_camel_case_types)]
@@ -21,6 +21,9 @@
// CHECK-LABEL: dyn_simd_extract
// CHECK: extractelement <16 x i8> %x, i32 %idx
#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
unsafe extern "C" fn dyn_simd_extract(x: i8x16, idx: u32) -> i8 {
simd_extract_dyn(x, idx)
}
@@ -28,6 +31,9 @@
// CHECK-LABEL: literal_dyn_simd_extract
// CHECK: extractelement <16 x i8> %x, i32 7
#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
unsafe extern "C" fn literal_dyn_simd_extract(x: i8x16) -> i8 {
simd_extract_dyn(x, 7)
}
@@ -35,6 +41,9 @@
// CHECK-LABEL: const_dyn_simd_extract
// CHECK: extractelement <16 x i8> %x, i32 7
#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
unsafe extern "C" fn const_dyn_simd_extract(x: i8x16) -> i8 {
simd_extract_dyn(x, const { 3 + 4 })
}
@@ -42,6 +51,9 @@
// CHECK-LABEL: const_simd_extract
// CHECK: extractelement <16 x i8> %x, i32 7
#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
unsafe extern "C" fn const_simd_extract(x: i8x16) -> i8 {
simd_extract(x, const { 3 + 4 })
}
@@ -49,6 +61,9 @@
// CHECK-LABEL: dyn_simd_insert
// CHECK: insertelement <16 x i8> %x, i8 %e, i32 %idx
#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
unsafe extern "C" fn dyn_simd_insert(x: i8x16, e: i8, idx: u32) -> i8x16 {
simd_insert_dyn(x, idx, e)
}
@@ -56,6 +71,9 @@
// CHECK-LABEL: literal_dyn_simd_insert
// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7
#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
unsafe extern "C" fn literal_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 {
simd_insert_dyn(x, 7, e)
}
@@ -63,6 +81,9 @@
// CHECK-LABEL: const_dyn_simd_insert
// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7
#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
unsafe extern "C" fn const_dyn_simd_insert(x: i8x16, e: i8) -> i8x16 {
simd_insert_dyn(x, const { 3 + 4 }, e)
}
@@ -70,6 +91,9 @@
// CHECK-LABEL: const_simd_insert
// CHECK: insertelement <16 x i8> %x, i8 %e, i32 7
#[no_mangle]
+#[cfg_attr(target_family = "wasm", target_feature(enable = "simd128"))]
+#[cfg_attr(target_arch = "arm", target_feature(enable = "neon"))]
+#[cfg_attr(target_arch = "x86", target_feature(enable = "sse"))]
unsafe extern "C" fn const_simd_insert(x: i8x16, e: i8) -> i8x16 {
simd_insert(x, const { 3 + 4 }, e)
}
diff --git a/tests/crashes/100618.rs b/tests/crashes/100618.rs
deleted file mode 100644
index 911c409..0000000
--- a/tests/crashes/100618.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//@ known-bug: #100618
-//@ compile-flags: -Cdebuginfo=2
-
-//@ only-x86_64
-enum Foo<T: 'static> {
- Value(T),
- Recursive(&'static Foo<Option<T>>),
-}
-
-fn main() {
- let _x = Foo::Value(());
-}
diff --git a/tests/crashes/115994.rs b/tests/crashes/115994.rs
deleted file mode 100644
index 23d1507..0000000
--- a/tests/crashes/115994.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//@ known-bug: #115994
-//@ compile-flags: -Cdebuginfo=2 --crate-type lib
-
-// To prevent "overflow while adding drop-check rules".
-use std::mem::ManuallyDrop;
-
-pub enum Foo<U> {
- Leaf(U),
-
- Branch(BoxedFoo<BoxedFoo<U>>),
-}
-
-pub type BoxedFoo<U> = ManuallyDrop<Box<Foo<U>>>;
-
-pub fn test() -> Foo<usize> {
- todo!()
-}
diff --git a/tests/crashes/121538.rs b/tests/crashes/121538.rs
deleted file mode 100644
index f18bad8..0000000
--- a/tests/crashes/121538.rs
+++ /dev/null
@@ -1,30 +0,0 @@
-//@ known-bug: #121538
-//@ compile-flags: -Cdebuginfo=2
-
-use std::marker::PhantomData;
-
-struct Digit<T> {
- elem: T
-}
-
-struct Node<T:'static> { m: PhantomData<&'static T> }
-
-enum FingerTree<T:'static> {
- Single(T),
-
- Deep(
- Digit<T>,
- Node<FingerTree<Node<T>>>,
- )
-}
-
-enum Wrapper<T:'static> {
- Simple,
- Other(FingerTree<T>),
-}
-
-fn main() {
- let w =
- Some(Wrapper::Simple::<u32>);
-
-}
diff --git a/tests/crashes/130627.rs b/tests/crashes/130627.rs
deleted file mode 100644
index 59d3606..0000000
--- a/tests/crashes/130627.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-//@ known-bug: #130627
-
-#![feature(trait_alias)]
-
-trait Test {}
-
-#[diagnostic::on_unimplemented(
- message="message",
- label="label",
- note="note"
-)]
-trait Alias = Test;
-
-// Use trait alias as bound on type parameter.
-fn foo<T: Alias>(v: &T) {
-}
-
-pub fn main() {
- foo(&1);
-}
diff --git a/tests/crashes/133868.rs b/tests/crashes/133868.rs
deleted file mode 100644
index dc25cb9..0000000
--- a/tests/crashes/133868.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ known-bug: #133868
-
-trait Foo {
- type Assoc;
-}
-
-trait Bar {
- fn method() -> impl Sized;
-}
-impl<T> Bar for T where <T as Foo>::Assoc: Sized
-{
- fn method() {}
-}
diff --git a/tests/crashes/74451.rs b/tests/crashes/74451.rs
deleted file mode 100644
index 8f93699..0000000
--- a/tests/crashes/74451.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-//@ known-bug: #74451
-//@ compile-flags: -Copt-level=0
-
-#![feature(specialization)]
-#![feature(unsize, coerce_unsized)]
-#![allow(incomplete_features)]
-#![crate_type = "lib"]
-
-use std::ops::CoerceUnsized;
-
-pub struct SmartassPtr<A: Smartass+?Sized>(A::Data);
-
-pub trait Smartass {
- type Data;
- type Data2: CoerceUnsized<*const [u8]>;
-}
-
-pub trait MaybeObjectSafe {}
-
-impl MaybeObjectSafe for () {}
-
-impl<T> Smartass for T {
- type Data = <Self as Smartass>::Data2;
- default type Data2 = *const [u8; 0];
-}
-
-impl Smartass for () {
- type Data2 = *const [u8; 1];
-}
-
-impl Smartass for dyn MaybeObjectSafe {
- type Data = *const [u8];
- type Data2 = *const [u8; 0];
-}
-
-impl<U: Smartass+?Sized, T: Smartass+?Sized> CoerceUnsized<SmartassPtr<T>> for SmartassPtr<U>
- where <U as Smartass>::Data: std::ops::CoerceUnsized<<T as Smartass>::Data>
-{}
-
-pub fn conv(s: SmartassPtr<()>) -> SmartassPtr<dyn MaybeObjectSafe> {
- s // This shouldn't coerce
-}
diff --git a/tests/debuginfo/drop-locations.rs b/tests/debuginfo/drop-locations.rs
index a55cf7b..91b3da5 100644
--- a/tests/debuginfo/drop-locations.rs
+++ b/tests/debuginfo/drop-locations.rs
@@ -1,5 +1,7 @@
//@ ignore-android
-//@ ignore-test: #128971
+
+// FIXME: stepping with "next" in a debugger skips past end-of-scope drops
+//@ ignore-test (broken, see #128971)
#![allow(unused)]
diff --git a/tests/debuginfo/recursive-enum.rs b/tests/debuginfo/recursive-enum.rs
index c2c3e71..b861e6d 100644
--- a/tests/debuginfo/recursive-enum.rs
+++ b/tests/debuginfo/recursive-enum.rs
@@ -4,7 +4,7 @@
// gdb-command:run
// Test whether compiling a recursive enum definition crashes debug info generation. The test case
-// is taken from issue #11083.
+// is taken from issue #11083 and #135093.
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
@@ -18,6 +18,21 @@ struct WindowCallbacks<'a> {
pos_callback: Option<Box<FnMut(&Window, i32, i32) + 'a>>,
}
+enum ExpandingRecursive<T> {
+ Recurse(Indirect<T>),
+ Item(T),
+}
+
+struct Indirect<U> {
+ rec: *const ExpandingRecursive<Option<U>>,
+}
+
+
fn main() {
let x = WindowCallbacks { pos_callback: None };
+
+ // EXPANDING RECURSIVE
+ let expanding_recursive: ExpandingRecursive<u64> = ExpandingRecursive::Recurse(Indirect {
+ rec: &ExpandingRecursive::Item(Option::Some(42)),
+ });
}
diff --git a/tests/crashes/107362.rs b/tests/debuginfo/recursive-type-with-gat.rs
similarity index 96%
rename from tests/crashes/107362.rs
rename to tests/debuginfo/recursive-type-with-gat.rs
index 8d55d61..b8a67d8 100644
--- a/tests/crashes/107362.rs
+++ b/tests/debuginfo/recursive-type-with-gat.rs
@@ -1,4 +1,3 @@
-//@ known-bug: #107362
//@ compile-flags: -Cdebuginfo=2
pub trait Functor
diff --git a/tests/incremental/const-generic-type-cycle.rs b/tests/incremental/const-generic-type-cycle.rs
index cd0437f..40a40eb 100644
--- a/tests/incremental/const-generic-type-cycle.rs
+++ b/tests/incremental/const-generic-type-cycle.rs
@@ -3,7 +3,6 @@
//
//@ compile-flags: -Zincremental-ignore-spans
//@ revisions: cpass cfail
-//@ error-pattern: cycle detected when computing type of `Bar::N`
#![feature(trait_alias)]
#![crate_type="lib"]
@@ -13,5 +12,9 @@ trait Bar<const N: usize> {}
#[cfg(cfail)]
trait Bar<const N: dyn BB> {}
+//[cfail]~^ ERROR cycle detected when computing type of `Bar::N`
+//[cfail]~| ERROR cycle detected when computing type of `Bar::N`
+//[cfail]~| ERROR cycle detected when computing type of `Bar::N`
+//[cfail]~| ERROR `(dyn Bar<{ 2 + 1 }> + 'static)` is forbidden as the type of a const generic parameter
trait BB = Bar<{ 2 + 1 }>;
diff --git a/tests/incremental/delayed_span_bug.rs b/tests/incremental/delayed_span_bug.rs
index 1534aca..7b409db 100644
--- a/tests/incremental/delayed_span_bug.rs
+++ b/tests/incremental/delayed_span_bug.rs
@@ -1,8 +1,7 @@
//@ revisions: cfail1 cfail2
//@ should-ice
-//@ error-pattern: delayed bug triggered by #[rustc_delayed_bug_from_inside_query]
#![feature(rustc_attrs)]
#[rustc_delayed_bug_from_inside_query]
-fn main() {}
+fn main() {} //~ ERROR delayed bug triggered by #[rustc_delayed_bug_from_inside_query]
diff --git a/tests/incremental/link_order/main.rs b/tests/incremental/link_order/main.rs
index 847a47a..20931e2 100644
--- a/tests/incremental/link_order/main.rs
+++ b/tests/incremental/link_order/main.rs
@@ -1,5 +1,4 @@
//@ aux-build:my_lib.rs
-//@ error-pattern: error: linking with
//@ revisions:cfail1 cfail2
//@ compile-flags:-Z query-dep-graph
@@ -10,3 +9,5 @@
extern crate my_lib;
fn main() {}
+
+//~? ERROR linking with
diff --git a/tests/mir-opt/building/logical_or_in_conditional.rs b/tests/mir-opt/building/logical_or_in_conditional.rs
index e6872e6..249ccf7 100644
--- a/tests/mir-opt/building/logical_or_in_conditional.rs
+++ b/tests/mir-opt/building/logical_or_in_conditional.rs
@@ -1,6 +1,6 @@
// skip-filecheck
//@ compile-flags: -Z validate-mir
-#![feature(let_chains)]
+//@ edition: 2024
struct Droppy(u8);
impl Drop for Droppy {
fn drop(&mut self) {
diff --git a/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir b/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir
index 72bd460..327b3b6 100644
--- a/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir
+++ b/tests/mir-opt/building/logical_or_in_conditional.test_complex.built.after.mir
@@ -19,7 +19,7 @@
bb0: {
StorageLive(_1);
StorageLive(_2);
- _2 = E::f() -> [return: bb1, unwind: bb34];
+ _2 = E::f() -> [return: bb1, unwind: bb35];
}
bb1: {
@@ -42,7 +42,7 @@
bb5: {
StorageLive(_4);
- _4 = always_true() -> [return: bb6, unwind: bb34];
+ _4 = always_true() -> [return: bb6, unwind: bb35];
}
bb6: {
@@ -64,7 +64,7 @@
}
bb9: {
- drop(_7) -> [return: bb11, unwind: bb34];
+ drop(_7) -> [return: bb11, unwind: bb35];
}
bb10: {
@@ -78,7 +78,7 @@
}
bb12: {
- drop(_7) -> [return: bb13, unwind: bb34];
+ drop(_7) -> [return: bb13, unwind: bb35];
}
bb13: {
@@ -98,7 +98,7 @@
}
bb15: {
- drop(_10) -> [return: bb17, unwind: bb34];
+ drop(_10) -> [return: bb17, unwind: bb35];
}
bb16: {
@@ -113,11 +113,12 @@
bb18: {
_1 = const ();
+ StorageDead(_2);
goto -> bb22;
}
bb19: {
- drop(_10) -> [return: bb20, unwind: bb34];
+ drop(_10) -> [return: bb20, unwind: bb35];
}
bb20: {
@@ -127,6 +128,7 @@
}
bb21: {
+ StorageDead(_2);
_1 = const ();
goto -> bb22;
}
@@ -135,10 +137,9 @@
StorageDead(_8);
StorageDead(_5);
StorageDead(_4);
- StorageDead(_2);
StorageDead(_1);
StorageLive(_11);
- _11 = always_true() -> [return: bb23, unwind: bb34];
+ _11 = always_true() -> [return: bb23, unwind: bb35];
}
bb23: {
@@ -146,7 +147,7 @@
}
bb24: {
- goto -> bb32;
+ goto -> bb33;
}
bb25: {
@@ -155,7 +156,7 @@
bb26: {
StorageLive(_12);
- _12 = E::f() -> [return: bb27, unwind: bb34];
+ _12 = E::f() -> [return: bb27, unwind: bb35];
}
bb27: {
@@ -178,21 +179,26 @@
bb31: {
_0 = const ();
- goto -> bb33;
+ StorageDead(_12);
+ goto -> bb34;
}
bb32: {
- _0 = const ();
+ StorageDead(_12);
goto -> bb33;
}
bb33: {
+ _0 = const ();
+ goto -> bb34;
+ }
+
+ bb34: {
StorageDead(_11);
- StorageDead(_12);
return;
}
- bb34 (cleanup): {
+ bb35 (cleanup): {
resume;
}
}
diff --git a/tests/mir-opt/building/match/exponential_or.match_tuple.SimplifyCfg-initial.after.mir b/tests/mir-opt/building/match/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
index d52241b..2a965fe 100644
--- a/tests/mir-opt/building/match/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/building/match/exponential_or.match_tuple.SimplifyCfg-initial.after.mir
@@ -24,43 +24,47 @@
bb1: {
_0 = const 0_u32;
- goto -> bb10;
+ goto -> bb11;
}
bb2: {
- _2 = discriminant((_1.2: std::option::Option<i32>));
- switchInt(move _2) -> [0: bb4, 1: bb3, otherwise: bb1];
+ switchInt(copy (_1.1: bool)) -> [0: bb3, otherwise: bb3];
}
bb3: {
- switchInt(copy (((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1: bb4, 8: bb4, otherwise: bb1];
+ _2 = discriminant((_1.2: std::option::Option<i32>));
+ switchInt(move _2) -> [0: bb5, 1: bb4, otherwise: bb1];
}
bb4: {
- _5 = Le(const 6_u32, copy (_1.3: u32));
- switchInt(move _5) -> [0: bb5, otherwise: bb7];
+ switchInt(copy (((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1: bb5, 8: bb5, otherwise: bb1];
}
bb5: {
- _3 = Le(const 13_u32, copy (_1.3: u32));
- switchInt(move _3) -> [0: bb1, otherwise: bb6];
+ _5 = Le(const 6_u32, copy (_1.3: u32));
+ switchInt(move _5) -> [0: bb6, otherwise: bb8];
}
bb6: {
- _4 = Le(copy (_1.3: u32), const 16_u32);
- switchInt(move _4) -> [0: bb1, otherwise: bb8];
+ _3 = Le(const 13_u32, copy (_1.3: u32));
+ switchInt(move _3) -> [0: bb1, otherwise: bb7];
}
bb7: {
- _6 = Le(copy (_1.3: u32), const 9_u32);
- switchInt(move _6) -> [0: bb5, otherwise: bb8];
+ _4 = Le(copy (_1.3: u32), const 16_u32);
+ switchInt(move _4) -> [0: bb1, otherwise: bb9];
}
bb8: {
- falseEdge -> [real: bb9, imaginary: bb1];
+ _6 = Le(copy (_1.3: u32), const 9_u32);
+ switchInt(move _6) -> [0: bb6, otherwise: bb9];
}
bb9: {
+ falseEdge -> [real: bb10, imaginary: bb1];
+ }
+
+ bb10: {
StorageLive(_7);
_7 = copy (_1.0: u32);
StorageLive(_8);
@@ -74,10 +78,10 @@
StorageDead(_9);
StorageDead(_8);
StorageDead(_7);
- goto -> bb10;
+ goto -> bb11;
}
- bb10: {
+ bb11: {
return;
}
}
diff --git a/tests/mir-opt/dead-store-elimination/place_mention.rs b/tests/mir-opt/dead-store-elimination/place_mention.rs
index 5e4a286..1848a02 100644
--- a/tests/mir-opt/dead-store-elimination/place_mention.rs
+++ b/tests/mir-opt/dead-store-elimination/place_mention.rs
@@ -2,7 +2,7 @@
// and don't remove it as a dead store.
//
//@ test-mir-pass: DeadStoreElimination-initial
-//@ compile-flags: -Zmir-keep-place-mention
+//@ compile-flags: -Zmir-preserve-ub
// EMIT_MIR place_mention.main.DeadStoreElimination-initial.diff
fn main() {
diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff
index 56d4d50..151580d 100644
--- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-abort.diff
@@ -33,7 +33,7 @@
- _4 = g() -> [return: bb1, unwind unreachable];
+ _4 = {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8 (#0)};
+ _3 = &mut _4;
-+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}> { __pointer: copy _3 };
++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}> { pointer: copy _3 };
+ StorageDead(_3);
+ StorageLive(_5);
+ _5 = const false;
diff --git a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff
index 751916a..6196fc0 100644
--- a/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff
+++ b/tests/mir-opt/inline/inline_coroutine.main.Inline.panic-unwind.diff
@@ -33,7 +33,7 @@
- _4 = g() -> [return: bb1, unwind continue];
+ _4 = {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8 (#0)};
+ _3 = &mut _4;
-+ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}> { __pointer: copy _3 };
++ _2 = Pin::<&mut {coroutine@$DIR/inline_coroutine.rs:20:5: 20:8}> { pointer: copy _3 };
+ StorageDead(_3);
+ StorageLive(_5);
+ _5 = const false;
diff --git "a/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-abort.diff" "b/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-abort.diff"
index e49d7ce..1e9a6dd 100644
--- "a/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-abort.diff"
+++ "b/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-abort.diff"
@@ -121,7 +121,7 @@
- }
-
- bb2: {
-+ _4 = Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}> { __pointer: copy _5 };
++ _4 = Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}> { pointer: copy _5 };
StorageDead(_5);
StorageLive(_6);
StorageLive(_7);
@@ -218,7 +218,7 @@
+ _37 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>);
+ _20 = &mut (*_21);
-+ _19 = Pin::<&mut std::future::Ready<()>> { __pointer: copy _20 };
++ _19 = Pin::<&mut std::future::Ready<()>> { pointer: copy _20 };
+ StorageDead(_20);
+ StorageLive(_22);
+ StorageLive(_23);
@@ -239,7 +239,7 @@
+ _48 = &mut (_19.0: &mut std::future::Ready<()>);
+ _45 = copy (_19.0: &mut std::future::Ready<()>);
+ StorageDead(_48);
-+ _47 = Pin::<&mut std::future::Ready<()>> { __pointer: copy _45 };
++ _47 = Pin::<&mut std::future::Ready<()>> { pointer: copy _45 };
+ StorageDead(_47);
+ _44 = &mut ((*_45).0: std::option::Option<()>);
+ StorageLive(_49);
diff --git "a/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-unwind.diff" "b/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-unwind.diff"
index e7aed556..94b89a31 100644
--- "a/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-unwind.diff"
+++ "b/tests/mir-opt/inline_coroutine_body.run2-\173closure\0430\175.Inline.panic-unwind.diff"
@@ -123,7 +123,7 @@
- }
-
- bb2: {
-+ _4 = Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}> { __pointer: copy _5 };
++ _4 = Pin::<&mut {async fn body of ActionPermit<'_, T>::perform()}> { pointer: copy _5 };
StorageDead(_5);
StorageLive(_6);
StorageLive(_7);
@@ -235,7 +235,7 @@
+ _37 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>);
+ _20 = &mut (*_21);
-+ _19 = Pin::<&mut std::future::Ready<()>> { __pointer: copy _20 };
++ _19 = Pin::<&mut std::future::Ready<()>> { pointer: copy _20 };
+ StorageDead(_20);
+ StorageLive(_22);
+ StorageLive(_23);
@@ -256,7 +256,7 @@
+ _50 = &mut (_19.0: &mut std::future::Ready<()>);
+ _47 = copy (_19.0: &mut std::future::Ready<()>);
+ StorageDead(_50);
-+ _49 = Pin::<&mut std::future::Ready<()>> { __pointer: copy _47 };
++ _49 = Pin::<&mut std::future::Ready<()>> { pointer: copy _47 };
+ StorageDead(_49);
+ _46 = &mut ((*_47).0: std::option::Option<()>);
+ StorageLive(_51);
diff --git a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff
index 047441e..c3272f2 100644
--- a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff
+++ b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-abort.diff
@@ -3,7 +3,7 @@
fn bitwise_not() -> i32 {
let mut _0: i32;
- let mut _1: i32;
+ let _1: i32;
let mut _2: bool;
let mut _3: i32;
let mut _4: i32;
@@ -13,7 +13,6 @@
bb0: {
StorageLive(_1);
- _1 = const 0_i32;
_1 = const 1_i32;
StorageLive(_2);
StorageLive(_3);
@@ -22,7 +21,8 @@
_3 = Not(move _4);
StorageDead(_4);
_2 = Eq(move _3, const 0_i32);
- switchInt(move _2) -> [0: bb2, otherwise: bb1];
+- switchInt(move _2) -> [0: bb2, otherwise: bb1];
++ goto -> bb2;
}
bb1: {
diff --git a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff
index 047441e..c3272f2 100644
--- a/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff
+++ b/tests/mir-opt/jump_threading.bitwise_not.JumpThreading.panic-unwind.diff
@@ -3,7 +3,7 @@
fn bitwise_not() -> i32 {
let mut _0: i32;
- let mut _1: i32;
+ let _1: i32;
let mut _2: bool;
let mut _3: i32;
let mut _4: i32;
@@ -13,7 +13,6 @@
bb0: {
StorageLive(_1);
- _1 = const 0_i32;
_1 = const 1_i32;
StorageLive(_2);
StorageLive(_3);
@@ -22,7 +21,8 @@
_3 = Not(move _4);
StorageDead(_4);
_2 = Eq(move _3, const 0_i32);
- switchInt(move _2) -> [0: bb2, otherwise: bb1];
+- switchInt(move _2) -> [0: bb2, otherwise: bb1];
++ goto -> bb2;
}
bb1: {
diff --git a/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-abort.diff
new file mode 100644
index 0000000..ad8be1e
--- /dev/null
+++ b/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-abort.diff
@@ -0,0 +1,46 @@
+- // MIR for `logical_not` before JumpThreading
++ // MIR for `logical_not` after JumpThreading
+
+ fn logical_not() -> i32 {
+ let mut _0: i32;
+ let _1: bool;
+ let mut _2: bool;
+ let mut _3: bool;
+ let mut _4: bool;
+ scope 1 {
+ debug a => _1;
+ }
+
+ bb0: {
+ StorageLive(_1);
+ _1 = const false;
+ StorageLive(_2);
+ StorageLive(_3);
+ StorageLive(_4);
+ _4 = copy _1;
+ _3 = Not(move _4);
+ StorageDead(_4);
+ _2 = Eq(move _3, const true);
+- switchInt(move _2) -> [0: bb2, otherwise: bb1];
++ goto -> bb1;
+ }
+
+ bb1: {
+ StorageDead(_3);
+ _0 = const 1_i32;
+ goto -> bb3;
+ }
+
+ bb2: {
+ StorageDead(_3);
+ _0 = const 0_i32;
+ goto -> bb3;
+ }
+
+ bb3: {
+ StorageDead(_2);
+ StorageDead(_1);
+ return;
+ }
+ }
+
diff --git a/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-unwind.diff
new file mode 100644
index 0000000..ad8be1e
--- /dev/null
+++ b/tests/mir-opt/jump_threading.logical_not.JumpThreading.panic-unwind.diff
@@ -0,0 +1,46 @@
+- // MIR for `logical_not` before JumpThreading
++ // MIR for `logical_not` after JumpThreading
+
+ fn logical_not() -> i32 {
+ let mut _0: i32;
+ let _1: bool;
+ let mut _2: bool;
+ let mut _3: bool;
+ let mut _4: bool;
+ scope 1 {
+ debug a => _1;
+ }
+
+ bb0: {
+ StorageLive(_1);
+ _1 = const false;
+ StorageLive(_2);
+ StorageLive(_3);
+ StorageLive(_4);
+ _4 = copy _1;
+ _3 = Not(move _4);
+ StorageDead(_4);
+ _2 = Eq(move _3, const true);
+- switchInt(move _2) -> [0: bb2, otherwise: bb1];
++ goto -> bb1;
+ }
+
+ bb1: {
+ StorageDead(_3);
+ _0 = const 1_i32;
+ goto -> bb3;
+ }
+
+ bb2: {
+ StorageDead(_3);
+ _0 = const 0_i32;
+ goto -> bb3;
+ }
+
+ bb3: {
+ StorageDead(_2);
+ StorageDead(_1);
+ return;
+ }
+ }
+
diff --git a/tests/mir-opt/jump_threading.rs b/tests/mir-opt/jump_threading.rs
index 743ee8e..009e106 100644
--- a/tests/mir-opt/jump_threading.rs
+++ b/tests/mir-opt/jump_threading.rs
@@ -532,14 +532,19 @@ fn floats() -> u32 {
pub fn bitwise_not() -> i32 {
// CHECK-LABEL: fn bitwise_not(
- // CHECK: switchInt(
// Test for #131195, which was optimizing `!a == b` into `a != b`.
- let mut a: i32 = 0;
- a = 1;
+ let a = 1;
if !a == 0 { 1 } else { 0 }
}
+pub fn logical_not() -> i32 {
+ // CHECK-LABEL: fn logical_not(
+
+ let a = false;
+ if !a == true { 1 } else { 0 }
+}
+
fn main() {
// CHECK-LABEL: fn main(
too_complex(Ok(0));
@@ -555,6 +560,8 @@ fn main() {
aggregate(7);
assume(7, false);
floats();
+ bitwise_not();
+ logical_not();
}
// EMIT_MIR jump_threading.too_complex.JumpThreading.diff
@@ -572,3 +579,4 @@ fn main() {
// EMIT_MIR jump_threading.aggregate_copy.JumpThreading.diff
// EMIT_MIR jump_threading.floats.JumpThreading.diff
// EMIT_MIR jump_threading.bitwise_not.JumpThreading.diff
+// EMIT_MIR jump_threading.logical_not.JumpThreading.diff
diff --git a/tests/mir-opt/or_pattern.single_switchint.SimplifyCfg-initial.after.mir b/tests/mir-opt/or_pattern.single_switchint.SimplifyCfg-initial.after.mir
index 889ff6f..be0931e 100644
--- a/tests/mir-opt/or_pattern.single_switchint.SimplifyCfg-initial.after.mir
+++ b/tests/mir-opt/or_pattern.single_switchint.SimplifyCfg-initial.after.mir
@@ -14,7 +14,7 @@
}
bb1: {
- switchInt(copy (_2.0: i32)) -> [3: bb8, 4: bb8, otherwise: bb7];
+ switchInt(copy (_2.0: i32)) -> [3: bb9, 4: bb9, otherwise: bb8];
}
bb2: {
@@ -22,7 +22,7 @@
}
bb3: {
- falseEdge -> [real: bb12, imaginary: bb4];
+ falseEdge -> [real: bb14, imaginary: bb4];
}
bb4: {
@@ -30,43 +30,51 @@
}
bb5: {
- falseEdge -> [real: bb11, imaginary: bb6];
+ falseEdge -> [real: bb13, imaginary: bb6];
}
bb6: {
- falseEdge -> [real: bb10, imaginary: bb1];
+ switchInt(copy (_2.1: bool)) -> [0: bb7, otherwise: bb7];
}
bb7: {
- _1 = const 5_i32;
- goto -> bb13;
+ falseEdge -> [real: bb12, imaginary: bb1];
}
bb8: {
- falseEdge -> [real: bb9, imaginary: bb7];
+ _1 = const 5_i32;
+ goto -> bb15;
}
bb9: {
- _1 = const 4_i32;
- goto -> bb13;
+ switchInt(copy (_2.1: bool)) -> [0: bb10, otherwise: bb10];
}
bb10: {
- _1 = const 3_i32;
- goto -> bb13;
+ falseEdge -> [real: bb11, imaginary: bb8];
}
bb11: {
- _1 = const 2_i32;
- goto -> bb13;
+ _1 = const 4_i32;
+ goto -> bb15;
}
bb12: {
- _1 = const 1_i32;
- goto -> bb13;
+ _1 = const 3_i32;
+ goto -> bb15;
}
bb13: {
+ _1 = const 2_i32;
+ goto -> bb15;
+ }
+
+ bb14: {
+ _1 = const 1_i32;
+ goto -> bb15;
+ }
+
+ bb15: {
StorageDead(_2);
StorageDead(_1);
_0 = const ();
diff --git a/tests/mir-opt/read_from_trivial_switch.main.SimplifyCfg-initial.diff b/tests/mir-opt/read_from_trivial_switch.main.SimplifyCfg-initial.diff
new file mode 100644
index 0000000..8775840
--- /dev/null
+++ b/tests/mir-opt/read_from_trivial_switch.main.SimplifyCfg-initial.diff
@@ -0,0 +1,49 @@
+- // MIR for `main` before SimplifyCfg-initial
++ // MIR for `main` after SimplifyCfg-initial
+
+ fn main() -> () {
+ let mut _0: ();
+ let _1: &i32;
+ let _2: i32;
+ scope 1 {
+ debug ref_ => _1;
+ scope 2 {
+ }
+ }
+
+ bb0: {
+ StorageLive(_1);
+ StorageLive(_2);
+ _2 = const 1_i32;
+ _1 = &_2;
+ FakeRead(ForLet(None), _1);
+ PlaceMention(_1);
+- switchInt(copy (*_1)) -> [0: bb2, otherwise: bb1];
++ switchInt(copy (*_1)) -> [0: bb1, otherwise: bb1];
+ }
+
+ bb1: {
+- goto -> bb5;
+- }
+-
+- bb2: {
+- goto -> bb5;
+- }
+-
+- bb3: {
+- goto -> bb1;
+- }
+-
+- bb4: {
+- FakeRead(ForMatchedPlace(None), _1);
+- unreachable;
+- }
+-
+- bb5: {
+ _0 = const ();
+ StorageDead(_2);
+ StorageDead(_1);
+ return;
+ }
+ }
+
diff --git a/tests/mir-opt/read_from_trivial_switch.rs b/tests/mir-opt/read_from_trivial_switch.rs
new file mode 100644
index 0000000..1c64c1d
--- /dev/null
+++ b/tests/mir-opt/read_from_trivial_switch.rs
@@ -0,0 +1,15 @@
+// Ensure that we don't optimize out `SwitchInt` reads even if that terminator
+// branches to the same basic block on every target, since the operand may have
+// side-effects that affect analysis of the MIR.
+//
+// See <https://github.com/rust-lang/miri/issues/4237>.
+
+//@ test-mir-pass: SimplifyCfg-initial
+//@ compile-flags: -Zmir-preserve-ub
+
+// EMIT_MIR read_from_trivial_switch.main.SimplifyCfg-initial.diff
+fn main() {
+ let ref_ = &1i32;
+ // CHECK: switchInt
+ let &(0 | _) = ref_;
+}
diff --git a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir
index ee6e16d..7d7cb76 100644
--- a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir
+++ b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-abort.mir
@@ -73,9 +73,6 @@
}
bb7: {
- backward incompatible drop(_2);
- backward incompatible drop(_4);
- backward incompatible drop(_5);
goto -> bb21;
}
diff --git a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir
index ee6e16d..7d7cb76 100644
--- a/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir
+++ b/tests/mir-opt/tail_expr_drop_order_unwind.method_1.ElaborateDrops.after.panic-unwind.mir
@@ -73,9 +73,6 @@
}
bb7: {
- backward incompatible drop(_2);
- backward incompatible drop(_4);
- backward incompatible drop(_5);
goto -> bb21;
}
diff --git a/tests/pretty/ast-stmt-expr-attr.rs b/tests/pretty/ast-stmt-expr-attr.rs
index fd7272a..4ca6046 100644
--- a/tests/pretty/ast-stmt-expr-attr.rs
+++ b/tests/pretty/ast-stmt-expr-attr.rs
@@ -2,7 +2,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn syntax() {
let _ = #[attr] [];
let _ = #[attr] [0];
diff --git a/tests/pretty/autodiff_forward.pp b/tests/pretty/autodiff/autodiff_forward.pp
similarity index 100%
rename from tests/pretty/autodiff_forward.pp
rename to tests/pretty/autodiff/autodiff_forward.pp
diff --git a/tests/pretty/autodiff_forward.rs b/tests/pretty/autodiff/autodiff_forward.rs
similarity index 100%
rename from tests/pretty/autodiff_forward.rs
rename to tests/pretty/autodiff/autodiff_forward.rs
diff --git a/tests/pretty/autodiff_reverse.pp b/tests/pretty/autodiff/autodiff_reverse.pp
similarity index 100%
rename from tests/pretty/autodiff_reverse.pp
rename to tests/pretty/autodiff/autodiff_reverse.pp
diff --git a/tests/pretty/autodiff_reverse.rs b/tests/pretty/autodiff/autodiff_reverse.rs
similarity index 100%
rename from tests/pretty/autodiff_reverse.rs
rename to tests/pretty/autodiff/autodiff_reverse.rs
diff --git a/tests/pretty/autodiff/inherent_impl.pp b/tests/pretty/autodiff/inherent_impl.pp
new file mode 100644
index 0000000..97ac766
--- /dev/null
+++ b/tests/pretty/autodiff/inherent_impl.pp
@@ -0,0 +1,41 @@
+#![feature(prelude_import)]
+#![no_std]
+//@ needs-enzyme
+
+#![feature(autodiff)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+//@ pretty-mode:expanded
+//@ pretty-compare-only
+//@ pp-exact:inherent_impl.pp
+
+use std::autodiff::autodiff;
+
+struct Foo {
+ a: f64,
+}
+
+trait MyTrait {
+ fn f(&self, x: f64)
+ -> f64;
+ fn df(&self, x: f64, seed: f64)
+ -> (f64, f64);
+}
+
+impl MyTrait for Foo {
+ #[rustc_autodiff]
+ #[inline(never)]
+ fn f(&self, x: f64) -> f64 {
+ self.a * 0.25 * (x * x - 1.0 - 2.0 * x.ln())
+ }
+ #[rustc_autodiff(Reverse, 1, Const, Active, Active)]
+ #[inline(never)]
+ fn df(&self, x: f64, dret: f64) -> (f64, f64) {
+ unsafe { asm!("NOP", options(pure, nomem)); };
+ ::core::hint::black_box(self.f(x));
+ ::core::hint::black_box((dret,));
+ ::core::hint::black_box((self.f(x), f64::default()))
+ }
+}
diff --git a/tests/pretty/autodiff/inherent_impl.rs b/tests/pretty/autodiff/inherent_impl.rs
new file mode 100644
index 0000000..59de93f
--- /dev/null
+++ b/tests/pretty/autodiff/inherent_impl.rs
@@ -0,0 +1,24 @@
+//@ needs-enzyme
+
+#![feature(autodiff)]
+//@ pretty-mode:expanded
+//@ pretty-compare-only
+//@ pp-exact:inherent_impl.pp
+
+use std::autodiff::autodiff;
+
+struct Foo {
+ a: f64,
+}
+
+trait MyTrait {
+ fn f(&self, x: f64) -> f64;
+ fn df(&self, x: f64, seed: f64) -> (f64, f64);
+}
+
+impl MyTrait for Foo {
+ #[autodiff(df, Reverse, Const, Active, Active)]
+ fn f(&self, x: f64) -> f64 {
+ self.a * 0.25 * (x * x - 1.0 - 2.0 * x.ln())
+ }
+}
diff --git a/tests/pretty/enum-variant-vis.rs b/tests/pretty/enum-variant-vis.rs
index 3397e7d..5b9f7e0 100644
--- a/tests/pretty/enum-variant-vis.rs
+++ b/tests/pretty/enum-variant-vis.rs
@@ -4,5 +4,5 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
enum Foo { pub V, }
diff --git a/tests/pretty/hir-fn-variadic.pp b/tests/pretty/hir-fn-variadic.pp
index dfbaff6..b6bc8e9 100644
--- a/tests/pretty/hir-fn-variadic.pp
+++ b/tests/pretty/hir-fn-variadic.pp
@@ -13,3 +13,39 @@
}
unsafe extern "C" fn bar(_: i32, mut va2: ...) -> usize { va2.arg::<usize>() }
+
+fn main() {
+ fn g1(_: extern "C" fn(_: u8, va: ...)) { }
+ fn g2(_: extern "C" fn(_: u8, ...)) { }
+ fn g3(_: extern "C" fn(u8, va: ...)) { }
+ fn g4(_: extern "C" fn(u8, ...)) { }
+
+ fn g5(_: extern "C" fn(va: ...)) { }
+ fn g6(_: extern "C" fn(...)) { }
+
+ {
+ let _ =
+ {
+ unsafe extern "C" fn f1(_: u8, va: ...) { }
+ };
+ };
+ {
+ let _ =
+ {
+ unsafe extern "C" fn f2(_: u8, _: ...) { }
+ };
+ };
+
+ {
+ let _ =
+ {
+ unsafe extern "C" fn f5(va: ...) { }
+ };
+ };
+ {
+ let _ =
+ {
+ unsafe extern "C" fn f6(_: ...) { }
+ };
+ };
+}
diff --git a/tests/pretty/hir-fn-variadic.rs b/tests/pretty/hir-fn-variadic.rs
index 3d3f7ee..99aa402 100644
--- a/tests/pretty/hir-fn-variadic.rs
+++ b/tests/pretty/hir-fn-variadic.rs
@@ -11,3 +11,19 @@
pub unsafe extern "C" fn bar(_: i32, mut va2: ...) -> usize {
va2.arg::<usize>()
}
+
+fn main() {
+ fn g1(_: extern "C" fn(_: u8, va: ...)) {}
+ fn g2(_: extern "C" fn(_: u8, ...)) {}
+ fn g3(_: extern "C" fn(u8, va: ...)) {}
+ fn g4(_: extern "C" fn(u8, ...)) {}
+
+ fn g5(_: extern "C" fn(va: ...)) {}
+ fn g6(_: extern "C" fn(...)) {}
+
+ _ = { unsafe extern "C" fn f1(_: u8, va: ...) {} };
+ _ = { unsafe extern "C" fn f2(_: u8, ...) {} };
+
+ _ = { unsafe extern "C" fn f5(va: ...) {} };
+ _ = { unsafe extern "C" fn f6(...) {} };
+}
diff --git a/tests/pretty/if-attr.rs b/tests/pretty/if-attr.rs
index 89d6130..8b343a8 100644
--- a/tests/pretty/if-attr.rs
+++ b/tests/pretty/if-attr.rs
@@ -1,6 +1,6 @@
//@ pp-exact
-#[cfg(FALSE)]
+#[cfg(false)]
fn simple_attr() {
#[attr]
@@ -10,21 +10,21 @@ fn simple_attr() {
if true {}
}
-#[cfg(FALSE)]
+#[cfg(false)]
fn if_else_chain() {
#[first_attr]
if true {} else if false {} else {}
}
-#[cfg(FALSE)]
+#[cfg(false)]
fn if_let() {
#[attr]
if let Some(_) = Some(true) {}
}
-#[cfg(FALSE)]
+#[cfg(false)]
fn let_attr_if() {
let _ = #[attr] if let _ = 0 {};
let _ = #[attr] if true {};
diff --git a/tests/pretty/nested-item-vis-defaultness.rs b/tests/pretty/nested-item-vis-defaultness.rs
index 1e971fc..68f56a1 100644
--- a/tests/pretty/nested-item-vis-defaultness.rs
+++ b/tests/pretty/nested-item-vis-defaultness.rs
@@ -4,7 +4,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
extern "C" {
static X: u8;
type X;
@@ -14,7 +14,7 @@ fn main() {}
pub fn foo();
}
-#[cfg(FALSE)]
+#[cfg(false)]
trait T {
const X: u8;
type X;
@@ -30,7 +30,7 @@ trait T {
pub default fn foo();
}
-#[cfg(FALSE)]
+#[cfg(false)]
impl T for S {
const X: u8;
type X;
diff --git a/tests/pretty/postfix-yield.rs b/tests/pretty/postfix-yield.rs
index f76e814..60380a40 100644
--- a/tests/pretty/postfix-yield.rs
+++ b/tests/pretty/postfix-yield.rs
@@ -2,7 +2,8 @@
//@ edition: 2024
//@ pp-exact
-#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr)]
+#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr,
+stmt_expr_attributes)]
use std::ops::{Coroutine, CoroutineState};
use std::pin::pin;
diff --git a/tests/run-make/broken-pipe-no-ice/rmake.rs b/tests/run-make/broken-pipe-no-ice/rmake.rs
index 3e54b57..0521b39 100644
--- a/tests/run-make/broken-pipe-no-ice/rmake.rs
+++ b/tests/run-make/broken-pipe-no-ice/rmake.rs
@@ -14,9 +14,7 @@
use std::io::Read;
use std::process::{Command, Stdio};
-// FIXME(#137532): replace `os_pipe` dependency with std `anonymous_pipe` once that stabilizes and
-// reaches beta.
-use run_make_support::{env_var, os_pipe};
+use run_make_support::env_var;
#[derive(Debug, PartialEq)]
enum Binary {
@@ -25,7 +23,7 @@ enum Binary {
}
fn check_broken_pipe_handled_gracefully(bin: Binary, mut cmd: Command) {
- let (reader, writer) = os_pipe::pipe().unwrap();
+ let (reader, writer) = std::io::pipe().unwrap();
drop(reader); // close read-end
cmd.stdout(writer).stderr(Stdio::piped());
diff --git a/tests/run-make/crate-data-smoke/rmake.rs b/tests/run-make/crate-data-smoke/rmake.rs
index 70f8e46..b5708d0 100644
--- a/tests/run-make/crate-data-smoke/rmake.rs
+++ b/tests/run-make/crate-data-smoke/rmake.rs
@@ -1,9 +1,20 @@
-use run_make_support::{bin_name, rust_lib_name, rustc};
+use run_make_support::{bin_name, rust_lib_name, rustc, target};
fn main() {
- rustc().print("crate-name").input("crate.rs").run().assert_stdout_equals("foo");
- rustc().print("file-names").input("crate.rs").run().assert_stdout_equals(bin_name("foo"));
rustc()
+ .target(target())
+ .print("crate-name")
+ .input("crate.rs")
+ .run()
+ .assert_stdout_equals("foo");
+ rustc()
+ .target(target())
+ .print("file-names")
+ .input("crate.rs")
+ .run()
+ .assert_stdout_equals(bin_name("foo"));
+ rustc()
+ .target(target())
.print("file-names")
.crate_type("lib")
.arg("--test")
@@ -11,11 +22,22 @@ fn main() {
.run()
.assert_stdout_equals(bin_name("foo"));
rustc()
+ .target(target())
.print("file-names")
.arg("--test")
.input("lib.rs")
.run()
.assert_stdout_equals(bin_name("mylib"));
- rustc().print("file-names").input("lib.rs").run().assert_stdout_equals(rust_lib_name("mylib"));
- rustc().print("file-names").input("rlib.rs").run().assert_stdout_equals(rust_lib_name("mylib"));
+ rustc()
+ .target(target())
+ .print("file-names")
+ .input("lib.rs")
+ .run()
+ .assert_stdout_equals(rust_lib_name("mylib"));
+ rustc()
+ .target(target())
+ .print("file-names")
+ .input("rlib.rs")
+ .run()
+ .assert_stdout_equals(rust_lib_name("mylib"));
}
diff --git a/tests/run-make/crate-loading-multiple-candidates/crateresolve1-1.rs b/tests/run-make/crate-loading-multiple-candidates/crateresolve1-1.rs
new file mode 100644
index 0000000..fe00f04
--- /dev/null
+++ b/tests/run-make/crate-loading-multiple-candidates/crateresolve1-1.rs
@@ -0,0 +1,6 @@
+#![crate_name = "crateresolve1"]
+#![crate_type = "lib"]
+
+pub fn f() -> isize {
+ 10
+}
diff --git a/tests/run-make/crate-loading-multiple-candidates/crateresolve1-2.rs b/tests/run-make/crate-loading-multiple-candidates/crateresolve1-2.rs
new file mode 100644
index 0000000..0fb8591
--- /dev/null
+++ b/tests/run-make/crate-loading-multiple-candidates/crateresolve1-2.rs
@@ -0,0 +1,6 @@
+#![crate_name = "crateresolve1"]
+#![crate_type = "lib"]
+
+pub fn f() -> isize {
+ 20
+}
diff --git a/tests/run-make/crate-loading-multiple-candidates/multiple-candidates.rs b/tests/run-make/crate-loading-multiple-candidates/multiple-candidates.rs
new file mode 100644
index 0000000..27cd7ca
--- /dev/null
+++ b/tests/run-make/crate-loading-multiple-candidates/multiple-candidates.rs
@@ -0,0 +1,3 @@
+extern crate crateresolve1;
+
+fn main() {}
diff --git a/tests/run-make/crate-loading-multiple-candidates/multiple-candidates.stderr b/tests/run-make/crate-loading-multiple-candidates/multiple-candidates.stderr
new file mode 100644
index 0000000..de7fc3b
--- /dev/null
+++ b/tests/run-make/crate-loading-multiple-candidates/multiple-candidates.stderr
@@ -0,0 +1,12 @@
+error[E0464]: multiple candidates for `rlib` dependency `crateresolve1` found
+ --> multiple-candidates.rs:1:1
+ |
+LL | extern crate crateresolve1;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: candidate #1: ./mylibs/libcrateresolve1-1.rlib
+ = note: candidate #2: ./mylibs/libcrateresolve1-2.rlib
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0464`.
diff --git a/tests/run-make/crate-loading-multiple-candidates/rmake.rs b/tests/run-make/crate-loading-multiple-candidates/rmake.rs
new file mode 100644
index 0000000..ce09085
--- /dev/null
+++ b/tests/run-make/crate-loading-multiple-candidates/rmake.rs
@@ -0,0 +1,34 @@
+//@ needs-symlink
+//@ ignore-cross-compile
+
+// Tests that the multiple candidate dependencies diagnostic prints relative
+// paths if a relative library path was passed in.
+
+use run_make_support::{bare_rustc, diff, rfs, rustc};
+
+fn main() {
+ // Check that relative paths are preserved in the diagnostic
+ rfs::create_dir("mylibs");
+ rustc().input("crateresolve1-1.rs").out_dir("mylibs").extra_filename("-1").run();
+ rustc().input("crateresolve1-2.rs").out_dir("mylibs").extra_filename("-2").run();
+ check("./mylibs");
+
+ // Check that symlinks aren't followed when printing the diagnostic
+ rfs::rename("mylibs", "original");
+ rfs::symlink_dir("original", "mylibs");
+ check("./mylibs");
+}
+
+fn check(library_path: &str) {
+ let out = rustc()
+ .input("multiple-candidates.rs")
+ .library_search_path(library_path)
+ .ui_testing()
+ .run_fail()
+ .stderr_utf8();
+ diff()
+ .expected_file("multiple-candidates.stderr")
+ .normalize(r"\\", "/")
+ .actual_text("(rustc)", &out)
+ .run();
+}
diff --git a/tests/run-make/crate-name-priority/rmake.rs b/tests/run-make/crate-name-priority/rmake.rs
index 5bdb49b..82e482b 100644
--- a/tests/run-make/crate-name-priority/rmake.rs
+++ b/tests/run-make/crate-name-priority/rmake.rs
@@ -4,6 +4,8 @@
// and the compiler flags, and checks that the flag is favoured each time.
// See https://github.com/rust-lang/rust/pull/15518
+//@ ignore-cross-compile (relocations in generic ELF against `arm-unknown-linux-gnueabihf`)
+
use run_make_support::{bin_name, rfs, rustc};
fn main() {
diff --git a/tests/run-make/embed-source-dwarf/rmake.rs b/tests/run-make/embed-source-dwarf/rmake.rs
index 0aae07f..550c8b9 100644
--- a/tests/run-make/embed-source-dwarf/rmake.rs
+++ b/tests/run-make/embed-source-dwarf/rmake.rs
@@ -21,7 +21,7 @@ fn main() {
.output(&output)
.arg("-g")
.arg("-Zembed-source=yes")
- .arg("-Zdwarf-version=5")
+ .arg("-Cdwarf-version=5")
.run();
let output = rfs::read(output);
let obj = object::File::parse(output.as_slice()).unwrap();
diff --git a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs
index 0910045..f93a3ec 100644
--- a/tests/run-make/extra-filename-with-temp-outputs/rmake.rs
+++ b/tests/run-make/extra-filename-with-temp-outputs/rmake.rs
@@ -6,6 +6,8 @@
// are named as expected.
// See https://github.com/rust-lang/rust/pull/15686
+//@ ignore-cross-compile (relocations in generic ELF against `arm-unknown-linux-gnueabihf`)
+
use run_make_support::{bin_name, cwd, has_prefix, has_suffix, rfs, rustc, shallow_find_files};
fn main() {
diff --git a/tests/run-make/metadata-dep-info/dash-separated_something-extra.expected.d b/tests/run-make/metadata-dep-info/dash-separated_something-extra.expected.d
index 497d76b..43e8f91 100644
--- a/tests/run-make/metadata-dep-info/dash-separated_something-extra.expected.d
+++ b/tests/run-make/metadata-dep-info/dash-separated_something-extra.expected.d
@@ -1,5 +1,5 @@
-libdash_separated_something-extra.rmeta: dash-separated.rs
-
dash-separated_something-extra.d: dash-separated.rs
+libdash_separated_something-extra.rmeta: dash-separated.rs
+
dash-separated.rs:
diff --git a/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs
index f98a203..ce787f8 100644
--- a/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs
+++ b/tests/run-make/naked-symbol-visibility/a_rust_dylib.rs
@@ -1,4 +1,4 @@
-#![feature(naked_functions, linkage)]
+#![feature(linkage)]
#![crate_type = "dylib"]
use std::arch::naked_asm;
@@ -26,9 +26,9 @@ extern "C" fn private_vanilla() -> u32 {
42
}
-#[naked]
+#[unsafe(naked)]
extern "C" fn private_naked() -> u32 {
- unsafe { naked_asm!("mov rax, 42", "ret") }
+ naked_asm!("mov rax, 42", "ret")
}
#[no_mangle]
@@ -36,19 +36,19 @@ pub extern "C" fn public_vanilla() -> u32 {
42
}
-#[naked]
+#[unsafe(naked)]
#[no_mangle]
pub extern "C" fn public_naked_nongeneric() -> u32 {
- unsafe { naked_asm!("mov rax, 42", "ret") }
+ naked_asm!("mov rax, 42", "ret")
}
pub extern "C" fn public_vanilla_generic<T: TraitWithConst>() -> u32 {
T::COUNT
}
-#[naked]
+#[unsafe(naked)]
pub extern "C" fn public_naked_generic<T: TraitWithConst>() -> u32 {
- unsafe { naked_asm!("mov rax, {}", "ret", const T::COUNT) }
+ naked_asm!("mov rax, {}", "ret", const T::COUNT)
}
#[linkage = "external"]
@@ -56,10 +56,10 @@ extern "C" fn vanilla_external_linkage() -> u32 {
42
}
-#[naked]
+#[unsafe(naked)]
#[linkage = "external"]
extern "C" fn naked_external_linkage() -> u32 {
- unsafe { naked_asm!("mov rax, 42", "ret") }
+ naked_asm!("mov rax, 42", "ret")
}
#[cfg(not(windows))]
@@ -68,11 +68,11 @@ extern "C" fn vanilla_weak_linkage() -> u32 {
42
}
-#[naked]
+#[unsafe(naked)]
#[cfg(not(windows))]
#[linkage = "weak"]
extern "C" fn naked_weak_linkage() -> u32 {
- unsafe { naked_asm!("mov rax, 42", "ret") }
+ naked_asm!("mov rax, 42", "ret")
}
// functions that are declared in an `extern "C"` block are currently not exported
diff --git a/tests/run-make/output-type-permutations/rmake.rs b/tests/run-make/output-type-permutations/rmake.rs
index c0569af..8da0bfa 100644
--- a/tests/run-make/output-type-permutations/rmake.rs
+++ b/tests/run-make/output-type-permutations/rmake.rs
@@ -4,6 +4,9 @@
// files are exactly what is expected, no more, no less.
// See https://github.com/rust-lang/rust/pull/12020
+//@ ignore-cross-compile
+// Reason: some cross-compiled targets don't support various crate types and fail to link.
+
use std::path::PathBuf;
use run_make_support::{
@@ -17,6 +20,7 @@
// `dir`: the name of the directory where the test happens
// `rustc_invocation`: the rustc command being tested
// Any unexpected output files not listed in `must_exist` or `can_exist` will cause a failure.
+#[track_caller]
fn assert_expected_output_files(expectations: Expectations, rustc_invocation: impl Fn()) {
let Expectations { expected_files: must_exist, allowed_files: can_exist, test_dir: dir } =
expectations;
diff --git a/tests/run-make/print-request-help-stable-unstable/help-diff.diff b/tests/run-make/print-request-help-stable-unstable/help-diff.diff
new file mode 100644
index 0000000..07eafca
--- /dev/null
+++ b/tests/run-make/print-request-help-stable-unstable/help-diff.diff
@@ -0,0 +1,7 @@
+@@ -1,5 +1,5 @@
+ error: unknown print request: `xxx`
+ |
+- = help: valid print requests are: `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `tls-models`
++ = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models`
+ = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information
+
diff --git a/tests/run-make/print-request-help-stable-unstable/rmake.rs b/tests/run-make/print-request-help-stable-unstable/rmake.rs
new file mode 100644
index 0000000..a59963d
--- /dev/null
+++ b/tests/run-make/print-request-help-stable-unstable/rmake.rs
@@ -0,0 +1,33 @@
+//! Check that unstable print requests are omitted from help if compiler is in stable channel.
+//!
+//! Issue: <https://github.com/rust-lang/rust/issues/138698>
+use run_make_support::{diff, rustc, similar};
+
+fn main() {
+ let stable_invalid_print_request_help = rustc()
+ .env("RUSTC_BOOTSTRAP", "-1")
+ .cfg("force_stable")
+ .print("xxx")
+ .run_fail()
+ .stderr_utf8();
+ assert!(!stable_invalid_print_request_help.contains("all-target-specs-json"));
+ diff()
+ .expected_file("stable-invalid-print-request-help.err")
+ .actual_text("stable_invalid_print_request_help", &stable_invalid_print_request_help)
+ .run();
+
+ let unstable_invalid_print_request_help = rustc().print("xxx").run_fail().stderr_utf8();
+ assert!(unstable_invalid_print_request_help.contains("all-target-specs-json"));
+ diff()
+ .expected_file("unstable-invalid-print-request-help.err")
+ .actual_text("unstable_invalid_print_request_help", &unstable_invalid_print_request_help)
+ .run();
+
+ let help_diff = similar::TextDiff::from_lines(
+ &stable_invalid_print_request_help,
+ &unstable_invalid_print_request_help,
+ )
+ .unified_diff()
+ .to_string();
+ diff().expected_file("help-diff.diff").actual_text("help_diff", help_diff).run();
+}
diff --git a/tests/run-make/print-request-help-stable-unstable/stable-invalid-print-request-help.err b/tests/run-make/print-request-help-stable-unstable/stable-invalid-print-request-help.err
new file mode 100644
index 0000000..019a578
--- /dev/null
+++ b/tests/run-make/print-request-help-stable-unstable/stable-invalid-print-request-help.err
@@ -0,0 +1,5 @@
+error: unknown print request: `xxx`
+ |
+ = help: valid print requests are: `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `tls-models`
+ = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information
+
diff --git a/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err b/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err
new file mode 100644
index 0000000..50ef340
--- /dev/null
+++ b/tests/run-make/print-request-help-stable-unstable/unstable-invalid-print-request-help.err
@@ -0,0 +1,5 @@
+error: unknown print request: `xxx`
+ |
+ = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `crate-root-lint-levels`, `deployment-target`, `file-names`, `host-tuple`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `supported-crate-types`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models`
+ = help: for more information, see the rustc book: https://doc.rust-lang.org/rustc/command-line-arguments.html#--print-print-compiler-information
+
diff --git a/tests/run-make/reproducible-build/rmake.rs b/tests/run-make/reproducible-build/rmake.rs
index 8a8b0d6..93fc30d 100644
--- a/tests/run-make/reproducible-build/rmake.rs
+++ b/tests/run-make/reproducible-build/rmake.rs
@@ -20,6 +20,8 @@
// See https://github.com/rust-lang/rust/pull/32293
// Tracking Issue: https://github.com/rust-lang/rust/issues/129080
+//@ ignore-cross-compile (linker binary needs to run)
+
use run_make_support::{
bin_name, cwd, diff, is_darwin, is_windows, regex, rfs, run_in_tmpdir, rust_lib_name, rustc,
};
diff --git a/tests/run-make/rustc-help/help-v.diff b/tests/run-make/rustc-help/help-v.diff
index 22c5dd8..0ea79f3 100644
--- a/tests/run-make/rustc-help/help-v.diff
+++ b/tests/run-make/rustc-help/help-v.diff
@@ -1,4 +1,4 @@
-@@ -51,10 +51,27 @@
+@@ -63,10 +63,27 @@
Set a codegen option
-V, --version Print version info and exit
-v, --verbose Use verbose output
diff --git a/tests/run-make/rustc-help/help-v.stdout b/tests/run-make/rustc-help/help-v.stdout
index f19ca1e..744453d 100644
--- a/tests/run-make/rustc-help/help-v.stdout
+++ b/tests/run-make/rustc-help/help-v.stdout
@@ -26,11 +26,23 @@
Specify which edition of the compiler to use when
compiling code. The default is 2015 and the latest
stable edition is 2024.
- --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]
+ --emit TYPE[=FILE]
Comma separated list of types of output for the
- compiler to emit
- --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models]
- Compiler information to print on stdout
+ compiler to emit.
+ Each TYPE has the default FILE name:
+ * asm - CRATE_NAME.s
+ * llvm-bc - CRATE_NAME.bc
+ * dep-info - CRATE_NAME.d
+ * link - (platform and crate-type dependent)
+ * llvm-ir - CRATE_NAME.ll
+ * metadata - libCRATE_NAME.rmeta
+ * mir - CRATE_NAME.mir
+ * obj - CRATE_NAME.o
+ * thin-link-bitcode - CRATE_NAME.indexing.o
+ --print INFO[=FILE]
+ Compiler information to print on stdout (or to a file)
+ INFO may be one of
+ (all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models).
-g Equivalent to -C debuginfo=2
-O Equivalent to -C opt-level=3
-o FILENAME Write output to <filename>
diff --git a/tests/run-make/rustc-help/help.stdout b/tests/run-make/rustc-help/help.stdout
index f7d3529..3043755 100644
--- a/tests/run-make/rustc-help/help.stdout
+++ b/tests/run-make/rustc-help/help.stdout
@@ -26,11 +26,23 @@
Specify which edition of the compiler to use when
compiling code. The default is 2015 and the latest
stable edition is 2024.
- --emit [asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info|mir]
+ --emit TYPE[=FILE]
Comma separated list of types of output for the
- compiler to emit
- --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models]
- Compiler information to print on stdout
+ compiler to emit.
+ Each TYPE has the default FILE name:
+ * asm - CRATE_NAME.s
+ * llvm-bc - CRATE_NAME.bc
+ * dep-info - CRATE_NAME.d
+ * link - (platform and crate-type dependent)
+ * llvm-ir - CRATE_NAME.ll
+ * metadata - libCRATE_NAME.rmeta
+ * mir - CRATE_NAME.mir
+ * obj - CRATE_NAME.o
+ * thin-link-bitcode - CRATE_NAME.indexing.o
+ --print INFO[=FILE]
+ Compiler information to print on stdout (or to a file)
+ INFO may be one of
+ (all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models).
-g Equivalent to -C debuginfo=2
-O Equivalent to -C opt-level=3
-o FILENAME Write output to <filename>
diff --git a/tests/run-make/simd-ffi/rmake.rs b/tests/run-make/simd-ffi/rmake.rs
index ef71dfa..c631507 100644
--- a/tests/run-make/simd-ffi/rmake.rs
+++ b/tests/run-make/simd-ffi/rmake.rs
@@ -52,11 +52,20 @@ fn main() {
// enabled by-default for i686 and ARM; these features will be invalid
// on some platforms, but LLVM just prints a warning so that's fine for
// now.
+ let target_feature = if target.starts_with("i686") || target.starts_with("x86") {
+ "+sse2"
+ } else if target.starts_with("arm") || target.starts_with("aarch64") {
+ "-soft-float,+neon"
+ } else if target.starts_with("mips") {
+ "+msa,+fp64"
+ } else {
+ panic!("missing target_feature case for {target}");
+ };
rustc()
.target(&target)
.emit("llvm-ir,asm")
.input("simd.rs")
- .arg("-Ctarget-feature=-soft-float,+neon,+sse")
+ .arg(format!("-Ctarget-feature={target_feature}"))
.arg(&format!("-Cextra-filename=-{target}"))
.run();
}
diff --git a/tests/run-make/strip/rmake.rs b/tests/run-make/strip/rmake.rs
index ef1acc2..01b31ac 100644
--- a/tests/run-make/strip/rmake.rs
+++ b/tests/run-make/strip/rmake.rs
@@ -1,4 +1,5 @@
-//@ ignore-windows Windows does not actually strip
+//@ ignore-windows (Windows does not actually strip)
+//@ ignore-cross-compile (relocations in generic ELF against `arm-unknown-linux-gnueabihf`)
// Test that -Cstrip correctly strips/preserves debuginfo and symbols.
diff --git a/tests/run-make/symbols-all-mangled/rmake.rs b/tests/run-make/symbols-all-mangled/rmake.rs
index 1fb03c6..79ddd06 100644
--- a/tests/run-make/symbols-all-mangled/rmake.rs
+++ b/tests/run-make/symbols-all-mangled/rmake.rs
@@ -1,5 +1,7 @@
// Check that all symbols in cdylibs, staticlibs and bins are mangled
//@ only-elf some object file formats create multiple symbols for each function with different names
+//@ ignore-nvptx64 (needs target std)
+//@ ignore-cross-compile (host-only)
use run_make_support::object::read::{Object, ObjectSymbol};
use run_make_support::{bin_name, dynamic_lib_name, object, rfs, rustc, static_lib_name};
diff --git a/tests/rustdoc-js-std/unbox-type-result.js b/tests/rustdoc-js-std/unbox-type-result.js
new file mode 100644
index 0000000..1f5cba5
--- /dev/null
+++ b/tests/rustdoc-js-std/unbox-type-result.js
@@ -0,0 +1,20 @@
+// exact-check
+
+// Test case for https://github.com/rust-lang/rust/issues/139665
+// make sure that std::io::Result and std::thread::Result get unboxed
+
+const EXPECTED = [
+ {
+ query: "File -> Metadata",
+ others: [
+ { path: "std::fs::File", name: "metadata" },
+ { path: "std::fs::File", name: "metadata_at" },
+ ]
+ },
+ {
+ query: "JoinHandle<T> -> T",
+ others: [
+ { path: "std::thread::JoinHandle", name: "join" },
+ ]
+ },
+];
diff --git a/tests/rustdoc-js/generics-unbox.js b/tests/rustdoc-js/generics-unbox.js
index 6baf00c..a4f2ba8 100644
--- a/tests/rustdoc-js/generics-unbox.js
+++ b/tests/rustdoc-js/generics-unbox.js
@@ -31,4 +31,10 @@
{ 'path': 'generics_unbox', 'name': 'beta' },
],
},
+ {
+ 'query': '-> Sigma',
+ 'others': [
+ { 'path': 'generics_unbox', 'name': 'delta' },
+ ],
+ },
];
diff --git a/tests/rustdoc-js/generics-unbox.rs b/tests/rustdoc-js/generics-unbox.rs
index c257857..b16e35e 100644
--- a/tests/rustdoc-js/generics-unbox.rs
+++ b/tests/rustdoc-js/generics-unbox.rs
@@ -42,3 +42,15 @@ pub fn beta<T, U>(_: Inside<T>) -> Out<Out3<T, U>, Out4<U, T>> {
pub fn gamma<T, U>(_: Inside<T>) -> Out<Out3<U, T>, Out4<T, U>> {
loop {}
}
+
+pub fn delta(_: i32) -> Epsilon<Sigma> {
+ loop {}
+}
+
+#[doc(search_unbox)]
+pub struct Theta<T>(T);
+
+#[doc(search_unbox)]
+pub type Epsilon<T> = Theta<T>;
+
+pub struct Sigma;
diff --git a/tests/rustdoc-json/fns/return_type_alias.rs b/tests/rustdoc-json/fns/return_type_alias.rs
index 0aa1db4..c39abc7 100644
--- a/tests/rustdoc-json/fns/return_type_alias.rs
+++ b/tests/rustdoc-json/fns/return_type_alias.rs
@@ -1,6 +1,6 @@
// Regression test for <https://github.com/rust-lang/rust/issues/104851>
-///@ set foo = "$.index[?(@.name=='Foo')].id"
+//@ set foo = "$.index[?(@.name=='Foo')].id"
pub type Foo = i32;
//@ is "$.index[?(@.name=='demo')].inner.function.sig.output.resolved_path.id" $foo
diff --git a/tests/rustdoc-json/impls/auto.rs b/tests/rustdoc-json/impls/auto.rs
index f94f733..5440301 100644
--- a/tests/rustdoc-json/impls/auto.rs
+++ b/tests/rustdoc-json/impls/auto.rs
@@ -15,8 +15,10 @@ pub fn baz(&self) {}
}
// Testing spans, so all tests below code
-//@ is "$.index[?(@.docs=='has span')].span.begin" "[13, 0]"
-//@ is "$.index[?(@.docs=='has span')].span.end" "[15, 1]"
-// FIXME: this doesn't work due to https://github.com/freestrings/jsonpath/issues/91
-// is "$.index[?(@.inner.impl.is_synthetic==true)].span" null
+//@ is "$.index[?(@.docs=='has span')].span.begin" "[13, 1]"
+//@ is "$.index[?(@.docs=='has span')].span.end" "[15, 2]"
+//@ is "$.index[?(@.docs=='has span')].inner.impl.is_synthetic" false
+//@ is "$.index[?(@.inner.impl.is_synthetic==true)].span" null
+//@ is "$.index[?(@.inner.impl.is_synthetic==true)].inner.impl.for.resolved_path.path" '"Foo"'
+//@ is "$.index[?(@.inner.impl.is_synthetic==true)].inner.impl.trait.path" '"Bar"'
pub struct Foo;
diff --git a/tests/rustdoc-json/span.rs b/tests/rustdoc-json/span.rs
new file mode 100644
index 0000000..c96879d
--- /dev/null
+++ b/tests/rustdoc-json/span.rs
@@ -0,0 +1,4 @@
+pub mod bar {}
+// This test ensures that spans are 1-indexed.
+//@ is "$.index[?(@.name=='span')].span.begin" "[1, 1]"
+//@ is "$.index[?(@.name=='bar')].span.begin" "[1, 1]"
diff --git a/tests/rustdoc-json/targets/aarch64_apple_darwin.rs b/tests/rustdoc-json/targets/aarch64_apple_darwin.rs
new file mode 100644
index 0000000..c6ae551
--- /dev/null
+++ b/tests/rustdoc-json/targets/aarch64_apple_darwin.rs
@@ -0,0 +1,14 @@
+//@ only-aarch64-apple-darwin
+
+//@ is "$.target.triple" \"aarch64-apple-darwin\"
+//@ is "$.target.target_features[?(@.name=='vh')].globally_enabled" true
+//@ is "$.target.target_features[?(@.name=='sve')].globally_enabled" false
+//@ has "$.target.target_features[?(@.name=='sve2')].implies_features" '["sve"]'
+//@ is "$.target.target_features[?(@.name=='sve2')].unstable_feature_gate" null
+
+// If this breaks due to stabilization, check rustc_target::target_features for a replacement
+//@ is "$.target.target_features[?(@.name=='cssc')].unstable_feature_gate" '"aarch64_unstable_target_feature"'
+//@ is "$.target.target_features[?(@.name=='v9a')].unstable_feature_gate" '"aarch64_ver_target_feature"'
+
+// Ensure we don't look like x86-64
+//@ !has "$.target.target_features[?(@.name=='avx2')]"
diff --git a/tests/rustdoc-json/targets/aarch64_reflects_compiler_options.rs b/tests/rustdoc-json/targets/aarch64_reflects_compiler_options.rs
new file mode 100644
index 0000000..f91221e
--- /dev/null
+++ b/tests/rustdoc-json/targets/aarch64_reflects_compiler_options.rs
@@ -0,0 +1,10 @@
+//@ only-aarch64
+
+// If we enable SVE Bit Permute, we should see that it is enabled
+//@ compile-flags: -Ctarget-feature=+sve2-bitperm
+//@ is "$.target.target_features[?(@.name=='sve2-bitperm')].globally_enabled" true
+
+// As well as its dependency chain
+//@ is "$.target.target_features[?(@.name=='sve2')].globally_enabled" true
+//@ is "$.target.target_features[?(@.name=='sve')].globally_enabled" true
+//@ is "$.target.target_features[?(@.name=='neon')].globally_enabled" true
diff --git a/tests/rustdoc-json/targets/aarch64_unknown_linux_gnu.rs b/tests/rustdoc-json/targets/aarch64_unknown_linux_gnu.rs
new file mode 100644
index 0000000..9139b00
--- /dev/null
+++ b/tests/rustdoc-json/targets/aarch64_unknown_linux_gnu.rs
@@ -0,0 +1,14 @@
+//@ only-aarch64-unknown-linux-gnu
+
+//@ is "$.target.triple" \"aarch64-unknown-linux-gnu\"
+//@ is "$.target.target_features[?(@.name=='neon')].globally_enabled" true
+//@ is "$.target.target_features[?(@.name=='sve')].globally_enabled" false
+//@ has "$.target.target_features[?(@.name=='sve2')].implies_features" '["sve"]'
+//@ is "$.target.target_features[?(@.name=='sve2')].unstable_feature_gate" null
+
+// If this breaks due to stabilization, check rustc_target::target_features for a replacement
+//@ is "$.target.target_features[?(@.name=='cssc')].unstable_feature_gate" '"aarch64_unstable_target_feature"'
+//@ is "$.target.target_features[?(@.name=='v9a')].unstable_feature_gate" '"aarch64_ver_target_feature"'
+
+// Ensure we don't look like x86-64
+//@ !has "$.target.target_features[?(@.name=='avx2')]"
diff --git a/tests/rustdoc-json/targets/i686_pc_windows_msvc.rs b/tests/rustdoc-json/targets/i686_pc_windows_msvc.rs
new file mode 100644
index 0000000..088c741
--- /dev/null
+++ b/tests/rustdoc-json/targets/i686_pc_windows_msvc.rs
@@ -0,0 +1,14 @@
+//@ only-i686-pc-windows-msvc
+
+//@ is "$.target.triple" \"i686-pc-windows-msvc\"
+//@ is "$.target.target_features[?(@.name=='sse2')].globally_enabled" true
+//@ is "$.target.target_features[?(@.name=='avx2')].globally_enabled" false
+//@ has "$.target.target_features[?(@.name=='avx2')].implies_features" '["avx"]'
+//@ is "$.target.target_features[?(@.name=='avx2')].unstable_feature_gate" null
+
+// If this breaks due to stabilization, check rustc_target::target_features for a replacement
+//@ is "$.target.target_features[?(@.name=='amx-tile')].unstable_feature_gate" '"x86_amx_intrinsics"'
+//@ is "$.target.target_features[?(@.name=='x87')].unstable_feature_gate" '"x87_target_feature"'
+
+// Ensure we don't look like aarch64
+//@ !has "$.target.target_features[?(@.name=='sve2')]"
diff --git a/tests/rustdoc-json/targets/i686_unknown_linux_gnu.rs b/tests/rustdoc-json/targets/i686_unknown_linux_gnu.rs
new file mode 100644
index 0000000..03788b0
--- /dev/null
+++ b/tests/rustdoc-json/targets/i686_unknown_linux_gnu.rs
@@ -0,0 +1,14 @@
+//@ only-i686-unknown-linux-gnu
+
+//@ is "$.target.triple" \"i686-unknown-linux-gnu\"
+//@ is "$.target.target_features[?(@.name=='sse2')].globally_enabled" true
+//@ is "$.target.target_features[?(@.name=='avx2')].globally_enabled" false
+//@ has "$.target.target_features[?(@.name=='avx2')].implies_features" '["avx"]'
+//@ is "$.target.target_features[?(@.name=='avx2')].unstable_feature_gate" null
+
+// If this breaks due to stabilization, check rustc_target::target_features for a replacement
+//@ is "$.target.target_features[?(@.name=='amx-tile')].unstable_feature_gate" '"x86_amx_intrinsics"'
+//@ is "$.target.target_features[?(@.name=='x87')].unstable_feature_gate" '"x87_target_feature"'
+
+// Ensure we don't look like aarch64
+//@ !has "$.target.target_features[?(@.name=='sve2')]"
diff --git a/tests/rustdoc-json/targets/x86_64_apple_darwin.rs b/tests/rustdoc-json/targets/x86_64_apple_darwin.rs
new file mode 100644
index 0000000..a46f913
--- /dev/null
+++ b/tests/rustdoc-json/targets/x86_64_apple_darwin.rs
@@ -0,0 +1,14 @@
+//@ only-x86_64-apple-darwin
+
+//@ is "$.target.triple" \"x86_64-apple-darwin\"
+//@ is "$.target.target_features[?(@.name=='sse2')].globally_enabled" true
+//@ is "$.target.target_features[?(@.name=='avx2')].globally_enabled" false
+//@ has "$.target.target_features[?(@.name=='avx2')].implies_features" '["avx"]'
+//@ is "$.target.target_features[?(@.name=='avx2')].unstable_feature_gate" null
+
+// If this breaks due to stabilization, check rustc_target::target_features for a replacement
+//@ is "$.target.target_features[?(@.name=='amx-tile')].unstable_feature_gate" '"x86_amx_intrinsics"'
+//@ is "$.target.target_features[?(@.name=='x87')].unstable_feature_gate" '"x87_target_feature"'
+
+// Ensure we don't look like aarch64
+//@ !has "$.target.target_features[?(@.name=='sve2')]"
diff --git a/tests/rustdoc-json/targets/x86_64_pc_windows_gnu.rs b/tests/rustdoc-json/targets/x86_64_pc_windows_gnu.rs
new file mode 100644
index 0000000..7da12eb
--- /dev/null
+++ b/tests/rustdoc-json/targets/x86_64_pc_windows_gnu.rs
@@ -0,0 +1,14 @@
+//@ only-x86_64-pc-windows-gnu
+
+//@ is "$.target.triple" \"x86_64-pc-windows-gnu\"
+//@ is "$.target.target_features[?(@.name=='sse2')].globally_enabled" true
+//@ is "$.target.target_features[?(@.name=='avx2')].globally_enabled" false
+//@ has "$.target.target_features[?(@.name=='avx2')].implies_features" '["avx"]'
+//@ is "$.target.target_features[?(@.name=='avx2')].unstable_feature_gate" null
+
+// If this breaks due to stabilization, check rustc_target::target_features for a replacement
+//@ is "$.target.target_features[?(@.name=='amx-tile')].unstable_feature_gate" '"x86_amx_intrinsics"'
+//@ is "$.target.target_features[?(@.name=='x87')].unstable_feature_gate" '"x87_target_feature"'
+
+// Ensure we don't look like aarch64
+//@ !has "$.target.target_features[?(@.name=='sve2')]"
diff --git a/tests/rustdoc-json/targets/x86_64_pc_windows_msvc.rs b/tests/rustdoc-json/targets/x86_64_pc_windows_msvc.rs
new file mode 100644
index 0000000..d55f577
--- /dev/null
+++ b/tests/rustdoc-json/targets/x86_64_pc_windows_msvc.rs
@@ -0,0 +1,14 @@
+//@ only-x86_64-pc-windows-msvc
+
+//@ is "$.target.triple" \"x86_64-pc-windows-msvc\"
+//@ is "$.target.target_features[?(@.name=='sse2')].globally_enabled" true
+//@ is "$.target.target_features[?(@.name=='avx2')].globally_enabled" false
+//@ has "$.target.target_features[?(@.name=='avx2')].implies_features" '["avx"]'
+//@ is "$.target.target_features[?(@.name=='avx2')].unstable_feature_gate" null
+
+// If this breaks due to stabilization, check rustc_target::target_features for a replacement
+//@ is "$.target.target_features[?(@.name=='amx-tile')].unstable_feature_gate" '"x86_amx_intrinsics"'
+//@ is "$.target.target_features[?(@.name=='x87')].unstable_feature_gate" '"x87_target_feature"'
+
+// Ensure we don't look like aarch64
+//@ !has "$.target.target_features[?(@.name=='sve2')]"
diff --git a/tests/rustdoc-json/targets/x86_64_reflects_compiler_options.rs b/tests/rustdoc-json/targets/x86_64_reflects_compiler_options.rs
new file mode 100644
index 0000000..ba029b0
--- /dev/null
+++ b/tests/rustdoc-json/targets/x86_64_reflects_compiler_options.rs
@@ -0,0 +1,10 @@
+//@ only-x86_64
+
+// If we enable AVX2, we should see that it is enabled
+//@ compile-flags: -Ctarget-feature=+avx2
+//@ is "$.target.target_features[?(@.name=='avx2')].globally_enabled" true
+
+// As well as its dependency chain
+//@ is "$.target.target_features[?(@.name=='avx')].globally_enabled" true
+//@ is "$.target.target_features[?(@.name=='sse4.2')].globally_enabled" true
+//@ is "$.target.target_features[?(@.name=='sse4.1')].globally_enabled" true
diff --git a/tests/rustdoc-json/targets/x86_64_unknown_linux_gnu.rs b/tests/rustdoc-json/targets/x86_64_unknown_linux_gnu.rs
new file mode 100644
index 0000000..3372fe7
--- /dev/null
+++ b/tests/rustdoc-json/targets/x86_64_unknown_linux_gnu.rs
@@ -0,0 +1,14 @@
+//@ only-x86_64-unknown-linux-gnu
+
+//@ is "$.target.triple" \"x86_64-unknown-linux-gnu\"
+//@ is "$.target.target_features[?(@.name=='sse2')].globally_enabled" true
+//@ is "$.target.target_features[?(@.name=='avx2')].globally_enabled" false
+//@ has "$.target.target_features[?(@.name=='avx2')].implies_features" '["avx"]'
+//@ is "$.target.target_features[?(@.name=='avx2')].unstable_feature_gate" null
+
+// If this breaks due to stabilization, check rustc_target::target_features for a replacement
+//@ is "$.target.target_features[?(@.name=='amx-tile')].unstable_feature_gate" '"x86_amx_intrinsics"'
+//@ is "$.target.target_features[?(@.name=='x87')].unstable_feature_gate" '"x87_target_feature"'
+
+// Ensure we don't look like aarch64
+//@ !has "$.target.target_features[?(@.name=='sve2')]"
diff --git a/tests/rustdoc-ui/cfg-boolean-literal.rs b/tests/rustdoc-ui/cfg-boolean-literal.rs
index 4d4e599..74808d0 100644
--- a/tests/rustdoc-ui/cfg-boolean-literal.rs
+++ b/tests/rustdoc-ui/cfg-boolean-literal.rs
@@ -1,6 +1,5 @@
//@ check-pass
-#![feature(cfg_boolean_literals)]
#![feature(doc_cfg)]
#[doc(cfg(false))]
diff --git a/tests/rustdoc-ui/deprecated-attrs.rs b/tests/rustdoc-ui/deprecated-attrs.rs
index 0ae65a5..dcf8a52 100644
--- a/tests/rustdoc-ui/deprecated-attrs.rs
+++ b/tests/rustdoc-ui/deprecated-attrs.rs
@@ -1,5 +1,4 @@
//@ compile-flags: --passes unknown-pass
-//@ error-pattern: the `passes` flag no longer functions
#![doc(no_default_passes)]
//~^ ERROR unknown `doc` attribute `no_default_passes`
diff --git a/tests/rustdoc-ui/deprecated-attrs.stderr b/tests/rustdoc-ui/deprecated-attrs.stderr
index a30523e..3e98205 100644
--- a/tests/rustdoc-ui/deprecated-attrs.stderr
+++ b/tests/rustdoc-ui/deprecated-attrs.stderr
@@ -4,7 +4,7 @@
= help: you may want to use --document-private-items
error: unknown `doc` attribute `no_default_passes`
- --> $DIR/deprecated-attrs.rs:4:8
+ --> $DIR/deprecated-attrs.rs:3:8
|
LL | #![doc(no_default_passes)]
| ^^^^^^^^^^^^^^^^^ no longer functions
@@ -15,7 +15,7 @@
= note: `#[deny(invalid_doc_attributes)]` on by default
error: unknown `doc` attribute `passes`
- --> $DIR/deprecated-attrs.rs:11:8
+ --> $DIR/deprecated-attrs.rs:10:8
|
LL | #![doc(passes = "collapse-docs unindent-comments")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no longer functions
@@ -25,7 +25,7 @@
= note: `doc(passes)` is now a no-op
error: unknown `doc` attribute `plugins`
- --> $DIR/deprecated-attrs.rs:17:8
+ --> $DIR/deprecated-attrs.rs:16:8
|
LL | #![doc(plugins = "xxx")]
| ^^^^^^^^^^^^^^^ no longer functions
diff --git a/tests/rustdoc-ui/doc-cfg-unstable.rs b/tests/rustdoc-ui/doc-cfg-unstable.rs
index 14c2e83..b77c365 100644
--- a/tests/rustdoc-ui/doc-cfg-unstable.rs
+++ b/tests/rustdoc-ui/doc-cfg-unstable.rs
@@ -1,10 +1,6 @@
// #138113: rustdoc didn't gate unstable predicates inside `doc(cfg(..))`
#![feature(doc_cfg)]
-// `cfg_boolean_literals`
-#[doc(cfg(false))] //~ ERROR `cfg(false)` is experimental and subject to change
-pub fn cfg_boolean_literals() {}
-
// `cfg_version`
#[doc(cfg(sanitize = "thread"))] //~ ERROR `cfg(sanitize)` is experimental and subject to change
pub fn cfg_sanitize() {}
diff --git a/tests/rustdoc-ui/doc-cfg-unstable.stderr b/tests/rustdoc-ui/doc-cfg-unstable.stderr
index 54de3b1..9651c5f 100644
--- a/tests/rustdoc-ui/doc-cfg-unstable.stderr
+++ b/tests/rustdoc-ui/doc-cfg-unstable.stderr
@@ -1,15 +1,5 @@
-error[E0658]: `cfg(false)` is experimental and subject to change
- --> $DIR/doc-cfg-unstable.rs:5:11
- |
-LL | #[doc(cfg(false))]
- | ^^^^^
- |
- = note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
- = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
error[E0658]: `cfg(sanitize)` is experimental and subject to change
- --> $DIR/doc-cfg-unstable.rs:9:11
+ --> $DIR/doc-cfg-unstable.rs:5:11
|
LL | #[doc(cfg(sanitize = "thread"))]
| ^^^^^^^^^^^^^^^^^^^
@@ -18,6 +8,6 @@
= help: add `#![feature(cfg_sanitize)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout
index 90c0463..2b04b77 100644
--- a/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout
+++ b/tests/rustdoc-ui/doctest/failed-doctest-should-panic.stdout
@@ -5,7 +5,7 @@
failures:
---- $DIR/failed-doctest-should-panic.rs - Foo (line 10) stdout ----
-note: test did not panic as expected
+note: test did not panic as expected at $DIR/failed-doctest-should-panic.rs:10:0
failures:
$DIR/failed-doctest-should-panic.rs - Foo (line 10)
diff --git a/tests/rustdoc-ui/intra-doc/empty-associated-items.rs b/tests/rustdoc-ui/intra-doc/empty-associated-items.rs
new file mode 100644
index 0000000..ea94cb3
--- /dev/null
+++ b/tests/rustdoc-ui/intra-doc/empty-associated-items.rs
@@ -0,0 +1,8 @@
+// This test ensures that an empty associated item will not crash rustdoc.
+// This is a regression test for <https://github.com/rust-lang/rust/issues/140026>.
+
+#[deny(rustdoc::broken_intra_doc_links)]
+
+/// [`String::`]
+//~^ ERROR
+pub struct Foo;
diff --git a/tests/rustdoc-ui/intra-doc/empty-associated-items.stderr b/tests/rustdoc-ui/intra-doc/empty-associated-items.stderr
new file mode 100644
index 0000000..b052791
--- /dev/null
+++ b/tests/rustdoc-ui/intra-doc/empty-associated-items.stderr
@@ -0,0 +1,14 @@
+error: unresolved link to `String::`
+ --> $DIR/empty-associated-items.rs:6:7
+ |
+LL | /// [`String::`]
+ | ^^^^^^^^ the struct `String` has no field or associated item named ``
+ |
+note: the lint level is defined here
+ --> $DIR/empty-associated-items.rs:4:8
+ |
+LL | #[deny(rustdoc::broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/rustdoc-ui/invalid-theme-name.rs b/tests/rustdoc-ui/invalid-theme-name.rs
index 7f1d191..22b5e61 100644
--- a/tests/rustdoc-ui/invalid-theme-name.rs
+++ b/tests/rustdoc-ui/invalid-theme-name.rs
@@ -1,4 +1,4 @@
//@ compile-flags:--theme {{src-base}}/invalid-theme-name.rs
-//@ error-pattern: must have a .css extension
//~? ERROR invalid argument: "$DIR/invalid-theme-name.rs"
+//~? HELP must have a .css extension
diff --git a/tests/rustdoc/anon-fn-params.rs b/tests/rustdoc/anon-fn-params.rs
new file mode 100644
index 0000000..9af1af3
--- /dev/null
+++ b/tests/rustdoc/anon-fn-params.rs
@@ -0,0 +1,25 @@
+// Test that we render the deprecated anonymous trait function parameters from Rust 2015 as
+// underscores in order not to perpetuate it and for legibility.
+
+//@ edition: 2015
+#![expect(anonymous_parameters)]
+
+// Check the "local case" (HIR cleaning) //
+
+//@ has anon_fn_params/trait.Trait.html
+pub trait Trait {
+ //@ has - '//*[@id="tymethod.required"]' 'fn required(_: Option<i32>, _: impl Fn(&str) -> bool)'
+ fn required(Option<i32>, impl Fn(&str) -> bool);
+ //@ has - '//*[@id="method.provided"]' 'fn provided(_: [i32; 2])'
+ fn provided([i32; 2]) {}
+}
+
+// Check the "extern case" (middle cleaning) //
+
+//@ aux-build: ext-anon-fn-params.rs
+extern crate ext_anon_fn_params;
+
+//@ has anon_fn_params/trait.ExtTrait.html
+//@ has - '//*[@id="tymethod.required"]' 'fn required(_: Option<i32>, _: impl Fn(&str) -> bool)'
+//@ has - '//*[@id="method.provided"]' 'fn provided(_: [i32; 2])'
+pub use ext_anon_fn_params::Trait as ExtTrait;
diff --git a/tests/rustdoc/assoc-fns.rs b/tests/rustdoc/assoc-fns.rs
new file mode 100644
index 0000000..6ffbebc
--- /dev/null
+++ b/tests/rustdoc/assoc-fns.rs
@@ -0,0 +1,13 @@
+// Basic testing for associated functions (in traits, trait impls & inherent impls).
+
+//@ has assoc_fns/trait.Trait.html
+pub trait Trait {
+ //@ has - '//*[@id="tymethod.required"]' 'fn required(first: i32, second: &str)'
+ fn required(first: i32, second: &str);
+
+ //@ has - '//*[@id="method.provided"]' 'fn provided(only: ())'
+ fn provided(only: ()) {}
+
+ //@ has - '//*[@id="tymethod.params_are_unnamed"]' 'fn params_are_unnamed(_: i32, _: u32)'
+ fn params_are_unnamed(_: i32, _: u32);
+}
diff --git a/tests/rustdoc/auxiliary/ext-anon-fn-params.rs b/tests/rustdoc/auxiliary/ext-anon-fn-params.rs
new file mode 100644
index 0000000..1acb919
--- /dev/null
+++ b/tests/rustdoc/auxiliary/ext-anon-fn-params.rs
@@ -0,0 +1,7 @@
+//@ edition: 2015
+#![expect(anonymous_parameters)]
+
+pub trait Trait {
+ fn required(Option<i32>, impl Fn(&str) -> bool);
+ fn provided([i32; 2]) {}
+}
diff --git a/tests/rustdoc/auxiliary/ext-trait-aliases.rs b/tests/rustdoc/auxiliary/ext-trait-aliases.rs
new file mode 100644
index 0000000..8454c04
--- /dev/null
+++ b/tests/rustdoc/auxiliary/ext-trait-aliases.rs
@@ -0,0 +1,13 @@
+#![feature(trait_alias)]
+
+pub trait ExtAlias0 = Copy + Iterator<Item = u8>;
+
+pub trait ExtAlias1<'a, T: 'a + Clone, const N: usize> = From<[&'a T; N]>;
+
+pub trait ExtAlias2<T> = where T: From<String>, String: Into<T>;
+
+pub trait ExtAlias3 = Sized;
+
+pub trait ExtAlias4 = where Self: Sized;
+
+pub trait ExtAlias5 = ;
diff --git a/tests/rustdoc/auxiliary/trait-alias-mention.rs b/tests/rustdoc/auxiliary/trait-alias-mention.rs
deleted file mode 100644
index 6df06c8..0000000
--- a/tests/rustdoc/auxiliary/trait-alias-mention.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-#![feature(trait_alias)]
-
-pub trait SomeAlias = std::fmt::Debug + std::marker::Copy;
diff --git a/tests/rustdoc/ffi.rs b/tests/rustdoc/ffi.rs
index 5ba7cdb..524fb0e 100644
--- a/tests/rustdoc/ffi.rs
+++ b/tests/rustdoc/ffi.rs
@@ -9,4 +9,8 @@
extern "C" {
//@ has ffi/fn.another.html //pre 'pub unsafe extern "C" fn another(cold_as_ice: u32)'
pub fn another(cold_as_ice: u32);
+
+ //@ has ffi/fn.params_are_unnamed.html //pre \
+ // 'pub unsafe extern "C" fn params_are_unnamed(_: i32, _: u32)'
+ pub fn params_are_unnamed(_: i32, _: u32);
}
diff --git a/tests/rustdoc/inline_cross/auxiliary/fn-type.rs b/tests/rustdoc/inline_cross/auxiliary/fn-ptr-ty.rs
similarity index 100%
rename from tests/rustdoc/inline_cross/auxiliary/fn-type.rs
rename to tests/rustdoc/inline_cross/auxiliary/fn-ptr-ty.rs
diff --git a/tests/rustdoc/inline_cross/default-generic-args.rs b/tests/rustdoc/inline_cross/default-generic-args.rs
index 0469221..5124fbd 100644
--- a/tests/rustdoc/inline_cross/default-generic-args.rs
+++ b/tests/rustdoc/inline_cross/default-generic-args.rs
@@ -53,17 +53,17 @@
//@ has user/type.H0.html
// Check that we handle higher-ranked regions correctly:
-//@ has - '//*[@class="rust item-decl"]//code' "fn(_: for<'a> fn(_: Re<'a>))"
+//@ has - '//*[@class="rust item-decl"]//code' "fn(for<'a> fn(Re<'a>))"
pub use default_generic_args::H0;
//@ has user/type.H1.html
// Check that we don't conflate distinct universially quantified regions (#1):
-//@ has - '//*[@class="rust item-decl"]//code' "for<'b> fn(_: for<'a> fn(_: Re<'a, &'b ()>))"
+//@ has - '//*[@class="rust item-decl"]//code' "for<'b> fn(for<'a> fn(Re<'a, &'b ()>))"
pub use default_generic_args::H1;
//@ has user/type.H2.html
// Check that we don't conflate distinct universially quantified regions (#2):
-//@ has - '//*[@class="rust item-decl"]//code' "for<'a> fn(_: for<'b> fn(_: Re<'a, &'b ()>))"
+//@ has - '//*[@class="rust item-decl"]//code' "for<'a> fn(for<'b> fn(Re<'a, &'b ()>))"
pub use default_generic_args::H2;
//@ has user/type.P0.html
@@ -86,7 +86,7 @@
// Demonstrates that we currently don't elide generic arguments that are alpha-equivalent to their
// respective generic parameter (after instantiation) for perf reasons (it would require us to
// create an inference context).
-//@ has - '//*[@class="rust item-decl"]//code' "Alpha<for<'arbitrary> fn(_: &'arbitrary ())>"
+//@ has - '//*[@class="rust item-decl"]//code' "Alpha<for<'arbitrary> fn(&'arbitrary ())>"
pub use default_generic_args::A1;
//@ has user/type.M0.html
diff --git a/tests/rustdoc/inline_cross/fn-type.rs b/tests/rustdoc/inline_cross/fn-ptr-ty.rs
similarity index 71%
rename from tests/rustdoc/inline_cross/fn-type.rs
rename to tests/rustdoc/inline_cross/fn-ptr-ty.rs
index 8db6f65..0105962 100644
--- a/tests/rustdoc/inline_cross/fn-type.rs
+++ b/tests/rustdoc/inline_cross/fn-ptr-ty.rs
@@ -2,11 +2,11 @@
// They should be rendered exactly as the user wrote it, i.e., in source order and with unused
// parameters present, not stripped.
-//@ aux-crate:fn_type=fn-type.rs
+//@ aux-crate:fn_ptr_ty=fn-ptr-ty.rs
//@ edition: 2021
#![crate_name = "user"]
//@ has user/type.F.html
//@ has - '//*[@class="rust item-decl"]//code' \
-// "for<'z, 'a, '_unused> fn(_: &'z for<'b> fn(_: &'b str), _: &'a ()) -> &'a ();"
-pub use fn_type::F;
+// "for<'z, 'a, '_unused> fn(&'z for<'b> fn(&'b str), &'a ()) -> &'a ();"
+pub use fn_ptr_ty::F;
diff --git a/tests/rustdoc/inline_cross/impl_trait.rs b/tests/rustdoc/inline_cross/impl_trait.rs
index e6baf33..468ac08 100644
--- a/tests/rustdoc/inline_cross/impl_trait.rs
+++ b/tests/rustdoc/inline_cross/impl_trait.rs
@@ -29,7 +29,7 @@
//@ has impl_trait/fn.func5.html
//@ has - '//pre[@class="rust item-decl"]' "func5("
//@ has - '//pre[@class="rust item-decl"]' "_f: impl for<'any> Fn(&'any str, &'any str) -> bool + for<'r> Other<T<'r> = ()>,"
-//@ has - '//pre[@class="rust item-decl"]' "_a: impl for<'beta, 'alpha, '_gamma> Auxiliary<'alpha, Item<'beta> = fn(_: &'beta ())>"
+//@ has - '//pre[@class="rust item-decl"]' "_a: impl for<'beta, 'alpha, '_gamma> Auxiliary<'alpha, Item<'beta> = fn(&'beta ())>"
//@ !has - '//pre[@class="rust item-decl"]' 'where'
pub use impl_trait_aux::func5;
diff --git a/tests/rustdoc/trait-alias-mention.rs b/tests/rustdoc/trait-alias-mention.rs
deleted file mode 100644
index b6ef926..0000000
--- a/tests/rustdoc/trait-alias-mention.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-//@ aux-build:trait-alias-mention.rs
-//@ build-aux-docs
-
-#![crate_name = "foo"]
-
-extern crate trait_alias_mention;
-
-//@ has foo/fn.mention_alias_in_bounds.html '//a[@href="../trait_alias_mention/traitalias.SomeAlias.html"]' 'SomeAlias'
-pub fn mention_alias_in_bounds<T: trait_alias_mention::SomeAlias>() {
-}
diff --git a/tests/rustdoc/trait-aliases.rs b/tests/rustdoc/trait-aliases.rs
new file mode 100644
index 0000000..1be93f7
--- /dev/null
+++ b/tests/rustdoc/trait-aliases.rs
@@ -0,0 +1,82 @@
+// Basic testing for trait aliases.
+#![feature(trait_alias)]
+#![crate_name = "it"]
+
+// Check the "local case" (HIR cleaning) //
+
+//@ has it/all.html '//a[@href="traitalias.Alias0.html"]' 'Alias0'
+//@ has it/index.html '//h2[@id="trait-aliases"]' 'Trait Aliases'
+//@ has it/index.html '//a[@class="traitalias"]' 'Alias0'
+//@ has it/traitalias.Alias0.html
+//@ has - '//*[@class="rust item-decl"]//code' 'trait Alias0 = Copy + Iterator<Item = u8>;'
+pub trait Alias0 = Copy + Iterator<Item = u8>;
+
+//@ has it/traitalias.Alias1.html
+//@ has - '//pre[@class="rust item-decl"]' \
+// "trait Alias1<'a, T: 'a + Clone, const N: usize> = From<[&'a T; N]>;"
+pub trait Alias1<'a, T: 'a + Clone, const N: usize> = From<[&'a T; N]>;
+
+//@ has it/traitalias.Alias2.html
+//@ has - '//pre[@class="rust item-decl"]' \
+// 'trait Alias2<T> = where T: From<String>, String: Into<T>;'
+pub trait Alias2<T> = where T: From<String>, String: Into<T>;
+
+//@ has it/traitalias.Alias3.html
+//@ has - '//pre[@class="rust item-decl"]' 'trait Alias3 = ;'
+pub trait Alias3 =;
+
+//@ has it/traitalias.Alias4.html
+//@ has - '//pre[@class="rust item-decl"]' 'trait Alias4 = ;'
+pub trait Alias4 = where;
+
+//@ has it/fn.usage0.html
+//@ has - '//pre[@class="rust item-decl"]' "pub fn usage0(_: impl Alias0)"
+//@ has - '//a[@href="traitalias.Alias0.html"]' 'Alias0'
+pub fn usage0(_: impl Alias0) {}
+
+// FIXME: One can only "disambiguate" intra-doc links to trait aliases with `type@` but not with
+// `trait@` (fails to resolve) or `traitalias@` (doesn't exist). We should make at least one of
+// the latter two work, right?
+
+//@ has it/link0/index.html
+//@ has - '//a/@href' 'traitalias.Alias0.html'
+//@ has - '//a/@href' 'traitalias.Alias1.html'
+/// [Alias0], [type@Alias1]
+pub mod link0 {}
+
+// Check the "extern case" (middle cleaning) //
+
+//@ aux-build: ext-trait-aliases.rs
+extern crate ext_trait_aliases as ext;
+
+//@ has it/traitalias.ExtAlias0.html
+//@ has - '//pre[@class="rust item-decl"]' 'trait ExtAlias0 = Copy + Iterator<Item = u8>;'
+pub use ext::ExtAlias0;
+
+//@ has it/traitalias.ExtAlias1.html
+//@ has - '//pre[@class="rust item-decl"]' \
+// "trait ExtAlias1<'a, T, const N: usize> = From<[&'a T; N]> where T: 'a + Clone;"
+pub use ext::ExtAlias1;
+
+//@ has it/traitalias.ExtAlias2.html
+//@ has - '//pre[@class="rust item-decl"]' \
+// 'trait ExtAlias2<T> = where T: From<String>, String: Into<T>;'
+pub use ext::ExtAlias2;
+
+//@ has it/traitalias.ExtAlias3.html
+//@ has - '//pre[@class="rust item-decl"]' 'trait ExtAlias3 = Sized;'
+pub use ext::ExtAlias3;
+
+// NOTE: Middle cleaning can't discern `= Sized` and `= where Self: Sized` and that's okay.
+//@ has it/traitalias.ExtAlias4.html
+//@ has - '//pre[@class="rust item-decl"]' 'trait ExtAlias4 = Sized;'
+pub use ext::ExtAlias4;
+
+//@ has it/traitalias.ExtAlias5.html
+//@ has - '//pre[@class="rust item-decl"]' 'trait ExtAlias5 = ;'
+pub use ext::ExtAlias5;
+
+//@ has it/fn.usage1.html
+//@ has - '//pre[@class="rust item-decl"]' "pub fn usage1(_: impl ExtAlias0)"
+//@ has - '//a[@href="traitalias.ExtAlias0.html"]' 'ExtAlias0'
+pub fn usage1(_: impl ExtAlias0) {}
diff --git a/tests/rustdoc/trait_alias.rs b/tests/rustdoc/trait_alias.rs
deleted file mode 100644
index bfdb9d4..0000000
--- a/tests/rustdoc/trait_alias.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-#![feature(trait_alias)]
-
-#![crate_name = "foo"]
-
-use std::fmt::Debug;
-
-//@ has foo/all.html '//a[@href="traitalias.CopyAlias.html"]' 'CopyAlias'
-//@ has foo/all.html '//a[@href="traitalias.Alias2.html"]' 'Alias2'
-//@ has foo/all.html '//a[@href="traitalias.Foo.html"]' 'Foo'
-
-//@ has foo/index.html '//h2[@id="trait-aliases"]' 'Trait Aliases'
-//@ has foo/index.html '//a[@class="traitalias"]' 'CopyAlias'
-//@ has foo/index.html '//a[@class="traitalias"]' 'Alias2'
-//@ has foo/index.html '//a[@class="traitalias"]' 'Foo'
-
-//@ has foo/traitalias.CopyAlias.html
-//@ has - '//section[@id="main-content"]/pre[@class="rust item-decl"]' 'trait CopyAlias = Copy;'
-pub trait CopyAlias = Copy;
-//@ has foo/traitalias.Alias2.html
-//@ has - '//section[@id="main-content"]/pre[@class="rust item-decl"]' 'trait Alias2 = Copy + Debug;'
-pub trait Alias2 = Copy + Debug;
-//@ has foo/traitalias.Foo.html
-//@ has - '//section[@id="main-content"]/pre[@class="rust item-decl"]' 'trait Foo<T> = Into<T> + Debug;'
-pub trait Foo<T> = Into<T> + Debug;
-//@ has foo/fn.bar.html '//a[@href="traitalias.Alias2.html"]' 'Alias2'
-pub fn bar<T>() where T: Alias2 {}
diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.rs b/tests/ui-fulldeps/internal-lints/diagnostics.rs
index 442f9d7..1238fef 100644
--- a/tests/ui-fulldeps/internal-lints/diagnostics.rs
+++ b/tests/ui-fulldeps/internal-lints/diagnostics.rs
@@ -15,7 +15,7 @@
use rustc_errors::{
Diag, DiagCtxtHandle, DiagInner, DiagMessage, Diagnostic, EmissionGuarantee, Level,
- LintDiagnostic, SubdiagMessage, SubdiagMessageOp, Subdiagnostic,
+ LintDiagnostic, SubdiagMessage, Subdiagnostic,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::Span;
@@ -56,10 +56,9 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> {
pub struct UntranslatableInAddtoDiag;
impl Subdiagnostic for UntranslatableInAddtoDiag {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+ fn add_to_diag<G: EmissionGuarantee>(
self,
diag: &mut Diag<'_, G>,
- f: &F,
) {
diag.note("untranslatable diagnostic");
//~^ ERROR diagnostics should be created using translatable messages
@@ -69,10 +68,9 @@ fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
pub struct TranslatableInAddtoDiag;
impl Subdiagnostic for TranslatableInAddtoDiag {
- fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+ fn add_to_diag<G: EmissionGuarantee>(
self,
diag: &mut Diag<'_, G>,
- f: &F,
) {
diag.note(crate::fluent_generated::no_crate_note);
}
diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.stderr b/tests/ui-fulldeps/internal-lints/diagnostics.stderr
index 36dd3cf..b260c4b 100644
--- a/tests/ui-fulldeps/internal-lints/diagnostics.stderr
+++ b/tests/ui-fulldeps/internal-lints/diagnostics.stderr
@@ -11,19 +11,19 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should be created using translatable messages
- --> $DIR/diagnostics.rs:64:19
+ --> $DIR/diagnostics.rs:63:19
|
LL | diag.note("untranslatable diagnostic");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should be created using translatable messages
- --> $DIR/diagnostics.rs:85:19
+ --> $DIR/diagnostics.rs:83:19
|
LL | diag.note("untranslatable diagnostic");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls
- --> $DIR/diagnostics.rs:99:21
+ --> $DIR/diagnostics.rs:97:21
|
LL | let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example);
| ^^^^^^^^^^
@@ -35,37 +35,37 @@
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls
- --> $DIR/diagnostics.rs:102:21
+ --> $DIR/diagnostics.rs:100:21
|
LL | let _diag = dcx.struct_err("untranslatable diagnostic");
| ^^^^^^^^^^
error: diagnostics should be created using translatable messages
- --> $DIR/diagnostics.rs:102:32
+ --> $DIR/diagnostics.rs:100:32
|
LL | let _diag = dcx.struct_err("untranslatable diagnostic");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should be created using translatable messages
- --> $DIR/diagnostics.rs:120:7
+ --> $DIR/diagnostics.rs:118:7
|
LL | f("untranslatable diagnostic", crate::fluent_generated::no_crate_example);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should be created using translatable messages
- --> $DIR/diagnostics.rs:122:50
+ --> $DIR/diagnostics.rs:120:50
|
LL | f(crate::fluent_generated::no_crate_example, "untranslatable diagnostic");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should be created using translatable messages
- --> $DIR/diagnostics.rs:124:7
+ --> $DIR/diagnostics.rs:122:7
|
LL | f("untranslatable diagnostic", "untranslatable diagnostic");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: diagnostics should be created using translatable messages
- --> $DIR/diagnostics.rs:124:36
+ --> $DIR/diagnostics.rs:122:36
|
LL | f("untranslatable diagnostic", "untranslatable diagnostic");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui-fulldeps/missing-rustc-driver-error.rs b/tests/ui-fulldeps/missing-rustc-driver-error.rs
index d582efa..c6dff2d 100644
--- a/tests/ui-fulldeps/missing-rustc-driver-error.rs
+++ b/tests/ui-fulldeps/missing-rustc-driver-error.rs
@@ -1,11 +1,15 @@
// Test that we get the following hint when trying to use a compiler crate without rustc_driver.
-//@ error-pattern: try adding `extern crate rustc_driver;` at the top level of this crate
-//@ compile-flags: --emit link --error-format=human
+//@ compile-flags: --emit link
//@ normalize-stderr: ".*crate .* required.*\n\n" -> ""
//@ normalize-stderr: "aborting due to [0-9]+" -> "aborting due to NUMBER"
+//@ dont-require-annotations: ERROR
#![feature(rustc_private)]
extern crate rustc_serialize;
fn main() {}
+
+//~? HELP try adding `extern crate rustc_driver;` at the top level of this crate
+//~? HELP try adding `extern crate rustc_driver;` at the top level of this crate
+//~? HELP try adding `extern crate rustc_driver;` at the top level of this crate
diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs
index ef2d5b4..ebf2e33 100644
--- a/tests/ui-fulldeps/stable-mir/check_abi.rs
+++ b/tests/ui-fulldeps/stable-mir/check_abi.rs
@@ -17,7 +17,6 @@
extern crate rustc_interface;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use stable_mir::abi::{
ArgAbi, CallConvention, FieldsShape, IntegerLength, PassMode, Primitive, Scalar, ValueAbi,
VariantsShape,
diff --git a/tests/ui-fulldeps/stable-mir/check_allocation.rs b/tests/ui-fulldeps/stable-mir/check_allocation.rs
index c102f86..ae2609b 100644
--- a/tests/ui-fulldeps/stable-mir/check_allocation.rs
+++ b/tests/ui-fulldeps/stable-mir/check_allocation.rs
@@ -19,7 +19,6 @@
extern crate rustc_interface;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use stable_mir::crate_def::CrateDef;
use stable_mir::mir::alloc::GlobalAlloc;
use stable_mir::mir::mono::{Instance, InstanceKind, StaticDef};
diff --git a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs
index f751136..9d61154 100644
--- a/tests/ui-fulldeps/stable-mir/check_assoc_items.rs
+++ b/tests/ui-fulldeps/stable-mir/check_assoc_items.rs
@@ -17,7 +17,6 @@
extern crate rustc_interface;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use std::io::Write;
use std::collections::HashSet;
use stable_mir::CrateDef;
diff --git a/tests/ui-fulldeps/stable-mir/check_attribute.rs b/tests/ui-fulldeps/stable-mir/check_attribute.rs
index de5ba15..4148fc0 100644
--- a/tests/ui-fulldeps/stable-mir/check_attribute.rs
+++ b/tests/ui-fulldeps/stable-mir/check_attribute.rs
@@ -15,7 +15,6 @@
extern crate rustc_interface;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use stable_mir::{CrateDef, CrateItems};
use std::io::Write;
use std::ops::ControlFlow;
diff --git a/tests/ui-fulldeps/stable-mir/check_binop.rs b/tests/ui-fulldeps/stable-mir/check_binop.rs
index 65b3ffd..6a141e9 100644
--- a/tests/ui-fulldeps/stable-mir/check_binop.rs
+++ b/tests/ui-fulldeps/stable-mir/check_binop.rs
@@ -15,7 +15,6 @@
extern crate rustc_interface;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use stable_mir::mir::mono::Instance;
use stable_mir::mir::visit::{Location, MirVisitor};
use stable_mir::mir::{LocalDecl, Rvalue, Statement, StatementKind, Terminator, TerminatorKind};
diff --git a/tests/ui-fulldeps/stable-mir/check_crate_defs.rs b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs
index 71cca94..31c4719 100644
--- a/tests/ui-fulldeps/stable-mir/check_crate_defs.rs
+++ b/tests/ui-fulldeps/stable-mir/check_crate_defs.rs
@@ -16,7 +16,6 @@
extern crate rustc_interface;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use stable_mir::CrateDef;
use std::collections::HashSet;
use std::io::Write;
diff --git a/tests/ui-fulldeps/stable-mir/check_def_ty.rs b/tests/ui-fulldeps/stable-mir/check_def_ty.rs
index 37b9a83..00a34f1 100644
--- a/tests/ui-fulldeps/stable-mir/check_def_ty.rs
+++ b/tests/ui-fulldeps/stable-mir/check_def_ty.rs
@@ -17,7 +17,6 @@
extern crate rustc_interface;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use stable_mir::ty::{Ty, ForeignItemKind};
use stable_mir::*;
use std::io::Write;
diff --git a/tests/ui-fulldeps/stable-mir/check_defs.rs b/tests/ui-fulldeps/stable-mir/check_defs.rs
index cd3d76d..1ba7337 100644
--- a/tests/ui-fulldeps/stable-mir/check_defs.rs
+++ b/tests/ui-fulldeps/stable-mir/check_defs.rs
@@ -19,7 +19,6 @@
use std::assert_matches::assert_matches;
use mir::{mono::Instance, TerminatorKind::*};
use stable_mir::mir::mono::InstanceKind;
-use rustc_smir::rustc_internal;
use stable_mir::ty::{RigidTy, TyKind, Ty, UintTy};
use stable_mir::*;
use std::io::Write;
diff --git a/tests/ui-fulldeps/stable-mir/check_foreign.rs b/tests/ui-fulldeps/stable-mir/check_foreign.rs
index bc3956b..4419050 100644
--- a/tests/ui-fulldeps/stable-mir/check_foreign.rs
+++ b/tests/ui-fulldeps/stable-mir/check_foreign.rs
@@ -17,7 +17,6 @@
extern crate rustc_span;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use stable_mir::{
ty::{Abi, ForeignItemKind},
*,
diff --git a/tests/ui-fulldeps/stable-mir/check_instance.rs b/tests/ui-fulldeps/stable-mir/check_instance.rs
index 72a138f..1510a62 100644
--- a/tests/ui-fulldeps/stable-mir/check_instance.rs
+++ b/tests/ui-fulldeps/stable-mir/check_instance.rs
@@ -21,7 +21,6 @@
use mir::mono::Instance;
use mir::TerminatorKind::*;
-use rustc_smir::rustc_internal;
use stable_mir::ty::{RigidTy, TyKind};
use stable_mir::*;
diff --git a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs
index 07a2a62..3f04abb 100644
--- a/tests/ui-fulldeps/stable-mir/check_intrinsics.rs
+++ b/tests/ui-fulldeps/stable-mir/check_intrinsics.rs
@@ -20,7 +20,6 @@
extern crate rustc_interface;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use stable_mir::mir::mono::{Instance, InstanceKind};
use stable_mir::mir::visit::{Location, MirVisitor};
use stable_mir::mir::{LocalDecl, Terminator, TerminatorKind};
diff --git a/tests/ui-fulldeps/stable-mir/check_item_kind.rs b/tests/ui-fulldeps/stable-mir/check_item_kind.rs
index 647ce53..bb8c00c 100644
--- a/tests/ui-fulldeps/stable-mir/check_item_kind.rs
+++ b/tests/ui-fulldeps/stable-mir/check_item_kind.rs
@@ -16,7 +16,6 @@
extern crate rustc_interface;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use stable_mir::*;
use std::io::Write;
use std::ops::ControlFlow;
diff --git a/tests/ui-fulldeps/stable-mir/check_normalization.rs b/tests/ui-fulldeps/stable-mir/check_normalization.rs
index de14202..797cb4c 100644
--- a/tests/ui-fulldeps/stable-mir/check_normalization.rs
+++ b/tests/ui-fulldeps/stable-mir/check_normalization.rs
@@ -17,7 +17,6 @@
use mir::mono::Instance;
use ty::{Ty, TyKind, RigidTy};
-use rustc_smir::rustc_internal;
use stable_mir::*;
use std::io::Write;
use std::ops::ControlFlow;
diff --git a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs
index 23c2844..d9170d0 100644
--- a/tests/ui-fulldeps/stable-mir/check_trait_queries.rs
+++ b/tests/ui-fulldeps/stable-mir/check_trait_queries.rs
@@ -16,7 +16,6 @@
extern crate rustc_interface;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use stable_mir::CrateDef;
use std::collections::HashSet;
use std::io::Write;
diff --git a/tests/ui-fulldeps/stable-mir/check_transform.rs b/tests/ui-fulldeps/stable-mir/check_transform.rs
index d9fc924..604cc72 100644
--- a/tests/ui-fulldeps/stable-mir/check_transform.rs
+++ b/tests/ui-fulldeps/stable-mir/check_transform.rs
@@ -17,7 +17,6 @@
extern crate rustc_interface;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use stable_mir::mir::alloc::GlobalAlloc;
use stable_mir::mir::mono::Instance;
use stable_mir::mir::{Body, ConstOperand, Operand, Rvalue, StatementKind, TerminatorKind};
diff --git a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs
index 9d71697..23233f8 100644
--- a/tests/ui-fulldeps/stable-mir/check_ty_fold.rs
+++ b/tests/ui-fulldeps/stable-mir/check_ty_fold.rs
@@ -17,7 +17,6 @@
extern crate rustc_interface;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use stable_mir::mir::{
Body, FieldIdx, MirVisitor, Place, ProjectionElem,
visit::{Location, PlaceContext},
diff --git a/tests/ui-fulldeps/stable-mir/compilation-result.rs b/tests/ui-fulldeps/stable-mir/compilation-result.rs
index b8a9e72..3941663 100644
--- a/tests/ui-fulldeps/stable-mir/compilation-result.rs
+++ b/tests/ui-fulldeps/stable-mir/compilation-result.rs
@@ -16,7 +16,6 @@
extern crate rustc_interface;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use std::io::Write;
/// This test will generate and analyze a dummy crate using the stable mir.
diff --git a/tests/ui-fulldeps/stable-mir/crate-info.rs b/tests/ui-fulldeps/stable-mir/crate-info.rs
index 4d2d7e2..e2086d5 100644
--- a/tests/ui-fulldeps/stable-mir/crate-info.rs
+++ b/tests/ui-fulldeps/stable-mir/crate-info.rs
@@ -18,7 +18,6 @@
extern crate stable_mir;
use rustc_hir::def::DefKind;
-use rustc_smir::rustc_internal;
use stable_mir::ItemKind;
use stable_mir::crate_def::CrateDef;
use stable_mir::mir::mono::Instance;
diff --git a/tests/ui-fulldeps/stable-mir/projections.rs b/tests/ui-fulldeps/stable-mir/projections.rs
index 6f82eba..f3bd894 100644
--- a/tests/ui-fulldeps/stable-mir/projections.rs
+++ b/tests/ui-fulldeps/stable-mir/projections.rs
@@ -17,7 +17,6 @@
extern crate rustc_interface;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use stable_mir::ItemKind;
use stable_mir::crate_def::CrateDef;
use stable_mir::mir::{ProjectionElem, Rvalue, StatementKind};
diff --git a/tests/ui-fulldeps/stable-mir/smir_serde.rs b/tests/ui-fulldeps/stable-mir/smir_serde.rs
index 9b3638a..3b3d743 100644
--- a/tests/ui-fulldeps/stable-mir/smir_serde.rs
+++ b/tests/ui-fulldeps/stable-mir/smir_serde.rs
@@ -19,7 +19,6 @@
extern crate stable_mir;
use rustc_middle::ty::TyCtxt;
-use rustc_smir::rustc_internal;
use serde_json::to_string;
use stable_mir::mir::Body;
use std::io::{BufWriter, Write};
diff --git a/tests/ui-fulldeps/stable-mir/smir_visitor.rs b/tests/ui-fulldeps/stable-mir/smir_visitor.rs
index 0a579a0..d225d97 100644
--- a/tests/ui-fulldeps/stable-mir/smir_visitor.rs
+++ b/tests/ui-fulldeps/stable-mir/smir_visitor.rs
@@ -16,7 +16,6 @@
extern crate rustc_interface;
extern crate stable_mir;
-use rustc_smir::rustc_internal;
use stable_mir::mir::MirVisitor;
use stable_mir::mir::MutMirVisitor;
use stable_mir::*;
diff --git a/tests/ui/README.md b/tests/ui/README.md
deleted file mode 100644
index aa36481..0000000
--- a/tests/ui/README.md
+++ /dev/null
@@ -1,35 +0,0 @@
-# UI Tests
-
-This folder contains `rustc`'s
-[UI tests](https://rustc-dev-guide.rust-lang.org/tests/ui.html).
-
-## Test Directives (Headers)
-
-Typically, a UI test will have some test directives / headers which are
-special comments that tell compiletest how to build and interpret a test.
-
-As part of an ongoing effort to rewrite compiletest
-(see <https://github.com/rust-lang/compiler-team/issues/536>), a major
-change proposal to change legacy compiletest-style headers `// <directive>`
-to [`ui_test`](https://github.com/oli-obk/ui_test)-style headers
-`//@ <directive>` was accepted (see
-<https://github.com/rust-lang/compiler-team/issues/512>.
-
-An example directive is `ignore-test`. In legacy compiletest style, the header
-would be written as
-
-```rs
-// ignore-test
-```
-
-but in `ui_test` style, the header would be written as
-
-```rs
-//@ ignore-test
-```
-
-compiletest is changed to accept only `//@` directives for UI tests
-(currently), and will reject and report an error if it encounters any
-comments `// <content>` that may be parsed as a legacy compiletest-style
-test header. To fix this, you should migrate to the `ui_test`-style header
-`//@ <content>`.
diff --git a/tests/ui/abi/debug.rs b/tests/ui/abi/debug.rs
index 6dbc316..c0d8de0 100644
--- a/tests/ui/abi/debug.rs
+++ b/tests/ui/abi/debug.rs
@@ -52,3 +52,6 @@ fn assoc_test(&self) { } //~ ERROR: fn_abi
#[rustc_abi(assert_eq)]
type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); //~ ERROR: cannot be known at compilation time
+
+#[rustc_abi("assert_eq")] //~ ERROR unrecognized argument
+type Bad = u32;
diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr
index 2239ba0..480f3f0 100644
--- a/tests/ui/abi/debug.stderr
+++ b/tests/ui/abi/debug.stderr
@@ -906,6 +906,12 @@
= help: the trait `Sized` is not implemented for `str`
= note: only the last element of a tuple may have a dynamically sized type
+error: unrecognized argument
+ --> $DIR/debug.rs:56:13
+ |
+LL | #[rustc_abi("assert_eq")]
+ | ^^^^^^^^^^^
+
error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
--> $DIR/debug.rs:29:5
|
@@ -1004,6 +1010,6 @@
LL | fn assoc_test(&self) { }
| ^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 11 previous errors
+error: aborting due to 12 previous errors
For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/abi/fixed_x18.rs b/tests/ui/abi/fixed_x18.rs
index d373468..d64b845 100644
--- a/tests/ui/abi/fixed_x18.rs
+++ b/tests/ui/abi/fixed_x18.rs
@@ -2,7 +2,6 @@
// Behavior on aarch64 is tested by tests/codegen/fixed-x18.rs.
//
//@ revisions: x64 i686 arm riscv32 riscv64
-//@ error-pattern: the `-Zfixed-x18` flag is not supported
//@ dont-check-compiler-stderr
//
//@ compile-flags: -Zfixed-x18
diff --git a/tests/ui/abi/simd-abi-checks-avx.rs b/tests/ui/abi/simd-abi-checks-avx.rs
index c31af64..7725127 100644
--- a/tests/ui/abi/simd-abi-checks-avx.rs
+++ b/tests/ui/abi/simd-abi-checks-avx.rs
@@ -1,6 +1,5 @@
//@ only-x86_64
-//@ build-pass
-//@ ignore-pass (test emits codegen-time warnings)
+//@ build-fail
//@ compile-flags: -C target-feature=-avx
#![feature(avx512_target_feature)]
@@ -14,20 +13,17 @@
struct Wrapper(__m256);
unsafe extern "C" fn w(_: Wrapper) {
- //~^ WARN requires the `avx` target feature, which is not enabled
- //~| WARNING this was previously accepted by the compiler
+ //~^ ERROR: requires the `avx` target feature, which is not enabled
todo!()
}
unsafe extern "C" fn f(_: __m256) {
- //~^ WARN requires the `avx` target feature, which is not enabled
- //~| WARNING this was previously accepted by the compiler
+ //~^ ERROR: requires the `avx` target feature, which is not enabled
todo!()
}
unsafe extern "C" fn g() -> __m256 {
- //~^ WARN requires the `avx` target feature, which is not enabled
- //~| WARNING this was previously accepted by the compiler
+ //~^ ERROR: requires the `avx` target feature, which is not enabled
todo!()
}
@@ -56,25 +52,20 @@ unsafe fn test() {
unsafe fn in_closure() -> impl FnOnce() -> __m256 {
#[inline(always)] // this disables target-feature inheritance
|| g()
- //~^ WARNING requires the `avx` target feature, which is not enabled in the caller
- //~| WARNING this was previously accepted by the compiler
+ //~^ ERROR requires the `avx` target feature, which is not enabled in the caller
}
fn main() {
unsafe {
f(g());
- //~^ WARNING requires the `avx` target feature, which is not enabled in the caller
- //~| WARNING requires the `avx` target feature, which is not enabled in the caller
- //~| WARNING this was previously accepted by the compiler
- //~| WARNING this was previously accepted by the compiler
+ //~^ ERROR requires the `avx` target feature, which is not enabled in the caller
+ //~| ERROR requires the `avx` target feature, which is not enabled in the caller
}
unsafe {
gavx(favx());
- //~^ WARNING requires the `avx` target feature, which is not enabled in the caller
- //~| WARNING requires the `avx` target feature, which is not enabled in the caller
- //~| WARNING this was previously accepted by the compiler
- //~| WARNING this was previously accepted by the compiler
+ //~^ ERROR requires the `avx` target feature, which is not enabled in the caller
+ //~| ERROR requires the `avx` target feature, which is not enabled in the caller
}
unsafe {
@@ -83,10 +74,8 @@ fn main() {
unsafe {
w(Wrapper(g()));
- //~^ WARNING requires the `avx` target feature, which is not enabled in the caller
- //~| WARNING requires the `avx` target feature, which is not enabled in the caller
- //~| WARNING this was previously accepted by the compiler
- //~| WARNING this was previously accepted by the compiler
+ //~^ ERROR requires the `avx` target feature, which is not enabled in the caller
+ //~| ERROR requires the `avx` target feature, which is not enabled in the caller
}
unsafe {
@@ -99,8 +88,7 @@ fn main() {
fn some_extern() -> __m256;
}
some_extern();
- //~^ WARNING requires the `avx` target feature, which is not enabled in the caller
- //~| WARNING this was previously accepted by the compiler
+ //~^ ERROR requires the `avx` target feature, which is not enabled in the caller
}
}
diff --git a/tests/ui/abi/simd-abi-checks-avx.stderr b/tests/ui/abi/simd-abi-checks-avx.stderr
index 5419970..48db30b 100644
--- a/tests/ui/abi/simd-abi-checks-avx.stderr
+++ b/tests/ui/abi/simd-abi-checks-avx.stderr
@@ -1,245 +1,96 @@
-warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:65:11
+error: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
+ --> $DIR/simd-abi-checks-avx.rs:60:11
|
LL | f(g());
| ^^^ function called here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
-warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:65:9
+error: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
+ --> $DIR/simd-abi-checks-avx.rs:60:9
|
LL | f(g());
| ^^^^^^ function called here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
-warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:73:14
+error: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
+ --> $DIR/simd-abi-checks-avx.rs:66:14
|
LL | gavx(favx());
| ^^^^^^ function called here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
-warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:73:9
+error: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
+ --> $DIR/simd-abi-checks-avx.rs:66:9
|
LL | gavx(favx());
| ^^^^^^^^^^^^ function called here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
-warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:85:19
+error: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
+ --> $DIR/simd-abi-checks-avx.rs:76:19
|
LL | w(Wrapper(g()));
| ^^^ function called here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
-warning: this function call uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:85:9
+error: this function call uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
+ --> $DIR/simd-abi-checks-avx.rs:76:9
|
LL | w(Wrapper(g()));
| ^^^^^^^^^^^^^^^ function called here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
-warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:101:9
+error: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
+ --> $DIR/simd-abi-checks-avx.rs:90:9
|
LL | some_extern();
| ^^^^^^^^^^^^^ function called here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
-warning: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled
- --> $DIR/simd-abi-checks-avx.rs:28:1
+error: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled
+ --> $DIR/simd-abi-checks-avx.rs:25:1
|
LL | unsafe extern "C" fn g() -> __m256 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
-warning: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled
- --> $DIR/simd-abi-checks-avx.rs:22:1
+error: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled
+ --> $DIR/simd-abi-checks-avx.rs:20:1
|
LL | unsafe extern "C" fn f(_: __m256) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
-warning: this function definition uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled
- --> $DIR/simd-abi-checks-avx.rs:16:1
+error: this function definition uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled
+ --> $DIR/simd-abi-checks-avx.rs:15:1
|
LL | unsafe extern "C" fn w(_: Wrapper) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
-warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:58:8
+error: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
+ --> $DIR/simd-abi-checks-avx.rs:54:8
|
LL | || g()
| ^^^ function called here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
-warning: 11 warnings emitted
+note: the above error was encountered while instantiating `fn in_closure::{closure#0}`
+ --> $DIR/simd-abi-checks-avx.rs:82:9
+ |
+LL | in_closure()();
+ | ^^^^^^^^^^^^^^
-Future incompatibility report: Future breakage diagnostic:
-warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:65:11
- |
-LL | f(g());
- | ^^^ function called here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
-
-Future breakage diagnostic:
-warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:65:9
- |
-LL | f(g());
- | ^^^^^^ function called here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
-
-Future breakage diagnostic:
-warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:73:14
- |
-LL | gavx(favx());
- | ^^^^^^ function called here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
-
-Future breakage diagnostic:
-warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:73:9
- |
-LL | gavx(favx());
- | ^^^^^^^^^^^^ function called here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
-
-Future breakage diagnostic:
-warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:85:19
- |
-LL | w(Wrapper(g()));
- | ^^^ function called here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
-
-Future breakage diagnostic:
-warning: this function call uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:85:9
- |
-LL | w(Wrapper(g()));
- | ^^^^^^^^^^^^^^^ function called here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
-
-Future breakage diagnostic:
-warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:101:9
- |
-LL | some_extern();
- | ^^^^^^^^^^^^^ function called here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
-
-Future breakage diagnostic:
-warning: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled
- --> $DIR/simd-abi-checks-avx.rs:28:1
- |
-LL | unsafe extern "C" fn g() -> __m256 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
-
-Future breakage diagnostic:
-warning: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled
- --> $DIR/simd-abi-checks-avx.rs:22:1
- |
-LL | unsafe extern "C" fn f(_: __m256) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
-
-Future breakage diagnostic:
-warning: this function definition uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled
- --> $DIR/simd-abi-checks-avx.rs:16:1
- |
-LL | unsafe extern "C" fn w(_: Wrapper) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
-
-Future breakage diagnostic:
-warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
- --> $DIR/simd-abi-checks-avx.rs:58:8
- |
-LL | || g()
- | ^^^ function called here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
+error: aborting due to 11 previous errors
diff --git a/tests/ui/abi/simd-abi-checks-empty-list.rs b/tests/ui/abi/simd-abi-checks-empty-list.rs
index ba1b38a..d00445b 100644
--- a/tests/ui/abi/simd-abi-checks-empty-list.rs
+++ b/tests/ui/abi/simd-abi-checks-empty-list.rs
@@ -1,8 +1,9 @@
+//! At the time of writing, the list of "which target feature enables which vector size" is empty
+//! for SPARC. Ensure that this leads to all vector sizes causing an error.
//@ add-core-stubs
//@ needs-llvm-components: sparc
//@ compile-flags: --target=sparc-unknown-none-elf --crate-type=rlib
-//@ build-pass
-//@ ignore-pass (test emits codegen-time warnings)
+//@ build-fail
#![no_core]
#![feature(no_core, repr_simd)]
#![allow(improper_ctypes_definitions)]
@@ -14,5 +15,4 @@
pub struct SimdVec([i32; 4]);
pub extern "C" fn pass_by_vec(_: SimdVec) {}
-//~^ WARN this function definition uses SIMD vector type `SimdVec` which is not currently supported with the chosen ABI
-//~| WARNING this was previously accepted by the compiler
+//~^ ERROR: this function definition uses SIMD vector type `SimdVec` which is not currently supported with the chosen ABI
diff --git a/tests/ui/abi/simd-abi-checks-empty-list.stderr b/tests/ui/abi/simd-abi-checks-empty-list.stderr
index 111dda4..780afb3 100644
--- a/tests/ui/abi/simd-abi-checks-empty-list.stderr
+++ b/tests/ui/abi/simd-abi-checks-empty-list.stderr
@@ -1,23 +1,8 @@
-warning: this function definition uses SIMD vector type `SimdVec` which is not currently supported with the chosen ABI
- --> $DIR/simd-abi-checks-empty-list.rs:16:1
+error: this function definition uses SIMD vector type `SimdVec` which is not currently supported with the chosen ABI
+ --> $DIR/simd-abi-checks-empty-list.rs:17:1
|
LL | pub extern "C" fn pass_by_vec(_: SimdVec) {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
-warning: 1 warning emitted
-
-Future incompatibility report: Future breakage diagnostic:
-warning: this function definition uses SIMD vector type `SimdVec` which is not currently supported with the chosen ABI
- --> $DIR/simd-abi-checks-empty-list.rs:16:1
- |
-LL | pub extern "C" fn pass_by_vec(_: SimdVec) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
+error: aborting due to 1 previous error
diff --git a/tests/ui/abi/simd-abi-checks-s390x.rs b/tests/ui/abi/simd-abi-checks-s390x.rs
index 3743c75..2d4eb7a 100644
--- a/tests/ui/abi/simd-abi-checks-s390x.rs
+++ b/tests/ui/abi/simd-abi-checks-s390x.rs
@@ -13,7 +13,6 @@
#![no_core]
#![crate_type = "lib"]
#![allow(non_camel_case_types, improper_ctypes_definitions)]
-#![deny(abi_unsupported_vector_types)]
extern crate minicore;
use minicore::*;
@@ -38,13 +37,11 @@ impl<T: Copy> Copy for TransparentWrapper<T> {}
#[no_mangle]
extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
//~^ ERROR requires the `vector` target feature, which is not enabled
- //~^^ WARN this was previously accepted
*x
}
#[no_mangle]
extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
//~^ ERROR requires the `vector` target feature, which is not enabled
- //~^^ WARN this was previously accepted
*x
}
#[no_mangle]
@@ -93,7 +90,6 @@ extern "C" fn vector_transparent_wrapper_ret_small(
x: &TransparentWrapper<i8x8>,
) -> TransparentWrapper<i8x8> {
//~^^^ ERROR requires the `vector` target feature, which is not enabled
- //~^^^^ WARN this was previously accepted
*x
}
#[no_mangle]
@@ -101,7 +97,6 @@ extern "C" fn vector_transparent_wrapper_ret(
x: &TransparentWrapper<i8x16>,
) -> TransparentWrapper<i8x16> {
//~^^^ ERROR requires the `vector` target feature, which is not enabled
- //~^^^^ WARN this was previously accepted
*x
}
#[no_mangle]
@@ -115,13 +110,11 @@ extern "C" fn vector_transparent_wrapper_ret_large(
#[no_mangle]
extern "C" fn vector_arg_small(x: i8x8) -> i64 {
//~^ ERROR requires the `vector` target feature, which is not enabled
- //~^^ WARN this was previously accepted
unsafe { *(&x as *const i8x8 as *const i64) }
}
#[no_mangle]
extern "C" fn vector_arg(x: i8x16) -> i64 {
//~^ ERROR requires the `vector` target feature, which is not enabled
- //~^^ WARN this was previously accepted
unsafe { *(&x as *const i8x16 as *const i64) }
}
#[no_mangle]
@@ -133,13 +126,11 @@ extern "C" fn vector_arg_large(x: i8x32) -> i64 {
#[no_mangle]
extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
//~^ ERROR requires the `vector` target feature, which is not enabled
- //~^^ WARN this was previously accepted
unsafe { *(&x as *const Wrapper<i8x8> as *const i64) }
}
#[no_mangle]
extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
//~^ ERROR requires the `vector` target feature, which is not enabled
- //~^^ WARN this was previously accepted
unsafe { *(&x as *const Wrapper<i8x16> as *const i64) }
}
#[no_mangle]
@@ -151,13 +142,11 @@ extern "C" fn vector_wrapper_arg_large(x: Wrapper<i8x32>) -> i64 {
#[no_mangle]
extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
//~^ ERROR requires the `vector` target feature, which is not enabled
- //~^^ WARN this was previously accepted
unsafe { *(&x as *const TransparentWrapper<i8x8> as *const i64) }
}
#[no_mangle]
extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
//~^ ERROR requires the `vector` target feature, which is not enabled
- //~^^ WARN this was previously accepted
unsafe { *(&x as *const TransparentWrapper<i8x16> as *const i64) }
}
#[no_mangle]
diff --git a/tests/ui/abi/simd-abi-checks-s390x.z10.stderr b/tests/ui/abi/simd-abi-checks-s390x.z10.stderr
index d2f7abb..c1c4e90 100644
--- a/tests/ui/abi/simd-abi-checks-s390x.z10.stderr
+++ b/tests/ui/abi/simd-abi-checks-s390x.z10.stderr
@@ -1,275 +1,86 @@
error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:39:1
+ --> $DIR/simd-abi-checks-s390x.rs:38:1
|
LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:45:1
+ --> $DIR/simd-abi-checks-s390x.rs:43:1
|
LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:92:1
+ --> $DIR/simd-abi-checks-s390x.rs:89:1
|
LL | / extern "C" fn vector_transparent_wrapper_ret_small(
LL | | x: &TransparentWrapper<i8x8>,
LL | | ) -> TransparentWrapper<i8x8> {
| |_____________________________^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:100:1
+ --> $DIR/simd-abi-checks-s390x.rs:96:1
|
LL | / extern "C" fn vector_transparent_wrapper_ret(
LL | | x: &TransparentWrapper<i8x16>,
LL | | ) -> TransparentWrapper<i8x16> {
| |______________________________^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:116:1
+ --> $DIR/simd-abi-checks-s390x.rs:111:1
|
LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:122:1
+ --> $DIR/simd-abi-checks-s390x.rs:116:1
|
LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:134:1
+ --> $DIR/simd-abi-checks-s390x.rs:127:1
|
LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:140:1
+ --> $DIR/simd-abi-checks-s390x.rs:132:1
|
LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:152:1
+ --> $DIR/simd-abi-checks-s390x.rs:143:1
|
LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:158:1
+ --> $DIR/simd-abi-checks-s390x.rs:148:1
|
LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: aborting due to 10 previous errors
-Future incompatibility report: Future breakage diagnostic:
-error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:39:1
- |
-LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:45:1
- |
-LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:92:1
- |
-LL | / extern "C" fn vector_transparent_wrapper_ret_small(
-LL | | x: &TransparentWrapper<i8x8>,
-LL | | ) -> TransparentWrapper<i8x8> {
- | |_____________________________^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:100:1
- |
-LL | / extern "C" fn vector_transparent_wrapper_ret(
-LL | | x: &TransparentWrapper<i8x16>,
-LL | | ) -> TransparentWrapper<i8x16> {
- | |______________________________^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:116:1
- |
-LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:122:1
- |
-LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:134:1
- |
-LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:140:1
- |
-LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:152:1
- |
-LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:158:1
- |
-LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
diff --git a/tests/ui/abi/simd-abi-checks-s390x.z13_no_vector.stderr b/tests/ui/abi/simd-abi-checks-s390x.z13_no_vector.stderr
index d2f7abb..c1c4e90 100644
--- a/tests/ui/abi/simd-abi-checks-s390x.z13_no_vector.stderr
+++ b/tests/ui/abi/simd-abi-checks-s390x.z13_no_vector.stderr
@@ -1,275 +1,86 @@
error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:39:1
+ --> $DIR/simd-abi-checks-s390x.rs:38:1
|
LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:45:1
+ --> $DIR/simd-abi-checks-s390x.rs:43:1
|
LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:92:1
+ --> $DIR/simd-abi-checks-s390x.rs:89:1
|
LL | / extern "C" fn vector_transparent_wrapper_ret_small(
LL | | x: &TransparentWrapper<i8x8>,
LL | | ) -> TransparentWrapper<i8x8> {
| |_____________________________^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:100:1
+ --> $DIR/simd-abi-checks-s390x.rs:96:1
|
LL | / extern "C" fn vector_transparent_wrapper_ret(
LL | | x: &TransparentWrapper<i8x16>,
LL | | ) -> TransparentWrapper<i8x16> {
| |______________________________^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:116:1
+ --> $DIR/simd-abi-checks-s390x.rs:111:1
|
LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:122:1
+ --> $DIR/simd-abi-checks-s390x.rs:116:1
|
LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:134:1
+ --> $DIR/simd-abi-checks-s390x.rs:127:1
|
LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:140:1
+ --> $DIR/simd-abi-checks-s390x.rs:132:1
|
LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:152:1
+ --> $DIR/simd-abi-checks-s390x.rs:143:1
|
LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:158:1
+ --> $DIR/simd-abi-checks-s390x.rs:148:1
|
LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: aborting due to 10 previous errors
-Future incompatibility report: Future breakage diagnostic:
-error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:39:1
- |
-LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:45:1
- |
-LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:92:1
- |
-LL | / extern "C" fn vector_transparent_wrapper_ret_small(
-LL | | x: &TransparentWrapper<i8x8>,
-LL | | ) -> TransparentWrapper<i8x8> {
- | |_____________________________^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:100:1
- |
-LL | / extern "C" fn vector_transparent_wrapper_ret(
-LL | | x: &TransparentWrapper<i8x16>,
-LL | | ) -> TransparentWrapper<i8x16> {
- | |______________________________^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:116:1
- |
-LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:122:1
- |
-LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:134:1
- |
-LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:140:1
- |
-LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:152:1
- |
-LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:158:1
- |
-LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
diff --git a/tests/ui/abi/simd-abi-checks-s390x.z13_soft_float.stderr b/tests/ui/abi/simd-abi-checks-s390x.z13_soft_float.stderr
index d2f7abb..c1c4e90 100644
--- a/tests/ui/abi/simd-abi-checks-s390x.z13_soft_float.stderr
+++ b/tests/ui/abi/simd-abi-checks-s390x.z13_soft_float.stderr
@@ -1,275 +1,86 @@
error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:39:1
+ --> $DIR/simd-abi-checks-s390x.rs:38:1
|
LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:45:1
+ --> $DIR/simd-abi-checks-s390x.rs:43:1
|
LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:92:1
+ --> $DIR/simd-abi-checks-s390x.rs:89:1
|
LL | / extern "C" fn vector_transparent_wrapper_ret_small(
LL | | x: &TransparentWrapper<i8x8>,
LL | | ) -> TransparentWrapper<i8x8> {
| |_____________________________^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:100:1
+ --> $DIR/simd-abi-checks-s390x.rs:96:1
|
LL | / extern "C" fn vector_transparent_wrapper_ret(
LL | | x: &TransparentWrapper<i8x16>,
LL | | ) -> TransparentWrapper<i8x16> {
| |______________________________^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:116:1
+ --> $DIR/simd-abi-checks-s390x.rs:111:1
|
LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:122:1
+ --> $DIR/simd-abi-checks-s390x.rs:116:1
|
LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:134:1
+ --> $DIR/simd-abi-checks-s390x.rs:127:1
|
LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:140:1
+ --> $DIR/simd-abi-checks-s390x.rs:132:1
|
LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:152:1
+ --> $DIR/simd-abi-checks-s390x.rs:143:1
|
LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:158:1
+ --> $DIR/simd-abi-checks-s390x.rs:148:1
|
LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
error: aborting due to 10 previous errors
-Future incompatibility report: Future breakage diagnostic:
-error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:39:1
- |
-LL | extern "C" fn vector_ret_small(x: &i8x8) -> i8x8 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:45:1
- |
-LL | extern "C" fn vector_ret(x: &i8x16) -> i8x16 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:92:1
- |
-LL | / extern "C" fn vector_transparent_wrapper_ret_small(
-LL | | x: &TransparentWrapper<i8x8>,
-LL | | ) -> TransparentWrapper<i8x8> {
- | |_____________________________^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:100:1
- |
-LL | / extern "C" fn vector_transparent_wrapper_ret(
-LL | | x: &TransparentWrapper<i8x16>,
-LL | | ) -> TransparentWrapper<i8x16> {
- | |______________________________^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `i8x8` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:116:1
- |
-LL | extern "C" fn vector_arg_small(x: i8x8) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `i8x16` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:122:1
- |
-LL | extern "C" fn vector_arg(x: i8x16) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `Wrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:134:1
- |
-LL | extern "C" fn vector_wrapper_arg_small(x: Wrapper<i8x8>) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `Wrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:140:1
- |
-LL | extern "C" fn vector_wrapper_arg(x: Wrapper<i8x16>) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `TransparentWrapper<i8x8>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:152:1
- |
-LL | extern "C" fn vector_transparent_wrapper_arg_small(x: TransparentWrapper<i8x8>) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Future breakage diagnostic:
-error: this function definition uses SIMD vector type `TransparentWrapper<i8x16>` which (with the chosen ABI) requires the `vector` target feature, which is not enabled
- --> $DIR/simd-abi-checks-s390x.rs:158:1
- |
-LL | extern "C" fn vector_transparent_wrapper_arg(x: TransparentWrapper<i8x16>) -> i64 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+vector`) or locally (`#[target_feature(enable="vector")]`)
-note: the lint level is defined here
- --> $DIR/simd-abi-checks-s390x.rs:16:9
- |
-LL | #![deny(abi_unsupported_vector_types)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
diff --git a/tests/ui/abi/simd-abi-checks-sse.rs b/tests/ui/abi/simd-abi-checks-sse.rs
index d5fa9c0..817f9b6 100644
--- a/tests/ui/abi/simd-abi-checks-sse.rs
+++ b/tests/ui/abi/simd-abi-checks-sse.rs
@@ -3,8 +3,7 @@
//@ compile-flags: --crate-type=rlib --target=i586-unknown-linux-gnu
//@ compile-flags: -Ctarget-cpu=pentium4 -C target-feature=-sse,-sse2
//@ add-core-stubs
-//@ build-pass
-//@ ignore-pass (test emits codegen-time warnings)
+//@ build-fail
//@ needs-llvm-components: x86
#![feature(no_core, repr_simd)]
#![no_core]
@@ -18,6 +17,5 @@
#[no_mangle]
pub unsafe extern "C" fn f(_: SseVector) {
- //~^ WARN this function definition uses SIMD vector type `SseVector` which (with the chosen ABI) requires the `sse` target feature, which is not enabled
- //~| WARNING this was previously accepted by the compiler
+ //~^ ERROR: this function definition uses SIMD vector type `SseVector` which (with the chosen ABI) requires the `sse` target feature, which is not enabled
}
diff --git a/tests/ui/abi/simd-abi-checks-sse.stderr b/tests/ui/abi/simd-abi-checks-sse.stderr
index c0f2e6e..a5a2ba8 100644
--- a/tests/ui/abi/simd-abi-checks-sse.stderr
+++ b/tests/ui/abi/simd-abi-checks-sse.stderr
@@ -1,25 +1,10 @@
-warning: this function definition uses SIMD vector type `SseVector` which (with the chosen ABI) requires the `sse` target feature, which is not enabled
- --> $DIR/simd-abi-checks-sse.rs:20:1
+error: this function definition uses SIMD vector type `SseVector` which (with the chosen ABI) requires the `sse` target feature, which is not enabled
+ --> $DIR/simd-abi-checks-sse.rs:19:1
|
LL | pub unsafe extern "C" fn f(_: SseVector) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
= help: consider enabling it globally (`-C target-feature=+sse`) or locally (`#[target_feature(enable="sse")]`)
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
-warning: 1 warning emitted
-
-Future incompatibility report: Future breakage diagnostic:
-warning: this function definition uses SIMD vector type `SseVector` which (with the chosen ABI) requires the `sse` target feature, which is not enabled
- --> $DIR/simd-abi-checks-sse.rs:20:1
- |
-LL | pub unsafe extern "C" fn f(_: SseVector) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
- = help: consider enabling it globally (`-C target-feature=+sse`) or locally (`#[target_feature(enable="sse")]`)
- = note: `#[warn(abi_unsupported_vector_types)]` on by default
+error: aborting due to 1 previous error
diff --git a/tests/ui/amdgpu-require-explicit-cpu.rs b/tests/ui/amdgpu-require-explicit-cpu.rs
deleted file mode 100644
index d40cb97..0000000
--- a/tests/ui/amdgpu-require-explicit-cpu.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-//@ revisions: nocpu cpu
-//@ no-prefer-dynamic
-//@ compile-flags: --crate-type=cdylib --target=amdgcn-amd-amdhsa
-//@ needs-llvm-components: amdgpu
-//@ needs-rust-lld
-//@[nocpu] build-fail
-//@[cpu] compile-flags: -Ctarget-cpu=gfx900
-//@[cpu] build-pass
-
-#![feature(no_core, lang_items)]
-#![no_core]
-
-#[lang="sized"]
-trait Sized {}
-
-pub fn foo() {}
-
-//[nocpu]~? ERROR target requires explicitly specifying a cpu with `-C target-cpu`
diff --git a/tests/ui/argument-suggestions/exotic-calls.rs b/tests/ui/argument-suggestions/exotic-calls.rs
index 569a39a..765b4bc 100644
--- a/tests/ui/argument-suggestions/exotic-calls.rs
+++ b/tests/ui/argument-suggestions/exotic-calls.rs
@@ -1,8 +1,18 @@
+//! Checks variations of E0057, which is the incorrect number of agruments passed into a closure
+
+//@ check-fail
+
fn foo<T: Fn()>(t: T) {
t(1i32);
//~^ ERROR function takes 0 arguments but 1 argument was supplied
}
+/// Regression test for <https://github.com/rust-lang/rust/issues/16939>
+fn foo2<T: Fn()>(f: T) {
+ |t| f(t);
+ //~^ ERROR function takes 0 arguments but 1 argument was supplied
+}
+
fn bar(t: impl Fn()) {
t(1i32);
//~^ ERROR function takes 0 arguments but 1 argument was supplied
diff --git a/tests/ui/argument-suggestions/exotic-calls.stderr b/tests/ui/argument-suggestions/exotic-calls.stderr
index aca3b8a..e78871c 100644
--- a/tests/ui/argument-suggestions/exotic-calls.stderr
+++ b/tests/ui/argument-suggestions/exotic-calls.stderr
@@ -1,11 +1,11 @@
error[E0057]: this function takes 0 arguments but 1 argument was supplied
- --> $DIR/exotic-calls.rs:2:5
+ --> $DIR/exotic-calls.rs:6:5
|
LL | t(1i32);
| ^ ---- unexpected argument of type `i32`
|
note: callable defined here
- --> $DIR/exotic-calls.rs:1:11
+ --> $DIR/exotic-calls.rs:5:11
|
LL | fn foo<T: Fn()>(t: T) {
| ^^^^
@@ -16,13 +16,30 @@
|
error[E0057]: this function takes 0 arguments but 1 argument was supplied
- --> $DIR/exotic-calls.rs:7:5
+ --> $DIR/exotic-calls.rs:12:9
+ |
+LL | |t| f(t);
+ | ^ - unexpected argument
+ |
+note: callable defined here
+ --> $DIR/exotic-calls.rs:11:12
+ |
+LL | fn foo2<T: Fn()>(f: T) {
+ | ^^^^
+help: remove the extra argument
+ |
+LL - |t| f(t);
+LL + |t| f();
+ |
+
+error[E0057]: this function takes 0 arguments but 1 argument was supplied
+ --> $DIR/exotic-calls.rs:17:5
|
LL | t(1i32);
| ^ ---- unexpected argument of type `i32`
|
note: type parameter defined here
- --> $DIR/exotic-calls.rs:6:11
+ --> $DIR/exotic-calls.rs:16:11
|
LL | fn bar(t: impl Fn()) {
| ^^^^^^^^^
@@ -33,13 +50,13 @@
|
error[E0057]: this function takes 0 arguments but 1 argument was supplied
- --> $DIR/exotic-calls.rs:16:5
+ --> $DIR/exotic-calls.rs:26:5
|
LL | baz()(1i32)
| ^^^^^ ---- unexpected argument of type `i32`
|
note: opaque type defined here
- --> $DIR/exotic-calls.rs:11:13
+ --> $DIR/exotic-calls.rs:21:13
|
LL | fn baz() -> impl Fn() {
| ^^^^^^^^^
@@ -50,13 +67,13 @@
|
error[E0057]: this function takes 0 arguments but 1 argument was supplied
- --> $DIR/exotic-calls.rs:22:5
+ --> $DIR/exotic-calls.rs:32:5
|
LL | x(1i32);
| ^ ---- unexpected argument of type `i32`
|
note: closure defined here
- --> $DIR/exotic-calls.rs:21:13
+ --> $DIR/exotic-calls.rs:31:13
|
LL | let x = || {};
| ^^
@@ -66,6 +83,6 @@
LL + x();
|
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0057`.
diff --git a/tests/ui/asm/naked-asm-outside-naked-fn.rs b/tests/ui/asm/naked-asm-outside-naked-fn.rs
index 1696008..0a15b21 100644
--- a/tests/ui/asm/naked-asm-outside-naked-fn.rs
+++ b/tests/ui/asm/naked-asm-outside-naked-fn.rs
@@ -3,7 +3,6 @@
//@ ignore-nvptx64
//@ ignore-spirv
-#![feature(naked_functions)]
#![crate_type = "lib"]
use std::arch::naked_asm;
@@ -12,24 +11,24 @@ fn main() {
test1();
}
-#[naked]
+#[unsafe(naked)]
extern "C" fn test1() {
- unsafe { naked_asm!("") }
+ naked_asm!("")
}
extern "C" fn test2() {
- unsafe { naked_asm!("") }
- //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[naked]`
+ naked_asm!("")
+ //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
}
extern "C" fn test3() {
- unsafe { (|| naked_asm!(""))() }
- //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[naked]`
+ (|| naked_asm!(""))()
+ //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
}
fn test4() {
async move {
- unsafe { naked_asm!("") } ;
- //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[naked]`
+ naked_asm!("");
+ //~^ ERROR the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
};
}
diff --git a/tests/ui/asm/naked-asm-outside-naked-fn.stderr b/tests/ui/asm/naked-asm-outside-naked-fn.stderr
index 6e91359..2cebaa9 100644
--- a/tests/ui/asm/naked-asm-outside-naked-fn.stderr
+++ b/tests/ui/asm/naked-asm-outside-naked-fn.stderr
@@ -1,20 +1,20 @@
-error: the `naked_asm!` macro can only be used in functions marked with `#[naked]`
- --> $DIR/naked-asm-outside-naked-fn.rs:21:14
+error: the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
+ --> $DIR/naked-asm-outside-naked-fn.rs:20:5
|
-LL | unsafe { naked_asm!("") }
- | ^^^^^^^^^^^^^^
+LL | naked_asm!("")
+ | ^^^^^^^^^^^^^^
-error: the `naked_asm!` macro can only be used in functions marked with `#[naked]`
- --> $DIR/naked-asm-outside-naked-fn.rs:26:18
+error: the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
+ --> $DIR/naked-asm-outside-naked-fn.rs:25:9
|
-LL | unsafe { (|| naked_asm!(""))() }
- | ^^^^^^^^^^^^^^
+LL | (|| naked_asm!(""))()
+ | ^^^^^^^^^^^^^^
-error: the `naked_asm!` macro can only be used in functions marked with `#[naked]`
- --> $DIR/naked-asm-outside-naked-fn.rs:32:19
+error: the `naked_asm!` macro can only be used in functions marked with `#[unsafe(naked)]`
+ --> $DIR/naked-asm-outside-naked-fn.rs:31:9
|
-LL | unsafe { naked_asm!("") } ;
- | ^^^^^^^^^^^^^^
+LL | naked_asm!("");
+ | ^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
diff --git a/tests/ui/asm/naked-functions-ffi.rs b/tests/ui/asm/naked-functions-ffi.rs
index b78d1e6..565c440 100644
--- a/tests/ui/asm/naked-functions-ffi.rs
+++ b/tests/ui/asm/naked-functions-ffi.rs
@@ -1,15 +1,12 @@
//@ check-pass
//@ needs-asm-support
-#![feature(naked_functions)]
#![crate_type = "lib"]
use std::arch::naked_asm;
-#[naked]
+#[unsafe(naked)]
pub extern "C" fn naked(p: char) -> u128 {
//~^ WARN uses type `char`
//~| WARN uses type `u128`
- unsafe {
- naked_asm!("");
- }
+ naked_asm!("")
}
diff --git a/tests/ui/asm/naked-functions-ffi.stderr b/tests/ui/asm/naked-functions-ffi.stderr
index 908881b..9df6185 100644
--- a/tests/ui/asm/naked-functions-ffi.stderr
+++ b/tests/ui/asm/naked-functions-ffi.stderr
@@ -1,5 +1,5 @@
warning: `extern` fn uses type `char`, which is not FFI-safe
- --> $DIR/naked-functions-ffi.rs:9:28
+ --> $DIR/naked-functions-ffi.rs:8:28
|
LL | pub extern "C" fn naked(p: char) -> u128 {
| ^^^^ not FFI-safe
@@ -9,7 +9,7 @@
= note: `#[warn(improper_ctypes_definitions)]` on by default
warning: `extern` fn uses type `u128`, which is not FFI-safe
- --> $DIR/naked-functions-ffi.rs:9:37
+ --> $DIR/naked-functions-ffi.rs:8:37
|
LL | pub extern "C" fn naked(p: char) -> u128 {
| ^^^^ not FFI-safe
diff --git a/tests/ui/asm/naked-functions-inline.rs b/tests/ui/asm/naked-functions-inline.rs
index 74049e8..93741f2 100644
--- a/tests/ui/asm/naked-functions-inline.rs
+++ b/tests/ui/asm/naked-functions-inline.rs
@@ -1,38 +1,37 @@
//@ needs-asm-support
-#![feature(naked_functions)]
#![crate_type = "lib"]
use std::arch::naked_asm;
-#[naked]
-pub unsafe extern "C" fn inline_none() {
+#[unsafe(naked)]
+pub extern "C" fn inline_none() {
naked_asm!("");
}
-#[naked]
+#[unsafe(naked)]
#[inline]
//~^ ERROR [E0736]
-pub unsafe extern "C" fn inline_hint() {
+pub extern "C" fn inline_hint() {
naked_asm!("");
}
-#[naked]
+#[unsafe(naked)]
#[inline(always)]
//~^ ERROR [E0736]
-pub unsafe extern "C" fn inline_always() {
+pub extern "C" fn inline_always() {
naked_asm!("");
}
-#[naked]
+#[unsafe(naked)]
#[inline(never)]
//~^ ERROR [E0736]
-pub unsafe extern "C" fn inline_never() {
+pub extern "C" fn inline_never() {
naked_asm!("");
}
-#[naked]
+#[unsafe(naked)]
#[cfg_attr(all(), inline(never))]
//~^ ERROR [E0736]
-pub unsafe extern "C" fn conditional_inline_never() {
+pub extern "C" fn conditional_inline_never() {
naked_asm!("");
}
diff --git a/tests/ui/asm/naked-functions-inline.stderr b/tests/ui/asm/naked-functions-inline.stderr
index 84a688f..07d5f3b 100644
--- a/tests/ui/asm/naked-functions-inline.stderr
+++ b/tests/ui/asm/naked-functions-inline.stderr
@@ -1,34 +1,34 @@
-error[E0736]: attribute incompatible with `#[naked]`
- --> $DIR/naked-functions-inline.rs:13:1
+error[E0736]: attribute incompatible with `#[unsafe(naked)]`
+ --> $DIR/naked-functions-inline.rs:12:1
|
-LL | #[naked]
- | -------- function marked with `#[naked]` here
+LL | #[unsafe(naked)]
+ | ---------------- function marked with `#[unsafe(naked)]` here
LL | #[inline]
- | ^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]`
+ | ^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]`
-error[E0736]: attribute incompatible with `#[naked]`
- --> $DIR/naked-functions-inline.rs:20:1
+error[E0736]: attribute incompatible with `#[unsafe(naked)]`
+ --> $DIR/naked-functions-inline.rs:19:1
|
-LL | #[naked]
- | -------- function marked with `#[naked]` here
+LL | #[unsafe(naked)]
+ | ---------------- function marked with `#[unsafe(naked)]` here
LL | #[inline(always)]
- | ^^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]`
+ | ^^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]`
-error[E0736]: attribute incompatible with `#[naked]`
- --> $DIR/naked-functions-inline.rs:27:1
+error[E0736]: attribute incompatible with `#[unsafe(naked)]`
+ --> $DIR/naked-functions-inline.rs:26:1
|
-LL | #[naked]
- | -------- function marked with `#[naked]` here
+LL | #[unsafe(naked)]
+ | ---------------- function marked with `#[unsafe(naked)]` here
LL | #[inline(never)]
- | ^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]`
+ | ^^^^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]`
-error[E0736]: attribute incompatible with `#[naked]`
- --> $DIR/naked-functions-inline.rs:34:19
+error[E0736]: attribute incompatible with `#[unsafe(naked)]`
+ --> $DIR/naked-functions-inline.rs:33:19
|
-LL | #[naked]
- | -------- function marked with `#[naked]` here
+LL | #[unsafe(naked)]
+ | ---------------- function marked with `#[unsafe(naked)]` here
LL | #[cfg_attr(all(), inline(never))]
- | ^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[naked]`
+ | ^^^^^^^^^^^^^ the `inline` attribute is incompatible with `#[unsafe(naked)]`
error: aborting due to 4 previous errors
diff --git a/tests/ui/asm/naked-functions-instruction-set.rs b/tests/ui/asm/naked-functions-instruction-set.rs
index 28241ba..69927a5 100644
--- a/tests/ui/asm/naked-functions-instruction-set.rs
+++ b/tests/ui/asm/naked-functions-instruction-set.rs
@@ -5,22 +5,22 @@
//@ build-pass
#![crate_type = "lib"]
-#![feature(no_core, naked_functions)]
+#![feature(no_core)]
#![no_core]
extern crate minicore;
use minicore::*;
#[no_mangle]
-#[naked]
+#[unsafe(naked)]
#[instruction_set(arm::t32)]
-unsafe extern "C" fn test_thumb() {
+extern "C" fn test_thumb() {
naked_asm!("bx lr");
}
#[no_mangle]
-#[naked]
+#[unsafe(naked)]
#[instruction_set(arm::a32)]
-unsafe extern "C" fn test_arm() {
+extern "C" fn test_arm() {
naked_asm!("bx lr");
}
diff --git a/tests/ui/asm/naked-functions-rustic-abi.rs b/tests/ui/asm/naked-functions-rustic-abi.rs
new file mode 100644
index 0000000..d9c1147
--- /dev/null
+++ b/tests/ui/asm/naked-functions-rustic-abi.rs
@@ -0,0 +1,27 @@
+//@ revisions: x86_64 aarch64
+//
+//@[aarch64] only-aarch64
+//@[x86_64] only-x86_64
+//
+//@ build-pass
+//@ needs-asm-support
+
+#![feature(naked_functions_rustic_abi, rust_cold_cc)]
+#![crate_type = "lib"]
+
+use std::arch::{asm, naked_asm};
+
+#[unsafe(naked)]
+pub fn rust_implicit() {
+ naked_asm!("ret");
+}
+
+#[unsafe(naked)]
+pub extern "Rust" fn rust_explicit() {
+ naked_asm!("ret");
+}
+
+#[unsafe(naked)]
+pub extern "rust-cold" fn rust_cold() {
+ naked_asm!("ret");
+}
diff --git a/tests/ui/asm/naked-functions-target-feature.rs b/tests/ui/asm/naked-functions-target-feature.rs
index afe1a38..57ad79b 100644
--- a/tests/ui/asm/naked-functions-target-feature.rs
+++ b/tests/ui/asm/naked-functions-target-feature.rs
@@ -1,21 +1,21 @@
//@ build-pass
//@ needs-asm-support
-#![feature(naked_functions, naked_functions_target_feature)]
+#![feature(naked_functions_target_feature)]
#![crate_type = "lib"]
use std::arch::{asm, naked_asm};
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "sse2")]
-#[naked]
-pub unsafe extern "C" fn compatible_target_feature() {
- naked_asm!("");
+#[unsafe(naked)]
+pub extern "C" fn compatible_target_feature() {
+ naked_asm!("ret");
}
#[cfg(target_arch = "aarch64")]
#[target_feature(enable = "neon")]
-#[naked]
-pub unsafe extern "C" fn compatible_target_feature() {
- naked_asm!("");
+#[unsafe(naked)]
+pub extern "C" fn compatible_target_feature() {
+ naked_asm!("ret");
}
diff --git a/tests/ui/asm/naked-functions-testattrs.rs b/tests/ui/asm/naked-functions-testattrs.rs
index 7e37327..6dc14a6 100644
--- a/tests/ui/asm/naked-functions-testattrs.rs
+++ b/tests/ui/asm/naked-functions-testattrs.rs
@@ -1,39 +1,37 @@
//@ needs-asm-support
//@ compile-flags: --test
-#![allow(undefined_naked_function_abi)]
-#![feature(naked_functions)]
#![feature(test)]
#![crate_type = "lib"]
use std::arch::naked_asm;
#[test]
-#[naked]
+#[unsafe(naked)]
//~^ ERROR [E0736]
-fn test_naked() {
- unsafe { naked_asm!("") };
+extern "C" fn test_naked() {
+ naked_asm!("")
}
#[should_panic]
#[test]
-#[naked]
+#[unsafe(naked)]
//~^ ERROR [E0736]
-fn test_naked_should_panic() {
- unsafe { naked_asm!("") };
+extern "C" fn test_naked_should_panic() {
+ naked_asm!("")
}
#[ignore]
#[test]
-#[naked]
+#[unsafe(naked)]
//~^ ERROR [E0736]
-fn test_naked_ignore() {
- unsafe { naked_asm!("") };
+extern "C" fn test_naked_ignore() {
+ naked_asm!("")
}
#[bench]
-#[naked]
+#[unsafe(naked)]
//~^ ERROR [E0736]
-fn bench_naked() {
- unsafe { naked_asm!("") };
+extern "C" fn bench_naked() {
+ naked_asm!("")
}
diff --git a/tests/ui/asm/naked-functions-testattrs.stderr b/tests/ui/asm/naked-functions-testattrs.stderr
index 4dabe41..8aab2f0 100644
--- a/tests/ui/asm/naked-functions-testattrs.stderr
+++ b/tests/ui/asm/naked-functions-testattrs.stderr
@@ -1,34 +1,34 @@
-error[E0736]: cannot use `#[naked]` with testing attributes
- --> $DIR/naked-functions-testattrs.rs:12:1
+error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes
+ --> $DIR/naked-functions-testattrs.rs:10:1
|
LL | #[test]
| ------- function marked with testing attribute here
-LL | #[naked]
- | ^^^^^^^^ `#[naked]` is incompatible with testing attributes
+LL | #[unsafe(naked)]
+ | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes
-error[E0736]: cannot use `#[naked]` with testing attributes
- --> $DIR/naked-functions-testattrs.rs:20:1
+error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes
+ --> $DIR/naked-functions-testattrs.rs:18:1
|
LL | #[test]
| ------- function marked with testing attribute here
-LL | #[naked]
- | ^^^^^^^^ `#[naked]` is incompatible with testing attributes
+LL | #[unsafe(naked)]
+ | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes
-error[E0736]: cannot use `#[naked]` with testing attributes
- --> $DIR/naked-functions-testattrs.rs:28:1
+error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes
+ --> $DIR/naked-functions-testattrs.rs:26:1
|
LL | #[test]
| ------- function marked with testing attribute here
-LL | #[naked]
- | ^^^^^^^^ `#[naked]` is incompatible with testing attributes
+LL | #[unsafe(naked)]
+ | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes
-error[E0736]: cannot use `#[naked]` with testing attributes
- --> $DIR/naked-functions-testattrs.rs:35:1
+error[E0736]: cannot use `#[unsafe(naked)]` with testing attributes
+ --> $DIR/naked-functions-testattrs.rs:33:1
|
LL | #[bench]
| -------- function marked with testing attribute here
-LL | #[naked]
- | ^^^^^^^^ `#[naked]` is incompatible with testing attributes
+LL | #[unsafe(naked)]
+ | ^^^^^^^^^^^^^^^^ `#[unsafe(naked)]` is incompatible with testing attributes
error: aborting due to 4 previous errors
diff --git a/tests/ui/asm/naked-functions-unused.aarch64.stderr b/tests/ui/asm/naked-functions-unused.aarch64.stderr
index ea63ced..bfb2923 100644
--- a/tests/ui/asm/naked-functions-unused.aarch64.stderr
+++ b/tests/ui/asm/naked-functions-unused.aarch64.stderr
@@ -1,5 +1,5 @@
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:17:32
+ --> $DIR/naked-functions-unused.rs:16:32
|
LL | pub extern "C" fn function(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
@@ -12,55 +12,55 @@
= note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:17:42
+ --> $DIR/naked-functions-unused.rs:16:42
|
LL | pub extern "C" fn function(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:28:38
+ --> $DIR/naked-functions-unused.rs:27:38
|
LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:28:48
+ --> $DIR/naked-functions-unused.rs:27:48
|
LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:36:41
+ --> $DIR/naked-functions-unused.rs:35:41
|
LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:36:51
+ --> $DIR/naked-functions-unused.rs:35:51
|
LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:46:40
+ --> $DIR/naked-functions-unused.rs:45:40
|
LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:46:50
+ --> $DIR/naked-functions-unused.rs:45:50
|
LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:54:43
+ --> $DIR/naked-functions-unused.rs:53:43
|
LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:54:53
+ --> $DIR/naked-functions-unused.rs:53:53
|
LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
diff --git a/tests/ui/asm/naked-functions-unused.rs b/tests/ui/asm/naked-functions-unused.rs
index c270378..945ab1a 100644
--- a/tests/ui/asm/naked-functions-unused.rs
+++ b/tests/ui/asm/naked-functions-unused.rs
@@ -3,7 +3,6 @@
//@[x86_64] only-x86_64
//@[aarch64] only-aarch64
#![deny(unused)]
-#![feature(naked_functions)]
#![crate_type = "lib"]
pub trait Trait {
@@ -64,44 +63,34 @@ extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
pub mod naked {
use std::arch::naked_asm;
- #[naked]
+ #[unsafe(naked)]
pub extern "C" fn function(a: usize, b: usize) -> usize {
- unsafe {
- naked_asm!("");
- }
+ naked_asm!("")
}
pub struct Naked;
impl Naked {
- #[naked]
+ #[unsafe(naked)]
pub extern "C" fn associated(a: usize, b: usize) -> usize {
- unsafe {
- naked_asm!("");
- }
+ naked_asm!("")
}
- #[naked]
+ #[unsafe(naked)]
pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
- unsafe {
- naked_asm!("");
- }
+ naked_asm!("")
}
}
impl super::Trait for Naked {
- #[naked]
+ #[unsafe(naked)]
extern "C" fn trait_associated(a: usize, b: usize) -> usize {
- unsafe {
- naked_asm!("");
- }
+ naked_asm!("")
}
- #[naked]
+ #[unsafe(naked)]
extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
- unsafe {
- naked_asm!("");
- }
+ naked_asm!("")
}
}
}
diff --git a/tests/ui/asm/naked-functions-unused.x86_64.stderr b/tests/ui/asm/naked-functions-unused.x86_64.stderr
index ea63ced..bfb2923 100644
--- a/tests/ui/asm/naked-functions-unused.x86_64.stderr
+++ b/tests/ui/asm/naked-functions-unused.x86_64.stderr
@@ -1,5 +1,5 @@
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:17:32
+ --> $DIR/naked-functions-unused.rs:16:32
|
LL | pub extern "C" fn function(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
@@ -12,55 +12,55 @@
= note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:17:42
+ --> $DIR/naked-functions-unused.rs:16:42
|
LL | pub extern "C" fn function(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:28:38
+ --> $DIR/naked-functions-unused.rs:27:38
|
LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:28:48
+ --> $DIR/naked-functions-unused.rs:27:48
|
LL | pub extern "C" fn associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:36:41
+ --> $DIR/naked-functions-unused.rs:35:41
|
LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:36:51
+ --> $DIR/naked-functions-unused.rs:35:51
|
LL | pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:46:40
+ --> $DIR/naked-functions-unused.rs:45:40
|
LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:46:50
+ --> $DIR/naked-functions-unused.rs:45:50
|
LL | extern "C" fn trait_associated(a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
error: unused variable: `a`
- --> $DIR/naked-functions-unused.rs:54:43
+ --> $DIR/naked-functions-unused.rs:53:43
|
LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_a`
error: unused variable: `b`
- --> $DIR/naked-functions-unused.rs:54:53
+ --> $DIR/naked-functions-unused.rs:53:53
|
LL | extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
| ^ help: if this is intentional, prefix it with an underscore: `_b`
diff --git a/tests/ui/asm/naked-functions.rs b/tests/ui/asm/naked-functions.rs
index 3d4d414..1eeb716 100644
--- a/tests/ui/asm/naked-functions.rs
+++ b/tests/ui/asm/naked-functions.rs
@@ -2,15 +2,14 @@
//@ ignore-nvptx64
//@ ignore-spirv
-#![feature(naked_functions)]
#![feature(asm_unwind, linkage)]
#![crate_type = "lib"]
use std::arch::{asm, naked_asm};
-#[naked]
-pub unsafe extern "C" fn inline_asm_macro() {
- asm!("", options(raw));
+#[unsafe(naked)]
+pub extern "C" fn inline_asm_macro() {
+ unsafe { asm!("", options(raw)) };
//~^ERROR the `asm!` macro is not allowed in naked functions
}
@@ -20,8 +19,8 @@ pub struct P {
y: u16,
}
-#[naked]
-pub unsafe extern "C" fn patterns(
+#[unsafe(naked)]
+pub extern "C" fn patterns(
mut a: u32,
//~^ ERROR patterns not allowed in naked function parameters
&b: &i32,
@@ -34,28 +33,28 @@ pub struct P {
naked_asm!("")
}
-#[naked]
-pub unsafe extern "C" fn inc(a: u32) -> u32 {
+#[unsafe(naked)]
+pub extern "C" fn inc(a: u32) -> u32 {
//~^ ERROR naked functions must contain a single `naked_asm!` invocation
a + 1
//~^ ERROR referencing function parameters is not allowed in naked functions
}
-#[naked]
+#[unsafe(naked)]
#[allow(asm_sub_register)]
-pub unsafe extern "C" fn inc_asm(a: u32) -> u32 {
+pub extern "C" fn inc_asm(a: u32) -> u32 {
naked_asm!("/* {0} */", in(reg) a)
//~^ ERROR the `in` operand cannot be used with `naked_asm!`
}
-#[naked]
-pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
+#[unsafe(naked)]
+pub extern "C" fn inc_closure(a: u32) -> u32 {
//~^ ERROR naked functions must contain a single `naked_asm!` invocation
(|| a + 1)()
}
-#[naked]
-pub unsafe extern "C" fn unsupported_operands() {
+#[unsafe(naked)]
+pub extern "C" fn unsupported_operands() {
//~^ ERROR naked functions must contain a single `naked_asm!` invocation
let mut a = 0usize;
let mut b = 0usize;
@@ -76,23 +75,22 @@ pub struct P {
);
}
-#[naked]
+#[unsafe(naked)]
pub extern "C" fn missing_assembly() {
//~^ ERROR naked functions must contain a single `naked_asm!` invocation
}
-#[naked]
+#[unsafe(naked)]
pub extern "C" fn too_many_asm_blocks() {
//~^ ERROR naked functions must contain a single `naked_asm!` invocation
- unsafe {
- naked_asm!("", options(noreturn));
- //~^ ERROR the `noreturn` option cannot be used with `naked_asm!`
- naked_asm!("");
- }
+
+ naked_asm!("", options(noreturn));
+ //~^ ERROR the `noreturn` option cannot be used with `naked_asm!`
+ naked_asm!("");
}
pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
- #[naked]
+ #[unsafe(naked)]
pub extern "C" fn inner(y: usize) -> usize {
//~^ ERROR naked functions must contain a single `naked_asm!` invocation
*&y
@@ -101,14 +99,14 @@ pub extern "C" fn inner(y: usize) -> usize {
inner
}
-#[naked]
+#[unsafe(naked)]
unsafe extern "C" fn invalid_options() {
naked_asm!("", options(nomem, preserves_flags));
//~^ ERROR the `nomem` option cannot be used with `naked_asm!`
//~| ERROR the `preserves_flags` option cannot be used with `naked_asm!`
}
-#[naked]
+#[unsafe(naked)]
unsafe extern "C" fn invalid_options_continued() {
naked_asm!("", options(readonly, nostack), options(pure));
//~^ ERROR the `readonly` option cannot be used with `naked_asm!`
@@ -116,77 +114,60 @@ pub extern "C" fn inner(y: usize) -> usize {
//~| ERROR the `pure` option cannot be used with `naked_asm!`
}
-#[naked]
+#[unsafe(naked)]
unsafe extern "C" fn invalid_may_unwind() {
naked_asm!("", options(may_unwind));
//~^ ERROR the `may_unwind` option cannot be used with `naked_asm!`
}
-#[naked]
-pub unsafe fn default_abi() {
- //~^ WARN Rust ABI is unsupported in naked functions
- naked_asm!("");
-}
-
-#[naked]
-pub unsafe fn rust_abi() {
- //~^ WARN Rust ABI is unsupported in naked functions
- naked_asm!("");
-}
-
-#[naked]
+#[unsafe(naked)]
pub extern "C" fn valid_a<T>() -> T {
- unsafe {
- naked_asm!("");
- }
+ naked_asm!("");
}
-#[naked]
+#[unsafe(naked)]
pub extern "C" fn valid_b() {
- unsafe {
+ {
{
- {
- naked_asm!("");
- };
+ naked_asm!("");
};
- }
+ };
}
-#[naked]
-pub unsafe extern "C" fn valid_c() {
+#[unsafe(naked)]
+pub extern "C" fn valid_c() {
naked_asm!("");
}
#[cfg(target_arch = "x86_64")]
-#[naked]
-pub unsafe extern "C" fn valid_att_syntax() {
+#[unsafe(naked)]
+pub extern "C" fn valid_att_syntax() {
naked_asm!("", options(att_syntax));
}
-#[naked]
-#[naked]
-pub unsafe extern "C" fn allow_compile_error(a: u32) -> u32 {
+#[unsafe(naked)]
+pub extern "C" fn allow_compile_error(a: u32) -> u32 {
compile_error!("this is a user specified error")
//~^ ERROR this is a user specified error
}
-#[naked]
-pub unsafe extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 {
+#[unsafe(naked)]
+pub extern "C" fn allow_compile_error_and_asm(a: u32) -> u32 {
compile_error!("this is a user specified error");
//~^ ERROR this is a user specified error
naked_asm!("")
}
-#[naked]
-pub unsafe extern "C" fn invalid_asm_syntax(a: u32) -> u32 {
+#[unsafe(naked)]
+pub extern "C" fn invalid_asm_syntax(a: u32) -> u32 {
naked_asm!(invalid_syntax)
//~^ ERROR asm template must be a string literal
}
#[cfg(target_arch = "x86_64")]
#[cfg_attr(target_pointer_width = "64", no_mangle)]
-#[naked]
-pub unsafe extern "C" fn compatible_cfg_attributes() {
+#[unsafe(naked)]
+pub extern "C" fn compatible_cfg_attributes() {
naked_asm!("", options(att_syntax));
}
@@ -194,21 +175,21 @@ pub extern "C" fn valid_b() {
#[warn(dead_code)]
#[deny(dead_code)]
#[forbid(dead_code)]
-#[naked]
-pub unsafe extern "C" fn compatible_diagnostic_attributes() {
+#[unsafe(naked)]
+pub extern "C" fn compatible_diagnostic_attributes() {
naked_asm!("", options(raw));
}
#[deprecated = "test"]
-#[naked]
-pub unsafe extern "C" fn compatible_deprecated_attributes() {
+#[unsafe(naked)]
+pub extern "C" fn compatible_deprecated_attributes() {
naked_asm!("", options(raw));
}
#[cfg(target_arch = "x86_64")]
#[must_use]
-#[naked]
-pub unsafe extern "C" fn compatible_must_use_attributes() -> u64 {
+#[unsafe(naked)]
+pub extern "C" fn compatible_must_use_attributes() -> u64 {
naked_asm!(
"
mov rax, 42
@@ -219,14 +200,14 @@ pub extern "C" fn valid_b() {
#[export_name = "exported_function_name"]
#[link_section = ".custom_section"]
-#[naked]
-pub unsafe extern "C" fn compatible_ffi_attributes_1() {
+#[unsafe(naked)]
+pub extern "C" fn compatible_ffi_attributes_1() {
naked_asm!("", options(raw));
}
#[cold]
-#[naked]
-pub unsafe extern "C" fn compatible_codegen_attributes() {
+#[unsafe(naked)]
+pub extern "C" fn compatible_codegen_attributes() {
naked_asm!("", options(raw));
}
@@ -234,13 +215,13 @@ pub extern "C" fn valid_b() {
/// a doc comment
// a normal comment
#[doc(alias = "ADocAlias")]
-#[naked]
-pub unsafe extern "C" fn compatible_doc_attributes() {
+#[unsafe(naked)]
+pub extern "C" fn compatible_doc_attributes() {
naked_asm!("", options(raw));
}
#[linkage = "external"]
-#[naked]
-pub unsafe extern "C" fn compatible_linkage() {
+#[unsafe(naked)]
+pub extern "C" fn compatible_linkage() {
naked_asm!("", options(raw));
}
diff --git a/tests/ui/asm/naked-functions.stderr b/tests/ui/asm/naked-functions.stderr
index 0898f36..b94a09b 100644
--- a/tests/ui/asm/naked-functions.stderr
+++ b/tests/ui/asm/naked-functions.stderr
@@ -1,107 +1,107 @@
error: the `in` operand cannot be used with `naked_asm!`
- --> $DIR/naked-functions.rs:47:29
+ --> $DIR/naked-functions.rs:46:29
|
LL | naked_asm!("/* {0} */", in(reg) a)
| ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it
error: the `in` operand cannot be used with `naked_asm!`
- --> $DIR/naked-functions.rs:68:10
+ --> $DIR/naked-functions.rs:67:10
|
LL | in(reg) a,
| ^^ the `in` operand is not meaningful for global-scoped inline assembly, remove it
error: the `noreturn` option cannot be used with `naked_asm!`
- --> $DIR/naked-functions.rs:88:32
+ --> $DIR/naked-functions.rs:87:28
|
-LL | naked_asm!("", options(noreturn));
- | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly
+LL | naked_asm!("", options(noreturn));
+ | ^^^^^^^^ the `noreturn` option is not meaningful for global-scoped inline assembly
error: the `nomem` option cannot be used with `naked_asm!`
- --> $DIR/naked-functions.rs:106:28
+ --> $DIR/naked-functions.rs:104:28
|
LL | naked_asm!("", options(nomem, preserves_flags));
| ^^^^^ the `nomem` option is not meaningful for global-scoped inline assembly
error: the `preserves_flags` option cannot be used with `naked_asm!`
- --> $DIR/naked-functions.rs:106:35
+ --> $DIR/naked-functions.rs:104:35
|
LL | naked_asm!("", options(nomem, preserves_flags));
| ^^^^^^^^^^^^^^^ the `preserves_flags` option is not meaningful for global-scoped inline assembly
error: the `readonly` option cannot be used with `naked_asm!`
- --> $DIR/naked-functions.rs:113:28
+ --> $DIR/naked-functions.rs:111:28
|
LL | naked_asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^^ the `readonly` option is not meaningful for global-scoped inline assembly
error: the `nostack` option cannot be used with `naked_asm!`
- --> $DIR/naked-functions.rs:113:38
+ --> $DIR/naked-functions.rs:111:38
|
LL | naked_asm!("", options(readonly, nostack), options(pure));
| ^^^^^^^ the `nostack` option is not meaningful for global-scoped inline assembly
error: the `pure` option cannot be used with `naked_asm!`
- --> $DIR/naked-functions.rs:113:56
+ --> $DIR/naked-functions.rs:111:56
|
LL | naked_asm!("", options(readonly, nostack), options(pure));
| ^^^^ the `pure` option is not meaningful for global-scoped inline assembly
error: the `may_unwind` option cannot be used with `naked_asm!`
- --> $DIR/naked-functions.rs:121:28
+ --> $DIR/naked-functions.rs:119:28
|
LL | naked_asm!("", options(may_unwind));
| ^^^^^^^^^^ the `may_unwind` option is not meaningful for global-scoped inline assembly
error: this is a user specified error
- --> $DIR/naked-functions.rs:169:5
+ --> $DIR/naked-functions.rs:150:5
|
LL | compile_error!("this is a user specified error")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this is a user specified error
- --> $DIR/naked-functions.rs:175:5
+ --> $DIR/naked-functions.rs:156:5
|
LL | compile_error!("this is a user specified error");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: asm template must be a string literal
- --> $DIR/naked-functions.rs:182:16
+ --> $DIR/naked-functions.rs:163:16
|
LL | naked_asm!(invalid_syntax)
| ^^^^^^^^^^^^^^
error[E0787]: the `asm!` macro is not allowed in naked functions
- --> $DIR/naked-functions.rs:13:5
+ --> $DIR/naked-functions.rs:12:14
|
-LL | asm!("", options(raw));
- | ^^^^^^^^^^^^^^^^^^^^^^ consider using the `naked_asm!` macro instead
+LL | unsafe { asm!("", options(raw)) };
+ | ^^^^^^^^^^^^^^^^^^^^^^ consider using the `naked_asm!` macro instead
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:25:5
+ --> $DIR/naked-functions.rs:24:5
|
LL | mut a: u32,
| ^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:27:5
+ --> $DIR/naked-functions.rs:26:5
|
LL | &b: &i32,
| ^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:29:6
+ --> $DIR/naked-functions.rs:28:6
|
LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>,
| ^^^^^^^^^^^^^^
error: patterns not allowed in naked function parameters
- --> $DIR/naked-functions.rs:31:5
+ --> $DIR/naked-functions.rs:30:5
|
LL | P { x, y }: P,
| ^^^^^^^^^^
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:40:5
+ --> $DIR/naked-functions.rs:39:5
|
LL | a + 1
| ^
@@ -109,28 +109,28 @@
= help: follow the calling convention in asm block to use parameters
error[E0787]: naked functions must contain a single `naked_asm!` invocation
- --> $DIR/naked-functions.rs:38:1
+ --> $DIR/naked-functions.rs:37:1
|
-LL | pub unsafe extern "C" fn inc(a: u32) -> u32 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | pub extern "C" fn inc(a: u32) -> u32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | a + 1
| ----- not allowed in naked functions
error[E0787]: naked functions must contain a single `naked_asm!` invocation
- --> $DIR/naked-functions.rs:52:1
+ --> $DIR/naked-functions.rs:51:1
|
-LL | pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | pub extern "C" fn inc_closure(a: u32) -> u32 {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | (|| a + 1)()
| ------------ not allowed in naked functions
error[E0787]: naked functions must contain a single `naked_asm!` invocation
- --> $DIR/naked-functions.rs:58:1
+ --> $DIR/naked-functions.rs:57:1
|
-LL | pub unsafe extern "C" fn unsupported_operands() {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | pub extern "C" fn unsupported_operands() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
LL |
LL | let mut a = 0usize;
| ------------------- not allowed in naked functions
@@ -144,22 +144,22 @@
| ------------------- not allowed in naked functions
error[E0787]: naked functions must contain a single `naked_asm!` invocation
- --> $DIR/naked-functions.rs:80:1
+ --> $DIR/naked-functions.rs:79:1
|
LL | pub extern "C" fn missing_assembly() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0787]: naked functions must contain a single `naked_asm!` invocation
- --> $DIR/naked-functions.rs:85:1
+ --> $DIR/naked-functions.rs:84:1
|
LL | pub extern "C" fn too_many_asm_blocks() {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...
-LL | naked_asm!("");
- | -------------- multiple `naked_asm!` invocations are not allowed in naked functions
+LL | naked_asm!("");
+ | -------------- multiple `naked_asm!` invocations are not allowed in naked functions
error: referencing function parameters is not allowed in naked functions
- --> $DIR/naked-functions.rs:98:11
+ --> $DIR/naked-functions.rs:96:11
|
LL | *&y
| ^
@@ -167,7 +167,7 @@
= help: follow the calling convention in asm block to use parameters
error[E0787]: naked functions must contain a single `naked_asm!` invocation
- --> $DIR/naked-functions.rs:96:5
+ --> $DIR/naked-functions.rs:94:5
|
LL | pub extern "C" fn inner(y: usize) -> usize {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -175,20 +175,6 @@
LL | *&y
| --- not allowed in naked functions
-warning: Rust ABI is unsupported in naked functions
- --> $DIR/naked-functions.rs:126:1
- |
-LL | pub unsafe fn default_abi() {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: `#[warn(undefined_naked_function_abi)]` on by default
-
-warning: Rust ABI is unsupported in naked functions
- --> $DIR/naked-functions.rs:132:1
- |
-LL | pub unsafe fn rust_abi() {
- | ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 25 previous errors; 2 warnings emitted
+error: aborting due to 25 previous errors
For more information about this error, try `rustc --explain E0787`.
diff --git a/tests/ui/asm/naked-invalid-attr.rs b/tests/ui/asm/naked-invalid-attr.rs
index 4053c58..c3a3131 100644
--- a/tests/ui/asm/naked-invalid-attr.rs
+++ b/tests/ui/asm/naked-invalid-attr.rs
@@ -1,53 +1,53 @@
-// Checks that #[naked] attribute can be placed on function definitions only.
+// Checks that the #[unsafe(naked)] attribute can be placed on function definitions only.
//
//@ needs-asm-support
-#![feature(naked_functions)]
-#![naked] //~ ERROR should be applied to a function definition
+#![unsafe(naked)] //~ ERROR should be applied to a function definition
use std::arch::naked_asm;
extern "C" {
- #[naked] //~ ERROR should be applied to a function definition
+ #[unsafe(naked)] //~ ERROR should be applied to a function definition
fn f();
}
-#[naked] //~ ERROR should be applied to a function definition
+#[unsafe(naked)] //~ ERROR should be applied to a function definition
#[repr(C)]
struct S {
+ #[unsafe(naked)] //~ ERROR should be applied to a function definition
a: u32,
b: u32,
}
trait Invoke {
- #[naked] //~ ERROR should be applied to a function definition
+ #[unsafe(naked)] //~ ERROR should be applied to a function definition
extern "C" fn invoke(&self);
}
impl Invoke for S {
- #[naked]
+ #[unsafe(naked)]
extern "C" fn invoke(&self) {
- unsafe { naked_asm!("") }
+ naked_asm!("")
}
}
-#[naked]
+#[unsafe(naked)]
extern "C" fn ok() {
- unsafe { naked_asm!("") }
+ naked_asm!("")
}
impl S {
- #[naked]
+ #[unsafe(naked)]
extern "C" fn g() {
- unsafe { naked_asm!("") }
+ naked_asm!("")
}
- #[naked]
+ #[unsafe(naked)]
extern "C" fn h(&self) {
- unsafe { naked_asm!("") }
+ naked_asm!("")
}
}
fn main() {
- #[naked] //~ ERROR should be applied to a function definition
+ #[unsafe(naked)] //~ ERROR should be applied to a function definition
|| {};
}
diff --git a/tests/ui/asm/naked-invalid-attr.stderr b/tests/ui/asm/naked-invalid-attr.stderr
index 640f9d9..81d30e6 100644
--- a/tests/ui/asm/naked-invalid-attr.stderr
+++ b/tests/ui/asm/naked-invalid-attr.stderr
@@ -1,44 +1,53 @@
error: attribute should be applied to a function definition
- --> $DIR/naked-invalid-attr.rs:14:1
+ --> $DIR/naked-invalid-attr.rs:13:1
|
-LL | #[naked]
- | ^^^^^^^^
+LL | #[unsafe(naked)]
+ | ^^^^^^^^^^^^^^^^
LL | #[repr(C)]
LL | / struct S {
+LL | | #[unsafe(naked)]
LL | | a: u32,
LL | | b: u32,
LL | | }
| |_- not a function definition
error: attribute should be applied to a function definition
+ --> $DIR/naked-invalid-attr.rs:16:5
+ |
+LL | #[unsafe(naked)]
+ | ^^^^^^^^^^^^^^^^
+LL | a: u32,
+ | ------ not a function definition
+
+error: attribute should be applied to a function definition
--> $DIR/naked-invalid-attr.rs:51:5
|
-LL | #[naked]
- | ^^^^^^^^
+LL | #[unsafe(naked)]
+ | ^^^^^^^^^^^^^^^^
LL | || {};
| ----- not a function definition
error: attribute should be applied to a function definition
--> $DIR/naked-invalid-attr.rs:22:5
|
-LL | #[naked]
- | ^^^^^^^^
+LL | #[unsafe(naked)]
+ | ^^^^^^^^^^^^^^^^
LL | extern "C" fn invoke(&self);
| ---------------------------- not a function definition
error: attribute should be applied to a function definition
- --> $DIR/naked-invalid-attr.rs:10:5
+ --> $DIR/naked-invalid-attr.rs:9:5
|
-LL | #[naked]
- | ^^^^^^^^
+LL | #[unsafe(naked)]
+ | ^^^^^^^^^^^^^^^^
LL | fn f();
| ------- not a function definition
error: attribute should be applied to a function definition
- --> $DIR/naked-invalid-attr.rs:5:1
+ --> $DIR/naked-invalid-attr.rs:4:1
|
-LL | #![naked]
- | ^^^^^^^^^ cannot be applied to crates
+LL | #![unsafe(naked)]
+ | ^^^^^^^^^^^^^^^^^ cannot be applied to crates
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.rs b/tests/ui/asm/naked-with-invalid-repr-attr.rs
index 18b9c10..96eed70 100644
--- a/tests/ui/asm/naked-with-invalid-repr-attr.rs
+++ b/tests/ui/asm/naked-with-invalid-repr-attr.rs
@@ -1,48 +1,47 @@
//@ needs-asm-support
-#![feature(naked_functions)]
#![feature(fn_align)]
#![crate_type = "lib"]
use std::arch::naked_asm;
#[repr(C)]
//~^ ERROR attribute should be applied to a struct, enum, or union [E0517]
-#[naked]
+#[unsafe(naked)]
extern "C" fn example1() {
//~^ NOTE not a struct, enum, or union
- unsafe { naked_asm!("") }
+ naked_asm!("")
}
#[repr(transparent)]
//~^ ERROR attribute should be applied to a struct, enum, or union [E0517]
-#[naked]
+#[unsafe(naked)]
extern "C" fn example2() {
//~^ NOTE not a struct, enum, or union
- unsafe { naked_asm!("") }
+ naked_asm!("")
}
#[repr(align(16), C)]
//~^ ERROR attribute should be applied to a struct, enum, or union [E0517]
-#[naked]
+#[unsafe(naked)]
extern "C" fn example3() {
//~^ NOTE not a struct, enum, or union
- unsafe { naked_asm!("") }
+ naked_asm!("")
}
// note: two errors because of packed and C
#[repr(C, packed)]
//~^ ERROR attribute should be applied to a struct or union [E0517]
//~| ERROR attribute should be applied to a struct, enum, or union [E0517]
-#[naked]
+#[unsafe(naked)]
extern "C" fn example4() {
//~^ NOTE not a struct, enum, or union
//~| NOTE not a struct or union
- unsafe { naked_asm!("") }
+ naked_asm!("")
}
#[repr(u8)]
//~^ ERROR attribute should be applied to an enum [E0517]
-#[naked]
+#[unsafe(naked)]
extern "C" fn example5() {
//~^ NOTE not an enum
- unsafe { naked_asm!("") }
+ naked_asm!("")
}
diff --git a/tests/ui/asm/naked-with-invalid-repr-attr.stderr b/tests/ui/asm/naked-with-invalid-repr-attr.stderr
index 8248a8c..f173a39 100644
--- a/tests/ui/asm/naked-with-invalid-repr-attr.stderr
+++ b/tests/ui/asm/naked-with-invalid-repr-attr.stderr
@@ -1,41 +1,41 @@
error[E0517]: attribute should be applied to a struct, enum, or union
- --> $DIR/naked-with-invalid-repr-attr.rs:7:8
+ --> $DIR/naked-with-invalid-repr-attr.rs:6:8
|
LL | #[repr(C)]
| ^
...
LL | / extern "C" fn example1() {
LL | |
-LL | | unsafe { naked_asm!("") }
+LL | | naked_asm!("")
LL | | }
| |_- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
- --> $DIR/naked-with-invalid-repr-attr.rs:15:8
+ --> $DIR/naked-with-invalid-repr-attr.rs:14:8
|
LL | #[repr(transparent)]
| ^^^^^^^^^^^
...
LL | / extern "C" fn example2() {
LL | |
-LL | | unsafe { naked_asm!("") }
+LL | | naked_asm!("")
LL | | }
| |_- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
- --> $DIR/naked-with-invalid-repr-attr.rs:23:19
+ --> $DIR/naked-with-invalid-repr-attr.rs:22:19
|
LL | #[repr(align(16), C)]
| ^
...
LL | / extern "C" fn example3() {
LL | |
-LL | | unsafe { naked_asm!("") }
+LL | | naked_asm!("")
LL | | }
| |_- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct, enum, or union
- --> $DIR/naked-with-invalid-repr-attr.rs:32:8
+ --> $DIR/naked-with-invalid-repr-attr.rs:31:8
|
LL | #[repr(C, packed)]
| ^
@@ -43,12 +43,12 @@
LL | / extern "C" fn example4() {
LL | |
LL | |
-LL | | unsafe { naked_asm!("") }
+LL | | naked_asm!("")
LL | | }
| |_- not a struct, enum, or union
error[E0517]: attribute should be applied to a struct or union
- --> $DIR/naked-with-invalid-repr-attr.rs:32:11
+ --> $DIR/naked-with-invalid-repr-attr.rs:31:11
|
LL | #[repr(C, packed)]
| ^^^^^^
@@ -56,19 +56,19 @@
LL | / extern "C" fn example4() {
LL | |
LL | |
-LL | | unsafe { naked_asm!("") }
+LL | | naked_asm!("")
LL | | }
| |_- not a struct or union
error[E0517]: attribute should be applied to an enum
- --> $DIR/naked-with-invalid-repr-attr.rs:42:8
+ --> $DIR/naked-with-invalid-repr-attr.rs:41:8
|
LL | #[repr(u8)]
| ^^
...
LL | / extern "C" fn example5() {
LL | |
-LL | | unsafe { naked_asm!("") }
+LL | | naked_asm!("")
LL | | }
| |_- not an enum
diff --git a/tests/ui/asm/named-asm-labels.rs b/tests/ui/asm/named-asm-labels.rs
index 77831e6..996fb82 100644
--- a/tests/ui/asm/named-asm-labels.rs
+++ b/tests/ui/asm/named-asm-labels.rs
@@ -10,8 +10,6 @@
// which causes less readable LLVM errors and in the worst cases causes ICEs
// or segfaults based on system dependent behavior and codegen flags.
-#![feature(naked_functions)]
-
use std::arch::{asm, global_asm, naked_asm};
#[no_mangle]
@@ -175,9 +173,9 @@ fn main() {
// Trigger on naked fns too, even though they can't be inlined, reusing a
// label or LTO can cause labels to break
-#[naked]
+#[unsafe(naked)]
pub extern "C" fn foo() -> i32 {
- unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) }
+ naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1)
//~^ ERROR avoid using named labels
}
@@ -188,21 +186,21 @@ pub extern "C" fn bar() {
//~^ ERROR avoid using named labels
}
-#[naked]
+#[unsafe(naked)]
pub extern "C" fn aaa() {
fn _local() {}
- unsafe { naked_asm!(".Laaa: nop; ret;") } //~ ERROR avoid using named labels
+ naked_asm!(".Laaa: nop; ret;") //~ ERROR avoid using named labels
}
pub fn normal() {
fn _local1() {}
- #[naked]
+ #[unsafe(naked)]
pub extern "C" fn bbb() {
fn _very_local() {}
- unsafe { naked_asm!(".Lbbb: nop; ret;") } //~ ERROR avoid using named labels
+ naked_asm!(".Lbbb: nop; ret;") //~ ERROR avoid using named labels
}
fn _local2() {}
@@ -219,8 +217,8 @@ fn closures() {
};
|| {
- #[naked]
- unsafe extern "C" fn _nested() {
+ #[unsafe(naked)]
+ extern "C" fn _nested() {
naked_asm!("ret;");
}
diff --git a/tests/ui/asm/named-asm-labels.stderr b/tests/ui/asm/named-asm-labels.stderr
index 44ce358..cd7e7a0 100644
--- a/tests/ui/asm/named-asm-labels.stderr
+++ b/tests/ui/asm/named-asm-labels.stderr
@@ -1,5 +1,5 @@
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:23:15
+ --> $DIR/named-asm-labels.rs:21:15
|
LL | asm!("bar: nop");
| ^^^
@@ -9,7 +9,7 @@
= note: `#[deny(named_asm_labels)]` on by default
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:26:15
+ --> $DIR/named-asm-labels.rs:24:15
|
LL | asm!("abcd:");
| ^^^^
@@ -18,7 +18,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:29:15
+ --> $DIR/named-asm-labels.rs:27:15
|
LL | asm!("foo: bar1: nop");
| ^^^
@@ -27,7 +27,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:29:20
+ --> $DIR/named-asm-labels.rs:27:20
|
LL | asm!("foo: bar1: nop");
| ^^^^
@@ -36,7 +36,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:34:15
+ --> $DIR/named-asm-labels.rs:32:15
|
LL | asm!("foo1: nop", "nop");
| ^^^^
@@ -45,7 +45,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:35:15
+ --> $DIR/named-asm-labels.rs:33:15
|
LL | asm!("foo2: foo3: nop", "nop");
| ^^^^
@@ -54,7 +54,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:35:21
+ --> $DIR/named-asm-labels.rs:33:21
|
LL | asm!("foo2: foo3: nop", "nop");
| ^^^^
@@ -63,7 +63,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:38:22
+ --> $DIR/named-asm-labels.rs:36:22
|
LL | asm!("nop", "foo4: nop");
| ^^^^
@@ -72,7 +72,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:39:15
+ --> $DIR/named-asm-labels.rs:37:15
|
LL | asm!("foo5: nop", "foo6: nop");
| ^^^^
@@ -81,7 +81,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:39:28
+ --> $DIR/named-asm-labels.rs:37:28
|
LL | asm!("foo5: nop", "foo6: nop");
| ^^^^
@@ -90,7 +90,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:44:15
+ --> $DIR/named-asm-labels.rs:42:15
|
LL | asm!("foo7: nop; foo8: nop");
| ^^^^
@@ -99,7 +99,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:44:26
+ --> $DIR/named-asm-labels.rs:42:26
|
LL | asm!("foo7: nop; foo8: nop");
| ^^^^
@@ -108,7 +108,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:47:15
+ --> $DIR/named-asm-labels.rs:45:15
|
LL | asm!("foo9: nop; nop");
| ^^^^
@@ -117,7 +117,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:48:20
+ --> $DIR/named-asm-labels.rs:46:20
|
LL | asm!("nop; foo10: nop");
| ^^^^^
@@ -126,7 +126,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:51:15
+ --> $DIR/named-asm-labels.rs:49:15
|
LL | asm!("bar2: nop\n bar3: nop");
| ^^^^
@@ -135,7 +135,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:51:27
+ --> $DIR/named-asm-labels.rs:49:27
|
LL | asm!("bar2: nop\n bar3: nop");
| ^^^^
@@ -144,7 +144,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:54:15
+ --> $DIR/named-asm-labels.rs:52:15
|
LL | asm!("bar4: nop\n nop");
| ^^^^
@@ -153,7 +153,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:55:21
+ --> $DIR/named-asm-labels.rs:53:21
|
LL | asm!("nop\n bar5: nop");
| ^^^^
@@ -162,7 +162,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:56:21
+ --> $DIR/named-asm-labels.rs:54:21
|
LL | asm!("nop\n bar6: bar7: nop");
| ^^^^
@@ -171,7 +171,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:56:27
+ --> $DIR/named-asm-labels.rs:54:27
|
LL | asm!("nop\n bar6: bar7: nop");
| ^^^^
@@ -180,7 +180,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:63:13
+ --> $DIR/named-asm-labels.rs:61:13
|
LL | blah2: nop
| ^^^^^
@@ -189,7 +189,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:64:13
+ --> $DIR/named-asm-labels.rs:62:13
|
LL | blah3: nop
| ^^^^^
@@ -198,7 +198,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:73:19
+ --> $DIR/named-asm-labels.rs:71:19
|
LL | nop ; blah4: nop
| ^^^^^
@@ -207,7 +207,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:87:15
+ --> $DIR/named-asm-labels.rs:85:15
|
LL | asm!("blah1: 2bar: nop");
| ^^^^^
@@ -216,7 +216,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:90:15
+ --> $DIR/named-asm-labels.rs:88:15
|
LL | asm!("def: def: nop");
| ^^^
@@ -225,7 +225,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:90:15
+ --> $DIR/named-asm-labels.rs:88:15
|
LL | asm!("def: def: nop");
| ^^^
@@ -235,7 +235,7 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:93:15
+ --> $DIR/named-asm-labels.rs:91:15
|
LL | asm!("def: nop\ndef: nop");
| ^^^
@@ -244,7 +244,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:93:15
+ --> $DIR/named-asm-labels.rs:91:15
|
LL | asm!("def: nop\ndef: nop");
| ^^^
@@ -254,7 +254,7 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:96:15
+ --> $DIR/named-asm-labels.rs:94:15
|
LL | asm!("def: nop; def: nop");
| ^^^
@@ -263,7 +263,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:96:15
+ --> $DIR/named-asm-labels.rs:94:15
|
LL | asm!("def: nop; def: nop");
| ^^^
@@ -273,7 +273,7 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:106:15
+ --> $DIR/named-asm-labels.rs:104:15
|
LL | asm!("fooo\u{003A} nop");
| ^^^^^^^^^^^^^^^^
@@ -282,7 +282,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:107:15
+ --> $DIR/named-asm-labels.rs:105:15
|
LL | asm!("foooo\x3A nop");
| ^^^^^^^^^^^^^
@@ -291,7 +291,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:110:15
+ --> $DIR/named-asm-labels.rs:108:15
|
LL | asm!("fooooo:\u{000A} nop");
| ^^^^^^
@@ -300,7 +300,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:111:15
+ --> $DIR/named-asm-labels.rs:109:15
|
LL | asm!("foooooo:\x0A nop");
| ^^^^^^^
@@ -309,7 +309,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:115:14
+ --> $DIR/named-asm-labels.rs:113:14
|
LL | asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -319,7 +319,7 @@
= note: the label may be declared in the expansion of a macro
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:123:13
+ --> $DIR/named-asm-labels.rs:121:13
|
LL | ab: nop // ab: does foo
| ^^
@@ -328,7 +328,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:144:19
+ --> $DIR/named-asm-labels.rs:142:19
|
LL | asm!("test_{}: nop", in(reg) 10);
| ^^^^^^^
@@ -338,7 +338,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:146:15
+ --> $DIR/named-asm-labels.rs:144:15
|
LL | asm!("test_{}: nop", const 10);
| ^^^^^^^
@@ -348,7 +348,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:147:15
+ --> $DIR/named-asm-labels.rs:145:15
|
LL | asm!("test_{}: nop", sym main);
| ^^^^^^^
@@ -358,7 +358,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:148:15
+ --> $DIR/named-asm-labels.rs:146:15
|
LL | asm!("{}_test: nop", const 10);
| ^^^^^^^
@@ -368,7 +368,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:149:15
+ --> $DIR/named-asm-labels.rs:147:15
|
LL | asm!("test_{}_test: nop", const 10);
| ^^^^^^^^^^^^
@@ -378,7 +378,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:150:15
+ --> $DIR/named-asm-labels.rs:148:15
|
LL | asm!("{}: nop", const 10);
| ^^
@@ -388,7 +388,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:152:15
+ --> $DIR/named-asm-labels.rs:150:15
|
LL | asm!("{uwu}: nop", uwu = const 10);
| ^^^^^
@@ -398,7 +398,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:153:15
+ --> $DIR/named-asm-labels.rs:151:15
|
LL | asm!("{0}: nop", const 10);
| ^^^
@@ -408,7 +408,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:154:15
+ --> $DIR/named-asm-labels.rs:152:15
|
LL | asm!("{1}: nop", "/* {0} */", const 10, const 20);
| ^^^
@@ -418,7 +418,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:157:14
+ --> $DIR/named-asm-labels.rs:155:14
|
LL | asm!(include_str!("named-asm-labels.s"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -428,7 +428,7 @@
= note: the label may be declared in the expansion of a macro
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:157:14
+ --> $DIR/named-asm-labels.rs:155:14
|
LL | asm!(include_str!("named-asm-labels.s"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -439,7 +439,7 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:157:14
+ --> $DIR/named-asm-labels.rs:155:14
|
LL | asm!(include_str!("named-asm-labels.s"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -450,7 +450,7 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:157:14
+ --> $DIR/named-asm-labels.rs:155:14
|
LL | asm!(include_str!("named-asm-labels.s"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -461,7 +461,7 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
warning: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:171:19
+ --> $DIR/named-asm-labels.rs:169:19
|
LL | asm!("warned: nop");
| ^^^^^^
@@ -469,22 +469,22 @@
= help: only local labels of the form `<number>:` should be used in inline asm
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
note: the lint level is defined here
- --> $DIR/named-asm-labels.rs:169:16
+ --> $DIR/named-asm-labels.rs:167:16
|
LL | #[warn(named_asm_labels)]
| ^^^^^^^^^^^^^^^^
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:180:26
+ --> $DIR/named-asm-labels.rs:178:17
|
-LL | unsafe { naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1) }
- | ^^^^^
+LL | naked_asm!(".Lfoo: mov rax, {}; ret;", "nop", const 1)
+ | ^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:187:20
+ --> $DIR/named-asm-labels.rs:185:20
|
LL | unsafe { asm!(".Lbar: mov rax, {}; ret;", "nop", const 1, options(noreturn)) }
| ^^^^^
@@ -493,25 +493,25 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:195:26
+ --> $DIR/named-asm-labels.rs:193:17
|
-LL | unsafe { naked_asm!(".Laaa: nop; ret;") }
- | ^^^^^
+LL | naked_asm!(".Laaa: nop; ret;")
+ | ^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:205:30
+ --> $DIR/named-asm-labels.rs:203:21
|
-LL | unsafe { naked_asm!(".Lbbb: nop; ret;") }
- | ^^^^^
+LL | naked_asm!(".Lbbb: nop; ret;")
+ | ^^^^^
|
= help: only local labels of the form `<number>:` should be used in inline asm
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:214:15
+ --> $DIR/named-asm-labels.rs:212:15
|
LL | asm!("closure1: nop");
| ^^^^^^^^
@@ -520,7 +520,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:218:15
+ --> $DIR/named-asm-labels.rs:216:15
|
LL | asm!("closure2: nop");
| ^^^^^^^^
@@ -529,7 +529,7 @@
= note: see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
error: avoid using named labels in inline assembly
- --> $DIR/named-asm-labels.rs:228:19
+ --> $DIR/named-asm-labels.rs:226:19
|
LL | asm!("closure3: nop");
| ^^^^^^^^
diff --git a/tests/ui/asm/simple_global_asm.rs b/tests/ui/asm/simple_global_asm.rs
index 9b193b3..68b0b83 100644
--- a/tests/ui/asm/simple_global_asm.rs
+++ b/tests/ui/asm/simple_global_asm.rs
@@ -1,7 +1,6 @@
//@ run-pass
//@ needs-asm-support
-#![feature(naked_functions)]
#![allow(dead_code)]
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
diff --git a/tests/ui/asm/unpretty-expanded.rs b/tests/ui/asm/unpretty-expanded.rs
index 1da2c77..3eb46fe 100644
--- a/tests/ui/asm/unpretty-expanded.rs
+++ b/tests/ui/asm/unpretty-expanded.rs
@@ -1,4 +1,5 @@
//@ needs-asm-support
//@ check-pass
//@ compile-flags: -Zunpretty=expanded
+//@ edition: 2015
core::arch::global_asm!("x: .byte 42");
diff --git a/tests/ui/asm/unpretty-expanded.stdout b/tests/ui/asm/unpretty-expanded.stdout
index 80ccd12..7ba1702 100644
--- a/tests/ui/asm/unpretty-expanded.stdout
+++ b/tests/ui/asm/unpretty-expanded.stdout
@@ -7,4 +7,5 @@
//@ needs-asm-support
//@ check-pass
//@ compile-flags: -Zunpretty=expanded
+//@ edition: 2015
global_asm! ("x: .byte 42");
diff --git a/tests/ui/associated-types/associated-type-macro.rs b/tests/ui/associated-types/associated-type-macro.rs
index 22b5bca..8586dc1 100644
--- a/tests/ui/associated-types/associated-type-macro.rs
+++ b/tests/ui/associated-types/associated-type-macro.rs
@@ -1,4 +1,4 @@
fn main() {
- #[cfg(FALSE)]
+ #[cfg(false)]
<() as module>::mac!(); //~ ERROR macros cannot use qualified paths
}
diff --git a/tests/ui/associated-types/issue-36499.rs b/tests/ui/associated-types/issue-36499.rs
index 606918b..941b1aa 100644
--- a/tests/ui/associated-types/issue-36499.rs
+++ b/tests/ui/associated-types/issue-36499.rs
@@ -1,5 +1,3 @@
-//@ error-pattern: aborting due to 1 previous error
-
fn main() {
2 + +2; //~ ERROR leading `+` is not supported
}
diff --git a/tests/ui/associated-types/issue-36499.stderr b/tests/ui/associated-types/issue-36499.stderr
index dd91bac..aebf0fa 100644
--- a/tests/ui/associated-types/issue-36499.stderr
+++ b/tests/ui/associated-types/issue-36499.stderr
@@ -1,5 +1,5 @@
error: leading `+` is not supported
- --> $DIR/issue-36499.rs:4:9
+ --> $DIR/issue-36499.rs:2:9
|
LL | 2 + +2;
| ^ unexpected `+`
diff --git a/tests/ui/async-await/async-closures/is-not-fn.next.stderr b/tests/ui/async-await/async-closures/is-not-fn.next.stderr
index 0fab1c1..970970a 100644
--- a/tests/ui/async-await/async-closures/is-not-fn.next.stderr
+++ b/tests/ui/async-await/async-closures/is-not-fn.next.stderr
@@ -1,13 +1,11 @@
-error[E0271]: expected `{async closure@is-not-fn.rs:8:14}` to return `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}`
+error[E0271]: type mismatch resolving `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25} == ()`
--> $DIR/is-not-fn.rs:8:14
|
LL | needs_fn(async || {});
- | -------- ^^^^^^^^^^^ expected `()`, found `async` closure body
+ | -------- ^^^^^^^^^^^ types differ
| |
| required by a bound introduced by this call
|
- = note: expected unit type `()`
- found `async` closure body `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25}`
note: required by a bound in `needs_fn`
--> $DIR/is-not-fn.rs:7:25
|
diff --git a/tests/ui/async-await/async-closures/is-not-fn.rs b/tests/ui/async-await/async-closures/is-not-fn.rs
index e5ab474..c09ccb3 100644
--- a/tests/ui/async-await/async-closures/is-not-fn.rs
+++ b/tests/ui/async-await/async-closures/is-not-fn.rs
@@ -6,5 +6,6 @@
fn main() {
fn needs_fn(x: impl FnOnce()) {}
needs_fn(async || {});
- //~^ ERROR expected `{async closure@is-not-fn.rs:8:14}` to return `()`
+ //[current]~^ ERROR expected `{async closure@is-not-fn.rs:8:14}` to return `()`
+ //[next]~^^ ERROR type mismatch resolving `{async closure body@$DIR/is-not-fn.rs:8:23: 8:25} == ()`
}
diff --git a/tests/ui/async-await/async-gen-move-suggestion.fixed b/tests/ui/async-await/async-gen-move-suggestion.fixed
new file mode 100644
index 0000000..d802076
--- /dev/null
+++ b/tests/ui/async-await/async-gen-move-suggestion.fixed
@@ -0,0 +1,35 @@
+// This is a regression test for <https://github.com/rust-lang/rust/issues/139839>.
+// It ensures that the "add `move` keyword" suggestion is valid.
+
+//@ run-rustfix
+//@ edition:2024
+
+#![feature(coroutines)]
+#![feature(gen_blocks)]
+#![feature(async_iterator)]
+
+use std::async_iter::AsyncIterator;
+
+#[allow(dead_code)]
+fn moved() -> impl AsyncIterator<Item = u32> {
+ let mut x = "foo".to_string();
+
+ async gen move { //~ ERROR
+ x.clear();
+ for x in 3..6 { yield x }
+ }
+}
+
+#[allow(dead_code)]
+fn check_with_whitespace_chars() -> impl AsyncIterator<Item = u32> {
+ let mut x = "foo".to_string();
+
+ async // Just to check that whitespace characters are correctly handled
+ gen move { //~^ ERROR
+ x.clear();
+ for x in 3..6 { yield x }
+ }
+}
+
+fn main() {
+}
diff --git a/tests/ui/async-await/async-gen-move-suggestion.rs b/tests/ui/async-await/async-gen-move-suggestion.rs
new file mode 100644
index 0000000..825fb0f
--- /dev/null
+++ b/tests/ui/async-await/async-gen-move-suggestion.rs
@@ -0,0 +1,35 @@
+// This is a regression test for <https://github.com/rust-lang/rust/issues/139839>.
+// It ensures that the "add `move` keyword" suggestion is valid.
+
+//@ run-rustfix
+//@ edition:2024
+
+#![feature(coroutines)]
+#![feature(gen_blocks)]
+#![feature(async_iterator)]
+
+use std::async_iter::AsyncIterator;
+
+#[allow(dead_code)]
+fn moved() -> impl AsyncIterator<Item = u32> {
+ let mut x = "foo".to_string();
+
+ async gen { //~ ERROR
+ x.clear();
+ for x in 3..6 { yield x }
+ }
+}
+
+#[allow(dead_code)]
+fn check_with_whitespace_chars() -> impl AsyncIterator<Item = u32> {
+ let mut x = "foo".to_string();
+
+ async // Just to check that whitespace characters are correctly handled
+ gen { //~^ ERROR
+ x.clear();
+ for x in 3..6 { yield x }
+ }
+}
+
+fn main() {
+}
diff --git a/tests/ui/async-await/async-gen-move-suggestion.stderr b/tests/ui/async-await/async-gen-move-suggestion.stderr
new file mode 100644
index 0000000..b8cdb8b
--- /dev/null
+++ b/tests/ui/async-await/async-gen-move-suggestion.stderr
@@ -0,0 +1,47 @@
+error[E0373]: async gen block may outlive the current function, but it borrows `x`, which is owned by the current function
+ --> $DIR/async-gen-move-suggestion.rs:17:5
+ |
+LL | async gen {
+ | ^^^^^^^^^ may outlive borrowed value `x`
+LL | x.clear();
+ | - `x` is borrowed here
+ |
+note: async gen block is returned here
+ --> $DIR/async-gen-move-suggestion.rs:17:5
+ |
+LL | / async gen {
+LL | | x.clear();
+LL | | for x in 3..6 { yield x }
+LL | | }
+ | |_____^
+help: to force the async gen block to take ownership of `x` (and any other referenced variables), use the `move` keyword
+ |
+LL | async gen move {
+ | ++++
+
+error[E0373]: async gen block may outlive the current function, but it borrows `x`, which is owned by the current function
+ --> $DIR/async-gen-move-suggestion.rs:27:5
+ |
+LL | / async // Just to check that whitespace characters are correctly handled
+LL | | gen {
+ | |_______^ may outlive borrowed value `x`
+LL | x.clear();
+ | - `x` is borrowed here
+ |
+note: async gen block is returned here
+ --> $DIR/async-gen-move-suggestion.rs:27:5
+ |
+LL | / async // Just to check that whitespace characters are correctly handled
+LL | | gen {
+LL | | x.clear();
+LL | | for x in 3..6 { yield x }
+LL | | }
+ | |_____^
+help: to force the async gen block to take ownership of `x` (and any other referenced variables), use the `move` keyword
+ |
+LL | gen move {
+ | ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0373`.
diff --git a/tests/ui/async-await/feature-async-for-loop.rs b/tests/ui/async-await/feature-async-for-loop.rs
index 67817cb..22d3290 100644
--- a/tests/ui/async-await/feature-async-for-loop.rs
+++ b/tests/ui/async-await/feature-async-for-loop.rs
@@ -11,7 +11,7 @@ fn f() {
};
}
-#[cfg(FALSE)]
+#[cfg(false)]
fn g() {
let _ = async {
for await _i in core::async_iter::from_iter(0..3) {
diff --git a/tests/ui/async-await/no-unsafe-async.rs b/tests/ui/async-await/no-unsafe-async.rs
index e58d878..cc7e89e 100644
--- a/tests/ui/async-await/no-unsafe-async.rs
+++ b/tests/ui/async-await/no-unsafe-async.rs
@@ -3,11 +3,11 @@
struct S;
impl S {
- #[cfg(FALSE)]
+ #[cfg(false)]
unsafe async fn g() {} //~ ERROR expected one of `extern` or `fn`, found keyword `async`
}
-#[cfg(FALSE)]
+#[cfg(false)]
unsafe async fn f() {} //~ ERROR expected one of `extern` or `fn`, found keyword `async`
fn main() {}
diff --git a/tests/ui/async-await/pin-ergonomics/reborrow-once.stderr b/tests/ui/async-await/pin-ergonomics/reborrow-once.stderr
index a1ea2b4..dc8e424 100644
--- a/tests/ui/async-await/pin-ergonomics/reborrow-once.stderr
+++ b/tests/ui/async-await/pin-ergonomics/reborrow-once.stderr
@@ -1,4 +1,4 @@
-error[E0499]: cannot borrow `*x.__pointer` as mutable more than once at a time
+error[E0499]: cannot borrow `*x.pointer` as mutable more than once at a time
--> $DIR/reborrow-once.rs:12:14
|
LL | twice(x, x);
diff --git a/tests/ui/async-await/post-cleanup-phase-validation.rs b/tests/ui/async-await/post-cleanup-phase-validation.rs
new file mode 100644
index 0000000..a347e35
--- /dev/null
+++ b/tests/ui/async-await/post-cleanup-phase-validation.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: -Zvalidate-mir
+//@ edition: 2024
+//@ build-pass
+
+// Regression test that we don't ICE when encountering a transmute in a coroutine's
+// drop shim body, which is conceptually in the Runtime phase but wasn't having the
+// phase updated b/c the pass manager neither optimizes nor updates the phase for
+// drop shim bodies.
+
+struct HasDrop;
+impl Drop for HasDrop {
+ fn drop(&mut self) {}
+}
+
+fn main() {
+ async {
+ vec![async { HasDrop }.await];
+ };
+}
diff --git a/tests/ui/async-await/suggest-missing-await.rs b/tests/ui/async-await/suggest-missing-await.rs
index 9897928..de0b2ce 100644
--- a/tests/ui/async-await/suggest-missing-await.rs
+++ b/tests/ui/async-await/suggest-missing-await.rs
@@ -1,4 +1,5 @@
//@ edition:2018
+//@ dont-require-annotations: SUGGESTION
fn take_u32(_x: u32) {}
diff --git a/tests/ui/async-await/suggest-missing-await.stderr b/tests/ui/async-await/suggest-missing-await.stderr
index f9db86e..9db7eb9 100644
--- a/tests/ui/async-await/suggest-missing-await.stderr
+++ b/tests/ui/async-await/suggest-missing-await.stderr
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
- --> $DIR/suggest-missing-await.rs:12:14
+ --> $DIR/suggest-missing-await.rs:13:14
|
LL | take_u32(x)
| -------- ^ expected `u32`, found future
@@ -7,12 +7,12 @@
| arguments to this function are incorrect
|
note: calling an async function returns a future
- --> $DIR/suggest-missing-await.rs:12:14
+ --> $DIR/suggest-missing-await.rs:13:14
|
LL | take_u32(x)
| ^
note: function defined here
- --> $DIR/suggest-missing-await.rs:3:4
+ --> $DIR/suggest-missing-await.rs:4:4
|
LL | fn take_u32(_x: u32) {}
| ^^^^^^^^ -------
@@ -22,13 +22,13 @@
| ++++++
error[E0308]: mismatched types
- --> $DIR/suggest-missing-await.rs:22:5
+ --> $DIR/suggest-missing-await.rs:23:5
|
LL | dummy()
| ^^^^^^^ expected `()`, found future
|
note: calling an async function returns a future
- --> $DIR/suggest-missing-await.rs:22:5
+ --> $DIR/suggest-missing-await.rs:23:5
|
LL | dummy()
| ^^^^^^^
@@ -42,7 +42,7 @@
| +
error[E0308]: `if` and `else` have incompatible types
- --> $DIR/suggest-missing-await.rs:35:9
+ --> $DIR/suggest-missing-await.rs:36:9
|
LL | let _x = if true {
| ______________-
@@ -64,7 +64,7 @@
| ++++++
error[E0308]: `match` arms have incompatible types
- --> $DIR/suggest-missing-await.rs:45:14
+ --> $DIR/suggest-missing-await.rs:46:14
|
LL | let _x = match 0usize {
| ______________-
@@ -87,7 +87,7 @@
|
error[E0308]: mismatched types
- --> $DIR/suggest-missing-await.rs:53:9
+ --> $DIR/suggest-missing-await.rs:54:9
|
LL | let _x = match dummy() {
| ------- this expression has type `impl Future<Output = ()>`
@@ -102,7 +102,7 @@
| ++++++
error[E0308]: mismatched types
- --> $DIR/suggest-missing-await.rs:67:9
+ --> $DIR/suggest-missing-await.rs:68:9
|
LL | match dummy_result() {
| -------------- this expression has type `impl Future<Output = Result<(), ()>>`
@@ -118,7 +118,7 @@
| ++++++
error[E0308]: mismatched types
- --> $DIR/suggest-missing-await.rs:69:9
+ --> $DIR/suggest-missing-await.rs:70:9
|
LL | match dummy_result() {
| -------------- this expression has type `impl Future<Output = Result<(), ()>>`
@@ -134,7 +134,7 @@
| ++++++
error[E0308]: mismatched types
- --> $DIR/suggest-missing-await.rs:77:27
+ --> $DIR/suggest-missing-await.rs:78:27
|
LL | Some(do_async()).map(|()| {});
| ^^
diff --git a/tests/ui/attributes/check-builtin-attr-ice.rs b/tests/ui/attributes/check-builtin-attr-ice.rs
index 9ef5890..7745849 100644
--- a/tests/ui/attributes/check-builtin-attr-ice.rs
+++ b/tests/ui/attributes/check-builtin-attr-ice.rs
@@ -39,13 +39,17 @@
// Notably, `should_panic` is a `AttributeType::Normal` attribute that is checked separately.
+#![deny(unused_attributes)]
+
struct Foo {
#[should_panic::skip]
//~^ ERROR failed to resolve
+ //~| ERROR `#[should_panic::skip]` only has an effect on functions
pub field: u8,
#[should_panic::a::b::c]
//~^ ERROR failed to resolve
+ //~| ERROR `#[should_panic::a::b::c]` only has an effect on functions
pub field2: u8,
}
diff --git a/tests/ui/attributes/check-builtin-attr-ice.stderr b/tests/ui/attributes/check-builtin-attr-ice.stderr
index 06a4769..4f26f71 100644
--- a/tests/ui/attributes/check-builtin-attr-ice.stderr
+++ b/tests/ui/attributes/check-builtin-attr-ice.stderr
@@ -1,21 +1,39 @@
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `should_panic`
- --> $DIR/check-builtin-attr-ice.rs:43:7
+ --> $DIR/check-builtin-attr-ice.rs:45:7
|
LL | #[should_panic::skip]
| ^^^^^^^^^^^^ use of unresolved module or unlinked crate `should_panic`
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `should_panic`
- --> $DIR/check-builtin-attr-ice.rs:47:7
+ --> $DIR/check-builtin-attr-ice.rs:50:7
|
LL | #[should_panic::a::b::c]
| ^^^^^^^^^^^^ use of unresolved module or unlinked crate `should_panic`
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `deny`
- --> $DIR/check-builtin-attr-ice.rs:55:7
+ --> $DIR/check-builtin-attr-ice.rs:59:7
|
LL | #[deny::skip]
| ^^^^ use of unresolved module or unlinked crate `deny`
-error: aborting due to 3 previous errors
+error: `#[should_panic::skip]` only has an effect on functions
+ --> $DIR/check-builtin-attr-ice.rs:45:5
+ |
+LL | #[should_panic::skip]
+ | ^^^^^^^^^^^^^^^^^^^^^
+ |
+note: the lint level is defined here
+ --> $DIR/check-builtin-attr-ice.rs:42:9
+ |
+LL | #![deny(unused_attributes)]
+ | ^^^^^^^^^^^^^^^^^
+
+error: `#[should_panic::a::b::c]` only has an effect on functions
+ --> $DIR/check-builtin-attr-ice.rs:50:5
+ |
+LL | #[should_panic::a::b::c]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0433`.
diff --git a/tests/ui/attributes/invalid_macro_export_argument.deny.stderr b/tests/ui/attributes/invalid_macro_export_argument.deny.stderr
index 644acc2..9d44bd1 100644
--- a/tests/ui/attributes/invalid_macro_export_argument.deny.stderr
+++ b/tests/ui/attributes/invalid_macro_export_argument.deny.stderr
@@ -10,11 +10,17 @@
LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: `not_local_inner_macros` isn't a valid `#[macro_export]` argument
+error: invalid `#[macro_export]` argument
--> $DIR/invalid_macro_export_argument.rs:13:16
|
LL | #[macro_export(not_local_inner_macros)]
| ^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 2 previous errors
+error: invalid `#[macro_export]` argument
+ --> $DIR/invalid_macro_export_argument.rs:33:16
+ |
+LL | #[macro_export("blah")]
+ | ^^^^^^
+
+error: aborting due to 3 previous errors
diff --git a/tests/ui/attributes/invalid_macro_export_argument.rs b/tests/ui/attributes/invalid_macro_export_argument.rs
index 96f6699..c5fe39d 100644
--- a/tests/ui/attributes/invalid_macro_export_argument.rs
+++ b/tests/ui/attributes/invalid_macro_export_argument.rs
@@ -11,7 +11,7 @@ macro_rules! a {
}
#[macro_export(not_local_inner_macros)]
-//[deny]~^ ERROR `not_local_inner_macros` isn't a valid `#[macro_export]` argument
+//[deny]~^ ERROR invalid `#[macro_export]` argument
macro_rules! b {
() => ()
}
@@ -30,4 +30,10 @@ macro_rules! e {
() => ()
}
+#[macro_export("blah")]
+//[deny]~^ ERROR invalid `#[macro_export]` argument
+macro_rules! f {
+ () => ()
+}
+
fn main() {}
diff --git a/tests/ui/attributes/no-sanitize.rs b/tests/ui/attributes/no-sanitize.rs
index 8c79866..ddf909b 100644
--- a/tests/ui/attributes/no-sanitize.rs
+++ b/tests/ui/attributes/no-sanitize.rs
@@ -38,3 +38,8 @@ fn valid() {}
#[no_sanitize(address)]
static VALID : i32 = 0;
+
+#[no_sanitize("address")]
+//~^ ERROR `#[no_sanitize(...)]` should be applied to a function
+//~| ERROR invalid argument for `no_sanitize`
+static VALID2 : i32 = 0;
diff --git a/tests/ui/attributes/no-sanitize.stderr b/tests/ui/attributes/no-sanitize.stderr
index 9b0b76e..8d5fbb1 100644
--- a/tests/ui/attributes/no-sanitize.stderr
+++ b/tests/ui/attributes/no-sanitize.stderr
@@ -59,5 +59,22 @@
LL | static INVALID : i32 = 0;
| ------------------------- not a function
-error: aborting due to 7 previous errors
+error: `#[no_sanitize(...)]` should be applied to a function
+ --> $DIR/no-sanitize.rs:42:15
+ |
+LL | #[no_sanitize("address")]
+ | ^^^^^^^^^
+...
+LL | static VALID2 : i32 = 0;
+ | ------------------------ not a function
+
+error: invalid argument for `no_sanitize`
+ --> $DIR/no-sanitize.rs:42:15
+ |
+LL | #[no_sanitize("address")]
+ | ^^^^^^^^^
+ |
+ = note: expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
+
+error: aborting due to 9 previous errors
diff --git a/tests/ui/attributes/z-crate-attr/cfg-false.rs b/tests/ui/attributes/z-crate-attr/cfg-false.rs
index db37cfd..5e5662c 100644
--- a/tests/ui/attributes/z-crate-attr/cfg-false.rs
+++ b/tests/ui/attributes/z-crate-attr/cfg-false.rs
@@ -1,5 +1,5 @@
-// Ensure that `-Z crate-attr=cfg(FALSE)` can comment out the whole crate
-//@ compile-flags: --crate-type=lib -Zcrate-attr=cfg(FALSE)
+// Ensure that `-Z crate-attr=cfg(false)` can comment out the whole crate
+//@ compile-flags: --crate-type=lib -Zcrate-attr=cfg(false)
//@ check-pass
// NOTE: duplicate items are load-bearing
diff --git a/tests/ui/attributes/z-crate-attr/garbage.stderr b/tests/ui/attributes/z-crate-attr/garbage.stderr
index 082046e..12d18b0 100644
--- a/tests/ui/attributes/z-crate-attr/garbage.stderr
+++ b/tests/ui/attributes/z-crate-attr/garbage.stderr
@@ -1,20 +1,20 @@
error: unknown start of token: `
- --> <crate attribute>:1:1
+ --> <crate attribute>:1:4
|
-LL | `%~@$#
- | ^
+LL | #![`%~@$#]
+ | ^
|
help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not
|
-LL - `%~@$#
-LL + '%~@$#
+LL - #![`%~@$#]
+LL + #!['%~@$#]
|
error: expected identifier, found `%`
- --> <crate attribute>:1:2
+ --> <crate attribute>:1:5
|
-LL | `%~@$#
- | ^ expected identifier
+LL | #![`%~@$#]
+ | ^ expected identifier
error: aborting due to 2 previous errors
diff --git a/tests/ui/attributes/z-crate-attr/injection.rs b/tests/ui/attributes/z-crate-attr/injection.rs
index a91f9d2..ee7a27c 100644
--- a/tests/ui/attributes/z-crate-attr/injection.rs
+++ b/tests/ui/attributes/z-crate-attr/injection.rs
@@ -1,5 +1,3 @@
//@ compile-flags: '-Zcrate-attr=feature(yeet_expr)]fn main(){}#[inline'
-
-fn foo() {}
-
-//~? ERROR unexpected closing delimiter: `]`
+//~? ERROR unexpected token
+fn foo() {} //~ ERROR `main` function not found
diff --git a/tests/ui/attributes/z-crate-attr/injection.stderr b/tests/ui/attributes/z-crate-attr/injection.stderr
index 6fec98b..899dad0 100644
--- a/tests/ui/attributes/z-crate-attr/injection.stderr
+++ b/tests/ui/attributes/z-crate-attr/injection.stderr
@@ -1,8 +1,15 @@
-error: unexpected closing delimiter: `]`
- --> <crate attribute>:1:19
+error: unexpected token: keyword `fn`
+ --> <crate attribute>:1:23
|
-LL | feature(yeet_expr)]fn main(){}#[inline
- | ^ unexpected closing delimiter
+LL | #![feature(yeet_expr)]fn main(){}#[inline]
+ | ^^ unexpected token after this
-error: aborting due to 1 previous error
+error[E0601]: `main` function not found in crate `injection`
+ --> $DIR/injection.rs:3:12
+ |
+LL | fn foo() {}
+ | ^ consider adding a `main` function to `$DIR/injection.rs`
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/tests/ui/attributes/z-crate-attr/injection2.rs b/tests/ui/attributes/z-crate-attr/injection2.rs
new file mode 100644
index 0000000..67ae3d1
--- /dev/null
+++ b/tests/ui/attributes/z-crate-attr/injection2.rs
@@ -0,0 +1,3 @@
+//@ compile-flags: -Zcrate-attr=feature(yeet_expr)]#![allow(warnings)
+//~? ERROR unexpected token
+fn foo() {} //~ ERROR `main` function not found
diff --git a/tests/ui/attributes/z-crate-attr/injection2.stderr b/tests/ui/attributes/z-crate-attr/injection2.stderr
new file mode 100644
index 0000000..51f54f9
--- /dev/null
+++ b/tests/ui/attributes/z-crate-attr/injection2.stderr
@@ -0,0 +1,15 @@
+error: unexpected token: `#`
+ --> <crate attribute>:1:23
+ |
+LL | #![feature(yeet_expr)]#![allow(warnings)]
+ | ^ unexpected token after this
+
+error[E0601]: `main` function not found in crate `injection2`
+ --> $DIR/injection2.rs:3:12
+ |
+LL | fn foo() {}
+ | ^ consider adding a `main` function to `$DIR/injection2.rs`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0601`.
diff --git a/tests/ui/attributes/z-crate-attr/inner-attr.stderr b/tests/ui/attributes/z-crate-attr/inner-attr.stderr
index 06a063d..1acb8c2 100644
--- a/tests/ui/attributes/z-crate-attr/inner-attr.stderr
+++ b/tests/ui/attributes/z-crate-attr/inner-attr.stderr
@@ -1,8 +1,8 @@
error: expected identifier, found `#`
- --> <crate attribute>:1:1
+ --> <crate attribute>:1:4
|
-LL | #![feature(foo)]
- | ^ expected identifier
+LL | #![#![feature(foo)]]
+ | ^ expected identifier
error: aborting due to 1 previous error
diff --git a/tests/ui/attributes/z-crate-attr/multiple.rs b/tests/ui/attributes/z-crate-attr/multiple.rs
index 47d35d2..8c60ea6 100644
--- a/tests/ui/attributes/z-crate-attr/multiple.rs
+++ b/tests/ui/attributes/z-crate-attr/multiple.rs
@@ -1,5 +1,3 @@
//@ compile-flags: -Zcrate-attr=feature(foo),feature(bar)
-
+//~? ERROR expected `]`
fn main() {}
-
-//~? ERROR invalid crate attribute
diff --git a/tests/ui/attributes/z-crate-attr/multiple.stderr b/tests/ui/attributes/z-crate-attr/multiple.stderr
index 9f968a7..b95c95d 100644
--- a/tests/ui/attributes/z-crate-attr/multiple.stderr
+++ b/tests/ui/attributes/z-crate-attr/multiple.stderr
@@ -1,8 +1,8 @@
-error: invalid crate attribute
- --> <crate attribute>:1:1
+error: expected `]`, found `,`
+ --> <crate attribute>:1:16
|
-LL | feature(foo),feature(bar)
- | ^^^^^^^^^^^^^
+LL | #![feature(foo),feature(bar)]
+ | ^ expected `]`
error: aborting due to 1 previous error
diff --git a/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs b/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs
index 77d5d69..5ef0a75 100644
--- a/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs
+++ b/tests/ui/attributes/z-crate-attr/unbalanced-paren.rs
@@ -1,6 +1,4 @@
// Show diagnostics for unbalanced parens.
//@ compile-flags: -Zcrate-attr=(
-
+//~? ERROR mismatched closing delimiter
fn main() {}
-
-//~? ERROR this file contains an unclosed delimiter
diff --git a/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr b/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr
index 47b1b76..f6545d1 100644
--- a/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr
+++ b/tests/ui/attributes/z-crate-attr/unbalanced-paren.stderr
@@ -1,10 +1,11 @@
-error: this file contains an unclosed delimiter
- --> <crate attribute>:1:2
+error: mismatched closing delimiter: `]`
+ --> <crate attribute>:1:4
|
-LL | (
- | -^
- | |
- | unclosed delimiter
+LL | #![(]
+ | -^^ mismatched closing delimiter
+ | ||
+ | |unclosed delimiter
+ | closing delimiter possibly meant for this
error: aborting due to 1 previous error
diff --git a/tests/ui/auto-instantiate.rs b/tests/ui/auto-instantiate.rs
deleted file mode 100644
index 73ad5d7..0000000
--- a/tests/ui/auto-instantiate.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-//@ run-pass
-
-#![allow(dead_code)]
-#[derive(Debug)]
-struct Pair<T, U> { a: T, b: U }
-struct Triple { x: isize, y: isize, z: isize }
-
-fn f<T,U>(x: T, y: U) -> Pair<T, U> { return Pair {a: x, b: y}; }
-
-pub fn main() {
- println!("{}", f(Triple {x: 3, y: 4, z: 5}, 4).a.x);
- println!("{}", f(5, 6).a);
-}
diff --git a/tests/ui/auto-traits/pre-cfg.rs b/tests/ui/auto-traits/pre-cfg.rs
index e806686..4820a53 100644
--- a/tests/ui/auto-traits/pre-cfg.rs
+++ b/tests/ui/auto-traits/pre-cfg.rs
@@ -1,6 +1,6 @@
//@ check-pass
-#[cfg(FALSE)]
+#[cfg(false)]
auto trait Foo {}
//~^ WARN `auto` traits are unstable
//~| WARN unstable syntax can change at any point in the future, causing a hard error!
diff --git a/tests/ui/augmented-assignments-rpass.rs b/tests/ui/binop/augmented-assignment.rs
similarity index 100%
rename from tests/ui/augmented-assignments-rpass.rs
rename to tests/ui/binop/augmented-assignment.rs
diff --git a/tests/ui/augmented-assignments-feature-gate-cross.rs b/tests/ui/binop/augmented-assignments-cross-crate.rs
similarity index 72%
rename from tests/ui/augmented-assignments-feature-gate-cross.rs
rename to tests/ui/binop/augmented-assignments-cross-crate.rs
index d402d20..6dbb035 100644
--- a/tests/ui/augmented-assignments-feature-gate-cross.rs
+++ b/tests/ui/binop/augmented-assignments-cross-crate.rs
@@ -1,3 +1,5 @@
+//! Smoke test for overloaded compound assignments cross-crate.
+
//@ run-pass
//@ aux-build:augmented_assignments.rs
diff --git a/tests/ui/auxiliary/augmented_assignments.rs b/tests/ui/binop/auxiliary/augmented_assignments.rs
similarity index 100%
rename from tests/ui/auxiliary/augmented_assignments.rs
rename to tests/ui/binop/auxiliary/augmented_assignments.rs
diff --git a/tests/ui/bootstrap/self-test/a.rs b/tests/ui/bootstrap/self-test/a.rs
index 64d2d6f..0818665 100644
--- a/tests/ui/bootstrap/self-test/a.rs
+++ b/tests/ui/bootstrap/self-test/a.rs
@@ -1,2 +1 @@
//! Not used by compiler, this is used by bootstrap cli self-test.
-//@ ignore-test
diff --git a/tests/ui/bootstrap/self-test/b.rs b/tests/ui/bootstrap/self-test/b.rs
index 91f92f6..aeb4688 100644
--- a/tests/ui/bootstrap/self-test/b.rs
+++ b/tests/ui/bootstrap/self-test/b.rs
@@ -1,2 +1 @@
//! Not used by compiler, used by bootstrap cli self-test.
-//@ ignore-test
diff --git a/tests/ui/bootstrap/self-test/compiletest-ignore-dir b/tests/ui/bootstrap/self-test/compiletest-ignore-dir
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/ui/bootstrap/self-test/compiletest-ignore-dir
diff --git a/tests/ui/augmented-assignments.rs b/tests/ui/borrowck/augmented-assignments.rs
similarity index 83%
rename from tests/ui/augmented-assignments.rs
rename to tests/ui/borrowck/augmented-assignments.rs
index 35ab2d4..d717dcc 100644
--- a/tests/ui/augmented-assignments.rs
+++ b/tests/ui/borrowck/augmented-assignments.rs
@@ -1,3 +1,6 @@
+//! Check that overloaded compound assignment operators respect usual borrowck rules and emit
+//! reasonable diagnostics.
+
use std::ops::AddAssign;
#[derive(Clone)]
diff --git a/tests/ui/augmented-assignments.stderr b/tests/ui/borrowck/augmented-assignments.stderr
similarity index 88%
rename from tests/ui/augmented-assignments.stderr
rename to tests/ui/borrowck/augmented-assignments.stderr
index a4b75cb..4b945cd 100644
--- a/tests/ui/augmented-assignments.stderr
+++ b/tests/ui/borrowck/augmented-assignments.stderr
@@ -1,5 +1,5 @@
error[E0505]: cannot move out of `x` because it is borrowed
- --> $DIR/augmented-assignments.rs:17:5
+ --> $DIR/augmented-assignments.rs:20:5
|
LL | let mut x = Int(1);
| ----- binding `x` declared here
@@ -10,7 +10,7 @@
| ^ move out of `x` occurs here
error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable
- --> $DIR/augmented-assignments.rs:24:5
+ --> $DIR/augmented-assignments.rs:27:5
|
LL | y
| ^ cannot borrow as mutable
diff --git a/tests/ui/borrowck/move-error-snippets-ext.rs b/tests/ui/borrowck/move-error-snippets-ext.rs
index f810322..6dd6843 100644
--- a/tests/ui/borrowck/move-error-snippets-ext.rs
+++ b/tests/ui/borrowck/move-error-snippets-ext.rs
@@ -1,4 +1,4 @@
-//@ ignore-test (auxiliary, used by other tests)
+//@ ignore-auxiliary (used by `./move-error-snippets.rs`)
macro_rules! aaa {
($c:ident) => {{
diff --git a/tests/ui/borrowck/static-trait-bound-lost.rs b/tests/ui/borrowck/static-trait-bound-lost.rs
new file mode 100644
index 0000000..0288ace
--- /dev/null
+++ b/tests/ui/borrowck/static-trait-bound-lost.rs
@@ -0,0 +1,54 @@
+// This test is a reduced version of a bug introduced during work on type-tests for Polonius.
+// The underlying problem is that the 'static bound is lost for a type parameter that is
+// threaded deeply enough, causing an error.
+// The bug was first observed in exr-1.4.1/src/image/read/mod.rs:124:5 during perf test.
+
+//@ check-pass
+
+use std::marker::PhantomData;
+
+struct ReadAllLayers<ReadChannels> {
+ px: PhantomData<ReadChannels>,
+}
+
+trait ReadLayers<'s> {}
+
+impl<'s, C> ReadLayers<'s> for ReadAllLayers<C> where C: ReadChannels<'s> {}
+
+fn make_builder<A, Set, Pixels>(
+ _: Set,
+) -> ReadAllLayers<CollectPixels<A, Pixels, Set>>
+where
+ Set: Fn(&mut Pixels),
+{
+ todo!()
+}
+
+struct CollectPixels<Pixel, PixelStorage, SetPixel> {
+ px: PhantomData<(SetPixel, Pixel, PixelStorage)>,
+}
+
+impl<'s, PixelStorage, SetPixel: 's> ReadChannels<'s>
+ for CollectPixels<usize, PixelStorage, SetPixel>
+where
+ SetPixel: Fn(&mut PixelStorage),
+{
+}
+
+trait ReadChannels<'s> {}
+
+fn from_file<L>(_: L)
+where
+ for<'s> L: ReadLayers<'s>,
+{
+}
+
+pub fn read_all_rgba_layers_from_file<Set: 'static, Pixels: 'static>(
+ set_pixel: Set,
+) where
+ Set: Fn(&mut Pixels),
+{
+ from_file(make_builder(set_pixel)); // Error triggered.
+}
+
+pub fn main() {}
diff --git a/tests/ui/writing-to-immutable-vec.rs b/tests/ui/borrowck/writing-to-immutable-vec.rs
similarity index 100%
rename from tests/ui/writing-to-immutable-vec.rs
rename to tests/ui/borrowck/writing-to-immutable-vec.rs
diff --git a/tests/ui/writing-to-immutable-vec.stderr b/tests/ui/borrowck/writing-to-immutable-vec.stderr
similarity index 100%
rename from tests/ui/writing-to-immutable-vec.stderr
rename to tests/ui/borrowck/writing-to-immutable-vec.stderr
diff --git a/tests/ui/cast/cast-array-issue-138836.rs b/tests/ui/cast/cast-array-issue-138836.rs
new file mode 100644
index 0000000..3f8098e
--- /dev/null
+++ b/tests/ui/cast/cast-array-issue-138836.rs
@@ -0,0 +1,5 @@
+fn main() {
+ let a: [u8; 3] = [1,2,3];
+ let b = &a;
+ let c = b as *const [u32; 3]; //~ ERROR casting `&[u8; 3]` as `*const [u32; 3]` is invalid
+}
diff --git a/tests/ui/cast/cast-array-issue-138836.stderr b/tests/ui/cast/cast-array-issue-138836.stderr
new file mode 100644
index 0000000..309474c
--- /dev/null
+++ b/tests/ui/cast/cast-array-issue-138836.stderr
@@ -0,0 +1,9 @@
+error[E0606]: casting `&[u8; 3]` as `*const [u32; 3]` is invalid
+ --> $DIR/cast-array-issue-138836.rs:4:13
+ |
+LL | let c = b as *const [u32; 3];
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0606`.
diff --git a/tests/ui/cast/cast-as-bool.rs b/tests/ui/cast/cast-as-bool.rs
index 511a027..fa9664e 100644
--- a/tests/ui/cast/cast-as-bool.rs
+++ b/tests/ui/cast/cast-as-bool.rs
@@ -1,3 +1,5 @@
+//@ dont-require-annotations: SUGGESTION
+
fn main() {
let u = 5 as bool; //~ ERROR cannot cast `i32` as `bool`
//~| HELP compare with zero instead
diff --git a/tests/ui/cast/cast-as-bool.stderr b/tests/ui/cast/cast-as-bool.stderr
index b2c9ae5..25377ebeb 100644
--- a/tests/ui/cast/cast-as-bool.stderr
+++ b/tests/ui/cast/cast-as-bool.stderr
@@ -1,5 +1,5 @@
error[E0054]: cannot cast `i32` as `bool`
- --> $DIR/cast-as-bool.rs:2:13
+ --> $DIR/cast-as-bool.rs:4:13
|
LL | let u = 5 as bool;
| ^^^^^^^^^
@@ -11,7 +11,7 @@
|
error[E0054]: cannot cast `i32` as `bool`
- --> $DIR/cast-as-bool.rs:6:13
+ --> $DIR/cast-as-bool.rs:8:13
|
LL | let t = (1 + 2) as bool;
| ^^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@
|
error[E0054]: cannot cast `u32` as `bool`
- --> $DIR/cast-as-bool.rs:10:13
+ --> $DIR/cast-as-bool.rs:12:13
|
LL | let _ = 5_u32 as bool;
| ^^^^^^^^^^^^^
@@ -35,7 +35,7 @@
|
error[E0054]: cannot cast `f64` as `bool`
- --> $DIR/cast-as-bool.rs:13:13
+ --> $DIR/cast-as-bool.rs:15:13
|
LL | let _ = 64.0_f64 as bool;
| ^^^^^^^^^^^^^^^^
@@ -47,43 +47,43 @@
|
error[E0054]: cannot cast `IntEnum` as `bool`
- --> $DIR/cast-as-bool.rs:24:13
+ --> $DIR/cast-as-bool.rs:26:13
|
LL | let _ = IntEnum::One as bool;
| ^^^^^^^^^^^^^^^^^^^^ unsupported cast
error[E0054]: cannot cast `fn(u8) -> String {uwu}` as `bool`
- --> $DIR/cast-as-bool.rs:33:13
+ --> $DIR/cast-as-bool.rs:35:13
|
LL | let _ = uwu as bool;
| ^^^^^^^^^^^ unsupported cast
error[E0054]: cannot cast `unsafe fn() {owo}` as `bool`
- --> $DIR/cast-as-bool.rs:35:13
+ --> $DIR/cast-as-bool.rs:37:13
|
LL | let _ = owo as bool;
| ^^^^^^^^^^^ unsupported cast
error[E0054]: cannot cast `fn(u8) -> String` as `bool`
- --> $DIR/cast-as-bool.rs:38:13
+ --> $DIR/cast-as-bool.rs:40:13
|
LL | let _ = uwu as fn(u8) -> String as bool;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsupported cast
error[E0054]: cannot cast `char` as `bool`
- --> $DIR/cast-as-bool.rs:40:13
+ --> $DIR/cast-as-bool.rs:42:13
|
LL | let _ = 'x' as bool;
| ^^^^^^^^^^^ unsupported cast
error[E0054]: cannot cast `*const ()` as `bool`
- --> $DIR/cast-as-bool.rs:44:13
+ --> $DIR/cast-as-bool.rs:46:13
|
LL | let _ = ptr as bool;
| ^^^^^^^^^^^ unsupported cast
error[E0606]: casting `&'static str` as `bool` is invalid
- --> $DIR/cast-as-bool.rs:46:13
+ --> $DIR/cast-as-bool.rs:48:13
|
LL | let v = "hello" as bool;
| ^^^^^^^^^^^^^^^
diff --git a/tests/ui/cfg/auxiliary/cfg_false_lib.rs b/tests/ui/cfg/auxiliary/cfg_false_lib.rs
index 6c2dbb4..d1768e6 100644
--- a/tests/ui/cfg/auxiliary/cfg_false_lib.rs
+++ b/tests/ui/cfg/auxiliary/cfg_false_lib.rs
@@ -1,4 +1,4 @@
-// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(FALSE)`.
+// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(false)`.
// This crate has no such attribute, therefore this crate does link to libstd.
-#![cfg(FALSE)]
+#![cfg(false)]
diff --git a/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_after.rs b/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_after.rs
index 3cfa6c5..cd3170f 100644
--- a/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_after.rs
+++ b/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_after.rs
@@ -1,5 +1,5 @@
-// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(FALSE)`.
+// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(false)`.
// Therefore this crate does link to libstd.
-#![cfg(FALSE)]
+#![cfg(false)]
#![no_std]
diff --git a/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_before.rs b/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_before.rs
index a5c14be..ce4e169 100644
--- a/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_before.rs
+++ b/tests/ui/cfg/auxiliary/cfg_false_lib_no_std_before.rs
@@ -1,8 +1,8 @@
-// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(FALSE)`.
+// `#![no_std]` on a fully unconfigured crate is respected if it's placed before `cfg(false)`.
// Therefore this crate doesn't link to libstd.
//@ no-prefer-dynamic
#![no_std]
#![crate_type = "lib"]
-#![cfg(FALSE)]
+#![cfg(false)]
diff --git a/tests/ui/cfg/auxiliary/cfged_out.rs b/tests/ui/cfg/auxiliary/cfged_out.rs
index f6a9089..564280b 100644
--- a/tests/ui/cfg/auxiliary/cfged_out.rs
+++ b/tests/ui/cfg/auxiliary/cfged_out.rs
@@ -1,8 +1,8 @@
pub mod inner {
- #[cfg(FALSE)]
+ #[cfg(false)]
pub fn uwu() {}
- #[cfg(FALSE)]
+ #[cfg(false)]
pub mod doesnt_exist {
pub fn hello() {}
}
diff --git a/tests/ui/cfg/both-true-false.rs b/tests/ui/cfg/both-true-false.rs
new file mode 100644
index 0000000..5fca8f6
--- /dev/null
+++ b/tests/ui/cfg/both-true-false.rs
@@ -0,0 +1,14 @@
+/// Test that placing a `cfg(true)` and `cfg(false)` on the same item result in
+//. it being disabled.`
+
+#[cfg(false)]
+#[cfg(true)]
+fn foo() {}
+
+#[cfg(true)]
+#[cfg(false)]
+fn foo() {}
+
+fn main() {
+ foo(); //~ ERROR cannot find function `foo` in this scope
+}
diff --git a/tests/ui/cfg/both-true-false.stderr b/tests/ui/cfg/both-true-false.stderr
new file mode 100644
index 0000000..1526cc2
--- /dev/null
+++ b/tests/ui/cfg/both-true-false.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find function `foo` in this scope
+ --> $DIR/both-true-false.rs:13:5
+ |
+LL | foo();
+ | ^^^ not found in this scope
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/cfg/cfg-false-feature.rs b/tests/ui/cfg/cfg-false-feature.rs
index 716b184..f66e472 100644
--- a/tests/ui/cfg/cfg-false-feature.rs
+++ b/tests/ui/cfg/cfg-false-feature.rs
@@ -1,10 +1,10 @@
-// Features above `cfg(FALSE)` are in effect in a fully unconfigured crate (issue #104633).
+// Features above `cfg(false)` are in effect in a fully unconfigured crate (issue #104633).
//@ check-pass
//@ compile-flags: --crate-type lib
#![feature(decl_macro)]
-#![cfg(FALSE)]
+#![cfg(false)]
#![feature(box_patterns)]
macro mac() {} // OK
diff --git a/tests/ui/cfg/cfg-macros-notfoo.rs b/tests/ui/cfg/cfg-macros-notfoo.rs
index 9feb06b..c25cf1c 100644
--- a/tests/ui/cfg/cfg-macros-notfoo.rs
+++ b/tests/ui/cfg/cfg-macros-notfoo.rs
@@ -3,7 +3,7 @@
// check that cfg correctly chooses between the macro impls (see also
// cfg-macros-foo.rs)
-#[cfg(FALSE)]
+#[cfg(false)]
#[macro_use]
mod foo {
macro_rules! bar {
diff --git a/tests/ui/cfg/cfg-match-arm.rs b/tests/ui/cfg/cfg-match-arm.rs
index f6cd52c..cb5bf0a 100644
--- a/tests/ui/cfg/cfg-match-arm.rs
+++ b/tests/ui/cfg/cfg-match-arm.rs
@@ -11,7 +11,7 @@ fn foo(f: Foo) {
Foo::Bar => {},
#[cfg(not(FALSE))]
Foo::Baz => {},
- #[cfg(FALSE)]
+ #[cfg(false)]
Basdfwe => {}
}
}
diff --git a/tests/ui/cfg/cfg-stmt-recovery.rs b/tests/ui/cfg/cfg-stmt-recovery.rs
index 2e0839d..f0f9a64 100644
--- a/tests/ui/cfg/cfg-stmt-recovery.rs
+++ b/tests/ui/cfg/cfg-stmt-recovery.rs
@@ -6,7 +6,7 @@
#[cfg_eval]
fn main() {
#[cfg_eval]
- let _ = #[cfg(FALSE)] 0;
+ let _ = #[cfg(false)] 0;
//~^ ERROR removing an expression is not supported in this position
//~| ERROR expected expression, found `;`
//~| ERROR removing an expression is not supported in this position
diff --git a/tests/ui/cfg/cfg-stmt-recovery.stderr b/tests/ui/cfg/cfg-stmt-recovery.stderr
index cb15e21..e34da72 100644
--- a/tests/ui/cfg/cfg-stmt-recovery.stderr
+++ b/tests/ui/cfg/cfg-stmt-recovery.stderr
@@ -1,19 +1,19 @@
error: removing an expression is not supported in this position
--> $DIR/cfg-stmt-recovery.rs:9:13
|
-LL | let _ = #[cfg(FALSE)] 0;
+LL | let _ = #[cfg(false)] 0;
| ^^^^^^^^^^^^^
error: expected expression, found `;`
--> $DIR/cfg-stmt-recovery.rs:9:28
|
-LL | let _ = #[cfg(FALSE)] 0;
+LL | let _ = #[cfg(false)] 0;
| ^ expected expression
error: removing an expression is not supported in this position
--> $DIR/cfg-stmt-recovery.rs:9:13
|
-LL | let _ = #[cfg(FALSE)] 0;
+LL | let _ = #[cfg(false)] 0;
| ^^^^^^^^^^^^^
error: aborting due to 3 previous errors
diff --git a/tests/ui/cfg/cfg_false_no_std-2.rs b/tests/ui/cfg/cfg_false_no_std-2.rs
index 349c494..18b2c69 100644
--- a/tests/ui/cfg/cfg_false_no_std-2.rs
+++ b/tests/ui/cfg/cfg_false_no_std-2.rs
@@ -1,6 +1,6 @@
// Error, the linked empty library is `no_std` and doesn't provide a panic handler.
-//@ dont-require-annotations:ERROR
+//@ dont-require-annotations: ERROR
//@ dont-check-compiler-stderr
//@ aux-build: cfg_false_lib_no_std_before.rs
diff --git a/tests/ui/cfg/cfg_stmt_expr.rs b/tests/ui/cfg/cfg_stmt_expr.rs
index 9245f6d..361b159 100644
--- a/tests/ui/cfg/cfg_stmt_expr.rs
+++ b/tests/ui/cfg/cfg_stmt_expr.rs
@@ -7,47 +7,47 @@
fn main() {
let a = 413;
- #[cfg(FALSE)]
+ #[cfg(false)]
let a = ();
assert_eq!(a, 413);
let mut b = 612;
- #[cfg(FALSE)]
+ #[cfg(false)]
{
b = 1111;
}
assert_eq!(b, 612);
- #[cfg(FALSE)]
+ #[cfg(false)]
undefined_fn();
- #[cfg(FALSE)]
+ #[cfg(false)]
undefined_macro!();
- #[cfg(FALSE)]
+ #[cfg(false)]
undefined_macro![];
- #[cfg(FALSE)]
+ #[cfg(false)]
undefined_macro!{};
// pretty printer bug...
- // #[cfg(FALSE)]
+ // #[cfg(false)]
// undefined_macro!{}
- let () = (#[cfg(FALSE)] 341,); // Should this also work on parens?
- let t = (1, #[cfg(FALSE)] 3, 4);
+ let () = (#[cfg(false)] 341,); // Should this also work on parens?
+ let t = (1, #[cfg(false)] 3, 4);
assert_eq!(t, (1, 4));
let f = |_: u32, _: u32| ();
- f(2, 1, #[cfg(FALSE)] 6);
+ f(2, 1, #[cfg(false)] 6);
- let _: u32 = a.clone(#[cfg(FALSE)] undefined);
+ let _: u32 = a.clone(#[cfg(false)] undefined);
- let _: [(); 0] = [#[cfg(FALSE)] 126];
- let t = [#[cfg(FALSE)] 1, 2, 6];
+ let _: [(); 0] = [#[cfg(false)] 126];
+ let t = [#[cfg(false)] 1, 2, 6];
assert_eq!(t, [2, 6]);
{
let r;
- #[cfg(FALSE)]
+ #[cfg(false)]
(r = 5);
#[cfg(not(FALSE))]
(r = 10);
@@ -75,7 +75,7 @@ macro_rules! if_cfg {
612
});
- assert_eq!((#[cfg(FALSE)] 1, #[cfg(not(FALSE))] 2), (2,));
+ assert_eq!((#[cfg(false)] 1, #[cfg(not(FALSE))] 2), (2,));
assert_eq!(n, 612);
// check that lints work
diff --git a/tests/ui/cfg/cmdline-false.rs b/tests/ui/cfg/cmdline-false.rs
new file mode 100644
index 0000000..d4b7d3b
--- /dev/null
+++ b/tests/ui/cfg/cmdline-false.rs
@@ -0,0 +1,9 @@
+/// Test that `--cfg false` doesn't cause `cfg(false)` to evaluate to `true`
+//@ compile-flags: --cfg false
+
+#[cfg(false)]
+fn foo() {}
+
+fn main() {
+ foo(); //~ ERROR cannot find function `foo` in this scope
+}
diff --git a/tests/ui/cfg/cmdline-false.stderr b/tests/ui/cfg/cmdline-false.stderr
new file mode 100644
index 0000000..5f57c75
--- /dev/null
+++ b/tests/ui/cfg/cmdline-false.stderr
@@ -0,0 +1,9 @@
+error[E0425]: cannot find function `foo` in this scope
+ --> $DIR/cmdline-false.rs:8:5
+ |
+LL | foo();
+ | ^^^ not found in this scope
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0425`.
diff --git a/tests/ui/cfg/conditional-compile.rs b/tests/ui/cfg/conditional-compile.rs
index dff2800..0739e87 100644
--- a/tests/ui/cfg/conditional-compile.rs
+++ b/tests/ui/cfg/conditional-compile.rs
@@ -6,16 +6,16 @@
// Crate use statements
-#[cfg(FALSE)]
+#[cfg(false)]
use flippity;
-#[cfg(FALSE)]
+#[cfg(false)]
static b: bool = false;
static b: bool = true;
mod rustrt {
- #[cfg(FALSE)]
+ #[cfg(false)]
extern "C" {
// This symbol doesn't exist and would be a link error if this
// module was codegened
@@ -25,12 +25,12 @@ mod rustrt {
extern "C" {}
}
-#[cfg(FALSE)]
+#[cfg(false)]
type t = isize;
type t = bool;
-#[cfg(FALSE)]
+#[cfg(false)]
enum tg {
foo,
}
@@ -39,12 +39,12 @@ enum tg {
bar,
}
-#[cfg(FALSE)]
+#[cfg(false)]
struct r {
i: isize,
}
-#[cfg(FALSE)]
+#[cfg(false)]
fn r(i: isize) -> r {
r { i: i }
}
@@ -57,7 +57,7 @@ fn r(i: isize) -> r {
r { i: i }
}
-#[cfg(FALSE)]
+#[cfg(false)]
mod m {
// This needs to parse but would fail in typeck. Since it's not in
// the current config it should not be typechecked.
@@ -69,7 +69,7 @@ pub fn FALSE() {
mod m {
// Submodules have slightly different code paths than the top-level
// module, so let's make sure this jazz works here as well
- #[cfg(FALSE)]
+ #[cfg(false)]
pub fn f() {}
pub fn f() {}
@@ -77,7 +77,7 @@ pub fn f() {}
// Since the FALSE configuration isn't defined main will just be
// parsed, but nothing further will be done with it
-#[cfg(FALSE)]
+#[cfg(false)]
pub fn main() {
panic!()
}
@@ -93,14 +93,14 @@ pub fn main() {
}
fn test_in_fn_ctxt() {
- #[cfg(FALSE)]
+ #[cfg(false)]
fn f() {
panic!()
}
fn f() {}
f();
- #[cfg(FALSE)]
+ #[cfg(false)]
static i: isize = 0;
static i: isize = 1;
assert_eq!(i, 1);
@@ -109,7 +109,7 @@ fn f() {}
mod test_foreign_items {
pub mod rustrt {
extern "C" {
- #[cfg(FALSE)]
+ #[cfg(false)]
pub fn write() -> String;
pub fn write() -> String;
}
@@ -117,7 +117,7 @@ pub mod rustrt {
}
mod test_use_statements {
- #[cfg(FALSE)]
+ #[cfg(false)]
use flippity_foo;
}
@@ -127,24 +127,24 @@ struct Foo {
}
impl Fooable for Foo {
- #[cfg(FALSE)]
+ #[cfg(false)]
fn what(&self) {}
fn what(&self) {}
- #[cfg(FALSE)]
+ #[cfg(false)]
fn the(&self) {}
fn the(&self) {}
}
trait Fooable {
- #[cfg(FALSE)]
+ #[cfg(false)]
fn what(&self);
fn what(&self);
- #[cfg(FALSE)]
+ #[cfg(false)]
fn the(&self);
fn the(&self);
diff --git a/tests/ui/cfg/diagnostics-cross-crate.stderr b/tests/ui/cfg/diagnostics-cross-crate.stderr
index 07ad4e3..3e32a85 100644
--- a/tests/ui/cfg/diagnostics-cross-crate.stderr
+++ b/tests/ui/cfg/diagnostics-cross-crate.stderr
@@ -12,7 +12,7 @@
note: the item is gated here
--> $DIR/auxiliary/cfged_out.rs:5:5
|
-LL | #[cfg(FALSE)]
+LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0425]: cannot find function `uwu` in crate `cfged_out`
@@ -35,7 +35,7 @@
note: the item is gated here
--> $DIR/auxiliary/cfged_out.rs:2:5
|
-LL | #[cfg(FALSE)]
+LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0425]: cannot find function `meow` in module `cfged_out::inner::right`
diff --git a/tests/ui/cfg/diagnostics-reexport.rs b/tests/ui/cfg/diagnostics-reexport.rs
index 9ae7d93..56fac56 100644
--- a/tests/ui/cfg/diagnostics-reexport.rs
+++ b/tests/ui/cfg/diagnostics-reexport.rs
@@ -1,10 +1,10 @@
pub mod inner {
- #[cfg(FALSE)]
+ #[cfg(false)]
mod gone {
pub fn uwu() {}
}
- #[cfg(FALSE)] //~ NOTE the item is gated here
+ #[cfg(false)] //~ NOTE the item is gated here
pub use super::uwu;
//~^ NOTE found an item that was configured out
}
@@ -14,7 +14,7 @@ pub fn uwu() {}
//~| NOTE no `x` in `a`
mod a {
- #[cfg(FALSE)] //~ NOTE the item is gated here
+ #[cfg(false)] //~ NOTE the item is gated here
pub fn x() {}
//~^ NOTE found an item that was configured out
}
@@ -25,10 +25,10 @@ pub fn x() {}
//~| NOTE no `y` in `b`
mod b {
- #[cfg(FALSE)] //~ NOTE the item is gated here
+ #[cfg(false)] //~ NOTE the item is gated here
pub fn x() {}
//~^ NOTE found an item that was configured out
- #[cfg(FALSE)] //~ NOTE the item is gated here
+ #[cfg(false)] //~ NOTE the item is gated here
pub fn y() {}
//~^ NOTE found an item that was configured out
}
diff --git a/tests/ui/cfg/diagnostics-reexport.stderr b/tests/ui/cfg/diagnostics-reexport.stderr
index 737202f..95dc4fa 100644
--- a/tests/ui/cfg/diagnostics-reexport.stderr
+++ b/tests/ui/cfg/diagnostics-reexport.stderr
@@ -12,7 +12,7 @@
note: the item is gated here
--> $DIR/diagnostics-reexport.rs:17:5
|
-LL | #[cfg(FALSE)]
+LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0432]: unresolved imports `b::x`, `b::y`
@@ -31,7 +31,7 @@
note: the item is gated here
--> $DIR/diagnostics-reexport.rs:28:5
|
-LL | #[cfg(FALSE)]
+LL | #[cfg(false)]
| ^^^^^^^^^^^^^
note: found an item that was configured out
--> $DIR/diagnostics-reexport.rs:32:12
@@ -41,7 +41,7 @@
note: the item is gated here
--> $DIR/diagnostics-reexport.rs:31:5
|
-LL | #[cfg(FALSE)]
+LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0425]: cannot find function `uwu` in module `inner`
@@ -58,7 +58,7 @@
note: the item is gated here
--> $DIR/diagnostics-reexport.rs:7:5
|
-LL | #[cfg(FALSE)]
+LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error: aborting due to 3 previous errors
diff --git a/tests/ui/cfg/diagnostics-same-crate.rs b/tests/ui/cfg/diagnostics-same-crate.rs
index d6f8dd2..9153f20 100644
--- a/tests/ui/cfg/diagnostics-same-crate.rs
+++ b/tests/ui/cfg/diagnostics-same-crate.rs
@@ -1,11 +1,11 @@
#![allow(unexpected_cfgs)] // since we want to recognize them as unexpected
pub mod inner {
- #[cfg(FALSE)] //~ NOTE the item is gated here
+ #[cfg(false)] //~ NOTE the item is gated here
pub fn uwu() {}
//~^ NOTE found an item that was configured out
- #[cfg(FALSE)] //~ NOTE the item is gated here
+ #[cfg(false)] //~ NOTE the item is gated here
//~^ NOTE the item is gated here
//~| NOTE the item is gated here
pub mod doesnt_exist {
diff --git a/tests/ui/cfg/diagnostics-same-crate.stderr b/tests/ui/cfg/diagnostics-same-crate.stderr
index dd0d10c..75a1bc3 100644
--- a/tests/ui/cfg/diagnostics-same-crate.stderr
+++ b/tests/ui/cfg/diagnostics-same-crate.stderr
@@ -12,7 +12,7 @@
note: the item is gated here
--> $DIR/diagnostics-same-crate.rs:8:5
|
-LL | #[cfg(FALSE)]
+LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0432]: unresolved import `super::inner::doesnt_exist`
@@ -29,7 +29,7 @@
note: the item is gated here
--> $DIR/diagnostics-same-crate.rs:8:5
|
-LL | #[cfg(FALSE)]
+LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0433]: failed to resolve: could not find `doesnt_exist` in `inner`
@@ -46,7 +46,7 @@
note: the item is gated here
--> $DIR/diagnostics-same-crate.rs:8:5
|
-LL | #[cfg(FALSE)]
+LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0425]: cannot find function `uwu` in module `inner`
@@ -63,7 +63,7 @@
note: the item is gated here
--> $DIR/diagnostics-same-crate.rs:4:5
|
-LL | #[cfg(FALSE)]
+LL | #[cfg(false)]
| ^^^^^^^^^^^^^
error[E0425]: cannot find function `meow` in module `inner::right`
diff --git a/tests/ui/cfg/true-false.rs b/tests/ui/cfg/true-false.rs
index 03d96fb..0bd1cf4 100644
--- a/tests/ui/cfg/true-false.rs
+++ b/tests/ui/cfg/true-false.rs
@@ -1,7 +1,6 @@
//@ run-pass
#![feature(link_cfg)]
-#![feature(cfg_boolean_literals)]
#[cfg(true)]
fn foo() -> bool {
diff --git a/tests/ui/check-cfg/allow-same-level.rs b/tests/ui/check-cfg/allow-same-level.rs
index 8260b57..3f673cb 100644
--- a/tests/ui/check-cfg/allow-same-level.rs
+++ b/tests/ui/check-cfg/allow-same-level.rs
@@ -12,7 +12,7 @@
//@ compile-flags: --check-cfg=cfg() --cfg=unknown_but_active_cfg
#[allow(unexpected_cfgs)]
-#[cfg(FALSE)]
+#[cfg(unknown_and_inactive_cfg)]
//~^ WARNING unexpected `cfg` condition name
fn bar() {}
diff --git a/tests/ui/check-cfg/allow-same-level.stderr b/tests/ui/check-cfg/allow-same-level.stderr
index a705cd4..cfff030 100644
--- a/tests/ui/check-cfg/allow-same-level.stderr
+++ b/tests/ui/check-cfg/allow-same-level.stderr
@@ -1,10 +1,10 @@
-warning: unexpected `cfg` condition name: `FALSE`
+warning: unexpected `cfg` condition name: `unknown_and_inactive_cfg`
--> $DIR/allow-same-level.rs:15:7
|
-LL | #[cfg(FALSE)]
- | ^^^^^
+LL | #[cfg(unknown_and_inactive_cfg)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
|
- = help: to expect this configuration use `--check-cfg=cfg(FALSE)`
+ = help: to expect this configuration use `--check-cfg=cfg(unknown_and_inactive_cfg)`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
= note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/allow-top-level.rs b/tests/ui/check-cfg/allow-top-level.rs
index cf94ed5..7ccecd2 100644
--- a/tests/ui/check-cfg/allow-top-level.rs
+++ b/tests/ui/check-cfg/allow-top-level.rs
@@ -6,7 +6,7 @@
#![allow(unexpected_cfgs)]
-#[cfg(FALSE)]
+#[cfg(false)]
fn bar() {}
fn foo() {
diff --git a/tests/ui/check-cfg/allow-upper-level.rs b/tests/ui/check-cfg/allow-upper-level.rs
index 2e6664c..657a476 100644
--- a/tests/ui/check-cfg/allow-upper-level.rs
+++ b/tests/ui/check-cfg/allow-upper-level.rs
@@ -6,7 +6,7 @@
#[allow(unexpected_cfgs)]
mod aa {
- #[cfg(FALSE)]
+ #[cfg(false)]
fn bar() {}
}
diff --git a/tests/ui/check-cfg/cargo-feature.rs b/tests/ui/check-cfg/cargo-feature.rs
index a9380dd..a02b043 100644
--- a/tests/ui/check-cfg/cargo-feature.rs
+++ b/tests/ui/check-cfg/cargo-feature.rs
@@ -10,7 +10,7 @@
//@ [none]compile-flags: --check-cfg=cfg(feature,values())
//@ [some]compile-flags: --check-cfg=cfg(feature,values("bitcode"))
//@ [some]compile-flags: --check-cfg=cfg(CONFIG_NVME,values("y"))
-//@ [none]error-pattern:Cargo.toml
+//@ dont-require-annotations: HELP
#[cfg(feature = "serde")]
//~^ WARNING unexpected `cfg` condition value
@@ -27,6 +27,7 @@ fn tokio() {}
#[cfg(CONFIG_NVME = "m")]
//[none]~^ WARNING unexpected `cfg` condition name
//[some]~^^ WARNING unexpected `cfg` condition value
+//[none]~| HELP Cargo.toml
fn tokio() {}
fn main() {}
diff --git a/tests/ui/check-cfg/target_feature.stderr b/tests/ui/check-cfg/target_feature.stderr
index aa5fd09..4f7b834 100644
--- a/tests/ui/check-cfg/target_feature.stderr
+++ b/tests/ui/check-cfg/target_feature.stderr
@@ -49,6 +49,7 @@
`avxvnni`
`avxvnniint16`
`avxvnniint8`
+`b`
`backchain`
`bf16`
`bmi1`
@@ -318,17 +319,25 @@
`zbkc`
`zbkx`
`zbs`
+`zca`
+`zcb`
+`zcmop`
`zdinx`
+`zfa`
`zfh`
`zfhmin`
`zfinx`
`zhinx`
`zhinxmin`
+`zicboz`
`zicntr`
+`zicond`
`zicsr`
`zifencei`
+`zihintntl`
`zihintpause`
`zihpm`
+`zimop`
`zk`
`zkn`
`zknd`
@@ -339,6 +348,7 @@
`zksed`
`zksh`
`zkt`
+`ztso`
`zvbb`
`zvbc`
`zve32f`
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index 4636b69..7cda6c2e 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -201,7 +201,7 @@
LL | target_os = "_UNEXPECTED_VALUE",
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
- = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
+ = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -274,7 +274,7 @@
| |
| help: there is a expected value with a similar name: `"linux"`
|
- = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
+ = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
warning: 28 warnings emitted
diff --git a/tests/ui/closures/issue-78720.rs b/tests/ui/closures/issue-78720.rs
index 81af030..a615cdf 100644
--- a/tests/ui/closures/issue-78720.rs
+++ b/tests/ui/closures/issue-78720.rs
@@ -1,5 +1,6 @@
fn server() -> impl {
//~^ ERROR at least one trait must be specified
+ //~^^ ERROR type annotations needed
().map2(|| "")
}
diff --git a/tests/ui/closures/issue-78720.stderr b/tests/ui/closures/issue-78720.stderr
index 90672cd..3e95fab 100644
--- a/tests/ui/closures/issue-78720.stderr
+++ b/tests/ui/closures/issue-78720.stderr
@@ -5,7 +5,7 @@
| ^^^^
error[E0412]: cannot find type `F` in this scope
- --> $DIR/issue-78720.rs:13:12
+ --> $DIR/issue-78720.rs:14:12
|
LL | _func: F,
| ^
@@ -22,8 +22,14 @@
LL | struct Map2<Segment2, F> {
| +++
+error[E0282]: type annotations needed
+ --> $DIR/issue-78720.rs:1:16
+ |
+LL | fn server() -> impl {
+ | ^^^^ cannot infer type
+
error[E0308]: mismatched types
- --> $DIR/issue-78720.rs:7:39
+ --> $DIR/issue-78720.rs:8:39
|
LL | fn map2<F>(self, f: F) -> Map2<F> {}
| ^^ expected `Map2<F>`, found `()`
@@ -32,7 +38,7 @@
found unit type `()`
error[E0277]: the size for values of type `Self` cannot be known at compilation time
- --> $DIR/issue-78720.rs:7:16
+ --> $DIR/issue-78720.rs:8:16
|
LL | fn map2<F>(self, f: F) -> Map2<F> {}
| ^^^^ doesn't have a size known at compile-time
@@ -47,7 +53,7 @@
LL | fn map2<F>(&self, f: F) -> Map2<F> {}
| +
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
-Some errors have detailed explanations: E0277, E0308, E0412.
+Some errors have detailed explanations: E0277, E0282, E0308, E0412.
For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/codegen/empty-static-libs-issue-108825.rs b/tests/ui/codegen/empty-static-libs-issue-108825.rs
index 46bd6d6..4c644be 100644
--- a/tests/ui/codegen/empty-static-libs-issue-108825.rs
+++ b/tests/ui/codegen/empty-static-libs-issue-108825.rs
@@ -3,7 +3,6 @@
//@ compile-flags: -Cpanic=abort --print=native-static-libs
//@ build-pass
-//@ error-pattern: note: native-static-libs:
//@ dont-check-compiler-stderr (libcore links `/defaultlib:msvcrt` or `/defaultlib:libcmt` on MSVC)
//@ ignore-pass (the note is emitted later in the compilation pipeline, needs build)
@@ -14,3 +13,6 @@
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}
+
+//~? NOTE native-static-libs:
+//~? NOTE Link against the following native artifacts when linking against this static library
diff --git a/tests/ui/codegen/overflow-during-mono.rs b/tests/ui/codegen/overflow-during-mono.rs
index 83a8b6b..a904584 100644
--- a/tests/ui/codegen/overflow-during-mono.rs
+++ b/tests/ui/codegen/overflow-during-mono.rs
@@ -1,4 +1,4 @@
-//~ ERROR overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized`
+//~ ERROR overflow evaluating the requirement `for<'a> {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: FnMut(&'a _)`
//@ build-fail
#![recursion_limit = "32"]
diff --git a/tests/ui/codegen/overflow-during-mono.stderr b/tests/ui/codegen/overflow-during-mono.stderr
index f7a3e2d..74d98fd 100644
--- a/tests/ui/codegen/overflow-during-mono.stderr
+++ b/tests/ui/codegen/overflow-during-mono.stderr
@@ -1,4 +1,4 @@
-error[E0275]: overflow evaluating the requirement `{closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: Sized`
+error[E0275]: overflow evaluating the requirement `for<'a> {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}: FnMut(&'a _)`
|
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "64"]` attribute to your crate (`overflow_during_mono`)
= note: required for `Filter<std::array::IntoIter<i32, 11>, {closure@$DIR/overflow-during-mono.rs:13:41: 13:44}>` to implement `Iterator`
diff --git a/tests/ui/codegen/ref-dyn-trait-in-structs-and-enums.rs b/tests/ui/codegen/ref-dyn-trait-in-structs-and-enums.rs
new file mode 100644
index 0000000..0454881
--- /dev/null
+++ b/tests/ui/codegen/ref-dyn-trait-in-structs-and-enums.rs
@@ -0,0 +1,54 @@
+//! Regression test for an LLVM assertion that used to be hit when:
+//!
+//! - There's a generic enum contained within a tuple struct
+//! - When the tuple struct is parameterized by some lifetime `'a`
+//! - The enum is concretized with its type argument being a reference to a trait object (of
+//! lifetime `'a`)
+//!
+//! Issue: <https://github.com/rust-lang/rust/issues/9719>
+
+//@ build-pass
+
+// Dummy trait implemented for `isize` to use in the test cases
+pub trait MyTrait {
+ fn dummy(&self) {}
+}
+impl MyTrait for isize {}
+
+// `&dyn MyTrait` contained in enum variant
+pub struct EnumRefDynTrait<'a>(Enum<&'a (dyn MyTrait + 'a)>);
+pub enum Enum<T> {
+ Variant(T),
+}
+
+fn enum_dyn_trait() {
+ let x: isize = 42;
+ let y = EnumRefDynTrait(Enum::Variant(&x as &dyn MyTrait));
+ let _ = y;
+}
+
+// `&dyn MyTrait` contained behind `Option` in named field of struct
+struct RefDynTraitNamed<'a> {
+ x: Option<&'a (dyn MyTrait + 'a)>,
+}
+
+fn named_option_dyn_trait() {
+ let x: isize = 42;
+ let y = RefDynTraitNamed { x: Some(&x as &dyn MyTrait) };
+ let _ = y;
+}
+
+// `&dyn MyTrait` contained behind `Option` in unnamed field of struct
+pub struct RefDynTraitUnnamed<'a>(Option<&'a (dyn MyTrait + 'a)>);
+
+fn unnamed_option_dyn_trait() {
+ let x: isize = 42;
+ let y = RefDynTraitUnnamed(Some(&x as &dyn MyTrait));
+ let _ = y;
+}
+
+pub fn main() {
+ enum_dyn_trait();
+ named_option_dyn_trait();
+ unnamed_option_dyn_trait();
+}
diff --git a/tests/ui/codemap_tests/two_files_data.rs b/tests/ui/codemap_tests/two_files_data.rs
index a4e4cf7..82852f6 100644
--- a/tests/ui/codemap_tests/two_files_data.rs
+++ b/tests/ui/codemap_tests/two_files_data.rs
@@ -1,4 +1,4 @@
-//@ ignore-test (auxiliary, used by other tests)
+//@ ignore-auxiliary (used by `./two_files.rs`)
trait Foo { }
diff --git a/tests/ui/codemap_tests/unicode.expanded.stdout b/tests/ui/codemap_tests/unicode.expanded.stdout
index eb53d12..c88035d 100644
--- a/tests/ui/codemap_tests/unicode.expanded.stdout
+++ b/tests/ui/codemap_tests/unicode.expanded.stdout
@@ -7,6 +7,7 @@
//@ revisions: normal expanded
//@[expanded] check-pass
//@[expanded]compile-flags: -Zunpretty=expanded
+//@ edition: 2015
extern "路濫狼á́́" fn foo() {}
diff --git a/tests/ui/codemap_tests/unicode.normal.stderr b/tests/ui/codemap_tests/unicode.normal.stderr
index 0f254e0..10cb34f 100644
--- a/tests/ui/codemap_tests/unicode.normal.stderr
+++ b/tests/ui/codemap_tests/unicode.normal.stderr
@@ -1,5 +1,5 @@
error[E0703]: invalid ABI: found `路濫狼á́́`
- --> $DIR/unicode.rs:5:8
+ --> $DIR/unicode.rs:6:8
|
LL | extern "路濫狼á́́" fn foo() {}
| ^^^^^^^^^ invalid ABI
diff --git a/tests/ui/codemap_tests/unicode.rs b/tests/ui/codemap_tests/unicode.rs
index 73023e3..4b93ef0 100644
--- a/tests/ui/codemap_tests/unicode.rs
+++ b/tests/ui/codemap_tests/unicode.rs
@@ -1,6 +1,7 @@
//@ revisions: normal expanded
//@[expanded] check-pass
//@[expanded]compile-flags: -Zunpretty=expanded
+//@ edition: 2015
extern "路濫狼á́́" fn foo() {} //[normal]~ ERROR invalid ABI
diff --git a/tests/ui/coercion/codegen-smart-pointer-with-alias.rs b/tests/ui/coercion/codegen-smart-pointer-with-alias.rs
new file mode 100644
index 0000000..a68952b
--- /dev/null
+++ b/tests/ui/coercion/codegen-smart-pointer-with-alias.rs
@@ -0,0 +1,32 @@
+//@ build-pass
+
+// Regression test for <https://github.com/rust-lang/rust/issues/139812>.
+
+// Make sure that the unsize coercion we collect in mono for `Signal<i32> -> Signal<dyn Any>`
+// doesn't choke on the fact that the inner unsized field of `Signal<T>` is a (trivial) alias.
+// This exercises a normalize call that is necessary since we're getting a type from the type
+// system, which isn't guaranteed to be normalized after substitution.
+
+#![feature(coerce_unsized)]
+
+use std::ops::CoerceUnsized;
+
+trait Mirror {
+ type Assoc: ?Sized;
+}
+impl<T: ?Sized> Mirror for T {
+ type Assoc = T;
+}
+
+trait Any {}
+impl<T> Any for T {}
+
+struct Signal<'a, T: ?Sized>(<&'a T as Mirror>::Assoc);
+
+// This `CoerceUnsized` impl isn't special; it's a bit more restricted than we'd see in the wild,
+// but this ICE also reproduces if we were to make it general over `Signal<T> -> Signal<U>`.
+impl<'a> CoerceUnsized<Signal<'a, dyn Any>> for Signal<'a, i32> {}
+
+fn main() {
+ Signal(&1i32) as Signal<dyn Any>;
+}
diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs
index cd181f4..28d2d26 100644
--- a/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs
+++ b/tests/ui/conditional-compilation/cfg-arg-invalid-1.rs
@@ -1,3 +1,5 @@
-//@ compile-flags: --error-format=human --cfg a(b=c)
-//@ error-pattern: invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\")
+//@ compile-flags: --cfg a(b=c)
+
fn main() {}
+
+//~? ERROR invalid `--cfg` argument: `a(b=c)` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\")
diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs
index a0c16bd..a460226 100644
--- a/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs
+++ b/tests/ui/conditional-compilation/cfg-arg-invalid-2.rs
@@ -1,3 +1,5 @@
-//@ compile-flags: --error-format=human --cfg a{b}
-//@ error-pattern: invalid `--cfg` argument: `a{b}` (expected `key` or `key="value"`)
+//@ compile-flags: --cfg a{b}
+
fn main() {}
+
+//~? ERROR invalid `--cfg` argument: `a{b}` (expected `key` or `key="value"`)
diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs
index 30402d5..ba34708 100644
--- a/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs
+++ b/tests/ui/conditional-compilation/cfg-arg-invalid-4.rs
@@ -1,3 +1,5 @@
-//@ compile-flags: --error-format=human --cfg a(b)
-//@ error-pattern: invalid `--cfg` argument: `a(b)` (expected `key` or `key="value"`)
+//@ compile-flags: --cfg a(b)
+
fn main() {}
+
+//~? ERROR invalid `--cfg` argument: `a(b)` (expected `key` or `key="value"`)
diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs
index e0ce66e..2c2fc10 100644
--- a/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs
+++ b/tests/ui/conditional-compilation/cfg-arg-invalid-6.rs
@@ -1,3 +1,5 @@
-//@ compile-flags: --error-format=human --cfg a{
-//@ error-pattern: invalid `--cfg` argument: `a{` (expected `key` or `key="value"`)
+//@ compile-flags: --cfg a{
+
fn main() {}
+
+//~? ERROR invalid `--cfg` argument: `a{` (expected `key` or `key="value"`)
diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs
index 33f8da2..c9185fc 100644
--- a/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs
+++ b/tests/ui/conditional-compilation/cfg-arg-invalid-8.rs
@@ -1,3 +1,5 @@
-//@ compile-flags: --error-format=human --cfg )
-//@ error-pattern: invalid `--cfg` argument: `)` (expected `key` or `key="value"`)
+//@ compile-flags: --cfg )
+
fn main() {}
+
+//~? ERROR invalid `--cfg` argument: `)` (expected `key` or `key="value"`)
diff --git a/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs b/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs
index 8ab3b10..8d07165 100644
--- a/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs
+++ b/tests/ui/conditional-compilation/cfg-arg-invalid-9.rs
@@ -1,4 +1,6 @@
// Test for missing quotes around value, issue #66450.
-//@ compile-flags: --error-format=human --cfg key=value
-//@ error-pattern: invalid `--cfg` argument: `key=value` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\")
+//@ compile-flags: --cfg key=value
+
fn main() {}
+
+//~? ERROR invalid `--cfg` argument: `key=value` (expected `key` or `key="value"`, ensure escaping is appropriate for your shell, try 'key="value"' or key=\"value\")
diff --git a/tests/ui/conditional-compilation/cfg-empty-codemap.rs b/tests/ui/conditional-compilation/cfg-empty-codemap.rs
index d8fc027..9f7ef1b 100644
--- a/tests/ui/conditional-compilation/cfg-empty-codemap.rs
+++ b/tests/ui/conditional-compilation/cfg-empty-codemap.rs
@@ -1,8 +1,8 @@
// Tests that empty source_maps don't ICE (#23301)
-//@ compile-flags: --error-format=human --cfg ""
-
-//@ error-pattern: invalid `--cfg` argument: `""` (expected `key` or `key="value"`)
+//@ compile-flags: --cfg ""
pub fn main() {
}
+
+//~? ERROR invalid `--cfg` argument: `""` (expected `key` or `key="value"`)
diff --git a/tests/ui/conditional-compilation/cfg-generic-params.rs b/tests/ui/conditional-compilation/cfg-generic-params.rs
index 4bb8f8a..6480a0f 100644
--- a/tests/ui/conditional-compilation/cfg-generic-params.rs
+++ b/tests/ui/conditional-compilation/cfg-generic-params.rs
@@ -1,18 +1,18 @@
//@ compile-flags:--cfg yes --check-cfg=cfg(yes,no)
-fn f_lt<#[cfg(yes)] 'a: 'a, #[cfg(FALSE)] T>() {}
-fn f_ty<#[cfg(FALSE)] 'a: 'a, #[cfg(yes)] T>() {}
+fn f_lt<#[cfg(yes)] 'a: 'a, #[cfg(false)] T>() {}
+fn f_ty<#[cfg(false)] 'a: 'a, #[cfg(yes)] T>() {}
-type FnGood = for<#[cfg(yes)] 'a, #[cfg(FALSE)] T> fn(); // OK
-type FnBad = for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> fn();
+type FnGood = for<#[cfg(yes)] 'a, #[cfg(false)] T> fn(); // OK
+type FnBad = for<#[cfg(false)] 'a, #[cfg(yes)] T> fn();
//~^ ERROR only lifetime parameters can be used in this context
-type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(FALSE)] T> Copy; // OK
-type PolyBad = dyn for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> Copy;
+type PolyGood = dyn for<#[cfg(yes)] 'a, #[cfg(false)] T> Copy; // OK
+type PolyBad = dyn for<#[cfg(false)] 'a, #[cfg(yes)] T> Copy;
//~^ ERROR only lifetime parameters can be used in this context
-struct WhereGood where for<#[cfg(yes)] 'a, #[cfg(FALSE)] T> u8: Copy; // OK
-struct WhereBad where for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> u8: Copy;
+struct WhereGood where for<#[cfg(yes)] 'a, #[cfg(false)] T> u8: Copy; // OK
+struct WhereBad where for<#[cfg(false)] 'a, #[cfg(yes)] T> u8: Copy;
//~^ ERROR only lifetime parameters can be used in this context
fn f_lt_no<#[cfg_attr(FALSE, unknown)] 'a>() {} // OK
diff --git a/tests/ui/conditional-compilation/cfg-generic-params.stderr b/tests/ui/conditional-compilation/cfg-generic-params.stderr
index 563616b..bae75dd 100644
--- a/tests/ui/conditional-compilation/cfg-generic-params.stderr
+++ b/tests/ui/conditional-compilation/cfg-generic-params.stderr
@@ -31,7 +31,7 @@
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:7:48
|
-LL | type FnBad = for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> fn();
+LL | type FnBad = for<#[cfg(false)] 'a, #[cfg(yes)] T> fn();
| ^
|
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
@@ -41,7 +41,7 @@
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:11:54
|
-LL | type PolyBad = dyn for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> Copy;
+LL | type PolyBad = dyn for<#[cfg(false)] 'a, #[cfg(yes)] T> Copy;
| ^
|
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
@@ -51,7 +51,7 @@
error[E0658]: only lifetime parameters can be used in this context
--> $DIR/cfg-generic-params.rs:15:57
|
-LL | struct WhereBad where for<#[cfg(FALSE)] 'a, #[cfg(yes)] T> u8: Copy;
+LL | struct WhereBad where for<#[cfg(false)] 'a, #[cfg(yes)] T> u8: Copy;
| ^
|
= note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information
diff --git a/tests/ui/conditional-compilation/cfg-in-crate-1.rs b/tests/ui/conditional-compilation/cfg-in-crate-1.rs
index a1faa23..b9efa32 100644
--- a/tests/ui/conditional-compilation/cfg-in-crate-1.rs
+++ b/tests/ui/conditional-compilation/cfg-in-crate-1.rs
@@ -1 +1 @@
-#![cfg(FALSE)] //~ ERROR `main` function not found in crate `cfg_in_crate_1`
+#![cfg(false)] //~ ERROR `main` function not found in crate `cfg_in_crate_1`
diff --git a/tests/ui/conditional-compilation/cfg-in-crate-1.stderr b/tests/ui/conditional-compilation/cfg-in-crate-1.stderr
index 126e10cf..352baf3 100644
--- a/tests/ui/conditional-compilation/cfg-in-crate-1.stderr
+++ b/tests/ui/conditional-compilation/cfg-in-crate-1.stderr
@@ -1,7 +1,7 @@
error[E0601]: `main` function not found in crate `cfg_in_crate_1`
--> $DIR/cfg-in-crate-1.rs:1:15
|
-LL | #![cfg(FALSE)]
+LL | #![cfg(false)]
| ^ consider adding a `main` function to `$DIR/cfg-in-crate-1.rs`
error: aborting due to 1 previous error
diff --git a/tests/ui/conditional-compilation/cfg-non-opt-expr.rs b/tests/ui/conditional-compilation/cfg-non-opt-expr.rs
index ae85f38..cae07ae 100644
--- a/tests/ui/conditional-compilation/cfg-non-opt-expr.rs
+++ b/tests/ui/conditional-compilation/cfg-non-opt-expr.rs
@@ -2,10 +2,10 @@
#![feature(custom_test_frameworks)]
fn main() {
- let _ = #[cfg(FALSE)] ();
+ let _ = #[cfg(false)] ();
//~^ ERROR removing an expression is not supported in this position
- let _ = 1 + 2 + #[cfg(FALSE)] 3;
+ let _ = 1 + 2 + #[cfg(false)] 3;
//~^ ERROR removing an expression is not supported in this position
- let _ = [1, 2, 3][#[cfg(FALSE)] 1];
+ let _ = [1, 2, 3][#[cfg(false)] 1];
//~^ ERROR removing an expression is not supported in this position
}
diff --git a/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr b/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr
index 06eaa59..bd1bfeb 100644
--- a/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr
+++ b/tests/ui/conditional-compilation/cfg-non-opt-expr.stderr
@@ -1,19 +1,19 @@
error: removing an expression is not supported in this position
--> $DIR/cfg-non-opt-expr.rs:5:13
|
-LL | let _ = #[cfg(FALSE)] ();
+LL | let _ = #[cfg(false)] ();
| ^^^^^^^^^^^^^
error: removing an expression is not supported in this position
--> $DIR/cfg-non-opt-expr.rs:7:21
|
-LL | let _ = 1 + 2 + #[cfg(FALSE)] 3;
+LL | let _ = 1 + 2 + #[cfg(false)] 3;
| ^^^^^^^^^^^^^
error: removing an expression is not supported in this position
--> $DIR/cfg-non-opt-expr.rs:9:23
|
-LL | let _ = [1, 2, 3][#[cfg(FALSE)] 1];
+LL | let _ = [1, 2, 3][#[cfg(false)] 1];
| ^^^^^^^^^^^^^
error: aborting due to 3 previous errors
diff --git a/tests/ui/conditional-compilation/module_with_cfg.rs b/tests/ui/conditional-compilation/module_with_cfg.rs
index 778379f..a96f8a3 100644
--- a/tests/ui/conditional-compilation/module_with_cfg.rs
+++ b/tests/ui/conditional-compilation/module_with_cfg.rs
@@ -1,3 +1,3 @@
-//@ ignore-test (auxiliary, used by other tests)
+//@ ignore-auxiliary (used by `./inner-cfg-non-inline-mod.rs`)
-#![cfg_attr(all(), cfg(FALSE))]
+#![cfg_attr(all(), cfg(false))]
diff --git a/tests/ui/const-generics/defaults/pretty-printing-ast.rs b/tests/ui/const-generics/defaults/pretty-printing-ast.rs
index 20bf900..f7a166d 100644
--- a/tests/ui/const-generics/defaults/pretty-printing-ast.rs
+++ b/tests/ui/const-generics/defaults/pretty-printing-ast.rs
@@ -1,6 +1,7 @@
// Test the AST pretty printer correctly handles default values for const generics
//@ check-pass
//@ compile-flags: -Z unpretty=expanded
+//@ edition: 2015
#![crate_type = "lib"]
diff --git a/tests/ui/const-generics/defaults/pretty-printing-ast.stdout b/tests/ui/const-generics/defaults/pretty-printing-ast.stdout
index f1cd145..b6cb7fa 100644
--- a/tests/ui/const-generics/defaults/pretty-printing-ast.stdout
+++ b/tests/ui/const-generics/defaults/pretty-printing-ast.stdout
@@ -3,6 +3,7 @@
// Test the AST pretty printer correctly handles default values for const generics
//@ check-pass
//@ compile-flags: -Z unpretty=expanded
+//@ edition: 2015
#![crate_type = "lib"]
#[prelude_import]
diff --git a/tests/ui/const-generics/generic_const_exprs/const-generics-closure.rs b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.rs
new file mode 100644
index 0000000..aad8cef
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.rs
@@ -0,0 +1,13 @@
+// Regression test for issue #127424
+
+fn bar() -> impl Into<
+ [u8; {
+ //~^ ERROR mismatched types [E0308]
+ let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { *x };
+ //~^ ERROR `for<...>` binders for closures are experimental [E0658]
+ }],
+> {
+ [89]
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/generic_const_exprs/const-generics-closure.stderr b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.stderr
new file mode 100644
index 0000000..5410bbd
--- /dev/null
+++ b/tests/ui/const-generics/generic_const_exprs/const-generics-closure.stderr
@@ -0,0 +1,26 @@
+error[E0658]: `for<...>` binders for closures are experimental
+ --> $DIR/const-generics-closure.rs:6:17
+ |
+LL | let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { *x };
+ | ^^^^^^^^^^^
+ |
+ = note: see issue #97362 <https://github.com/rust-lang/rust/issues/97362> for more information
+ = help: add `#![feature(closure_lifetime_binder)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+ = help: consider removing `for<...>`
+
+error[E0308]: mismatched types
+ --> $DIR/const-generics-closure.rs:4:10
+ |
+LL | [u8; {
+ | __________^
+LL | |
+LL | | let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { *x };
+LL | |
+LL | | }],
+ | |_____^ expected `usize`, found `()`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0658.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/consts/const-blocks/const-block-in-array-size.rs b/tests/ui/consts/const-blocks/const-block-in-array-size.rs
new file mode 100644
index 0000000..ecab2432
--- /dev/null
+++ b/tests/ui/consts/const-blocks/const-block-in-array-size.rs
@@ -0,0 +1,5 @@
+//@ check-pass
+
+type A = [u32; const { 2 }];
+
+fn main() {}
diff --git a/tests/ui/consts/const-cast-wrong-type.rs b/tests/ui/consts/const-cast-wrong-type.rs
index 6e055a2..9936a66 100644
--- a/tests/ui/consts/const-cast-wrong-type.rs
+++ b/tests/ui/consts/const-cast-wrong-type.rs
@@ -1,5 +1,5 @@
const a: [u8; 3] = ['h' as u8, 'i' as u8, 0 as u8];
-const b: *const i8 = &a as *const i8; //~ ERROR mismatched types
+const b: *const i8 = &a as *const i8; //~ ERROR casting `&[u8; 3]` as `*const i8` is invalid
fn main() {
}
diff --git a/tests/ui/consts/const-cast-wrong-type.stderr b/tests/ui/consts/const-cast-wrong-type.stderr
index 44361f1..0730bac 100644
--- a/tests/ui/consts/const-cast-wrong-type.stderr
+++ b/tests/ui/consts/const-cast-wrong-type.stderr
@@ -1,9 +1,9 @@
-error[E0308]: mismatched types
+error[E0606]: casting `&[u8; 3]` as `*const i8` is invalid
--> $DIR/const-cast-wrong-type.rs:2:22
|
LL | const b: *const i8 = &a as *const i8;
- | ^^^^^^^^^^^^^^^ expected `u8`, found `i8`
+ | ^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0606`.
diff --git a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs
index 7ced248..5072897 100644
--- a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs
+++ b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier-2.rs
@@ -1,6 +1,6 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn container() {
const unsafe WhereIsFerris Now() {}
//~^ ERROR expected one of `extern` or `fn`
diff --git a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs
index 6f575d0..20e79ca 100644
--- a/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs
+++ b/tests/ui/consts/const-extern-fn/issue-68062-const-extern-fns-dont-need-fn-specifier.rs
@@ -1,6 +1,6 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn container() {
const extern "Rust" PUT_ANYTHING_YOU_WANT_HERE bug() -> usize { 1 }
//~^ ERROR expected `fn`
diff --git a/tests/ui/consts/miri_unleashed/drop.rs b/tests/ui/consts/miri_unleashed/drop.rs
index 17d0892..190072d 100644
--- a/tests/ui/consts/miri_unleashed/drop.rs
+++ b/tests/ui/consts/miri_unleashed/drop.rs
@@ -1,5 +1,4 @@
//@ compile-flags: -Zunleash-the-miri-inside-of-you
-//@ error-pattern: calling non-const function `<Vec<i32> as Drop>::drop`
use std::mem::ManuallyDrop;
@@ -15,5 +14,7 @@ fn main() {}
static TEST_BAD: () = {
let _v: Vec<i32> = Vec::new();
}; //~ ERROR could not evaluate static initializer
+ //~| NOTE calling non-const function `<Vec<i32> as Drop>::drop`
+ //~| NOTE inside `std::ptr::drop_in_place::<Vec<i32>> - shim(Some(Vec<i32>))`
//~? WARN skipping const checks
diff --git a/tests/ui/consts/miri_unleashed/drop.stderr b/tests/ui/consts/miri_unleashed/drop.stderr
index 40a29d5..f9ff549 100644
--- a/tests/ui/consts/miri_unleashed/drop.stderr
+++ b/tests/ui/consts/miri_unleashed/drop.stderr
@@ -1,5 +1,5 @@
error[E0080]: could not evaluate static initializer
- --> $DIR/drop.rs:17:1
+ --> $DIR/drop.rs:16:1
|
LL | };
| ^ calling non-const function `<Vec<i32> as Drop>::drop`
@@ -10,7 +10,7 @@
warning: skipping const checks
|
help: skipping check that does not even have a feature gate
- --> $DIR/drop.rs:16:9
+ --> $DIR/drop.rs:15:9
|
LL | let _v: Vec<i32> = Vec::new();
| ^^
diff --git a/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr
index 4a47671..b6f2e01 100644
--- a/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr
+++ b/tests/ui/contracts/contract-captures-via-closure-noncopy.stderr
@@ -16,6 +16,7 @@
| | within this `{closure@$DIR/contract-captures-via-closure-noncopy.rs:12:42: 12:57}`
| | this tail expression is of type `{closure@contract-captures-via-closure-noncopy.rs:12:42}`
| unsatisfied trait bound
+ | required by a bound introduced by this call
|
= help: within `{closure@$DIR/contract-captures-via-closure-noncopy.rs:12:42: 12:57}`, the trait `std::marker::Copy` is not implemented for `Baz`
note: required because it's used within this closure
diff --git a/tests/ui/contracts/contract-const-fn.all_pass.stderr b/tests/ui/contracts/contract-const-fn.all_pass.stderr
new file mode 100644
index 0000000..e5b1df6
--- /dev/null
+++ b/tests/ui/contracts/contract-const-fn.all_pass.stderr
@@ -0,0 +1,11 @@
+warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/contract-const-fn.rs:17:12
+ |
+LL | #![feature(contracts)]
+ | ^^^^^^^^^
+ |
+ = note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/contracts/contract-const-fn.rs b/tests/ui/contracts/contract-const-fn.rs
new file mode 100644
index 0000000..733a06a
--- /dev/null
+++ b/tests/ui/contracts/contract-const-fn.rs
@@ -0,0 +1,56 @@
+//! Check if we can annotate a constant function with contracts.
+//!
+//! The contract is only checked at runtime, and it will not fail if evaluated statically.
+//! This is an existing limitation due to the existing architecture and the lack of constant
+//! closures.
+//!
+//@ revisions: all_pass runtime_fail_pre runtime_fail_post
+//
+//@ [all_pass] run-pass
+//
+//@ [runtime_fail_pre] run-fail
+//@ [runtime_fail_post] run-fail
+//
+//@ [all_pass] compile-flags: -Zcontract-checks=yes
+//@ [runtime_fail_pre] compile-flags: -Zcontract-checks=yes
+//@ [runtime_fail_post] compile-flags: -Zcontract-checks=yes
+#![feature(contracts)]
+//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
+
+extern crate core;
+use core::contracts::*;
+
+#[requires(x < 100)]
+const fn less_than_100(x: u8) -> u8 {
+ x
+}
+
+// This is wrong on purpose.
+#[ensures(|ret| *ret)]
+const fn always_true(b: bool) -> bool {
+ b
+}
+
+const ZERO: u8 = less_than_100(0);
+// This is no-op because the contract cannot be checked at compilation time.
+const TWO_HUNDRED: u8 = less_than_100(200);
+
+/// Example from <https://github.com/rust-lang/rust/issues/136925>.
+#[ensures(move |ret: &u32| *ret > x)]
+const fn broken_sum(x: u32, y: u32) -> u32 {
+ x + y
+}
+
+fn main() {
+ assert_eq!(ZERO, 0);
+ assert_eq!(TWO_HUNDRED, 200);
+ assert_eq!(broken_sum(0, 1), 1);
+ assert_eq!(always_true(true), true);
+
+ #[cfg(runtime_fail_post)]
+ let _ok = always_true(false);
+
+ // Runtime check should fail.
+ #[cfg(runtime_fail_pre)]
+ let _200 = less_than_100(200);
+}
diff --git a/tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr b/tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr
new file mode 100644
index 0000000..e5b1df6
--- /dev/null
+++ b/tests/ui/contracts/contract-const-fn.runtime_fail_post.stderr
@@ -0,0 +1,11 @@
+warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/contract-const-fn.rs:17:12
+ |
+LL | #![feature(contracts)]
+ | ^^^^^^^^^
+ |
+ = note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr b/tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr
new file mode 100644
index 0000000..e5b1df6
--- /dev/null
+++ b/tests/ui/contracts/contract-const-fn.runtime_fail_pre.stderr
@@ -0,0 +1,11 @@
+warning: the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/contract-const-fn.rs:17:12
+ |
+LL | #![feature(contracts)]
+ | ^^^^^^^^^
+ |
+ = note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
+ = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs
index ae692af..c62b8cc 100644
--- a/tests/ui/contracts/internal_machinery/contract-intrinsics.rs
+++ b/tests/ui/contracts/internal_machinery/contract-intrinsics.rs
@@ -26,11 +26,11 @@ fn main() {
#[cfg(any(default, unchk_pass, chk_fail_requires))]
core::intrinsics::contract_check_requires(|| false);
- let doubles_to_two = { let old = 2; move |ret| ret + ret == old };
+ let doubles_to_two = { let old = 2; move |ret: &u32 | ret + ret == old };
// Always pass
- core::intrinsics::contract_check_ensures(&1, doubles_to_two);
+ core::intrinsics::contract_check_ensures(doubles_to_two, 1);
// Fail if enabled
#[cfg(any(default, unchk_pass, chk_fail_ensures))]
- core::intrinsics::contract_check_ensures(&2, doubles_to_two);
+ core::intrinsics::contract_check_ensures(doubles_to_two, 2);
}
diff --git a/tests/ui/contracts/internal_machinery/contract-lang-items.rs b/tests/ui/contracts/internal_machinery/contract-lang-items.rs
index e91bbed..73c5919 100644
--- a/tests/ui/contracts/internal_machinery/contract-lang-items.rs
+++ b/tests/ui/contracts/internal_machinery/contract-lang-items.rs
@@ -15,14 +15,14 @@
#![feature(contracts)] // to access core::contracts
//~^ WARN the feature `contracts` is incomplete and may not be safe to use and/or cause compiler crashes [incomplete_features]
#![feature(contracts_internals)] // to access check_requires lang item
-
+#![feature(core_intrinsics)]
fn foo(x: Baz) -> i32 {
let injected_checker = {
core::contracts::build_check_ensures(|ret| *ret > 100)
};
let ret = x.baz + 50;
- injected_checker(ret)
+ core::intrinsics::contract_check_ensures(injected_checker, ret)
}
struct Baz { baz: i32 }
diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs
index 1b76eef..6e5a7a3 100644
--- a/tests/ui/contracts/internal_machinery/internal-feature-gating.rs
+++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.rs
@@ -6,7 +6,7 @@ fn main() {
//~^ ERROR use of unstable library feature `contracts_internals`
core::intrinsics::contract_check_requires(|| true);
//~^ ERROR use of unstable library feature `contracts_internals`
- core::intrinsics::contract_check_ensures(&1, |_|true);
+ core::intrinsics::contract_check_ensures( |_|true, &1);
//~^ ERROR use of unstable library feature `contracts_internals`
core::contracts::build_check_ensures(|_: &()| true);
diff --git a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr
index 7302694..1e39bd6 100644
--- a/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr
+++ b/tests/ui/contracts/internal_machinery/internal-feature-gating.stderr
@@ -41,7 +41,7 @@
error[E0658]: use of unstable library feature `contracts_internals`
--> $DIR/internal-feature-gating.rs:9:5
|
-LL | core::intrinsics::contract_check_ensures(&1, |_|true);
+LL | core::intrinsics::contract_check_ensures( |_|true, &1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #128044 <https://github.com/rust-lang/rust/issues/128044> for more information
diff --git a/tests/ui/coroutine/clone-rpit.next.stderr b/tests/ui/coroutine/clone-rpit.next.stderr
deleted file mode 100644
index 213e9e9..0000000
--- a/tests/ui/coroutine/clone-rpit.next.stderr
+++ /dev/null
@@ -1,47 +0,0 @@
-error[E0391]: cycle detected when type-checking `foo`
- --> $DIR/clone-rpit.rs:13:1
- |
-LL | pub fn foo<'a, 'b>() -> impl Clone {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: ...which requires coroutine witness types for `foo::{closure#0}`...
- --> $DIR/clone-rpit.rs:15:5
- |
-LL | move |_: ()| {
- | ^^^^^^^^^^^^
-note: ...which requires promoting constants in MIR for `foo::{closure#0}`...
- --> $DIR/clone-rpit.rs:15:5
- |
-LL | move |_: ()| {
- | ^^^^^^^^^^^^
-note: ...which requires checking if `foo::{closure#0}` contains FFI-unwind calls...
- --> $DIR/clone-rpit.rs:15:5
- |
-LL | move |_: ()| {
- | ^^^^^^^^^^^^
-note: ...which requires building MIR for `foo::{closure#0}`...
- --> $DIR/clone-rpit.rs:15:5
- |
-LL | move |_: ()| {
- | ^^^^^^^^^^^^
-note: ...which requires match-checking `foo::{closure#0}`...
- --> $DIR/clone-rpit.rs:15:5
- |
-LL | move |_: ()| {
- | ^^^^^^^^^^^^
-note: ...which requires type-checking `foo::{closure#0}`...
- --> $DIR/clone-rpit.rs:15:5
- |
-LL | move |_: ()| {
- | ^^^^^^^^^^^^
- = note: ...which again requires type-checking `foo`, completing the cycle
-note: cycle used when match-checking `foo`
- --> $DIR/clone-rpit.rs:13:1
- |
-LL | pub fn foo<'a, 'b>() -> impl Clone {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/coroutine/clone-rpit.rs b/tests/ui/coroutine/clone-rpit.rs
index 66569b4..3882564 100644
--- a/tests/ui/coroutine/clone-rpit.rs
+++ b/tests/ui/coroutine/clone-rpit.rs
@@ -1,8 +1,7 @@
//@ revisions: current next
//@ ignore-compare-mode-next-solver (explicit revisions)
//@[next] compile-flags: -Znext-solver
-//@[current] check-pass
-//@[next] known-bug: trait-system-refactor-initiative#82
+//@ check-pass
#![feature(coroutines, coroutine_trait, coroutine_clone)]
diff --git a/tests/ui/coroutine/higher-ranked-rigid.rs b/tests/ui/coroutine/higher-ranked-rigid.rs
new file mode 100644
index 0000000..23a7d51
--- /dev/null
+++ b/tests/ui/coroutine/higher-ranked-rigid.rs
@@ -0,0 +1,41 @@
+//@ edition: 2024
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+
+// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/177>.
+// Coroutines erase all free lifetimes from their interior types, replacing them with higher-
+// ranked regions which act as universals, to properly represent the fact that we don't know what
+// the value of the region is within the coroutine.
+//
+// In the future in `from_request`, that means that the `'r` lifetime is being replaced in
+// `<T as FromRequest<'r>>::Assoc`, which is in present in the existential bounds of the
+// `dyn Future` that it's awaiting. Normalizing this associated type, with its free lifetimes
+// replaced, means proving `T: FromRequest<'!0>`, which doesn't hold without constraining the
+// `'!0` lifetime, which we don't do today.
+
+// Proving `T: Trait` holds when `<T as Trait>::Assoc` is rigid is not necessary for soundness,
+// at least not *yet*, and it's not even necessary for diagnostics since we have other special
+// casing for, e.g., AliasRelate goals failing in the BestObligation folder.
+
+// The old solver unintentioanlly avoids this by never checking that `T: Trait` holds when
+// `<T as Trait>::Assoc` is rigid. Introducing this additional requirement when projecting rigidly
+// in the old solver causes this (and tons of production crates) to fail. See the fallout from the
+// crater run at <https://github.com/rust-lang/rust/pull/139763>.
+
+use std::future::Future;
+use std::pin::Pin;
+
+pub trait FromRequest<'r> {
+ type Assoc;
+ fn from_request() -> Pin<Box<dyn Future<Output = Self::Assoc> + Send>>;
+}
+
+fn test<'r, T: FromRequest<'r>>() -> Pin<Box<dyn Future<Output = ()> + Send>> {
+ Box::pin(async move {
+ T::from_request().await;
+ })
+}
+
+fn main() {}
diff --git a/tests/ui/coroutine/postfix-yield.rs b/tests/ui/coroutine/postfix-yield.rs
index ff84313..f2fdceb 100644
--- a/tests/ui/coroutine/postfix-yield.rs
+++ b/tests/ui/coroutine/postfix-yield.rs
@@ -3,7 +3,7 @@
//@ run-pass
//@ edition: 2024
-#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr)]
+#![feature(gen_blocks, coroutines, coroutine_trait, yield_expr, stmt_expr_attributes)]
use std::ops::{Coroutine, CoroutineState};
use std::pin::pin;
diff --git a/tests/ui/cross/cross-file-errors/underscore.rs b/tests/ui/cross/cross-file-errors/underscore.rs
index 9d07573..73eb36c 100644
--- a/tests/ui/cross/cross-file-errors/underscore.rs
+++ b/tests/ui/cross/cross-file-errors/underscore.rs
@@ -1,4 +1,4 @@
-//@ ignore-test (auxiliary, used by other tests)
+//@ ignore-auxiliary (used by `./main.rs`)
#![crate_type = "lib"]
macro_rules! underscore {
diff --git a/tests/ui/debuginfo/dwarf-versions.rs b/tests/ui/debuginfo/dwarf-versions.rs
index 6030b2f..8f731f1 100644
--- a/tests/ui/debuginfo/dwarf-versions.rs
+++ b/tests/ui/debuginfo/dwarf-versions.rs
@@ -1,26 +1,25 @@
// This test verifies the expected behavior of various options passed to
-// `-Zdwarf-version`: 2 - 5 (valid) with all other options being invalid.
+// `-Cdwarf-version`: 2 - 5 (valid) with all other options being invalid.
//@ revisions: zero one two three four five six
-//@[zero] compile-flags: -Zdwarf-version=0
+//@[zero] compile-flags: -Cdwarf-version=0
-//@[one] compile-flags: -Zdwarf-version=1
-//@[one] error-pattern: requested DWARF version 1 is not supported
+//@[one] compile-flags: -Cdwarf-version=1
-//@[two] compile-flags: -Zdwarf-version=2
+//@[two] compile-flags: -Cdwarf-version=2
//@[two] check-pass
-//@[three] compile-flags: -Zdwarf-version=3
+//@[three] compile-flags: -Cdwarf-version=3
//@[three] check-pass
-//@[four] compile-flags: -Zdwarf-version=4
+//@[four] compile-flags: -Cdwarf-version=4
//@[four] check-pass
-//@[five] compile-flags: -Zdwarf-version=5
+//@[five] compile-flags: -Cdwarf-version=5
//@[five] check-pass
-//@[six] compile-flags: -Zdwarf-version=6
+//@[six] compile-flags: -Cdwarf-version=6
//@ compile-flags: -g --target x86_64-unknown-linux-gnu --crate-type cdylib
//@ needs-llvm-components: x86
diff --git a/tests/ui/delegation/explicit-paths-signature-pass.rs b/tests/ui/delegation/explicit-paths-signature-pass.rs
index 8c16ad9..11bc8a7 100644
--- a/tests/ui/delegation/explicit-paths-signature-pass.rs
+++ b/tests/ui/delegation/explicit-paths-signature-pass.rs
@@ -6,7 +6,7 @@
mod to_reuse {
use crate::S;
- pub fn foo<'a>(#[cfg(FALSE)] a: u8, _b: &'a S) -> u32 {
+ pub fn foo<'a>(#[cfg(false)] a: u8, _b: &'a S) -> u32 {
1
}
}
diff --git a/tests/ui/deref-non-pointer.rs b/tests/ui/deref-patterns/deref-non-pointer.rs
similarity index 100%
rename from tests/ui/deref-non-pointer.rs
rename to tests/ui/deref-patterns/deref-non-pointer.rs
diff --git a/tests/ui/deref-non-pointer.stderr b/tests/ui/deref-patterns/deref-non-pointer.stderr
similarity index 100%
rename from tests/ui/deref-non-pointer.stderr
rename to tests/ui/deref-patterns/deref-non-pointer.stderr
diff --git a/tests/ui/deriving/auxiliary/malicious-macro.rs b/tests/ui/deriving/auxiliary/malicious-macro.rs
index 6665b40..c551b3f 100644
--- a/tests/ui/deriving/auxiliary/malicious-macro.rs
+++ b/tests/ui/deriving/auxiliary/malicious-macro.rs
@@ -1,4 +1,4 @@
-#![feature(let_chains)]
+//@ edition: 2024
extern crate proc_macro;
diff --git a/tests/ui/deriving/built-in-proc-macro-scope.rs b/tests/ui/deriving/built-in-proc-macro-scope.rs
index e67197b..69128a0 100644
--- a/tests/ui/deriving/built-in-proc-macro-scope.rs
+++ b/tests/ui/deriving/built-in-proc-macro-scope.rs
@@ -1,6 +1,7 @@
//@ check-pass
//@ proc-macro: another-proc-macro.rs
//@ compile-flags: -Zunpretty=expanded
+//@ edition:2015
#![feature(derive_coerce_pointee)]
diff --git a/tests/ui/deriving/built-in-proc-macro-scope.stdout b/tests/ui/deriving/built-in-proc-macro-scope.stdout
index fa4e509..2697618 100644
--- a/tests/ui/deriving/built-in-proc-macro-scope.stdout
+++ b/tests/ui/deriving/built-in-proc-macro-scope.stdout
@@ -3,6 +3,7 @@
//@ check-pass
//@ proc-macro: another-proc-macro.rs
//@ compile-flags: -Zunpretty=expanded
+//@ edition:2015
#![feature(derive_coerce_pointee)]
#[prelude_import]
diff --git a/tests/ui/deriving/deriving-coerce-pointee-expanded.rs b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs
index 94be703..9394ae4 100644
--- a/tests/ui/deriving/deriving-coerce-pointee-expanded.rs
+++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.rs
@@ -1,5 +1,6 @@
//@ check-pass
//@ compile-flags: -Zunpretty=expanded
+//@ edition: 2015
#![feature(derive_coerce_pointee)]
use std::marker::CoercePointee;
diff --git a/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout
index a774efb..84f8e9a 100644
--- a/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout
+++ b/tests/ui/deriving/deriving-coerce-pointee-expanded.stdout
@@ -2,6 +2,7 @@
#![no_std]
//@ check-pass
//@ compile-flags: -Zunpretty=expanded
+//@ edition: 2015
#![feature(derive_coerce_pointee)]
#[prelude_import]
use ::std::prelude::rust_2015::*;
diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.rs b/tests/ui/deriving/proc-macro-attribute-mixing.rs
index 2c11c3f..c9e123d 100644
--- a/tests/ui/deriving/proc-macro-attribute-mixing.rs
+++ b/tests/ui/deriving/proc-macro-attribute-mixing.rs
@@ -7,6 +7,7 @@
//@ check-pass
//@ proc-macro: another-proc-macro.rs
//@ compile-flags: -Zunpretty=expanded
+//@ edition: 2015
#![feature(derive_coerce_pointee)]
diff --git a/tests/ui/deriving/proc-macro-attribute-mixing.stdout b/tests/ui/deriving/proc-macro-attribute-mixing.stdout
index ad743d0..faa9c02 100644
--- a/tests/ui/deriving/proc-macro-attribute-mixing.stdout
+++ b/tests/ui/deriving/proc-macro-attribute-mixing.stdout
@@ -9,6 +9,7 @@
//@ check-pass
//@ proc-macro: another-proc-macro.rs
//@ compile-flags: -Zunpretty=expanded
+//@ edition: 2015
#![feature(derive_coerce_pointee)]
#[prelude_import]
diff --git a/tests/ui/diagnostic_namespace/on_impl_trait.rs b/tests/ui/diagnostic_namespace/on_impl_trait.rs
new file mode 100644
index 0000000..32a492c
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_impl_trait.rs
@@ -0,0 +1,17 @@
+// used to ICE, see <https://github.com/rust-lang/rust/issues/130627>
+// Instead it should just ignore the diagnostic attribute
+#![feature(trait_alias)]
+
+trait Test {}
+
+#[diagnostic::on_unimplemented(message = "blah", label = "blah", note = "blah")]
+//~^ WARN `#[diagnostic::on_unimplemented]` can only be applied to trait definitions
+trait Alias = Test;
+
+// Use trait alias as bound on type parameter.
+fn foo<T: Alias>(v: &T) {}
+
+pub fn main() {
+ foo(&1);
+ //~^ ERROR the trait bound `{integer}: Alias` is not satisfied
+}
diff --git a/tests/ui/diagnostic_namespace/on_impl_trait.stderr b/tests/ui/diagnostic_namespace/on_impl_trait.stderr
new file mode 100644
index 0000000..59b9c31
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/on_impl_trait.stderr
@@ -0,0 +1,31 @@
+warning: `#[diagnostic::on_unimplemented]` can only be applied to trait definitions
+ --> $DIR/on_impl_trait.rs:7:1
+ |
+LL | #[diagnostic::on_unimplemented(message = "blah", label = "blah", note = "blah")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
+
+error[E0277]: the trait bound `{integer}: Alias` is not satisfied
+ --> $DIR/on_impl_trait.rs:15:9
+ |
+LL | foo(&1);
+ | --- ^^ the trait `Test` is not implemented for `{integer}`
+ | |
+ | required by a bound introduced by this call
+ |
+help: this trait has no implementations, consider adding one
+ --> $DIR/on_impl_trait.rs:5:1
+ |
+LL | trait Test {}
+ | ^^^^^^^^^^
+ = note: required for `{integer}` to implement `Alias`
+note: required by a bound in `foo`
+ --> $DIR/on_impl_trait.rs:12:11
+ |
+LL | fn foo<T: Alias>(v: &T) {}
+ | ^^^^^ required by this bound in `foo`
+
+error: aborting due to 1 previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
index 7fd51c7..a82a1e7 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/broken_format.stderr
@@ -1,52 +1,52 @@
warning: unmatched `}` found
- --> $DIR/broken_format.rs:2:32
+ --> $DIR/broken_format.rs:2:42
|
LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^
|
= note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
warning: positional format arguments are not allowed here
- --> $DIR/broken_format.rs:7:32
+ --> $DIR/broken_format.rs:7:49
|
LL | #[diagnostic::on_unimplemented(message = "Test {}")]
- | ^^^^^^^^^^^^^^^^^^^
+ | ^
|
= help: only named format arguments with the name of one of the generic types are allowed in this context
warning: positional format arguments are not allowed here
- --> $DIR/broken_format.rs:12:32
+ --> $DIR/broken_format.rs:12:49
|
LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^
|
= help: only named format arguments with the name of one of the generic types are allowed in this context
warning: invalid format specifier
- --> $DIR/broken_format.rs:17:32
+ --> $DIR/broken_format.rs:17:42
|
LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^
|
= help: no format specifier are supported in this position
warning: expected `}`, found `!`
- --> $DIR/broken_format.rs:22:32
+ --> $DIR/broken_format.rs:22:42
|
LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^
warning: unmatched `}` found
- --> $DIR/broken_format.rs:22:32
+ --> $DIR/broken_format.rs:22:42
|
LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^
warning: unmatched `}` found
- --> $DIR/broken_format.rs:2:32
+ --> $DIR/broken_format.rs:2:42
|
LL | #[diagnostic::on_unimplemented(message = "{{Test } thing")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
@@ -70,10 +70,10 @@
| ^^^^^^^^^^^^^^^ required by this bound in `check_1`
warning: positional format arguments are not allowed here
- --> $DIR/broken_format.rs:7:32
+ --> $DIR/broken_format.rs:7:49
|
LL | #[diagnostic::on_unimplemented(message = "Test {}")]
- | ^^^^^^^^^^^^^^^^^^^
+ | ^
|
= help: only named format arguments with the name of one of the generic types are allowed in this context
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
@@ -98,10 +98,10 @@
| ^^^^^^^^^^^^^^^ required by this bound in `check_2`
warning: positional format arguments are not allowed here
- --> $DIR/broken_format.rs:12:32
+ --> $DIR/broken_format.rs:12:49
|
LL | #[diagnostic::on_unimplemented(message = "Test {1:}")]
- | ^^^^^^^^^^^^^^^^^^^^^
+ | ^
|
= help: only named format arguments with the name of one of the generic types are allowed in this context
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
@@ -126,10 +126,10 @@
| ^^^^^^^^^^^^^^^ required by this bound in `check_3`
warning: invalid format specifier
- --> $DIR/broken_format.rs:17:32
+ --> $DIR/broken_format.rs:17:42
|
LL | #[diagnostic::on_unimplemented(message = "Test {Self:123}")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^
|
= help: no format specifier are supported in this position
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
@@ -154,18 +154,18 @@
| ^^^^^^^^^^^^^^^ required by this bound in `check_4`
warning: expected `}`, found `!`
- --> $DIR/broken_format.rs:22:32
+ --> $DIR/broken_format.rs:22:42
|
LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
warning: unmatched `}` found
- --> $DIR/broken_format.rs:22:32
+ --> $DIR/broken_format.rs:22:42
|
LL | #[diagnostic::on_unimplemented(message = "Test {Self:!}")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^
|
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr
index bb455d9..88816a9 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_accept_options_of_the_internal_rustc_attribute.stderr
@@ -39,82 +39,82 @@
= help: only `message`, `note` and `label` are allowed as options
warning: there is no parameter `from_desugaring` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:17
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
warning: there is no parameter `direct` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:34
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
warning: there is no parameter `cause` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:42
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
warning: there is no parameter `integral` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:49
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
warning: there is no parameter `integer` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:59
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
warning: there is no parameter `float` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:15
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
warning: there is no parameter `_Self` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:22
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
warning: there is no parameter `crate_local` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:29
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
warning: there is no parameter `Trait` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:42
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
warning: there is no parameter `ItemContext` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:49
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
@@ -191,91 +191,91 @@
| ^^^ required by this bound in `takes_bar`
warning: there is no parameter `from_desugaring` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:17
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
warning: there is no parameter `direct` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:34
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
warning: there is no parameter `cause` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:42
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
warning: there is no parameter `integral` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:49
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
warning: there is no parameter `integer` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:33:59
|
LL | message = "{from_desugaring}{direct}{cause}{integral}{integer}",
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
warning: there is no parameter `float` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:15
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
warning: there is no parameter `_Self` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:22
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
warning: there is no parameter `crate_local` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:29
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
warning: there is no parameter `Trait` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:42
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
warning: there is no parameter `ItemContext` on trait `Baz`
- --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:5
+ --> $DIR/do_not_accept_options_of_the_internal_rustc_attribute.rs:44:49
|
LL | label = "{float}{_Self}{crate_local}{Trait}{ItemContext}"
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
index 1126358..4dd8c1a 100644
--- a/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
+++ b/tests/ui/diagnostic_namespace/on_unimplemented/do_not_fail_parsing_on_invalid_options_1.stderr
@@ -47,10 +47,10 @@
= help: at least one of the `message`, `note` and `label` options are expected
warning: there is no parameter `DoesNotExist` on trait `Test`
- --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32
+ --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:44
|
LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
@@ -167,10 +167,10 @@
| ^^^^^^^^ required by this bound in `take_whatever`
warning: there is no parameter `DoesNotExist` on trait `Test`
- --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:32
+ --> $DIR/do_not_fail_parsing_on_invalid_options_1.rs:31:44
|
LL | #[diagnostic::on_unimplemented(message = "{DoesNotExist}")]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^
|
= help: expect either a generic argument name or `{Self}` as format argument
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
diff --git a/tests/ui/did_you_mean/E0178.stderr b/tests/ui/did_you_mean/E0178.stderr
index 5f289da..36e4dbd 100644
--- a/tests/ui/did_you_mean/E0178.stderr
+++ b/tests/ui/did_you_mean/E0178.stderr
@@ -1,41 +1,43 @@
-error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`
+error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/E0178.rs:6:8
|
LL | w: &'a Foo + Copy,
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^
|
help: try adding parentheses
|
LL | w: &'a (Foo + Copy),
| + +
-error[E0178]: expected a path on the left-hand side of `+`, not `&'a Foo`
+error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/E0178.rs:7:8
|
LL | x: &'a Foo + 'a,
- | ^^^^^^^^^^^^
+ | ^^^^^^^
|
help: try adding parentheses
|
LL | x: &'a (Foo + 'a),
| + +
-error[E0178]: expected a path on the left-hand side of `+`, not `&'a mut Foo`
+error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/E0178.rs:8:8
|
LL | y: &'a mut Foo + 'a,
- | ^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^
|
help: try adding parentheses
|
LL | y: &'a mut (Foo + 'a),
| + +
-error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> Foo`
+error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/E0178.rs:9:8
|
LL | z: fn() -> Foo + 'a,
- | ^^^^^^^^^^^^^^^^ perhaps you forgot parentheses?
+ | ^^^^^^^^^^^-----
+ | |
+ | perhaps you forgot parentheses?
error: aborting due to 4 previous errors
diff --git a/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr b/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr
index d4812d4..c74cb89 100644
--- a/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr
+++ b/tests/ui/did_you_mean/issue-48492-tuple-destructure-missing-parens.stderr
@@ -66,7 +66,6 @@
LL | let women, men: (Vec<Genome>, Vec<Genome>) = genomes.iter().cloned()
| ^
|
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: try adding parentheses to match on a tuple
|
LL | let (women, men): (Vec<Genome>, Vec<Genome>) = genomes.iter().cloned()
diff --git a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr
index 4fee6cc..762b37b 100644
--- a/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr
+++ b/tests/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr
@@ -1,19 +1,19 @@
-error[E0178]: expected a path on the left-hand side of `+`, not `&Copy`
+error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12
|
LL | let _: &Copy + 'static;
- | ^^^^^^^^^^^^^^^
+ | ^^^^^
|
help: try adding parentheses
|
LL | let _: &(Copy + 'static);
| + +
-error[E0178]: expected a path on the left-hand side of `+`, not `&'static Copy`
+error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/trait-object-reference-without-parens-suggestion.rs:6:12
|
LL | let _: &'static Copy + 'static;
- | ^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^
|
help: try adding parentheses
|
diff --git a/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/bar.rs b/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/bar.rs
index 1d832a3..2ccdd79 100644
--- a/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/bar.rs
+++ b/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/bar.rs
@@ -1 +1 @@
-//@ ignore-test not a test, auxiliary
+//@ ignore-auxiliary (used by `../../macro-expanded-mod.rs`)
diff --git a/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/mod.rs b/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/mod.rs
index 08349ba..9009f80 100644
--- a/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/mod.rs
+++ b/tests/ui/directory_ownership/macro_expanded_mod_helper/foo/mod.rs
@@ -1,3 +1,3 @@
-//@ ignore-test not a test, auxiliary
+//@ ignore-auxiliary (used by `../../macro-expanded-mod.rs`)
mod_decl!(bar);
diff --git a/tests/ui/directory_ownership/mod_file_not_owning_aux1.rs b/tests/ui/directory_ownership/mod_file_not_owning_aux1.rs
deleted file mode 100644
index 6d6884f..0000000
--- a/tests/ui/directory_ownership/mod_file_not_owning_aux1.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//@ ignore-test this is not a test
-
-macro_rules! m {
- () => { mod mod_file_not_owning_aux2; }
-}
-m!();
diff --git a/tests/ui/directory_ownership/mod_file_not_owning_aux2.rs b/tests/ui/directory_ownership/mod_file_not_owning_aux2.rs
deleted file mode 100644
index 76f1c1a..0000000
--- a/tests/ui/directory_ownership/mod_file_not_owning_aux2.rs
+++ /dev/null
@@ -1 +0,0 @@
-//@ ignore-test this is not a test
diff --git a/tests/ui/directory_ownership/mod_file_not_owning_aux3.rs b/tests/ui/directory_ownership/mod_file_not_owning_aux3.rs
deleted file mode 100644
index 96a5780..0000000
--- a/tests/ui/directory_ownership/mod_file_not_owning_aux3.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-//@ ignore-test this is not a test
-
-mod mod_file_not_owning_aux2;
diff --git a/tests/ui/drop/drop-order-comparisons.e2021.fixed b/tests/ui/drop/drop-order-comparisons.e2021.fixed
index 78cf421..71158cb 100644
--- a/tests/ui/drop/drop-order-comparisons.e2021.fixed
+++ b/tests/ui/drop/drop-order-comparisons.e2021.fixed
@@ -24,7 +24,7 @@
//@ [e2024] edition: 2024
//@ run-pass
-#![feature(let_chains)]
+#![cfg_attr(e2021, feature(let_chains))]
#![cfg_attr(e2021, warn(rust_2024_compatibility))]
fn t_bindings() {
diff --git a/tests/ui/drop/drop-order-comparisons.rs b/tests/ui/drop/drop-order-comparisons.rs
index 78c75a9..0492b3a 100644
--- a/tests/ui/drop/drop-order-comparisons.rs
+++ b/tests/ui/drop/drop-order-comparisons.rs
@@ -24,7 +24,7 @@
//@ [e2024] edition: 2024
//@ run-pass
-#![feature(let_chains)]
+#![cfg_attr(e2021, feature(let_chains))]
#![cfg_attr(e2021, warn(rust_2024_compatibility))]
fn t_bindings() {
diff --git a/tests/crashes/137287.rs b/tests/ui/drop/drop_elaboration_with_errors2.rs
similarity index 67%
rename from tests/crashes/137287.rs
rename to tests/ui/drop/drop_elaboration_with_errors2.rs
index 59fdf56..946c253 100644
--- a/tests/crashes/137287.rs
+++ b/tests/ui/drop/drop_elaboration_with_errors2.rs
@@ -1,11 +1,14 @@
-//@ known-bug: #137287
+// Regression test for #137287
mod defining_scope {
use super::*;
pub type Alias<T> = impl Sized;
+ //~^ ERROR unconstrained opaque type
+ //~| ERROR `impl Trait` in type aliases is unstable
pub fn cast<T>(x: Container<Alias<T>, T>) -> Container<T, T> {
x
+ //~^ ERROR mismatched types
}
}
@@ -21,6 +24,7 @@ impl<T> Trait<T> for T {
type Assoc = Box<u32>;
}
impl<T> Trait<T> for defining_scope::Alias<T> {
+ //~^ ERROR conflicting implementations of trait `Trait<_>`
type Assoc = usize;
}
diff --git a/tests/ui/drop/drop_elaboration_with_errors2.stderr b/tests/ui/drop/drop_elaboration_with_errors2.stderr
new file mode 100644
index 0000000..15fe3f6
--- /dev/null
+++ b/tests/ui/drop/drop_elaboration_with_errors2.stderr
@@ -0,0 +1,47 @@
+error[E0658]: `impl Trait` in type aliases is unstable
+ --> $DIR/drop_elaboration_with_errors2.rs:5:25
+ |
+LL | pub type Alias<T> = impl Sized;
+ | ^^^^^^^^^^
+ |
+ = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information
+ = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0119]: conflicting implementations of trait `Trait<_>`
+ --> $DIR/drop_elaboration_with_errors2.rs:26:1
+ |
+LL | impl<T> Trait<T> for T {
+ | ---------------------- first implementation here
+...
+LL | impl<T> Trait<T> for defining_scope::Alias<T> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
+
+error: unconstrained opaque type
+ --> $DIR/drop_elaboration_with_errors2.rs:5:25
+ |
+LL | pub type Alias<T> = impl Sized;
+ | ^^^^^^^^^^
+ |
+ = note: `Alias` must be used in combination with a concrete type within the same crate
+
+error[E0308]: mismatched types
+ --> $DIR/drop_elaboration_with_errors2.rs:10:9
+ |
+LL | pub type Alias<T> = impl Sized;
+ | ---------- the found opaque type
+...
+LL | pub fn cast<T>(x: Container<Alias<T>, T>) -> Container<T, T> {
+ | - expected this type parameter --------------- expected `Container<T, T>` because of return type
+LL | x
+ | ^ expected `Container<T, T>`, found `Container<Alias<T>, T>`
+ |
+ = note: expected struct `Container<T, _>`
+ found struct `Container<Alias<T>, _>`
+ = help: type parameters must be constrained to match other types
+ = note: for more information, visit https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0119, E0308, E0658.
+For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/crashes/135668.rs b/tests/ui/drop/drop_elaboration_with_errors3.rs
similarity index 86%
rename from tests/crashes/135668.rs
rename to tests/ui/drop/drop_elaboration_with_errors3.rs
index 00d7b5d..c5ed63e 100644
--- a/tests/crashes/135668.rs
+++ b/tests/ui/drop/drop_elaboration_with_errors3.rs
@@ -1,5 +1,6 @@
-//@ known-bug: #135668
+// Regression test for #135668
//@ edition: 2021
+
use std::future::Future;
pub async fn foo() {
@@ -11,7 +12,8 @@ async fn create_task() -> impl Sized {
}
async fn documentation() {
- include_str!("nonexistent");
+ compile_error!("bonjour");
+ //~^ ERROR bonjour
}
fn bind<F>(_filter: F) -> impl Sized
@@ -36,3 +38,5 @@ impl<F, R> FilterBase for F
{
type Assoc = F;
}
+
+fn main() {}
diff --git a/tests/ui/drop/drop_elaboration_with_errors3.stderr b/tests/ui/drop/drop_elaboration_with_errors3.stderr
new file mode 100644
index 0000000..2d44e7c
--- /dev/null
+++ b/tests/ui/drop/drop_elaboration_with_errors3.stderr
@@ -0,0 +1,8 @@
+error: bonjour
+ --> $DIR/drop_elaboration_with_errors3.rs:15:5
+ |
+LL | compile_error!("bonjour");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/drop/drop_order.rs b/tests/ui/drop/drop_order.rs
index d1a5b9b..b96e55a 100644
--- a/tests/ui/drop/drop_order.rs
+++ b/tests/ui/drop/drop_order.rs
@@ -2,9 +2,10 @@
//@ compile-flags: -Z validate-mir
//@ revisions: edition2021 edition2024
//@ [edition2021] edition: 2021
+//@ [edition2024] compile-flags: -Z lint-mir
//@ [edition2024] edition: 2024
-#![feature(let_chains)]
+#![cfg_attr(edition2021, feature(let_chains))]
use std::cell::RefCell;
use std::convert::TryInto;
diff --git a/tests/ui/drop/drop_order_if_let_rescope.rs b/tests/ui/drop/drop_order_if_let_rescope.rs
index 7445e3a..27bced5 100644
--- a/tests/ui/drop/drop_order_if_let_rescope.rs
+++ b/tests/ui/drop/drop_order_if_let_rescope.rs
@@ -1,8 +1,6 @@
//@ run-pass
//@ edition:2024
-//@ compile-flags: -Z validate-mir
-
-#![feature(let_chains)]
+//@ compile-flags: -Z validate-mir -Z lint-mir
use std::cell::RefCell;
use std::convert::TryInto;
diff --git a/tests/ui/drop/issue-100276.rs b/tests/ui/drop/issue-100276.rs
index b44710e..5d212b3 100644
--- a/tests/ui/drop/issue-100276.rs
+++ b/tests/ui/drop/issue-100276.rs
@@ -1,6 +1,11 @@
//@ check-pass
//@ compile-flags: -Z validate-mir
-#![feature(let_chains)]
+//@ revisions: edition2021 edition2024
+//@ [edition2021] edition: 2021
+//@ [edition2024] compile-flags: -Z lint-mir
+//@ [edition2024] edition: 2024
+
+#![cfg_attr(edition2021, feature(let_chains))]
fn let_chains(entry: std::io::Result<std::fs::DirEntry>) {
if let Ok(entry) = entry
diff --git a/tests/ui/error-codes/E0152-duplicate-lang-items.rs b/tests/ui/error-codes/E0152-duplicate-lang-items.rs
index 089810b..f707b72 100644
--- a/tests/ui/error-codes/E0152-duplicate-lang-items.rs
+++ b/tests/ui/error-codes/E0152-duplicate-lang-items.rs
@@ -3,8 +3,9 @@
//!
//! Issue: <https://github.com/rust-lang/rust/issues/31788>
-//@ error-pattern: first defined in crate `std`
//@ normalize-stderr: "loaded from .*libstd-.*.rlib" -> "loaded from SYSROOT/libstd-*.rlib"
+//@ dont-require-annotations: NOTE
+
#![feature(lang_items)]
extern crate core;
@@ -14,6 +15,7 @@
#[lang = "panic_impl"]
fn panic_impl(info: &PanicInfo) -> ! {
//~^ ERROR: found duplicate lang item `panic_impl`
+ //~| NOTE first defined in crate `std`
loop {}
}
diff --git a/tests/ui/error-codes/E0152-duplicate-lang-items.stderr b/tests/ui/error-codes/E0152-duplicate-lang-items.stderr
index 3c3d643..2fe0d18 100644
--- a/tests/ui/error-codes/E0152-duplicate-lang-items.stderr
+++ b/tests/ui/error-codes/E0152-duplicate-lang-items.stderr
@@ -1,8 +1,9 @@
error[E0152]: found duplicate lang item `panic_impl`
- --> $DIR/E0152-duplicate-lang-items.rs:15:1
+ --> $DIR/E0152-duplicate-lang-items.rs:16:1
|
LL | / fn panic_impl(info: &PanicInfo) -> ! {
LL | |
+LL | |
LL | | loop {}
LL | | }
| |_^
diff --git a/tests/ui/error-codes/E0602.rs b/tests/ui/error-codes/E0602.rs
index cba15bb9..381bd1f 100644
--- a/tests/ui/error-codes/E0602.rs
+++ b/tests/ui/error-codes/E0602.rs
@@ -1,11 +1,11 @@
//@ compile-flags:-D bogus
//@ check-pass
-
-//@ error-pattern:requested on the command line with `-D bogus`
-//@ error-pattern:`#[warn(unknown_lints)]` on by default
+//@ dont-require-annotations: NOTE
fn main() {}
//~? WARN unknown lint: `bogus`
//~? WARN unknown lint: `bogus`
//~? WARN unknown lint: `bogus`
+//~? NOTE requested on the command line with `-D bogus`
+//~? NOTE `#[warn(unknown_lints)]` on by default
diff --git a/tests/ui/errors/pic-linker.rs b/tests/ui/errors/pic-linker.rs
index d909899..36495ca 100644
--- a/tests/ui/errors/pic-linker.rs
+++ b/tests/ui/errors/pic-linker.rs
@@ -5,6 +5,7 @@
//@ ignore-windows
//@ ignore-macos
//@ ignore-cross-compile
+//@ ignore-aix
//@ compile-flags: -Clink-args=-Wl,-z,text
//@ run-pass
diff --git a/tests/ui/expr/if/attrs/bad-cfg.rs b/tests/ui/expr/if/attrs/bad-cfg.rs
index 3f84929..6e7f4b0 100644
--- a/tests/ui/expr/if/attrs/bad-cfg.rs
+++ b/tests/ui/expr/if/attrs/bad-cfg.rs
@@ -1,5 +1,5 @@
#![feature(stmt_expr_attributes)]
fn main() {
- let _ = #[cfg(FALSE)] if true {}; //~ ERROR removing an expression
+ let _ = #[cfg(false)] if true {}; //~ ERROR removing an expression
}
diff --git a/tests/ui/expr/if/attrs/bad-cfg.stderr b/tests/ui/expr/if/attrs/bad-cfg.stderr
index ca0eced..d12f5ee 100644
--- a/tests/ui/expr/if/attrs/bad-cfg.stderr
+++ b/tests/ui/expr/if/attrs/bad-cfg.stderr
@@ -1,7 +1,7 @@
error: removing an expression is not supported in this position
--> $DIR/bad-cfg.rs:4:13
|
-LL | let _ = #[cfg(FALSE)] if true {};
+LL | let _ = #[cfg(false)] if true {};
| ^^^^^^^^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/expr/if/attrs/cfg-false-if-attr.rs b/tests/ui/expr/if/attrs/cfg-false-if-attr.rs
index c139b347..e6c83b8 100644
--- a/tests/ui/expr/if/attrs/cfg-false-if-attr.rs
+++ b/tests/ui/expr/if/attrs/cfg-false-if-attr.rs
@@ -1,12 +1,12 @@
//@ check-pass
-#[cfg(FALSE)]
+#[cfg(false)]
fn simple_attr() {
#[attr] if true {}
#[allow_warnings] if true {}
}
-#[cfg(FALSE)]
+#[cfg(false)]
fn if_else_chain() {
#[first_attr] if true {
} else if false {
@@ -14,20 +14,20 @@ fn if_else_chain() {
}
}
-#[cfg(FALSE)]
+#[cfg(false)]
fn if_let() {
#[attr] if let Some(_) = Some(true) {}
}
fn bar() {
- #[cfg(FALSE)]
+ #[cfg(false)]
if true {
- let x: () = true; // Should not error due to the #[cfg(FALSE)]
+ let x: () = true; // Should not error due to the #[cfg(false)]
}
- #[cfg_attr(not(FALSE), cfg(FALSE))]
+ #[cfg_attr(not(FALSE), cfg(false))]
if true {
- let a: () = true; // Should not error due to the applied #[cfg(FALSE)]
+ let a: () = true; // Should not error due to the applied #[cfg(false)]
}
}
diff --git a/tests/ui/expr/if/attrs/else-attrs.rs b/tests/ui/expr/if/attrs/else-attrs.rs
index 85da7cf..4010d9d 100644
--- a/tests/ui/expr/if/attrs/else-attrs.rs
+++ b/tests/ui/expr/if/attrs/else-attrs.rs
@@ -1,11 +1,11 @@
-#[cfg(FALSE)]
+#[cfg(false)]
fn if_else_parse_error() {
if true {
} #[attr] else if false { //~ ERROR expected
}
}
-#[cfg(FALSE)]
+#[cfg(false)]
fn else_attr_ifparse_error() {
if true {
} else #[attr] if false { //~ ERROR outer attributes are not allowed
@@ -13,7 +13,7 @@ fn else_attr_ifparse_error() {
}
}
-#[cfg(FALSE)]
+#[cfg(false)]
fn else_parse_error() {
if true {
} else if false {
diff --git a/tests/ui/expr/if/attrs/gate-whole-expr.rs b/tests/ui/expr/if/attrs/gate-whole-expr.rs
index bab0159..8859090 100644
--- a/tests/ui/expr/if/attrs/gate-whole-expr.rs
+++ b/tests/ui/expr/if/attrs/gate-whole-expr.rs
@@ -3,7 +3,7 @@
fn main() {
let x = 1;
- #[cfg(FALSE)]
+ #[cfg(false)]
if false {
x = 2;
} else if true {
diff --git a/tests/ui/expr/if/attrs/let-chains-attr.rs b/tests/ui/expr/if/attrs/let-chains-attr.rs
index b3dbd53..7b74b17 100644
--- a/tests/ui/expr/if/attrs/let-chains-attr.rs
+++ b/tests/ui/expr/if/attrs/let-chains-attr.rs
@@ -1,8 +1,7 @@
//@ check-pass
+//@ edition:2024
-#![feature(let_chains)]
-
-#[cfg(FALSE)]
+#[cfg(false)]
fn foo() {
#[attr]
if let Some(_) = Some(true) && let Ok(_) = Ok(1) {
diff --git a/tests/ui/extern-flag/invalid-crate-name-dashed.rs b/tests/ui/extern-flag/invalid-crate-name-dashed.rs
index b336cc8..bbf473c 100644
--- a/tests/ui/extern-flag/invalid-crate-name-dashed.rs
+++ b/tests/ui/extern-flag/invalid-crate-name-dashed.rs
@@ -1,5 +1,4 @@
//@ compile-flags: --extern=my-awesome-library=libawesome.rlib
-//@ error-pattern: consider replacing the dashes with underscores: `my_awesome_library`
// In a sense, this is a regression test for issue #113035. We no longer suggest
// `pub use my-awesome-library::*;` (sic!) as we outright ban this crate name.
@@ -9,3 +8,4 @@
fn main() {}
//~? ERROR crate name `my-awesome-library` passed to `--extern` is not a valid ASCII identifier
+//~? HELP consider replacing the dashes with underscores: `my_awesome_library`
diff --git a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs
deleted file mode 100644
index 6784b44..0000000
--- a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#[cfg(true)] //~ ERROR `cfg(true)` is experimental
-fn foo() {}
-
-#[cfg_attr(true, cfg(false))] //~ ERROR `cfg(true)` is experimental
-//~^ ERROR `cfg(false)` is experimental
-fn foo() {}
-
-fn main() {
- cfg!(false); //~ ERROR `cfg(false)` is experimental
-}
diff --git a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr b/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr
deleted file mode 100644
index 6449146..0000000
--- a/tests/ui/feature-gates/feature-gate-cfg-boolean-literals.stderr
+++ /dev/null
@@ -1,43 +0,0 @@
-error[E0658]: `cfg(true)` is experimental and subject to change
- --> $DIR/feature-gate-cfg-boolean-literals.rs:1:7
- |
-LL | #[cfg(true)]
- | ^^^^
- |
- = note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
- = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `cfg(true)` is experimental and subject to change
- --> $DIR/feature-gate-cfg-boolean-literals.rs:4:12
- |
-LL | #[cfg_attr(true, cfg(false))]
- | ^^^^
- |
- = note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
- = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `cfg(false)` is experimental and subject to change
- --> $DIR/feature-gate-cfg-boolean-literals.rs:4:22
- |
-LL | #[cfg_attr(true, cfg(false))]
- | ^^^^^
- |
- = note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
- = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `cfg(false)` is experimental and subject to change
- --> $DIR/feature-gate-cfg-boolean-literals.rs:9:10
- |
-LL | cfg!(false);
- | ^^^^^
- |
- = note: see issue #131204 <https://github.com/rust-lang/rust/issues/131204> for more information
- = help: add `#![feature(cfg_boolean_literals)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-coroutines.rs b/tests/ui/feature-gates/feature-gate-coroutines.rs
index f20dc56..b37a61d 100644
--- a/tests/ui/feature-gates/feature-gate-coroutines.rs
+++ b/tests/ui/feature-gates/feature-gate-coroutines.rs
@@ -12,7 +12,7 @@ fn main() {
//~^^ ERROR `yield` can only be used
}
-#[cfg(FALSE)]
+#[cfg(false)]
fn foo() {
// Ok in 2024 edition
yield; //~ ERROR yield syntax is experimental
diff --git a/tests/ui/feature-gates/feature-gate-deref_patterns.rs b/tests/ui/feature-gates/feature-gate-deref_patterns.rs
index b43001f..53b4301 100644
--- a/tests/ui/feature-gates/feature-gate-deref_patterns.rs
+++ b/tests/ui/feature-gates/feature-gate-deref_patterns.rs
@@ -4,6 +4,6 @@
println!("x: {}", x);
// `box` syntax is allowed to be cfg-ed out for historical reasons (#65742).
- #[cfg(FALSE)]
+ #[cfg(false)]
let box _x = Box::new('c');
}
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed
new file mode 100644
index 0000000..525f78d
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.fixed
@@ -0,0 +1,45 @@
+// The purpose of this feature gate is to make something into a hard error in a
+// future edition. Consequently, this test differs from most other feature gate
+// tests. Instead of verifying that an error occurs when the feature gate is
+// missing, it ensures that the hard error is only produced with the feature
+// gate is present in the `future` edition -- and otherwise that only a warning
+// is emitted.
+
+//@ revisions: current current_feature future future_feature
+
+//@ [current] run-rustfix
+//@ [current] check-pass
+
+//@ [current_feature] run-rustfix
+//@ [current_feature] check-pass
+
+//@ [future] edition: future
+//@ [future] compile-flags: -Z unstable-options
+//@ [future] run-rustfix
+//@ [future] check-pass
+
+//@ [future_feature] edition: future
+//@ [future_feature] compile-flags: -Z unstable-options
+
+#![cfg_attr(future_feature, feature(explicit_extern_abis))]
+#![cfg_attr(current_feature, feature(explicit_extern_abis))]
+
+extern "C" fn _foo() {}
+//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
+//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
+
+unsafe extern "C" fn _bar() {}
+//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
+//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
+
+unsafe extern "C" {}
+//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
+//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr
new file mode 100644
index 0000000..cf92780
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current.stderr
@@ -0,0 +1,22 @@
+warning: `extern` declarations without an explicit ABI are deprecated
+ --> $DIR/feature-gate-explicit-extern-abis.rs:27:1
+ |
+LL | extern fn _foo() {}
+ | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
+ |
+ = note: `#[warn(missing_abi)]` on by default
+
+warning: `extern` declarations without an explicit ABI are deprecated
+ --> $DIR/feature-gate-explicit-extern-abis.rs:33:8
+ |
+LL | unsafe extern fn _bar() {}
+ | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
+
+warning: `extern` declarations without an explicit ABI are deprecated
+ --> $DIR/feature-gate-explicit-extern-abis.rs:39:8
+ |
+LL | unsafe extern {}
+ | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed
new file mode 100644
index 0000000..525f78d
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.fixed
@@ -0,0 +1,45 @@
+// The purpose of this feature gate is to make something into a hard error in a
+// future edition. Consequently, this test differs from most other feature gate
+// tests. Instead of verifying that an error occurs when the feature gate is
+// missing, it ensures that the hard error is only produced with the feature
+// gate is present in the `future` edition -- and otherwise that only a warning
+// is emitted.
+
+//@ revisions: current current_feature future future_feature
+
+//@ [current] run-rustfix
+//@ [current] check-pass
+
+//@ [current_feature] run-rustfix
+//@ [current_feature] check-pass
+
+//@ [future] edition: future
+//@ [future] compile-flags: -Z unstable-options
+//@ [future] run-rustfix
+//@ [future] check-pass
+
+//@ [future_feature] edition: future
+//@ [future_feature] compile-flags: -Z unstable-options
+
+#![cfg_attr(future_feature, feature(explicit_extern_abis))]
+#![cfg_attr(current_feature, feature(explicit_extern_abis))]
+
+extern "C" fn _foo() {}
+//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
+//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
+
+unsafe extern "C" fn _bar() {}
+//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
+//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
+
+unsafe extern "C" {}
+//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
+//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr
new file mode 100644
index 0000000..cf92780
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.current_feature.stderr
@@ -0,0 +1,22 @@
+warning: `extern` declarations without an explicit ABI are deprecated
+ --> $DIR/feature-gate-explicit-extern-abis.rs:27:1
+ |
+LL | extern fn _foo() {}
+ | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
+ |
+ = note: `#[warn(missing_abi)]` on by default
+
+warning: `extern` declarations without an explicit ABI are deprecated
+ --> $DIR/feature-gate-explicit-extern-abis.rs:33:8
+ |
+LL | unsafe extern fn _bar() {}
+ | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
+
+warning: `extern` declarations without an explicit ABI are deprecated
+ --> $DIR/feature-gate-explicit-extern-abis.rs:39:8
+ |
+LL | unsafe extern {}
+ | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed
new file mode 100644
index 0000000..525f78d
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.fixed
@@ -0,0 +1,45 @@
+// The purpose of this feature gate is to make something into a hard error in a
+// future edition. Consequently, this test differs from most other feature gate
+// tests. Instead of verifying that an error occurs when the feature gate is
+// missing, it ensures that the hard error is only produced with the feature
+// gate is present in the `future` edition -- and otherwise that only a warning
+// is emitted.
+
+//@ revisions: current current_feature future future_feature
+
+//@ [current] run-rustfix
+//@ [current] check-pass
+
+//@ [current_feature] run-rustfix
+//@ [current_feature] check-pass
+
+//@ [future] edition: future
+//@ [future] compile-flags: -Z unstable-options
+//@ [future] run-rustfix
+//@ [future] check-pass
+
+//@ [future_feature] edition: future
+//@ [future_feature] compile-flags: -Z unstable-options
+
+#![cfg_attr(future_feature, feature(explicit_extern_abis))]
+#![cfg_attr(current_feature, feature(explicit_extern_abis))]
+
+extern "C" fn _foo() {}
+//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
+//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
+
+unsafe extern "C" fn _bar() {}
+//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
+//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
+
+unsafe extern "C" {}
+//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
+//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr
new file mode 100644
index 0000000..cf92780
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future.stderr
@@ -0,0 +1,22 @@
+warning: `extern` declarations without an explicit ABI are deprecated
+ --> $DIR/feature-gate-explicit-extern-abis.rs:27:1
+ |
+LL | extern fn _foo() {}
+ | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
+ |
+ = note: `#[warn(missing_abi)]` on by default
+
+warning: `extern` declarations without an explicit ABI are deprecated
+ --> $DIR/feature-gate-explicit-extern-abis.rs:33:8
+ |
+LL | unsafe extern fn _bar() {}
+ | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
+
+warning: `extern` declarations without an explicit ABI are deprecated
+ --> $DIR/feature-gate-explicit-extern-abis.rs:39:8
+ |
+LL | unsafe extern {}
+ | ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr
new file mode 100644
index 0000000..096a6f4
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.future_feature.stderr
@@ -0,0 +1,26 @@
+error: `extern` declarations without an explicit ABI are disallowed
+ --> $DIR/feature-gate-explicit-extern-abis.rs:27:1
+ |
+LL | extern fn _foo() {}
+ | ^^^^^^ help: specify an ABI: `extern "<abi>"`
+ |
+ = help: prior to Rust 2024, a default ABI was inferred
+
+error: `extern` declarations without an explicit ABI are disallowed
+ --> $DIR/feature-gate-explicit-extern-abis.rs:33:8
+ |
+LL | unsafe extern fn _bar() {}
+ | ^^^^^^ help: specify an ABI: `extern "<abi>"`
+ |
+ = help: prior to Rust 2024, a default ABI was inferred
+
+error: `extern` declarations without an explicit ABI are disallowed
+ --> $DIR/feature-gate-explicit-extern-abis.rs:39:8
+ |
+LL | unsafe extern {}
+ | ^^^^^^ help: specify an ABI: `extern "<abi>"`
+ |
+ = help: prior to Rust 2024, a default ABI was inferred
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs
new file mode 100644
index 0000000..379c45f
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-explicit-extern-abis.rs
@@ -0,0 +1,45 @@
+// The purpose of this feature gate is to make something into a hard error in a
+// future edition. Consequently, this test differs from most other feature gate
+// tests. Instead of verifying that an error occurs when the feature gate is
+// missing, it ensures that the hard error is only produced with the feature
+// gate is present in the `future` edition -- and otherwise that only a warning
+// is emitted.
+
+//@ revisions: current current_feature future future_feature
+
+//@ [current] run-rustfix
+//@ [current] check-pass
+
+//@ [current_feature] run-rustfix
+//@ [current_feature] check-pass
+
+//@ [future] edition: future
+//@ [future] compile-flags: -Z unstable-options
+//@ [future] run-rustfix
+//@ [future] check-pass
+
+//@ [future_feature] edition: future
+//@ [future_feature] compile-flags: -Z unstable-options
+
+#![cfg_attr(future_feature, feature(explicit_extern_abis))]
+#![cfg_attr(current_feature, feature(explicit_extern_abis))]
+
+extern fn _foo() {}
+//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
+//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
+
+unsafe extern fn _bar() {}
+//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
+//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
+
+unsafe extern {}
+//[current]~^ WARN `extern` declarations without an explicit ABI are deprecated
+//[current_feature]~^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
+//[future_feature]~^^^^ ERROR `extern` declarations without an explicit ABI are disallowed
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-ffi_const.rs b/tests/ui/feature-gates/feature-gate-ffi_const.rs
index 9f3d783..35f91b99 100644
--- a/tests/ui/feature-gates/feature-gate-ffi_const.rs
+++ b/tests/ui/feature-gates/feature-gate-ffi_const.rs
@@ -1,6 +1,6 @@
#![crate_type = "lib"]
extern "C" {
- #[ffi_const] //~ ERROR the `#[ffi_const]` attribute is an experimental feature
+ #[unsafe(ffi_const)] //~ ERROR the `#[ffi_const]` attribute is an experimental feature
pub fn foo();
}
diff --git a/tests/ui/feature-gates/feature-gate-ffi_const.stderr b/tests/ui/feature-gates/feature-gate-ffi_const.stderr
index d083b82..7e8c941 100644
--- a/tests/ui/feature-gates/feature-gate-ffi_const.stderr
+++ b/tests/ui/feature-gates/feature-gate-ffi_const.stderr
@@ -1,8 +1,8 @@
error[E0658]: the `#[ffi_const]` attribute is an experimental feature
--> $DIR/feature-gate-ffi_const.rs:4:5
|
-LL | #[ffi_const]
- | ^^^^^^^^^^^^
+LL | #[unsafe(ffi_const)]
+ | ^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #58328 <https://github.com/rust-lang/rust/issues/58328> for more information
= help: add `#![feature(ffi_const)]` to the crate attributes to enable
diff --git a/tests/ui/feature-gates/feature-gate-ffi_pure.rs b/tests/ui/feature-gates/feature-gate-ffi_pure.rs
index b0dfa01..0f1288b 100644
--- a/tests/ui/feature-gates/feature-gate-ffi_pure.rs
+++ b/tests/ui/feature-gates/feature-gate-ffi_pure.rs
@@ -1,6 +1,6 @@
#![crate_type = "lib"]
extern "C" {
- #[ffi_pure] //~ ERROR the `#[ffi_pure]` attribute is an experimental feature
+ #[unsafe(ffi_pure)] //~ ERROR the `#[ffi_pure]` attribute is an experimental feature
pub fn foo();
}
diff --git a/tests/ui/feature-gates/feature-gate-ffi_pure.stderr b/tests/ui/feature-gates/feature-gate-ffi_pure.stderr
index 6544d45..cf92353 100644
--- a/tests/ui/feature-gates/feature-gate-ffi_pure.stderr
+++ b/tests/ui/feature-gates/feature-gate-ffi_pure.stderr
@@ -1,8 +1,8 @@
error[E0658]: the `#[ffi_pure]` attribute is an experimental feature
--> $DIR/feature-gate-ffi_pure.rs:4:5
|
-LL | #[ffi_pure]
- | ^^^^^^^^^^^
+LL | #[unsafe(ffi_pure)]
+ | ^^^^^^^^^^^^^^^^^^^
|
= note: see issue #58329 <https://github.com/rust-lang/rust/issues/58329> for more information
= help: add `#![feature(ffi_pure)]` to the crate attributes to enable
diff --git a/tests/ui/feature-gates/feature-gate-gen_blocks.rs b/tests/ui/feature-gates/feature-gate-gen_blocks.rs
index 01fd922..989daf4 100644
--- a/tests/ui/feature-gates/feature-gate-gen_blocks.rs
+++ b/tests/ui/feature-gates/feature-gate-gen_blocks.rs
@@ -17,7 +17,7 @@ fn test_async_gen() {
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn foo() {
gen {};
//[e2024]~^ ERROR: gen blocks are experimental
diff --git a/tests/ui/feature-gates/feature-gate-guard-patterns.rs b/tests/ui/feature-gates/feature-gate-guard-patterns.rs
index 52ed89e..74fb581 100644
--- a/tests/ui/feature-gates/feature-gate-guard-patterns.rs
+++ b/tests/ui/feature-gates/feature-gate-guard-patterns.rs
@@ -30,7 +30,7 @@ fn other_guards_dont() {
while let (x if guard(x)) = 0 {}
//~^ ERROR: guard patterns are experimental
- #[cfg(FALSE)]
+ #[cfg(false)]
while let (x if guard(x)) = 0 {}
//~^ ERROR: guard patterns are experimental
}
diff --git a/tests/ui/feature-gates/feature-gate-mut-ref.rs b/tests/ui/feature-gates/feature-gate-mut-ref.rs
index 806b25d..752ae35 100644
--- a/tests/ui/feature-gates/feature-gate-mut-ref.rs
+++ b/tests/ui/feature-gates/feature-gate-mut-ref.rs
@@ -6,8 +6,8 @@
let mut ref mut z = 14; //~ ERROR [E0658]
z = &mut 15;
- #[cfg(FALSE)]
+ #[cfg(false)]
let mut ref x = 10; //~ ERROR [E0658]
- #[cfg(FALSE)]
+ #[cfg(false)]
let mut ref mut y = 10; //~ ERROR [E0658]
}
diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.rs b/tests/ui/feature-gates/feature-gate-naked_functions.rs
deleted file mode 100644
index 77a67e0..0000000
--- a/tests/ui/feature-gates/feature-gate-naked_functions.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-//@ needs-asm-support
-
-use std::arch::naked_asm;
-//~^ ERROR use of unstable library feature `naked_functions`
-
-#[naked]
-//~^ ERROR the `#[naked]` attribute is an experimental feature
-extern "C" fn naked() {
- naked_asm!("")
- //~^ ERROR use of unstable library feature `naked_functions`
- //~| ERROR: requires unsafe
-}
-
-#[naked]
-//~^ ERROR the `#[naked]` attribute is an experimental feature
-extern "C" fn naked_2() -> isize {
- naked_asm!("")
- //~^ ERROR use of unstable library feature `naked_functions`
- //~| ERROR: requires unsafe
-}
-
-fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-naked_functions.stderr b/tests/ui/feature-gates/feature-gate-naked_functions.stderr
deleted file mode 100644
index 9bfb927..0000000
--- a/tests/ui/feature-gates/feature-gate-naked_functions.stderr
+++ /dev/null
@@ -1,70 +0,0 @@
-error[E0658]: use of unstable library feature `naked_functions`
- --> $DIR/feature-gate-naked_functions.rs:9:5
- |
-LL | naked_asm!("")
- | ^^^^^^^^^
- |
- = note: see issue #90957 <https://github.com/rust-lang/rust/issues/90957> for more information
- = help: add `#![feature(naked_functions)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature `naked_functions`
- --> $DIR/feature-gate-naked_functions.rs:17:5
- |
-LL | naked_asm!("")
- | ^^^^^^^^^
- |
- = note: see issue #90957 <https://github.com/rust-lang/rust/issues/90957> for more information
- = help: add `#![feature(naked_functions)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: the `#[naked]` attribute is an experimental feature
- --> $DIR/feature-gate-naked_functions.rs:6:1
- |
-LL | #[naked]
- | ^^^^^^^^
- |
- = note: see issue #90957 <https://github.com/rust-lang/rust/issues/90957> for more information
- = help: add `#![feature(naked_functions)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: the `#[naked]` attribute is an experimental feature
- --> $DIR/feature-gate-naked_functions.rs:14:1
- |
-LL | #[naked]
- | ^^^^^^^^
- |
- = note: see issue #90957 <https://github.com/rust-lang/rust/issues/90957> for more information
- = help: add `#![feature(naked_functions)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: use of unstable library feature `naked_functions`
- --> $DIR/feature-gate-naked_functions.rs:3:5
- |
-LL | use std::arch::naked_asm;
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #90957 <https://github.com/rust-lang/rust/issues/90957> for more information
- = help: add `#![feature(naked_functions)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
- --> $DIR/feature-gate-naked_functions.rs:9:5
- |
-LL | naked_asm!("")
- | ^^^^^^^^^^^^^^ use of inline assembly
- |
- = note: inline assembly is entirely unchecked and can cause undefined behavior
-
-error[E0133]: use of inline assembly is unsafe and requires unsafe function or block
- --> $DIR/feature-gate-naked_functions.rs:17:5
- |
-LL | naked_asm!("")
- | ^^^^^^^^^^^^^^ use of inline assembly
- |
- = note: inline assembly is entirely unchecked and can cause undefined behavior
-
-error: aborting due to 7 previous errors
-
-Some errors have detailed explanations: E0133, E0658.
-For more information about an error, try `rustc --explain E0133`.
diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs
new file mode 100644
index 0000000..d16c6cc
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.rs
@@ -0,0 +1,26 @@
+//@ needs-asm-support
+//@ only-x86_64
+
+#![feature(rust_cold_cc)]
+
+use std::arch::naked_asm;
+
+#[unsafe(naked)]
+pub unsafe fn rust_implicit() {
+ //~^ ERROR `#[naked]` is currently unstable on `extern "Rust"` functions
+ naked_asm!("ret");
+}
+
+#[unsafe(naked)]
+pub unsafe extern "Rust" fn rust_explicit() {
+ //~^ ERROR `#[naked]` is currently unstable on `extern "Rust"` functions
+ naked_asm!("ret");
+}
+
+#[unsafe(naked)]
+pub unsafe extern "rust-cold" fn rust_cold() {
+ //~^ ERROR `#[naked]` is currently unstable on `extern "rust-cold"` functions
+ naked_asm!("ret");
+}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.stderr b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.stderr
new file mode 100644
index 0000000..ba45e15
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-naked_functions_rustic_abi.stderr
@@ -0,0 +1,33 @@
+error[E0658]: `#[naked]` is currently unstable on `extern "Rust"` functions
+ --> $DIR/feature-gate-naked_functions_rustic_abi.rs:9:1
+ |
+LL | pub unsafe fn rust_implicit() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #138997 <https://github.com/rust-lang/rust/issues/138997> for more information
+ = help: add `#![feature(naked_functions_rustic_abi)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `#[naked]` is currently unstable on `extern "Rust"` functions
+ --> $DIR/feature-gate-naked_functions_rustic_abi.rs:15:1
+ |
+LL | pub unsafe extern "Rust" fn rust_explicit() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #138997 <https://github.com/rust-lang/rust/issues/138997> for more information
+ = help: add `#![feature(naked_functions_rustic_abi)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `#[naked]` is currently unstable on `extern "rust-cold"` functions
+ --> $DIR/feature-gate-naked_functions_rustic_abi.rs:21:1
+ |
+LL | pub unsafe extern "rust-cold" fn rust_cold() {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #138997 <https://github.com/rust-lang/rust/issues/138997> for more information
+ = help: add `#![feature(naked_functions_rustic_abi)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs
index 0d3af4c..1fee3e7 100644
--- a/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs
+++ b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.rs
@@ -1,11 +1,9 @@
//@ needs-asm-support
//@ only-x86_64
-#![feature(naked_functions)]
-
use std::arch::naked_asm;
-#[naked]
+#[unsafe(naked)]
#[target_feature(enable = "avx2")]
//~^ ERROR: `#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions
extern "C" fn naked() {
diff --git a/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr
index b0592d0..8e601a1 100644
--- a/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr
+++ b/tests/ui/feature-gates/feature-gate-naked_functions_target_feature.stderr
@@ -1,5 +1,5 @@
error[E0658]: `#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions
- --> $DIR/feature-gate-naked_functions_target_feature.rs:9:1
+ --> $DIR/feature-gate-naked_functions_target_feature.rs:7:1
|
LL | #[target_feature(enable = "avx2")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/feature-gates/feature-gate-never_patterns.rs b/tests/ui/feature-gates/feature-gate-never_patterns.rs
index d23405a..2cb0b5a 100644
--- a/tests/ui/feature-gates/feature-gate-never_patterns.rs
+++ b/tests/ui/feature-gates/feature-gate-never_patterns.rs
@@ -15,12 +15,12 @@ fn main() {
//~^ ERROR `!` patterns are experimental
}
// Check that the gate operates even behind `cfg`.
- #[cfg(FALSE)]
+ #[cfg(false)]
match *ptr {
!
//~^ ERROR `!` patterns are experimental
}
- #[cfg(FALSE)]
+ #[cfg(false)]
match *ptr {
! => {}
//~^ ERROR `!` patterns are experimental
@@ -60,13 +60,13 @@ fn main() {
// Check that the gate operates even behind `cfg`.
match Some(0) {
None => {}
- #[cfg(FALSE)]
+ #[cfg(false)]
Some(_)
//~^ ERROR `match` arm with no body
}
match Some(0) {
_ => {}
- #[cfg(FALSE)]
+ #[cfg(false)]
Some(_) if false
//~^ ERROR `match` arm with no body
}
diff --git a/tests/ui/feature-gates/feature-gate-postfix_match.rs b/tests/ui/feature-gates/feature-gate-postfix_match.rs
index dce7e81..2226816 100644
--- a/tests/ui/feature-gates/feature-gate-postfix_match.rs
+++ b/tests/ui/feature-gates/feature-gate-postfix_match.rs
@@ -9,7 +9,7 @@ fn main() {
};
// Test that the gate works behind a cfg
- #[cfg(FALSE)]
+ #[cfg(false)]
val.match { //~ ERROR postfix match is experimental
Some(42) => "the answer to life, the universe, and everything",
_ => "might be the answer to something"
diff --git a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs
deleted file mode 100644
index deb5a2f..0000000
--- a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//@ edition:2018
-#![forbid(internal_features, unsafe_code)]
-#![feature(unsafe_pin_internals)]
-//~^ ERROR the feature `unsafe_pin_internals` is internal to the compiler or standard library
-
-use core::{marker::PhantomPinned, pin::Pin};
-
-/// The `unsafe_pin_internals` is indeed unsound.
-fn non_unsafe_pin_new_unchecked<T>(pointer: &mut T) -> Pin<&mut T> {
- Pin { __pointer: pointer }
-}
-
-fn main() {
- let mut self_referential = PhantomPinned;
- let _: Pin<&mut PhantomPinned> = non_unsafe_pin_new_unchecked(&mut self_referential);
-}
diff --git a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr
deleted file mode 100644
index fc9bcd9..0000000
--- a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: the feature `unsafe_pin_internals` is internal to the compiler or standard library
- --> $DIR/feature-gate-unsafe_pin_internals.rs:3:12
- |
-LL | #![feature(unsafe_pin_internals)]
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = note: using it is strongly discouraged
-note: the lint level is defined here
- --> $DIR/feature-gate-unsafe_pin_internals.rs:2:11
- |
-LL | #![forbid(internal_features, unsafe_code)]
- | ^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs b/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs
index a32ebed..73a17c1 100644
--- a/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs
+++ b/tests/ui/feature-gates/feature-gate-yeet_expr-in-cfg.rs
@@ -1,7 +1,7 @@
//@ edition: 2021
pub fn demo() -> Option<i32> {
- #[cfg(FALSE)]
+ #[cfg(false)]
{
do yeet //~ ERROR `do yeet` expression is experimental
}
@@ -9,7 +9,7 @@ pub fn demo() -> Option<i32> {
Some(1)
}
-#[cfg(FALSE)]
+#[cfg(false)]
pub fn alternative() -> Result<(), String> {
do yeet "hello"; //~ ERROR `do yeet` expression is experimental
}
diff --git a/tests/ui/feature-gates/soft-syntax-gates-with-errors.rs b/tests/ui/feature-gates/soft-syntax-gates-with-errors.rs
index 2aa2ed3..87629a5 100644
--- a/tests/ui/feature-gates/soft-syntax-gates-with-errors.rs
+++ b/tests/ui/feature-gates/soft-syntax-gates-with-errors.rs
@@ -5,7 +5,7 @@
macro a() {}
//~^ ERROR: `macro` is experimental
-#[cfg(FALSE)]
+#[cfg(false)]
macro b() {}
macro_rules! identity {
@@ -17,13 +17,13 @@ macro_rules! identity {
//~^ ERROR: `macro` is experimental
}
-#[cfg(FALSE)]
+#[cfg(false)]
identity! {
macro d() {} // No error
}
identity! {
- #[cfg(FALSE)]
+ #[cfg(false)]
macro e() {}
}
diff --git a/tests/ui/feature-gates/soft-syntax-gates-without-errors.rs b/tests/ui/feature-gates/soft-syntax-gates-without-errors.rs
index 056c8fb..72d0bf1 100644
--- a/tests/ui/feature-gates/soft-syntax-gates-without-errors.rs
+++ b/tests/ui/feature-gates/soft-syntax-gates-without-errors.rs
@@ -2,7 +2,7 @@
// This file is used to test the behavior of the early-pass syntax warnings.
// If macro syntax is stabilized, replace with a different unstable syntax.
-#[cfg(FALSE)]
+#[cfg(false)]
macro b() {}
//~^ WARN: `macro` is experimental
//~| WARN: unstable syntax
@@ -11,13 +11,13 @@ macro_rules! identity {
($($x:tt)*) => ($($x)*);
}
-#[cfg(FALSE)]
+#[cfg(false)]
identity! {
macro d() {} // No error
}
identity! {
- #[cfg(FALSE)]
+ #[cfg(false)]
macro e() {}
//~^ WARN: `macro` is experimental
//~| WARN: unstable syntax
diff --git a/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs
index a160a9b..4523afa 100644
--- a/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs
+++ b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs
@@ -25,7 +25,7 @@ fn a() {}
// Check that cfg works right
-#[cfg(FALSE)]
+#[cfg(false)]
fn c() {
#[rustc_dummy]
5;
@@ -37,7 +37,7 @@ fn j() {
5;
}
-#[cfg_attr(not(FALSE), cfg(FALSE))]
+#[cfg_attr(not(FALSE), cfg(false))]
fn d() {
#[rustc_dummy]
8;
@@ -57,7 +57,7 @@ fn $e() {
#[rustc_dummy]
42;
- #[cfg(FALSE)]
+ #[cfg(false)]
fn f() {
#[rustc_dummy]
5;
@@ -69,7 +69,7 @@ fn k() {
5;
}
- #[cfg_attr(not(FALSE), cfg(FALSE))]
+ #[cfg_attr(not(FALSE), cfg(false))]
fn g() {
#[rustc_dummy]
8;
@@ -90,42 +90,42 @@ fn h() {
// check that the gate visitor works right:
extern "C" {
- #[cfg(FALSE)]
+ #[cfg(false)]
fn x(a: [u8; #[rustc_dummy] 5]);
fn y(a: [u8; #[rustc_dummy] 5]); //~ ERROR attributes on expressions are experimental
}
struct Foo;
impl Foo {
- #[cfg(FALSE)]
+ #[cfg(false)]
const X: u8 = #[rustc_dummy] 5;
const Y: u8 = #[rustc_dummy] 5; //~ ERROR attributes on expressions are experimental
}
trait Bar {
- #[cfg(FALSE)]
+ #[cfg(false)]
const X: [u8; #[rustc_dummy] 5];
const Y: [u8; #[rustc_dummy] 5]; //~ ERROR attributes on expressions are experimental
}
struct Joyce {
- #[cfg(FALSE)]
+ #[cfg(false)]
field: [u8; #[rustc_dummy] 5],
field2: [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental
}
struct Walky(
- #[cfg(FALSE)] [u8; #[rustc_dummy] 5],
+ #[cfg(false)] [u8; #[rustc_dummy] 5],
[u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental
);
enum Mike {
Happy(
- #[cfg(FALSE)] [u8; #[rustc_dummy] 5],
+ #[cfg(false)] [u8; #[rustc_dummy] 5],
[u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental
),
Angry {
- #[cfg(FALSE)]
+ #[cfg(false)]
field: [u8; #[rustc_dummy] 5],
field2: [u8; #[rustc_dummy] 5] //~ ERROR attributes on expressions are experimental
}
@@ -133,7 +133,7 @@ enum Mike {
fn pat() {
match 5 {
- #[cfg(FALSE)]
+ #[cfg(false)]
5 => #[rustc_dummy] (),
6 => #[rustc_dummy] (), //~ ERROR attributes on expressions are experimental
_ => (),
diff --git a/tests/ui/ffi-attrs/ffi_const.rs b/tests/ui/ffi-attrs/ffi_const.rs
index aa20a4d..dddc862 100644
--- a/tests/ui/ffi-attrs/ffi_const.rs
+++ b/tests/ui/ffi-attrs/ffi_const.rs
@@ -1,15 +1,18 @@
#![feature(ffi_const)]
#![crate_type = "lib"]
-#[ffi_const] //~ ERROR `#[ffi_const]` may only be used on foreign functions
+#[unsafe(ffi_const)] //~ ERROR `#[ffi_const]` may only be used on foreign functions
pub fn foo() {}
-#[ffi_const] //~ ERROR `#[ffi_const]` may only be used on foreign functions
+#[unsafe(ffi_const)] //~ ERROR `#[ffi_const]` may only be used on foreign functions
macro_rules! bar {
- () => ()
+ () => {};
}
extern "C" {
- #[ffi_const] //~ ERROR `#[ffi_const]` may only be used on foreign functions
+ #[unsafe(ffi_const)] //~ ERROR `#[ffi_const]` may only be used on foreign functions
static INT: i32;
+
+ #[ffi_const] //~ ERROR unsafe attribute used without unsafe
+ fn bar();
}
diff --git a/tests/ui/ffi-attrs/ffi_const.stderr b/tests/ui/ffi-attrs/ffi_const.stderr
index 394b98f..7f31237 100644
--- a/tests/ui/ffi-attrs/ffi_const.stderr
+++ b/tests/ui/ffi-attrs/ffi_const.stderr
@@ -1,21 +1,32 @@
+error: unsafe attribute used without unsafe
+ --> $DIR/ffi_const.rs:16:7
+ |
+LL | #[ffi_const]
+ | ^^^^^^^^^ usage of unsafe attribute
+ |
+help: wrap the attribute in `unsafe(...)`
+ |
+LL | #[unsafe(ffi_const)]
+ | +++++++ +
+
error[E0756]: `#[ffi_const]` may only be used on foreign functions
--> $DIR/ffi_const.rs:4:1
|
-LL | #[ffi_const]
- | ^^^^^^^^^^^^
+LL | #[unsafe(ffi_const)]
+ | ^^^^^^^^^^^^^^^^^^^^
error[E0756]: `#[ffi_const]` may only be used on foreign functions
--> $DIR/ffi_const.rs:7:1
|
-LL | #[ffi_const]
- | ^^^^^^^^^^^^
+LL | #[unsafe(ffi_const)]
+ | ^^^^^^^^^^^^^^^^^^^^
error[E0756]: `#[ffi_const]` may only be used on foreign functions
--> $DIR/ffi_const.rs:13:5
|
-LL | #[ffi_const]
- | ^^^^^^^^^^^^
+LL | #[unsafe(ffi_const)]
+ | ^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0756`.
diff --git a/tests/ui/ffi-attrs/ffi_const2.rs b/tests/ui/ffi-attrs/ffi_const2.rs
index 82fe8a9..8a8de13 100644
--- a/tests/ui/ffi-attrs/ffi_const2.rs
+++ b/tests/ui/ffi-attrs/ffi_const2.rs
@@ -1,8 +1,8 @@
#![feature(ffi_const, ffi_pure)]
extern "C" {
- #[ffi_pure] //~ ERROR `#[ffi_const]` function cannot be `#[ffi_pure]`
- #[ffi_const]
+ #[unsafe(ffi_pure)] //~ ERROR `#[ffi_const]` function cannot be `#[ffi_pure]`
+ #[unsafe(ffi_const)]
pub fn baz();
}
diff --git a/tests/ui/ffi-attrs/ffi_const2.stderr b/tests/ui/ffi-attrs/ffi_const2.stderr
index b8cbc29..d4c9bc4 100644
--- a/tests/ui/ffi-attrs/ffi_const2.stderr
+++ b/tests/ui/ffi-attrs/ffi_const2.stderr
@@ -1,8 +1,8 @@
error[E0757]: `#[ffi_const]` function cannot be `#[ffi_pure]`
--> $DIR/ffi_const2.rs:4:5
|
-LL | #[ffi_pure]
- | ^^^^^^^^^^^
+LL | #[unsafe(ffi_pure)]
+ | ^^^^^^^^^^^^^^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/ffi-attrs/ffi_pure.rs b/tests/ui/ffi-attrs/ffi_pure.rs
index 6d2f3a6..1f4812f 100644
--- a/tests/ui/ffi-attrs/ffi_pure.rs
+++ b/tests/ui/ffi-attrs/ffi_pure.rs
@@ -1,15 +1,18 @@
#![feature(ffi_pure)]
#![crate_type = "lib"]
-#[ffi_pure] //~ ERROR `#[ffi_pure]` may only be used on foreign functions
+#[unsafe(ffi_pure)] //~ ERROR `#[ffi_pure]` may only be used on foreign functions
pub fn foo() {}
-#[ffi_pure] //~ ERROR `#[ffi_pure]` may only be used on foreign functions
+#[unsafe(ffi_pure)] //~ ERROR `#[ffi_pure]` may only be used on foreign functions
macro_rules! bar {
- () => ()
+ () => {};
}
extern "C" {
- #[ffi_pure] //~ ERROR `#[ffi_pure]` may only be used on foreign functions
+ #[unsafe(ffi_pure)] //~ ERROR `#[ffi_pure]` may only be used on foreign functions
static INT: i32;
+
+ #[ffi_pure] //~ ERROR unsafe attribute used without unsafe
+ fn bar();
}
diff --git a/tests/ui/ffi-attrs/ffi_pure.stderr b/tests/ui/ffi-attrs/ffi_pure.stderr
index 8b61a4b..bd1177c 100644
--- a/tests/ui/ffi-attrs/ffi_pure.stderr
+++ b/tests/ui/ffi-attrs/ffi_pure.stderr
@@ -1,21 +1,32 @@
+error: unsafe attribute used without unsafe
+ --> $DIR/ffi_pure.rs:16:7
+ |
+LL | #[ffi_pure]
+ | ^^^^^^^^ usage of unsafe attribute
+ |
+help: wrap the attribute in `unsafe(...)`
+ |
+LL | #[unsafe(ffi_pure)]
+ | +++++++ +
+
error[E0755]: `#[ffi_pure]` may only be used on foreign functions
--> $DIR/ffi_pure.rs:4:1
|
-LL | #[ffi_pure]
- | ^^^^^^^^^^^
+LL | #[unsafe(ffi_pure)]
+ | ^^^^^^^^^^^^^^^^^^^
error[E0755]: `#[ffi_pure]` may only be used on foreign functions
--> $DIR/ffi_pure.rs:7:1
|
-LL | #[ffi_pure]
- | ^^^^^^^^^^^
+LL | #[unsafe(ffi_pure)]
+ | ^^^^^^^^^^^^^^^^^^^
error[E0755]: `#[ffi_pure]` may only be used on foreign functions
--> $DIR/ffi_pure.rs:13:5
|
-LL | #[ffi_pure]
- | ^^^^^^^^^^^
+LL | #[unsafe(ffi_pure)]
+ | ^^^^^^^^^^^^^^^^^^^
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0755`.
diff --git a/tests/ui/filter-block-view-items.rs b/tests/ui/filter-block-view-items.rs
index 975ab19..cb599c2 100644
--- a/tests/ui/filter-block-view-items.rs
+++ b/tests/ui/filter-block-view-items.rs
@@ -3,5 +3,5 @@
pub fn main() {
// Make sure that this view item is filtered out because otherwise it would
// trigger a compilation error
- #[cfg(FALSE)] use bar as foo;
+ #[cfg(false)] use bar as foo;
}
diff --git a/tests/ui/fn/suggest-return-closure.rs b/tests/ui/fn/suggest-return-closure.rs
index 30e25ca8..67be8de 100644
--- a/tests/ui/fn/suggest-return-closure.rs
+++ b/tests/ui/fn/suggest-return-closure.rs
@@ -19,6 +19,7 @@ fn fn_mut() -> _ {
let x = String::new();
//~^ HELP: consider changing this to be mutable
//~| NOTE binding `x` declared here
+ //~| SUGGESTION mut
|c| { //~ NOTE: value captured here
x.push(c);
//~^ ERROR: does not live long enough
diff --git a/tests/ui/fn/suggest-return-closure.stderr b/tests/ui/fn/suggest-return-closure.stderr
index 45c12b5..1860d1c 100644
--- a/tests/ui/fn/suggest-return-closure.stderr
+++ b/tests/ui/fn/suggest-return-closure.stderr
@@ -21,7 +21,7 @@
= note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
error[E0121]: the placeholder `_` is not allowed within types on item signatures for return types
- --> $DIR/suggest-return-closure.rs:32:13
+ --> $DIR/suggest-return-closure.rs:33:13
|
LL | fn fun() -> _ {
| ^
@@ -32,7 +32,7 @@
= note: for more information on `Fn` traits and closure types, see https://doc.rust-lang.org/book/ch13-01-closures.html
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
- --> $DIR/suggest-return-closure.rs:23:9
+ --> $DIR/suggest-return-closure.rs:24:9
|
LL | x.push(c);
| ^ cannot borrow as mutable
@@ -43,7 +43,7 @@
| +++
error[E0597]: `x` does not live long enough
- --> $DIR/suggest-return-closure.rs:23:9
+ --> $DIR/suggest-return-closure.rs:24:9
|
LL | let x = String::new();
| - binding `x` declared here
diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
index 85661c1..294fb67 100644
--- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
+++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.rs
@@ -3,7 +3,7 @@
}
fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
- //~^ ERROR: lifetime in trait object type must be followed by `+`
+ //~^ ERROR: lifetimes must be followed by `+` to form a trait object type
//~| ERROR: parenthesized generic arguments cannot be used
//~| ERROR associated type takes 0 generic arguments but 1 generic argument
//~| ERROR associated type takes 1 lifetime argument but 0 lifetime arguments
diff --git a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
index 99300ea..e18d819 100644
--- a/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
+++ b/tests/ui/generic-associated-types/gat-trait-path-parenthesised-args.stderr
@@ -1,8 +1,13 @@
-error: lifetime in trait object type must be followed by `+`
+error: lifetimes must be followed by `+` to form a trait object type
--> $DIR/gat-trait-path-parenthesised-args.rs:5:29
|
LL | fn foo<'a>(arg: Box<dyn X<Y('a) = &'a ()>>) {}
| ^^
+ |
+help: consider adding a trait bound after the potential lifetime bound
+ |
+LL | fn foo<'a>(arg: Box<dyn X<Y('a + /* Trait */) = &'a ()>>) {}
+ | +++++++++++++
error: parenthesized generic arguments cannot be used in associated type constraints
--> $DIR/gat-trait-path-parenthesised-args.rs:5:27
diff --git a/tests/ui/generic-associated-types/impl_bounds.stderr b/tests/ui/generic-associated-types/impl_bounds.stderr
index 231c0dd..7847bbd 100644
--- a/tests/ui/generic-associated-types/impl_bounds.stderr
+++ b/tests/ui/generic-associated-types/impl_bounds.stderr
@@ -57,14 +57,14 @@
|
LL | #[derive(Copy, Clone)]
| ^^^^ unsatisfied trait bound introduced in this `derive` macro
-note: the requirement `Fooy<T>: Copy` appears on the `impl`'s method `d` but not on the corresponding trait's method
+note: the requirement `Fooy<T>: Copy` appears on the `impl`'s associated function `d` but not on the corresponding trait's associated function
--> $DIR/impl_bounds.rs:7:8
|
LL | trait Foo {
| --- in this trait
...
LL | fn d() where Self: Clone;
- | ^ this trait's method doesn't have the requirement `Fooy<T>: Copy`
+ | ^ this trait's associated function doesn't have the requirement `Fooy<T>: Copy`
help: consider restricting type parameter `T` with trait `Copy`
|
LL | impl<T: std::marker::Copy> Foo for Fooy<T> {
diff --git a/tests/ui/generics/single-colon-path-not-const-generics.stderr b/tests/ui/generics/single-colon-path-not-const-generics.stderr
index c14a5e6..9eb62de 100644
--- a/tests/ui/generics/single-colon-path-not-const-generics.stderr
+++ b/tests/ui/generics/single-colon-path-not-const-generics.stderr
@@ -4,7 +4,6 @@
LL | a: Vec<foo::bar:A>,
| ^
|
- = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: use a double colon instead
|
LL | a: Vec<foo::bar::A>,
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs
index 33506a5..01f4340 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-dotdotdot-bad-syntax.rs
@@ -9,7 +9,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn syntax() {
match scrutinee {
...X => {} //~ ERROR range-to patterns with `...` are not allowed
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs
index 2f1ec65..24eb993 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-inclusive-no-end.rs
@@ -3,7 +3,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn foo() {
if let 0... = 1 {} //~ ERROR inclusive range with no end
if let 0..= = 1 {} //~ ERROR inclusive range with no end
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs
index 2d63fe0..6b33ead 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-ref-ambiguous-interp.rs
@@ -1,6 +1,6 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn syntax() {
match &0 {
&0.. | _ => {}
diff --git a/tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs b/tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs
index 4e3fffb..02699e7 100644
--- a/tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs
+++ b/tests/ui/half-open-range-patterns/half-open-range-pats-syntactic-pass.rs
@@ -4,7 +4,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn syntax() {
match scrutinee {
X.. | 0.. | 'a'.. | 0.0f32.. => {}
diff --git a/tests/ui/hygiene/rustc-macro-transparency.rs b/tests/ui/hygiene/rustc-macro-transparency.rs
index 5f36993..1a78a75 100644
--- a/tests/ui/hygiene/rustc-macro-transparency.rs
+++ b/tests/ui/hygiene/rustc-macro-transparency.rs
@@ -6,9 +6,9 @@
let transparent = 0;
}
#[rustc_macro_transparency = "semitransparent"]
-macro semitransparent() {
- struct SemiTransparent;
- let semitransparent = 0;
+macro semiopaque() {
+ struct SemiOpaque;
+ let semiopaque = 0;
}
#[rustc_macro_transparency = "opaque"]
macro opaque() {
@@ -18,14 +18,14 @@
fn main() {
transparent!();
- semitransparent!();
+ semiopaque!();
opaque!();
Transparent; // OK
- SemiTransparent; // OK
+ SemiOpaque; // OK
Opaque; //~ ERROR cannot find value `Opaque` in this scope
transparent; // OK
- semitransparent; //~ ERROR expected value, found macro `semitransparent`
+ semiopaque; //~ ERROR expected value, found macro `semiopaque`
opaque; //~ ERROR expected value, found macro `opaque`
}
diff --git a/tests/ui/hygiene/rustc-macro-transparency.stderr b/tests/ui/hygiene/rustc-macro-transparency.stderr
index 1d2a1e1..1bea8a0 100644
--- a/tests/ui/hygiene/rustc-macro-transparency.stderr
+++ b/tests/ui/hygiene/rustc-macro-transparency.stderr
@@ -4,17 +4,17 @@
LL | Opaque;
| ^^^^^^ not found in this scope
-error[E0423]: expected value, found macro `semitransparent`
+error[E0423]: expected value, found macro `semiopaque`
--> $DIR/rustc-macro-transparency.rs:29:5
|
-LL | struct SemiTransparent;
- | ----------------------- similarly named unit struct `SemiTransparent` defined here
+LL | struct SemiOpaque;
+ | ------------------ similarly named unit struct `SemiOpaque` defined here
...
-LL | semitransparent;
- | ^^^^^^^^^^^^^^^
+LL | semiopaque;
+ | ^^^^^^^^^^
| |
| not a value
- | help: a unit struct with a similar name exists: `SemiTransparent`
+ | help: a unit struct with a similar name exists (notice the capitalization): `SemiOpaque`
error[E0423]: expected value, found macro `opaque`
--> $DIR/rustc-macro-transparency.rs:30:5
diff --git a/tests/ui/hygiene/unpretty-debug.stdout b/tests/ui/hygiene/unpretty-debug.stdout
index e475cfa..f35bd7a 100644
--- a/tests/ui/hygiene/unpretty-debug.stdout
+++ b/tests/ui/hygiene/unpretty-debug.stdout
@@ -24,5 +24,5 @@
SyntaxContexts:
#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque)
-#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiTransparent)
+#1: parent: #0, outer_mark: (crate0::{{expn1}}, SemiOpaque)
*/
diff --git a/tests/ui/impl-trait/auto-trait-coherence.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.rs
similarity index 100%
rename from tests/ui/impl-trait/auto-trait-coherence.rs
rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.rs
diff --git a/tests/ui/impl-trait/auto-trait-coherence.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.stderr
similarity index 100%
rename from tests/ui/impl-trait/auto-trait-coherence.stderr
rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-coherence.stderr
diff --git a/tests/ui/impl-trait/auto-trait-contains-err.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.rs
similarity index 100%
rename from tests/ui/impl-trait/auto-trait-contains-err.rs
rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.rs
diff --git a/tests/ui/impl-trait/auto-trait-contains-err.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.stderr
similarity index 100%
rename from tests/ui/impl-trait/auto-trait-contains-err.stderr
rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-contains-err.stderr
diff --git a/tests/ui/impl-trait/auto-trait-leak-rpass.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak-rpass.rs
similarity index 100%
rename from tests/ui/impl-trait/auto-trait-leak-rpass.rs
rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak-rpass.rs
diff --git a/tests/ui/impl-trait/auto-trait-leak.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs
similarity index 100%
rename from tests/ui/impl-trait/auto-trait-leak.rs
rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.rs
diff --git a/tests/ui/impl-trait/auto-trait-leak.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr
similarity index 100%
rename from tests/ui/impl-trait/auto-trait-leak.stderr
rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak.stderr
diff --git a/tests/ui/impl-trait/auto-trait-leak2.rs b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.rs
similarity index 100%
rename from tests/ui/impl-trait/auto-trait-leak2.rs
rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.rs
diff --git a/tests/ui/impl-trait/auto-trait-leak2.stderr b/tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.stderr
similarity index 100%
rename from tests/ui/impl-trait/auto-trait-leak2.stderr
rename to tests/ui/impl-trait/auto-trait-leakage/auto-trait-leak2.stderr
diff --git a/tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs b/tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs
new file mode 100644
index 0000000..7f366fd
--- /dev/null
+++ b/tests/ui/impl-trait/auto-trait-leakage/avoid-query-cycle-via-item-bound.rs
@@ -0,0 +1,33 @@
+//@ check-pass
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+
+// When proving auto trait bounds, make sure that we depend on auto trait
+// leakage if we can also prove it via an item bound.
+fn is_send<T: Send>(_: T) {}
+
+fn direct() -> impl Send {
+ is_send(check(false)); // leaks auto traits, depends on `check`
+ 1u16
+}
+
+trait Indir: Send {}
+impl Indir for u32 {}
+fn indir() -> impl Indir {
+ is_send(check(false)); // leaks auto traits, depends on `check`
+ 1u32
+}
+
+fn check(b: bool) -> impl Sized {
+ if b {
+ // must not leak auto traits, as we otherwise get a query cycle.
+ is_send(direct());
+ is_send(indir());
+ }
+ 1u64
+}
+
+fn main() {
+ check(true);
+}
diff --git a/tests/ui/impl-trait/impl-trait-plus-priority.rs b/tests/ui/impl-trait/impl-trait-plus-priority.rs
index 5575493..8f76d41 100644
--- a/tests/ui/impl-trait/impl-trait-plus-priority.rs
+++ b/tests/ui/impl-trait/impl-trait-plus-priority.rs
@@ -27,7 +27,7 @@ fn f(self) -> A + B { // OK
type A = fn() -> dyn A + B;
//~^ ERROR ambiguous `+` in a type
type A = fn() -> A + B;
-//~^ ERROR expected a path on the left-hand side of `+`, not `fn() -> A`
+//~^ ERROR expected a path on the left-hand side of `+`
type A = Fn() -> impl A +;
//~^ ERROR ambiguous `+` in a type
@@ -44,6 +44,6 @@ fn f(self) -> A + B { // OK
type A = &dyn A + B;
//~^ ERROR ambiguous `+` in a type
type A = &A + B;
-//~^ ERROR expected a path on the left-hand side of `+`, not `&A`
+//~^ ERROR expected a path on the left-hand side of `+`
fn main() {}
diff --git a/tests/ui/impl-trait/impl-trait-plus-priority.stderr b/tests/ui/impl-trait/impl-trait-plus-priority.stderr
index 03e7910..1612065 100644
--- a/tests/ui/impl-trait/impl-trait-plus-priority.stderr
+++ b/tests/ui/impl-trait/impl-trait-plus-priority.stderr
@@ -31,11 +31,13 @@
LL | type A = fn() -> (dyn A + B);
| + +
-error[E0178]: expected a path on the left-hand side of `+`, not `fn() -> A`
+error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/impl-trait-plus-priority.rs:29:10
|
LL | type A = fn() -> A + B;
- | ^^^^^^^^^^^^^ perhaps you forgot parentheses?
+ | ^^^^^^^^^----
+ | |
+ | perhaps you forgot parentheses?
error: ambiguous `+` in a type
--> $DIR/impl-trait-plus-priority.rs:32:18
@@ -103,11 +105,11 @@
LL | type A = &(dyn A + B);
| + +
-error[E0178]: expected a path on the left-hand side of `+`, not `&A`
+error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/impl-trait-plus-priority.rs:46:10
|
LL | type A = &A + B;
- | ^^^^^^
+ | ^^
|
help: try adding parentheses
|
diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-2.rs b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-2.rs
new file mode 100644
index 0000000..e8329e3
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-2.rs
@@ -0,0 +1,12 @@
+trait Foo {
+ fn rpitit() -> impl Sized;
+}
+
+// Ensure that we don't try to probe the name of the RPITIT when looking for
+// fixes to suggest for the redundant generic below.
+
+fn test<T: Foo<i32, Assoc = i32>>() {}
+//~^ ERROR trait takes 0 generic arguments but 1 generic argument was supplied
+//~| ERROR associated type `Assoc` not found for `Foo`
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-2.stderr b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-2.stderr
new file mode 100644
index 0000000..1058ef0
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-2.stderr
@@ -0,0 +1,24 @@
+error[E0107]: trait takes 0 generic arguments but 1 generic argument was supplied
+ --> $DIR/dont-probe-missing-item-name-2.rs:8:12
+ |
+LL | fn test<T: Foo<i32, Assoc = i32>>() {}
+ | ^^^------------------ help: remove the unnecessary generics
+ | |
+ | expected 0 generic arguments
+ |
+note: trait defined here, with 0 generic parameters
+ --> $DIR/dont-probe-missing-item-name-2.rs:1:7
+ |
+LL | trait Foo {
+ | ^^^
+
+error[E0220]: associated type `Assoc` not found for `Foo`
+ --> $DIR/dont-probe-missing-item-name-2.rs:8:21
+ |
+LL | fn test<T: Foo<i32, Assoc = i32>>() {}
+ | ^^^^^ associated type `Assoc` not found
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0107, E0220.
+For more information about an error, try `rustc --explain E0107`.
diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-3.rs b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-3.rs
new file mode 100644
index 0000000..db39bb3
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-3.rs
@@ -0,0 +1,11 @@
+trait Trait {
+ fn method() -> impl Sized;
+}
+
+// Ensure that we don't try to probe the name of the RPITIT when looking for
+// fixes to suggest for the missing associated type's trait path below.
+
+fn foo() -> i32::Assoc {}
+//~^ ERROR ambiguous associated type
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-3.stderr b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-3.stderr
new file mode 100644
index 0000000..f30d022
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name-3.stderr
@@ -0,0 +1,15 @@
+error[E0223]: ambiguous associated type
+ --> $DIR/dont-probe-missing-item-name-3.rs:8:13
+ |
+LL | fn foo() -> i32::Assoc {}
+ | ^^^^^^^^^^
+ |
+help: if there were a trait named `Example` with associated type `Assoc` implemented for `i32`, you could use the fully-qualified path
+ |
+LL - fn foo() -> i32::Assoc {}
+LL + fn foo() -> <i32 as Example>::Assoc {}
+ |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0223`.
diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs
new file mode 100644
index 0000000..450f41e
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.rs
@@ -0,0 +1,12 @@
+// Regression test for <https://github.com/rust-lang/rust/issues/139873>.
+
+// Test that we don't try to get the (nonexistent) name of the RPITIT in `Trait::foo`
+// when emitting an error for a missing associated item `Trait::Output`.
+
+trait Trait {
+ fn foo() -> impl Sized;
+ fn bar() -> Self::Output;
+ //~^ ERROR associated type `Output` not found for `Self`
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.stderr b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.stderr
new file mode 100644
index 0000000..74e1578
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/dont-probe-missing-item-name.stderr
@@ -0,0 +1,9 @@
+error[E0220]: associated type `Output` not found for `Self`
+ --> $DIR/dont-probe-missing-item-name.rs:8:23
+ |
+LL | fn bar() -> Self::Output;
+ | ^^^^^^ associated type `Output` not found
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0220`.
diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr
new file mode 100644
index 0000000..bf598d6
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.current.stderr
@@ -0,0 +1,58 @@
+error[E0391]: cycle detected when computing type of `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::{anon_assoc#0}`
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:24
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^
+ |
+note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:24
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^
+ = note: ...which requires evaluating trait selection obligation `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo::{opaque#0}: core::marker::Send`...
+note: ...which requires computing type of opaque `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo::{opaque#0}`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:24
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^
+note: ...which requires borrow-checking `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires promoting constants in MIR for `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires checking if `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo` contains FFI-unwind calls...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires building MIR for `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires match-checking `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires type-checking `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: ...which again requires computing type of `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::{anon_assoc#0}`, completing the cycle
+note: cycle used when checking that `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>` is well-formed
+ --> $DIR/method-compatability-via-leakage-cycle.rs:17:1
+ |
+LL | impl Trait for u32 {
+ | ^^^^^^^^^^^^^^^^^^
+ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr
new file mode 100644
index 0000000..6bec5bb
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.next.stderr
@@ -0,0 +1,122 @@
+error[E0391]: cycle detected when computing type of `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::{anon_assoc#0}`
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:24
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^
+ |
+note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires computing type of `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo::{opaque#0}`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:24
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^
+note: ...which requires computing type of opaque `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo::{opaque#0}`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:24
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^
+note: ...which requires borrow-checking `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires promoting constants in MIR for `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires checking if `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo` contains FFI-unwind calls...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires building MIR for `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires match-checking `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires type-checking `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: ...which again requires computing type of `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::{anon_assoc#0}`, completing the cycle
+note: cycle used when checking that `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>` is well-formed
+ --> $DIR/method-compatability-via-leakage-cycle.rs:17:1
+ |
+LL | impl Trait for u32 {
+ | ^^^^^^^^^^^^^^^^^^
+ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+
+error[E0391]: cycle detected when computing type of `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::{anon_assoc#0}`
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:24
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^
+ |
+note: ...which requires comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires computing type of `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo::{opaque#0}`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:24
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^
+note: ...which requires computing type of opaque `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo::{opaque#0}`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:24
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^
+note: ...which requires borrow-checking `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires promoting constants in MIR for `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires checking if `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo` contains FFI-unwind calls...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires building MIR for `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires match-checking `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires type-checking `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::foo`...
+ --> $DIR/method-compatability-via-leakage-cycle.rs:21:5
+ |
+LL | fn foo(b: bool) -> impl Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: ...which again requires computing type of `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>::{anon_assoc#0}`, completing the cycle
+note: cycle used when checking that `<impl at $DIR/method-compatability-via-leakage-cycle.rs:17:1: 17:19>` is well-formed
+ --> $DIR/method-compatability-via-leakage-cycle.rs:17:1
+ |
+LL | impl Trait for u32 {
+ | ^^^^^^^^^^^^^^^^^^
+ = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0391`.
diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.rs b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.rs
new file mode 100644
index 0000000..917820d
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage-cycle.rs
@@ -0,0 +1,30 @@
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@ known-bug: #139788
+
+// Recursively using the trait method inside of an impl in case checking
+// method compatability relies on opaque type leakage currently causes a
+// cycle error.
+
+trait Trait {
+ // desugars to
+ // type Assoc: Sized + Send;
+ // fn foo(b: bool) -> Self::Assoc;
+ fn foo(b: bool) -> impl Sized + Send;
+}
+
+impl Trait for u32 {
+ // desugars to
+ // type Assoc = impl_rpit::<Self>;
+ // fn foo(b: bool) -> Self::Assoc { .. }
+ fn foo(b: bool) -> impl Sized {
+ if b {
+ u32::foo(false)
+ } else {
+ 1u32
+ }
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/method-compatability-via-leakage.rs b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage.rs
new file mode 100644
index 0000000..249ec07
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/method-compatability-via-leakage.rs
@@ -0,0 +1,14 @@
+//@ check-pass
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
+
+trait Trait {
+ fn foo() -> impl Sized + Send;
+}
+
+impl Trait for u32 {
+ fn foo() -> impl Sized {}
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/refine-cycle.rs b/tests/ui/impl-trait/in-trait/refine-cycle.rs
index 78d672a..d97f982 100644
--- a/tests/ui/impl-trait/in-trait/refine-cycle.rs
+++ b/tests/ui/impl-trait/in-trait/refine-cycle.rs
@@ -1,4 +1,7 @@
//@ check-pass
+//@ revisions: current next
+//@[next] compile-flags: -Znext-solver
+//@ ignore-compare-mode-next-solver (explicit revisions)
// Make sure that refinement checking doesn't cause a cycle in `Instance::resolve`
// which calls `compare_impl_item`.
diff --git a/tests/ui/impl-unused-tps.stderr b/tests/ui/impl-unused-tps.stderr
index 09c3fce..eff5fff 100644
--- a/tests/ui/impl-unused-tps.stderr
+++ b/tests/ui/impl-unused-tps.stderr
@@ -7,23 +7,6 @@
LL | impl<T, U> Foo<T> for U {
| ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `[isize; 0]`
-error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
- --> $DIR/impl-unused-tps.rs:32:9
- |
-LL | impl<T, U> Bar for T {
- | ^ unconstrained type parameter
-
-error[E0119]: conflicting implementations of trait `Bar`
- --> $DIR/impl-unused-tps.rs:40:1
- |
-LL | impl<T, U> Bar for T {
- | -------------------- first implementation here
-...
-LL | / impl<T, U> Bar for T
-LL | | where
-LL | | T: Bar<Out = U>,
- | |____________________^ conflicting implementation
-
error[E0119]: conflicting implementations of trait `Foo<[isize; 0]>` for type `[isize; 0]`
--> $DIR/impl-unused-tps.rs:49:1
|
@@ -53,6 +36,12 @@
| ^ unconstrained type parameter
error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
+ --> $DIR/impl-unused-tps.rs:32:9
+ |
+LL | impl<T, U> Bar for T {
+ | ^ unconstrained type parameter
+
+error[E0207]: the type parameter `U` is not constrained by the impl trait, self type, or predicates
--> $DIR/impl-unused-tps.rs:40:9
|
LL | impl<T, U> Bar for T
@@ -70,6 +59,17 @@
LL | impl<T, U, V> Foo<T> for T
| ^ unconstrained type parameter
+error[E0119]: conflicting implementations of trait `Bar`
+ --> $DIR/impl-unused-tps.rs:40:1
+ |
+LL | impl<T, U> Bar for T {
+ | -------------------- first implementation here
+...
+LL | / impl<T, U> Bar for T
+LL | | where
+LL | | T: Bar<Out = U>,
+ | |____________________^ conflicting implementation
+
error: aborting due to 9 previous errors
Some errors have detailed explanations: E0119, E0207.
diff --git a/tests/ui/inference/auto-instantiate.rs b/tests/ui/inference/auto-instantiate.rs
new file mode 100644
index 0000000..bf43330
--- /dev/null
+++ b/tests/ui/inference/auto-instantiate.rs
@@ -0,0 +1,28 @@
+//! Check that type parameters in generic function arg position and in "nested" return type position
+//! can be inferred on an invocation of the generic function.
+//!
+//! See <https://github.com/rust-lang/rust/issues/45>.
+
+//@ run-pass
+
+#![allow(dead_code)]
+#[derive(Debug)]
+struct Pair<T, U> {
+ a: T,
+ b: U,
+}
+
+struct Triple {
+ x: isize,
+ y: isize,
+ z: isize,
+}
+
+fn f<T, U>(x: T, y: U) -> Pair<T, U> {
+ return Pair { a: x, b: y };
+}
+
+pub fn main() {
+ println!("{}", f(Triple {x: 3, y: 4, z: 5}, 4).a.x);
+ println!("{}", f(5, 6).a);
+}
diff --git a/tests/ui/inner-attrs-on-impl.rs b/tests/ui/inner-attrs-on-impl.rs
index 75f4062..1dce1cd 100644
--- a/tests/ui/inner-attrs-on-impl.rs
+++ b/tests/ui/inner-attrs-on-impl.rs
@@ -3,7 +3,7 @@
struct Foo;
impl Foo {
- #![cfg(FALSE)]
+ #![cfg(false)]
fn method(&self) -> bool { false }
}
@@ -12,7 +12,7 @@ impl Foo {
#![cfg(not(FALSE))]
// check that we don't eat attributes too eagerly.
- #[cfg(FALSE)]
+ #[cfg(false)]
fn method(&self) -> bool { false }
fn method(&self) -> bool { true }
diff --git a/tests/ui/intrinsics/intrinsic-atomics.rs b/tests/ui/intrinsics/intrinsic-atomics.rs
index 6bc3f8d..9127cc6 100644
--- a/tests/ui/intrinsics/intrinsic-atomics.rs
+++ b/tests/ui/intrinsics/intrinsic-atomics.rs
@@ -1,53 +1,6 @@
//@ run-pass
-#![feature(intrinsics)]
-
-mod rusti {
-
- #[rustc_intrinsic]
- pub unsafe fn atomic_cxchg_seqcst_seqcst<T>(dst: *mut T, old: T, src: T) -> (T, bool);
- #[rustc_intrinsic]
- pub unsafe fn atomic_cxchg_acquire_acquire<T>(dst: *mut T, old: T, src: T) -> (T, bool);
- #[rustc_intrinsic]
- pub unsafe fn atomic_cxchg_release_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
-
- #[rustc_intrinsic]
- pub unsafe fn atomic_cxchgweak_seqcst_seqcst<T>(dst: *mut T, old: T, src: T) -> (T, bool);
- #[rustc_intrinsic]
- pub unsafe fn atomic_cxchgweak_acquire_acquire<T>(dst: *mut T, old: T, src: T) -> (T, bool);
- #[rustc_intrinsic]
- pub unsafe fn atomic_cxchgweak_release_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
-
- #[rustc_intrinsic]
- pub unsafe fn atomic_load_seqcst<T>(src: *const T) -> T;
- #[rustc_intrinsic]
- pub unsafe fn atomic_load_acquire<T>(src: *const T) -> T;
-
- #[rustc_intrinsic]
- pub unsafe fn atomic_store_seqcst<T>(dst: *mut T, val: T);
- #[rustc_intrinsic]
- pub unsafe fn atomic_store_release<T>(dst: *mut T, val: T);
-
- #[rustc_intrinsic]
- pub unsafe fn atomic_xchg_seqcst<T>(dst: *mut T, src: T) -> T;
- #[rustc_intrinsic]
- pub unsafe fn atomic_xchg_acquire<T>(dst: *mut T, src: T) -> T;
- #[rustc_intrinsic]
- pub unsafe fn atomic_xchg_release<T>(dst: *mut T, src: T) -> T;
-
- #[rustc_intrinsic]
- pub unsafe fn atomic_xadd_seqcst<T>(dst: *mut T, src: T) -> T;
- #[rustc_intrinsic]
- pub unsafe fn atomic_xadd_acquire<T>(dst: *mut T, src: T) -> T;
- #[rustc_intrinsic]
- pub unsafe fn atomic_xadd_release<T>(dst: *mut T, src: T) -> T;
-
- #[rustc_intrinsic]
- pub unsafe fn atomic_xsub_seqcst<T>(dst: *mut T, src: T) -> T;
- #[rustc_intrinsic]
- pub unsafe fn atomic_xsub_acquire<T>(dst: *mut T, src: T) -> T;
- #[rustc_intrinsic]
- pub unsafe fn atomic_xsub_release<T>(dst: *mut T, src: T) -> T;
-}
+#![feature(core_intrinsics)]
+use std::intrinsics as rusti;
pub fn main() {
unsafe {
diff --git a/tests/ui/invalid-compile-flags/emit-output-types-without-args.rs b/tests/ui/invalid-compile-flags/emit-output-types-without-args.rs
new file mode 100644
index 0000000..a96eeb0
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/emit-output-types-without-args.rs
@@ -0,0 +1,2 @@
+//@ compile-flags: --emit
+//@ error-pattern: Argument to option 'emit' missing
diff --git a/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr b/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr
new file mode 100644
index 0000000..669913b
--- /dev/null
+++ b/tests/ui/invalid-compile-flags/emit-output-types-without-args.stderr
@@ -0,0 +1,15 @@
+error: Argument to option 'emit' missing
+ Usage:
+ --emit TYPE[=FILE] Comma separated list of types of output for the
+ compiler to emit.
+ Each TYPE has the default FILE name:
+ * asm - CRATE_NAME.s
+ * llvm-bc - CRATE_NAME.bc
+ * dep-info - CRATE_NAME.d
+ * link - (platform and crate-type dependent)
+ * llvm-ir - CRATE_NAME.ll
+ * metadata - libCRATE_NAME.rmeta
+ * mir - CRATE_NAME.mir
+ * obj - CRATE_NAME.o
+ * thin-link-bitcode - CRATE_NAME.indexing.o
+
diff --git a/tests/ui/invalid-compile-flags/print-without-arg.stderr b/tests/ui/invalid-compile-flags/print-without-arg.stderr
index 8abaee5..fd2a36e 100644
--- a/tests/ui/invalid-compile-flags/print-without-arg.stderr
+++ b/tests/ui/invalid-compile-flags/print-without-arg.stderr
@@ -1,5 +1,6 @@
error: Argument to option 'print' missing
Usage:
- --print [all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models]
- Compiler information to print on stdout
+ --print INFO[=FILE] Compiler information to print on stdout (or to a file)
+ INFO may be one of
+ (all-target-specs-json|calling-conventions|cfg|check-cfg|code-models|crate-name|crate-root-lint-levels|deployment-target|file-names|host-tuple|link-args|native-static-libs|relocation-models|split-debuginfo|stack-protector-strategies|supported-crate-types|sysroot|target-cpus|target-features|target-libdir|target-list|target-spec-json|tls-models).
diff --git a/tests/ui/issues/auxiliary/issue-14421.rs b/tests/ui/issues/auxiliary/issue-14421.rs
deleted file mode 100644
index 5fe4b24..0000000
--- a/tests/ui/issues/auxiliary/issue-14421.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-#![crate_type="lib"]
-#![deny(warnings)]
-#![allow(dead_code)]
-
-pub use src::aliases::B;
-pub use src::hidden_core::make;
-
-mod src {
- pub mod aliases {
- use super::hidden_core::A;
- pub type B = A<f32>;
- }
-
- pub mod hidden_core {
- use super::aliases::B;
-
- pub struct A<T> { t: T }
-
- pub fn make() -> B { A { t: 1.0 } }
-
- impl<T> A<T> {
- pub fn foo(&mut self) { println!("called foo"); }
- }
- }
-}
diff --git a/tests/ui/issues/issue-11004.rs b/tests/ui/issues/issue-11004.rs
index 714fa51..0c34554 100644
--- a/tests/ui/issues/issue-11004.rs
+++ b/tests/ui/issues/issue-11004.rs
@@ -9,7 +9,7 @@ unsafe fn access(n:*mut A) -> (i32, f64) {
(x, y)
}
-#[cfg(FALSE)]
+#[cfg(false)]
unsafe fn access(n:*mut A) -> (i32, f64) {
let x : i32 = (*n).x;
let y : f64 = (*n).y;
diff --git a/tests/ui/issues/issue-11085.rs b/tests/ui/issues/issue-11085.rs
index d0703b0..c3f1319 100644
--- a/tests/ui/issues/issue-11085.rs
+++ b/tests/ui/issues/issue-11085.rs
@@ -3,7 +3,7 @@
#![allow(dead_code)]
struct Foo {
- #[cfg(FALSE)]
+ #[cfg(false)]
bar: baz,
foo: isize,
}
@@ -15,18 +15,18 @@ struct Foo2 {
enum Bar1 {
Bar1_1,
- #[cfg(FALSE)]
+ #[cfg(false)]
Bar1_2(NotAType),
}
enum Bar2 {
- #[cfg(FALSE)]
+ #[cfg(false)]
Bar2_1(NotAType),
}
enum Bar3 {
Bar3_1 {
- #[cfg(FALSE)]
+ #[cfg(false)]
foo: isize,
bar: isize,
}
diff --git a/tests/ui/issues/issue-14421.rs b/tests/ui/issues/issue-14421.rs
deleted file mode 100644
index b703858..0000000
--- a/tests/ui/issues/issue-14421.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ run-pass
-#![allow(non_snake_case)]
-
-//@ aux-build:issue-14421.rs
-
-
-extern crate issue_14421 as bug_lib;
-
-use bug_lib::B;
-use bug_lib::make;
-
-pub fn main() {
- let mut an_A: B = make();
- an_A.foo();
-}
diff --git a/tests/ui/issues/issue-16819.rs b/tests/ui/issues/issue-16819.rs
index e2b1090..2805c82 100644
--- a/tests/ui/issues/issue-16819.rs
+++ b/tests/ui/issues/issue-16819.rs
@@ -3,7 +3,7 @@
// `#[cfg]` on struct field permits empty unusable struct
struct S {
- #[cfg(FALSE)]
+ #[cfg(false)]
a: int,
}
diff --git a/tests/ui/issues/issue-16939.rs b/tests/ui/issues/issue-16939.rs
deleted file mode 100644
index ad72483..0000000
--- a/tests/ui/issues/issue-16939.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-// Make sure we don't ICE when making an overloaded call with the
-// wrong arity.
-
-fn _foo<F: Fn()> (f: F) {
- |t| f(t); //~ ERROR E0057
-}
-
-fn main() {}
diff --git a/tests/ui/issues/issue-16939.stderr b/tests/ui/issues/issue-16939.stderr
deleted file mode 100644
index 6e0889b..0000000
--- a/tests/ui/issues/issue-16939.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error[E0057]: this function takes 0 arguments but 1 argument was supplied
- --> $DIR/issue-16939.rs:5:9
- |
-LL | |t| f(t);
- | ^ - unexpected argument
- |
-note: callable defined here
- --> $DIR/issue-16939.rs:4:12
- |
-LL | fn _foo<F: Fn()> (f: F) {
- | ^^^^
-help: remove the extra argument
- |
-LL - |t| f(t);
-LL + |t| f();
- |
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0057`.
diff --git a/tests/ui/issues/issue-23808.rs b/tests/ui/issues/issue-23808.rs
deleted file mode 100644
index 6af0bd4..0000000
--- a/tests/ui/issues/issue-23808.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-//@ run-pass
-
-#![deny(dead_code)]
-
-// use different types / traits to test all combinations
-
-trait Const {
- const C: ();
-}
-
-trait StaticFn {
- fn sfn();
-}
-
-struct ConstStruct;
-struct StaticFnStruct;
-
-enum ConstEnum {}
-enum StaticFnEnum {}
-
-struct AliasedConstStruct;
-struct AliasedStaticFnStruct;
-
-enum AliasedConstEnum {}
-enum AliasedStaticFnEnum {}
-
-type AliasConstStruct = AliasedConstStruct;
-type AliasStaticFnStruct = AliasedStaticFnStruct;
-type AliasConstEnum = AliasedConstEnum;
-type AliasStaticFnEnum = AliasedStaticFnEnum;
-
-macro_rules! impl_Const {($($T:ident),*) => {$(
- impl Const for $T {
- const C: () = ();
- }
-)*}}
-
-macro_rules! impl_StaticFn {($($T:ident),*) => {$(
- impl StaticFn for $T {
- fn sfn() {}
- }
-)*}}
-
-impl_Const!(ConstStruct, ConstEnum, AliasedConstStruct, AliasedConstEnum);
-impl_StaticFn!(StaticFnStruct, StaticFnEnum, AliasedStaticFnStruct, AliasedStaticFnEnum);
-
-fn main() {
- let () = ConstStruct::C;
- let () = ConstEnum::C;
-
- StaticFnStruct::sfn();
- StaticFnEnum::sfn();
-
- let () = AliasConstStruct::C;
- let () = AliasConstEnum::C;
-
- AliasStaticFnStruct::sfn();
- AliasStaticFnEnum::sfn();
-}
diff --git a/tests/ui/issues/issue-37131.rs b/tests/ui/issues/issue-37131.rs
index 16681ac..e91c76e 100644
--- a/tests/ui/issues/issue-37131.rs
+++ b/tests/ui/issues/issue-37131.rs
@@ -1,4 +1,6 @@
//~ ERROR can't find crate for `std`
+//~| NOTE target may not be installed
+//~| NOTE can't find crate
// Tests that compiling for a target which is not installed will result in a helpful
// error message.
@@ -6,5 +8,4 @@
//@ ignore-arm
//@ needs-llvm-components: arm
-//@ error-pattern:target may not be installed
fn main() { }
diff --git a/tests/ui/issues/issue-9719.rs b/tests/ui/issues/issue-9719.rs
deleted file mode 100644
index 904768c..0000000
--- a/tests/ui/issues/issue-9719.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-//@ build-pass
-#![allow(dead_code)]
-
-mod a {
- pub enum Enum<T> {
- A(T),
- }
-
- pub trait X {
- fn dummy(&self) { }
- }
- impl X for isize {}
-
- pub struct Z<'a>(Enum<&'a (dyn X + 'a)>);
- fn foo() { let x: isize = 42; let z = Z(Enum::A(&x as &dyn X)); let _ = z; }
-}
-
-mod b {
- trait X {
- fn dummy(&self) { }
- }
- impl X for isize {}
- struct Y<'a>{
- x:Option<&'a (dyn X + 'a)>,
- }
-
- fn bar() {
- let x: isize = 42;
- let _y = Y { x: Some(&x as &dyn X) };
- }
-}
-
-mod c {
- pub trait X { fn f(&self); }
- impl X for isize { fn f(&self) {} }
- pub struct Z<'a>(Option<&'a (dyn X + 'a)>);
- fn main() { let x: isize = 42; let z = Z(Some(&x as &dyn X)); let _ = z; }
-}
-
-pub fn main() {}
diff --git a/tests/ui/layout/unknown-when-no-type-parameter.rs b/tests/ui/layout/unknown-when-no-type-parameter.rs
index 500b793..87f90aa 100644
--- a/tests/ui/layout/unknown-when-no-type-parameter.rs
+++ b/tests/ui/layout/unknown-when-no-type-parameter.rs
@@ -1,13 +1,13 @@
#![feature(trivial_bounds)]
-//@ error-pattern: the type `<() as Project>::Assoc` has an unknown layout
-
trait Project {
type Assoc;
}
fn foo() where (): Project {
[(); size_of::<<() as Project>::Assoc>()]; //~ ERROR evaluation of constant value failed
+ //~| NOTE the type `<() as Project>::Assoc` has an unknown layout
+ //~| NOTE inside `std::mem::size_of::<<() as Project>::Assoc>`
}
fn main() {}
diff --git a/tests/ui/layout/unknown-when-no-type-parameter.stderr b/tests/ui/layout/unknown-when-no-type-parameter.stderr
index a2dbb19..35fbb11 100644
--- a/tests/ui/layout/unknown-when-no-type-parameter.stderr
+++ b/tests/ui/layout/unknown-when-no-type-parameter.stderr
@@ -1,5 +1,5 @@
error[E0080]: evaluation of constant value failed
- --> $DIR/unknown-when-no-type-parameter.rs:10:10
+ --> $DIR/unknown-when-no-type-parameter.rs:8:10
|
LL | [(); size_of::<<() as Project>::Assoc>()];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the type `<() as Project>::Assoc` has an unknown layout
diff --git a/tests/ui/lazy-and-or.rs b/tests/ui/lazy-and-or.rs
deleted file mode 100644
index f9dbeb6..0000000
--- a/tests/ui/lazy-and-or.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//@ run-pass
-
-fn incr(x: &mut isize) -> bool { *x += 1; assert!((false)); return false; }
-
-pub fn main() {
- let x = 1 == 2 || 3 == 3;
- assert!((x));
- let mut y: isize = 10;
- println!("{}", x || incr(&mut y));
- assert_eq!(y, 10);
- if true && x { assert!((true)); } else { assert!((false)); }
-}
diff --git a/tests/ui/lexer/error-stage.rs b/tests/ui/lexer/error-stage.rs
index c8d88f7..f0ccb88 100644
--- a/tests/ui/lexer/error-stage.rs
+++ b/tests/ui/lexer/error-stage.rs
@@ -59,7 +59,7 @@ macro_rules! sink {
// The invalid literals used to cause errors, but this was changed by #102944.
// Except for `0b010.0f32`, because it's a lexer error.
-#[cfg(FALSE)]
+#[cfg(false)]
fn configured_out() {
"string"any_suffix; // OK
10u123; // OK
diff --git a/tests/ui/link-native-libs/link-attr-validation-late.rs b/tests/ui/link-native-libs/link-attr-validation-late.rs
index 34f720d..4eeb8ba 100644
--- a/tests/ui/link-native-libs/link-attr-validation-late.rs
+++ b/tests/ui/link-native-libs/link-attr-validation-late.rs
@@ -9,7 +9,7 @@
#[link(name = "foo", name = "bar")] //~ ERROR multiple `name` arguments
#[link(name = "...", kind = "dylib", kind = "bar")] //~ ERROR multiple `kind` arguments
#[link(name = "...", modifiers = "+verbatim", modifiers = "bar")] //~ ERROR multiple `modifiers` arguments
-#[link(name = "...", cfg(FALSE), cfg(FALSE))] //~ ERROR multiple `cfg` arguments
+#[link(name = "...", cfg(false), cfg(false))] //~ ERROR multiple `cfg` arguments
#[link(wasm_import_module = "foo", wasm_import_module = "bar")] //~ ERROR multiple `wasm_import_module` arguments
extern "C" {}
diff --git a/tests/ui/link-native-libs/link-attr-validation-late.stderr b/tests/ui/link-native-libs/link-attr-validation-late.stderr
index 1ad5fba..f3989c0 100644
--- a/tests/ui/link-native-libs/link-attr-validation-late.stderr
+++ b/tests/ui/link-native-libs/link-attr-validation-late.stderr
@@ -31,7 +31,7 @@
error: multiple `cfg` arguments in a single `#[link]` attribute
--> $DIR/link-attr-validation-late.rs:12:34
|
-LL | #[link(name = "...", cfg(FALSE), cfg(FALSE))]
+LL | #[link(name = "...", cfg(false), cfg(false))]
| ^^^^^^^^^^
error: multiple `wasm_import_module` arguments in a single `#[link]` attribute
diff --git a/tests/ui/link-native-libs/suggest-libname-only-1.rs b/tests/ui/link-native-libs/suggest-libname-only-1.rs
index 4ccfa08..8699e48 100644
--- a/tests/ui/link-native-libs/suggest-libname-only-1.rs
+++ b/tests/ui/link-native-libs/suggest-libname-only-1.rs
@@ -1,10 +1,11 @@
//@ build-fail
//@ compile-flags: --crate-type rlib
-//@ error-pattern: only provide the library name `foo`, not the full filename
#[link(name = "libfoo.a", kind = "static")]
-extern { } //~ WARN extern declarations without an explicit ABI are deprecated
+extern { } //~ WARN `extern` declarations without an explicit ABI are deprecated
+ //~| HELP explicitly specify the "C" ABI
pub fn main() { }
//~? ERROR could not find native static library `libfoo.a`
+//~? HELP only provide the library name `foo`, not the full filename
diff --git a/tests/ui/link-native-libs/suggest-libname-only-1.stderr b/tests/ui/link-native-libs/suggest-libname-only-1.stderr
index 85a3599..59bd99f 100644
--- a/tests/ui/link-native-libs/suggest-libname-only-1.stderr
+++ b/tests/ui/link-native-libs/suggest-libname-only-1.stderr
@@ -1,5 +1,5 @@
-warning: extern declarations without an explicit ABI are deprecated
- --> $DIR/suggest-libname-only-1.rs:6:1
+warning: `extern` declarations without an explicit ABI are deprecated
+ --> $DIR/suggest-libname-only-1.rs:5:1
|
LL | extern { }
| ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
diff --git a/tests/ui/link-native-libs/suggest-libname-only-2.rs b/tests/ui/link-native-libs/suggest-libname-only-2.rs
index c35b4a6..87373f5 100644
--- a/tests/ui/link-native-libs/suggest-libname-only-2.rs
+++ b/tests/ui/link-native-libs/suggest-libname-only-2.rs
@@ -1,10 +1,11 @@
//@ build-fail
//@ compile-flags: --crate-type rlib
-//@ error-pattern: only provide the library name `bar`, not the full filename
#[link(name = "bar.lib", kind = "static")]
-extern { } //~ WARN extern declarations without an explicit ABI are deprecated
+extern { } //~ WARN `extern` declarations without an explicit ABI are deprecated
+ //~| HELP explicitly specify the "C" ABI
pub fn main() { }
//~? ERROR could not find native static library `bar.lib`
+//~? HELP only provide the library name `bar`, not the full filename
diff --git a/tests/ui/link-native-libs/suggest-libname-only-2.stderr b/tests/ui/link-native-libs/suggest-libname-only-2.stderr
index d5c8893..298a9ce 100644
--- a/tests/ui/link-native-libs/suggest-libname-only-2.stderr
+++ b/tests/ui/link-native-libs/suggest-libname-only-2.stderr
@@ -1,5 +1,5 @@
-warning: extern declarations without an explicit ABI are deprecated
- --> $DIR/suggest-libname-only-2.rs:6:1
+warning: `extern` declarations without an explicit ABI are deprecated
+ --> $DIR/suggest-libname-only-2.rs:5:1
|
LL | extern { }
| ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
diff --git a/tests/ui/lint/break-with-label-and-unsafe-block.rs b/tests/ui/lint/break-with-label-and-unsafe-block.rs
new file mode 100644
index 0000000..a76a576
--- /dev/null
+++ b/tests/ui/lint/break-with-label-and-unsafe-block.rs
@@ -0,0 +1,11 @@
+//@ check-pass
+
+#![deny(break_with_label_and_loop)]
+
+unsafe fn foo() -> i32 { 42 }
+
+fn main () {
+ 'label: loop {
+ break 'label unsafe { foo() }
+ };
+}
diff --git a/tests/ui/lint/cli-lint-override.forbid_warn.stderr b/tests/ui/lint/cli-lint-override.forbid_warn.stderr
index fb8779a..fe3437a 100644
--- a/tests/ui/lint/cli-lint-override.forbid_warn.stderr
+++ b/tests/ui/lint/cli-lint-override.forbid_warn.stderr
@@ -1,4 +1,4 @@
-error: extern declarations without an explicit ABI are deprecated
+error: `extern` declarations without an explicit ABI are deprecated
--> $DIR/cli-lint-override.rs:12:1
|
LL | extern fn foo() {}
diff --git a/tests/ui/lint/cli-lint-override.force_warn_deny.stderr b/tests/ui/lint/cli-lint-override.force_warn_deny.stderr
index 10fc13e..f48fca4 100644
--- a/tests/ui/lint/cli-lint-override.force_warn_deny.stderr
+++ b/tests/ui/lint/cli-lint-override.force_warn_deny.stderr
@@ -1,4 +1,4 @@
-warning: extern declarations without an explicit ABI are deprecated
+warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/cli-lint-override.rs:12:1
|
LL | extern fn foo() {}
diff --git a/tests/ui/lint/cli-lint-override.rs b/tests/ui/lint/cli-lint-override.rs
index 4b3fd0d..b733872 100644
--- a/tests/ui/lint/cli-lint-override.rs
+++ b/tests/ui/lint/cli-lint-override.rs
@@ -10,8 +10,8 @@
extern fn foo() {}
-//[warn_deny]~^ ERROR extern declarations without an explicit ABI are deprecated
-//[forbid_warn]~^^ ERROR extern declarations without an explicit ABI are deprecated
-//[force_warn_deny]~^^^ WARN extern declarations without an explicit ABI are deprecated
+//[warn_deny]~^ ERROR `extern` declarations without an explicit ABI are deprecated
+//[forbid_warn]~^^ ERROR `extern` declarations without an explicit ABI are deprecated
+//[force_warn_deny]~^^^ WARN `extern` declarations without an explicit ABI are deprecated
fn main() {}
diff --git a/tests/ui/lint/cli-lint-override.warn_deny.stderr b/tests/ui/lint/cli-lint-override.warn_deny.stderr
index 979ca22..91baad1 100644
--- a/tests/ui/lint/cli-lint-override.warn_deny.stderr
+++ b/tests/ui/lint/cli-lint-override.warn_deny.stderr
@@ -1,4 +1,4 @@
-error: extern declarations without an explicit ABI are deprecated
+error: `extern` declarations without an explicit ABI are deprecated
--> $DIR/cli-lint-override.rs:12:1
|
LL | extern fn foo() {}
diff --git a/tests/ui/lint/cli-unknown-force-warn.rs b/tests/ui/lint/cli-unknown-force-warn.rs
index 330d557..0c60f48 100644
--- a/tests/ui/lint/cli-unknown-force-warn.rs
+++ b/tests/ui/lint/cli-unknown-force-warn.rs
@@ -3,12 +3,12 @@
//@ check-pass
//@ compile-flags: --force-warn foo-qux
-
-//@ error-pattern: requested on the command line with `--force-warn foo_qux`
-//@ error-pattern: `#[warn(unknown_lints)]` on by default
+//@ dont-require-annotations: NOTE
fn main() {}
//~? WARN unknown lint: `foo_qux`
//~? WARN unknown lint: `foo_qux`
//~? WARN unknown lint: `foo_qux`
+//~? NOTE requested on the command line with `--force-warn foo_qux`
+//~? NOTE `#[warn(unknown_lints)]` on by default
diff --git a/tests/ui/lint/dead-code/auxiliary/no-dead-code-reexported-types-across-crates.rs b/tests/ui/lint/dead-code/auxiliary/no-dead-code-reexported-types-across-crates.rs
new file mode 100644
index 0000000..5f328d1
--- /dev/null
+++ b/tests/ui/lint/dead-code/auxiliary/no-dead-code-reexported-types-across-crates.rs
@@ -0,0 +1,33 @@
+//! Auxilary file for testing `dead_code` lint. This crate is compiled as a library and exposes
+//! aliased types. When used externally, there should not be warnings of `dead_code`
+//!
+//! Issue: <https://github.com/rust-lang/rust/issues/14421>
+
+// Expose internal types to be used in external test
+pub use src::aliases::ExposedType;
+pub use src::hidden_core::new;
+
+mod src {
+ pub mod aliases {
+ use super::hidden_core::InternalStruct;
+ pub type ExposedType = InternalStruct<f32>;
+ }
+
+ pub mod hidden_core {
+ use super::aliases::ExposedType;
+
+ pub struct InternalStruct<T> {
+ _x: T,
+ }
+
+ pub fn new() -> ExposedType {
+ InternalStruct { _x: 1.0 }
+ }
+
+ impl<T> InternalStruct<T> {
+ pub fn foo(&mut self) {
+ println!("called foo");
+ }
+ }
+ }
+}
diff --git a/tests/ui/lint/dead-code/no-dead-code-for-static-trait-impl.rs b/tests/ui/lint/dead-code/no-dead-code-for-static-trait-impl.rs
new file mode 100644
index 0000000..8d54eda
--- /dev/null
+++ b/tests/ui/lint/dead-code/no-dead-code-for-static-trait-impl.rs
@@ -0,0 +1,61 @@
+//! Regression test to ensure false positive `dead_code` diagnostic warnings are not triggered for
+//! structs and enums that implement static trait functions or use associated constants.
+//!
+//! Aliased versions of all cases are also tested
+//!
+//! Issue: <https://github.com/rust-lang/rust/issues/23808>
+
+//@ check-pass
+#![deny(dead_code)]
+
+trait Const {
+ const C: ();
+}
+
+trait StaticFn {
+ fn sfn();
+}
+
+macro_rules! impl_const {($($T:ident),*) => {$(
+ impl Const for $T {
+ const C: () = ();
+ }
+)*}}
+
+macro_rules! impl_static_fn {($($T:ident),*) => {$(
+ impl StaticFn for $T {
+ fn sfn() {}
+ }
+)*}}
+
+struct ConstStruct;
+enum ConstEnum {}
+struct AliasedConstStruct;
+type AliasConstStruct = AliasedConstStruct;
+enum AliasedConstEnum {}
+type AliasConstEnum = AliasedConstEnum;
+
+impl_const!(ConstStruct, ConstEnum, AliasedConstStruct, AliasedConstEnum);
+
+struct StaticFnStruct;
+enum StaticFnEnum {}
+struct AliasedStaticFnStruct;
+type AliasStaticFnStruct = AliasedStaticFnStruct;
+enum AliasedStaticFnEnum {}
+type AliasStaticFnEnum = AliasedStaticFnEnum;
+
+impl_static_fn!(StaticFnStruct, StaticFnEnum, AliasedStaticFnStruct, AliasedStaticFnEnum);
+
+fn main() {
+ // Use the associated constant for all the types, they should be considered "used"
+ let () = ConstStruct::C;
+ let () = ConstEnum::C;
+ let () = AliasConstStruct::C;
+ let () = AliasConstEnum::C;
+
+ // Use the associated static function for all the types, they should be considered "used"
+ StaticFnStruct::sfn();
+ StaticFnEnum::sfn();
+ AliasStaticFnStruct::sfn();
+ AliasStaticFnEnum::sfn();
+}
diff --git a/tests/ui/lint/dead-code/no-dead-code-reexported-types-across-crates.rs b/tests/ui/lint/dead-code/no-dead-code-reexported-types-across-crates.rs
new file mode 100644
index 0000000..11082f7
--- /dev/null
+++ b/tests/ui/lint/dead-code/no-dead-code-reexported-types-across-crates.rs
@@ -0,0 +1,17 @@
+//! Regression test to ensure that `dead_code` warning does not get triggered when using re-exported
+//! types that are exposed from a different crate
+//!
+//! Issue: <https://github.com/rust-lang/rust/issues/14421>
+
+//@ check-pass
+//@ aux-build:no-dead-code-reexported-types-across-crates.rs
+
+extern crate no_dead_code_reexported_types_across_crates as bug_lib;
+
+use bug_lib::ExposedType;
+use bug_lib::new;
+
+pub fn main() {
+ let mut x: ExposedType = new();
+ x.foo();
+}
diff --git a/tests/ui/lint/dead-code/self-assign.rs b/tests/ui/lint/dead-code/self-assign.rs
index 072a899..357846b 100644
--- a/tests/ui/lint/dead-code/self-assign.rs
+++ b/tests/ui/lint/dead-code/self-assign.rs
@@ -1,19 +1,29 @@
-// Test that dead code warnings are issued for superfluous assignments of
-// fields or variables to themselves (issue #75356).
-
-//@ ignore-test FIXME(81658, 83171)
+//! Test that dead code warnings are issued for superfluous assignments of fields or variables to
+//! themselves (issue #75356).
+//!
+//! # History of this test (to aid relanding of a fixed version of #81473)
+//!
+//! - Original lint request was about self-assignments not triggering sth like `dead_code`.
+//! - `dead_code` lint expansion for self-assignments was implemented in #87129.
+//! - Unfortunately implementation components of #87129 had to be disabled as part of reverts
+//! #86212, #83171 (to revert #81473) to address regressions #81626 and #81658.
+//! - Consequently, none of the following warnings are emitted.
//@ check-pass
+
+// Implementation of self-assignment `dead_code` lint expansions disabled due to reverts.
+//@ known-bug: #75356
+
#![allow(unused_assignments)]
#![warn(dead_code)]
fn main() {
let mut x = 0;
x = x;
- //~^ WARNING: useless assignment of variable of type `i32` to itself
+ // FIXME ~^ WARNING: useless assignment of variable of type `i32` to itself
x = (x);
- //~^ WARNING: useless assignment of variable of type `i32` to itself
+ // FIXME ~^ WARNING: useless assignment of variable of type `i32` to itself
x = {x};
// block expressions don't count as self-assignments
@@ -22,10 +32,10 @@ fn main() {
struct S<'a> { f: &'a str }
let mut s = S { f: "abc" };
s = s;
- //~^ WARNING: useless assignment of variable of type `S` to itself
+ // FIXME ~^ WARNING: useless assignment of variable of type `S` to itself
s.f = s.f;
- //~^ WARNING: useless assignment of field of type `&str` to itself
+ // FIXME ~^ WARNING: useless assignment of field of type `&str` to itself
struct N0 { x: Box<i32> }
@@ -34,11 +44,11 @@ struct N1 { n: N0 }
struct N3 { n: N2 };
let mut n3 = N3 { n: N2(N1 { n: N0 { x: Box::new(42) } }) };
n3.n.0.n.x = n3.n.0.n.x;
- //~^ WARNING: useless assignment of field of type `Box<i32>` to itself
+ // FIXME ~^ WARNING: useless assignment of field of type `Box<i32>` to itself
let mut t = (1, ((2, 3, (4, 5)),));
t.1.0.2.1 = t.1.0.2.1;
- //~^ WARNING: useless assignment of field of type `i32` to itself
+ // FIXME ~^ WARNING: useless assignment of field of type `i32` to itself
let mut y = 0;
diff --git a/tests/ui/lint/dead-code/self-assign.stderr b/tests/ui/lint/dead-code/self-assign.stderr
deleted file mode 100644
index bb79c0e..0000000
--- a/tests/ui/lint/dead-code/self-assign.stderr
+++ /dev/null
@@ -1,44 +0,0 @@
-warning: useless assignment of variable of type `i32` to itself
- --> $DIR/self-assign.rs:10:5
- |
-LL | x = x;
- | ^^^^^
- |
-note: the lint level is defined here
- --> $DIR/self-assign.rs:6:9
- |
-LL | #![warn(dead_code)]
- | ^^^^^^^^^
-
-warning: useless assignment of variable of type `i32` to itself
- --> $DIR/self-assign.rs:13:5
- |
-LL | x = (x);
- | ^^^^^^^
-
-warning: useless assignment of variable of type `S` to itself
- --> $DIR/self-assign.rs:22:5
- |
-LL | s = s;
- | ^^^^^
-
-warning: useless assignment of field of type `&str` to itself
- --> $DIR/self-assign.rs:25:5
- |
-LL | s.f = s.f;
- | ^^^^^^^^^
-
-warning: useless assignment of field of type `Box<i32>` to itself
- --> $DIR/self-assign.rs:34:5
- |
-LL | n3.n.0.n.x = n3.n.0.n.x;
- | ^^^^^^^^^^^^^^^^^^^^^^^
-
-warning: useless assignment of field of type `i32` to itself
- --> $DIR/self-assign.rs:38:5
- |
-LL | t.1.0.2.1 = t.1.0.2.1;
- | ^^^^^^^^^^^^^^^^^^^^^
-
-warning: 6 warnings emitted
-
diff --git a/tests/ui/lint/expansion-time-include.rs b/tests/ui/lint/expansion-time-include.rs
index 3ecc01b..cbe3510 100644
--- a/tests/ui/lint/expansion-time-include.rs
+++ b/tests/ui/lint/expansion-time-include.rs
@@ -1,4 +1,4 @@
-//@ ignore-test auxiliary file for expansion-time.rs
+//@ ignore-auxiliary (used by `./expansion-time.rs`)
1
2
diff --git a/tests/ui/lint/inert-attr-macro.rs b/tests/ui/lint/inert-attr-macro.rs
index 5d4133d..f2d50e3 100644
--- a/tests/ui/lint/inert-attr-macro.rs
+++ b/tests/ui/lint/inert-attr-macro.rs
@@ -1,6 +1,5 @@
//@ check-pass
-#![feature(cfg_boolean_literals)]
#![warn(unused)]
macro_rules! foo {
diff --git a/tests/ui/lint/inert-attr-macro.stderr b/tests/ui/lint/inert-attr-macro.stderr
index b85b031..5ccb4ff 100644
--- a/tests/ui/lint/inert-attr-macro.stderr
+++ b/tests/ui/lint/inert-attr-macro.stderr
@@ -1,41 +1,41 @@
warning: unused attribute `inline`
- --> $DIR/inert-attr-macro.rs:11:5
+ --> $DIR/inert-attr-macro.rs:10:5
|
LL | #[inline] foo!();
| ^^^^^^^^^
|
note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo`
- --> $DIR/inert-attr-macro.rs:11:15
+ --> $DIR/inert-attr-macro.rs:10:15
|
LL | #[inline] foo!();
| ^^^
note: the lint level is defined here
- --> $DIR/inert-attr-macro.rs:4:9
+ --> $DIR/inert-attr-macro.rs:3:9
|
LL | #![warn(unused)]
| ^^^^^^
= note: `#[warn(unused_attributes)]` implied by `#[warn(unused)]`
warning: unused attribute `allow`
- --> $DIR/inert-attr-macro.rs:15:5
+ --> $DIR/inert-attr-macro.rs:14:5
|
LL | #[allow(warnings)] #[inline] foo!();
| ^^^^^^^^^^^^^^^^^^
|
note: the built-in attribute `allow` will be ignored, since it's applied to the macro invocation `foo`
- --> $DIR/inert-attr-macro.rs:15:34
+ --> $DIR/inert-attr-macro.rs:14:34
|
LL | #[allow(warnings)] #[inline] foo!();
| ^^^
warning: unused attribute `inline`
- --> $DIR/inert-attr-macro.rs:15:24
+ --> $DIR/inert-attr-macro.rs:14:24
|
LL | #[allow(warnings)] #[inline] foo!();
| ^^^^^^^^^
|
note: the built-in attribute `inline` will be ignored, since it's applied to the macro invocation `foo`
- --> $DIR/inert-attr-macro.rs:15:34
+ --> $DIR/inert-attr-macro.rs:14:34
|
LL | #[allow(warnings)] #[inline] foo!();
| ^^^
diff --git a/tests/ui/lint/inline-exported.rs b/tests/ui/lint/inline-exported.rs
index 69e322e..6a23cd5 100644
--- a/tests/ui/lint/inline-exported.rs
+++ b/tests/ui/lint/inline-exported.rs
@@ -2,9 +2,7 @@
//! because `#[inline]` is ignored for such functions.
#![crate_type = "lib"]
-
#![feature(linkage)]
-#![feature(naked_functions)]
#![deny(unused_attributes)]
#[inline]
diff --git a/tests/ui/lint/inline-exported.stderr b/tests/ui/lint/inline-exported.stderr
index dcf63cc..05a2bda 100644
--- a/tests/ui/lint/inline-exported.stderr
+++ b/tests/ui/lint/inline-exported.stderr
@@ -1,18 +1,18 @@
error: `#[inline]` is ignored on externally exported functions
- --> $DIR/inline-exported.rs:10:1
+ --> $DIR/inline-exported.rs:8:1
|
LL | #[inline]
| ^^^^^^^^^
|
= help: externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]`
note: the lint level is defined here
- --> $DIR/inline-exported.rs:8:9
+ --> $DIR/inline-exported.rs:6:9
|
LL | #![deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^
error: `#[inline]` is ignored on externally exported functions
- --> $DIR/inline-exported.rs:15:1
+ --> $DIR/inline-exported.rs:13:1
|
LL | #[inline]
| ^^^^^^^^^
@@ -20,7 +20,7 @@
= help: externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]`
error: `#[inline]` is ignored on externally exported functions
- --> $DIR/inline-exported.rs:20:1
+ --> $DIR/inline-exported.rs:18:1
|
LL | #[inline]
| ^^^^^^^^^
diff --git a/tests/ui/lint/issue-121070-let-range.rs b/tests/ui/lint/issue-121070-let-range.rs
index 1f575cf..8287858 100644
--- a/tests/ui/lint/issue-121070-let-range.rs
+++ b/tests/ui/lint/issue-121070-let-range.rs
@@ -1,6 +1,6 @@
//@ check-pass
+//@ edition:2024
-#![feature(let_chains)]
#![allow(irrefutable_let_patterns)]
fn main() {
let _a = 0..1;
diff --git a/tests/ui/lint/known-tool-in-submodule/submodule.rs b/tests/ui/lint/known-tool-in-submodule/submodule.rs
index 0bb2b93..9c24964 100644
--- a/tests/ui/lint/known-tool-in-submodule/submodule.rs
+++ b/tests/ui/lint/known-tool-in-submodule/submodule.rs
@@ -1,4 +1,4 @@
-//@ ignore-test: not a test
+//@ ignore-auxiliary (used by `./root.rs`)
#[allow(tool::lint)]
pub fn foo() {}
diff --git a/tests/ui/lint/lint-removed-cmdline-deny.rs b/tests/ui/lint/lint-removed-cmdline-deny.rs
index 6616781..83bbd24 100644
--- a/tests/ui/lint/lint-removed-cmdline-deny.rs
+++ b/tests/ui/lint/lint-removed-cmdline-deny.rs
@@ -2,9 +2,7 @@
// cc #30346
//@ compile-flags:-D renamed-and-removed-lints -D raw_pointer_derive
-
-//@ error-pattern:requested on the command line with `-D raw_pointer_derive`
-//@ error-pattern:requested on the command line with `-D renamed-and-removed-lints`
+//@ dont-require-annotations: NOTE
#![warn(unused)]
@@ -14,3 +12,5 @@
//~? ERROR lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
//~? ERROR lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
//~? ERROR lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+//~? NOTE requested on the command line with `-D raw_pointer_derive`
+//~? NOTE requested on the command line with `-D renamed-and-removed-lints`
diff --git a/tests/ui/lint/lint-removed-cmdline-deny.stderr b/tests/ui/lint/lint-removed-cmdline-deny.stderr
index 27a3504..2fb2373 100644
--- a/tests/ui/lint/lint-removed-cmdline-deny.stderr
+++ b/tests/ui/lint/lint-removed-cmdline-deny.stderr
@@ -14,13 +14,13 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: unused variable: `unused`
- --> $DIR/lint-removed-cmdline-deny.rs:12:17
+ --> $DIR/lint-removed-cmdline-deny.rs:10:17
|
LL | fn main() { let unused = (); }
| ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused`
|
note: the lint level is defined here
- --> $DIR/lint-removed-cmdline-deny.rs:11:8
+ --> $DIR/lint-removed-cmdline-deny.rs:9:8
|
LL | #[deny(warnings)]
| ^^^^^^^^
diff --git a/tests/ui/lint/lint-removed-cmdline.rs b/tests/ui/lint/lint-removed-cmdline.rs
index 4dde3db..f83747a 100644
--- a/tests/ui/lint/lint-removed-cmdline.rs
+++ b/tests/ui/lint/lint-removed-cmdline.rs
@@ -2,9 +2,7 @@
// cc #30346
//@ compile-flags:-D raw_pointer_derive
-
-//@ error-pattern:`#[warn(renamed_and_removed_lints)]` on by default
-//@ error-pattern:requested on the command line with `-D raw_pointer_derive`
+//@ dont-require-annotations: NOTE
#![warn(unused)]
@@ -14,3 +12,5 @@
//~? WARN lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
//~? WARN lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
//~? WARN lint `raw_pointer_derive` has been removed: using derive with raw pointers is ok
+//~? NOTE `#[warn(renamed_and_removed_lints)]` on by default
+//~? NOTE requested on the command line with `-D raw_pointer_derive`
diff --git a/tests/ui/lint/lint-removed-cmdline.stderr b/tests/ui/lint/lint-removed-cmdline.stderr
index 7994f9b..64e7c57 100644
--- a/tests/ui/lint/lint-removed-cmdline.stderr
+++ b/tests/ui/lint/lint-removed-cmdline.stderr
@@ -14,13 +14,13 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: unused variable: `unused`
- --> $DIR/lint-removed-cmdline.rs:12:17
+ --> $DIR/lint-removed-cmdline.rs:10:17
|
LL | fn main() { let unused = (); }
| ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused`
|
note: the lint level is defined here
- --> $DIR/lint-removed-cmdline.rs:11:8
+ --> $DIR/lint-removed-cmdline.rs:9:8
|
LL | #[deny(warnings)]
| ^^^^^^^^
diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.rs b/tests/ui/lint/lint-renamed-cmdline-deny.rs
index 0ea4ce4..c8b0350 100644
--- a/tests/ui/lint/lint-renamed-cmdline-deny.rs
+++ b/tests/ui/lint/lint-renamed-cmdline-deny.rs
@@ -1,8 +1,6 @@
//@ compile-flags:-D renamed-and-removed-lints -D bare_trait_object
-
-//@ error-pattern:use the new name `bare_trait_objects`
-//@ error-pattern:requested on the command line with `-D bare_trait_object`
-//@ error-pattern:requested on the command line with `-D renamed-and-removed-lints`
+//@ dont-require-annotations: HELP
+//@ dont-require-annotations: NOTE
#[deny(unused)]
fn main() { let unused = (); } //~ ERROR unused variable: `unused`
@@ -10,3 +8,6 @@
//~? ERROR lint `bare_trait_object` has been renamed to `bare_trait_objects`
//~? ERROR lint `bare_trait_object` has been renamed to `bare_trait_objects`
//~? ERROR lint `bare_trait_object` has been renamed to `bare_trait_objects`
+//~? HELP use the new name `bare_trait_objects`
+//~? NOTE requested on the command line with `-D bare_trait_object`
+//~? NOTE requested on the command line with `-D renamed-and-removed-lints`
diff --git a/tests/ui/lint/lint-renamed-cmdline-deny.stderr b/tests/ui/lint/lint-renamed-cmdline-deny.stderr
index a49cdc8..b42b828 100644
--- a/tests/ui/lint/lint-renamed-cmdline-deny.stderr
+++ b/tests/ui/lint/lint-renamed-cmdline-deny.stderr
@@ -17,13 +17,13 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: unused variable: `unused`
- --> $DIR/lint-renamed-cmdline-deny.rs:8:17
+ --> $DIR/lint-renamed-cmdline-deny.rs:6:17
|
LL | fn main() { let unused = (); }
| ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused`
|
note: the lint level is defined here
- --> $DIR/lint-renamed-cmdline-deny.rs:7:8
+ --> $DIR/lint-renamed-cmdline-deny.rs:5:8
|
LL | #[deny(unused)]
| ^^^^^^
diff --git a/tests/ui/lint/lint-renamed-cmdline.rs b/tests/ui/lint/lint-renamed-cmdline.rs
index 45df7b6..757cb51 100644
--- a/tests/ui/lint/lint-renamed-cmdline.rs
+++ b/tests/ui/lint/lint-renamed-cmdline.rs
@@ -1,7 +1,5 @@
//@ compile-flags:-D bare_trait_object
-
-//@ error-pattern:requested on the command line with `-D bare_trait_object`
-//@ error-pattern:`#[warn(renamed_and_removed_lints)]` on by default
+//@ dont-require-annotations: NOTE
#[deny(unused)]
fn main() { let unused = (); } //~ ERROR unused variable: `unused`
@@ -9,3 +7,5 @@
//~? WARN lint `bare_trait_object` has been renamed to `bare_trait_objects`
//~? WARN lint `bare_trait_object` has been renamed to `bare_trait_objects`
//~? WARN lint `bare_trait_object` has been renamed to `bare_trait_objects`
+//~? NOTE requested on the command line with `-D bare_trait_object`
+//~? NOTE `#[warn(renamed_and_removed_lints)]` on by default
diff --git a/tests/ui/lint/lint-renamed-cmdline.stderr b/tests/ui/lint/lint-renamed-cmdline.stderr
index 901e7a6..efd399e 100644
--- a/tests/ui/lint/lint-renamed-cmdline.stderr
+++ b/tests/ui/lint/lint-renamed-cmdline.stderr
@@ -17,13 +17,13 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: unused variable: `unused`
- --> $DIR/lint-renamed-cmdline.rs:7:17
+ --> $DIR/lint-renamed-cmdline.rs:5:17
|
LL | fn main() { let unused = (); }
| ^^^^^^ help: if this is intentional, prefix it with an underscore: `_unused`
|
note: the lint level is defined here
- --> $DIR/lint-renamed-cmdline.rs:6:8
+ --> $DIR/lint-renamed-cmdline.rs:4:8
|
LL | #[deny(unused)]
| ^^^^^^
diff --git a/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs
index e2f7c73..ac001e1 100644
--- a/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs
+++ b/tests/ui/lint/lint-unknown-lint-cmdline-deny.rs
@@ -1,9 +1,6 @@
//@ compile-flags:-D unknown-lints -D bogus -D dead_cod
-
-//@ error-pattern:requested on the command line with `-D bogus`
-//@ error-pattern:requested on the command line with `-D dead_cod`
-//@ error-pattern:requested on the command line with `-D unknown-lints`
-//@ error-pattern:did you mean: `dead_code`
+//@ dont-require-annotations: HELP
+//@ dont-require-annotations: NOTE
fn main() { }
@@ -13,3 +10,7 @@ fn main() { }
//~? ERROR unknown lint: `dead_cod`
//~? ERROR unknown lint: `bogus`
//~? ERROR unknown lint: `dead_cod`
+//~? NOTE requested on the command line with `-D bogus`
+//~? NOTE requested on the command line with `-D dead_cod`
+//~? NOTE requested on the command line with `-D unknown-lints`
+//~? HELP did you mean: `dead_code`
diff --git a/tests/ui/lint/lint-unknown-lint-cmdline.rs b/tests/ui/lint/lint-unknown-lint-cmdline.rs
index 931e945..7eb8c1f 100644
--- a/tests/ui/lint/lint-unknown-lint-cmdline.rs
+++ b/tests/ui/lint/lint-unknown-lint-cmdline.rs
@@ -1,10 +1,7 @@
//@ check-pass
//@ compile-flags:-D bogus -D dead_cod
-
-//@ error-pattern:requested on the command line with `-D bogus`
-//@ error-pattern:`#[warn(unknown_lints)]` on by default
-//@ error-pattern:requested on the command line with `-D dead_cod`
-//@ error-pattern:did you mean: `dead_code`
+//@ dont-require-annotations: HELP
+//@ dont-require-annotations: NOTE
fn main() { }
@@ -14,3 +11,7 @@ fn main() { }
//~? WARN unknown lint: `dead_cod`
//~? WARN unknown lint: `bogus`
//~? WARN unknown lint: `dead_cod`
+//~? NOTE requested on the command line with `-D bogus`
+//~? NOTE `#[warn(unknown_lints)]` on by default
+//~? NOTE requested on the command line with `-D dead_cod`
+//~? HELP did you mean: `dead_code`
diff --git a/tests/ui/lint/lint_pre_expansion_extern_module_aux.rs b/tests/ui/lint/lint_pre_expansion_extern_module_aux.rs
index 6e16a79..10e3c0f 100644
--- a/tests/ui/lint/lint_pre_expansion_extern_module_aux.rs
+++ b/tests/ui/lint/lint_pre_expansion_extern_module_aux.rs
@@ -1,3 +1,3 @@
-//@ ignore-test: not a test
+//@ ignore-auxiliary (used by `./lint-pre-expansion-extern-module.rs`)
pub fn try() {}
diff --git a/tests/ui/lint/non-local-defs/cargo-update.rs b/tests/ui/lint/non-local-defs/cargo-update.rs
index 8b8c157..f778752 100644
--- a/tests/ui/lint/non-local-defs/cargo-update.rs
+++ b/tests/ui/lint/non-local-defs/cargo-update.rs
@@ -8,7 +8,7 @@
//
// and since we specifically want to check the presence
// of the `cargo update` suggestion we assert it here.
-//@ error-pattern: `cargo update -p non_local_macro`
+//@ dont-require-annotations: NOTE
extern crate non_local_macro;
@@ -16,5 +16,6 @@
non_local_macro::non_local_impl!(LocalStruct);
//~^ WARN non-local `impl` definition
+//~| NOTE `cargo update -p non_local_macro`
fn main() {}
diff --git a/tests/ui/lint/removed-lints/undefined_naked_function_abi.rs b/tests/ui/lint/removed-lints/undefined_naked_function_abi.rs
new file mode 100644
index 0000000..cf3ac66
--- /dev/null
+++ b/tests/ui/lint/removed-lints/undefined_naked_function_abi.rs
@@ -0,0 +1,5 @@
+//@ check-pass
+
+#![deny(undefined_naked_function_abi)]
+//~^ WARN lint `undefined_naked_function_abi` has been removed
+fn main() {}
diff --git a/tests/ui/lint/removed-lints/undefined_naked_function_abi.stderr b/tests/ui/lint/removed-lints/undefined_naked_function_abi.stderr
new file mode 100644
index 0000000..5a54668
--- /dev/null
+++ b/tests/ui/lint/removed-lints/undefined_naked_function_abi.stderr
@@ -0,0 +1,10 @@
+warning: lint `undefined_naked_function_abi` has been removed: converted into hard error, see PR #139001 <https://github.com/rust-lang/rust/issues/139001> for more information
+ --> $DIR/undefined_naked_function_abi.rs:3:9
+ |
+LL | #![deny(undefined_naked_function_abi)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(renamed_and_removed_lints)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs
index 9e38b94..11ee2bc 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs
+++ b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.rs
@@ -1,6 +1,7 @@
// This ensures that ICEs like rust#94953 don't happen
//@ check-pass
//@ compile-flags: -Z unpretty=expanded
+//@ edition: 2015
// This `expect` will create an expectation with an unstable expectation id
#[expect(while_true)]
diff --git a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout
index d804c1d..d63abea 100644
--- a/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout
+++ b/tests/ui/lint/rfc-2383-lint-reason/no_ice_for_partial_compiler_runs.stdout
@@ -7,6 +7,7 @@
// This ensures that ICEs like rust#94953 don't happen
//@ check-pass
//@ compile-flags: -Z unpretty=expanded
+//@ edition: 2015
// This `expect` will create an expectation with an unstable expectation id
#[expect(while_true)]
diff --git a/tests/ui/lint/unknown-lints/other.rs b/tests/ui/lint/unknown-lints/other.rs
index f917bff..7770bc5 100644
--- a/tests/ui/lint/unknown-lints/other.rs
+++ b/tests/ui/lint/unknown-lints/other.rs
@@ -1,6 +1,4 @@
-//@ ignore-test
-
-// Companion to allow-in-other-module.rs
+//@ ignore-auxiliary (used by `./allow-in-other-module.rs`)
// This should not warn.
#![allow(not_a_real_lint)]
diff --git a/tests/ui/lint/unused/unused-attr-macro-rules.rs b/tests/ui/lint/unused/unused-attr-macro-rules.rs
index c0fc280..7a8a1bb 100644
--- a/tests/ui/lint/unused/unused-attr-macro-rules.rs
+++ b/tests/ui/lint/unused/unused-attr-macro-rules.rs
@@ -17,7 +17,7 @@ macro_rules! foo2 {
() => {};
}
-#[cfg(FALSE)]
+#[cfg(false)]
macro_rules! foo {
() => {};
}
diff --git a/tests/ui/lint/wasm_c_abi_transition.rs b/tests/ui/lint/wasm_c_abi_transition.rs
index 1fe8167..6a933a0 100644
--- a/tests/ui/lint/wasm_c_abi_transition.rs
+++ b/tests/ui/lint/wasm_c_abi_transition.rs
@@ -39,3 +39,9 @@ pub fn call_other_fun(x: MyType) {
unsafe { other_fun(x) } //~ERROR: wasm ABI transition
//~^WARN: previously accepted
}
+
+// Zero-sized types are safe in both ABIs
+#[repr(C)]
+pub struct MyZstType;
+#[allow(improper_ctypes_definitions)]
+pub extern "C" fn zst_safe(_x: (), _y: MyZstType) {}
diff --git a/tests/ui/list.rs b/tests/ui/list.rs
deleted file mode 100644
index 443c4c9..0000000
--- a/tests/ui/list.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@ run-pass
-
-#![allow(non_camel_case_types)]
-
-enum list { #[allow(dead_code)] cons(isize, Box<list>), nil, }
-
-pub fn main() {
- list::cons(10, Box::new(list::cons(11, Box::new(list::cons(12, Box::new(list::nil))))));
-}
diff --git a/tests/ui/lto/auxiliary/dwarf-mixed-versions-lto-aux.rs b/tests/ui/lto/auxiliary/dwarf-mixed-versions-lto-aux.rs
index 3c81127..2f2bf57 100644
--- a/tests/ui/lto/auxiliary/dwarf-mixed-versions-lto-aux.rs
+++ b/tests/ui/lto/auxiliary/dwarf-mixed-versions-lto-aux.rs
@@ -1,4 +1,4 @@
-//@ compile-flags: -g --crate-type=rlib -Zdwarf-version=4
+//@ compile-flags: -g --crate-type=rlib -Cdwarf-version=4
pub fn say_hi() {
println!("hello there")
diff --git a/tests/ui/lto/dwarf-mixed-versions-lto.rs b/tests/ui/lto/dwarf-mixed-versions-lto.rs
index 14ef65a..900274e 100644
--- a/tests/ui/lto/dwarf-mixed-versions-lto.rs
+++ b/tests/ui/lto/dwarf-mixed-versions-lto.rs
@@ -4,7 +4,7 @@
//@ ignore-msvc Platform must use DWARF
//@ aux-build:dwarf-mixed-versions-lto-aux.rs
-//@ compile-flags: -C lto -g -Zdwarf-version=5
+//@ compile-flags: -C lto -g -Cdwarf-version=5
//@ no-prefer-dynamic
//@ build-pass
diff --git a/tests/ui/macros/auxiliary/macro-include-items-expr.rs b/tests/ui/macros/auxiliary/macro-include-items-expr.rs
index 7394f19..d00491f 100644
--- a/tests/ui/macros/auxiliary/macro-include-items-expr.rs
+++ b/tests/ui/macros/auxiliary/macro-include-items-expr.rs
@@ -1,3 +1 @@
-// ignore-test: this is not a test
-
1
diff --git a/tests/ui/macros/auxiliary/macro-include-items-item.rs b/tests/ui/macros/auxiliary/macro-include-items-item.rs
index 7d54745..761cd00 100644
--- a/tests/ui/macros/auxiliary/macro-include-items-item.rs
+++ b/tests/ui/macros/auxiliary/macro-include-items-item.rs
@@ -1,3 +1 @@
-// ignore-test: this is not a test
-
fn foo() { bar() }
diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.rs b/tests/ui/macros/genercs-in-path-with-prettry-hir.rs
index 84370fc..e6773f6 100644
--- a/tests/ui/macros/genercs-in-path-with-prettry-hir.rs
+++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.rs
@@ -1,4 +1,5 @@
//@ compile-flags: -Zunpretty=hir
+//@ edition: 2015
// issue#97006
diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr b/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr
index 8fcc7c6..173e775 100644
--- a/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr
+++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr
@@ -1,5 +1,5 @@
error: unexpected generic arguments in path
- --> $DIR/genercs-in-path-with-prettry-hir.rs:12:10
+ --> $DIR/genercs-in-path-with-prettry-hir.rs:13:10
|
LL | m!(inline<u8>);
| ^^^^
diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout
index e8c88d2..6b41eb5 100644
--- a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout
+++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout
@@ -3,6 +3,7 @@
#[macro_use]
extern crate std;
//@ compile-flags: -Zunpretty=hir
+//@ edition: 2015
// issue#97006
diff --git a/tests/ui/macros/include-single-expr-helper-1.rs b/tests/ui/macros/include-single-expr-helper-1.rs
index ddeeb98..6802719 100644
--- a/tests/ui/macros/include-single-expr-helper-1.rs
+++ b/tests/ui/macros/include-single-expr-helper-1.rs
@@ -1,4 +1,4 @@
-//@ ignore-test auxiliary file for include-single-expr.rs
+//@ ignore-auxiliary (used by `./include-single-expr.rs`)
0
diff --git a/tests/ui/macros/include-single-expr-helper.rs b/tests/ui/macros/include-single-expr-helper.rs
index e8ad974..bd75bbb 100644
--- a/tests/ui/macros/include-single-expr-helper.rs
+++ b/tests/ui/macros/include-single-expr-helper.rs
@@ -1,4 +1,4 @@
-//@ ignore-test auxiliary file for include-single-expr.rs
+//@ ignore-auxiliary (used by `./include-single-expr.rs`)
0
10
diff --git a/tests/ui/macros/issue-69838-dir/bar.rs b/tests/ui/macros/issue-69838-dir/bar.rs
index 4433005..6f91f8e 100644
--- a/tests/ui/macros/issue-69838-dir/bar.rs
+++ b/tests/ui/macros/issue-69838-dir/bar.rs
@@ -1,3 +1,3 @@
-//@ ignore-test -- this is an auxiliary file as part of another test.
+//@ ignore-auxiliary (used by `../issue-69838-mods-relative-to-included-path.rs`)
pub fn i_am_in_bar() {}
diff --git a/tests/ui/macros/issue-69838-dir/included.rs b/tests/ui/macros/issue-69838-dir/included.rs
index 11fcd3e..328334d 100644
--- a/tests/ui/macros/issue-69838-dir/included.rs
+++ b/tests/ui/macros/issue-69838-dir/included.rs
@@ -1,3 +1,3 @@
-//@ ignore-test -- this is an auxiliary file as part of another test.
+//@ ignore-auxiliary (used by `../issue-69838-mods-relative-to-included-path.rs`)
pub mod bar;
diff --git a/tests/ui/macros/lint-trailing-macro-call.rs b/tests/ui/macros/lint-trailing-macro-call.rs
index 66dce05..78b861f 100644
--- a/tests/ui/macros/lint-trailing-macro-call.rs
+++ b/tests/ui/macros/lint-trailing-macro-call.rs
@@ -6,7 +6,7 @@
macro_rules! expand_it {
() => {
- #[cfg(FALSE)] 25; //~ WARN trailing semicolon in macro
+ #[cfg(false)] 25; //~ WARN trailing semicolon in macro
//~| WARN this was previously
}
}
diff --git a/tests/ui/macros/lint-trailing-macro-call.stderr b/tests/ui/macros/lint-trailing-macro-call.stderr
index 13cecc3..223b85e 100644
--- a/tests/ui/macros/lint-trailing-macro-call.stderr
+++ b/tests/ui/macros/lint-trailing-macro-call.stderr
@@ -1,7 +1,7 @@
warning: trailing semicolon in macro used in expression position
--> $DIR/lint-trailing-macro-call.rs:9:25
|
-LL | #[cfg(FALSE)] 25;
+LL | #[cfg(false)] 25;
| ^
...
LL | expand_it!()
@@ -20,7 +20,7 @@
warning: trailing semicolon in macro used in expression position
--> $DIR/lint-trailing-macro-call.rs:9:25
|
-LL | #[cfg(FALSE)] 25;
+LL | #[cfg(false)] 25;
| ^
...
LL | expand_it!()
diff --git a/tests/ui/macros/macro-as-fn-body.rs b/tests/ui/macros/macro-as-fn-body.rs
index e0542ed..188c7f7 100644
--- a/tests/ui/macros/macro-as-fn-body.rs
+++ b/tests/ui/macros/macro-as-fn-body.rs
@@ -1,7 +1,7 @@
//
//@ run-pass
//
-// Description - ensure Interpolated blocks can act as valid function bodies
+// Description - ensure block metavariables can act as valid function bodies
// Covered cases: free functions, struct methods, and default trait functions
macro_rules! def_fn {
diff --git a/tests/ui/macros/macro-attributes.rs b/tests/ui/macros/macro-attributes.rs
index 8329079..976d2cb 100644
--- a/tests/ui/macros/macro-attributes.rs
+++ b/tests/ui/macros/macro-attributes.rs
@@ -9,7 +9,7 @@ macro_rules! compiles_fine {
// check that the attributes are recognised by requiring this
// to be removed to avoid a compile error
- #[cfg(FALSE)]
+ #[cfg(false)]
static MISTYPED: () = "foo";
}
}
diff --git a/tests/ui/macros/macro-expanded-include/foo/mod.rs b/tests/ui/macros/macro-expanded-include/foo/mod.rs
index 926d84c..4e6d9e4 100644
--- a/tests/ui/macros/macro-expanded-include/foo/mod.rs
+++ b/tests/ui/macros/macro-expanded-include/foo/mod.rs
@@ -1,4 +1,4 @@
-//@ ignore-test (auxiliary, used by other tests)
+//@ ignore-auxiliary (used by `../test.rs`)
macro_rules! m {
() => { include!("file.txt"); }
diff --git a/tests/ui/macros/macro-inner-attributes.rs b/tests/ui/macros/macro-inner-attributes.rs
index a1eb7cd..1a832ca 100644
--- a/tests/ui/macros/macro-inner-attributes.rs
+++ b/tests/ui/macros/macro-inner-attributes.rs
@@ -5,7 +5,7 @@ macro_rules! test { ($nm:ident,
$i:item) => (mod $nm { #![$a] $i }); }
test!(a,
- #[cfg(FALSE)],
+ #[cfg(false)],
pub fn bar() { });
test!(b,
diff --git a/tests/ui/macros/macro-outer-attributes.rs b/tests/ui/macros/macro-outer-attributes.rs
index 8c79683..5b41cf9 100644
--- a/tests/ui/macros/macro-outer-attributes.rs
+++ b/tests/ui/macros/macro-outer-attributes.rs
@@ -5,7 +5,7 @@ macro_rules! test { ($nm:ident,
$i:item) => (mod $nm { #[$a] $i }); }
test!(a,
- #[cfg(FALSE)],
+ #[cfg(false)],
pub fn bar() { });
test!(b,
diff --git a/tests/ui/macros/macro-outer-attributes.stderr b/tests/ui/macros/macro-outer-attributes.stderr
index a8809f3..a894c90 100644
--- a/tests/ui/macros/macro-outer-attributes.stderr
+++ b/tests/ui/macros/macro-outer-attributes.stderr
@@ -16,7 +16,7 @@
| ^^^^^
LL |
LL | / test!(a,
-LL | | #[cfg(FALSE)],
+LL | | #[cfg(false)],
LL | | pub fn bar() { });
| |_______________________- in this macro invocation
= note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/macros/macro-with-attrs2.rs b/tests/ui/macros/macro-with-attrs2.rs
index 37188e4..7d0bf91 100644
--- a/tests/ui/macros/macro-with-attrs2.rs
+++ b/tests/ui/macros/macro-with-attrs2.rs
@@ -1,6 +1,6 @@
//@ run-pass
-#[cfg(FALSE)]
+#[cfg(false)]
macro_rules! foo { () => (1) }
#[cfg(not(FALSE))]
diff --git a/tests/ui/macros/remove-repetition-issue-139480.rs b/tests/ui/macros/remove-repetition-issue-139480.rs
new file mode 100644
index 0000000..1efb430
--- /dev/null
+++ b/tests/ui/macros/remove-repetition-issue-139480.rs
@@ -0,0 +1,28 @@
+macro_rules! ciallo {
+ ($($v: vis)? $name: ident) => {
+ //~^ error: repetition matches empty token tree
+ };
+}
+
+macro_rules! meow {
+ ($name: ident $($v: vis)?) => {
+ //~^ error: repetition matches empty token tree
+ };
+}
+
+macro_rules! gbc {
+ ($name: ident $/*
+ this comment gets removed by the suggestion
+ */
+ ($v: vis)?) => {
+ //~^ error: repetition matches empty token tree
+ };
+}
+
+ciallo!(hello);
+
+meow!(miaow, pub);
+
+gbc!(mygo,);
+
+fn main() {}
diff --git a/tests/ui/macros/remove-repetition-issue-139480.stderr b/tests/ui/macros/remove-repetition-issue-139480.stderr
new file mode 100644
index 0000000..c247558
--- /dev/null
+++ b/tests/ui/macros/remove-repetition-issue-139480.stderr
@@ -0,0 +1,44 @@
+error: repetition matches empty token tree
+ --> $DIR/remove-repetition-issue-139480.rs:2:7
+ |
+LL | ($($v: vis)? $name: ident) => {
+ | ^^^^^^^^^
+ |
+ = note: a `vis` fragment can already be empty
+help: remove the `$(` and `)?`
+ |
+LL - ($($v: vis)? $name: ident) => {
+LL + ($v: vis $name: ident) => {
+ |
+
+error: repetition matches empty token tree
+ --> $DIR/remove-repetition-issue-139480.rs:8:20
+ |
+LL | ($name: ident $($v: vis)?) => {
+ | ^^^^^^^^^
+ |
+ = note: a `vis` fragment can already be empty
+help: remove the `$(` and `)?`
+ |
+LL - ($name: ident $($v: vis)?) => {
+LL + ($name: ident $v: vis) => {
+ |
+
+error: repetition matches empty token tree
+ --> $DIR/remove-repetition-issue-139480.rs:17:9
+ |
+LL | ($v: vis)?) => {
+ | ^^^^^^^^^
+ |
+ = note: a `vis` fragment can already be empty
+help: remove the `$(` and `)?`
+ |
+LL - ($name: ident $/*
+LL - this comment gets removed by the suggestion
+LL - */
+LL - ($v: vis)?) => {
+LL + ($name: ident $v: vis) => {
+ |
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/macros/reparse-expr-issue-139495.rs b/tests/ui/macros/reparse-expr-issue-139495.rs
index 38d2457..89734ca 100644
--- a/tests/ui/macros/reparse-expr-issue-139495.rs
+++ b/tests/ui/macros/reparse-expr-issue-139495.rs
@@ -1,7 +1,15 @@
-macro_rules! m {
- ($abi : expr) => { extern $abi } //~ ERROR expected expression, found keyword `extern`
+macro_rules! m1 {
+ ($abi: literal) => { extern $abi } //~ ERROR expected expression, found keyword `extern`
+}
+
+macro_rules! m2 {
+ ($abi: expr) => { extern $abi } //~ ERROR expected expression, found keyword `extern`
}
fn main() {
- m!(-2)
+ m1!(-2)
+}
+
+fn f() {
+ m2!(-2)
}
diff --git a/tests/ui/macros/reparse-expr-issue-139495.stderr b/tests/ui/macros/reparse-expr-issue-139495.stderr
index 73a8ed8..e2e05d6 100644
--- a/tests/ui/macros/reparse-expr-issue-139495.stderr
+++ b/tests/ui/macros/reparse-expr-issue-139495.stderr
@@ -1,13 +1,24 @@
error: expected expression, found keyword `extern`
- --> $DIR/reparse-expr-issue-139495.rs:2:22
+ --> $DIR/reparse-expr-issue-139495.rs:2:24
|
-LL | ($abi : expr) => { extern $abi }
- | ^^^^^^ expected expression
+LL | ($abi: literal) => { extern $abi }
+ | ^^^^^^ expected expression
...
-LL | m!(-2)
- | ------ in this macro invocation
+LL | m1!(-2)
+ | ------- in this macro invocation
|
- = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: this error originates in the macro `m1` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 1 previous error
+error: expected expression, found keyword `extern`
+ --> $DIR/reparse-expr-issue-139495.rs:6:21
+ |
+LL | ($abi: expr) => { extern $abi }
+ | ^^^^^^ expected expression
+...
+LL | m2!(-2)
+ | ------- in this macro invocation
+ |
+ = note: this error originates in the macro `m2` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs
index cf47a1e..29f71d1 100644
--- a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.rs
@@ -1,5 +1,6 @@
//@ check-pass
//@ compile-flags: -Z unpretty=expanded
+//@ edition: 2015
#![feature(core_intrinsics, generic_assert)]
diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
index 8065d0d..9300f61 100644
--- a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
+++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout
@@ -2,6 +2,7 @@
#![no_std]
//@ check-pass
//@ compile-flags: -Z unpretty=expanded
+//@ edition: 2015
#![feature(core_intrinsics, generic_assert)]
#[prelude_import]
diff --git a/tests/ui/macros/syntax-error-recovery.rs b/tests/ui/macros/syntax-error-recovery.rs
index 6cf9d54..e1681ea 100644
--- a/tests/ui/macros/syntax-error-recovery.rs
+++ b/tests/ui/macros/syntax-error-recovery.rs
@@ -5,14 +5,14 @@ pub enum TokenKind {
$(
#[$attr]
$token $($inner)? = $value,
+ //~^ ERROR expected one of `!` or `::`, found `<eof>`
)*
}
};
}
-//~^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable
+//~^^^^^^ ERROR expected one of `(`, `,`, `=`, `{`, or `}`, found `ty` metavariable
//~| ERROR macro expansion ignores `ty` metavariable and any tokens following
values!(STRING(1) as (String) => cfg(test),);
-//~^ ERROR expected one of `!` or `::`, found `<eof>`
fn main() {}
diff --git a/tests/ui/macros/syntax-error-recovery.stderr b/tests/ui/macros/syntax-error-recovery.stderr
index 61758fb..a2059aa 100644
--- a/tests/ui/macros/syntax-error-recovery.stderr
+++ b/tests/ui/macros/syntax-error-recovery.stderr
@@ -22,10 +22,10 @@
= note: the usage of `values!` is likely invalid in item context
error: expected one of `!` or `::`, found `<eof>`
- --> $DIR/syntax-error-recovery.rs:15:9
+ --> $DIR/syntax-error-recovery.rs:7:17
|
-LL | values!(STRING(1) as (String) => cfg(test),);
- | ^^^^^^ expected one of `!` or `::`
+LL | $token $($inner)? = $value,
+ | ^^^^^^ expected one of `!` or `::`
error: aborting due to 3 previous errors
diff --git a/tests/ui/match/issue-82392.rs b/tests/ui/match/issue-82392.rs
index 6f9527f..4ae08fe 100644
--- a/tests/ui/match/issue-82392.rs
+++ b/tests/ui/match/issue-82392.rs
@@ -1,6 +1,7 @@
// https://github.com/rust-lang/rust/issues/82329
//@ compile-flags: -Zunpretty=hir,typed
//@ check-pass
+//@ edition:2015
pub fn main() {
if true {
diff --git a/tests/ui/match/issue-82392.stdout b/tests/ui/match/issue-82392.stdout
index 8949611..8b7edab 100644
--- a/tests/ui/match/issue-82392.stdout
+++ b/tests/ui/match/issue-82392.stdout
@@ -5,6 +5,7 @@
// https://github.com/rust-lang/rust/issues/82329
//@ compile-flags: -Zunpretty=hir,typed
//@ check-pass
+//@ edition:2015
fn main() ({
(if (true as bool)
diff --git a/tests/ui/minus-string.rs b/tests/ui/minus-string.rs
deleted file mode 100644
index b83347b..0000000
--- a/tests/ui/minus-string.rs
+++ /dev/null
@@ -1 +0,0 @@
-fn main() { -"foo".to_string(); } //~ ERROR cannot apply unary operator `-` to type `String`
diff --git a/tests/ui/mir-dataflow/README.md b/tests/ui/mir-dataflow/README.md
index a3ab14b..8860202 100644
--- a/tests/ui/mir-dataflow/README.md
+++ b/tests/ui/mir-dataflow/README.md
@@ -42,12 +42,3 @@
on *entry* to each block, as well as the gen- and kill-sets that
were so-called "transfer functions" summarizing the effect of each
basic block.
-
- * (In addition to the `borrowck_graphviz_postflow` attribute-key
- noted above, there is also `borrowck_graphviz_preflow`; it has the
- same interface and generates the same set of files, but it renders
- the dataflow state after building the gen- and kill-sets but
- *before* running the dataflow analysis itself, so each entry-set is
- just the initial default state for that dataflow analysis. This is
- less useful for understanding the error message output in these
- tests.)
diff --git a/tests/ui/mir/issue-99852.rs b/tests/ui/mir/issue-99852.rs
index 59459c6..af754cf 100644
--- a/tests/ui/mir/issue-99852.rs
+++ b/tests/ui/mir/issue-99852.rs
@@ -1,6 +1,6 @@
//@ check-pass
//@ compile-flags: -Z validate-mir
-#![feature(let_chains)]
+//@ edition: 2024
fn lambda<T, U>() -> U
where
diff --git a/tests/ui/mir/mir_let_chains_drop_order.rs b/tests/ui/mir/mir_let_chains_drop_order.rs
index 8991c6d..4794f34 100644
--- a/tests/ui/mir/mir_let_chains_drop_order.rs
+++ b/tests/ui/mir/mir_let_chains_drop_order.rs
@@ -6,7 +6,7 @@
// See `mir_drop_order.rs` for more information
-#![feature(let_chains)]
+#![cfg_attr(edition2021, feature(let_chains))]
#![allow(irrefutable_let_patterns)]
use std::cell::RefCell;
diff --git a/tests/ui/missing/missing-return.rs b/tests/ui/missing/missing-return.rs
index 5d9839a..4d48e7c 100644
--- a/tests/ui/missing/missing-return.rs
+++ b/tests/ui/missing/missing-return.rs
@@ -1,5 +1,4 @@
-//@ error-pattern: return
-
fn f() -> isize { } //~ ERROR mismatched types
-
+ //~| NOTE implicitly returns `()` as its body has no tail or `return` expression
+ //~| NOTE expected `isize`, found `()`
fn main() { f(); }
diff --git a/tests/ui/missing/missing-return.stderr b/tests/ui/missing/missing-return.stderr
index 5f7fb50..b2d202b 100644
--- a/tests/ui/missing/missing-return.stderr
+++ b/tests/ui/missing/missing-return.stderr
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
- --> $DIR/missing-return.rs:3:11
+ --> $DIR/missing-return.rs:1:11
|
LL | fn f() -> isize { }
| - ^^^^^ expected `isize`, found `()`
diff --git a/tests/ui/missing_non_modrs_mod/foo.rs b/tests/ui/missing_non_modrs_mod/foo.rs
index dd3e970..afdc5e3 100644
--- a/tests/ui/missing_non_modrs_mod/foo.rs
+++ b/tests/ui/missing_non_modrs_mod/foo.rs
@@ -1,4 +1,3 @@
-//
-//@ ignore-test this is just a helper for the real test in this dir
+//@ ignore-auxiliary (used by `./missing_non_modrs_mod.rs`)
mod missing;
diff --git a/tests/ui/missing_non_modrs_mod/foo_inline.rs b/tests/ui/missing_non_modrs_mod/foo_inline.rs
index 9d46e9b..ed6d3a4 100644
--- a/tests/ui/missing_non_modrs_mod/foo_inline.rs
+++ b/tests/ui/missing_non_modrs_mod/foo_inline.rs
@@ -1,4 +1,4 @@
-//@ ignore-test this is just a helper for the real test in this dir
+//@ ignore-auxiliary (used by `./missing_non_modrs_mod_inline.rs`)
mod inline {
mod missing;
diff --git a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr
index 4e48799..c084fbf 100644
--- a/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr
+++ b/tests/ui/missing_non_modrs_mod/missing_non_modrs_mod.stderr
@@ -1,5 +1,5 @@
error[E0583]: file not found for module `missing`
- --> $DIR/foo.rs:4:1
+ --> $DIR/foo.rs:3:1
|
LL | mod missing;
| ^^^^^^^^^^^^
diff --git a/tests/ui/modules/mod_file_aux.rs b/tests/ui/modules/mod_file_aux.rs
index f37296b..eec38d1 100644
--- a/tests/ui/modules/mod_file_aux.rs
+++ b/tests/ui/modules/mod_file_aux.rs
@@ -1,4 +1,3 @@
-//@ run-pass
-//@ ignore-test Not a test. Used by other tests
+//@ ignore-auxiliary (used by `./mod_file_with_path_attr.rs` and `mod_file.rs`)
pub fn foo() -> isize { 10 }
diff --git a/tests/ui/modules_and_files_visibility/mod_file_aux.rs b/tests/ui/modules_and_files_visibility/mod_file_aux.rs
index 77390da..6fac8da 100644
--- a/tests/ui/modules_and_files_visibility/mod_file_aux.rs
+++ b/tests/ui/modules_and_files_visibility/mod_file_aux.rs
@@ -1,3 +1,3 @@
-//@ ignore-test Not a test. Used by other tests
+//@ ignore-auxiliary (used by `./mod_file_correct_spans.rs`)
pub fn foo() -> isize { 10 }
diff --git a/tests/ui/modules_and_files_visibility/mod_file_disambig_aux.rs b/tests/ui/modules_and_files_visibility/mod_file_disambig_aux.rs
index e00b562..9a0b1c4 100644
--- a/tests/ui/modules_and_files_visibility/mod_file_disambig_aux.rs
+++ b/tests/ui/modules_and_files_visibility/mod_file_disambig_aux.rs
@@ -1 +1 @@
-//@ ignore-test not a test. aux file
+//@ ignore-auxiliary (used by `./mod_file_disambig.rs`)
diff --git a/tests/ui/modules_and_files_visibility/mod_file_disambig_aux/mod.rs b/tests/ui/modules_and_files_visibility/mod_file_disambig_aux/mod.rs
index e00b562..232c933 100644
--- a/tests/ui/modules_and_files_visibility/mod_file_disambig_aux/mod.rs
+++ b/tests/ui/modules_and_files_visibility/mod_file_disambig_aux/mod.rs
@@ -1 +1 @@
-//@ ignore-test not a test. aux file
+//@ ignore-auxiliary (used by `../mod_file_disambig.rs`)
diff --git a/tests/ui/nested-cfg-attrs.rs b/tests/ui/nested-cfg-attrs.rs
index 0af28fc..941807a 100644
--- a/tests/ui/nested-cfg-attrs.rs
+++ b/tests/ui/nested-cfg-attrs.rs
@@ -1,4 +1,4 @@
-#[cfg_attr(all(), cfg_attr(all(), cfg(FALSE)))]
+#[cfg_attr(all(), cfg_attr(all(), cfg(false)))]
fn f() {}
fn main() { f() } //~ ERROR cannot find function `f` in this scope
diff --git a/tests/ui/nested-ty-params.rs b/tests/ui/nested-ty-params.rs
index 866e623..c00c3bc 100644
--- a/tests/ui/nested-ty-params.rs
+++ b/tests/ui/nested-ty-params.rs
@@ -1,4 +1,3 @@
-//@ error-pattern:can't use generic parameters from outer item
fn hd<U>(v: Vec<U> ) -> U {
fn hd1(w: [U]) -> U { return w[0]; }
//~^ ERROR can't use generic parameters from outer item
diff --git a/tests/ui/nested-ty-params.stderr b/tests/ui/nested-ty-params.stderr
index a9cdec6..7ca65b4 100644
--- a/tests/ui/nested-ty-params.stderr
+++ b/tests/ui/nested-ty-params.stderr
@@ -1,5 +1,5 @@
error[E0401]: can't use generic parameters from outer item
- --> $DIR/nested-ty-params.rs:3:16
+ --> $DIR/nested-ty-params.rs:2:16
|
LL | fn hd<U>(v: Vec<U> ) -> U {
| - type parameter from outer item
@@ -9,7 +9,7 @@
| help: try introducing a local generic parameter here: `<U>`
error[E0401]: can't use generic parameters from outer item
- --> $DIR/nested-ty-params.rs:3:23
+ --> $DIR/nested-ty-params.rs:2:23
|
LL | fn hd<U>(v: Vec<U> ) -> U {
| - type parameter from outer item
diff --git a/tests/ui/nll/relate_tys/placeholder-outlives-existential.rs b/tests/ui/nll/relate_tys/placeholder-outlives-existential.rs
new file mode 100644
index 0000000..3f22e9a
--- /dev/null
+++ b/tests/ui/nll/relate_tys/placeholder-outlives-existential.rs
@@ -0,0 +1,31 @@
+// Test that we correctly handle some cases of placeholder leaks.
+//
+//@ compile-flags:-Zno-leak-check
+
+
+struct Co<'a>(&'a ());
+struct Inv<'a>(*mut &'a ());
+struct Contra<'a>(fn(&'a ()));
+
+// `exists<'e> forall<'p> 'p: 'e` -> ERROR
+fn p_outlives_e(
+ x: for<'e> fn(for<'p> fn(fn(fn(Contra<'e>, Co<'p>)))),
+) -> fn(fn(fn(for<'unify> fn(Contra<'unify>, Co<'unify>)))) {
+ x //~ ERROR mismatched types [E0308]
+}
+
+// `exists<'e> forall<'p> 'e: 'p` -> Ok, 'e: 'static
+fn e_outlives_p_static(
+ x: for<'e> fn(Inv<'e>, for<'p> fn(fn(fn(Contra<'p>, Co<'e>)))),
+) -> fn(Inv<'static>, fn(fn(for<'unify> fn(Contra<'unify>, Co<'unify>)))) {
+ x
+}
+
+// `exists<'e> forall<'p> 'e: 'p` -> Ok, 'e: 'static -> ERROR
+fn e_outlives_p_static_err<'not_static>(
+ x: for<'e> fn(Inv<'e>, for<'p> fn(fn(fn(Contra<'p>, Co<'e>)))),
+) -> fn(Inv<'not_static>, fn(fn(for<'unify> fn(Contra<'unify>, Co<'unify>)))) {
+ x //~ ERROR lifetime may not live long enough
+}
+
+fn main() {}
diff --git a/tests/ui/nll/relate_tys/placeholder-outlives-existential.stderr b/tests/ui/nll/relate_tys/placeholder-outlives-existential.stderr
new file mode 100644
index 0000000..80ab5c8
--- /dev/null
+++ b/tests/ui/nll/relate_tys/placeholder-outlives-existential.stderr
@@ -0,0 +1,25 @@
+error[E0308]: mismatched types
+ --> $DIR/placeholder-outlives-existential.rs:14:5
+ |
+LL | x
+ | ^ one type is more general than the other
+ |
+ = note: expected fn pointer `fn(fn(fn(for<'unify> fn(Contra<'unify>, Co<'unify>))))`
+ found fn pointer `for<'e> fn(for<'e, 'p> fn(for<'e, 'p> fn(for<'e, 'p> fn(Contra<'e>, Co<'p>))))`
+
+error: lifetime may not live long enough
+ --> $DIR/placeholder-outlives-existential.rs:28:5
+ |
+LL | fn e_outlives_p_static_err<'not_static>(
+ | ----------- lifetime `'not_static` defined here
+...
+LL | x
+ | ^ returning this value requires that `'not_static` must outlive `'static`
+ |
+ = note: requirement occurs because of the type `Inv<'_>`, which makes the generic argument `'_` invariant
+ = note: the struct `Inv<'a>` is invariant over the parameter `'a`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/no_std/no-std-no-start-binary.rs b/tests/ui/no_std/no-std-no-start-binary.rs
index df68b99..6853e2d 100644
--- a/tests/ui/no_std/no-std-no-start-binary.rs
+++ b/tests/ui/no_std/no-std-no-start-binary.rs
@@ -1,5 +1,4 @@
//@ compile-flags: -Cpanic=abort --emit link
-//@ error-pattern:using `fn main` requires the standard library
// Make sure that we don't emit an error message mentioning internal lang items.
diff --git a/tests/ui/non_modrs_mods/foors_mod.rs b/tests/ui/non_modrs_mods/foors_mod.rs
index b215e5f..dfaa11b 100644
--- a/tests/ui/non_modrs_mods/foors_mod.rs
+++ b/tests/ui/non_modrs_mods/foors_mod.rs
@@ -1,6 +1,4 @@
-//@ run-pass
-//
-//@ ignore-test: not a test, used by non_modrs_mods.rs
+//@ ignore-auxiliary (used by `./non_modrs_mods.rs`)
pub mod inner_modrs_mod;
pub mod inner_foors_mod;
diff --git a/tests/ui/non_modrs_mods_and_inline_mods/x.rs b/tests/ui/non_modrs_mods_and_inline_mods/x.rs
index c4548d3..38ff011 100644
--- a/tests/ui/non_modrs_mods_and_inline_mods/x.rs
+++ b/tests/ui/non_modrs_mods_and_inline_mods/x.rs
@@ -1,4 +1,4 @@
-//@ ignore-test: not a test
+//@ ignore-auxiliary (used by `./non_modrs_mods_and_inline_mods.rs`)
pub mod y {
pub mod z;
diff --git a/tests/ui/non_modrs_mods_and_inline_mods/x/y/z/mod.rs b/tests/ui/non_modrs_mods_and_inline_mods/x/y/z/mod.rs
index ec7b7de..cac5e27 100644
--- a/tests/ui/non_modrs_mods_and_inline_mods/x/y/z/mod.rs
+++ b/tests/ui/non_modrs_mods_and_inline_mods/x/y/z/mod.rs
@@ -1 +1 @@
-//@ ignore-test: not a test
+//@ ignore-auxiliary (used by `../../../non_modrs_mods_and_inline_mods.rs`)
diff --git a/tests/ui/numbers-arithmetic/int.rs b/tests/ui/numbers-arithmetic/int.rs
deleted file mode 100644
index 42f8e50..0000000
--- a/tests/ui/numbers-arithmetic/int.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//@ run-pass
-
-
-
-
-pub fn main() { let _x: isize = 10; }
diff --git a/tests/ui/numbers-arithmetic/isize-base.rs b/tests/ui/numbers-arithmetic/isize-base.rs
new file mode 100644
index 0000000..412e7ac
--- /dev/null
+++ b/tests/ui/numbers-arithmetic/isize-base.rs
@@ -0,0 +1,25 @@
+//! Tests basic `isize` functionality
+
+//@ run-pass
+
+pub fn main() {
+ // Literal matches assignment type
+ let a: isize = 42isize;
+ // Literal cast
+ let b: isize = 42 as isize;
+ // Literal type inference from assignment type
+ let c: isize = 42;
+ // Assignment type inference from literal (and later comparison)
+ let d = 42isize;
+ // Function return value type inference
+ let e = return_val();
+
+ assert_eq!(a, b);
+ assert_eq!(a, c);
+ assert_eq!(a, d);
+ assert_eq!(a, e);
+}
+
+fn return_val() -> isize {
+ 42
+}
diff --git a/tests/ui/numbers-arithmetic/saturating-float-casts-impl.rs b/tests/ui/numbers-arithmetic/saturating-float-casts-impl.rs
index 4b176ef..4e578f6 100644
--- a/tests/ui/numbers-arithmetic/saturating-float-casts-impl.rs
+++ b/tests/ui/numbers-arithmetic/saturating-float-casts-impl.rs
@@ -1,4 +1,4 @@
-//@ ignore-test (auxiliary, used by other tests)
+//@ ignore-auxiliary (used by `./saturating-float-casts.rs` and `./saturating-float-casts-wasm.rs`)
// Tests saturating float->int casts. See u128-as-f32.rs for the opposite direction.
//
diff --git a/tests/ui/numbers-arithmetic/uint.rs b/tests/ui/numbers-arithmetic/uint.rs
deleted file mode 100644
index c2087b5..0000000
--- a/tests/ui/numbers-arithmetic/uint.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//@ run-pass
-
-
-
-
-pub fn main() { let _x: usize = 10 as usize; }
diff --git a/tests/ui/numbers-arithmetic/usize-base.rs b/tests/ui/numbers-arithmetic/usize-base.rs
new file mode 100644
index 0000000..833fc04
--- /dev/null
+++ b/tests/ui/numbers-arithmetic/usize-base.rs
@@ -0,0 +1,25 @@
+//! Tests basic `usize` functionality
+
+//@ run-pass
+
+pub fn main() {
+ // Literal matches assignment type
+ let a: usize = 42usize;
+ // Literal cast
+ let b: usize = 42 as usize;
+ // Literal type inference from assignment type
+ let c: usize = 42;
+ // Assignment type inference from literal (and later comparison)
+ let d = 42usize;
+ // Function return value type inference
+ let e = return_val();
+
+ assert_eq!(a, b);
+ assert_eq!(a, c);
+ assert_eq!(a, d);
+ assert_eq!(a, e);
+}
+
+fn return_val() -> usize {
+ 42
+}
diff --git a/tests/ui/on-unimplemented/bad-annotation.rs b/tests/ui/on-unimplemented/bad-annotation.rs
index 3f0f697..f2b9786 100644
--- a/tests/ui/on-unimplemented/bad-annotation.rs
+++ b/tests/ui/on-unimplemented/bad-annotation.rs
@@ -20,12 +20,12 @@ trait BadAnnotation1
{}
#[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"]
-//~^ ERROR there is no parameter `C` on trait `BadAnnotation2`
+//~^ ERROR cannot find parameter C on this trait
trait BadAnnotation2<A,B>
{}
#[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"]
-//~^ ERROR only named generic parameters are allowed
+//~^ ERROR positional format arguments are not allowed here
trait BadAnnotation3<A,B>
{}
diff --git a/tests/ui/on-unimplemented/bad-annotation.stderr b/tests/ui/on-unimplemented/bad-annotation.stderr
index 4ceea77..afd737d 100644
--- a/tests/ui/on-unimplemented/bad-annotation.stderr
+++ b/tests/ui/on-unimplemented/bad-annotation.stderr
@@ -11,17 +11,17 @@
LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")]
| ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-error[E0230]: there is no parameter `C` on trait `BadAnnotation2`
- --> $DIR/bad-annotation.rs:22:1
+error[E0230]: cannot find parameter C on this trait
+ --> $DIR/bad-annotation.rs:22:90
|
LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{C}>`"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^
-error[E0231]: only named generic parameters are allowed
- --> $DIR/bad-annotation.rs:27:1
+error[E0231]: positional format arguments are not allowed here
+ --> $DIR/bad-annotation.rs:27:90
|
LL | #[rustc_on_unimplemented = "Unimplemented trait error on `{Self}` with params `<{A},{B},{}>`"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^
error[E0232]: this attribute must have a valid value
--> $DIR/bad-annotation.rs:32:26
diff --git a/tests/ui/on-unimplemented/impl-substs.rs b/tests/ui/on-unimplemented/impl-substs.rs
deleted file mode 100644
index fe9c50e..0000000
--- a/tests/ui/on-unimplemented/impl-substs.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-#![feature(rustc_attrs)]
-
-trait Foo<A> {
- fn foo(self);
-}
-
-#[rustc_on_unimplemented = "an impl did not match: {A} {B} {C}"]
-impl<A, B, C> Foo<A> for (A, B, C) {
- fn foo(self) {}
-}
-
-fn main() {
- Foo::<usize>::foo((1i32, 1i32, 1i32));
- //~^ ERROR the trait bound `(i32, i32, i32): Foo<usize>` is not satisfied
-}
diff --git a/tests/ui/on-unimplemented/impl-substs.stderr b/tests/ui/on-unimplemented/impl-substs.stderr
deleted file mode 100644
index b85d45e..0000000
--- a/tests/ui/on-unimplemented/impl-substs.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error[E0277]: the trait bound `(i32, i32, i32): Foo<usize>` is not satisfied
- --> $DIR/impl-substs.rs:13:23
- |
-LL | Foo::<usize>::foo((1i32, 1i32, 1i32));
- | ----------------- ^^^^^^^^^^^^^^^^^^ an impl did not match: usize _ _
- | |
- | required by a bound introduced by this call
- |
- = help: the trait `Foo<usize>` is not implemented for `(i32, i32, i32)`
- but trait `Foo<i32>` is implemented for it
- = help: for that trait implementation, expected `i32`, found `usize`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/on-unimplemented/issue-104140.rs b/tests/ui/on-unimplemented/issue-104140.rs
deleted file mode 100644
index ade3f72..0000000
--- a/tests/ui/on-unimplemented/issue-104140.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#![feature(rustc_attrs)]
-
-trait Foo {}
-
-#[rustc_on_unimplemented] //~ ERROR malformed `rustc_on_unimplemented` attribute input
-impl Foo for u32 {}
-
-fn main() {}
diff --git a/tests/ui/on-unimplemented/issue-104140.stderr b/tests/ui/on-unimplemented/issue-104140.stderr
deleted file mode 100644
index 3c31713..0000000
--- a/tests/ui/on-unimplemented/issue-104140.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: malformed `rustc_on_unimplemented` attribute input
- --> $DIR/issue-104140.rs:5:1
- |
-LL | #[rustc_on_unimplemented]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-help: the following are the possible correct uses
- |
-LL | #[rustc_on_unimplemented = "message"]
- | +++++++++++
-LL | #[rustc_on_unimplemented(/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...")]
- | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/on-unimplemented/multiple-impls.rs b/tests/ui/on-unimplemented/multiple-impls.rs
deleted file mode 100644
index b74957e..0000000
--- a/tests/ui/on-unimplemented/multiple-impls.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-// Test if the on_unimplemented message override works
-
-#![feature(rustc_attrs)]
-
-
-struct Foo<T>(T);
-struct Bar<T>(T);
-
-#[rustc_on_unimplemented = "trait message"]
-trait Index<Idx: ?Sized> {
- type Output: ?Sized;
- fn index(&self, index: Idx) -> &Self::Output;
-}
-
-#[rustc_on_unimplemented = "on impl for Foo"]
-impl Index<Foo<usize>> for [i32] {
- type Output = i32;
- fn index(&self, _index: Foo<usize>) -> &i32 {
- loop {}
- }
-}
-
-#[rustc_on_unimplemented = "on impl for Bar"]
-impl Index<Bar<usize>> for [i32] {
- type Output = i32;
- fn index(&self, _index: Bar<usize>) -> &i32 {
- loop {}
- }
-}
-
-
-fn main() {
- Index::index(&[] as &[i32], 2u32);
- //~^ ERROR E0277
- //~| ERROR E0277
- Index::index(&[] as &[i32], Foo(2u32));
- //~^ ERROR E0277
- //~| ERROR E0277
- Index::index(&[] as &[i32], Bar(2u32));
- //~^ ERROR E0277
- //~| ERROR E0277
-}
diff --git a/tests/ui/on-unimplemented/multiple-impls.stderr b/tests/ui/on-unimplemented/multiple-impls.stderr
deleted file mode 100644
index ba4e43f..0000000
--- a/tests/ui/on-unimplemented/multiple-impls.stderr
+++ /dev/null
@@ -1,75 +0,0 @@
-error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
- --> $DIR/multiple-impls.rs:33:33
- |
-LL | Index::index(&[] as &[i32], 2u32);
- | ------------ ^^^^ trait message
- | |
- | required by a bound introduced by this call
- |
- = help: the trait `Index<u32>` is not implemented for `[i32]`
- = help: the following other types implement trait `Index<Idx>`:
- `[i32]` implements `Index<Bar<usize>>`
- `[i32]` implements `Index<Foo<usize>>`
-
-error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied
- --> $DIR/multiple-impls.rs:36:33
- |
-LL | Index::index(&[] as &[i32], Foo(2u32));
- | ------------ ^^^^^^^^^ on impl for Foo
- | |
- | required by a bound introduced by this call
- |
- = help: the trait `Index<Foo<u32>>` is not implemented for `[i32]`
- = help: the following other types implement trait `Index<Idx>`:
- `[i32]` implements `Index<Bar<usize>>`
- `[i32]` implements `Index<Foo<usize>>`
-
-error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied
- --> $DIR/multiple-impls.rs:39:33
- |
-LL | Index::index(&[] as &[i32], Bar(2u32));
- | ------------ ^^^^^^^^^ on impl for Bar
- | |
- | required by a bound introduced by this call
- |
- = help: the trait `Index<Bar<u32>>` is not implemented for `[i32]`
- = help: the following other types implement trait `Index<Idx>`:
- `[i32]` implements `Index<Bar<usize>>`
- `[i32]` implements `Index<Foo<usize>>`
-
-error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
- --> $DIR/multiple-impls.rs:33:5
- |
-LL | Index::index(&[] as &[i32], 2u32);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trait message
- |
- = help: the trait `Index<u32>` is not implemented for `[i32]`
- = help: the following other types implement trait `Index<Idx>`:
- `[i32]` implements `Index<Bar<usize>>`
- `[i32]` implements `Index<Foo<usize>>`
-
-error[E0277]: the trait bound `[i32]: Index<Foo<u32>>` is not satisfied
- --> $DIR/multiple-impls.rs:36:5
- |
-LL | Index::index(&[] as &[i32], Foo(2u32));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Foo
- |
- = help: the trait `Index<Foo<u32>>` is not implemented for `[i32]`
- = help: the following other types implement trait `Index<Idx>`:
- `[i32]` implements `Index<Bar<usize>>`
- `[i32]` implements `Index<Foo<usize>>`
-
-error[E0277]: the trait bound `[i32]: Index<Bar<u32>>` is not satisfied
- --> $DIR/multiple-impls.rs:39:5
- |
-LL | Index::index(&[] as &[i32], Bar(2u32));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ on impl for Bar
- |
- = help: the trait `Index<Bar<u32>>` is not implemented for `[i32]`
- = help: the following other types implement trait `Index<Idx>`:
- `[i32]` implements `Index<Bar<usize>>`
- `[i32]` implements `Index<Foo<usize>>`
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/on-unimplemented/on-impl.rs b/tests/ui/on-unimplemented/on-impl.rs
deleted file mode 100644
index ab3e67d..0000000
--- a/tests/ui/on-unimplemented/on-impl.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-// Test if the on_unimplemented message override works
-
-#![feature(rustc_attrs)]
-
-
-#[rustc_on_unimplemented = "invalid"]
-trait Index<Idx: ?Sized> {
- type Output: ?Sized;
- fn index(&self, index: Idx) -> &Self::Output;
-}
-
-#[rustc_on_unimplemented = "a usize is required to index into a slice"]
-impl Index<usize> for [i32] {
- type Output = i32;
- fn index(&self, index: usize) -> &i32 {
- &self[index]
- }
-}
-
-
-fn main() {
- Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
- //~^ ERROR E0277
- //~| ERROR E0277
-}
diff --git a/tests/ui/on-unimplemented/on-impl.stderr b/tests/ui/on-unimplemented/on-impl.stderr
deleted file mode 100644
index 5e7e2c4..0000000
--- a/tests/ui/on-unimplemented/on-impl.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
- --> $DIR/on-impl.rs:22:47
- |
-LL | Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
- | ------------------- ^^^^ a usize is required to index into a slice
- | |
- | required by a bound introduced by this call
- |
- = help: the trait `Index<u32>` is not implemented for `[i32]`
- but trait `Index<usize>` is implemented for it
- = help: for that trait implementation, expected `usize`, found `u32`
-
-error[E0277]: the trait bound `[i32]: Index<u32>` is not satisfied
- --> $DIR/on-impl.rs:22:5
- |
-LL | Index::<u32>::index(&[1, 2, 3] as &[i32], 2u32);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a usize is required to index into a slice
- |
- = help: the trait `Index<u32>` is not implemented for `[i32]`
- but trait `Index<usize>` is implemented for it
- = help: for that trait implementation, expected `usize`, found `u32`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/on-unimplemented/use_self_no_underscore.rs b/tests/ui/on-unimplemented/use_self_no_underscore.rs
new file mode 100644
index 0000000..045ef1a
--- /dev/null
+++ b/tests/ui/on-unimplemented/use_self_no_underscore.rs
@@ -0,0 +1,14 @@
+#![feature(rustc_attrs)]
+
+#[rustc_on_unimplemented(on(
+ all(A = "{integer}", any(Self = "[{integral}; _]",)),
+ message = "an array of type `{Self}` cannot be built directly from an iterator",
+))]
+pub trait FromIterator<A>: Sized {
+ fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self;
+}
+fn main() {
+ let iter = 0..42_8;
+ let x: [u8; 8] = FromIterator::from_iter(iter);
+ //~^ ERROR an array of type `[u8; 8]` cannot be built directly from an iterator
+}
diff --git a/tests/ui/on-unimplemented/use_self_no_underscore.stderr b/tests/ui/on-unimplemented/use_self_no_underscore.stderr
new file mode 100644
index 0000000..d01aee3
--- /dev/null
+++ b/tests/ui/on-unimplemented/use_self_no_underscore.stderr
@@ -0,0 +1,15 @@
+error[E0277]: an array of type `[u8; 8]` cannot be built directly from an iterator
+ --> $DIR/use_self_no_underscore.rs:12:22
+ |
+LL | let x: [u8; 8] = FromIterator::from_iter(iter);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `FromIterator<{integer}>` is not implemented for `[u8; 8]`
+ |
+help: this trait has no implementations, consider adding one
+ --> $DIR/use_self_no_underscore.rs:7:1
+ |
+LL | pub trait FromIterator<A>: Sized {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/optimization-remark.rs b/tests/ui/optimization-remark.rs
index ebcf3b4..165fc63c 100644
--- a/tests/ui/optimization-remark.rs
+++ b/tests/ui/optimization-remark.rs
@@ -12,9 +12,8 @@
//
//@ [merge1] compile-flags: -Cremark=all -Cremark=giraffe
//@ [merge2] compile-flags: -Cremark=inline -Cremark=giraffe
-//
-//@ error-pattern: inline (missed): 'f' not inlined into 'g'
//@ dont-check-compiler-stderr
+//@ dont-require-annotations: NOTE
#[no_mangle]
#[inline(never)]
@@ -25,3 +24,5 @@ pub fn f() {
pub fn g() {
f();
}
+
+//~? NOTE inline (missed): 'f' not inlined into 'g'
diff --git a/tests/ui/or-patterns/fn-param-wrap-parens.fixed b/tests/ui/or-patterns/fn-param-wrap-parens.fixed
index 7b0bbd0..fbf6006 100644
--- a/tests/ui/or-patterns/fn-param-wrap-parens.fixed
+++ b/tests/ui/or-patterns/fn-param-wrap-parens.fixed
@@ -9,5 +9,5 @@
enum E { A, B }
use E::*;
-#[cfg(FALSE)]
+#[cfg(false)]
fn fun1((A | B): E) {} //~ ERROR top-level or-patterns are not allowed
diff --git a/tests/ui/or-patterns/fn-param-wrap-parens.rs b/tests/ui/or-patterns/fn-param-wrap-parens.rs
index dadbb8a..d796f99 100644
--- a/tests/ui/or-patterns/fn-param-wrap-parens.rs
+++ b/tests/ui/or-patterns/fn-param-wrap-parens.rs
@@ -9,5 +9,5 @@ fn main() {}
enum E { A, B }
use E::*;
-#[cfg(FALSE)]
+#[cfg(false)]
fn fun1(A | B: E) {} //~ ERROR top-level or-patterns are not allowed
diff --git a/tests/ui/or-patterns/lazy-and-or.rs b/tests/ui/or-patterns/lazy-and-or.rs
new file mode 100644
index 0000000..3d69553
--- /dev/null
+++ b/tests/ui/or-patterns/lazy-and-or.rs
@@ -0,0 +1,25 @@
+//@ run-pass
+// This test verifies the short-circuiting behavior of logical operators `||` and `&&`.
+// It ensures that the right-hand expression is not evaluated when the left-hand
+// expression is sufficient to determine the result.
+
+fn would_panic_if_called(x: &mut isize) -> bool {
+ *x += 1;
+ assert!(false, "This function should never be called due to short-circuiting");
+ false
+}
+
+fn main() {
+ let x = 1 == 2 || 3 == 3;
+ assert!(x);
+
+ let mut y: isize = 10;
+ println!("Result of short-circuit: {}", x || would_panic_if_called(&mut y));
+ assert_eq!(y, 10, "y should remain 10 if short-circuiting works correctly");
+
+ if true && x {
+ assert!(true);
+ } else {
+ assert!(false, "This branch should not be reached");
+ }
+}
diff --git a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr
index 5608138..74e4cea 100644
--- a/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr
+++ b/tests/ui/or-patterns/or-patterns-syntactic-fail.stderr
@@ -6,7 +6,6 @@
| |
| while parsing the body of this closure
|
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: you might have meant to open the body of the closure
|
LL | let _ = |A | { B: E| ();
diff --git a/tests/ui/or-patterns/or-patterns-syntactic-pass.rs b/tests/ui/or-patterns/or-patterns-syntactic-pass.rs
index 6a8d0a5..6fd5840 100644
--- a/tests/ui/or-patterns/or-patterns-syntactic-pass.rs
+++ b/tests/ui/or-patterns/or-patterns-syntactic-pass.rs
@@ -18,7 +18,7 @@ macro_rules! accept_pat {
// Non-macro tests:
-#[cfg(FALSE)]
+#[cfg(false)]
fn or_patterns() {
// Top level of `let`:
let (| A | B);
diff --git a/tests/ui/or-patterns/remove-leading-vert.fixed b/tests/ui/or-patterns/remove-leading-vert.fixed
index 3ec815c..136ca57 100644
--- a/tests/ui/or-patterns/remove-leading-vert.fixed
+++ b/tests/ui/or-patterns/remove-leading-vert.fixed
@@ -6,7 +6,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn leading() {
fn fun1( A: E) {} //~ ERROR top-level or-patterns are not allowed
fn fun2( A: E) {} //~ ERROR unexpected `||` before function parameter
@@ -21,7 +21,7 @@
let NS { f: | A }: NS; //~ ERROR unexpected token `||` in pattern
}
-#[cfg(FALSE)]
+#[cfg(false)]
fn trailing() {
let ( A ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
let (a ,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern
diff --git a/tests/ui/or-patterns/remove-leading-vert.rs b/tests/ui/or-patterns/remove-leading-vert.rs
index 2aeeb0e..d9e9c9f 100644
--- a/tests/ui/or-patterns/remove-leading-vert.rs
+++ b/tests/ui/or-patterns/remove-leading-vert.rs
@@ -6,7 +6,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn leading() {
fn fun1( | A: E) {} //~ ERROR top-level or-patterns are not allowed
fn fun2( || A: E) {} //~ ERROR unexpected `||` before function parameter
@@ -21,7 +21,7 @@ fn fun2( || A: E) {} //~ ERROR unexpected `||` before function parameter
let NS { f: || A }: NS; //~ ERROR unexpected token `||` in pattern
}
-#[cfg(FALSE)]
+#[cfg(false)]
fn trailing() {
let ( A | ): E; //~ ERROR a trailing `|` is not allowed in an or-pattern
let (a |,): (E,); //~ ERROR a trailing `|` is not allowed in an or-pattern
diff --git a/tests/ui/packed/packed-struct-generic-transmute.rs b/tests/ui/packed/packed-struct-generic-transmute.rs
index 17e72be..6697263 100644
--- a/tests/ui/packed/packed-struct-generic-transmute.rs
+++ b/tests/ui/packed/packed-struct-generic-transmute.rs
@@ -3,8 +3,6 @@
// the error points to the start of the file, not the line with the
// transmute
-//@ error-pattern: cannot transmute between types of different sizes, or dependently-sized types
-
use std::mem;
#[repr(packed)]
diff --git a/tests/ui/packed/packed-struct-generic-transmute.stderr b/tests/ui/packed/packed-struct-generic-transmute.stderr
index e91f498..983742b 100644
--- a/tests/ui/packed/packed-struct-generic-transmute.stderr
+++ b/tests/ui/packed/packed-struct-generic-transmute.stderr
@@ -1,5 +1,5 @@
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
- --> $DIR/packed-struct-generic-transmute.rs:24:38
+ --> $DIR/packed-struct-generic-transmute.rs:22:38
|
LL | let oof: Oof<[u8; 5], i32> = mem::transmute(foo);
| ^^^^^^^^^^^^^^
diff --git a/tests/ui/packed/packed-struct-transmute.rs b/tests/ui/packed/packed-struct-transmute.rs
index 5ad6524..24ac1f4 100644
--- a/tests/ui/packed/packed-struct-transmute.rs
+++ b/tests/ui/packed/packed-struct-transmute.rs
@@ -4,7 +4,6 @@
// transmute
//@ normalize-stderr: "\d+ bits" -> "N bits"
-//@ error-pattern: cannot transmute between types of different sizes, or dependently-sized types
use std::mem;
diff --git a/tests/ui/packed/packed-struct-transmute.stderr b/tests/ui/packed/packed-struct-transmute.stderr
index 4d75820..c5f556f 100644
--- a/tests/ui/packed/packed-struct-transmute.stderr
+++ b/tests/ui/packed/packed-struct-transmute.stderr
@@ -1,5 +1,5 @@
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
- --> $DIR/packed-struct-transmute.rs:26:24
+ --> $DIR/packed-struct-transmute.rs:25:24
|
LL | let oof: Oof = mem::transmute(foo);
| ^^^^^^^^^^^^^^
diff --git a/tests/ui/panic-runtime/two-panic-runtimes.rs b/tests/ui/panic-runtime/two-panic-runtimes.rs
index 7add07e..80591ed 100644
--- a/tests/ui/panic-runtime/two-panic-runtimes.rs
+++ b/tests/ui/panic-runtime/two-panic-runtimes.rs
@@ -1,6 +1,6 @@
// ignore-tidy-linelength
//@ build-fail
-//@ dont-require-annotations:ERROR
+//@ dont-require-annotations: ERROR
//@ dont-check-compiler-stderr
//@ aux-build:panic-runtime-unwind.rs
//@ aux-build:panic-runtime-unwind2.rs
diff --git a/tests/ui/panic-runtime/want-abort-got-unwind.rs b/tests/ui/panic-runtime/want-abort-got-unwind.rs
index 1ae2e62..42cdf8b 100644
--- a/tests/ui/panic-runtime/want-abort-got-unwind.rs
+++ b/tests/ui/panic-runtime/want-abort-got-unwind.rs
@@ -1,6 +1,6 @@
// ignore-tidy-linelength
//@ build-fail
-//@ dont-require-annotations:ERROR
+//@ dont-require-annotations: ERROR
//@ dont-check-compiler-stderr
//@ aux-build:panic-runtime-unwind.rs
//@ compile-flags:-C panic=abort
diff --git a/tests/ui/panic-runtime/want-abort-got-unwind2.rs b/tests/ui/panic-runtime/want-abort-got-unwind2.rs
index dc4d3ea..ddf12cd 100644
--- a/tests/ui/panic-runtime/want-abort-got-unwind2.rs
+++ b/tests/ui/panic-runtime/want-abort-got-unwind2.rs
@@ -1,6 +1,6 @@
// ignore-tidy-linelength
//@ build-fail
-//@ dont-require-annotations:ERROR
+//@ dont-require-annotations: ERROR
//@ dont-check-compiler-stderr
//@ aux-build:panic-runtime-unwind.rs
//@ aux-build:wants-panic-runtime-unwind.rs
diff --git a/tests/ui/parser/assoc/assoc-const-underscore-syntactic-pass.rs b/tests/ui/parser/assoc/assoc-const-underscore-syntactic-pass.rs
index 6c04537..63c567b 100644
--- a/tests/ui/parser/assoc/assoc-const-underscore-syntactic-pass.rs
+++ b/tests/ui/parser/assoc/assoc-const-underscore-syntactic-pass.rs
@@ -4,7 +4,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
const _: () = {
pub trait A {
const _: () = ();
diff --git a/tests/ui/parser/assoc/assoc-static-syntactic-fail.rs b/tests/ui/parser/assoc/assoc-static-syntactic-fail.rs
index 492f2ea..e875d73 100644
--- a/tests/ui/parser/assoc/assoc-static-syntactic-fail.rs
+++ b/tests/ui/parser/assoc/assoc-static-syntactic-fail.rs
@@ -2,7 +2,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
impl S {
static IA: u8 = 0; //~ ERROR associated `static` items are not allowed
static IB: u8; //~ ERROR associated `static` items are not allowed
@@ -12,7 +12,7 @@ impl S {
//~^ ERROR a static item cannot be `default`
}
-#[cfg(FALSE)]
+#[cfg(false)]
trait T {
static TA: u8 = 0; //~ ERROR associated `static` items are not allowed
static TB: u8; //~ ERROR associated `static` items are not allowed
@@ -22,7 +22,7 @@ trait T {
//~^ ERROR a static item cannot be `default`
}
-#[cfg(FALSE)]
+#[cfg(false)]
impl T for S {
static TA: u8 = 0; //~ ERROR associated `static` items are not allowed
static TB: u8; //~ ERROR associated `static` items are not allowed
diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs
index 26761a1..1380974 100644
--- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs
+++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.rs
@@ -1,108 +1,108 @@
fn main() {}
-#[cfg(FALSE)] fn e() { let _ = [#[attr]]; }
+#[cfg(false)] fn e() { let _ = [#[attr]]; }
//~^ ERROR expected expression, found `]`
-#[cfg(FALSE)] fn e() { let _ = foo#[attr](); }
+#[cfg(false)] fn e() { let _ = foo#[attr](); }
//~^ ERROR expected one of
-#[cfg(FALSE)] fn e() { let _ = foo(#![attr]); }
+#[cfg(false)] fn e() { let _ = foo(#![attr]); }
//~^ ERROR an inner attribute is not permitted in this context
//~| ERROR an inner attribute is not permitted in this context
//~| ERROR expected expression, found `)`
-#[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); }
+#[cfg(false)] fn e() { let _ = x.foo(#![attr]); }
//~^ ERROR an inner attribute is not permitted in this context
//~| ERROR expected expression, found `)`
-#[cfg(FALSE)] fn e() { let _ = 0 + #![attr] 0; }
+#[cfg(false)] fn e() { let _ = 0 + #![attr] 0; }
//~^ ERROR an inner attribute is not permitted in this context
-#[cfg(FALSE)] fn e() { let _ = !#![attr] 0; }
+#[cfg(false)] fn e() { let _ = !#![attr] 0; }
//~^ ERROR an inner attribute is not permitted in this context
-#[cfg(FALSE)] fn e() { let _ = -#![attr] 0; }
+#[cfg(false)] fn e() { let _ = -#![attr] 0; }
//~^ ERROR an inner attribute is not permitted in this context
-#[cfg(FALSE)] fn e() { let _ = x #![attr] as Y; }
+#[cfg(false)] fn e() { let _ = x #![attr] as Y; }
//~^ ERROR expected one of
-#[cfg(FALSE)] fn e() { let _ = || #![attr] foo; }
+#[cfg(false)] fn e() { let _ = || #![attr] foo; }
//~^ ERROR an inner attribute is not permitted in this context
-#[cfg(FALSE)] fn e() { let _ = move || #![attr] foo; }
+#[cfg(false)] fn e() { let _ = move || #![attr] foo; }
//~^ ERROR an inner attribute is not permitted in this context
-#[cfg(FALSE)] fn e() { let _ = || #![attr] {foo}; }
+#[cfg(false)] fn e() { let _ = || #![attr] {foo}; }
//~^ ERROR an inner attribute is not permitted in this context
-#[cfg(FALSE)] fn e() { let _ = move || #![attr] {foo}; }
+#[cfg(false)] fn e() { let _ = move || #![attr] {foo}; }
//~^ ERROR an inner attribute is not permitted in this context
-#[cfg(FALSE)] fn e() { let _ = #[attr] ..#[attr] 0; }
+#[cfg(false)] fn e() { let _ = #[attr] ..#[attr] 0; }
//~^ ERROR attributes are not allowed on range expressions starting with `..`
-#[cfg(FALSE)] fn e() { let _ = #[attr] ..; }
+#[cfg(false)] fn e() { let _ = #[attr] ..; }
//~^ ERROR attributes are not allowed on range expressions starting with `..`
-#[cfg(FALSE)] fn e() { let _ = #[attr] &#![attr] 0; }
+#[cfg(false)] fn e() { let _ = #[attr] &#![attr] 0; }
//~^ ERROR an inner attribute is not permitted in this context
-#[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; }
+#[cfg(false)] fn e() { let _ = #[attr] &mut #![attr] 0; }
//~^ ERROR an inner attribute is not permitted in this context
-#[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
+#[cfg(false)] fn e() { let _ = if 0 #[attr] {}; }
//~^ ERROR outer attributes are not allowed on `if`
-#[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; }
+#[cfg(false)] fn e() { let _ = if 0 {#![attr]}; }
//~^ ERROR an inner attribute is not permitted in this context
-#[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; }
+#[cfg(false)] fn e() { let _ = if 0 {} #[attr] else {}; }
//~^ ERROR expected one of
-#[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; }
+#[cfg(false)] fn e() { let _ = if 0 {} else #[attr] {}; }
//~^ ERROR outer attributes are not allowed on `if`
-#[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; }
+#[cfg(false)] fn e() { let _ = if 0 {} else {#![attr]}; }
//~^ ERROR an inner attribute is not permitted in this context
-#[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
+#[cfg(false)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
//~^ ERROR outer attributes are not allowed on `if`
-#[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
+#[cfg(false)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
//~^ ERROR outer attributes are not allowed on `if`
-#[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; }
+#[cfg(false)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; }
//~^ ERROR an inner attribute is not permitted in this context
-#[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
+#[cfg(false)] fn e() { let _ = if let _ = 0 #[attr] {}; }
//~^ ERROR outer attributes are not allowed on `if`
-#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; }
+#[cfg(false)] fn e() { let _ = if let _ = 0 {#![attr]}; }
//~^ ERROR an inner attribute is not permitted in this context
-#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; }
+#[cfg(false)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; }
//~^ ERROR expected one of
-#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
+#[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
//~^ ERROR outer attributes are not allowed on `if`
-#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; }
+#[cfg(false)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; }
//~^ ERROR an inner attribute is not permitted in this context
-#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
+#[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
//~^ ERROR outer attributes are not allowed on `if`
-#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
+#[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
//~^ ERROR outer attributes are not allowed on `if`
-#[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; }
+#[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; }
//~^ ERROR an inner attribute is not permitted in this context
-#[cfg(FALSE)] fn s() { #[attr] #![attr] let _ = 0; }
+#[cfg(false)] fn s() { #[attr] #![attr] let _ = 0; }
//~^ ERROR an inner attribute is not permitted following an outer attribute
-#[cfg(FALSE)] fn s() { #[attr] #![attr] 0; }
+#[cfg(false)] fn s() { #[attr] #![attr] 0; }
//~^ ERROR an inner attribute is not permitted following an outer attribute
-#[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); }
+#[cfg(false)] fn s() { #[attr] #![attr] foo!(); }
//~^ ERROR an inner attribute is not permitted following an outer attribute
-#[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; }
+#[cfg(false)] fn s() { #[attr] #![attr] foo![]; }
//~^ ERROR an inner attribute is not permitted following an outer attribute
-#[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; }
+#[cfg(false)] fn s() { #[attr] #![attr] foo!{}; }
//~^ ERROR an inner attribute is not permitted following an outer attribute
// FIXME: Allow attributes in pattern constexprs?
// note: requires parens in patterns to allow disambiguation
-#[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
+#[cfg(false)] fn e() { match 0 { 0..=#[attr] 10 => () } }
//~^ ERROR inclusive range with no end
//~| ERROR expected one of `=>`, `if`, or `|`, found `#`
-#[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
+#[cfg(false)] fn e() { match 0 { 0..=#[attr] -10 => () } }
//~^ ERROR inclusive range with no end
//~| ERROR expected one of `=>`, `if`, or `|`, found `#`
-#[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } }
+#[cfg(false)] fn e() { match 0 { 0..=-#[attr] 10 => () } }
//~^ ERROR unexpected token: `#`
-#[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
+#[cfg(false)] fn e() { match 0 { 0..=#[attr] FOO => () } }
//~^ ERROR inclusive range with no end
//~| ERROR expected one of `=>`, `if`, or `|`, found `#`
-#[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
+#[cfg(false)] fn e() { let _ = x.#![attr]foo(); }
//~^ ERROR unexpected token: `#`
//~| ERROR expected one of `.`
-#[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
+#[cfg(false)] fn e() { let _ = x.#[attr]foo(); }
//~^ ERROR unexpected token: `#`
//~| ERROR expected one of `.`
// make sure we don't catch this bug again...
-#[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } }
+#[cfg(false)] fn e() { { fn foo() { #[attr]; } } }
//~^ ERROR expected statement after outer attribute
-#[cfg(FALSE)] fn e() { { fn foo() { #[attr] } } }
+#[cfg(false)] fn e() { { fn foo() { #[attr] } } }
//~^ ERROR expected statement after outer attribute
diff --git a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
index bd86084..5d94a8d 100644
--- a/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
+++ b/tests/ui/parser/attribute/attr-stmt-expr-attr-bad.stderr
@@ -1,19 +1,19 @@
error: expected expression, found `]`
--> $DIR/attr-stmt-expr-attr-bad.rs:3:40
|
-LL | #[cfg(FALSE)] fn e() { let _ = [#[attr]]; }
+LL | #[cfg(false)] fn e() { let _ = [#[attr]]; }
| ^ expected expression
error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:5:35
|
-LL | #[cfg(FALSE)] fn e() { let _ = foo#[attr](); }
+LL | #[cfg(false)] fn e() { let _ = foo#[attr](); }
| ^ expected one of 8 possible tokens
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:7:36
|
-LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); }
+LL | #[cfg(false)] fn e() { let _ = foo(#![attr]); }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -22,7 +22,7 @@
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:7:36
|
-LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); }
+LL | #[cfg(false)] fn e() { let _ = foo(#![attr]); }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -32,13 +32,13 @@
error: expected expression, found `)`
--> $DIR/attr-stmt-expr-attr-bad.rs:7:44
|
-LL | #[cfg(FALSE)] fn e() { let _ = foo(#![attr]); }
+LL | #[cfg(false)] fn e() { let _ = foo(#![attr]); }
| ^ expected expression
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:11:38
|
-LL | #[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); }
+LL | #[cfg(false)] fn e() { let _ = x.foo(#![attr]); }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -47,13 +47,13 @@
error: expected expression, found `)`
--> $DIR/attr-stmt-expr-attr-bad.rs:11:46
|
-LL | #[cfg(FALSE)] fn e() { let _ = x.foo(#![attr]); }
+LL | #[cfg(false)] fn e() { let _ = x.foo(#![attr]); }
| ^ expected expression
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:14:36
|
-LL | #[cfg(FALSE)] fn e() { let _ = 0 + #![attr] 0; }
+LL | #[cfg(false)] fn e() { let _ = 0 + #![attr] 0; }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -62,7 +62,7 @@
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:16:33
|
-LL | #[cfg(FALSE)] fn e() { let _ = !#![attr] 0; }
+LL | #[cfg(false)] fn e() { let _ = !#![attr] 0; }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -71,7 +71,7 @@
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:18:33
|
-LL | #[cfg(FALSE)] fn e() { let _ = -#![attr] 0; }
+LL | #[cfg(false)] fn e() { let _ = -#![attr] 0; }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -80,13 +80,13 @@
error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:20:34
|
-LL | #[cfg(FALSE)] fn e() { let _ = x #![attr] as Y; }
+LL | #[cfg(false)] fn e() { let _ = x #![attr] as Y; }
| ^ expected one of 8 possible tokens
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:22:35
|
-LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] foo; }
+LL | #[cfg(false)] fn e() { let _ = || #![attr] foo; }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -95,7 +95,7 @@
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:24:40
|
-LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] foo; }
+LL | #[cfg(false)] fn e() { let _ = move || #![attr] foo; }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -104,7 +104,7 @@
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:26:35
|
-LL | #[cfg(FALSE)] fn e() { let _ = || #![attr] {foo}; }
+LL | #[cfg(false)] fn e() { let _ = || #![attr] {foo}; }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -113,7 +113,7 @@
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:28:40
|
-LL | #[cfg(FALSE)] fn e() { let _ = move || #![attr] {foo}; }
+LL | #[cfg(false)] fn e() { let _ = move || #![attr] {foo}; }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -122,19 +122,19 @@
error: attributes are not allowed on range expressions starting with `..`
--> $DIR/attr-stmt-expr-attr-bad.rs:30:40
|
-LL | #[cfg(FALSE)] fn e() { let _ = #[attr] ..#[attr] 0; }
+LL | #[cfg(false)] fn e() { let _ = #[attr] ..#[attr] 0; }
| ^^
error: attributes are not allowed on range expressions starting with `..`
--> $DIR/attr-stmt-expr-attr-bad.rs:32:40
|
-LL | #[cfg(FALSE)] fn e() { let _ = #[attr] ..; }
+LL | #[cfg(false)] fn e() { let _ = #[attr] ..; }
| ^^
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:34:41
|
-LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &#![attr] 0; }
+LL | #[cfg(false)] fn e() { let _ = #[attr] &#![attr] 0; }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -143,7 +143,7 @@
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:36:45
|
-LL | #[cfg(FALSE)] fn e() { let _ = #[attr] &mut #![attr] 0; }
+LL | #[cfg(false)] fn e() { let _ = #[attr] &mut #![attr] 0; }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -152,21 +152,21 @@
error: outer attributes are not allowed on `if` and `else` branches
--> $DIR/attr-stmt-expr-attr-bad.rs:38:37
|
-LL | #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
+LL | #[cfg(false)] fn e() { let _ = if 0 #[attr] {}; }
| -- ^^^^^^^ -- the attributes are attached to this branch
| |
| the branch belongs to this `if`
|
help: remove the attributes
|
-LL - #[cfg(FALSE)] fn e() { let _ = if 0 #[attr] {}; }
-LL + #[cfg(FALSE)] fn e() { let _ = if 0 {}; }
+LL - #[cfg(false)] fn e() { let _ = if 0 #[attr] {}; }
+LL + #[cfg(false)] fn e() { let _ = if 0 {}; }
|
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:40:38
|
-LL | #[cfg(FALSE)] fn e() { let _ = if 0 {#![attr]}; }
+LL | #[cfg(false)] fn e() { let _ = if 0 {#![attr]}; }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -175,27 +175,27 @@
error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:42:40
|
-LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} #[attr] else {}; }
+LL | #[cfg(false)] fn e() { let _ = if 0 {} #[attr] else {}; }
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
error: outer attributes are not allowed on `if` and `else` branches
--> $DIR/attr-stmt-expr-attr-bad.rs:44:45
|
-LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; }
+LL | #[cfg(false)] fn e() { let _ = if 0 {} else #[attr] {}; }
| ---- ^^^^^^^ -- the attributes are attached to this branch
| |
| the branch belongs to this `else`
|
help: remove the attributes
|
-LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] {}; }
-LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else {}; }
+LL - #[cfg(false)] fn e() { let _ = if 0 {} else #[attr] {}; }
+LL + #[cfg(false)] fn e() { let _ = if 0 {} else {}; }
|
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:46:46
|
-LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else {#![attr]}; }
+LL | #[cfg(false)] fn e() { let _ = if 0 {} else {#![attr]}; }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -204,35 +204,35 @@
error: outer attributes are not allowed on `if` and `else` branches
--> $DIR/attr-stmt-expr-attr-bad.rs:48:45
|
-LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
+LL | #[cfg(false)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
| ---- ^^^^^^^ ------- the attributes are attached to this branch
| |
| the branch belongs to this `else`
|
help: remove the attributes
|
-LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
-LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {}; }
+LL - #[cfg(false)] fn e() { let _ = if 0 {} else #[attr] if 0 {}; }
+LL + #[cfg(false)] fn e() { let _ = if 0 {} else if 0 {}; }
|
error: outer attributes are not allowed on `if` and `else` branches
--> $DIR/attr-stmt-expr-attr-bad.rs:50:50
|
-LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
+LL | #[cfg(false)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
| -- ^^^^^^^ -- the attributes are attached to this branch
| |
| the branch belongs to this `if`
|
help: remove the attributes
|
-LL - #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
-LL + #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {}; }
+LL - #[cfg(false)] fn e() { let _ = if 0 {} else if 0 #[attr] {}; }
+LL + #[cfg(false)] fn e() { let _ = if 0 {} else if 0 {}; }
|
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:52:51
|
-LL | #[cfg(FALSE)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; }
+LL | #[cfg(false)] fn e() { let _ = if 0 {} else if 0 {#![attr]}; }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -241,21 +241,21 @@
error: outer attributes are not allowed on `if` and `else` branches
--> $DIR/attr-stmt-expr-attr-bad.rs:54:45
|
-LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
+LL | #[cfg(false)] fn e() { let _ = if let _ = 0 #[attr] {}; }
| -- ^^^^^^^ -- the attributes are attached to this branch
| |
| the branch belongs to this `if`
|
help: remove the attributes
|
-LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 #[attr] {}; }
-LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {}; }
+LL - #[cfg(false)] fn e() { let _ = if let _ = 0 #[attr] {}; }
+LL + #[cfg(false)] fn e() { let _ = if let _ = 0 {}; }
|
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:56:46
|
-LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {#![attr]}; }
+LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {#![attr]}; }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -264,27 +264,27 @@
error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:58:48
|
-LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; }
+LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} #[attr] else {}; }
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
error: outer attributes are not allowed on `if` and `else` branches
--> $DIR/attr-stmt-expr-attr-bad.rs:60:53
|
-LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
+LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
| ---- ^^^^^^^ -- the attributes are attached to this branch
| |
| the branch belongs to this `else`
|
help: remove the attributes
|
-LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
-LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {}; }
+LL - #[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] {}; }
+LL + #[cfg(false)] fn e() { let _ = if let _ = 0 {} else {}; }
|
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:62:54
|
-LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; }
+LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} else {#![attr]}; }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -293,35 +293,35 @@
error: outer attributes are not allowed on `if` and `else` branches
--> $DIR/attr-stmt-expr-attr-bad.rs:64:53
|
-LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
+LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
| ---- ^^^^^^^ --------------- the attributes are attached to this branch
| |
| the branch belongs to this `else`
|
help: remove the attributes
|
-LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
-LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; }
+LL - #[cfg(false)] fn e() { let _ = if let _ = 0 {} else #[attr] if let _ = 0 {}; }
+LL + #[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; }
|
error: outer attributes are not allowed on `if` and `else` branches
--> $DIR/attr-stmt-expr-attr-bad.rs:66:66
|
-LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
+LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
| -- ^^^^^^^ -- the attributes are attached to this branch
| |
| the branch belongs to this `if`
|
help: remove the attributes
|
-LL - #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
-LL + #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; }
+LL - #[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 #[attr] {}; }
+LL + #[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {}; }
|
error: an inner attribute is not permitted in this context
--> $DIR/attr-stmt-expr-attr-bad.rs:68:67
|
-LL | #[cfg(FALSE)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; }
+LL | #[cfg(false)] fn e() { let _ = if let _ = 0 {} else if let _ = 0 {#![attr]}; }
| ^^^^^^^^
|
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
@@ -330,7 +330,7 @@
error: an inner attribute is not permitted following an outer attribute
--> $DIR/attr-stmt-expr-attr-bad.rs:71:32
|
-LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] let _ = 0; }
+LL | #[cfg(false)] fn s() { #[attr] #![attr] let _ = 0; }
| ------- ^^^^^^^^ not permitted following an outer attribute
| |
| previous outer attribute
@@ -341,7 +341,7 @@
error: an inner attribute is not permitted following an outer attribute
--> $DIR/attr-stmt-expr-attr-bad.rs:73:32
|
-LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] 0; }
+LL | #[cfg(false)] fn s() { #[attr] #![attr] 0; }
| ------- ^^^^^^^^ not permitted following an outer attribute
| |
| previous outer attribute
@@ -352,7 +352,7 @@
error: an inner attribute is not permitted following an outer attribute
--> $DIR/attr-stmt-expr-attr-bad.rs:75:32
|
-LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!(); }
+LL | #[cfg(false)] fn s() { #[attr] #![attr] foo!(); }
| ------- ^^^^^^^^ ------- the inner attribute doesn't annotate this item macro invocation
| | |
| | not permitted following an outer attribute
@@ -363,7 +363,7 @@
error: an inner attribute is not permitted following an outer attribute
--> $DIR/attr-stmt-expr-attr-bad.rs:77:32
|
-LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo![]; }
+LL | #[cfg(false)] fn s() { #[attr] #![attr] foo![]; }
| ------- ^^^^^^^^ ------- the inner attribute doesn't annotate this item macro invocation
| | |
| | not permitted following an outer attribute
@@ -374,7 +374,7 @@
error: an inner attribute is not permitted following an outer attribute
--> $DIR/attr-stmt-expr-attr-bad.rs:79:32
|
-LL | #[cfg(FALSE)] fn s() { #[attr] #![attr] foo!{}; }
+LL | #[cfg(false)] fn s() { #[attr] #![attr] foo!{}; }
| ------- ^^^^^^^^ ------ the inner attribute doesn't annotate this item macro invocation
| | |
| | not permitted following an outer attribute
@@ -385,100 +385,100 @@
error[E0586]: inclusive range with no end
--> $DIR/attr-stmt-expr-attr-bad.rs:85:35
|
-LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
+LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] 10 => () } }
| ^^^
|
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
help: use `..` instead
|
-LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
-LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] 10 => () } }
+LL - #[cfg(false)] fn e() { match 0 { 0..=#[attr] 10 => () } }
+LL + #[cfg(false)] fn e() { match 0 { 0..#[attr] 10 => () } }
|
error: expected one of `=>`, `if`, or `|`, found `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:85:38
|
-LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] 10 => () } }
+LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] 10 => () } }
| ^ expected one of `=>`, `if`, or `|`
error[E0586]: inclusive range with no end
--> $DIR/attr-stmt-expr-attr-bad.rs:88:35
|
-LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
+LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] -10 => () } }
| ^^^
|
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
help: use `..` instead
|
-LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
-LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] -10 => () } }
+LL - #[cfg(false)] fn e() { match 0 { 0..=#[attr] -10 => () } }
+LL + #[cfg(false)] fn e() { match 0 { 0..#[attr] -10 => () } }
|
error: expected one of `=>`, `if`, or `|`, found `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:88:38
|
-LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] -10 => () } }
+LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] -10 => () } }
| ^ expected one of `=>`, `if`, or `|`
error: unexpected token: `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:91:39
|
-LL | #[cfg(FALSE)] fn e() { match 0 { 0..=-#[attr] 10 => () } }
+LL | #[cfg(false)] fn e() { match 0 { 0..=-#[attr] 10 => () } }
| ^
error[E0586]: inclusive range with no end
--> $DIR/attr-stmt-expr-attr-bad.rs:93:35
|
-LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
+LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] FOO => () } }
| ^^^
|
= note: inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
help: use `..` instead
|
-LL - #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
-LL + #[cfg(FALSE)] fn e() { match 0 { 0..#[attr] FOO => () } }
+LL - #[cfg(false)] fn e() { match 0 { 0..=#[attr] FOO => () } }
+LL + #[cfg(false)] fn e() { match 0 { 0..#[attr] FOO => () } }
|
error: expected one of `=>`, `if`, or `|`, found `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:93:38
|
-LL | #[cfg(FALSE)] fn e() { match 0 { 0..=#[attr] FOO => () } }
+LL | #[cfg(false)] fn e() { match 0 { 0..=#[attr] FOO => () } }
| ^ expected one of `=>`, `if`, or `|`
error: unexpected token: `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:97:34
|
-LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
+LL | #[cfg(false)] fn e() { let _ = x.#![attr]foo(); }
| ^
error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:97:34
|
-LL | #[cfg(FALSE)] fn e() { let _ = x.#![attr]foo(); }
+LL | #[cfg(false)] fn e() { let _ = x.#![attr]foo(); }
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
error: unexpected token: `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:100:34
|
-LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
+LL | #[cfg(false)] fn e() { let _ = x.#[attr]foo(); }
| ^
error: expected one of `.`, `;`, `?`, `else`, or an operator, found `#`
--> $DIR/attr-stmt-expr-attr-bad.rs:100:34
|
-LL | #[cfg(FALSE)] fn e() { let _ = x.#[attr]foo(); }
+LL | #[cfg(false)] fn e() { let _ = x.#[attr]foo(); }
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
error: expected statement after outer attribute
--> $DIR/attr-stmt-expr-attr-bad.rs:105:37
|
-LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr]; } } }
+LL | #[cfg(false)] fn e() { { fn foo() { #[attr]; } } }
| ^^^^^^^
error: expected statement after outer attribute
--> $DIR/attr-stmt-expr-attr-bad.rs:107:37
|
-LL | #[cfg(FALSE)] fn e() { { fn foo() { #[attr] } } }
+LL | #[cfg(false)] fn e() { { fn foo() { #[attr] } } }
| ^^^^^^^
error: aborting due to 53 previous errors
diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs
index 33671df..371f19d 100644
--- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs
+++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.rs
@@ -1,7 +1,7 @@
#![feature(stmt_expr_attributes)]
fn foo() -> String {
- #[cfg(FALSE)]
+ #[cfg(false)]
[1, 2, 3].iter().map(|c| c.to_string()).collect::<String>() //~ ERROR expected `;`, found `#`
#[cfg(not(FALSE))]
String::new()
diff --git a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr
index 6266718..3a97a14 100644
--- a/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr
+++ b/tests/ui/parser/attribute/multiple-tail-expr-behind-cfg.stderr
@@ -1,7 +1,7 @@
error: expected `;`, found `#`
--> $DIR/multiple-tail-expr-behind-cfg.rs:5:64
|
-LL | #[cfg(FALSE)]
+LL | #[cfg(false)]
| ------------- only `;` terminated statements or tail expressions are allowed after this attribute
LL | [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
| ^ expected `;` here
@@ -18,7 +18,7 @@
| + +
help: it seems like you are trying to provide different expressions depending on `cfg`, consider using `if cfg!(..)`
|
-LL ~ if cfg!(FALSE) {
+LL ~ if cfg!(false) {
LL ~ [1, 2, 3].iter().map(|c| c.to_string()).collect::<String>()
LL ~ } else if cfg!(not(FALSE)) {
LL ~ String::new()
diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs
index e2a6292..1cd3f13 100644
--- a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs
+++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.rs
@@ -5,7 +5,7 @@ macro_rules! the_macro {
#[cfg()]
$foo //~ ERROR expected `;`, found `#`
- #[cfg(FALSE)]
+ #[cfg(false)]
$bar
};
}
diff --git a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr
index fa4409f..41e7b5a 100644
--- a/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr
+++ b/tests/ui/parser/attribute/properly-recover-from-trailing-outer-attribute-in-body-2.stderr
@@ -6,7 +6,7 @@
LL | $foo
| ^ expected `;` here
LL |
-LL | #[cfg(FALSE)]
+LL | #[cfg(false)]
| - unexpected token
...
LL | the_macro!( (); (); );
diff --git a/tests/ui/parser/bad-lit-suffixes.stderr b/tests/ui/parser/bad-lit-suffixes.stderr
index d6b50b0..86ef35b 100644
--- a/tests/ui/parser/bad-lit-suffixes.stderr
+++ b/tests/ui/parser/bad-lit-suffixes.stderr
@@ -51,7 +51,7 @@
|
= help: the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
-warning: extern declarations without an explicit ABI are deprecated
+warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/bad-lit-suffixes.rs:3:1
|
LL | extern
@@ -59,7 +59,7 @@
|
= note: `#[warn(missing_abi)]` on by default
-warning: extern declarations without an explicit ABI are deprecated
+warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/bad-lit-suffixes.rs:7:1
|
LL | extern
diff --git a/tests/ui/parser/brace-in-let-chain.rs b/tests/ui/parser/brace-in-let-chain.rs
index 2009bc8..2558644 100644
--- a/tests/ui/parser/brace-in-let-chain.rs
+++ b/tests/ui/parser/brace-in-let-chain.rs
@@ -1,6 +1,6 @@
// issue #117766
+//@ edition: 2024
-#![feature(let_chains)]
fn main() {
if let () = ()
&& let () = () {
diff --git a/tests/ui/parser/circular_modules_hello.rs b/tests/ui/parser/circular_modules_hello.rs
index eb0284d..540752e 100644
--- a/tests/ui/parser/circular_modules_hello.rs
+++ b/tests/ui/parser/circular_modules_hello.rs
@@ -1,4 +1,4 @@
-//@ ignore-test: this is an auxiliary file for circular-modules-main.rs
+//@ ignore-auxiliary (used by `./circular-modules-main.rs`)
#[path = "circular_modules_main.rs"]
mod circular_modules_main;
diff --git a/tests/ui/parser/constraints-before-generic-args-syntactic-pass.rs b/tests/ui/parser/constraints-before-generic-args-syntactic-pass.rs
index ed3ffed..acc58a4 100644
--- a/tests/ui/parser/constraints-before-generic-args-syntactic-pass.rs
+++ b/tests/ui/parser/constraints-before-generic-args-syntactic-pass.rs
@@ -1,6 +1,6 @@
//@ check-pass
-#[cfg(FALSE)]
+#[cfg(false)]
fn syntax() {
foo::<T = u8, T: Ord, String>();
foo::<T = u8, 'a, T: Ord>();
diff --git a/tests/ui/parser/default-on-wrong-item-kind.rs b/tests/ui/parser/default-on-wrong-item-kind.rs
index 98a95cf..da990a4 100644
--- a/tests/ui/parser/default-on-wrong-item-kind.rs
+++ b/tests/ui/parser/default-on-wrong-item-kind.rs
@@ -4,7 +4,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
mod free_items {
default extern crate foo; //~ ERROR an extern crate cannot be `default`
default use foo; //~ ERROR a `use` import cannot be `default`
@@ -28,7 +28,7 @@ mod free_items {
default macro_rules! foo {} //~ ERROR a macro definition cannot be `default`
}
-#[cfg(FALSE)]
+#[cfg(false)]
extern "C" {
default extern crate foo; //~ ERROR an extern crate cannot be `default`
//~^ ERROR extern crate is not supported in `extern` blocks
@@ -65,7 +65,7 @@ mod free_items {
//~^ ERROR macro definition is not supported in `extern` blocks
}
-#[cfg(FALSE)]
+#[cfg(false)]
impl S {
default extern crate foo; //~ ERROR an extern crate cannot be `default`
//~^ ERROR extern crate is not supported in `trait`s or `impl`s
@@ -102,7 +102,7 @@ impl S {
//~^ ERROR macro definition is not supported in `trait`s or `impl`s
}
-#[cfg(FALSE)]
+#[cfg(false)]
trait T {
default extern crate foo; //~ ERROR an extern crate cannot be `default`
//~^ ERROR extern crate is not supported in `trait`s or `impl`s
diff --git a/tests/ui/parser/deli-ident-issue-1.rs b/tests/ui/parser/deli-ident-issue-1.rs
index 224ee6c..b7e7df1 100644
--- a/tests/ui/parser/deli-ident-issue-1.rs
+++ b/tests/ui/parser/deli-ident-issue-1.rs
@@ -1,4 +1,4 @@
-#![feature(let_chains)]
+//@ edition: 2024
trait Demo {}
impl dyn Demo {
diff --git a/tests/ui/parser/expr-rarrow-call-on-a-raw-pointer.rs b/tests/ui/parser/expr-rarrow-call-on-a-raw-pointer.rs
new file mode 100644
index 0000000..0ce5e23
--- /dev/null
+++ b/tests/ui/parser/expr-rarrow-call-on-a-raw-pointer.rs
@@ -0,0 +1,22 @@
+#![allow(
+ dead_code,
+ unused_must_use
+)]
+
+struct Named {
+ foo: usize,
+}
+
+struct Unnamed(usize);
+
+unsafe fn named_struct_field_access(named: *mut Named) {
+ named->foo += 1; //~ ERROR `->` is not valid syntax for field accesses and method calls
+ //~^ ERROR no field `foo` on type `*mut Named`
+}
+
+unsafe fn unnamed_struct_field_access(unnamed: *mut Unnamed) {
+ unnamed->0 += 1; //~ ERROR `->` is not valid syntax for field accesses and method calls
+ //~^ ERROR no field `0` on type `*mut Unnamed`
+}
+
+fn main() {}
diff --git a/tests/ui/parser/expr-rarrow-call-on-a-raw-pointer.stderr b/tests/ui/parser/expr-rarrow-call-on-a-raw-pointer.stderr
new file mode 100644
index 0000000..45f3c55
--- /dev/null
+++ b/tests/ui/parser/expr-rarrow-call-on-a-raw-pointer.stderr
@@ -0,0 +1,53 @@
+error: `->` is not valid syntax for field accesses and method calls
+ --> $DIR/expr-rarrow-call-on-a-raw-pointer.rs:13:10
+ |
+LL | named->foo += 1;
+ | ^^
+ |
+ = help: the `.` operator will automatically dereference the value, except if the value is a raw pointer
+help: try using `.` instead
+ |
+LL - named->foo += 1;
+LL + named.foo += 1;
+ |
+
+error: `->` is not valid syntax for field accesses and method calls
+ --> $DIR/expr-rarrow-call-on-a-raw-pointer.rs:18:12
+ |
+LL | unnamed->0 += 1;
+ | ^^
+ |
+ = help: the `.` operator will automatically dereference the value, except if the value is a raw pointer
+help: try using `.` instead
+ |
+LL - unnamed->0 += 1;
+LL + unnamed.0 += 1;
+ |
+
+error[E0609]: no field `foo` on type `*mut Named`
+ --> $DIR/expr-rarrow-call-on-a-raw-pointer.rs:13:12
+ |
+LL | named->foo += 1;
+ | ^^^ unknown field
+ |
+help: `named` is a raw pointer; try dereferencing it
+ |
+LL - named->foo += 1;
+LL + (*named).foo += 1;
+ |
+
+error[E0609]: no field `0` on type `*mut Unnamed`
+ --> $DIR/expr-rarrow-call-on-a-raw-pointer.rs:18:14
+ |
+LL | unnamed->0 += 1;
+ | ^ unknown field
+ |
+help: `unnamed` is a raw pointer; try dereferencing it
+ |
+LL - unnamed->0 += 1;
+LL + (*unnamed).0 += 1;
+ |
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0609`.
diff --git a/tests/ui/parser/expr-rarrow-call.fixed b/tests/ui/parser/expr-rarrow-call.fixed
index 9a05e20..c97284c 100644
--- a/tests/ui/parser/expr-rarrow-call.fixed
+++ b/tests/ui/parser/expr-rarrow-call.fixed
@@ -11,23 +11,23 @@
struct Unnamed(usize);
fn named_struct_field_access(named: &Named) {
- named.foo; //~ ERROR `->` used for field access or method call
+ named.foo; //~ ERROR `->` is not valid syntax for field accesses and method calls
}
fn unnamed_struct_field_access(unnamed: &Unnamed) {
- unnamed.0; //~ ERROR `->` used for field access or method call
+ unnamed.0; //~ ERROR `->` is not valid syntax for field accesses and method calls
}
fn tuple_field_access(t: &(u8, u8)) {
- t.0; //~ ERROR `->` used for field access or method call
- t.1; //~ ERROR `->` used for field access or method call
+ t.0; //~ ERROR `->` is not valid syntax for field accesses and method calls
+ t.1; //~ ERROR `->` is not valid syntax for field accesses and method calls
}
#[derive(Clone)]
struct Foo;
fn method_call(foo: &Foo) {
- foo.clone(); //~ ERROR `->` used for field access or method call
+ foo.clone(); //~ ERROR `->` is not valid syntax for field accesses and method calls
}
fn main() {}
diff --git a/tests/ui/parser/expr-rarrow-call.rs b/tests/ui/parser/expr-rarrow-call.rs
index 760b0f6..78cd72b 100644
--- a/tests/ui/parser/expr-rarrow-call.rs
+++ b/tests/ui/parser/expr-rarrow-call.rs
@@ -11,23 +11,23 @@ struct Named {
struct Unnamed(usize);
fn named_struct_field_access(named: &Named) {
- named->foo; //~ ERROR `->` used for field access or method call
+ named->foo; //~ ERROR `->` is not valid syntax for field accesses and method calls
}
fn unnamed_struct_field_access(unnamed: &Unnamed) {
- unnamed->0; //~ ERROR `->` used for field access or method call
+ unnamed->0; //~ ERROR `->` is not valid syntax for field accesses and method calls
}
fn tuple_field_access(t: &(u8, u8)) {
- t->0; //~ ERROR `->` used for field access or method call
- t->1; //~ ERROR `->` used for field access or method call
+ t->0; //~ ERROR `->` is not valid syntax for field accesses and method calls
+ t->1; //~ ERROR `->` is not valid syntax for field accesses and method calls
}
#[derive(Clone)]
struct Foo;
fn method_call(foo: &Foo) {
- foo->clone(); //~ ERROR `->` used for field access or method call
+ foo->clone(); //~ ERROR `->` is not valid syntax for field accesses and method calls
}
fn main() {}
diff --git a/tests/ui/parser/expr-rarrow-call.stderr b/tests/ui/parser/expr-rarrow-call.stderr
index 2e168ca..0b10527 100644
--- a/tests/ui/parser/expr-rarrow-call.stderr
+++ b/tests/ui/parser/expr-rarrow-call.stderr
@@ -1,62 +1,62 @@
-error: `->` used for field access or method call
+error: `->` is not valid syntax for field accesses and method calls
--> $DIR/expr-rarrow-call.rs:14:10
|
LL | named->foo;
| ^^
|
- = help: the `.` operator will dereference the value if needed
+ = help: the `.` operator will automatically dereference the value, except if the value is a raw pointer
help: try using `.` instead
|
LL - named->foo;
LL + named.foo;
|
-error: `->` used for field access or method call
+error: `->` is not valid syntax for field accesses and method calls
--> $DIR/expr-rarrow-call.rs:18:12
|
LL | unnamed->0;
| ^^
|
- = help: the `.` operator will dereference the value if needed
+ = help: the `.` operator will automatically dereference the value, except if the value is a raw pointer
help: try using `.` instead
|
LL - unnamed->0;
LL + unnamed.0;
|
-error: `->` used for field access or method call
+error: `->` is not valid syntax for field accesses and method calls
--> $DIR/expr-rarrow-call.rs:22:6
|
LL | t->0;
| ^^
|
- = help: the `.` operator will dereference the value if needed
+ = help: the `.` operator will automatically dereference the value, except if the value is a raw pointer
help: try using `.` instead
|
LL - t->0;
LL + t.0;
|
-error: `->` used for field access or method call
+error: `->` is not valid syntax for field accesses and method calls
--> $DIR/expr-rarrow-call.rs:23:6
|
LL | t->1;
| ^^
|
- = help: the `.` operator will dereference the value if needed
+ = help: the `.` operator will automatically dereference the value, except if the value is a raw pointer
help: try using `.` instead
|
LL - t->1;
LL + t.1;
|
-error: `->` used for field access or method call
+error: `->` is not valid syntax for field accesses and method calls
--> $DIR/expr-rarrow-call.rs:30:8
|
LL | foo->clone();
| ^^
|
- = help: the `.` operator will dereference the value if needed
+ = help: the `.` operator will automatically dereference the value, except if the value is a raw pointer
help: try using `.` instead
|
LL - foo->clone();
diff --git a/tests/ui/parser/extern-abi-syntactic.rs b/tests/ui/parser/extern-abi-syntactic.rs
index d3e2ba0..28565a3 100644
--- a/tests/ui/parser/extern-abi-syntactic.rs
+++ b/tests/ui/parser/extern-abi-syntactic.rs
@@ -5,13 +5,13 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
extern "some_abi_that_we_are_sure_does_not_exist_semantically" fn foo() {}
-#[cfg(FALSE)]
+#[cfg(false)]
extern "some_abi_that_we_are_sure_does_not_exist_semantically" {
fn foo();
}
-#[cfg(FALSE)]
+#[cfg(false)]
type T = extern "some_abi_that_we_are_sure_does_not_exist_semantically" fn();
diff --git a/tests/ui/parser/extern-crate-async.rs b/tests/ui/parser/extern-crate-async.rs
index 7c77690..529e0f1 100644
--- a/tests/ui/parser/extern-crate-async.rs
+++ b/tests/ui/parser/extern-crate-async.rs
@@ -5,8 +5,8 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
extern crate async;
-#[cfg(FALSE)]
+#[cfg(false)]
extern crate async as something_else;
diff --git a/tests/ui/parser/fn-body-optional-syntactic-pass.rs b/tests/ui/parser/fn-body-optional-syntactic-pass.rs
index 140471d..762247e6 100644
--- a/tests/ui/parser/fn-body-optional-syntactic-pass.rs
+++ b/tests/ui/parser/fn-body-optional-syntactic-pass.rs
@@ -4,7 +4,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn syntax() {
fn f();
fn f() {}
diff --git a/tests/ui/parser/fn-header-syntactic-pass.rs b/tests/ui/parser/fn-header-syntactic-pass.rs
index 065ded3..1e15886 100644
--- a/tests/ui/parser/fn-header-syntactic-pass.rs
+++ b/tests/ui/parser/fn-header-syntactic-pass.rs
@@ -5,7 +5,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn syntax() {
async fn f();
unsafe fn f();
diff --git a/tests/ui/parser/foreign-const-syntactic-fail.rs b/tests/ui/parser/foreign-const-syntactic-fail.rs
index a6e77f8..fc3cd0b 100644
--- a/tests/ui/parser/foreign-const-syntactic-fail.rs
+++ b/tests/ui/parser/foreign-const-syntactic-fail.rs
@@ -2,7 +2,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
extern "C" {
const A: isize; //~ ERROR extern items cannot be `const`
const B: isize = 42; //~ ERROR extern items cannot be `const`
diff --git a/tests/ui/parser/foreign-static-syntactic-pass.rs b/tests/ui/parser/foreign-static-syntactic-pass.rs
index a76b9ba..d7c21c6 100644
--- a/tests/ui/parser/foreign-static-syntactic-pass.rs
+++ b/tests/ui/parser/foreign-static-syntactic-pass.rs
@@ -4,7 +4,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
extern "C" {
static X: u8;
static mut Y: u8;
diff --git a/tests/ui/parser/foreign-ty-syntactic-pass.rs b/tests/ui/parser/foreign-ty-syntactic-pass.rs
index 50bb68c..3372768 100644
--- a/tests/ui/parser/foreign-ty-syntactic-pass.rs
+++ b/tests/ui/parser/foreign-ty-syntactic-pass.rs
@@ -2,7 +2,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
extern "C" {
type A: Ord;
type A<'a> where 'a: 'static;
diff --git a/tests/ui/parser/impl-item-const-pass.rs b/tests/ui/parser/impl-item-const-pass.rs
index 8ebdf63..6ca4cd9 100644
--- a/tests/ui/parser/impl-item-const-pass.rs
+++ b/tests/ui/parser/impl-item-const-pass.rs
@@ -2,7 +2,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
impl X {
const Y: u8;
}
diff --git a/tests/ui/parser/impl-item-fn-no-body-pass.rs b/tests/ui/parser/impl-item-fn-no-body-pass.rs
index 5a593fe..b8269fc 100644
--- a/tests/ui/parser/impl-item-fn-no-body-pass.rs
+++ b/tests/ui/parser/impl-item-fn-no-body-pass.rs
@@ -2,7 +2,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
impl X {
fn f();
}
diff --git a/tests/ui/parser/impl-item-type-no-body-pass.rs b/tests/ui/parser/impl-item-type-no-body-pass.rs
index 039825b..979b5f7 100644
--- a/tests/ui/parser/impl-item-type-no-body-pass.rs
+++ b/tests/ui/parser/impl-item-type-no-body-pass.rs
@@ -2,7 +2,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
impl X {
type Y;
type Z: Ord;
diff --git a/tests/ui/parser/inverted-parameters.rs b/tests/ui/parser/inverted-parameters.rs
index 5c42725..bc2f53f 100644
--- a/tests/ui/parser/inverted-parameters.rs
+++ b/tests/ui/parser/inverted-parameters.rs
@@ -1,3 +1,5 @@
+//@ dont-require-annotations: SUGGESTION
+
struct S;
impl S {
diff --git a/tests/ui/parser/inverted-parameters.stderr b/tests/ui/parser/inverted-parameters.stderr
index 8662277..7b96903 100644
--- a/tests/ui/parser/inverted-parameters.stderr
+++ b/tests/ui/parser/inverted-parameters.stderr
@@ -1,5 +1,5 @@
error: expected one of `:`, `@`, or `|`, found `bar`
- --> $DIR/inverted-parameters.rs:4:24
+ --> $DIR/inverted-parameters.rs:6:24
|
LL | fn foo(&self, &str bar) {}
| -----^^^
@@ -8,7 +8,7 @@
| help: declare the type after the parameter binding: `<identifier>: <type>`
error: expected one of `:`, `@`, or `|`, found `quux`
- --> $DIR/inverted-parameters.rs:10:10
+ --> $DIR/inverted-parameters.rs:12:10
|
LL | fn baz(S quux, xyzzy: i32) {}
| --^^^^
@@ -17,19 +17,19 @@
| help: declare the type after the parameter binding: `<identifier>: <type>`
error: expected one of `:`, `@`, or `|`, found `a`
- --> $DIR/inverted-parameters.rs:15:12
+ --> $DIR/inverted-parameters.rs:17:12
|
LL | fn one(i32 a b) {}
| ^ expected one of `:`, `@`, or `|`
error: expected one of `:` or `|`, found `(`
- --> $DIR/inverted-parameters.rs:18:23
+ --> $DIR/inverted-parameters.rs:20:23
|
LL | fn pattern((i32, i32) (a, b)) {}
| ^ expected one of `:` or `|`
error: expected one of `:`, `@`, or `|`, found `)`
- --> $DIR/inverted-parameters.rs:21:12
+ --> $DIR/inverted-parameters.rs:23:12
|
LL | fn fizz(i32) {}
| ^ expected one of `:`, `@`, or `|`
@@ -49,7 +49,7 @@
| ++
error: expected one of `:`, `@`, or `|`, found `S`
- --> $DIR/inverted-parameters.rs:27:23
+ --> $DIR/inverted-parameters.rs:29:23
|
LL | fn missing_colon(quux S) {}
| -----^
diff --git a/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/recursive.rs b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/recursive.rs
index 3d758be..2e9a15e 100644
--- a/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/recursive.rs
+++ b/tests/ui/parser/issues/circular-module-with-doc-comment-issue-97589/recursive.rs
@@ -1,4 +1,4 @@
-//@ ignore-test: this is an auxiliary file for circular-module-with-doc-comment-issue-97589.rs
+//@ ignore-auxiliary (used by `./circular-module-with-doc-comment-issue-97589.rs`)
//! this comment caused the circular dependency checker to break
diff --git a/tests/ui/parser/issues/issue-103381.fixed b/tests/ui/parser/issues/issue-103381.fixed
index 87c3087..955b246 100644
--- a/tests/ui/parser/issues/issue-103381.fixed
+++ b/tests/ui/parser/issues/issue-103381.fixed
@@ -1,6 +1,6 @@
+//@ edition: 2024
//@ run-rustfix
-#![feature(let_chains)]
#![allow(unused_variables)]
#![allow(dead_code)]
#![allow(irrefutable_let_patterns)]
diff --git a/tests/ui/parser/issues/issue-103381.rs b/tests/ui/parser/issues/issue-103381.rs
index ccbc40e..d4b06b9 100644
--- a/tests/ui/parser/issues/issue-103381.rs
+++ b/tests/ui/parser/issues/issue-103381.rs
@@ -1,6 +1,6 @@
+//@ edition: 2024
//@ run-rustfix
-#![feature(let_chains)]
#![allow(unused_variables)]
#![allow(dead_code)]
#![allow(irrefutable_let_patterns)]
diff --git a/tests/ui/parser/issues/issue-118530-ice.rs b/tests/ui/parser/issues/issue-118530-ice.rs
index cf14eeb..8930eb8 100644
--- a/tests/ui/parser/issues/issue-118530-ice.rs
+++ b/tests/ui/parser/issues/issue-118530-ice.rs
@@ -5,7 +5,7 @@
attr::fn bar() -> String { //~ ERROR expected identifier, found keyword `fn`
//~^ ERROR expected one of `(`, `.`, `::`, `;`, `?`, `}`, or an operator, found `{`
//~| ERROR expected `;`, found `bar`
- //~| ERROR `->` used for field access or method call
+ //~| ERROR `->` is not valid syntax for field accesses and method calls
#[attr]
[1, 2, 3].iter().map().collect::<String>()
#[attr]
diff --git a/tests/ui/parser/issues/issue-118530-ice.stderr b/tests/ui/parser/issues/issue-118530-ice.stderr
index 72c0397..ef891d1 100644
--- a/tests/ui/parser/issues/issue-118530-ice.stderr
+++ b/tests/ui/parser/issues/issue-118530-ice.stderr
@@ -33,13 +33,13 @@
| |
| help: add `;` here
-error: `->` used for field access or method call
+error: `->` is not valid syntax for field accesses and method calls
--> $DIR/issue-118530-ice.rs:5:20
|
LL | attr::fn bar() -> String {
| ^^
|
- = help: the `.` operator will dereference the value if needed
+ = help: the `.` operator will automatically dereference the value, except if the value is a raw pointer
help: try using `.` instead
|
LL - attr::fn bar() -> String {
diff --git a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
index e34371b..64cf8ba 100644
--- a/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
+++ b/tests/ui/parser/issues/issue-35813-postfix-after-cast.stderr
@@ -49,24 +49,18 @@
|
LL | let _ = 0i32: i32: i32.count_ones();
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
- |
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
error: expected one of `!`, `(`, `.`, `::`, `;`, `<`, `?`, or `else`, found `:`
--> $DIR/issue-35813-postfix-after-cast.rs:43:21
|
LL | let _ = 0 as i32: i32.count_ones();
| ^ expected one of 8 possible tokens
- |
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:`
--> $DIR/issue-35813-postfix-after-cast.rs:47:17
|
LL | let _ = 0i32: i32 as i32.count_ones();
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
- |
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
error: cast cannot be followed by a method call
--> $DIR/issue-35813-postfix-after-cast.rs:51:13
@@ -84,16 +78,12 @@
|
LL | let _ = 0i32: i32: i32 as u32 as i32.count_ones();
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
- |
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:`
--> $DIR/issue-35813-postfix-after-cast.rs:60:17
|
LL | let _ = 0i32: i32.count_ones(): u32;
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
- |
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
error: cast cannot be followed by a method call
--> $DIR/issue-35813-postfix-after-cast.rs:64:13
@@ -111,16 +101,12 @@
|
LL | let _ = 0 as i32.count_ones(): u32;
| ^ expected one of `.`, `;`, `?`, or `else`
- |
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
error: expected one of `.`, `;`, `?`, `else`, or an operator, found `:`
--> $DIR/issue-35813-postfix-after-cast.rs:69:17
|
LL | let _ = 0i32: i32.count_ones() as u32;
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
- |
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
error: cast cannot be followed by a method call
--> $DIR/issue-35813-postfix-after-cast.rs:73:13
@@ -138,8 +124,6 @@
|
LL | let _ = 0i32: i32: i32.count_ones() as u32 as i32;
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
- |
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
error: cast cannot be followed by a method call
--> $DIR/issue-35813-postfix-after-cast.rs:82:13
@@ -262,8 +246,6 @@
|
LL | drop_ptr: F();
| ^ expected identifier
- |
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `:`
--> $DIR/issue-35813-postfix-after-cast.rs:160:13
diff --git a/tests/ui/parser/issues/issue-48508-aux.rs b/tests/ui/parser/issues/issue-48508-aux.rs
index 0f2b442..0bf6490e 100644
--- a/tests/ui/parser/issues/issue-48508-aux.rs
+++ b/tests/ui/parser/issues/issue-48508-aux.rs
@@ -1,5 +1,4 @@
-//@ run-pass
-//@ ignore-test Not a test. Used by issue-48508.rs
+//@ ignore-auxiliary (used by `./issue-48508.rs`)
pub fn other() -> f64 {
let µ = 1.0;
diff --git a/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs b/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs
index 4fa803b..13bb935 100644
--- a/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs
+++ b/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-enum.rs
@@ -20,7 +20,7 @@ enum Enum {
mac_variant!(MARKER);
// We also accept visibilities on variants syntactically but not semantically.
-#[cfg(FALSE)]
+#[cfg(false)]
enum E {
pub U,
pub(crate) T(u8),
diff --git a/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs b/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs
index cd474db..55e69cd 100644
--- a/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs
+++ b/tests/ui/parser/issues/issue-65041-empty-vis-matcher-in-trait.rs
@@ -20,7 +20,7 @@ trait Alpha {
}
// We also accept visibilities on items in traits syntactically but not semantically.
-#[cfg(FALSE)]
+#[cfg(false)]
trait Foo {
pub fn bar();
pub(crate) type baz;
diff --git a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs
index cf754a6..782a46a 100644
--- a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs
+++ b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.rs
@@ -12,7 +12,7 @@ fn w<$lt>(w: &mut $lt i32) {}
// avoid false positives
fn y<'a>(y: &mut 'a + Send) {
- //~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a`
+ //~^ ERROR expected a path on the left-hand side of `+`
//~| ERROR at least one trait is required for an object type
let z = y as &mut 'a + Send;
//~^ ERROR expected value, found trait `Send`
diff --git a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr
index 6b8f8e4..ae1ed72 100644
--- a/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr
+++ b/tests/ui/parser/issues/issue-73568-lifetime-after-mut.stderr
@@ -10,11 +10,11 @@
LL + fn x<'a>(x: &'a mut i32){}
|
-error[E0178]: expected a path on the left-hand side of `+`, not `&mut 'a`
+error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/issue-73568-lifetime-after-mut.rs:14:13
|
LL | fn y<'a>(y: &mut 'a + Send) {
- | ^^^^^^^^^^^^^^
+ | ^^^^^^^
|
help: try adding parentheses
|
diff --git a/tests/ui/parser/item-free-const-no-body-syntactic-pass.rs b/tests/ui/parser/item-free-const-no-body-syntactic-pass.rs
index 4edbee5..0b92298 100644
--- a/tests/ui/parser/item-free-const-no-body-syntactic-pass.rs
+++ b/tests/ui/parser/item-free-const-no-body-syntactic-pass.rs
@@ -4,5 +4,5 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
const X: u8;
diff --git a/tests/ui/parser/item-free-static-no-body-syntactic-pass.rs b/tests/ui/parser/item-free-static-no-body-syntactic-pass.rs
index df51926..8dae433 100644
--- a/tests/ui/parser/item-free-static-no-body-syntactic-pass.rs
+++ b/tests/ui/parser/item-free-static-no-body-syntactic-pass.rs
@@ -4,5 +4,5 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
static X: u8;
diff --git a/tests/ui/parser/item-free-type-bounds-syntactic-pass.rs b/tests/ui/parser/item-free-type-bounds-syntactic-pass.rs
index 80de3cf..8603dc3 100644
--- a/tests/ui/parser/item-free-type-bounds-syntactic-pass.rs
+++ b/tests/ui/parser/item-free-type-bounds-syntactic-pass.rs
@@ -2,7 +2,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn syntax() {
type A: Ord;
type B: Ord = u8;
diff --git a/tests/ui/parser/lit-err-in-macro.stderr b/tests/ui/parser/lit-err-in-macro.stderr
index 9422f22..08fe586 100644
--- a/tests/ui/parser/lit-err-in-macro.stderr
+++ b/tests/ui/parser/lit-err-in-macro.stderr
@@ -4,7 +4,7 @@
LL | f!("Foo"__);
| ^^^^^^^ invalid suffix `__`
-warning: extern declarations without an explicit ABI are deprecated
+warning: `extern` declarations without an explicit ABI are deprecated
--> $DIR/lit-err-in-macro.rs:3:9
|
LL | extern $abi fn f() {}
diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.e2015.stderr b/tests/ui/parser/macro/trait-object-macro-matcher.e2015.stderr
new file mode 100644
index 0000000..f2db351
--- /dev/null
+++ b/tests/ui/parser/macro/trait-object-macro-matcher.e2015.stderr
@@ -0,0 +1,32 @@
+error: lifetimes must be followed by `+` to form a trait object type
+ --> $DIR/trait-object-macro-matcher.rs:17:8
+ |
+LL | m!('static);
+ | ^^^^^^^
+ |
+help: consider adding a trait bound after the potential lifetime bound
+ |
+LL | m!('static + /* Trait */);
+ | +++++++++++++
+
+error: lifetimes must be followed by `+` to form a trait object type
+ --> $DIR/trait-object-macro-matcher.rs:17:8
+ |
+LL | m!('static);
+ | ^^^^^^^
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: consider adding a trait bound after the potential lifetime bound
+ |
+LL | m!('static + /* Trait */);
+ | +++++++++++++
+
+error[E0224]: at least one trait is required for an object type
+ --> $DIR/trait-object-macro-matcher.rs:17:8
+ |
+LL | m!('static);
+ | ^^^^^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0224`.
diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.e2021.stderr b/tests/ui/parser/macro/trait-object-macro-matcher.e2021.stderr
new file mode 100644
index 0000000..7d9e8d7
--- /dev/null
+++ b/tests/ui/parser/macro/trait-object-macro-matcher.e2021.stderr
@@ -0,0 +1,16 @@
+error: expected type, found lifetime
+ --> $DIR/trait-object-macro-matcher.rs:17:8
+ |
+LL | m!('static);
+ | ^^^^^^^ expected type
+
+error: expected type, found lifetime
+ --> $DIR/trait-object-macro-matcher.rs:17:8
+ |
+LL | m!('static);
+ | ^^^^^^^ expected type
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.rs b/tests/ui/parser/macro/trait-object-macro-matcher.rs
index d4ec199..ba61752 100644
--- a/tests/ui/parser/macro/trait-object-macro-matcher.rs
+++ b/tests/ui/parser/macro/trait-object-macro-matcher.rs
@@ -1,6 +1,10 @@
// A single lifetime is not parsed as a type.
// `ty` matcher in particular doesn't accept a single lifetime
+//@ revisions: e2015 e2021
+//@[e2015] edition: 2015
+//@[e2021] edition: 2021
+
macro_rules! m {
($t: ty) => {
let _: $t;
@@ -8,8 +12,10 @@ macro_rules! m {
}
fn main() {
+ //[e2021]~vv ERROR expected type, found lifetime
+ //[e2021]~v ERROR expected type, found lifetime
m!('static);
- //~^ ERROR lifetime in trait object type must be followed by `+`
- //~| ERROR lifetime in trait object type must be followed by `+`
- //~| ERROR at least one trait is required for an object type
+ //[e2015]~^ ERROR lifetimes must be followed by `+` to form a trait object type
+ //[e2015]~| ERROR lifetimes must be followed by `+` to form a trait object type
+ //[e2015]~| ERROR at least one trait is required for an object type
}
diff --git a/tests/ui/parser/macro/trait-object-macro-matcher.stderr b/tests/ui/parser/macro/trait-object-macro-matcher.stderr
deleted file mode 100644
index 81dca6f..0000000
--- a/tests/ui/parser/macro/trait-object-macro-matcher.stderr
+++ /dev/null
@@ -1,23 +0,0 @@
-error: lifetime in trait object type must be followed by `+`
- --> $DIR/trait-object-macro-matcher.rs:11:8
- |
-LL | m!('static);
- | ^^^^^^^
-
-error: lifetime in trait object type must be followed by `+`
- --> $DIR/trait-object-macro-matcher.rs:11:8
- |
-LL | m!('static);
- | ^^^^^^^
- |
- = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error[E0224]: at least one trait is required for an object type
- --> $DIR/trait-object-macro-matcher.rs:11:8
- |
-LL | m!('static);
- | ^^^^^^^
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0224`.
diff --git a/tests/ui/parser/recover/raw-no-const-mut.rs b/tests/ui/parser/recover/raw-no-const-mut.rs
new file mode 100644
index 0000000..d0ae69c
--- /dev/null
+++ b/tests/ui/parser/recover/raw-no-const-mut.rs
@@ -0,0 +1,31 @@
+fn a() {
+ let x = &raw 1;
+ //~^ ERROR expected one of
+}
+
+fn b() {
+ [&raw const 1, &raw 2]
+ //~^ ERROR expected one of
+ //~| ERROR cannot find value `raw` in this scope
+ //~| ERROR cannot take address of a temporary
+}
+
+fn c() {
+ if x == &raw z {}
+ //~^ ERROR expected `{`
+}
+
+fn d() {
+ f(&raw 2);
+ //~^ ERROR expected one of
+ //~| ERROR cannot find value `raw` in this scope
+ //~| ERROR cannot find function `f` in this scope
+}
+
+fn e() {
+ let x;
+ x = &raw 1;
+ //~^ ERROR expected one of
+}
+
+fn main() {}
diff --git a/tests/ui/parser/recover/raw-no-const-mut.stderr b/tests/ui/parser/recover/raw-no-const-mut.stderr
new file mode 100644
index 0000000..65032c8
--- /dev/null
+++ b/tests/ui/parser/recover/raw-no-const-mut.stderr
@@ -0,0 +1,109 @@
+error: expected one of `!`, `.`, `::`, `;`, `?`, `const`, `else`, `mut`, `{`, or an operator, found `1`
+ --> $DIR/raw-no-const-mut.rs:2:18
+ |
+LL | let x = &raw 1;
+ | ^ expected one of 10 possible tokens
+ |
+help: `&raw` must be followed by `const` or `mut` to be a raw reference expression
+ |
+LL | let x = &raw const 1;
+ | +++++
+LL | let x = &raw mut 1;
+ | +++
+
+error: expected one of `!`, `,`, `.`, `::`, `?`, `]`, `const`, `mut`, `{`, or an operator, found `2`
+ --> $DIR/raw-no-const-mut.rs:7:25
+ |
+LL | [&raw const 1, &raw 2]
+ | ^ expected one of 10 possible tokens
+ |
+help: `&raw` must be followed by `const` or `mut` to be a raw reference expression
+ |
+LL | [&raw const 1, &raw const 2]
+ | +++++
+LL | [&raw const 1, &raw mut 2]
+ | +++
+help: missing `,`
+ |
+LL | [&raw const 1, &raw, 2]
+ | +
+
+error: expected `{`, found `z`
+ --> $DIR/raw-no-const-mut.rs:14:18
+ |
+LL | if x == &raw z {}
+ | ^ expected `{`
+ |
+note: the `if` expression is missing a block after this condition
+ --> $DIR/raw-no-const-mut.rs:14:8
+ |
+LL | if x == &raw z {}
+ | ^^^^^^^^^
+help: `&raw` must be followed by `const` or `mut` to be a raw reference expression
+ |
+LL | if x == &raw const z {}
+ | +++++
+LL | if x == &raw mut z {}
+ | +++
+
+error: expected one of `!`, `)`, `,`, `.`, `::`, `?`, `const`, `mut`, `{`, or an operator, found `2`
+ --> $DIR/raw-no-const-mut.rs:19:12
+ |
+LL | f(&raw 2);
+ | ^ expected one of 10 possible tokens
+ |
+help: `&raw` must be followed by `const` or `mut` to be a raw reference expression
+ |
+LL | f(&raw const 2);
+ | +++++
+LL | f(&raw mut 2);
+ | +++
+help: missing `,`
+ |
+LL | f(&raw, 2);
+ | +
+
+error: expected one of `!`, `.`, `::`, `;`, `?`, `const`, `mut`, `{`, `}`, or an operator, found `1`
+ --> $DIR/raw-no-const-mut.rs:27:14
+ |
+LL | x = &raw 1;
+ | ^ expected one of 10 possible tokens
+ |
+help: `&raw` must be followed by `const` or `mut` to be a raw reference expression
+ |
+LL | x = &raw const 1;
+ | +++++
+LL | x = &raw mut 1;
+ | +++
+
+error[E0425]: cannot find value `raw` in this scope
+ --> $DIR/raw-no-const-mut.rs:7:21
+ |
+LL | [&raw const 1, &raw 2]
+ | ^^^ not found in this scope
+
+error[E0425]: cannot find value `raw` in this scope
+ --> $DIR/raw-no-const-mut.rs:19:8
+ |
+LL | f(&raw 2);
+ | ^^^ not found in this scope
+
+error[E0745]: cannot take address of a temporary
+ --> $DIR/raw-no-const-mut.rs:7:17
+ |
+LL | [&raw const 1, &raw 2]
+ | ^ temporary value
+
+error[E0425]: cannot find function `f` in this scope
+ --> $DIR/raw-no-const-mut.rs:19:5
+ |
+LL | fn a() {
+ | ------ similarly named function `a` defined here
+...
+LL | f(&raw 2);
+ | ^ help: a function with a similar name exists: `a`
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0425, E0745.
+For more information about an error, try `rustc --explain E0425`.
diff --git a/tests/ui/parser/recover/recover-ampersand-less-ref-ty.rs b/tests/ui/parser/recover/recover-ampersand-less-ref-ty.rs
new file mode 100644
index 0000000..8f1a424
--- /dev/null
+++ b/tests/ui/parser/recover/recover-ampersand-less-ref-ty.rs
@@ -0,0 +1,13 @@
+//@ edition: 2021
+
+struct Entity<'a> {
+ name: 'a str, //~ ERROR expected type, found lifetime
+ //~^ HELP you might have meant to write a reference type here
+}
+
+struct Buffer<'buf> {
+ bytes: 'buf mut [u8], //~ ERROR expected type, found lifetime
+ //~^ HELP you might have meant to write a reference type here
+}
+
+fn main() {}
diff --git a/tests/ui/parser/recover/recover-ampersand-less-ref-ty.stderr b/tests/ui/parser/recover/recover-ampersand-less-ref-ty.stderr
new file mode 100644
index 0000000..033348b
--- /dev/null
+++ b/tests/ui/parser/recover/recover-ampersand-less-ref-ty.stderr
@@ -0,0 +1,24 @@
+error: expected type, found lifetime
+ --> $DIR/recover-ampersand-less-ref-ty.rs:4:11
+ |
+LL | name: 'a str,
+ | ^^ expected type
+ |
+help: you might have meant to write a reference type here
+ |
+LL | name: &'a str,
+ | +
+
+error: expected type, found lifetime
+ --> $DIR/recover-ampersand-less-ref-ty.rs:9:12
+ |
+LL | bytes: 'buf mut [u8],
+ | ^^^^ expected type
+ |
+help: you might have meant to write a reference type here
+ |
+LL | bytes: &'buf mut [u8],
+ | +
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/parser/recover/recover-assoc-const-constraint.rs b/tests/ui/parser/recover/recover-assoc-const-constraint.rs
index 1453e6c..d938b4c 100644
--- a/tests/ui/parser/recover/recover-assoc-const-constraint.rs
+++ b/tests/ui/parser/recover/recover-assoc-const-constraint.rs
@@ -1,4 +1,4 @@
-#[cfg(FALSE)]
+#[cfg(false)]
fn syntax() {
bar::<Item = 42>();
//~^ ERROR associated const equality is incomplete
diff --git a/tests/ui/parser/recover/recover-assoc-eq-missing-term.rs b/tests/ui/parser/recover/recover-assoc-eq-missing-term.rs
index 4b42c44..73b4e22 100644
--- a/tests/ui/parser/recover/recover-assoc-eq-missing-term.rs
+++ b/tests/ui/parser/recover/recover-assoc-eq-missing-term.rs
@@ -1,4 +1,4 @@
-#[cfg(FALSE)]
+#[cfg(false)]
fn syntax() {
bar::<Item = >(); //~ ERROR missing type to the right of `=`
}
diff --git a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs
index cb65f80..30bac49 100644
--- a/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs
+++ b/tests/ui/parser/recover/recover-assoc-lifetime-constraint.rs
@@ -1,4 +1,4 @@
-#[cfg(FALSE)]
+#[cfg(false)]
fn syntax() {
bar::<Item = 'a>(); //~ ERROR lifetimes are not permitted in this context
}
diff --git a/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr b/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr
index 583b98c..c0f9db9 100644
--- a/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr
+++ b/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr
@@ -4,7 +4,6 @@
LL | let x = Tr<A, A:>;
| ^ expected one of 8 possible tokens
|
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: maybe write a path separator here
|
LL | let x = Tr<A, A::>;
diff --git a/tests/ui/parser/self-param-syntactic-pass.rs b/tests/ui/parser/self-param-syntactic-pass.rs
index c7fdc52..331e652 100644
--- a/tests/ui/parser/self-param-syntactic-pass.rs
+++ b/tests/ui/parser/self-param-syntactic-pass.rs
@@ -5,7 +5,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn free() {
fn f(self) {}
fn f(mut self) {}
@@ -17,7 +17,7 @@ fn f(self: u8) {}
fn f(mut self: u8) {}
}
-#[cfg(FALSE)]
+#[cfg(false)]
extern "C" {
fn f(self);
fn f(mut self);
@@ -29,7 +29,7 @@ fn f(mut self: u8) {}
fn f(mut self: u8);
}
-#[cfg(FALSE)]
+#[cfg(false)]
trait X {
fn f(self) {}
fn f(mut self) {}
@@ -41,7 +41,7 @@ fn f(self: u8) {}
fn f(mut self: u8) {}
}
-#[cfg(FALSE)]
+#[cfg(false)]
impl X for Y {
fn f(self) {}
fn f(mut self) {}
@@ -53,7 +53,7 @@ fn f(self: u8) {}
fn f(mut self: u8) {}
}
-#[cfg(FALSE)]
+#[cfg(false)]
impl X for Y {
type X = fn(self);
type X = fn(mut self);
diff --git a/tests/ui/parser/semi-in-let-chain.rs b/tests/ui/parser/semi-in-let-chain.rs
index 9c21af0..522b90e 100644
--- a/tests/ui/parser/semi-in-let-chain.rs
+++ b/tests/ui/parser/semi-in-let-chain.rs
@@ -1,6 +1,5 @@
// Issue #117720
-
-#![feature(let_chains)]
+//@ edition: 2024
fn main() {
if let () = ()
diff --git a/tests/ui/parser/semi-in-let-chain.stderr b/tests/ui/parser/semi-in-let-chain.stderr
index c1a8f92..f36d5e0 100644
--- a/tests/ui/parser/semi-in-let-chain.stderr
+++ b/tests/ui/parser/semi-in-let-chain.stderr
@@ -1,11 +1,11 @@
error: expected `{`, found `;`
- --> $DIR/semi-in-let-chain.rs:7:23
+ --> $DIR/semi-in-let-chain.rs:6:23
|
LL | && let () = ();
| ^ expected `{`
|
note: you likely meant to continue parsing the let-chain starting here
- --> $DIR/semi-in-let-chain.rs:8:9
+ --> $DIR/semi-in-let-chain.rs:7:9
|
LL | && let () = ()
| ^^^^^^
@@ -16,13 +16,13 @@
|
error: expected `{`, found `;`
- --> $DIR/semi-in-let-chain.rs:15:20
+ --> $DIR/semi-in-let-chain.rs:14:20
|
LL | && () == ();
| ^ expected `{`
|
note: the `if` expression is missing a block after this condition
- --> $DIR/semi-in-let-chain.rs:14:8
+ --> $DIR/semi-in-let-chain.rs:13:8
|
LL | if let () = ()
| ________^
@@ -30,13 +30,13 @@
| |___________________^
error: expected `{`, found `;`
- --> $DIR/semi-in-let-chain.rs:23:20
+ --> $DIR/semi-in-let-chain.rs:22:20
|
LL | && () == ();
| ^ expected `{`
|
note: you likely meant to continue parsing the let-chain starting here
- --> $DIR/semi-in-let-chain.rs:24:9
+ --> $DIR/semi-in-let-chain.rs:23:9
|
LL | && let () = ()
| ^^^^^^
diff --git a/tests/ui/parser/stripped-nested-outline-mod-pass.rs b/tests/ui/parser/stripped-nested-outline-mod-pass.rs
index 8909d8a..166a60f 100644
--- a/tests/ui/parser/stripped-nested-outline-mod-pass.rs
+++ b/tests/ui/parser/stripped-nested-outline-mod-pass.rs
@@ -5,7 +5,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
mod foo {
mod bar {
mod baz; // This was an error before.
diff --git a/tests/ui/parser/ternary_operator.stderr b/tests/ui/parser/ternary_operator.stderr
index 6635e16..e12a7ff 100644
--- a/tests/ui/parser/ternary_operator.stderr
+++ b/tests/ui/parser/ternary_operator.stderr
@@ -33,8 +33,6 @@
|
LL | let x = 5 > 2 ? { let x = vec![]: Vec<u16>; x } : { false };
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
- |
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
error: Rust has no ternary operator
--> $DIR/ternary_operator.rs:26:19
diff --git a/tests/ui/parser/trait-item-with-defaultness-pass.rs b/tests/ui/parser/trait-item-with-defaultness-pass.rs
index c636342..164d0b1 100644
--- a/tests/ui/parser/trait-item-with-defaultness-pass.rs
+++ b/tests/ui/parser/trait-item-with-defaultness-pass.rs
@@ -2,7 +2,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
trait X {
default const A: u8;
default const B: u8 = 0;
diff --git a/tests/ui/parser/trait-object-bad-parens.rs b/tests/ui/parser/trait-object-bad-parens.rs
index 8e267c7..bb047a4 100644
--- a/tests/ui/parser/trait-object-bad-parens.rs
+++ b/tests/ui/parser/trait-object-bad-parens.rs
@@ -5,12 +5,8 @@
auto trait Auto {}
fn main() {
- let _: Box<((Auto)) + Auto>;
- //~^ ERROR expected a path on the left-hand side of `+`, not `((Auto))`
- let _: Box<(Auto + Auto) + Auto>;
- //~^ ERROR expected a path on the left-hand side of `+`, not `(Auto + Auto)`
- let _: Box<(Auto +) + Auto>;
- //~^ ERROR expected a path on the left-hand side of `+`, not `(Auto)`
- let _: Box<(dyn Auto) + Auto>;
- //~^ ERROR expected a path on the left-hand side of `+`, not `(dyn Auto)`
+ let _: Box<((Auto)) + Auto>; //~ ERROR expected a path on the left-hand side of `+`
+ let _: Box<(Auto + Auto) + Auto>; //~ ERROR expected a path on the left-hand side of `+`
+ let _: Box<(Auto +) + Auto>; //~ ERROR expected a path on the left-hand side of `+`
+ let _: Box<(dyn Auto) + Auto>; //~ ERROR expected a path on the left-hand side of `+`
}
diff --git a/tests/ui/parser/trait-object-bad-parens.stderr b/tests/ui/parser/trait-object-bad-parens.stderr
index 74e484e..7c2559c 100644
--- a/tests/ui/parser/trait-object-bad-parens.stderr
+++ b/tests/ui/parser/trait-object-bad-parens.stderr
@@ -1,26 +1,26 @@
-error[E0178]: expected a path on the left-hand side of `+`, not `((Auto))`
+error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/trait-object-bad-parens.rs:8:16
|
LL | let _: Box<((Auto)) + Auto>;
- | ^^^^^^^^^^^^^^^ expected a path
+ | ^^^^^^^^ expected a path
-error[E0178]: expected a path on the left-hand side of `+`, not `(Auto + Auto)`
- --> $DIR/trait-object-bad-parens.rs:10:16
+error[E0178]: expected a path on the left-hand side of `+`
+ --> $DIR/trait-object-bad-parens.rs:9:16
|
LL | let _: Box<(Auto + Auto) + Auto>;
- | ^^^^^^^^^^^^^^^^^^^^ expected a path
+ | ^^^^^^^^^^^^^ expected a path
-error[E0178]: expected a path on the left-hand side of `+`, not `(Auto)`
- --> $DIR/trait-object-bad-parens.rs:12:16
+error[E0178]: expected a path on the left-hand side of `+`
+ --> $DIR/trait-object-bad-parens.rs:10:16
|
LL | let _: Box<(Auto +) + Auto>;
- | ^^^^^^^^^^^^^^^ expected a path
+ | ^^^^^^^^ expected a path
-error[E0178]: expected a path on the left-hand side of `+`, not `(dyn Auto)`
- --> $DIR/trait-object-bad-parens.rs:14:16
+error[E0178]: expected a path on the left-hand side of `+`
+ --> $DIR/trait-object-bad-parens.rs:11:16
|
LL | let _: Box<(dyn Auto) + Auto>;
- | ^^^^^^^^^^^^^^^^^ expected a path
+ | ^^^^^^^^^^ expected a path
error: aborting due to 4 previous errors
diff --git a/tests/ui/parser/trait-object-lifetime-parens.stderr b/tests/ui/parser/trait-object-lifetime-parens.e2015.stderr
similarity index 60%
rename from tests/ui/parser/trait-object-lifetime-parens.stderr
rename to tests/ui/parser/trait-object-lifetime-parens.e2015.stderr
index 280c0e4..cf0b3d7 100644
--- a/tests/ui/parser/trait-object-lifetime-parens.stderr
+++ b/tests/ui/parser/trait-object-lifetime-parens.e2015.stderr
@@ -1,5 +1,5 @@
error: parenthesized lifetime bounds are not supported
- --> $DIR/trait-object-lifetime-parens.rs:5:21
+ --> $DIR/trait-object-lifetime-parens.rs:9:21
|
LL | fn f<'a, T: Trait + ('a)>() {}
| ^^^^
@@ -11,7 +11,7 @@
|
error: parenthesized lifetime bounds are not supported
- --> $DIR/trait-object-lifetime-parens.rs:8:24
+ --> $DIR/trait-object-lifetime-parens.rs:12:24
|
LL | let _: Box<Trait + ('a)>;
| ^^^^
@@ -22,11 +22,16 @@
LL + let _: Box<Trait + 'a>;
|
-error: lifetime in trait object type must be followed by `+`
- --> $DIR/trait-object-lifetime-parens.rs:10:17
+error: lifetimes must be followed by `+` to form a trait object type
+ --> $DIR/trait-object-lifetime-parens.rs:16:17
|
LL | let _: Box<('a) + Trait>;
| ^^
+ |
+help: consider adding a trait bound after the potential lifetime bound
+ |
+LL | let _: Box<('a + /* Trait */) + Trait>;
+ | +++++++++++++
error: aborting due to 3 previous errors
diff --git a/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr b/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr
new file mode 100644
index 0000000..b65c079
--- /dev/null
+++ b/tests/ui/parser/trait-object-lifetime-parens.e2021.stderr
@@ -0,0 +1,51 @@
+error: parenthesized lifetime bounds are not supported
+ --> $DIR/trait-object-lifetime-parens.rs:9:21
+ |
+LL | fn f<'a, T: Trait + ('a)>() {}
+ | ^^^^
+ |
+help: remove the parentheses
+ |
+LL - fn f<'a, T: Trait + ('a)>() {}
+LL + fn f<'a, T: Trait + 'a>() {}
+ |
+
+error: parenthesized lifetime bounds are not supported
+ --> $DIR/trait-object-lifetime-parens.rs:12:24
+ |
+LL | let _: Box<Trait + ('a)>;
+ | ^^^^
+ |
+help: remove the parentheses
+ |
+LL - let _: Box<Trait + ('a)>;
+LL + let _: Box<Trait + 'a>;
+ |
+
+error: expected type, found lifetime
+ --> $DIR/trait-object-lifetime-parens.rs:16:17
+ |
+LL | let _: Box<('a) + Trait>;
+ | ^^ expected type
+
+error[E0178]: expected a path on the left-hand side of `+`
+ --> $DIR/trait-object-lifetime-parens.rs:16:16
+ |
+LL | let _: Box<('a) + Trait>;
+ | ^^^^ expected a path
+
+error[E0782]: expected a type, found a trait
+ --> $DIR/trait-object-lifetime-parens.rs:12:16
+ |
+LL | let _: Box<Trait + ('a)>;
+ | ^^^^^^^^^^^^
+ |
+help: you can add the `dyn` keyword if you want a trait object
+ |
+LL | let _: Box<dyn Trait + ('a)>;
+ | +++
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0178, E0782.
+For more information about an error, try `rustc --explain E0178`.
diff --git a/tests/ui/parser/trait-object-lifetime-parens.rs b/tests/ui/parser/trait-object-lifetime-parens.rs
index f44ebe5..0ff4660 100644
--- a/tests/ui/parser/trait-object-lifetime-parens.rs
+++ b/tests/ui/parser/trait-object-lifetime-parens.rs
@@ -1,4 +1,8 @@
-#![allow(bare_trait_objects)]
+//@ revisions: e2015 e2021
+//@[e2015] edition: 2015
+//@[e2021] edition: 2021
+
+#![cfg_attr(e2015, allow(bare_trait_objects))]
trait Trait {}
@@ -6,8 +10,12 @@ fn f<'a, T: Trait + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not s
fn check<'a>() {
let _: Box<Trait + ('a)>; //~ ERROR parenthesized lifetime bounds are not supported
- // FIXME: It'd be great if we could add suggestion to the following case.
- let _: Box<('a) + Trait>; //~ ERROR lifetime in trait object type must be followed by `+`
+ //[e2021]~^ ERROR expected a type, found a trait
+ // FIXME: It'd be great if we could suggest removing the parentheses here too.
+ //[e2015]~v ERROR lifetimes must be followed by `+` to form a trait object type
+ let _: Box<('a) + Trait>;
+ //[e2021]~^ ERROR expected type, found lifetime
+ //[e2021]~| ERROR expected a path on the left-hand side of `+`
}
fn main() {}
diff --git a/tests/ui/parser/trait-object-polytrait-priority.rs b/tests/ui/parser/trait-object-polytrait-priority.rs
index e7f0851..85568f0 100644
--- a/tests/ui/parser/trait-object-polytrait-priority.rs
+++ b/tests/ui/parser/trait-object-polytrait-priority.rs
@@ -4,6 +4,6 @@ trait Trait<'a> {}
fn main() {
let _: &for<'a> Trait<'a> + 'static;
- //~^ ERROR expected a path on the left-hand side of `+`, not `&for<'a> Trait<'a>`
+ //~^ ERROR expected a path on the left-hand side of `+`
//~| HELP try adding parentheses
}
diff --git a/tests/ui/parser/trait-object-polytrait-priority.stderr b/tests/ui/parser/trait-object-polytrait-priority.stderr
index 8cb564e..a291a8e 100644
--- a/tests/ui/parser/trait-object-polytrait-priority.stderr
+++ b/tests/ui/parser/trait-object-polytrait-priority.stderr
@@ -1,8 +1,8 @@
-error[E0178]: expected a path on the left-hand side of `+`, not `&for<'a> Trait<'a>`
+error[E0178]: expected a path on the left-hand side of `+`
--> $DIR/trait-object-polytrait-priority.rs:6:12
|
LL | let _: &for<'a> Trait<'a> + 'static;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^
|
help: try adding parentheses
|
diff --git a/tests/ui/parser/utf16-be-without-bom.rs b/tests/ui/parser/utf16-be-without-bom.rs
index 5387287..1f2abc1 100644
--- a/tests/ui/parser/utf16-be-without-bom.rs
+++ b/tests/ui/parser/utf16-be-without-bom.rs
Binary files differ
diff --git a/tests/ui/parser/utf16-le-without-bom.rs b/tests/ui/parser/utf16-le-without-bom.rs
index fc41366..bb95f0d 100644
--- a/tests/ui/parser/utf16-le-without-bom.rs
+++ b/tests/ui/parser/utf16-le-without-bom.rs
Binary files differ
diff --git a/tests/ui/parser/variadic-ffi-syntactic-pass.rs b/tests/ui/parser/variadic-ffi-syntactic-pass.rs
index da81f13..ebe0b6c 100644
--- a/tests/ui/parser/variadic-ffi-syntactic-pass.rs
+++ b/tests/ui/parser/variadic-ffi-syntactic-pass.rs
@@ -2,31 +2,31 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn f1_1(x: isize, ...) {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn f1_2(...) {}
-#[cfg(FALSE)]
+#[cfg(false)]
extern "C" fn f2_1(x: isize, ...) {}
-#[cfg(FALSE)]
+#[cfg(false)]
extern "C" fn f2_2(...) {}
-#[cfg(FALSE)]
+#[cfg(false)]
extern "C" fn f2_3(..., x: isize) {}
-#[cfg(FALSE)]
+#[cfg(false)]
extern fn f3_1(x: isize, ...) {}
-#[cfg(FALSE)]
+#[cfg(false)]
extern fn f3_2(...) {}
-#[cfg(FALSE)]
+#[cfg(false)]
extern fn f3_3(..., x: isize) {}
-#[cfg(FALSE)]
+#[cfg(false)]
extern {
fn e_f1(...);
fn e_f2(..., x: isize);
@@ -34,7 +34,7 @@ extern "C" fn f2_3(..., x: isize) {}
struct X;
-#[cfg(FALSE)]
+#[cfg(false)]
impl X {
fn i_f1(x: isize, ...) {}
fn i_f2(...) {}
@@ -42,7 +42,7 @@ fn i_f3(..., x: isize, ...) {}
fn i_f4(..., x: isize, ...) {}
}
-#[cfg(FALSE)]
+#[cfg(false)]
trait T {
fn t_f1(x: isize, ...) {}
fn t_f2(x: isize, ...);
diff --git a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs
index 01a978d..9582d27 100644
--- a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs
+++ b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.rs
@@ -13,19 +13,19 @@ fn _ok() {
fn _f(_a @ _b: u8) {} // OK.
}
-#[cfg(FALSE)]
+#[cfg(false)]
fn case_1() {
let a: u8 @ b = 0;
//~^ ERROR expected one of `!`
}
-#[cfg(FALSE)]
+#[cfg(false)]
fn case_2() {
let a @ (b: u8);
//~^ ERROR expected one of `)`
}
-#[cfg(FALSE)]
+#[cfg(false)]
fn case_3() {
let a: T1 @ Outer(b: T2);
//~^ ERROR expected one of `!`
diff --git a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr
index 6ce8f6d..1847e40 100644
--- a/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr
+++ b/tests/ui/pattern/bindings-after-at/nested-type-ascription-syntactically-invalid.stderr
@@ -11,8 +11,6 @@
|
LL | let a @ (b: u8);
| ^ expected one of `)`, `,`, `@`, `if`, or `|`
- |
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
error: expected one of `!`, `(`, `+`, `::`, `;`, `<`, or `=`, found `@`
--> $DIR/nested-type-ascription-syntactically-invalid.rs:30:15
diff --git a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs
index 50ac0ef..c3994d3 100644
--- a/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs
+++ b/tests/ui/pattern/bindings-after-at/wild-before-at-syntactically-rejected.rs
@@ -3,7 +3,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
fn wild_before_at_is_bad_syntax() {
let _ @ a = 0;
//~^ ERROR pattern on wrong side of `@`
diff --git a/tests/ui/pattern/deref-patterns/bindings.rs b/tests/ui/pattern/deref-patterns/bindings.rs
index 5881e41..c14d57f 100644
--- a/tests/ui/pattern/deref-patterns/bindings.rs
+++ b/tests/ui/pattern/deref-patterns/bindings.rs
@@ -1,7 +1,9 @@
+//@ revisions: explicit implicit
//@ run-pass
#![feature(deref_patterns)]
#![allow(incomplete_features)]
+#[cfg(explicit)]
fn simple_vec(vec: Vec<u32>) -> u32 {
match vec {
deref!([]) => 100,
@@ -13,6 +15,19 @@ fn simple_vec(vec: Vec<u32>) -> u32 {
}
}
+#[cfg(implicit)]
+fn simple_vec(vec: Vec<u32>) -> u32 {
+ match vec {
+ [] => 100,
+ [x] if x == 4 => x + 4,
+ [x] => x,
+ [1, x] => x + 200,
+ deref!(ref slice) => slice.iter().sum(),
+ _ => 2000,
+ }
+}
+
+#[cfg(explicit)]
fn nested_vec(vecvec: Vec<Vec<u32>>) -> u32 {
match vecvec {
deref!([]) => 0,
@@ -24,6 +39,19 @@ fn nested_vec(vecvec: Vec<Vec<u32>>) -> u32 {
}
}
+#[cfg(implicit)]
+fn nested_vec(vecvec: Vec<Vec<u32>>) -> u32 {
+ match vecvec {
+ [] => 0,
+ [[x]] => x,
+ [[0, x] | [1, x]] => x,
+ [ref x] => x.iter().sum(),
+ [[], [1, x, y]] => y - x,
+ _ => 2000,
+ }
+}
+
+#[cfg(explicit)]
fn ref_mut(val: u32) -> u32 {
let mut b = Box::new(0u32);
match &mut b {
@@ -37,6 +65,21 @@ fn ref_mut(val: u32) -> u32 {
*x
}
+#[cfg(implicit)]
+fn ref_mut(val: u32) -> u32 {
+ let mut b = Box::new((0u32,));
+ match &mut b {
+ (_x,) if false => unreachable!(),
+ (x,) => {
+ *x = val;
+ }
+ _ => unreachable!(),
+ }
+ let (x,) = &b else { unreachable!() };
+ *x
+}
+
+#[cfg(explicit)]
#[rustfmt::skip]
fn or_and_guard(tuple: (u32, u32)) -> u32 {
let mut sum = 0;
@@ -48,6 +91,18 @@ fn or_and_guard(tuple: (u32, u32)) -> u32 {
sum
}
+#[cfg(implicit)]
+#[rustfmt::skip]
+fn or_and_guard(tuple: (u32, u32)) -> u32 {
+ let mut sum = 0;
+ let b = Box::new(tuple);
+ match b {
+ (x, _) | (_, x) if { sum += x; false } => {},
+ _ => {},
+ }
+ sum
+}
+
fn main() {
assert_eq!(simple_vec(vec![1]), 1);
assert_eq!(simple_vec(vec![1, 2]), 202);
diff --git a/tests/ui/pattern/deref-patterns/branch.rs b/tests/ui/pattern/deref-patterns/branch.rs
index 1bac100..9d72b35 100644
--- a/tests/ui/pattern/deref-patterns/branch.rs
+++ b/tests/ui/pattern/deref-patterns/branch.rs
@@ -1,8 +1,10 @@
+//@ revisions: explicit implicit
//@ run-pass
// Test the execution of deref patterns.
#![feature(deref_patterns)]
#![allow(incomplete_features)]
+#[cfg(explicit)]
fn branch(vec: Vec<u32>) -> u32 {
match vec {
deref!([]) => 0,
@@ -12,6 +14,17 @@ fn branch(vec: Vec<u32>) -> u32 {
}
}
+#[cfg(implicit)]
+fn branch(vec: Vec<u32>) -> u32 {
+ match vec {
+ [] => 0,
+ [1, _, 3] => 1,
+ [2, ..] => 2,
+ _ => 1000,
+ }
+}
+
+#[cfg(explicit)]
fn nested(vec: Vec<Vec<u32>>) -> u32 {
match vec {
deref!([deref!([]), ..]) => 1,
@@ -20,6 +33,15 @@ fn nested(vec: Vec<Vec<u32>>) -> u32 {
}
}
+#[cfg(implicit)]
+fn nested(vec: Vec<Vec<u32>>) -> u32 {
+ match vec {
+ [[], ..] => 1,
+ [[0, ..], [1, ..]] => 2,
+ _ => 1000,
+ }
+}
+
fn main() {
assert!(matches!(Vec::<u32>::new(), deref!([])));
assert!(matches!(vec![1], deref!([1])));
diff --git a/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs
index 84b5ec0..791776b 100644
--- a/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs
+++ b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.rs
@@ -21,4 +21,22 @@ fn cant_move_out_rc(rc: Rc<Struct>) -> Struct {
}
}
+struct Container(Struct);
+
+fn cant_move_out_box_implicit(b: Box<Container>) -> Struct {
+ match b {
+ //~^ ERROR: cannot move out of a shared reference
+ Container(x) => x,
+ _ => unreachable!(),
+ }
+}
+
+fn cant_move_out_rc_implicit(rc: Rc<Container>) -> Struct {
+ match rc {
+ //~^ ERROR: cannot move out of a shared reference
+ Container(x) => x,
+ _ => unreachable!(),
+ }
+}
+
fn main() {}
diff --git a/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr
index 2cf435b..1887800 100644
--- a/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr
+++ b/tests/ui/pattern/deref-patterns/cant_move_out_of_pattern.stderr
@@ -32,6 +32,40 @@
LL | deref!(ref x) => x,
| +++
-error: aborting due to 2 previous errors
+error[E0507]: cannot move out of a shared reference
+ --> $DIR/cant_move_out_of_pattern.rs:27:11
+ |
+LL | match b {
+ | ^
+LL |
+LL | Container(x) => x,
+ | -
+ | |
+ | data moved here
+ | move occurs because `x` has type `Struct`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | Container(ref x) => x,
+ | +++
+
+error[E0507]: cannot move out of a shared reference
+ --> $DIR/cant_move_out_of_pattern.rs:35:11
+ |
+LL | match rc {
+ | ^^
+LL |
+LL | Container(x) => x,
+ | -
+ | |
+ | data moved here
+ | move occurs because `x` has type `Struct`, which does not implement the `Copy` trait
+ |
+help: consider borrowing the pattern binding
+ |
+LL | Container(ref x) => x,
+ | +++
+
+error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0507`.
diff --git a/tests/ui/pattern/deref-patterns/closure_capture.rs b/tests/ui/pattern/deref-patterns/closure_capture.rs
index fc0dded..08586b6 100644
--- a/tests/ui/pattern/deref-patterns/closure_capture.rs
+++ b/tests/ui/pattern/deref-patterns/closure_capture.rs
@@ -11,6 +11,15 @@ fn main() {
assert_eq!(b.len(), 3);
f();
+ let v = vec![1, 2, 3];
+ let f = || {
+ // this should count as a borrow of `v` as a whole
+ let [.., x] = v else { unreachable!() };
+ assert_eq!(x, 3);
+ };
+ assert_eq!(v, [1, 2, 3]);
+ f();
+
let mut b = Box::new("aaa".to_string());
let mut f = || {
let deref!(ref mut s) = b else { unreachable!() };
@@ -18,4 +27,22 @@ fn main() {
};
f();
assert_eq!(b.len(), 5);
+
+ let mut v = vec![1, 2, 3];
+ let mut f = || {
+ // this should count as a mutable borrow of `v` as a whole
+ let [.., ref mut x] = v else { unreachable!() };
+ *x = 4;
+ };
+ f();
+ assert_eq!(v, [1, 2, 4]);
+
+ let mut v = vec![1, 2, 3];
+ let mut f = || {
+ // here, `[.., x]` is adjusted by both an overloaded deref and a builtin deref
+ let [.., x] = &mut v else { unreachable!() };
+ *x = 4;
+ };
+ f();
+ assert_eq!(v, [1, 2, 4]);
}
diff --git a/tests/ui/pattern/deref-patterns/fake_borrows.rs b/tests/ui/pattern/deref-patterns/fake_borrows.rs
index 35fa9cb..bf614d7 100644
--- a/tests/ui/pattern/deref-patterns/fake_borrows.rs
+++ b/tests/ui/pattern/deref-patterns/fake_borrows.rs
@@ -11,4 +11,11 @@ fn main() {
deref!(false) => {}
_ => {},
}
+ match b {
+ true => {}
+ _ if { *b = true; false } => {}
+ //~^ ERROR cannot assign `*b` in match guard
+ false => {}
+ _ => {},
+ }
}
diff --git a/tests/ui/pattern/deref-patterns/fake_borrows.stderr b/tests/ui/pattern/deref-patterns/fake_borrows.stderr
index 6a591e6..8c06023 100644
--- a/tests/ui/pattern/deref-patterns/fake_borrows.stderr
+++ b/tests/ui/pattern/deref-patterns/fake_borrows.stderr
@@ -7,6 +7,15 @@
LL | _ if { *b = true; false } => {}
| ^^^^^^^^^ cannot assign
-error: aborting due to 1 previous error
+error[E0510]: cannot assign `*b` in match guard
+ --> $DIR/fake_borrows.rs:16:16
+ |
+LL | match b {
+ | - value is immutable in match guard
+LL | true => {}
+LL | _ if { *b = true; false } => {}
+ | ^^^^^^^^^ cannot assign
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0510`.
diff --git a/tests/ui/pattern/deref-patterns/implicit-const-deref.rs b/tests/ui/pattern/deref-patterns/implicit-const-deref.rs
new file mode 100644
index 0000000..70f8962
--- /dev/null
+++ b/tests/ui/pattern/deref-patterns/implicit-const-deref.rs
@@ -0,0 +1,19 @@
+//! Test that we get an error about structural equality rather than a type error when attempting to
+//! use const patterns of library pointer types. Currently there aren't any smart pointers that can
+//! be used in constant patterns, but we still need to make sure we don't implicitly dereference the
+//! scrutinee and end up with a type error; this would prevent us from reporting that only constants
+//! supporting structural equality can be used as patterns.
+#![feature(deref_patterns)]
+#![allow(incomplete_features)]
+
+const EMPTY: Vec<()> = Vec::new();
+
+fn main() {
+ // FIXME(inline_const_pat): if `inline_const_pat` is reinstated, there should be a case here for
+ // inline const block patterns as well; they're checked differently than named constants.
+ match vec![()] {
+ EMPTY => {}
+ //~^ ERROR: constant of non-structural type `Vec<()>` in a pattern
+ _ => {}
+ }
+}
diff --git a/tests/ui/pattern/deref-patterns/implicit-const-deref.stderr b/tests/ui/pattern/deref-patterns/implicit-const-deref.stderr
new file mode 100644
index 0000000..21d09ec4
--- /dev/null
+++ b/tests/ui/pattern/deref-patterns/implicit-const-deref.stderr
@@ -0,0 +1,16 @@
+error: constant of non-structural type `Vec<()>` in a pattern
+ --> $DIR/implicit-const-deref.rs:15:9
+ |
+LL | const EMPTY: Vec<()> = Vec::new();
+ | -------------------- constant defined here
+...
+LL | EMPTY => {}
+ | ^^^^^ constant of non-structural type
+ --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ |
+ = note: `Vec<()>` must be annotated with `#[derive(PartialEq)]` to be usable in patterns
+ |
+ = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs b/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs
new file mode 100644
index 0000000..a9b8de8
--- /dev/null
+++ b/tests/ui/pattern/deref-patterns/implicit-cow-deref.rs
@@ -0,0 +1,45 @@
+//@ run-pass
+//! Test that implicit deref patterns interact as expected with `Cow` constructor patterns.
+#![feature(deref_patterns)]
+#![allow(incomplete_features)]
+
+use std::borrow::Cow;
+
+fn main() {
+ let cow: Cow<'static, [u8]> = Cow::Borrowed(&[1, 2, 3]);
+
+ match cow {
+ [..] => {}
+ _ => unreachable!(),
+ }
+
+ match cow {
+ Cow::Borrowed(_) => {}
+ Cow::Owned(_) => unreachable!(),
+ }
+
+ match Box::new(&cow) {
+ Cow::Borrowed { 0: _ } => {}
+ Cow::Owned { 0: _ } => unreachable!(),
+ _ => unreachable!(),
+ }
+
+ let cow_of_cow: Cow<'_, Cow<'static, [u8]>> = Cow::Owned(cow);
+
+ match cow_of_cow {
+ [..] => {}
+ _ => unreachable!(),
+ }
+
+ // This matches on the outer `Cow` (the owned one).
+ match cow_of_cow {
+ Cow::Borrowed(_) => unreachable!(),
+ Cow::Owned(_) => {}
+ }
+
+ match Box::new(&cow_of_cow) {
+ Cow::Borrowed { 0: _ } => unreachable!(),
+ Cow::Owned { 0: _ } => {}
+ _ => unreachable!(),
+ }
+}
diff --git a/tests/ui/pattern/deref-patterns/needs-gate.rs b/tests/ui/pattern/deref-patterns/needs-gate.rs
new file mode 100644
index 0000000..2d5ec45
--- /dev/null
+++ b/tests/ui/pattern/deref-patterns/needs-gate.rs
@@ -0,0 +1,15 @@
+// gate-test-deref_patterns
+
+fn main() {
+ match Box::new(0) {
+ deref!(0) => {}
+ //~^ ERROR: use of unstable library feature `deref_patterns`: placeholder syntax for deref patterns
+ _ => {}
+ }
+
+ match Box::new(0) {
+ 0 => {}
+ //~^ ERROR: mismatched types
+ _ => {}
+ }
+}
diff --git a/tests/ui/pattern/deref-patterns/needs-gate.stderr b/tests/ui/pattern/deref-patterns/needs-gate.stderr
new file mode 100644
index 0000000..8687b5d
--- /dev/null
+++ b/tests/ui/pattern/deref-patterns/needs-gate.stderr
@@ -0,0 +1,29 @@
+error[E0658]: use of unstable library feature `deref_patterns`: placeholder syntax for deref patterns
+ --> $DIR/needs-gate.rs:5:9
+ |
+LL | deref!(0) => {}
+ | ^^^^^
+ |
+ = note: see issue #87121 <https://github.com/rust-lang/rust/issues/87121> for more information
+ = help: add `#![feature(deref_patterns)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0308]: mismatched types
+ --> $DIR/needs-gate.rs:11:9
+ |
+LL | match Box::new(0) {
+ | ----------- this expression has type `Box<{integer}>`
+LL | 0 => {}
+ | ^ expected `Box<{integer}>`, found integer
+ |
+ = note: expected struct `Box<{integer}>`
+ found type `{integer}`
+help: consider dereferencing to access the inner value using the Deref trait
+ |
+LL | match *Box::new(0) {
+ | +
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0658.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/deref-patterns/recursion-limit.rs b/tests/ui/pattern/deref-patterns/recursion-limit.rs
new file mode 100644
index 0000000..c5fe520
--- /dev/null
+++ b/tests/ui/pattern/deref-patterns/recursion-limit.rs
@@ -0,0 +1,23 @@
+//! Test that implicit deref patterns respect the recursion limit
+#![feature(deref_patterns)]
+#![allow(incomplete_features)]
+#![recursion_limit = "8"]
+
+use std::ops::Deref;
+
+struct Cyclic;
+impl Deref for Cyclic {
+ type Target = Cyclic;
+ fn deref(&self) -> &Cyclic {
+ &Cyclic
+ }
+}
+
+fn main() {
+ match &Box::new(Cyclic) {
+ () => {}
+ //~^ ERROR: reached the recursion limit while auto-dereferencing `Cyclic`
+ //~| ERROR: the trait bound `Cyclic: DerefPure` is not satisfied
+ _ => {}
+ }
+}
diff --git a/tests/ui/pattern/deref-patterns/recursion-limit.stderr b/tests/ui/pattern/deref-patterns/recursion-limit.stderr
new file mode 100644
index 0000000..9a83d1e
--- /dev/null
+++ b/tests/ui/pattern/deref-patterns/recursion-limit.stderr
@@ -0,0 +1,18 @@
+error[E0055]: reached the recursion limit while auto-dereferencing `Cyclic`
+ --> $DIR/recursion-limit.rs:18:9
+ |
+LL | () => {}
+ | ^^ deref recursion limit reached
+ |
+ = help: consider increasing the recursion limit by adding a `#![recursion_limit = "16"]` attribute to your crate (`recursion_limit`)
+
+error[E0277]: the trait bound `Cyclic: DerefPure` is not satisfied
+ --> $DIR/recursion-limit.rs:18:9
+ |
+LL | () => {}
+ | ^^ the trait `DerefPure` is not implemented for `Cyclic`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0055, E0277.
+For more information about an error, try `rustc --explain E0055`.
diff --git a/tests/ui/pattern/deref-patterns/ref-mut.rs b/tests/ui/pattern/deref-patterns/ref-mut.rs
index 1918008..4373867 100644
--- a/tests/ui/pattern/deref-patterns/ref-mut.rs
+++ b/tests/ui/pattern/deref-patterns/ref-mut.rs
@@ -8,10 +8,19 @@ fn main() {
deref!(x) => {}
_ => {}
}
+ match &mut vec![1] {
+ [x] => {}
+ _ => {}
+ }
match &mut Rc::new(1) {
deref!(x) => {}
//~^ ERROR the trait bound `Rc<{integer}>: DerefMut` is not satisfied
_ => {}
}
+ match &mut Rc::new((1,)) {
+ (x,) => {}
+ //~^ ERROR the trait bound `Rc<({integer},)>: DerefMut` is not satisfied
+ _ => {}
+ }
}
diff --git a/tests/ui/pattern/deref-patterns/ref-mut.stderr b/tests/ui/pattern/deref-patterns/ref-mut.stderr
index 41f1c30..24a35b4 100644
--- a/tests/ui/pattern/deref-patterns/ref-mut.stderr
+++ b/tests/ui/pattern/deref-patterns/ref-mut.stderr
@@ -8,13 +8,19 @@
= note: `#[warn(incomplete_features)]` on by default
error[E0277]: the trait bound `Rc<{integer}>: DerefMut` is not satisfied
- --> $DIR/ref-mut.rs:13:9
+ --> $DIR/ref-mut.rs:17:9
|
LL | deref!(x) => {}
| ^^^^^^^^^ the trait `DerefMut` is not implemented for `Rc<{integer}>`
|
= note: this error originates in the macro `deref` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: aborting due to 1 previous error; 1 warning emitted
+error[E0277]: the trait bound `Rc<({integer},)>: DerefMut` is not satisfied
+ --> $DIR/ref-mut.rs:22:9
+ |
+LL | (x,) => {}
+ | ^^^^ the trait `DerefMut` is not implemented for `Rc<({integer},)>`
+
+error: aborting due to 2 previous errors; 1 warning emitted
For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/pattern/deref-patterns/typeck.rs b/tests/ui/pattern/deref-patterns/typeck.rs
index f23f704..3a7ce9d 100644
--- a/tests/ui/pattern/deref-patterns/typeck.rs
+++ b/tests/ui/pattern/deref-patterns/typeck.rs
@@ -10,26 +10,32 @@ fn main() {
let vec: Vec<u32> = Vec::new();
match vec {
deref!([..]) => {}
+ [..] => {}
_ => {}
}
match Box::new(true) {
deref!(true) => {}
+ true => {}
_ => {}
}
match &Box::new(true) {
deref!(true) => {}
+ true => {}
_ => {}
}
match &Rc::new(0) {
deref!(1..) => {}
+ 1.. => {}
_ => {}
}
let _: &Struct = match &Rc::new(Struct) {
deref!(x) => x,
+ Struct => &Struct,
_ => unreachable!(),
};
let _: &[Struct] = match &Rc::new(vec![Struct]) {
deref!(deref!(x)) => x,
+ [Struct] => &[Struct],
_ => unreachable!(),
};
}
diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.rs b/tests/ui/pattern/deref-patterns/typeck_fail.rs
index 0401184..4b9ad7d 100644
--- a/tests/ui/pattern/deref-patterns/typeck_fail.rs
+++ b/tests/ui/pattern/deref-patterns/typeck_fail.rs
@@ -7,11 +7,22 @@ fn main() {
match "foo".to_string() {
deref!("foo") => {}
//~^ ERROR: mismatched types
+ "foo" => {}
+ //~^ ERROR: mismatched types
_ => {}
}
match &"foo".to_string() {
deref!("foo") => {}
//~^ ERROR: mismatched types
+ "foo" => {}
+ //~^ ERROR: mismatched types
+ _ => {}
+ }
+
+ // Make sure we don't try implicitly dereferncing any ADT.
+ match Some(0) {
+ Ok(0) => {}
+ //~^ ERROR: mismatched types
_ => {}
}
}
diff --git a/tests/ui/pattern/deref-patterns/typeck_fail.stderr b/tests/ui/pattern/deref-patterns/typeck_fail.stderr
index 1c14802..3e2f356 100644
--- a/tests/ui/pattern/deref-patterns/typeck_fail.stderr
+++ b/tests/ui/pattern/deref-patterns/typeck_fail.stderr
@@ -7,13 +7,45 @@
| ^^^^^ expected `str`, found `&str`
error[E0308]: mismatched types
- --> $DIR/typeck_fail.rs:13:16
+ --> $DIR/typeck_fail.rs:10:9
+ |
+LL | match "foo".to_string() {
+ | ----------------- this expression has type `String`
+...
+LL | "foo" => {}
+ | ^^^^^ expected `String`, found `&str`
+
+error[E0308]: mismatched types
+ --> $DIR/typeck_fail.rs:15:16
|
LL | match &"foo".to_string() {
| ------------------ this expression has type `&String`
LL | deref!("foo") => {}
| ^^^^^ expected `str`, found `&str`
-error: aborting due to 2 previous errors
+error[E0308]: mismatched types
+ --> $DIR/typeck_fail.rs:17:9
+ |
+LL | match &"foo".to_string() {
+ | ------------------ this expression has type `&String`
+...
+LL | "foo" => {}
+ | ^^^^^ expected `&String`, found `&str`
+ |
+ = note: expected reference `&String`
+ found reference `&'static str`
+
+error[E0308]: mismatched types
+ --> $DIR/typeck_fail.rs:24:9
+ |
+LL | match Some(0) {
+ | ------- this expression has type `Option<{integer}>`
+LL | Ok(0) => {}
+ | ^^^^^ expected `Option<{integer}>`, found `Result<_, _>`
+ |
+ = note: expected enum `Option<{integer}>`
+ found enum `Result<_, _>`
+
+error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/pattern/deref-patterns/unsatisfied-bounds.rs b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.rs
new file mode 100644
index 0000000..00064b2
--- /dev/null
+++ b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.rs
@@ -0,0 +1,21 @@
+#![feature(deref_patterns)]
+#![allow(incomplete_features)]
+
+struct MyPointer;
+
+impl std::ops::Deref for MyPointer {
+ type Target = ();
+ fn deref(&self) -> &() {
+ &()
+ }
+}
+
+fn main() {
+ // Test that we get a trait error if a user attempts implicit deref pats on their own impls.
+ // FIXME(deref_patterns): there should be a special diagnostic for missing `DerefPure`.
+ match MyPointer {
+ () => {}
+ //~^ the trait bound `MyPointer: DerefPure` is not satisfied
+ _ => {}
+ }
+}
diff --git a/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr
new file mode 100644
index 0000000..983ce27
--- /dev/null
+++ b/tests/ui/pattern/deref-patterns/unsatisfied-bounds.stderr
@@ -0,0 +1,9 @@
+error[E0277]: the trait bound `MyPointer: DerefPure` is not satisfied
+ --> $DIR/unsatisfied-bounds.rs:17:9
+ |
+LL | () => {}
+ | ^^ the trait `DerefPure` is not implemented for `MyPointer`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/pattern/rest-pat-syntactic.rs b/tests/ui/pattern/rest-pat-syntactic.rs
index 1de29e6..59c687b 100644
--- a/tests/ui/pattern/rest-pat-syntactic.rs
+++ b/tests/ui/pattern/rest-pat-syntactic.rs
@@ -11,7 +11,7 @@ macro_rules! accept_pat {
accept_pat!(..);
-#[cfg(FALSE)]
+#[cfg(false)]
fn rest_patterns() {
// Top level:
fn foo(..: u8) {}
diff --git a/tests/ui/pattern/uninit-trivial.rs b/tests/ui/pattern/uninit-trivial.rs
new file mode 100644
index 0000000..6ea6796
--- /dev/null
+++ b/tests/ui/pattern/uninit-trivial.rs
@@ -0,0 +1,8 @@
+// Regression test for the semantic changes in
+// <https://github.com/rust-lang/rust/pull/139042>.
+
+fn main() {
+ let x;
+ let (0 | _) = x;
+ //~^ ERROR used binding `x` isn't initialized
+}
diff --git a/tests/ui/pattern/uninit-trivial.stderr b/tests/ui/pattern/uninit-trivial.stderr
new file mode 100644
index 0000000..2ff8557
--- /dev/null
+++ b/tests/ui/pattern/uninit-trivial.stderr
@@ -0,0 +1,16 @@
+error[E0381]: used binding `x` isn't initialized
+ --> $DIR/uninit-trivial.rs:6:10
+ |
+LL | let x;
+ | - binding declared here but left uninitialized
+LL | let (0 | _) = x;
+ | ^^^^^ `x` used here but it isn't initialized
+ |
+help: consider assigning a value
+ |
+LL | let x = 42;
+ | ++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0381`.
diff --git a/tests/ui/pin-macro/cant_access_internals.rs b/tests/ui/pin-macro/cant_access_internals.rs
deleted file mode 100644
index 36a47d0..0000000
--- a/tests/ui/pin-macro/cant_access_internals.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-//@ edition:2018
-
-use core::{
- marker::PhantomPinned,
- mem,
- pin::{pin, Pin},
-};
-
-fn main() {
- let mut phantom_pinned = pin!(PhantomPinned);
- mem::take(phantom_pinned.__pointer); //~ ERROR use of unstable library feature `unsafe_pin_internals`
-}
diff --git a/tests/ui/pin-macro/cant_access_internals.stderr b/tests/ui/pin-macro/cant_access_internals.stderr
deleted file mode 100644
index 8ad897b..0000000
--- a/tests/ui/pin-macro/cant_access_internals.stderr
+++ /dev/null
@@ -1,12 +0,0 @@
-error[E0658]: use of unstable library feature `unsafe_pin_internals`
- --> $DIR/cant_access_internals.rs:11:15
- |
-LL | mem::take(phantom_pinned.__pointer);
- | ^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = help: add `#![feature(unsafe_pin_internals)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs
index 8a0244e..e505fe4 100644
--- a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs
+++ b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs
@@ -9,14 +9,14 @@
fn function_call_stops_borrow_extension() {
let phantom_pinned = identity(pin!(PhantomPinned));
- //~^ ERROR temporary value dropped while borrowed
+ //~^ ERROR does not live long enough
stuff(phantom_pinned)
}
fn promotion_only_works_for_the_innermost_block() {
let phantom_pinned = {
let phantom_pinned = pin!(PhantomPinned);
- //~^ ERROR temporary value dropped while borrowed
+ //~^ ERROR does not live long enough
phantom_pinned
};
stuff(phantom_pinned)
diff --git a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr
index 9df7f0f..43fb82b 100644
--- a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr
+++ b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr
@@ -1,35 +1,29 @@
-error[E0716]: temporary value dropped while borrowed
+error[E0597]: value does not live long enough
--> $DIR/lifetime_errors_on_promotion_misusage.rs:11:35
|
LL | let phantom_pinned = identity(pin!(PhantomPinned));
- | ^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
+ | ^^^^^^^^^^^^^^^^^^^ - value dropped here while still borrowed
| |
- | creates a temporary value which is freed while still in use
+ | borrowed value does not live long enough
LL |
LL | stuff(phantom_pinned)
| -------------- borrow later used here
|
= note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info)
-help: consider using a `let` binding to create a longer lived value
- |
-LL ~ let binding = pin!(PhantomPinned);
-LL ~ let phantom_pinned = identity(binding);
- |
-error[E0716]: temporary value dropped while borrowed
+error[E0597]: value does not live long enough
--> $DIR/lifetime_errors_on_promotion_misusage.rs:18:30
|
LL | let phantom_pinned = {
| -------------- borrow later stored here
LL | let phantom_pinned = pin!(PhantomPinned);
- | ^^^^^^^^^^^^^^^^^^^ creates a temporary value which is freed while still in use
+ | ^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
...
LL | };
- | - temporary value is freed at the end of this statement
+ | - value dropped here while still borrowed
|
- = note: consider using a `let` binding to create a longer lived value
= note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0716`.
+For more information about this error, try `rustc --explain E0597`.
diff --git a/tests/ui/pin-macro/pin_move.stderr b/tests/ui/pin-macro/pin_move.stderr
index c9b8ad9..3f46602 100644
--- a/tests/ui/pin-macro/pin_move.stderr
+++ b/tests/ui/pin-macro/pin_move.stderr
@@ -31,6 +31,11 @@
LL | let mut pointee = NotCopy(PhantomPinned);
LL | pin!(*&mut pointee);
| ------------- you could clone this value
+help: consider removing the dereference here
+ |
+LL - pin!(*&mut pointee);
+LL + pin!(&mut pointee);
+ |
error: aborting due to 2 previous errors
diff --git a/tests/ui/precondition-checks/read.rs b/tests/ui/precondition-checks/read.rs
index ab9921a..d5ab777 100644
--- a/tests/ui/precondition-checks/read.rs
+++ b/tests/ui/precondition-checks/read.rs
@@ -2,7 +2,7 @@
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
//@ error-pattern: unsafe precondition(s) violated: ptr::read requires
//@ revisions: null misaligned
-//@ ignore-test
+//@ ignore-test (unimplemented)
use std::ptr;
diff --git a/tests/ui/precondition-checks/write.rs b/tests/ui/precondition-checks/write.rs
index f76e776..5d6b958 100644
--- a/tests/ui/precondition-checks/write.rs
+++ b/tests/ui/precondition-checks/write.rs
@@ -2,7 +2,7 @@
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
//@ error-pattern: unsafe precondition(s) violated: ptr::write requires
//@ revisions: null misaligned
-//@ ignore-test
+//@ ignore-test (unimplemented)
use std::ptr;
diff --git a/tests/ui/precondition-checks/write_bytes.rs b/tests/ui/precondition-checks/write_bytes.rs
index 3f64be9..be4f5a0 100644
--- a/tests/ui/precondition-checks/write_bytes.rs
+++ b/tests/ui/precondition-checks/write_bytes.rs
@@ -2,7 +2,7 @@
//@ compile-flags: -Copt-level=3 -Cdebug-assertions=no -Zub-checks=yes
//@ error-pattern: unsafe precondition(s) violated: ptr::write requires
//@ revisions: null misaligned
-//@ ignore-test
+//@ ignore-test (unimplemented)
use std::ptr;
diff --git a/tests/ui/print-request/print-lints-help.rs b/tests/ui/print-request/print-lints-help.rs
index 6dd88a7..9a706a2 100644
--- a/tests/ui/print-request/print-lints-help.rs
+++ b/tests/ui/print-request/print-lints-help.rs
@@ -2,7 +2,8 @@
//! `--print=lints` (which is not a valid print request).
//@ compile-flags: --print lints
-//@ error-pattern: help: use `-Whelp` to print a list of lints
-//@ error-pattern: help: for more information, see the rustc book
//~? ERROR unknown print request: `lints`
+//~? HELP use `-Whelp` to print a list of lints
+//~? HELP for more information, see the rustc book
+//~? HELP valid print requests are
diff --git a/tests/ui/proc-macro/attribute-after-derive.rs b/tests/ui/proc-macro/attribute-after-derive.rs
index f2e2eb1..382ef1f 100644
--- a/tests/ui/proc-macro/attribute-after-derive.rs
+++ b/tests/ui/proc-macro/attribute-after-derive.rs
@@ -14,14 +14,14 @@
#[print_attr]
#[derive(Print)]
struct AttributeDerive {
- #[cfg(FALSE)]
+ #[cfg(false)]
field: u8,
}
#[derive(Print)]
#[print_attr]
struct DeriveAttribute {
- #[cfg(FALSE)]
+ #[cfg(false)]
field: u8,
}
diff --git a/tests/ui/proc-macro/attribute-after-derive.stdout b/tests/ui/proc-macro/attribute-after-derive.stdout
index 6d9531d..bc0fc6d 100644
--- a/tests/ui/proc-macro/attribute-after-derive.stdout
+++ b/tests/ui/proc-macro/attribute-after-derive.stdout
@@ -1,5 +1,5 @@
-PRINT-ATTR INPUT (DISPLAY): #[derive(Print)] struct AttributeDerive { #[cfg(FALSE)] field: u8, }
-PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): #[derive(Print)] struct AttributeDerive { #[cfg(FALSE)] field : u8, }
+PRINT-ATTR INPUT (DISPLAY): #[derive(Print)] struct AttributeDerive { #[cfg(false)] field: u8, }
+PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): #[derive(Print)] struct AttributeDerive { #[cfg(false)] field : u8, }
PRINT-ATTR INPUT (DEBUG): TokenStream [
Punct {
ch: '#',
@@ -53,7 +53,7 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "FALSE",
+ ident: "false",
span: $DIR/attribute-after-derive.rs:17:11: 17:16 (#0),
},
],
@@ -131,8 +131,8 @@
span: $DIR/attribute-after-derive.rs:23:24: 26:2 (#0),
},
]
-PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { #[cfg(FALSE)] field: u8, }
-PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): struct DeriveAttribute { #[cfg(FALSE)] field : u8, }
+PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { #[cfg(false)] field: u8, }
+PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): struct DeriveAttribute { #[cfg(false)] field : u8, }
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
@@ -161,7 +161,7 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "FALSE",
+ ident: "false",
span: $DIR/attribute-after-derive.rs:24:11: 24:16 (#0),
},
],
diff --git a/tests/ui/proc-macro/auxiliary/expand-expr.rs b/tests/ui/proc-macro/auxiliary/expand-expr.rs
index 78c9fa7..14efc3c 100644
--- a/tests/ui/proc-macro/auxiliary/expand-expr.rs
+++ b/tests/ui/proc-macro/auxiliary/expand-expr.rs
@@ -3,9 +3,10 @@
extern crate proc_macro;
-use proc_macro::*;
use std::str::FromStr;
+use proc_macro::*;
+
// Flatten the TokenStream, removing any toplevel `Delimiter::None`s for
// comparison.
fn flatten(ts: TokenStream) -> Vec<TokenTree> {
@@ -136,9 +137,8 @@ pub fn check_expand_expr_file(ts: TokenStream) -> TokenStream {
.to_string();
assert_eq!(input_t, parse_t);
- // Check that the literal matches `Span::call_site().source_file().path()`
- let expect_t =
- Literal::string(&Span::call_site().source_file().path().to_string_lossy()).to_string();
+ // Check that the literal matches `Span::call_site().file()`
+ let expect_t = Literal::string(&Span::call_site().file()).to_string();
assert_eq!(input_t, expect_t);
TokenStream::new()
diff --git a/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs b/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs
index 4971de2..11e1910 100644
--- a/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs
+++ b/tests/ui/proc-macro/auxiliary/macro-only-syntax.rs
@@ -79,7 +79,7 @@ fn check_useful_span(token: TokenTree, expected_filename: &str) {
let span = token.span();
assert!(span.column() < span.end().column());
- let source_path = span.source_file().path();
+ let source_path = span.local_file().unwrap();
let filename = source_path.components().last().unwrap();
assert_eq!(filename, Component::Normal(expected_filename.as_ref()));
}
diff --git a/tests/ui/proc-macro/auxiliary/span-api-tests.rs b/tests/ui/proc-macro/auxiliary/span-api-tests.rs
index 99db66e..036f2e3 100644
--- a/tests/ui/proc-macro/auxiliary/span-api-tests.rs
+++ b/tests/ui/proc-macro/auxiliary/span-api-tests.rs
@@ -11,20 +11,9 @@ pub fn reemit(input: TokenStream) -> TokenStream {
}
#[proc_macro]
-pub fn assert_fake_source_file(input: TokenStream) -> TokenStream {
+pub fn assert_local_file(input: TokenStream) -> TokenStream {
for tk in input {
- let source_file = tk.span().source_file();
- assert!(!source_file.is_real(), "Source file is real: {:?}", source_file);
- }
-
- "".parse().unwrap()
-}
-
-#[proc_macro]
-pub fn assert_source_file(input: TokenStream) -> TokenStream {
- for tk in input {
- let source_file = tk.span().source_file();
- assert!(source_file.is_real(), "Source file is not real: {:?}", source_file);
+ assert!(tk.span().local_file().is_some(), "No local file for span: {:?}", tk.span());
}
"".parse().unwrap()
diff --git a/tests/ui/proc-macro/cfg-attr-trace.rs b/tests/ui/proc-macro/cfg-attr-trace.rs
index 140dd10..412c65b 100644
--- a/tests/ui/proc-macro/cfg-attr-trace.rs
+++ b/tests/ui/proc-macro/cfg-attr-trace.rs
@@ -3,7 +3,6 @@
//@ check-pass
//@ proc-macro: test-macros.rs
-#![feature(cfg_boolean_literals)]
#![feature(cfg_eval)]
#[macro_use]
diff --git a/tests/ui/proc-macro/cfg-attr-trace.stdout b/tests/ui/proc-macro/cfg-attr-trace.stdout
index 52f9ff4..33bcfe5 100644
--- a/tests/ui/proc-macro/cfg-attr-trace.stdout
+++ b/tests/ui/proc-macro/cfg-attr-trace.stdout
@@ -4,75 +4,75 @@
Punct {
ch: '#',
spacing: Alone,
- span: #0 bytes(305..306),
+ span: #0 bytes(271..272),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "test_macros",
- span: #0 bytes(322..333),
+ span: #0 bytes(288..299),
},
Punct {
ch: ':',
spacing: Joint,
- span: #0 bytes(333..334),
+ span: #0 bytes(299..300),
},
Punct {
ch: ':',
spacing: Alone,
- span: #0 bytes(334..335),
+ span: #0 bytes(300..301),
},
Ident {
ident: "print_attr",
- span: #0 bytes(335..345),
+ span: #0 bytes(301..311),
},
],
- span: #0 bytes(306..347),
+ span: #0 bytes(272..313),
},
Ident {
ident: "struct",
- span: #0 bytes(348..354),
+ span: #0 bytes(314..320),
},
Ident {
ident: "S",
- span: #0 bytes(355..356),
+ span: #0 bytes(321..322),
},
Punct {
ch: ';',
spacing: Alone,
- span: #0 bytes(356..357),
+ span: #0 bytes(322..323),
},
]
PRINT-ATTR INPUT (DISPLAY): struct S;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #0 bytes(348..354),
+ span: #0 bytes(314..320),
},
Ident {
ident: "S",
- span: #0 bytes(355..356),
+ span: #0 bytes(321..322),
},
Punct {
ch: ';',
spacing: Alone,
- span: #0 bytes(356..357),
+ span: #0 bytes(322..323),
},
]
PRINT-ATTR INPUT (DISPLAY): struct Z;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #0 bytes(411..417),
+ span: #0 bytes(377..383),
},
Ident {
ident: "Z",
- span: #0 bytes(418..419),
+ span: #0 bytes(384..385),
},
Punct {
ch: ';',
spacing: Alone,
- span: #0 bytes(419..420),
+ span: #0 bytes(385..386),
},
]
diff --git a/tests/ui/proc-macro/cfg-eval-fail.rs b/tests/ui/proc-macro/cfg-eval-fail.rs
index a259aa2..a94dcd2 100644
--- a/tests/ui/proc-macro/cfg-eval-fail.rs
+++ b/tests/ui/proc-macro/cfg-eval-fail.rs
@@ -2,6 +2,6 @@
#![feature(stmt_expr_attributes)]
fn main() {
- let _ = #[cfg_eval] #[cfg(FALSE)] 0;
+ let _ = #[cfg_eval] #[cfg(false)] 0;
//~^ ERROR removing an expression is not supported in this position
}
diff --git a/tests/ui/proc-macro/cfg-eval-fail.stderr b/tests/ui/proc-macro/cfg-eval-fail.stderr
index 945ad46..7f21e46 100644
--- a/tests/ui/proc-macro/cfg-eval-fail.stderr
+++ b/tests/ui/proc-macro/cfg-eval-fail.stderr
@@ -1,7 +1,7 @@
error: removing an expression is not supported in this position
--> $DIR/cfg-eval-fail.rs:5:25
|
-LL | let _ = #[cfg_eval] #[cfg(FALSE)] 0;
+LL | let _ = #[cfg_eval] #[cfg(false)] 0;
| ^^^^^^^^^^^^^
error: aborting due to 1 previous error
diff --git a/tests/ui/proc-macro/cfg-eval-inner.rs b/tests/ui/proc-macro/cfg-eval-inner.rs
index 7493f3e..dc4efd6 100644
--- a/tests/ui/proc-macro/cfg-eval-inner.rs
+++ b/tests/ui/proc-macro/cfg-eval-inner.rs
@@ -32,7 +32,7 @@ struct Inner {
#![cfg_attr(not(FALSE), rustc_dummy(evaluated_attr))]
fn bar() {
- #[cfg(FALSE)] let a = 1;
+ #[cfg(false)] let a = 1;
}
}
diff --git a/tests/ui/proc-macro/cfg-eval.rs b/tests/ui/proc-macro/cfg-eval.rs
index 1d9b4f2..ddf3708 100644
--- a/tests/ui/proc-macro/cfg-eval.rs
+++ b/tests/ui/proc-macro/cfg-eval.rs
@@ -15,7 +15,7 @@
#[cfg_eval]
#[print_attr]
struct S1 {
- #[cfg(FALSE)]
+ #[cfg(false)]
field_false: u8,
#[cfg(all(/*true*/))]
#[cfg_attr(FALSE, unknown_attr)]
@@ -24,7 +24,7 @@ struct S1 {
}
#[cfg_eval]
-#[cfg(FALSE)]
+#[cfg(false)]
struct S2 {}
fn main() {
@@ -33,5 +33,5 @@ fn main() {
// expression. `#[cfg]` is not supported inside parenthesized expressions, so this will
// produce an error when attribute collection runs.
let _ = #[cfg_eval] #[print_attr] #[cfg_attr(not(FALSE), rustc_dummy)]
- (#[cfg(FALSE)] 0, #[cfg(all(/*true*/))] 1,);
+ (#[cfg(false)] 0, #[cfg(all(/*true*/))] 1,);
}
diff --git a/tests/ui/proc-macro/derive-cfg-nested-tokens.rs b/tests/ui/proc-macro/derive-cfg-nested-tokens.rs
index 7d4e8d8..ec6aba0 100644
--- a/tests/ui/proc-macro/derive-cfg-nested-tokens.rs
+++ b/tests/ui/proc-macro/derive-cfg-nested-tokens.rs
@@ -15,7 +15,7 @@ struct S {
// - on eagerly configured `S` (from `impl Copy`), only 11 should be printed
// - on non-configured `S` (from `struct S`), both 10 and 11 should be printed
field: [u8; #[print_attr] {
- #[cfg(FALSE)] { 10 }
+ #[cfg(false)] { 10 }
#[cfg(not(FALSE))] { 11 }
}],
}
diff --git a/tests/ui/proc-macro/derive-cfg-nested-tokens.stdout b/tests/ui/proc-macro/derive-cfg-nested-tokens.stdout
index 05bf21e..9dbddc9 100644
--- a/tests/ui/proc-macro/derive-cfg-nested-tokens.stdout
+++ b/tests/ui/proc-macro/derive-cfg-nested-tokens.stdout
@@ -54,7 +54,7 @@
span: #0 bytes(452..523),
},
]
-PRINT-ATTR INPUT (DISPLAY): { #[cfg(FALSE)] { 10 } #[cfg(not(FALSE))] { 11 } }
+PRINT-ATTR INPUT (DISPLAY): { #[cfg(false)] { 10 } #[cfg(not(FALSE))] { 11 } }
PRINT-ATTR INPUT (DEBUG): TokenStream [
Group {
delimiter: Brace,
@@ -75,7 +75,7 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "FALSE",
+ ident: "false",
span: #0 bytes(468..473),
},
],
diff --git a/tests/ui/proc-macro/expand-to-derive.rs b/tests/ui/proc-macro/expand-to-derive.rs
index 0e38e47..05c8e32 100644
--- a/tests/ui/proc-macro/expand-to-derive.rs
+++ b/tests/ui/proc-macro/expand-to-derive.rs
@@ -14,7 +14,7 @@ macro_rules! expand_to_derive {
($item:item) => {
#[derive(Print)]
struct Foo {
- #[cfg(FALSE)] removed: bool,
+ #[cfg(false)] removed: bool,
field: [bool; {
$item
0
@@ -26,7 +26,7 @@ struct Foo {
expand_to_derive! {
#[cfg_attr(not(FALSE), rustc_dummy)]
struct Inner {
- #[cfg(FALSE)] removed_inner_field: bool,
+ #[cfg(false)] removed_inner_field: bool,
other_inner_field: u8,
}
}
diff --git a/tests/ui/proc-macro/inner-attrs.rs b/tests/ui/proc-macro/inner-attrs.rs
index 34c37dd..ca4b202 100644
--- a/tests/ui/proc-macro/inner-attrs.rs
+++ b/tests/ui/proc-macro/inner-attrs.rs
@@ -1,6 +1,5 @@
// gate-test-custom_inner_attributes
-//@ compile-flags: -Z span-debug --error-format human
-//@ error-pattern:expected non-macro inner attribute
+//@ compile-flags: -Z span-debug
//@ proc-macro: test-macros.rs
//@ edition:2018
@@ -63,23 +62,27 @@ fn bar() {
for _ in &[true] {
#![print_attr]
+ //~^ ERROR expected non-macro inner attribute, found attribute macro `print_attr`
}
let _ = {
#![print_attr]
+ //~^ ERROR expected non-macro inner attribute, found attribute macro `print_attr`
};
let _ = async {
#![print_attr]
+ //~^ ERROR expected non-macro inner attribute, found attribute macro `print_attr`
};
{
#![print_attr]
+ //~^ ERROR expected non-macro inner attribute, found attribute macro `print_attr`
};
}
-extern {
+extern { //~ WARN `extern` declarations without an explicit ABI are deprecated
fn weird_extern() {
#![print_target_and_args_consume(tenth)]
}
diff --git a/tests/ui/proc-macro/inner-attrs.stderr b/tests/ui/proc-macro/inner-attrs.stderr
index 8b5fec1..54cccae 100644
--- a/tests/ui/proc-macro/inner-attrs.stderr
+++ b/tests/ui/proc-macro/inner-attrs.stderr
@@ -1,5 +1,5 @@
error: expected non-macro inner attribute, found attribute macro `print_attr`
- --> $DIR/inner-attrs.rs:65:12
+ --> $DIR/inner-attrs.rs:64:12
|
LL | #![print_attr]
| ^^^^^^^^^^ not a non-macro inner attribute
@@ -11,19 +11,19 @@
| ^^^^^^^^^^ not a non-macro inner attribute
error: expected non-macro inner attribute, found attribute macro `print_attr`
- --> $DIR/inner-attrs.rs:73:12
+ --> $DIR/inner-attrs.rs:74:12
|
LL | #![print_attr]
| ^^^^^^^^^^ not a non-macro inner attribute
error: expected non-macro inner attribute, found attribute macro `print_attr`
- --> $DIR/inner-attrs.rs:77:12
+ --> $DIR/inner-attrs.rs:79:12
|
LL | #![print_attr]
| ^^^^^^^^^^ not a non-macro inner attribute
-warning: extern declarations without an explicit ABI are deprecated
- --> $DIR/inner-attrs.rs:82:1
+warning: `extern` declarations without an explicit ABI are deprecated
+ --> $DIR/inner-attrs.rs:85:1
|
LL | extern {
| ^^^^^^ help: explicitly specify the "C" ABI: `extern "C"`
diff --git a/tests/ui/proc-macro/inner-attrs.stdout b/tests/ui/proc-macro/inner-attrs.stdout
index ed47ee2..4496f7b 100644
--- a/tests/ui/proc-macro/inner-attrs.stdout
+++ b/tests/ui/proc-macro/inner-attrs.stdout
@@ -2,7 +2,7 @@
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "first",
- span: $DIR/inner-attrs.rs:18:25: 18:30 (#0),
+ span: $DIR/inner-attrs.rs:17:25: 17:30 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(second)] fn foo()
@@ -13,40 +13,40 @@
Punct {
ch: '#',
spacing: Alone,
- span: $DIR/inner-attrs.rs:19:1: 19:2 (#0),
+ span: $DIR/inner-attrs.rs:18:1: 18:2 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:19:3: 19:24 (#0),
+ span: $DIR/inner-attrs.rs:18:3: 18:24 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "second",
- span: $DIR/inner-attrs.rs:19:25: 19:31 (#0),
+ span: $DIR/inner-attrs.rs:18:25: 18:31 (#0),
},
],
- span: $DIR/inner-attrs.rs:19:24: 19:32 (#0),
+ span: $DIR/inner-attrs.rs:18:24: 18:32 (#0),
},
],
- span: $DIR/inner-attrs.rs:19:2: 19:33 (#0),
+ span: $DIR/inner-attrs.rs:18:2: 18:33 (#0),
},
Ident {
ident: "fn",
- span: $DIR/inner-attrs.rs:20:1: 20:3 (#0),
+ span: $DIR/inner-attrs.rs:19:1: 19:3 (#0),
},
Ident {
ident: "foo",
- span: $DIR/inner-attrs.rs:20:4: 20:7 (#0),
+ span: $DIR/inner-attrs.rs:19:4: 19:7 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [],
- span: $DIR/inner-attrs.rs:20:7: 20:9 (#0),
+ span: $DIR/inner-attrs.rs:19:7: 19:9 (#0),
},
Group {
delimiter: Brace,
@@ -54,6 +54,36 @@
Punct {
ch: '#',
spacing: Joint,
+ span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
+ },
+ Punct {
+ ch: '!',
+ spacing: Alone,
+ span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "print_target_and_args",
+ span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "third",
+ span: $DIR/inner-attrs.rs:20:30: 20:35 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:20:29: 20:36 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:20:7: 20:37 (#0),
+ },
+ Punct {
+ ch: '#',
+ spacing: Joint,
span: $DIR/inner-attrs.rs:21:5: 21:6 (#0),
},
Punct {
@@ -72,54 +102,24 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "third",
- span: $DIR/inner-attrs.rs:21:30: 21:35 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:21:29: 21:36 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:21:7: 21:37 (#0),
- },
- Punct {
- ch: '#',
- spacing: Joint,
- span: $DIR/inner-attrs.rs:22:5: 22:6 (#0),
- },
- Punct {
- ch: '!',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:22:6: 22:7 (#0),
- },
- Group {
- delimiter: Bracket,
- stream: TokenStream [
- Ident {
- ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:22:8: 22:29 (#0),
- },
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [
- Ident {
ident: "fourth",
- span: $DIR/inner-attrs.rs:22:30: 22:36 (#0),
+ span: $DIR/inner-attrs.rs:21:30: 21:36 (#0),
},
],
- span: $DIR/inner-attrs.rs:22:29: 22:37 (#0),
+ span: $DIR/inner-attrs.rs:21:29: 21:37 (#0),
},
],
- span: $DIR/inner-attrs.rs:22:7: 22:38 (#0),
+ span: $DIR/inner-attrs.rs:21:7: 21:38 (#0),
},
],
- span: $DIR/inner-attrs.rs:20:10: 23:2 (#0),
+ span: $DIR/inner-attrs.rs:19:10: 22:2 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): second
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "second",
- span: $DIR/inner-attrs.rs:19:25: 19:31 (#0),
+ span: $DIR/inner-attrs.rs:18:25: 18:31 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): fn foo()
@@ -129,16 +129,106 @@
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
- span: $DIR/inner-attrs.rs:20:1: 20:3 (#0),
+ span: $DIR/inner-attrs.rs:19:1: 19:3 (#0),
},
Ident {
ident: "foo",
- span: $DIR/inner-attrs.rs:20:4: 20:7 (#0),
+ span: $DIR/inner-attrs.rs:19:4: 19:7 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [],
- span: $DIR/inner-attrs.rs:20:7: 20:9 (#0),
+ span: $DIR/inner-attrs.rs:19:7: 19:9 (#0),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Joint,
+ span: $DIR/inner-attrs.rs:20:5: 20:6 (#0),
+ },
+ Punct {
+ ch: '!',
+ spacing: Alone,
+ span: $DIR/inner-attrs.rs:20:6: 20:7 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "print_target_and_args",
+ span: $DIR/inner-attrs.rs:20:8: 20:29 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "third",
+ span: $DIR/inner-attrs.rs:20:30: 20:35 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:20:29: 20:36 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:20:7: 20:37 (#0),
+ },
+ Punct {
+ ch: '#',
+ spacing: Joint,
+ span: $DIR/inner-attrs.rs:21:5: 21:6 (#0),
+ },
+ Punct {
+ ch: '!',
+ spacing: Alone,
+ span: $DIR/inner-attrs.rs:21:6: 21:7 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "print_target_and_args",
+ span: $DIR/inner-attrs.rs:21:8: 21:29 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "fourth",
+ span: $DIR/inner-attrs.rs:21:30: 21:36 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:21:29: 21:37 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:21:7: 21:38 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:19:10: 22:2 (#0),
+ },
+]
+PRINT-ATTR_ARGS INPUT (DISPLAY): third
+PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "third",
+ span: $DIR/inner-attrs.rs:20:30: 20:35 (#0),
+ },
+]
+PRINT-ATTR INPUT (DISPLAY): fn foo() { #![print_target_and_args(fourth)] }
+PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): fn foo() { #! [print_target_and_args(fourth)] }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "fn",
+ span: $DIR/inner-attrs.rs:19:1: 19:3 (#0),
+ },
+ Ident {
+ ident: "foo",
+ span: $DIR/inner-attrs.rs:19:4: 19:7 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [],
+ span: $DIR/inner-attrs.rs:19:7: 19:9 (#0),
},
Group {
delimiter: Brace,
@@ -164,142 +254,52 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "third",
- span: $DIR/inner-attrs.rs:21:30: 21:35 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:21:29: 21:36 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:21:7: 21:37 (#0),
- },
- Punct {
- ch: '#',
- spacing: Joint,
- span: $DIR/inner-attrs.rs:22:5: 22:6 (#0),
- },
- Punct {
- ch: '!',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:22:6: 22:7 (#0),
- },
- Group {
- delimiter: Bracket,
- stream: TokenStream [
- Ident {
- ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:22:8: 22:29 (#0),
- },
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [
- Ident {
ident: "fourth",
- span: $DIR/inner-attrs.rs:22:30: 22:36 (#0),
+ span: $DIR/inner-attrs.rs:21:30: 21:36 (#0),
},
],
- span: $DIR/inner-attrs.rs:22:29: 22:37 (#0),
+ span: $DIR/inner-attrs.rs:21:29: 21:37 (#0),
},
],
- span: $DIR/inner-attrs.rs:22:7: 22:38 (#0),
+ span: $DIR/inner-attrs.rs:21:7: 21:38 (#0),
},
],
- span: $DIR/inner-attrs.rs:20:10: 23:2 (#0),
- },
-]
-PRINT-ATTR_ARGS INPUT (DISPLAY): third
-PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
- Ident {
- ident: "third",
- span: $DIR/inner-attrs.rs:21:30: 21:35 (#0),
- },
-]
-PRINT-ATTR INPUT (DISPLAY): fn foo() { #![print_target_and_args(fourth)] }
-PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): fn foo() { #! [print_target_and_args(fourth)] }
-PRINT-ATTR INPUT (DEBUG): TokenStream [
- Ident {
- ident: "fn",
- span: $DIR/inner-attrs.rs:20:1: 20:3 (#0),
- },
- Ident {
- ident: "foo",
- span: $DIR/inner-attrs.rs:20:4: 20:7 (#0),
- },
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [],
- span: $DIR/inner-attrs.rs:20:7: 20:9 (#0),
- },
- Group {
- delimiter: Brace,
- stream: TokenStream [
- Punct {
- ch: '#',
- spacing: Joint,
- span: $DIR/inner-attrs.rs:22:5: 22:6 (#0),
- },
- Punct {
- ch: '!',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:22:6: 22:7 (#0),
- },
- Group {
- delimiter: Bracket,
- stream: TokenStream [
- Ident {
- ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:22:8: 22:29 (#0),
- },
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [
- Ident {
- ident: "fourth",
- span: $DIR/inner-attrs.rs:22:30: 22:36 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:22:29: 22:37 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:22:7: 22:38 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:20:10: 23:2 (#0),
+ span: $DIR/inner-attrs.rs:19:10: 22:2 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): fourth
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "fourth",
- span: $DIR/inner-attrs.rs:22:30: 22:36 (#0),
+ span: $DIR/inner-attrs.rs:21:30: 21:36 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): fn foo() {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
- span: $DIR/inner-attrs.rs:20:1: 20:3 (#0),
+ span: $DIR/inner-attrs.rs:19:1: 19:3 (#0),
},
Ident {
ident: "foo",
- span: $DIR/inner-attrs.rs:20:4: 20:7 (#0),
+ span: $DIR/inner-attrs.rs:19:4: 19:7 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [],
- span: $DIR/inner-attrs.rs:20:7: 20:9 (#0),
+ span: $DIR/inner-attrs.rs:19:7: 19:9 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [],
- span: $DIR/inner-attrs.rs:20:10: 23:2 (#0),
+ span: $DIR/inner-attrs.rs:19:10: 22:2 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): mod_first
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "mod_first",
- span: $DIR/inner-attrs.rs:25:25: 25:34 (#0),
+ span: $DIR/inner-attrs.rs:24:25: 24:34 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): #[print_target_and_args(mod_second)] mod inline_mod
@@ -313,35 +313,35 @@
Punct {
ch: '#',
spacing: Alone,
- span: $DIR/inner-attrs.rs:26:1: 26:2 (#0),
+ span: $DIR/inner-attrs.rs:25:1: 25:2 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:26:3: 26:24 (#0),
+ span: $DIR/inner-attrs.rs:25:3: 25:24 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "mod_second",
- span: $DIR/inner-attrs.rs:26:25: 26:35 (#0),
+ span: $DIR/inner-attrs.rs:25:25: 25:35 (#0),
},
],
- span: $DIR/inner-attrs.rs:26:24: 26:36 (#0),
+ span: $DIR/inner-attrs.rs:25:24: 25:36 (#0),
},
],
- span: $DIR/inner-attrs.rs:26:2: 26:37 (#0),
+ span: $DIR/inner-attrs.rs:25:2: 25:37 (#0),
},
Ident {
ident: "mod",
- span: $DIR/inner-attrs.rs:27:1: 27:4 (#0),
+ span: $DIR/inner-attrs.rs:26:1: 26:4 (#0),
},
Ident {
ident: "inline_mod",
- span: $DIR/inner-attrs.rs:27:5: 27:15 (#0),
+ span: $DIR/inner-attrs.rs:26:5: 26:15 (#0),
},
Group {
delimiter: Brace,
@@ -349,6 +349,36 @@
Punct {
ch: '#',
spacing: Joint,
+ span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
+ },
+ Punct {
+ ch: '!',
+ spacing: Alone,
+ span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "print_target_and_args",
+ span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "mod_third",
+ span: $DIR/inner-attrs.rs:27:30: 27:39 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:27:29: 27:40 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:27:7: 27:41 (#0),
+ },
+ Punct {
+ ch: '#',
+ spacing: Joint,
span: $DIR/inner-attrs.rs:28:5: 28:6 (#0),
},
Punct {
@@ -367,54 +397,24 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "mod_third",
- span: $DIR/inner-attrs.rs:28:30: 28:39 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:28:29: 28:40 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:28:7: 28:41 (#0),
- },
- Punct {
- ch: '#',
- spacing: Joint,
- span: $DIR/inner-attrs.rs:29:5: 29:6 (#0),
- },
- Punct {
- ch: '!',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:29:6: 29:7 (#0),
- },
- Group {
- delimiter: Bracket,
- stream: TokenStream [
- Ident {
- ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:29:8: 29:29 (#0),
- },
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [
- Ident {
ident: "mod_fourth",
- span: $DIR/inner-attrs.rs:29:30: 29:40 (#0),
+ span: $DIR/inner-attrs.rs:28:30: 28:40 (#0),
},
],
- span: $DIR/inner-attrs.rs:29:29: 29:41 (#0),
+ span: $DIR/inner-attrs.rs:28:29: 28:41 (#0),
},
],
- span: $DIR/inner-attrs.rs:29:7: 29:42 (#0),
+ span: $DIR/inner-attrs.rs:28:7: 28:42 (#0),
},
],
- span: $DIR/inner-attrs.rs:27:16: 30:2 (#0),
+ span: $DIR/inner-attrs.rs:26:16: 29:2 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): mod_second
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "mod_second",
- span: $DIR/inner-attrs.rs:26:25: 26:35 (#0),
+ span: $DIR/inner-attrs.rs:25:25: 25:35 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): mod inline_mod
@@ -427,11 +427,96 @@
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "mod",
- span: $DIR/inner-attrs.rs:27:1: 27:4 (#0),
+ span: $DIR/inner-attrs.rs:26:1: 26:4 (#0),
},
Ident {
ident: "inline_mod",
- span: $DIR/inner-attrs.rs:27:5: 27:15 (#0),
+ span: $DIR/inner-attrs.rs:26:5: 26:15 (#0),
+ },
+ Group {
+ delimiter: Brace,
+ stream: TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Joint,
+ span: $DIR/inner-attrs.rs:27:5: 27:6 (#0),
+ },
+ Punct {
+ ch: '!',
+ spacing: Alone,
+ span: $DIR/inner-attrs.rs:27:6: 27:7 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "print_target_and_args",
+ span: $DIR/inner-attrs.rs:27:8: 27:29 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "mod_third",
+ span: $DIR/inner-attrs.rs:27:30: 27:39 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:27:29: 27:40 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:27:7: 27:41 (#0),
+ },
+ Punct {
+ ch: '#',
+ spacing: Joint,
+ span: $DIR/inner-attrs.rs:28:5: 28:6 (#0),
+ },
+ Punct {
+ ch: '!',
+ spacing: Alone,
+ span: $DIR/inner-attrs.rs:28:6: 28:7 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "print_target_and_args",
+ span: $DIR/inner-attrs.rs:28:8: 28:29 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "mod_fourth",
+ span: $DIR/inner-attrs.rs:28:30: 28:40 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:28:29: 28:41 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:28:7: 28:42 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:26:16: 29:2 (#0),
+ },
+]
+PRINT-ATTR_ARGS INPUT (DISPLAY): mod_third
+PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "mod_third",
+ span: $DIR/inner-attrs.rs:27:30: 27:39 (#0),
+ },
+]
+PRINT-ATTR INPUT (DISPLAY): mod inline_mod { #![print_target_and_args(mod_fourth)] }
+PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): mod inline_mod { #! [print_target_and_args(mod_fourth)] }
+PRINT-ATTR INPUT (DEBUG): TokenStream [
+ Ident {
+ ident: "mod",
+ span: $DIR/inner-attrs.rs:26:1: 26:4 (#0),
+ },
+ Ident {
+ ident: "inline_mod",
+ span: $DIR/inner-attrs.rs:26:5: 26:15 (#0),
},
Group {
delimiter: Brace,
@@ -457,125 +542,40 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "mod_third",
- span: $DIR/inner-attrs.rs:28:30: 28:39 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:28:29: 28:40 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:28:7: 28:41 (#0),
- },
- Punct {
- ch: '#',
- spacing: Joint,
- span: $DIR/inner-attrs.rs:29:5: 29:6 (#0),
- },
- Punct {
- ch: '!',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:29:6: 29:7 (#0),
- },
- Group {
- delimiter: Bracket,
- stream: TokenStream [
- Ident {
- ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:29:8: 29:29 (#0),
- },
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [
- Ident {
ident: "mod_fourth",
- span: $DIR/inner-attrs.rs:29:30: 29:40 (#0),
+ span: $DIR/inner-attrs.rs:28:30: 28:40 (#0),
},
],
- span: $DIR/inner-attrs.rs:29:29: 29:41 (#0),
+ span: $DIR/inner-attrs.rs:28:29: 28:41 (#0),
},
],
- span: $DIR/inner-attrs.rs:29:7: 29:42 (#0),
+ span: $DIR/inner-attrs.rs:28:7: 28:42 (#0),
},
],
- span: $DIR/inner-attrs.rs:27:16: 30:2 (#0),
- },
-]
-PRINT-ATTR_ARGS INPUT (DISPLAY): mod_third
-PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
- Ident {
- ident: "mod_third",
- span: $DIR/inner-attrs.rs:28:30: 28:39 (#0),
- },
-]
-PRINT-ATTR INPUT (DISPLAY): mod inline_mod { #![print_target_and_args(mod_fourth)] }
-PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): mod inline_mod { #! [print_target_and_args(mod_fourth)] }
-PRINT-ATTR INPUT (DEBUG): TokenStream [
- Ident {
- ident: "mod",
- span: $DIR/inner-attrs.rs:27:1: 27:4 (#0),
- },
- Ident {
- ident: "inline_mod",
- span: $DIR/inner-attrs.rs:27:5: 27:15 (#0),
- },
- Group {
- delimiter: Brace,
- stream: TokenStream [
- Punct {
- ch: '#',
- spacing: Joint,
- span: $DIR/inner-attrs.rs:29:5: 29:6 (#0),
- },
- Punct {
- ch: '!',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:29:6: 29:7 (#0),
- },
- Group {
- delimiter: Bracket,
- stream: TokenStream [
- Ident {
- ident: "print_target_and_args",
- span: $DIR/inner-attrs.rs:29:8: 29:29 (#0),
- },
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [
- Ident {
- ident: "mod_fourth",
- span: $DIR/inner-attrs.rs:29:30: 29:40 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:29:29: 29:41 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:29:7: 29:42 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:27:16: 30:2 (#0),
+ span: $DIR/inner-attrs.rs:26:16: 29:2 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): mod_fourth
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "mod_fourth",
- span: $DIR/inner-attrs.rs:29:30: 29:40 (#0),
+ span: $DIR/inner-attrs.rs:28:30: 28:40 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): mod inline_mod {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "mod",
- span: $DIR/inner-attrs.rs:27:1: 27:4 (#0),
+ span: $DIR/inner-attrs.rs:26:1: 26:4 (#0),
},
Ident {
ident: "inline_mod",
- span: $DIR/inner-attrs.rs:27:5: 27:15 (#0),
+ span: $DIR/inner-attrs.rs:26:5: 26:15 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [],
- span: $DIR/inner-attrs.rs:27:16: 30:2 (#0),
+ span: $DIR/inner-attrs.rs:26:16: 29:2 (#0),
},
]
PRINT-DERIVE INPUT (DISPLAY): struct MyDerivePrint
@@ -585,63 +585,63 @@
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: $DIR/inner-attrs.rs:37:1: 37:7 (#0),
+ span: $DIR/inner-attrs.rs:36:1: 36:7 (#0),
},
Ident {
ident: "MyDerivePrint",
- span: $DIR/inner-attrs.rs:37:8: 37:21 (#0),
+ span: $DIR/inner-attrs.rs:36:8: 36:21 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [
Ident {
ident: "field",
- span: $DIR/inner-attrs.rs:38:5: 38:10 (#0),
+ span: $DIR/inner-attrs.rs:37:5: 37:10 (#0),
},
Punct {
ch: ':',
spacing: Alone,
- span: $DIR/inner-attrs.rs:38:10: 38:11 (#0),
+ span: $DIR/inner-attrs.rs:37:10: 37:11 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "u8",
- span: $DIR/inner-attrs.rs:38:13: 38:15 (#0),
+ span: $DIR/inner-attrs.rs:37:13: 37:15 (#0),
},
Punct {
ch: ';',
spacing: Alone,
- span: $DIR/inner-attrs.rs:38:15: 38:16 (#0),
+ span: $DIR/inner-attrs.rs:37:15: 37:16 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [
Ident {
ident: "match",
- span: $DIR/inner-attrs.rs:39:9: 39:14 (#0),
+ span: $DIR/inner-attrs.rs:38:9: 38:14 (#0),
},
Ident {
ident: "true",
- span: $DIR/inner-attrs.rs:39:15: 39:19 (#0),
+ span: $DIR/inner-attrs.rs:38:15: 38:19 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [
Ident {
ident: "_",
- span: $DIR/inner-attrs.rs:40:13: 40:14 (#0),
+ span: $DIR/inner-attrs.rs:39:13: 39:14 (#0),
},
Punct {
ch: '=',
spacing: Joint,
- span: $DIR/inner-attrs.rs:40:15: 40:16 (#0),
+ span: $DIR/inner-attrs.rs:39:15: 39:16 (#0),
},
Punct {
ch: '>',
spacing: Alone,
- span: $DIR/inner-attrs.rs:40:16: 40:17 (#0),
+ span: $DIR/inner-attrs.rs:39:16: 39:17 (#0),
},
Group {
delimiter: Brace,
@@ -649,69 +649,69 @@
Punct {
ch: '#',
spacing: Joint,
- span: $DIR/inner-attrs.rs:41:17: 41:18 (#0),
+ span: $DIR/inner-attrs.rs:40:17: 40:18 (#0),
},
Punct {
ch: '!',
spacing: Alone,
- span: $DIR/inner-attrs.rs:41:18: 41:19 (#0),
+ span: $DIR/inner-attrs.rs:40:18: 40:19 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "rustc_dummy",
- span: $DIR/inner-attrs.rs:41:41: 41:52 (#0),
+ span: $DIR/inner-attrs.rs:40:41: 40:52 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "third",
- span: $DIR/inner-attrs.rs:41:53: 41:58 (#0),
+ span: $DIR/inner-attrs.rs:40:53: 40:58 (#0),
},
],
- span: $DIR/inner-attrs.rs:41:52: 41:59 (#0),
+ span: $DIR/inner-attrs.rs:40:52: 40:59 (#0),
},
],
- span: $DIR/inner-attrs.rs:41:19: 41:61 (#0),
+ span: $DIR/inner-attrs.rs:40:19: 40:61 (#0),
},
Ident {
ident: "true",
- span: $DIR/inner-attrs.rs:42:17: 42:21 (#0),
+ span: $DIR/inner-attrs.rs:41:17: 41:21 (#0),
},
],
- span: $DIR/inner-attrs.rs:40:18: 43:14 (#0),
+ span: $DIR/inner-attrs.rs:39:18: 42:14 (#0),
},
],
- span: $DIR/inner-attrs.rs:39:20: 44:10 (#0),
+ span: $DIR/inner-attrs.rs:38:20: 43:10 (#0),
},
Punct {
ch: ';',
spacing: Alone,
- span: $DIR/inner-attrs.rs:44:10: 44:11 (#0),
+ span: $DIR/inner-attrs.rs:43:10: 43:11 (#0),
},
Literal {
kind: Integer,
symbol: "0",
suffix: None,
- span: $DIR/inner-attrs.rs:45:9: 45:10 (#0),
+ span: $DIR/inner-attrs.rs:44:9: 44:10 (#0),
},
],
- span: $DIR/inner-attrs.rs:38:17: 46:6 (#0),
+ span: $DIR/inner-attrs.rs:37:17: 45:6 (#0),
},
],
- span: $DIR/inner-attrs.rs:38:12: 46:7 (#0),
+ span: $DIR/inner-attrs.rs:37:12: 45:7 (#0),
},
],
- span: $DIR/inner-attrs.rs:37:22: 47:2 (#0),
+ span: $DIR/inner-attrs.rs:36:22: 46:2 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "tuple_attrs",
- span: $DIR/inner-attrs.rs:50:29: 50:40 (#0),
+ span: $DIR/inner-attrs.rs:49:29: 49:40 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): (3, 4, { #![cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 });
@@ -724,23 +724,23 @@
kind: Integer,
symbol: "3",
suffix: None,
- span: $DIR/inner-attrs.rs:51:9: 51:10 (#0),
+ span: $DIR/inner-attrs.rs:50:9: 50:10 (#0),
},
Punct {
ch: ',',
spacing: Alone,
- span: $DIR/inner-attrs.rs:51:10: 51:11 (#0),
+ span: $DIR/inner-attrs.rs:50:10: 50:11 (#0),
},
Literal {
kind: Integer,
symbol: "4",
suffix: None,
- span: $DIR/inner-attrs.rs:51:12: 51:13 (#0),
+ span: $DIR/inner-attrs.rs:50:12: 50:13 (#0),
},
Punct {
ch: ',',
spacing: Alone,
- span: $DIR/inner-attrs.rs:51:13: 51:14 (#0),
+ span: $DIR/inner-attrs.rs:50:13: 50:14 (#0),
},
Group {
delimiter: Brace,
@@ -748,85 +748,85 @@
Punct {
ch: '#',
spacing: Joint,
+ span: $DIR/inner-attrs.rs:51:13: 51:14 (#0),
+ },
+ Punct {
+ ch: '!',
+ spacing: Alone,
+ span: $DIR/inner-attrs.rs:51:14: 51:15 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "cfg_attr",
+ span: $DIR/inner-attrs.rs:51:16: 51:24 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "not",
+ span: $DIR/inner-attrs.rs:51:25: 51:28 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "FALSE",
+ span: $DIR/inner-attrs.rs:51:29: 51:34 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:51:28: 51:35 (#0),
+ },
+ Punct {
+ ch: ',',
+ spacing: Alone,
+ span: $DIR/inner-attrs.rs:51:35: 51:36 (#0),
+ },
+ Ident {
+ ident: "rustc_dummy",
+ span: $DIR/inner-attrs.rs:51:37: 51:48 (#0),
+ },
+ Group {
+ delimiter: Parenthesis,
+ stream: TokenStream [
+ Ident {
+ ident: "innermost",
+ span: $DIR/inner-attrs.rs:51:49: 51:58 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:51:48: 51:59 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:51:24: 51:60 (#0),
+ },
+ ],
+ span: $DIR/inner-attrs.rs:51:15: 51:61 (#0),
+ },
+ Literal {
+ kind: Integer,
+ symbol: "5",
+ suffix: None,
span: $DIR/inner-attrs.rs:52:13: 52:14 (#0),
},
- Punct {
- ch: '!',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:52:14: 52:15 (#0),
- },
- Group {
- delimiter: Bracket,
- stream: TokenStream [
- Ident {
- ident: "cfg_attr",
- span: $DIR/inner-attrs.rs:52:16: 52:24 (#0),
- },
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [
- Ident {
- ident: "not",
- span: $DIR/inner-attrs.rs:52:25: 52:28 (#0),
- },
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [
- Ident {
- ident: "FALSE",
- span: $DIR/inner-attrs.rs:52:29: 52:34 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:52:28: 52:35 (#0),
- },
- Punct {
- ch: ',',
- spacing: Alone,
- span: $DIR/inner-attrs.rs:52:35: 52:36 (#0),
- },
- Ident {
- ident: "rustc_dummy",
- span: $DIR/inner-attrs.rs:52:37: 52:48 (#0),
- },
- Group {
- delimiter: Parenthesis,
- stream: TokenStream [
- Ident {
- ident: "innermost",
- span: $DIR/inner-attrs.rs:52:49: 52:58 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:52:48: 52:59 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:52:24: 52:60 (#0),
- },
- ],
- span: $DIR/inner-attrs.rs:52:15: 52:61 (#0),
- },
- Literal {
- kind: Integer,
- symbol: "5",
- suffix: None,
- span: $DIR/inner-attrs.rs:53:13: 53:14 (#0),
- },
],
- span: $DIR/inner-attrs.rs:51:15: 54:10 (#0),
+ span: $DIR/inner-attrs.rs:50:15: 53:10 (#0),
},
],
- span: $DIR/inner-attrs.rs:50:43: 55:6 (#0),
+ span: $DIR/inner-attrs.rs:49:43: 54:6 (#0),
},
Punct {
ch: ';',
spacing: Alone,
- span: $DIR/inner-attrs.rs:55:6: 55:7 (#0),
+ span: $DIR/inner-attrs.rs:54:6: 54:7 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): tuple_attrs
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "tuple_attrs",
- span: $DIR/inner-attrs.rs:57:29: 57:40 (#0),
+ span: $DIR/inner-attrs.rs:56:29: 56:40 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): (3, 4, { #![cfg_attr(not(FALSE), rustc_dummy(innermost))] 5 });
@@ -839,23 +839,23 @@
kind: Integer,
symbol: "3",
suffix: None,
- span: $DIR/inner-attrs.rs:58:9: 58:10 (#0),
+ span: $DIR/inner-attrs.rs:57:9: 57:10 (#0),
},
Punct {
ch: ',',
spacing: Alone,
- span: $DIR/inner-attrs.rs:58:10: 58:11 (#0),
+ span: $DIR/inner-attrs.rs:57:10: 57:11 (#0),
},
Literal {
kind: Integer,
symbol: "4",
suffix: None,
- span: $DIR/inner-attrs.rs:58:12: 58:13 (#0),
+ span: $DIR/inner-attrs.rs:57:12: 57:13 (#0),
},
Punct {
ch: ',',
spacing: Alone,
- span: $DIR/inner-attrs.rs:58:13: 58:14 (#0),
+ span: $DIR/inner-attrs.rs:57:13: 57:14 (#0),
},
Group {
delimiter: Brace,
@@ -863,105 +863,105 @@
Punct {
ch: '#',
spacing: Joint,
- span: $DIR/inner-attrs.rs:59:13: 59:14 (#0),
+ span: $DIR/inner-attrs.rs:58:13: 58:14 (#0),
},
Punct {
ch: '!',
spacing: Alone,
- span: $DIR/inner-attrs.rs:59:14: 59:15 (#0),
+ span: $DIR/inner-attrs.rs:58:14: 58:15 (#0),
},
Group {
delimiter: Bracket,
stream: TokenStream [
Ident {
ident: "cfg_attr",
- span: $DIR/inner-attrs.rs:59:16: 59:24 (#0),
+ span: $DIR/inner-attrs.rs:58:16: 58:24 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "not",
- span: $DIR/inner-attrs.rs:59:25: 59:28 (#0),
+ span: $DIR/inner-attrs.rs:58:25: 58:28 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "FALSE",
- span: $DIR/inner-attrs.rs:59:29: 59:34 (#0),
+ span: $DIR/inner-attrs.rs:58:29: 58:34 (#0),
},
],
- span: $DIR/inner-attrs.rs:59:28: 59:35 (#0),
+ span: $DIR/inner-attrs.rs:58:28: 58:35 (#0),
},
Punct {
ch: ',',
spacing: Alone,
- span: $DIR/inner-attrs.rs:59:35: 59:36 (#0),
+ span: $DIR/inner-attrs.rs:58:35: 58:36 (#0),
},
Ident {
ident: "rustc_dummy",
- span: $DIR/inner-attrs.rs:59:37: 59:48 (#0),
+ span: $DIR/inner-attrs.rs:58:37: 58:48 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "innermost",
- span: $DIR/inner-attrs.rs:59:49: 59:58 (#0),
+ span: $DIR/inner-attrs.rs:58:49: 58:58 (#0),
},
],
- span: $DIR/inner-attrs.rs:59:48: 59:59 (#0),
+ span: $DIR/inner-attrs.rs:58:48: 58:59 (#0),
},
],
- span: $DIR/inner-attrs.rs:59:24: 59:60 (#0),
+ span: $DIR/inner-attrs.rs:58:24: 58:60 (#0),
},
],
- span: $DIR/inner-attrs.rs:59:15: 59:61 (#0),
+ span: $DIR/inner-attrs.rs:58:15: 58:61 (#0),
},
Literal {
kind: Integer,
symbol: "5",
suffix: None,
- span: $DIR/inner-attrs.rs:60:13: 60:14 (#0),
+ span: $DIR/inner-attrs.rs:59:13: 59:14 (#0),
},
],
- span: $DIR/inner-attrs.rs:58:15: 61:10 (#0),
+ span: $DIR/inner-attrs.rs:57:15: 60:10 (#0),
},
],
- span: $DIR/inner-attrs.rs:57:43: 62:6 (#0),
+ span: $DIR/inner-attrs.rs:56:43: 61:6 (#0),
},
Punct {
ch: ';',
spacing: Alone,
- span: $DIR/inner-attrs.rs:62:6: 62:7 (#0),
+ span: $DIR/inner-attrs.rs:61:6: 61:7 (#0),
},
]
PRINT-ATTR_ARGS INPUT (DISPLAY): tenth
PRINT-ATTR_ARGS INPUT (DEBUG): TokenStream [
Ident {
ident: "tenth",
- span: $DIR/inner-attrs.rs:84:42: 84:47 (#0),
+ span: $DIR/inner-attrs.rs:87:42: 87:47 (#0),
},
]
PRINT-ATTR INPUT (DISPLAY): fn weird_extern() {}
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "fn",
- span: $DIR/inner-attrs.rs:83:5: 83:7 (#0),
+ span: $DIR/inner-attrs.rs:86:5: 86:7 (#0),
},
Ident {
ident: "weird_extern",
- span: $DIR/inner-attrs.rs:83:8: 83:20 (#0),
+ span: $DIR/inner-attrs.rs:86:8: 86:20 (#0),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [],
- span: $DIR/inner-attrs.rs:83:20: 83:22 (#0),
+ span: $DIR/inner-attrs.rs:86:20: 86:22 (#0),
},
Group {
delimiter: Brace,
stream: TokenStream [],
- span: $DIR/inner-attrs.rs:83:23: 85:6 (#0),
+ span: $DIR/inner-attrs.rs:86:23: 88:6 (#0),
},
]
diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.rs b/tests/ui/proc-macro/issue-75930-derive-cfg.rs
index 376a8ea..f0851b3 100644
--- a/tests/ui/proc-macro/issue-75930-derive-cfg.rs
+++ b/tests/ui/proc-macro/issue-75930-derive-cfg.rs
@@ -31,7 +31,7 @@
//
// It is because of this code from below:
// ```
-// struct Foo<#[cfg(FALSE)] A, B>
+// struct Foo<#[cfg(false)] A, B>
// ```
// When the token stream is formed during parsing, `<` is followed immediately
// by `#`, which is punctuation, so it is marked `Joint`. But before being
@@ -51,22 +51,22 @@
#[print_attr]
#[derive(Print)]
#[print_helper(b)]
-struct Foo<#[cfg(FALSE)] A, B> {
- #[cfg(FALSE)] first: String,
+struct Foo<#[cfg(false)] A, B> {
+ #[cfg(false)] first: String,
#[cfg_attr(FALSE, deny(warnings))] second: bool,
third: [u8; {
- #[cfg(FALSE)] struct Bar;
+ #[cfg(false)] struct Bar;
#[cfg(not(FALSE))] struct Inner;
- #[cfg(FALSE)] let a = 25;
+ #[cfg(false)] let a = 25;
match true {
- #[cfg(FALSE)] true => {},
+ #[cfg(false)] true => {},
#[cfg_attr(not(FALSE), allow(warnings))] false => {},
_ => {}
};
#[print_helper(should_be_removed)]
fn removed_fn() {
- #![cfg(FALSE)]
+ #![cfg(false)]
}
#[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() {
@@ -76,22 +76,22 @@ fn removed_fn() {
enum TupleEnum {
Foo(
- #[cfg(FALSE)] u8,
- #[cfg(FALSE)] bool,
+ #[cfg(false)] u8,
+ #[cfg(false)] bool,
#[cfg(not(FALSE))] i32,
- #[cfg(FALSE)] String, u8
+ #[cfg(false)] String, u8
)
}
struct TupleStruct(
- #[cfg(FALSE)] String,
+ #[cfg(false)] String,
#[cfg(not(FALSE))] i32,
- #[cfg(FALSE)] bool,
+ #[cfg(false)] bool,
u8
);
fn plain_removed_fn() {
- #![cfg_attr(not(FALSE), cfg(FALSE))]
+ #![cfg_attr(not(FALSE), cfg(false))]
}
0
diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout
index 4dcf2b7..549621f 100644
--- a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout
+++ b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout
@@ -1,73 +1,73 @@
PRINT-ATTR INPUT (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[derive(Print)] #[print_helper(b)]
-struct Foo<#[cfg(FALSE)] A, B>
+struct Foo<#[cfg(false)] A, B>
{
- #[cfg(FALSE)] first: String, #[cfg_attr(FALSE, deny(warnings))] second:
+ #[cfg(false)] first: String, #[cfg_attr(FALSE, deny(warnings))] second:
bool, third:
[u8;
{
- #[cfg(FALSE)] struct Bar; #[cfg(not(FALSE))] struct Inner;
- #[cfg(FALSE)] let a = 25; match true
+ #[cfg(false)] struct Bar; #[cfg(not(FALSE))] struct Inner;
+ #[cfg(false)] let a = 25; match true
{
- #[cfg(FALSE)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))]
+ #[cfg(false)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))]
false => {}, _ => {}
}; #[print_helper(should_be_removed)] fn removed_fn()
- { #![cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn()
+ { #![cfg(false)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn()
{ #![cfg(not(FALSE))] let my_val = true; } enum TupleEnum
{
- Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32,
- #[cfg(FALSE)] String, u8)
+ Foo(#[cfg(false)] u8, #[cfg(false)] bool, #[cfg(not(FALSE))] i32,
+ #[cfg(false)] String, u8)
} struct
- TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32,
- #[cfg(FALSE)] bool, u8); fn plain_removed_fn()
- { #![cfg_attr(not(FALSE), cfg(FALSE))] } 0
+ TupleStruct(#[cfg(false)] String, #[cfg(not(FALSE))] i32,
+ #[cfg(false)] bool, u8); fn plain_removed_fn()
+ { #![cfg_attr(not(FALSE), cfg(false))] } 0
}], #[print_helper(d)] fourth: B
}
PRINT-ATTR RE-COLLECTED (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[derive(Print)] #[print_helper(b)]
-struct Foo <#[cfg(FALSE)] A, B >
+struct Foo <#[cfg(false)] A, B >
{
- #[cfg(FALSE)] first: String, #[cfg_attr(FALSE, deny(warnings))] second:
+ #[cfg(false)] first: String, #[cfg_attr(FALSE, deny(warnings))] second:
bool, third:
[u8;
{
- #[cfg(FALSE)] struct Bar; #[cfg(not(FALSE))] struct Inner;
- #[cfg(FALSE)] let a = 25; match true
+ #[cfg(false)] struct Bar; #[cfg(not(FALSE))] struct Inner;
+ #[cfg(false)] let a = 25; match true
{
- #[cfg(FALSE)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))]
+ #[cfg(false)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))]
false => {}, _ => {}
}; #[print_helper(should_be_removed)] fn removed_fn()
- { #![cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn()
+ { #![cfg(false)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn()
{ #![cfg(not(FALSE))] let my_val = true; } enum TupleEnum
{
- Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32,
- #[cfg(FALSE)] String, u8)
+ Foo(#[cfg(false)] u8, #[cfg(false)] bool, #[cfg(not(FALSE))] i32,
+ #[cfg(false)] String, u8)
} struct
- TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32,
- #[cfg(FALSE)] bool, u8); fn plain_removed_fn()
- { #![cfg_attr(not(FALSE), cfg(FALSE))] } 0
+ TupleStruct(#[cfg(false)] String, #[cfg(not(FALSE))] i32,
+ #[cfg(false)] bool, u8); fn plain_removed_fn()
+ { #![cfg_attr(not(FALSE), cfg(false))] } 0
}], #[print_helper(d)] fourth: B
}
PRINT-ATTR DEEP-RE-COLLECTED (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[derive(Print)] #[print_helper(b)]
-struct Foo <#[cfg(FALSE)] A, B >
+struct Foo <#[cfg(false)] A, B >
{
- #[cfg(FALSE)] first : String, #[cfg_attr(FALSE, deny(warnings))] second :
+ #[cfg(false)] first : String, #[cfg_attr(FALSE, deny(warnings))] second :
bool, third :
[u8;
{
- #[cfg(FALSE)] struct Bar; #[cfg(not(FALSE))] struct Inner;
- #[cfg(FALSE)] let a = 25; match true
+ #[cfg(false)] struct Bar; #[cfg(not(FALSE))] struct Inner;
+ #[cfg(false)] let a = 25; match true
{
- #[cfg(FALSE)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))]
+ #[cfg(false)] true => {}, #[cfg_attr(not(FALSE), allow(warnings))]
false => {}, _ => {}
}; #[print_helper(should_be_removed)] fn removed_fn()
- { #! [cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn()
+ { #! [cfg(false)] } #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn()
{ #! [cfg(not(FALSE))] let my_val = true; } enum TupleEnum
{
- Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32,
- #[cfg(FALSE)] String, u8)
+ Foo(#[cfg(false)] u8, #[cfg(false)] bool, #[cfg(not(FALSE))] i32,
+ #[cfg(false)] String, u8)
} struct
- TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32,
- #[cfg(FALSE)] bool, u8); fn plain_removed_fn()
- { #! [cfg_attr(not(FALSE), cfg(FALSE))] } 0
+ TupleStruct(#[cfg(false)] String, #[cfg(not(FALSE))] i32,
+ #[cfg(false)] bool, u8); fn plain_removed_fn()
+ { #! [cfg_attr(not(FALSE), cfg(false))] } 0
}], #[print_helper(d)] fourth : B
}
PRINT-ATTR INPUT (DEBUG): TokenStream [
@@ -200,7 +200,7 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "FALSE",
+ ident: "false",
span: $DIR/issue-75930-derive-cfg.rs:54:18: 54:23 (#0),
},
],
@@ -246,7 +246,7 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "FALSE",
+ ident: "false",
span: $DIR/issue-75930-derive-cfg.rs:55:11: 55:16 (#0),
},
],
@@ -375,7 +375,7 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "FALSE",
+ ident: "false",
span: $DIR/issue-75930-derive-cfg.rs:58:15: 58:20 (#0),
},
],
@@ -461,7 +461,7 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "FALSE",
+ ident: "false",
span: $DIR/issue-75930-derive-cfg.rs:60:15: 60:20 (#0),
},
],
@@ -521,7 +521,7 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "FALSE",
+ ident: "false",
span: $DIR/issue-75930-derive-cfg.rs:62:19: 62:24 (#0),
},
],
@@ -721,7 +721,7 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "FALSE",
+ ident: "false",
span: $DIR/issue-75930-derive-cfg.rs:69:20: 69:25 (#0),
},
],
@@ -908,7 +908,7 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "FALSE",
+ ident: "false",
span: $DIR/issue-75930-derive-cfg.rs:79:23: 79:28 (#0),
},
],
@@ -942,7 +942,7 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "FALSE",
+ ident: "false",
span: $DIR/issue-75930-derive-cfg.rs:80:23: 80:28 (#0),
},
],
@@ -1020,7 +1020,7 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "FALSE",
+ ident: "false",
span: $DIR/issue-75930-derive-cfg.rs:82:23: 82:28 (#0),
},
],
@@ -1075,7 +1075,7 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "FALSE",
+ ident: "false",
span: $DIR/issue-75930-derive-cfg.rs:87:19: 87:24 (#0),
},
],
@@ -1153,7 +1153,7 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "FALSE",
+ ident: "false",
span: $DIR/issue-75930-derive-cfg.rs:89:19: 89:24 (#0),
},
],
@@ -1246,7 +1246,7 @@
delimiter: Parenthesis,
stream: TokenStream [
Ident {
- ident: "FALSE",
+ ident: "false",
span: $DIR/issue-75930-derive-cfg.rs:94:41: 94:46 (#0),
},
],
diff --git a/tests/ui/proc-macro/meta-macro-hygiene.stdout b/tests/ui/proc-macro/meta-macro-hygiene.stdout
index 1ee7179..1734b9a 100644
--- a/tests/ui/proc-macro/meta-macro-hygiene.stdout
+++ b/tests/ui/proc-macro/meta-macro-hygiene.stdout
@@ -60,11 +60,11 @@
#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque)
#1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque)
#2: parent: #0, outer_mark: (crate0::{{expn1}}, Transparent)
-#3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiTransparent)
+#3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiOpaque)
#4: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque)
#5: parent: #3, outer_mark: (crate0::{{expn3}}, Transparent)
-#6: parent: #0, outer_mark: (crate0::{{expn3}}, SemiTransparent)
+#6: parent: #0, outer_mark: (crate0::{{expn3}}, SemiOpaque)
#7: parent: #0, outer_mark: (crate0::{{expn4}}, Opaque)
#8: parent: #4, outer_mark: (crate0::{{expn4}}, Transparent)
-#9: parent: #4, outer_mark: (crate0::{{expn4}}, SemiTransparent)
+#9: parent: #4, outer_mark: (crate0::{{expn4}}, SemiOpaque)
*/
diff --git a/tests/ui/proc-macro/module.rs b/tests/ui/proc-macro/module.rs
index 210c059..5878f1b 100644
--- a/tests/ui/proc-macro/module.rs
+++ b/tests/ui/proc-macro/module.rs
@@ -1 +1 @@
-//@ ignore-test (auxiliary, used by other tests)
+//@ ignore-auxiliary (used by `./attributes-on-modules-fail.rs`)
diff --git a/tests/ui/proc-macro/module_with_attrs.rs b/tests/ui/proc-macro/module_with_attrs.rs
index 8a4ca92..7e4ec97 100644
--- a/tests/ui/proc-macro/module_with_attrs.rs
+++ b/tests/ui/proc-macro/module_with_attrs.rs
@@ -1,4 +1,4 @@
-//@ ignore-test (auxiliary, used by other tests)
+//@ ignore-auxiliary (used by `../inner-attr-non-inline-mod.rs`)
#![rustfmt::skip]
#![print_attr]
diff --git a/tests/ui/proc-macro/nested-derive-cfg.rs b/tests/ui/proc-macro/nested-derive-cfg.rs
index bd8f231..b3dcfb7 100644
--- a/tests/ui/proc-macro/nested-derive-cfg.rs
+++ b/tests/ui/proc-macro/nested-derive-cfg.rs
@@ -10,10 +10,10 @@
#[derive(Print)]
struct Foo {
- #[cfg(FALSE)] removed: bool,
+ #[cfg(false)] removed: bool,
my_array: [bool; {
struct Inner {
- #[cfg(FALSE)] removed_inner_field: u8,
+ #[cfg(false)] removed_inner_field: u8,
non_removed_inner_field: usize
}
0
diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.rs b/tests/ui/proc-macro/nonterminal-token-hygiene.rs
index e2aedb2..b7b0d1e 100644
--- a/tests/ui/proc-macro/nonterminal-token-hygiene.rs
+++ b/tests/ui/proc-macro/nonterminal-token-hygiene.rs
@@ -8,6 +8,7 @@
//@ normalize-stdout: "expn\d{3,}" -> "expnNNN"
//@ normalize-stdout: "extern crate compiler_builtins /\* \d+ \*/" -> "extern crate compiler_builtins /* NNN */"
//@ proc-macro: test-macros.rs
+//@ edition: 2015
#![feature(decl_macro)]
#![no_std] // Don't load unnecessary hygiene information from std
diff --git a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
index 6fd6cb4..4225731 100644
--- a/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
+++ b/tests/ui/proc-macro/nonterminal-token-hygiene.stdout
@@ -5,19 +5,19 @@
stream: TokenStream [
Ident {
ident: "struct",
- span: $DIR/nonterminal-token-hygiene.rs:32:5: 32:11 (#5),
+ span: $DIR/nonterminal-token-hygiene.rs:33:5: 33:11 (#5),
},
Ident {
ident: "S",
- span: $DIR/nonterminal-token-hygiene.rs:32:12: 32:13 (#5),
+ span: $DIR/nonterminal-token-hygiene.rs:33:12: 33:13 (#5),
},
Punct {
ch: ';',
spacing: Alone,
- span: $DIR/nonterminal-token-hygiene.rs:32:13: 32:14 (#5),
+ span: $DIR/nonterminal-token-hygiene.rs:33:13: 33:14 (#5),
},
],
- span: $DIR/nonterminal-token-hygiene.rs:22:27: 22:32 (#4),
+ span: $DIR/nonterminal-token-hygiene.rs:23:27: 23:32 (#4),
},
]
#![feature /* 0#0 */(prelude_import)]
@@ -32,6 +32,7 @@
//@ normalize-stdout: "expn\d{3,}" -> "expnNNN"
//@ normalize-stdout: "extern crate compiler_builtins /\* \d+ \*/" -> "extern crate compiler_builtins /* NNN */"
//@ proc-macro: test-macros.rs
+//@ edition: 2015
#![feature /* 0#0 */(decl_macro)]
#![no_std /* 0#0 */]
@@ -82,10 +83,10 @@
#0: parent: #0, outer_mark: (crate0::{{expn0}}, Opaque)
#1: parent: #0, outer_mark: (crate0::{{expn1}}, Opaque)
#2: parent: #0, outer_mark: (crate0::{{expn1}}, Transparent)
-#3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiTransparent)
+#3: parent: #0, outer_mark: (crate0::{{expn2}}, SemiOpaque)
#4: parent: #3, outer_mark: (crate0::{{expn3}}, Opaque)
#5: parent: #0, outer_mark: (crate0::{{expn3}}, Opaque)
#6: parent: #0, outer_mark: (crate0::{{expn4}}, Opaque)
#7: parent: #4, outer_mark: (crate0::{{expn4}}, Transparent)
-#8: parent: #5, outer_mark: (crate0::{{expn4}}, SemiTransparent)
+#8: parent: #5, outer_mark: (crate0::{{expn4}}, SemiOpaque)
*/
diff --git a/tests/ui/proc-macro/outer/inner.rs b/tests/ui/proc-macro/outer/inner.rs
index 210c059..d0f2087 100644
--- a/tests/ui/proc-macro/outer/inner.rs
+++ b/tests/ui/proc-macro/outer/inner.rs
@@ -1 +1 @@
-//@ ignore-test (auxiliary, used by other tests)
+//@ ignore-auxiliary (used by `../attributes-on-modules-fail.rs`)
diff --git a/tests/ui/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs b/tests/ui/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs
index f89098f..a27176a 100644
--- a/tests/ui/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs
+++ b/tests/ui/proc-macro/pretty-print-hack/allsorts-rental-0.5.6/src/lib.rs
@@ -1,4 +1,4 @@
-//@ ignore-test (auxiliary, used by other tests)
+//@ ignore-auxiliary (used by `../../../pretty-print-hack-show.rs`)
#[derive(Print)]
enum ProceduralMasqueradeDummyType {
diff --git a/tests/ui/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs b/tests/ui/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs
index f89098f..a27176a 100644
--- a/tests/ui/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs
+++ b/tests/ui/proc-macro/pretty-print-hack/rental-0.5.5/src/lib.rs
@@ -1,4 +1,4 @@
-//@ ignore-test (auxiliary, used by other tests)
+//@ ignore-auxiliary (used by `../../../pretty-print-hack-show.rs`)
#[derive(Print)]
enum ProceduralMasqueradeDummyType {
diff --git a/tests/ui/proc-macro/pretty-print-hack/rental-0.5.6/src/lib.rs b/tests/ui/proc-macro/pretty-print-hack/rental-0.5.6/src/lib.rs
index f89098f..765ee4b 100644
--- a/tests/ui/proc-macro/pretty-print-hack/rental-0.5.6/src/lib.rs
+++ b/tests/ui/proc-macro/pretty-print-hack/rental-0.5.6/src/lib.rs
@@ -1,4 +1,4 @@
-//@ ignore-test (auxiliary, used by other tests)
+//@ ignore-auxiliary (used by `../../../pretty-print-hack/hide.rs`)
#[derive(Print)]
enum ProceduralMasqueradeDummyType {
diff --git a/tests/ui/proc-macro/quote/debug.rs b/tests/ui/proc-macro/quote/debug.rs
index ce11307..ce1ef81 100644
--- a/tests/ui/proc-macro/quote/debug.rs
+++ b/tests/ui/proc-macro/quote/debug.rs
@@ -3,6 +3,7 @@
//@ no-prefer-dynamic
//@ compile-flags: -Z unpretty=expanded
//@ needs-unwind compiling proc macros with panic=abort causes a warning
+//@ edition: 2015
//
// This file is not actually used as a proc-macro - instead,
// it's just used to show the output of the `quote!` macro
diff --git a/tests/ui/proc-macro/quote/debug.stdout b/tests/ui/proc-macro/quote/debug.stdout
index 3eaad9e..6ebb3a3 100644
--- a/tests/ui/proc-macro/quote/debug.stdout
+++ b/tests/ui/proc-macro/quote/debug.stdout
@@ -5,6 +5,7 @@
//@ no-prefer-dynamic
//@ compile-flags: -Z unpretty=expanded
//@ needs-unwind compiling proc macros with panic=abort causes a warning
+//@ edition: 2015
//
// This file is not actually used as a proc-macro - instead,
// it's just used to show the output of the `quote!` macro
diff --git a/tests/ui/proc-macro/span-api-tests.rs b/tests/ui/proc-macro/span-api-tests.rs
index ac42a7e..792859e 100644
--- a/tests/ui/proc-macro/span-api-tests.rs
+++ b/tests/ui/proc-macro/span-api-tests.rs
@@ -8,26 +8,24 @@
extern crate span_api_tests;
-// FIXME(69775): Investigate `assert_fake_source_file`.
-
-use span_api_tests::{reemit, assert_source_file, macro_stringify};
+use span_api_tests::{reemit, assert_local_file, macro_stringify};
macro_rules! say_hello {
($macname:ident) => ( $macname! { "Hello, world!" })
}
-assert_source_file! { "Hello, world!" }
+assert_local_file! { "Hello, world!" }
-say_hello! { assert_source_file }
+say_hello! { assert_local_file }
reemit_legacy! {
- assert_source_file! { "Hello, world!" }
+ assert_local_file! { "Hello, world!" }
}
-say_hello_extern! { assert_source_file }
+say_hello_extern! { assert_local_file }
reemit! {
- assert_source_file! { "Hello, world!" }
+ assert_local_file! { "Hello, world!" }
}
fn main() {
diff --git a/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.rs b/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.rs
new file mode 100644
index 0000000..b3310ac
--- /dev/null
+++ b/tests/ui/reachable/unreachable-by-call-arguments-issue-139627.rs
@@ -0,0 +1,16 @@
+//@ check-pass
+#![deny(unreachable_code)]
+#![deny(unused)]
+
+pub enum Void {}
+
+pub struct S<T>(T);
+
+pub fn foo(void: Void, void1: Void) {
+ let s = S(void);
+ drop(s);
+ let s1 = S { 0: void1 };
+ drop(s1);
+}
+
+fn main() {}
diff --git a/tests/ui/recursion/recursive-enum-box.rs b/tests/ui/recursion/recursive-enum-box.rs
new file mode 100644
index 0000000..540b0c5
--- /dev/null
+++ b/tests/ui/recursion/recursive-enum-box.rs
@@ -0,0 +1,21 @@
+//@ run-pass
+// A smoke test for recursive enum structures using Box<T>.
+// This test constructs a linked list-like structure to exercise memory allocation and ownership.
+// Originally introduced in 2010, this is one of Rust’s earliest test cases.
+
+#![allow(dead_code)]
+
+enum List {
+ Cons(isize, Box<List>),
+ Nil,
+}
+
+fn main() {
+ List::Cons(
+ 10,
+ Box::new(List::Cons(
+ 11,
+ Box::new(List::Cons(12, Box::new(List::Nil))),
+ )),
+ );
+}
diff --git a/tests/ui/regions/region-invariant-static-error-reporting.rs b/tests/ui/regions/region-invariant-static-error-reporting.rs
index e58eea3..9792c10 100644
--- a/tests/ui/regions/region-invariant-static-error-reporting.rs
+++ b/tests/ui/regions/region-invariant-static-error-reporting.rs
@@ -3,7 +3,7 @@
// over time, but this test used to exhibit some pretty bogus messages
// that were not remotely helpful.
-//@ error-pattern:requires that `'a` must outlive `'static`
+//@ dont-require-annotations: NOTE
struct Invariant<'a>(Option<&'a mut &'a mut ()>);
@@ -14,6 +14,7 @@ fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) {
x.unwrap()
} else {
mk_static() //~ ERROR lifetime may not live long enough
+ //~| NOTE assignment requires that `'a` must outlive `'static`
};
f(bad);
}
diff --git a/tests/ui/resolve/auxiliary/empty.rs b/tests/ui/resolve/auxiliary/empty.rs
new file mode 100644
index 0000000..bd9ec07
--- /dev/null
+++ b/tests/ui/resolve/auxiliary/empty.rs
@@ -0,0 +1 @@
+// Intentionally empty.
diff --git a/tests/ui/resolve/prim-crate-partial-res.rs b/tests/ui/resolve/prim-crate-partial-res.rs
new file mode 100644
index 0000000..955f4fa
--- /dev/null
+++ b/tests/ui/resolve/prim-crate-partial-res.rs
@@ -0,0 +1,8 @@
+//@ aux-build: empty.rs
+
+extern crate empty as usize;
+
+fn foo() -> usize<()> { 0 }
+//~^ ERROR type arguments are not allowed on builtin type `usize`
+
+fn main() {}
diff --git a/tests/ui/resolve/prim-crate-partial-res.stderr b/tests/ui/resolve/prim-crate-partial-res.stderr
new file mode 100644
index 0000000..d10d37c
--- /dev/null
+++ b/tests/ui/resolve/prim-crate-partial-res.stderr
@@ -0,0 +1,17 @@
+error[E0109]: type arguments are not allowed on builtin type `usize`
+ --> $DIR/prim-crate-partial-res.rs:5:19
+ |
+LL | fn foo() -> usize<()> { 0 }
+ | ----- ^^ type argument not allowed
+ | |
+ | not allowed on builtin type `usize`
+ |
+help: primitive type `usize` doesn't have generic parameters
+ |
+LL - fn foo() -> usize<()> { 0 }
+LL + fn foo() -> usize { 0 }
+ |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0109`.
diff --git a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs
index 6b85ada..60e5452 100644
--- a/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs
+++ b/tests/ui/rfcs/rfc-0000-never_patterns/diverges-not.rs
@@ -1,5 +1,5 @@
+//@ edition: 2024
#![feature(never_patterns)]
-#![feature(let_chains)]
#![allow(incomplete_features)]
#![deny(unreachable_patterns)]
diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs
index 0e85515..a4baf1f 100644
--- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs
+++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.rs
@@ -1,11 +1,10 @@
//@ needs-asm-support
-#![feature(naked_functions)]
use std::arch::naked_asm;
#[track_caller] //~ ERROR [E0736]
//~^ ERROR `#[track_caller]` requires Rust ABI
-#[naked]
+#[unsafe(naked)]
extern "C" fn f() {
unsafe {
naked_asm!("");
@@ -17,7 +16,7 @@ extern "C" fn f() {
impl S {
#[track_caller] //~ ERROR [E0736]
//~^ ERROR `#[track_caller]` requires Rust ABI
- #[naked]
+ #[unsafe(naked)]
extern "C" fn g() {
unsafe {
naked_asm!("");
diff --git a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr
index 0625ed1..d3cafbc 100644
--- a/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr
+++ b/tests/ui/rfcs/rfc-2091-track-caller/error-with-naked.stderr
@@ -1,29 +1,29 @@
-error[E0736]: attribute incompatible with `#[naked]`
- --> $DIR/error-with-naked.rs:6:1
+error[E0736]: attribute incompatible with `#[unsafe(naked)]`
+ --> $DIR/error-with-naked.rs:5:1
|
LL | #[track_caller]
- | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[naked]`
+ | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[unsafe(naked)]`
LL |
-LL | #[naked]
- | -------- function marked with `#[naked]` here
+LL | #[unsafe(naked)]
+ | ---------------- function marked with `#[unsafe(naked)]` here
-error[E0736]: attribute incompatible with `#[naked]`
- --> $DIR/error-with-naked.rs:18:5
+error[E0736]: attribute incompatible with `#[unsafe(naked)]`
+ --> $DIR/error-with-naked.rs:17:5
|
LL | #[track_caller]
- | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[naked]`
+ | ^^^^^^^^^^^^^^^ the `track_caller` attribute is incompatible with `#[unsafe(naked)]`
LL |
-LL | #[naked]
- | -------- function marked with `#[naked]` here
+LL | #[unsafe(naked)]
+ | ---------------- function marked with `#[unsafe(naked)]` here
error[E0737]: `#[track_caller]` requires Rust ABI
- --> $DIR/error-with-naked.rs:6:1
+ --> $DIR/error-with-naked.rs:5:1
|
LL | #[track_caller]
| ^^^^^^^^^^^^^^^
error[E0737]: `#[track_caller]` requires Rust ABI
- --> $DIR/error-with-naked.rs:18:5
+ --> $DIR/error-with-naked.rs:17:5
|
LL | #[track_caller]
| ^^^^^^^^^^^^^^^
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs
index 110c03d..b1e3058 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.rs
@@ -15,11 +15,9 @@ fn _if_let_guard() {
() if true && let 0 = 1 => {}
//~^ ERROR `if let` guards are experimental
- //~| ERROR `let` expressions in this position are unstable
() if let 0 = 1 && true => {}
//~^ ERROR `if let` guards are experimental
- //~| ERROR `let` expressions in this position are unstable
() if (let 0 = 1) && true => {}
//~^ ERROR expected expression, found `let` statement
@@ -33,8 +31,6 @@ fn _if_let_guard() {
() if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
//~^ ERROR `if let` guards are experimental
- //~| ERROR `let` expressions in this position are unstable
- //~| ERROR `let` expressions in this position are unstable
//~| ERROR expected expression, found `let` statement
//~| ERROR expected expression, found `let` statement
//~| ERROR expected expression, found `let` statement
@@ -42,7 +38,6 @@ fn _if_let_guard() {
() if let Range { start: _, end: _ } = (true..true) && false => {}
//~^ ERROR `if let` guards are experimental
- //~| ERROR `let` expressions in this position are unstable
_ => {}
}
@@ -64,7 +59,7 @@ macro_rules! use_expr {
//~^ ERROR expected expression, found `let` statement
//~| ERROR expected expression, found `let` statement
match () {
- #[cfg(FALSE)]
+ #[cfg(false)]
() if let 0 = 1 => {}
//~^ ERROR `if let` guards are experimental
_ => {}
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr
index 0997f0c..19d1f4b0 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/feature-gate.stderr
@@ -25,98 +25,98 @@
| ^^^^^^^^^
error: expected expression, found `let` statement
- --> $DIR/feature-gate.rs:24:16
+ --> $DIR/feature-gate.rs:22:16
|
LL | () if (let 0 = 1) && true => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/feature-gate.rs:24:16
+ --> $DIR/feature-gate.rs:22:16
|
LL | () if (let 0 = 1) && true => {}
| ^^^^^^^^^
error: expected expression, found `let` statement
- --> $DIR/feature-gate.rs:27:24
+ --> $DIR/feature-gate.rs:25:24
|
LL | () if true && (let 0 = 1) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/feature-gate.rs:27:24
+ --> $DIR/feature-gate.rs:25:24
|
LL | () if true && (let 0 = 1) => {}
| ^^^^^^^^^
error: expected expression, found `let` statement
- --> $DIR/feature-gate.rs:30:16
+ --> $DIR/feature-gate.rs:28:16
|
LL | () if (let 0 = 1) && (let 0 = 1) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/feature-gate.rs:30:16
+ --> $DIR/feature-gate.rs:28:16
|
LL | () if (let 0 = 1) && (let 0 = 1) => {}
| ^^^^^^^^^
error: expected expression, found `let` statement
- --> $DIR/feature-gate.rs:30:31
+ --> $DIR/feature-gate.rs:28:31
|
LL | () if (let 0 = 1) && (let 0 = 1) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/feature-gate.rs:30:31
+ --> $DIR/feature-gate.rs:28:31
|
LL | () if (let 0 = 1) && (let 0 = 1) => {}
| ^^^^^^^^^
error: expected expression, found `let` statement
- --> $DIR/feature-gate.rs:34:42
+ --> $DIR/feature-gate.rs:32:42
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/feature-gate.rs:34:42
+ --> $DIR/feature-gate.rs:32:42
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: expected expression, found `let` statement
- --> $DIR/feature-gate.rs:34:55
+ --> $DIR/feature-gate.rs:32:55
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/feature-gate.rs:34:42
+ --> $DIR/feature-gate.rs:32:42
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: expected expression, found `let` statement
- --> $DIR/feature-gate.rs:34:68
+ --> $DIR/feature-gate.rs:32:68
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
note: `let`s wrapped in parentheses are not supported in a context with let chains
- --> $DIR/feature-gate.rs:34:42
+ --> $DIR/feature-gate.rs:32:42
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: expected expression, found `let` statement
- --> $DIR/feature-gate.rs:60:16
+ --> $DIR/feature-gate.rs:55:16
|
LL | use_expr!((let 0 = 1 && 0 == 0));
| ^^^
@@ -124,7 +124,7 @@
= note: only supported directly in conditions of `if` and `while` expressions
error: expected expression, found `let` statement
- --> $DIR/feature-gate.rs:60:16
+ --> $DIR/feature-gate.rs:55:16
|
LL | use_expr!((let 0 = 1 && 0 == 0));
| ^^^
@@ -133,7 +133,7 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: expected expression, found `let` statement
- --> $DIR/feature-gate.rs:63:16
+ --> $DIR/feature-gate.rs:58:16
|
LL | use_expr!((let 0 = 1));
| ^^^
@@ -141,7 +141,7 @@
= note: only supported directly in conditions of `if` and `while` expressions
error: expected expression, found `let` statement
- --> $DIR/feature-gate.rs:63:16
+ --> $DIR/feature-gate.rs:58:16
|
LL | use_expr!((let 0 = 1));
| ^^^
@@ -150,7 +150,7 @@
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
error: no rules expected keyword `let`
- --> $DIR/feature-gate.rs:72:15
+ --> $DIR/feature-gate.rs:67:15
|
LL | macro_rules! use_expr {
| --------------------- when calling this macro
@@ -159,7 +159,7 @@
| ^^^ no rules expected this token in macro call
|
note: while trying to match meta-variable `$e:expr`
- --> $DIR/feature-gate.rs:53:10
+ --> $DIR/feature-gate.rs:48:10
|
LL | ($e:expr) => {
| ^^^^^^^
@@ -187,7 +187,7 @@
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
error[E0658]: `if let` guards are experimental
- --> $DIR/feature-gate.rs:20:12
+ --> $DIR/feature-gate.rs:19:12
|
LL | () if let 0 = 1 && true => {}
| ^^^^^^^^^^^^^^^^^^^^
@@ -198,7 +198,7 @@
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
error[E0658]: `if let` guards are experimental
- --> $DIR/feature-gate.rs:34:12
+ --> $DIR/feature-gate.rs:32:12
|
LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -209,7 +209,7 @@
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
error[E0658]: `if let` guards are experimental
- --> $DIR/feature-gate.rs:43:12
+ --> $DIR/feature-gate.rs:39:12
|
LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +220,7 @@
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
error[E0658]: `if let` guards are experimental
- --> $DIR/feature-gate.rs:68:12
+ --> $DIR/feature-gate.rs:63:12
|
LL | () if let 0 = 1 => {}
| ^^^^^^^^^^^^
@@ -230,56 +230,6 @@
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
-error[E0658]: `let` expressions in this position are unstable
- --> $DIR/feature-gate.rs:16:23
- |
-LL | () if true && let 0 = 1 => {}
- | ^^^^^^^^^
- |
- = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
- = help: add `#![feature(let_chains)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
- --> $DIR/feature-gate.rs:20:15
- |
-LL | () if let 0 = 1 && true => {}
- | ^^^^^^^^^
- |
- = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
- = help: add `#![feature(let_chains)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
- --> $DIR/feature-gate.rs:34:15
- |
-LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
- | ^^^^^^^^^
- |
- = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
- = help: add `#![feature(let_chains)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
- --> $DIR/feature-gate.rs:34:28
- |
-LL | () if let 0 = 1 && let 1 = 2 && (let 2 = 3 && let 3 = 4 && let 4 = 5) => {}
- | ^^^^^^^^^
- |
- = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
- = help: add `#![feature(let_chains)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error[E0658]: `let` expressions in this position are unstable
- --> $DIR/feature-gate.rs:43:15
- |
-LL | () if let Range { start: _, end: _ } = (true..true) && false => {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
- = help: add `#![feature(let_chains)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 25 previous errors
+error: aborting due to 20 previous errors
For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs
index 423a2cd..e113883 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.rs
@@ -1,7 +1,6 @@
// Expression macros can't expand to a let match guard.
#![feature(if_let_guard)]
-#![feature(let_chains)]
macro_rules! m {
($e:expr) => { let Some(x) = $e }
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.stderr b/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.stderr
index b8065b9..921cd08 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.stderr
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/macro-expanded.stderr
@@ -1,5 +1,5 @@
error: expected expression, found `let` statement
- --> $DIR/macro-expanded.rs:7:20
+ --> $DIR/macro-expanded.rs:6:20
|
LL | ($e:expr) => { let Some(x) = $e }
| ^^^
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs
index 47653ef..29f529a 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/move-guard-if-let-chain.rs
@@ -1,5 +1,5 @@
+//@ edition: 2024
#![feature(if_let_guard)]
-#![feature(let_chains)]
#![allow(irrefutable_let_patterns)]
fn same_pattern(c: bool) {
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs
index f12824d..a4cb73c 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/parens.rs
@@ -1,9 +1,9 @@
+//@ edition: 2024
// Parenthesised let "expressions" are not allowed in guards
#![feature(if_let_guard)]
-#![feature(let_chains)]
-#[cfg(FALSE)]
+#[cfg(false)]
fn un_cfged() {
match () {
() if let 0 = 1 => {}
diff --git a/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs b/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs
index 32a223c..e7946a2 100644
--- a/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs
+++ b/tests/ui/rfcs/rfc-2294-if-let-guard/shadowing.rs
@@ -1,8 +1,8 @@
// Check shadowing in if let guards works as expected.
//@ check-pass
+//@ edition: 2024
#![feature(if_let_guard)]
-#![feature(let_chains)]
fn main() {
let x: Option<Option<i32>> = Some(Some(6));
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs
index e1edde6..dc052c3 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-lowering-does-not-wrap-let-chains.rs
@@ -1,6 +1,6 @@
//@ run-pass
+//@ edition: 2024
-#![feature(let_chains)]
#![allow(irrefutable_let_patterns)]
fn main() {
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs
index 8d78264..16165c4 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.rs
@@ -1,5 +1,6 @@
//@ check-pass
//@ compile-flags: -Z unpretty=expanded
+//@ edition: 2015
fn main() {
if let 0 = 1 {}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout
index 1c103f0..e2e45ae 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-pretty-check.stdout
@@ -6,5 +6,6 @@
extern crate std;
//@ check-pass
//@ compile-flags: -Z unpretty=expanded
+//@ edition: 2015
fn main() { if let 0 = 1 {} }
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs
index cb3be59..ae13f7c 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ast-validate-guards.rs
@@ -1,4 +1,4 @@
-#![feature(let_chains)]
+//@ edition: 2024
fn let_or_guard(x: Result<Option<i32>, ()>) {
match x {
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/auxiliary/macro-in-2021.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/auxiliary/macro-in-2021.rs
new file mode 100644
index 0000000..d2d5ae1
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/auxiliary/macro-in-2021.rs
@@ -0,0 +1,26 @@
+//@ edition: 2021
+
+#[macro_export]
+macro_rules! make_if {
+ (($($tt:tt)*) { $body:expr } { $else:expr }) => {{
+ if $($tt)* {
+ $body
+ } else {
+ $else
+ }
+ }};
+ (let ($expr:expr) { $body:expr } { $else:expr }) => {{
+ if let None = $expr {
+ $body
+ } else {
+ $else
+ }
+ }};
+ (let ($expr:expr) let ($expr2:expr) { $body:expr } { $else:expr }) => {{
+ if let None = $expr && let None = $expr2 {
+ $body
+ } else {
+ $else
+ }
+ }};
+}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/auxiliary/macro-in-2024.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/auxiliary/macro-in-2024.rs
new file mode 100644
index 0000000..f5b6f35
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/auxiliary/macro-in-2024.rs
@@ -0,0 +1,26 @@
+//@ edition: 2024
+
+#[macro_export]
+macro_rules! make_if {
+ (($($tt:tt)*) { $body:expr } { $else:expr }) => {{
+ if $($tt)* {
+ $body
+ } else {
+ $else
+ }
+ }};
+ (let ($expr:expr) { $body:expr } { $else:expr }) => {{
+ if let None = $expr {
+ $body
+ } else {
+ $else
+ }
+ }};
+ (let ($expr:expr) let ($expr2:expr) { $body:expr } { $else:expr }) => {{
+ if let None = $expr && let None = $expr2 {
+ $body
+ } else {
+ $else
+ }
+ }};
+}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs
index 99f99c2..0b0abe6 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/disallowed-positions.rs
@@ -340,12 +340,12 @@ fn _check_try_binds_tighter() -> Result<(), ()> {
//~| ERROR expected expression, found `let` statement
{
- #[cfg(FALSE)]
+ #[cfg(false)]
let x = true && let y = 1;
//~^ ERROR expected expression, found `let` statement
}
- #[cfg(FALSE)]
+ #[cfg(false)]
{
[1, 2, 3][let _ = ()]
//~^ ERROR expected expression, found `let` statement
@@ -436,11 +436,11 @@ fn with_parenthesis() {
//[no_feature]~^ ERROR `let` expressions in this position are unstable
}
- #[cfg(FALSE)]
+ #[cfg(false)]
let x = (true && let y = 1);
//~^ ERROR expected expression, found `let` statement
- #[cfg(FALSE)]
+ #[cfg(false)]
{
([1, 2, 3][let _ = ()])
//~^ ERROR expected expression, found `let` statement
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr
new file mode 100644
index 0000000..23700f8
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2021.stderr
@@ -0,0 +1,65 @@
+error[E0658]: `let` expressions in this position are unstable
+ --> $DIR/edition-gate-macro-error.rs:19:30
+ |
+LL | macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+ = help: add `#![feature(let_chains)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+ --> $DIR/edition-gate-macro-error.rs:19:52
+ |
+LL | macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+ = help: add `#![feature(let_chains)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+ --> $DIR/edition-gate-macro-error.rs:22:5
+ |
+LL | macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+ = help: add `#![feature(let_chains)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+ = note: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0658]: `let` expressions in this position are unstable
+ --> $DIR/edition-gate-macro-error.rs:22:5
+ |
+LL | macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+ = help: add `#![feature(let_chains)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+ = note: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0658]: `let` expressions in this position are unstable
+ --> $DIR/edition-gate-macro-error.rs:26:30
+ |
+LL | macro_in_2024::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+ = help: add `#![feature(let_chains)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+ --> $DIR/edition-gate-macro-error.rs:26:52
+ |
+LL | macro_in_2024::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+ = help: add `#![feature(let_chains)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr
new file mode 100644
index 0000000..3af844f
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.edition2024.stderr
@@ -0,0 +1,45 @@
+error[E0658]: `let` expressions in this position are unstable
+ --> $DIR/edition-gate-macro-error.rs:19:30
+ |
+LL | macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+ = help: add `#![feature(let_chains)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+ --> $DIR/edition-gate-macro-error.rs:19:52
+ |
+LL | macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+ | ^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+ = help: add `#![feature(let_chains)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: `let` expressions in this position are unstable
+ --> $DIR/edition-gate-macro-error.rs:22:5
+ |
+LL | macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+ = help: add `#![feature(let_chains)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+ = note: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0658]: `let` expressions in this position are unstable
+ --> $DIR/edition-gate-macro-error.rs:22:5
+ |
+LL | macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
+ = help: add `#![feature(let_chains)]` to the crate attributes to enable
+ = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+ = note: this error originates in the macro `macro_in_2021::make_if` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs
new file mode 100644
index 0000000..89b555d
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro-error.rs
@@ -0,0 +1,30 @@
+//@ revisions: edition2021 edition2024
+//@ compile-flags: -Z lint-mir -Z validate-mir
+//@ [edition2021] edition: 2021
+//@ [edition2024] edition: 2024
+//@ aux-build:macro-in-2021.rs
+//@ aux-build:macro-in-2024.rs
+
+use std::unreachable as never;
+
+// Compiletest doesn't specify the needed --extern flags to make `extern crate` unneccessary
+extern crate macro_in_2021;
+extern crate macro_in_2024;
+
+fn main() {
+ // Gated on both 2021 and 2024 if the `if` comes from a 2021 macro
+ // Gated only on 2021 if the `if` comes from a 2024 macro
+ // No gating if both the `if` and the chain are from a 2024 macro
+
+ macro_in_2021::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+ //~^ ERROR `let` expressions in this position are unstable
+ //~| ERROR `let` expressions in this position are unstable
+ macro_in_2021::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
+ //~^ ERROR `let` expressions in this position are unstable
+ //~| ERROR `let` expressions in this position are unstable
+
+ macro_in_2024::make_if!((let Some(0) = None && let Some(0) = None) { never!() } { never!() });
+ //[edition2021]~^ ERROR `let` expressions in this position are unstable
+ //[edition2021]~| ERROR `let` expressions in this position are unstable
+ macro_in_2024::make_if!(let (Some(0)) let (Some(0)) { never!() } { never!() });
+}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro.rs
new file mode 100644
index 0000000..5dd928d
--- /dev/null
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/edition-gate-macro.rs
@@ -0,0 +1,76 @@
+//@ revisions: edition2021 edition2024
+//@ compile-flags: -Z lint-mir -Z validate-mir
+//@ [edition2021] edition: 2021
+//@ [edition2024] edition: 2024
+//@ aux-build:macro-in-2021.rs
+//@ aux-build:macro-in-2024.rs
+//@ run-pass
+
+#![allow(dead_code)]
+
+use std::unreachable as never;
+use std::cell::RefCell;
+use std::convert::TryInto;
+
+// Compiletest doesn't specify the needed --extern flags to make `extern crate` unneccessary
+extern crate macro_in_2021;
+extern crate macro_in_2024;
+
+#[derive(Default)]
+struct DropOrderCollector(RefCell<Vec<u32>>);
+
+struct LoudDrop<'a>(&'a DropOrderCollector, u32);
+
+impl Drop for LoudDrop<'_> {
+ fn drop(&mut self) {
+ println!("{}", self.1);
+ self.0.0.borrow_mut().push(self.1);
+ }
+}
+
+impl DropOrderCollector {
+ fn print(&self, n: u32) {
+ println!("{n}");
+ self.0.borrow_mut().push(n)
+ }
+ fn some_loud(&self, n: u32) -> Option<LoudDrop> {
+ Some(LoudDrop(self, n))
+ }
+
+ #[track_caller]
+ fn validate(self) {
+ assert!(
+ self.0
+ .into_inner()
+ .into_iter()
+ .enumerate()
+ .all(|(idx, item)| idx + 1 == item.try_into().unwrap())
+ );
+ }
+ fn with_macro_2021(self) {
+ // Edition 2021 drop behaviour
+ macro_in_2021::make_if!((let None = self.some_loud(2)) { never!() } {self.print(1) });
+ macro_in_2021::make_if!(let (self.some_loud(4)) { never!() } { self.print(3) });
+ self.validate();
+ }
+ fn with_macro_2024(self) {
+ // Edition 2024 drop behaviour
+ macro_in_2024::make_if!((let None = self.some_loud(1)) { never!() } { self.print(2) });
+ macro_in_2024::make_if!(let (self.some_loud(3)) { never!() } { self.print(4) });
+ self.validate();
+ }
+}
+
+fn main() {
+ // 2021 drop order if it's a 2021 macro creating the `if`
+ // 2024 drop order if it's a 2024 macro creating the `if`
+
+ // Compare this with edition-gate-macro-error.rs: We want to avoid exposing 2021 drop order,
+ // because it can create bad MIR (issue #104843)
+ // This test doesn't contain any let chains at all: it should be understood
+ // in combination with `edition-gate-macro-error.rs`
+
+ DropOrderCollector::default().with_macro_2021();
+ DropOrderCollector::default().with_macro_2024();
+
+}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs
index 3c57205..8e7db9a 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/ensure-that-let-else-does-not-interact-with-let-chains.rs
@@ -1,4 +1,4 @@
-#![feature(let_chains)]
+//@ edition: 2024
fn main() {
let opt = Some(1i32);
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs
index 2087fc4..dad02b7 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.rs
@@ -51,7 +51,7 @@ macro_rules! use_expr {
while $e {}
}
}
- #[cfg(FALSE)] (let 0 = 1);
+ #[cfg(false)] (let 0 = 1);
//~^ ERROR expected expression, found `let` statement
use_expr!(let 0 = 1);
//~^ ERROR no rules expected keyword `let`
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr
index 7c874ae..b9dac47 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/feature-gate.stderr
@@ -1,7 +1,7 @@
error: expected expression, found `let` statement
--> $DIR/feature-gate.rs:54:20
|
-LL | #[cfg(FALSE)] (let 0 = 1);
+LL | #[cfg(false)] (let 0 = 1);
| ^^^
|
= note: only supported directly in conditions of `if` and `while` expressions
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs
index dce1c19..ae525ae 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/invalid-let-in-a-valid-let-context.rs
@@ -3,12 +3,12 @@
fn main() {
let _opt = Some(1i32);
- #[cfg(FALSE)]
+ #[cfg(false)]
{
let _ = &&let Some(x) = Some(42);
//~^ ERROR expected expression, found `let` statement
}
- #[cfg(FALSE)]
+ #[cfg(false)]
{
if let Some(elem) = _opt && [1, 2, 3][let _ = &&let Some(x) = Some(42)] = 1 {
//~^ ERROR expected expression, found `let` statement
@@ -18,7 +18,7 @@ fn main() {
}
}
- #[cfg(FALSE)]
+ #[cfg(false)]
{
if let Some(elem) = _opt && {
[1, 2, 3][let _ = ()];
@@ -28,7 +28,7 @@ fn main() {
}
}
- #[cfg(FALSE)]
+ #[cfg(false)]
{
if let Some(elem) = _opt && [1, 2, 3][let _ = ()] = 1 {
//~^ ERROR expected expression, found `let` statement
@@ -36,7 +36,7 @@ fn main() {
true
}
}
- #[cfg(FALSE)]
+ #[cfg(false)]
{
if let a = 1 && {
let x = let y = 1;
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs
index 59c81d0..0113a87 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-90722.rs
@@ -1,6 +1,5 @@
//@ check-pass
-
-#![feature(let_chains)]
+//@ edition: 2024
fn main() {
let x = Some(vec!["test"]);
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs
index ea4b34e..f5d87d6 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-92145.rs
@@ -1,6 +1,5 @@
//@ check-pass
-
-#![feature(let_chains)]
+//@ edition:2024
fn main() {
let opt = Some("foo bar");
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs
index f90b9ab..f6de378 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.rs
@@ -2,7 +2,6 @@
match true {
_ if let true = true && true => {}
//~^ ERROR `if let` guards are
- //~| ERROR `let` expressions in this
_ => {}
}
}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.stderr b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.stderr
index 637ae49..17fa37d 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.stderr
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-93150.stderr
@@ -9,16 +9,6 @@
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= help: you can write `if matches!(<expr>, <pattern>)` instead of `if let <pattern> = <expr>`
-error[E0658]: `let` expressions in this position are unstable
- --> $DIR/issue-93150.rs:3:14
- |
-LL | _ if let true = true && true => {}
- | ^^^^^^^^^^^^^^^
- |
- = note: see issue #53667 <https://github.com/rust-lang/rust/issues/53667> for more information
- = help: add `#![feature(let_chains)]` to the crate attributes to enable
- = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs
index 77756d0..7589b33 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/issue-99938.rs
@@ -1,6 +1,7 @@
//@ compile-flags: -Zvalidate-mir -C opt-level=3
//@ build-pass
-#![feature(let_chains)]
+//@ edition: 2024
+
struct TupleIter<T, I: Iterator<Item = T>> {
inner: I,
}
diff --git a/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs b/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs
index 2c7fe2e..7d8dfe3 100644
--- a/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs
+++ b/tests/ui/rfcs/rfc-2497-if-let-chains/temporary-early-drop.rs
@@ -3,7 +3,6 @@
//@ edition: 2024
//@ check-pass
-#![feature(let_chains)]
#![allow(irrefutable_let_patterns)]
struct Pd;
diff --git a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs
index eeb2191..c0f1757 100644
--- a/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs
+++ b/tests/ui/rfcs/rfc-2565-param-attrs/attr-without-param.rs
@@ -1,14 +1,14 @@
-#[cfg(FALSE)]
+#[cfg(false)]
impl S {
fn f(#[attr]) {} //~ ERROR expected parameter name, found `)`
}
-#[cfg(FALSE)]
+#[cfg(false)]
impl T for S {
fn f(#[attr]) {} //~ ERROR expected parameter name, found `)`
}
-#[cfg(FALSE)]
+#[cfg(false)]
trait T {
fn f(#[attr]); //~ ERROR expected argument name, found `)`
}
diff --git a/tests/ui/rfcs/rfc-3467-unsafe-pinned/unsafe-pinned-hides-niche.rs b/tests/ui/rfcs/rfc-3467-unsafe-pinned/unsafe-pinned-hides-niche.rs
new file mode 100644
index 0000000..a1ff9a1
--- /dev/null
+++ b/tests/ui/rfcs/rfc-3467-unsafe-pinned/unsafe-pinned-hides-niche.rs
@@ -0,0 +1,29 @@
+//@ check-pass
+// this test ensures that UnsafePinned hides the niche of its inner type, just like UnsafeCell does
+
+#![crate_type = "lib"]
+#![feature(unsafe_pinned)]
+
+use std::num::NonZero;
+use std::pin::UnsafePinned;
+
+macro_rules! assert_size_is {
+ ($ty:ty = $size:expr) => {
+ const _: () = assert!(size_of::<$ty>() == $size);
+ };
+}
+
+assert_size_is!(UnsafePinned<()> = 0);
+assert_size_is!(UnsafePinned<u8> = 1);
+
+assert_size_is!( UnsafePinned< u32> = 4);
+assert_size_is!( UnsafePinned< NonZero<u32>> = 4);
+assert_size_is!( UnsafePinned<Option<NonZero<u32>>> = 4);
+assert_size_is!(Option<UnsafePinned< u32>> = 8);
+assert_size_is!(Option<UnsafePinned< NonZero<u32>>> = 8);
+assert_size_is!(Option<UnsafePinned<Option<NonZero<u32>>>> = 8);
+
+assert_size_is!( UnsafePinned< &()> = size_of::<usize>());
+assert_size_is!( UnsafePinned<Option<&()>> = size_of::<usize>());
+assert_size_is!(Option<UnsafePinned< &()>> = size_of::<usize>() * 2);
+assert_size_is!(Option<UnsafePinned<Option<&()>>> = size_of::<usize>() * 2);
diff --git a/tests/ui/runtime/backtrace-debuginfo-aux.rs b/tests/ui/runtime/backtrace-debuginfo-aux.rs
index 24180ed..4493fa5 100644
--- a/tests/ui/runtime/backtrace-debuginfo-aux.rs
+++ b/tests/ui/runtime/backtrace-debuginfo-aux.rs
@@ -1,5 +1,4 @@
-//@ run-pass
-//@ ignore-test: not a test, used by backtrace-debuginfo.rs to test file!()
+//@ ignore-auxiliary (used by `./backtrace-debuginfo.rs` to test `file!()`)
#[inline(never)]
pub fn callback<F>(f: F) where F: FnOnce((&'static str, u32)) {
diff --git a/tests/ui/runtime/rt-explody-panic-payloads.rs b/tests/ui/runtime/rt-explody-panic-payloads.rs
index c177fd2..d564a26 100644
--- a/tests/ui/runtime/rt-explody-panic-payloads.rs
+++ b/tests/ui/runtime/rt-explody-panic-payloads.rs
@@ -27,6 +27,6 @@ fn main() {
// by QEMU in the stderr whenever a core dump happens. Remove it before the check.
v.strip_suffix("qemu: uncaught target signal 6 (Aborted) - core dumped\n").unwrap_or(v)
})
- .map(|v| { v.ends_with("fatal runtime error: drop of the panic payload panicked\n") })
+ .map(|v| v.ends_with("fatal runtime error: drop of the panic payload panicked, aborting\n"))
.unwrap_or(false));
}
diff --git a/tests/ui/simd/intrinsic/generic-gather-pass.rs b/tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs
similarity index 100%
rename from tests/ui/simd/intrinsic/generic-gather-pass.rs
rename to tests/ui/simd/intrinsic/generic-gather-scatter-pass.rs
diff --git a/tests/ui/simd/intrinsic/generic-gather.rs b/tests/ui/simd/intrinsic/generic-gather-scatter.rs
similarity index 70%
rename from tests/ui/simd/intrinsic/generic-gather.rs
rename to tests/ui/simd/intrinsic/generic-gather-scatter.rs
index 118d802..c1de7fd 100644
--- a/tests/ui/simd/intrinsic/generic-gather.rs
+++ b/tests/ui/simd/intrinsic/generic-gather-scatter.rs
@@ -20,7 +20,6 @@ fn main() {
let s_strided = x4([0_f32, 2., -3., 6.]);
let mask = x4([-1_i32, -1, 0, -1]);
- let umask = x4([0u16; 4]);
let fmask = x4([0_f32; 4]);
let pointer = x.as_mut_ptr();
@@ -31,11 +30,8 @@ fn main() {
simd_gather(default, mask, mask);
//~^ ERROR expected element type `i32` of second argument `x4<i32>` to be a pointer to the element type `f32`
- simd_gather(default, pointers, umask);
- //~^ ERROR expected element type `u16` of third argument `x4<u16>` to be a signed integer type
-
simd_gather(default, pointers, fmask);
- //~^ ERROR expected element type `f32` of third argument `x4<f32>` to be a signed integer type
+ //~^ ERROR expected mask element type to be an integer, found `f32`
}
unsafe {
@@ -43,10 +39,7 @@ fn main() {
simd_scatter(values, mask, mask);
//~^ ERROR expected element type `i32` of second argument `x4<i32>` to be a pointer to the element type `f32` of the first argument `x4<f32>`, found `i32` != `*mut f32`
- simd_scatter(values, pointers, umask);
- //~^ ERROR expected element type `u16` of third argument `x4<u16>` to be a signed integer type
-
simd_scatter(values, pointers, fmask);
- //~^ ERROR expected element type `f32` of third argument `x4<f32>` to be a signed integer type
+ //~^ ERROR expected mask element type to be an integer, found `f32`
}
}
diff --git a/tests/ui/simd/intrinsic/generic-gather-scatter.stderr b/tests/ui/simd/intrinsic/generic-gather-scatter.stderr
new file mode 100644
index 0000000..e180667
--- /dev/null
+++ b/tests/ui/simd/intrinsic/generic-gather-scatter.stderr
@@ -0,0 +1,27 @@
+error[E0511]: invalid monomorphization of `simd_gather` intrinsic: expected element type `i32` of second argument `x4<i32>` to be a pointer to the element type `f32` of the first argument `x4<f32>`, found `i32` != `*_ f32`
+ --> $DIR/generic-gather-scatter.rs:30:9
+ |
+LL | simd_gather(default, mask, mask);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_gather` intrinsic: expected mask element type to be an integer, found `f32`
+ --> $DIR/generic-gather-scatter.rs:33:9
+ |
+LL | simd_gather(default, pointers, fmask);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_scatter` intrinsic: expected element type `i32` of second argument `x4<i32>` to be a pointer to the element type `f32` of the first argument `x4<f32>`, found `i32` != `*mut f32`
+ --> $DIR/generic-gather-scatter.rs:39:9
+ |
+LL | simd_scatter(values, mask, mask);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0511]: invalid monomorphization of `simd_scatter` intrinsic: expected mask element type to be an integer, found `f32`
+ --> $DIR/generic-gather-scatter.rs:42:9
+ |
+LL | simd_scatter(values, pointers, fmask);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0511`.
diff --git a/tests/ui/simd/intrinsic/generic-gather.stderr b/tests/ui/simd/intrinsic/generic-gather.stderr
deleted file mode 100644
index 81e10fc..0000000
--- a/tests/ui/simd/intrinsic/generic-gather.stderr
+++ /dev/null
@@ -1,39 +0,0 @@
-error[E0511]: invalid monomorphization of `simd_gather` intrinsic: expected element type `i32` of second argument `x4<i32>` to be a pointer to the element type `f32` of the first argument `x4<f32>`, found `i32` != `*_ f32`
- --> $DIR/generic-gather.rs:31:9
- |
-LL | simd_gather(default, mask, mask);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0511]: invalid monomorphization of `simd_gather` intrinsic: expected element type `u16` of third argument `x4<u16>` to be a signed integer type
- --> $DIR/generic-gather.rs:34:9
- |
-LL | simd_gather(default, pointers, umask);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0511]: invalid monomorphization of `simd_gather` intrinsic: expected element type `f32` of third argument `x4<f32>` to be a signed integer type
- --> $DIR/generic-gather.rs:37:9
- |
-LL | simd_gather(default, pointers, fmask);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0511]: invalid monomorphization of `simd_scatter` intrinsic: expected element type `i32` of second argument `x4<i32>` to be a pointer to the element type `f32` of the first argument `x4<f32>`, found `i32` != `*mut f32`
- --> $DIR/generic-gather.rs:43:9
- |
-LL | simd_scatter(values, mask, mask);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0511]: invalid monomorphization of `simd_scatter` intrinsic: expected element type `u16` of third argument `x4<u16>` to be a signed integer type
- --> $DIR/generic-gather.rs:46:9
- |
-LL | simd_scatter(values, pointers, umask);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0511]: invalid monomorphization of `simd_scatter` intrinsic: expected element type `f32` of third argument `x4<f32>` to be a signed integer type
- --> $DIR/generic-gather.rs:49:9
- |
-LL | simd_scatter(values, pointers, fmask);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 6 previous errors
-
-For more information about this error, try `rustc --explain E0511`.
diff --git a/tests/ui/simd/intrinsic/generic-select.rs b/tests/ui/simd/intrinsic/generic-select.rs
index db14032..924938f 100644
--- a/tests/ui/simd/intrinsic/generic-select.rs
+++ b/tests/ui/simd/intrinsic/generic-select.rs
@@ -36,11 +36,8 @@ fn main() {
simd_select(m8, x, x);
//~^ ERROR mismatched lengths: mask length `8` != other vector length `4`
- simd_select(x, x, x);
- //~^ ERROR mask element type is `u32`, expected a signed integer type
-
simd_select(z, z, z);
- //~^ ERROR mask element type is `f32`, expected a signed integer type
+ //~^ ERROR expected mask element type to be an integer, found `f32`
simd_select(m4, 0u32, 1u32);
//~^ ERROR found non-SIMD `u32`
diff --git a/tests/ui/simd/intrinsic/generic-select.stderr b/tests/ui/simd/intrinsic/generic-select.stderr
index b9af865..36b56ad 100644
--- a/tests/ui/simd/intrinsic/generic-select.stderr
+++ b/tests/ui/simd/intrinsic/generic-select.stderr
@@ -4,52 +4,42 @@
LL | simd_select(m8, x, x);
| ^^^^^^^^^^^^^^^^^^^^^
-error[E0511]: invalid monomorphization of `simd_select` intrinsic: found mask element type is `u32`, expected a signed integer type
+error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected mask element type to be an integer, found `f32`
--> $DIR/generic-select.rs:39:9
|
-LL | simd_select(x, x, x);
- | ^^^^^^^^^^^^^^^^^^^^
- |
- = note: the mask may be widened, which only has the correct behavior for signed integers
-
-error[E0511]: invalid monomorphization of `simd_select` intrinsic: found mask element type is `f32`, expected a signed integer type
- --> $DIR/generic-select.rs:42:9
- |
LL | simd_select(z, z, z);
| ^^^^^^^^^^^^^^^^^^^^
- |
- = note: the mask may be widened, which only has the correct behavior for signed integers
error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected SIMD argument type, found non-SIMD `u32`
- --> $DIR/generic-select.rs:45:9
+ --> $DIR/generic-select.rs:42:9
|
LL | simd_select(m4, 0u32, 1u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `u16`, expected `u8` or `[u8; 1]`
- --> $DIR/generic-select.rs:48:9
+ --> $DIR/generic-select.rs:45:9
|
LL | simd_select_bitmask(0u16, x, x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: expected SIMD argument type, found non-SIMD `u32`
- --> $DIR/generic-select.rs:51:9
+ --> $DIR/generic-select.rs:48:9
|
LL | simd_select_bitmask(0u8, 1u32, 2u32);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `f32`, expected `u8` or `[u8; 1]`
- --> $DIR/generic-select.rs:54:9
+ --> $DIR/generic-select.rs:51:9
|
LL | simd_select_bitmask(0.0f32, x, x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `&str`, expected `u8` or `[u8; 1]`
- --> $DIR/generic-select.rs:57:9
+ --> $DIR/generic-select.rs:54:9
|
LL | simd_select_bitmask("x", x, x);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 8 previous errors
+error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0511`.
diff --git a/tests/ui/simd/masked-load-store-build-fail.rs b/tests/ui/simd/masked-load-store-build-fail.rs
index ad2de55..4b6cc17 100644
--- a/tests/ui/simd/masked-load-store-build-fail.rs
+++ b/tests/ui/simd/masked-load-store-build-fail.rs
@@ -21,8 +21,8 @@ fn main() {
simd_masked_load(Simd::<i8, 4>([-1, 0, -1, -1]), arr.as_ptr(), Simd::<u32, 4>([9; 4]));
//~^ ERROR expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd<u32, 4>`, found `u32` != `*_ u32`
- simd_masked_load(Simd::<u8, 4>([1, 0, 1, 1]), arr.as_ptr(), default);
- //~^ ERROR expected element type `u8` of third argument `Simd<u8, 4>` to be a signed integer type
+ simd_masked_load(Simd::<f32, 4>([1.0, 0.0, 1.0, 1.0]), arr.as_ptr(), default);
+ //~^ ERROR expected mask element type to be an integer, found `f32`
simd_masked_store(Simd([-1i8; 4]), arr.as_ptr(), Simd([5u32; 4]));
//~^ ERROR expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd<u32, 4>`, found `u32` != `*mut u32`
@@ -33,7 +33,7 @@ fn main() {
simd_masked_store(Simd([-1i8; 4]), arr.as_mut_ptr(), Simd([5u8; 2]));
//~^ ERROR expected third argument with length 4 (same as input type `Simd<i8, 4>`), found `Simd<u8, 2>` with length 2
- simd_masked_store(Simd([1u32; 4]), arr.as_mut_ptr(), Simd([5u8; 4]));
- //~^ ERROR expected element type `u8` of third argument `Simd<u32, 4>` to be a signed integer type
+ simd_masked_store(Simd([1f32; 4]), arr.as_mut_ptr(), Simd([5u8; 4]));
+ //~^ ERROR expected mask element type to be an integer, found `f32`
}
}
diff --git a/tests/ui/simd/masked-load-store-build-fail.stderr b/tests/ui/simd/masked-load-store-build-fail.stderr
index d57e0aa..7f09841 100644
--- a/tests/ui/simd/masked-load-store-build-fail.stderr
+++ b/tests/ui/simd/masked-load-store-build-fail.stderr
@@ -16,11 +16,11 @@
LL | simd_masked_load(Simd::<i8, 4>([-1, 0, -1, -1]), arr.as_ptr(), Simd::<u32, 4>([9; 4]));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected element type `u8` of third argument `Simd<u8, 4>` to be a signed integer type
+error[E0511]: invalid monomorphization of `simd_masked_load` intrinsic: expected mask element type to be an integer, found `f32`
--> $DIR/masked-load-store-build-fail.rs:24:9
|
-LL | simd_masked_load(Simd::<u8, 4>([1, 0, 1, 1]), arr.as_ptr(), default);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | simd_masked_load(Simd::<f32, 4>([1.0, 0.0, 1.0, 1.0]), arr.as_ptr(), default);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected element type `u32` of second argument `*const u8` to be a pointer to the element type `u32` of the first argument `Simd<u32, 4>`, found `u32` != `*mut u32`
--> $DIR/masked-load-store-build-fail.rs:27:9
@@ -40,10 +40,10 @@
LL | simd_masked_store(Simd([-1i8; 4]), arr.as_mut_ptr(), Simd([5u8; 2]));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected element type `u8` of third argument `Simd<u32, 4>` to be a signed integer type
+error[E0511]: invalid monomorphization of `simd_masked_store` intrinsic: expected mask element type to be an integer, found `f32`
--> $DIR/masked-load-store-build-fail.rs:36:9
|
-LL | simd_masked_store(Simd([1u32; 4]), arr.as_mut_ptr(), Simd([5u8; 4]));
+LL | simd_masked_store(Simd([1f32; 4]), arr.as_mut_ptr(), Simd([5u8; 4]));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 8 previous errors
diff --git a/tests/ui/specialization/issue-63716-parse-async.rs b/tests/ui/specialization/issue-63716-parse-async.rs
index 3314b4e..00c0b29 100644
--- a/tests/ui/specialization/issue-63716-parse-async.rs
+++ b/tests/ui/specialization/issue-63716-parse-async.rs
@@ -8,7 +8,7 @@
fn main() {}
-#[cfg(FALSE)]
+#[cfg(false)]
impl Foo for Bar {
default async fn baz() {}
}
diff --git a/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr b/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr
index 92947e3..713b071 100644
--- a/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr
+++ b/tests/ui/suggestions/argument-list-from-path-sep-error-129273.stderr
@@ -4,7 +4,6 @@
LL | fn fmt(&self, f: &mut fmt:Formatter) -> fmt::Result {
| ^
|
- = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: use a double colon instead
|
LL | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
diff --git a/tests/ui/suggestions/const-no-type.rs b/tests/ui/suggestions/const-no-type.rs
index c6fdcda..b72ace9 100644
--- a/tests/ui/suggestions/const-no-type.rs
+++ b/tests/ui/suggestions/const-no-type.rs
@@ -10,19 +10,19 @@ fn main() {}
// These will not reach typeck:
-#[cfg(FALSE)]
+#[cfg(false)]
const C2 = 42;
//~^ ERROR missing type for `const` item
//~| HELP provide a type for the item
//~| SUGGESTION : <type>
-#[cfg(FALSE)]
+#[cfg(false)]
static S2 = "abc";
//~^ ERROR missing type for `static` item
//~| HELP provide a type for the item
//~| SUGGESTION : <type>
-#[cfg(FALSE)]
+#[cfg(false)]
static mut SM2 = "abc";
//~^ ERROR missing type for `static mut` item
//~| HELP provide a type for the item
diff --git a/tests/ui/suggestions/many-type-ascription.stderr b/tests/ui/suggestions/many-type-ascription.stderr
index feddc7d..47e19c5 100644
--- a/tests/ui/suggestions/many-type-ascription.stderr
+++ b/tests/ui/suggestions/many-type-ascription.stderr
@@ -3,8 +3,6 @@
|
LL | let _ = 0: i32;
| ^ expected one of `.`, `;`, `?`, `else`, or an operator
- |
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
error: aborting due to 1 previous error
diff --git a/tests/ui/suggestions/raw-c-string-prefix.rs b/tests/ui/suggestions/raw-c-string-prefix.rs
new file mode 100644
index 0000000..6af72df
--- /dev/null
+++ b/tests/ui/suggestions/raw-c-string-prefix.rs
@@ -0,0 +1,10 @@
+// `rc` and `cr` are easy to confuse; check that we issue a suggestion to help.
+
+//@ edition:2021
+
+fn main() {
+ rc"abc";
+ //~^ ERROR: prefix `rc` is unknown
+ //~| HELP: use `cr` for a raw C-string
+ //~| ERROR: expected one of
+}
diff --git a/tests/ui/suggestions/raw-c-string-prefix.stderr b/tests/ui/suggestions/raw-c-string-prefix.stderr
new file mode 100644
index 0000000..5341e3d
--- /dev/null
+++ b/tests/ui/suggestions/raw-c-string-prefix.stderr
@@ -0,0 +1,21 @@
+error: prefix `rc` is unknown
+ --> $DIR/raw-c-string-prefix.rs:6:5
+ |
+LL | rc"abc";
+ | ^^ unknown prefix
+ |
+ = note: prefixed identifiers and literals are reserved since Rust 2021
+help: use `cr` for a raw C-string
+ |
+LL - rc"abc";
+LL + cr"abc";
+ |
+
+error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `"abc"`
+ --> $DIR/raw-c-string-prefix.rs:6:7
+ |
+LL | rc"abc";
+ | ^^^^^ expected one of 8 possible tokens
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/suggestions/struct-field-type-including-single-colon.stderr b/tests/ui/suggestions/struct-field-type-including-single-colon.stderr
index ce16aca..b9302b0 100644
--- a/tests/ui/suggestions/struct-field-type-including-single-colon.stderr
+++ b/tests/ui/suggestions/struct-field-type-including-single-colon.stderr
@@ -4,7 +4,6 @@
LL | a: foo:A,
| ^
|
- = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: use a double colon instead
|
LL | a: foo::A,
@@ -16,7 +15,6 @@
LL | b: foo::bar:B,
| ^
|
- = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: use a double colon instead
|
LL | b: foo::bar::B,
diff --git a/tests/ui/suggestions/suggest-ref-mut.rs b/tests/ui/suggestions/suggest-ref-mut.rs
index 9f5df93..2a933f6 100644
--- a/tests/ui/suggestions/suggest-ref-mut.rs
+++ b/tests/ui/suggestions/suggest-ref-mut.rs
@@ -1,3 +1,5 @@
+//@ dont-require-annotations: SUGGESTION
+
struct X(usize);
impl X {
diff --git a/tests/ui/suggestions/suggest-ref-mut.stderr b/tests/ui/suggestions/suggest-ref-mut.stderr
index 935a04c..7c0899f 100644
--- a/tests/ui/suggestions/suggest-ref-mut.stderr
+++ b/tests/ui/suggestions/suggest-ref-mut.stderr
@@ -1,5 +1,5 @@
error[E0594]: cannot assign to `self.0`, which is behind a `&` reference
- --> $DIR/suggest-ref-mut.rs:7:9
+ --> $DIR/suggest-ref-mut.rs:9:9
|
LL | self.0 = 32;
| ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written
@@ -10,7 +10,7 @@
| +++
error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
- --> $DIR/suggest-ref-mut.rs:15:5
+ --> $DIR/suggest-ref-mut.rs:17:5
|
LL | *foo = 32;
| ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written
@@ -21,7 +21,7 @@
| +++
error[E0594]: cannot assign to `*bar`, which is behind a `&` reference
- --> $DIR/suggest-ref-mut.rs:19:9
+ --> $DIR/suggest-ref-mut.rs:21:9
|
LL | *bar = 32;
| ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written
@@ -32,7 +32,7 @@
| +++
error[E0594]: cannot assign to `*quo`, which is behind a `&` reference
- --> $DIR/suggest-ref-mut.rs:23:22
+ --> $DIR/suggest-ref-mut.rs:25:22
|
LL | ref quo => { *quo = 32; },
| ^^^^^^^^^ `quo` is a `&` reference, so the data it refers to cannot be written
diff --git a/tests/ui/suggestions/type-ascription-and-other-error.rs b/tests/ui/suggestions/type-ascription-and-other-error.rs
index 99ab2f3..da985b5 100644
--- a/tests/ui/suggestions/type-ascription-and-other-error.rs
+++ b/tests/ui/suggestions/type-ascription-and-other-error.rs
@@ -1,6 +1,6 @@
fn main() {
not rust; //~ ERROR
let _ = 0: i32; // (error hidden by existing error)
- #[cfg(FALSE)]
+ #[cfg(false)]
let _ = 0: i32; // (warning hidden by existing error)
}
diff --git a/tests/ui/suggestions/type-ascription-instead-of-method.stderr b/tests/ui/suggestions/type-ascription-instead-of-method.stderr
index 0bef1c1..6dc7b5e 100644
--- a/tests/ui/suggestions/type-ascription-instead-of-method.stderr
+++ b/tests/ui/suggestions/type-ascription-instead-of-method.stderr
@@ -4,7 +4,6 @@
LL | let _ = Box:new("foo".to_string());
| ^
|
- = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: use a double colon instead
|
LL | let _ = Box::new("foo".to_string());
diff --git a/tests/ui/suggestions/type-ascription-instead-of-path-2.stderr b/tests/ui/suggestions/type-ascription-instead-of-path-2.stderr
index 0b37bf9..79dffc0 100644
--- a/tests/ui/suggestions/type-ascription-instead-of-path-2.stderr
+++ b/tests/ui/suggestions/type-ascription-instead-of-path-2.stderr
@@ -4,7 +4,6 @@
LL | let _ = vec![Ok(2)].into_iter().collect:<Result<Vec<_>,_>>()?;
| ^ expected one of 7 possible tokens
|
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: maybe write a path separator here
|
LL | let _ = vec![Ok(2)].into_iter().collect::<Result<Vec<_>,_>>()?;
diff --git a/tests/ui/suggestions/type-ascription-instead-of-path.stderr b/tests/ui/suggestions/type-ascription-instead-of-path.stderr
index 8c16acf..a836461 100644
--- a/tests/ui/suggestions/type-ascription-instead-of-path.stderr
+++ b/tests/ui/suggestions/type-ascription-instead-of-path.stderr
@@ -4,7 +4,6 @@
LL | std:io::stdin();
| ^
|
- = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: use a double colon instead
|
LL | std::io::stdin();
diff --git a/tests/ui/suggestions/type-ascription-instead-of-variant.stderr b/tests/ui/suggestions/type-ascription-instead-of-variant.stderr
index f0b3172..e836b37 100644
--- a/tests/ui/suggestions/type-ascription-instead-of-variant.stderr
+++ b/tests/ui/suggestions/type-ascription-instead-of-variant.stderr
@@ -4,7 +4,6 @@
LL | let _ = Option:Some("");
| ^
|
- = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: use a double colon instead
|
LL | let _ = Option::Some("");
diff --git a/tests/ui/amdgpu-require-explicit-cpu.nocpu.stderr b/tests/ui/target-cpu/explicit-target-cpu.amdgcn_nocpu.stderr
similarity index 100%
rename from tests/ui/amdgpu-require-explicit-cpu.nocpu.stderr
rename to tests/ui/target-cpu/explicit-target-cpu.amdgcn_nocpu.stderr
diff --git a/tests/ui/amdgpu-require-explicit-cpu.nocpu.stderr b/tests/ui/target-cpu/explicit-target-cpu.avr_nocpu.stderr
similarity index 100%
copy from tests/ui/amdgpu-require-explicit-cpu.nocpu.stderr
copy to tests/ui/target-cpu/explicit-target-cpu.avr_nocpu.stderr
diff --git a/tests/ui/target-cpu/explicit-target-cpu.rs b/tests/ui/target-cpu/explicit-target-cpu.rs
new file mode 100644
index 0000000..cd4c238
--- /dev/null
+++ b/tests/ui/target-cpu/explicit-target-cpu.rs
@@ -0,0 +1,37 @@
+//! Check that certain target *requires* the user to specify a target CPU via `-C target-cpu`.
+
+//@ revisions: amdgcn_nocpu amdgcn_cpu
+
+//@[amdgcn_nocpu] compile-flags: --target=amdgcn-amd-amdhsa
+//@[amdgcn_nocpu] needs-llvm-components: amdgpu
+//@[amdgcn_nocpu] build-fail
+
+//@[amdgcn_cpu] compile-flags: --target=amdgcn-amd-amdhsa
+//@[amdgcn_cpu] needs-llvm-components: amdgpu
+//@[amdgcn_cpu] compile-flags: -Ctarget-cpu=gfx900
+//@[amdgcn_cpu] build-pass
+
+//@ revisions: avr_nocpu avr_cpu
+
+//@[avr_nocpu] compile-flags: --target=avr-none
+//@[avr_nocpu] needs-llvm-components: avr
+//@[avr_nocpu] build-fail
+
+//@[avr_cpu] compile-flags: --target=avr-none
+//@[avr_cpu] needs-llvm-components: avr
+//@[avr_cpu] compile-flags: -Ctarget-cpu=atmega328p
+//@[avr_cpu] build-pass
+
+#![crate_type = "rlib"]
+
+// FIXME(#140038): this can't use `minicore` yet because `minicore` doesn't currently propagate the
+// `-C target-cpu` for targets that *require* a `target-cpu` being specified.
+#![feature(no_core, lang_items)]
+#![no_core]
+
+#[lang="sized"]
+trait Sized {}
+
+pub fn foo() {}
+
+//[amdgcn_nocpu,avr_nocpu]~? ERROR target requires explicitly specifying a cpu with `-C target-cpu`
diff --git a/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs b/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs
index fda0b1c..d394dbe 100644
--- a/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs
+++ b/tests/ui/target-feature/forbidden-target-feature-flag-disable.rs
@@ -4,7 +4,7 @@
//@ compile-flags: -Ctarget-feature=-forced-atomics
// For now this is just a warning.
//@ build-pass
-//@error-pattern: unsound because it changes the ABI
+
#![feature(no_core, lang_items)]
#![no_core]
diff --git a/tests/ui/target-feature/tied-features-no-implication-1.rs b/tests/ui/target-feature/tied-features-no-implication-1.rs
index 0a98a7e..63a1d77 100644
--- a/tests/ui/target-feature/tied-features-no-implication-1.rs
+++ b/tests/ui/target-feature/tied-features-no-implication-1.rs
@@ -2,9 +2,7 @@
//@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu
//@ needs-llvm-components: aarch64
//@[paca] compile-flags: -Ctarget-feature=+paca
-//@[paca] error-pattern: the target features paca, pacg must all be either enabled or disabled together
//@[pacg] compile-flags: -Ctarget-feature=+pacg
-//@[paca] error-pattern: the target features paca, pacg must all be either enabled or disabled together
#![feature(no_core, lang_items)]
#![no_core]
diff --git a/tests/ui/test-attrs/test-should-panic-failed-show-span.rs b/tests/ui/test-attrs/test-should-panic-failed-show-span.rs
new file mode 100644
index 0000000..f400f61
--- /dev/null
+++ b/tests/ui/test-attrs/test-should-panic-failed-show-span.rs
@@ -0,0 +1,46 @@
+//@ compile-flags: --test
+//@ run-flags: --test-threads=1 --nocapture
+//@ run-fail
+//@ check-run-results
+//@ exec-env:RUST_BACKTRACE=0
+//@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME"
+//@ normalize-stdout: "TypeId\(0x[0-9a-f]+\)" -> "TypeId($$HEX)"
+//@ needs-threads
+//@ needs-unwind (panic)
+
+#[test]
+#[should_panic]
+fn should_panic_with_any_message() {
+ panic!("Panic!");
+}
+
+#[test]
+#[should_panic = "message"]
+fn should_panic_with_message() {
+ panic!("message");
+}
+
+#[test]
+#[should_panic]
+fn should_panic_with_any_message_does_not_panic() {
+ // DON'T PANIC
+}
+
+#[test]
+#[should_panic = "message"]
+fn should_panic_with_message_does_not_panic() {
+ // DON'T PANIC
+}
+
+#[test]
+#[should_panic = "message"]
+fn should_panic_with_substring_panics_with_incorrect_string() {
+ panic!("ZOMGWTFBBQ");
+}
+
+#[test]
+#[should_panic = "message"]
+#[expect(non_fmt_panics)]
+fn should_panic_with_substring_panics_with_non_string_value() {
+ panic!(123);
+}
diff --git a/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stderr b/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stderr
new file mode 100644
index 0000000..db379a1
--- /dev/null
+++ b/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stderr
@@ -0,0 +1,13 @@
+
+thread 'should_panic_with_any_message' panicked at $DIR/test-should-panic-failed-show-span.rs:14:5:
+Panic!
+note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
+
+thread 'should_panic_with_message' panicked at $DIR/test-should-panic-failed-show-span.rs:20:5:
+message
+
+thread 'should_panic_with_substring_panics_with_incorrect_string' panicked at $DIR/test-should-panic-failed-show-span.rs:38:5:
+ZOMGWTFBBQ
+
+thread 'should_panic_with_substring_panics_with_non_string_value' panicked at $DIR/test-should-panic-failed-show-span.rs:45:5:
+Box<dyn Any>
diff --git a/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stdout b/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stdout
new file mode 100644
index 0000000..75600b4
--- /dev/null
+++ b/tests/ui/test-attrs/test-should-panic-failed-show-span.run.stdout
@@ -0,0 +1,32 @@
+
+running 6 tests
+test should_panic_with_any_message - should panic ... ok
+test should_panic_with_any_message_does_not_panic - should panic ... FAILED
+test should_panic_with_message - should panic ... ok
+test should_panic_with_message_does_not_panic - should panic ... FAILED
+test should_panic_with_substring_panics_with_incorrect_string - should panic ... FAILED
+test should_panic_with_substring_panics_with_non_string_value - should panic ... FAILED
+
+failures:
+
+---- should_panic_with_any_message_does_not_panic stdout ----
+note: test did not panic as expected at $DIR/test-should-panic-failed-show-span.rs:25:4
+---- should_panic_with_message_does_not_panic stdout ----
+note: test did not panic as expected at $DIR/test-should-panic-failed-show-span.rs:31:4
+---- should_panic_with_substring_panics_with_incorrect_string stdout ----
+note: panic did not contain expected string
+ panic message: `"ZOMGWTFBBQ"`,
+ expected substring: `"message"`
+---- should_panic_with_substring_panics_with_non_string_value stdout ----
+note: expected panic with string value,
+ found non-string value: `TypeId($HEX)`
+ expected substring: `"message"`
+
+failures:
+ should_panic_with_any_message_does_not_panic
+ should_panic_with_message_does_not_panic
+ should_panic_with_substring_panics_with_incorrect_string
+ should_panic_with_substring_panics_with_non_string_value
+
+test result: FAILED. 2 passed; 4 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME
+
diff --git a/tests/ui/traits/associated_type_bound/hrtb-associated.rs b/tests/ui/traits/associated_type_bound/hrtb-associated.rs
new file mode 100644
index 0000000..59e5a09
--- /dev/null
+++ b/tests/ui/traits/associated_type_bound/hrtb-associated.rs
@@ -0,0 +1,30 @@
+//@ check-pass
+//! This test ensures that HRTB (higher-ranked trait bounds) on associated types
+//! compile correctly. This was previously rejected by the compiler.
+//! Related issue: <https://github.com/rust-lang/rust/issues/34834>
+
+pub trait Provides<'a> {
+ type Item;
+}
+
+pub trait Selector: for<'a> Provides<'a> {
+ type Namespace: PartialEq + for<'a> PartialEq<<Self as Provides<'a>>::Item>;
+
+ fn get_namespace(&self) -> <Self as Provides>::Item;
+}
+
+pub struct MySelector;
+
+impl<'a> Provides<'a> for MySelector {
+ type Item = &'a str;
+}
+
+impl Selector for MySelector {
+ type Namespace = String;
+
+ fn get_namespace(&self) -> &str {
+ unimplemented!()
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/traits/deep-norm-pending.rs b/tests/ui/traits/deep-norm-pending.rs
new file mode 100644
index 0000000..f56c3cf
--- /dev/null
+++ b/tests/ui/traits/deep-norm-pending.rs
@@ -0,0 +1,24 @@
+trait Foo {
+ type Assoc;
+}
+
+trait Bar {
+ fn method() -> impl Sized;
+ //~^ ERROR the trait bound `T: Foo` is not satisfied
+}
+impl<T> Bar for T
+//~^ ERROR the trait bound `T: Foo` is not satisfied
+//~| ERROR the trait bound `T: Foo` is not satisfied
+where
+ <T as Foo>::Assoc: Sized,
+{
+ fn method() {}
+ //~^ ERROR the trait bound `T: Foo` is not satisfied
+ //~| ERROR the trait bound `T: Foo` is not satisfied
+ //~| ERROR the trait bound `T: Foo` is not satisfied
+ //~| ERROR the trait bound `T: Foo` is not satisfied
+ //~| ERROR the trait bound `T: Foo` is not satisfied
+ //~| ERROR the trait bound `T: Foo` is not satisfied
+}
+
+fn main() {}
diff --git a/tests/ui/traits/deep-norm-pending.stderr b/tests/ui/traits/deep-norm-pending.stderr
new file mode 100644
index 0000000..b95b9d7
--- /dev/null
+++ b/tests/ui/traits/deep-norm-pending.stderr
@@ -0,0 +1,130 @@
+error[E0277]: the trait bound `T: Foo` is not satisfied
+ --> $DIR/deep-norm-pending.rs:15:5
+ |
+LL | fn method() {}
+ | ^^^^^^^^^^^ the trait `Foo` is not implemented for `T`
+ |
+help: consider further restricting type parameter `T` with trait `Foo`
+ |
+LL | <T as Foo>::Assoc: Sized, T: Foo
+ | ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+ --> $DIR/deep-norm-pending.rs:9:1
+ |
+LL | / impl<T> Bar for T
+LL | |
+LL | |
+LL | | where
+LL | | <T as Foo>::Assoc: Sized,
+ | |_____________________________^ the trait `Foo` is not implemented for `T`
+ |
+help: consider further restricting type parameter `T` with trait `Foo`
+ |
+LL | <T as Foo>::Assoc: Sized, T: Foo
+ | ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+ --> $DIR/deep-norm-pending.rs:9:1
+ |
+LL | / impl<T> Bar for T
+LL | |
+LL | |
+LL | | where
+... |
+LL | | }
+ | |_^ the trait `Foo` is not implemented for `T`
+ |
+help: consider further restricting type parameter `T` with trait `Foo`
+ |
+LL | <T as Foo>::Assoc: Sized, T: Foo
+ | ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+ --> $DIR/deep-norm-pending.rs:15:5
+ |
+LL | fn method() {}
+ | ^^^^^^^^^^^ the trait `Foo` is not implemented for `T`
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: consider further restricting type parameter `T` with trait `Foo`
+ |
+LL | <T as Foo>::Assoc: Sized, T: Foo
+ | ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+ --> $DIR/deep-norm-pending.rs:15:5
+ |
+LL | fn method() {}
+ | ^^^^^^^^^^^ the trait `Foo` is not implemented for `T`
+ |
+note: required for `T` to implement `Bar`
+ --> $DIR/deep-norm-pending.rs:9:9
+ |
+LL | impl<T> Bar for T
+ | ^^^ ^
+...
+LL | <T as Foo>::Assoc: Sized,
+ | ----- unsatisfied trait bound introduced here
+help: consider further restricting type parameter `T` with trait `Foo`
+ |
+LL | <T as Foo>::Assoc: Sized, T: Foo
+ | ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+ --> $DIR/deep-norm-pending.rs:15:5
+ |
+LL | fn method() {}
+ | ^^^^^^^^^^^ the trait `Foo` is not implemented for `T`
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: consider further restricting type parameter `T` with trait `Foo`
+ |
+LL | <T as Foo>::Assoc: Sized, T: Foo
+ | ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+ --> $DIR/deep-norm-pending.rs:6:20
+ |
+LL | fn method() -> impl Sized;
+ | ^^^^^^^^^^ the trait `Foo` is not implemented for `T`
+ |
+note: required for `T` to implement `Bar`
+ --> $DIR/deep-norm-pending.rs:9:9
+ |
+LL | impl<T> Bar for T
+ | ^^^ ^
+...
+LL | <T as Foo>::Assoc: Sized,
+ | ----- unsatisfied trait bound introduced here
+help: consider further restricting type parameter `T` with trait `Foo`
+ |
+LL | <T as Foo>::Assoc: Sized, T: Foo
+ | ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+ --> $DIR/deep-norm-pending.rs:15:5
+ |
+LL | fn method() {}
+ | ^^^^^^^^^^^ the trait `Foo` is not implemented for `T`
+ |
+ = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+help: consider further restricting type parameter `T` with trait `Foo`
+ |
+LL | <T as Foo>::Assoc: Sized, T: Foo
+ | ++++++
+
+error[E0277]: the trait bound `T: Foo` is not satisfied
+ --> $DIR/deep-norm-pending.rs:15:8
+ |
+LL | fn method() {}
+ | ^^^^^^ the trait `Foo` is not implemented for `T`
+ |
+help: consider further restricting type parameter `T` with trait `Foo`
+ |
+LL | <T as Foo>::Assoc: Sized, T: Foo
+ | ++++++
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs
index b0c778e..754fc87 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs
+++ b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.rs
@@ -34,9 +34,17 @@ impl Trait for MultipleCandidates
MultipleNested: Trait,
{}
+// We ignore the trivially true global where-bounds when checking that this
+// impl is well-formed, meaning that we depend on `MultipleNested: Trait` when
+// recursively proving `MultipleCandidates: Trait`.
+//
+// These overflow errors will disappear once we treat these cycles as either
+// productive or an error.
impl Trait for MultipleNested
+//~^ ERROR overflow evaluating the requirement `MultipleNested: Trait`
where
MultipleCandidates: Trait,
+ //~^ ERROR overflow evaluating the requirement `MultipleCandidates: Trait`
DoesNotImpl: Trait,
{}
diff --git a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr
index acacaf6..7895a26 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr
+++ b/tests/ui/traits/next-solver/cycles/inductive-cycle-but-err.stderr
@@ -1,16 +1,29 @@
+error[E0275]: overflow evaluating the requirement `MultipleNested: Trait`
+ --> $DIR/inductive-cycle-but-err.rs:43:16
+ |
+LL | impl Trait for MultipleNested
+ | ^^^^^^^^^^^^^^
+
+error[E0275]: overflow evaluating the requirement `MultipleCandidates: Trait`
+ --> $DIR/inductive-cycle-but-err.rs:46:25
+ |
+LL | MultipleCandidates: Trait,
+ | ^^^^^
+
error[E0277]: the trait bound `MultipleCandidates: Trait` is not satisfied
- --> $DIR/inductive-cycle-but-err.rs:46:19
+ --> $DIR/inductive-cycle-but-err.rs:54:19
|
LL | impls_trait::<MultipleCandidates>();
| ^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `MultipleCandidates`
|
= help: the trait `Trait` is implemented for `MultipleCandidates`
note: required by a bound in `impls_trait`
- --> $DIR/inductive-cycle-but-err.rs:43:19
+ --> $DIR/inductive-cycle-but-err.rs:51:19
|
LL | fn impls_trait<T: Trait>() {}
| ^^^^^ required by this bound in `impls_trait`
-error: aborting due to 1 previous error
+error: aborting due to 3 previous errors
-For more information about this error, try `rustc --explain E0277`.
+Some errors have detailed explanations: E0275, E0277.
+For more information about an error, try `rustc --explain E0275`.
diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive-2.rs b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive-2.rs
new file mode 100644
index 0000000..bb3540f
--- /dev/null
+++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive-2.rs
@@ -0,0 +1,24 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+
+// Regression test for trait-system-refactor-initiative#176.
+//
+// Normalizing `<Vec<T> as IntoIterator>::IntoIter` has two candidates
+// inside of the function:
+// - `impl<T> IntoIterator for Vec<T>` which trivially applies
+// - `impl<I: Iterator> IntoIterator for I`
+// - requires `Vec<T>: Iterator`
+// - where-clause requires `<Vec<T> as IntoIterator>::IntoIter eq Vec<T>`
+// - normalize `<Vec<T> as IntoIterator>::IntoIter` again, cycle
+//
+// We need to treat this cycle as an error to be able to use the actual impl.
+
+fn test<T>()
+where
+ <Vec<T> as IntoIterator>::IntoIter: Iterator,
+{
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.current.stderr b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.current.stderr
new file mode 100644
index 0000000..0a5b90f
--- /dev/null
+++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.current.stderr
@@ -0,0 +1,48 @@
+error[E0277]: the trait bound `Foo: Bound` is not satisfied
+ --> $DIR/normalizes-to-is-not-productive.rs:41:1
+ |
+LL | / fn generic<T>()
+LL | | where
+LL | | <Foo as Trait<T>>::Assoc: Bound,
+ | |____________________________________^ the trait `Bound` is not implemented for `Foo`
+ |
+ = help: the trait `Bound` is implemented for `u32`
+note: required for `Foo` to implement `Trait<T>`
+ --> $DIR/normalizes-to-is-not-productive.rs:24:19
+ |
+LL | impl<T: Bound, U> Trait<U> for T {
+ | ----- ^^^^^^^^ ^
+ | |
+ | unsatisfied trait bound introduced here
+
+error[E0277]: the trait bound `Foo: Bound` is not satisfied
+ --> $DIR/normalizes-to-is-not-productive.rs:41:4
+ |
+LL | fn generic<T>()
+ | ^^^^^^^ the trait `Bound` is not implemented for `Foo`
+ |
+ = help: the trait `Bound` is implemented for `u32`
+note: required for `Foo` to implement `Trait<T>`
+ --> $DIR/normalizes-to-is-not-productive.rs:24:19
+ |
+LL | impl<T: Bound, U> Trait<U> for T {
+ | ----- ^^^^^^^^ ^
+ | |
+ | unsatisfied trait bound introduced here
+
+error[E0277]: the trait bound `Foo: Bound` is not satisfied
+ --> $DIR/normalizes-to-is-not-productive.rs:48:19
+ |
+LL | impls_bound::<Foo>();
+ | ^^^ the trait `Bound` is not implemented for `Foo`
+ |
+ = help: the trait `Bound` is implemented for `u32`
+note: required by a bound in `impls_bound`
+ --> $DIR/normalizes-to-is-not-productive.rs:28:19
+ |
+LL | fn impls_bound<T: Bound>() {
+ | ^^^^^ required by this bound in `impls_bound`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.next.stderr b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.next.stderr
new file mode 100644
index 0000000..d888fbf
--- /dev/null
+++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.next.stderr
@@ -0,0 +1,31 @@
+error[E0277]: the trait bound `Foo: Bound` is not satisfied
+ --> $DIR/normalizes-to-is-not-productive.rs:43:31
+ |
+LL | <Foo as Trait<T>>::Assoc: Bound,
+ | ^^^^^ the trait `Bound` is not implemented for `Foo`
+ |
+ = help: the trait `Bound` is implemented for `u32`
+note: required for `Foo` to implement `Trait<T>`
+ --> $DIR/normalizes-to-is-not-productive.rs:24:19
+ |
+LL | impl<T: Bound, U> Trait<U> for T {
+ | ----- ^^^^^^^^ ^
+ | |
+ | unsatisfied trait bound introduced here
+
+error[E0277]: the trait bound `Foo: Bound` is not satisfied
+ --> $DIR/normalizes-to-is-not-productive.rs:48:19
+ |
+LL | impls_bound::<Foo>();
+ | ^^^ the trait `Bound` is not implemented for `Foo`
+ |
+ = help: the trait `Bound` is implemented for `u32`
+note: required by a bound in `impls_bound`
+ --> $DIR/normalizes-to-is-not-productive.rs:28:19
+ |
+LL | fn impls_bound<T: Bound>() {
+ | ^^^^^ required by this bound in `impls_bound`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.rs b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.rs
new file mode 100644
index 0000000..ffbbeca
--- /dev/null
+++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.rs
@@ -0,0 +1,54 @@
+//@ ignore-compare-mode-next-solver (explicit)
+//@ compile-flags: -Znext-solver
+
+// Make sure that stepping into impl where-clauses of `NormalizesTo`
+// goals is unproductive. This must not compile, see the inline
+// comments.
+
+trait Bound {
+ fn method();
+}
+impl Bound for u32 {
+ fn method() {}
+}
+trait Trait<T> {
+ type Assoc: Bound;
+}
+
+struct Foo;
+
+impl Trait<u32> for Foo {
+ type Assoc = u32;
+}
+impl<T: Bound, U> Trait<U> for T {
+ type Assoc = T;
+}
+
+fn impls_bound<T: Bound>() {
+ T::method();
+}
+
+// The where-clause requires `Foo: Trait<T>` to hold to be wf.
+// If stepping into where-clauses during normalization is considered
+// to be productive, this would be the case:
+//
+// - `Foo: Trait<T>`
+// - via blanket impls, requires `Foo: Bound`
+// - via where-bound, requires `Foo eq <Foo as Trait<T>>::Assoc`
+// - normalize `<Foo as Trait<T>>::Assoc`
+// - via blanket impl, requires where-clause `Foo: Bound` -> cycle
+fn generic<T>()
+where
+ <Foo as Trait<T>>::Assoc: Bound,
+ //~^ ERROR the trait bound `Foo: Bound` is not satisfied
+{
+ // Requires proving `Foo: Bound` by normalizing
+ // `<Foo as Trait<T>>::Assoc` to `Foo`.
+ impls_bound::<Foo>();
+ //~^ ERROR the trait bound `Foo: Bound` is not satisfied
+}
+fn main() {
+ // Requires proving `<Foo as Trait<u32>>::Assoc: Bound`.
+ // This is trivially true.
+ generic::<u32>();
+}
diff --git a/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr
new file mode 100644
index 0000000..8901805
--- /dev/null
+++ b/tests/ui/traits/next-solver/cycles/normalizes-to-is-not-productive.stderr
@@ -0,0 +1,31 @@
+error[E0277]: the trait bound `Foo: Bound` is not satisfied
+ --> $DIR/normalizes-to-is-not-productive.rs:42:31
+ |
+LL | <Foo as Trait<T>>::Assoc: Bound,
+ | ^^^^^ the trait `Bound` is not implemented for `Foo`
+ |
+ = help: the trait `Bound` is implemented for `u32`
+note: required for `Foo` to implement `Trait<T>`
+ --> $DIR/normalizes-to-is-not-productive.rs:23:19
+ |
+LL | impl<T: Bound, U> Trait<U> for T {
+ | ----- ^^^^^^^^ ^
+ | |
+ | unsatisfied trait bound introduced here
+
+error[E0277]: the trait bound `Foo: Bound` is not satisfied
+ --> $DIR/normalizes-to-is-not-productive.rs:47:19
+ |
+LL | impls_bound::<Foo>();
+ | ^^^ the trait `Bound` is not implemented for `Foo`
+ |
+ = help: the trait `Bound` is implemented for `u32`
+note: required by a bound in `impls_bound`
+ --> $DIR/normalizes-to-is-not-productive.rs:27:19
+ |
+LL | fn impls_bound<T: Bound>() {
+ | ^^^^^ required by this bound in `impls_bound`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr
index 74a0a90..d179c80 100644
--- a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr
+++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr
@@ -4,14 +4,14 @@
LL | Self::Assoc: A<T>,
| ^^^^
|
-note: the requirement `<() as A<T>>::Assoc: A<T>` appears on the `impl`'s method `f` but not on the corresponding trait's method
+note: the requirement `<() as A<T>>::Assoc: A<T>` appears on the `impl`'s associated function `f` but not on the corresponding trait's associated function
--> $DIR/normalize-param-env-2.rs:12:8
|
LL | trait A<T> {
| - in this trait
...
LL | fn f()
- | ^ this trait's method doesn't have the requirement `<() as A<T>>::Assoc: A<T>`
+ | ^ this trait's associated function doesn't have the requirement `<() as A<T>>::Assoc: A<T>`
error[E0275]: overflow evaluating the requirement `<() as A<T>>::Assoc: A<T>`
--> $DIR/normalize-param-env-2.rs:24:22
diff --git a/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs b/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs
index 11a2617..3ef6bea 100644
--- a/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs
+++ b/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs
@@ -1,5 +1,5 @@
//@ compile-flags: -Znext-solver
-//@ ignore-test
+//@ ignore-test (see #114196)
trait Trait {
type Gat<'lt>;
diff --git a/tests/ui/traits/next-solver/rpitit-cycle-due-to-rigid.rs b/tests/ui/traits/next-solver/rpitit-cycle-due-to-rigid.rs
new file mode 100644
index 0000000..ec3d710
--- /dev/null
+++ b/tests/ui/traits/next-solver/rpitit-cycle-due-to-rigid.rs
@@ -0,0 +1,32 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+//@ edition: 2024
+
+// Ensure we don't end up in a query cycle due to trying to assemble an impl candidate
+// for an RPITIT normalizes-to goal, even though that impl candidate would *necessarily*
+// be made rigid by a where clause. This query cycle is thus avoidable by not assembling
+// that impl candidate which we *know* we are going to throw away anyways.
+
+use std::future::Future;
+
+pub trait ReactiveFunction: Send {
+ type Output;
+
+ fn invoke(self) -> Self::Output;
+}
+
+trait AttributeValue {
+ fn resolve(self) -> impl Future<Output = ()> + Send;
+}
+
+impl<F, V> AttributeValue for F
+where
+ F: ReactiveFunction<Output = V>,
+ V: AttributeValue,
+{
+ async fn resolve(self) {
+ self.invoke().resolve().await
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/supertrait-alias-1.rs b/tests/ui/traits/next-solver/supertrait-alias-1.rs
new file mode 100644
index 0000000..579a446
--- /dev/null
+++ b/tests/ui/traits/next-solver/supertrait-alias-1.rs
@@ -0,0 +1,22 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/171>.
+// Tests that we don't try to replace `<V as Super>::Output` when replacing projections in the
+// required bounds for `dyn Trait`, b/c `V` is not relevant to the dyn type, which we were
+// previously encountering b/c we were walking into the existential projection bounds of the dyn
+// type itself.
+
+pub trait Trait: Super {}
+
+pub trait Super {
+ type Output;
+}
+
+fn bound<T: Trait + ?Sized>() {}
+
+fn visit_simd_operator<V: Super + ?Sized>() {
+ bound::<dyn Trait<Output = <V as Super>::Output>>();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/supertrait-alias-2.rs b/tests/ui/traits/next-solver/supertrait-alias-2.rs
new file mode 100644
index 0000000..a0f3e03
--- /dev/null
+++ b/tests/ui/traits/next-solver/supertrait-alias-2.rs
@@ -0,0 +1,25 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/171>.
+// Tests that we don't try to replace `<T as Other>::Assoc` when replacing projections in the
+// required bounds for `dyn Foo`, b/c `T` is not relevant to the dyn type, which we were
+// encountering when walking through the elaborated supertraits of `dyn Foo`.
+
+trait Other<X> {}
+
+trait Foo<T: Foo<T>>: Other<<T as Foo<T>>::Assoc> {
+ type Assoc;
+}
+
+impl<T> Foo<T> for T {
+ type Assoc = ();
+}
+
+impl<T: ?Sized> Other<()> for T {}
+
+fn is_foo<T: Foo<()> + ?Sized>() {}
+
+fn main() {
+ is_foo::<dyn Foo<(), Assoc = ()>>();
+}
diff --git a/tests/ui/traits/next-solver/supertrait-alias-3.rs b/tests/ui/traits/next-solver/supertrait-alias-3.rs
new file mode 100644
index 0000000..78182bb
--- /dev/null
+++ b/tests/ui/traits/next-solver/supertrait-alias-3.rs
@@ -0,0 +1,32 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+// Regression test for <https://github.com/rust-lang/trait-system-refactor-initiative/issues/171>.
+// Exercises a case where structural equality is insufficient when replacing projections in a dyn's
+// bounds. In this case, the bound will contain `<Self as Super<<i32 as Mirror>:Assoc>::Assoc`, but
+// the existential projections from the dyn will have `<Self as Super<i32>>::Assoc` because as an
+// optimization we eagerly normalize aliases in goals.
+
+trait Other<T> {}
+impl<T> Other<T> for T {}
+
+trait Super<T> {
+ type Assoc;
+}
+
+trait Mirror {
+ type Assoc;
+}
+impl<T> Mirror for T {
+ type Assoc = T;
+}
+
+trait Foo<A, B>: Super<<A as Mirror>::Assoc, Assoc = A> {
+ type FooAssoc: Other<<Self as Super<<A as Mirror>::Assoc>>::Assoc>;
+}
+
+fn is_foo<F: Foo<T, U> + ?Sized, T, U>() {}
+
+fn main() {
+ is_foo::<dyn Foo<i32, u32, FooAssoc = i32>, _, _>();
+}
diff --git a/tests/ui/traits/next-solver/supertrait-alias-4.rs b/tests/ui/traits/next-solver/supertrait-alias-4.rs
new file mode 100644
index 0000000..919a768
--- /dev/null
+++ b/tests/ui/traits/next-solver/supertrait-alias-4.rs
@@ -0,0 +1,24 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+// Exercises the ambiguity that comes from replacing the associated types within the bounds
+// that are required for a `impl Trait for dyn Trait` built-in object impl to hold.
+
+trait Sup<T> {
+ type Assoc;
+}
+
+trait Foo<A, B>: Sup<A, Assoc = A> + Sup<B, Assoc = B> {
+ type Other: Bar<<Self as Sup<A>>::Assoc>;
+}
+
+trait Bar<T> {}
+impl Bar<i32> for () {}
+
+fn foo<A, B>(x: &(impl Foo<A, B> + ?Sized)) {}
+
+fn main() {
+ let x: &dyn Foo<_, _, Other = ()> = todo!();
+ foo(x);
+ let y: &dyn Foo<i32, u32, Other = ()> = x;
+}
diff --git a/tests/ui/traits/winnowing/global-where-bound-region-constraints-2.rs b/tests/ui/traits/winnowing/global-where-bound-region-constraints-2.rs
new file mode 100644
index 0000000..d422605
--- /dev/null
+++ b/tests/ui/traits/winnowing/global-where-bound-region-constraints-2.rs
@@ -0,0 +1,33 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+
+// Regression test for trait-system-refactor-initiative#172.
+//
+// In this test the global where-bound simply constrains the
+// object lifetime bound to 'static while the builtin impl
+// ends up also emitting a `dyn Any: 'static` type outlives
+// constraint. This previously resulted in ambiguity. We now
+// always prefer the impl.
+
+pub trait Any: 'static {}
+
+pub trait Downcast<T>: Any
+where
+ T: Any,
+{
+}
+
+// elided object lifetime: `dyn Any + 'static`
+impl dyn Any {
+ pub fn is<T>(&self)
+ where
+ T: Any,
+ // elaboration adds global where-clause `dyn Any + 'static: Any`
+ Self: Downcast<T>,
+ {
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/traits/winnowing/global-where-bound-region-constraints.rs b/tests/ui/traits/winnowing/global-where-bound-region-constraints.rs
new file mode 100644
index 0000000..3bc8b04
--- /dev/null
+++ b/tests/ui/traits/winnowing/global-where-bound-region-constraints.rs
@@ -0,0 +1,29 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+
+// Regression test for trait-system-refactor-initiative#172.
+//
+// The next-generation trait solver previously simply tried
+// to merge the global where-bounds with the impl candidates.
+// This caused ambiguity in case the where-bound had stricter
+// region requirements than the impl.
+
+trait Trait {}
+struct Foo<'a, 'b>(&'a (), &'b ());
+impl<'a> Trait for Foo<'a, 'static> {}
+
+fn impls_trait<T: Trait>() {}
+fn foo()
+where
+ Foo<'static, 'static>: Trait,
+{
+ // impl requires `'1 to be 'static
+ // global where-bound requires both '0 and '1 to be 'static
+ //
+ // we always prefer the impl here.
+ impls_trait::<Foo<'_, '_>>();
+}
+
+fn main() {}
diff --git a/tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs b/tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs
new file mode 100644
index 0000000..cdfb0ee
--- /dev/null
+++ b/tests/ui/traits/winnowing/norm-where-bound-gt-alias-bound.rs
@@ -0,0 +1,29 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+//@ check-pass
+
+// Make sure we prefer the `I::IntoIterator: Iterator<Item = ()>`
+// where-bound over the `I::Intoiterator: Iterator<Item = I::Item>`
+// alias-bound.
+
+trait Iterator {
+ type Item;
+}
+
+trait IntoIterator {
+ type Item;
+ type IntoIter: Iterator<Item = Self::Item>;
+}
+
+fn normalize<I: Iterator<Item = ()>>() {}
+
+fn foo<I>()
+where
+ I: IntoIterator,
+ I::IntoIter: Iterator<Item = ()>,
+{
+ normalize::<I::IntoIter>();
+}
+
+fn main() {}
diff --git a/tests/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs b/tests/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs
index 736a9df..be8b7fa 100644
--- a/tests/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs
+++ b/tests/ui/type-alias-impl-trait/cross_inference_pattern_bug_no_type.rs
@@ -1,6 +1,5 @@
//@ compile-flags: --crate-type=lib
//@ edition: 2021
-//@ rustc-env:RUST_BACKTRACE=0
//@ check-pass
// tracked in https://github.com/rust-lang/rust/issues/96572
diff --git a/tests/ui/type-alias-impl-trait/destructure_tait-ice-113594.rs b/tests/ui/type-alias-impl-trait/destructure_tait-ice-113594.rs
index a3b1aba..a42ea08 100644
--- a/tests/ui/type-alias-impl-trait/destructure_tait-ice-113594.rs
+++ b/tests/ui/type-alias-impl-trait/destructure_tait-ice-113594.rs
@@ -1,3 +1,5 @@
+//@ revisions: current next
+//@ [next] compile-flags: -Znext-solver
//@ build-pass
//@ edition: 2021
diff --git a/tests/ui/type-alias-impl-trait/issue-60662.rs b/tests/ui/type-alias-impl-trait/issue-60662.rs
index 35d96e5..7ecdd26 100644
--- a/tests/ui/type-alias-impl-trait/issue-60662.rs
+++ b/tests/ui/type-alias-impl-trait/issue-60662.rs
@@ -1,5 +1,6 @@
//@ check-pass
//@ compile-flags: -Z unpretty=hir
+//@ edition: 2015
#![feature(type_alias_impl_trait)]
diff --git a/tests/ui/type-alias-impl-trait/issue-60662.stdout b/tests/ui/type-alias-impl-trait/issue-60662.stdout
index b541cbe..56fef85 100644
--- a/tests/ui/type-alias-impl-trait/issue-60662.stdout
+++ b/tests/ui/type-alias-impl-trait/issue-60662.stdout
@@ -1,5 +1,6 @@
//@ check-pass
//@ compile-flags: -Z unpretty=hir
+//@ edition: 2015
#![feature(type_alias_impl_trait)]
#[prelude_import]
diff --git a/tests/ui/type-alias-impl-trait/tait-normalize.rs b/tests/ui/type-alias-impl-trait/tait-normalize.rs
index 38e09b6..a34d167 100644
--- a/tests/ui/type-alias-impl-trait/tait-normalize.rs
+++ b/tests/ui/type-alias-impl-trait/tait-normalize.rs
@@ -1,3 +1,5 @@
+//@ revisions: current next
+//@ [next] compile-flags: -Znext-solver
//@ check-pass
#![feature(type_alias_impl_trait)]
diff --git a/tests/ui/type/ascription/issue-47666.stderr b/tests/ui/type/ascription/issue-47666.stderr
index fd825e8..6568845 100644
--- a/tests/ui/type/ascription/issue-47666.stderr
+++ b/tests/ui/type/ascription/issue-47666.stderr
@@ -4,7 +4,6 @@
LL | let _ = Option:Some(vec![0, 1]);
| ^
|
- = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: use a double colon instead
|
LL | let _ = Option::Some(vec![0, 1]);
diff --git a/tests/ui/type/ascription/issue-54516.stderr b/tests/ui/type/ascription/issue-54516.stderr
index 64fdc1f..925080e 100644
--- a/tests/ui/type/ascription/issue-54516.stderr
+++ b/tests/ui/type/ascription/issue-54516.stderr
@@ -4,7 +4,6 @@
LL | println!("{}", std::mem:size_of::<BTreeMap<u32, u32>>());
| ^
|
- = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: use a double colon instead
|
LL | println!("{}", std::mem::size_of::<BTreeMap<u32, u32>>());
diff --git a/tests/ui/type/ascription/issue-60933.stderr b/tests/ui/type/ascription/issue-60933.stderr
index c68394d..7b55935 100644
--- a/tests/ui/type/ascription/issue-60933.stderr
+++ b/tests/ui/type/ascription/issue-60933.stderr
@@ -4,7 +4,6 @@
LL | let _: usize = std::mem:size_of::<u32>();
| ^
|
- = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: use a double colon instead
|
LL | let _: usize = std::mem::size_of::<u32>();
diff --git a/tests/ui/type/missing-let-in-binding.stderr b/tests/ui/type/missing-let-in-binding.stderr
index a9d766e..dee3d56 100644
--- a/tests/ui/type/missing-let-in-binding.stderr
+++ b/tests/ui/type/missing-let-in-binding.stderr
@@ -4,7 +4,6 @@
LL | _foo: i32 = 4;
| ^ expected identifier
|
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: you might have meant to introduce a new binding
|
LL | let _foo: i32 = 4;
diff --git a/tests/ui/type/pattern_types/derives.rs b/tests/ui/type/pattern_types/derives.rs
index 3878c47..a3959b3 100644
--- a/tests/ui/type/pattern_types/derives.rs
+++ b/tests/ui/type/pattern_types/derives.rs
@@ -1,4 +1,5 @@
-//! Check that pattern types don't implement traits of their base automatically
+//! Check that pattern types don't implement traits of their base automatically.
+//! Exceptions are `Clone` and `Copy`, which have builtin impls for pattern types.
#![feature(pattern_types)]
#![feature(pattern_type_macro)]
diff --git a/tests/ui/type/pattern_types/derives.stderr b/tests/ui/type/pattern_types/derives.stderr
index f59617e..2d83684 100644
--- a/tests/ui/type/pattern_types/derives.stderr
+++ b/tests/ui/type/pattern_types/derives.stderr
@@ -1,5 +1,5 @@
error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
- --> $DIR/derives.rs:10:20
+ --> $DIR/derives.rs:11:20
|
LL | #[derive(Clone, Copy, PartialEq)]
| --------- in this derive macro expansion
diff --git a/tests/ui/type/pattern_types/derives_fail.rs b/tests/ui/type/pattern_types/derives_fail.rs
new file mode 100644
index 0000000..a3fbad6
--- /dev/null
+++ b/tests/ui/type/pattern_types/derives_fail.rs
@@ -0,0 +1,26 @@
+//! Check that pattern types don't implement traits of their base automatically.
+//! Exceptions are `Clone` and `Copy`, which have bultin impls for pattern types.
+
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+#[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+#[repr(transparent)]
+struct Nanoseconds(NanoI32);
+//~^ ERROR: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied
+//~| ERROR: `(i32) is 0..=999999999` doesn't implement `Debug`
+//~| ERROR: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied
+//~| ERROR: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied
+//~| ERROR: the trait bound `(i32) is 0..=999999999: Default` is not satisfied
+//~| ERROR: can't compare `(i32) is 0..=999999999` with `_`
+//~| ERROR: `==` cannot be applied
+
+type NanoI32 = crate::pattern_type!(i32 is 0..=999_999_999);
+
+fn main() {
+ let x = Nanoseconds(unsafe { std::mem::transmute(42) });
+ let y = x.clone();
+ if y == x {}
+}
diff --git a/tests/ui/type/pattern_types/derives_fail.stderr b/tests/ui/type/pattern_types/derives_fail.stderr
new file mode 100644
index 0000000..78bef72
--- /dev/null
+++ b/tests/ui/type/pattern_types/derives_fail.stderr
@@ -0,0 +1,74 @@
+error[E0369]: binary operation `==` cannot be applied to type `(i32) is 0..=999999999`
+ --> $DIR/derives_fail.rs:11:20
+ |
+LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+ | --------- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+ | ^^^^^^^
+
+error[E0277]: the trait bound `(i32) is 0..=999999999: Eq` is not satisfied
+ --> $DIR/derives_fail.rs:11:20
+ |
+LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+ | -- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+ | ^^^^^^^ the trait `Eq` is not implemented for `(i32) is 0..=999999999`
+ |
+note: required by a bound in `AssertParamIsEq`
+ --> $SRC_DIR/core/src/cmp.rs:LL:COL
+
+error[E0277]: `(i32) is 0..=999999999` doesn't implement `Debug`
+ --> $DIR/derives_fail.rs:11:20
+ |
+LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+ | ----- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+ | ^^^^^^^ `(i32) is 0..=999999999` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+ |
+ = help: the trait `Debug` is not implemented for `(i32) is 0..=999999999`
+
+error[E0277]: the trait bound `(i32) is 0..=999999999: Ord` is not satisfied
+ --> $DIR/derives_fail.rs:11:20
+ |
+LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+ | --- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+ | ^^^^^^^ the trait `Ord` is not implemented for `(i32) is 0..=999999999`
+
+error[E0277]: can't compare `(i32) is 0..=999999999` with `_`
+ --> $DIR/derives_fail.rs:11:20
+ |
+LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+ | ---------- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+ | ^^^^^^^ no implementation for `(i32) is 0..=999999999 < _` and `(i32) is 0..=999999999 > _`
+ |
+ = help: the trait `PartialOrd<_>` is not implemented for `(i32) is 0..=999999999`
+
+error[E0277]: the trait bound `(i32) is 0..=999999999: Hash` is not satisfied
+ --> $DIR/derives_fail.rs:11:20
+ |
+LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+ | ---- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+ | ^^^^^^^ the trait `Hash` is not implemented for `(i32) is 0..=999999999`
+
+error[E0277]: the trait bound `(i32) is 0..=999999999: Default` is not satisfied
+ --> $DIR/derives_fail.rs:11:20
+ |
+LL | #[derive(Clone, Copy, PartialEq, Eq, Debug, Ord, PartialOrd, Hash, Default)]
+ | ------- in this derive macro expansion
+LL | #[repr(transparent)]
+LL | struct Nanoseconds(NanoI32);
+ | ^^^^^^^ the trait `Default` is not implemented for `(i32) is 0..=999999999`
+
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0277, E0369.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/type/pattern_types/matching.rs b/tests/ui/type/pattern_types/matching.rs
new file mode 100644
index 0000000..b8463a8
--- /dev/null
+++ b/tests/ui/type/pattern_types/matching.rs
@@ -0,0 +1,26 @@
+#![feature(pattern_types, pattern_type_macro, structural_match)]
+
+//@ check-pass
+
+use std::marker::StructuralPartialEq;
+use std::pat::pattern_type;
+
+struct Thing(pattern_type!(u32 is 1..));
+
+impl StructuralPartialEq for Thing {}
+impl PartialEq for Thing {
+ fn eq(&self, other: &Thing) -> bool {
+ unsafe { std::mem::transmute::<_, u32>(self.0) == std::mem::transmute::<_, u32>(other.0) }
+ }
+}
+
+impl Eq for Thing {}
+
+const TWO: Thing = Thing(2);
+
+const _: () = match TWO {
+ TWO => {}
+ _ => unreachable!(),
+};
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/matching_fail.rs b/tests/ui/type/pattern_types/matching_fail.rs
new file mode 100644
index 0000000..8e2c741
--- /dev/null
+++ b/tests/ui/type/pattern_types/matching_fail.rs
@@ -0,0 +1,25 @@
+#![feature(pattern_types, pattern_type_macro, structural_match)]
+
+use std::pat::pattern_type;
+
+const THREE: pattern_type!(u32 is 1..) = 3;
+
+const _: () = match THREE {
+ THREE => {}
+ //~^ ERROR non-structural type
+ _ => unreachable!(),
+};
+
+const _: () = match THREE {
+ 3 => {}
+ //~^ ERROR mismatched types
+ _ => unreachable!(),
+};
+
+const _: () = match 3 {
+ THREE => {}
+ //~^ ERROR mismatched types
+ _ => unreachable!(),
+};
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/matching_fail.stderr b/tests/ui/type/pattern_types/matching_fail.stderr
new file mode 100644
index 0000000..446180d
--- /dev/null
+++ b/tests/ui/type/pattern_types/matching_fail.stderr
@@ -0,0 +1,43 @@
+error: constant of non-structural type `(u32) is 1..` in a pattern
+ --> $DIR/matching_fail.rs:8:5
+ |
+LL | const THREE: pattern_type!(u32 is 1..) = 3;
+ | -------------------------------------- constant defined here
+...
+LL | THREE => {}
+ | ^^^^^ constant of non-structural type
+ |
+ = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralPartialEq.html for details
+
+error[E0308]: mismatched types
+ --> $DIR/matching_fail.rs:14:5
+ |
+LL | const _: () = match THREE {
+ | ----- this expression has type `(u32) is 1..`
+LL | 3 => {}
+ | ^ expected `(u32) is 1..`, found integer
+ |
+ = note: expected pattern type `(u32) is 1..`
+ found type `{integer}`
+
+error[E0308]: mismatched types
+ --> $DIR/matching_fail.rs:20:5
+ |
+LL | const THREE: pattern_type!(u32 is 1..) = 3;
+ | -------------------------------------- constant defined here
+...
+LL | const _: () = match 3 {
+ | - this expression has type `{integer}`
+LL | THREE => {}
+ | ^^^^^
+ | |
+ | expected integer, found `(u32) is 1..`
+ | `THREE` is interpreted as a constant, not a new binding
+ | help: introduce a new binding instead: `other_three`
+ |
+ = note: expected type `{integer}`
+ found pattern type `(u32) is 1..`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/type/type-ascription-instead-of-statement-end.stderr b/tests/ui/type/type-ascription-instead-of-statement-end.stderr
index 34759b4..82b7fd2 100644
--- a/tests/ui/type/type-ascription-instead-of-statement-end.stderr
+++ b/tests/ui/type/type-ascription-instead-of-statement-end.stderr
@@ -4,7 +4,6 @@
LL | println!("test"):
| ^
|
- = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: use a semicolon instead
|
LL - println!("test"):
diff --git a/tests/ui/type/type-ascription-precedence.stderr b/tests/ui/type/type-ascription-precedence.stderr
index 09cdc37..f7ae612 100644
--- a/tests/ui/type/type-ascription-precedence.stderr
+++ b/tests/ui/type/type-ascription-precedence.stderr
@@ -33,8 +33,6 @@
|
LL | S .. S: S;
| ^ expected identifier
- |
- = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
error: expected one of `.`, `;`, `?`, `}`, or an operator, found `:`
--> $DIR/type-ascription-precedence.rs:53:13
diff --git a/tests/ui/type/type-ascription-with-fn-call.stderr b/tests/ui/type/type-ascription-with-fn-call.stderr
index 4222762..803c9f1 100644
--- a/tests/ui/type/type-ascription-with-fn-call.stderr
+++ b/tests/ui/type/type-ascription-with-fn-call.stderr
@@ -4,7 +4,6 @@
LL | f() :
| ^
|
- = note: if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
help: use a semicolon instead
|
LL - f() :
diff --git a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs
index 0be1237..dd83395 100644
--- a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs
+++ b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.rs
@@ -1,4 +1,5 @@
//@ edition:2018
+//@ dont-require-annotations: SUGGESTION
async fn hello() { //~ HELP try adding a return type
0
diff --git a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr
index c46f4ec..3680df2 100644
--- a/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr
+++ b/tests/ui/typeck/issue-90027-async-fn-return-suggestion.stderr
@@ -1,5 +1,5 @@
error[E0308]: mismatched types
- --> $DIR/issue-90027-async-fn-return-suggestion.rs:4:5
+ --> $DIR/issue-90027-async-fn-return-suggestion.rs:5:5
|
LL | async fn hello() {
| - help: try adding a return type: `-> i32`
@@ -7,7 +7,7 @@
| ^ expected `()`, found integer
error[E0308]: mismatched types
- --> $DIR/issue-90027-async-fn-return-suggestion.rs:9:5
+ --> $DIR/issue-90027-async-fn-return-suggestion.rs:10:5
|
LL | async fn world() -> () {
| -- expected `()` because of return type
@@ -15,13 +15,13 @@
| ^ expected `()`, found integer
error[E0308]: mismatched types
- --> $DIR/issue-90027-async-fn-return-suggestion.rs:14:5
+ --> $DIR/issue-90027-async-fn-return-suggestion.rs:15:5
|
LL | hello()
| ^^^^^^^ expected `()`, found future
|
note: calling an async function returns a future
- --> $DIR/issue-90027-async-fn-return-suggestion.rs:14:5
+ --> $DIR/issue-90027-async-fn-return-suggestion.rs:15:5
|
LL | hello()
| ^^^^^^^
diff --git a/tests/ui/typeck/minus-string.rs b/tests/ui/typeck/minus-string.rs
new file mode 100644
index 0000000..1c0f73a
--- /dev/null
+++ b/tests/ui/typeck/minus-string.rs
@@ -0,0 +1,7 @@
+// Regression test for issue #813.
+// This ensures that the unary negation operator `-` cannot be applied to an owned `String`.
+// Previously, due to a type-checking bug, this was mistakenly accepted by the compiler.
+
+fn main() {
+ -"foo".to_string(); //~ ERROR cannot apply unary operator `-` to type `String`
+}
diff --git a/tests/ui/minus-string.stderr b/tests/ui/typeck/minus-string.stderr
similarity index 69%
rename from tests/ui/minus-string.stderr
rename to tests/ui/typeck/minus-string.stderr
index 153965c..d2ebcd0 100644
--- a/tests/ui/minus-string.stderr
+++ b/tests/ui/typeck/minus-string.stderr
@@ -1,8 +1,8 @@
error[E0600]: cannot apply unary operator `-` to type `String`
- --> $DIR/minus-string.rs:1:13
+ --> $DIR/minus-string.rs:6:5
|
-LL | fn main() { -"foo".to_string(); }
- | ^^^^^^^^^^^^^^^^^^ cannot apply unary operator `-`
+LL | -"foo".to_string();
+ | ^^^^^^^^^^^^^^^^^^ cannot apply unary operator `-`
|
note: the foreign item type `String` doesn't implement `Neg`
--> $SRC_DIR/alloc/src/string.rs:LL:COL
diff --git a/tests/ui/typeck/pointer-arith-assign.fixed b/tests/ui/typeck/pointer-arith-assign.fixed
new file mode 100644
index 0000000..9072085
--- /dev/null
+++ b/tests/ui/typeck/pointer-arith-assign.fixed
@@ -0,0 +1,20 @@
+//@ run-rustfix
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+
+fn test_add_assign_raw_pointer() {
+ let mut arr = [0u8; 10];
+ let mut _ptr = arr.as_mut_ptr();
+
+ _ptr = _ptr.wrapping_add(2); //~ ERROR binary assignment operation `+=` cannot be applied to type `*mut u8` [E0368]
+}
+
+fn test_sub_assign_raw_pointer() {
+ let mut arr = [0u8; 10];
+ let mut _ptr = arr.as_mut_ptr();
+
+ _ptr = _ptr.wrapping_sub(2); //~ ERROR binary assignment operation `-=` cannot be applied to type `*mut u8` [E0368]
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/pointer-arith-assign.rs b/tests/ui/typeck/pointer-arith-assign.rs
new file mode 100644
index 0000000..0f4ef6a
--- /dev/null
+++ b/tests/ui/typeck/pointer-arith-assign.rs
@@ -0,0 +1,20 @@
+//@ run-rustfix
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+
+fn test_add_assign_raw_pointer() {
+ let mut arr = [0u8; 10];
+ let mut _ptr = arr.as_mut_ptr();
+
+ _ptr += 2; //~ ERROR binary assignment operation `+=` cannot be applied to type `*mut u8` [E0368]
+}
+
+fn test_sub_assign_raw_pointer() {
+ let mut arr = [0u8; 10];
+ let mut _ptr = arr.as_mut_ptr();
+
+ _ptr -= 2; //~ ERROR binary assignment operation `-=` cannot be applied to type `*mut u8` [E0368]
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/pointer-arith-assign.stderr b/tests/ui/typeck/pointer-arith-assign.stderr
new file mode 100644
index 0000000..a2bebe5
--- /dev/null
+++ b/tests/ui/typeck/pointer-arith-assign.stderr
@@ -0,0 +1,31 @@
+error[E0368]: binary assignment operation `+=` cannot be applied to type `*mut u8`
+ --> $DIR/pointer-arith-assign.rs:10:5
+ |
+LL | _ptr += 2;
+ | ----^^^^^
+ | |
+ | cannot use `+=` on type `*mut u8`
+ |
+help: consider using `add` or `wrapping_add` to do pointer arithmetic
+ |
+LL - _ptr += 2;
+LL + _ptr = _ptr.wrapping_add(2);
+ |
+
+error[E0368]: binary assignment operation `-=` cannot be applied to type `*mut u8`
+ --> $DIR/pointer-arith-assign.rs:17:5
+ |
+LL | _ptr -= 2;
+ | ----^^^^^
+ | |
+ | cannot use `-=` on type `*mut u8`
+ |
+help: consider using `sub` or `wrapping_sub` to do pointer arithmetic
+ |
+LL - _ptr -= 2;
+LL + _ptr = _ptr.wrapping_sub(2);
+ |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0368`.
diff --git a/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs b/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs
index 9304e20..6005bc9 100644
--- a/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs
+++ b/tests/ui/unknown-unstable-lints/deny-unstable-lint-command-line.rs
@@ -1,6 +1,7 @@
//~ ERROR unknown lint: `test_unstable_lint`
+//~^ NOTE the `test_unstable_lint` lint is unstable
//@ check-fail
//@ compile-flags: -Dunknown_lints -Atest_unstable_lint
-//@ error-pattern: the `test_unstable_lint` lint is unstable
+//@ dont-require-annotations: NOTE
fn main() {}
diff --git a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs b/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs
index 7698341..c32a21a 100644
--- a/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs
+++ b/tests/ui/unknown-unstable-lints/warn-unknown-unstable-lint-command-line.rs
@@ -1,6 +1,7 @@
//~ WARN unknown lint: `test_unstable_lint`
+//~^ NOTE the `test_unstable_lint` lint is unstable
//@ check-pass
//@ compile-flags: -Wunknown_lints -Atest_unstable_lint
-//@ error-pattern: the `test_unstable_lint` lint is unstable
+//@ dont-require-annotations: NOTE
fn main() {}
diff --git a/tests/ui/unpretty/bad-literal.rs b/tests/ui/unpretty/bad-literal.rs
index 3737789..0ec1d7b 100644
--- a/tests/ui/unpretty/bad-literal.rs
+++ b/tests/ui/unpretty/bad-literal.rs
@@ -1,5 +1,6 @@
//@ compile-flags: -Zunpretty=hir
//@ check-fail
+//@ edition: 2015
// In #100948 this caused an ICE with -Zunpretty=hir.
fn main() {
diff --git a/tests/ui/unpretty/bad-literal.stderr b/tests/ui/unpretty/bad-literal.stderr
index b625948..fd1801a 100644
--- a/tests/ui/unpretty/bad-literal.stderr
+++ b/tests/ui/unpretty/bad-literal.stderr
@@ -1,5 +1,5 @@
error: invalid suffix `u` for number literal
- --> $DIR/bad-literal.rs:6:5
+ --> $DIR/bad-literal.rs:7:5
|
LL | 1u;
| ^^ invalid suffix `u`
diff --git a/tests/ui/unpretty/bad-literal.stdout b/tests/ui/unpretty/bad-literal.stdout
index c527271..06116a4 100644
--- a/tests/ui/unpretty/bad-literal.stdout
+++ b/tests/ui/unpretty/bad-literal.stdout
@@ -4,6 +4,7 @@
extern crate std;
//@ compile-flags: -Zunpretty=hir
//@ check-fail
+//@ edition: 2015
// In #100948 this caused an ICE with -Zunpretty=hir.
fn main() {
diff --git a/tests/ui/unpretty/debug-fmt-hir.rs b/tests/ui/unpretty/debug-fmt-hir.rs
index c19f3c4..c79349d 100644
--- a/tests/ui/unpretty/debug-fmt-hir.rs
+++ b/tests/ui/unpretty/debug-fmt-hir.rs
@@ -1,5 +1,6 @@
//@ compile-flags: -Zunpretty=hir
//@ check-pass
+//@ edition: 2015
use std::fmt;
diff --git a/tests/ui/unpretty/debug-fmt-hir.stdout b/tests/ui/unpretty/debug-fmt-hir.stdout
index 2c9c96d..dc18675 100644
--- a/tests/ui/unpretty/debug-fmt-hir.stdout
+++ b/tests/ui/unpretty/debug-fmt-hir.stdout
@@ -4,6 +4,7 @@
extern crate std;
//@ compile-flags: -Zunpretty=hir
//@ check-pass
+//@ edition: 2015
use std::fmt;
diff --git a/tests/ui/unpretty/deprecated-attr.rs b/tests/ui/unpretty/deprecated-attr.rs
index dda362a..0c80203 100644
--- a/tests/ui/unpretty/deprecated-attr.rs
+++ b/tests/ui/unpretty/deprecated-attr.rs
@@ -1,5 +1,6 @@
//@ compile-flags: -Zunpretty=hir
//@ check-pass
+//@ edition: 2015
#[deprecated]
pub struct PlainDeprecated;
diff --git a/tests/ui/unpretty/deprecated-attr.stdout b/tests/ui/unpretty/deprecated-attr.stdout
index 42de7b4..97d863b 100644
--- a/tests/ui/unpretty/deprecated-attr.stdout
+++ b/tests/ui/unpretty/deprecated-attr.stdout
@@ -4,6 +4,7 @@
extern crate std;
//@ compile-flags: -Zunpretty=hir
//@ check-pass
+//@ edition: 2015
#[attr = Deprecation {deprecation: Deprecation {since: Unspecified}}]
struct PlainDeprecated;
diff --git a/tests/ui/unpretty/diagnostic-attr.rs b/tests/ui/unpretty/diagnostic-attr.rs
index 27f5b69..4ef85c7 100644
--- a/tests/ui/unpretty/diagnostic-attr.rs
+++ b/tests/ui/unpretty/diagnostic-attr.rs
@@ -1,5 +1,6 @@
//@ compile-flags: -Zunpretty=hir
//@ check-pass
+//@ edition: 2015
#[diagnostic::on_unimplemented(
message = "My Message for `ImportantTrait<{A}>` implemented for `{Self}`",
diff --git a/tests/ui/unpretty/diagnostic-attr.stdout b/tests/ui/unpretty/diagnostic-attr.stdout
index e8696d0..81d71b9 100644
--- a/tests/ui/unpretty/diagnostic-attr.stdout
+++ b/tests/ui/unpretty/diagnostic-attr.stdout
@@ -4,6 +4,7 @@
extern crate std;
//@ compile-flags: -Zunpretty=hir
//@ check-pass
+//@ edition: 2015
#[diagnostic::on_unimplemented(message =
"My Message for `ImportantTrait<{A}>` implemented for `{Self}`", label =
diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs
index 4d1f12e..0fb5a26 100644
--- a/tests/ui/unpretty/expanded-exhaustive.rs
+++ b/tests/ui/unpretty/expanded-exhaustive.rs
@@ -12,7 +12,6 @@
#![feature(dyn_star)]
#![feature(explicit_tail_calls)]
#![feature(gen_blocks)]
-#![feature(let_chains)]
#![feature(more_qualified_paths)]
#![feature(never_patterns)]
#![feature(never_type)]
diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout
index d8da941..8febd2d 100644
--- a/tests/ui/unpretty/expanded-exhaustive.stdout
+++ b/tests/ui/unpretty/expanded-exhaustive.stdout
@@ -13,7 +13,6 @@
#![feature(dyn_star)]
#![feature(explicit_tail_calls)]
#![feature(gen_blocks)]
-#![feature(let_chains)]
#![feature(more_qualified_paths)]
#![feature(never_patterns)]
#![feature(never_type)]
diff --git a/tests/ui/unpretty/expanded-interpolation.rs b/tests/ui/unpretty/expanded-interpolation.rs
index 1dc72c6..95280f9 100644
--- a/tests/ui/unpretty/expanded-interpolation.rs
+++ b/tests/ui/unpretty/expanded-interpolation.rs
@@ -1,4 +1,5 @@
//@ compile-flags: -Zunpretty=expanded
+//@ edition:2024
//@ check-pass
// This test covers the AST pretty-printer's insertion of parentheses in some
@@ -7,7 +8,6 @@
// Rust syntax. We also test negative cases: the pretty-printer should not be
// synthesizing parentheses indiscriminately; only where necessary.
-#![feature(let_chains)]
#![feature(if_let_guard)]
macro_rules! expr {
diff --git a/tests/ui/unpretty/expanded-interpolation.stdout b/tests/ui/unpretty/expanded-interpolation.stdout
index 556e57d..d46b46b 100644
--- a/tests/ui/unpretty/expanded-interpolation.stdout
+++ b/tests/ui/unpretty/expanded-interpolation.stdout
@@ -1,6 +1,6 @@
#![feature(prelude_import)]
-#![no_std]
//@ compile-flags: -Zunpretty=expanded
+//@ edition:2024
//@ check-pass
// This test covers the AST pretty-printer's insertion of parentheses in some
@@ -9,10 +9,9 @@
// Rust syntax. We also test negative cases: the pretty-printer should not be
// synthesizing parentheses indiscriminately; only where necessary.
-#![feature(let_chains)]
#![feature(if_let_guard)]
#[prelude_import]
-use ::std::prelude::rust_2015::*;
+use std::prelude::rust_2024::*;
#[macro_use]
extern crate std;
diff --git a/tests/ui/unpretty/flattened-format-args.rs b/tests/ui/unpretty/flattened-format-args.rs
index 772f44c..ab065f4 100644
--- a/tests/ui/unpretty/flattened-format-args.rs
+++ b/tests/ui/unpretty/flattened-format-args.rs
@@ -1,5 +1,6 @@
//@ compile-flags: -Zunpretty=hir -Zflatten-format-args=yes
//@ check-pass
+//@ edition: 2015
fn main() {
let x = 1;
diff --git a/tests/ui/unpretty/flattened-format-args.stdout b/tests/ui/unpretty/flattened-format-args.stdout
index 2de1cdd..a5d9432 100644
--- a/tests/ui/unpretty/flattened-format-args.stdout
+++ b/tests/ui/unpretty/flattened-format-args.stdout
@@ -4,6 +4,7 @@
extern crate std;
//@ compile-flags: -Zunpretty=hir -Zflatten-format-args=yes
//@ check-pass
+//@ edition: 2015
fn main() {
let x = 1;
diff --git a/tests/ui/unpretty/let-else-hir.rs b/tests/ui/unpretty/let-else-hir.rs
index 9c23118..786c84a 100644
--- a/tests/ui/unpretty/let-else-hir.rs
+++ b/tests/ui/unpretty/let-else-hir.rs
@@ -1,5 +1,6 @@
//@ compile-flags: -Zunpretty=hir
//@ check-pass
+//@ edition: 2015
diff --git a/tests/ui/unpretty/let-else-hir.stdout b/tests/ui/unpretty/let-else-hir.stdout
index a2ffa5d..a6dd943 100644
--- a/tests/ui/unpretty/let-else-hir.stdout
+++ b/tests/ui/unpretty/let-else-hir.stdout
@@ -4,6 +4,7 @@
extern crate std;
//@ compile-flags: -Zunpretty=hir
//@ check-pass
+//@ edition: 2015
diff --git a/tests/ui/unpretty/self-hir.rs b/tests/ui/unpretty/self-hir.rs
index 448d828..70e0ba5 100644
--- a/tests/ui/unpretty/self-hir.rs
+++ b/tests/ui/unpretty/self-hir.rs
@@ -1,5 +1,6 @@
//@ compile-flags: -Zunpretty=hir
//@ check-pass
+//@ edition: 2015
pub struct Bar {
a: String,
diff --git a/tests/ui/unpretty/self-hir.stdout b/tests/ui/unpretty/self-hir.stdout
index 4da080d..a9e80b1 100644
--- a/tests/ui/unpretty/self-hir.stdout
+++ b/tests/ui/unpretty/self-hir.stdout
@@ -4,6 +4,7 @@
extern crate std;
//@ compile-flags: -Zunpretty=hir
//@ check-pass
+//@ edition: 2015
struct Bar {
a: String,
diff --git a/tests/ui/unpretty/unpretty-expr-fn-arg.rs b/tests/ui/unpretty/unpretty-expr-fn-arg.rs
index 7f496e7..b2ab2e0 100644
--- a/tests/ui/unpretty/unpretty-expr-fn-arg.rs
+++ b/tests/ui/unpretty/unpretty-expr-fn-arg.rs
@@ -6,6 +6,7 @@
//@ check-pass
//@ compile-flags: -Zunpretty=hir,typed
+//@ edition: 2015
#![allow(dead_code)]
fn main() {}
diff --git a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout
index 43aa93c..fd2e794 100644
--- a/tests/ui/unpretty/unpretty-expr-fn-arg.stdout
+++ b/tests/ui/unpretty/unpretty-expr-fn-arg.stdout
@@ -6,6 +6,7 @@
//@ check-pass
//@ compile-flags: -Zunpretty=hir,typed
+//@ edition: 2015
#![allow(dead_code)]
#[prelude_import]
use ::std::prelude::rust_2015::*;
diff --git a/tests/ui/wasm/wasm-import-module.rs b/tests/ui/wasm/wasm-import-module.rs
index bff0884..2b3bca9 100644
--- a/tests/ui/wasm/wasm-import-module.rs
+++ b/tests/ui/wasm/wasm-import-module.rs
@@ -15,7 +15,7 @@
#[link(wasm_import_module = "foo", kind = "dylib")] //~ ERROR: `wasm_import_module` is incompatible with other arguments
extern "C" {}
-#[link(wasm_import_module = "foo", cfg(FALSE))] //~ ERROR: `wasm_import_module` is incompatible with other arguments
+#[link(wasm_import_module = "foo", cfg(false))] //~ ERROR: `wasm_import_module` is incompatible with other arguments
extern "C" {}
fn main() {}
diff --git a/tests/ui/wasm/wasm-import-module.stderr b/tests/ui/wasm/wasm-import-module.stderr
index e792c33..84f4379 100644
--- a/tests/ui/wasm/wasm-import-module.stderr
+++ b/tests/ui/wasm/wasm-import-module.stderr
@@ -31,7 +31,7 @@
error: `wasm_import_module` is incompatible with other arguments in `#[link]` attributes
--> $DIR/wasm-import-module.rs:18:8
|
-LL | #[link(wasm_import_module = "foo", cfg(FALSE))]
+LL | #[link(wasm_import_module = "foo", cfg(false))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 6 previous errors
diff --git a/triagebot.toml b/triagebot.toml
index 226f024..189223f 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -659,6 +659,7 @@
"""\
/poll Approve stable backport of #{number}?
approve
+approve (but does not justify new dot release on its own)
decline
don't know
""",
@@ -1119,6 +1120,11 @@
[mentions."compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs"]
cc = ["@ZuseZ4"]
+[mentions."library/core/src/fmt/rt.rs"]
+cc = ["@m-ou-se"]
+[mentions."compiler/rustc_ast_lowering/src/format.rs"]
+cc = ["@m-ou-se"]
+
[assign]
warn_non_default_branch.enable = true
contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html"